diff --git a/.github/workflows/update-upstream.yml b/.github/workflows/update-upstream.yml index 95d4824..18363ef 100644 --- a/.github/workflows/update-upstream.yml +++ b/.github/workflows/update-upstream.yml @@ -33,6 +33,7 @@ jobs: set -euo pipefail bash -n scripts/update_upstream.sh python3 scripts/test_update_whitespace.py + python3 scripts/test_publish_generated_branch.py variant=$(tr -d '[:space:]' < UPSTREAM_VARIANT) scripts/update_upstream.sh "$variant" --check-only git diff --exit-code @@ -193,30 +194,37 @@ jobs: echo 'No generated changes to propose.' exit 0 fi - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git switch -c "$UPDATE_BRANCH" - git commit -m "Update $VARIANT ImGui and ImPlot bindings" remote_ref="refs/heads/$UPDATE_BRANCH" remote_sha=$(git ls-remote origin "$remote_ref" | awk '{print $1}') if [[ -n "$remote_sha" ]]; then existing=$(gh pr list --base "$BASE_BRANCH" --head "$UPDATE_BRANCH" \ --state open --json number --jq '.[0].number // empty') - [[ -n "$existing" ]] || { - echo "Refusing to replace $remote_ref without an open update PR." >&2 - exit 1 - } - git push --force-with-lease="$remote_ref:$remote_sha" origin "HEAD:$remote_ref" - echo "Updated PR #$existing" - else - git push origin "HEAD:$remote_ref" + if [[ -z "$existing" ]]; then + git fetch --no-tags origin "$remote_ref" + [[ $(git rev-parse FETCH_HEAD) == "$remote_sha" ]] || exit 1 + [[ $(git write-tree) == $(git rev-parse 'FETCH_HEAD^{tree}') ]] || { + echo "Refusing to replace $remote_ref without an open update PR." >&2 + exit 1 + } + fi + fi + before=$(git rev-parse HEAD) + python3 scripts/publish_generated_branch.py "$UPDATE_BRANCH" "Update $VARIANT ImGui and ImPlot bindings" + pushed=false + if [[ $(git rev-parse HEAD) != "$before" ]]; then pushed=true; fi + # Even after a no-op push, recover a missing PR without editing an existing one. + existing=$(gh pr list --base "$BASE_BRANCH" --head "$UPDATE_BRANCH" \ + --state open --json number --jq '.[0].number // empty') + created=false + if [[ -z "$existing" ]]; then gh pr create --draft --base "$BASE_BRANCH" --head "$UPDATE_BRANCH" \ --title "Update $VARIANT ImGui and ImPlot bindings" \ --body "Automated upstream refresh for the $VARIANT variant. cimgui: $(git -C cimgui rev-parse HEAD); cimplot: $(git -C cimplot rev-parse HEAD). Generated V bindings and native sources must pass CI and receive human review before merge." + created=true fi # A repository-token PR needs explicit CI dispatch. A personal token # already triggers PR checks, so do not duplicate them. - if [[ "$DISPATCH_CI" == true ]]; then + if [[ "$DISPATCH_CI" == true && ( "$pushed" == true || "$created" == true ) ]]; then for workflow in demo-release.yml mobile-native.yml application-accessibility.yml portable-tooling.yml; do gh workflow run "$workflow" --ref "$UPDATE_BRANCH" done diff --git a/README.md b/README.md index 16ac2f8..2b52708 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,10 @@ This repository supports both official Dear ImGui lines: multi-viewport support while retaining the normal Dear ImGui API. - The `standard` branch tracks Dear ImGui's smaller standard line. -Both currently track Dear ImGui `1.92.9b`. The `b` is an upstream patch-level -suffix shared by the release; it does not identify the docking variant. Check +The standard line tracks Dear ImGui `1.93.0`; the docking line remains on +`1.92.9b` until its upstream generated docking API is ready. See +[Migrating to 1.93](docs/migrating-1.93.md) before upgrading a consumer. +The `b` is an upstream patch-level suffix, not a docking marker. Check `UPSTREAM_VARIANT` in a checkout to see which line its generated bindings and native sources use. Do not mix a generated binding from one line with a native library built from the other. @@ -58,8 +60,8 @@ and secondary-viewport rendering helpers become safe no-ops there. The setup and build tooling uses V, CMake, Git and a C/C++ toolchain. Python, Rust and Cargo are not required. -`v install antono2.vulkan@v2.0.0`
-`v install antono2.glfw` +Run `v install` in this checkout to install the tested dependency versions from +[`v.mod`](v.mod). Keep those pins aligned with `compatibility.json`. ## Install ```bash diff --git a/VERSION b/VERSION index 49b8476..95784ef 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.92.9b +1.93.0 diff --git a/cimgui b/cimgui index bb4d484..c4461a7 160000 --- a/cimgui +++ b/cimgui @@ -1 +1 @@ -Subproject commit bb4d4848b759e037a6cc26d23be0387a148ac39f +Subproject commit c4461a7eadbd17b6a6a8124a8abbf499aba6318d diff --git a/cimplot b/cimplot index 11f13e6..c809ff2 160000 --- a/cimplot +++ b/cimplot @@ -1 +1 @@ -Subproject commit 11f13e6cd0f80e83d6409e78592b392967fa7954 +Subproject commit c809ff29c84813fe1cdc8a0c069145ef2285f22a diff --git a/docs/migrating-1.93.md b/docs/migrating-1.93.md new file mode 100644 index 0000000..bdd7aa4 --- /dev/null +++ b/docs/migrating-1.93.md @@ -0,0 +1,45 @@ +# Dear ImGui 1.93 standard bindings + +`v0.4.0-standard` updates the **standard** variant to Dear ImGui 1.93.0. +It is an API/ABI update, not a drop-in native-library replacement. The docking +variant remains on 1.92.9b; do not switch variants or reuse its native library +implicitly. + +```sh +v install antono2.imgui@v0.4.0-standard +cd ~/.vmodules/antono2/imgui +v install +v run build_vimgui.vsh --linkage shared --glfw system +``` + +Rebuild your application and its native libraries together. Do not mix old +generated V structures with a new `libvimgui`, or the reverse. + +Notable source changes include: + +- `ImDrawListFlags`/`ImDrawListFlags_` are replaced by the new draw flags API. +- Draw-list methods such as `im_draw_list_add_line` and + `im_draw_list_add_circle` gain an explicit flags argument. Review the new + signature and desired stroke/cap/join behavior rather than copying old bits. +- `Style.AntiAliasedLinesUseTex` is removed because the new line renderer + always uses textures. `AntiAliasedLineEnds` controls line-ending anti-aliasing; + it is not a replacement texture toggle. +- `CurveTessellationTol` used squared-pixel units; `CurveTessellationMaxError` + uses pixels. Convert a customized old threshold with `sqrt(old_threshold)` + rather than copying the old value unchanged. +- Font remapping uses `im_font_add_remap_codepoint` instead of + `im_font_add_remap_char`. +- Text-filter, draw-list and other generated structures have changed layouts. + Treat fixed-array helper aliases as generated implementation details. + +These are highlights, not a complete API diff. Compare `imgui.v`, +`implot/implot.v` and the bundled upstream changelog for APIs your project uses. +Update the generator/normalizer when a binding fix is needed; never patch +generated declarations independently of their matching C API. + +Consumers using only the unchanged widget/frame/backend calls may need no +source edits, but still need a rebuilt native library, installation checks and +runtime validation. `v_vulkan_video --imgui-demo` exercises actual UI rendering +and input over hardware video playback; the examples cover GLFW/Vulkan, +widgets, native application UI and ImPlot. Docking and platform-viewports +helpers remain safe no-ops on the standard variant. diff --git a/imgui.v b/imgui.v index a39e535..a39aaec 100644 --- a/imgui.v +++ b/imgui.v @@ -66,8 +66,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -pub const version = '1.92.9b' -pub const version_num = 19291 +pub const version = '1.93.0' +pub const version_num = 19300 pub type BindingFixedArray1 = [61]ImVec4_c pub type BindingFixedArray2 = [5]bool @@ -77,29 +77,33 @@ pub type BindingFixedArray5 = [5]f64 pub type BindingFixedArray6 = [5]ImU16 pub type BindingFixedArray7 = [5]f32 pub type BindingFixedArray8 = [33]i8 -pub type BindingFixedArray9 = [40]i8 -pub type BindingFixedArray10 = [33]ImVec4_c -pub type BindingFixedArray11 = [1]ImU8 -pub type BindingFixedArray12 = [48]ImVec2_c -pub type BindingFixedArray13 = [64]ImU8 -pub type BindingFixedArray14 = [8]ImU8 -pub type BindingFixedArray15 = [4]ImU16 -pub type BindingFixedArray16 = [5]ImU32 -pub type BindingFixedArray17 = [155]KeyRoutingIndex -pub type BindingFixedArray18 = [64]i8 -pub type BindingFixedArray19 = [2]ImRect_c -pub type BindingFixedArray20 = [2]f32 -pub type BindingFixedArray21 = [6]DebugAllocEntry -pub type BindingFixedArray22 = [16]i8 -pub type BindingFixedArray23 = [155]KeyOwnerData -pub type BindingFixedArray24 = [16]u8 -pub type BindingFixedArray25 = [60]f32 -pub type BindingFixedArray26 = [2]ID -pub type BindingFixedArray27 = [2]ImVec2_c -pub type BindingFixedArray28 = [2]ImU32 -pub type BindingFixedArray29 = [80]i8 -pub type BindingFixedArray30 = [99]StbUndoRecord -pub type BindingFixedArray31 = [999]i8 +pub type BindingFixedArray9 = [256]i8 +pub type BindingFixedArray10 = [3]ImDrawFlags +pub type BindingFixedArray11 = [40]i8 +pub type BindingFixedArray12 = [1]ImU8 +pub type BindingFixedArray13 = [48]ImVec2_c +pub type BindingFixedArray14 = [64]ImU8 +pub type BindingFixedArray15 = [8]ImU8 +pub type BindingFixedArray16 = [4]ImU16 +pub type BindingFixedArray17 = [5]ImU32 +pub type BindingFixedArray18 = [155]KeyRoutingIndex +pub type BindingFixedArray19 = [64]i8 +pub type BindingFixedArray20 = [2]ImRect_c +pub type BindingFixedArray21 = [2]i32 +pub type BindingFixedArray22 = [2]f32 +pub type BindingFixedArray23 = [6]DebugAllocEntry +pub type BindingFixedArray24 = [16]i8 +pub type BindingFixedArray25 = [155]KeyOwnerData +pub type BindingFixedArray26 = [16]u8 +pub type BindingFixedArray27 = [60]f32 +pub type BindingFixedArray28 = [2]ID +pub type BindingFixedArray29 = [2]ImVec2_c +pub type BindingFixedArray30 = [2]ImU32 +pub type BindingFixedArray31 = [80]i8 +pub type BindingFixedArray32 = [46]ImVec4_c +pub type BindingFixedArray33 = [64]ImVec4_c +pub type BindingFixedArray34 = [99]StbUndoRecord +pub type BindingFixedArray35 = [999]i8 pub type ImWchar = u32 @@ -131,11 +135,6 @@ pub type ImVec2 = C.ImVec2_c pub type ImVec2i = C.ImVec2i_c pub type ImVec4 = C.ImVec4_c -pub type TextFilter = C.ImGuiTextFilter - -@[typedef] -pub struct C.ImGuiTextFilter {} - pub type InputTextDeactivateData = C.ImGuiInputTextDeactivateData @[typedef] @@ -168,7 +167,6 @@ pub type MouseCursor = i32 pub type StyleVar = i32 pub type TableBgTarget = i32 pub type ImDrawFlags = i32 -pub type ImDrawListFlags = i32 pub type ImDrawTextFlags = i32 pub type ImFontFlags = i32 pub type ImFontAtlasFlags = i32 @@ -282,6 +280,7 @@ pub enum ItemFlags_ { live_edit_on_input_text = 1 << 7 live_edit_on_input_scalar = 1 << 8 live_edit_on_input = 1 << 7 | 1 << 8 + mixed_value = 1 << 9 } pub enum InputTextFlags_ { @@ -1069,9 +1068,9 @@ pub mut: DisplaySafeAreaPadding ImVec2_c MouseCursorScale f32 AntiAliasedLines bool - AntiAliasedLinesUseTex bool + AntiAliasedLineEnds bool AntiAliasedFill bool - CurveTessellationTol f32 + CurveTessellationMaxError f32 CircleTessellationMaxError f32 Colors BindingFixedArray1 HoverStationaryDelay f32 @@ -1159,6 +1158,7 @@ pub mut: ConfigDebugBeginReturnValueOnce bool ConfigDebugBeginReturnValueLoop bool ConfigDebugIgnoreFocusLoss bool + ConfigDebugDrawListDefaultsToStrokeLegacy bool BackendPlatformName &char BackendRendererName &char BackendPlatformUserData voidptr @@ -1269,23 +1269,24 @@ pub mut: RefFrame i32 } -pub type TextRange = C.ImGuiTextRange +pub type ImVector_TextFilterItem = C.ImVector_ImGuiTextFilterItem @[typedef] -pub struct C.ImGuiTextRange { +pub struct C.ImVector_ImGuiTextFilterItem { pub mut: - B &char - E &char + Size i32 + Capacity i32 + Data &TextFilterItem } -pub type ImVector_TextRange = C.ImVector_ImGuiTextRange +pub type TextFilter = C.ImGuiTextFilter @[typedef] -pub struct C.ImVector_ImGuiTextRange { +pub struct C.ImGuiTextFilter { pub mut: - Size i32 - Capacity i32 - Data &TextRange + InputBuf BindingFixedArray9 + _CountExclude i32 + _Items ImVector_TextFilterItem } pub type ImVector_char = C.ImVector_char @@ -1538,29 +1539,36 @@ pub mut: } pub enum ImDrawFlags_ { - none = 0 - round_corners_top_left = 1 << 4 - round_corners_top_right = 1 << 5 - round_corners_bottom_left = 1 << 6 - round_corners_bottom_right = 1 << 7 - round_corners_none = 1 << 8 - round_corners_all = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 - round_corners_top = 1 << 4 | 1 << 5 - round_corners_bottom = 1 << 6 | 1 << 7 - round_corners_left = 1 << 4 | 1 << 6 - round_corners_right = 1 << 5 | 1 << 7 - round_corners_mask_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 - closed = 1 << 9 - invalid_mask_ = -2147483633 -} - -pub enum ImDrawListFlags_ { - none = 0 - anti_aliased_lines = 1 << 0 - anti_aliased_lines_use_tex = 1 << 1 - anti_aliased_fill = 1 << 2 - allow_vtx_offset = 1 << 3 - text_no_pixel_snap = 1 << 4 + none = 0 + round_top_left = 1 << 4 + round_top_right = 1 << 5 + round_bottom_left = 1 << 6 + round_bottom_right = 1 << 7 + round_none = 1 << 8 + round_all = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 + round_top = 1 << 4 | 1 << 5 + round_bottom = 1 << 6 | 1 << 7 + round_left = 1 << 4 | 1 << 6 + round_right = 1 << 5 | 1 << 7 + closed = 1 << 9 + join_miter = 1 << 10 + cap_square = 1 << 11 + aa_fill = 1 << 12 + aa_lines = 1 << 13 + aa_line_ends = 1 << 14 + stroke_inside = 1 << 17 + stroke_center = 1 << 18 + stroke_center_biased = 1 << 17 | 1 << 18 + stroke_outside = 1 << 19 + stroke_legacy = 1 << 17 | 1 << 18 | 1 << 19 + text_no_pixel_snap = 1 << 20 + use_tex_for_round_corners = 1 << 21 + use_vtx_offset = 1 << 22 + allow_tex_for_round_corners_ = 1 << 23 + round_mask_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 + allow_in_push_scope_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 20 | 1 << 21 | 1 << 22 + allow_in_frame_scope_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 + invalid_mask_ = -2147483633 } pub type ImVector_ImDrawVert = C.ImVector_ImDrawVert @@ -1613,27 +1621,39 @@ pub mut: Data &ImU8 } +pub type ImSmallStack__ImDrawFlags__3 = C.ImSmallStack__ImDrawFlags__3 + +@[typedef] +pub struct C.ImSmallStack__ImDrawFlags__3 { +pub mut: + LocalData BindingFixedArray10 + Size ImU16 +} + pub type ImDrawList = C.ImDrawList @[typedef] pub struct C.ImDrawList { pub mut: - CmdBuffer ImVector_ImDrawCmd - IdxBuffer ImVector_ImDrawIdx - VtxBuffer ImVector_ImDrawVert - Flags ImDrawListFlags - _VtxCurrentIdx u32 - _Data &ImDrawListSharedData - _VtxWritePtr &ImDrawVert - _IdxWritePtr &ImDrawIdx - _Path ImVector_ImVec2 - _CmdHeader ImDrawCmdHeader - _Splitter ImDrawListSplitter - _ClipRectStack ImVector_ImVec4 - _TextureStack ImVector_ImTextureRef - _CallbacksDataBuf ImVector_ImU8 - _FringeScale f32 - _OwnerName &char + CmdBuffer ImVector_ImDrawCmd + IdxBuffer ImVector_ImDrawIdx + VtxBuffer ImVector_ImDrawVert + Flags ImDrawFlags + _VtxCurrentIdx u32 + _Data &ImDrawListSharedData + _VtxWritePtr &ImDrawVert + _IdxWritePtr &ImDrawIdx + _Path ImVector_ImVec2 + _CmdHeader ImDrawCmdHeader + _Splitter ImDrawListSplitter + _ClipRectStack ImVector_ImVec4 + _TextureStack ImVector_ImTextureRef + _CallbacksDataBuf ImVector_ImU8 + _DrawFlagsStack ImSmallStack__ImDrawFlags__3 + _FringeScale f32 + _InvFringeScale f32 + _FringeScaleIsInteger bool + _OwnerName &char } pub type ImVector_ImDrawListPtr = C.ImVector_ImDrawListPtr @@ -1736,7 +1756,7 @@ pub type ImFontConfig = C.ImFontConfig @[typedef] pub struct C.ImFontConfig { pub mut: - Name BindingFixedArray9 + Name BindingFixedArray11 FontData voidptr FontDataSize i32 FontDataOwnedByAtlas bool @@ -1822,6 +1842,7 @@ pub enum ImFontAtlasFlags_ { no_power_of_two_height = 1 << 0 no_mouse_cursors = 1 << 1 no_baked_lines = 1 << 2 + no_baked_round_corners = 1 << 3 } pub type ImVector_ImFontPtr = C.ImVector_ImFontPtr @@ -1878,7 +1899,6 @@ pub mut: TexUvWhitePixel ImVec2_c Fonts ImVector_ImFontPtr Sources ImVector_ImFontConfig - TexUvLines BindingFixedArray10 TexNextUniqueID i32 FontNextUniqueID i32 DrawListSharedDatas ImVector_ImDrawListSharedDataPtr @@ -1977,7 +1997,7 @@ pub mut: Sources ImVector_ImFontConfigPtr EllipsisChar ImWchar FallbackChar ImWchar - Used8kPagesMap BindingFixedArray11 + Used8kPagesMap BindingFixedArray12 EllipsisAutoBake bool RemapPairs Storage } @@ -2025,6 +2045,7 @@ pub mut: DrawCallback_ResetRenderState ImDrawCallback DrawCallback_SetSamplerLinear ImDrawCallback DrawCallback_SetSamplerNearest ImDrawCallback + DrawCallback_SetSamplerFromTex ImDrawCallback Textures ImVector_ImTextureDataPtr } @@ -2142,6 +2163,17 @@ pub mut: EndOffset i32 } +pub type TextFilterItem = C.ImGuiTextFilterItem + +@[typedef] +pub struct C.ImGuiTextFilterItem { +pub mut: + Begin &char + Len i32 + CountInclude i16 + MatchIncludesMask u16 +} + pub type PackedDate = C.ImGuiPackedDate @[typedef] @@ -2159,21 +2191,21 @@ pub struct C.ImDrawListSharedData { pub mut: TexUvWhitePixel ImVec2_c TexUvLines &ImVec4_c + TexUvCorners &ImVec4_c FontAtlas &ImFontAtlas Font &ImFont FontSize f32 FontScale f32 - CurveTessellationTol f32 + CurveTessellationMaxError f32 CircleTessellationMaxError f32 - InitialFringeScale f32 - InitialFlags ImDrawListFlags + InitialDrawFlags ImDrawFlags ClipRectFullscreen ImVec4_c TempBuffer ImVector_ImVec2 DrawLists ImVector_ImDrawListPtr Context &Context - ArcFastVtx BindingFixedArray12 + ArcFastVtx BindingFixedArray13 ArcFastRadiusCutoff f32 - CircleSegmentCounts BindingFixedArray13 + CircleSegmentCounts BindingFixedArray14 } pub type ImDrawDataBuilder = C.ImDrawDataBuilder @@ -2227,7 +2259,7 @@ pub type DataTypeStorage = C.ImGuiDataTypeStorage @[typedef] pub struct C.ImGuiDataTypeStorage { pub mut: - Data BindingFixedArray14 + Data BindingFixedArray15 } pub type DataTypeInfo = C.ImGuiDataTypeInfo @@ -2248,7 +2280,6 @@ pub enum DataTypePrivate_ { pub enum ItemFlagsPrivate_ { read_only = 1 << 11 - mixed_value = 1 << 12 no_window_hoverable_check = 1 << 13 allow_overlap = 1 << 14 no_nav_disable_mouse_hover = 1 << 15 @@ -2307,10 +2338,6 @@ pub enum ButtonFlagsPrivate_ { pressed_on_mask_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 9 } -pub enum ComboFlagsPrivate_ { - custom_preview = 1 << 20 -} - pub enum SliderFlagsPrivate_ { vertical = 1 << 20 read_only = 1 << 21 @@ -2392,7 +2419,10 @@ pub mut: BackupCursorMaxPos ImVec2_c BackupCursorPosPrevLine ImVec2_c BackupPrevLineTextBaseOffset f32 + BackupWorkRectMaxX f32 + BackupContentRectMaxX f32 BackupLayout LayoutType + WithinPreview i32 } pub type GroupData = C.ImGuiGroupData @@ -2428,7 +2458,7 @@ pub mut: OffsetLabel ImU16 OffsetShortcut ImU16 OffsetMark ImU16 - Widths BindingFixedArray15 + Widths BindingFixedArray16 } pub type InputTextDeactivatedState = C.ImGuiInputTextDeactivatedState @@ -2486,6 +2516,7 @@ pub mut: SelectedAllMouseLock bool EditedBefore bool EditedThisFrame bool + ValidatedThisFrame bool WantReloadUserBuf bool LastMoveDirectionLR ImS8 ReloadSelectionStart i32 @@ -2533,8 +2564,10 @@ pub mut: SizeVal ImVec2_c ContentSizeVal ImVec2_c ScrollVal ImVec2_c - WindowFlags i32 - ChildFlags i32 + WindowFlagsSet WindowFlags + WindowFlagsClear WindowFlags + ChildFlagsSet ChildFlags + ChildFlagsClear ChildFlags CollapsedVal bool SizeConstraintRect ImRect_c SizeCallback SizeCallback @@ -2630,6 +2663,7 @@ pub mut: StackSizesInBegin ErrorRecoveryState DisabledOverrideReenable bool DisabledOverrideReenableAlphaBackup f32 + ParentLastComboPreviewRect ImRect_c } pub type ShrinkWidthItem = C.ImGuiShrinkWidthItem @@ -2688,7 +2722,7 @@ pub type ImBitArray_Key_NamedKey_COUNT__lessKey_NamedKey_BEGIN = C.ImBitArray_Im @[typedef] pub struct C.ImBitArray_ImGuiKey_NamedKey_COUNT__lessImGuiKey_NamedKey_BEGIN { pub mut: - Data BindingFixedArray16 + Data BindingFixedArray17 } pub type ImBitArrayForNamedKeys = C.ImBitArray_ImGuiKey_NamedKey_COUNT__lessImGuiKey_NamedKey_BEGIN @@ -2809,7 +2843,7 @@ pub type KeyRoutingTable = C.ImGuiKeyRoutingTable @[typedef] pub struct C.ImGuiKeyRoutingTable { pub mut: - Index BindingFixedArray17 + Index BindingFixedArray18 Entries ImVector_KeyRoutingData EntriesNext ImVector_KeyRoutingData } @@ -2990,7 +3024,7 @@ pub type TypingSelectState = C.ImGuiTypingSelectState pub struct C.ImGuiTypingSelectState { pub mut: Request TypingSelectRequest - SearchBuffer BindingFixedArray18 + SearchBuffer BindingFixedArray19 FocusScope ID LastRequestFrame i32 LastRequestTime f32 @@ -3069,7 +3103,7 @@ pub mut: Window &Window UnclipMode bool UnclipRect ImRect_c - UnclipRects BindingFixedArray19 + UnclipRects BindingFixedArray20 BoxSelectRectPrev ImRect_c BoxSelectRectCurr ImRect_c } @@ -3117,15 +3151,16 @@ pub type ViewportP = C.ImGuiViewportP @[typedef] pub struct C.ImGuiViewportP { pub mut: - _ImGuiViewport Viewport - BgFgDrawListsLastTimeActive BindingFixedArray20 + _ImGuiViewport Viewport BgFgDrawLists[2]&ImDrawList - DrawDataP ImDrawData - DrawDataBuilder ImDrawDataBuilder - WorkInsetMin ImVec2_c - WorkInsetMax ImVec2_c - BuildWorkInsetMin ImVec2_c - BuildWorkInsetMax ImVec2_c + BgFgDrawListsLastFrameActive BindingFixedArray21 + BgFgDrawListsLastTimeActive BindingFixedArray22 + DrawDataP ImDrawData + DrawDataBuilder ImDrawDataBuilder + WorkInsetMin ImVec2_c + WorkInsetMax ImVec2_c + BuildWorkInsetMin ImVec2_c + BuildWorkInsetMax ImVec2_c } pub type WindowSettings = C.ImGuiWindowSettings @@ -3239,7 +3274,7 @@ pub mut: TotalAllocCount i32 TotalFreeCount i32 LastEntriesIdx ImS16 - LastEntriesBuf BindingFixedArray21 + LastEntriesBuf BindingFixedArray23 } pub type MetricsConfig = C.ImGuiMetricsConfig @@ -3651,7 +3686,7 @@ pub mut: FrameCountEnded i32 FrameCountRendered i32 Time f64 - ContextName BindingFixedArray22 + ContextName BindingFixedArray24 IO IO PlatformIO PlatformIO Style Style @@ -3661,7 +3696,7 @@ pub mut: FontSize f32 FontSizeBase f32 FontBakedScale f32 - FontRasterizerDensity f32 + CurrentPixelDensity f32 CurrentDpiScale f32 DrawListSharedData ImDrawListSharedData WithinEndChildID ID @@ -3691,6 +3726,7 @@ pub mut: WheelingWindowReleaseTimer f32 WheelingWindowWheelRemainder ImVec2_c WheelingAxisAvg ImVec2_c + MixedValueLabel &char DebugDrawIdConflictsId ID DebugHookIdInfoId ID HoveredId ID @@ -3730,7 +3766,7 @@ pub mut: LastKeyModsChangeFromNoneTime f64 LastKeyboardKeyPressTime f64 KeysMayBeCharInput ImBitArrayForNamedKeys - KeysOwnerData BindingFixedArray23 + KeysOwnerData BindingFixedArray25 KeysRoutingTable KeyRoutingTable ActiveIdUsingNavDirMask ImU32 ActiveIdUsingAllKeyboardKeys bool @@ -3804,6 +3840,7 @@ pub mut: NavJustMovedToFocusScopeId ID NavJustMovedToKeyMods KeyChord NavJustMovedToIsTabbing bool + NavJustMovedToIsInit bool NavJustMovedToHasSelectionData bool ConfigNavEnableTabbing bool ConfigNavWindowingWithGamepad bool @@ -3839,7 +3876,7 @@ pub mut: DragDropAcceptFrameCount i32 DragDropHoldJustPressedId ID DragDropPayloadBufHeap ImVector_unsigned_char - DragDropPayloadBufLocal BindingFixedArray24 + DragDropPayloadBufLocal BindingFixedArray26 ClipperTempDataStacked i32 ClipperTempData ImVector_ListClipperData CurrentTable &Table @@ -3954,7 +3991,7 @@ pub mut: DebugItemPathQuery DebugItemPathQuery DebugIDStackTool IDStackTool DebugAllocInfo DebugAllocInfo - FramerateSecPerFrame BindingFixedArray25 + FramerateSecPerFrame BindingFixedArray27 FramerateSecPerFrameIdx i32 FramerateSecPerFrameCount i32 FramerateSecPerFrameAccum f32 @@ -3962,7 +3999,7 @@ pub mut: WantCaptureKeyboardNextFrame i32 WantTextInputNextFrame i32 TempBuffer ImVector_char - TempKeychordName BindingFixedArray18 + TempKeychordName BindingFixedArray19 } pub type WindowTempData = C.ImGuiWindowTempData @@ -4127,9 +4164,9 @@ pub mut: RootWindowForNav &Window ParentWindowForFocusRoute &Window NavLastChildNavWindow &Window - NavLastIds BindingFixedArray26 - NavRectRel BindingFixedArray19 - NavPreferredScoringPosRel BindingFixedArray27 + NavLastIds BindingFixedArray28 + NavRectRel BindingFixedArray20 + NavPreferredScoringPosRel BindingFixedArray29 NavRootFocusScopeId ID MemoryDrawListIdxCapacity i32 MemoryDrawListVtxCapacity i32 @@ -4403,7 +4440,7 @@ pub mut: RowFlags TableRowFlags LastRowFlags TableRowFlags RowBgColorCounter i32 - RowBgColor BindingFixedArray28 + RowBgColor BindingFixedArray30 BorderColorStrong ImU32 BorderColorLight ImU32 BorderX1 f32 @@ -4438,9 +4475,9 @@ pub mut: DrawSplitter &ImDrawListSplitter InstanceDataFirst TableInstanceData InstanceDataExtra ImVector_TableInstanceData - SortSpecsSingle TableColumnSortSpecs - SortSpecsMulti ImVector_TableColumnSortSpecs SortSpecs TableSortSpecs + SortSpecsMulti ImVector_TableColumnSortSpecs + SortSpecsSingle TableColumnSortSpecs SortSpecsCount TableColumnIdx ColumnsEnabledCount TableColumnIdx ColumnsEnabledFixedCount TableColumnIdx @@ -4472,6 +4509,7 @@ pub mut: NavLayer ImS8 IsLayoutLocked bool IsInsideRow bool + IsNewTable bool IsInitializing bool IsReconcileMode bool IsSortSpecsDirty bool @@ -4575,16 +4613,17 @@ pub type ImFontLoader = C.ImFontLoader @[typedef] pub struct C.ImFontLoader { pub mut: - Name &char - LoaderInit fn (&ImFontAtlas) bool - LoaderShutdown fn (&ImFontAtlas) - FontSrcInit fn (&ImFontAtlas, &ImFontConfig) bool - FontSrcDestroy fn (&ImFontAtlas, &ImFontConfig) - FontSrcContainsGlyph fn (&ImFontAtlas, &ImFontConfig, ImWchar) bool - FontBakedInit fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr) bool - FontBakedDestroy fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr) - FontBakedLoadGlyph fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr, ImWchar, &ImFontGlyph, &f32) bool - FontBakedSrcLoaderDataSize usize + Name &char + LoaderInit fn (&ImFontAtlas) bool + LoaderShutdown fn (&ImFontAtlas) + FontSrcInit fn (&ImFontAtlas, &ImFontConfig) bool + FontSrcDestroy fn (&ImFontAtlas, &ImFontConfig) + FontSrcGetGlyphIndexFromCodepoint fn (&ImFontAtlas, &ImFontConfig, ImWchar) i32 + FontSrcContainsGlyph fn (&ImFontAtlas, &ImFontConfig, i32) bool + FontBakedInit fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr) bool + FontBakedDestroy fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr) + FontBakedLoadGlyph fn (&ImFontAtlas, &ImFontConfig, &ImFontBaked, voidptr, i32, &ImFontGlyph, &f32) bool + FontBakedSrcLoaderDataSize usize } pub type ImFontAtlasRectEntry = C.ImFontAtlasRectEntry @@ -4621,7 +4660,7 @@ pub type Stbrp_context_opaque = C.stbrp_context_opaque @[typedef] pub struct C.stbrp_context_opaque { pub mut: - Data BindingFixedArray29 + Data BindingFixedArray31 } pub type ImVector_stbrp_node_im = C.ImVector_stbrp_node_im @@ -4689,6 +4728,10 @@ pub mut: BakedDiscardedCount i32 PackIdMouseCursors ImFontAtlasRectId PackIdLinesTexData ImFontAtlasRectId + PackIdLineFractTexData ImFontAtlasRectId + PackIdCornersTexData ImFontAtlasRectId + TexUvLines BindingFixedArray32 + TexUvCorners BindingFixedArray33 } pub type StbUndoRecord = C.StbUndoRecord @@ -4707,8 +4750,8 @@ pub type StbUndoState = C.StbUndoState @[typedef] pub struct C.StbUndoState { pub mut: - Undo_rec BindingFixedArray30 - Undo_char BindingFixedArray31 + Undo_rec BindingFixedArray34 + Undo_char BindingFixedArray35 Undo_point i16 Redo_point i16 Undo_char_point i32 @@ -8368,14 +8411,6 @@ pub fn text_filter_destroy(self &TextFilter) { C.ImGuiTextFilter_destroy(self) } -@[keep_args_alive] -fn C.ImGuiTextFilter_Draw(self &TextFilter, const_label &char, width f32) bool - -@[inline] -pub fn text_filter_draw(self &TextFilter, const_label &char, width f32) bool { - return C.ImGuiTextFilter_Draw(self, const_label, width) -} - @[keep_args_alive] fn C.ImGuiTextFilter_PassFilter(self &TextFilter, const_text &char, const_text_end &char) bool @@ -8409,43 +8444,19 @@ pub fn text_filter_is_active(self &TextFilter) bool { } @[keep_args_alive] -fn C.ImGuiTextRange_ImGuiTextRange_Nil() &TextRange - -@[inline] -pub fn text_range_text_range_nil() &TextRange { - return C.ImGuiTextRange_ImGuiTextRange_Nil() -} - -@[keep_args_alive] -fn C.ImGuiTextRange_destroy(self &TextRange) - -@[inline] -pub fn text_range_destroy(self &TextRange) { - C.ImGuiTextRange_destroy(self) -} - -@[keep_args_alive] -fn C.ImGuiTextRange_ImGuiTextRange_Str(_b &char, _e &char) &TextRange - -@[inline] -pub fn text_range_text_range_str(_b &char, _e &char) &TextRange { - return C.ImGuiTextRange_ImGuiTextRange_Str(_b, _e) -} - -@[keep_args_alive] -fn C.ImGuiTextRange_empty(self &TextRange) bool +fn C.ImGuiTextFilter_Draw(self &TextFilter, const_label &char) bool @[inline] -pub fn text_range_empty(self &TextRange) bool { - return C.ImGuiTextRange_empty(self) +pub fn text_filter_draw(self &TextFilter, const_label &char) bool { + return C.ImGuiTextFilter_Draw(self, const_label) } @[keep_args_alive] -fn C.ImGuiTextRange_split(self &TextRange, separator i8, out &ImVector_TextRange) +fn C.ImGuiTextFilter_DrawWithHint(self &TextFilter, const_label &char, hint &char) bool @[inline] -pub fn text_range_split(self &TextRange, separator i8, out &ImVector_TextRange) { - C.ImGuiTextRange_split(self, separator, out) +pub fn text_filter_draw_with_hint(self &TextFilter, const_label &char, hint &char) bool { + return C.ImGuiTextFilter_DrawWithHint(self, const_label, hint) } @[keep_args_alive] @@ -9056,6 +9067,22 @@ pub fn im_draw_list_pop_texture(self &ImDrawList) { C.ImDrawList_PopTexture(self) } +@[keep_args_alive] +fn C.ImDrawList_PushDrawFlag(self &ImDrawList, flags ImDrawFlags, enabled bool) + +@[inline] +pub fn im_draw_list_push_draw_flag(self &ImDrawList, flags ImDrawFlags, enabled bool) { + C.ImDrawList_PushDrawFlag(self, flags, enabled) +} + +@[keep_args_alive] +fn C.ImDrawList_PopDrawFlag(self &ImDrawList) + +@[inline] +pub fn im_draw_list_pop_draw_flag(self &ImDrawList) { + C.ImDrawList_PopDrawFlag(self) +} + @[keep_args_alive] fn C.ImDrawList_GetClipRectMin(self &ImDrawList) ImVec2_c @@ -9073,27 +9100,27 @@ pub fn im_draw_list_get_clip_rect_max(self &ImDrawList) ImVec2_c { } @[keep_args_alive] -fn C.ImDrawList_AddLine(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32) +fn C.ImDrawList_AddLine(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_line(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32) { - C.ImDrawList_AddLine(self, p1, p2, col, thickness) +pub fn im_draw_list_add_line(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddLine(self, p1, p2, col, thickness, flags) } @[keep_args_alive] -fn C.ImDrawList_AddLineH(self &ImDrawList, min_x f32, max_x f32, y f32, col ImU32, thickness f32) +fn C.ImDrawList_AddLineH(self &ImDrawList, min_x f32, max_x f32, y f32, col ImU32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_line_h(self &ImDrawList, min_x f32, max_x f32, y f32, col ImU32, thickness f32) { - C.ImDrawList_AddLineH(self, min_x, max_x, y, col, thickness) +pub fn im_draw_list_add_line_h(self &ImDrawList, min_x f32, max_x f32, y f32, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddLineH(self, min_x, max_x, y, col, thickness, flags) } @[keep_args_alive] -fn C.ImDrawList_AddLineV(self &ImDrawList, x f32, min_y f32, max_y f32, col ImU32, thickness f32) +fn C.ImDrawList_AddLineV(self &ImDrawList, x f32, min_y f32, max_y f32, col ImU32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_line_v(self &ImDrawList, x f32, min_y f32, max_y f32, col ImU32, thickness f32) { - C.ImDrawList_AddLineV(self, x, min_y, max_y, col, thickness) +pub fn im_draw_list_add_line_v(self &ImDrawList, x f32, min_y f32, max_y f32, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddLineV(self, x, min_y, max_y, col, thickness, flags) } @[keep_args_alive] @@ -9121,11 +9148,11 @@ pub fn im_draw_list_add_rect_filled_multi_color(self &ImDrawList, p_min ImVec2_c } @[keep_args_alive] -fn C.ImDrawList_AddQuad(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32) +fn C.ImDrawList_AddQuad(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_quad(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32) { - C.ImDrawList_AddQuad(self, p1, p2, p3, p4, col, thickness) +pub fn im_draw_list_add_quad(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddQuad(self, p1, p2, p3, p4, col, thickness, flags) } @[keep_args_alive] @@ -9137,11 +9164,11 @@ pub fn im_draw_list_add_quad_filled(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, } @[keep_args_alive] -fn C.ImDrawList_AddTriangle(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32) +fn C.ImDrawList_AddTriangle(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_triangle(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32) { - C.ImDrawList_AddTriangle(self, p1, p2, p3, col, thickness) +pub fn im_draw_list_add_triangle(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddTriangle(self, p1, p2, p3, col, thickness, flags) } @[keep_args_alive] @@ -9153,11 +9180,11 @@ pub fn im_draw_list_add_triangle_filled(self &ImDrawList, p1 ImVec2_c, p2 ImVec2 } @[keep_args_alive] -fn C.ImDrawList_AddCircle(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32) +fn C.ImDrawList_AddCircle(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_circle(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32) { - C.ImDrawList_AddCircle(self, center, radius, col, num_segments, thickness) +pub fn im_draw_list_add_circle(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddCircle(self, center, radius, col, num_segments, thickness, flags) } @[keep_args_alive] @@ -9169,11 +9196,11 @@ pub fn im_draw_list_add_circle_filled(self &ImDrawList, center ImVec2_c, radius } @[keep_args_alive] -fn C.ImDrawList_AddNgon(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32) +fn C.ImDrawList_AddNgon(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_ngon(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32) { - C.ImDrawList_AddNgon(self, center, radius, col, num_segments, thickness) +pub fn im_draw_list_add_ngon(self &ImDrawList, center ImVec2_c, radius f32, col ImU32, num_segments i32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddNgon(self, center, radius, col, num_segments, thickness, flags) } @[keep_args_alive] @@ -9185,11 +9212,11 @@ pub fn im_draw_list_add_ngon_filled(self &ImDrawList, center ImVec2_c, radius f3 } @[keep_args_alive] -fn C.ImDrawList_AddEllipse(self &ImDrawList, center ImVec2_c, radius ImVec2_c, col ImU32, rot f32, num_segments i32, thickness f32) +fn C.ImDrawList_AddEllipse(self &ImDrawList, center ImVec2_c, radius ImVec2_c, col ImU32, rot f32, num_segments i32, thickness f32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_ellipse(self &ImDrawList, center ImVec2_c, radius ImVec2_c, col ImU32, rot f32, num_segments i32, thickness f32) { - C.ImDrawList_AddEllipse(self, center, radius, col, rot, num_segments, thickness) +pub fn im_draw_list_add_ellipse(self &ImDrawList, center ImVec2_c, radius ImVec2_c, col ImU32, rot f32, num_segments i32, thickness f32, flags ImDrawFlags) { + C.ImDrawList_AddEllipse(self, center, radius, col, rot, num_segments, thickness, flags) } @[keep_args_alive] @@ -9217,19 +9244,19 @@ pub fn im_draw_list_add_text_font_ptr(self &ImDrawList, font &ImFont, font_size } @[keep_args_alive] -fn C.ImDrawList_AddBezierCubic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, num_segments i32) +fn C.ImDrawList_AddBezierCubic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, num_segments i32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_bezier_cubic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, num_segments i32) { - C.ImDrawList_AddBezierCubic(self, p1, p2, p3, p4, col, thickness, num_segments) +pub fn im_draw_list_add_bezier_cubic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col ImU32, thickness f32, num_segments i32, flags ImDrawFlags) { + C.ImDrawList_AddBezierCubic(self, p1, p2, p3, p4, col, thickness, num_segments, flags) } @[keep_args_alive] -fn C.ImDrawList_AddBezierQuadratic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, num_segments i32) +fn C.ImDrawList_AddBezierQuadratic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, num_segments i32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_bezier_quadratic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, num_segments i32) { - C.ImDrawList_AddBezierQuadratic(self, p1, p2, p3, col, thickness, num_segments) +pub fn im_draw_list_add_bezier_quadratic(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col ImU32, thickness f32, num_segments i32, flags ImDrawFlags) { + C.ImDrawList_AddBezierQuadratic(self, p1, p2, p3, col, thickness, num_segments, flags) } @[keep_args_alive] @@ -9241,11 +9268,11 @@ pub fn im_draw_list_add_polyline(self &ImDrawList, points &ImVec2_c, num_points } @[keep_args_alive] -fn C.ImDrawList_AddConvexPolyFilled(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32) +fn C.ImDrawList_AddConvexPolyFilled(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_add_convex_poly_filled(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32) { - C.ImDrawList_AddConvexPolyFilled(self, points, num_points, col) +pub fn im_draw_list_add_convex_poly_filled(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32, flags ImDrawFlags) { + C.ImDrawList_AddConvexPolyFilled(self, points, num_points, col, flags) } @[keep_args_alive] @@ -9305,11 +9332,11 @@ pub fn im_draw_list_path_line_to_merge_duplicate(self &ImDrawList, pos ImVec2_c) } @[keep_args_alive] -fn C.ImDrawList_PathFillConvex(self &ImDrawList, col ImU32) +fn C.ImDrawList_PathFillConvex(self &ImDrawList, col ImU32, flags ImDrawFlags) @[inline] -pub fn im_draw_list_path_fill_convex(self &ImDrawList, col ImU32) { - C.ImDrawList_PathFillConvex(self, col) +pub fn im_draw_list_path_fill_convex(self &ImDrawList, col ImU32, flags ImDrawFlags) { + C.ImDrawList_PathFillConvex(self, col, flags) } @[keep_args_alive] @@ -9504,6 +9531,14 @@ pub fn im_draw_list__reset_for_new_frame(self &ImDrawList) { C.ImDrawList__ResetForNewFrame(self) } +@[keep_args_alive] +fn C.ImDrawList__SetPixelDensity(self &ImDrawList, pixel_density f32) + +@[inline] +pub fn im_draw_list__set_pixel_density(self &ImDrawList, pixel_density f32) { + C.ImDrawList__SetPixelDensity(self, pixel_density) +} + @[keep_args_alive] fn C.ImDrawList__ClearFreeMemory(self &ImDrawList) @@ -9584,6 +9619,62 @@ pub fn im_draw_list__path_arc_to_n(self &ImDrawList, center ImVec2_c, radius f32 C.ImDrawList__PathArcToN(self, center, radius, a_min, a_max, num_segments) } +@[keep_args_alive] +fn C.ImDrawList__AddRectFilledBaked(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, r f32, tex_uvs ImVec4_c, flags ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_filled_baked(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, r f32, tex_uvs ImVec4_c, flags ImDrawFlags) { + C.ImDrawList__AddRectFilledBaked(self, p_min, p_max, col, r, tex_uvs, flags) +} + +@[keep_args_alive] +fn C.ImDrawList__AddRectBaked(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, r f32, t f32, tex_uvs ImVec4_c, flags ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_baked(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, r f32, t f32, tex_uvs ImVec4_c, flags ImDrawFlags) { + C.ImDrawList__AddRectBaked(self, p_min, p_max, col, r, t, tex_uvs, flags) +} + +@[keep_args_alive] +fn C.ImDrawList__AddLine(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_line(self &ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col ImU32, thickness f32, flags ImDrawFlags) { + C.ImDrawList__AddLine(self, p1, p2, col, thickness, flags) +} + +@[keep_args_alive] +fn C.ImDrawList__AddRectTinyRounding(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, rounding f32, thickness f32, flags ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_tiny_rounding(self &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, rounding f32, thickness f32, flags ImDrawFlags) { + C.ImDrawList__AddRectTinyRounding(self, p_min, p_max, col, rounding, thickness, flags) +} + +@[keep_args_alive] +fn C.ImDrawList__SelectLineTexture(self &ImDrawList, screen_thickness f32, out_uv0 &ImVec2_c, out_uv1 &ImVec2_c, out_fringe &f32, flags ImDrawFlags) + +@[inline] +pub fn im_draw_list__select_line_texture(self &ImDrawList, screen_thickness f32, out_uv0 &ImVec2_c, out_uv1 &ImVec2_c, out_fringe &f32, flags ImDrawFlags) { + C.ImDrawList__SelectLineTexture(self, screen_thickness, out_uv0, out_uv1, out_fringe, flags) +} + +@[keep_args_alive] +fn C.ImDrawList__CalculateCenterBiasedOffset(self &ImDrawList, thickness f32) f32 + +@[inline] +pub fn im_draw_list__calculate_center_biased_offset(self &ImDrawList, thickness f32) f32 { + return C.ImDrawList__CalculateCenterBiasedOffset(self, thickness) +} + +@[keep_args_alive] +fn C.ImDrawList__AddPolyline(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32, thickness f32, flags ImDrawFlags, max_inner_offset f32) + +@[inline] +pub fn im_draw_list__add_polyline(self &ImDrawList, points &ImVec2_c, num_points i32, col ImU32, thickness f32, flags ImDrawFlags, max_inner_offset f32) { + C.ImDrawList__AddPolyline(self, points, num_points, col, thickness, flags, max_inner_offset) +} + @[keep_args_alive] fn C.ImDrawData_ImDrawData() &ImDrawData @@ -10161,11 +10252,19 @@ pub fn im_font_clear_output_data(self &ImFont) { } @[keep_args_alive] -fn C.ImFont_AddRemapChar(self &ImFont, from_codepoint ImWchar, to_codepoint ImWchar) +fn C.ImFont_AddRemapCodepoint(self &ImFont, from_codepoint ImWchar, to_codepoint ImWchar) + +@[inline] +pub fn im_font_add_remap_codepoint(self &ImFont, from_codepoint ImWchar, to_codepoint ImWchar) { + C.ImFont_AddRemapCodepoint(self, from_codepoint, to_codepoint) +} + +@[keep_args_alive] +fn C.ImFont_AddRemapCodepointToGlyphIndex(self &ImFont, from_codepoint ImWchar, font_src_idx i32, glyph_idx i32) @[inline] -pub fn im_font_add_remap_char(self &ImFont, from_codepoint ImWchar, to_codepoint ImWchar) { - C.ImFont_AddRemapChar(self, from_codepoint, to_codepoint) +pub fn im_font_add_remap_codepoint_to_glyph_index(self &ImFont, from_codepoint ImWchar, font_src_idx i32, glyph_idx i32) { + C.ImFont_AddRemapCodepointToGlyphIndex(self, from_codepoint, font_src_idx, glyph_idx) } @[keep_args_alive] @@ -10808,6 +10907,14 @@ pub fn im_rsqrt_float(x f32) f32 { return C.igImRsqrt_Float(x) } +@[keep_args_alive] +fn C.igImRsqrtPrecise(x f32) f32 + +@[inline] +pub fn im_rsqrt_precise(x f32) f32 { + return C.igImRsqrtPrecise(x) +} + @[keep_args_alive] fn C.igImRsqrt_double(x f64) f64 @@ -10817,27 +10924,75 @@ pub fn im_rsqrt_double(x f64) f64 { } @[keep_args_alive] -fn C.igImMin(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c +fn C.igImMin_Int(lhs i32, rhs i32) i32 + +@[inline] +pub fn im_min_int(lhs i32, rhs i32) i32 { + return C.igImMin_Int(lhs, rhs) +} + +@[keep_args_alive] +fn C.igImMax_Int(lhs i32, rhs i32) i32 + +@[inline] +pub fn im_max_int(lhs i32, rhs i32) i32 { + return C.igImMax_Int(lhs, rhs) +} + +@[keep_args_alive] +fn C.igImClamp_Int(v i32, mn i32, mx i32) i32 + +@[inline] +pub fn im_clamp_int(v i32, mn i32, mx i32) i32 { + return C.igImClamp_Int(v, mn, mx) +} + +@[keep_args_alive] +fn C.igImMin_Float(lhs f32, rhs f32) f32 + +@[inline] +pub fn im_min_float(lhs f32, rhs f32) f32 { + return C.igImMin_Float(lhs, rhs) +} + +@[keep_args_alive] +fn C.igImMax_Float(lhs f32, rhs f32) f32 + +@[inline] +pub fn im_max_float(lhs f32, rhs f32) f32 { + return C.igImMax_Float(lhs, rhs) +} + +@[keep_args_alive] +fn C.igImClamp_Float(v f32, mn f32, mx f32) f32 + +@[inline] +pub fn im_clamp_float(v f32, mn f32, mx f32) f32 { + return C.igImClamp_Float(v, mn, mx) +} + +@[keep_args_alive] +fn C.igImMin_Vec2(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c @[inline] -pub fn im_min(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c { - return C.igImMin(lhs, rhs) +pub fn im_min_vec2(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c { + return C.igImMin_Vec2(lhs, rhs) } @[keep_args_alive] -fn C.igImMax(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c +fn C.igImMax_Vec2(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c @[inline] -pub fn im_max(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c { - return C.igImMax(lhs, rhs) +pub fn im_max_vec2(lhs ImVec2_c, rhs ImVec2_c) ImVec2_c { + return C.igImMax_Vec2(lhs, rhs) } @[keep_args_alive] -fn C.igImClamp(v ImVec2_c, mn ImVec2_c, mx ImVec2_c) ImVec2_c +fn C.igImClamp_Vec2(v ImVec2_c, mn ImVec2_c, mx ImVec2_c) ImVec2_c @[inline] -pub fn im_clamp(v ImVec2_c, mn ImVec2_c, mx ImVec2_c) ImVec2_c { - return C.igImClamp(v, mn, mx) +pub fn im_clamp_vec2(v ImVec2_c, mn ImVec2_c, mx ImVec2_c) ImVec2_c { + return C.igImClamp_Vec2(v, mn, mx) } @[keep_args_alive] @@ -10937,11 +11092,19 @@ pub fn im_trunc64(f f32) f32 { } @[keep_args_alive] -fn C.igImRound64(f f32) f32 +fn C.igImRoundPositive64(f f32) f32 @[inline] -pub fn im_round64(f f32) f32 { - return C.igImRound64(f) +pub fn im_round_positive64(f f32) f32 { + return C.igImRoundPositive64(f) +} + +@[keep_args_alive] +fn C.igImRoundSigned64(f f32) f32 + +@[inline] +pub fn im_round_signed64(f f32) f32 { + return C.igImRoundSigned64(f) } @[keep_args_alive] @@ -11016,6 +11179,22 @@ pub fn im_exponential_moving_average(avg f32, sample f32, n i32) f32 { return C.igImExponentialMovingAverage(avg, sample, n) } +@[keep_args_alive] +fn C.igImIsTruncated(x f32) bool + +@[inline] +pub fn im_is_truncated(x f32) bool { + return C.igImIsTruncated(x) +} + +@[keep_args_alive] +fn C.igImIsTruncated4(x f32, y f32, z f32, w f32) bool + +@[inline] +pub fn im_is_truncated4(x f32, y f32, z f32, w f32) bool { + return C.igImIsTruncated4(x, y, z, w) +} + @[keep_args_alive] fn C.igImBezierCubicCalc(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, t f32) ImVec2_c @@ -11033,11 +11212,11 @@ pub fn im_bezier_cubic_closest_point(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 I } @[keep_args_alive] -fn C.igImBezierCubicClosestPointCasteljau(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, p ImVec2_c, tess_tol f32) ImVec2_c +fn C.igImBezierCubicClosestPointCasteljau(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, p ImVec2_c, max_error f32) ImVec2_c @[inline] -pub fn im_bezier_cubic_closest_point_casteljau(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, p ImVec2_c, tess_tol f32) ImVec2_c { - return C.igImBezierCubicClosestPointCasteljau(p1, p2, p3, p4, p, tess_tol) +pub fn im_bezier_cubic_closest_point_casteljau(p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, p ImVec2_c, max_error f32) ImVec2_c { + return C.igImBezierCubicClosestPointCasteljau(p1, p2, p3, p4, p, max_error) } @[keep_args_alive] @@ -11560,6 +11739,22 @@ pub fn text_index_append(self &TextIndex, base &char, old_size i32, new_size i32 C.ImGuiTextIndex_append(self, base, old_size, new_size) } +@[keep_args_alive] +fn C.ImGuiTextFilterItem_ImGuiTextFilterItem(b &char, e &char) &TextFilterItem + +@[inline] +pub fn text_filter_item_text_filter_item(b &char, e &char) &TextFilterItem { + return C.ImGuiTextFilterItem_ImGuiTextFilterItem(b, e) +} + +@[keep_args_alive] +fn C.ImGuiTextFilterItem_destroy(self &TextFilterItem) + +@[inline] +pub fn text_filter_item_destroy(self &TextFilterItem) { + C.ImGuiTextFilterItem_destroy(self) +} + @[keep_args_alive] fn C.ImGuiPackedDate_ImGuiPackedDate_Nil() &PackedDate @@ -13488,6 +13683,22 @@ pub fn window_pos_rel_to_abs(window &Window, p ImVec2_c) ImVec2_c { return C.igWindowPosRelToAbs(window, p) } +@[keep_args_alive] +fn C.igSetNextWindowFlags(flags WindowFlags, enabled bool) + +@[inline] +pub fn set_next_window_flags(flags WindowFlags, enabled bool) { + C.igSetNextWindowFlags(flags, enabled) +} + +@[keep_args_alive] +fn C.igSetNextWindowChildFlags(flags ChildFlags, enabled bool) + +@[inline] +pub fn set_next_window_child_flags(flags ChildFlags, enabled bool) { + C.igSetNextWindowChildFlags(flags, enabled) +} + @[keep_args_alive] fn C.igFocusWindow(window &Window, flags FocusRequestFlags) @@ -13609,19 +13820,19 @@ pub fn update_current_font_size(restore_font_size_after_scaling f32) { } @[keep_args_alive] -fn C.igSetFontRasterizerDensity(rasterizer_density f32) +fn C.igSetPixelDensity(pixel_density f32) @[inline] -pub fn set_font_rasterizer_density(rasterizer_density f32) { - C.igSetFontRasterizerDensity(rasterizer_density) +pub fn set_pixel_density(pixel_density f32) { + C.igSetPixelDensity(pixel_density) } @[keep_args_alive] -fn C.igGetFontRasterizerDensity() f32 +fn C.igGetPixelDensity() f32 @[inline] -pub fn get_font_rasterizer_density() f32 { - return C.igGetFontRasterizerDensity() +pub fn get_pixel_density() f32 { + return C.igGetPixelDensity() } @[keep_args_alive] @@ -15000,6 +15211,14 @@ pub fn render_drag_drop_target_rect_for_item(bb ImRect_c) { C.igRenderDragDropTargetRectForItem(bb) } +@[keep_args_alive] +fn C.igRenderDragDropTargetRectForViewport(viewport_id ID, bb ImRect_c) + +@[inline] +pub fn render_drag_drop_target_rect_for_viewport(viewport_id ID, bb ImRect_c) { + C.igRenderDragDropTargetRectForViewport(viewport_id, bb) +} + @[keep_args_alive] fn C.igRenderDragDropTargetRectEx(draw_list &ImDrawList, bb ImRect_c, rounding f32) @@ -15176,6 +15395,14 @@ pub fn tab_bar_get_tab_name(tab_bar &TabBar, tab &TabItem) &char { return C.igTabBarGetTabName(tab_bar, tab) } +@[keep_args_alive] +fn C.igTabBarGetTabPos(tab_bar &TabBar, tab &TabItem) ImVec2_c + +@[inline] +pub fn tab_bar_get_tab_pos(tab_bar &TabBar, tab &TabItem) ImVec2_c { + return C.igTabBarGetTabPos(tab_bar, tab) +} + @[keep_args_alive] fn C.igTabBarRemoveTab(tab_bar &TabBar, tab_id ID) @@ -15345,11 +15572,11 @@ pub fn render_color_component_marker(bb ImRect_c, col ImU32, rounding f32) { } @[keep_args_alive] -fn C.igRenderColorRectWithAlphaCheckerboard(draw_list &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, fill_col ImU32, grid_step f32, grid_off ImVec2_c, rounding f32, flags ImDrawFlags) +fn C.igRenderColorRectWithAlphaCheckerboard(draw_list &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, alpha f32, grid_step f32, grid_off ImVec2_c, rounding f32, flags ImDrawFlags) @[inline] -pub fn render_color_rect_with_alpha_checkerboard(draw_list &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, fill_col ImU32, grid_step f32, grid_off ImVec2_c, rounding f32, flags ImDrawFlags) { - C.igRenderColorRectWithAlphaCheckerboard(draw_list, p_min, p_max, fill_col, grid_step, grid_off, rounding, flags) +pub fn render_color_rect_with_alpha_checkerboard(draw_list &ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col ImU32, alpha f32, grid_step f32, grid_off ImVec2_c, rounding f32, flags ImDrawFlags) { + C.igRenderColorRectWithAlphaCheckerboard(draw_list, p_min, p_max, col, alpha, grid_step, grid_off, rounding, flags) } @[keep_args_alive] @@ -15441,19 +15668,19 @@ pub fn text_ex(const_text &char, const_text_end &char, flags TextFlags) { } @[keep_args_alive] -fn C.igTextAligned(align_x f32, size_x f32, const_fmt &char) +fn C.igTextAligned(align_x f32, width f32, const_fmt &char) @[inline] -pub fn text_aligned(align_x f32, size_x f32, const_fmt &char) { - C.igTextAligned(align_x, size_x, const_fmt) +pub fn text_aligned(align_x f32, width f32, const_fmt &char) { + C.igTextAligned(align_x, width, const_fmt) } @[keep_args_alive] -fn C.igTextAlignedV(align_x f32, size_x f32, const_fmt &char, args C.va_list) +fn C.igTextAlignedV(align_x f32, width f32, const_fmt &char, args C.va_list) @[inline] -pub fn text_aligned_v(align_x f32, size_x f32, const_fmt &char, args C.va_list) { - C.igTextAlignedV(align_x, size_x, const_fmt, args) +pub fn text_aligned_v(align_x f32, width f32, const_fmt &char, args C.va_list) { + C.igTextAlignedV(align_x, width, const_fmt, args) } @[keep_args_alive] diff --git a/impl_vulkan/imgui_impl_vulkan.c.v b/impl_vulkan/imgui_impl_vulkan.c.v index bba0e83..374a74f 100644 --- a/impl_vulkan/imgui_impl_vulkan.c.v +++ b/impl_vulkan/imgui_impl_vulkan.c.v @@ -62,7 +62,7 @@ pub mut: pipeline_info_main PipelineInfo use_dynamic_rendering bool allocator &vk.AllocationCallbacks = unsafe { nil } - check_vk_result_fn PFN_CheckVkResult = unsafe { nil } + check_vk_result_fn PFN_CheckVkResult = unsafe { nil } min_allocation_size vk.DeviceSize custom_shader_vert_create_info vk.ShaderModuleCreateInfo custom_shader_frag_create_info vk.ShaderModuleCreateInfo @@ -434,11 +434,11 @@ pub fn create_window_swap_chain(physical_device vk.PhysicalDevice, device vk.Dev image_view_ci.components.b = vk.ComponentSwizzle.b image_view_ci.components.a = vk.ComponentSwizzle.a image_range := vk.ImageSubresourceRange{ - aspectMask: vk.ImageAspectFlags(vk.ImageAspectFlagBits.color) - baseMipLevel: 0 - levelCount: 1 + aspectMask: vk.ImageAspectFlags(vk.ImageAspectFlagBits.color) + baseMipLevel: 0 + levelCount: 1 baseArrayLayer: 0 - layerCount: 1 + layerCount: 1 } image_view_ci.subresourceRange = image_range for i in 0 .. wd.image_count { diff --git a/implot/implot.v b/implot/implot.v index 24eb0ed..986b0de 100644 --- a/implot/implot.v +++ b/implot/implot.v @@ -71,8 +71,8 @@ SOFTWARE. */ -pub const version = '1.1 WIP' -pub const version_num = 10100 +pub const version = '1.2 WIP' +pub const version_num = 10200 pub type BindingFixedArray1 = [16]ImVec4_c pub type BindingFixedArray2 = [16]i8 @@ -150,7 +150,6 @@ pub type ImGuiMouseCursor = i32 pub type ImGuiStyleVar = i32 pub type ImGuiTableBgTarget = i32 pub type ImDrawFlags = i32 -pub type ImDrawListFlags = i32 pub type ImDrawTextFlags = i32 pub type ImFontFlags = i32 pub type ImFontAtlasFlags = i32 @@ -251,6 +250,7 @@ pub enum ImGuiItemFlags_ { live_edit_on_input_text = 1 << 7 live_edit_on_input_scalar = 1 << 8 live_edit_on_input = 1 << 7 | 1 << 8 + mixed_value = 1 << 9 } @@ -980,7 +980,7 @@ pub enum ImGuiTableBgTarget_ { pub type ImVector_ImWchar = imgui.ImVector_ImWchar -pub type ImVector_ImGuiTextRange = imgui.ImVector_TextRange +pub type ImVector_ImGuiTextFilterItem = imgui.ImVector_TextFilterItem pub type ImVector_char = imgui.ImVector_char @@ -1050,31 +1050,37 @@ pub type ImDrawListSplitter = imgui.ImDrawListSplitter pub enum ImDrawFlags_ { none = 0 - round_corners_top_left = 1 << 4 - round_corners_top_right = 1 << 5 - round_corners_bottom_left = 1 << 6 - round_corners_bottom_right = 1 << 7 - round_corners_none = 1 << 8 - round_corners_all = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 - round_corners_top = 1 << 4 | 1 << 5 - round_corners_bottom = 1 << 6 | 1 << 7 - round_corners_left = 1 << 4 | 1 << 6 - round_corners_right = 1 << 5 | 1 << 7 - round_corners_mask_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 + round_top_left = 1 << 4 + round_top_right = 1 << 5 + round_bottom_left = 1 << 6 + round_bottom_right = 1 << 7 + round_none = 1 << 8 + round_all = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 + round_top = 1 << 4 | 1 << 5 + round_bottom = 1 << 6 | 1 << 7 + round_left = 1 << 4 | 1 << 6 + round_right = 1 << 5 | 1 << 7 closed = 1 << 9 + join_miter = 1 << 10 + cap_square = 1 << 11 + aa_fill = 1 << 12 + aa_lines = 1 << 13 + aa_line_ends = 1 << 14 + stroke_inside = 1 << 17 + stroke_center = 1 << 18 + stroke_center_biased = 1 << 17 | 1 << 18 + stroke_outside = 1 << 19 + stroke_legacy = 1 << 17 | 1 << 18 | 1 << 19 + text_no_pixel_snap = 1 << 20 + use_tex_for_round_corners = 1 << 21 + use_vtx_offset = 1 << 22 + allow_tex_for_round_corners_ = 1 << 23 + round_mask_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 + allow_in_push_scope_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 20 | 1 << 21 | 1 << 22 + allow_in_frame_scope_ = 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 12 | 1 << 13 | 1 << 14 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 invalid_mask_ = -2147483633 } - -pub enum ImDrawListFlags_ { - none = 0 - anti_aliased_lines = 1 << 0 - anti_aliased_lines_use_tex = 1 << 1 - anti_aliased_fill = 1 << 2 - allow_vtx_offset = 1 << 3 - text_no_pixel_snap = 1 << 4 -} - pub type ImVector_ImDrawVert = imgui.ImVector_ImDrawVert pub type ImVector_ImVec2 = imgui.ImVector_ImVec2 @@ -1085,6 +1091,8 @@ pub type ImVector_ImTextureRef = imgui.ImVector_ImTextureRef pub type ImVector_ImU8 = imgui.ImVector_ImU8 +pub type ImSmallStack__ImDrawFlags__3 = imgui.ImSmallStack__ImDrawFlags__3 + pub type ImDrawList = imgui.ImDrawList pub type ImVector_ImDrawListPtr = imgui.ImVector_ImDrawListPtr @@ -1132,6 +1140,7 @@ pub enum ImFontAtlasFlags_ { no_power_of_two_height = 1 << 0 no_mouse_cursors = 1 << 1 no_baked_lines = 1 << 2 + no_baked_round_corners = 1 << 3 } pub type ImVector_ImFontPtr = imgui.ImVector_ImFontPtr @@ -1240,7 +1249,6 @@ pub enum ImGuiDataTypePrivate_ { pub enum ImGuiItemFlagsPrivate_ { read_only = 1 << 11 - mixed_value = 1 << 12 no_window_hoverable_check = 1 << 13 allow_overlap = 1 << 14 no_nav_disable_mouse_hover = 1 << 15 @@ -1304,11 +1312,6 @@ pub enum ImGuiButtonFlagsPrivate_ { } -pub enum ImGuiComboFlagsPrivate_ { - custom_preview = 1 << 20 -} - - pub enum ImGuiSliderFlagsPrivate_ { vertical = 1 << 20 read_only = 1 << 21 @@ -2073,6 +2076,24 @@ pub fn im_draw_list_pop_texture(self &imgui.ImDrawList) { } +@[keep_args_alive] +fn C.ImDrawList_PushDrawFlag(self &imgui.ImDrawList, flags imgui.ImDrawFlags, enabled bool) + +@[inline] +pub fn im_draw_list_push_draw_flag(self &imgui.ImDrawList, flags imgui.ImDrawFlags, enabled bool) { + C.ImDrawList_PushDrawFlag(self, flags, enabled) +} + + +@[keep_args_alive] +fn C.ImDrawList_PopDrawFlag(self &imgui.ImDrawList) + +@[inline] +pub fn im_draw_list_pop_draw_flag(self &imgui.ImDrawList) { + C.ImDrawList_PopDrawFlag(self) +} + + @[keep_args_alive] fn C.ImDrawList_GetClipRectMin(self &imgui.ImDrawList) ImVec2_c @@ -2092,29 +2113,29 @@ pub fn im_draw_list_get_clip_rect_max(self &imgui.ImDrawList) ImVec2_c { @[keep_args_alive] -fn C.ImDrawList_AddLine(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32) +fn C.ImDrawList_AddLine(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_line(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32) { - C.ImDrawList_AddLine(self, p1, p2, col, thickness) +pub fn im_draw_list_add_line(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddLine(self, p1, p2, col, thickness, flags) } @[keep_args_alive] -fn C.ImDrawList_AddLineH(self &imgui.ImDrawList, min_x f32, max_x f32, y f32, col u32, thickness f32) +fn C.ImDrawList_AddLineH(self &imgui.ImDrawList, min_x f32, max_x f32, y f32, col u32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_line_h(self &imgui.ImDrawList, min_x f32, max_x f32, y f32, col u32, thickness f32) { - C.ImDrawList_AddLineH(self, min_x, max_x, y, col, thickness) +pub fn im_draw_list_add_line_h(self &imgui.ImDrawList, min_x f32, max_x f32, y f32, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddLineH(self, min_x, max_x, y, col, thickness, flags) } @[keep_args_alive] -fn C.ImDrawList_AddLineV(self &imgui.ImDrawList, x f32, min_y f32, max_y f32, col u32, thickness f32) +fn C.ImDrawList_AddLineV(self &imgui.ImDrawList, x f32, min_y f32, max_y f32, col u32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_line_v(self &imgui.ImDrawList, x f32, min_y f32, max_y f32, col u32, thickness f32) { - C.ImDrawList_AddLineV(self, x, min_y, max_y, col, thickness) +pub fn im_draw_list_add_line_v(self &imgui.ImDrawList, x f32, min_y f32, max_y f32, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddLineV(self, x, min_y, max_y, col, thickness, flags) } @@ -2146,11 +2167,11 @@ pub fn im_draw_list_add_rect_filled_multi_color(self &imgui.ImDrawList, p_min Im @[keep_args_alive] -fn C.ImDrawList_AddQuad(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32) +fn C.ImDrawList_AddQuad(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_quad(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32) { - C.ImDrawList_AddQuad(self, p1, p2, p3, p4, col, thickness) +pub fn im_draw_list_add_quad(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddQuad(self, p1, p2, p3, p4, col, thickness, flags) } @@ -2164,11 +2185,11 @@ pub fn im_draw_list_add_quad_filled(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVe @[keep_args_alive] -fn C.ImDrawList_AddTriangle(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32) +fn C.ImDrawList_AddTriangle(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_triangle(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32) { - C.ImDrawList_AddTriangle(self, p1, p2, p3, col, thickness) +pub fn im_draw_list_add_triangle(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddTriangle(self, p1, p2, p3, col, thickness, flags) } @@ -2182,11 +2203,11 @@ pub fn im_draw_list_add_triangle_filled(self &imgui.ImDrawList, p1 ImVec2_c, p2 @[keep_args_alive] -fn C.ImDrawList_AddCircle(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32) +fn C.ImDrawList_AddCircle(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_circle(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32) { - C.ImDrawList_AddCircle(self, center, radius, col, num_segments, thickness) +pub fn im_draw_list_add_circle(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddCircle(self, center, radius, col, num_segments, thickness, flags) } @@ -2200,11 +2221,11 @@ pub fn im_draw_list_add_circle_filled(self &imgui.ImDrawList, center ImVec2_c, r @[keep_args_alive] -fn C.ImDrawList_AddNgon(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32) +fn C.ImDrawList_AddNgon(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_ngon(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32) { - C.ImDrawList_AddNgon(self, center, radius, col, num_segments, thickness) +pub fn im_draw_list_add_ngon(self &imgui.ImDrawList, center ImVec2_c, radius f32, col u32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddNgon(self, center, radius, col, num_segments, thickness, flags) } @@ -2218,11 +2239,11 @@ pub fn im_draw_list_add_ngon_filled(self &imgui.ImDrawList, center ImVec2_c, rad @[keep_args_alive] -fn C.ImDrawList_AddEllipse(self &imgui.ImDrawList, center ImVec2_c, radius ImVec2_c, col u32, rot f32, num_segments i32, thickness f32) +fn C.ImDrawList_AddEllipse(self &imgui.ImDrawList, center ImVec2_c, radius ImVec2_c, col u32, rot f32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_ellipse(self &imgui.ImDrawList, center ImVec2_c, radius ImVec2_c, col u32, rot f32, num_segments i32, thickness f32) { - C.ImDrawList_AddEllipse(self, center, radius, col, rot, num_segments, thickness) +pub fn im_draw_list_add_ellipse(self &imgui.ImDrawList, center ImVec2_c, radius ImVec2_c, col u32, rot f32, num_segments i32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddEllipse(self, center, radius, col, rot, num_segments, thickness, flags) } @@ -2254,20 +2275,20 @@ pub fn im_draw_list_add_text_font_ptr(self &imgui.ImDrawList, font &imgui.ImFont @[keep_args_alive] -fn C.ImDrawList_AddBezierCubic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, num_segments i32) +fn C.ImDrawList_AddBezierCubic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, num_segments i32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_bezier_cubic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, num_segments i32) { - C.ImDrawList_AddBezierCubic(self, p1, p2, p3, p4, col, thickness, num_segments) +pub fn im_draw_list_add_bezier_cubic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, p4 ImVec2_c, col u32, thickness f32, num_segments i32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddBezierCubic(self, p1, p2, p3, p4, col, thickness, num_segments, flags) } @[keep_args_alive] -fn C.ImDrawList_AddBezierQuadratic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, num_segments i32) +fn C.ImDrawList_AddBezierQuadratic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, num_segments i32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_bezier_quadratic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, num_segments i32) { - C.ImDrawList_AddBezierQuadratic(self, p1, p2, p3, col, thickness, num_segments) +pub fn im_draw_list_add_bezier_quadratic(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, p3 ImVec2_c, col u32, thickness f32, num_segments i32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddBezierQuadratic(self, p1, p2, p3, col, thickness, num_segments, flags) } @@ -2281,11 +2302,11 @@ pub fn im_draw_list_add_polyline(self &imgui.ImDrawList, points &ImVec2_c, num_p @[keep_args_alive] -fn C.ImDrawList_AddConvexPolyFilled(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32) +fn C.ImDrawList_AddConvexPolyFilled(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_add_convex_poly_filled(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32) { - C.ImDrawList_AddConvexPolyFilled(self, points, num_points, col) +pub fn im_draw_list_add_convex_poly_filled(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32, flags imgui.ImDrawFlags) { + C.ImDrawList_AddConvexPolyFilled(self, points, num_points, col, flags) } @@ -2353,11 +2374,11 @@ pub fn im_draw_list_path_line_to_merge_duplicate(self &imgui.ImDrawList, pos ImV @[keep_args_alive] -fn C.ImDrawList_PathFillConvex(self &imgui.ImDrawList, col u32) +fn C.ImDrawList_PathFillConvex(self &imgui.ImDrawList, col u32, flags imgui.ImDrawFlags) @[inline] -pub fn im_draw_list_path_fill_convex(self &imgui.ImDrawList, col u32) { - C.ImDrawList_PathFillConvex(self, col) +pub fn im_draw_list_path_fill_convex(self &imgui.ImDrawList, col u32, flags imgui.ImDrawFlags) { + C.ImDrawList_PathFillConvex(self, col, flags) } @@ -2577,6 +2598,15 @@ pub fn im_draw_list__reset_for_new_frame(self &imgui.ImDrawList) { } +@[keep_args_alive] +fn C.ImDrawList__SetPixelDensity(self &imgui.ImDrawList, pixel_density f32) + +@[inline] +pub fn im_draw_list__set_pixel_density(self &imgui.ImDrawList, pixel_density f32) { + C.ImDrawList__SetPixelDensity(self, pixel_density) +} + + @[keep_args_alive] fn C.ImDrawList__ClearFreeMemory(self &imgui.ImDrawList) @@ -2667,6 +2697,69 @@ pub fn im_draw_list__path_arc_to_n(self &imgui.ImDrawList, center ImVec2_c, radi } +@[keep_args_alive] +fn C.ImDrawList__AddRectFilledBaked(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, r f32, tex_uvs ImVec4_c, flags imgui.ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_filled_baked(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, r f32, tex_uvs ImVec4_c, flags imgui.ImDrawFlags) { + C.ImDrawList__AddRectFilledBaked(self, p_min, p_max, col, r, tex_uvs, flags) +} + + +@[keep_args_alive] +fn C.ImDrawList__AddRectBaked(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, r f32, t f32, tex_uvs ImVec4_c, flags imgui.ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_baked(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, r f32, t f32, tex_uvs ImVec4_c, flags imgui.ImDrawFlags) { + C.ImDrawList__AddRectBaked(self, p_min, p_max, col, r, t, tex_uvs, flags) +} + + +@[keep_args_alive] +fn C.ImDrawList__AddLine(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_line(self &imgui.ImDrawList, p1 ImVec2_c, p2 ImVec2_c, col u32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList__AddLine(self, p1, p2, col, thickness, flags) +} + + +@[keep_args_alive] +fn C.ImDrawList__AddRectTinyRounding(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, rounding f32, thickness f32, flags imgui.ImDrawFlags) + +@[inline] +pub fn im_draw_list__add_rect_tiny_rounding(self &imgui.ImDrawList, p_min ImVec2_c, p_max ImVec2_c, col u32, rounding f32, thickness f32, flags imgui.ImDrawFlags) { + C.ImDrawList__AddRectTinyRounding(self, p_min, p_max, col, rounding, thickness, flags) +} + + +@[keep_args_alive] +fn C.ImDrawList__SelectLineTexture(self &imgui.ImDrawList, screen_thickness f32, out_uv0 &ImVec2_c, out_uv1 &ImVec2_c, out_fringe &f32, flags imgui.ImDrawFlags) + +@[inline] +pub fn im_draw_list__select_line_texture(self &imgui.ImDrawList, screen_thickness f32, out_uv0 &ImVec2_c, out_uv1 &ImVec2_c, out_fringe &f32, flags imgui.ImDrawFlags) { + C.ImDrawList__SelectLineTexture(self, screen_thickness, out_uv0, out_uv1, out_fringe, flags) +} + + +@[keep_args_alive] +fn C.ImDrawList__CalculateCenterBiasedOffset(self &imgui.ImDrawList, thickness f32) f32 + +@[inline] +pub fn im_draw_list__calculate_center_biased_offset(self &imgui.ImDrawList, thickness f32) f32 { + return C.ImDrawList__CalculateCenterBiasedOffset(self, thickness) +} + + +@[keep_args_alive] +fn C.ImDrawList__AddPolyline(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32, thickness f32, flags imgui.ImDrawFlags, max_inner_offset f32) + +@[inline] +pub fn im_draw_list__add_polyline(self &imgui.ImDrawList, points &ImVec2_c, num_points i32, col u32, thickness f32, flags imgui.ImDrawFlags, max_inner_offset f32) { + C.ImDrawList__AddPolyline(self, points, num_points, col, thickness, flags, max_inner_offset) +} + + @[keep_args_alive] fn C.ImDrawData_ImDrawData() &imgui.ImDrawData @@ -3316,11 +3409,20 @@ pub fn im_font_clear_output_data(self &imgui.ImFont) { @[keep_args_alive] -fn C.ImFont_AddRemapChar(self &imgui.ImFont, from_codepoint u32, to_codepoint u32) +fn C.ImFont_AddRemapCodepoint(self &imgui.ImFont, from_codepoint u32, to_codepoint u32) + +@[inline] +pub fn im_font_add_remap_codepoint(self &imgui.ImFont, from_codepoint u32, to_codepoint u32) { + C.ImFont_AddRemapCodepoint(self, from_codepoint, to_codepoint) +} + + +@[keep_args_alive] +fn C.ImFont_AddRemapCodepointToGlyphIndex(self &imgui.ImFont, from_codepoint u32, font_src_idx i32, glyph_idx i32) @[inline] -pub fn im_font_add_remap_char(self &imgui.ImFont, from_codepoint u32, to_codepoint u32) { - C.ImFont_AddRemapChar(self, from_codepoint, to_codepoint) +pub fn im_font_add_remap_codepoint_to_glyph_index(self &imgui.ImFont, from_codepoint u32, font_src_idx i32, glyph_idx i32) { + C.ImFont_AddRemapCodepointToGlyphIndex(self, from_codepoint, font_src_idx, glyph_idx) } @@ -4055,6 +4157,7 @@ pub enum AxisFlags_ { pan_stretch = 1 << 13 lock_min = 1 << 14 lock_max = 1 << 15 + tick_labels_inside = 1 << 16 lock = 1 << 14 | 1 << 15 no_decorations = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 aux_default = 1 << 1 | 1 << 8 @@ -4104,6 +4207,8 @@ pub enum DragToolFlags_ { no_fit = 1 << 1 no_inputs = 1 << 2 delayed = 1 << 3 + no_move = 1 << 4 + no_resize = 1 << 5 } @@ -4312,6 +4417,8 @@ pub enum Marker_ { cross plus asterisk + vertical + horizontal count } @@ -4950,6 +5057,16 @@ pub mut: } +pub type ImVector_ImRect = C.ImVector_ImRect +@[typedef] +pub struct C.ImVector_ImRect { +pub mut: + Size i32 + Capacity i32 + Data &ImRect_c +} + + pub type ImPool_AlignmentData = C.ImPool_ImPlotAlignmentData @[typedef] pub struct C.ImPool_ImPlotAlignmentData { @@ -4984,6 +5101,7 @@ pub mut: TempDouble1 ImVector_double TempDouble2 ImVector_double TempInt1 ImVector_int + TempRect1 ImVector_ImRect DigitalPlotItemCnt i32 DigitalPlotOffset i32 NextPlotData NextPlotData @@ -8388,6 +8506,15 @@ pub fn hide_next_item(hidden bool, cond Cond) { } +@[keep_args_alive] +fn C.ImPlot_IsItemHidden(label_id &char) bool + +@[inline] +pub fn is_item_hidden(label_id &char) bool { + return C.ImPlot_IsItemHidden(label_id) +} + + @[keep_args_alive] fn C.ImPlot_BeginAlignedPlots(group_id &char, vertical bool) bool @@ -8622,6 +8749,15 @@ pub fn get_last_item_color() ImVec4_c { } +@[keep_args_alive] +fn C.ImPlot_IsLastItemHidden() bool + +@[inline] +pub fn is_last_item_hidden() bool { + return C.ImPlot_IsLastItemHidden() +} + + @[keep_args_alive] fn C.ImPlot_GetStyleColorName(idx Col) &char @@ -9180,6 +9316,15 @@ pub fn im_pos_mod(l i32, r i32) i32 { } +@[keep_args_alive] +fn C.ImPlot_ImDoubleBits(val f64) u64 + +@[inline] +pub fn im_double_bits(val f64) u64 { + return C.ImPlot_ImDoubleBits(val) +} + + @[keep_args_alive] fn C.ImPlot_ImNan(val f64) bool @@ -10593,6 +10738,15 @@ pub fn axis_has_tick_labels(self &Axis) bool { } +@[keep_args_alive] +fn C.ImPlotAxis_HasTickLabelsInside(self &Axis) bool + +@[inline] +pub fn axis_has_tick_labels_inside(self &Axis) bool { + return C.ImPlotAxis_HasTickLabelsInside(self) +} + + @[keep_args_alive] fn C.ImPlotAxis_HasTickMarks(self &Axis) bool @@ -11637,6 +11791,24 @@ pub fn render_color_bar(colors &u32, size i32, draw_list &imgui.ImDrawList, boun } +@[keep_args_alive] +fn C.ImPlot_AddLineH(draw_list &imgui.ImDrawList, x1 f32, x2 f32, y f32, col u32, thickness f32) + +@[inline] +pub fn add_line_h(draw_list &imgui.ImDrawList, x1 f32, x2 f32, y f32, col u32, thickness f32) { + C.ImPlot_AddLineH(draw_list, x1, x2, y, col, thickness) +} + + +@[keep_args_alive] +fn C.ImPlot_AddLineV(draw_list &imgui.ImDrawList, x f32, y1 f32, y2 f32, col u32, thickness f32) + +@[inline] +pub fn add_line_v(draw_list &imgui.ImDrawList, x f32, y1 f32, y2 f32, col u32, thickness f32) { + C.ImPlot_AddLineV(draw_list, x, y1, y2, col, thickness) +} + + @[keep_args_alive] fn C.ImPlot_NiceNum(x f64, round bool) f64 diff --git a/include/cimgui.cpp b/include/cimgui.cpp index bf9e1ff..815f544 100644 --- a/include/cimgui.cpp +++ b/include/cimgui.cpp @@ -1,5 +1,5 @@ //This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui -//based on imgui.h file version "1.92.9b" 19291 from Dear ImGui https://github.com/ocornut/imgui +//based on imgui.h file version "1.93.0" 19300 from Dear ImGui https://github.com/ocornut/imgui //with imgui_internal.h api //with imgui_freetype.h api @@ -2038,10 +2038,6 @@ CIMGUI_API void ImGuiTextFilter_destroy(ImGuiTextFilter* self) { IM_DELETE(self); } -CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label,float width) -{ - return self->Draw(label,width); -} CIMGUI_API bool ImGuiTextFilter_PassFilter(ImGuiTextFilter* self,const char* text,const char* text_end) { return self->PassFilter(text,text_end); @@ -2058,25 +2054,13 @@ CIMGUI_API bool ImGuiTextFilter_IsActive(ImGuiTextFilter* self) { return self->IsActive(); } -CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Nil(void) +CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label) { - return IM_NEW(ImGuiTextRange)(); -} -CIMGUI_API void ImGuiTextRange_destroy(ImGuiTextRange* self) -{ - IM_DELETE(self); + return self->Draw(label); } -CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Str(const char* _b,const char* _e) +CIMGUI_API bool ImGuiTextFilter_DrawWithHint(ImGuiTextFilter* self,const char* label,const char* hint) { - return IM_NEW(ImGuiTextRange)(_b,_e); -} -CIMGUI_API bool ImGuiTextRange_empty(ImGuiTextRange* self) -{ - return self->empty(); -} -CIMGUI_API void ImGuiTextRange_split(ImGuiTextRange* self,char separator,ImVector_ImGuiTextRange* out) -{ - return self->split(separator,out); + return self->DrawWithHint(label,hint); } CIMGUI_API ImGuiTextBuffer* ImGuiTextBuffer_ImGuiTextBuffer(void) { @@ -2382,6 +2366,14 @@ CIMGUI_API void ImDrawList_PopTexture(ImDrawList* self) { return self->PopTexture(); } +CIMGUI_API void ImDrawList_PushDrawFlag(ImDrawList* self,ImDrawFlags flags,bool enabled) +{ + return self->PushDrawFlag(flags,enabled); +} +CIMGUI_API void ImDrawList_PopDrawFlag(ImDrawList* self) +{ + return self->PopDrawFlag(); +} CIMGUI_API ImVec2_c ImDrawList_GetClipRectMin(ImDrawList* self) { return ConvertFromCPP_ImVec2(self->GetClipRectMin()); @@ -2390,17 +2382,17 @@ CIMGUI_API ImVec2_c ImDrawList_GetClipRectMax(ImDrawList* self) { return ConvertFromCPP_ImVec2(self->GetClipRectMax()); } -CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness) +CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness,ImDrawFlags flags) { - return self->AddLine(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),col,thickness); + return self->AddLine(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),col,thickness,flags); } -CIMGUI_API void ImDrawList_AddLineH(ImDrawList* self,float min_x,float max_x,float y,ImU32 col,float thickness) +CIMGUI_API void ImDrawList_AddLineH(ImDrawList* self,float min_x,float max_x,float y,ImU32 col,float thickness,ImDrawFlags flags) { - return self->AddLineH(min_x,max_x,y,col,thickness); + return self->AddLineH(min_x,max_x,y,col,thickness,flags); } -CIMGUI_API void ImDrawList_AddLineV(ImDrawList* self,float x,float min_y,float max_y,ImU32 col,float thickness) +CIMGUI_API void ImDrawList_AddLineV(ImDrawList* self,float x,float min_y,float max_y,ImU32 col,float thickness,ImDrawFlags flags) { - return self->AddLineV(x,min_y,max_y,col,thickness); + return self->AddLineV(x,min_y,max_y,col,thickness,flags); } CIMGUI_API void ImDrawList_AddRect(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float rounding,float thickness,ImDrawFlags flags) { @@ -2414,41 +2406,41 @@ CIMGUI_API void ImDrawList_AddRectFilledMultiColor(ImDrawList* self,const ImVec2 { return self->AddRectFilledMultiColor(ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),col_upr_left,col_upr_right,col_bot_right,col_bot_left); } -CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness) +CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,ImDrawFlags flags) { - return self->AddQuad(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),col,thickness); + return self->AddQuad(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),col,thickness,flags); } CIMGUI_API void ImDrawList_AddQuadFilled(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col) { return self->AddQuadFilled(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),col); } -CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness) +CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,ImDrawFlags flags) { - return self->AddTriangle(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),col,thickness); + return self->AddTriangle(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),col,thickness,flags); } CIMGUI_API void ImDrawList_AddTriangleFilled(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col) { return self->AddTriangleFilled(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),col); } -CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness) +CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness,ImDrawFlags flags) { - return self->AddCircle(ConvertToCPP_ImVec2(center),radius,col,num_segments,thickness); + return self->AddCircle(ConvertToCPP_ImVec2(center),radius,col,num_segments,thickness,flags); } CIMGUI_API void ImDrawList_AddCircleFilled(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments) { return self->AddCircleFilled(ConvertToCPP_ImVec2(center),radius,col,num_segments); } -CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness) +CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness,ImDrawFlags flags) { - return self->AddNgon(ConvertToCPP_ImVec2(center),radius,col,num_segments,thickness); + return self->AddNgon(ConvertToCPP_ImVec2(center),radius,col,num_segments,thickness,flags); } CIMGUI_API void ImDrawList_AddNgonFilled(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments) { return self->AddNgonFilled(ConvertToCPP_ImVec2(center),radius,col,num_segments); } -CIMGUI_API void ImDrawList_AddEllipse(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments,float thickness) +CIMGUI_API void ImDrawList_AddEllipse(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments,float thickness,ImDrawFlags flags) { - return self->AddEllipse(ConvertToCPP_ImVec2(center),ConvertToCPP_ImVec2(radius),col,rot,num_segments,thickness); + return self->AddEllipse(ConvertToCPP_ImVec2(center),ConvertToCPP_ImVec2(radius),col,rot,num_segments,thickness,flags); } CIMGUI_API void ImDrawList_AddEllipseFilled(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments) { @@ -2462,21 +2454,21 @@ CIMGUI_API void ImDrawList_AddText_FontPtr(ImDrawList* self,ImFont* font,float f { return self->AddText(font,font_size,ConvertToCPP_ImVec2(pos),col,text_begin,text_end,wrap_width,cpu_fine_clip_rect); } -CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,int num_segments) +CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,int num_segments,ImDrawFlags flags) { - return self->AddBezierCubic(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),col,thickness,num_segments); + return self->AddBezierCubic(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),col,thickness,num_segments,flags); } -CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,int num_segments) +CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,int num_segments,ImDrawFlags flags) { - return self->AddBezierQuadratic(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),col,thickness,num_segments); + return self->AddBezierQuadratic(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),col,thickness,num_segments,flags); } CIMGUI_API void ImDrawList_AddPolyline(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,float thickness,ImDrawFlags flags) { return self->AddPolyline(reinterpret_cast(points),num_points,col,thickness,flags); } -CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col) +CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,ImDrawFlags flags) { - return self->AddConvexPolyFilled(reinterpret_cast(points),num_points,col); + return self->AddConvexPolyFilled(reinterpret_cast(points),num_points,col,flags); } CIMGUI_API void ImDrawList_AddConcavePolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col) { @@ -2506,9 +2498,9 @@ CIMGUI_API void ImDrawList_PathLineToMergeDuplicate(ImDrawList* self,const ImVec { return self->PathLineToMergeDuplicate(ConvertToCPP_ImVec2(pos)); } -CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col) +CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col,ImDrawFlags flags) { - return self->PathFillConvex(col); + return self->PathFillConvex(col,flags); } CIMGUI_API void ImDrawList_PathFillConcave(ImDrawList* self,ImU32 col) { @@ -2606,6 +2598,10 @@ CIMGUI_API void ImDrawList__ResetForNewFrame(ImDrawList* self) { return self->_ResetForNewFrame(); } +CIMGUI_API void ImDrawList__SetPixelDensity(ImDrawList* self,float pixel_density) +{ + return self->_SetPixelDensity(pixel_density); +} CIMGUI_API void ImDrawList__ClearFreeMemory(ImDrawList* self) { return self->_ClearFreeMemory(); @@ -2646,6 +2642,34 @@ CIMGUI_API void ImDrawList__PathArcToN(ImDrawList* self,const ImVec2_c center,fl { return self->_PathArcToN(ConvertToCPP_ImVec2(center),radius,a_min,a_max,num_segments); } +CIMGUI_API void ImDrawList__AddRectFilledBaked(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float r,const ImVec4_c tex_uvs,ImDrawFlags flags) +{ + return self->_AddRectFilledBaked(ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),col,r,ConvertToCPP_ImVec4(tex_uvs),flags); +} +CIMGUI_API void ImDrawList__AddRectBaked(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float r,float t,const ImVec4_c tex_uvs,ImDrawFlags flags) +{ + return self->_AddRectBaked(ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),col,r,t,ConvertToCPP_ImVec4(tex_uvs),flags); +} +CIMGUI_API void ImDrawList__AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness,ImDrawFlags flags) +{ + return self->_AddLine(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),col,thickness,flags); +} +CIMGUI_API void ImDrawList__AddRectTinyRounding(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float rounding,float thickness,ImDrawFlags flags) +{ + return self->_AddRectTinyRounding(ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),col,rounding,thickness,flags); +} +CIMGUI_API void ImDrawList__SelectLineTexture(ImDrawList* self,float screen_thickness,ImVec2_c* out_uv0,ImVec2_c* out_uv1,float* out_fringe,ImDrawFlags flags) +{ + return self->_SelectLineTexture(screen_thickness,reinterpret_cast(out_uv0),reinterpret_cast(out_uv1),out_fringe,flags); +} +CIMGUI_API float ImDrawList__CalculateCenterBiasedOffset(ImDrawList* self,float thickness) +{ + return self->_CalculateCenterBiasedOffset(thickness); +} +CIMGUI_API void ImDrawList__AddPolyline(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,float thickness,ImDrawFlags flags,float max_inner_offset) +{ + return self->_AddPolyline(reinterpret_cast(points),num_points,col,thickness,flags,max_inner_offset); +} CIMGUI_API ImDrawData* ImDrawData_ImDrawData(void) { return IM_NEW(ImDrawData)(); @@ -2934,9 +2958,13 @@ CIMGUI_API void ImFont_ClearOutputData(ImFont* self) { return self->ClearOutputData(); } -CIMGUI_API void ImFont_AddRemapChar(ImFont* self,ImWchar from_codepoint,ImWchar to_codepoint) +CIMGUI_API void ImFont_AddRemapCodepoint(ImFont* self,ImWchar from_codepoint,ImWchar to_codepoint) +{ + return self->AddRemapCodepoint(from_codepoint,to_codepoint); +} +CIMGUI_API void ImFont_AddRemapCodepointToGlyphIndex(ImFont* self,ImWchar from_codepoint,int font_src_idx,int glyph_idx) { - return self->AddRemapChar(from_codepoint,to_codepoint); + return self->AddRemapCodepointToGlyphIndex(from_codepoint,font_src_idx,glyph_idx); } CIMGUI_API bool ImFont_IsGlyphRangeUnused(ImFont* self,unsigned int c_begin,unsigned int c_last) { @@ -3277,19 +3305,47 @@ CIMGUI_API float igImRsqrt_Float(float x) { return ImRsqrt(x); } +CIMGUI_API float igImRsqrtPrecise(float x) +{ + return ImRsqrtPrecise(x); +} CIMGUI_API double igImRsqrt_double(double x) { return ImRsqrt(x); } -CIMGUI_API ImVec2_c igImMin(const ImVec2_c lhs,const ImVec2_c rhs) +CIMGUI_API int igImMin_Int(int lhs,int rhs) +{ + return ImMin(lhs,rhs); +} +CIMGUI_API int igImMax_Int(int lhs,int rhs) +{ + return ImMax(lhs,rhs); +} +CIMGUI_API int igImClamp_Int(int v,int mn,int mx) +{ + return ImClamp(v,mn,mx); +} +CIMGUI_API float igImMin_Float(float lhs,float rhs) +{ + return ImMin(lhs,rhs); +} +CIMGUI_API float igImMax_Float(float lhs,float rhs) +{ + return ImMax(lhs,rhs); +} +CIMGUI_API float igImClamp_Float(float v,float mn,float mx) +{ + return ImClamp(v,mn,mx); +} +CIMGUI_API ImVec2_c igImMin_Vec2(const ImVec2_c lhs,const ImVec2_c rhs) { return ConvertFromCPP_ImVec2(ImMin(ConvertToCPP_ImVec2(lhs),ConvertToCPP_ImVec2(rhs))); } -CIMGUI_API ImVec2_c igImMax(const ImVec2_c lhs,const ImVec2_c rhs) +CIMGUI_API ImVec2_c igImMax_Vec2(const ImVec2_c lhs,const ImVec2_c rhs) { return ConvertFromCPP_ImVec2(ImMax(ConvertToCPP_ImVec2(lhs),ConvertToCPP_ImVec2(rhs))); } -CIMGUI_API ImVec2_c igImClamp(const ImVec2_c v,const ImVec2_c mn,const ImVec2_c mx) +CIMGUI_API ImVec2_c igImClamp_Vec2(const ImVec2_c v,const ImVec2_c mn,const ImVec2_c mx) { return ConvertFromCPP_ImVec2(ImClamp(ConvertToCPP_ImVec2(v),ConvertToCPP_ImVec2(mn),ConvertToCPP_ImVec2(mx))); } @@ -3341,9 +3397,13 @@ CIMGUI_API float igImTrunc64(float f) { return ImTrunc64(f); } -CIMGUI_API float igImRound64(float f) +CIMGUI_API float igImRoundPositive64(float f) +{ + return ImRoundPositive64(f); +} +CIMGUI_API float igImRoundSigned64(float f) { - return ImRound64(f); + return ImRoundSigned64(f); } CIMGUI_API float igImCeilFast(float f) { @@ -3381,6 +3441,14 @@ CIMGUI_API float igImExponentialMovingAverage(float avg,float sample,int n) { return ImExponentialMovingAverage(avg,sample,n); } +CIMGUI_API bool igImIsTruncated(float x) +{ + return ImIsTruncated(x); +} +CIMGUI_API bool igImIsTruncated4(float x,float y,float z,float w) +{ + return ImIsTruncated4(x,y,z,w); +} CIMGUI_API ImVec2_c igImBezierCubicCalc(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,float t) { return ConvertFromCPP_ImVec2(ImBezierCubicCalc(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),t)); @@ -3389,9 +3457,9 @@ CIMGUI_API ImVec2_c igImBezierCubicClosestPoint(const ImVec2_c p1,const ImVec2_c { return ConvertFromCPP_ImVec2(ImBezierCubicClosestPoint(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),ConvertToCPP_ImVec2(p),num_segments)); } -CIMGUI_API ImVec2_c igImBezierCubicClosestPointCasteljau(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c p,float tess_tol) +CIMGUI_API ImVec2_c igImBezierCubicClosestPointCasteljau(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c p,float max_error) { - return ConvertFromCPP_ImVec2(ImBezierCubicClosestPointCasteljau(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),ConvertToCPP_ImVec2(p),tess_tol)); + return ConvertFromCPP_ImVec2(ImBezierCubicClosestPointCasteljau(ConvertToCPP_ImVec2(p1),ConvertToCPP_ImVec2(p2),ConvertToCPP_ImVec2(p3),ConvertToCPP_ImVec2(p4),ConvertToCPP_ImVec2(p),max_error)); } CIMGUI_API ImVec2_c igImBezierQuadraticCalc(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,float t) { @@ -3653,6 +3721,14 @@ CIMGUI_API void ImGuiTextIndex_append(ImGuiTextIndex* self,const char* base,int { return self->append(base,old_size,new_size); } +CIMGUI_API ImGuiTextFilterItem* ImGuiTextFilterItem_ImGuiTextFilterItem(const char* b,const char* e) +{ + return IM_NEW(ImGuiTextFilterItem)(b,e); +} +CIMGUI_API void ImGuiTextFilterItem_destroy(ImGuiTextFilterItem* self) +{ + IM_DELETE(self); +} CIMGUI_API ImGuiPackedDate* ImGuiPackedDate_ImGuiPackedDate_Nil(void) { return IM_NEW(ImGuiPackedDate)(); @@ -4617,6 +4693,14 @@ CIMGUI_API ImVec2_c igWindowPosRelToAbs(ImGuiWindow* window,const ImVec2_c p) { return ConvertFromCPP_ImVec2(ImGui::WindowPosRelToAbs(window,ConvertToCPP_ImVec2(p))); } +CIMGUI_API void igSetNextWindowFlags(ImGuiWindowFlags flags,bool enabled) +{ + return ImGui::SetNextWindowFlags(flags,enabled); +} +CIMGUI_API void igSetNextWindowChildFlags(ImGuiChildFlags flags,bool enabled) +{ + return ImGui::SetNextWindowChildFlags(flags,enabled); +} CIMGUI_API void igFocusWindow(ImGuiWindow* window,ImGuiFocusRequestFlags flags) { return ImGui::FocusWindow(window,flags); @@ -4677,13 +4761,13 @@ CIMGUI_API void igUpdateCurrentFontSize(float restore_font_size_after_scaling) { return ImGui::UpdateCurrentFontSize(restore_font_size_after_scaling); } -CIMGUI_API void igSetFontRasterizerDensity(float rasterizer_density) +CIMGUI_API void igSetPixelDensity(float pixel_density) { - return ImGui::SetFontRasterizerDensity(rasterizer_density); + return ImGui::SetPixelDensity(pixel_density); } -CIMGUI_API float igGetFontRasterizerDensity() +CIMGUI_API float igGetPixelDensity() { - return ImGui::GetFontRasterizerDensity(); + return ImGui::GetPixelDensity(); } CIMGUI_API float igGetRoundedFontSize(float size) { @@ -5373,6 +5457,10 @@ CIMGUI_API void igRenderDragDropTargetRectForItem(const ImRect_c bb) { return ImGui::RenderDragDropTargetRectForItem(ConvertToCPP_ImRect(bb)); } +CIMGUI_API void igRenderDragDropTargetRectForViewport(ImGuiID viewport_id,const ImRect_c bb) +{ + return ImGui::RenderDragDropTargetRectForViewport(viewport_id,ConvertToCPP_ImRect(bb)); +} CIMGUI_API void igRenderDragDropTargetRectEx(ImDrawList* draw_list,const ImRect_c bb,float rounding) { return ImGui::RenderDragDropTargetRectEx(draw_list,ConvertToCPP_ImRect(bb),rounding); @@ -5461,6 +5549,10 @@ CIMGUI_API const char* igTabBarGetTabName(ImGuiTabBar* tab_bar,ImGuiTabItem* tab { return ImGui::TabBarGetTabName(tab_bar,tab); } +CIMGUI_API ImVec2_c igTabBarGetTabPos(ImGuiTabBar* tab_bar,ImGuiTabItem* tab) +{ + return ConvertFromCPP_ImVec2(ImGui::TabBarGetTabPos(tab_bar,tab)); +} CIMGUI_API void igTabBarRemoveTab(ImGuiTabBar* tab_bar,ImGuiID tab_id) { return ImGui::TabBarRemoveTab(tab_bar,tab_id); @@ -5545,9 +5637,9 @@ CIMGUI_API void igRenderColorComponentMarker(const ImRect_c bb,ImU32 col,float r { return ImGui::RenderColorComponentMarker(ConvertToCPP_ImRect(bb),col,rounding); } -CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2_c p_min,ImVec2_c p_max,ImU32 fill_col,float grid_step,ImVec2_c grid_off,float rounding,ImDrawFlags flags) +CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2_c p_min,ImVec2_c p_max,ImU32 col,float alpha,float grid_step,ImVec2_c grid_off,float rounding,ImDrawFlags flags) { - return ImGui::RenderColorRectWithAlphaCheckerboard(draw_list,ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),fill_col,grid_step,ConvertToCPP_ImVec2(grid_off),rounding,flags); + return ImGui::RenderColorRectWithAlphaCheckerboard(draw_list,ConvertToCPP_ImVec2(p_min),ConvertToCPP_ImVec2(p_max),col,alpha,grid_step,ConvertToCPP_ImVec2(grid_off),rounding,flags); } CIMGUI_API void igRenderNavCursor(const ImRect_c bb,ImGuiID id,ImGuiNavRenderCursorFlags flags,float rounding) { @@ -5593,22 +5685,22 @@ CIMGUI_API void igTextEx(const char* text,const char* text_end,ImGuiTextFlags fl { return ImGui::TextEx(text,text_end,flags); } -CIMGUI_API void igTextAligned(float align_x,float size_x,const char* fmt,...) +CIMGUI_API void igTextAligned(float align_x,float width,const char* fmt,...) { va_list args; va_start(args, fmt); - ImGui::TextAlignedV(align_x,size_x,fmt,args); + ImGui::TextAlignedV(align_x,width,fmt,args); va_end(args); } #ifdef CIMGUI_VARGS0 -CIMGUI_API void igTextAligned0(float align_x,float size_x,const char* fmt) +CIMGUI_API void igTextAligned0(float align_x,float width,const char* fmt) { - igTextAligned(align_x,size_x,fmt); + igTextAligned(align_x,width,fmt); } #endif -CIMGUI_API void igTextAlignedV(float align_x,float size_x,const char* fmt,va_list args) +CIMGUI_API void igTextAlignedV(float align_x,float width,const char* fmt,va_list args) { - return ImGui::TextAlignedV(align_x,size_x,fmt,args); + return ImGui::TextAlignedV(align_x,width,fmt,args); } CIMGUI_API bool igButtonEx(const char* label,const ImVec2_c size_arg,ImGuiButtonFlags flags) { diff --git a/include/cimgui.h b/include/cimgui.h index 00ee5a2..65409ef 100644 --- a/include/cimgui.h +++ b/include/cimgui.h @@ -1,5 +1,5 @@ //This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui -//based on imgui.h file version "1.92.9b" 19291 from Dear ImGui https://github.com/ocornut/imgui +//based on imgui.h file version "1.93.0" 19300 from Dear ImGui https://github.com/ocornut/imgui //with imgui_internal.h api //with imgui_freetype.h api #ifndef CIMGUI_INCLUDED @@ -94,6 +94,7 @@ typedef struct ImGuiTableColumnSortSpecs ImGuiTableColumnSortSpecs; typedef struct ImGuiTextBuffer ImGuiTextBuffer; typedef struct ImGuiTextFilter ImGuiTextFilter; typedef struct ImGuiViewport ImGuiViewport; +typedef struct ImGuiTextFilterItem ImGuiTextFilterItem; typedef struct ImBitVector ImBitVector; typedef struct ImRect_c ImRect_c; typedef struct ImGuiTextIndex ImGuiTextIndex; @@ -140,6 +141,7 @@ typedef struct ImGuiTypingSelectRequest ImGuiTypingSelectRequest; typedef struct ImGuiWindow ImGuiWindow; typedef struct ImGuiWindowTempData ImGuiWindowTempData; typedef struct ImGuiWindowSettings ImGuiWindowSettings; +typedef struct ImGuiWindowStackData ImGuiWindowStackData; typedef struct STB_TexteditState STB_TexteditState; typedef struct stbrp_node stbrp_node; typedef unsigned int ImGuiID; @@ -200,7 +202,6 @@ typedef int ImGuiMouseCursor; typedef int ImGuiStyleVar; typedef int ImGuiTableBgTarget; typedef int ImDrawFlags; -typedef int ImDrawListFlags; typedef int ImDrawTextFlags; typedef int ImFontFlags; typedef int ImFontAtlasFlags; @@ -323,6 +324,7 @@ typedef enum { ImGuiItemFlags_LiveEditOnInputText = 1 << 7, ImGuiItemFlags_LiveEditOnInputScalar = 1 << 8, ImGuiItemFlags_LiveEditOnInput = ImGuiItemFlags_LiveEditOnInputText | ImGuiItemFlags_LiveEditOnInputScalar, + ImGuiItemFlags_MixedValue = 1 << 9, }ImGuiItemFlags_; typedef enum { ImGuiInputTextFlags_None = 0, @@ -1072,9 +1074,9 @@ struct ImGuiStyle ImVec2_c DisplaySafeAreaPadding; float MouseCursorScale; bool AntiAliasedLines; - bool AntiAliasedLinesUseTex; + bool AntiAliasedLineEnds; bool AntiAliasedFill; - float CurveTessellationTol; + float CurveTessellationMaxError; float CircleTessellationMaxError; ImVec4_c Colors[ImGuiCol_COUNT]; float HoverStationaryDelay; @@ -1146,6 +1148,7 @@ struct ImGuiIO bool ConfigDebugBeginReturnValueOnce; bool ConfigDebugBeginReturnValueLoop; bool ConfigDebugIgnoreFocusLoss; + bool ConfigDebugDrawListDefaultsToStrokeLegacy; const char* BackendPlatformName; const char* BackendRendererName; void* BackendPlatformUserData; @@ -1239,22 +1242,15 @@ struct ImGuiOnceUponAFrame { int RefFrame; }; -struct ImGuiTextRange -{ - const char* b; - const char* e; -}; -typedef struct ImGuiTextRange ImGuiTextRange; - -typedef struct ImVector_ImGuiTextRange {int Size;int Capacity;ImGuiTextRange* Data;} ImVector_ImGuiTextRange; +struct ImGuiTextFilterItem; +typedef struct ImVector_ImGuiTextFilterItem {int Size;int Capacity;ImGuiTextFilterItem* Data;} ImVector_ImGuiTextFilterItem; struct ImGuiTextFilter { char InputBuf[256]; - ImVector_ImGuiTextRange Filters; - int CountGrep; + int _CountExclude; + ImVector_ImGuiTextFilterItem _Items; }; -typedef struct ImGuiTextRange ImGuiTextRange; typedef struct ImVector_char {int Size;int Capacity;char* Data;} ImVector_char; struct ImGuiTextBuffer @@ -1403,29 +1399,37 @@ struct ImDrawListSplitter }; typedef enum { ImDrawFlags_None = 0, - ImDrawFlags_RoundCornersTopLeft = 1 << 4, - ImDrawFlags_RoundCornersTopRight = 1 << 5, - ImDrawFlags_RoundCornersBottomLeft = 1 << 6, - ImDrawFlags_RoundCornersBottomRight = 1 << 7, - ImDrawFlags_RoundCornersNone = 1 << 8, - ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, - ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, - ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, - ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, - ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, - ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, - ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, + ImDrawFlags_RoundTopLeft = 1 << 4, + ImDrawFlags_RoundTopRight = 1 << 5, + ImDrawFlags_RoundBottomLeft = 1 << 6, + ImDrawFlags_RoundBottomRight = 1 << 7, + ImDrawFlags_RoundNone = 1 << 8, + ImDrawFlags_RoundAll = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundTopRight | ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundBottomRight, + ImDrawFlags_RoundTop = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundTopRight, + ImDrawFlags_RoundBottom = ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundBottomRight, + ImDrawFlags_RoundLeft = ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundTopLeft, + ImDrawFlags_RoundRight = ImDrawFlags_RoundBottomRight | ImDrawFlags_RoundTopRight, ImDrawFlags_Closed = 1 << 9, + ImDrawFlags_JoinMiter = 1 << 10, + ImDrawFlags_CapSquare = 1 << 11, + ImDrawFlags_AAFill = 1 << 12, + ImDrawFlags_AALines = 1 << 13, + ImDrawFlags_AALineEnds = 1 << 14, + ImDrawFlags_StrokeInside = 1 << 17, + ImDrawFlags_StrokeCenter = 2 << 17, + ImDrawFlags_StrokeCenterBiased = 3 << 17, + ImDrawFlags_StrokeOutside = 4 << 17, + ImDrawFlags_StrokeLegacy = 7 << 17, + ImDrawFlags_TextNoPixelSnap = 1 << 20, + ImDrawFlags_UseTexForRoundCorners = 1 << 21, + ImDrawFlags_UseVtxOffset = 1 << 22, + ImDrawFlags_AllowTexForRoundCorners_= 1 << 23, + ImDrawFlags_RoundMask_ = ImDrawFlags_RoundAll | ImDrawFlags_RoundNone, + ImDrawFlags_AllowInPushScope_ = ImDrawFlags_AAFill | ImDrawFlags_AALines | ImDrawFlags_AALineEnds | ImDrawFlags_StrokeLegacy | ImDrawFlags_TextNoPixelSnap | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_UseVtxOffset | ImDrawFlags_RoundMask_, + ImDrawFlags_AllowInFrameScope_ = ImDrawFlags_AllowInPushScope_ | ImDrawFlags_AllowTexForRoundCorners_, + ImDrawFlags_StrokeMask_ = 0x07 << 17, ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, }ImDrawFlags_; -typedef enum { - ImDrawListFlags_None = 0, - ImDrawListFlags_AntiAliasedLines = 1 << 0, - ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, - ImDrawListFlags_AntiAliasedFill = 1 << 2, - ImDrawListFlags_AllowVtxOffset = 1 << 3, - ImDrawListFlags_TextNoPixelSnap = 1 << 4, -}ImDrawListFlags_; typedef struct ImVector_ImDrawVert {int Size;int Capacity;ImDrawVert* Data;} ImVector_ImDrawVert; typedef struct ImVector_ImVec2 {int Size;int Capacity;ImVec2_c* Data;} ImVector_ImVec2; @@ -1436,12 +1440,14 @@ typedef struct ImVector_ImTextureRef {int Size;int Capacity;ImTextureRef_c* Data typedef struct ImVector_ImU8 {int Size;int Capacity;ImU8* Data;} ImVector_ImU8; +typedef struct ImSmallStack__ImDrawFlags__3 {ImDrawFlags LocalData[3];ImU16 Size;} ImSmallStack__ImDrawFlags__3; + struct ImDrawList { ImVector_ImDrawCmd CmdBuffer; ImVector_ImDrawIdx IdxBuffer; ImVector_ImDrawVert VtxBuffer; - ImDrawListFlags Flags; + ImDrawFlags Flags; unsigned int _VtxCurrentIdx; ImDrawListSharedData* _Data; ImDrawVert* _VtxWritePtr; @@ -1452,7 +1458,10 @@ struct ImDrawList ImVector_ImVec4 _ClipRectStack; ImVector_ImTextureRef _TextureStack; ImVector_ImU8 _CallbacksDataBuf; + ImSmallStack__ImDrawFlags__3 _DrawFlagsStack; float _FringeScale; + float _InvFringeScale; + bool _FringeScaleIsInteger; const char* _OwnerName; }; typedef struct ImVector_ImDrawListPtr {int Size;int Capacity;ImDrawList** Data;} ImVector_ImDrawListPtr; @@ -1570,6 +1579,7 @@ typedef enum { ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, ImFontAtlasFlags_NoMouseCursors = 1 << 1, ImFontAtlasFlags_NoBakedLines = 1 << 2, + ImFontAtlasFlags_NoBakedRoundCorners= 1 << 3, }ImFontAtlasFlags_; typedef struct ImVector_ImFontPtr {int Size;int Capacity;ImFont** Data;} ImVector_ImFontPtr; @@ -1598,7 +1608,6 @@ struct ImFontAtlas ImVec2_c TexUvWhitePixel; ImVector_ImFontPtr Fonts; ImVector_ImFontConfig Sources; - ImVec4_c TexUvLines[(32) + 1]; int TexNextUniqueID; int FontNextUniqueID; ImVector_ImDrawListSharedDataPtr DrawListSharedDatas; @@ -1694,6 +1703,7 @@ struct ImGuiPlatformIO ImDrawCallback DrawCallback_ResetRenderState; ImDrawCallback DrawCallback_SetSamplerLinear; ImDrawCallback DrawCallback_SetSamplerNearest; + ImDrawCallback DrawCallback_SetSamplerFromTex; ImVector_ImTextureDataPtr Textures; }; struct ImGuiPlatformImeData @@ -1753,6 +1763,7 @@ struct ImGuiTypingSelectRequest; struct ImGuiWindow; struct ImGuiWindowTempData; struct ImGuiWindowSettings; +struct ImGuiWindowStackData; typedef int ImGuiLayoutType; typedef int ImDrawTextFlags; typedef int ImGuiActivateFlags; @@ -1823,6 +1834,13 @@ struct ImGuiTextIndex ImVector_int Offsets; int EndOffset; }; +struct ImGuiTextFilterItem +{ + const char* Begin; + int Len; + short CountInclude; + unsigned short MatchIncludesMask; +}; struct ImGuiPackedDate { ImU16 Year : 7; @@ -1833,19 +1851,19 @@ struct ImDrawListSharedData { ImVec2_c TexUvWhitePixel; const ImVec4_c* TexUvLines; + const ImVec4_c* TexUvCorners; ImFontAtlas* FontAtlas; ImFont* Font; float FontSize; float FontScale; - float CurveTessellationTol; + float CurveTessellationMaxError; float CircleTessellationMaxError; - float InitialFringeScale; - ImDrawListFlags InitialFlags; + ImDrawFlags InitialDrawFlags; ImVec4_c ClipRectFullscreen; ImVector_ImVec2 TempBuffer; ImVector_ImDrawListPtr DrawLists; ImGuiContext* Context; - ImVec2_c ArcFastVtx[48]; + ImVec2_c ArcFastVtx[(48)]; float ArcFastRadiusCutoff; ImU8 CircleSegmentCounts[64]; }; @@ -1895,7 +1913,6 @@ typedef enum { }ImGuiDataTypePrivate_; typedef enum { ImGuiItemFlags_ReadOnly = 1 << 11, - ImGuiItemFlags_MixedValue = 1 << 12, ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, ImGuiItemFlags_AllowOverlap = 1 << 14, ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, @@ -1950,9 +1967,6 @@ typedef enum { ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, }ImGuiButtonFlagsPrivate_; -typedef enum { - ImGuiComboFlags_CustomPreview = 1 << 20, -}ImGuiComboFlagsPrivate_; typedef enum { ImGuiSliderFlags_Vertical = 1 << 20, ImGuiSliderFlags_ReadOnly = 1 << 21, @@ -2021,7 +2035,10 @@ struct ImGuiComboPreviewData ImVec2_c BackupCursorMaxPos; ImVec2_c BackupCursorPosPrevLine; float BackupPrevLineTextBaseOffset; - ImGuiLayoutType BackupLayout; + float BackupWorkRectMaxX; + float BackupContentRectMaxX; + ImGuiLayoutType BackupLayout : 8; + int WithinPreview : 2; }; struct ImGuiGroupData { @@ -2080,6 +2097,7 @@ struct ImGuiInputTextState bool SelectedAllMouseLock; bool EditedBefore; bool EditedThisFrame; + bool ValidatedThisFrame; bool WantReloadUserBuf; ImS8 LastMoveDirectionLR; int ReloadSelectionStart; @@ -2120,8 +2138,10 @@ struct ImGuiNextWindowData ImVec2_c SizeVal; ImVec2_c ContentSizeVal; ImVec2_c ScrollVal; - ImGuiWindowFlags WindowFlags; - ImGuiChildFlags ChildFlags; + ImGuiWindowFlags WindowFlagsSet; + ImGuiWindowFlags WindowFlagsClear; + ImGuiChildFlags ChildFlagsSet; + ImGuiChildFlags ChildFlagsClear; bool CollapsedVal; ImRect_c SizeConstraintRect; ImGuiSizeCallback SizeCallback; @@ -2189,7 +2209,6 @@ struct ImGuiErrorRecoveryState short SizeOfBeginPopupStack; short SizeOfDisabledStack; }; -typedef struct ImGuiWindowStackData ImGuiWindowStackData; struct ImGuiWindowStackData { ImGuiWindow* Window; @@ -2197,6 +2216,7 @@ struct ImGuiWindowStackData ImGuiErrorRecoveryState StackSizesInBegin; bool DisabledOverrideReenable; float DisabledOverrideReenableAlphaBackup; + ImRect_c ParentLastComboPreviewRect; }; typedef struct ImGuiShrinkWidthItem ImGuiShrinkWidthItem; struct ImGuiShrinkWidthItem @@ -2552,8 +2572,9 @@ typedef struct ImGuiViewportP ImGuiViewportP; struct ImGuiViewportP { ImGuiViewport _ImGuiViewport; - float BgFgDrawListsLastTimeActive[2]; ImDrawList* BgFgDrawLists[2]; + int BgFgDrawListsLastFrameActive[2]; + float BgFgDrawListsLastTimeActive[2]; ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; ImVec2_c WorkInsetMin; @@ -2800,7 +2821,7 @@ struct ImGuiContext float FontSize; float FontSizeBase; float FontBakedScale; - float FontRasterizerDensity; + float CurrentPixelDensity; float CurrentDpiScale; ImDrawListSharedData DrawListSharedData; ImGuiID WithinEndChildID; @@ -2830,6 +2851,7 @@ struct ImGuiContext float WheelingWindowReleaseTimer; ImVec2_c WheelingWindowWheelRemainder; ImVec2_c WheelingAxisAvg; + const char* MixedValueLabel; ImGuiID DebugDrawIdConflictsId; ImGuiID DebugHookIdInfoId; ImGuiID HoveredId; @@ -2943,6 +2965,7 @@ struct ImGuiContext ImGuiID NavJustMovedToFocusScopeId; ImGuiKeyChord NavJustMovedToKeyMods; bool NavJustMovedToIsTabbing; + bool NavJustMovedToIsInit; bool NavJustMovedToHasSelectionData; bool ConfigNavEnableTabbing; bool ConfigNavWindowingWithGamepad; @@ -3478,9 +3501,9 @@ struct ImGuiTable ImDrawListSplitter* DrawSplitter; ImGuiTableInstanceData InstanceDataFirst; ImVector_ImGuiTableInstanceData InstanceDataExtra; - ImGuiTableColumnSortSpecs SortSpecsSingle; - ImVector_ImGuiTableColumnSortSpecs SortSpecsMulti; ImGuiTableSortSpecs SortSpecs; + ImVector_ImGuiTableColumnSortSpecs SortSpecsMulti; + ImGuiTableColumnSortSpecs SortSpecsSingle; ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; ImGuiTableColumnIdx ColumnsEnabledFixedCount; @@ -3512,6 +3535,7 @@ struct ImGuiTable ImS8 NavLayer; bool IsLayoutLocked; bool IsInsideRow; + bool IsNewTable; bool IsInitializing; bool IsReconcileMode; bool IsSortSpecsDirty; @@ -3589,10 +3613,11 @@ struct ImFontLoader void (*LoaderShutdown)(ImFontAtlas* atlas); bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); - bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); + int (*FontSrcGetGlyphIndexFromCodepoint)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); + bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, int glyph_index); bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); - bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x); + bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x); size_t FontBakedSrcLoaderDataSize; }; struct ImFontAtlasRectEntry @@ -3650,6 +3675,10 @@ struct ImFontAtlasBuilder int BakedDiscardedCount; ImFontAtlasRectId PackIdMouseCursors; ImFontAtlasRectId PackIdLinesTexData; + ImFontAtlasRectId PackIdLineFractTexData; + ImFontAtlasRectId PackIdCornersTexData; + ImVec4_c TexUvLines[(32) + 1 + (((4) - 1) * (4) + 1)]; + ImVec4_c TexUvCorners[(16) * (4)]; }; typedef struct StbUndoRecord StbUndoRecord; struct StbUndoRecord @@ -3759,13 +3788,13 @@ struct ImRect_c { #ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS -typedef struct ImGuiTextFilter::ImGuiTextRange ImGuiTextRange; typedef ImStb::STB_TexteditState STB_TexteditState; typedef ImChunkStream ImChunkStream_ImGuiTableSettings; typedef ImChunkStream ImChunkStream_ImGuiWindowSettings; typedef ImPool ImPool_ImGuiMultiSelectState; typedef ImPool ImPool_ImGuiTabBar; typedef ImPool ImPool_ImGuiTable; +typedef ImSmallStack_ ImSmallStack__ImDrawFlags__3; typedef ImSpan ImSpan_ImGuiTableCellData; typedef ImSpan ImSpan_ImGuiTableColumn; typedef ImSpan ImSpan_ImGuiTableColumnIdx; @@ -3810,7 +3839,7 @@ typedef ImVector ImVector_ImGuiTableHeaderData; typedef ImVector ImVector_ImGuiTableInstanceData; typedef ImVector ImVector_ImGuiTableReconcileColumnData; typedef ImVector ImVector_ImGuiTableTempData; -typedef ImVector ImVector_ImGuiTextRange; +typedef ImVector ImVector_ImGuiTextFilterItem; typedef ImVector ImVector_ImGuiTreeNodeStackData; typedef ImVector ImVector_ImGuiViewportPPtr; typedef ImVector ImVector_ImGuiWindowPtr; @@ -4323,16 +4352,12 @@ CIMGUI_API ImGuiOnceUponAFrame* ImGuiOnceUponAFrame_ImGuiOnceUponAFrame(void); CIMGUI_API void ImGuiOnceUponAFrame_destroy(ImGuiOnceUponAFrame* self); CIMGUI_API ImGuiTextFilter* ImGuiTextFilter_ImGuiTextFilter(const char* default_filter); CIMGUI_API void ImGuiTextFilter_destroy(ImGuiTextFilter* self); -CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label,float width); CIMGUI_API bool ImGuiTextFilter_PassFilter(ImGuiTextFilter* self,const char* text,const char* text_end); CIMGUI_API void ImGuiTextFilter_Build(ImGuiTextFilter* self); CIMGUI_API void ImGuiTextFilter_Clear(ImGuiTextFilter* self); CIMGUI_API bool ImGuiTextFilter_IsActive(ImGuiTextFilter* self); -CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Nil(void); -CIMGUI_API void ImGuiTextRange_destroy(ImGuiTextRange* self); -CIMGUI_API ImGuiTextRange* ImGuiTextRange_ImGuiTextRange_Str(const char* _b,const char* _e); -CIMGUI_API bool ImGuiTextRange_empty(ImGuiTextRange* self); -CIMGUI_API void ImGuiTextRange_split(ImGuiTextRange* self,char separator,ImVector_ImGuiTextRange* out); +CIMGUI_API bool ImGuiTextFilter_Draw(ImGuiTextFilter* self,const char* label); +CIMGUI_API bool ImGuiTextFilter_DrawWithHint(ImGuiTextFilter* self,const char* label,const char* hint); CIMGUI_API ImGuiTextBuffer* ImGuiTextBuffer_ImGuiTextBuffer(void); CIMGUI_API void ImGuiTextBuffer_destroy(ImGuiTextBuffer* self); CIMGUI_API const char* ImGuiTextBuffer_begin(ImGuiTextBuffer* self); @@ -4409,30 +4434,32 @@ CIMGUI_API void ImDrawList_PushClipRectFullScreen(ImDrawList* self); CIMGUI_API void ImDrawList_PopClipRect(ImDrawList* self); CIMGUI_API void ImDrawList_PushTexture(ImDrawList* self,ImTextureRef_c tex_ref); CIMGUI_API void ImDrawList_PopTexture(ImDrawList* self); +CIMGUI_API void ImDrawList_PushDrawFlag(ImDrawList* self,ImDrawFlags flags,bool enabled); +CIMGUI_API void ImDrawList_PopDrawFlag(ImDrawList* self); CIMGUI_API ImVec2_c ImDrawList_GetClipRectMin(ImDrawList* self); CIMGUI_API ImVec2_c ImDrawList_GetClipRectMax(ImDrawList* self); -CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness); -CIMGUI_API void ImDrawList_AddLineH(ImDrawList* self,float min_x,float max_x,float y,ImU32 col,float thickness); -CIMGUI_API void ImDrawList_AddLineV(ImDrawList* self,float x,float min_y,float max_y,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddLineH(ImDrawList* self,float min_x,float max_x,float y,ImU32 col,float thickness,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddLineV(ImDrawList* self,float x,float min_y,float max_y,ImU32 col,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddRect(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float rounding,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddRectFilled(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float rounding,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddRectFilledMultiColor(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col_upr_left,ImU32 col_upr_right,ImU32 col_bot_right,ImU32 col_bot_left); -CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddQuad(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddQuadFilled(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col); -CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness); +CIMGUI_API void ImDrawList_AddTriangle(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddTriangleFilled(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col); -CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddCircle(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddCircleFilled(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments); -CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddNgon(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddNgonFilled(ImDrawList* self,const ImVec2_c center,float radius,ImU32 col,int num_segments); -CIMGUI_API void ImDrawList_AddEllipse(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments,float thickness); +CIMGUI_API void ImDrawList_AddEllipse(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddEllipseFilled(ImDrawList* self,const ImVec2_c center,const ImVec2_c radius,ImU32 col,float rot,int num_segments); CIMGUI_API void ImDrawList_AddText_Vec2(ImDrawList* self,const ImVec2_c pos,ImU32 col,const char* text_begin,const char* text_end); CIMGUI_API void ImDrawList_AddText_FontPtr(ImDrawList* self,ImFont* font,float font_size,const ImVec2_c pos,ImU32 col,const char* text_begin,const char* text_end,float wrap_width,const ImVec4* cpu_fine_clip_rect); -CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,int num_segments); -CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,int num_segments); +CIMGUI_API void ImDrawList_AddBezierCubic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,ImU32 col,float thickness,int num_segments,ImDrawFlags flags); +CIMGUI_API void ImDrawList_AddBezierQuadratic(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,ImU32 col,float thickness,int num_segments,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddPolyline(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,float thickness,ImDrawFlags flags); -CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col); +CIMGUI_API void ImDrawList_AddConvexPolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,ImDrawFlags flags); CIMGUI_API void ImDrawList_AddConcavePolyFilled(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col); CIMGUI_API void ImDrawList_AddImage(ImDrawList* self,ImTextureRef_c tex_ref,const ImVec2_c p_min,const ImVec2_c p_max,const ImVec2_c uv_min,const ImVec2_c uv_max,ImU32 col); CIMGUI_API void ImDrawList_AddImageQuad(ImDrawList* self,ImTextureRef_c tex_ref,const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c uv1,const ImVec2_c uv2,const ImVec2_c uv3,const ImVec2_c uv4,ImU32 col); @@ -4440,7 +4467,7 @@ CIMGUI_API void ImDrawList_AddImageRounded(ImDrawList* self,ImTextureRef_c tex_r CIMGUI_API void ImDrawList_PathClear(ImDrawList* self); CIMGUI_API void ImDrawList_PathLineTo(ImDrawList* self,const ImVec2_c pos); CIMGUI_API void ImDrawList_PathLineToMergeDuplicate(ImDrawList* self,const ImVec2_c pos); -CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col); +CIMGUI_API void ImDrawList_PathFillConvex(ImDrawList* self,ImU32 col,ImDrawFlags flags); CIMGUI_API void ImDrawList_PathFillConcave(ImDrawList* self,ImU32 col); CIMGUI_API void ImDrawList_PathStroke(ImDrawList* self,ImU32 col,float thickness,ImDrawFlags flags); CIMGUI_API void ImDrawList_PathArcTo(ImDrawList* self,const ImVec2_c center,float radius,float a_min,float a_max,int num_segments); @@ -4465,6 +4492,7 @@ CIMGUI_API void ImDrawList_PrimWriteIdx(ImDrawList* self,ImDrawIdx idx); CIMGUI_API void ImDrawList_PrimVtx(ImDrawList* self,const ImVec2_c pos,const ImVec2_c uv,ImU32 col); CIMGUI_API void ImDrawList__SetDrawListSharedData(ImDrawList* self,ImDrawListSharedData* data); CIMGUI_API void ImDrawList__ResetForNewFrame(ImDrawList* self); +CIMGUI_API void ImDrawList__SetPixelDensity(ImDrawList* self,float pixel_density); CIMGUI_API void ImDrawList__ClearFreeMemory(ImDrawList* self); CIMGUI_API void ImDrawList__PopUnusedDrawCmd(ImDrawList* self); CIMGUI_API void ImDrawList__TryMergeDrawCmds(ImDrawList* self); @@ -4475,6 +4503,13 @@ CIMGUI_API void ImDrawList__SetTexture(ImDrawList* self,ImTextureRef_c tex_ref); CIMGUI_API int ImDrawList__CalcCircleAutoSegmentCount(ImDrawList* self,float radius); CIMGUI_API void ImDrawList__PathArcToFastEx(ImDrawList* self,const ImVec2_c center,float radius,int a_min_sample,int a_max_sample,int a_step); CIMGUI_API void ImDrawList__PathArcToN(ImDrawList* self,const ImVec2_c center,float radius,float a_min,float a_max,int num_segments); +CIMGUI_API void ImDrawList__AddRectFilledBaked(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float r,const ImVec4_c tex_uvs,ImDrawFlags flags); +CIMGUI_API void ImDrawList__AddRectBaked(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float r,float t,const ImVec4_c tex_uvs,ImDrawFlags flags); +CIMGUI_API void ImDrawList__AddLine(ImDrawList* self,const ImVec2_c p1,const ImVec2_c p2,ImU32 col,float thickness,ImDrawFlags flags); +CIMGUI_API void ImDrawList__AddRectTinyRounding(ImDrawList* self,const ImVec2_c p_min,const ImVec2_c p_max,ImU32 col,float rounding,float thickness,ImDrawFlags flags); +CIMGUI_API void ImDrawList__SelectLineTexture(ImDrawList* self,float screen_thickness,ImVec2_c* out_uv0,ImVec2_c* out_uv1,float* out_fringe,ImDrawFlags flags); +CIMGUI_API float ImDrawList__CalculateCenterBiasedOffset(ImDrawList* self,float thickness); +CIMGUI_API void ImDrawList__AddPolyline(ImDrawList* self,const ImVec2_c* points,int num_points,ImU32 col,float thickness,ImDrawFlags flags,float max_inner_offset); CIMGUI_API ImDrawData* ImDrawData_ImDrawData(void); CIMGUI_API void ImDrawData_destroy(ImDrawData* self); CIMGUI_API void ImDrawData_Clear(ImDrawData* self); @@ -4547,7 +4582,8 @@ CIMGUI_API const char* ImFont_CalcWordWrapPosition(ImFont* self,float size,const CIMGUI_API void ImFont_RenderChar(ImFont* self,ImDrawList* draw_list,float size,const ImVec2_c pos,ImU32 col,ImWchar c,const ImVec4* cpu_fine_clip); CIMGUI_API void ImFont_RenderText(ImFont* self,ImDrawList* draw_list,float size,const ImVec2_c pos,ImU32 col,const ImVec4_c clip_rect,const char* text_begin,const char* text_end,float wrap_width,ImDrawTextFlags flags); CIMGUI_API void ImFont_ClearOutputData(ImFont* self); -CIMGUI_API void ImFont_AddRemapChar(ImFont* self,ImWchar from_codepoint,ImWchar to_codepoint); +CIMGUI_API void ImFont_AddRemapCodepoint(ImFont* self,ImWchar from_codepoint,ImWchar to_codepoint); +CIMGUI_API void ImFont_AddRemapCodepointToGlyphIndex(ImFont* self,ImWchar from_codepoint,int font_src_idx,int glyph_idx); CIMGUI_API bool ImFont_IsGlyphRangeUnused(ImFont* self,unsigned int c_begin,unsigned int c_last); CIMGUI_API ImGuiViewport* ImGuiViewport_ImGuiViewport(void); CIMGUI_API void ImGuiViewport_destroy(ImGuiViewport* self); @@ -4634,10 +4670,17 @@ CIMGUI_API double igImAbs_double(double x); CIMGUI_API float igImSign_Float(float x); CIMGUI_API double igImSign_double(double x); CIMGUI_API float igImRsqrt_Float(float x); +CIMGUI_API float igImRsqrtPrecise(float x); CIMGUI_API double igImRsqrt_double(double x); -CIMGUI_API ImVec2_c igImMin(const ImVec2_c lhs,const ImVec2_c rhs); -CIMGUI_API ImVec2_c igImMax(const ImVec2_c lhs,const ImVec2_c rhs); -CIMGUI_API ImVec2_c igImClamp(const ImVec2_c v,const ImVec2_c mn,const ImVec2_c mx); +CIMGUI_API int igImMin_Int(int lhs,int rhs); +CIMGUI_API int igImMax_Int(int lhs,int rhs); +CIMGUI_API int igImClamp_Int(int v,int mn,int mx); +CIMGUI_API float igImMin_Float(float lhs,float rhs); +CIMGUI_API float igImMax_Float(float lhs,float rhs); +CIMGUI_API float igImClamp_Float(float v,float mn,float mx); +CIMGUI_API ImVec2_c igImMin_Vec2(const ImVec2_c lhs,const ImVec2_c rhs); +CIMGUI_API ImVec2_c igImMax_Vec2(const ImVec2_c lhs,const ImVec2_c rhs); +CIMGUI_API ImVec2_c igImClamp_Vec2(const ImVec2_c v,const ImVec2_c mn,const ImVec2_c mx); CIMGUI_API ImVec2_c igImLerp_Vec2Float(const ImVec2_c a,const ImVec2_c b,float t); CIMGUI_API ImVec2_c igImLerp_Vec2Vec2(const ImVec2_c a,const ImVec2_c b,const ImVec2_c t); CIMGUI_API ImVec4_c igImLerp_Vec4(const ImVec4_c a,const ImVec4_c b,float t); @@ -4650,7 +4693,8 @@ CIMGUI_API ImVec2_c igImTrunc_Vec2(const ImVec2_c v); CIMGUI_API float igImFloor_Float(float f); CIMGUI_API ImVec2_c igImFloor_Vec2(const ImVec2_c v); CIMGUI_API float igImTrunc64(float f); -CIMGUI_API float igImRound64(float f); +CIMGUI_API float igImRoundPositive64(float f); +CIMGUI_API float igImRoundSigned64(float f); CIMGUI_API float igImCeilFast(float f); CIMGUI_API int igImModPositive(int a,int b); CIMGUI_API float igImDot(const ImVec2_c a,const ImVec2_c b); @@ -4660,9 +4704,11 @@ CIMGUI_API float igImLinearRemapClamp(float s0,float s1,float d0,float d1,float CIMGUI_API ImVec2_c igImMul(const ImVec2_c lhs,const ImVec2_c rhs); CIMGUI_API bool igImIsFloatAboveGuaranteedIntegerPrecision(float f); CIMGUI_API float igImExponentialMovingAverage(float avg,float sample,int n); +CIMGUI_API bool igImIsTruncated(float x); +CIMGUI_API bool igImIsTruncated4(float x,float y,float z,float w); CIMGUI_API ImVec2_c igImBezierCubicCalc(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,float t); CIMGUI_API ImVec2_c igImBezierCubicClosestPoint(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c p,int num_segments); -CIMGUI_API ImVec2_c igImBezierCubicClosestPointCasteljau(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c p,float tess_tol); +CIMGUI_API ImVec2_c igImBezierCubicClosestPointCasteljau(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,const ImVec2_c p4,const ImVec2_c p,float max_error); CIMGUI_API ImVec2_c igImBezierQuadraticCalc(const ImVec2_c p1,const ImVec2_c p2,const ImVec2_c p3,float t); CIMGUI_API ImVec2_c igImLineClosestPoint(const ImVec2_c a,const ImVec2_c b,const ImVec2_c p); CIMGUI_API bool igImTriangleContainsPoint(const ImVec2_c a,const ImVec2_c b,const ImVec2_c c,const ImVec2_c p); @@ -4728,6 +4774,8 @@ CIMGUI_API int ImGuiTextIndex_size(ImGuiTextIndex* self); CIMGUI_API const char* ImGuiTextIndex_get_line_begin(ImGuiTextIndex* self,const char* base,int n); CIMGUI_API const char* ImGuiTextIndex_get_line_end(ImGuiTextIndex* self,const char* base,int n); CIMGUI_API void ImGuiTextIndex_append(ImGuiTextIndex* self,const char* base,int old_size,int new_size); +CIMGUI_API ImGuiTextFilterItem* ImGuiTextFilterItem_ImGuiTextFilterItem(const char* b,const char* e); +CIMGUI_API void ImGuiTextFilterItem_destroy(ImGuiTextFilterItem* self); CIMGUI_API ImGuiPackedDate* ImGuiPackedDate_ImGuiPackedDate_Nil(void); CIMGUI_API void ImGuiPackedDate_destroy(ImGuiPackedDate* self); CIMGUI_API ImGuiPackedDate* ImGuiPackedDate_ImGuiPackedDate_Int(int yyyymmdd); @@ -4969,6 +5017,8 @@ CIMGUI_API ImRect_c igWindowRectAbsToRel(ImGuiWindow* window,const ImRect_c r); CIMGUI_API ImRect_c igWindowRectRelToAbs(ImGuiWindow* window,const ImRect_c r); CIMGUI_API ImVec2_c igWindowPosAbsToRel(ImGuiWindow* window,const ImVec2_c p); CIMGUI_API ImVec2_c igWindowPosRelToAbs(ImGuiWindow* window,const ImVec2_c p); +CIMGUI_API void igSetNextWindowFlags(ImGuiWindowFlags flags,bool enabled); +CIMGUI_API void igSetNextWindowChildFlags(ImGuiChildFlags flags,bool enabled); CIMGUI_API void igFocusWindow(ImGuiWindow* window,ImGuiFocusRequestFlags flags); CIMGUI_API void igFocusTopMostWindowUnderOne(ImGuiWindow* under_this_window,ImGuiWindow* ignore_window,ImGuiViewport* filter_viewport,ImGuiFocusRequestFlags flags); CIMGUI_API void igBringWindowToFocusFront(ImGuiWindow* window); @@ -4984,8 +5034,8 @@ CIMGUI_API void igRegisterFontAtlas(ImFontAtlas* atlas); CIMGUI_API void igUnregisterFontAtlas(ImFontAtlas* atlas); CIMGUI_API void igSetCurrentFont(ImFont* font,float font_size_before_scaling,float font_size_after_scaling); CIMGUI_API void igUpdateCurrentFontSize(float restore_font_size_after_scaling); -CIMGUI_API void igSetFontRasterizerDensity(float rasterizer_density); -CIMGUI_API float igGetFontRasterizerDensity(void); +CIMGUI_API void igSetPixelDensity(float pixel_density); +CIMGUI_API float igGetPixelDensity(void); CIMGUI_API float igGetRoundedFontSize(float size); CIMGUI_API ImFont* igGetDefaultFont(void); CIMGUI_API void igPushPasswordFont(void); @@ -5158,6 +5208,7 @@ CIMGUI_API bool igBeginDragDropTargetViewport(ImGuiViewport* viewport,const ImRe CIMGUI_API void igClearDragDrop(void); CIMGUI_API bool igIsDragDropPayloadBeingAccepted(void); CIMGUI_API void igRenderDragDropTargetRectForItem(const ImRect_c bb); +CIMGUI_API void igRenderDragDropTargetRectForViewport(ImGuiID viewport_id,const ImRect_c bb); CIMGUI_API void igRenderDragDropTargetRectEx(ImDrawList* draw_list,const ImRect_c bb,float rounding); CIMGUI_API ImGuiTypingSelectRequest* igGetTypingSelectRequest(ImGuiTypingSelectFlags flags); CIMGUI_API int igTypingSelectFindMatch(ImGuiTypingSelectRequest* req,int items_count,const char*(*get_item_name_func)(void*,int),void* user_data,int nav_item_idx); @@ -5180,6 +5231,7 @@ CIMGUI_API ImGuiTabItem* igTabBarFindTabByOrder(ImGuiTabBar* tab_bar,int order); CIMGUI_API ImGuiTabItem* igTabBarGetCurrentTab(ImGuiTabBar* tab_bar); CIMGUI_API int igTabBarGetTabOrder(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); CIMGUI_API const char* igTabBarGetTabName(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); +CIMGUI_API ImVec2_c igTabBarGetTabPos(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); CIMGUI_API void igTabBarRemoveTab(ImGuiTabBar* tab_bar,ImGuiID tab_id); CIMGUI_API void igTabBarCloseTab(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); CIMGUI_API void igTabBarQueueFocus_TabItemPtr(ImGuiTabBar* tab_bar,ImGuiTabItem* tab); @@ -5201,7 +5253,7 @@ CIMGUI_API void igRenderTextEllipsis(ImDrawList* draw_list,const ImVec2_c pos_mi CIMGUI_API void igRenderFrame(ImVec2_c p_min,ImVec2_c p_max,ImU32 fill_col,bool borders,float rounding); CIMGUI_API void igRenderFrameBorder(ImVec2_c p_min,ImVec2_c p_max,float rounding); CIMGUI_API void igRenderColorComponentMarker(const ImRect_c bb,ImU32 col,float rounding); -CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2_c p_min,ImVec2_c p_max,ImU32 fill_col,float grid_step,ImVec2_c grid_off,float rounding,ImDrawFlags flags); +CIMGUI_API void igRenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list,ImVec2_c p_min,ImVec2_c p_max,ImU32 col,float alpha,float grid_step,ImVec2_c grid_off,float rounding,ImDrawFlags flags); CIMGUI_API void igRenderNavCursor(const ImRect_c bb,ImGuiID id,ImGuiNavRenderCursorFlags flags,float rounding); CIMGUI_API const char* igFindRenderedTextEnd(const char* text,const char* text_end); CIMGUI_API void igRenderMouseCursor(ImVec2_c pos,float scale,ImGuiMouseCursor mouse_cursor,ImU32 col_fill,ImU32 col_border,ImU32 col_shadow); @@ -5213,11 +5265,11 @@ CIMGUI_API void igRenderRectFilledInRangeH(ImDrawList* draw_list,const ImRect_c CIMGUI_API void igRenderRectFilledWithHole(ImDrawList* draw_list,const ImRect_c outer,const ImRect_c inner,ImU32 col,float rounding); CIMGUI_API ImDrawFlags igCalcRoundingFlagsForRectInRect(const ImRect_c r_in,const ImRect_c r_outer,float threshold); CIMGUI_API void igTextEx(const char* text,const char* text_end,ImGuiTextFlags flags); -CIMGUI_API void igTextAligned(float align_x,float size_x,const char* fmt,...); +CIMGUI_API void igTextAligned(float align_x,float width,const char* fmt,...); #ifdef CIMGUI_VARGS0 -CIMGUI_API void igTextAligned0(float align_x,float size_x,const char* fmt); +CIMGUI_API void igTextAligned0(float align_x,float width,const char* fmt); #endif -CIMGUI_API void igTextAlignedV(float align_x,float size_x,const char* fmt,va_list args); +CIMGUI_API void igTextAlignedV(float align_x,float width,const char* fmt,va_list args); CIMGUI_API bool igButtonEx(const char* label,const ImVec2_c size_arg,ImGuiButtonFlags flags); CIMGUI_API bool igArrowButtonEx(const char* str_id,ImGuiDir dir,ImVec2_c size_arg,ImGuiButtonFlags flags); CIMGUI_API bool igImageButtonEx(ImGuiID id,ImTextureRef_c tex_ref,const ImVec2_c image_size,const ImVec2_c uv0,const ImVec2_c uv1,const ImVec4_c bg_col,const ImVec4_c tint_col,ImGuiButtonFlags flags); diff --git a/include/cimgui_impl.h b/include/cimgui_impl.h index 8e7e913..b3c726d 100644 --- a/include/cimgui_impl.h +++ b/include/cimgui_impl.h @@ -47,6 +47,7 @@ CIMGUI_API ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState(void) CIMGUI_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version); CIMGUI_API void ImGui_ImplOpenGL3_NewFrame(void); CIMGUI_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); +CIMGUI_API void ImGui_ImplOpenGL3_SetClipOrigin(unsigned int gl_clip_origin); CIMGUI_API void ImGui_ImplOpenGL3_Shutdown(void); CIMGUI_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); @@ -220,6 +221,7 @@ CIMGUI_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDe CIMGUI_API ImGui_ImplVulkanH_Window* ImGui_ImplVulkanH_Window_ImGui_ImplVulkanH_Window(void); CIMGUI_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view,VkImageLayout image_layout); CIMGUI_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_PipelineInfo* info); +CIMGUI_API ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState(void); CIMGUI_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); CIMGUI_API bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version,PFN_vkVoidFunction(*loader_func)(const char* function_name,void* user_data),void* user_data); CIMGUI_API void ImGui_ImplVulkan_NewFrame(void); diff --git a/include/cimplot.cpp b/include/cimplot.cpp index 5b1c67d..27e3ff8 100644 --- a/include/cimplot.cpp +++ b/include/cimplot.cpp @@ -1,5 +1,5 @@ //This file is automatically generated by generator.lua from https://github.com/cimgui/cimplot -//based on implot.h file version 1.1 WIP from implot https://github.com/epezent/implot +//based on implot.h file version 1.2 WIP from implot https://github.com/epezent/implot //with implot_internal.h api #include "./implot/implot.h" @@ -1946,6 +1946,10 @@ CIMGUI_API void ImPlot_HideNextItem(bool hidden,ImPlotCond cond) { return ImPlot::HideNextItem(hidden,cond); } +CIMGUI_API bool ImPlot_IsItemHidden(const char* label_id) +{ + return ImPlot::IsItemHidden(label_id); +} CIMGUI_API bool ImPlot_BeginAlignedPlots(const char* group_id,bool vertical) { return ImPlot::BeginAlignedPlots(group_id,vertical); @@ -2050,6 +2054,10 @@ CIMGUI_API ImVec4_c ImPlot_GetLastItemColor() { return ConvertFromCPP_ImVec4(ImPlot::GetLastItemColor()); } +CIMGUI_API bool ImPlot_IsLastItemHidden() +{ + return ImPlot::IsLastItemHidden(); +} CIMGUI_API const char* ImPlot_GetStyleColorName(ImPlotCol idx) { return ImPlot::GetStyleColorName(idx); @@ -2298,6 +2306,10 @@ CIMGUI_API int ImPlot_ImPosMod(int l,int r) { return ImPosMod(l,r); } +CIMGUI_API ImU64 ImPlot_ImDoubleBits(double val) +{ + return ImDoubleBits(val); +} CIMGUI_API bool ImPlot_ImNan(double val) { return ImNan(val); @@ -2944,6 +2956,10 @@ CIMGUI_API bool ImPlotAxis_HasTickLabels(ImPlotAxis* self) { return self->HasTickLabels(); } +CIMGUI_API bool ImPlotAxis_HasTickLabelsInside(ImPlotAxis* self) +{ + return self->HasTickLabelsInside(); +} CIMGUI_API bool ImPlotAxis_HasTickMarks(ImPlotAxis* self) { return self->HasTickMarks(); @@ -3408,6 +3424,14 @@ CIMGUI_API void ImPlot_RenderColorBar(const ImU32* colors,int size,ImDrawList* D { return ImPlot::RenderColorBar(colors,size,*DrawList,ConvertToCPP_ImRect(bounds),vert,reversed,continuous); } +CIMGUI_API void ImPlot_AddLineH(ImDrawList* draw_list,float x1,float x2,float y,ImU32 col,float thickness) +{ + return ImPlot::AddLineH(draw_list,x1,x2,y,col,thickness); +} +CIMGUI_API void ImPlot_AddLineV(ImDrawList* draw_list,float x,float y1,float y2,ImU32 col,float thickness) +{ + return ImPlot::AddLineV(draw_list,x,y1,y2,col,thickness); +} CIMGUI_API double ImPlot_NiceNum(double x,bool round) { return ImPlot::NiceNum(x,round); diff --git a/include/cimplot.h b/include/cimplot.h index f00377c..94c7ce4 100644 --- a/include/cimplot.h +++ b/include/cimplot.h @@ -1,5 +1,5 @@ //This file is automatically generated by generator.lua from https://github.com/cimgui/cimplot -//based on implot.h file version 1.1 WIP from implot https://github.com/epezent/implot +//based on implot.h file version 1.2 WIP from implot https://github.com/epezent/implot //with implot_internal.h api #ifndef CIMGUIPLOT_INCLUDED #define CIMGUIPLOT_INCLUDED @@ -135,6 +135,7 @@ typedef enum { ImPlotAxisFlags_PanStretch = 1 << 13, ImPlotAxisFlags_LockMin = 1 << 14, ImPlotAxisFlags_LockMax = 1 << 15, + ImPlotAxisFlags_TickLabelsInside = 1 << 16, ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax, ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels, ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite @@ -176,6 +177,8 @@ typedef enum { ImPlotDragToolFlags_NoFit = 1 << 1, ImPlotDragToolFlags_NoInputs = 1 << 2, ImPlotDragToolFlags_Delayed = 1 << 3, + ImPlotDragToolFlags_NoMove = 1 << 4, + ImPlotDragToolFlags_NoResize = 1 << 5, }ImPlotDragToolFlags_; typedef enum { ImPlotColormapScaleFlags_None = 0, @@ -334,6 +337,8 @@ typedef enum { ImPlotMarker_Cross, ImPlotMarker_Plus, ImPlotMarker_Asterisk, + ImPlotMarker_Vertical, + ImPlotMarker_Horizontal, ImPlotMarker_COUNT }ImPlotMarker_; typedef enum { @@ -780,6 +785,8 @@ typedef struct ImVector_ImPlotColormap {int Size;int Capacity;ImPlotColormap* Da typedef struct ImVector_double {int Size;int Capacity;double* Data;} ImVector_double; +typedef struct ImVector_ImRect {int Size;int Capacity;ImRect_c* Data;} ImVector_ImRect; + typedef struct ImPool_ImPlotAlignmentData {ImVector_ImPlotAlignmentData Buf;ImGuiStorage Map;ImPoolIdx FreeIdx;ImPoolIdx AliveCount;} ImPool_ImPlotAlignmentData; struct ImPlotContext @@ -802,6 +809,7 @@ struct ImPlotContext tm Tm; ImVector_double TempDouble1, TempDouble2; ImVector_int TempInt1; + ImVector_ImRect TempRect1; int DigitalPlotItemCnt; int DigitalPlotOffset; ImPlotNextPlotData NextPlotData; @@ -966,6 +974,7 @@ typedef ImVector ImVector_ImPlotColormap; typedef ImVector ImVector_ImPlotRange; typedef ImVector ImVector_ImPlotTag; typedef ImVector ImVector_ImPlotTick; +typedef ImVector ImVector_ImRect; typedef ImVector ImVector_ImS16; typedef ImVector ImVector_ImS32; typedef ImVector ImVector_ImS64; @@ -1362,6 +1371,7 @@ CIMGUI_API bool ImPlot_IsPlotSelected(void); CIMGUI_API ImPlotRect_c ImPlot_GetPlotSelection(ImAxis x_axis,ImAxis y_axis); CIMGUI_API void ImPlot_CancelPlotSelection(void); CIMGUI_API void ImPlot_HideNextItem(bool hidden,ImPlotCond cond); +CIMGUI_API bool ImPlot_IsItemHidden(const char* label_id); CIMGUI_API bool ImPlot_BeginAlignedPlots(const char* group_id,bool vertical); CIMGUI_API void ImPlot_EndAlignedPlots(void); CIMGUI_API bool ImPlot_BeginLegendPopup(const char* label_id,ImGuiMouseButton mouse_button); @@ -1388,6 +1398,7 @@ CIMGUI_API void ImPlot_PushStyleVar_Int(ImPlotStyleVar idx,int val); CIMGUI_API void ImPlot_PushStyleVar_Vec2(ImPlotStyleVar idx,const ImVec2_c val); CIMGUI_API void ImPlot_PopStyleVar(int count); CIMGUI_API ImVec4_c ImPlot_GetLastItemColor(void); +CIMGUI_API bool ImPlot_IsLastItemHidden(void); CIMGUI_API const char* ImPlot_GetStyleColorName(ImPlotCol idx); CIMGUI_API const char* ImPlot_GetMarkerName(ImPlotMarker idx); CIMGUI_API ImPlotMarker ImPlot_NextMarker(void); @@ -1450,6 +1461,7 @@ CIMGUI_API ImU32 ImPlot_ImRemap01_U32(ImU32 x,ImU32 x0,ImU32 x1); CIMGUI_API ImS64 ImPlot_ImRemap01_S64(ImS64 x,ImS64 x0,ImS64 x1); CIMGUI_API ImU64 ImPlot_ImRemap01_U64(ImU64 x,ImU64 x0,ImU64 x1); CIMGUI_API int ImPlot_ImPosMod(int l,int r); +CIMGUI_API ImU64 ImPlot_ImDoubleBits(double val); CIMGUI_API bool ImPlot_ImNan(double val); CIMGUI_API bool ImPlot_ImNanOrInf(double val); CIMGUI_API double ImPlot_ImConstrainNan(double val); @@ -1613,6 +1625,7 @@ CIMGUI_API void ImPlotAxis_ApplyFit(ImPlotAxis* self,float padding); CIMGUI_API bool ImPlotAxis_HasLabel(ImPlotAxis* self); CIMGUI_API bool ImPlotAxis_HasGridLines(ImPlotAxis* self); CIMGUI_API bool ImPlotAxis_HasTickLabels(ImPlotAxis* self); +CIMGUI_API bool ImPlotAxis_HasTickLabelsInside(ImPlotAxis* self); CIMGUI_API bool ImPlotAxis_HasTickMarks(ImPlotAxis* self); CIMGUI_API bool ImPlotAxis_WillRender(ImPlotAxis* self); CIMGUI_API bool ImPlotAxis_IsOpposite(ImPlotAxis* self); @@ -1729,6 +1742,8 @@ CIMGUI_API ImU32 ImPlot_GetColormapColorU32(int idx,ImPlotColormap cmap); CIMGUI_API ImU32 ImPlot_NextColormapColorU32(void); CIMGUI_API ImU32 ImPlot_SampleColormapU32(float t,ImPlotColormap cmap); CIMGUI_API void ImPlot_RenderColorBar(const ImU32* colors,int size,ImDrawList* DrawList,const ImRect_c bounds,bool vert,bool reversed,bool continuous); +CIMGUI_API void ImPlot_AddLineH(ImDrawList* draw_list,float x1,float x2,float y,ImU32 col,float thickness); +CIMGUI_API void ImPlot_AddLineV(ImDrawList* draw_list,float x,float y1,float y2,ImU32 col,float thickness); CIMGUI_API double ImPlot_NiceNum(double x,bool round); CIMGUI_API int ImPlot_OrderOfMagnitude(double val); CIMGUI_API int ImPlot_OrderToPrecision(int order); diff --git a/include/imgui/.github/ISSUE_TEMPLATE/issue_template.yml b/include/imgui/.github/ISSUE_TEMPLATE/issue_template.yml index 6ed6249..dda2213 100644 --- a/include/imgui/.github/ISSUE_TEMPLATE/issue_template.yml +++ b/include/imgui/.github/ISSUE_TEMPLATE/issue_template.yml @@ -14,6 +14,7 @@ body: attributes: value: | **Prerequisites:** + - I am not using a LLM to think or write for me. Please distill information to what's necessary and meaningful. - I have read [Frequently Asked Questions](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md). - I have read [Contributing Guidelines -> General Advices](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#getting-started--general-advice). - I have read [Contributing Guidelines -> How to open an Issue](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#how-to-open-an-issue). diff --git a/include/imgui/.github/pull_request_template.md b/include/imgui/.github/pull_request_template.md index 27cb3e1..998b254 100644 --- a/include/imgui/.github/pull_request_template.md +++ b/include/imgui/.github/pull_request_template.md @@ -1,12 +1,12 @@ (Click "Preview" to turn any http URL into a clickable link) -1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md) +1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md). By submitting a PR you are agreeing with the [CLA](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#copyright--contributor-license-agreement). 2. **Make sure you're using a special branch just for this pull request**. (In git, 1 PR = 1 branch. If you update the branch the PR will be updated.) 3. Consider running the [imgui_test_suite](https://github.com/ocornut/imgui_test_engine) or adding new tests to test for expected behaviors. -4. PLEASE DO NOT SUBMIT AI SLOP OR AUTOMATED REPORTS. Submissions that are lacking proper human review/judgement before being passed to us are not welcome. +4. PLEASE DO NOT SUBMIT AI-GENERATED PROSE. ONLY SUBMIT CODE THAT YOU REVIEWED AND UNDERSTAND. Submissions that are lacking proper human review/judgement before being passed to us are not welcome. 5. Clear this template before submitting your PR. diff --git a/include/imgui/.github/workflows/build.yml b/include/imgui/.github/workflows/build.yml index 5bbaefd..4e276e1 100644 --- a/include/imgui/.github/workflows/build.yml +++ b/include/imgui/.github/workflows/build.yml @@ -601,6 +601,10 @@ jobs: run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2 if: github.event_name == 'workflow_run' + - name: Build macOS example_apple_opengl3 + run: xcodebuild -project examples/example_apple_opengl3/example_apple_opengl3.xcodeproj -target example_osx_opengl3 + if: github.event_name == 'workflow_run' + Build-iOS: runs-on: macos-14 name: Build - iOS diff --git a/include/imgui/.gitignore b/include/imgui/.gitignore index 83c0ab4..009e61e 100644 --- a/include/imgui/.gitignore +++ b/include/imgui/.gitignore @@ -9,6 +9,8 @@ imgui*.ini ## General build artifacts *.o +*.so* +*.a *.obj *.exe examples/*/Debug/* @@ -57,9 +59,15 @@ examples/example_sdl3_wgpu/web/* .idea cmake-build-* +## QNX artifacts +*.pinfo +*.dep +*.gcno + ## Unix executables from our example Makefiles examples/example_apple_metal/example_apple_metal examples/example_apple_opengl2/example_apple_opengl2 +examples/example_apple_opengl3/example_apple_opengl3 examples/example_glfw_metal/example_glfw_metal examples/example_glfw_opengl2/example_glfw_opengl2 examples/example_glfw_opengl3/example_glfw_opengl3 diff --git a/include/imgui/backends/imgui_impl_allegro5.cpp b/include/imgui/backends/imgui_impl_allegro5.cpp index 79b169d..bd877f3 100644 --- a/include/imgui/backends/imgui_impl_allegro5.cpp +++ b/include/imgui/backends/imgui_impl_allegro5.cpp @@ -268,8 +268,7 @@ void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex) IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); - // Create texture - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Create texture (bilinear sampling is required) const int new_bitmap_flags = al_get_new_bitmap_flags(); int new_bitmap_format = al_get_new_bitmap_format(); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); diff --git a/include/imgui/backends/imgui_impl_dx10.cpp b/include/imgui/backends/imgui_impl_dx10.cpp index 9e570ef..a81d813 100644 --- a/include/imgui/backends/imgui_impl_dx10.cpp +++ b/include/imgui/backends/imgui_impl_dx10.cpp @@ -5,6 +5,7 @@ // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -16,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378) // 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -99,6 +101,11 @@ static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState() +{ + return (ImGui_ImplDX10_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device) { @@ -106,8 +113,8 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* // Setup viewport D3D10_VIEWPORT vp = {}; - vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; @@ -557,8 +564,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects() bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); } - // Create texture sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Create texture sampler (bilinear sampling is required) { D3D10_SAMPLER_DESC desc; ZeroMemory(&desc, sizeof(desc)); diff --git a/include/imgui/backends/imgui_impl_dx10.h b/include/imgui/backends/imgui_impl_dx10.h index 179756f..3ab1669 100644 --- a/include/imgui/backends/imgui_impl_dx10.h +++ b/include/imgui/backends/imgui_impl_dx10.h @@ -5,6 +5,7 @@ // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -45,5 +46,6 @@ struct ImGui_ImplDX10_RenderState //ID3D10SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) //ID3D10SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; +IMGUI_IMPL_API ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_dx11.cpp b/include/imgui/backends/imgui_impl_dx11.cpp index 73f722a..a7d2cdf 100644 --- a/include/imgui/backends/imgui_impl_dx11.cpp +++ b/include/imgui/backends/imgui_impl_dx11.cpp @@ -5,7 +5,7 @@ // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -103,6 +103,11 @@ static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState() +{ + return (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx) { @@ -110,8 +115,8 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D // Setup viewport D3D11_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; - vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; + vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; diff --git a/include/imgui/backends/imgui_impl_dx11.h b/include/imgui/backends/imgui_impl_dx11.h index 56166b9..5fd8ddc 100644 --- a/include/imgui/backends/imgui_impl_dx11.h +++ b/include/imgui/backends/imgui_impl_dx11.h @@ -5,7 +5,7 @@ // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -48,5 +48,6 @@ struct ImGui_ImplDX11_RenderState //ID3D11SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) //ID3D11SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; +IMGUI_IMPL_API ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_dx12.cpp b/include/imgui/backends/imgui_impl_dx12.cpp index 53c7b3d..22a9bdc 100644 --- a/include/imgui/backends/imgui_impl_dx12.cpp +++ b/include/imgui/backends/imgui_impl_dx12.cpp @@ -5,7 +5,7 @@ // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState(). // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -20,6 +20,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) +// 2026-08-05: DirectX12: *BREAKING CHANGE* Removed support for legacy `ImGui_ImplDX12_Init()` signature obsoleted in 1.91.6 (2024-11-15) because it needed to forcefully disable support for ImGuiBackendFlags_RendererHasTextures. (#9487) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961) @@ -131,6 +133,11 @@ static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState() +{ + return (ImGui_ImplDX12_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Buffers used during the rendering of a frame struct ImGui_ImplDX12_RenderBuffers { @@ -182,8 +189,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic // Setup viewport D3D12_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; - vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; + vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0.0f; @@ -608,7 +615,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() param[1].DescriptorTable.pDescriptorRanges = &descRange; param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + // Bilinear sampling is required D3D12_STATIC_SAMPLER_DESC staticSampler[1] = {}; staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; staticSampler[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; @@ -956,37 +963,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) return true; } -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Legacy initialization API Obsoleted in 1.91.5 -// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' -bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) -{ - ImGui_ImplDX12_InitInfo init_info; - init_info.Device = device; - init_info.NumFramesInFlight = num_frames_in_flight; - init_info.RTVFormat = rtv_format; - init_info.SrvDescriptorHeap = srv_descriptor_heap; - init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle; - init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle; - - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.NodeMask = 1; - HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue)); - IM_ASSERT(SUCCEEDED(hr)); - - bool ret = ImGui_ImplDX12_Init(&init_info); - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - bd->commandQueueOwned = true; - - ImGuiIO& io = ImGui::GetIO(); - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures. - - return ret; -} -#endif - void ImGui_ImplDX12_Shutdown() { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); diff --git a/include/imgui/backends/imgui_impl_dx12.h b/include/imgui/backends/imgui_impl_dx12.h index b8be8db..106b4b4 100644 --- a/include/imgui/backends/imgui_impl_dx12.h +++ b/include/imgui/backends/imgui_impl_dx12.h @@ -5,7 +5,7 @@ // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState(). // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -59,13 +59,6 @@ IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Legacy initialization API Obsoleted in 1.91.5 -// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' -// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field. -IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); -#endif - // Use if you want to reset your rendering device without losing Dear ImGui state. IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); @@ -81,6 +74,15 @@ struct ImGui_ImplDX12_RenderState ID3D12Device* Device; ID3D12GraphicsCommandList* CommandList; }; +IMGUI_IMPL_API ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState(); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy initialization API Obsoleted in 1.91.5 +// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' +// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field. +// - DOES NOT SUPPORT ImGuiBackendFlags_RendererHasTextures. +//IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); +#endif #if defined(__clang__) #pragma clang diagnostic pop diff --git a/include/imgui/backends/imgui_impl_metal.mm b/include/imgui/backends/imgui_impl_metal.mm index 445c4b3..43019b5 100644 --- a/include/imgui/backends/imgui_impl_metal.mm +++ b/include/imgui/backends/imgui_impl_metal.mm @@ -16,6 +16,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-10-06: Added support for render passes with multiple color attachments: we render to the first one and leave the others untouched. (#9574) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378) // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) @@ -57,14 +59,16 @@ @interface MetalBuffer : NSObject - (instancetype)initWithBuffer:(id)buffer; @end +#define IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS 8 // Metal's limit (see Metal Feature Set Tables). Not configurable. + // An object that encapsulates the data necessary to uniquely identify a // render pipeline state. These are used as cache keys. @interface FramebufferDescriptor : NSObject @property (nonatomic, assign) unsigned long sampleCount; -@property (nonatomic, assign) MTLPixelFormat colorPixelFormat; @property (nonatomic, assign) MTLPixelFormat depthPixelFormat; @property (nonatomic, assign) MTLPixelFormat stencilPixelFormat; - (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor; +- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index; @end @interface MetalTexture : NSObject @@ -163,8 +167,8 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, idDisplaySize.x * draw_data->FramebufferScale.x), - .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y), + .width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f), + .height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f), .znear = 0.0, .zfar = 1.0 }; @@ -203,8 +207,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id MetalContext* ctx = bd->SharedMetalContext; // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; @@ -476,23 +480,33 @@ - (instancetype)initWithBuffer:(id)buffer #pragma mark - FramebufferDescriptor implementation @implementation FramebufferDescriptor +{ + MTLPixelFormat _colorPixelFormats[IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS]; +} + - (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor { if ((self = [super init])) { _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; - _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; + for (NSUInteger n = 0; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) + _colorPixelFormats[n] = renderPassDescriptor.colorAttachments[n].texture.pixelFormat; _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat; _stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat; } return self; } +- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index +{ + return _colorPixelFormats[index]; +} + - (nonnull id)copyWithZone:(nullable NSZone*)zone { FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init]; copy.sampleCount = self.sampleCount; - copy.colorPixelFormat = self.colorPixelFormat; + memcpy(copy->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)); copy.depthPixelFormat = self.depthPixelFormat; copy.stencilPixelFormat = self.stencilPixelFormat; return copy; @@ -501,10 +515,12 @@ - (nonnull id)copyWithZone:(nullable NSZone*)zone - (NSUInteger)hash { NSUInteger sc = _sampleCount & 0x3; - NSUInteger cf = _colorPixelFormat & 0x3FF; + NSUInteger cf = _colorPixelFormats[0] & 0x3FF; NSUInteger df = _depthPixelFormat & 0x3FF; NSUInteger sf = _stencilPixelFormat & 0x3FF; NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc; + for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) + hash = hash * 31 + _colorPixelFormats[n]; return hash; } @@ -514,7 +530,7 @@ - (BOOL)isEqual:(id)object if (![other isKindOfClass:[FramebufferDescriptor class]]) return NO; return other.sampleCount == self.sampleCount && - other.colorPixelFormat == self.colorPixelFormat && + memcmp(other->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)) == 0 && other.depthPixelFormat == self.depthPixelFormat && other.stencilPixelFormat == self.stencilPixelFormat; } @@ -584,7 +600,7 @@ - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(idFlags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. +// Bilinear sampling is required. - (id)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id)device { NSError* error = nil; @@ -660,7 +676,7 @@ - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)buffer; @end +#define IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS 8 // Metal's limit (see Metal Feature Set Tables). Not configurable. + // An object that encapsulates the data necessary to uniquely identify a // render pipeline state. These are used as cache keys. @interface FramebufferDescriptor : NSObject @property (nonatomic, assign) unsigned long sampleCount; -@property (nonatomic, assign) MTLPixelFormat colorPixelFormat; @property (nonatomic, assign) MTLPixelFormat depthPixelFormat; @property (nonatomic, assign) MTLPixelFormat stencilPixelFormat; - (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor; +- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index; @end @interface MetalTexture : NSObject @@ -162,8 +166,8 @@ static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, idDisplaySize.x * draw_data->FramebufferScale.x), - .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y), + .width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f), + .height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f), .znear = 0.0, .zfar = 1.0 }; @@ -203,8 +207,8 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, idSharedMetalContext; // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; @@ -513,23 +517,33 @@ - (instancetype)initWithBuffer:(id)buffer #pragma mark - FramebufferDescriptor implementation @implementation FramebufferDescriptor +{ + MTLPixelFormat _colorPixelFormats[IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS]; +} + - (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor { if ((self = [super init])) { _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; - _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; + for (NSUInteger n = 0; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) + _colorPixelFormats[n] = renderPassDescriptor.colorAttachments[n].texture.pixelFormat; _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat; _stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat; } return self; } +- (MTLPixelFormat)colorPixelFormatAtIndex:(NSUInteger)index +{ + return _colorPixelFormats[index]; +} + - (nonnull id)copyWithZone:(nullable NSZone*)zone { FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init]; copy.sampleCount = self.sampleCount; - copy.colorPixelFormat = self.colorPixelFormat; + memcpy(copy->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)); copy.depthPixelFormat = self.depthPixelFormat; copy.stencilPixelFormat = self.stencilPixelFormat; return copy; @@ -538,10 +552,12 @@ - (nonnull id)copyWithZone:(nullable NSZone*)zone - (NSUInteger)hash { NSUInteger sc = _sampleCount & 0x3; - NSUInteger cf = _colorPixelFormat & 0x3FF; + NSUInteger cf = _colorPixelFormats[0] & 0x3FF; NSUInteger df = _depthPixelFormat & 0x3FF; NSUInteger sf = _stencilPixelFormat & 0x3FF; NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc; + for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) + hash = hash * 31 + _colorPixelFormats[n]; return hash; } @@ -551,7 +567,7 @@ - (BOOL)isEqual:(id)object if (![other isKindOfClass:[FramebufferDescriptor class]]) return NO; return other.sampleCount == self.sampleCount && - other.colorPixelFormat == self.colorPixelFormat && + memcmp(other->_colorPixelFormats, _colorPixelFormats, sizeof(_colorPixelFormats)) == 0 && other.depthPixelFormat == self.depthPixelFormat && other.stencilPixelFormat == self.stencilPixelFormat; } @@ -718,7 +734,7 @@ fragment half4 fragment_main(VertexOut in [[stage_in]], pipelineDescriptor.fragmentFunction = fragmentFunction; pipelineDescriptor.vertexDescriptor = vertexDescriptor; pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount; - pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat; + pipelineDescriptor.colorAttachments[0].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:0]; pipelineDescriptor.colorAttachments[0].blendingEnabled = YES; pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; @@ -726,6 +742,11 @@ fragment half4 fragment_main(VertexOut in [[stage_in]], pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + for (NSUInteger n = 1; n < IMGUI_IMPL_METAL_MAX_COLOR_ATTACHMENTS; n++) // Don't write to other color attachments, if any. + { + pipelineDescriptor.colorAttachments[n].pixelFormat = [self.framebufferDescriptor colorPixelFormatAtIndex:n]; + pipelineDescriptor.colorAttachments[n].writeMask = MTLColorWriteMaskNone; + } pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat; pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; diff --git a/include/imgui/backends/imgui_impl_opengl2.cpp b/include/imgui/backends/imgui_impl_opengl2.cpp index 111f374..88eed8c 100644 --- a/include/imgui/backends/imgui_impl_opengl2.cpp +++ b/include/imgui/backends/imgui_impl_opengl2.cpp @@ -26,6 +26,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378) +// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473) // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) @@ -131,6 +133,8 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glShadeModel(GL_SMOOTH); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + bd->UseTexParameterToSetSampler = false; bd->NextSampler = GL_LINEAR; // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), @@ -157,9 +161,13 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid } // Draw callbacks -static void ImGui_ImplOpenGL2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. -static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } -static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } +// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture!! +// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups. +// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything, which is the initial state. +static void ImGui_ImplOpenGL2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } +static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } +static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = false; } // OpenGL2 Render function. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. @@ -168,8 +176,8 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width == 0 || fb_height == 0) return; @@ -276,8 +284,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) const void* pixels = tex->GetPixels(); GLuint gl_texture_id = 0; - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Upload texture to graphics system (bilinear sampling is required). GLint last_texture; GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); GL_CALL(glGenTextures(1, &gl_texture_id)); @@ -360,6 +367,7 @@ bool ImGui_ImplOpenGL2_Init() platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex; return true; } diff --git a/include/imgui/backends/imgui_impl_opengl3.cpp b/include/imgui/backends/imgui_impl_opengl3.cpp index ff99800..d9cf487 100644 --- a/include/imgui/backends/imgui_impl_opengl3.cpp +++ b/include/imgui/backends/imgui_impl_opengl3.cpp @@ -7,6 +7,7 @@ // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState(). // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. @@ -23,6 +24,11 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-10-01: OpenGL: Added ImGui_ImplOpenGL3_SetClipOrigin() to specify clip origins (GL_LOWER_LEFT/GL_UPPER_LEFT, or use 0 to autodetect). (#2186, #3998, #3146, #3143, #8640) +// (Breaking): we now default to GL_LOWER_LEFT instead of 0=autodetect. Because 1) detection is not reliable and 2) is slow. +// 2026-10-01: OpenGL: Avoid querying glGetIntegerv(GL_CLIP_ORIGIN) multiple times when using DrawCallback_ResetRenderState. (#2186, #3998, #3146, #3143, #8640) +// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378) +// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473) // 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering. // 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577) @@ -186,6 +192,10 @@ #define IMGUI_IMPL_OPENGL_LOADER_IMGL3W #include "imgui_impl_opengl3_loader.h" #endif +#ifndef GL_LOWER_LEFT +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#endif // Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension #ifndef IMGUI_IMPL_OPENGL_ES2 @@ -256,6 +266,8 @@ struct ImGui_ImplOpenGL3_Data bool HasPolygonMode; bool HasBindSampler; bool HasClipOrigin; + GLenum ClipOriginRequest; // Default = GL_LOWER_LEFT. Change using ImGui_ImplOpenGL3_SetClipOrigin(). + GLenum ClipOriginCurrent; bool UseBufferSubData; #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER GLuint TexSamplers[2]; // Used if HasBindSimpler. (0=linear, 1=nearest) @@ -273,6 +285,11 @@ static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() +{ + return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only) #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY struct ImGui_ImplOpenGL3_VtxAttribState @@ -353,17 +370,6 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif - // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) -#if defined(GL_CLIP_ORIGIN) - bool clip_origin_lower_left = true; - if (bd->HasClipOrigin) - { - GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); - if (current_clip_origin == GL_UPPER_LEFT) - clip_origin_lower_left = false; - } -#endif - // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); @@ -371,9 +377,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; -#if defined(GL_CLIP_ORIGIN) - if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left -#endif + if (bd->ClipOriginCurrent == GL_UPPER_LEFT) { float tmp = T; T = B; B = tmp; } // Swap top and bottom const float ortho_projection[4][4] = { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, @@ -385,8 +389,12 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl glUniform1i(bd->AttribLocationTex, 0); glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); + render_state->UseBindSampler = bd->HasBindSampler; + render_state->UseTexParameterFilter = false; + render_state->CurrentSampler = 0; + render_state->CurrentTexParameterFilter = 0; #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER - if (render_state->UseBindSampler) + if (bd->HasBindSampler && render_state->UseBindSampler) { render_state->CurrentSampler = bd->TexSamplers[0]; glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. @@ -409,16 +417,15 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col))); } -// Draw callbacks -static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) +static void ImGui_ImplOpenGL3_DrawCallback_SetSampler(unsigned int sampler_idx, unsigned int tex_parameter_filter) { ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); + IM_UNUSED(sampler_idx); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); - if (bd->HasBindSampler) + if (bd->HasBindSampler && render_state->UseBindSampler) { - render_state->CurrentSampler = bd->TexSamplers[0]; + render_state->CurrentSampler = bd->TexSamplers[sampler_idx]; render_state->UseTexParameterFilter = false; glBindSampler(0, render_state->CurrentSampler); } @@ -426,26 +433,38 @@ static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, c #endif { render_state->UseTexParameterFilter = true; - render_state->CurrentTexParameterFilter = GL_LINEAR; + render_state->CurrentTexParameterFilter = tex_parameter_filter; } } -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) + +// Draw callbacks +// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture if used on a GL context not supporting glBindSampler()!! +// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups. +// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything. +static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(0, GL_LINEAR); } +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(1, GL_NEAREST); } +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { - render_state->CurrentSampler = bd->TexSamplers[1]; - render_state->UseTexParameterFilter = false; - glBindSampler(0, render_state->CurrentSampler); + render_state->CurrentSampler = 0; + glBindSampler(0, 0); } - else #endif - { - render_state->UseTexParameterFilter = true; - render_state->CurrentTexParameterFilter = GL_NEAREST; - } + render_state->UseBindSampler = false; + render_state->UseTexParameterFilter = false; +} + +// Default is GL_LOWER_LEFT since 2026/10/01. Used to be auto. +void ImGui_ImplOpenGL3_SetClipOrigin(unsigned int clip_origin) +{ + IM_ASSERT(clip_origin == 0 || clip_origin == GL_UPPER_LEFT || clip_origin == GL_LOWER_LEFT); + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + bd->ClipOriginRequest = clip_origin; } // OpenGL3 Render function. @@ -454,8 +473,8 @@ static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; @@ -509,6 +528,17 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) GLboolean last_enable_primitive_restart = (!bd->GlProfileIsES3 && bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE; #endif + // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) + bd->ClipOriginCurrent = bd->ClipOriginRequest; + if (bd->ClipOriginCurrent == 0) + { + bd->ClipOriginCurrent = GL_LOWER_LEFT; +#ifdef GL_CLIP_ORIGIN + if (bd->HasClipOrigin) + glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&bd->ClipOriginCurrent); +#endif + } + // Setup desired GL state // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. @@ -519,11 +549,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // Setup render state structure (for callbacks and custom texture bindings) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplOpenGL3_RenderState render_state; - render_state.UseBindSampler = bd->HasBindSampler; - render_state.UseTexParameterFilter = false; - render_state.CurrentSampler = 0; - render_state.CurrentTexParameterFilter = 0; + ImGui_ImplOpenGL3_RenderState render_state = {}; platform_io.Renderer_RenderState = &render_state; ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object); @@ -689,8 +715,7 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) const void* pixels = tex->GetPixels(); GLuint gl_texture_id = 0; - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Upload texture to graphics system (bilinear sampling is required). GLint last_texture; GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); GL_CALL(glGenTextures(1, &gl_texture_id)); @@ -1094,6 +1119,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL3_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex; // Store GLSL version string so we can refer to it later in case we recreate shaders. // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure. @@ -1139,6 +1165,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) bd->HasClipOrigin = true; } #endif + bd->ClipOriginCurrent = bd->ClipOriginRequest = GL_LOWER_LEFT; return true; } diff --git a/include/imgui/backends/imgui_impl_opengl3.h b/include/imgui/backends/imgui_impl_opengl3.h index a938042..17a49cd 100644 --- a/include/imgui/backends/imgui_impl_opengl3.h +++ b/include/imgui/backends/imgui_impl_opengl3.h @@ -7,6 +7,7 @@ // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState(). // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. @@ -43,6 +44,9 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); // (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); +// (Advanced) Specify clip origin, same value as glClipControl() or 0 for auto-detection. +IMGUI_IMPL_API void ImGui_ImplOpenGL3_SetClipOrigin(unsigned int gl_clip_origin); + // Configuration flags to add in your imconfig file: //#define IMGUI_IMPL_OPENGL_ES2 // Enable ES 2 (Auto-detected on Emscripten) //#define IMGUI_IMPL_OPENGL_ES3 // Enable ES 3 (Auto-detected on iOS/Android) @@ -72,10 +76,9 @@ struct ImGui_ImplOpenGL3_RenderState { bool UseBindSampler; bool UseTexParameterFilter; - unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true, otherwise always 0 - unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterToSetSampler == true + unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true (and are available), otherwise always 0 + unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterFilter == true }; - -static inline ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() { return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_opengl3_loader.h b/include/imgui/backends/imgui_impl_opengl3_loader.h index 2c48584..47f9fb3 100644 --- a/include/imgui/backends/imgui_impl_opengl3_loader.h +++ b/include/imgui/backends/imgui_impl_opengl3_loader.h @@ -114,7 +114,7 @@ extern "C" { #define GLAPI extern #endif /* glcorearb.h is for use with OpenGL core profile implementations. -** It should should be placed in the same directory as gl.h and +** It should be placed in the same directory as gl.h and ** included as . ** ** glcorearb.h includes only APIs in the latest OpenGL core profile @@ -303,6 +303,7 @@ typedef khronos_uint16_t GLushort; #define GL_LINK_STATUS 0x8B82 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_CURRENT_PROGRAM 0x8B8D +#define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); diff --git a/include/imgui/backends/imgui_impl_qnx.cpp b/include/imgui/backends/imgui_impl_qnx.cpp new file mode 100644 index 0000000..3730f54 --- /dev/null +++ b/include/imgui/backends/imgui_impl_qnx.cpp @@ -0,0 +1,759 @@ +// dear imgui: Platform Backend for QNX Screen +// This needs to be used along with a Renderer Backend (e.g. OpenGL3, Vulkan). + +// Implemented features: +// [X] Platform: Keyboard support. Uses io.AddKeyEvent() and native QNX key symbols. +// [X] Platform: Mouse support. Handles position, three buttons and horizontal/vertical wheels. +// [X] Platform: Touch support. Maps the first active touch contact to the primary mouse button. +// [X] Platform: Focus and window-size updates. +// Missing features or Issues: +// [ ] Platform: Clipboard support. +// [ ] Platform: Gamepad support. +// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). +// [ ] Platform: Multi-viewport support. + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2026-08-04: Initial QNX Screen backend. (#9492) + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_qnx.h" + +#include +#include +#include +#include +#include + +static unsigned int ImGui_ImplQNX_KeySymToUnicode(unsigned int keysym); + +struct ImGui_ImplQNX_Data +{ + screen_context_t Context; + screen_window_t Window; + uint64_t TimeNanoseconds; + int MouseButtons; + int ActiveTouchId; + bool LeftSuper; + bool RightSuper; + + ImGui_ImplQNX_Data() + { + memset(this, 0, sizeof(*this)); + ActiveTouchId = -1; + } +}; + +static ImGui_ImplQNX_Data* ImGui_ImplQNX_GetBackendData() +{ + return ImGui::GetCurrentContext() != nullptr ? (ImGui_ImplQNX_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; +} + +static uint64_t ImGui_ImplQNX_GetTimeNanoseconds() +{ + struct timespec timestamp = {}; + if (clock_gettime(CLOCK_MONOTONIC, ×tamp) != 0) + { + return 0; + } + return (uint64_t)timestamp.tv_sec * UINT64_C(1000000000) + (uint64_t)timestamp.tv_nsec; +} + +static ImGuiKey ImGui_ImplQNX_KeyCodeToImGuiKey(int key_code) +{ + switch (key_code) + { + case KEYCODE_TAB: return ImGuiKey_Tab; + case KEYCODE_LEFT: return ImGuiKey_LeftArrow; + case KEYCODE_RIGHT: return ImGuiKey_RightArrow; + case KEYCODE_UP: return ImGuiKey_UpArrow; + case KEYCODE_DOWN: return ImGuiKey_DownArrow; + case KEYCODE_PG_UP: return ImGuiKey_PageUp; + case KEYCODE_PG_DOWN: return ImGuiKey_PageDown; + case KEYCODE_HOME: return ImGuiKey_Home; + case KEYCODE_END: return ImGuiKey_End; + case KEYCODE_INSERT: return ImGuiKey_Insert; + case KEYCODE_DELETE: return ImGuiKey_Delete; + case KEYCODE_BACKSPACE: return ImGuiKey_Backspace; + case KEYCODE_SPACE: return ImGuiKey_Space; + case KEYCODE_RETURN: return ImGuiKey_Enter; + case KEYCODE_ESCAPE: return ImGuiKey_Escape; + case KEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; + case KEYCODE_COMMA: return ImGuiKey_Comma; + case KEYCODE_MINUS: return ImGuiKey_Minus; + case KEYCODE_PERIOD: return ImGuiKey_Period; + case KEYCODE_SLASH: return ImGuiKey_Slash; + case KEYCODE_SEMICOLON: return ImGuiKey_Semicolon; + case KEYCODE_EQUAL: return ImGuiKey_Equal; + case KEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case KEYCODE_BACK_SLASH: return ImGuiKey_Backslash; + case KEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case KEYCODE_GRAVE: return ImGuiKey_GraveAccent; + case KEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; + case KEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case KEYCODE_NUM_LOCK: return ImGuiKey_NumLock; + case KEYCODE_PRINT: return ImGuiKey_PrintScreen; + case KEYCODE_PAUSE: return ImGuiKey_Pause; + case KEYCODE_KP_DIVIDE: return ImGuiKey_KeypadDivide; + case KEYCODE_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; + case KEYCODE_KP_MINUS: return ImGuiKey_KeypadSubtract; + case KEYCODE_KP_PLUS: return ImGuiKey_KeypadAdd; + case KEYCODE_KP_ENTER: return ImGuiKey_KeypadEnter; + // QNX reports keypad digits by their navigation key-cap names. + case KEYCODE_KP_INSERT: return ImGuiKey_Keypad0; + case KEYCODE_KP_END: return ImGuiKey_Keypad1; + case KEYCODE_KP_DOWN: return ImGuiKey_Keypad2; + case KEYCODE_KP_PG_DOWN: return ImGuiKey_Keypad3; + case KEYCODE_KP_LEFT: return ImGuiKey_Keypad4; + case KEYCODE_KP_FIVE: return ImGuiKey_Keypad5; + case KEYCODE_KP_RIGHT: return ImGuiKey_Keypad6; + case KEYCODE_KP_HOME: return ImGuiKey_Keypad7; + case KEYCODE_KP_UP: return ImGuiKey_Keypad8; + case KEYCODE_KP_PG_UP: return ImGuiKey_Keypad9; + case KEYCODE_KP_DELETE: return ImGuiKey_KeypadDecimal; + case KEYCODE_LEFT_CTRL: return ImGuiKey_LeftCtrl; + case KEYCODE_LEFT_SHIFT: return ImGuiKey_LeftShift; + case KEYCODE_LEFT_ALT: return ImGuiKey_LeftAlt; + case KEYCODE_RIGHT_CTRL: return ImGuiKey_RightCtrl; + case KEYCODE_RIGHT_SHIFT: return ImGuiKey_RightShift; + case KEYCODE_RIGHT_ALT: return ImGuiKey_RightAlt; + case KEYCODE_LEFT_HYPER: return ImGuiKey_LeftSuper; + case KEYCODE_RIGHT_HYPER: return ImGuiKey_RightSuper; + case KEYCODE_MENU: return ImGuiKey_Menu; + case KEYCODE_ZERO: return ImGuiKey_0; + case KEYCODE_ONE: return ImGuiKey_1; + case KEYCODE_TWO: return ImGuiKey_2; + case KEYCODE_THREE: return ImGuiKey_3; + case KEYCODE_FOUR: return ImGuiKey_4; + case KEYCODE_FIVE: return ImGuiKey_5; + case KEYCODE_SIX: return ImGuiKey_6; + case KEYCODE_SEVEN: return ImGuiKey_7; + case KEYCODE_EIGHT: return ImGuiKey_8; + case KEYCODE_NINE: return ImGuiKey_9; + case KEYCODE_A: return ImGuiKey_A; + case KEYCODE_B: return ImGuiKey_B; + case KEYCODE_C: return ImGuiKey_C; + case KEYCODE_D: return ImGuiKey_D; + case KEYCODE_E: return ImGuiKey_E; + case KEYCODE_F: return ImGuiKey_F; + case KEYCODE_G: return ImGuiKey_G; + case KEYCODE_H: return ImGuiKey_H; + case KEYCODE_I: return ImGuiKey_I; + case KEYCODE_J: return ImGuiKey_J; + case KEYCODE_K: return ImGuiKey_K; + case KEYCODE_L: return ImGuiKey_L; + case KEYCODE_M: return ImGuiKey_M; + case KEYCODE_N: return ImGuiKey_N; + case KEYCODE_O: return ImGuiKey_O; + case KEYCODE_P: return ImGuiKey_P; + case KEYCODE_Q: return ImGuiKey_Q; + case KEYCODE_R: return ImGuiKey_R; + case KEYCODE_S: return ImGuiKey_S; + case KEYCODE_T: return ImGuiKey_T; + case KEYCODE_U: return ImGuiKey_U; + case KEYCODE_V: return ImGuiKey_V; + case KEYCODE_W: return ImGuiKey_W; + case KEYCODE_X: return ImGuiKey_X; + case KEYCODE_Y: return ImGuiKey_Y; + case KEYCODE_Z: return ImGuiKey_Z; + case KEYCODE_F1: return ImGuiKey_F1; + case KEYCODE_F2: return ImGuiKey_F2; + case KEYCODE_F3: return ImGuiKey_F3; + case KEYCODE_F4: return ImGuiKey_F4; + case KEYCODE_F5: return ImGuiKey_F5; + case KEYCODE_F6: return ImGuiKey_F6; + case KEYCODE_F7: return ImGuiKey_F7; + case KEYCODE_F8: return ImGuiKey_F8; + case KEYCODE_F9: return ImGuiKey_F9; + case KEYCODE_F10: return ImGuiKey_F10; + case KEYCODE_F11: return ImGuiKey_F11; + case KEYCODE_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} + +static void ImGui_ImplQNX_UpdateKeyModifiers(ImGuiIO& io, ImGui_ImplQNX_Data* bd, int modifiers, ImGuiKey key, bool down) +{ + // SCREEN_PROPERTY_MODIFIERS is the authoritative state for Shift/Ctrl/Alt. + // Tracking those keys locally loses sticky modifiers and can become stale if + // a key transition is consumed elsewhere. qterm uses this same Screen state. + if (key == ImGuiKey_LeftSuper) + { + bd->LeftSuper = down; + } + else if (key == ImGuiKey_RightSuper) + { + bd->RightSuper = down; + } + + io.AddKeyEvent(ImGuiMod_Ctrl, (modifiers & KEYMOD_CTRL) != 0); + io.AddKeyEvent(ImGuiMod_Shift, (modifiers & KEYMOD_SHIFT) != 0); + io.AddKeyEvent(ImGuiMod_Alt, (modifiers & KEYMOD_ALT) != 0); + io.AddKeyEvent(ImGuiMod_Super, bd->LeftSuper || bd->RightSuper); +} + +static void ImGui_ImplQNX_ClearModifierState(ImGuiIO& io, ImGui_ImplQNX_Data* bd) +{ + bd->LeftSuper = false; + bd->RightSuper = false; + io.AddKeyEvent(ImGuiMod_Ctrl, false); + io.AddKeyEvent(ImGuiMod_Shift, false); + io.AddKeyEvent(ImGuiMod_Alt, false); + io.AddKeyEvent(ImGuiMod_Super, false); +} + +static bool ImGui_ImplQNX_IsTextCodePoint(unsigned int code_point) +{ + // At this point the QNX keysym has already been converted to Unicode. + // Do not reject Unicode private-use characters: a user keymap may emit one. + const bool surrogate = code_point >= 0xd800u && code_point <= 0xdfffu; + const bool control = code_point < 0x20u || (code_point >= 0x7fu && code_point <= 0x9fu); + return code_point <= IM_UNICODE_CODEPOINT_MAX && !surrogate && !control; +} + +static bool ImGui_ImplQNX_ProcessKeyboardEvent(ImGui_ImplQNX_Data* bd, screen_event_t event) +{ + int flags = 0; + int modifiers = 0; + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags) != 0 || + screen_get_event_property_iv(event, SCREEN_PROPERTY_MODIFIERS, &modifiers) != 0) + { + return false; + } + + // KEY_CAP is the unmodified key identity used for ImGuiKey events. SYM is + // the layout/modifier-translated QNX keysym used for text input. + int key_cap = 0; + int key_sym = 0; + int scan_code = 0; + const bool cap_valid = (flags & SCREEN_FLAG_CAP_VALID) != 0; + const bool sym_valid = (flags & SCREEN_FLAG_SYM_VALID) != 0; + const bool scan_valid = (flags & SCREEN_FLAG_SCAN_VALID) != 0; + const bool down = (flags & (SCREEN_FLAG_KEY_DOWN | SCREEN_FLAG_KEY_REPEAT)) != 0; + + if (cap_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &key_cap) != 0) + { + return false; + } + if (sym_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &key_sym) != 0) + { + return false; + } + if (scan_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_SCAN, &scan_code) != 0) + { + scan_code = 0; + } + + const ImGuiKey key = cap_valid ? ImGui_ImplQNX_KeyCodeToImGuiKey(key_cap) : ImGuiKey_None; + ImGuiIO& io = ImGui::GetIO(); + + // Modifier events must precede the ordinary key event in Dear ImGui's queue. + // Unlike qterm, we still submit the individual modifier key because ImGui + // exposes Left/Right Ctrl, Shift, Alt and Super as named keys. + ImGui_ImplQNX_UpdateKeyModifiers(io, bd, modifiers, key, down); + + if (key != ImGuiKey_None) + { + io.AddKeyEvent(key, down); + io.SetKeyEventNativeData(key, key_cap, scan_code); + } + + bool text_added = false; + if (down && sym_valid && key_sym >= 0) + { + const unsigned int keysym = (unsigned int)key_sym; + // QNX special/function symbols begin at KEYCODE_PC_KEYS. Printable + // symbols below that boundary use X11 keysym encoding. Also accept the + // standard directly encoded UCS keysym form (0x01000000 | codepoint). + if (keysym < (unsigned int)KEYCODE_PC_KEYS || (keysym & 0xff000000u) == 0x01000000u) + { + const unsigned int code_point = ImGui_ImplQNX_KeySymToUnicode(keysym); + if (ImGui_ImplQNX_IsTextCodePoint(code_point)) + { + io.AddInputCharacter(code_point); + text_added = true; + } + } + } + + return key != ImGuiKey_None || text_added || cap_valid || sym_valid; +} + +static bool ImGui_ImplQNX_ProcessPointerEvent(ImGui_ImplQNX_Data* bd, screen_event_t event) +{ + int position[2] = {}; + int buttons = 0; + int wheel_vertical = 0; + int wheel_horizontal = 0; + + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, position) != 0 && + screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, position) != 0) + { + return false; + } + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttons) != 0) + { + buttons = bd->MouseButtons; + } + + ImGuiIO& io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMousePosEvent((float)position[0], (float)position[1]); + + const int changed_buttons = buttons ^ bd->MouseButtons; + if ((changed_buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0) + { + io.AddMouseButtonEvent(0, (buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0); + } + if ((changed_buttons & SCREEN_RIGHT_MOUSE_BUTTON) != 0) + { + io.AddMouseButtonEvent(1, (buttons & SCREEN_RIGHT_MOUSE_BUTTON) != 0); + } + if ((changed_buttons & SCREEN_MIDDLE_MOUSE_BUTTON) != 0) + { + io.AddMouseButtonEvent(2, (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) != 0); + } + bd->MouseButtons = buttons; + + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel_vertical) != 0) + { + wheel_vertical = 0; + } + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL, &wheel_horizontal) != 0) + { + wheel_horizontal = 0; + } + if (wheel_vertical != 0 || wheel_horizontal != 0) + { + // Screen: up/left are negative. Dear ImGui: up/left are positive. + io.AddMouseWheelEvent((float)-wheel_horizontal, (float)-wheel_vertical); + } + return true; +} + +static bool ImGui_ImplQNX_ProcessTouchEvent(ImGui_ImplQNX_Data* bd, screen_event_t event, int event_type) +{ + int touch_id = -1; + int position[2] = {}; + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touch_id) != 0) + { + return false; + } + + const bool is_release = event_type == SCREEN_EVENT_MTOUCH_RELEASE; + if (bd->ActiveTouchId != -1 && touch_id != bd->ActiveTouchId) + { + return false; + } + + ImGuiIO& io = ImGui::GetIO(); + io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); + + if (!is_release) + { + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, position) != 0 && + screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, position) != 0) + { + return false; + } + io.AddMousePosEvent((float)position[0], (float)position[1]); + } + + if (event_type == SCREEN_EVENT_MTOUCH_TOUCH) + { + bd->ActiveTouchId = touch_id; + io.AddMouseButtonEvent(0, true); + } + else if (is_release) + { + io.AddMouseButtonEvent(0, false); + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + bd->ActiveTouchId = -1; + } + return true; +} + +bool ImGui_ImplQNX_ProcessEvent(screen_event_t event) +{ + ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplQNX_Init()?"); + if (bd == nullptr || event == nullptr) + { + return false; + } + + int event_type = SCREEN_EVENT_NONE; + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &event_type) != 0 || event_type == SCREEN_EVENT_NONE) + { + return false; + } + switch (event_type) + { + case SCREEN_EVENT_KEYBOARD: + return ImGui_ImplQNX_ProcessKeyboardEvent(bd, event); + case SCREEN_EVENT_POINTER: + return ImGui_ImplQNX_ProcessPointerEvent(bd, event); + case SCREEN_EVENT_MTOUCH_TOUCH: + case SCREEN_EVENT_MTOUCH_MOVE: + case SCREEN_EVENT_MTOUCH_RELEASE: + return ImGui_ImplQNX_ProcessTouchEvent(bd, event, event_type); + case SCREEN_EVENT_PROPERTY: + { + int property = 0; + if (screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0) + { + return false; + } + if (property == SCREEN_PROPERTY_FOCUS) + { + int focused = 0; + if (screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_FOCUS, &focused) == 0) + { + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(focused != 0); + if (focused == 0) + { + ImGui_ImplQNX_ClearModifierState(io, bd); + } + } + return true; + } + if (property == SCREEN_PROPERTY_SIZE || property == SCREEN_PROPERTY_BUFFER_SIZE || property == SCREEN_PROPERTY_VISIBLE) + { + return true; + } + return false; + } + case SCREEN_EVENT_CLOSE: + { + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(false); + ImGui_ImplQNX_ClearModifierState(io, bd); + return true; + } + default: + return false; + } +} + +bool ImGui_ImplQNX_Init(screen_context_t context, screen_window_t window) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); + IM_ASSERT(context != nullptr && window != nullptr); + if (context == nullptr || window == nullptr) + { + return false; + } + + ImGui_ImplQNX_Data* bd = IM_NEW(ImGui_ImplQNX_Data)(); + io.BackendPlatformUserData = (void*)bd; + io.BackendPlatformName = "imgui_impl_qnx"; + + bd->Context = context; + bd->Window = window; + bd->TimeNanoseconds = ImGui_ImplQNX_GetTimeNanoseconds(); + + int focused = 0; + if (screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focused) == 0) + { + io.AddFocusEvent(focused != 0); + } + return true; +} + +void ImGui_ImplQNX_Shutdown() +{ + ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData(); + IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + if (bd == nullptr) + { + return; + } + + ImGuiIO& io = ImGui::GetIO(); + io.BackendPlatformName = nullptr; + io.BackendPlatformUserData = nullptr; + IM_DELETE(bd); +} + +void ImGui_ImplQNX_NewFrame() +{ + ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplQNX_Init()?"); + if (bd == nullptr) + { + return; + } + + ImGuiIO& io = ImGui::GetIO(); + int size[2] = {}; + if (screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_BUFFER_SIZE, size) != 0 || + size[0] <= 0 || size[1] <= 0) + { + size[0] = 0; + size[1] = 0; + (void)screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_SIZE, size); + } + if (size[0] > 0 && size[1] > 0) + { + io.DisplaySize = ImVec2((float)size[0], (float)size[1]); + io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + } + + const uint64_t current_time = ImGui_ImplQNX_GetTimeNanoseconds(); + if (current_time > bd->TimeNanoseconds && bd->TimeNanoseconds != 0) + { + io.DeltaTime = (float)((double)(current_time - bd->TimeNanoseconds) / 1000000000.0); + } + else + { + io.DeltaTime = 1.0f / 60.0f; + } + bd->TimeNanoseconds = current_time; +} + +// Generated by Markus Kuhn's public-domain unicode/convmap.pl from X11 keysymdef.h and UnicodeData. +// Original source: https://www.cl.cam.ac.uk/~mgk25/ucs/keysym2ucs.c +// The table must remain sorted by keysym for the binary search below. +struct ImGui_ImplQNX_KeySymPair +{ + uint16_t KeySym; + uint16_t Unicode; +}; + +static const ImGui_ImplQNX_KeySymPair ImGui_ImplQNX_KeySymTable[] = +{ + { 0x01a1, 0x0104 }, { 0x01a2, 0x02d8 }, { 0x01a3, 0x0141 }, { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, { 0x01a9, 0x0160 }, { 0x01aa, 0x015e }, { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, { 0x01ae, 0x017d }, { 0x01af, 0x017b }, { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, { 0x01b3, 0x0142 }, { 0x01b5, 0x013e }, { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, { 0x01b9, 0x0161 }, { 0x01ba, 0x015f }, { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, { 0x01bd, 0x02dd }, { 0x01be, 0x017e }, { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, { 0x01c3, 0x0102 }, { 0x01c5, 0x0139 }, { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, { 0x01ca, 0x0118 }, { 0x01cc, 0x011a }, { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, { 0x01d1, 0x0143 }, { 0x01d2, 0x0147 }, { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, { 0x01d9, 0x016e }, { 0x01db, 0x0170 }, { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, { 0x01e3, 0x0103 }, { 0x01e5, 0x013a }, { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, { 0x01ea, 0x0119 }, { 0x01ec, 0x011b }, { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, { 0x01f1, 0x0144 }, { 0x01f2, 0x0148 }, { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, { 0x01f9, 0x016f }, { 0x01fb, 0x0171 }, { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, { 0x02a1, 0x0126 }, { 0x02a6, 0x0124 }, { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, { 0x02ac, 0x0134 }, { 0x02b1, 0x0127 }, { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, { 0x02bb, 0x011f }, { 0x02bc, 0x0135 }, { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, { 0x02d5, 0x0120 }, { 0x02d8, 0x011c }, { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, { 0x02e5, 0x010b }, { 0x02e6, 0x0109 }, { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, { 0x02fd, 0x016d }, { 0x02fe, 0x015d }, { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, { 0x03a5, 0x0128 }, { 0x03a6, 0x013b }, { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, { 0x03ac, 0x0166 }, { 0x03b3, 0x0157 }, { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, { 0x03ba, 0x0113 }, { 0x03bb, 0x0123 }, { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, { 0x03bf, 0x014b }, { 0x03c0, 0x0100 }, { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, { 0x03cf, 0x012a }, { 0x03d1, 0x0145 }, { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, { 0x03d9, 0x0172 }, { 0x03dd, 0x0168 }, { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, { 0x03e7, 0x012f }, { 0x03ec, 0x0117 }, { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, { 0x03f2, 0x014d }, { 0x03f3, 0x0137 }, { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, { 0x03fe, 0x016b }, { 0x047e, 0x203e }, { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, { 0x04a3, 0x300d }, { 0x04a4, 0x3001 }, { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, { 0x04a7, 0x30a1 }, { 0x04a8, 0x30a3 }, { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, { 0x04ab, 0x30a9 }, { 0x04ac, 0x30e3 }, { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, { 0x04af, 0x30c3 }, { 0x04b0, 0x30fc }, { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, { 0x04b3, 0x30a6 }, { 0x04b4, 0x30a8 }, { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, { 0x04b7, 0x30ad }, { 0x04b8, 0x30af }, { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, { 0x04bb, 0x30b5 }, { 0x04bc, 0x30b7 }, { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, { 0x04bf, 0x30bd }, { 0x04c0, 0x30bf }, { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, { 0x04c3, 0x30c6 }, { 0x04c4, 0x30c8 }, { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, { 0x04c7, 0x30cc }, { 0x04c8, 0x30cd }, { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, { 0x04cb, 0x30d2 }, { 0x04cc, 0x30d5 }, { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, { 0x04cf, 0x30de }, { 0x04d0, 0x30df }, { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, { 0x04d3, 0x30e2 }, { 0x04d4, 0x30e4 }, { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, { 0x04d7, 0x30e9 }, { 0x04d8, 0x30ea }, { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, { 0x04db, 0x30ed }, { 0x04dc, 0x30ef }, { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, { 0x04df, 0x309c }, { 0x05ac, 0x060c }, { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, { 0x05c1, 0x0621 }, { 0x05c2, 0x0622 }, { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, { 0x05c5, 0x0625 }, { 0x05c6, 0x0626 }, { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, { 0x05c9, 0x0629 }, { 0x05ca, 0x062a }, { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, { 0x05cd, 0x062d }, { 0x05ce, 0x062e }, { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, { 0x05d1, 0x0631 }, { 0x05d2, 0x0632 }, { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, { 0x05d5, 0x0635 }, { 0x05d6, 0x0636 }, { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, { 0x05d9, 0x0639 }, { 0x05da, 0x063a }, { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, { 0x05e2, 0x0642 }, { 0x05e3, 0x0643 }, { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, { 0x05e6, 0x0646 }, { 0x05e7, 0x0647 }, { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, { 0x05ea, 0x064a }, { 0x05eb, 0x064b }, { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, { 0x05ee, 0x064e }, { 0x05ef, 0x064f }, { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, { 0x05f2, 0x0652 }, { 0x06a1, 0x0452 }, { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, { 0x06a4, 0x0454 }, { 0x06a5, 0x0455 }, { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, { 0x06a8, 0x0458 }, { 0x06a9, 0x0459 }, { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, { 0x06ac, 0x045c }, { 0x06ae, 0x045e }, { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, { 0x06b1, 0x0402 }, { 0x06b2, 0x0403 }, { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, { 0x06b5, 0x0405 }, { 0x06b6, 0x0406 }, { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, { 0x06b9, 0x0409 }, { 0x06ba, 0x040a }, { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, { 0x06be, 0x040e }, { 0x06bf, 0x040f }, { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, { 0x06c2, 0x0431 }, { 0x06c3, 0x0446 }, { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, { 0x06c6, 0x0444 }, { 0x06c7, 0x0433 }, { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, { 0x06ca, 0x0439 }, { 0x06cb, 0x043a }, { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, { 0x06ce, 0x043d }, { 0x06cf, 0x043e }, { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, { 0x06d2, 0x0440 }, { 0x06d3, 0x0441 }, { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, { 0x06d6, 0x0436 }, { 0x06d7, 0x0432 }, { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, { 0x06da, 0x0437 }, { 0x06db, 0x0448 }, { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, { 0x06de, 0x0447 }, { 0x06df, 0x044a }, { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, { 0x06e2, 0x0411 }, { 0x06e3, 0x0426 }, { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, { 0x06e6, 0x0424 }, { 0x06e7, 0x0413 }, { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, { 0x06ea, 0x0419 }, { 0x06eb, 0x041a }, { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, { 0x06ee, 0x041d }, { 0x06ef, 0x041e }, { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, { 0x06f2, 0x0420 }, { 0x06f3, 0x0421 }, { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, { 0x06f6, 0x0416 }, { 0x06f7, 0x0412 }, { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, { 0x06fa, 0x0417 }, { 0x06fb, 0x0428 }, { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, { 0x06fe, 0x0427 }, { 0x06ff, 0x042a }, { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, { 0x07a3, 0x0389 }, { 0x07a4, 0x038a }, { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, { 0x07a8, 0x038e }, { 0x07a9, 0x03ab }, { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, { 0x07af, 0x2015 }, { 0x07b1, 0x03ac }, { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, { 0x07b4, 0x03af }, { 0x07b5, 0x03ca }, { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, { 0x07b8, 0x03cd }, { 0x07b9, 0x03cb }, { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, { 0x07c1, 0x0391 }, { 0x07c2, 0x0392 }, { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, { 0x07c5, 0x0395 }, { 0x07c6, 0x0396 }, { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, { 0x07c9, 0x0399 }, { 0x07ca, 0x039a }, { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, { 0x07cd, 0x039d }, { 0x07ce, 0x039e }, { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, { 0x07d1, 0x03a1 }, { 0x07d2, 0x03a3 }, { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, { 0x07d6, 0x03a6 }, { 0x07d7, 0x03a7 }, { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, { 0x07e1, 0x03b1 }, { 0x07e2, 0x03b2 }, { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, { 0x07e5, 0x03b5 }, { 0x07e6, 0x03b6 }, { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, { 0x07e9, 0x03b9 }, { 0x07ea, 0x03ba }, { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, { 0x07ed, 0x03bd }, { 0x07ee, 0x03be }, { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, { 0x07f1, 0x03c1 }, { 0x07f2, 0x03c3 }, { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, { 0x07f5, 0x03c5 }, { 0x07f6, 0x03c6 }, { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, { 0x07f9, 0x03c9 }, { 0x08a1, 0x23b7 }, { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, { 0x08a4, 0x2320 }, { 0x08a5, 0x2321 }, { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, { 0x08a8, 0x23a3 }, { 0x08a9, 0x23a4 }, { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, { 0x08ac, 0x239d }, { 0x08ad, 0x239e }, { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, { 0x08b0, 0x23ac }, { 0x08bc, 0x2264 }, { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, { 0x08bf, 0x222b }, { 0x08c0, 0x2234 }, { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, { 0x08c5, 0x2207 }, { 0x08c8, 0x223c }, { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, { 0x08ce, 0x21d2 }, { 0x08cf, 0x2261 }, { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, { 0x08db, 0x2283 }, { 0x08dc, 0x2229 }, { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, { 0x08df, 0x2228 }, { 0x08ef, 0x2202 }, { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, { 0x08fc, 0x2191 }, { 0x08fd, 0x2192 }, { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, { 0x09e1, 0x2592 }, { 0x09e2, 0x2409 }, { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, { 0x09e5, 0x240a }, { 0x09e8, 0x2424 }, { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, { 0x09eb, 0x2510 }, { 0x09ec, 0x250c }, { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, { 0x09ef, 0x23ba }, { 0x09f0, 0x23bb }, { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, { 0x09f3, 0x23bd }, { 0x09f4, 0x251c }, { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, { 0x09f7, 0x252c }, { 0x09f8, 0x2502 }, { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, { 0x0aa3, 0x2004 }, { 0x0aa4, 0x2005 }, { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, { 0x0aa7, 0x2009 }, { 0x0aa8, 0x200a }, { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, { 0x0aae, 0x2026 }, { 0x0aaf, 0x2025 }, { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, { 0x0ab2, 0x2155 }, { 0x0ab3, 0x2156 }, { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, { 0x0ab6, 0x2159 }, { 0x0ab7, 0x215a }, { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, { 0x0abc, 0x2329 }, { 0x0abe, 0x232a }, { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, { 0x0ac5, 0x215d }, { 0x0ac6, 0x215e }, { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, { 0x0acc, 0x25c1 }, { 0x0acd, 0x25b7 }, { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, { 0x0ad0, 0x2018 }, { 0x0ad1, 0x2019 }, { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, { 0x0ad4, 0x211e }, { 0x0ad6, 0x2032 }, { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, { 0x0adb, 0x25ac }, { 0x0adc, 0x25c0 }, { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, { 0x0adf, 0x25ae }, { 0x0ae0, 0x25e6 }, { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, { 0x0ae3, 0x25b3 }, { 0x0ae4, 0x25bd }, { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, { 0x0ae7, 0x25aa }, { 0x0ae8, 0x25b2 }, { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, { 0x0aeb, 0x261e }, { 0x0aec, 0x2663 }, { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, { 0x0af0, 0x2720 }, { 0x0af1, 0x2020 }, { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, { 0x0af4, 0x2717 }, { 0x0af5, 0x266f }, { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, { 0x0af8, 0x2640 }, { 0x0af9, 0x260e }, { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, { 0x0afc, 0x2038 }, { 0x0afd, 0x201a }, { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, { 0x0ba6, 0x003e }, { 0x0ba8, 0x2228 }, { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, { 0x0bc2, 0x22a5 }, { 0x0bc3, 0x2229 }, { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, { 0x0bca, 0x2218 }, { 0x0bcc, 0x2395 }, { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, { 0x0bd3, 0x2308 }, { 0x0bd6, 0x222a }, { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, { 0x0bdc, 0x22a2 }, { 0x0bfc, 0x22a3 }, { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, { 0x0ce1, 0x05d1 }, { 0x0ce2, 0x05d2 }, { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, { 0x0ce5, 0x05d5 }, { 0x0ce6, 0x05d6 }, { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, { 0x0ce9, 0x05d9 }, { 0x0cea, 0x05da }, { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, { 0x0ced, 0x05dd }, { 0x0cee, 0x05de }, { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, { 0x0cf1, 0x05e1 }, { 0x0cf2, 0x05e2 }, { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, { 0x0cf5, 0x05e5 }, { 0x0cf6, 0x05e6 }, { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, { 0x0cf9, 0x05e9 }, { 0x0cfa, 0x05ea }, { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, { 0x0da3, 0x0e03 }, { 0x0da4, 0x0e04 }, { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, { 0x0da7, 0x0e07 }, { 0x0da8, 0x0e08 }, { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, { 0x0dab, 0x0e0b }, { 0x0dac, 0x0e0c }, { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, { 0x0daf, 0x0e0f }, { 0x0db0, 0x0e10 }, { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, { 0x0db3, 0x0e13 }, { 0x0db4, 0x0e14 }, { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, { 0x0db7, 0x0e17 }, { 0x0db8, 0x0e18 }, { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, { 0x0dbb, 0x0e1b }, { 0x0dbc, 0x0e1c }, { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, { 0x0dbf, 0x0e1f }, { 0x0dc0, 0x0e20 }, { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, { 0x0dc3, 0x0e23 }, { 0x0dc4, 0x0e24 }, { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, { 0x0dc7, 0x0e27 }, { 0x0dc8, 0x0e28 }, { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, { 0x0dcb, 0x0e2b }, { 0x0dcc, 0x0e2c }, { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, { 0x0dcf, 0x0e2f }, { 0x0dd0, 0x0e30 }, { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, { 0x0dd3, 0x0e33 }, { 0x0dd4, 0x0e34 }, { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, { 0x0dd7, 0x0e37 }, { 0x0dd8, 0x0e38 }, { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, { 0x0ddf, 0x0e3f }, { 0x0de0, 0x0e40 }, { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, { 0x0de3, 0x0e43 }, { 0x0de4, 0x0e44 }, { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, { 0x0de7, 0x0e47 }, { 0x0de8, 0x0e48 }, { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, { 0x0deb, 0x0e4b }, { 0x0dec, 0x0e4c }, { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, { 0x0df1, 0x0e51 }, { 0x0df2, 0x0e52 }, { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, { 0x0df5, 0x0e55 }, { 0x0df6, 0x0e56 }, { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, { 0x0df9, 0x0e59 }, { 0x0ea1, 0x3131 }, { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, { 0x0ea4, 0x3134 }, { 0x0ea5, 0x3135 }, { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, { 0x0ea8, 0x3138 }, { 0x0ea9, 0x3139 }, { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, { 0x0eac, 0x313c }, { 0x0ead, 0x313d }, { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, { 0x0eb0, 0x3140 }, { 0x0eb1, 0x3141 }, { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, { 0x0eb4, 0x3144 }, { 0x0eb5, 0x3145 }, { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, { 0x0eb8, 0x3148 }, { 0x0eb9, 0x3149 }, { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, { 0x0ebc, 0x314c }, { 0x0ebd, 0x314d }, { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, { 0x0ec0, 0x3150 }, { 0x0ec1, 0x3151 }, { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, { 0x0ec4, 0x3154 }, { 0x0ec5, 0x3155 }, { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, { 0x0ec8, 0x3158 }, { 0x0ec9, 0x3159 }, { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, { 0x0ecc, 0x315c }, { 0x0ecd, 0x315d }, { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, { 0x0ed0, 0x3160 }, { 0x0ed1, 0x3161 }, { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, { 0x0ed4, 0x11a8 }, { 0x0ed5, 0x11a9 }, { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, { 0x0ed8, 0x11ac }, { 0x0ed9, 0x11ad }, { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, { 0x0edc, 0x11b0 }, { 0x0edd, 0x11b1 }, { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, { 0x0ee0, 0x11b4 }, { 0x0ee1, 0x11b5 }, { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, { 0x0ee4, 0x11b8 }, { 0x0ee5, 0x11b9 }, { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, { 0x0ee8, 0x11bc }, { 0x0ee9, 0x11bd }, { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, { 0x0eec, 0x11c0 }, { 0x0eed, 0x11c1 }, { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, { 0x0ef0, 0x3171 }, { 0x0ef1, 0x3178 }, { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, { 0x0ef4, 0x3184 }, { 0x0ef5, 0x3186 }, { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, { 0x0ef8, 0x11eb }, { 0x0ef9, 0x11f0 }, { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, { 0x13a4, 0x20ac }, { 0x13bc, 0x0152 }, { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, { 0x20ac, 0x20ac }, +}; + +static unsigned int ImGui_ImplQNX_KeySymToUnicode(unsigned int keysym) +{ + // Latin-1 keysyms map directly to Unicode. + if ((keysym >= 0x0020u && keysym <= 0x007eu) || + (keysym >= 0x00a0u && keysym <= 0x00ffu)) + { + return keysym; + } + + // X11-style directly encoded UCS keysyms use 0x01000000 | codepoint. + if ((keysym & 0xff000000u) == 0x01000000u) + { + const unsigned int codepoint = keysym & 0x00ffffffu; + return codepoint <= IM_UNICODE_CODEPOINT_MAX ? codepoint : 0u; + } + + int min = 0; + int max = (int)(sizeof(ImGui_ImplQNX_KeySymTable) / sizeof(ImGui_ImplQNX_KeySymTable[0])) - 1; + while (max >= min) + { + const int mid = min + (max - min) / 2; + if (ImGui_ImplQNX_KeySymTable[mid].KeySym < keysym) + { + min = mid + 1; + } + else if (ImGui_ImplQNX_KeySymTable[mid].KeySym > keysym) + { + max = mid - 1; + } + else + { + return ImGui_ImplQNX_KeySymTable[mid].Unicode; + } + } + + return 0u; +} + +#endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_qnx.h b/include/imgui/backends/imgui_impl_qnx.h new file mode 100644 index 0000000..7bd86f4 --- /dev/null +++ b/include/imgui/backends/imgui_impl_qnx.h @@ -0,0 +1,35 @@ +// dear imgui: Platform Backend for QNX Screen +// This needs to be used along with a Renderer Backend (e.g. OpenGL3, Vulkan). + +// Implemented features: +// [X] Platform: Keyboard support. Uses io.AddKeyEvent() and native QNX key symbols. +// [X] Platform: Mouse support. Handles position, three buttons and horizontal/vertical wheels. +// [X] Platform: Touch support. Maps the first active touch contact to the primary mouse button. +// [X] Platform: Focus and window-size updates. +// Missing features or Issues: +// [ ] Platform: Clipboard support. +// [ ] Platform: Gamepad support. +// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_DISABLE + +#include + +// The application owns the Screen context, window and event object. +// Poll events with screen_get_event() and pass each non-NONE event to ProcessEvent(). +IMGUI_IMPL_API bool ImGui_ImplQNX_Init(screen_context_t context, screen_window_t window); +IMGUI_IMPL_API void ImGui_ImplQNX_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplQNX_NewFrame(); +IMGUI_IMPL_API bool ImGui_ImplQNX_ProcessEvent(screen_event_t event); + +#endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_sdl2.cpp b/include/imgui/backends/imgui_impl_sdl2.cpp index eec4e00..a93bcc2 100644 --- a/include/imgui/backends/imgui_impl_sdl2.cpp +++ b/include/imgui/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-08-06: Fixed querying framebuffer scale when using Metal. (#5592) // 2026-07-15: Inputs: restore SDL_StartTextInput()/SDL_StopTextInput() in IME handler for on-screen keyboard support on Android/mobile. (#7636, #9474) // 2026-04-16: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL2_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235) @@ -135,10 +136,18 @@ #endif #define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#if defined(__APPLE__) +#define SDL_HAS_METAL SDL_VERSION_ATLEAST(2,0,14) +#else +#define SDL_HAS_METAL 0 +#endif #define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14) #if SDL_HAS_VULKAN #include #endif +#if SDL_HAS_METAL +#include +#endif // SDL Data struct ImGui_ImplSDL2_Data @@ -899,6 +908,10 @@ static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, #if SDL_HAS_VULKAN else if (SDL_GetWindowFlags(window) & SDL_WINDOW_VULKAN) SDL_Vulkan_GetDrawableSize(window, &display_w, &display_h); +#endif +#if SDL_HAS_METAL + else if (SDL_GetWindowFlags(window) & SDL_WINDOW_METAL) + SDL_Metal_GetDrawableSize(window, &display_w, &display_h); #endif else SDL_GL_GetDrawableSize(window, &display_w, &display_h); diff --git a/include/imgui/backends/imgui_impl_sdlgpu3.cpp b/include/imgui/backends/imgui_impl_sdlgpu3.cpp index 8f0408c..2f6b250 100644 --- a/include/imgui/backends/imgui_impl_sdlgpu3.cpp +++ b/include/imgui/backends/imgui_impl_sdlgpu3.cpp @@ -5,6 +5,7 @@ // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState(). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -22,6 +23,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378) // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) @@ -92,6 +94,11 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState() +{ + return (ImGui_ImplSDLGPU3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); @@ -163,8 +170,8 @@ static void CreateOrResizeBuffers(SDL_GPUBuffer** buffer, SDL_GPUTransferBuffer* void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) return; @@ -229,8 +236,8 @@ static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; @@ -591,7 +598,7 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects() if (bd->TexSamplerLinear == nullptr) { - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + // Bilinear sampling is required. SDL_GPUSamplerCreateInfo sampler_info = {}; sampler_info.min_filter = SDL_GPU_FILTER_LINEAR; sampler_info.mag_filter = SDL_GPU_FILTER_LINEAR; diff --git a/include/imgui/backends/imgui_impl_sdlgpu3.h b/include/imgui/backends/imgui_impl_sdlgpu3.h index bc21d1c..a517c43 100644 --- a/include/imgui/backends/imgui_impl_sdlgpu3.h +++ b/include/imgui/backends/imgui_impl_sdlgpu3.h @@ -5,6 +5,7 @@ // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState(). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -58,5 +59,6 @@ struct ImGui_ImplSDLGPU3_RenderState { SDL_GPUDevice* Device; }; +IMGUI_IMPL_API ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_sdlrenderer2.cpp b/include/imgui/backends/imgui_impl_sdlrenderer2.cpp index d9f329b..d8dcfb1 100644 --- a/include/imgui/backends/imgui_impl_sdlrenderer2.cpp +++ b/include/imgui/backends/imgui_impl_sdlrenderer2.cpp @@ -55,7 +55,8 @@ #endif // SDL -#include +#include +#include #if !SDL_VERSION_ATLEAST(2,0,17) #error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function #endif @@ -75,6 +76,11 @@ static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState() +{ + return (ImGui_ImplSDLRenderer2_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer) { @@ -213,8 +219,7 @@ void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex) IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); - // Create texture - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Create texture (bilinear sampling is required) SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height); IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!"); SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch()); diff --git a/include/imgui/backends/imgui_impl_sdlrenderer2.h b/include/imgui/backends/imgui_impl_sdlrenderer2.h index f33bc16..e16b8ca 100644 --- a/include/imgui/backends/imgui_impl_sdlrenderer2.h +++ b/include/imgui/backends/imgui_impl_sdlrenderer2.h @@ -51,5 +51,6 @@ struct ImGui_ImplSDLRenderer2_RenderState { SDL_Renderer* Renderer; }; +IMGUI_IMPL_API ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_sdlrenderer3.cpp b/include/imgui/backends/imgui_impl_sdlrenderer3.cpp index d4c043c..6dd4c14 100644 --- a/include/imgui/backends/imgui_impl_sdlrenderer3.cpp +++ b/include/imgui/backends/imgui_impl_sdlrenderer3.cpp @@ -13,7 +13,7 @@ // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-17: Restore modified texture scale modes at the end of RenderDrawData(). Added DrawCallback_SetSamplerFromTex support. Added CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState (#9543, #9378) // 2026-07-15: Fixed default sampler state to be linear (broken 2026-04-23). (#9470, #9378) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) @@ -51,19 +52,24 @@ #endif // SDL -#include +#include +#include #if !SDL_VERSION_ATLEAST(3,0,0) #error This backend requires SDL 3.0.0+ #endif // SDL_Renderer data +struct ImGui_ImplSDLRenderer3_TexScaleModeEntry +{ + SDL_Texture* Texture; + SDL_ScaleMode ScaleModeBackup; +}; + struct ImGui_ImplSDLRenderer3_Data { SDL_Renderer* Renderer; // Main viewport's renderer ImVector ColorBuffer; - - // Render State - SDL_ScaleMode CurrentScaleMode; + ImVector TexScaleModeBackups; // Backup of texture scale modes ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -75,17 +81,21 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState() +{ + return (ImGui_ImplSDLRenderer3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer) { - ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); + ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); // Clear out any viewports and cliprect set by the user // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process. SDL_SetRenderViewport(renderer, nullptr); SDL_SetRenderClipRect(renderer, nullptr); - - bd->CurrentScaleMode = SDL_SCALEMODE_LINEAR; + render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR; } void ImGui_ImplSDLRenderer3_NewFrame() @@ -115,8 +125,61 @@ static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVectorCurrentScaleMode = SDL_SCALEMODE_LINEAR; } -static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); bd->CurrentScaleMode = SDL_SCALEMODE_NEAREST; } +static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR; } +static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_NEAREST; } +static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID; } // SDL_SCALEMODE_INVALID = use/keep value in texture. + +// SDLRenderer has various design issues which makes it hard to do it compared to regular graphics API. +// - scale/filtering mode is tied to a texture. +// - scale/filtering mode is not queued as part of the SDL_RenderGeometryXXX commands, so a change in one texture requires a flush. +static void ImGui_ImplSDLRenderer3_TexScaleModeUpdate(SDL_Renderer* renderer, SDL_Texture* tex, SDL_ScaleMode desired_scale_mode) +{ + ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); + if (desired_scale_mode != SDL_SCALEMODE_INVALID) + { + // Enforce a scale mode + SDL_ScaleMode tex_scale_mode = desired_scale_mode; + if (!SDL_GetTextureScaleMode(tex, &tex_scale_mode) || tex_scale_mode == desired_scale_mode) + return; + SDL_FlushRenderer(renderer); + SDL_SetTextureScaleMode(tex, desired_scale_mode); + + // Store backup of old scale mode (FIXME-OPT) + for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups) + if (entry.Texture == tex) + { + if (entry.ScaleModeBackup == SDL_SCALEMODE_INVALID) + entry.ScaleModeBackup = tex_scale_mode; + return; + } + ImGui_ImplSDLRenderer3_TexScaleModeEntry entry = { tex, tex_scale_mode }; + bd->TexScaleModeBackups.push_back(entry); + } + else + { + // Use scale mode that was set in texture by user. If there is an entry, restore it and clear the entry. + for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups) + if (entry.Texture == tex && entry.ScaleModeBackup != SDL_SCALEMODE_INVALID) + { + SDL_FlushRenderer(renderer); + SDL_SetTextureScaleMode(tex, entry.ScaleModeBackup); + entry.ScaleModeBackup = SDL_SCALEMODE_INVALID; + return; + } + } +} + +static void ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(SDL_Renderer* renderer) +{ + ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); + if (bd->TexScaleModeBackups.Size == 0) + return; + SDL_FlushRenderer(renderer); + for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups) + if (entry.ScaleModeBackup != SDL_SCALEMODE_INVALID) + SDL_SetTextureScaleMode(entry.Texture, entry.ScaleModeBackup); + bd->TexScaleModeBackups.resize(0); +} void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) { @@ -159,19 +222,19 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* SDL_GetRenderViewport(renderer, &old.Viewport); SDL_GetRenderClipRect(renderer, &old.ClipRect); - // Setup desired state - ImGui_ImplSDLRenderer3_SetupRenderState(renderer); - // Setup render state structure (for callbacks and custom texture bindings) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLRenderer3_RenderState render_state; render_state.Renderer = renderer; platform_io.Renderer_RenderState = &render_state; + // Setup desired state + ImGui_ImplSDLRenderer3_SetupRenderState(renderer); + IM_ASSERT(bd->TexScaleModeBackups.Size == 0); + // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = render_scale; - SDL_ScaleMode last_scale_mode = bd->CurrentScaleMode; // Render command lists for (const ImDrawList* draw_list : draw_data->CmdLists) @@ -201,20 +264,17 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; - SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) }; SDL_SetRenderClipRect(renderer, &r); + // Setup texture scale/filtering mode + SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); + ImGui_ImplSDLRenderer3_TexScaleModeUpdate(renderer, tex, render_state.CurrentScaleMode); + + // Draw const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos)); const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv)); - const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+ - - if (last_scale_mode != bd->CurrentScaleMode) - SDL_FlushRenderer(renderer); - - // Bind texture, Draw - SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); - SDL_SetTextureScaleMode(tex, bd->CurrentScaleMode); + const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex, xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), @@ -229,6 +289,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* // Restore modified SDL_Renderer state SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr); SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr); + ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(renderer); } void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) @@ -242,8 +303,7 @@ void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); - // Create texture - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Create texture (bilinear sampling is required) SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height); IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!"); SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch()); @@ -311,6 +371,7 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState; platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear; platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest; + platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex; bd->Renderer = renderer; diff --git a/include/imgui/backends/imgui_impl_sdlrenderer3.h b/include/imgui/backends/imgui_impl_sdlrenderer3.h index c01a16d..ee701be 100644 --- a/include/imgui/backends/imgui_impl_sdlrenderer3.h +++ b/include/imgui/backends/imgui_impl_sdlrenderer3.h @@ -13,7 +13,7 @@ // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -27,7 +27,8 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE -struct SDL_Renderer; +// For SDL_ScaleMode which cannot be forward declared. +#include // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer); @@ -48,6 +49,8 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) struct ImGui_ImplSDLRenderer3_RenderState { SDL_Renderer* Renderer; + SDL_ScaleMode CurrentScaleMode; // Current scale mode during render. Set to SDL_SCALEMODE_INVALID to use "SetSamplerFromTex" mode. }; +IMGUI_IMPL_API ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/include/imgui/backends/imgui_impl_vulkan.cpp b/include/imgui/backends/imgui_impl_vulkan.cpp index ef7dd62..7017a6f 100644 --- a/include/imgui/backends/imgui_impl_vulkan.cpp +++ b/include/imgui/backends/imgui_impl_vulkan.cpp @@ -5,7 +5,7 @@ // [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState(). // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -27,6 +27,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-10-06: Added support for dynamic rendering with multiple color attachments (PipelineRenderingCreateInfo.colorAttachmentCount > 1): we render to the first one and leave the others untouched. (#9574) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) +// 2026-09-03: Added for support for multiple Vulkan contexts with custom loaders. (#6616) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends. // - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. @@ -230,10 +233,28 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkWaitForFences) +struct ImGui_ImplVulkan_Functions +{ // Define function pointers -#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; +#define IMGUI_VULKAN_FUNC_DEF(func) PFN_##func pfn_##func; IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) #undef IMGUI_VULKAN_FUNC_DEF +}; + +// Globally available function pointers used for initialization of the backend data +static ImGui_ImplVulkan_Functions ImGuiImplVulkanFuncs; + +// Multi Vulkan contexts support: wrap each Vulkan function pointer to properly dispatch it using the current backend data +static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions(); +#define IMGUI_VULKAN_FUNC_WRAPPER(func) \ + template \ + auto func(Args&&... args) -> decltype(ImGui_ImplVulkan_GetFunctions().pfn_##func(args...)) \ + { \ + return ImGui_ImplVulkan_GetFunctions().pfn_##func(args...); \ + } +IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_WRAPPER) +#undef IMGUI_VULKAN_FUNC_WRAPPER + #endif // IMGUI_IMPL_VULKAN_USE_LOADER #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING @@ -300,6 +321,11 @@ struct ImGui_ImplVulkan_Data // Render buffers for main window ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; + // Vulkan function pointers loaded for this context +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER + ImGui_ImplVulkan_Functions Functions; +#endif + ImGui_ImplVulkan_Data() { memset((void*)this, 0, sizeof(*this)); @@ -434,6 +460,21 @@ static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState() +{ + return (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER +// Get the Vulkan function pointers used by the current backend. +// If no backend is available, return the currently loaded global function pointers (ImGuiImplVulkanFuncs). +static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions() +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + return bd ? bd->Functions : ImGuiImplVulkanFuncs; +} +#endif + static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -529,7 +570,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline constants[1] = 2.0f / draw_data->DisplaySize.y; constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; - vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); + vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (uint32_t)sizeof(float) * 4, constants); // Setup sampler vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); @@ -553,8 +594,8 @@ void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImD void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; @@ -1022,7 +1063,14 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; ms_info.rasterizationSamples = (info->MSAASamples != 0) ? info->MSAASamples : VK_SAMPLE_COUNT_1_BIT; - VkPipelineColorBlendAttachmentState color_attachment[1] = {}; + // Blend into the first color attachment. With dynamic rendering, other color attachments of the rendering are left untouched (requires independentBlend feature). + int color_attachment_count = 1; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (bd->VulkanInitInfo.UseDynamicRendering && info->PipelineRenderingCreateInfo.colorAttachmentCount > 1) + color_attachment_count = (int)info->PipelineRenderingCreateInfo.colorAttachmentCount; +#endif + ImVector color_attachment; + color_attachment.resize(color_attachment_count, VkPipelineColorBlendAttachmentState()); // colorWriteMask = 0 color_attachment[0].blendEnable = VK_TRUE; color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -1037,8 +1085,8 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - blend_info.attachmentCount = 1; - blend_info.pAttachments = color_attachment; + blend_info.attachmentCount = (uint32_t)color_attachment.Size; + blend_info.pAttachments = color_attachment.Data; ImVector dynamic_states = info->ExtraDynamicStates; dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); @@ -1153,8 +1201,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - // Create samplers - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + // Create samplers (bilinear sampling is required) if (!bd->SamplerLinear || !bd->SamplerNearest) { VkSamplerCreateInfo info = {}; @@ -1322,8 +1369,8 @@ bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction( #ifdef IMGUI_IMPL_VULKAN_USE_LOADER #define IMGUI_VULKAN_FUNC_LOAD(func) \ - func = reinterpret_cast(loader_func(#func, user_data)); \ - if (func == nullptr) \ + ImGuiImplVulkanFuncs.pfn_##func = reinterpret_cast(loader_func(#func, user_data)); \ + if (ImGuiImplVulkanFuncs.pfn_##func == nullptr) \ return false; IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD) #undef IMGUI_VULKAN_FUNC_LOAD @@ -1391,6 +1438,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE); bd->VulkanInitInfo = *info; +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER + bd->Functions = ImGuiImplVulkanFuncs; +#endif VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); diff --git a/include/imgui/backends/imgui_impl_vulkan.h b/include/imgui/backends/imgui_impl_vulkan.h index cf6a3be..44c76c9 100644 --- a/include/imgui/backends/imgui_impl_vulkan.h +++ b/include/imgui/backends/imgui_impl_vulkan.h @@ -5,7 +5,7 @@ // [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState(). // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -101,6 +101,7 @@ struct ImGui_ImplVulkan_PipelineInfo // - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you. // - About dynamic rendering: // - When using dynamic rendering, set UseDynamicRendering=true + fill PipelineInfoMain.PipelineRenderingCreateInfo structure. +// - PipelineRenderingCreateInfo may describe multiple color attachments: we render to the first one and leave the others untouched. This requires the 'independentBlend' device feature. struct ImGui_ImplVulkan_InitInfo { uint32_t ApiVersion; // Fill with API version of Instance, e.g. VK_API_VERSION_1_3 or your value of VkApplicationInfo::apiVersion. May be lower than header version (VK_HEADER_VERSION_COMPLETE) @@ -175,6 +176,7 @@ struct ImGui_ImplVulkan_RenderState VkPipeline Pipeline; VkPipelineLayout PipelineLayout; }; +IMGUI_IMPL_API ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState(); //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers diff --git a/include/imgui/backends/imgui_impl_wgpu.cpp b/include/imgui/backends/imgui_impl_wgpu.cpp index 9f0124f..002967b 100644 --- a/include/imgui/backends/imgui_impl_wgpu.cpp +++ b/include/imgui/backends/imgui_impl_wgpu.cpp @@ -5,8 +5,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState(). // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags. @@ -20,6 +20,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) +// 2026-08-31: Update to compile with wgpu-native 29.0. (#9377, #9532, #9530) +// 2026-08-18: Fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport() when FramebufferScale is >1.0f. (#9515, #8628) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) // 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) @@ -65,12 +68,6 @@ #error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore. #endif -#if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK -// Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413) -// Using type alias until WGPU adopts the same naming convention (#8369) -using WGPUProgrammableStageDescriptor = WGPUComputeState; -#endif - // Dear ImGui prototypes from imgui_internal.h extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed); #define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro). @@ -132,6 +129,11 @@ static ImGui_ImplWGPU_Data* ImGui_ImplWGPU_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplWGPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState() +{ + return (ImGui_ImplWGPU_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + //----------------------------------------------------------------------------- // SHADERS //----------------------------------------------------------------------------- @@ -316,7 +318,7 @@ static void SafeRelease(FrameResources& res) SafeRelease(res.VertexBufferHost); } -static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source) +static WGPUComputeState ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); IM_UNUSED(bd); @@ -343,7 +345,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(con pop_cb.userdata1 = &validation_error; wgpuDevicePopErrorScope(bd->wgpuDevice, pop_cb); - WGPUProgrammableStageDescriptor stage_desc = {}; + WGPUComputeState stage_desc = {}; if (module && !validation_error) { stage_desc.module = module; @@ -356,7 +358,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(con return stage_desc; } -static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleSPIRV(const void* spirv_binary, size_t spirv_length) +static WGPUComputeState ImGui_ImplWGPU_CreateShaderModuleSPIRV(const void* spirv_binary, size_t spirv_length) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); @@ -368,7 +370,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleSPIRV(co WGPUShaderModuleDescriptor desc = {}; desc.nextInChain = (WGPUChainedStruct*)&spirv_desc; - WGPUProgrammableStageDescriptor stage_desc = {}; + WGPUComputeState stage_desc = {}; stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); stage_desc.entryPoint = { "main", WGPU_STRLEN }; @@ -440,7 +442,9 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas } // Setup viewport - wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); + wgpuRenderPassEncoderSetViewport(ctx, 0, 0, (float)fb_width, (float)fb_height, 0, 1); // Bind shader and vertex buffers wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert)); @@ -462,8 +466,8 @@ static void ImGui_ImplWGPU_DrawCallback_SetSamplerNearest(const ImDrawList*, con void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder) { // Avoid rendering when minimized - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; @@ -769,7 +773,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() graphics_pipeline_desc.layout = wgpuDeviceCreatePipelineLayout(bd->wgpuDevice, &layout_desc); // Create the vertex shader - WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_vert_wgsl); + WGPUComputeState vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_vert_wgsl); if (!vertex_shader_desc.module) vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_vert_spirv, sizeof(__shader_vert_spirv)); graphics_pipeline_desc.vertex.module = vertex_shader_desc.module; graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint; @@ -777,15 +781,9 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Vertex input configuration WGPUVertexAttribute attribute_desc[] = { -#if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 }, { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 }, { nullptr, WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 }, -#else - { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 }, - { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 }, - { WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 }, -#endif }; WGPUVertexBufferLayout buffer_layouts[1]; @@ -798,7 +796,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() graphics_pipeline_desc.vertex.buffers = buffer_layouts; // Create the pixel shader - WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_frag_wgsl); + WGPUComputeState pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_frag_wgsl); if (!pixel_shader_desc.module) pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_frag_spirv, sizeof(__shader_frag_spirv)); // Create the blending setup @@ -844,8 +842,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() ImGui_ImplWGPU_CreateUniformBuffer(); - // Create samplers (Linear/Nearest) - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + // Create samplers (Linear/Nearest) (bilinear sampling is required) WGPUSamplerDescriptor sampler_desc = {}; sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; @@ -992,11 +989,7 @@ void ImGui_ImplWGPU_NewFrame() bool ImGui_ImplWGPU_IsSurfaceStatusError(WGPUSurfaceGetCurrentTextureStatus status) { -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) return (status == WGPUSurfaceGetCurrentTextureStatus_Error); -#else - return (status == WGPUSurfaceGetCurrentTextureStatus_OutOfMemory || status == WGPUSurfaceGetCurrentTextureStatus_DeviceLost); -#endif } bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextureStatus status) @@ -1009,7 +1002,6 @@ bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextureStatus } // Helpers to obtain a string -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type) { switch (type) @@ -1032,7 +1024,7 @@ const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type) default: return "Unknown"; } } -#elif !defined(__EMSCRIPTEN__) +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level) { switch (level) diff --git a/include/imgui/backends/imgui_impl_wgpu.h b/include/imgui/backends/imgui_impl_wgpu.h index c06c25f..9f206db 100644 --- a/include/imgui/backends/imgui_impl_wgpu.h +++ b/include/imgui/backends/imgui_impl_wgpu.h @@ -17,8 +17,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState(). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -81,6 +81,7 @@ struct ImGui_ImplWGPU_RenderState WGPUDevice Device; WGPURenderPassEncoder RenderPassEncoder; }; +IMGUI_IMPL_API ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState(); //------------------------------------------------------------------------- // Internal Helpers @@ -95,10 +96,9 @@ bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextur void ImGui_ImplWGPU_DebugPrintAdapterInfo(const WGPUAdapter& adapter); const char* ImGui_ImplWGPU_GetBackendTypeName(WGPUBackendType type); const char* ImGui_ImplWGPU_GetAdapterTypeName(WGPUAdapterType type); -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type); const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type); -#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level); #endif diff --git a/include/imgui/docs/BACKENDS.md b/include/imgui/docs/BACKENDS.md index 2f3a802..5aa0720 100644 --- a/include/imgui/docs/BACKENDS.md +++ b/include/imgui/docs/BACKENDS.md @@ -72,13 +72,14 @@ For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder: -List of Platforms Backends: +List of Platform Backends: imgui_impl_android.cpp ; Android native app API imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org + imgui_impl_qnx.cpp ; QNX Screen imgui_impl_win32.cpp ; Win32 native API (Windows) imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) @@ -234,9 +235,7 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) // - Scissor enabled MyEngineSetupenderState(); - // TODO: Setup texture sampling state - // - Sample with bilinear filtering (NOT point/nearest filtering). - // - Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. + // TODO: Setup texture sampler to bilinear (NOT point/nearest filtering). // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize diff --git a/include/imgui/docs/CHANGELOG.txt b/include/imgui/docs/CHANGELOG.txt index fbfd2aa..b5d9830 100644 --- a/include/imgui/docs/CHANGELOG.txt +++ b/include/imgui/docs/CHANGELOG.txt @@ -35,6 +35,418 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.93.0 (Released 2026-10-14) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.93.0 + +In 1.93.0, the `ImDrawList` rendering API has been improved to be more robust and +more consistent over the whole range of shapes. The rendering now matches much closer +to common vector drawing APIs, like html canvas. Improvements, like anti-aliased line +endings and stroke position were added. The coordinates passed to the API are now +consistently describing shape outlines. + +For code using custom rendering: some details are now rendered slightly differently +(even if generally more consistent). The difference in rendering is in the range of +half a pixel, but that can lead to issues like some lines now look blurrier or more +transparent. All Dear ImGui widgets should appear identical or better. + +The rendering of common shapes was optimized when the shapes fall on integer coordinates +(which is most of the UI). This includes skipping anti-aliasing when not needed, or +using textures instead of tessellated geometry to draw round corners. +The varying code-paths are designed to look indistinguishable from each others. + +New rendering code fixes some inconsistencies between graphics APIs +(e.g. DirectX vs OpenGL) which are using different diamond exits rules. +New code should work precisely the same regardless of which graphics API is used +(note that using _StrokeLegacy mode can lead to the same old inconsistencies). + +New rendering code also deals better with animating thickness and rounding +(integer values are recommended). + +While the current version doesn't make lots of visible use of the new features and +facilities, they are among the pillars that will make it easier to create prettier +contents, both for custom rendering and future versions of the library. + +Use `ImDrawFlags_StrokeLegacy` mode to emulate old rendering: +- Per-primitive: draw_list->AddLine(..., ..., ImDrawFlags_StrokeLegacy); +- For a given scope: draw_list->PushDrawFlag(ImDrawFlags_StrokeLegacy, true); draw_list->AddLine(...); draw_list->PopDrawFlag(); +- Globally: ImGui::Checkbox("DefaultsToStrokeLegacy", &io.ConfigDebugDrawListDefaultsToStrokeLegacy); // Map to a checkbox +- Globally: io.ConfigDebugDrawListDefaultsToStrokeLegacy = io.KeyShift; // Map on Shift + +Don't panic! +Many applications will not notice any difference! You will more likely see +differences if you used lots of direct `ImDrawList` calls for custom rendering. + +Credits for ImDrawList changes in 1.93.0: +- main work courtesy of @memononen. +- additional work/reviewing/guidance by @ocornut. +- with legacy bits from @thedmd, @potocpav. +Other credits marked below, or @ocornut when omitted. + +Refer to our guides: +- ImDrawList Vector Rendering Reference + https://github.com/ocornut/imgui/wiki/Draw-List + (includes a precise list of differences between 1.92.9 and 1.93.0). +- ImDrawList 1.92.9 vs 1.93.0 Interactive Testbed + https://www.dearimgui.com/docs/drawlist_v193 + (interactively compare differences between 1.92.9 and 1.93.0 + commentary) + (downloadable HTML file, may be used offline) +- Pixel Perfect Anti-aliased Rendering + https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering +- How Anti-aliased Polyline Rendering is Implemented + https://github.com/ocornut/imgui/wiki/Polyline-Rendering +- Discussion topic: + https://github.com/ocornut/imgui/issues/9504 + (if you have a problem to discuss, please open a new issue) + +Breaking Changes: + +- ImDrawList: + - AddLine(): removed the (+0.5f,+0.5f) offset that was sneakily added to input coordinates. (#9504) + - This fixes inconsistencies in the API and matches the PathXXX API. + - By default, stroke thickness extends on both side of the given segment. + e.g for a "pixel-perfect" looking line with thickness=1.0f, coords should be passed as center of each ends of the line. + - Use `ImDrawFlags_StrokeLegacy` to use old offset if required. Or you can apply the offset manually! + - Generally better, simple and faster to use `AddLineH()`, `AddLineV()` functions added in 1.92.8. + READ IF YOU ARE MINDFUL OF PIXEL-PERFECTNESS IN YOUR CUSTOM RENDERING/WIDGETS: + - TRANSITION GUIDE FOR AXIS-ALIGNED LINES: + - When switching from legacy `AddLine()` values to `AddLineV()`, `AddLineH()` you can keep same inputs coordinates as before: + - Old `AddLine({x, y1}, {x, y2}, col)` --> `AddLineV(x, y1, y2, col);` // Vertical line. + - Old `AddLine({x1, y}, {x2, y}, col)` --> `AddLineH(x1, x2, y, col);` // Horizontal line. + - This will be equivalent and faster for thickness=1.0f lines. + - Since `AddLine()` use default stroke pos Center and `AddLineV()`, `AddLineH()` use Inside, thickness>1.0f strokes will differ. + Using `ImDrawFlags_StrokeCenter` will match old result more closely (aka look centered), + but is more likely to look blurry as it already did before. + - Read table below about StrokePos and the "Pixel-Perfect Rendering" guide if you care about pixel-perfect lines. + - TRANSITION GUIDE FOR DIAGONAL LINES: + - Your lines will appear offset by -0.5f pixels on each axis. + Being anti-aliased diagonal lines, they won't look particularly better or worse, just slightly offset. + It'll likely only be noticeable if you carefully combined them with other primitives for a pixel-perfect result. + - Old `AddLine({x1, y1}, {x2, y2}, col)` --> `AddLine({x1 + 0.5f, y1 + 0.5f}, {x2+ 0.5f, y2 + 0.5f}, col);` // Same + or use `ImDrawFlags_StrokeLegacy` --> `AddLine({x1, y1}, {x2, y2}, col, thickness, ImDrawFlags_StrokeLegacy);` // Offset by +0.5f + disable AA ends. + This reapplies the old offset, and should get you exactly the same result you previously + got for thickness=1.0f lines. But said result were previously sometimes ambiguous and + renderer-dependent. (#3116, #3258, #2441) + - Old code did not support anti-aliased ends, which could create gaps when rendering shapes out + of multiple contiguous lines instead of using `AddPolyline()`. There is a possibility that you + legacy code added fudge offsets here and there; which may not be necessary anymore if you use + `_AALineEnds`, or if you combine rendering of contiguous lines using `AddPolyline()`. + - AddRect(), AddCircle(), AddNgon(), AddEllipse(), AddTriangle(), AddQuad(): defaulting to "inside" stroke. + - All closed shapes with thickness=1.0f will appear identical. + - The difference for thickness>1.0f shapes may be minimal since very large strokes + were not well supported for widgets, but stroke will default inside widgets. + - AddCircle(), AddNgon(): removed -0.5f offset added to radius. + - This fixes inconsistencies in the API. + - Use `ImDrawFlags_StrokeLegacy` to use old method if required. Or you can apply the offset manually! + - AddRectFilled(): non-integer coordinates will now display anti-aliased edges. + Previously, non-integer coordinates rendered with aliased edges snapped by the + rasterizer. (#6971) + - AddRect(), AddRectFilled(): rectangles with inverted coordinates won't be visible + unless using `ImDrawFlags_StrokeLegacy` mode. With inverted coordinates (min > max): + - Legacy `AddRect()` rounding off -> visible but incorrect outer size. + - Legacy `AddRect()` rounding on -> visible but very glitchy. + - Legacy `AddRectFilled()` rounding off -> visible and correct. + - Legacy `AddRectFilled()` rounding on -> visible but very glitchy. + - Use `ImDrawFlags_StrokeLegacy` to use old rendering for cases without rounding, or fix coordinates. + - Merged `ImDrawListFlags` into `ImDrawFlags`. `ImDrawListFlags` was rarely used directly + and generally setup by the ImGui context. + - `ImDrawListFlags_AntiAliasedLines` -> `ImDrawFlags_AALines` + - `ImDrawListFlags_AntiAliasedFill` -> `ImDrawFlags_AAFill` + - `ImDrawListFlags_AllowVtxOffset` -> `ImDrawFlags_UseVtxOffset` + - `ImDrawListFlags_TextNoPixelSnap` -> `ImDrawFlags_TextNoPixelSnap` + Unifying them allows easily using them for both per-primitives and scope alterations. + Kept redirection enums (will obsolete). + - Renamed all `ImDrawFlags_RoundCornersXXX` flags to `ImDrawFlags_RoundXXX`. + - `ImDrawFlags_RoundCornersAll` -> `ImDrawFlags_RoundAll` + - `ImDrawFlags_RoundCornersNone` -> `ImDrawFlags_RoundNone` + - `ImDrawFlags_RoundCornersTopLeft` -> `ImDrawFlags_RoundTopLeft` + - `ImDrawFlags_RoundCornersTopRight` -> `ImDrawFlags_RoundTopRight` + - `ImDrawFlags_RoundCornersBottomLeft` -> `ImDrawFlags_RoundBottomLeft` + - `ImDrawFlags_RoundCornersBottomRight` -> `ImDrawFlags_RoundBottomRight` + - `ImDrawFlags_RoundCornersTop` -> `ImDrawFlags_RoundTop` + - `ImDrawFlags_RoundCornersBottom` -> `ImDrawFlags_RoundBottom` + - `ImDrawFlags_RoundCornersLeft` -> `ImDrawFlags_RoundLeft` + - `ImDrawFlags_RoundCornersRight` -> `ImDrawFlags_RoundRight` + Kept redirection enums (will obsolete). + - Marked `ImDrawListFlags_AntiAliasedLinesUseTex` and `style.AntiAliasedLinesUseTex` as + obsolete, as the new line rendering code always uses textures. + - Enabling `ImFontAtlasFlags_NoBakedLines` in the font atlas will now disable support for + anti-aliased lines by clearing `style.AntiAliasedLines`/`style.AntiAliasedLineEnds`. +- Style: obsoleted `style.CurveTessellationTol` (default 1.25) which was in Pixels² unit in + favor of `style.CurveTessellationMaxError` (default 1.12) which is in Pixels unit. It is + easier to tweak + this allows us to easily scale error threshold on high density screens. + - style.CurveTessellationMaxError == sqrtf(style.CurveTessellationTol). +- ImGuiTextFilter: removed `float width` parameter of `Draw(const char* filter, float width)`: + prefer using `SetNextItemWidth(float)` which is standard. Kept inline redirection function. +- Fonts: renamed `AddRemapChar()` to `AddRemapCodepoint()` (rarely used, marked internal). + (#609, #5748, #9559) +- Backends: + - DirectX12: Removed support for legacy `ImGui_ImplDX12_Init()` signature, which was + obsoleted in 1.91.6 (December 2014), because it needed to forcefully disable support + for `ImGuiBackendFlags_RendererHasTextures`. Use the new signature! (#9487) + - OpenGL3: Does not attempt to read `GL_CLIP_ORIGIN` by default as the detection is + sub-optimal and not reliable on some setup. Use `ImGui_ImplOpenGL3_SetClipOrigin(0)` + to enable auto-detection, or e.g. `ImGui_ImplOpenGL3_SetClipOrigin(GL_UPPER_LEFT)`. + +Other Changes: + +- Style: + - StyleColorsDark(): minor refresh of the default style to look more modern: + - Changed WindowBg to use a slightly greyer value and removed opacity. + - Changed FrameBg values to use a dark black to make frames stand out better. + - Tweak TextDisabled, TableHeaderBg, TableBorders to match altered WindowBg. + - StyleColorsLight(): inverted `ImGuiCol_TitleBgXXX` colors so that the selected + window title bar appears brighter. +- ImDrawList: + - Added flags to specify stroke position in all `ImDrawList` stroking functions: (#9504) [@memononen] + - `ImDrawFlags_StrokeInside` (default for Rect, Circle/Ellipse, Triangle, Quad, Ngon + AddLineH, AddLineV) + - `ImDrawFlags_StrokeCenter` (default for Line, Polyline, Beziers, Paths function) + - `ImDrawFlags_StrokeCenterBiased` (center w/ bias for pixel perfect alignment) + - `ImDrawFlags_StrokeOutside` + - `ImDrawFlags_StrokeLegacy` (match old behavior) + - Legacy mode may be set as default for a given scope using `PushDrawFlag(ImDrawFlags_StrokeLegacy, true)`. + - Legacy code was generally applying +0.50f offsets which meant that, + - with thickness=1.0f: the stroke would appear inside. + - with thickness>1.0f: the stroke would start expanding on both sides but starting from that small initial offset. + - with thickness>1.0f for even integer values, the stroke would look blurry. + - TL;DR; the logic didn't make much sense for thickness>1.0f. + - Defaulting to Inside for closed shapes ensure that rectangles and lines are + never blurry, regardless of thickness, as long as input coordinates/sizes + are integers. (#9359) Recap: + ------------------------------------------------------------------------ + Thickness Legacy Inside Outside Center CenterBiased + ------------------------------------------------------------------------ + 1.0f sharp sharp sharp blurry sharp + 2.0f blurry sharp sharp sharp sharp + 3.0f sharp sharp sharp blurry sharp + ------------------------------------------------------------------------ + - Read our Wiki guides for more details! + https://github.com/ocornut/imgui/wiki/Draw-List + - And interactive 1.92.9 vs 1.93.0 comparing testbed: + https://www.dearimgui.com/docs/drawlist_v193 + - AddPolyline(), PathStroke(), AddTriangle(): the algorithm to render lines got overhauled. + (#9504, #2183, #2964, #7972 + #9360, #6331, #4250, #4091) [@memononen] + - Generally fixed rendering of thick strokes/paths. + - The new stroke expansion now uses corner miter calculation, which keeps thickness along + the line segments consistent. If the corner becomes too sharp, it will be beveled to + avoid long spikes at corners. + - There are also some robustness measures for the case where the line thickness is larger + than the features being drawn. + - Rendering artifacts are still possible when the path features are smaller than line thickness, + but the artifacts should be more localized. The new implementation attempted to favor simple + implementation and robustness over the corner case accuracy. + - All functions: new rendering code fixes some inconsistencies between graphics APIs + (e.g. DirectX vs OpenGL) which are using different diamond exits rules. New code should + work precisely the same regardless of graphics API. (#3116, #3258, #2441) [@memononen] + - Debug: added `io.ConfigDebugDrawListDefaultsToStrokeLegacy` to facilitate comparing old/new + behaviors. This is equivalent to calling `PushDrawFlag(ImDrawFlags_StrokeLegacy, true)` + on every drawlists. + Suggested uses, e.g. + - `io.ConfigDebugDrawListDefaultsToStrokeLegacy = io.KeyShift; // Map on holding Shift` + - `ImGui::Checkbox("DefaultsToStrokeLegacy", &io.ConfigDebugDrawListDefaultsToStrokeLegacy);` + - Added `ImDrawFlags_AALineEnds` flag to enable anti-aliased line ends. + - Most noticeable for thick lines. + - Also helps fill minor gaps if combining multiple individual lines. For best looking + continuous lines you should use AddPolyline(), it creates joins between line segments + to avoid any gaps. + - Added `style.AntiAliasedLineEnds` in ImGui to set default state. + - This is disabled by default! Enabling AA Ends by default would be more "correct", + but since it is very slightly slower and increases vertex/index data we decided + to not enable it by default. + This keeps situations such as "throw tens of thousands of lines at ImDrawList" + optimal. You can opt-in for a given shape or in a scope using `PushDrawFlag()`. + - Added `ImDrawFlags_JoinMiter` flag to disable using beveled corner. + - Closer to legacy rendering and slightly faster, but corners sharper than + 90 degrees may expand far out. + - Automatically used by AddRect(), AddCircle(), AddNgon(), AddEllipse() functions + since we know that the input path does not contain sharper corners. + - Added `ImDrawFlags_CapSquare` flag to extend lines ends using square caps. (#9360) + - AddConvexPolyFilled()/PathFillConvex(): improved to handle input geometry more robustly. + The rendering of sharp corners was improved. Earlier there were issues with sharp corners + either creating long spikes, or messing up the adjacent edge's anti-aliasing. Now the + anti-aliasing fringe calculation is more consistent, and sharp corners get beveled to + avoid spikes. There might still be issues when the smallest extent of a long thin polygon + is less than a pixel. Also supports `ImDrawFlags_JoinMiter`, to facilitate matching + a stroke using the same flag. + - `AddRect()`, `AddRectFilled()`: various optimizations for rounded rectangles. (#1962, #9504) + - Integer-aligned coordinates and thicknesses will automatically use baked textures, + saving on both CPU and vertex/index data. + - Enabled by default. Use `ImFontAtlasFlags_NoBakedRoundCorners` to disable baking + round corners in font atlas. + - Added `ImDrawFlags_UseTexForRoundCorners` flag to enable in scope or per-shape. + Added for consistency and debugging, not really needed in practice. + - `AddCircle()`, `AddCircleFilled()`: fixed large circles being under-tessellated + (when above ~140 with default CircleTessellationMaxError). + - Improved debug-build performance in various locations. + - Improved minor mismatches when overlapping strokes and filled shapes. + For example, when using inside strokes, + - `AddRect()` and `AddRectFilled()` with rounding now overlap better. (#3656) + - `AddCircle()` and `AddCircleFilled()` now overlap better. + - Added `ImDrawList::PushDrawFlag()`/`PopDrawFlag()` to alter certain flags for a + scope and a given `ImDrawList`. (#9489) + - e.g. `PushDrawFlag(ImDrawFlags_StrokeLegacy, true);` enforce legacy tweaks. + - About `ImDrawFlags_StrokeLegacy`: + - This is designed to emulate old behavior: + - Most shapes use `ImDrawFlags_StrokeCenter`. + - AddLine() add +0.5f,+0.5f offset to position. + - AddRect() and AddRectFilled() allow inverted positions. + - AddRectFilled() has no AA when passed non-integer coordinates. + - AddCircle(), AddNgon() add a -0.5f offset to radius. + - Closed shapes use miter corners. + - Lines don't have anti-aliased ends. + - But there are known difference between legacy code and ImDrawFlags_StrokeLegacy: + - Thick shapes with acute angles will now preserve thickness better, + which may make them appear as protruding a little more. + - About disabling anti-aliasing: + - Disabling anti-aliasing is now emulated by applying different UV coordinates. + - It does not result in a performance increase or vertex/index data decrease any more + (however the tendency is that the new code behaves better than old code). + - But may be a useful stylistic choice in some circumstances. + - Many thick shapes had broken corners with old no-AA code, and the old no-AA code + was wildly different from the AA code. Not the case any more. (#288) + - Per-viewport FramebufferScale for Apple/Retina screen is applied to draw lists: + - AA Fringe is scaled accordingly. (#9577) + - Circle and Curves tessellation error are scaled accordingly. + - Reworked assert in `PushTexture()` to allow convenience grace period of using a + texture that was queue for destroy during the frame. Make it safe to stick to + an existing texture during the frame. (#9528, #8465) + - Added optional `platform_io.DrawCallback_SetSamplerFromTex` standard backend-agnostic + draw callback for requesting to use the sampler associated already associated to a texture. + Currently only supported by the OpenGL2/3 and SDLRenderer3 backend. (#9378) + - Fixed dangling `ImDrawList::_OwnerName` when using animated label. (#9552) [@ubi-dcastonguay] +- Mixed Values: + - Added `ImGuiItemFlags_MixedValue` flag for representing mixed/indeterminate values. + Supported by: Checkbox(), RadioButton(), DragXXX(), SliderXXX(), InputXXX(), ColorXXX() + and Combo() functions. + The scoped flag is designed for usage by advanced property editors. (#5518, #5677, #6865) +- Drags, Sliders: + - Ongoing drags may be cancelled using Right-Click, Escape or Gamepad Triangle. + Cancelling reverts to the initial value. (#8564, #9534) + - Fixed an overflow using `ImGuiSliderFlags_Logarithmic` with S32/S64 types which + leads to clamped interactions. (#9526, #3361, #1823, #1316, #642) [@lailoken] +- TreeNode: + - Fixed issues/asserts with 32+ deep trees when using ImGuiTreeNodeFlags_DrawLinesXXX + features or other features requiring stack storage. (#9509) [@lasrod] +- TabBar: + - Improved scroll target when clicking a Tab that is larger than the scrolling + section width. + - Using <> scrolling buttons while the selected Tab is at either end of the + section mid-section but not fully visible always makes it fully visible + (before eventually selecting a Tab in the leading/trailing section). +- Tables: + - Fixed a bug restoring correct .ini columns order when table use is Sortable + but had no user changes. (regression from 1.92.9). (#9519, #9108) + - Fixed a bug tracking topology changes (insert new columns in the middle) + when the table is not _Reorderable: new columns would be ordered incorrectly. + (#9570, #9108, #9572) [@lailoken] +- InputText: + - Fixed a crash in some cases when using Home key in a WordWrap+ReadOnly field. (#9561) +- Selectable: + - Fixed `ImGuiSelectableFlags_SelectOnNav` triggering during NavInit. +- Fonts: + - Reworked `AddFontDefault()` to use `io.DisplayFrameBufferScale` as part of the heuristic + to select `AddFontDefaultVector()` by default, effectively using ProggyForever instead of + ProggyClean on most Apple/Retina setups by default. + - Added `ImFont::AddRemapCodepointToGlyphIndex()` allowing to access glyphs that are not + mapped to codepoints. (#9559, #5647, #609, #5748, #8466) + - imgui_freetype: Fixed blurriness rendering `AddFontDefaultVector()`. Caused by a + non-pixel aligned offset caused by `ExtraSizeScale`. (#9348, #9233) [@redpartizan, @RDMCz] + - (Internal) ImFontLoader: reworked `FontSrcContainsGlyph`, `FontBakedLoadGlyph` signatures + to take raw glyph index instead of codepoint. Added `FontSrcGetGlyphIndexFromCodepoint`. + (#9559, #5647, #9540, #8466, #8465) + - Added `IMGUI_DISABLE_STB_TRUETYPE` to completely omit the stb_truetype loader + code + stb_truetype.h code. (#9573) +- ColorEdit: + - ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by `BeginDisabled()` so + disabled color buttons have the same color as non-disabled oness. (#9511) + - ColorButton: fixed issues/inconsistencies with checkerboard rendering when combining + color alpha and global style alpha. (#9511) [@enjmiah, @ocornut] +- Popups: + - Amended context menu right-click opening code to check that the right-click + hasn't been owned by another items. This is more correct and also necessary + to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) + - Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within the + BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald] +- ImGuiTextFilter: + - Added support for space as an "and" filter, which is the standard. (#2435, #30) + e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data. + - Added support for double-quoted "xxx" blocks to e.g. match words sequences. (#2435) + e.g. w/ filter "hello world" the exact sequence needs to be in input data. + - Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude" + match always filters out. (#2435) [@kudaba, @ocornut] + - Added `DrawWithHint()` function. (#6206, #6395, #6447) + - Added a "incl -excl" hint by default when the search field is empty. (#6206, #6395, #6447) +- Widgets: + - Checkbox, Menus: check marks use anti-aliased ends. + - Tweaked rendering in various locations to avoid blurriness: + - Windows: title-bar and menu-bar border (when thickness>1.0f). + - SeparatorText: border (when thickness>1.0f). + - Tree: hierarchy lines (when thickness>1.0f). + - InputText: input caret (when thickness>1.0f). + - TabBar: selected overline border (when thickness>1.0f). +- Misc: + - Fixed `GetBackgroundDrawList()`/`GetForegroundDrawList()` not being properly reset + every frame when accumulated session time is very large (e.g. a few days). [@lailoken] + - Added `IM_NODEBUGSTEP` helper to tag functions with `__declspec(non_user_code)` (MSVC) + or `[[gnu::artificial]]` (Clang/GCC) in order to provide a hint to debuggers to skip + trivial functions when stepping into. + - Tagged various trivial functions using `IM_NODEBUGSTEP`: `ImVec2()`, `ImVec4()` etc. + and various operators. + - Fixed strict aliasing violation in `ImHashData()` affecting Clang 23 + SSE 4.2 + -flto. + Could manifest as `ImFontAtlasBakedGetId()` computation omitting font size from + the hashed data. (#9557, #9560) [@sthalik] + - IO: restore default clipboard/ime/shell platform handlers on `ClearPlatformHandlers()`, fixing + issues switching backends mid-session to one relying on default. (#9537, #8945, #2769) [@lstalmir] +- Demo: + - Added `Widgets->Mixed Values` section. (#5518, #5677, #6865) + - Custom Rendering section: exposed new flags; showcasing overlapping strokes + and filled shapes; added an option to animate thickness; added new shapes + to showcase new rendering features that previously hit limitations. + - Style Editor: fixed style/colors combo box applying style when opening Combo. +- Backends: + - QNX: added QNX Screen backend. (#9492) [@mgorchak-blackberry] + - Metal, Metal4: added support for rendering inside a render pass with multiple color + attachments (e.g. when merged with other passes): we render to the first color attachment + and leave the other ones untouched. (#9574) [@tqjxlm] + - OpenGL2, OpenGL3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw + callback to request using the sampler associated already associated to a texture. (#9378) + - OpenGL2, OpenGL3: fixed `DrawCallback_ResetRenderState` handler not resetting all states + in the glTexParameter() path. (#9378) + - OpenGL3: added `ImGui_ImplOpenGL3_SetClipOrigin()` to specify origin between + `GL_LOWER_LEFT` (new default), `GL_UPPER_LEFT` and `0` (autodetect, old default). + - OpenGL3: avoid querying `glGetIntegerv(GL_CLIP_ORIGIN)` multiple times when using + when using default and using `DrawCallback_ResetRenderState`, at it appear to stall + some drivers. (#2186, #3998, #3146, #3143, #8640) + - SDL2: fixed querying framebuffer scale/density when using Metal without + going through a SDL_Renderer. (#5592) [@lailoken] + - SDLRenderer3: restore any temporarily modified texture scale modes at the of `RenderDrawData()`. (#9378) + - SDLRenderer3: expose CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState. (#9543, #9378) [@Clownacy] + - SDLRenderer3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw callback to request + using the sampler associated already associated to a texture via `SDL_SetTextureScaleMode()`. (#9378) + It is equivalent to setting `render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID`. + Note: this callback is only supported by selected rendering backends: most other graphics API + don't have the equivalent of `SDL_SetTextureScaleMode()` and the callback won't work with them. + - Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir] + - Vulkan: added support for rendering inside a render pass with multiple color attachments + (e.g. when merged with other passes): we render to the first color attachment and leave the + other ones untouched. (#9574) [@tqjxlm] + - WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()` + when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] + - WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev] +- Examples: + - All: all examples now default to use a little bit of rounding (`FrameRounding` and `GrabRounding`). + - MSVC: disabled /JMC in Visual Studio projects (unnecessary overhead). + - GLFW/SDL2/SDL3+WebGPU: fixed running with wgpu-native missing `wgpuInstanceWaitAny()`. (#9377) + - GLFW/SDL2/SDL3+WebGPU: better select surface format. (#9576) [@ypujante] + - GLFW+Metal: fixed mistakenly calling `ImGui_ImplGlfw_InitForOpenGL()`, which + broke multi-viewport support. (#9564) [@ypujante] + - SDL2+Metal: create Metal context without using a `SDL_Renderer`. + - QNX+OpenGL3, QNX+Vulkan: added QNX Screen examples. (#9492) [@mgorchak-blackberry] + - OSX+OpenGL3: added example_apple_opengl3/ (OSX/Cocoa + OpenGL 3.2 Core profile). + + ----------------------------------------------------------------------- VERSION 1.92.9b (Released 2026-07-31) ----------------------------------------------------------------------- @@ -1635,7 +2047,7 @@ Non-breaking Fonts/Textures related changes: - Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured to not assert (this will be better exposed via future font flags). - Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale). -- Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on +- Fonts: added style.FontScaleDpi scaling factor. This is designed to be changed on per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically. (which is why it is separate from FontScaleBase). - Fonts: added optional font_size parameter to ImGui::PushFont() function. @@ -2790,7 +3202,7 @@ Other changes: - Backends: Vulkan: Remove Volk/ from volk.h #include directives. (#7722, #6582, #4854) [@martin-ejdestig] - Examples: SDL3: Remove use of SDL_HINT_IME_NATIVE_UI since new SDL_HINT_IME_IMPLEMENTED_UI - values has a more suitable default for our case case. + values has a more suitable default for our case. - Examples: GLFW+Vulkan, SDL+Vulkan: handle swap chain resize even without Vulkan returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671) [@AndreiNego, @ocornut] @@ -4743,7 +5155,7 @@ Other Changes: - ColorPicker4: Fixed picker being unable to select exact 1.0f color when dragging toward the edges of the SV square (previously picked 0.999989986f). (#3517) [@rokups] - Menus: Fixed vertical alignments of MenuItem() calls within a menu bar (broken in 1.84). (#4538) -- Menus: Improve closing logic when moving diagonally in empty between between parent and child menus to +- Menus: Improve closing logic when moving diagonally in empty space between parent and child menus to accommodate for varying font size and dpi. - Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510). - Menus: Fixed an assertion happening in some situations when closing nested menus (broken in 1.83). (#4640) diff --git a/include/imgui/docs/CONTRIBUTING.md b/include/imgui/docs/CONTRIBUTING.md index fb946c4..699209f 100644 --- a/include/imgui/docs/CONTRIBUTING.md +++ b/include/imgui/docs/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## Index - [Getting Started & General Advice](#getting-started--general-advice) -- [Issues vs Discussions](#issues-vs-discussions) +- [Using "Issues" for almost everything!](using-issues-for-almost-everything) - [How to open an Issue](#how-to-open-an-issue) - [How to open a Pull Request](#how-to-open-a-pull-request) - [Copyright / Contributor License Agreement](#copyright--contributor-license-agreement) @@ -23,18 +23,20 @@ - If you get a crash or assert, use a debugger to locate the line triggering it and read the comments around. - Please don't be a [Help Vampire](https://slash7.com/2006/12/22/vampires/). -## 'Issues' vs 'Discussions' +## Using "Issues" for almost everything! -We are happy to use 'Issues' for many type of open-ended questions. We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents. +We are happy to use 'Issues' for many type of open-ended questions. +We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents. -Only if you: +- Need help using the API? Open an Issue! +- Want to suggest a feature? Open an Issue! +- etc. + +ONLY IN THOSE CASE you can use the [Discussions forums](https://github.com/ocornut/imgui/discussions) - Cannot BUILD or LINK examples. - Cannot BUILD, or LINK, or RUN Dear ImGui in your application or custom engine. -- Cannot LOAD a font. - -Then please [use the Discussions forums](https://github.com/ocornut/imgui/discussions) instead of opening an issue. -If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue. +If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new Issue. ## How to open an issue diff --git a/include/imgui/docs/EXAMPLES.md b/include/imgui/docs/EXAMPLES.md index 6315a3a..231fe7f 100644 --- a/include/imgui/docs/EXAMPLES.md +++ b/include/imgui/docs/EXAMPLES.md @@ -70,8 +70,10 @@ OSX & iOS + Metal4 example, Mac only.
[example_apple_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_opengl2/)
OSX + OpenGL2 example.
= main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp
-(NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends. - You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.) + +[example_apple_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_opengl3/)
+OSX + OpenGL3 example.
+= main.mm + imgui_impl_osx.mm + imgui_impl_opengl3.cpp
[example_glfw_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_wgpu/)
GLFW + WebGPU example. Supports Emscripten (web), Dawn (native), WGPU (native).
@@ -117,6 +119,16 @@ Because this application doesn't create a window nor a graphic context, there's Please note that imgui_impl_null itself is a rather empty backend. We provide it for consistency but it is similarly easy to create a skeleton application without the null backend. +[example_qnx_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_qnx_opengl3/)
+QNX Screen + OpenGL ES 3 example.
+= main.cpp + imgui_impl_qnx.cpp + imgui_impl_opengl3.cpp
+Uses the QNX recursive make build system and compiles the OpenGL3 renderer with `IMGUI_IMPL_OPENGL_ES3`. + +[example_qnx_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_qnx_vulkan/)
+QNX Screen + Vulkan example using `VK_QNX_screen_surface`.
+= main.cpp + imgui_impl_qnx.cpp + imgui_impl_vulkan.cpp
+Uses the QNX recursive make build system and the Vulkan backend's example helper structures. + [example_sdl2_directx11/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_directx11/)
SDL2 + DirectX11 example, Windows only.
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_dx11.cpp
diff --git a/include/imgui/docs/FAQ.md b/include/imgui/docs/FAQ.md index d676167..5e3bd1e 100644 --- a/include/imgui/docs/FAQ.md +++ b/include/imgui/docs/FAQ.md @@ -570,8 +570,8 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or inte // Store a ImTextureID _or_ a ImTextureData*. struct ImTextureRef { - ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; } - ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } + ImTextureRef() { _TexData = nullptr; _TexID = ImTextureID_Invalid; } + ImTextureRef(ImTextureID tex_id) { _TexData = nullptr; _TexID = tex_id; } inline ImTextureID GetTexID() const { return _TexData ? _TexData->TexID : _TexID; } // Members (either are set, never both!) @@ -589,7 +589,7 @@ struct ImTextureRef We intentionally do not provide an `ImTextureRef` constructor for this: we don't expect this to be frequently useful to the end-user, and it would be erroneously called by many legacy code. - There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. - If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`. - - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` + - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = nullptr, .TexID = tex_id }; return tex_ref; }` **Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.** @@ -780,7 +780,7 @@ style.FontScaleDpi = 2.0f; To change font size: ```cpp -ImGui::PushFont(NULL, 42.0f); // This will be multiplied by style.FontScaleDpi +ImGui::PushFont(nullptr, 42.0f); // This will be multiplied by style.FontScaleDpi ``` To change font and font size: ```cpp diff --git a/include/imgui/docs/FONTS.md b/include/imgui/docs/FONTS.md index ac93bca..3f1e085 100644 --- a/include/imgui/docs/FONTS.md +++ b/include/imgui/docs/FONTS.md @@ -96,7 +96,7 @@ atlas->AddFont(...); v1.92 introduces a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature: - Users of icons, Asian and non-English languages do not need to pre-build all glyphs ahead of time. Saving on loading time, memory, and also reducing issues with missing glyphs. Specifying glyph ranges is not needed anymore. -- `PushFont(NULL, new_size)` may be used anytime to change font size. +- `PushFont(nullptr, new_size)` may be used anytime to change font size. - Packing custom rectangles is more convenient as pixels may be written to immediately. - Any update to fonts previously required backend specific calls to re-upload the texture, and said calls were not portable across backends. It is now possible to scale fonts etc. in a way that doesn't require you to make backend-specific calls. - It is possible to plug a custom loader/backend to any font source. diff --git a/include/imgui/examples/example_allegro5/example_allegro5.vcxproj b/include/imgui/examples/example_allegro5/example_allegro5.vcxproj index aa8a752..36c55bb 100644 --- a/include/imgui/examples/example_allegro5/example_allegro5.vcxproj +++ b/include/imgui/examples/example_allegro5/example_allegro5.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_allegro5/main.cpp b/include/imgui/examples/example_allegro5/main.cpp index ebb6d76..577f099 100644 --- a/include/imgui/examples/example_allegro5/main.cpp +++ b/include/imgui/examples/example_allegro5/main.cpp @@ -42,21 +42,24 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup Platform/Renderer backends ImGui_ImplAllegro5_Init(display); // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_android_opengl3/main.cpp b/include/imgui/examples/example_android_opengl3/main.cpp index 382006f..edd654f 100644 --- a/include/imgui/examples/example_android_opengl3/main.cpp +++ b/include/imgui/examples/example_android_opengl3/main.cpp @@ -144,8 +144,12 @@ void Init(struct android_app* app) io.IniFilename = g_IniFilename.c_str();; // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup Platform/Renderer backends ImGui_ImplAndroid_Init(g_App->window); @@ -153,20 +157,18 @@ void Init(struct android_app* app) // Setup scaling float main_scale = 2.0f; - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Android: The TTF files have to be placed into the assets/ directory (android/app/src/main/assets), we use our GetAssetData() helper to retrieve them. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); diff --git a/include/imgui/examples/example_apple_metal/main.mm b/include/imgui/examples/example_apple_metal/main.mm index b8edbd2..cddc109 100644 --- a/include/imgui/examples/example_apple_metal/main.mm +++ b/include/imgui/examples/example_apple_metal/main.mm @@ -62,21 +62,24 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup Renderer backend ImGui_ImplMetal_Init(_device); // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_apple_metal4/main.mm b/include/imgui/examples/example_apple_metal4/main.mm index 1102e41..553eeb3 100644 --- a/include/imgui/examples/example_apple_metal4/main.mm +++ b/include/imgui/examples/example_apple_metal4/main.mm @@ -66,8 +66,12 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. @@ -76,13 +80,12 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_apple_opengl2/main.mm b/include/imgui/examples/example_apple_opengl2/main.mm index 1cfa882..67b546e 100644 --- a/include/imgui/examples/example_apple_opengl2/main.mm +++ b/include/imgui/examples/example_apple_opengl2/main.mm @@ -6,6 +6,7 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp +#define GL_SILENCE_DEPRECATION #import #import #import @@ -32,7 +33,7 @@ -(void)prepareOpenGL #ifndef DEBUG GLint swapInterval = 1; - [[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; + [[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval]; if (swapInterval == 0) NSLog(@"Error: Cannot set swap interval."); #endif @@ -49,8 +50,12 @@ -(void)initialize io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup Platform/Renderer backends ImGui_ImplOSX_Init(self); @@ -58,13 +63,12 @@ -(void)initialize // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); @@ -130,8 +134,8 @@ -(void)updateAndDrawDemoView ImDrawData* draw_data = ImGui::GetDrawData(); [[self openGLContext] makeCurrentContext]; - GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); glViewport(0, 0, width, height); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); diff --git a/include/imgui/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj b/include/imgui/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj new file mode 100644 index 0000000..50ee35f --- /dev/null +++ b/include/imgui/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj @@ -0,0 +1,334 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E31B57274EF0360083FCB6 /* GameController.framework */; }; + 07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82EDA213941D00078D120 /* imgui_widgets.cpp */; }; + 4080A99820B02D340036BA46 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A98A20B02CD90036BA46 /* main.mm */; }; + 4080A9A220B034280036BA46 /* imgui_impl_opengl3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */; }; + 4080A9AD20B0343C0036BA46 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9A620B0343C0036BA46 /* imgui_demo.cpp */; }; + 4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9A720B0343C0036BA46 /* imgui.cpp */; }; + 4080A9AF20B0343C0036BA46 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */; }; + 4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */; }; + 4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B220B034E40036BA46 /* Cocoa.framework */; }; + 4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B420B034EA0036BA46 /* OpenGL.framework */; }; + 50798230257677FD0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822F257677FC0038A28D /* imgui_tables.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4080A96920B029B00036BA46 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 05E31B57274EF0360083FCB6 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; + 07A82EDA213941D00078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = ""; }; + 4080A96B20B029B00036BA46 /* example_osx_opengl3 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = example_osx_opengl3; sourceTree = BUILT_PRODUCTS_DIR; }; + 4080A98A20B02CD90036BA46 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; }; + 4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_impl_opengl3.cpp; path = ../../backends/imgui_impl_opengl3.cpp; sourceTree = ""; }; + 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = imgui_impl_osx.mm; path = ../../backends/imgui_impl_osx.mm; sourceTree = ""; }; + 4080A9A020B034280036BA46 /* imgui_impl_opengl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_opengl3.h; path = ../../backends/imgui_impl_opengl3.h; sourceTree = ""; }; + 4080A9A120B034280036BA46 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_osx.h; path = ../../backends/imgui_impl_osx.h; sourceTree = ""; }; + 4080A9A320B034280036BA46 /* imgui_impl_opengl3_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_opengl3_loader.h; path = ../../backends/imgui_impl_opengl3_loader.h; sourceTree = ""; }; + 4080A9A520B0343C0036BA46 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = ""; }; + 4080A9A620B0343C0036BA46 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../imgui_demo.cpp; sourceTree = ""; }; + 4080A9A720B0343C0036BA46 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../imgui.cpp; sourceTree = ""; }; + 4080A9A820B0343C0036BA46 /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = ../../imgui.h; sourceTree = ""; }; + 4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../../imgui_draw.cpp; sourceTree = ""; }; + 4080A9AC20B0343C0036BA46 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = ""; }; + 4080A9B220B034E40036BA46 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 4080A9B420B034EA0036BA46 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 5079822F257677FC0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4080A96820B029B00036BA46 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */, + 4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */, + 05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4080A96220B029B00036BA46 = { + isa = PBXGroup; + children = ( + 5079822F257677FC0038A28D /* imgui_tables.cpp */, + 4080A9AC20B0343C0036BA46 /* imconfig.h */, + 4080A9A720B0343C0036BA46 /* imgui.cpp */, + 4080A9A820B0343C0036BA46 /* imgui.h */, + 07A82EDA213941D00078D120 /* imgui_widgets.cpp */, + 4080A9A620B0343C0036BA46 /* imgui_demo.cpp */, + 4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */, + 4080A9A520B0343C0036BA46 /* imgui_internal.h */, + 4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */, + 4080A9A020B034280036BA46 /* imgui_impl_opengl3.h */, + 4080A9A320B034280036BA46 /* imgui_impl_opengl3_loader.h */, + 4080A9A120B034280036BA46 /* imgui_impl_osx.h */, + 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */, + 4080A98A20B02CD90036BA46 /* main.mm */, + 4080A96C20B029B00036BA46 /* Products */, + 4080A9B120B034E40036BA46 /* Frameworks */, + ); + sourceTree = ""; + }; + 4080A96C20B029B00036BA46 /* Products */ = { + isa = PBXGroup; + children = ( + 4080A96B20B029B00036BA46 /* example_osx_opengl3 */, + ); + name = Products; + sourceTree = ""; + }; + 4080A9B120B034E40036BA46 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 05E31B57274EF0360083FCB6 /* GameController.framework */, + 4080A9B420B034EA0036BA46 /* OpenGL.framework */, + 4080A9B220B034E40036BA46 /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4080A96A20B029B00036BA46 /* example_osx_opengl3 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4080A97220B029B00036BA46 /* Build configuration list for PBXNativeTarget "example_osx_opengl3" */; + buildPhases = ( + 4080A96720B029B00036BA46 /* Sources */, + 4080A96820B029B00036BA46 /* Frameworks */, + 4080A96920B029B00036BA46 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = example_osx_opengl3; + productName = example_osx_opengl3; + productReference = 4080A96B20B029B00036BA46 /* example_osx_opengl3 */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4080A96320B029B00036BA46 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = ImGui; + TargetAttributes = { + 4080A96A20B029B00036BA46 = { + CreatedOnToolsVersion = 9.3.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl3" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4080A96220B029B00036BA46; + productRefGroup = 4080A96C20B029B00036BA46 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4080A96A20B029B00036BA46 /* example_osx_opengl3 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 4080A96720B029B00036BA46 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4080A99820B02D340036BA46 /* main.mm in Sources */, + 4080A9AD20B0343C0036BA46 /* imgui_demo.cpp in Sources */, + 4080A9AF20B0343C0036BA46 /* imgui_draw.cpp in Sources */, + 4080A9A220B034280036BA46 /* imgui_impl_opengl3.cpp in Sources */, + 4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */, + 4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */, + 50798230257677FD0038A28D /* imgui_tables.cpp in Sources */, + 07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4080A97020B029B00036BA46 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 4080A97120B029B00036BA46 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 4080A97320B029B00036BA46 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + MACOSX_DEPLOYMENT_TARGET = 10.13; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = ../..; + }; + name = Debug; + }; + 4080A97420B029B00036BA46 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + MACOSX_DEPLOYMENT_TARGET = 10.13; + PRODUCT_NAME = "$(TARGET_NAME)"; + USER_HEADER_SEARCH_PATHS = ../..; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl3" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4080A97020B029B00036BA46 /* Debug */, + 4080A97120B029B00036BA46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4080A97220B029B00036BA46 /* Build configuration list for PBXNativeTarget "example_osx_opengl3" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4080A97320B029B00036BA46 /* Debug */, + 4080A97420B029B00036BA46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4080A96320B029B00036BA46 /* Project object */; +} diff --git a/include/imgui/examples/example_apple_opengl3/main.mm b/include/imgui/examples/example_apple_opengl3/main.mm new file mode 100644 index 0000000..7cb2e2a --- /dev/null +++ b/include/imgui/examples/example_apple_opengl3/main.mm @@ -0,0 +1,263 @@ +// Dear ImGui: standalone example application for OSX + OpenGL3 + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +#define GL_SILENCE_DEPRECATION +#import +#import + +#include "imgui.h" +#include "imgui_impl_opengl3.h" +#include "imgui_impl_osx.h" + +//----------------------------------------------------------------------------------- +// AppView +//----------------------------------------------------------------------------------- + +@interface AppView : NSOpenGLView +{ + NSTimer* animationTimer; +} +@end + +@implementation AppView + +-(void)prepareOpenGL +{ + [super prepareOpenGL]; + +#ifndef DEBUG + GLint swapInterval = 1; + [[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval]; + if (swapInterval == 0) + NSLog(@"Error: Cannot set swap interval."); +#endif +} + +-(void)initialize +{ + // Setup Dear ImGui context + // FIXME: This example doesn't have proper cleanup... + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; + + // Setup Platform/Renderer backends + [[self openGLContext] makeCurrentContext]; // ImGui_ImplOpenGL3_Init() requires a current GL context. + ImGui_ImplOSX_Init(self); + ImGui_ImplOpenGL3_Init(); + + // Load Fonts + // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. + // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). + // - Read 'docs/FONTS.md' for more instructions and details. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefaultVector(); + //io.Fonts->AddFontDefaultBitmap(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); + //IM_ASSERT(font != nullptr); +} + +-(void)updateAndDrawDemoView +{ + // Start the Dear ImGui frame + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplOSX_NewFrame(self); + ImGui::NewFrame(); + + // Our state (make them static = more or less global) as a convenience to keep the example terse. + static bool show_demo_window = true; + static bool show_another_window = false; + static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + + [[self openGLContext] makeCurrentContext]; + GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); + glViewport(0, 0, width, height); + glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + + ImGui_ImplOpenGL3_RenderDrawData(draw_data); + + // Present + [[self openGLContext] flushBuffer]; + + if (!animationTimer) + animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES]; +} + +-(void)reshape { [super reshape]; [[self openGLContext] update]; [self updateAndDrawDemoView]; } +-(void)drawRect:(NSRect)bounds { [self updateAndDrawDemoView]; } +-(void)animationTimerFired:(NSTimer*)timer { [self setNeedsDisplay:YES]; } +-(void)dealloc { animationTimer = nil; } + +@end + +//----------------------------------------------------------------------------------- +// AppDelegate +//----------------------------------------------------------------------------------- + +@interface AppDelegate : NSObject +@property (nonatomic, readonly) NSWindow* window; +@end + +@implementation AppDelegate +@synthesize window = _window; + +-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication +{ + return YES; +} + +-(NSWindow*)window +{ + if (_window != nil) + return _window; + + NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 800.0); + + _window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:YES]; + [_window setTitle:@"Dear ImGui OSX+OpenGL3 Example"]; + [_window setAcceptsMouseMovedEvents:YES]; + [_window setOpaque:YES]; + [_window makeKeyAndOrderFront:NSApp]; + + return _window; +} + +-(void)setupMenu +{ + NSMenu* mainMenuBar = [[NSMenu alloc] init]; + NSMenu* appMenu; + NSMenuItem* menuItem; + + appMenu = [[NSMenu alloc] initWithTitle:@"Dear ImGui OSX+OpenGL3 Example"]; + menuItem = [appMenu addItemWithTitle:@"Quit Dear ImGui OSX+OpenGL3 Example" action:@selector(terminate:) keyEquivalent:@"q"]; + [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; + + menuItem = [[NSMenuItem alloc] init]; + [menuItem setSubmenu:appMenu]; + + [mainMenuBar addItem:menuItem]; + + appMenu = nil; + [NSApp setMainMenu:mainMenuBar]; +} + +-(void)dealloc +{ + _window = nil; +} + +-(void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + // Make the application a foreground application (else it won't receive keyboard events) + ProcessSerialNumber psn = {0, kCurrentProcess}; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + + // Menu + [self setupMenu]; + + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 32, + 0 + }; + + NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + AppView* view = [[AppView alloc] initWithFrame:self.window.frame pixelFormat:format]; + format = nil; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) + [view setWantsBestResolutionOpenGLSurface:YES]; +#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + [self.window setContentView:view]; + + if ([view openGLContext] == nil) + NSLog(@"No OpenGL Context!"); + + [view initialize]; +} + +@end + +//----------------------------------------------------------------------------------- +// Application main() function +//----------------------------------------------------------------------------------- + +int main(int argc, const char* argv[]) +{ + @autoreleasepool + { + NSApp = [NSApplication sharedApplication]; + AppDelegate* delegate = [[AppDelegate alloc] init]; + [[NSApplication sharedApplication] setDelegate:delegate]; + [NSApp run]; + } + return NSApplicationMain(argc, argv); +} diff --git a/include/imgui/examples/example_glfw_metal/main.mm b/include/imgui/examples/example_glfw_metal/main.mm index 0ded0a3..d398adc 100644 --- a/include/imgui/examples/example_glfw_metal/main.mm +++ b/include/imgui/examples/example_glfw_metal/main.mm @@ -46,11 +46,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -58,18 +61,17 @@ int main(int, char**) id commandQueue = [device newCommandQueue]; // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplGlfw_InitForOther(window, true); ImGui_ImplMetal_Init(device); // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj b/include/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj index bce5781..18d9589 100644 --- a/include/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj +++ b/include/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_glfw_opengl2/main.cpp b/include/imgui/examples/example_glfw_opengl2/main.cpp index 48584ea..454849c 100644 --- a/include/imgui/examples/example_glfw_opengl2/main.cpp +++ b/include/imgui/examples/example_glfw_opengl2/main.cpp @@ -55,11 +55,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -69,13 +72,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj b/include/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj index cd59dae..3e9d71e 100644 --- a/include/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj +++ b/include/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_glfw_opengl3/main.cpp b/include/imgui/examples/example_glfw_opengl3/main.cpp index fbcc3e5..5abf465 100644 --- a/include/imgui/examples/example_glfw_opengl3/main.cpp +++ b/include/imgui/examples/example_glfw_opengl3/main.cpp @@ -83,11 +83,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -100,14 +103,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/include/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj index 6f44abf..492aa0e 100644 --- a/include/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj +++ b/include/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj @@ -93,6 +93,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -109,6 +110,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_glfw_vulkan/main.cpp b/include/imgui/examples/example_glfw_vulkan/main.cpp index f2139ce..e5f4d75 100644 --- a/include/imgui/examples/example_glfw_vulkan/main.cpp +++ b/include/imgui/examples/example_glfw_vulkan/main.cpp @@ -392,11 +392,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -422,13 +425,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_glfw_wgpu/CMakeLists.txt b/include/imgui/examples/example_glfw_wgpu/CMakeLists.txt index 4eaaee7..b760548 100644 --- a/include/imgui/examples/example_glfw_wgpu/CMakeLists.txt +++ b/include/imgui/examples/example_glfw_wgpu/CMakeLists.txt @@ -1,10 +1,3 @@ -# Building for desktop with Dawn: -# 1. git clone https://github.com/google/dawn dawn -# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn -# 3. cmake --build build -# The resulting binary will be found at one of the following locations: -# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe] - # Building for desktop with WGPU-Native: # 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases # 2. unzip the downloaded file in your_preferred_folder @@ -13,7 +6,14 @@ # The resulting binary will be found at one of the following locations: # * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe] -# Building for desktop with WGVK (MUCH EASIER) +# Building for desktop with Dawn: (VERY LONG TO BUILD) +# 1. git clone https://github.com/google/dawn dawn +# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn +# 3. cmake --build build +# The resulting binary will be found at one of the following locations: +# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe] + +# Building for desktop with WGVK: # 1. git clone https://github.com/manuel5975p/WGVK wgvk # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk # 3. cmake --build build @@ -29,7 +29,7 @@ # 4. emrun build/index.html cmake_minimum_required(VERSION 3.22) # Dawn requires CMake >= 3.22 -project(imgui_example_glfw_wgpu C CXX) +project(example_glfw_wgpu C CXX) set(IMGUI_EXECUTABLE example_glfw_wgpu) diff --git a/include/imgui/examples/example_glfw_wgpu/main.cpp b/include/imgui/examples/example_glfw_wgpu/main.cpp index 9d48258..441da4a 100644 --- a/include/imgui/examples/example_glfw_wgpu/main.cpp +++ b/include/imgui/examples/example_glfw_wgpu/main.cpp @@ -89,11 +89,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -111,14 +114,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS @@ -290,6 +292,16 @@ int main(int, char**) return 0; } +static WGPUTextureFormat SelectSurfaceFormat(const WGPUSurfaceCapabilities& capabilities) +{ + const WGPUTextureFormat preferredFormats[] = { WGPUTextureFormat_BGRA8Unorm, WGPUTextureFormat_RGBA8Unorm, WGPUTextureFormat_BGRA8UnormSrgb, WGPUTextureFormat_RGBA8UnormSrgb }; + for (WGPUTextureFormat preferredFormat : preferredFormats) + for (size_t n = 0; n < capabilities.formatCount; n++) + if (capabilities.formats[n] == preferredFormat) + return preferredFormat; + return capabilities.formatCount > 0 ? capabilities.formats[0] : WGPUTextureFormat_Undefined; +} + #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) static WGPUAdapter RequestAdapter(wgpu::Instance& instance) { @@ -344,29 +356,25 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestAdapterStatus_Success) - { - WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; - *extAdapter = adapter; - } - else + if (status != WGPURequestAdapterStatus_Success) { - printf("Request_adapter status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; + *extAdapter = adapter; } static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestDeviceStatus_Success) + if (status != WGPURequestDeviceStatus_Success) { - WGPUDevice* extDevice = (WGPUDevice*)userdata1; - *extDevice = device; - } - else - { - printf("Request_device status=%#.8x message=%.*s\n", status, (int) message.length, message.data); + printf("Request_device status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUDevice* extDevice = (WGPUDevice*)userdata1; + *extDevice = device; } static WGPUAdapter RequestAdapter(WGPUInstance& instance) @@ -380,8 +388,10 @@ static WGPUAdapter RequestAdapter(WGPUInstance& instance) adapterCallbackInfo.userdata1 = &local_adapter; WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, adapterCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#endif IM_ASSERT(local_adapter && "Error on Adapter request"); return local_adapter; } @@ -393,15 +403,20 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) deviceCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly; deviceCallbackInfo.callback = handle_request_device; deviceCallbackInfo.userdata1 = &local_device; + WGPUFuture future = wgpuAdapterRequestDevice(adapter, nullptr, deviceCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#else + IM_UNUSED(instance); +#endif IM_ASSERT(local_device && "Error on Device request"); return local_device; } #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU -bool InitWGPU(GLFWwindow* window) +static bool InitWGPU(GLFWwindow* window) { WGPUTextureFormat preferred_fmt = WGPUTextureFormat_Undefined; // acquired from SurfaceCapabilities @@ -437,8 +452,7 @@ bool InitWGPU(GLFWwindow* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter.Get(), &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); // WGPU backend: Adapter and Device acquisition, Surface creation #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) @@ -450,7 +464,7 @@ bool InitWGPU(GLFWwindow* window) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) wgpuSetLogCallback( - [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr + [](WGPULogLevel level, WGPUStringView msg, void*) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); wgpuSetLogLevel(WGPULogLevel_Warn); #endif @@ -467,8 +481,7 @@ bool InitWGPU(GLFWwindow* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; @@ -548,7 +561,7 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, GLFWwindow* window) { create_info.System = "win32"; create_info.RawWindow = (void*)glfwGetWin32Window(window); - create_info.RawInstance = (void*)::GetModuleHandle(NULL); + create_info.RawInstance = (void*)::GetModuleHandle(nullptr); return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info); } #else diff --git a/include/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj b/include/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj index 2e12665..bdd9af4 100644 --- a/include/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj +++ b/include/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj @@ -92,6 +92,7 @@ Disabled $(GLUT_INCLUDE_DIR);..\..;..\..\backends;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled $(GLUT_INCLUDE_DIR);..\..;..\..\backends;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_glut_opengl2/main.cpp b/include/imgui/examples/example_glut_opengl2/main.cpp index ca8017f..227dad4 100644 --- a/include/imgui/examples/example_glut_opengl2/main.cpp +++ b/include/imgui/examples/example_glut_opengl2/main.cpp @@ -63,8 +63,12 @@ int main(int argc, char** argv) io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup Platform/Renderer backends // FIXME: Consider reworking this example to install our own GLUT funcs + forward calls ImGui_ImplGLUT_XXX ones, instead of using ImGui_ImplGLUT_InstallFuncs(). @@ -80,13 +84,12 @@ int main(int argc, char** argv) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_null/example_null.vcxproj b/include/imgui/examples/example_null/example_null.vcxproj index 75fd43b..61e388f 100644 --- a/include/imgui/examples/example_null/example_null.vcxproj +++ b/include/imgui/examples/example_null/example_null.vcxproj @@ -88,6 +88,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true @@ -102,6 +103,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_null/main.cpp b/include/imgui/examples/example_null/main.cpp index eba6756..ee6319f 100644 --- a/include/imgui/examples/example_null/main.cpp +++ b/include/imgui/examples/example_null/main.cpp @@ -16,6 +16,14 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); + // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; + ImGui_ImplNullPlatform_Init(); ImGui_ImplNullRender_Init(); diff --git a/include/imgui/examples/example_qnx_opengl3/README.md b/include/imgui/examples/example_qnx_opengl3/README.md new file mode 100644 index 0000000..2fd97d6 --- /dev/null +++ b/include/imgui/examples/example_qnx_opengl3/README.md @@ -0,0 +1,29 @@ +# Dear ImGui QNX Screen + OpenGL ES 3 example + +This example uses: + +- `imgui_impl_qnx.cpp` as the QNX Screen platform backend +- `imgui_impl_opengl3.cpp` as the renderer backend +- EGL to create an OpenGL ES 3 context and Screen window surface + +`imgui_impl_opengl3.cpp` supports desktop OpenGL and OpenGL ES. On QNX this +example compiles it with `IMGUI_IMPL_OPENGL_ES3` and uses `#version 300 es`. +No separate Screen/OpenGL renderer backend is required. + +## Build + +Load the QNX SDP environment, then run: + +```sh +cd examples/example_qnx_opengl3 +make +``` + +The QNX recursive make files build for the CPUs enabled in your SDP +configuration and install the program as `example_qnx_opengl3`. + +## Input + +The application polls its `screen_context_t` event queue and forwards every +non-`SCREEN_EVENT_NONE` event to `ImGui_ImplQNX_ProcessEvent()`. +Escape exits the example. diff --git a/include/imgui/examples/example_qnx_opengl3/common.mk b/include/imgui/examples/example_qnx_opengl3/common.mk new file mode 100644 index 0000000..d162d68 --- /dev/null +++ b/include/imgui/examples/example_qnx_opengl3/common.mk @@ -0,0 +1,31 @@ +ifndef QCONFIG +QCONFIG=qconfig.mk +endif +include $(QCONFIG) + +NAME=example_qnx_opengl3 + +SRCS = \ + main.cpp \ + imgui.cpp \ + imgui_demo.cpp \ + imgui_draw.cpp \ + imgui_tables.cpp \ + imgui_widgets.cpp \ + imgui_impl_qnx.cpp \ + imgui_impl_opengl3.cpp + +EXTRA_SRCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends +EXTRA_INCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends + +CXXFLAGS += -std=gnu++11 -DIMGUI_IMPL_OPENGL_ES3 +LIBS += EGL GLESv2 screen m + +INSTALLDIR=$(firstword $(INSTALLDIR_$(OS)) usr/bin) + +define PINFO +PINFO DESCRIPTION=Dear ImGui QNX Screen and OpenGL ES 3 example +endef + +include $(MKFILES_ROOT)/qmacros.mk +include $(MKFILES_ROOT)/qtargets.mk diff --git a/include/imgui/examples/example_qnx_opengl3/main.cpp b/include/imgui/examples/example_qnx_opengl3/main.cpp new file mode 100644 index 0000000..f7f3f4a --- /dev/null +++ b/include/imgui/examples/example_qnx_opengl3/main.cpp @@ -0,0 +1,309 @@ +// Dear ImGui: standalone example application for QNX Screen + OpenGL ES 3 + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +#include "imgui.h" +#include "imgui_impl_qnx.h" +#include "imgui_impl_opengl3.h" +#include // printf, fprintf +#include +#include +#include +#include +#include +#include + +#ifndef EGL_OPENGL_ES3_BIT +#ifdef EGL_OPENGL_ES3_BIT_KHR +#define EGL_OPENGL_ES3_BIT EGL_OPENGL_ES3_BIT_KHR +#else +#define EGL_OPENGL_ES3_BIT 0x0040 +#endif +#endif + +struct QNXWindow +{ + screen_context_t Context = nullptr; + screen_window_t Window = nullptr; + screen_event_t Event = nullptr; + EGLDisplay Display = EGL_NO_DISPLAY; + EGLContext GLContext = EGL_NO_CONTEXT; + EGLSurface GLSurface = EGL_NO_SURFACE; + int Size[2] = {}; +}; + +// Forward declarations of helper functions +bool CreateQNXWindow(QNXWindow* window); +void DestroyQNXWindow(QNXWindow* window); +bool ProcessQNXEvents(QNXWindow* window); + +// Main code +int main(int, char**) +{ + // Setup QNX Screen and EGL + QNXWindow window; + if (!CreateQNXWindow(&window)) + { + DestroyQNXWindow(&window); + return 1; + } + + // GL ES 3.0 + GLSL 300 es + const char* glsl_version = "#version 300 es"; + float main_scale = 1.0f; + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + + // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; + + // Setup scaling + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) + + // Setup Platform/Renderer backends + ImGui_ImplQNX_Init(window.Context, window.Window); + ImGui_ImplOpenGL3_Init(glsl_version); + + // Load Fonts + // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. + // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). + // - Read 'docs/FONTS.md' for more instructions and details. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefaultVector(); + //io.Fonts->AddFontDefaultBitmap(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + if (!ProcessQNXEvents(&window)) + done = true; + + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplQNX_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); + glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + eglSwapBuffers(window.Display, window.GLSurface); + } + + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplQNX_Shutdown(); + ImGui::DestroyContext(); + + DestroyQNXWindow(&window); + + return 0; +} + +// Helper functions + +bool CreateQNXWindow(QNXWindow* window) +{ + if (screen_create_context(&window->Context, 0) != 0 || + screen_create_window(&window->Window, window->Context) != 0 || + screen_create_event(&window->Event) != 0) + { + fprintf(stderr, "QNX Screen initialization failed: %s\n", strerror(errno)); + return false; + } + + // A newly created QNX Screen window reports the fullscreen dimensions. + if (screen_get_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || window->Size[0] <= 0 || window->Size[1] <= 0) + { + fprintf(stderr, "Failed to obtain QNX Screen window size: %s\n", strerror(errno)); + return false; + } + + const int usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_OPENGL_ES3 | SCREEN_USAGE_NATIVE; + const int transparency = SCREEN_TRANSPARENCY_NONE; + const int swap_interval = 1; + if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_USAGE, &usage) != 0 || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_TRANSPARENCY, &transparency) != 0 || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SWAP_INTERVAL, &swap_interval) != 0) + { + fprintf(stderr, "Failed to configure QNX Screen window: %s\n", strerror(errno)); + return false; + } + + window->Display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (window->Display == EGL_NO_DISPLAY || eglInitialize(window->Display, nullptr, nullptr) != EGL_TRUE || eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE) + { + fprintf(stderr, "EGL initialization failed: 0x%04x\n", eglGetError()); + return false; + } + + const EGLint config_attributes[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + EGLConfig config = nullptr; + EGLint config_count = 0; + if (eglChooseConfig(window->Display, config_attributes, &config, 1, &config_count) != EGL_TRUE || config_count == 0) + { + fprintf(stderr, "eglChooseConfig() failed: 0x%04x\n", eglGetError()); + return false; + } + + EGLint native_visual = 0; + if (eglGetConfigAttrib(window->Display, config, EGL_NATIVE_VISUAL_ID, &native_visual) != EGL_TRUE || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_FORMAT, &native_visual) != 0 || + screen_create_window_buffers(window->Window, 2) != 0) + { + fprintf(stderr, "Failed to create QNX Screen buffers: %s\n", strerror(errno)); + return false; + } + + const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; + window->GLContext = eglCreateContext(window->Display, config, EGL_NO_CONTEXT, context_attributes); + window->GLSurface = eglCreateWindowSurface(window->Display, config, window->Window, nullptr); + if (window->GLContext == EGL_NO_CONTEXT || window->GLSurface == EGL_NO_SURFACE || + eglMakeCurrent(window->Display, window->GLSurface, window->GLSurface, window->GLContext) != EGL_TRUE || + eglSwapInterval(window->Display, 1) != EGL_TRUE) + { + fprintf(stderr, "EGL context creation failed: 0x%04x\n", eglGetError()); + return false; + } + + const int visible = 1; + if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_VISIBLE, &visible) != 0) + { + fprintf(stderr, "Failed to show QNX Screen window: %s\n", strerror(errno)); + return false; + } + return true; +} + +void DestroyQNXWindow(QNXWindow* window) +{ + if (window->Display != EGL_NO_DISPLAY) + { + eglMakeCurrent(window->Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (window->GLSurface != EGL_NO_SURFACE) + eglDestroySurface(window->Display, window->GLSurface); + if (window->GLContext != EGL_NO_CONTEXT) + eglDestroyContext(window->Display, window->GLContext); + eglTerminate(window->Display); + } + if (window->Event != nullptr) + screen_destroy_event(window->Event); + if (window->Window != nullptr) + screen_destroy_window(window->Window); + if (window->Context != nullptr) + screen_destroy_context(window->Context); +} + +bool ProcessQNXEvents(QNXWindow* window) +{ + for (;;) + { + if (screen_get_event(window->Context, window->Event, 0) != 0) + return false; + + int type = SCREEN_EVENT_NONE; + if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_TYPE, &type) != 0) + return false; + if (type == SCREEN_EVENT_NONE) + return true; + + ImGui_ImplQNX_ProcessEvent(window->Event); + if (type == SCREEN_EVENT_CLOSE) + return false; + if (type == SCREEN_EVENT_KEYBOARD) + { + int flags = 0; + int key_cap = 0; + if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_FLAGS, &flags) == 0 && + screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_KEY_CAP, &key_cap) == 0 && + (flags & SCREEN_FLAG_KEY_DOWN) != 0 && key_cap == KEYCODE_ESCAPE) + return false; + } + } +} + diff --git a/include/imgui/examples/example_qnx_vulkan/README.md b/include/imgui/examples/example_qnx_vulkan/README.md new file mode 100644 index 0000000..13eba6f --- /dev/null +++ b/include/imgui/examples/example_qnx_vulkan/README.md @@ -0,0 +1,29 @@ +# Dear ImGui QNX Screen + Vulkan example + +This example uses: + +- `imgui_impl_qnx.cpp` as the QNX Screen platform backend +- the unmodified `imgui_impl_vulkan.cpp` renderer backend +- `vkCreateScreenSurfaceQNX()` and `VK_QNX_screen_surface` + +No separate Screen/Vulkan renderer backend is required. The QNX-specific work +is limited to the Screen platform backend, native window setup, and Vulkan WSI +surface creation. + +## Build + +Load the QNX SDP environment, then run: + +```sh +cd examples/example_qnx_vulkan +make +``` + +The build defines `VK_USE_PLATFORM_SCREEN_QNX` and links `libvulkan` and +`libscreen`. + +## Input and resize + +The application forwards Screen input events to `ImGui_ImplQNX_ProcessEvent()`. +It recreates the Vulkan swapchain when the Screen window size changes or Vulkan +reports `VK_ERROR_OUT_OF_DATE_KHR` / `VK_SUBOPTIMAL_KHR`. Escape exits. diff --git a/include/imgui/examples/example_qnx_vulkan/common.mk b/include/imgui/examples/example_qnx_vulkan/common.mk new file mode 100644 index 0000000..7d99539 --- /dev/null +++ b/include/imgui/examples/example_qnx_vulkan/common.mk @@ -0,0 +1,31 @@ +ifndef QCONFIG +QCONFIG=qconfig.mk +endif +include $(QCONFIG) + +NAME=example_qnx_vulkan + +SRCS = \ + main.cpp \ + imgui.cpp \ + imgui_demo.cpp \ + imgui_draw.cpp \ + imgui_tables.cpp \ + imgui_widgets.cpp \ + imgui_impl_qnx.cpp \ + imgui_impl_vulkan.cpp + +EXTRA_SRCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends +EXTRA_INCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends + +CXXFLAGS += -std=gnu++11 -DVK_USE_PLATFORM_SCREEN_QNX=1 +LIBS += vulkan screen m + +INSTALLDIR=$(firstword $(INSTALLDIR_$(OS)) usr/bin) + +define PINFO +PINFO DESCRIPTION=Dear ImGui QNX Screen and Vulkan example +endef + +include $(MKFILES_ROOT)/qmacros.mk +include $(MKFILES_ROOT)/qtargets.mk diff --git a/include/imgui/examples/example_qnx_vulkan/main.cpp b/include/imgui/examples/example_qnx_vulkan/main.cpp new file mode 100644 index 0000000..1d596d7 --- /dev/null +++ b/include/imgui/examples/example_qnx_vulkan/main.cpp @@ -0,0 +1,628 @@ +// Dear ImGui: standalone example application for QNX Screen + Vulkan + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. +// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. +// You will use those if you want to use this rendering backend in your engine/app. +// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by +// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. +// Read comments in imgui_impl_vulkan.h. + +#ifndef VK_USE_PLATFORM_SCREEN_QNX +#define VK_USE_PLATFORM_SCREEN_QNX +#endif +#include "imgui.h" +#include "imgui_impl_qnx.h" +#include "imgui_impl_vulkan.h" +#include // printf, fprintf +#include // abort +#include +#include +#include +#include +#include + +// Volk headers +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK +#define VOLK_IMPLEMENTATION +#include +#endif + +//#define APP_USE_UNLIMITED_FRAME_RATE +#ifdef _DEBUG +#define APP_USE_VULKAN_DEBUG_REPORT +static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; +#endif + +// Data +static VkAllocationCallbacks* g_Allocator = nullptr; +static VkInstance g_Instance = VK_NULL_HANDLE; +static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static uint32_t g_QueueFamily = (uint32_t)-1; +static VkQueue g_Queue = VK_NULL_HANDLE; +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; + +static ImGui_ImplVulkanH_Window g_MainWindowData; +static uint32_t g_MinImageCount = 2; +static bool g_SwapChainRebuild = false; + +static void check_vk_result(VkResult err) +{ + if (err == VK_SUCCESS) + return; + fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); + if (err < 0) + abort(); +} + +#ifdef APP_USE_VULKAN_DEBUG_REPORT +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) +{ + (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments + fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); + return VK_FALSE; +} +#endif // APP_USE_VULKAN_DEBUG_REPORT + +static bool IsExtensionAvailable(const ImVector& properties, const char* extension) +{ + for (const VkExtensionProperties& p : properties) + if (strcmp(p.extensionName, extension) == 0) + return true; + return false; +} + +static void SetupVulkan(ImVector instance_extensions) +{ + VkResult err; +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK + volkInitialize(); +#endif + + // Create Vulkan Instance + { + VkInstanceCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + + // Enumerate available extensions + uint32_t properties_count; + ImVector properties; + vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, nullptr); + properties.resize(properties_count); + err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, properties.Data); + check_vk_result(err); + + // Enable required extensions + if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) + { + instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } +#endif + + // Enabling validation layers +#ifdef APP_USE_VULKAN_DEBUG_REPORT + const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; + create_info.enabledLayerCount = 1; + create_info.ppEnabledLayerNames = layers; + instance_extensions.push_back("VK_EXT_debug_report"); +#endif + + // Create Vulkan Instance + create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size; + create_info.ppEnabledExtensionNames = instance_extensions.Data; + err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); + check_vk_result(err); +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK + volkLoadInstance(g_Instance); +#endif + + // Setup the debug report callback +#ifdef APP_USE_VULKAN_DEBUG_REPORT + auto f_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); + IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr); + VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; + debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + debug_report_ci.pfnCallback = debug_report; + debug_report_ci.pUserData = nullptr; + err = f_vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport); + check_vk_result(err); +#endif + } + + // Select Physical Device (GPU) + g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); + IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); + + // Select graphics queue family + g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); + + // Create Logical Device (with 1 queue) + { + ImVector device_extensions; + device_extensions.push_back("VK_KHR_swapchain"); + + // Enumerate physical device extension + uint32_t properties_count; + ImVector properties; + vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr); + properties.resize(properties_count); + vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, properties.Data); +#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) + device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); +#endif + + const float queue_priority[] = { 1.0f }; + VkDeviceQueueCreateInfo queue_info[1] = {}; + queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_info[0].queueFamilyIndex = g_QueueFamily; + queue_info[0].queueCount = 1; + queue_info[0].pQueuePriorities = queue_priority; + VkDeviceCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]); + create_info.pQueueCreateInfos = queue_info; + create_info.enabledExtensionCount = (uint32_t)device_extensions.Size; + create_info.ppEnabledExtensionNames = device_extensions.Data; + err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device); + check_vk_result(err); + vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue); + } + + // Create Descriptor Pool + // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. + { + VkDescriptorPoolSize pool_sizes[] = + { + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE }, + }; + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = 0; + for (VkDescriptorPoolSize& pool_size : pool_sizes) + pool_info.maxSets += pool_size.descriptorCount; + pool_info.poolSizeCount = (uint32_t)IM_COUNTOF(pool_sizes); + pool_info.pPoolSizes = pool_sizes; + err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); + check_vk_result(err); + } +} + +// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo. +// Your real engine/app may not use them. +static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) +{ + // Check for WSI support + VkBool32 res; + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res); + if (res != VK_TRUE) + { + fprintf(stderr, "Error no WSI support on physical device 0\n"); + exit(-1); + } + + // Select Surface Format + const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; + const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->Surface = surface; + wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace); + + // Select Present Mode +#ifdef APP_USE_UNLIMITED_FRAME_RATE + VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; +#else + VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; +#endif + wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_COUNTOF(present_modes)); + //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode); + + // Create SwapChain, RenderPass, Framebuffer, etc. + IM_ASSERT(g_MinImageCount >= 2); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0); +} + +static void CleanupVulkan() +{ + vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); + +#ifdef APP_USE_VULKAN_DEBUG_REPORT + // Remove the debug report callback + auto f_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); + f_vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); +#endif // APP_USE_VULKAN_DEBUG_REPORT + + vkDestroyDevice(g_Device, g_Allocator); + vkDestroyInstance(g_Instance, g_Allocator); +} + +static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd) +{ + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator); + vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator); +} + +static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) +{ + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; + VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) + return; + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); + + ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; + { + err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking + check_vk_result(err); + + err = vkResetFences(g_Device, 1, &fd->Fence); + check_vk_result(err); + } + { + err = vkResetCommandPool(g_Device, fd->CommandPool, 0); + check_vk_result(err); + VkCommandBufferBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(fd->CommandBuffer, &info); + check_vk_result(err); + } + { + VkRenderPassBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.renderPass = wd->RenderPass; + info.framebuffer = fd->Framebuffer; + info.renderArea.extent.width = wd->Width; + info.renderArea.extent.height = wd->Height; + info.clearValueCount = 1; + info.pClearValues = &wd->ClearValue; + vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); + } + + // Record dear imgui primitives into command buffer + ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer); + + // Submit command buffer + vkCmdEndRenderPass(fd->CommandBuffer); + { + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &image_acquired_semaphore; + info.pWaitDstStageMask = &wait_stage; + info.commandBufferCount = 1; + info.pCommandBuffers = &fd->CommandBuffer; + info.signalSemaphoreCount = 1; + info.pSignalSemaphores = &render_complete_semaphore; + + err = vkEndCommandBuffer(fd->CommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); + check_vk_result(err); + } +} + +static void FramePresent(ImGui_ImplVulkanH_Window* wd) +{ + if (g_SwapChainRebuild) + return; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &render_complete_semaphore; + info.swapchainCount = 1; + info.pSwapchains = &wd->Swapchain; + info.pImageIndices = &wd->FrameIndex; + VkResult err = vkQueuePresentKHR(g_Queue, &info); + if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) + return; + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores +} + + +struct QNXWindow +{ + screen_context_t Context = nullptr; + screen_window_t Window = nullptr; + screen_event_t Event = nullptr; + int Size[2] = {}; +}; + +static bool CreateQNXWindow(QNXWindow* window) +{ + if (screen_create_context(&window->Context, 0) != 0 || + screen_create_window(&window->Window, window->Context) != 0 || + screen_create_event(&window->Event) != 0) + { + fprintf(stderr, "QNX Screen initialization failed: %s\n", strerror(errno)); + return false; + } + + // A newly created QNX Screen window reports the fullscreen dimensions. + if (screen_get_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || window->Size[0] <= 0 || window->Size[1] <= 0) + { + fprintf(stderr, "Failed to obtain QNX Screen window size: %s\n", strerror(errno)); + return false; + } + + const int usage = SCREEN_USAGE_VULKAN | SCREEN_USAGE_NATIVE; + const int transparency = SCREEN_TRANSPARENCY_NONE; + if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_USAGE, &usage) != 0 || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || + screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_TRANSPARENCY, &transparency) != 0) + { + fprintf(stderr, "Failed to configure QNX Screen window: %s\n", strerror(errno)); + return false; + } + return true; +} + +static void DestroyQNXWindow(QNXWindow* window) +{ + if (window->Event != nullptr) + screen_destroy_event(window->Event); + if (window->Window != nullptr) + screen_destroy_window(window->Window); + if (window->Context != nullptr) + screen_destroy_context(window->Context); +} + +static bool ProcessQNXEvents(QNXWindow* window) +{ + for (;;) + { + if (screen_get_event(window->Context, window->Event, 0) != 0) + return false; + + int type = SCREEN_EVENT_NONE; + if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_TYPE, &type) != 0) + return false; + if (type == SCREEN_EVENT_NONE) + return true; + + ImGui_ImplQNX_ProcessEvent(window->Event); + if (type == SCREEN_EVENT_CLOSE) + return false; + if (type == SCREEN_EVENT_KEYBOARD) + { + int flags = 0; + int key_cap = 0; + if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_FLAGS, &flags) == 0 && + screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_KEY_CAP, &key_cap) == 0 && + (flags & SCREEN_FLAG_KEY_DOWN) != 0 && key_cap == KEYCODE_ESCAPE) + return false; + } + } +} + +static void QNXSleep(int milliseconds) +{ + struct timespec request = { milliseconds / 1000, (milliseconds % 1000) * 1000000L }; + nanosleep(&request, nullptr); +} + +// Main code +int main(int, char**) +{ + // Create window with Vulkan graphics context + QNXWindow window; + if (!CreateQNXWindow(&window)) + { + DestroyQNXWindow(&window); + return 1; + } + float main_scale = 1.0f; + + ImVector extensions; + extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + extensions.push_back(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME); + SetupVulkan(extensions); + + // Create Window Surface + VkScreenSurfaceCreateInfoQNX surface_create_info = {}; + surface_create_info.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX; + surface_create_info.context = window.Context; + surface_create_info.window = window.Window; + VkSurfaceKHR surface; + VkResult err = vkCreateScreenSurfaceQNX(g_Instance, &surface_create_info, g_Allocator, &surface); + check_vk_result(err); + + // Create Framebuffers + int w = window.Size[0]; + int h = window.Size[1]; + ImGui_ImplVulkanH_Window* wd = &g_MainWindowData; + SetupVulkanWindow(wd, surface, w, h); + + const int visible = 1; + if (screen_set_window_property_iv(window.Window, SCREEN_PROPERTY_VISIBLE, &visible) != 0) + { + fprintf(stderr, "Failed to show QNX Screen window: %s\n", strerror(errno)); + return 1; + } + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + + // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; + + // Setup scaling + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) + + // Setup Platform/Renderer backends + ImGui_ImplQNX_Init(window.Context, window.Window); + ImGui_ImplVulkan_InitInfo init_info = {}; + //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. + init_info.Instance = g_Instance; + init_info.PhysicalDevice = g_PhysicalDevice; + init_info.Device = g_Device; + init_info.QueueFamily = g_QueueFamily; + init_info.Queue = g_Queue; + init_info.PipelineCache = g_PipelineCache; + init_info.DescriptorPool = g_DescriptorPool; + init_info.MinImageCount = g_MinImageCount; + init_info.ImageCount = wd->ImageCount; + init_info.Allocator = g_Allocator; + init_info.PipelineInfoMain.RenderPass = wd->RenderPass; + init_info.PipelineInfoMain.Subpass = 0; + init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + init_info.CheckVkResultFn = check_vk_result; + ImGui_ImplVulkan_Init(&init_info); + + // Load Fonts + // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. + // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). + // - Read 'docs/FONTS.md' for more instructions and details. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefaultVector(); + //io.Fonts->AddFontDefaultBitmap(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + if (!ProcessQNXEvents(&window)) + done = true; + + // Resize swap chain? + int framebuffer_size[2] = {}; + if (screen_get_window_property_iv(window.Window, SCREEN_PROPERTY_SIZE, framebuffer_size) != 0) + done = true; + int fb_width = framebuffer_size[0]; + int fb_height = framebuffer_size[1]; + if (fb_width <= 0 || fb_height <= 0) + { + QNXSleep(10); + continue; + } + if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height)) + { + ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0); + g_MainWindowData.FrameIndex = 0; + g_SwapChainRebuild = false; + } + + // Start the Dear ImGui frame + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplQNX_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); + if (!is_minimized) + { + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; + wd->ClearValue.color.float32[3] = clear_color.w; + FrameRender(wd, draw_data); + FramePresent(wd); + } + } + + // Cleanup + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplQNX_Shutdown(); + ImGui::DestroyContext(); + + CleanupVulkanWindow(&g_MainWindowData); + CleanupVulkan(); + + DestroyQNXWindow(&window); + + return 0; +} diff --git a/include/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj b/include/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj index 2bcc709..afa9d5d 100644 --- a/include/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj +++ b/include/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj @@ -93,6 +93,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -108,6 +109,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl2_directx11/main.cpp b/include/imgui/examples/example_sdl2_directx11/main.cpp index cf39716..c5bbc3b 100644 --- a/include/imgui/examples/example_sdl2_directx11/main.cpp +++ b/include/imgui/examples/example_sdl2_directx11/main.cpp @@ -77,11 +77,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -91,13 +94,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl2_metal/main.mm b/include/imgui/examples/example_sdl2_metal/main.mm index ea2afda..344310a 100644 --- a/include/imgui/examples/example_sdl2_metal/main.mm +++ b/include/imgui/examples/example_sdl2_metal/main.mm @@ -10,34 +10,87 @@ #include "imgui.h" #include "imgui_impl_sdl2.h" #include "imgui_impl_metal.h" -#include +#include // printf, fprintf #include #import #import +// Main code int main(int, char**) { + // Setup SDL + // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems, + // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) + { + printf("Error: SDL_Init(): %s\n", SDL_GetError()); + return 1; + } + + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + + // Create SDL window graphics context + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); + int window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); + if (window == nullptr) + { + printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); + return 1; + } + + // Create Metal device _before_ creating the view/layer + id metalDevice = MTLCreateSystemDefaultDevice(); + if (!metalDevice) + { + printf("Error: failed to create Metal device.\n"); + SDL_DestroyWindow(window); + SDL_Quit(); + return 1; + } + SDL_MetalView view = SDL_Metal_CreateView(window); + CAMetalLayer* layer = (__bridge CAMetalLayer*)SDL_Metal_GetLayer(view); + layer.device = metalDevice; + layer.pixelFormat = MTLPixelFormatBGRA8Unorm; + + id commandQueue = [layer.device newCommandQueue]; + MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new]; + // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - // Setup style + // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; + + // Setup scaling + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) + + // Setup Platform/Renderer backends + ImGui_ImplMetal_Init(layer.device); + ImGui_ImplSDL2_InitForMetal(window); // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); @@ -47,48 +100,10 @@ int main(int, char**) //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); - // Setup SDL - // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems, - // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!) - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) - { - printf("Error: %s\n", SDL_GetError()); - return 1; - } - - // Inform SDL that we will be using metal for rendering. Without this hint initialization of metal renderer may fail. - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); - - // Enable native IME. - SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); - - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 800, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - if (window == nullptr) - { - printf("Error creating window: %s\n", SDL_GetError()); - return -2; - } - - SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (renderer == nullptr) - { - printf("Error creating renderer: %s\n", SDL_GetError()); - return -3; - } - - // Setup Platform/Renderer backends - CAMetalLayer* layer = (__bridge CAMetalLayer*)SDL_RenderGetMetalLayer(renderer); - layer.pixelFormat = MTLPixelFormatBGRA8Unorm; - ImGui_ImplMetal_Init(layer.device); - ImGui_ImplSDL2_InitForMetal(window); - - id commandQueue = [layer.device newCommandQueue]; - MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new]; - // Our state bool show_demo_window = true; bool show_another_window = false; - float clear_color[4] = {0.45f, 0.55f, 0.60f, 1.00f}; + float clear_color[4] = { 0.45f, 0.55f, 0.60f, 1.00f }; // Main loop bool done = false; @@ -112,7 +127,8 @@ int main(int, char**) } int width, height; - SDL_GetRendererOutputSize(renderer, &width, &height); + SDL_GetWindowSizeInPixels(window, &width, &height); + layer.drawableSize = CGSizeMake(width, height); id drawable = [layer nextDrawable]; @@ -168,7 +184,8 @@ int main(int, char**) // Rendering ImGui::Render(); - ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder); + ImDrawData* draw_data = ImGui::GetDrawData(); + ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, renderEncoder); [renderEncoder popDebugGroup]; [renderEncoder endEncoding]; @@ -183,7 +200,6 @@ int main(int, char**) ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); - SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); diff --git a/include/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj b/include/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj index aca6edc..35b7ed7 100644 --- a/include/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj +++ b/include/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl2_opengl2/main.cpp b/include/imgui/examples/example_sdl2_opengl2/main.cpp index 3b3412b..081874a 100644 --- a/include/imgui/examples/example_sdl2_opengl2/main.cpp +++ b/include/imgui/examples/example_sdl2_opengl2/main.cpp @@ -66,11 +66,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -80,13 +83,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj b/include/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj index d0cb96b..b5a8019 100644 --- a/include/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj +++ b/include/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl2_opengl3/main.cpp b/include/imgui/examples/example_sdl2_opengl3/main.cpp index e7b1010..c1bc268 100644 --- a/include/imgui/examples/example_sdl2_opengl3/main.cpp +++ b/include/imgui/examples/example_sdl2_opengl3/main.cpp @@ -103,11 +103,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -117,14 +120,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj b/include/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj index 86b883a..9d7951b 100644 --- a/include/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj +++ b/include/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj @@ -93,6 +93,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -108,6 +109,7 @@ Disabled ..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl2_sdlrenderer2/main.cpp b/include/imgui/examples/example_sdl2_sdlrenderer2/main.cpp index b698673..9916dd8 100644 --- a/include/imgui/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/include/imgui/examples/example_sdl2_sdlrenderer2/main.cpp @@ -68,11 +68,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -82,13 +85,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/include/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj index 4bedc45..b2269bc 100644 --- a/include/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj +++ b/include/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj @@ -93,6 +93,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -109,6 +110,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl2_vulkan/main.cpp b/include/imgui/examples/example_sdl2_vulkan/main.cpp index 45a5a6d..7c9af9e 100644 --- a/include/imgui/examples/example_sdl2_vulkan/main.cpp +++ b/include/imgui/examples/example_sdl2_vulkan/main.cpp @@ -398,11 +398,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -428,13 +431,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl2_wgpu/CMakeLists.txt b/include/imgui/examples/example_sdl2_wgpu/CMakeLists.txt index aff4a18..0a8fed3 100644 --- a/include/imgui/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/include/imgui/examples/example_sdl2_wgpu/CMakeLists.txt @@ -1,10 +1,3 @@ -# Building for desktop with Dawn: -# 1. git clone https://github.com/google/dawn dawn -# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn -# 3. cmake --build build -# The resulting binary will be found at one of the following locations: -# * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe] - # Building for desktop with WGPU-Native: # 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases # 2. unzip the downloaded file in your_preferred_folder @@ -13,7 +6,14 @@ # The resulting binary will be found at one of the following locations: # * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe] -# Building for desktop with WGVK (MUCH EASIER) +# Building for desktop with Dawn: (VERY LONG TO BUILD) +# 1. git clone https://github.com/google/dawn dawn +# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn +# 3. cmake --build build +# The resulting binary will be found at one of the following locations: +# * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe] + +# Building for desktop with WGVK: # 1. git clone https://github.com/manuel5975p/WGVK wgvk # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk # 3. cmake --build build @@ -29,7 +29,7 @@ # 4. emrun build/index.html cmake_minimum_required(VERSION 3.22) # Dawn requires CMake >= 3.22 -project(imgui_example_sdl2_wgpu C CXX) +project(example_sdl2_wgpu C CXX) set(IMGUI_EXECUTABLE example_sdl2_wgpu) @@ -37,7 +37,7 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) endif() -set(CMAKE_CXX_STANDARD 10) # Dawn requires C++20 +set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20 # Dear ImGui set(IMGUI_DIR ../../) diff --git a/include/imgui/examples/example_sdl2_wgpu/main.cpp b/include/imgui/examples/example_sdl2_wgpu/main.cpp index 6898d03..abc7be2 100644 --- a/include/imgui/examples/example_sdl2_wgpu/main.cpp +++ b/include/imgui/examples/example_sdl2_wgpu/main.cpp @@ -74,11 +74,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -93,14 +96,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS @@ -276,6 +278,16 @@ int main(int, char**) return 0; } +static WGPUTextureFormat SelectSurfaceFormat(const WGPUSurfaceCapabilities& capabilities) +{ + const WGPUTextureFormat preferredFormats[] = { WGPUTextureFormat_BGRA8Unorm, WGPUTextureFormat_RGBA8Unorm, WGPUTextureFormat_BGRA8UnormSrgb, WGPUTextureFormat_RGBA8UnormSrgb }; + for (WGPUTextureFormat preferredFormat : preferredFormats) + for (size_t n = 0; n < capabilities.formatCount; n++) + if (capabilities.formats[n] == preferredFormat) + return preferredFormat; + return capabilities.formatCount > 0 ? capabilities.formats[0] : WGPUTextureFormat_Undefined; +} + #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) static WGPUAdapter RequestAdapter(wgpu::Instance& instance) { @@ -330,29 +342,25 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestAdapterStatus_Success) - { - WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; - *extAdapter = adapter; - } - else + if (status != WGPURequestAdapterStatus_Success) { printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; + *extAdapter = adapter; } static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestDeviceStatus_Success) - { - WGPUDevice* extDevice = (WGPUDevice*)userdata1; - *extDevice = device; - } - else + if (status != WGPURequestDeviceStatus_Success) { printf("Request_device status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUDevice* extDevice = (WGPUDevice*)userdata1; + *extDevice = device; } static WGPUAdapter RequestAdapter(WGPUInstance& instance) @@ -366,8 +374,10 @@ static WGPUAdapter RequestAdapter(WGPUInstance& instance) adapterCallbackInfo.userdata1 = &local_adapter; WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, adapterCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#endif IM_ASSERT(local_adapter && "Error on Adapter request"); return local_adapter; } @@ -379,9 +389,14 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) deviceCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly; deviceCallbackInfo.callback = handle_request_device; deviceCallbackInfo.userdata1 = &local_device; + WGPUFuture future = wgpuAdapterRequestDevice(adapter, nullptr, deviceCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#else + IM_UNUSED(instance); +#endif IM_ASSERT(local_device && "Error on Device request"); return local_device; } @@ -424,8 +439,7 @@ static bool InitWGPU(SDL_Window* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter.Get(), &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); // WGPU backend: Adapter and Device acquisition, Surface creation #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) @@ -437,7 +451,7 @@ static bool InitWGPU(SDL_Window* window) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) wgpuSetLogCallback( - [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr + [](WGPULogLevel level, WGPUStringView msg, void*) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); wgpuSetLogLevel(WGPULogLevel_Warn); #endif @@ -454,8 +468,7 @@ static bool InitWGPU(SDL_Window* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/include/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj b/include/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj index f38d290..0578741 100644 --- a/include/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj +++ b/include/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj @@ -93,6 +93,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -108,6 +109,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl3_directx11/main.cpp b/include/imgui/examples/example_sdl3_directx11/main.cpp index 4337d4e..8b28d13 100644 --- a/include/imgui/examples/example_sdl3_directx11/main.cpp +++ b/include/imgui/examples/example_sdl3_directx11/main.cpp @@ -68,11 +68,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -82,13 +85,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_metal/main.mm b/include/imgui/examples/example_sdl3_metal/main.mm index e6e3066..8edd50c 100644 --- a/include/imgui/examples/example_sdl3_metal/main.mm +++ b/include/imgui/examples/example_sdl3_metal/main.mm @@ -64,11 +64,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -78,13 +81,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_metal4/main.mm b/include/imgui/examples/example_sdl3_metal4/main.mm index 6debb51..b280793 100644 --- a/include/imgui/examples/example_sdl3_metal4/main.mm +++ b/include/imgui/examples/example_sdl3_metal4/main.mm @@ -80,11 +80,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -94,13 +97,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj b/include/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj index c470f88..dbe1fa9 100644 --- a/include/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj +++ b/include/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl3_opengl3/main.cpp b/include/imgui/examples/example_sdl3_opengl3/main.cpp index e7d22a4..819d9bd 100644 --- a/include/imgui/examples/example_sdl3_opengl3/main.cpp +++ b/include/imgui/examples/example_sdl3_opengl3/main.cpp @@ -93,11 +93,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -107,14 +110,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/include/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj index 02b0d35..bd83258 100644 --- a/include/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj +++ b/include/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj @@ -93,6 +93,7 @@ ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -109,6 +110,7 @@ ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl3_sdlgpu3/main.cpp b/include/imgui/examples/example_sdl3_sdlgpu3/main.cpp index 8edbbbb..6caa71c 100644 --- a/include/imgui/examples/example_sdl3_sdlgpu3/main.cpp +++ b/include/imgui/examples/example_sdl3_sdlgpu3/main.cpp @@ -70,11 +70,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -90,13 +93,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj b/include/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj index f420145..35fc962 100644 --- a/include/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj +++ b/include/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj @@ -92,6 +92,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true @@ -107,6 +108,7 @@ Disabled ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl3_sdlrenderer3/main.cpp b/include/imgui/examples/example_sdl3_sdlrenderer3/main.cpp index 88f9ac7..8fbd6a9 100644 --- a/include/imgui/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/include/imgui/examples/example_sdl3_sdlrenderer3/main.cpp @@ -58,11 +58,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -72,13 +75,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj b/include/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj index af11447..c3a200c 100644 --- a/include/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj +++ b/include/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj @@ -93,6 +93,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -109,6 +110,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) _MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_sdl3_vulkan/main.cpp b/include/imgui/examples/example_sdl3_vulkan/main.cpp index 0073b37..b0474e6 100644 --- a/include/imgui/examples/example_sdl3_vulkan/main.cpp +++ b/include/imgui/examples/example_sdl3_vulkan/main.cpp @@ -397,11 +397,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -427,13 +430,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_sdl3_wgpu/CMakeLists.txt b/include/imgui/examples/example_sdl3_wgpu/CMakeLists.txt index b7b0588..b05dcd4 100644 --- a/include/imgui/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/include/imgui/examples/example_sdl3_wgpu/CMakeLists.txt @@ -29,7 +29,7 @@ # 5. emrun build/index.html cmake_minimum_required(VERSION 3.22) # Dawn requires CMake >= 3.22 -project(imgui_example_sdl3_wgpu C CXX) +project(example_sdl3_wgpu C CXX) set(IMGUI_EXECUTABLE example_sdl3_wgpu) diff --git a/include/imgui/examples/example_sdl3_wgpu/main.cpp b/include/imgui/examples/example_sdl3_wgpu/main.cpp index bc17878..42053f0 100644 --- a/include/imgui/examples/example_sdl3_wgpu/main.cpp +++ b/include/imgui/examples/example_sdl3_wgpu/main.cpp @@ -81,11 +81,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -101,14 +104,13 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); #ifndef IMGUI_DISABLE_FILE_FUNCTIONS @@ -287,6 +289,16 @@ int main(int, char**) return 0; } +static WGPUTextureFormat SelectSurfaceFormat(const WGPUSurfaceCapabilities& capabilities) +{ + const WGPUTextureFormat preferredFormats[] = { WGPUTextureFormat_BGRA8Unorm, WGPUTextureFormat_RGBA8Unorm, WGPUTextureFormat_BGRA8UnormSrgb, WGPUTextureFormat_RGBA8UnormSrgb }; + for (WGPUTextureFormat preferredFormat : preferredFormats) + for (size_t n = 0; n < capabilities.formatCount; n++) + if (capabilities.formats[n] == preferredFormat) + return preferredFormat; + return capabilities.formatCount > 0 ? capabilities.formats[0] : WGPUTextureFormat_Undefined; +} + #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) static WGPUAdapter RequestAdapter(wgpu::Instance& instance) { @@ -341,29 +353,25 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestAdapterStatus_Success) - { - WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; - *extAdapter = adapter; - } - else + if (status != WGPURequestAdapterStatus_Success) { printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; + *extAdapter = adapter; } static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) { IM_UNUSED(userdata2); - if (status == WGPURequestDeviceStatus_Success) - { - WGPUDevice* extDevice = (WGPUDevice*)userdata1; - *extDevice = device; - } - else + if (status != WGPURequestDeviceStatus_Success) { printf("Request_device status=%#.8x message=%.*s\n", status, (int)message.length, message.data); + return; } + WGPUDevice* extDevice = (WGPUDevice*)userdata1; + *extDevice = device; } static WGPUAdapter RequestAdapter(WGPUInstance& instance) @@ -377,8 +385,10 @@ static WGPUAdapter RequestAdapter(WGPUInstance& instance) adapterCallbackInfo.userdata1 = &local_adapter; WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, adapterCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#endif IM_ASSERT(local_adapter && "Error on Adapter request"); return local_adapter; } @@ -390,9 +400,14 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) deviceCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly; deviceCallbackInfo.callback = handle_request_device; deviceCallbackInfo.userdata1 = &local_device; + WGPUFuture future = wgpuAdapterRequestDevice(adapter, nullptr, deviceCallbackInfo); +#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUFutureWaitInfo waitInfo = { future, false }; wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull); +#else + IM_UNUSED(instance); +#endif IM_ASSERT(local_device && "Error on Device request"); return local_device; } @@ -435,8 +450,7 @@ static bool InitWGPU(SDL_Window* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter.Get(), &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); // WGPU backend: Adapter and Device acquisition, Surface creation #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) @@ -448,7 +462,7 @@ static bool InitWGPU(SDL_Window* window) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) wgpuSetLogCallback( - [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr + [](WGPULogLevel level, WGPUStringView msg, void*) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); wgpuSetLogLevel(WGPULogLevel_Warn); #endif @@ -465,8 +479,7 @@ static bool InitWGPU(SDL_Window* window) WGPUSurfaceCapabilities surface_capabilities = {}; wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); - - preferred_fmt = surface_capabilities.formats[0]; + preferred_fmt = SelectSurfaceFormat(surface_capabilities); #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; @@ -505,29 +518,29 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, SDL_Window* window) #if defined(SDL_PLATFORM_MACOS) { create_info.System = "cocoa"; - create_info.RawWindow = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL); + create_info.RawWindow = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info); } #elif defined(SDL_PLATFORM_LINUX) if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) { create_info.System = "wayland"; - create_info.RawDisplay = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL); - create_info.RawSurface = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL); + create_info.RawDisplay = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr); + create_info.RawSurface = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info); } else if (!SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11")) { create_info.System = "x11"; create_info.RawWindow = (void*)SDL_GetNumberProperty(propertiesID, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); - create_info.RawDisplay = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL); + create_info.RawDisplay = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr); return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info); } #elif defined(SDL_PLATFORM_WIN32) { create_info.System = "win32"; - create_info.RawWindow = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); - create_info.RawInstance = (void*)::GetModuleHandle(NULL); + create_info.RawWindow = (void*)SDL_GetPointerProperty(propertiesID, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); + create_info.RawInstance = (void*)::GetModuleHandle(nullptr); return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info); } #else diff --git a/include/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj b/include/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj index 7fb7677..add37ed 100644 --- a/include/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj +++ b/include/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj @@ -88,6 +88,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true @@ -102,6 +103,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_directx10/main.cpp b/include/imgui/examples/example_win32_directx10/main.cpp index 2c34207..b68ba06 100644 --- a/include/imgui/examples/example_win32_directx10/main.cpp +++ b/include/imgui/examples/example_win32_directx10/main.cpp @@ -59,11 +59,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -73,13 +76,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj b/include/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj index 9e89353..ed0b509 100644 --- a/include/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj +++ b/include/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj @@ -88,6 +88,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true @@ -102,6 +103,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories); /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_directx11/main.cpp b/include/imgui/examples/example_win32_directx11/main.cpp index 524538a..5f3af38 100644 --- a/include/imgui/examples/example_win32_directx11/main.cpp +++ b/include/imgui/examples/example_win32_directx11/main.cpp @@ -59,11 +59,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -73,13 +76,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj b/include/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj index c4b81e7..27b501d 100644 --- a/include/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/include/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -89,6 +89,7 @@ ..\..;..\..\backends;%(AdditionalIncludeDirectories) _UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -104,6 +105,7 @@ ..\..;..\..\backends;%(AdditionalIncludeDirectories) _UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_directx12/main.cpp b/include/imgui/examples/example_win32_directx12/main.cpp index 0d8bb20..5fb0ed7 100644 --- a/include/imgui/examples/example_win32_directx12/main.cpp +++ b/include/imgui/examples/example_win32_directx12/main.cpp @@ -139,11 +139,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -168,13 +171,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj b/include/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj index c5efda3..84e16c9 100644 --- a/include/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj +++ b/include/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj @@ -88,6 +88,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories);$(DXSDK_DIR)Include; /utf-8 %(AdditionalOptions) + false true @@ -102,6 +103,7 @@ Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories);$(DXSDK_DIR)Include; /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_directx9/main.cpp b/include/imgui/examples/example_win32_directx9/main.cpp index fbe4c39..f071169 100644 --- a/include/imgui/examples/example_win32_directx9/main.cpp +++ b/include/imgui/examples/example_win32_directx9/main.cpp @@ -57,11 +57,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -71,13 +74,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj b/include/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj index b9b4267..2ffb7d4 100644 --- a/include/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj +++ b/include/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj @@ -88,6 +88,7 @@ Disabled ..\..;..\..\backends; /utf-8 %(AdditionalOptions) + false true @@ -102,6 +103,7 @@ Disabled ..\..;..\..\backends; /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_opengl3/main.cpp b/include/imgui/examples/example_win32_opengl3/main.cpp index cba8301..28c92a6 100644 --- a/include/imgui/examples/example_win32_opengl3/main.cpp +++ b/include/imgui/examples/example_win32_opengl3/main.cpp @@ -68,11 +68,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); + //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -82,13 +85,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/include/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj index f3ba4aa..bede521 100644 --- a/include/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj +++ b/include/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -89,6 +89,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) _UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true @@ -104,6 +105,7 @@ ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) _UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) + false true diff --git a/include/imgui/examples/example_win32_vulkan/main.cpp b/include/imgui/examples/example_win32_vulkan/main.cpp index cbdbdb8..4c66a54 100644 --- a/include/imgui/examples/example_win32_vulkan/main.cpp +++ b/include/imgui/examples/example_win32_vulkan/main.cpp @@ -385,11 +385,14 @@ int main(int, char**) io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style + ImGuiStyle& style = ImGui::GetStyle(); ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + //style.FontSizeBase = 16.0f; // Default to 13.0f when unspecified, which allows crisp legacy font for non-4K screens. + style.FrameRounding = 3.0f; + style.GrabRounding = 3.0f; // Setup scaling - ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) @@ -415,13 +418,12 @@ int main(int, char**) // Load Fonts // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). - // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. + // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a threshold. // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit). // - Read 'docs/FONTS.md' for more instructions and details. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefaultVector(); //io.Fonts->AddFontDefaultBitmap(); //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); diff --git a/include/imgui/imconfig.h b/include/imgui/imconfig.h index b40db38..d9c0569 100644 --- a/include/imgui/imconfig.h +++ b/include/imgui/imconfig.h @@ -72,7 +72,8 @@ //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) //#define IMGUI_USE_WCHAR32 -//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version. +// This is for if you already embed a copy of those library in your code and don't want duplicate code in your binary. // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" @@ -102,20 +103,24 @@ //---- Use stb_truetype to build and rasterize the font atlas (default) // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. //#define IMGUI_ENABLE_STB_TRUETYPE +//#define IMGUI_DISABLE_STB_TRUETYPE //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. // This will be inlined as part of ImVec2 and ImVec4 class declarations. /* #define IM_VEC2_CLASS_EXTRA \ - constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ - operator MyVec2() const { return MyVec2(x,y); } + IM_NODEBUGSTEP constexpr inline ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ + IM_NODEBUGSTEP inline operator MyVec2() const { return MyVec2(x,y); } -#define IM_VEC4_CLASS_EXTRA \ - constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ - operator MyVec4() const { return MyVec4(x,y,z,w); } +#define IM_VEC4_CLASS_EXTRA \ + IM_NODEBUGSTEP constexpr inline ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ + IM_NODEBUGSTEP inline operator MyVec4() const { return MyVec4(x,y,z,w); } */ -//---- ...Or use Dear ImGui's own very basic math operators. +//---- ...Or use Dear ImGui's own basic math operators in every file including imgui.h: +//#ifndef IMGUI_DEFINE_MATH_OPERATORS //#define IMGUI_DEFINE_MATH_OPERATORS +//#endif +//---- ...Or manually '#define IMGUI_DEFINE_MATH_OPERATORS' before '#include "imgui.h"' to use from one file. //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). diff --git a/include/imgui/imgui.cpp b/include/imgui/imgui.cpp index 7fa2d49..3705e72 100644 --- a/include/imgui/imgui.cpp +++ b/include/imgui/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (main code and documentation) // Help: @@ -230,7 +230,7 @@ CODE This is to increase compatibility, increase maintainability and facilitate use from other languages. - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. - We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. + We can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (so don't use ImVector in your code or at our own risk!). - Building: We don't use nor mandate a build system for the main library. @@ -395,6 +395,51 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + 2026/10/07 (1.93.0) - large cleanup/refactor of ImDrawList. many issues and inconsistencies fixed! (#9504) + BELOW IS A SIMPLIFIED/SHORTENED RECAP OF CHANGES. READ CHANGELOG AND LINKS ABOVE FOR MORE DETAILS! + useful links: + - ImDrawList 1.92.9 <> 1.93 Interactive Testbed: https://www.dearimgui.com/docs/drawlist_v193 (<-- you can download this locally) + - ImDrawList Wiki Reference: https://github.com/ocornut/imgui/wiki/Draw-List + - Discussion thread: https://github.com/ocornut/imgui/issues/9504 + - use ImDrawFlags_StrokeLegacy mode to emulate old rendering: + - Per-primitive: draw_list->AddLine(..., ..., ImDrawFlags_StrokeLegacy); + - For a given scope: draw_list->PushDrawFlag(ImDrawFlags_StrokeLegacy, true); draw_list->AddLine(...); draw_list->PopDrawFlag(); + - Globally: ImGui::Checkbox("DefaultsToStrokeLegacy", &io.ConfigDebugDrawListDefaultsToStrokeLegacy); // Map to a checkbox + - Globally: io.ConfigDebugDrawListDefaultsToStrokeLegacy = io.KeyShift; // Map on Shift + - AddLine: removed the (+0.5f,+0.5f) offset that was sneakily added to input coordinates by this function, and led to lots of inconsistencies. + - This fixes inconsistencies in the API and matches the PathXXX API. + - By default, stroke thickness extends on both side of the given segment. e.g for a "pixel-perfect" looking line with thickness=1.0f, coords should be passed as center of each ends of the line. + - Use `ImDrawFlags_StrokeLegacy` to use old offset if required. Or you can apply the offset manually! + - Generally better, simpler and faster to use `AddLineH()`, `AddLineV()` functions added in 1.92.8. + - IF YOU ARE MINDFUL OF PIXEL-PERFECTNESS IN YOUR CUSTOM RENDERING/WIDGETS read Changelog and links above for details. + - AddRect(), AddCircle(), AddNgon(), AddEllipse(), AddTriangle(), AddQuad(): defaulting to "inside" stroke. All closed shapes with thickness=1.0f will appear identical. The difference for thickness>1.0f shapes may be minimal since very large strokes were not well supported for widgets, but stroke will default inside widgets. + - AddCircle(), AddNgon(): removed +0.5f offset added to radius. This fixes inconsistencies in the API. Use `ImDrawFlags_StrokeLegacy` to use old method if required. Or you can apply the offset manually! + - AddRectFilled(): non-integer coordinates will now display anti-aliased edges. Previously, non-integer coordinates rendered with aliased edges snapped by the rasterizer. + - AddRect(), AddRectFilled(): rectangles with inverted coordinates won't be visible unless using ImDrawFlags_StrokeLegacy mode. + With inverted coordinates: + - Legacy `AddRect()` rounding off -> visible but incorrect outer size. + - Legacy `AddRect()` rounding on -> visible but very glitchy. + - Legacy `AddRectFilled()` rounding off -> visible and correct. + - Legacy `AddRectFilled()` rounding on -> visible but very glitchy. + - merged ImDrawListFlags into ImDrawFlags. obsoleted ImDrawListFlags (which were rarely used directly): + - ImDrawListFlags_AntiAliasedLines -> ImDrawFlags_AALines, + - ImDrawListFlags_AntiAliasedFill -> ImDrawFlags_AAFill, + - ImDrawListFlags_AllowVtxOffset -> ImDrawFlags_UseVtxOffset, + - ImDrawListFlags_TextNoPixelSnap -> ImDrawFlags_TextNoPixelSnap, + unifying them allows easily using them for both per-primitives alterations and scope alterations. + - renamed ImDrawFlags_RoundCornersXXXX to ImDrawFlags_RoundXXXX. + - ImDrawFlags_RoundCornersAll -> ImDrawFlags_RoundAll, + - ImDrawFlags_RoundCornersNone -> ImDrawFlags_RoundNone, + - ImDrawFlags_RoundCornersTopLeft -> ImDrawFlags_RoundTopLeft, + - ImDrawFlags_RoundCornersTopRight -> ImDrawFlags_RoundTopRight, + - ImDrawFlags_RoundCornersTop -> ImDrawFlags_RoundTop, + - ImDrawFlags_RoundCornersBottom -> ImDrawFlags_RoundBottom, + etc. kept redirection enums (will obsolete). + - obsoleted style.AntiAliasedLinesUseTex and ImDrawListFlags_AntiAliasedLinesUseTex, as the new line rendering code always uses textures. + - 2026/09/30 (1.93.0) - ImFont: renamed `AddRemapChar()` to `AddRemapCodepoint()` (rarely used, marked internal). (#609, #5748) + - 2026/09/18 (1.93.0) - ImGuiTextFilter: removed `float width` parameter of `Draw(const char* filter, float width)`: prefer using `SetNextItemWidth(float)` which is standard. Kept inline redirection function. + - 2026/08/03 (1.93.0) - Style: obsoleted `style.CurveTessellationTol` (default 1.25) which was in Pixels² unit in favor of `style.CurveTessellationMaxError` (default 1.12) which is in Pixels unit. + - style.CurveTessellationMaxError == sqrtf(style.CurveTessellationTol). - 2026/07/20 (1.92.9) - DragXXX, SliderXXX, InputScalar: with `ImGuiItemFlags_LiveEditOnInputScalar` now defaulting to being disabled: inputting a value with the keyboard doesn't write intermediate values to backing variable. (#9476) - Before: DragFloat() with user typing "123" --> write back 1, then 12, then 123. @@ -1385,10 +1430,9 @@ static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSetti static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); // Platform Dependents default implementation for ImGuiPlatformIO functions +static void InitializeDefaultPlatformHandlers(ImGuiPlatformIO& platform_io); static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx); static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text); -static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); -static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); namespace ImGui { @@ -1570,10 +1614,12 @@ ImGuiStyle::ImGuiStyle() DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. - AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. - AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). - AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). - CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + + // Rendering & Tessellation + AntiAliasedLines = true; // Enable anti-aliased lines/borders. Used at the beginning of the frame to set ImDrawFlags_AALines in all draw-lists. + AntiAliasedLineEnds = false; // Enable anti-aliased lines/borders ends. Nicer for thick lines but more expensive. Used at the beginning of the frame to set ImDrawFlags_AALineEnds in all draw-lists. + AntiAliasedFill = true; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Used at the beginning of the frame to set ImDrawFlags_AAFill in all draw-lists. + CurveTessellationMaxError = 1.12f; // Maximum error (in pixels) when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. // Behaviors @@ -1586,6 +1632,10 @@ ImGuiStyle::ImGuiStyle() // [Internal] _MainScale = 1.0f; _NextFrameFontSizeBase = 0.0f; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + CurveTessellationTol = 0.0f; // Old CurveTessellationTol = CurveTessellationMaxError*CurveTessellationMaxError. + AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures for legacy strokes. Require backend to render with bilinear filtering (NOT point/nearest filtering). +#endif // Default theme ImGui::StyleColorsDark(this); @@ -2100,7 +2150,7 @@ ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec } // Closely mimics PathBezierToCasteljau() in imgui_draw.cpp -static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float max_error_sqr, int level) { float dx = x4 - x1; float dy = y4 - y1; @@ -2108,7 +2158,7 @@ static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_cl float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); d2 = (d2 >= 0) ? d2 : -d2; d3 = (d3 >= 0) ? d3 : -d3; - if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + if ((d2 + d3) * (d2 + d3) < max_error_sqr * (dx * dx + dy * dy)) { ImVec2 p_current(x4, y4); ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); @@ -2128,20 +2178,21 @@ static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_cl float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; - ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); - ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, max_error_sqr, level + 1); + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, max_error_sqr, level + 1); } } -// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol +// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationMaxError // Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. -ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) +ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float max_error) { - IM_ASSERT(tess_tol > 0.0f); + IM_ASSERT(max_error > 0.0f); ImVec2 p_last = p1; ImVec2 p_closest; float p_closest_dist2 = FLT_MAX; - ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + float max_error_sqr = max_error * max_error; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, max_error_sqr, 0); return p_closest; } @@ -2485,7 +2536,13 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) #else while (data + 4 <= data_end) { +#if defined(_DEBUG) || defined(_MSC_VER) crc = _mm_crc32_u32(crc, *(ImU32*)data); +#else + ImU32 v; + memcpy(&v, data, sizeof(ImU32)); // Avoid aliasing violation (#9557) + crc = _mm_crc32_u32(crc, v); +#endif data += 4; } while (data < data_end) @@ -3082,11 +3139,11 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // [SECTION] ImGuiTextFilter //----------------------------------------------------------------------------- -// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'. ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077 { InputBuf[0] = 0; - CountGrep = 0; + _CountExclude = 0; if (default_filter) { ImStrncpy(InputBuf, default_filter, IM_COUNTOF(InputBuf)); @@ -3094,84 +3151,110 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077 } } -bool ImGuiTextFilter::Draw(const char* label, float width) +bool ImGuiTextFilter::Draw(const char* label) { - if (width != 0.0f) - ImGui::SetNextItemWidth(width); - bool value_changed = ImGui::InputText(label, InputBuf, IM_COUNTOF(InputBuf)); + return DrawWithHint(label, "incl -excl"); +} + +// Use ImGui::SetNextItemWidth() manually if you want to use this. +bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint) +{ + bool value_changed = ImGui::InputTextWithHint(label, hint, InputBuf, IM_COUNTOF(InputBuf)); if (value_changed) Build(); return value_changed; } -void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector* out) const +// Parse filter and split into a format optimal for PassFilter() +void ImGuiTextFilter::Build() { - out->resize(0); - const char* wb = b; - const char* we = wb; - while (we < e) - { - if (*we == separator) + _Items.resize(0); + _CountExclude = 0; + + const char* buf_e = InputBuf + ImStrlen(InputBuf); + const char* word_e; + int seq_start_idx = -1; + for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1) + { + // Trim blanks + while (word_b < buf_e && ImCharIsBlankA(word_b[0])) // FIXME: UTF-8 support + word_b++; + const bool is_excl = (word_b < buf_e && word_b[0] == '-'); + if (is_excl) + word_b++; + const bool is_quote = (word_b < buf_e && word_b[0] == '\"'); + if (is_quote) { - out->push_back(ImGuiTextRange(wb, we)); - wb = we + 1; + // Parsing quotes. Omit storing leading/trailing quotes. + word_e = ImStrchrRange(++word_b, buf_e, '\"'); + if (word_e == NULL) + word_e = buf_e; + } + else + { + // Handle both ' ' and ',' separators. + for (word_e = word_b; word_e < buf_e; word_e++) + if (*word_e == ' ' || *word_e == ',') + break; } - we++; - } - if (wb != we) - out->push_back(ImGuiTextRange(wb, we)); -} -void ImGuiTextFilter::Build() -{ - Filters.resize(0); - ImGuiTextRange input_range(InputBuf, InputBuf + ImStrlen(InputBuf)); - input_range.split(',', &Filters); + // Min length + if (word_e - word_b > 0) + { + // Add to list. The '-' is not stored in items but implicitly inferred using (n < CountExclude). + // FIXME-OPT: as items are derived from user input buffer and we expect the insert() to behave sanely. + if (is_excl) + { + _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilterItem(word_b, word_e)); + _CountExclude++; + if (seq_start_idx != -1) + seq_start_idx++; + } + else + { + if (seq_start_idx == -1) + seq_start_idx = _Items.Size; + _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilterItem(word_b, word_e)); + _Items.Data[seq_start_idx].CountInclude++; + } + } - CountGrep = 0; - for (ImGuiTextRange& f : Filters) - { - while (f.b < f.e && ImCharIsBlankA(f.b[0])) - f.b++; - while (f.e > f.b && ImCharIsBlankA(f.e[-1])) - f.e--; - if (f.empty()) - continue; - if (f.b[0] != '-') - CountGrep += 1; + // Next sequence + if (word_e[0] == ',') + seq_start_idx = -1; } } +// FIXME: Could use a specialized ImStristr() + pre-convert our filter to uppercase. bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { - if (Filters.Size == 0) + if (_Items.Size == 0) return true; - if (text == NULL) text = text_end = ""; - for (const ImGuiTextRange& f : Filters) - { - if (f.b == f.e) - continue; - if (f.b[0] == '-') - { - // Subtract - if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) - return false; - } - else - { - // Grep - if (ImStristr(text, text_end, f.b, f.e) != NULL) - return true; - } - } + // Filters are sorted so that '-' ones are always leading. + ImGuiTextFilterItem* seq = _Items.Data; + ImGuiTextFilterItem* seq_excl_end = _Items.Data + _CountExclude; + for (; seq < seq_excl_end; seq++) + if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) != NULL) + return false; - // Implicit * grep - if (CountGrep == 0) + // Process includes + ImGuiTextFilterItem* seq_end = _Items.Data + _Items.Size; + if (seq == seq_end) // When no inclusion are specified (only exclusions) we implicitly pass return true; - + while (seq < seq_end) + { + ImGuiTextFilterItem* seq_incl_end = seq + seq->CountInclude; + IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_incl_end <= seq_end); + for (; seq < seq_incl_end; seq++) + if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) == NULL) + break; + if (seq == seq_incl_end) // All matched + return true; + seq = seq_incl_end; // Try next + } return false; } @@ -3938,6 +4021,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take // better advantage of the render function taking size into account for coarse clipping. void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +// DOES NOT CALL LogRenderedText(), unlike RenderTextClipped!!! { // Perform CPU side clipping for single clipped element to avoid using scissor state ImVec2 pos = pos_min; @@ -4232,7 +4316,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Font = NULL; FontBaked = NULL; FontSize = FontSizeBase = FontBakedScale = CurrentDpiScale = 0.0f; - FontRasterizerDensity = 1.0f; + CurrentPixelDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); if (shared_font_atlas == NULL) IO.Fonts->OwnerContext = this; @@ -4329,7 +4413,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0; NavJustMovedToKeyMods = ImGuiMod_None; - NavJustMovedToIsTabbing = false; + NavJustMovedToIsTabbing = NavJustMovedToIsInit = false; NavJustMovedToHasSelectionData = false; // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac... @@ -4373,6 +4457,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseCursor = ImGuiMouseCursor_Arrow; MouseStationaryTimer = 0.0f; + MixedValueLabel = "-"; InputTextPasswordFontBackupFlags = ImFontFlags_None; InputTextReactivateId = 0; TempInputId = 0; @@ -4478,10 +4563,7 @@ void ImGui::Initialize() LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_COUNTOF(GLocalizationEntriesEnUS)); // Setup default ImGuiPlatformIO clipboard/IME handlers. - g.PlatformIO.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations - g.PlatformIO.Platform_SetClipboardTextFn = Platform_SetClipboardTextFn_DefaultImpl; - g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; - g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl; + InitializeDefaultPlatformHandlers(g.PlatformIO); // Setup session starting date #ifndef IMGUI_DISABLE_TIME_FUNCTIONS @@ -4703,7 +4785,7 @@ static void SetCurrentWindow(ImGuiWindow* window) if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) { ImGuiViewport* viewport = window->Viewport; - g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() + g.CurrentPixelDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetPixelDensity() } const bool backup_skip_items = window->SkipItems; window->SkipItems = false; @@ -5297,11 +5379,13 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw } // Our ImDrawList system requires that there is always a command - if (viewport->BgFgDrawListsLastTimeActive[drawlist_no] != (float)g.Time) + if (viewport->BgFgDrawListsLastFrameActive[drawlist_no] != g.FrameCount) { draw_list->_ResetForNewFrame(); + draw_list->_SetPixelDensity(viewport->FramebufferScale.x); draw_list->PushTexture(g.IO.Fonts->TexRef); draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->BgFgDrawListsLastFrameActive[drawlist_no] = g.FrameCount; viewport->BgFgDrawListsLastTimeActive[drawlist_no] = (float)g.Time; } return draw_list; @@ -5572,18 +5656,23 @@ static void SetupDrawListSharedData() for (ImGuiViewportP* viewport : g.Viewports) virtual_space.Add(viewport->GetMainRect()); g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); - g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.CurveTessellationMaxError = g.Style.CurveTessellationMaxError; g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); - g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; - if (g.Style.AntiAliasedLines) - g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; - if (g.Style.AntiAliasedLinesUseTex && !(g.IO.Fonts->Flags & ImFontAtlasFlags_NoBakedLines)) - g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex; + g.DrawListSharedData.InitialDrawFlags = ImDrawFlags_None; + if (g.IO.Fonts->Flags & ImFontAtlasFlags_NoBakedLines) + g.Style.AntiAliasedLines = g.Style.AntiAliasedLineEnds = false; if (g.Style.AntiAliasedFill) - g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_AAFill; + if (g.Style.AntiAliasedLines) + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_AALines; + if (g.Style.AntiAliasedLineEnds) + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_AALineEnds; + if (g.IO.ConfigDebugDrawListDefaultsToStrokeLegacy) + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_StrokeLegacy; + if (!(g.IO.Fonts->Flags & ImFontAtlasFlags_NoBakedRoundCorners)) + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_AllowTexForRoundCorners_; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) - g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; - g.DrawListSharedData.InitialFringeScale = 1.0f; // FIXME-DPI: Change this for some DPI scaling experiments. + g.DrawListSharedData.InitialDrawFlags |= ImDrawFlags_UseVtxOffset; } void ImGui::NewFrame() @@ -6204,7 +6293,7 @@ void ImGui::Render() for (ImGuiViewportP* viewport : g.Viewports) { InitViewportDrawData(viewport); - if (viewport->BgFgDrawLists[0] != NULL && viewport->BgFgDrawListsLastTimeActive[0] == (float)g.Time) + if (viewport->BgFgDrawLists[0] != NULL && viewport->BgFgDrawListsLastFrameActive[0] == g.FrameCount) AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); } @@ -6236,7 +6325,7 @@ void ImGui::Render() FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder); // Add foreground ImDrawList (for each active viewport) - if (viewport->BgFgDrawLists[1] != NULL && viewport->BgFgDrawListsLastTimeActive[1] == (float)g.Time) + if (viewport->BgFgDrawLists[1] != NULL && viewport->BgFgDrawListsLastFrameActive[1] == g.FrameCount) AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch). @@ -6529,6 +6618,9 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I ImGuiWindow* parent_window = g.CurrentWindow; IM_ASSERT(id != 0); + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) + child_flags = (child_flags | g.NextWindowData.ChildFlagsSet) & ~g.NextWindowData.ChildFlagsClear; + // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument. const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened; IM_UNUSED(ImGuiChildFlags_SupportedMask_); @@ -6591,13 +6683,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I } } SetNextWindowSize(size); - - // Forward child flags (we allow prior settings to merge but it'll only work for adding flags) - if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) - g.NextWindowData.ChildFlags |= child_flags; - else - g.NextWindowData.ChildFlags = child_flags; - g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasChildFlags; + SetNextWindowChildFlags(child_flags, true); // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. // FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround. @@ -7267,7 +7353,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) { float y = window->Pos.y + window->TitleBarHeight - 1; - window->DrawList->AddLineH(window->Pos.x + border_size * 0.5f, window->Pos.x + window->Size.x - border_size * 0.5f, y, border_col, g.Style.FrameBorderSize); + window->DrawList->AddLineH(window->Pos.x + border_size, window->Pos.x + window->Size.x - border_size, y, border_col, g.Style.FrameBorderSize, ImDrawFlags_StrokeCenterBiased); } } @@ -7315,7 +7401,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar if (bg_col & IM_COL32_A_MASK) { ImRect bg_rect(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size); - ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersBottom; + ImDrawFlags bg_rounding_flags = (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawFlags_RoundAll : ImDrawFlags_RoundBottom; ImDrawList* bg_draw_list = window->DrawList; bg_draw_list->AddRectFilled(bg_rect.Min, bg_rect.Max, bg_col, window_rounding, bg_rounding_flags); } @@ -7325,7 +7411,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); - window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundTop); } // Menu bar @@ -7333,9 +7419,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundTop); if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) - window->DrawList->AddLineH(menu_bar_rect.Min.x + window_border_size * 0.5f, menu_bar_rect.Max.x - window_border_size * 0.5f, menu_bar_rect.Max.y, GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + window->DrawList->AddLineH(menu_bar_rect.Min.x + window_border_size, menu_bar_rect.Max.x - window_border_size, menu_bar_rect.Max.y, GetColorU32(ImGuiCol_Border), style.FrameBorderSize, ImDrawFlags_StrokeCenterBiased); } // Scrollbars @@ -7542,6 +7628,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (g.DebugBreakInWindow == window->ID) IM_DEBUG_BREAK(); + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) + flags = (flags | g.NextWindowData.WindowFlagsSet) & ~g.NextWindowData.WindowFlagsClear; + // Automatically disable manual moving/resizing when NoInputs is set if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; @@ -7567,7 +7656,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { UpdateWindowInFocusOrderList(window, window_just_created, flags); window->Flags = (ImGuiWindowFlags)flags; - window->ChildFlags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : 0; + window->ChildFlags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlagsSet : 0; window->LastFrameActive = current_frame; window->LastTimeActive = (float)g.Time; window->BeginOrderWithinParent = 0; @@ -7721,6 +7810,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) size_t buf_len = (size_t)window->NameBufLen; window->Name = ImStrdupcpy(window->Name, &buf_len, name); window->NameBufLen = (int)buf_len; + window->DrawList->_OwnerName = window->Name; } // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS @@ -8073,6 +8163,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Setup draw list and outer clipping rectangle IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); + window->DrawList->_SetPixelDensity(window->Viewport->FramebufferScale.x); window->DrawList->PushTexture(g.Font->OwnerAtlas->TexRef); PushClipRect(host_rect.Min, host_rect.Max, false); @@ -8219,7 +8310,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Set default BgClickFlags // This is set at the end of this function, so UpdateWindowManualResize()/ClampWindowPos() may use last-frame value if overridden by user code. // FIXME: The general intent is that we will later expose config options to default to enable scrolling + select scrolling mouse button. - window->BgClickFlags = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->BgClickFlags : (g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move); + window->BgClickFlags = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->BgClickFlags : (g.IO.ConfigWindowsMoveFromTitleBarOnly ? ImGuiWindowBgClickFlags_None : ImGuiWindowBgClickFlags_Move); // -V1004 // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. @@ -8825,6 +8916,26 @@ void ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags) g.NextWindowData.RefreshFlagsVal = flags; } +void ImGui::SetNextWindowFlags(ImGuiWindowFlags flags, bool enabled) +{ + ImGuiContext& g = *GImGui; + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) == 0) + g.NextWindowData.WindowFlagsSet = g.NextWindowData.WindowFlagsClear = ImGuiChildFlags_None; + g.NextWindowData.WindowFlagsSet = enabled ? (g.NextWindowData.WindowFlagsSet | flags) : (g.NextWindowData.WindowFlagsSet & ~flags); + g.NextWindowData.WindowFlagsClear = !enabled ? (g.NextWindowData.WindowFlagsClear | flags) : (g.NextWindowData.WindowFlagsClear & ~flags); + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasWindowFlags; +} + +void ImGui::SetNextWindowChildFlags(ImGuiChildFlags flags, bool enabled) +{ + ImGuiContext& g = *GImGui; + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) == 0) + g.NextWindowData.ChildFlagsSet = g.NextWindowData.ChildFlagsClear = ImGuiChildFlags_None; + g.NextWindowData.ChildFlagsSet = enabled ? (g.NextWindowData.ChildFlagsSet | flags) : (g.NextWindowData.ChildFlagsSet & ~flags); + g.NextWindowData.ChildFlagsClear = !enabled ? (g.NextWindowData.ChildFlagsClear | flags) : (g.NextWindowData.ChildFlagsClear & ~flags); + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasChildFlags; +} + ImDrawList* ImGui::GetWindowDrawList() { ImGuiWindow* window = GetCurrentWindow(); @@ -9041,7 +9152,7 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // - UnregisterFontAtlas() [Internal] // - SetCurrentFont() [Internal] // - UpdateCurrentFontSize() [Internal] -// - SetFontRasterizerDensity() [Internal] +// - SetPixelDensity() [Internal] // - PushFont() // - PopFont() //----------------------------------------------------------------------------- @@ -9234,7 +9345,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) final_size = GetRoundedFontSize(final_size); final_size = ImClamp(final_size, 1.0f, IMGUI_FONT_SIZE_MAX); if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) - g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; + g.Font->CurrentRasterizerDensity = g.CurrentPixelDensity; g.FontSize = final_size; g.DrawListSharedData.FontSize = g.FontSize; @@ -9258,13 +9369,13 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) // Exposed in case user may want to override setting density. // IMPORTANT: Begin()/End() is overriding density. Be considerate of this you change it. -void ImGui::SetFontRasterizerDensity(float rasterizer_density) +void ImGui::SetPixelDensity(float pixel_density) { ImGuiContext& g = *GImGui; IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures); - if (g.FontRasterizerDensity == rasterizer_density) + if (g.CurrentPixelDensity == pixel_density) return; - g.FontRasterizerDensity = rasterizer_density; + g.CurrentPixelDensity = pixel_density; UpdateCurrentFontSize(0.0f); } @@ -10214,12 +10325,11 @@ void ImGui::TeleportMousePos(const ImVec2& pos) //IMGUI_DEBUG_LOG_IO("TeleportMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); } -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { ImGuiContext& g = *GImGui; if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.BeginPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; return g.IO.MousePos; } @@ -11098,7 +11208,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); - IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CurveTessellationMaxError > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting!"); @@ -11138,6 +11248,11 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() g.PlatformIO.Platform_GetClipboardTextFn = [](ImGuiContext* ctx) { return ctx->IO.GetClipboardTextFn(ctx->IO.ClipboardUserData); }; if (g.IO.SetClipboardTextFn != NULL && (g.PlatformIO.Platform_SetClipboardTextFn == NULL || g.PlatformIO.Platform_SetClipboardTextFn == Platform_SetClipboardTextFn_DefaultImpl)) g.PlatformIO.Platform_SetClipboardTextFn = [](ImGuiContext* ctx, const char* text) { return ctx->IO.SetClipboardTextFn(ctx->IO.ClipboardUserData, text); }; + + // Remap legacy CurveTessellationTol into CurveTessellationMaxError (OBSOLETED in 1.93.0, August 2026) + if (g.Style.CurveTessellationTol != 0.0f) + g.Style.CurveTessellationMaxError = ImSqrt(g.Style.CurveTessellationTol); + g.Style.CurveTessellationTol = 0.0f; #endif } @@ -12020,7 +12135,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) } scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); } - scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0f)); + scroll[axis] = ImRoundPositive64(ImMax(scroll[axis], 0.0f)); if (!window->Collapsed && !window->SkipItems) scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); } @@ -12660,13 +12775,7 @@ bool ImGui::BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags ext // As we bypass BeginChild(), set ImGuiChildFlags_AlwaysAutoResize as it is checked independently from ImGuiWindowFlags_AlwaysAutoResize for now (see #9355) // Ideally we should remove setting ImGuiWindowFlags_AlwaysAutoResize in BeginChild(). if ((extra_window_flags & ImGuiWindowFlags_ChildWindow) && (extra_window_flags & ImGuiWindowFlags_AlwaysAutoResize)) - { - if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) - g.NextWindowData.ChildFlags |= ImGuiChildFlags_AlwaysAutoResize; - else - g.NextWindowData.ChildFlags = ImGuiChildFlags_AlwaysAutoResize; - g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasChildFlags; - } + SetNextWindowChildFlags(ImGuiChildFlags_AlwaysAutoResize, true); char name[128]; IM_ASSERT(extra_window_flags & ImGuiWindowFlags_ChildMenu); @@ -12767,7 +12876,7 @@ bool ImGui::IsPopupOpenRequestForItem(ImGuiPopupFlags popup_flags, ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); - if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (IsMouseReleased(mouse_button, id) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) return true; if (g.NavOpenContextMenuItemId == id && (IsItemFocused() || id == g.CurrentWindow->MoveId)) return true; @@ -12778,7 +12887,7 @@ bool ImGui::IsPopupOpenRequestForWindow(ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); - if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (IsMouseReleased(mouse_button, ImGuiKeyOwner_NoOwner) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) return true; if (g.NavOpenContextMenuWindowId && g.CurrentWindow->ID) @@ -12805,7 +12914,7 @@ bool ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags // This is a helper to handle the simplest case of associating one named popup to one given widget. // - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. // - To create a popup with a specific identifier, pass it in str_id. -// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. // - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. // - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). // This is essentially the same as: @@ -12849,9 +12958,9 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flag ImGuiWindow* window = g.CurrentWindow; if (!str_id) str_id = "void_context"; - ImGuiID id = window->GetID(str_id); + ImGuiID id = window->GetID(str_id); // FIXME: Use a global ID? ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags); - if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + if (IsMouseReleased(mouse_button, id) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) if (GetTopMostPopupModal() == NULL) OpenPopupEx(id, popup_flags); return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); @@ -14147,6 +14256,7 @@ void ImGui::NavInitRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = 0; g.NavJustMovedToIsTabbing = false; + g.NavJustMovedToIsInit = true; g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; } @@ -14414,6 +14524,7 @@ void ImGui::NavMoveRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveKeyMods; g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; + g.NavJustMovedToIsInit = false; g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId); } @@ -15330,15 +15441,9 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame) const bool draw_target_rect = payload.Preview && !(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); if (draw_target_rect && g.DragDropTargetFullViewport != 0) - { - ImRect bb = g.DragDropTargetRect; - bb.Expand(-3.5f); - RenderDragDropTargetRectEx(GetForegroundDrawList(), bb, g.Style.DragDropTargetRounding); - } + RenderDragDropTargetRectForViewport(g.DragDropTargetFullViewport, g.DragDropTargetRect); else if (draw_target_rect) - { RenderDragDropTargetRectForItem(r); - } g.DragDropAcceptFrameCount = g.FrameCount; if ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) && g.DragDropMouseButton == -1) @@ -15369,6 +15474,17 @@ void ImGui::RenderDragDropTargetRectForItem(const ImRect& bb) window->DrawList->PopClipRect(); } +void ImGui::RenderDragDropTargetRectForViewport(ImGuiID viewport_id, const ImRect& bb) +{ + IM_ASSERT(viewport_id != 0); + IM_UNUSED(viewport_id); // Unused in this branch + ImGuiContext& g = *GImGui; + ImGuiViewport* viewport = g.Viewports[0]; + ImRect bb_padded = bb; + bb_padded.Expand(-g.Style.DragDropTargetPadding); + RenderDragDropTargetRectEx(GetForegroundDrawList(viewport), bb_padded, g.Style.DragDropTargetRounding); +} + void ImGui::RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding) { ImGuiContext& g = *GImGui; @@ -16072,13 +16188,14 @@ void ImGuiPlatformIO::ClearPlatformHandlers() Platform_OpenInShellUserData = NULL; Platform_SetImeDataFn = NULL; Platform_ImeUserData = NULL; + InitializeDefaultPlatformHandlers(*this); // Rrevents losing the functionality provided by Platform_*_DefaultImpl on backend re-creation. } void ImGuiPlatformIO::ClearRendererHandlers() { Renderer_TextureMaxWidth = Renderer_TextureMaxHeight = 0; Renderer_RenderState = NULL; - DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = NULL; + DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = DrawCallback_SetSamplerFromTex = NULL; } ImGuiViewport* ImGui::GetMainViewport() @@ -16212,7 +16329,7 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* t ::CloseClipboard(); } -#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) +#elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) #include // Use old API to avoid need for separate .mm file static PasteboardRef main_clipboard = 0; @@ -16384,6 +16501,15 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImG #endif // Default IME handlers +// Setup default ImGuiPlatformIO clipboard/IME handlers +static void InitializeDefaultPlatformHandlers(ImGuiPlatformIO& platform_io) +{ + platform_io.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; + platform_io.Platform_SetClipboardTextFn = Platform_SetClipboardTextFn_DefaultImpl; + platform_io.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; + platform_io.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl; +} + //----------------------------------------------------------------------------- // [SECTION] METRICS/DEBUGGER WINDOW //----------------------------------------------------------------------------- @@ -16611,7 +16737,7 @@ static const char* FormatTextureRefForDebugDisplay(char* buf, int buf_size, ImTe char* buf_end = buf + buf_size; if (tex_ref._TexData != NULL) buf_p += ImFormatString(buf_p, buf_end - buf_p, "#%03d: ", tex_ref._TexData->UniqueID); - ImFormatString(buf_p, buf_end - buf_p, "0x%X", ImGui::DebugTextureIDToU64(tex_ref.GetTexID())); + ImFormatString(buf_p, buf_end - buf_p, "0x%" IM_PRIX64, ImGui::DebugTextureIDToU64(tex_ref.GetTexID())); return buf; } @@ -16663,6 +16789,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL")) { const ImFontLoader* loader_current = atlas->FontLoader; + IM_UNUSED(loader_current); BeginDisabled(!atlas->RendererHasTextures); #ifdef IMGUI_ENABLE_STB_TRUETYPE const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype(); @@ -16783,7 +16910,7 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRe Checkbox("Show used rect", &cfg->ShowTextureUsedRect); PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); ImVec2 p = GetCursorScreenPos(); - if (tex->WantDestroyNextFrame) + if (tex->Status == ImTextureStatus_WantDestroy || tex->Status == ImTextureStatus_Destroyed) Dummy(ImVec2((float)tex->Width, (float)tex->Height)); else ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); @@ -17585,10 +17712,9 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con Selectable(buf, false); if (fg_draw_list && IsItemHovered()) { - ImDrawListFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->PushDrawFlag(ImDrawFlags_AALines, false); // Disable AA on triangle outlines is more readable for very large and thin triangles. fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), 1.0f, ImDrawFlags_Closed); - fg_draw_list->Flags = backup_flags; + fg_draw_list->PopDrawFlag(); } } TreePop(); @@ -17604,8 +17730,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co // Draw wire-frame version of all triangles ImRect clip_rect = draw_cmd->ClipRect; ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); - ImDrawListFlags backup_flags = out_draw_list->Flags; - out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + out_draw_list->PushDrawFlag(ImDrawFlags_AALines, false); // Disable AA on triangle outlines is more readable for very large and thin triangles. for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; ) { ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list @@ -17623,7 +17748,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co out_draw_list->AddRect(ImTrunc(clip_rect.Min), ImTrunc(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU out_draw_list->AddRect(ImTrunc(vtxs_rect.Min), ImTrunc(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles } - out_draw_list->Flags = backup_flags; + out_draw_list->PopDrawFlag(); } // [DEBUG] Compute mask of inputs with the same codepoint. @@ -17633,7 +17758,8 @@ static int CalcFontGlyphSrcOverlapMask(ImFontAtlas* atlas, ImFont* font, unsigne for (int src_n = 0; src_n < font->Sources.Size; src_n++) { ImFontConfig* src = font->Sources[src_n]; - if (!(src->FontLoader ? src->FontLoader : atlas->FontLoader)->FontSrcContainsGlyph(atlas, src, (ImWchar)codepoint)) + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, (ImWchar)codepoint) == 0) continue; mask |= (1 << src_n); count++; @@ -18239,9 +18365,9 @@ void ImGui::DebugDrawLineExtents(ImU32 col) float curr_x = window->DC.CursorPos.x; float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y); float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y); - window->DrawList->AddLineH(curr_x - 5.0f, curr_x + 5.0f, line_y1, col, 1.0f); - window->DrawList->AddLineV(curr_x - 0.5f, line_y1, line_y2, col, 1.0f); - window->DrawList->AddLineH(curr_x - 5.0f, curr_x + 5.0f, line_y2, col, 1.0f); + window->DrawList->AddLineH(curr_x - 4.0f, curr_x + 5.0f, line_y1, col, 1.0f); + window->DrawList->AddLineV(curr_x, line_y1, line_y2, col, 1.0f); + window->DrawList->AddLineH(curr_x - 4.0f, curr_x + 5.0f, line_y2, col, 1.0f); } // Draw last item rect in ForegroundDrawList (so it is always visible) diff --git a/include/imgui/imgui.h b/include/imgui/imgui.h index 611c5f2..a7b071d 100644 --- a/include/imgui/imgui.h +++ b/include/imgui/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (headers) // Help: @@ -29,8 +29,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.9b" -#define IMGUI_VERSION_NUM 19291 +#define IMGUI_VERSION "1.93.0" +#define IMGUI_VERSION_NUM 19300 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -49,7 +49,7 @@ Index of this file: // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) -// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawList, ImDrawData) // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) @@ -128,6 +128,18 @@ Index of this file: #define IM_MSVC_RUNTIME_CHECKS_RESTORE #endif +// Alternative to using a .natstepfilter file or other scripts in misc/debuggers/ to skip debug-stepping selected trivial functions. +// If you get a compiler error or warning related to use, please report it to us! +#ifndef IM_NODEBUGSTEP +#if (defined(__clang__) && (__clang_major__ >= 7)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +#define IM_NODEBUGSTEP [[gnu::artificial]] +#elif defined(_MSC_VER) && (_MSC_VER >= 1915) +#define IM_NODEBUGSTEP __declspec(non_user_code) +#else +#define IM_NODEBUGSTEP +#endif +#endif + // Warnings #ifdef _MSC_VER #pragma warning (push) @@ -236,7 +248,6 @@ typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A // - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments. // - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments. typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions -typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance typedef int ImDrawTextFlags; // -> enum ImDrawTextFlags_ // Internal, do not use! typedef int ImFontFlags; // -> enum ImFontFlags_ // Flags: for ImFont typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas @@ -294,11 +305,11 @@ typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { - float x, y; - constexpr ImVec2() : x(0.0f), y(0.0f) { } - constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } + float x, y; + IM_NODEBUGSTEP constexpr inline ImVec2() : x(0.0f), y(0.0f) { } + IM_NODEBUGSTEP constexpr inline ImVec2(float _x, float _y) : x(_x), y(_y) { } + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif @@ -307,9 +318,9 @@ struct ImVec2 // ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] struct ImVec4 { - float x, y, z, w; - constexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { } - constexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } + float x, y, z, w; + IM_NODEBUGSTEP constexpr inline ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { } + IM_NODEBUGSTEP constexpr inline ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } #ifdef IM_VEC4_CLASS_EXTRA IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. #endif @@ -983,7 +994,7 @@ namespace ImGui IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. returns NULL when drag and drop is finished or inactive. use ImGuiPayload::IsDataType() to test for the payload type. - // Disabling [BETA API] + // Disabling // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) // - Tooltips windows are automatically opted out of disabling. Note that IsItemHovered() by default returns false on disabled items, unless using ImGuiHoveredFlags_AllowWhenDisabled. @@ -1100,7 +1111,7 @@ namespace ImGui // - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them. // - The return value of SetItemKeyOwner() says if ownership has been requested for the item, which is a shortcut to calling yet non-public TestKeyOwner() function. // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. - IMGUI_API bool SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Return true when ownership has been set. Roughly equivalent to 'if (TestKeyOwner(key, GetItemID()) && (IsItemHovered() || IsItemActive())) { SetKeyOwner(key, GetItemID());'. + IMGUI_API bool SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Return true when ownership has been set. Roughly equivalent to 'if (TestKeyOwner(key, GetItemID()) && (IsItemHovered() || IsItemActive())) { SetKeyOwner(key, GetItemID());'. // Inputs Utilities: Mouse // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. @@ -1261,6 +1272,17 @@ enum ImGuiItemFlags_ ImGuiItemFlags_LiveEditOnInputText = 1 << 7, // true // InputText: apply keyboard edits to backing value while typing. Otherwise, edits are applied when validating, tabbing out or losing focus. ImGuiItemFlags_LiveEditOnInputScalar = 1 << 8, // false // DragXXX, SliderXXX, InputScalar: apply keyboard edits to backing value while typing. Otherwise, edits are applied when validating, tabbing out or losing focus. ImGuiItemFlags_LiveEditOnInput = ImGuiItemFlags_LiveEditOnInputText | ImGuiItemFlags_LiveEditOnInputScalar, + + //--------------------------------------------------------------------------------- + // [BETA] MixedValue mode used to represent a mixed/indeterminate state, typically for multi-selection. + // - Replace value display with "-" or a custom label. + // - Enter key validation apply an edit and return true even if value hasn't changed (in order to apply to all). + // - Supported by selected widgets: Checkbox, RadioButton, Sliders, Drags, Inputs, Combo. + // - Note: InputText-side Undo cannot be reliably combined with MixedValue + LiveEdit On: + // - Both the initial edit and subsequent undo/revert will typically make your app code write to all backing objects. + // - If you use MixedMode and the simplest solution is to ensure LiveEdit is off but widgets where this applies. + //--------------------------------------------------------------------------------- + ImGuiItemFlags_MixedValue = 1 << 9, // false // [BETA] Represent a mixed/indeterminate value. Replace value label with "-" and apply edits on validation. }; // Flags for ImGui::InputText() @@ -2259,13 +2281,13 @@ struct ImVector inline int size_in_bytes() const { return Size * (int)sizeof(T); } inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } inline int capacity() const { return Capacity; } - inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } - inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + IM_NODEBUGSTEP inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + IM_NODEBUGSTEP inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } - inline T* begin() { return Data; } - inline const T* begin() const { return Data; } - inline T* end() { return Data + Size; } - inline const T* end() const { return Data + Size; } + IM_NODEBUGSTEP inline T* begin() { return Data; } + IM_NODEBUGSTEP inline const T* begin() const { return Data; } + IM_NODEBUGSTEP inline T* end() { return Data + Size; } + IM_NODEBUGSTEP inline const T* end() const { return Data + Size; } inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } @@ -2356,7 +2378,7 @@ struct ImGuiStyle ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. - float MenuItemRounding; // Radius of MenuItem, BeginMenu rounding. + float MenuItemRounding; // Radius of MenuItem, BeginMenu rounding. float SelectableRounding; // Radius of Selectable rounding. MODIFYING THIS IS DISCOURAGED. CONTIGUOUS SELECTIONS WILL NOT LOOK RIGHT. (#7589) float DragDropTargetRounding; // Radius of the drag and drop target frame. When <0.0f: use FrameRounding. float DragDropTargetBorderSize; // Thickness of the drag and drop target border. @@ -2373,10 +2395,12 @@ struct ImGuiStyle ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured). float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. - bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). - bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). - bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). - float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + + // Rendering & Tessellation + bool AntiAliasedLines; // Enable anti-aliased lines/borders. Used at the beginning of the frame to set ImDrawFlags_AALines in all draw-lists. + bool AntiAliasedLineEnds; // Enable anti-aliased lines/borders ends. Nicer for thick lines but more expensive. Used at the beginning of the frame to set ImDrawFlags_AALineEnds in all draw-lists. + bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Used at the beginning of the frame to set ImDrawFlags_AAFill in all draw-lists. + float CurveTessellationMaxError; // Maximum error (in pixels) when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. // Colors @@ -2400,6 +2424,8 @@ struct ImGuiStyle // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + bool AntiAliasedLinesUseTex; // [OBSOLETE] Enable anti-aliased lines/borders using textures for legacy strokes. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). + float CurveTessellationTol; // [OBSOLETE] Old CurveTessellationTol = New CurveTessellationMaxError*CurveTessellationMaxError. // Changed in 1.93.0 // TabMinWidthForCloseButton = TabCloseButtonMinWidthUnselected // Renamed in 1.91.9. #endif }; @@ -2535,6 +2561,12 @@ struct ImGuiIO // - Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them. bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing. + // Option to compare < 1.93.0 rendering details vs 1.93.0 rendering details. (#9504) + // - Equivalent to calling PushDrawFlag(ImDrawFlags_StrokeLegacy,true) on every draw list instances. + // - Suggested use, e.g. io.ConfigDebugDrawListDefaultsToStrokeLegacy = io.KeyShift; // Map to SHIFT modifier + // - Also see our interactive testbed: https://www.dearimgui.com/docs/drawlist_v193 + bool ConfigDebugDrawListDefaultsToStrokeLegacy; // false // Default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering. + //------------------------------------------------------------------ // Platform Identifiers // (the imgui_impl_xxxx backend files are setting those up for you) @@ -2761,30 +2793,27 @@ struct ImGuiOnceUponAFrame operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } }; -// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +// Helper: Parse and apply text filters e.g. 'aaa bbb' (all), 'aaa,bbb' (any), '-aaa' (exclude), '"Hello, world"' (exact sequence) +struct ImGuiTextFilterItem; struct ImGuiTextFilter { IMGUI_API ImGuiTextFilter(const char* default_filter = ""); - IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; - IMGUI_API void Build(); - void Clear() { InputBuf[0] = 0; Build(); } - bool IsActive() const { return !Filters.empty(); } + IMGUI_API void Build(); // Update internal data when filter changes + inline void Clear() { InputBuf[0] = 0; Build(); } // Clear filter + inline bool IsActive() const { return _Items.Size != 0; } // Useful if you need e.g. an alternative code-path when there are no filters - // [Internal] - struct ImGuiTextRange - { - const char* b; - const char* e; - - ImGuiTextRange() { b = e = NULL; } - ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } - bool empty() const { return b == e; } - IMGUI_API void split(char separator, ImVector* out) const; - }; - char InputBuf[256]; - ImVectorFilters; - int CountGrep; + // Helper to call InputText() + Build() when buffer is changed. + IMGUI_API bool Draw(const char* label = "Filter"); + IMGUI_API bool DrawWithHint(const char* label = "Filter", const char* hint = "incl -excl"); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); } +#endif + + // Members + char InputBuf[256]; // User input buffer + int _CountExclude; // [Internal] >= 0 count of leading exclude + ImVector _Items; // [Internal] Pre-parsed, trimmed, reordered items }; // Helper: Growable text buffer for logging/accumulating text @@ -2864,6 +2893,20 @@ struct ImGuiStorage #endif }; +// [Internal] Used for small stacks. Do not use. +template +struct ImSmallStack_ +{ + T LocalData[Capacity]; // FIXME: should evolve into using heap, e.g union {} with T* HeapData + add SZ_T Capacity. + SZ_T Size = 0; + + inline void clear() { Size = 0; } + inline T& back() { IM_ASSERT(Size > 0); return LocalData[Size - 1]; } + inline void push_back(const T& v) { IM_ASSERT(Size < Capacity); memcpy(&LocalData[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline int capacity() const { return Capacity; } +}; + // Flags for ImGuiListClipper (currently not fully exposed in function calls: a future refactor will likely add this to ImGuiListClipper::Begin function equivalent) enum ImGuiListClipperFlags_ { @@ -2937,41 +2980,41 @@ struct ImGuiListClipper #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF // ImVec2 operators -inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } -inline ImVec2 operator*(const float lhs, const ImVec2& rhs) { return ImVec2(lhs * rhs.x, lhs * rhs.y); } -inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } -inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -inline ImVec2 operator+(const ImVec2& lhs) { return lhs; } -inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +IM_NODEBUGSTEP inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +IM_NODEBUGSTEP inline ImVec2 operator*(const float lhs, const ImVec2& rhs) { return ImVec2(lhs * rhs.x, lhs * rhs.y); } +IM_NODEBUGSTEP inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +IM_NODEBUGSTEP inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +IM_NODEBUGSTEP inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +IM_NODEBUGSTEP inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +IM_NODEBUGSTEP inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +IM_NODEBUGSTEP inline ImVec2 operator+(const ImVec2& lhs) { return lhs; } +IM_NODEBUGSTEP inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +IM_NODEBUGSTEP inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +IM_NODEBUGSTEP inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +IM_NODEBUGSTEP inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +IM_NODEBUGSTEP inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +IM_NODEBUGSTEP inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +IM_NODEBUGSTEP inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +IM_NODEBUGSTEP inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } +IM_NODEBUGSTEP inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } // ImVec4 operators -inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } -inline ImVec4 operator*(const float lhs, const ImVec4& rhs) { return ImVec4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); } -inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } -inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } -inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } -inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } -inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } -inline ImVec4 operator+(const ImVec4& lhs) { return lhs; } -inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } -inline ImVec4& operator*=(ImVec4& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; lhs.z *= rhs; lhs.w *= rhs; return lhs; } -inline ImVec4& operator/=(ImVec4& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; lhs.z /= rhs; lhs.w /= rhs; return lhs; } -inline ImVec4& operator+=(ImVec4& lhs, const ImVec4& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; lhs.w += rhs.w; return lhs; } -inline ImVec4& operator-=(ImVec4& lhs, const ImVec4& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; lhs.z -= rhs.z; lhs.w -= rhs.w; return lhs; } -inline ImVec4& operator*=(ImVec4& lhs, const ImVec4& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; lhs.z *= rhs.z; lhs.w *= rhs.w; return lhs; } -inline ImVec4& operator/=(ImVec4& lhs, const ImVec4& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; lhs.z /= rhs.z; lhs.w /= rhs.w; return lhs; } -inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } -inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } +IM_NODEBUGSTEP inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } +IM_NODEBUGSTEP inline ImVec4 operator*(const float lhs, const ImVec4& rhs) { return ImVec4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); } +IM_NODEBUGSTEP inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } +IM_NODEBUGSTEP inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +IM_NODEBUGSTEP inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +IM_NODEBUGSTEP inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +IM_NODEBUGSTEP inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } +IM_NODEBUGSTEP inline ImVec4 operator+(const ImVec4& lhs) { return lhs; } +IM_NODEBUGSTEP inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } +IM_NODEBUGSTEP inline ImVec4& operator*=(ImVec4& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; lhs.z *= rhs; lhs.w *= rhs; return lhs; } +IM_NODEBUGSTEP inline ImVec4& operator/=(ImVec4& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; lhs.z /= rhs; lhs.w /= rhs; return lhs; } +IM_NODEBUGSTEP inline ImVec4& operator+=(ImVec4& lhs, const ImVec4& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; lhs.w += rhs.w; return lhs; } +IM_NODEBUGSTEP inline ImVec4& operator-=(ImVec4& lhs, const ImVec4& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; lhs.z -= rhs.z; lhs.w -= rhs.w; return lhs; } +IM_NODEBUGSTEP inline ImVec4& operator*=(ImVec4& lhs, const ImVec4& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; lhs.z *= rhs.z; lhs.w *= rhs.w; return lhs; } +IM_NODEBUGSTEP inline ImVec4& operator/=(ImVec4& lhs, const ImVec4& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; lhs.z /= rhs.z; lhs.w /= rhs.w; return lhs; } +IM_NODEBUGSTEP inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } +IM_NODEBUGSTEP inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } IM_MSVC_RUNTIME_CHECKS_RESTORE #endif @@ -3177,15 +3220,10 @@ struct ImGuiSelectionExternalStorage }; //----------------------------------------------------------------------------- -// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawList, ImDrawData) // Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. //----------------------------------------------------------------------------- -// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. -#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX -#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) -#endif - // ImDrawIdx: vertex index. [Compile-time configurable type] // - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). // - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. @@ -3279,40 +3317,82 @@ struct ImDrawListSplitter // Flags for ImDrawList functions enum ImDrawFlags_ { - ImDrawFlags_None = 0, - - // Rounding for AddRect(), AddRectFilled(), PathRect() - // - When not specified, we defaults to ImDrawFlags_RoundCornersAll! So you only need to use those flags if you want another configuration. - ImDrawFlags_RoundCornersTopLeft = 1 << 4, // Round top-left corner only (when rounding > 0.0f, we default to all corners). - ImDrawFlags_RoundCornersTopRight = 1 << 5, // Round top-right corner only (when rounding > 0.0f, we default to all corners). - ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // Round bottom-left corner only (when rounding > 0.0f, we default to all corners). - ImDrawFlags_RoundCornersBottomRight = 1 << 7, // Round bottom-right corner only (when rounding > 0.0f, we default to all corners). - ImDrawFlags_RoundCornersNone = 1 << 8, // Disable rounding even if `float rounding > 0.0f`. This is NOT zero, NOT an implicit flag! - ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, // (Default!!) - ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified! - ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, - ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, - ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, - ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, - ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, - - // Stroke options - ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed. - //ImDrawFlags_Closed = 1, // Prior to 1.92.8 (May 2026), ImDrawFlags_Closed was guaranteed to be == 1<<0 == 1 for legacy compatibility reason. Hardcoded use of 1 or true should be replaced. - - ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, // == 0x8000000F, -}; + ImDrawFlags_None = 0, + //ImDrawFlags_Closed = 1, // -> FLAG MOVED BELOW. Prior to 1.92.8 (May 2026): ImDrawFlags_Closed was guaranteed to be == (1<<0) == 1, for legacy compatibility reason. Hardcoded use of 1 or true should be replaced with 'ImDrawFlags_Closed'. + + // About usage of flags: + // - "Prim" column: 'OK' = flag can be used to configure an individual AddXXX() call. + // - "Scope" column: 'OK' = initialized by ImGui based on Style options (e.g. whether anti-aliased is enabled) + may be modified using ImDrawList::PushDrawFlag(). + // OK(0)/OK(1) indicates whether this flag is set in the default ImGui Style settings. + + // - Rounding default to ImDrawFlags_RoundAll when 'rounding > 0'. + // - So you only need to use the ImDrawFlags_RoundXXX flags if you want a special configuration (e.g. a rectangle with one rounded corner). + // Rounding for AddRectXXX(), PathRect() ------ // Prim/Scope? + ImDrawFlags_RoundTopLeft = 1 << 4, // OK -- // Round top-left corner only (when 'rounding > 0.0f', we default to all corners). + ImDrawFlags_RoundTopRight = 1 << 5, // OK -- // Round top-right corner only (when 'rounding > 0.0f', we default to all corners). + ImDrawFlags_RoundBottomLeft = 1 << 6, // OK -- // Round bottom-left corner only (when 'rounding > 0.0f', we default to all corners). + ImDrawFlags_RoundBottomRight = 1 << 7, // OK -- // Round bottom-right corner only (when 'rounding > 0.0f', we default to all corners). + ImDrawFlags_RoundNone = 1 << 8, // OK -- // Disable rounding even when 'rounding > 0.0f'. This value is NOT zero, it is NOT an implicit flag! + ImDrawFlags_RoundAll = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundTopRight | ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundBottomRight, // (Default!!) + ImDrawFlags_RoundTop = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundTopRight, + ImDrawFlags_RoundBottom = ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundBottomRight, + ImDrawFlags_RoundLeft = ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundTopLeft, + ImDrawFlags_RoundRight = ImDrawFlags_RoundBottomRight | ImDrawFlags_RoundTopRight, + + // Stroke Options ----------------------------- // Prim/Scope? + ImDrawFlags_Closed = 1 << 9, // OK -- // PathStroke(), AddPolyline(): specify that shape should be closed. + ImDrawFlags_JoinMiter = 1 << 10, // OK -- // PathStroke(), AddPolyline(): use miter joins/corners only. This assumes that the input polyline does not have corners sharper than 90 degrees. Slightly faster. + ImDrawFlags_CapSquare = 1 << 11, // OK -- // PathStroke(), AddPolyline(): use square cap line ends. + + // About Stroke Ends: + // - Rendering is optimized for fast pixel-perfect UI, so line ends are not anti-aliased by default. It's cheaper (we can emit less vertices). + // - For more free-form drawings, light graphs and markers, or when using thick strokes: you can turn them on using the ImDrawFlags_AALineEnds flag. + // - See 'Demo->Examples->Custom Rendering' to interactively toy with those flags. + // - 'OK*' indicates using this at the AddXXX() call site is unlikely: it would only makes sense if (1) the option is disabled in style/scope and (2) you want to forcefully enable it for a single primitives. Possible but unlikely! Only supported for functions taking flags inputs. + // Stroke/Fill Anti-aliasing ------------------ // Prim/Scope? + ImDrawFlags_AAFill = 1 << 12, // OK* OK(1) // Enable anti-aliasing for Filled shapes. + ImDrawFlags_AALines = 1 << 13, // OK* OK(1) // Enable anti-aliasing for Strokes (lines, borders). + ImDrawFlags_AALineEnds = 1 << 14, // OK OK(0) // Enable anti-aliasing for Strokes Ends. Requires AALines to also be enabled. Useful on thick strokes or for precise continuity of multiple lines. A little more costly. + //ImDrawFlags_NoAA = 1 << 15, // OK -- // Disable anti-aliasing for a given primitive. + //ImDrawFlags_NoAALineEnds = 1 << 16, // OK -- // Disable anti-aliasing ends for a given primitive. + + // About Stroke Position: + // - Read https://github.com/ocornut/imgui/wiki/Draw-List (this guide includes a precise list of differences between 1.92.9 and 1.93.0) + // - Read https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering + // Stroke Position relative to shape outline -- // Prim/Scope? + ImDrawFlags_StrokeInside = 1 << 17, // OK -- // Draw stroke inside of the shape outline (default for closed shapes and AddLineH, AddLineV functions) + ImDrawFlags_StrokeCenter = 2 << 17, // OK -- // Draw stroke at the center of the shape outline (default for paths, bezier, and AddLine functions) + ImDrawFlags_StrokeCenterBiased = 3 << 17, // OK -- // Draw stroke at the center of the shape outline, so that half thickness rounded down will be outside, and the rest inside the shape outline. Useful for axis-aligned shapes: AddLineH, AddLineV, AddRect. Does not animate well! + ImDrawFlags_StrokeOutside = 4 << 17, // OK -- // Draw stroke outside of the shape outline + ImDrawFlags_StrokeLegacy = 7 << 17, // OK OK(0) // Use legacy positioning + enable JoinMiter + disable AALineEnds. Must be all bits set. + + // Other Options ------------------------------ // Prim/Scope? + ImDrawFlags_TextNoPixelSnap = 1 << 20, // OK OK(0) // Disable automatically snapping AddText() calls to pixel boundaries. + ImDrawFlags_UseTexForRoundCorners = 1 << 21, // -- OK(1) // Enable using textures instead of strokes to draw rounded corners/circles where possible (faster). Used by default unless 'ImFontAtlasFlags_NoBakedRoundCorners' is enabled in the font atlas. + ImDrawFlags_UseVtxOffset = 1 << 22, // -- OK(1) // Can emit 'VtxOffset > 0' to allow large meshes with 16-bit ImDrawIdx. Used by default when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled by the backend. + ImDrawFlags_AllowTexForRoundCorners_= 1 << 23, // -- OK(1) // [Internal] -// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. -// It is however possible to temporarily alter flags between calls to ImDrawList:: functions. -enum ImDrawListFlags_ -{ - ImDrawListFlags_None = 0, - ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) - ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). - ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). - ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. - ImDrawListFlags_TextNoPixelSnap = 1 << 4, // Disable automatically snapping AddText() calls to pixel boundaries. + // [Internal] + ImDrawFlags_RoundMask_ = ImDrawFlags_RoundAll | ImDrawFlags_RoundNone, // [Internal] + ImDrawFlags_AllowInPushScope_ = ImDrawFlags_AAFill | ImDrawFlags_AALines | ImDrawFlags_AALineEnds | ImDrawFlags_StrokeLegacy | ImDrawFlags_TextNoPixelSnap | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_UseVtxOffset | ImDrawFlags_RoundMask_, // [Internal] Values allowed in PushDrawFlag() scope. + ImDrawFlags_AllowInFrameScope_ = ImDrawFlags_AllowInPushScope_ | ImDrawFlags_AllowTexForRoundCorners_, + ImDrawFlags_StrokeMask_ = 0x07 << 17, // [Internal] + ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, // [Internal] == 0x8000000F. Reserved to detect misuses. + + // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // RENAMED in 1.93.0 (Oct 2026): ImDrawFlags_RoundCornersXXXX -> ImDrawFlags_RoundXXXX. + ImDrawFlags_RoundCornersTopLeft = ImDrawFlags_RoundTopLeft, + ImDrawFlags_RoundCornersTopRight = ImDrawFlags_RoundTopRight, + ImDrawFlags_RoundCornersBottomLeft = ImDrawFlags_RoundBottomLeft, + ImDrawFlags_RoundCornersBottomRight = ImDrawFlags_RoundBottomRight, + ImDrawFlags_RoundCornersNone = ImDrawFlags_RoundNone, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundAll, + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundTop, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundBottom, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundRight, +#endif }; // Draw command list @@ -3330,7 +3410,7 @@ struct ImDrawList ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those ImVector VtxBuffer; // Vertex buffer. - ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + ImDrawFlags Flags; // Current flags for drawing primitives. Alter with PushDrawFlag()/PopDrawFlags() to adjust defaults to a given scope. // [Internal, used while building lists] unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. @@ -3343,7 +3423,10 @@ struct ImDrawList ImVector _ClipRectStack; // [Internal] ImVector _TextureStack; // [Internal] ImVector _CallbacksDataBuf; // [Internal] + ImSmallStack_ _DrawFlagsStack;// [Internal] float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content + float _InvFringeScale; // [internal] 1.0 / _FringeScale // FIXME: Consider renaming to _PixelDensity. + bool _FringeScaleIsInteger; // [Internal] true if 1/_FringeScale is a whole number, used to select fast path for rendering const char* _OwnerName; // Pointer to owner window's name for debugging // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData(). @@ -3356,6 +3439,8 @@ struct ImDrawList IMGUI_API void PopClipRect(); IMGUI_API void PushTexture(ImTextureRef tex_ref); IMGUI_API void PopTexture(); + IMGUI_API void PushDrawFlag(ImDrawFlags flags, bool enabled); // [BETA] Please notify me if you are using this. + IMGUI_API void PopDrawFlag(); inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } @@ -3366,32 +3451,32 @@ struct ImDrawList // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. // In future versions we will use textures to provide cheaper and higher-quality circles. // Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides. - IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0); + IMGUI_API void AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0); + IMGUI_API void AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, float thickness = 1.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size) IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size) IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); - IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); - IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); - IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); - IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); - IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f, ImDrawFlags flags = 0); IMGUI_API void AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); IMGUI_API void AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); - IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) - IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0, ImDrawFlags flags = 0); // Cubic Bezier (4 control points) + IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0, ImDrawFlags flags = 0); // Quadratic Bezier (3 control points) // General polygon // - Only simple polygons are supported by filling functions (no self-intersections, no holes). // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library. - IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0); - IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); + inline void AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0) { _AddPolyline(points, num_points, col, thickness, flags, FLT_MAX); } + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags = 0); IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col); // Image primitives @@ -3408,9 +3493,9 @@ struct ImDrawList inline void PathClear() { _Path.Size = 0; } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } - inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } + inline void PathFillConvex(ImU32 col, ImDrawFlags flags = 0) { AddConvexPolyFilled(_Path.Data, _Path.Size, col, flags); _Path.Size = 0; } inline void PathFillConcave(ImU32 col) { AddConcavePolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } - inline void PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0) { AddPolyline(_Path.Data, _Path.Size, col, thickness, flags); _Path.Size = 0; } + inline void PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0) { _AddPolyline(_Path.Data, _Path.Size, col, thickness, flags, FLT_MAX); _Path.Size = 0; } IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0); IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments = 0); // Ellipse @@ -3477,6 +3562,7 @@ struct ImDrawList // [Internal helpers] IMGUI_API void _SetDrawListSharedData(ImDrawListSharedData* data); IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _SetPixelDensity(float pixel_density); IMGUI_API void _ClearFreeMemory(); IMGUI_API void _PopUnusedDrawCmd(); IMGUI_API void _TryMergeDrawCmds(); @@ -3487,6 +3573,13 @@ struct ImDrawList IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); + IMGUI_API void _AddRectFilledBaked(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float r, const ImVec4& tex_uvs, ImDrawFlags flags); + IMGUI_API void _AddRectBaked(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float r, float t, const ImVec4& tex_uvs, ImDrawFlags flags); + IMGUI_API void _AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness, ImDrawFlags flags); + IMGUI_API void _AddRectTinyRounding(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags); + IMGUI_API void _SelectLineTexture(float screen_thickness, ImVec2* out_uv0, ImVec2* out_uv1, float* out_fringe, ImDrawFlags flags); + IMGUI_API float _CalculateCenterBiasedOffset(float thickness); + IMGUI_API void _AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags, float max_inner_offset); }; // All draw data to render a Dear ImGui frame @@ -3703,7 +3796,8 @@ enum ImFontAtlasFlags_ ImFontAtlasFlags_None = 0, ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) - ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory, allow support for point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). + ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build anti-aliased line textures into the atlas (save a little texture memory). SINCE 1.93.0 THIS PREVENTS ANTI-ALIASED LINES FROM WORKING AND WILL DISABLE THEM. + ImFontAtlasFlags_NoBakedRoundCorners= 1 << 3, // Don't build round corners into the atlas. }; // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: @@ -3741,8 +3835,8 @@ struct ImFontAtlas IMGUI_API void CompactCache(); // Compact cached glyphs and texture. IMGUI_API void SetFontLoader(const ImFontLoader* font_loader); // Change font loader at runtime. - // Clearing the atlas/fonts has little use nowadays, unless you want to batch remove all fonts. - // - Since 1.92, you can call ClearFonts() mid-frame, if you load new fonts afterwards. + // Clearing the atlas/fonts has little use nowadays, unless you want to batch remove all fonts. + // - Since 1.92, you can call ClearFonts() mid-frame, if you load new fonts afterwards. // - As we are transitioning toward our new font system the semantic for those functions gets increasingly misleading and are often a source of issues. // TL;DR; most likely, don't use any of those functions. We expect to obsolete/rework them. IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame! @@ -3820,7 +3914,7 @@ struct ImFontAtlas // Input ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). - int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method never relies on bilinear filtering you may set this to 0. int TexMinWidth; // Minimum desired texture width. Must be a power of two. Default to 512. int TexMinHeight; // Minimum desired texture height. Must be a power of two. Default to 128. int TexMaxWidth; // Maximum desired texture width. Must be a power of two. Default to 8192. @@ -3847,7 +3941,6 @@ struct ImFontAtlas ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel. May change as new texture gets created. ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector Sources; // Source/configuration data - ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID int FontNextUniqueID; // Next value to be stored in ImFont->FontID ImVector DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. @@ -3944,7 +4037,7 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 17 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 8K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph (== EllipsisChar) needs to be generated by combining multiple '.'. - ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. + ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapCodepointXXX(). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() #endif @@ -3970,8 +4063,10 @@ struct ImFont // [Internal] Don't use! IMGUI_API void ClearOutputData(); - IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. + IMGUI_API void AddRemapCodepoint(ImWchar from_codepoint, ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. + IMGUI_API void AddRemapCodepointToGlyphIndex(ImWchar from_codepoint, int font_src_idx, int glyph_idx); IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); + //inline void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) { AddRemapCodepoint(from_codepoint, to_codepoint); } // Renamed in 1.93.0 (Sep 2026) }; // This is provided for consistency (but we don't actually use this) @@ -4088,6 +4183,7 @@ struct ImGuiPlatformIO ImDrawCallback DrawCallback_ResetRenderState; // Request to reset the graphics/render state. ImDrawCallback DrawCallback_SetSamplerLinear; // Request backend to set texture sampling to Linear. ImDrawCallback DrawCallback_SetSamplerNearest; // Request backend to set texture sampling to Nearest/Point. + ImDrawCallback DrawCallback_SetSamplerFromTex; // Request backend to use sampler associated to texture - only available in some backends: OpenGL2/3 and SDLRenderer3. //ImDrawCallback DrawCallback_SetSamplerCustom; // Request backend to set texture sampling using Backend Specific data. //------------------------------------------------------------------ @@ -4222,6 +4318,18 @@ namespace ImGui #define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // OBSOLETED in 1.92.8: Use ImGui::GetPlatformIO().DrawCallback_ResetRenderState +// -- RENAMED in 1.93.0: Merged ImDrawListFlags into ImDrawFlags. +typedef ImDrawFlags ImDrawListFlags; +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = ImDrawFlags_None, + ImDrawListFlags_AntiAliasedFill = ImDrawFlags_AAFill, + ImDrawListFlags_AntiAliasedLines = ImDrawFlags_AALines, + ImDrawListFlags_AntiAliasedLinesUseTex = ImDrawFlags_AALines, // No effect, anti-aliased rendering always uses textures from 1.93+ + ImDrawListFlags_AllowVtxOffset = ImDrawFlags_UseVtxOffset, + ImDrawListFlags_TextNoPixelSnap = ImDrawFlags_TextNoPixelSnap, +}; + //-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect // - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h @@ -4245,16 +4353,16 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect; //typedef ImDrawFlags ImDrawCornerFlags; //enum ImDrawCornerFlags_ //{ -// ImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit -// ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). -// ImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight, // Was == 0x02 (1 << 1) prior to 1.82. -// ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. -// ImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. -// ImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll, // Was == 0x0F prior to 1.82 -// ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, -// ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, -// ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, -// ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, +// ImDrawCornerFlags_None = ImDrawFlags_RoundNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundNone which is != 0 and not implicit +// ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). +// ImDrawCornerFlags_TopRight = ImDrawFlags_RoundTopRight, // Was == 0x02 (1 << 1) prior to 1.82. +// ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. +// ImDrawCornerFlags_BotRight = ImDrawFlags_RoundBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. +// ImDrawCornerFlags_All = ImDrawFlags_RoundAll, // Was == 0x0F prior to 1.82 +// ImDrawCornerFlags_Top = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundTopRight, +// ImDrawCornerFlags_Bot = ImDrawFlags_RoundBottomLeft | ImDrawFlags_RoundBottomRight, +// ImDrawCornerFlags_Left = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundBottomLeft, +// ImDrawCornerFlags_Right = ImDrawFlags_RoundTopRight | ImDrawFlags_RoundBottomRight, //}; // RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022) diff --git a/include/imgui/imgui_demo.cpp b/include/imgui/imgui_demo.cpp index 9f841b3..13734d3 100644 --- a/include/imgui/imgui_demo.cpp +++ b/include/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (demo code) // Help: @@ -87,6 +87,7 @@ Index of this file: // [SECTION] DemoWindowWidgetsImages() // [SECTION] DemoWindowWidgetsListBoxes() // [SECTION] DemoWindowWidgetsLiveEdit() +// [SECTION] DemoWindowWidgetsMixedValues() // [SECTION] DemoWindowWidgetsMultiComponents() // [SECTION] DemoWindowWidgetsPlotting() // [SECTION] DemoWindowWidgetsProgressBars() @@ -575,6 +576,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss); ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data."); + ImGui::Checkbox("io.ConfigDebugDrawListDefaultsToStrokeLegacy", &io.ConfigDebugDrawListDefaultsToStrokeLegacy); + ImGui::SameLine(); HelpMarker("Option to default all ImDrawList to ImDrawFlags_StrokeLegacy mode, mimicking pre-1.93.0 rendering."); ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings); ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)."); @@ -962,8 +965,9 @@ static void DemoWindowWidgetsBasic() ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::Button("Click"); - ImGui::PopStyleColor(3); + ImGui::PopStyleColor(4); ImGui::PopID(); } @@ -1258,6 +1262,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::OpenPopup("mypicker"); backup_color = color; } + float ref_sz = ImGui::GetFrameHeight(); if (ImGui::BeginPopup("mypicker")) { ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); @@ -1265,11 +1270,12 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); + ImVec2 color_button_sz(ref_sz * 3.0f, ref_sz * 2.0f); ImGui::BeginGroup(); // Lock X position ImGui::Text("Current"); - ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, color_button_sz); ImGui::Text("Previous"); - if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, color_button_sz)) color = backup_color; ImGui::Separator(); ImGui::Text("Palette"); @@ -1280,7 +1286,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags)) color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! // Allow user to drop colors into each palette entry. Note that ColorButton() is already a @@ -1303,8 +1309,9 @@ static void DemoWindowWidgetsColorAndPickers() IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)"); ImGui::Text("Color button only:"); static bool no_border = false; + const ImVec2 color_button_sz(ref_sz * 2.0f, ref_sz * 2.0f); ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), color_button_sz); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); ImGui::SeparatorText("Color picker"); @@ -1451,7 +1458,8 @@ static void DemoWindowWidgetsComboBoxes() filter.Clear(); } ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F); - filter.Draw("##Filter", -FLT_MIN); + ImGui::SetNextItemWidth(-FLT_MIN); + filter.DrawWithHint("##Filter", "Filter (incl -excl)"); for (int n = 0; n < IM_COUNTOF(items); n++) { @@ -1678,12 +1686,13 @@ static void DemoWindowWidgetsDragAndDrop() "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; + float sz = ImGui::GetFrameHeight() * 3.0f; for (int n = 0; n < IM_COUNTOF(names); n++) { ImGui::PushID(n); if ((n % 3) != 0) ImGui::SameLine(); - ImGui::Button(names[n], ImVec2(60, 60)); + ImGui::Button(names[n], ImVec2(sz, sz)); // Our buttons are both drag sources and drag targets here! if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) @@ -2020,7 +2029,7 @@ static void DemoWindowWidgetsLiveEdit(ImGuiDemoWindowData* demo_data) { if (ImGui::TreeNode("Live Edit Flags")) { - IMGUI_DEMO_MARKER("Widgets/Live Edit Flgs"); + IMGUI_DEMO_MARKER("Widgets/Live Edit Flags"); ImGui::TextWrapped("Select whether to apply keyboard edits to backing variables _while_ typing."); @@ -2050,6 +2059,66 @@ static void DemoWindowWidgetsLiveEdit(ImGuiDemoWindowData* demo_data) } } +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsMixedValues() +//----------------------------------------------------------------------------- + +static void DemoWindowWidgetsMixedValues() +{ + if (ImGui::TreeNode("Mixed Values")) + { + IMGUI_DEMO_MARKER("Widgets/Mixed Values"); + // This is designed for advanced property editors which are generally reusable and data-driven. + HelpMarker("Using ImGuiItemFlags_MixedValue."); + + static bool use_liveedit = false; + static float items[3] = { 12.0f, 0.0f, 0.0f }; + float* item_ref = &items[0]; + ImGui::Checkbox("ImGuiItemFlags_LiveEditOnInput", &use_liveedit); + + ImGui::SeparatorText("Scalar/Text Widgets"); + const bool is_mixed = memcmp(&items[0], &items[1], sizeof(float)) != 0 || memcmp(&items[0], &items[2], sizeof(float)) != 0; + + // Demonstrate Drags, Sliders, Inputs + ImGui::PushItemFlag(ImGuiItemFlags_LiveEditOnInput, use_liveedit); + ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, is_mixed); + bool edited = false; + edited |= ImGui::DragFloat("DragFloat", item_ref); + edited |= ImGui::SliderFloat("SliderFloat", item_ref, 0.0f, 100.0f); + edited |= ImGui::InputFloat("InputFloat", item_ref, 1.0f); + if (edited) + for (float& item : items) + if (&item != item_ref) + item = *item_ref; + ImGui::PopItemFlag(); + + ImGui::Text("Underlying data:"); + ImGui::InputFloat("item 0 (ref)", &items[0]); + ImGui::InputFloat("item 1", &items[1]); + ImGui::InputFloat("item 2", &items[2]); + ImGui::PopItemFlag(); + + // Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4() + ImGui::SeparatorText("Others Widgets"); + ImGui::Text("(note: edits are not applied in this demo)"); // <-- Would need more state tracking. + bool b_on = true, b_off = false; + ImGui::Checkbox("Checkbox On", &b_on); + ImGui::Checkbox("Checkbox Off", &b_off); + ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, true); + ImGui::Checkbox("Checkbox Mixed", &b_off); + ImGui::RadioButton("RadioButton Mixed", true); + ImGui::SameLine(); + ImGui::RadioButton("RadioButton Mixed##2", true); // Showing 2 radio buttons makes the example more clear + int combo_idx = 0; + ImGui::Combo("Combo", &combo_idx, "One\0Two\0Three\0"); + ImVec4 color(0.5f, 0.5f, 0.5f, 0.5f); + ImGui::ColorEdit4("ColorEdit4", &color.x); + ImGui::PopItemFlag(); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsMultiComponents() //----------------------------------------------------------------------------- @@ -2119,10 +2188,12 @@ static void DemoWindowWidgetsPlotting() static bool animate = true; ImGui::Checkbox("Animate", &animate); + ImVec2 plot_sz(0.0f, ImGui::GetFrameHeight() * 4.0f); + // Plot as lines and plot as histogram static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; ImGui::PlotLines("Frame Times", arr, IM_COUNTOF(arr)); - ImGui::PlotHistogram("Histogram", arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + ImGui::PlotHistogram("Histogram", arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, plot_sz); //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); // Fill an array of contiguous float values to plot @@ -2151,7 +2222,7 @@ static void DemoWindowWidgetsPlotting() average /= (float)IM_COUNTOF(values); char overlay[32]; sprintf(overlay, "avg %f", average); - ImGui::PlotLines("Lines", values, IM_COUNTOF(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); + ImGui::PlotLines("Lines", values, IM_COUNTOF(values), values_offset, overlay, -1.0f, 1.0f, plot_sz); } // Use functions to generate output @@ -2169,8 +2240,8 @@ static void DemoWindowWidgetsPlotting() ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; - ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, plot_sz); + ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, plot_sz); ImGui::TreePop(); } @@ -2230,12 +2301,14 @@ static void DemoWindowWidgetsQueryingStatuses() }; static int item_type = 4; static bool item_disabled = false; + static bool item_mixedvalue = false; static bool liveedit_flags_override = false; static ImGuiItemFlags liveedit_flags = 0; ImGui::Combo("Item Type", &item_type, item_names, IM_COUNTOF(item_names), IM_COUNTOF(item_names)); ImGui::SameLine(); HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); ImGui::Checkbox("Item Disabled", &item_disabled); + ImGui::Checkbox("Item MixedValue", &item_mixedvalue); ImGui::Checkbox("Override LiveEdit:", &liveedit_flags_override); ImGui::SameLine(); if (!liveedit_flags_override) @@ -2260,6 +2333,8 @@ static void DemoWindowWidgetsQueryingStatuses() static char str[16] = {}; if (item_disabled) ImGui::BeginDisabled(true); + if (item_mixedvalue) + ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, true); if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater) @@ -2343,6 +2418,8 @@ static void DemoWindowWidgetsQueryingStatuses() ImGui::PopItemFlag(); ImGui::PopItemFlag(); } + if (item_mixedvalue) + ImGui::PopItemFlag(); if (item_disabled) ImGui::EndDisabled(); @@ -3678,11 +3755,13 @@ static void DemoWindowWidgetsTabs() // but they tend to make more sense together) static bool show_leading_button = true; static bool show_trailing_button = true; + static bool show_leading_trailing_tabs = false; ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); + ImGui::Checkbox("Show Leading+Trailing TabItem()", &show_leading_trailing_tabs); // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink; + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyMixed; EditTabBarFittingPolicyFlags(&tab_bar_flags); if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) @@ -3697,6 +3776,15 @@ static void DemoWindowWidgetsTabs() ImGui::EndPopup(); } + // Demo Leading/Trailing Tabs + if (show_leading_trailing_tabs) + { + if (ImGui::BeginTabItem("Leading", NULL, ImGuiTabItemFlags_Leading)) + ImGui::EndTabItem(); + if (ImGui::BeginTabItem("Trailing", NULL, ImGuiTabItemFlags_Trailing)) + ImGui::EndTabItem(); + } + // Demo Trailing Tabs: click the "+" button to add a new tab. // (In your app you may want to use a font icon instead of the "+") // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. @@ -3865,14 +3953,24 @@ static void DemoWindowWidgetsTextFilter() static ImGuiTextFilter filter; ImGui::Text("Filter usage:\n" " \"\" display all lines\n" - " \"xxx\" display lines containing \"xxx\"\n" - " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); - filter.Draw(); - const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; - for (int i = 0; i < IM_COUNTOF(lines); i++) - if (filter.PassFilter(lines[i])) - ImGui::BulletText("%s", lines[i]); + " xxx display lines containing \"xxx\"\n" + " xxx yyy display lines containing \"xxx\" and \"yyy\"\n" + " \"xxx yyy\" display lines containing \"xxx yyy\"\n" + " xxx,yyy display lines containing \"xxx\" or \"yyy\"\n" + " -xxx hide lines containing \"xxx\""); + ImGui::SetNextItemWidth(-FLT_MIN); + filter.DrawWithHint("##Filter", "Filter (incl -excl)"); + if (ImGui::BeginChild("##items", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 15), ImGuiChildFlags_FrameStyle)) + { + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (const char* item : lines) + if (filter.PassFilter(item)) + ImGui::TextUnformatted(item); + for (const char* item : ExampleNames) + if (filter.PassFilter(item)) + ImGui::TextUnformatted(item); + } + ImGui::EndChild(); ImGui::TreePop(); } } @@ -4402,27 +4500,34 @@ static void DemoWindowWidgetsVerticalSliders() if (ImGui::TreeNode("Vertical Sliders")) { IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); - const float spacing = 4; - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + ImGuiStyle& style = ImGui::GetStyle(); + ImVec2 slider_sz(ImGui::GetFrameHeight(), ImGui::GetFrameHeight() * 9); + + ImGui::PushStyleVarX(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.x * 0.5f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, (float)(int)(slider_sz.x * 0.25f)); + ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, (float)(int)(slider_sz.x * 0.25f)); + float spacing = style.ItemSpacing.x; static int int_value = 0; - ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); + ImGui::VSliderInt("##int", slider_sz, &int_value, 0, 5); ImGui::SameLine(); static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; ImGui::PushID("set1"); for (int i = 0; i < 7; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0)ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); - ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", slider_sz, &values[i], 0.0f, 1.0f, ""); if (ImGui::IsItemActive() || ImGui::IsItemHovered()) ImGui::SetTooltip("%.3f", values[i]); - ImGui::PopStyleColor(4); + ImGui::PopStyleColor(5); ImGui::PopID(); } ImGui::PopID(); @@ -4431,15 +4536,15 @@ static void DemoWindowWidgetsVerticalSliders() ImGui::PushID("set2"); static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; const int rows = 3; - const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); + const ImVec2 slider_size_small(slider_sz.x, (float)(int)((slider_sz.y - (rows - 1) * spacing) / rows)); for (int nx = 0; nx < 4; nx++) { - if (nx > 0) ImGui::SameLine(); + if (nx > 0)ImGui::SameLine(); ImGui::BeginGroup(); for (int ny = 0; ny < rows; ny++) { ImGui::PushID(nx * rows + ny); - ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + ImGui::VSliderFloat("##v", slider_size_small, &values2[nx], 0.0f, 1.0f, ""); if (ImGui::IsItemActive() || ImGui::IsItemHovered()) ImGui::SetTooltip("%.3f", values2[nx]); ImGui::PopID(); @@ -4452,15 +4557,17 @@ static void DemoWindowWidgetsVerticalSliders() ImGui::PushID("set3"); for (int i = 0; i < 4; i++) { - if (i > 0) ImGui::SameLine(); + if (i > 0) + ImGui::SameLine(); ImGui::PushID(i); - ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); - ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, slider_sz.y * 0.25f); + ImGui::VSliderFloat("##v", ImVec2(slider_sz.x * 2.0f, slider_sz.y), &values[i], 0.0f, 1.0f, "%.2f\nsec"); ImGui::PopStyleVar(); ImGui::PopID(); } ImGui::PopID(); - ImGui::PopStyleVar(); + + ImGui::PopStyleVar(3); ImGui::TreePop(); } } @@ -4505,6 +4612,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); DemoWindowWidgetsLiveEdit(demo_data); + DemoWindowWidgetsMixedValues(); DemoWindowWidgetsMultiComponents(); DemoWindowWidgetsPlotting(); DemoWindowWidgetsProgressBars(); @@ -8072,7 +8180,8 @@ static void DemoWindowInputs() ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); - ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item + float ref_sz = ImGui::GetFrameHeight() * 4.0f; + ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(ref_sz, ref_sz)); // Dummy item if (ImGui::IsItemHovered() && capture_override_mouse != -1) ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1); if (ImGui::IsItemHovered() && capture_override_keyboard != -1) @@ -8742,9 +8851,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SameLine(); SetNextItemWidth(GetFontSize() * 10); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); SameLine(); Checkbox("Only Modified Colors", &output_only_modified); - static ImGuiTextFilter filter; - filter.Draw("Filter colors", GetFontSize() * 16); - static ImGuiColorEditFlags alpha_flags = 0; if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine(); if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine(); @@ -8754,6 +8860,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); + static ImGuiTextFilter filter; + SetNextItemWidth(-FLT_MIN); + filter.DrawWithHint("##FilterColors", "Filter Colors (incl -excl)"); + SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); PushItemWidth(GetFontSize() * -12); @@ -8821,15 +8931,25 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) Checkbox("Anti-aliased lines", &style.AntiAliasedLines); SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + BeginDisabled(style.AntiAliasedLines == false); + Checkbox("Anti-aliased line ends", &style.AntiAliasedLineEnds); + EndDisabled(); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + BeginDisabled(); Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); SameLine(); HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); + EndDisabled(); +#endif Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + Checkbox("Debug: DrawList Defaults to _StrokeLegacy", &ImGui::GetIO().ConfigDebugDrawListDefaultsToStrokeLegacy); + PushItemWidth(GetFontSize() * 8); - DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); - if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + DragFloat("Curve Tessellation Max Error", &style.CurveTessellationMaxError, 0.02f, 0.10f, 10.0f, "%.2f"); + if (style.CurveTessellationMaxError < 0.10f) + style.CurveTessellationMaxError = 0.10f; // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); @@ -9165,7 +9285,10 @@ struct ExampleAppConsole if (ImGui::Button("Options")) ImGui::OpenPopup("Options"); ImGui::SameLine(); - Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); + + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); + ImGui::SetNextItemWidth(-FLT_MIN); + Filter.DrawWithHint("##Filter", "Filter (incl -excl)"); ImGui::Separator(); // Reserve enough left-over height for 1 separator + 1 input text @@ -9500,7 +9623,8 @@ struct ExampleAppLog ImGui::SameLine(); bool copy = ImGui::Button("Copy"); ImGui::SameLine(); - Filter.Draw("Filter", -100.0f); + ImGui::SetNextItemWidth(-FLT_MIN); + Filter.DrawWithHint("##Filter", "Filter (incl -excl)"); ImGui::Separator(); @@ -9695,7 +9819,7 @@ struct ExampleAppPropertyEditor ImGui::Text("(%d root nodes)", root_node->Childs.Size); ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); - if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) + if (ImGui::InputTextWithHint("##Filter", "incl -excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) Filter.Build(); ImGui::PopItemFlag(); @@ -10236,13 +10360,10 @@ static void ShowExampleAppWindowTitles(bool*) // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() //----------------------------------------------------------------------------- -// Add a |_| looking shape -static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz) -{ - const ImVec2 pos_norms[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } }; - for (const ImVec2& p : pos_norms) - draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y))); -} +// See our Wiki guides: +// - ImDrawList Vector Rendering Reference: https://github.com/ocornut/imgui/wiki/Draw-List +// - Pixel Perfect Anti-aliased Rendering: https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering +// - How Anti-aliased Polyline Rendering is Implemented: https://github.com/ocornut/imgui/wiki/Polyline-Rendering // Demonstrate using the low-level ImDrawList to draw custom shapes. static void ShowExampleAppCustomRendering(bool* p_open) @@ -10274,118 +10395,250 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::Text("Gradients"); ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); { - ImVec2 p0 = ImGui::GetCursorScreenPos(); - ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImGui::InvisibleButton("##gradient1", gradient_size); ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); - draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); - ImGui::InvisibleButton("##gradient1", gradient_size); + draw_list->AddRectFilledMultiColor(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), col_a, col_b, col_b, col_a); } { - ImVec2 p0 = ImGui::GetCursorScreenPos(); - ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImGui::InvisibleButton("##gradient2", gradient_size); ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); - draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); - ImGui::InvisibleButton("##gradient2", gradient_size); + draw_list->AddRectFilledMultiColor(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), col_a, col_b, col_b, col_a); } // Draw a bunch of primitives ImGui::Text("All primitives"); static float sz = 42.0f; - static float thickness = 3.0f; - static int ngon_sides = 6; + static float base_rounding = 8.0f; + static float base_thickness = 3.0f; + static bool animate_rounding = false; + static bool animate_thickness = false; + static int ngon_segments = 6; static bool circle_segments_override = false; static int circle_segments_override_v = 12; static bool curve_segments_override = false; static int curve_segments_override_v = 8; - static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); - ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); - ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); - ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); - ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); + static ImVec4 colf_stroke = ImVec4(1.000f, 0.384f, 0.169f, 1.000f); + static ImVec4 colf_fill = ImVec4(0.416f, 0.378f, 0.420f, 1.000f); + + ImGui::DragFloat("Size", &sz, 0.2f, 0.2f, 100.0f, "%.0f"); + + const float rounding_anim_period = 3.0f; + const float rounding_wave = 1.0f - fabsf(fmodf((float)ImGui::GetTime(), rounding_anim_period) * (2.0f / rounding_anim_period) - 1.0f); + const float rounding = animate_rounding ? (float)(int)(rounding_wave * base_rounding * 10.0f) / 10.0f : base_rounding; // Sub-integer rounding works but has discontinuities in small values, so best disable we + ImGui::DragFloat("Rounding", &base_rounding, 0.02f, 0.0f, 32.0f, "%.1f"); ImGui::SameLine(); + ImGui::Checkbox("Animate##rounding", &animate_rounding); ImGui::SameLine(); + ImGui::Text("%.2f", rounding); + + const float thickness_anim_period = 5.0f; + const float thickness_wave = 1.0f - fabsf(fmodf((float)ImGui::GetTime(), thickness_anim_period) * (2.0f / thickness_anim_period) - 1.0f); + const float thickness = animate_thickness ? thickness_wave * base_thickness : base_thickness; + ImGui::DragFloat("Thickness", &base_thickness, 0.02f, 0.0f, 32.0f, "%.02f"); ImGui::SameLine(); + ImGui::Checkbox("Animate##thickness", &animate_thickness); ImGui::SameLine(); + ImGui::Text("%.2f", thickness); + + ImGui::SliderInt("N-gon sides", &ngon_segments, 3, 12); + ImGui::Checkbox("##CircleSegmentOverride", &circle_segments_override); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40); - ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override); + circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 30); + ImGui::Checkbox("##CurvesSegmentOverride", &curve_segments_override); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40); - ImGui::ColorEdit4("Color", &colf.x); - - const ImVec2 p = ImGui::GetCursorScreenPos(); - const ImU32 col = ImColor(colf); - const float spacing = 10.0f; - const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight; - const float rounding = sz / 5.0f; + curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 30); + ImGui::ColorEdit4("Stroke Color", &colf_stroke.x); + ImGui::ColorEdit4("Fill Color", &colf_fill.x); + + static ImDrawFlags prim_stroke_flags = ImDrawFlags_None; + static ImDrawFlags prim_other_flags = ImDrawFlags_AALineEnds; + ImGui::SeparatorText("Per primitive flags (AddXXX functions)"); + ImGui::RadioButton("Default", &prim_stroke_flags, ImDrawFlags_None); ImGui::SameLine(); + ImGui::RadioButton("Inside", &prim_stroke_flags, ImDrawFlags_StrokeInside); ImGui::SameLine(); + ImGui::RadioButton("Center", &prim_stroke_flags, ImDrawFlags_StrokeCenter); ImGui::SameLine(); + ImGui::RadioButton("CenterBiased", &prim_stroke_flags, ImDrawFlags_StrokeCenterBiased); ImGui::SameLine(); + ImGui::RadioButton("Outside", &prim_stroke_flags, ImDrawFlags_StrokeOutside); ImGui::SameLine(); + ImGui::RadioButton("Legacy", &prim_stroke_flags, ImDrawFlags_StrokeLegacy); + ImGui::CheckboxFlags("AAFill", &prim_other_flags, ImDrawFlags_AAFill); ImGui::SameLine(); // Note: Only for functions taking flags. + ImGui::CheckboxFlags("AALines", &prim_other_flags, ImDrawFlags_AALines); ImGui::SameLine(); // Note: Only for functions taking flags. + ImGui::CheckboxFlags("AALineEnds", &prim_other_flags, ImDrawFlags_AALineEnds); ImGui::SameLine(); + ImGui::CheckboxFlags("JoinMiter", &prim_other_flags, ImDrawFlags_JoinMiter); ImGui::SameLine(); + ImGui::CheckboxFlags("CapSquare", &prim_other_flags, ImDrawFlags_CapSquare); + //ImGui::CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners); + + static ImDrawFlags scope_flags = draw_list->Flags & ImDrawFlags_AllowInPushScope_; // First init copy current state. + ImGui::SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)"); + ImGui::PushID("ScopeFlags"); + ImGui::CheckboxFlags("AAFill", &scope_flags, ImDrawFlags_AAFill); ImGui::SameLine(); + ImGui::CheckboxFlags("AALines", &scope_flags, ImDrawFlags_AALines); ImGui::SameLine(); + ImGui::CheckboxFlags("AALineEnds", &scope_flags, ImDrawFlags_AALineEnds); ImGui::SameLine(); + ImGui::CheckboxFlags("StrokeLegacy", &scope_flags, ImDrawFlags_StrokeLegacy); + //ImGui::CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners); + ImGui::PopID(); + ImGui::Spacing(); + + draw_list->PushDrawFlag(ImDrawFlags_AllowInPushScope_, false); // Reset all existing (very unusual: done for this demo) + draw_list->PushDrawFlag(scope_flags, true); + const ImDrawFlags flags = prim_stroke_flags | prim_other_flags; + + const ImVec2 start_pos = ImGui::GetCursorScreenPos(); + const float pi = 3.141592f; + const float step = sz + 10.0f; + const ImDrawFlags corners_tl_br = ImDrawFlags_RoundTopLeft | ImDrawFlags_RoundBottomRight; + const float half_sz = sz * 0.5f; const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; - const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves - const ImVec2 cp4[4] = { ImVec2(0.0f, 0.0f), ImVec2(sz * 1.3f, sz * 0.3f), ImVec2(sz - sz * 1.3f, sz - sz * 0.3f), ImVec2(sz, sz) }; + const ImVec2 cp3[3] = { { 0.0f, sz * 0.6f }, { sz * 0.5f, -sz * 0.4f }, { sz, sz } }; // Control points for curves + const ImVec2 cp4[4] = { { 0.0f, 0.0f }, { sz * 1.3f, sz * 0.3f }, { sz - sz * 1.3f, sz - sz * 0.3f }, { sz, sz } }; + const ImVec2 concave_shape[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } }; // |_| looking shape. Normalized. + const ImVec2 zigzag_shape[] = { { 0.0f, 0.0f }, { 0.9f, 0.0f }, { 1.0f, 0.1f }, { 1.0f, 0.9f }, { 0.9f, 1.0f }, { 0.3f, 1.0f }, { 0.3f, 0.4f }, { 0.9f, 0.4f } }; + ImVec2 rotating_square[4]; + for (int side = 0; side < 4; side++) + { + float t = (float)ImGui::GetTime() * 0.1f + side * pi * 0.5f; + rotating_square[side] = { (float)cosf(t) * half_sz, (float)sinf(t) * half_sz }; + } - float x = p.x + 4.0f; - float y = p.y + 4.0f; - for (int n = 0; n < 2; n++) + float x = start_pos.x; + float y = start_pos.y; + for (int row = 0; row < 4; row++) { - // First line uses a thickness of 1.0f, second line uses the configurable thickness - float th = (n == 0) ? 1.0f : thickness; - draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon - draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle - draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, th); x += sz + spacing; // Square - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th); x += sz + spacing; // Square with all rounded corners - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, corners_tl_br); x += sz + spacing; // Square with two rounded corners - draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle - //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle - PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, th, ImDrawFlags_Closed); x += sz + spacing; // Concave Shape - //draw_list->AddPolyline(concave_shape, IM_COUNTOF(concave_shape), col, ImDrawFlags_Closed, th); - draw_list->AddLineH(x, x + sz, y, col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) - draw_list->AddLineV(x, y, y + sz, col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line - - // Path - draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f); - draw_list->PathStroke(col, th); - x += sz + spacing; - - // Quadratic Bezier Curve (3 control points) - draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments); - x += sz + spacing; - - // Cubic Bezier Curve (4 control points) - draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, th, curve_segments); - - x = p.x + 4; - y += sz + spacing; - } - - // Filled shapes - draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon - draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle - draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, circle_segments); x += sz + spacing;// Ellipse - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners - draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle - //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle - PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) - draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) - - // Path - draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f); - draw_list->PathFillConvex(col); - x += sz + spacing; - - // Quadratic Bezier Curve (3 control points) - draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y)); - draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments); - draw_list->PathFillConvex(col); - x += sz + spacing; - - draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); - x += sz + spacing; - - ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f)); + x = start_pos.x; + bool draw_fill = (row == 2 || row == 3); + bool draw_strokes = (row == 0 || row == 1 || row == 3); + if (draw_fill) + { + // FILLED SHAPES + const ImU32 col = ImColor(colf_fill); + draw_list->AddNgonFilled({ x + half_sz, y + half_sz }, half_sz, col, ngon_segments); x += step; // N-gon + draw_list->AddCircleFilled({ x + half_sz, y + half_sz }, half_sz, col, circle_segments); x += step; // Circle + draw_list->AddEllipseFilled({ x + half_sz, y + half_sz }, { half_sz, sz * 0.3f }, col, -0.3f, circle_segments); x += step;// Ellipse + draw_list->AddRectFilled({ x, y }, { x + sz, y + sz }, col, 0.0f, flags); x += step; // Square + draw_list->AddRectFilled({ x, y }, { x + sz, y + sz }, col, rounding, flags); x += step; // Square with all rounded corners + draw_list->AddRectFilled({ x, y }, { x + sz, y + sz }, col, rounding, flags | corners_tl_br); x += step; // Square with two rounded corners + draw_list->AddTriangleFilled({ x + sz * 0.5f, y }, { x + sz, y + sz }, { x, y + sz }, col); x += step; // Triangle + draw_list->AddTriangleFilled({ x + sz * 0.2f, y }, { x + sz * 0.4f, y + sz }, { x, y + sz }, col); x += step - (float)(int)(sz * 0.6f); // Thin triangle + + // Concave shape: U + for (const ImVec2& p : concave_shape) + draw_list->PathLineTo({ x + (int)(sz * p.x), y + (int)(sz * p.y) }); + draw_list->PathFillConcave(col); + x += step; + + // Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for (const ImVec2& p : zigzag_shape) + draw_list->PathLineTo({ x + (int)(sz * p.x), y + (int)(sz * p.y) }); + draw_list->PathFillConcave(col); + x += step; + + // Horizontal/Vertical lines + // (here for consistency with the strokes section. AddRectFilled() is roughly close to AddLineH(), AddLineV() + draw_list->AddRectFilled({ x, y }, { x + sz, y + thickness }, col); x += step; + draw_list->AddRectFilled({ x, y }, { x + thickness, y + sz }, col); x += step - (float)(int)half_sz; + if (!(draw_fill && draw_strokes)) //-V560 + for (int block_sz = 1, off = 0; block_sz < 16 && off + block_sz <= sz; off += block_sz + 1, block_sz++) + draw_list->AddRectFilled({ x, y + off }, { x + block_sz, y + off + block_sz }, col); + x += step - (float)(int)half_sz; + + // Rotating square + for (int n = 0; n < 4; n++) + draw_list->PathLineTo({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }); + draw_list->PathFillConvex(col, flags); + x += step; + + // Path + draw_list->PathArcTo({ x + half_sz, y + half_sz }, half_sz, pi * -0.5f, pi * 1.1f); + draw_list->PathFillConvex(col); + x += step; + + // Quadratic Bezier Curve (3 control points) + draw_list->PathLineTo({ x + cp3[0].x, y + cp3[0].y }); + draw_list->PathBezierQuadraticCurveTo({ x + cp3[1].x, y + cp3[1].y }, { x + cp3[2].x, y + cp3[2].y }, curve_segments); + draw_list->PathFillConvex(col); + x += step; + + if (!(draw_fill && draw_strokes)) //-V560 + { + draw_list->AddRectFilledMultiColor({ x, y }, { x + sz, y + sz }, IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); + x += step; + } + } + if (draw_fill && draw_strokes) + x = start_pos.x; + if (draw_strokes) + { + // STROKES + // First row uses a thickness of 1.0f, second row uses the configurable thickness + const ImU32 col = ImColor(colf_stroke); + float th = (row == 0) ? 1.0f : thickness; + draw_list->AddNgon({ x + half_sz, y + half_sz }, half_sz, col, ngon_segments, th, flags); x += step; // N-gon + draw_list->AddCircle({ x + half_sz, y + half_sz }, half_sz, col, circle_segments, th, flags); x += step; // Circle + draw_list->AddEllipse({ x + half_sz, y + half_sz }, { half_sz, sz * 0.3f }, col, -0.3f, circle_segments, th, flags); x += step; // Ellipse + draw_list->AddRect({ x, y }, { x + sz, y + sz }, col, 0.0f, th, flags); x += step; // Square + draw_list->AddRect({ x, y }, { x + sz, y + sz }, col, rounding, th, flags); x += step; // Square with all rounded corners + draw_list->AddRect({ x, y }, { x + sz, y + sz }, col, rounding, th, flags | corners_tl_br); x += step; // Square with two rounded corners + draw_list->AddTriangle({ x + sz * 0.5f, y }, { x + sz, y + sz }, { x, y + sz }, col, th, flags); x += step; // Triangle + draw_list->AddTriangle({ x + sz * 0.2f, y }, { x + sz * 0.4f, y + sz }, { x, y + sz }, col, th, flags); x += step - (float)(int)(sz * 0.6f); // Thin triangle + + // Concave shape: U + for (const ImVec2& p : concave_shape) + draw_list->PathLineTo({ x + (int)(sz * p.x), y + (int)(sz * p.y) }); + draw_list->PathStroke(col, th, flags | ImDrawFlags_Closed); + x += step; + + // Concave shape: Zig-Zag with sharp angles (see difference with/without JoinMiter) + for (const ImVec2& p : zigzag_shape) + draw_list->PathLineTo({ x + (int)(sz * p.x), y + (int)(sz * p.y) }); + draw_list->PathStroke(col, th, flags | ImDrawFlags_Closed); + x += step; + + // Horizontal/Vertical/Diagonal lines + const float off = (float)(int)(sz * 0.4f); + draw_list->AddLineH(x, x + sz, y, col, th, flags); + draw_list->AddLine({ x, y + off }, { x + sz, y + off }, col, th, flags); + x += step; + draw_list->AddLineV(x, y, y + sz, col, th, flags); + draw_list->AddLine({ x + off, y + sz }, { x + off, y }, col, th, flags); + x += step - (float)(int)half_sz; + if (!(draw_fill && draw_strokes)) //-V560 + { + draw_list->AddLine({ x, y }, { x + half_sz, y + sz }, col, th, flags); + draw_list->AddLine({ x, y + sz }, { x + half_sz, y }, col, th, flags); + } + x += step - (float)(int)half_sz; + + // Rotating square + for (int n = 0; n < 4; n++) + draw_list->PathLineTo({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }); + draw_list->PathStroke(col, th, flags | ImDrawFlags_Closed); + //for (int n = 0; n < 4; n++) // ...made of individual line + // draw_list->AddLine({ x + half_sz + rotating_square[n].x, y + half_sz + rotating_square[n].y }, { x + half_sz + rotating_square[(n + 1) & 3].x, y + half_sz + rotating_square[(n + 1) & 3].y }, col, th, flags); + x += step; + + // Path + draw_list->PathArcTo({ x + half_sz, y + half_sz }, half_sz, pi * -0.5f, pi * 1.1f); + draw_list->PathStroke(col, th, flags); + x += step; + + // Quadratic Bezier Curve (3 control points) + draw_list->AddBezierQuadratic({ x + cp3[0].x, y + cp3[0].y }, { x + cp3[1].x, y + cp3[1].y }, { x + cp3[2].x, y + cp3[2].y }, col, th, curve_segments, flags); + x += step; + + // Cubic Bezier Curve (4 control points) + if (!(draw_fill && draw_strokes)) //-V560 + { + draw_list->AddBezierCubic({ x + cp4[0].x, y + cp4[0].y }, { x + cp4[1].x, y + cp4[1].y }, { x + cp4[2].x, y + cp4[2].y }, { x + cp4[3].x, y + cp4[3].y }, col, th, curve_segments, flags); + x += step; + } + } + y += step; + } + + ImGui::Dummy(ImVec2(step * 15.5f, step * 4.0f)); + draw_list->PopDrawFlag(); + draw_list->PopDrawFlag(); + + ImGui::Text("ImDrawList Vector Rendering Reference:"); + ImGui::TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List"); + ImGui::PopItemFlag(); ImGui::PopItemWidth(); ImGui::EndTabItem(); @@ -10519,9 +10772,9 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::Text("Blue shape is drawn first: appears in back"); ImGui::Text("Red shape is drawn after: appears in front"); ImVec2 p0 = ImGui::GetCursorScreenPos(); - draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue - draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red - ImGui::Dummy(ImVec2(75, 75)); + draw_list->AddRectFilled({ p0.x, p0.y }, { p0.x + 50, p0.y + 50 }, IM_COL32(0, 0, 255, 255)); // Blue + draw_list->AddRectFilled({ p0.x + 25, p0.y + 25 }, { p0.x + 75, p0.y + 75 }, IM_COL32(255, 0, 0, 255)); // Red + ImGui::Dummy({ 75, 75 }); } ImGui::Separator(); { @@ -10533,14 +10786,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls. draw_list->ChannelsSplit(2); draw_list->ChannelsSetCurrent(1); - draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue + draw_list->AddRectFilled({ p1.x, p1.y }, { p1.x + 50, p1.y + 50 }, IM_COL32(0, 0, 255, 255)); // Blue draw_list->ChannelsSetCurrent(0); - draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red + draw_list->AddRectFilled({ p1.x + 25, p1.y + 25 }, { p1.x + 75, p1.y + 75 }, IM_COL32(255, 0, 0, 255)); // Red // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1. // This works by copying draw indices only (vertices are not copied). draw_list->ChannelsMerge(); - ImGui::Dummy(ImVec2(75, 75)); + ImGui::Dummy({ 75, 75 }); ImGui::Text("After reordering, contents of channel 0 appears below channel 1."); } ImGui::EndTabItem(); diff --git a/include/imgui/imgui_draw.cpp b/include/imgui/imgui_draw.cpp index e582f5c..0d54ee8 100644 --- a/include/imgui/imgui_draw.cpp +++ b/include/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (drawing and font code) /* @@ -105,7 +105,7 @@ namespace IMGUI_STB_NAMESPACE #pragma warning (push) #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration #pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. -#pragma warning (disable: 5262) // (stb_truetype) implicit fall-through occurs here; are you missing a break statement? +#pragma warning (disable: 5262) // (stb_truetype) implicit fall-through occurs here; are you missing a break statement? #pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. #pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. #endif @@ -190,15 +190,15 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) ImVec4* colors = style->Colors; colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.58f, 0.58f, 0.58f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.18f, 0.18f, 0.18f, 1.00f); colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_FrameBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.25f, 0.31f, 1.00f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.21f, 0.33f, 0.47f, 1.00f); colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); @@ -235,9 +235,9 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); - colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here - colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.28f, 0.28f, 0.29f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.40f, 0.40f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.32f, 0.32f, 0.34f, 1.00f); // Prefer using Alpha=1.0 here colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; @@ -336,9 +336,9 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); - colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_TitleBg] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.43f); colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); @@ -396,7 +396,6 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) ImDrawListSharedData::ImDrawListSharedData() { memset((void*)this, 0, sizeof(*this)); - InitialFringeScale = 1.0f; for (int i = 0; i < IM_COUNTOF(ArcFastVtx); i++) { const float a = ((float)i * 2 * IM_PI) / (float)IM_COUNTOF(ArcFastVtx); @@ -462,7 +461,8 @@ void ImDrawList::_ResetForNewFrame() CmdBuffer.resize(0); IdxBuffer.resize(0); VtxBuffer.resize(0); - Flags = _Data->InitialFlags; + Flags = _Data->InitialDrawFlags; + IM_ASSERT((Flags & ~ImDrawFlags_AllowInFrameScope_) == 0); memset(&_CmdHeader, 0, sizeof(_CmdHeader)); _VtxCurrentIdx = 0; _VtxWritePtr = NULL; @@ -470,10 +470,11 @@ void ImDrawList::_ResetForNewFrame() _ClipRectStack.resize(0); _TextureStack.resize(0); _CallbacksDataBuf.resize(0); + _DrawFlagsStack.clear(); _Path.resize(0); _Splitter.Clear(); CmdBuffer.push_back(ImDrawCmd()); - _FringeScale = _Data->InitialFringeScale; + // Caller needs to bet _SetPixelDensity() as well. } void ImDrawList::_ClearFreeMemory() @@ -481,13 +482,14 @@ void ImDrawList::_ClearFreeMemory() CmdBuffer.clear(); IdxBuffer.clear(); VtxBuffer.clear(); - Flags = ImDrawListFlags_None; + Flags = ImDrawFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _ClipRectStack.clear(); _TextureStack.clear(); _CallbacksDataBuf.clear(); + _DrawFlagsStack.clear(); _Path.clear(); _Splitter.ClearFreeMemory(); } @@ -655,6 +657,7 @@ void ImDrawList::_OnChangedVtxOffset() int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const { // Automatic segment count + radius *= _InvFringeScale; const int radius_idx = (int)(radius + 0.999f); // ceil to never reduce accuracy if (radius_idx >= 0 && radius_idx < IM_COUNTOF(_Data->CircleSegmentCounts)) return _Data->CircleSegmentCounts[radius_idx]; // Use cached value @@ -699,7 +702,7 @@ void ImDrawList::PushTexture(ImTextureRef tex_ref) _TextureStack.push_back(tex_ref); _CmdHeader.TexRef = tex_ref; if (tex_ref._TexData != NULL) - IM_ASSERT(tex_ref._TexData->WantDestroyNextFrame == false); + IM_ASSERT(tex_ref._TexData->Status != ImTextureStatus_WantDestroy && tex_ref._TexData->Status != ImTextureStatus_Destroyed); _OnChangedTexture(); } @@ -710,6 +713,26 @@ void ImDrawList::PopTexture() _OnChangedTexture(); } +// IMPORTANT: currently limited to 3 deep +void ImDrawList::PushDrawFlag(ImDrawFlags flags, bool enabled) +{ + IM_ASSERT((flags & ~ImDrawFlags_AllowInPushScope_) == 0); + IM_ASSERT((flags & ImDrawFlags_StrokeMask_) == 0 || (flags & ImDrawFlags_StrokeMask_) == ImDrawFlags_StrokeLegacy); + IM_ASSERT_USER_ERROR_RET(_DrawFlagsStack.Size < _DrawFlagsStack.capacity(), "PushDrawFlag() has a depth limit. Contact us."); + _DrawFlagsStack.push_back(Flags); + if (enabled) + Flags |= flags; + else + Flags &= ~flags; +} + +void ImDrawList::PopDrawFlag() +{ + IM_ASSERT_USER_ERROR_RET(_DrawFlagsStack.Size > 0, "Calling PopDrawFlag() too many times!"); + Flags = _DrawFlagsStack.back(); + _DrawFlagsStack.pop_back(); +} + // This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture(). void ImDrawList::_SetTexture(ImTextureRef tex_ref) { @@ -720,6 +743,15 @@ void ImDrawList::_SetTexture(ImTextureRef tex_ref) _OnChangedTexture(); } +void ImDrawList::_SetPixelDensity(float pixel_density) +{ + IM_ASSERT(pixel_density > 0.0f); + _FringeScale = 1.0f / pixel_density; + _InvFringeScale = pixel_density; + _FringeScaleIsInteger = ImIsTruncated(_InvFringeScale); +} + +IM_MSVC_RUNTIME_CHECKS_OFF // Reserve space for a number of vertices and indices. // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or // submit the intermediate results. PrimUnreserve() can be used to release unused allocations. @@ -727,7 +759,7 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) { // Large mesh support (when enabled) IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); - if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) + if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawFlags_UseVtxOffset)) { // FIXME: In theory we should be testing that vtx_count <64k here. // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us @@ -759,6 +791,26 @@ void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) IdxBuffer.shrink(IdxBuffer.Size - idx_count); } +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. +// We avoid using the 'do { } while (false)` idiom in those macros as they typically have overhead in debug builds. +#define IM_APPEND_VTX(PX, PY, UV, COL) \ + { \ + _VtxWritePtr->pos.x = PX; \ + _VtxWritePtr->pos.y = PY; \ + _VtxWritePtr->uv = UV; \ + _VtxWritePtr->col = COL; \ + _VtxWritePtr++; \ + _VtxCurrentIdx++; \ + } (void)0 + +#define IM_APPEND_TRI(a, b, c) \ + { \ + _IdxWritePtr[0] = (ImDrawIdx)(a); \ + _IdxWritePtr[1] = (ImDrawIdx)(b); \ + _IdxWritePtr[2] = (ImDrawIdx)(c); \ + _IdxWritePtr += 3; \ + } (void)0 + // Fully unrolled with inline call to keep our debug builds decently fast. void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) { @@ -804,6 +856,24 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c _IdxWritePtr += 6; } +float ImDrawList::_CalculateCenterBiasedOffset(float thickness) +{ + // Old jumpy one. + // return IM_TRUNC(thickness * 0.5f / _FringeScale) * _FringeScale; + + // Calculate outside offset for stroke position ImDrawFlags_StrokeCenterBiased + // so that one side the of the line is always at pixel boundary. + // On integer thickness both sides of the line are on pixel boundary. + const float screen_thickness = thickness * _InvFringeScale; + const int s_thickness = (int)screen_thickness; + return ((float)(s_thickness / 2) + (s_thickness & 1) * (screen_thickness - s_thickness)) * _FringeScale; +} +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Check if R is considered to be worthy rounding. Can be only used within ImDrawList due to use of _FringeScale. +// FIXME-OPT: Given unused padding space in ImDrawList would it make sense to store 0.25f * _FringeScale? +#define IM_HAS_ROUNDING(RAD) ((RAD) >= (0.25f * _FringeScale)) + // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. // - Those macros expects l-values and need to be used as their own statement. // - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. @@ -811,357 +881,650 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c #define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) #define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0 -// TODO: Thickness anti-aliased lines cap are missing their AA fringe. -// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. -void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, float thickness, ImDrawFlags flags) +// - The miter limit describes how much the miter cross section can be scaled before we turn it into a bevel instead. +// The minimum value of miter limit is 1.0, which translates to 180 (all corners are bevels), the higher the number, +// the closer to zero the angle is (never bevel a corner). The miter limit angle can be calculated as: +// miter_limit_angle = 2 * acos(1 / miter_limit) +// - We can use the miter limit angle to figure maximum number of beveled corners in a convex polygon, +// to prevent having allocate much extra memory (for a reasonable miter limit). +// (n - 2) * 360 > k * miter_limit_angle + (n - k) * 360 +// Where, n = number of corners in a polygon, k = beveled corners. Solved for k, simplifies to: +// k < 360 / (180 - miter_limit_angle) +// To find value strictly less than: +// max_bevels = k = floor(360/(180-miter_limit_angle)) +#define IM_POLYLINE_MITER_ANGLE_LIMIT (-0.9999619f) // Safeguard for miter corner calculation to avoid div by zero. cos(179.5) +#define IM_POLYLINE_MITER_LIMIT (4.0f) // (~29 deg corner) +#define IM_POLYLINE_CONVEX_POLY_MAX_BEVELS (2) // For miter value 4.0 + +// In debug builds the functions are likely not inlined, so inlined check is cheaper. +#if defined(DEBUG) || defined(_DEBUG) +#define IM_IS_TRUNCATED4(a, b, c, d) ((float)(int)(a) == (a)) && ((float)(int)(b) == (b)) && ((float)(int)(c) == (c)) && ((float)(int)(d) == (d)) +#define IM_IS_TRUNCATED(a) ((float)(int)(a) == (a)) +#else +#define IM_IS_TRUNCATED4(a, b, c, d) ImIsTruncated4(a, b, c, d) +#define IM_IS_TRUNCATED(a) ImIsTruncated(a) +#endif + +IM_MSVC_RUNTIME_CHECKS_OFF +static ImU32 ImAlphaMultiply(ImU32 col, float alpha_mul) +{ + IM_ASSERT_PARANOID(alpha_mul >= 0.0f && alpha_mul < 1.0f); // We don't clamp! + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * alpha_mul); // We don't need to clamp 0..255 because alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +// Select texture and adjust fringe size for specified line thickness. +void ImDrawList::_SelectLineTexture(float screen_thickness, ImVec2* out_uv0, ImVec2* out_uv1, float* out_fringe, ImDrawFlags flags) +{ + // We assume that the screen_thickness has been clamped to 1.0 by the caller. + IM_ASSERT_PARANOID(screen_thickness >= 1.0f); + + if (flags & ImDrawFlags_AALines) + { + // Handle the thickness between 1.0 - IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH]. + // We use super sampled textures in this range to make texture changes less noticeable. + // There are IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT textures, where 0 maps to 1.0 and IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT-1 maps to IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH (4.0). + int texture_idx; + if (screen_thickness <= IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH) IM_LIKELY + texture_idx = (int)((screen_thickness - 1.0f) * IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT + 0.5f) + (IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + else if (screen_thickness < (float)IM_DRAWLIST_TEX_LINES_WIDTH_MAX - 1.5f) IM_LIKELY + texture_idx = (int)(screen_thickness + 0.5f); + else + texture_idx = IM_DRAWLIST_TEX_LINES_WIDTH_MAX - 1; // Catches large values of screen_thickness (and +inf/NaN) that a ImMin() wouldn't. + + // Scale the fringe so that the texture matches the line thickness. + ImVec4 tex_uvs = _Data->TexUvLines[texture_idx]; + out_uv0->x = tex_uvs.x; + out_uv1->x = tex_uvs.y; + out_uv0->y = out_uv1->y = tex_uvs.z; + *out_fringe = _FringeScale * screen_thickness * tex_uvs.w; // tex_uvs.w = 1 / thickness + } + else + { + // For no anti-alias we use fully opaque texture, and no fringe expansion. + *out_uv0 = *out_uv1 = _Data->TexUvWhitePixel; + *out_fringe = 0.0f; + } +} + +#define _GetStrokePos(_FLAGS, _DEFAULT_STROKE_POS) (((_FLAGS) & ImDrawFlags_StrokeMask_) ? ((_FLAGS) & ImDrawFlags_StrokeMask_) : _DEFAULT_STROKE_POS) + +IM_MSVC_RUNTIME_CHECKS_RESTORE + +void ImDrawList::_AddPolyline(const ImVec2* points, const int points_count, ImU32 col, float thickness, ImDrawFlags flags, float max_inner_offset) { if (points_count < 2 || (col & IM_COL32_A_MASK) == 0) return; - const bool closed = (flags & ImDrawFlags_Closed) != 0; - const ImVec2 opaque_uv = _Data->TexUvWhitePixel; - const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw - const bool thick_line = (thickness > _FringeScale); + float screen_thickness = thickness * _InvFringeScale; + if (screen_thickness < 1.0f) IM_UNLIKELY + { + if (screen_thickness < 1.0f / 255.0f) IM_UNLIKELY + return; + col = ImAlphaMultiply(col, screen_thickness); + screen_thickness = 1.0f; + thickness = _FringeScale; + } // If this assert triggers on legacy code: // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced. // Read more details near AddRect() + see "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8. + flags |= Flags; IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); - if (Flags & ImDrawListFlags_AntiAliasedLines) + // Allocate data for temp buffers + _Data->TempBuffer.reserve_discard(points_count * 2); + ImVec2* normals = _Data->TempBuffer.Data; + float* sqr_lengths = (float*)(normals + points_count); + + // Calculate normals for each line segment + for (int i = 0; i < points_count - 1; i++) { - // Anti-aliased stroke - const float AA_SIZE = _FringeScale; - const ImU32 col_trans = col & ~IM_COL32_A_MASK; + float dx = points[i + 1].x - points[i].x; + float dy = points[i + 1].y - points[i].y; + const float d2 = dx * dx + dy * dy; + const float inv_len = (d2 > 0.0f) ? ImRsqrtPrecise(d2) : 0.0f; + normals[i].x = -dy * inv_len; + normals[i].y = dx * inv_len; + sqr_lengths[i] = d2; + } + if ((flags & ImDrawFlags_Closed) != 0) + { + const float dx = points[0].x - points[points_count - 1].x; + const float dy = points[0].y - points[points_count - 1].y; + const float d2 = dx * dx + dy * dy; + const float inv_len = (d2 > 0.0f) ? ImRsqrtPrecise(d2) : 0.0f; + normals[points_count - 1].x = -dy * inv_len; + normals[points_count - 1].y = dx * inv_len; + sqr_lengths[points_count - 1] = d2; + } + else + { + normals[points_count - 1] = normals[points_count - 2]; + sqr_lengths[points_count - 1] = 0.0f; + } - // Thicknesses <1.0 should behave like thickness 1.0 - thickness = ImMax(thickness, 1.0f); - const int integer_thickness = (int)thickness; - const float fractional_thickness = thickness - integer_thickness; + ImVec2 uv0, uv1; + float fringe; + _SelectLineTexture(screen_thickness, &uv0, &uv1, &fringe, flags); - // Do we want to draw this line using a texture? - // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. - // - If AA_SIZE is not 1.0f we cannot use the texture path. - const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + const ImU32 col_trans = col & ~IM_COL32_A_MASK; - // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off - IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->OwnerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); + const ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeCenter); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + flags = (flags | ImDrawFlags_JoinMiter) & ~ImDrawFlags_AALineEnds; - const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); - const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3); - PrimReserve(idx_count, vtx_count); + const bool closed = (flags & ImDrawFlags_Closed) != 0; + const bool miters_only = (flags & ImDrawFlags_JoinMiter) != 0; + const float miter_distance_limit_sqr = IM_POLYLINE_MITER_LIMIT * IM_POLYLINE_MITER_LIMIT; + + float thickness0 = (thickness + fringe) * 0.5f; // Center (or legacy) + if (stroke_pos == ImDrawFlags_StrokeOutside) + thickness0 = thickness + fringe * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + thickness0 = _CalculateCenterBiasedOffset(thickness) + fringe * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeInside) + thickness0 = fringe * 0.5f; + float thickness1 = (thickness + fringe) - thickness0; + + int idx_count = 0; + int vtx_count = 0; + const int max_verts_per_point = miters_only ? 2 : 4; + const int max_tris_per_point = miters_only ? 2 : 5; + if (closed) + { + vtx_count = /*body*/points_count * max_verts_per_point + /*closing*/2; + idx_count = (/*body*/points_count * max_tris_per_point + /*closing*/2) * 3; + } + else + { + vtx_count = /*body*/(points_count - 2) * max_verts_per_point + /*caps*/(4 * 2); + idx_count = (/*body*/(points_count - 2) * max_tris_per_point + /*last seg*/2 + /*caps*/(2 * 2)) * 3; + } + PrimReserve(idx_count, vtx_count); - // Temporary buffer - // The first items are normals at each line point, then after that there are either 2 or 4 temp points for each line point - _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5)); - ImVec2* temp_normals = _Data->TempBuffer.Data; - ImVec2* temp_points = temp_normals + points_count; + const float ratio = thickness0 / (thickness0 + thickness1); // The points that use uv2 are placed directly on the path (offset = 0), calculate the texture position from stroke offsets. + const ImVec2 uv2(uv0.x + (uv1.x - uv0.x) * ratio, uv0.y); + + // Clamp inner offset and adjust texture coordinates to match the change. + // This is used by some of the convex shape rendering to avoid rendering artifacts when thickness is about to fill the whole shape. + if (thickness1 > max_inner_offset) + { + thickness1 = max_inner_offset; + const float s = (thickness0 + thickness1) / (thickness + fringe); + const float du = uv1.x - uv0.x; + uv1.x = uv0.x + du * s; + } - // Calculate normals (tangents) for each line segment - for (int i1 = 0; i1 < count; i1++) + const float half_aa = _FringeScale * 0.5f; // Used for end caps, does not use "fringe" since end cap AA is not using the texture. + const bool use_aa_ends = (flags & (ImDrawFlags_AALines | ImDrawFlags_AALineEnds)) == (ImDrawFlags_AALines | ImDrawFlags_AALineEnds); + + const int first_vtx_offset = (int)(_VtxWritePtr - VtxBuffer.Data); + int base_idx = (int)_VtxCurrentIdx; + + ImVec2 pa, pb, dir; + ImVec2 p1; + ImVec2 n1; + float len_sqr1; + + int point_idx = 0; + int point_end = points_count; + if (!closed) + { + // Start cap + point_idx++; + point_end--; + p1 = points[0]; + n1 = normals[0]; + len_sqr1 = sqr_lengths[0]; + + dir.x = n1.y; + dir.y = -n1.x; + if (flags & ImDrawFlags_CapSquare) { - const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; - float dx = points[i2].x - points[i1].x; - float dy = points[i2].y - points[i1].y; - IM_NORMALIZE2F_OVER_ZERO(dx, dy); - temp_normals[i1].x = dy; - temp_normals[i1].y = -dx; + p1.x -= dir.x * thickness * 0.5f; + p1.y -= dir.y * thickness * 0.5f; } - if (!closed) - temp_normals[points_count - 1] = temp_normals[points_count - 2]; - // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point - if (use_texture || !thick_line) + if (!use_aa_ends) { - // [PATH 1] Texture-based lines (thick or non-thick) - // [PATH 2] Non texture-based lines (non-thick) - - // The width of the geometry we need to draw - this is essentially pixels for the line itself, plus "one pixel" for AA. - // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture - // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. - // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to - // allow scaling geometry while preserving one-screen-pixel AA fringe). - const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; - - // If line is not closed, the first and last points need to be generated differently as there are no normals to blend - if (!closed) - { - temp_points[0] = points[0] + temp_normals[0] * half_draw_size; - temp_points[1] = points[0] - temp_normals[0] * half_draw_size; - temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; - temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; - } + base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(p1.x - n1.x * thickness0, p1.y - n1.y * thickness0, uv0, col); + IM_APPEND_VTX(p1.x + n1.x * thickness1, p1.y + n1.y * thickness1, uv1, col); + } + else + { + pa.x = p1.x - dir.x * half_aa; + pa.y = p1.y - dir.y * half_aa; + pb.x = p1.x + dir.x * half_aa; + pb.y = p1.y + dir.y * half_aa; + + base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pa.x - n1.x * thickness0, pa.y - n1.y * thickness0, uv0, col_trans); + IM_APPEND_VTX(pa.x + n1.x * thickness1, pa.y + n1.y * thickness1, uv1, col_trans); + + int next_base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pb.x - n1.x * thickness0, pb.y - n1.y * thickness0, uv0, col); + IM_APPEND_VTX(pb.x + n1.x * thickness1, pb.y + n1.y * thickness1, uv1, col); + + // AA cap + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + base_idx = next_base_idx; + } + } + else + { + // Wrap around segment + p1 = points[points_count - 1]; + n1 = normals[points_count - 1]; + len_sqr1 = sqr_lengths[points_count - 1]; + + // This will be filled later, allocate space. + base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(0, 0, uv0, col); + IM_APPEND_VTX(0, 0, uv1, col); + } + + if (miters_only) + { + while (point_idx < point_end) + { + ImVec2 n0 = n1; + p1 = points[point_idx]; + n1 = normals[point_idx]; + + // theta is the angle between two segments + const float cos_theta = n0.x * n1.x + n0.y * n1.y; + + // miter offset formula is derived here: https://www.angusj.com/clipper2/Docs/Trigonometry.htm + const float cos_theta_clamped = ImMax(IM_POLYLINE_MITER_ANGLE_LIMIT, cos_theta); // Avoid div by 0. + const float miter_scale_factor = ImMin(1000.0f, 1.0f / (1.0f + cos_theta_clamped)); + const float miter_offset_x = (n0.x + n1.x) * miter_scale_factor; + const float miter_offset_y = (n0.y + n1.y) * miter_scale_factor; + + // Miter + const int next_base_idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p1.x - miter_offset_x * thickness0, p1.y - miter_offset_y * thickness0, uv0, col); // 2 + IM_APPEND_VTX(p1.x + miter_offset_x * thickness1, p1.y + miter_offset_y * thickness1, uv1, col); // 3 + + // Connect prev to next + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + + base_idx = next_base_idx; + + point_idx++; + } + } + else + { + while (point_idx < point_end) + { + ImVec2 n0 = n1; + float len_sqr0 = len_sqr1; + p1 = points[point_idx]; + n1 = normals[point_idx]; + len_sqr1 = sqr_lengths[point_idx]; + + // theta is the angle between two segments + const float cos_theta = n0.x * n1.x + n0.y * n1.y; + const float sin_theta = n0.y * n1.x - n0.x * n1.y; + + // miter offset formula is derived here: https://www.angusj.com/clipper2/Docs/Trigonometry.htm + const float cos_theta_clamped = ImMax(IM_POLYLINE_MITER_ANGLE_LIMIT, cos_theta); // Avoid div by 0. + const float miter_scale_factor = ImMin(1000.0f, 1.0f / (1.0f + cos_theta_clamped)); + float miter_offset_x = (n0.x + n1.x) * miter_scale_factor; + float miter_offset_y = (n0.y + n1.y) * miter_scale_factor; + + const float miter_distance_sqr = miter_offset_x * miter_offset_x + miter_offset_y * miter_offset_y; - // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges - // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) - // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. - unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment - for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + if (miter_distance_sqr > miter_distance_limit_sqr) { - const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment - const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment - - // Average normals - float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; - float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; - IM_FIXNORMAL2F(dm_x, dm_y); - dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area - dm_y *= half_draw_size; - - // Add temporary vertices for the outer edges - ImVec2* out_vtx = &temp_points[i2 * 2]; - out_vtx[0].x = points[i2].x + dm_x; - out_vtx[0].y = points[i2].y + dm_y; - out_vtx[1].x = points[i2].x - dm_x; - out_vtx[1].y = points[i2].y - dm_y; - - if (use_texture) - { - // Add indices for two triangles - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri - _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri - _IdxWritePtr += 6; - } - else + // Clipped bevel + + // Limit the inner miter offset to avoid overshooting. + const float ref_thickness = (sin_theta < 0.0f) ? thickness1 : thickness0; + const float ref_thickness_sqr = ref_thickness * ref_thickness; + const float limit_sqr = ImMax(ImMax(len_sqr0, len_sqr1), ref_thickness_sqr); + const float ref_miter_dist_sqr = miter_distance_sqr * ref_thickness_sqr; + if (ref_miter_dist_sqr > limit_sqr) { - // Add indexes for four triangles - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 - _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 - _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 - _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 - _IdxWritePtr += 12; + const float scale = ImSqrt(limit_sqr / ref_miter_dist_sqr); + miter_offset_x *= scale; + miter_offset_y *= scale; } - idx1 = idx2; - } + float bn_x = n0.x + n1.x; + float bn_y = n0.y + n1.y; + IM_NORMALIZE2F_OVER_ZERO(bn_x, bn_y); - // Add vertices for each point on the line - if (use_texture) - { - // If we're using textures we only need to emit the left/right edge vertices - ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness]; - /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false! - { - const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1]; - tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp() - tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness; - tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness; - tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness; - }*/ - ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y); - ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); - for (int i = 0; i < points_count; i++) + const float side_offset = ((n0.x * bn_x + n0.y * bn_y) - 1.0f) / (n0.y * bn_x - n0.x * bn_y); + const float sd_x = bn_y * side_offset; + const float sd_y = -bn_x * side_offset; + + // Bevel + if (sin_theta < 0.0f) { - _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge - _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge - _VtxWritePtr += 2; + IM_APPEND_VTX(p1.x - (bn_x + sd_x) * thickness0, p1.y - (bn_y + sd_y) * thickness0, uv0, col); // 2 + IM_APPEND_VTX(p1.x, p1.y, uv2, col); // 3 + const int next_base_idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p1.x - (bn_x - sd_x) * thickness0, p1.y - (bn_y - sd_y) * thickness0, uv0, col); // 4 + IM_APPEND_VTX(p1.x + miter_offset_x * thickness1, p1.y + miter_offset_y * thickness1, uv1, col); // 5 + + // Connect prev to next + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 5); + IM_APPEND_TRI(base_idx + 0, base_idx + 5, base_idx + 1); + // Bevel + IM_APPEND_TRI(base_idx + 3, base_idx + 5, base_idx + 2); + IM_APPEND_TRI(base_idx + 3, base_idx + 2, base_idx + 4); + IM_APPEND_TRI(base_idx + 3, base_idx + 4, base_idx + 5); + base_idx = next_base_idx; } - } - else - { - // If we're not using a texture, we need the center vertex as well - for (int i = 0; i < points_count; i++) + else { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line - _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge - _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge - _VtxWritePtr += 3; + IM_APPEND_VTX(p1.x + (bn_x + sd_x) * thickness1, p1.y + (bn_y + sd_y) * thickness1, uv1, col); // 2 + IM_APPEND_VTX(p1.x, p1.y, uv2, col); // 3 + const int next_base_idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p1.x - miter_offset_x * thickness0, p1.y - miter_offset_y * thickness0, uv0, col); // 4 + IM_APPEND_VTX(p1.x + (bn_x - sd_x) * thickness1, p1.y + (bn_y - sd_y) * thickness1, uv1, col); // 5 + + // Connect prev to next + IM_APPEND_TRI(base_idx + 0, base_idx + 4, base_idx + 2); + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 1); + // Bevel + IM_APPEND_TRI(base_idx + 3, base_idx + 2, base_idx + 4); + IM_APPEND_TRI(base_idx + 3, base_idx + 4, base_idx + 5); + IM_APPEND_TRI(base_idx + 3, base_idx + 5, base_idx + 2); + base_idx = next_base_idx; } } - } - else - { - // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point - const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; - - // If line is not closed, the first and last points need to be generated differently as there are no normals to blend - if (!closed) - { - const int points_last = points_count - 1; - temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); - temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); - temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); - temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); - temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); - temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); - temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); - temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); - } - - // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges - // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) - // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. - unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment - for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + else { - const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment - const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment - - // Average normals - float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; - float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; - IM_FIXNORMAL2F(dm_x, dm_y); - float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); - float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); - float dm_in_x = dm_x * half_inner_thickness; - float dm_in_y = dm_y * half_inner_thickness; - - // Add temporary vertices - ImVec2* out_vtx = &temp_points[i2 * 4]; - out_vtx[0].x = points[i2].x + dm_out_x; - out_vtx[0].y = points[i2].y + dm_out_y; - out_vtx[1].x = points[i2].x + dm_in_x; - out_vtx[1].y = points[i2].y + dm_in_y; - out_vtx[2].x = points[i2].x - dm_in_x; - out_vtx[2].y = points[i2].y - dm_in_y; - out_vtx[3].x = points[i2].x - dm_out_x; - out_vtx[3].y = points[i2].y - dm_out_y; - - // Add indexes - _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); - _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); - _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); - _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); - _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); - _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); - _IdxWritePtr += 18; - - idx1 = idx2; + // Miter + const int next_base_idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p1.x - miter_offset_x * thickness0, p1.y - miter_offset_y * thickness0, uv0, col); // 2 + IM_APPEND_VTX(p1.x + miter_offset_x * thickness1, p1.y + miter_offset_y * thickness1, uv1, col); // 3 + + // Connect prev to next + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + base_idx = next_base_idx; } - // Add vertices - for (int i = 0; i < points_count; i++) - { - _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; - _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; - _VtxWritePtr += 4; - } + point_idx++; } - _VtxCurrentIdx += (ImDrawIdx)vtx_count; } - else + + // End cap + if (!closed) { - // [PATH 4] Non texture-based, Non anti-aliased lines - const int idx_count = count * 6; - const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges - PrimReserve(idx_count, vtx_count); + p1 = points[points_count - 1]; + n1 = normals[points_count - 1]; - for (int i1 = 0; i1 < count; i1++) + // End cap + dir.x = n1.y; + dir.y = -n1.x; + if (flags & ImDrawFlags_CapSquare) { - const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; - const ImVec2& p1 = points[i1]; - const ImVec2& p2 = points[i2]; - - float dx = p2.x - p1.x; - float dy = p2.y - p1.y; - IM_NORMALIZE2F_OVER_ZERO(dx, dy); - dx *= (thickness * 0.5f); - dy *= (thickness * 0.5f); + p1.x += dir.x * thickness * 0.5f; + p1.y += dir.y * thickness * 0.5f; + } - _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; - _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; - _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; - _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; - _VtxWritePtr += 4; + if (!use_aa_ends) + { + IM_APPEND_VTX(p1.x - n1.x * thickness0, p1.y - n1.y * thickness0, uv0, col); + IM_APPEND_VTX(p1.x + n1.x * thickness1, p1.y + n1.y * thickness1, uv1, col); - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); - _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); - _IdxWritePtr += 6; - _VtxCurrentIdx += 4; + // Connect + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + } + else + { + pa.x = p1.x - dir.x * half_aa; + pa.y = p1.y - dir.y * half_aa; + pb.x = p1.x + dir.x * half_aa; + pb.y = p1.y + dir.y * half_aa; + + int next_base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pa.x - n1.x * thickness0, pa.y - n1.y * thickness0, uv0, col); + IM_APPEND_VTX(pa.x + n1.x * thickness1, pa.y + n1.y * thickness1, uv1, col); + + IM_APPEND_VTX(pb.x - n1.x * thickness0, pb.y - n1.y * thickness0, uv0, col_trans); + IM_APPEND_VTX(pb.x + n1.x * thickness1, pb.y + n1.y * thickness1, uv1, col_trans); + + // Connect + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + base_idx = next_base_idx; + + // AA cap + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); } } + else + { + // Connect the path. + VtxBuffer.Data[first_vtx_offset + 0] = VtxBuffer.Data[_CmdHeader.VtxOffset + base_idx + 0]; + VtxBuffer.Data[first_vtx_offset + 1] = VtxBuffer.Data[_CmdHeader.VtxOffset + base_idx + 1]; + } + + // Restore unused memory + const int cur_idx_offset = (int)(_IdxWritePtr - IdxBuffer.Data); + const int cur_vtx_offset = (int)(_VtxWritePtr - VtxBuffer.Data); + const int remaining_idx_count = IdxBuffer.Size - cur_idx_offset; + const int remaining_vtx_count = VtxBuffer.Size - cur_vtx_offset; + IM_ASSERT_PARANOID(remaining_idx_count >= 0 && remaining_vtx_count >= 0); + PrimUnreserve(remaining_idx_count, remaining_vtx_count); } // - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. -void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags) { if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) return; const ImVec2 uv = _Data->TexUvWhitePixel; - - if (Flags & ImDrawListFlags_AntiAliasedFill) + flags |= Flags; + if (flags & ImDrawFlags_AAFill) { - // Anti-aliased Fill - const float AA_SIZE = _FringeScale; - const ImU32 col_trans = col & ~IM_COL32_A_MASK; - const int idx_count = (points_count - 2)*3 + points_count * 6; - const int vtx_count = (points_count * 2); - PrimReserve(idx_count, vtx_count); + const float half_aa = _FringeScale * 0.5f; + ImU32 col_trans = col & ~IM_COL32_A_MASK; + const bool miters_only = (flags & ImDrawFlags_JoinMiter) != 0; + const float miter_distance_limit_sqr = IM_POLYLINE_MITER_LIMIT * IM_POLYLINE_MITER_LIMIT; - // Add indexes for fill - unsigned int vtx_inner_idx = _VtxCurrentIdx; - unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; - for (int i = 2; i < points_count; i++) - { - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); - _IdxWritePtr += 3; - } + const int idx_count = ((points_count - 2) + points_count * 2 + IM_POLYLINE_CONVEX_POLY_MAX_BEVELS) * 3; + const int vtx_count = points_count * 2 + IM_POLYLINE_CONVEX_POLY_MAX_BEVELS; + PrimReserve(idx_count, vtx_count); + ImDrawVert* start_vtx_ptr = _VtxWritePtr; + ImDrawIdx* start_idx_ptr = _IdxWritePtr; - // Compute normals - _Data->TempBuffer.reserve_discard(points_count); + // Compute normals and segment lengths + _Data->TempBuffer.reserve_discard(points_count * 2); ImVec2* temp_normals = _Data->TempBuffer.Data; + float* temp_sqr_lengths = (float*)(_Data->TempBuffer.Data + points_count); for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) { const ImVec2& p0 = points[i0]; const ImVec2& p1 = points[i1]; float dx = p1.x - p0.x; float dy = p1.y - p0.y; - IM_NORMALIZE2F_OVER_ZERO(dx, dy); + float d2 = dx * dx + dy * dy; + if (d2 > 0.0f) + { + const float inv_len = ImRsqrtPrecise(d2); + dx *= inv_len; + dy *= inv_len; + } temp_normals[i0].x = dy; temp_normals[i0].y = -dx; + temp_sqr_lengths[i0] = d2; } - for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + unsigned int vtx_inner_idx = _VtxCurrentIdx; + ImDrawVert* inner_vtx_ptr = _VtxWritePtr; + _VtxWritePtr += points_count; + _VtxCurrentIdx += points_count; + + unsigned int prev_outer_idx = 0; // This should be the index of the last vertex, but we don't know it yet. Will need to patch once we're done. + if (miters_only) { - // Average normals - const ImVec2& n0 = temp_normals[i0]; - const ImVec2& n1 = temp_normals[i1]; - float dm_x = (n0.x + n1.x) * 0.5f; - float dm_y = (n0.y + n1.y) * 0.5f; - IM_FIXNORMAL2F(dm_x, dm_y); - dm_x *= AA_SIZE * 0.5f; - dm_y *= AA_SIZE * 0.5f; + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2 p1 = points[i1]; + const ImVec2 n0 = temp_normals[i0]; + const ImVec2 n1 = temp_normals[i1]; + + // theta is the angle between two segments + const float cos_theta = n0.x * n1.x + n0.y * n1.y; + // miter offset formula is derived here: https://www.angusj.com/clipper2/Docs/Trigonometry.htm + const float cos_theta_clamped = ImMax(IM_POLYLINE_MITER_ANGLE_LIMIT, cos_theta); // Avoid div by 0. + const float miter_scale_factor = ImMin(1000.0f, 1.0f / (1.0f + cos_theta_clamped)); + const float miter_offset_x = (n0.x + n1.x) * miter_scale_factor * half_aa; + const float miter_offset_y = (n0.y + n1.y) * miter_scale_factor * half_aa; + + // Inner + inner_vtx_ptr->pos.x = p1.x - miter_offset_x; + inner_vtx_ptr->pos.y = p1.y - miter_offset_y; + inner_vtx_ptr->uv = uv; inner_vtx_ptr->col = col; + inner_vtx_ptr++; + + const unsigned int prev_inner_idx = vtx_inner_idx + i0; + const unsigned int inner_idx = vtx_inner_idx + i1; + const unsigned int outer_idx = _VtxCurrentIdx; + + // Outer + IM_APPEND_VTX(p1.x + miter_offset_x, p1.y + miter_offset_y, uv, col_trans); + // Connect with previous + IM_APPEND_TRI(prev_outer_idx, outer_idx, inner_idx); + IM_APPEND_TRI(prev_outer_idx, inner_idx, prev_inner_idx); + + prev_outer_idx = outer_idx; + } + } + else + { + int bevel_count = 0; + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2 p1 = points[i1]; + const ImVec2 n0 = temp_normals[i0]; + const ImVec2 n1 = temp_normals[i1]; + + // theta is the angle between two segments + const float cos_theta = n0.x * n1.x + n0.y * n1.y; + // miter offset formula is derived here: https://www.angusj.com/clipper2/Docs/Trigonometry.htm + const float cos_theta_clamped = ImMax(IM_POLYLINE_MITER_ANGLE_LIMIT, cos_theta); // Avoid div by 0. + const float miter_scale_factor = ImMin(1000.0f, 1.0f / (1.0f + cos_theta_clamped)); + float miter_offset_x = (n0.x + n1.x) * miter_scale_factor; + float miter_offset_y = (n0.y + n1.y) * miter_scale_factor; + + const float miter_distance_sqr = miter_offset_x * miter_offset_x + miter_offset_y * miter_offset_y; + const bool bevel = miter_distance_sqr > miter_distance_limit_sqr; + if (bevel) + { + // Limit inner bevel so that it is does not shoot out outside the polygon. + // (using ImMax is intentional: using min limited too much in Mikko's tests when you have short edge next to long one. + // The idea of that check is to keep that worst case overshoot no bigger than the polygon) + const float ref_thickness_sqr = half_aa * half_aa; + const float limit_sqr = ImMax(temp_sqr_lengths[i0], temp_sqr_lengths[i1]); + const float ref_miter_dist_sqr = miter_distance_sqr * ref_thickness_sqr; + if (ref_miter_dist_sqr > limit_sqr) + { + const float scale = ImSqrt(limit_sqr / ref_miter_dist_sqr); + miter_offset_x *= scale; + miter_offset_y *= scale; + } + } - // Add vertices - _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner - _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer - _VtxWritePtr += 2; + miter_offset_x *= half_aa; + miter_offset_y *= half_aa; - // Add indexes for fringes - _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); - _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); - _IdxWritePtr += 6; + // Inner + inner_vtx_ptr->pos.x = p1.x - miter_offset_x; + inner_vtx_ptr->pos.y = p1.y - miter_offset_y; + inner_vtx_ptr->uv = uv; inner_vtx_ptr->col = col; + inner_vtx_ptr++; + + const unsigned int prev_inner_idx = vtx_inner_idx + i0; + const unsigned int inner_idx = vtx_inner_idx + i1; + unsigned int outer_idx = _VtxCurrentIdx; + + // Outer + if (bevel && bevel_count < IM_POLYLINE_CONVEX_POLY_MAX_BEVELS) IM_UNLIKELY + { + // Because the polygon is convex, we know the maximum number of bevel corners we can hit (which is very small number). + // We keep track of them just in case the calculations disagree. + bevel_count++; + + IM_APPEND_VTX(p1.x + n0.x * half_aa, p1.y + n0.y * half_aa, uv, col_trans); + IM_APPEND_VTX(p1.x + n1.x * half_aa, p1.y + n1.y * half_aa, uv, col_trans); + // Connect with previous + IM_APPEND_TRI(prev_outer_idx, outer_idx, inner_idx); + IM_APPEND_TRI(prev_outer_idx, inner_idx, prev_inner_idx); + // Fill bevel + IM_APPEND_TRI(outer_idx, outer_idx + 1, inner_idx); + outer_idx++; + } + else + { + IM_APPEND_VTX(p1.x + miter_offset_x, p1.y + miter_offset_y, uv, col_trans); + // Connect with previous + IM_APPEND_TRI(prev_outer_idx, outer_idx, inner_idx); + IM_APPEND_TRI(prev_outer_idx, inner_idx, prev_inner_idx); + } + + prev_outer_idx = outer_idx; + } } - _VtxCurrentIdx += (ImDrawIdx)vtx_count; + + // Patch first segment to wrap around + start_idx_ptr[0] = (ImDrawIdx)prev_outer_idx; + start_idx_ptr[3] = (ImDrawIdx)prev_outer_idx; + + // Add indices for fill + for (int i = 2; i < points_count; i++) + IM_APPEND_TRI(vtx_inner_idx, vtx_inner_idx + i - 1, vtx_inner_idx + i); + + const int idx_used = (int)(_IdxWritePtr - start_idx_ptr); + const int vtx_used = (int)(_VtxWritePtr - start_vtx_ptr); + IM_ASSERT(idx_used <= idx_count && vtx_used <= vtx_count); + if (idx_used < idx_count || vtx_used < vtx_count) + PrimUnreserve(idx_count - idx_used, vtx_count - vtx_used); } else { // Non Anti-aliased Fill - const int idx_count = (points_count - 2)*3; + const int idx_count = (points_count - 2) * 3; const int vtx_count = points_count; PrimReserve(idx_count, vtx_count); + int base_idx = _VtxCurrentIdx; for (int i = 0; i < vtx_count; i++) - { - _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; - _VtxWritePtr++; - } + IM_APPEND_VTX(points[i].x, points[i].y, uv, col); for (int i = 2; i < points_count; i++) - { - _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); - _IdxWritePtr += 3; - } - _VtxCurrentIdx += (ImDrawIdx)vtx_count; + IM_APPEND_TRI(base_idx, base_idx + i - 1, base_idx + i); } } +// Calculates arc step and step count for 90 degree arc. The calculated arc step will complete a 90 degree arc when stepped arc_step_count times. +IM_MSVC_RUNTIME_CHECKS_OFF +static void CalcCornerArcStepAndCount(int segment_count, int& arc_step, int& arc_step_count) +{ + arc_step = ImClamp(IM_DRAWLIST_ARCFAST_SAMPLE_MAX / segment_count, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + arc_step_count = (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4) / arc_step; + if ((arc_step * arc_step_count) != (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4)) // Make sure that the arc step can iterate 90 degree arc. + arc_step = (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4) / arc_step_count; +} +IM_MSVC_RUNTIME_CHECKS_RESTORE + void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) { - if (radius < 0.5f) + if (!IM_HAS_ROUNDING(radius)) { _Path.push_back(center); return; @@ -1169,10 +1532,17 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ // Calculate arc auto segment step size if (a_step <= 0) - a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius); - - // Make sure we never do steps larger than one quarter of the circle - a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + { + // Calculate step size using the common function. No need to clamp, the step is already in range. + const int auto_seg_count = _CalcCircleAutoSegmentCount(radius); + int arc_step_count; + CalcCornerArcStepAndCount(auto_seg_count, a_step, arc_step_count); + } + else + { + // Make sure we never do steps larger than one quarter of the circle + a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + } const int sample_range = ImAbs(a_max_sample - a_min_sample); const int a_next_step = a_step; @@ -1253,7 +1623,7 @@ void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_ void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) { - if (radius < 0.5f) + if (!IM_HAS_ROUNDING(radius)) { _Path.push_back(center); return; @@ -1272,7 +1642,7 @@ void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, fl // 0: East, 3: South, 6: West, 9: North, 12: East void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) { - if (radius < 0.5f) + if (!IM_HAS_ROUNDING(radius)) { _Path.push_back(center); return; @@ -1282,7 +1652,7 @@ void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) { - if (radius < 0.5f) + if (!IM_HAS_ROUNDING(radius)) { _Path.push_back(center); return; @@ -1296,16 +1666,25 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa // Automatic segment count if (radius <= _Data->ArcFastRadiusCutoff) - { + { const bool a_is_reverse = a_max < a_min; + // Calculate number of segments per circle. + // First we calculate the step count as usual, then match to the precomputed directions. + // This will give us the spacing between the samples (step), and how many segments to use in total for a full circle. + const int auto_seg_count = _CalcCircleAutoSegmentCount(radius); + int arc_step, arc_step_count; + CalcCornerArcStepAndCount(auto_seg_count, arc_step, arc_step_count); + const int arc_seg_count = arc_step_count * 4; // Seg count for full circle. + // We are going to use precomputed values for mid samples. // Determine first and last sample in lookup table that belong to the arc. - const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f); - const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f); + // In first step we use the coarser segment count, and after rounding, convert back to the precomputed array index. + const float a_min_sample_f = arc_seg_count * a_min / (IM_PI * 2.0f); + const float a_max_sample_f = arc_seg_count * a_max / (IM_PI * 2.0f); - const int a_min_sample = a_is_reverse ? (int)ImFloor(a_min_sample_f) : (int)ImCeil(a_min_sample_f); - const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloor(a_max_sample_f); + const int a_min_sample = (a_is_reverse ? (int)ImFloor(a_min_sample_f) : (int)ImCeil(a_min_sample_f)) * arc_step; + const int a_max_sample = (a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloor(a_max_sample_f)) * arc_step; const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0); const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; @@ -1317,7 +1696,7 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa if (a_emit_start) _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)); if (a_mid_samples > 0) - _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0); + _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, arc_step); if (a_emit_end) _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)); } @@ -1370,7 +1749,7 @@ ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p } // Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp -static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float max_error_sqr, int level) { float dx = x4 - x1; float dy = y4 - y1; @@ -1378,7 +1757,7 @@ static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, fl float d3 = (x3 - x4) * dy - (y3 - y4) * dx; d2 = (d2 >= 0) ? d2 : -d2; d3 = (d3 >= 0) ? d3 : -d3; - if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + if ((d2 + d3) * (d2 + d3) < max_error_sqr * (dx * dx + dy * dy)) { path->push_back(ImVec2(x4, y4)); } @@ -1390,16 +1769,16 @@ static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, fl float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f; float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f; - PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); - PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, max_error_sqr, level + 1); + PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, max_error_sqr, level + 1); } } -static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level) +static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float max_error_sqr, int level) { float dx = x3 - x1, dy = y3 - y1; float det = (x2 - x3) * dy - (y2 - y3) * dx; - if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy)) + if (det * det * 4.0f < max_error_sqr * (dx * dx + dy * dy)) { path->push_back(ImVec2(x3, y3)); } @@ -1408,8 +1787,8 @@ static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1 float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; - PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1); - PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1); + PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, max_error_sqr, level + 1); + PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, max_error_sqr, level + 1); } } @@ -1418,8 +1797,9 @@ void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, cons ImVec2 p1 = _Path.back(); if (num_segments == 0) { - IM_ASSERT(_Data->CurveTessellationTol > 0.0f); - PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated + IM_ASSERT(_Data->CurveTessellationMaxError > 0.0f); + float max_error_sqr = (_Data->CurveTessellationMaxError * _FringeScale) * (_Data->CurveTessellationMaxError * _FringeScale); + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, max_error_sqr, 0); // Auto-tessellated } else { @@ -1434,8 +1814,9 @@ void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, ImVec2 p1 = _Path.back(); if (num_segments == 0) { - IM_ASSERT(_Data->CurveTessellationTol > 0.0f); - PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated + IM_ASSERT(_Data->CurveTessellationMaxError > 0.0f); + float max_error_sqr = (_Data->CurveTessellationMaxError * _FringeScale) * (_Data->CurveTessellationMaxError * _FringeScale); + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, max_error_sqr, 0);// Auto-tessellated } else { @@ -1447,15 +1828,16 @@ void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) { - if (rounding >= 0.5f) + const bool has_rounding = IM_HAS_ROUNDING(rounding); + if (has_rounding) { - if ((flags & ImDrawFlags_RoundCornersMask_) == 0) - flags |= ImDrawFlags_RoundCornersAll; + if ((flags & ImDrawFlags_RoundMask_) == 0) + flags |= ImDrawFlags_RoundAll; - rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f); - rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundTop) == ImDrawFlags_RoundTop) || ((flags & ImDrawFlags_RoundBottom) == ImDrawFlags_RoundBottom) ? 0.5f : 1.0f) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundLeft) == ImDrawFlags_RoundLeft) || ((flags & ImDrawFlags_RoundRight) == ImDrawFlags_RoundRight) ? 0.5f : 1.0f) - 1.0f); } - if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + if (!has_rounding || (flags & ImDrawFlags_RoundMask_) == ImDrawFlags_RoundNone) { PathLineTo(a); PathLineTo(ImVec2(b.x, a.y)); @@ -1464,10 +1846,10 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } else { - const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; - const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f; - const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f; - const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f; + const float rounding_tl = (flags & ImDrawFlags_RoundTopLeft) ? rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundTopRight) ? rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundBottomRight) ? rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundBottomLeft) ? rounding : 0.0f; PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); @@ -1475,71 +1857,777 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr } } -void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) +void ImDrawList::_AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) IM_UNLIKELY + return; + + float screen_thickness = thickness * _InvFringeScale; + if (screen_thickness < 1.0f) IM_UNLIKELY + { + if (screen_thickness < 1.0f / 255.0f) IM_UNLIKELY + return; + col = ImAlphaMultiply(col, screen_thickness); + screen_thickness = 1.0f; + thickness = _FringeScale; + } + + flags |= Flags; + ImVec2 uv0, uv1; + float fringe; + _SelectLineTexture(screen_thickness, &uv0, &uv1, &fringe, flags); + + float dir_x = p2.x - p1.x; + float dir_y = p2.y - p1.y; + const float d2 = dir_x * dir_x + dir_y * dir_y; + const float inv_len = (d2 > 0.0f) ? ImRsqrtPrecise(d2) : 0.0f; + dir_x *= inv_len; + dir_y *= inv_len; + const float norm_x = -dir_y; + const float norm_y = dir_x; + + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + const ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeCenter); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + flags = (flags | ImDrawFlags_JoinMiter) & ~ImDrawFlags_AALineEnds; + + float thickness0 = (thickness + fringe) * 0.5f; // Center (or legacy) + if (stroke_pos == ImDrawFlags_StrokeOutside) + thickness0 = thickness + fringe * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + thickness0 = _CalculateCenterBiasedOffset(thickness) + fringe * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeInside) + thickness0 = fringe * 0.5f; + const float thickness1 = (thickness + fringe) - thickness0; + + const float ratio = thickness0 / (thickness0 + thickness1); // The points using uv2 are placed on the path, calculate the position from stroke offsets. + const ImVec2 uv2(uv0.x + (uv1.x - uv0.x) * ratio, uv0.y); + + const float half_aa = _FringeScale * 0.5f; // Used for end caps, does not use "fringe" since end cap AA is not using the texture. + const bool use_aa_ends = (flags & (ImDrawFlags_AALines | ImDrawFlags_AALineEnds)) == (ImDrawFlags_AALines | ImDrawFlags_AALineEnds); + + if (!use_aa_ends) + PrimReserve(2*3, 4); + else + PrimReserve(6*3, 8); + + int base_idx = (int)_VtxCurrentIdx; + + float p1_x = p1.x; + float p1_y = p1.y; + float p2_x = p2.x; + float p2_y = p2.y; + if (flags & ImDrawFlags_CapSquare) + { + const float half_thickness = thickness * 0.5f; + p1_x -= dir_x * half_thickness; + p1_y -= dir_y * half_thickness; + p2_x += dir_x * half_thickness; + p2_y += dir_y * half_thickness; + } + + // Start cap + if (!use_aa_ends) + { + base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(p1_x - norm_x * thickness0, p1_y - norm_y * thickness0, uv0, col); + IM_APPEND_VTX(p1_x + norm_x * thickness1, p1_y + norm_y * thickness1, uv1, col); + IM_APPEND_VTX(p2_x - norm_x * thickness0, p2_y - norm_y * thickness0, uv0, col); + IM_APPEND_VTX(p2_x + norm_x * thickness1, p2_y + norm_y * thickness1, uv1, col); + + // Connect + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + } + else + { + // Start + float pa_x = p1_x - dir_x * half_aa; + float pa_y = p1_y - dir_y * half_aa; + float pb_x = p1_x + dir_x * half_aa; + float pb_y = p1_y + dir_y * half_aa; + + base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pa_x - norm_x * thickness0, pa_y - norm_y * thickness0, uv0, col_trans); + IM_APPEND_VTX(pa_x + norm_x * thickness1, pa_y + norm_y * thickness1, uv1, col_trans); + + int next_base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pb_x - norm_x * thickness0, pb_y - norm_y * thickness0, uv0, col); + IM_APPEND_VTX(pb_x + norm_x * thickness1, pb_y + norm_y * thickness1, uv1, col); + + // AA cap + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + base_idx = next_base_idx; + + // End + pa_x = p2_x - dir_x * half_aa; + pa_y = p2_y - dir_y * half_aa; + pb_x = p2_x + dir_x * half_aa; + pb_y = p2_y + dir_y * half_aa; + + next_base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(pa_x - norm_x * thickness0, pa_y - norm_y * thickness0, uv0, col); + IM_APPEND_VTX(pa_x + norm_x * thickness1, pa_y + norm_y * thickness1, uv1, col); + IM_APPEND_VTX(pb_x - norm_x * thickness0, pb_y - norm_y * thickness0, uv0, col_trans); + IM_APPEND_VTX(pb_x + norm_x * thickness1, pb_y + norm_y * thickness1, uv1, col_trans); + + // Connect + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + base_idx = next_base_idx; + + // AA cap + IM_APPEND_TRI(base_idx + 0, base_idx + 2, base_idx + 3); + IM_APPEND_TRI(base_idx + 0, base_idx + 3, base_idx + 1); + } +} + +void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - const ImVec2 points[2] = { ImVec2(p1.x + 0.5f, p1.y + 0.5f), ImVec2(p2.x + 0.5f, p2.y + 0.5f) }; - AddPolyline(points, 2, col, thickness); + + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeCenter); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + { + _AddLine(ImVec2(p1.x + 0.5f, p1.y + 0.5f), ImVec2(p2.x + 0.5f, p2.y + 0.5f), col, thickness, flags); + return; + } + + _AddLine(p1, p2, col, thickness, flags); } -void ImDrawList::AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness) +// AddLineH(10, 20, 5, col, 1.0f) == AddLine( {10,5.5}, {20,5.5}, col, 1.0f) +// == AddLine( {10,5}, {20,5}, col, 1.0f, ImDrawFlags_StrokeLegacy); // or before 1.93.0 +// Thickness extend inside/bottom by default. Faster than equivalent AddLine() call. +void ImDrawList::AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - const ImVec2 points[2] = { ImVec2(min_x + 0.5f, y + 0.5f), ImVec2(max_x + 0.5f, y + 0.5f) }; // Same as AddLine() above. - AddPolyline(points, 2, col, thickness); + + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + { + _AddLine(ImVec2(min_x + 0.5f, y + 0.5f), ImVec2(max_x + 0.5f, y + 0.5f), col, thickness, flags); + return; + } + + float top_y = y; // Inside + if (stroke_pos == ImDrawFlags_StrokeCenter) + top_y -= thickness * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + top_y -= _CalculateCenterBiasedOffset(thickness); + else if (stroke_pos == ImDrawFlags_StrokeOutside) + top_y -= thickness; + + const bool is_truncated = IM_IS_TRUNCATED4(min_x, max_x, top_y, thickness); + if (_FringeScaleIsInteger && is_truncated && (flags & ImDrawFlags_CapSquare) == 0) + { + if (thickness < _FringeScale) IM_UNLIKELY + { + if (thickness < (1.0f / 255.0f) * _FringeScale) + return; + col = ImAlphaMultiply(col, thickness * _InvFringeScale); + thickness = _FringeScale; + } + + // For pixel aligned case, use simple rectangle. + PrimReserve(6, 4); + PrimRect(ImVec2(min_x, top_y), ImVec2(max_x, top_y + thickness), col); + } + else + { + // Replace stroke pos with the already calculated one, as AddPolyline() default is different. + flags = (flags & ~ImDrawFlags_StrokeMask_) | stroke_pos; + + // For generic case use line, since it needs less triangles than AA rectangle. + _AddLine(ImVec2(min_x, y), ImVec2(max_x, y), col, thickness, flags); + } } -void ImDrawList::AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness) -{ - if ((col & IM_COL32_A_MASK) == 0) - return; - const ImVec2 points[2] = { ImVec2(x + 0.5f, min_y + 0.5f), ImVec2(x + 0.5f, max_y + 0.5f) }; // Same as AddLine() above. - AddPolyline(points, 2, col, thickness); +// AddLineV(5, 10, 20, col, 1.0f) == AddLine( {5.5,10}, {5.5,20}, col, 1.0f) +// == AddLine( {5,10}, {5,20}, col, 1.0f, ImDrawFlags_StrokeLegacy); // or before 1.93.0 +// Thickness extend inside/right by default. Faster than equivalent AddLine() call. +void ImDrawList::AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + { + _AddLine(ImVec2(x + 0.5f, min_y + 0.5f), ImVec2(x + 0.5f, max_y + 0.5f), col, thickness, flags); + return; + } + + float left_x = x; // Inside + if (stroke_pos == ImDrawFlags_StrokeCenter) + left_x -= thickness * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + left_x -= _CalculateCenterBiasedOffset(thickness); + else if (stroke_pos == ImDrawFlags_StrokeOutside) + left_x -= thickness; + + const bool is_truncated = IM_IS_TRUNCATED4(left_x, min_y, max_y, thickness); + if (_FringeScaleIsInteger && is_truncated && (flags & ImDrawFlags_CapSquare) == 0) + { + if (thickness < _FringeScale) IM_UNLIKELY + { + if (thickness < (1.0f / 255.0f) * _FringeScale) + return; + col = ImAlphaMultiply(col, thickness * _InvFringeScale); + thickness = _FringeScale; + } + + // For pixel aligned case, use simple rectangle. + PrimReserve(6, 4); + PrimRect(ImVec2(left_x, min_y), ImVec2(left_x + thickness, max_y), col); + } + else + { + // Replace stroke pos with the already calculated one, as AddPolyline() default is different. + flags = (flags & ~ImDrawFlags_StrokeMask_) | stroke_pos; + + // For generic case use line, since it needs less triangles than AA rectangle. + // Drawing for bottom to top, so that the inside stroke pos expands to right. + _AddLine(ImVec2(x, max_y), ImVec2(x, min_y), col, thickness, flags); + } +} + +void ImDrawList::_AddRectBaked(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float r, float t, const ImVec4& tex_uvs, ImDrawFlags flags) +{ + const ImVec2 uv_tl(tex_uvs.x, tex_uvs.y); + const ImVec2 uv_tr(tex_uvs.z, tex_uvs.y); + const ImVec2 uv_br(tex_uvs.z, tex_uvs.w); + const ImVec2 uv_bl(tex_uvs.x, tex_uvs.w); + + const int idx_allocated = 8 * 2 * 3; + const int vtx_allocated = 8 * 4; + PrimReserve(idx_allocated, vtx_allocated); + ImDrawVert* start_vtx_ptr = _VtxWritePtr; + ImDrawIdx* start_idx_ptr = _IdxWritePtr; + + if (flags & ImDrawFlags_RoundTopLeft) + { + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p_min.x, p_min.y, uv_tl, col); + IM_APPEND_VTX(p_min.x + r, p_min.y, uv_tr, col); + IM_APPEND_VTX(p_min.x + r, p_min.y + r, uv_br, col); + IM_APPEND_VTX(p_min.x, p_min.y + r, uv_bl, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + + if (flags & ImDrawFlags_RoundTopRight) + { + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p_max.x - r, p_min.y, uv_tr, col); + IM_APPEND_VTX(p_max.x, p_min.y, uv_tl, col); + IM_APPEND_VTX(p_max.x, p_min.y + r, uv_bl, col); + IM_APPEND_VTX(p_max.x - r, p_min.y + r, uv_br, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + + if (flags & ImDrawFlags_RoundBottomRight) + { + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p_max.x - r, p_max.y - r, uv_br, col); + IM_APPEND_VTX(p_max.x, p_max.y - r, uv_bl, col); + IM_APPEND_VTX(p_max.x, p_max.y, uv_tl, col); + IM_APPEND_VTX(p_max.x - r, p_max.y, uv_tr, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + + if (flags & ImDrawFlags_RoundBottomLeft) + { + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p_min.x, p_max.y - r, uv_bl, col); + IM_APPEND_VTX(p_min.x + r, p_max.y - r, uv_br, col); + IM_APPEND_VTX(p_min.x + r, p_max.y, uv_tr, col); + IM_APPEND_VTX(p_min.x, p_max.y, uv_tl, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + + const float r_tl = (flags & ImDrawFlags_RoundTopLeft) ? r : 0; + const float r_tr = (flags & ImDrawFlags_RoundTopRight) ? r : 0; + const float r_br = (flags & ImDrawFlags_RoundBottomRight) ? r : 0; + const float r_bl = (flags & ImDrawFlags_RoundBottomLeft) ? r : 0; + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + + { + // Top + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + const float x0 = p_min.x + r_tl; + const float x1 = p_max.x - r_tr; + IM_APPEND_VTX(x0, p_min.y, opaque_uv, col); + IM_APPEND_VTX(x1, p_min.y, opaque_uv, col); + IM_APPEND_VTX(x1, p_min.y + t, opaque_uv, col); + IM_APPEND_VTX(x0, p_min.y + t, opaque_uv, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + { + // Left + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + const float y0 = p_min.y + ImMax(r_tl, t); + const float y1 = p_max.y - ImMax(r_bl, t); + IM_APPEND_VTX(p_min.x, y0, opaque_uv, col); + IM_APPEND_VTX(p_min.x + t, y0, opaque_uv, col); + IM_APPEND_VTX(p_min.x + t, y1, opaque_uv, col); + IM_APPEND_VTX(p_min.x, y1, opaque_uv, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + { + // Right + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + const float y0 = p_min.y + ImMax(r_tr, t); + const float y1 = p_max.y - ImMax(r_br, t); + IM_APPEND_VTX(p_max.x - t, y0, opaque_uv, col); + IM_APPEND_VTX(p_max.x, y0, opaque_uv, col); + IM_APPEND_VTX(p_max.x, y1, opaque_uv, col); + IM_APPEND_VTX(p_max.x - t, y1, opaque_uv, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + { + // Bottom + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + const float x0 = p_min.x + r_bl; + const float x1 = p_max.x - r_br; + IM_APPEND_VTX(x0, p_max.y - t, opaque_uv, col); + IM_APPEND_VTX(x1, p_max.y - t, opaque_uv, col); + IM_APPEND_VTX(x1, p_max.y, opaque_uv, col); + IM_APPEND_VTX(x0, p_max.y, opaque_uv, col); + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + } + + const int idx_used = (int)(_IdxWritePtr - start_idx_ptr); + const int vtx_used = (int)(_VtxWritePtr - start_vtx_ptr); + IM_ASSERT_PARANOID(idx_used <= idx_allocated && vtx_used <= vtx_allocated); + if (idx_used < idx_allocated || vtx_used < vtx_allocated) + PrimUnreserve(idx_allocated - idx_used, vtx_allocated - vtx_used); +} + +// Draws rounded rectangle where thickness > rounding. If rendered using the regular polyline, the stroke will fold and leave artifacts on the corners if rendered with transparency. +// The stroke is positioned inside the rectangle. +void ImDrawList::_AddRectTinyRounding(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags) +{ + float screen_thickness = thickness * _InvFringeScale; + if (screen_thickness < 1.0f) IM_UNLIKELY + { + if (screen_thickness < 1.0f / 255.0f) IM_UNLIKELY + return; + col = ImAlphaMultiply(col, screen_thickness); + screen_thickness = 1.0f; + thickness = _FringeScale; + } + + flags |= Flags; + ImVec2 outer_uv, inner_uv; + float fringe; + _SelectLineTexture(screen_thickness, &outer_uv, &inner_uv, &fringe, flags); + + const int auto_seg_count = _CalcCircleAutoSegmentCount(rounding); + int arc_step, arc_step_count; + CalcCornerArcStepAndCount(auto_seg_count, arc_step, arc_step_count); + const int arc_point_count = arc_step_count + 1; + + int vtx_count = (2 + arc_point_count) * 4 + 3; + int idx_count = (4 + arc_point_count - 1) * 4 * 3; + + PrimReserve(idx_count, vtx_count); + ImDrawVert* start_vtx_ptr = _VtxWritePtr; + ImDrawIdx* start_idx_ptr = _IdxWritePtr; + + static const ImVec2 corner_offset[4] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} }; + static const ImDrawFlags corner_flags[4] = { ImDrawFlags_RoundTopLeft, ImDrawFlags_RoundTopRight, ImDrawFlags_RoundBottomRight, ImDrawFlags_RoundBottomLeft }; + const float half_fringe = fringe * 0.5f; + const ImVec2 corner_pos[4] = + { + ImVec2(p_min.x - half_fringe, p_min.y - half_fringe), + ImVec2(p_max.x + half_fringe, p_min.y - half_fringe), + ImVec2(p_max.x + half_fringe, p_max.y + half_fringe), + ImVec2(p_min.x - half_fringe, p_max.y + half_fringe) + }; + thickness += fringe; + rounding += half_fringe; + + const float stem_offset = ImMin(rounding, thickness); // The function might get called with rounding slightly bigger than thickness, which is ok, but we should keep the stem inside the shape. + const float ratio = stem_offset / thickness; + const ImVec2 stem_uv(outer_uv.x + (inner_uv.x - outer_uv.x) * ratio, outer_uv.y); + + // Previous vertices, copied from the last vertices. + int base_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(0, 0, inner_uv, col); + IM_APPEND_VTX(0, 0, stem_uv, col); + IM_APPEND_VTX(0, 0, outer_uv, col); + + for (int corner = 0; corner < 4; corner++) + { + const float outer_x = corner_pos[corner].x; + const float outer_y = corner_pos[corner].y; + const float stem_x = outer_x + corner_offset[corner].x * stem_offset; + const float stem_y = outer_y + corner_offset[corner].y * stem_offset; + const float inner_x = outer_x + corner_offset[corner].x * thickness; + const float inner_y = outer_y + corner_offset[corner].y * thickness; + const bool is_rounded = (flags & corner_flags[corner]); + + const int arc_idx = (int)_VtxCurrentIdx; + if (is_rounded) + { + const float center_x = outer_x + corner_offset[corner].x * rounding; + const float center_y = outer_y + corner_offset[corner].y * rounding; + int a = (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4) * corner; + for (int i = 0; i < arc_point_count; i++) + { + IM_APPEND_VTX(center_x - _Data->ArcFastVtx[a].x * rounding, center_y - _Data->ArcFastVtx[a].y * rounding, outer_uv, col); + a = (a + arc_step) % IM_DRAWLIST_ARCFAST_TABLE_SIZE; + } + } + else + { + IM_APPEND_VTX(outer_x, outer_y, outer_uv, col); + } + + const int stem_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(stem_x, stem_y, stem_uv, col); + const int inner_idx = (int)_VtxCurrentIdx; + IM_APPEND_VTX(inner_x, inner_y, inner_uv, col); + + // Arc + if (is_rounded) + for (int i = 0; i < arc_point_count - 1; i++) + { + IM_APPEND_TRI(stem_idx, arc_idx + i, arc_idx + i + 1); + } + + // Connect with previous + IM_APPEND_TRI(base_idx + 0, arc_idx, stem_idx); + IM_APPEND_TRI(base_idx + 0, stem_idx, base_idx + 1); + IM_APPEND_TRI(base_idx + 1, stem_idx, inner_idx); + IM_APPEND_TRI(base_idx + 1, inner_idx, base_idx + 2); + + base_idx = stem_idx - 1; + } + + // Close + start_vtx_ptr[0] = VtxBuffer.Data[_CmdHeader.VtxOffset + base_idx + 0]; + start_vtx_ptr[1] = VtxBuffer.Data[_CmdHeader.VtxOffset + base_idx + 1]; + start_vtx_ptr[2] = VtxBuffer.Data[_CmdHeader.VtxOffset + base_idx + 2]; + + const int idx_used = (int)(_IdxWritePtr - start_idx_ptr); + const int vtx_used = (int)(_VtxWritePtr - start_vtx_ptr); + IM_ASSERT_PARANOID(idx_used <= idx_count && vtx_used <= vtx_count); + if (idx_used < idx_count || vtx_used < vtx_count) + PrimUnreserve(idx_count - idx_used, vtx_count - vtx_used); +} + +// p_min = upper-left, p_max = lower-right +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags) +{ + // If this assert triggers on legacy code: + // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. + // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced. + // - 1.82.0 (2021/03): changed ImDrawCornerFlags to ImDrawFlags_RoundXXX values. + // If you used hard-coded 1 to 15 or ~0 in flags to configure corner rounding use the new flags! + // - Hard coded support for ~0 == ImDrawFlags_RoundAll. + // - Hard coded support for values 0x01 to 0x0F (matching 15 out of 16 old flags combinations) --> see FixRectCornerFlags() in <1.90 code. + // - Hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundNone or use 'float rounding = 0.0f'. + // See "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8. + IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values + + if ((col & IM_COL32_A_MASK) == 0) + return; + + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) IM_UNLIKELY + { + if (flags & ImDrawFlags_AALines) + PathRect(ImVec2(p_min.x + 0.50f, p_min.y + 0.50f), ImVec2(p_max.x - 0.50f, p_max.y - 0.50f), rounding, flags); + else + PathRect(ImVec2(p_min.x + 0.50f, p_min.y + 0.50f), ImVec2(p_max.x - 0.49f, p_max.y - 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | ImDrawFlags_StrokeCenter | (flags & ~ImDrawFlags_StrokeMask_)); + return; + } + + const bool has_rounding = IM_HAS_ROUNDING(rounding); + + // Calculate the outer boundary of the rectangle based on the stroke position. + ImVec2 outer_min = p_min; + ImVec2 outer_max = p_max; + float outer_rounding = rounding; + + float offset = 0.0f; // Inside + if (stroke_pos == ImDrawFlags_StrokeCenter) + offset = thickness * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + offset = _CalculateCenterBiasedOffset(thickness); + else if (stroke_pos == ImDrawFlags_StrokeOutside) + offset = thickness; + outer_min.x -= offset; + outer_min.y -= offset; + outer_max.x += offset; + outer_max.y += offset; + outer_rounding += has_rounding ? offset : 0.0f; + + const float width = outer_max.x - outer_min.x; + const float height = outer_max.y - outer_min.y; + const float half_min_dim = ImMin(width, height) * 0.5f; + if (half_min_dim <= thickness) IM_UNLIKELY + { + // Rectangle has collapsed into filled rectangle. + AddRectFilled(outer_min, outer_max, col, outer_rounding, flags); + return; + } + + if ((flags & ImDrawFlags_RoundMask_) == 0) + flags |= ImDrawFlags_RoundAll; + if (has_rounding) + { + // Constrain rounding to rect dimensions + outer_rounding = ImMin(outer_rounding, ImFabs(width) * (((flags & ImDrawFlags_RoundTop) == ImDrawFlags_RoundTop) || ((flags & ImDrawFlags_RoundBottom) == ImDrawFlags_RoundBottom) ? 0.5f : 1.0f) - 1.0f); + outer_rounding = ImMin(outer_rounding, ImFabs(height) * (((flags & ImDrawFlags_RoundLeft) == ImDrawFlags_RoundLeft) || ((flags & ImDrawFlags_RoundRight) == ImDrawFlags_RoundRight) ? 0.5f : 1.0f) - 1.0f); + } + + const bool is_truncated = IM_IS_TRUNCATED4(outer_min.x, outer_min.y, outer_max.x, outer_max.y) && IM_IS_TRUNCATED4(outer_rounding, thickness, 0.0f, 0.0f); //-V501 + if (_FringeScaleIsInteger && is_truncated) + { + int s_rounding = (int)(outer_rounding * _InvFringeScale); + int s_thickness = (int)(thickness * _InvFringeScale); + if (s_thickness <= 0) + return; + + if (s_rounding <= 0 || (flags & ImDrawFlags_RoundMask_) == ImDrawFlags_RoundNone) + { + // Pixel aligned non-rounded rect. + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + const float t = (float)s_thickness * _FringeScale; + + PrimReserve(8*3, 8); + const ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(outer_min.x, outer_min.y, opaque_uv, col); + IM_APPEND_VTX(outer_min.x + t, outer_min.y + t, opaque_uv, col); + IM_APPEND_VTX(outer_max.x, outer_min.y, opaque_uv, col); + IM_APPEND_VTX(outer_max.x - t, outer_min.y + t, opaque_uv, col); + IM_APPEND_VTX(outer_max.x, outer_max.y, opaque_uv, col); + IM_APPEND_VTX(outer_max.x - t, outer_max.y - t, opaque_uv, col); + IM_APPEND_VTX(outer_min.x, outer_max.y, opaque_uv, col); + IM_APPEND_VTX(outer_min.x + t, outer_max.y - t, opaque_uv, col); + + IM_APPEND_TRI(idx + 0, idx + 3, idx + 1); + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3); + + IM_APPEND_TRI(idx + 2, idx + 5, idx + 3); + IM_APPEND_TRI(idx + 2, idx + 4, idx + 5); + + IM_APPEND_TRI(idx + 4, idx + 7, idx + 5); + IM_APPEND_TRI(idx + 4, idx + 6, idx + 7); + + IM_APPEND_TRI(idx + 6, idx + 1, idx + 7); + IM_APPEND_TRI(idx + 6, idx + 0, idx + 1); + + return; + } + // Textured corners are baked with AA, do not use them if no-AA is requested. + const bool allow_tex_corners = (flags & (ImDrawFlags_AALines | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_AllowTexForRoundCorners_)) == (ImDrawFlags_AALines | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_AllowTexForRoundCorners_); + if (allow_tex_corners && s_thickness < IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX && s_rounding <= IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX) + { + // Pixel aligned rect with round corners rendered using baked textures. + IM_ASSERT_PARANOID(s_thickness > 0 && s_rounding > 0); + const int size = ImMax(s_rounding, s_thickness); // This is matching the baking calculations. + const int idx = (s_thickness * IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX) + s_rounding - 1; + IM_ASSERT_PARANOID((_Data->Font->OwnerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) == 0); + IM_ASSERT_PARANOID(idx >= 0 && idx < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX * IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX); + _AddRectBaked(outer_min, outer_max, col, (float)size * _FringeScale, (float)thickness, _Data->TexUvCorners[idx], flags); + return; + } + } + + if (!has_rounding || (flags & ImDrawFlags_RoundMask_) == ImDrawFlags_RoundNone) + { + const ImVec2 points[4] = { outer_min, ImVec2(outer_max.x, outer_min.y), outer_max, ImVec2(outer_min.x, outer_max.y) }; + _AddPolyline(points, 4, col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | ImDrawFlags_StrokeInside, half_min_dim); + _Path.Size = 0; + } + else + { + // Switch to specialized rendering a bit early to avoid overdraw visible in transparent shapes. + if (thickness + (0.75f * _FringeScale) > outer_rounding) + { + // Special case rendering to avoid rendering artifacts at the corners. + // If rendered using the regular polyline, the stroke will fold and leave artifacts on the corners if rendered with transparency. + _AddRectTinyRounding(outer_min, outer_max, col, outer_rounding, thickness, flags); + return; + } + const float rounding_tl = (flags & ImDrawFlags_RoundTopLeft) ? outer_rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundTopRight) ? outer_rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundBottomRight) ? outer_rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundBottomLeft) ? outer_rounding : 0.0f; + PathArcToFast(ImVec2(outer_min.x + rounding_tl, outer_min.y + rounding_tl), rounding_tl, 6, 9); + PathArcToFast(ImVec2(outer_max.x - rounding_tr, outer_min.y + rounding_tr), rounding_tr, 9, 12); + PathArcToFast(ImVec2(outer_max.x - rounding_br, outer_max.y - rounding_br), rounding_br, 0, 3); + PathArcToFast(ImVec2(outer_min.x + rounding_bl, outer_max.y - rounding_bl), rounding_bl, 3, 6); + + _AddPolyline(_Path.Data, _Path.Size, col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | ImDrawFlags_StrokeInside | (flags & ~ImDrawFlags_StrokeMask_), half_min_dim); + _Path.Size = 0; + } } -// p_min = upper-left, p_max = lower-right -// Note we don't render 1 pixels sized rectangles properly. -void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags) +void ImDrawList::_AddRectFilledBaked(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float r, const ImVec4& tex_uvs, ImDrawFlags flags) { - // If this assert triggers on legacy code: - // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. - // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced. - // - 1.82.0 (2021/03): changed ImDrawCornerFlags to ImDrawFlags_RoundCornersXXX values. - // If you used hard-coded 1 to 15 or ~0 in flags to configure corner rounding use the new flags! - // - Hard coded support for ~0 == ImDrawFlags_RoundCornersAll. - // - Hard coded support for values 0x01 to 0x0F (matching 15 out of 16 old flags combinations) --> see FixRectCornerFlags() in <1.90 code. - // - Hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'. - // See "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8. - IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values + // 9-slice with corner mirroring + const ImVec2 uv_tl(tex_uvs.x, tex_uvs.y); + const ImVec2 uv_tr(tex_uvs.z, tex_uvs.y); + const ImVec2 uv_br(tex_uvs.z, tex_uvs.w); + const ImVec2 uv_bl(tex_uvs.x, tex_uvs.w); - if ((col & IM_COL32_A_MASK) == 0) - return; - if (Flags & ImDrawListFlags_AntiAliasedLines) - PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags); - else - PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. - PathStroke(col, thickness, ImDrawFlags_Closed); + PrimReserve(9 * 2 * 3, 4 * 4); + + const float r_tl = (flags & ImDrawFlags_RoundTopLeft) ? r : 0.0f; + const float r_tr = (flags & ImDrawFlags_RoundTopRight) ? r : 0.0f; + const float r_br = (flags & ImDrawFlags_RoundBottomRight) ? r : 0.0f; + const float r_bl = (flags & ImDrawFlags_RoundBottomLeft) ? r : 0.0f; + + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + IM_APPEND_VTX(p_min.x, p_min.y, uv_tl, col); + IM_APPEND_VTX(p_min.x + r_tl, p_min.y, uv_tr, col); + IM_APPEND_VTX(p_max.x - r_tr, p_min.y, uv_tr, col); + IM_APPEND_VTX(p_max.x, p_min.y, uv_tl, col); + + IM_APPEND_VTX(p_min.x, p_min.y + r_tl, uv_bl, col); + IM_APPEND_VTX(p_min.x + r_tl, p_min.y + r_tl, uv_br, col); + IM_APPEND_VTX(p_max.x - r_tr, p_min.y + r_tr, uv_br, col); + IM_APPEND_VTX(p_max.x, p_min.y + r_tr, uv_bl, col); + + IM_APPEND_VTX(p_min.x, p_max.y - r_bl, uv_bl, col); + IM_APPEND_VTX(p_min.x + r_bl, p_max.y - r_bl, uv_br, col); + IM_APPEND_VTX(p_max.x - r_br, p_max.y - r_br, uv_br, col); + IM_APPEND_VTX(p_max.x, p_max.y - r_br, uv_bl, col); + + IM_APPEND_VTX(p_min.x, p_max.y, uv_tl, col); + IM_APPEND_VTX(p_min.x + r_bl, p_max.y, uv_tr, col); + IM_APPEND_VTX(p_max.x - r_br, p_max.y, uv_tr, col); + IM_APPEND_VTX(p_max.x, p_max.y, uv_tl, col); + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + IM_APPEND_TRI(idx + 4, idx + 0, idx + 1); + IM_APPEND_TRI(idx + 4, idx + 1, idx + 5); + idx++; + } + idx++; + } } void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + + float width = p_max.x - p_min.x; + float height = p_max.y - p_min.y; + const float min_dim = ImMin(width, height); + flags |= Flags; + + if ((flags & ImDrawFlags_StrokeMask_) == ImDrawFlags_StrokeLegacy && rounding < 0.5f) IM_UNLIKELY { PrimReserve(6, 4); PrimRect(p_min, p_max, col); + return; + } + + // The rect is smaller than pixel in one dimension. + if (min_dim < _FringeScale) IM_UNLIKELY + { + if (min_dim < (1.0f / 255.0f) * _FringeScale) IM_UNLIKELY + return; + if (width < _FringeScale) + { + col = ImAlphaMultiply(col, width * _InvFringeScale); + width = _FringeScale; + } + if (height < _FringeScale) + { + col = ImAlphaMultiply(col, height * _InvFringeScale); + height = _FringeScale; + } + const ImVec2 points[4] = { p_min, ImVec2(p_min.x + width, p_min.y), ImVec2(p_min.x + width, p_min.y + height), ImVec2(p_min.x, p_min.y + height) }; + AddConvexPolyFilled(points, 4, col, ImDrawFlags_JoinMiter); + return; + } + + // When rounding non-integer and under threshold, has_rounding may be false but still affect is_truncated. Likely not worth catering for. + const bool has_rounding = (flags & ImDrawFlags_RoundMask_) != ImDrawFlags_RoundNone && IM_HAS_ROUNDING(rounding); + const bool is_truncated = IM_IS_TRUNCATED4(p_min.x, p_min.y, p_max.x, p_max.y) && IM_IS_TRUNCATED(rounding); + + if (_FringeScaleIsInteger && is_truncated) + { + // Fast path for the non-AA non-rounded rect. + if (!has_rounding) + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + return; + } + + if ((flags & ImDrawFlags_RoundMask_) == 0) + flags |= ImDrawFlags_RoundAll; + + rounding = ImMin(rounding, ImFabs(width) * (((flags & ImDrawFlags_RoundTop) == ImDrawFlags_RoundTop) || ((flags & ImDrawFlags_RoundBottom) == ImDrawFlags_RoundBottom) ? 0.5f : 1.0f) - 1.0f); + rounding = ImMin(rounding, ImFabs(height) * (((flags & ImDrawFlags_RoundLeft) == ImDrawFlags_RoundLeft) || ((flags & ImDrawFlags_RoundRight) == ImDrawFlags_RoundRight) ? 0.5f : 1.0f) - 1.0f); + + const int s_rounding = (int)(rounding * _InvFringeScale); + if (s_rounding <= 0) + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + return; + } + // Textured corners are baked with AA, do not use them if no-AA is requested. + const bool allow_tex_corners = (flags & (ImDrawFlags_AAFill | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_AllowTexForRoundCorners_)) == (ImDrawFlags_AAFill | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_AllowTexForRoundCorners_); + if (allow_tex_corners && s_rounding <= IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX) + { + IM_ASSERT_PARANOID(!(_Data->Font->OwnerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners)); + // This is matching the baking calculations. The rounding clamping above makes sure that there's enough space for the extra pixel. + const int corner_size = s_rounding + 1; + // Check that the baked corners do not overlap (this could be made more accurate if tested for x and y separately). + if ((float)corner_size * 2.0f * _FringeScale < min_dim) + { + const int idx = (s_rounding - 1); + IM_ASSERT_PARANOID(idx >= 0 && idx < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX); + _AddRectFilledBaked(p_min, p_max, col, (float)corner_size * _FringeScale, _Data->TexUvCorners[idx], flags); + return; + } + } + } + + if (!has_rounding) + { + const ImVec2 points[4] = { p_min, ImVec2(p_max.x, p_min.y), p_max, ImVec2(p_min.x, p_max.y) }; + AddConvexPolyFilled(points, 4, col, ImDrawFlags_JoinMiter); } else { PathRect(p_min, p_max, rounding, flags); - PathFillConvex(col); + PathFillConvex(col, ImDrawFlags_JoinMiter); } } // p_min = upper-left, p_max = lower-right +// Note: this does not support anti-aliasing when provided non-integer vertices. void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) { if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) @@ -1555,16 +2643,17 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_ma PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); } -void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) +void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - PathLineTo(p1); - PathLineTo(p2); - PathLineTo(p3); - PathLineTo(p4); - PathStroke(col, thickness, ImDrawFlags_Closed); + //flags |= Flags; // Not needed. + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + flags = (flags & ~ImDrawFlags_StrokeMask_) | stroke_pos; // As AddPolyline() default is different + + const ImVec2 points[4] = { p1, p2, p3, p4 }; + _AddPolyline(points, 4, col, thickness, flags | ImDrawFlags_Closed, FLT_MAX); } void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) @@ -1572,22 +2661,21 @@ void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& if ((col & IM_COL32_A_MASK) == 0) return; - PathLineTo(p1); - PathLineTo(p2); - PathLineTo(p3); - PathLineTo(p4); - PathFillConvex(col); + const ImVec2 points[4] = { p1, p2, p3, p4 }; + AddConvexPolyFilled(points, 4, col); } -void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) +void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; - PathLineTo(p1); - PathLineTo(p2); - PathLineTo(p3); - PathStroke(col, thickness, ImDrawFlags_Closed); + //flags |= Flags; // Not needed. + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + flags = (flags & ~ImDrawFlags_StrokeMask_) | stroke_pos; // As AddPolyline() default is different + + const ImVec2 points[3] = { p1, p2, p3 }; + _AddPolyline(points, 3, col, thickness, flags | ImDrawFlags_Closed, FLT_MAX); } void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) @@ -1595,42 +2683,95 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV if ((col & IM_COL32_A_MASK) == 0) return; - PathLineTo(p1); - PathLineTo(p2); - PathLineTo(p3); - PathFillConvex(col); + const ImVec2 points[3] = { p1, p2, p3 }; + AddConvexPolyFilled(points, 3, col); +} + +static float ApproxApothem(int num_segments) +{ + // Calculates approximation (within 0.001%) distance from the center of the circumscribed circle to the edge of the polygon, cos(pi / n) + IM_ASSERT_PARANOID(num_segments >= 3); + const float u = 1.0f / num_segments; + return ((4.058712f * u * u) - 4.934802f) * u * u + 1.0f; } -void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness, ImDrawFlags flags) { - if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + if ((col & IM_COL32_A_MASK) == 0) return; - if (num_segments <= 0) + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) IM_UNLIKELY + { + radius -= 0.5f; + stroke_pos = ImDrawFlags_StrokeCenter; + } + radius = ImMax(0.01f, radius); + + float outer_radius = radius; + if (stroke_pos == ImDrawFlags_StrokeCenter) + outer_radius = radius + thickness * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + outer_radius = radius + _CalculateCenterBiasedOffset(thickness); + else if (stroke_pos == ImDrawFlags_StrokeInside) + outer_radius = radius; + else if (stroke_pos == ImDrawFlags_StrokeOutside) + outer_radius = radius + thickness; + + if (outer_radius <= thickness) IM_UNLIKELY + { + // The circle has collapsed into a filled circle. + AddCircleFilled(center, outer_radius, col, num_segments); + return; + } + + if (num_segments <= 0 && outer_radius <= _Data->ArcFastRadiusCutoff) { // Use arc with automatic segment count - _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + const int a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(outer_radius); // Use outer_radius for segment count to be consistent with rounded rect. + _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, a_step); _Path.Size--; } else { - // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + // Explicit segment count or above fast arc cutoff (still clamp to avoid drawing insanely tessellated shapes) + if (num_segments <= 0) + num_segments = _CalcCircleAutoSegmentCount(outer_radius); num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; - PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); } - PathStroke(col, thickness, ImDrawFlags_Closed); + if (_Path.Size >= 3) + { + // Calculate distance to the edge of the polygon describing the circle. + // This will be used by _AddPolyline() to clamp the inner stroke expansion, to avoid creating rendering artifacts. + const float unit_apothem = ApproxApothem(_Path.Size); + const float edge_dist = radius * unit_apothem; + _AddPolyline(_Path.Data, _Path.Size, col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | stroke_pos, edge_dist); + } + _Path.Size = 0; } void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) { - if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + if ((col & IM_COL32_A_MASK) == 0) return; - if (num_segments <= 0) + // Minimum radius, before the edge-AA will overlap. + const float min_radius = _FringeScale * 1.41421356f * 0.5f; + if (radius < min_radius) IM_UNLIKELY + { + if (radius < (1.0f / 255.0f) * min_radius) + return; + col = ImAlphaMultiply(col, radius / min_radius); + radius = min_radius; + } + + if (num_segments <= 0 && radius <= _Data->ArcFastRadiusCutoff) { // Use arc with automatic segment count _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); @@ -1638,7 +2779,9 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, } else { - // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + // Explicit segment count or above cutoff (still clamp to avoid drawing insanely tessellated shapes) + if (num_segments <= 0) + num_segments = _CalcCircleAutoSegmentCount(radius); num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); // Because we are filling a closed shape we remove 1 from the count of segments/points @@ -1646,19 +2789,54 @@ void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); } - PathFillConvex(col); + PathFillConvex(col, ImDrawFlags_JoinMiter); } // Guaranteed to honor 'num_segments' -void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; - // Because we are filling a closed shape we remove 1 from the count of segments/points + flags |= Flags; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) IM_UNLIKELY + { + radius -= 0.5f; + stroke_pos = ImDrawFlags_StrokeCenter; + } + radius = ImMax(0.01f, radius); + + // Calculate distance to the edge of the polygon describing the circle. + // This will be used by _AddPolyline() to clamp the inner stroke expansion, to avoid creating rendering artifacts. + const float unit_apothem = ApproxApothem(num_segments); + const float edge_dist = radius * unit_apothem; + + // Check overestimate first before testing details. + if (radius < thickness * 2.0f) + { + float outer_radius = radius; + if (stroke_pos == ImDrawFlags_StrokeCenter) + outer_radius = radius + thickness * 0.5f; + else if (stroke_pos == ImDrawFlags_StrokeCenterBiased) + outer_radius = radius + _CalculateCenterBiasedOffset(thickness); + else if (stroke_pos == ImDrawFlags_StrokeInside) + outer_radius = radius; + else if (stroke_pos == ImDrawFlags_StrokeOutside) + outer_radius = radius + thickness; + if (outer_radius * unit_apothem <= thickness) IM_UNLIKELY + { + // The polygon has collapsed into a filled polygon. + AddNgonFilled(center, outer_radius, col, num_segments); + return; + } + } + + // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; - PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); - PathStroke(col, thickness, ImDrawFlags_Closed); + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + _AddPolyline(_Path.Data, _Path.Size, col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | stroke_pos, edge_dist); + _Path.Size = 0; } // Guaranteed to honor 'num_segments' @@ -1667,25 +2845,48 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; + const float diameter = radius * 2.0f; + if (diameter < _FringeScale) IM_UNLIKELY + { + if (diameter < (1.0f / 255.0f) * _FringeScale) IM_UNLIKELY + return; + col = ImAlphaMultiply(col, diameter * _InvFringeScale); + radius = _FringeScale * 0.5f; + } + // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); - PathFillConvex(col); + PathFillConvex(col, ImDrawFlags_JoinMiter); } // Ellipse -void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness) +void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; + ImDrawFlags stroke_pos = _GetStrokePos(flags, ImDrawFlags_StrokeInside); + if (stroke_pos == ImDrawFlags_StrokeLegacy) + stroke_pos = ImDrawFlags_StrokeCenter; + + ImVec2 rad = radius; + rad.x = ImMax(0.01f, rad.x); + rad.y = ImMax(0.01f, rad.y); + if (num_segments <= 0) - num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. + num_segments = _CalcCircleAutoSegmentCount(ImMax(rad.x, rad.y)); // A bit pessimistic, maybe there's a better computation to do here. + + _Path.reserve(_Path.Size + (num_segments + 1)); // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments; - PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1); - PathStroke(col, thickness, ImDrawFlags_Closed); + PathEllipticalArcTo(center, rad, rot, 0.0f, a_max, num_segments - 1); + + // Prevent the inside part of the stroke to be expanded too much to prevent some rendering artifacts. + const float max_inner_offset = ImMin(rad.x, rad.y); + _AddPolyline(_Path.Data, _Path.Size, col, thickness, ImDrawFlags_Closed | ImDrawFlags_JoinMiter | stroke_pos, max_inner_offset); + _Path.Size = 0; } void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments) @@ -1693,6 +2894,28 @@ void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, Im if ((col & IM_COL32_A_MASK) == 0) return; + ImVec2 rad = radius; + float diameter_x = rad.x * 2.0f; + float diameter_y = rad.y * 2.0f; + const float min_dim = ImMin(diameter_x, diameter_y); + + // The ellipse is smaller than pixel in one dimension. + if (min_dim < _FringeScale) IM_UNLIKELY + { + if (min_dim < (1.0f / 255.0f) * _FringeScale) IM_UNLIKELY + return; + if (diameter_x < _FringeScale) + { + col = ImAlphaMultiply(col, diameter_x * _InvFringeScale); + rad.x = _FringeScale * 0.5f; + } + if (diameter_y < _FringeScale) + { + col = ImAlphaMultiply(col, diameter_y * _InvFringeScale); + rad.y = _FringeScale * 0.5f; + } + } + if (num_segments <= 0) num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here. @@ -1703,25 +2926,25 @@ void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, Im } // Cubic Bezier takes 4 controls points -void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) +void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(p1); PathBezierCubicCurveTo(p2, p3, p4, num_segments); - PathStroke(col, thickness); + PathStroke(col, thickness, flags); } // Quadratic Bezier takes 3 controls points -void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments) +void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(p1); PathBezierQuadraticCurveTo(p2, p3, num_segments); - PathStroke(col, thickness); + PathStroke(col, thickness, flags); } void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) @@ -1794,10 +3017,10 @@ void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, cons return; IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); // If this assert triggers on legacy code: see comments in ImDrawList::PathRect(). - if ((flags & ImDrawFlags_RoundCornersMask_) == 0) - flags |= ImDrawFlags_RoundCornersAll; + if ((flags & ImDrawFlags_RoundMask_) == 0) + flags |= ImDrawFlags_RoundAll; - if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + if (rounding < 0.5f || (flags & ImDrawFlags_RoundMask_) == ImDrawFlags_RoundNone) { AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col); return; @@ -1809,7 +3032,7 @@ void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, cons int vert_start_idx = VtxBuffer.Size; PathRect(p_min, p_max, rounding, flags); - PathFillConvex(col); + PathFillConvex(col, ImDrawFlags_JoinMiter); int vert_end_idx = VtxBuffer.Size; ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); @@ -2046,7 +3269,7 @@ void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_cou const ImVec2 uv = _Data->TexUvWhitePixel; ImTriangulator triangulator; unsigned int triangle[3]; - if (Flags & ImDrawListFlags_AntiAliasedFill) + if (Flags & ImDrawFlags_AAFill) { // Anti-aliased Fill const float AA_SIZE = _FringeScale; @@ -2303,7 +3526,7 @@ void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector // May trigger for you if you are using PrimXXX functions incorrectly. IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); - if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) + if (!(draw_list->Flags & ImDrawFlags_UseVtxOffset)) IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) @@ -3114,7 +4337,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } if (font_cfg->FontLoader != NULL) { - IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); + IM_ASSERT(font_cfg->FontLoader->FontSrcGetGlyphIndexFromCodepoint != NULL && font_cfg->FontLoader->FontBakedLoadGlyph != NULL); IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet. } // | Target w/ Implicit RefSize | Target w/ Explicit RefSize | @@ -3168,11 +4391,15 @@ const char* ImGui_GetDefaultCompressedFontDataProggyForever(int* out_size); // This duplicates some of the logic in UpdateFontsNewFrame() which is a bit chicken-and-eggy/tricky to extract due to variety of codepaths and possible initialization ordering. static float GetExpectedContextFontSize(ImGuiContext* ctx) { - return ((ctx->Style.FontSizeBase > 0.0f) ? ctx->Style.FontSizeBase : 13.0f) * ctx->Style.FontScaleMain * ctx->Style.FontScaleDpi; + float fb_scale = (ctx->IO.DisplayFramebufferScale.x != 0.0f) ? ctx->IO.DisplayFramebufferScale.x : 1.0f; + if (ctx->IO.DisplayFramebufferScale.x == 1.0f && ctx->IO.DisplaySize.x <= 0.0f && ctx->IO.ConfigMacOSXBehaviors) + fb_scale = 2.0f; // If called before backend had a chance to init DisplayFramebufferScale. default to expecting Retina. + float scale = ctx->Style.FontScaleMain * ctx->Style.FontScaleDpi * fb_scale; + return ((ctx->Style.FontSizeBase > 0.0f) ? ctx->Style.FontSizeBase : 13.0f) * scale; } // Legacy function with heuristic to select Pixel or Vector font. -// The selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold at the time of adding the default font. +// The selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi * io.DisplayFramebufferScale) reaching a small threshold at the time of adding the default font. // Prefer calling AddFontDefaultVector() or AddFontDefaultBitmap() based on your own logic. ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg) { @@ -3625,6 +4852,196 @@ static void ImFontAtlasBuildUpdateTexDataBasic(ImFontAtlas* atlas) atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); } + +#define IM_DRAWLIST_CORNER_POINTS_MAX (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4 + 3) // Max number of points in corner profiles + +static int InitCornerGeometry(float cx, float cy, float rounding, float circle_segment_max_error, ImVec2* line_normals, float* line_distances) +{ + // This tries to quite faithfully replicate how we render the corners using tessellation. + // Older code sampled a circle SDF directly, but it had clearly visible discrepancy between the baked corners + // and tessellated corners due to circle_segment_max_error. + + const int auto_seg_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(rounding, circle_segment_max_error); + int arc_step, arc_step_count; + CalcCornerArcStepAndCount(auto_seg_count, arc_step, arc_step_count); + const int arc_point_count = arc_step_count + 1; + + // Build arc of points, with straight segments at each end. + // . [n-2]..[n-1] + // .` + // . + // [1] x (cx,cy) + // : + // [0] + ImVec2 points[IM_DRAWLIST_CORNER_POINTS_MAX]; + int num_points = 0; + + points[num_points++] = ImVec2(cx - rounding, cy + 1.0f); + + float da = ((float)arc_step / (float)IM_DRAWLIST_ARCFAST_TABLE_SIZE) * IM_PI * 2.0f; + float a = IM_PI; + for (int i = 0; i < arc_point_count; i++) + { + float dx = cosf(a); + float dy = sinf(a); + points[num_points++] = ImVec2(cx + dx * rounding, cy + dy * rounding); + a += da; + } + + points[num_points++] = ImVec2(cx + 1.0f, cy - rounding); + + // Turn segments to half spaces. + for (int i = 0; i < num_points - 1; i++) + { + const ImVec2 diff = points[i + 1] - points[i]; + const float d2 = diff.x * diff.x + diff.y * diff.y; + const float inv_d = ImRsqrtPrecise(d2); + line_normals[i].x = diff.y * inv_d; // Normal points outwards + line_normals[i].y = -diff.x * inv_d; + line_distances[i] = -ImDot(points[i], line_normals[i]); + } + + return num_points - 1; +} + +// Returns distance to convex shape limited by lines. +static float SampleConvex(float x, float y, const ImVec2* line_normals, const float* line_distances, int num_lines) +{ + float result = -FLT_MAX; + for (int i = 0; i < num_lines; i++) + { + const float d = line_normals[i].x * x + line_normals[i].y * y + line_distances[i]; + if (d > result) + result = d; + } + return result; +} + +static ImU8 SampleCornerFillOrStroke(float x, float y, float thickness, const ImVec2* line_normals, const float* line_distances, int num_lines) +{ + const float d = SampleConvex(x, y, line_normals, line_distances, num_lines); + const float aa_width = 1.0f; + if (thickness == 0.0f) + { + // Fill + return (ImU8)(ImClamp(1.0f - (d + aa_width * 0.5f) / aa_width, 0.0f, 1.0f) * 255.0f); + } + else + { + // Stroke + const float outer = 1.0f - (d + aa_width * 0.5f) / aa_width; + const float inner = (d + thickness + aa_width * 0.5f) / aa_width; + return (ImU8)(ImClamp(ImMin(inner, outer), 0.0f, 1.0f) * 255.0f); + } +} + +#if 0 // Set to 1 to visualize coverage of textured corners +#define DEBUG_TEX_CORNER_U8(_LX, _H) ((_LX & 1) ? 255 : 0) +#define DEBUG_TEX_CORNER_U32(_LX, _H) IM_COL32((_LX & 1) ? 255: 0, 0, 0, (_LX & 1) ? 200 : 0) +#else +#define DEBUG_TEX_CORNER_U8(_LX, _H) 0xFF +#define DEBUG_TEX_CORNER_U32(_LX, _H) 0xFFFFFFFF +#endif + +static void ImFontAtlasBuildUpdateTexDataCorners(ImFontAtlas* atlas) +{ + if (atlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) + return; + + // Pack and store identifier so we can refresh UV coordinates on texture resize. + ImTextureData* tex = atlas->TexData; + ImFontAtlasBuilder* builder = atlas->Builder; + + // FIXME-TEXCORNERS: Ideally we should pick up the max error from the styles, but it does not seem be to set by the time we build the data the first time. + float circle_segment_max_error = 0.30f; // Default matching ImGuiStyle::CircleTessellationMaxError. + // if (atlas->OwnerContext) + // circle_segment_max_error = atlas->OwnerContext->DrawListSharedData.CircleSegmentMaxError; + + // Calculate size and pack + ImFontAtlasRect r; + bool add_and_draw = atlas->GetCustomRect(builder->PackIdCornersTexData, &r) == false; + if (add_and_draw) + { + // (thickness 0 for filled, thickness >0 for strokes) + ImVec2i pack_size(0, 0); + for (int thickness = 0; thickness < IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX; thickness++) + { + const bool is_filled = (thickness == 0); + int row_width = 0; + int row_height = 0; + for (int n = 0; n < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX; n++) + { + const int rounding = n + 1; + const int size = (is_filled ? (rounding + 1) : ImMax(rounding, thickness)); + row_width += size + 2; + row_height = ImMax(row_height, size + 2); + } + pack_size.x = ImMax(pack_size.x, row_width); + pack_size.y += row_height; + } + builder->PackIdCornersTexData = atlas->AddCustomRect(pack_size.x, pack_size.y, &r); + IM_ASSERT(builder->PackIdCornersTexData != ImFontAtlasRectId_Invalid); + } + + // Render + int y = r.y; + ImVec2 line_normals[IM_DRAWLIST_CORNER_POINTS_MAX]; + float line_distances[IM_DRAWLIST_CORNER_POINTS_MAX]; + for (int thickness = 0; thickness < IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX; thickness++) + { + const bool is_filled = (thickness == 0); + int x = r.x; + int row_height = 0; + for (int n = 0; n < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX; n++) + { + // Filled: Always add 1px to the fill side of the rounded corner to prevent the corner AA to bleed into the rectangle edges. + const int rounding = n + 1; + const int size = (is_filled ? (rounding + 1) : ImMax(rounding, thickness)); + const int w = size + 2; + const int h = size + 2; + + // Corner circle + const float cx = 1.0f + (float)(n + 1); + const float cy = 1.0f + (float)(n + 1); + IM_ASSERT((x + w) <= (r.x + r.w) && (y + h) <= (r.y + r.h)); // Make sure we're inside the texture bounds + const int num_lines = InitCornerGeometry(cx, cy, (float)rounding, circle_segment_max_error, line_normals, line_distances); + + // Write each slice + if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) + { + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(x, y); + const int pitch = tex->Width; + for (int ly = 0; ly < h; ly++) + { + for (int lx = 0; lx < w; lx++) + write_ptr[lx] = SampleCornerFillOrStroke((float)lx + 0.5f, (float)ly + 0.5f, (float)thickness, line_normals, line_distances, num_lines) & DEBUG_TEX_CORNER_U8(lx, h); + write_ptr += pitch; + } + } + else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) + { + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(x, y); + const int pitch = tex->Width; + for (int ly = 0; ly < h; ly++) + { + for (int lx = 0; lx < w; lx++) + write_ptr[lx] = IM_COL32(255, 255, 255, SampleCornerFillOrStroke((float)lx + 0.5f, (float)ly + 0.5f, (float)thickness, line_normals, line_distances, num_lines)) & DEBUG_TEX_CORNER_U32(lx, h); + write_ptr += pitch; + } + } + + // Refresh UV coordinates + ImVec2 uv0 = ImVec2((float)(x + 1), (float)(y + 1)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(x + 1 + size), (float)(y + 1 + size)) * atlas->TexUvScale; + builder->TexUvCorners[n + thickness * IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX] = ImVec4(uv0.x, uv0.y, uv1.x, uv1.y); + + x += w; + row_height = ImMax(row_height, h); + } + y += row_height; + } +} + static void ImFontAtlasBuildUpdateTexDataLines(ImFontAtlas* atlas) { if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) @@ -3638,54 +5055,116 @@ static void ImFontAtlasBuildUpdateTexDataLines(ImFontAtlas* atlas) bool add_and_draw = atlas->GetCustomRect(builder->PackIdLinesTexData, &r) == false; if (add_and_draw) { - ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + // Register texture region for thick lines + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row + ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1 + IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT); builder->PackIdLinesTexData = atlas->AddCustomRect(pack_size.x, pack_size.y, &r); IM_ASSERT(builder->PackIdLinesTexData != ImFontAtlasRectId_Invalid); } - // Register texture region for thick lines - // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row - // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them - for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { - // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle - const int y = n; - const int line_width = n; - const int pad_left = (r.w - line_width) / 2; - const int pad_right = r.w - (pad_left + line_width); - IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels - - // Write each slice - if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) + // FIXME: Lines 0 to IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH(4) are currently never used and could be ditched, saving DETAILED_WIDTH*WIDTH_MAX + for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { - ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = 0x00; - - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = 0xFF; + // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle + const int y = n; + const int line_width = n; + const int pad_left = (r.w - line_width) / 2; + const int pad_right = r.w - (pad_left + line_width); + IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels + + // Write each slice + if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) + { + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) + { + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); + } - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = 0x00; + // Refresh UV coordinates + ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 0.5f), (float)(r.y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 0.5f), (float)(r.y + y + 1)) * atlas->TexUvScale; + float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + // Store inverse of the line-width (thickness) to the w component so that we can avoid division when selecting texture. + float inv_line_width = (line_width > 0) ? (1.0f / (float)line_width) : 0.0f; + builder->TexUvLines[n] = ImVec4(uv0.x, uv1.x, half_v, inv_line_width); } - else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) - { - ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + } - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = IM_COL32_WHITE; + { + // Calculate super sampled line textures for smaller line widths to make transition between sizes smoother. - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); - } + // Calculate ramp used for all the textures. + ImU8 ramp[IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT]; + for (int n = 0; n < IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT; n++) + ramp[n] = (ImU8)(((float)n / IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT) * 255.0f); + + for (int n = 0; n < IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT; n++) + { + const int y = IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1 + n; + // For integer thickness lines the one pixel line texture looks like this: + // [ 0 | 1 | 0 ] + // :...........: + // Since the texture samples are at the center of the texel, we only use range above. + // The result after bilinear filtering is a triangle across the used uv range. + // + // To super 2x sample that signal, we end up with following texture: + // [ 0 | .5 | 1 | .5 | 0 ] + // :.......................: + // One might think that there should be 2 opaque pixels in the middle section, but no since we're super sampling the triangle signal. + const int line_width = 1 + n; + IM_ASSERT(IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT + line_width + IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT <= r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels + + // Write each slice + if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) + { + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); + int idx = 0; + for (int i = 0; i < IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT; i++) + write_ptr[idx++] = ramp[i]; + for (int i = 0; i < line_width; i++) + write_ptr[idx++] = 0xFF; + for (int i = IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT - 1; i >= 0; i--) + write_ptr[idx++] = ramp[i]; + while (idx < r.w) + write_ptr[idx++] = 0x0; + } + else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) + { + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); + int idx = 0; + for (int i = 0; i < IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT; i++) + write_ptr[idx++] = IM_COL32(255, 255, 255, ramp[i]); + for (int i = 0; i < line_width; i++) + write_ptr[idx++] = IM_COL32(255, 255, 255, 255); + for (int i = IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT - 1; i >= 0; i--) + write_ptr[idx++] = IM_COL32(255, 255, 255, ramp[i]); + while (idx < r.w) + write_ptr[idx++] = IM_COL32(255, 255, 255, 0); + } - // Refresh UV coordinates - ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale; - ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale; - float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts - atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); + // Refresh UV coordinates + ImVec2 uv0 = ImVec2((float)(r.x + 0.5f), (float)(r.y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r.x - 0.5f + IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT * 2 + line_width), (float)(r.y + y + 1)) * atlas->TexUvScale; + float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + // Store inverse of the line-width (thickness) to the w component so that we can avoid division when selecting texture. + float inv_line_width = 1.0f / (1.0f + (float)n / (float)IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT); + builder->TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1 + n] = ImVec4(uv0.x, uv1.x, half_v, inv_line_width); + } } } @@ -4059,7 +5538,8 @@ void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) if (shared_data->FontAtlas == atlas) { shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; - shared_data->TexUvLines = atlas->TexUvLines; + shared_data->TexUvLines = atlas->Builder->TexUvLines; + shared_data->TexUvCorners = atlas->Builder->TexUvCorners; } } @@ -4078,6 +5558,7 @@ static void ImFontAtlasBuildUpdateTexData(ImFontAtlas* atlas) { ImFontAtlasBuildUpdateTexDataBasic(atlas); ImFontAtlasBuildUpdateTexDataLines(atlas); + ImFontAtlasBuildUpdateTexDataCorners(atlas); } // Create a new texture, discard previous one @@ -4549,11 +6030,46 @@ static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); } -static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) +// Remap a codepoint to another codepoint +void ImFont::AddRemapCodepoint(ImWchar from_codepoint, ImWchar to_codepoint) +{ + ImU32 data = (ImU32)to_codepoint; + IM_ASSERT((data & (1u << 31)) == 0); + RemapPairs.SetInt((ImGuiID)from_codepoint, (int)data); +} + +static const int IMFONT_REMAPVALUE_GLYPHIDX_SHIFT = 0; +static const int IMFONT_REMAPVALUE_GLYPHIDX_MASK = 0xFFFF; +static const int IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT = 16; +static const int IMFONT_REMAPVALUE_FONTSRCIDX_MASK = 0xFF0000; + +// Remap a codepoint to a raw glyph index inside the font. Allows accessing glyphs which are not mapped to codepoints. (#9559) +// font_src_idx = index in font->Sources[], or -1 for last added source. +// glyph_idx = index in TTF or OTF file. +void ImFont::AddRemapCodepointToGlyphIndex(ImWchar from_codepoint, int font_src_idx, int glyph_idx) +{ + if (font_src_idx == -1) + font_src_idx = Sources.Size - 1; + IM_ASSERT(font_src_idx >= 0 && font_src_idx < Sources.Size && ((font_src_idx << IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT) & ~IMFONT_REMAPVALUE_FONTSRCIDX_MASK) == 0); + IM_ASSERT(glyph_idx >= 0 && ((glyph_idx << IMFONT_REMAPVALUE_GLYPHIDX_SHIFT) & ~IMFONT_REMAPVALUE_GLYPHIDX_MASK) == 0); + ImU32 data = ((ImU32)glyph_idx << IMFONT_REMAPVALUE_GLYPHIDX_SHIFT) | (font_src_idx << IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT) | (1u << 31); + RemapPairs.SetInt((ImGuiID)from_codepoint, (int)data); +} + +static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint, ImWchar* out_codepoint, int* out_font_src_idx, int* out_glyph_idx) { IM_UNUSED(atlas); - if (font->RemapPairs.Data.Size != 0) - *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c); + if (font->RemapPairs.Data.Size == 0) + return; + ImU32 data = (ImU32)font->RemapPairs.GetInt((ImGuiID)codepoint, (int)codepoint); + if (data & (1u << 31)) + { + *out_codepoint = (ImWchar)-1; + *out_font_src_idx = (data & IMFONT_REMAPVALUE_FONTSRCIDX_MASK) >> IMFONT_REMAPVALUE_FONTSRCIDX_SHIFT; + *out_glyph_idx = (data & IMFONT_REMAPVALUE_GLYPHIDX_MASK) >> IMFONT_REMAPVALUE_GLYPHIDX_SHIFT; + return; + } + *out_codepoint = (ImWchar)data; } static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint, float* only_load_advance_x) @@ -4570,7 +6086,8 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // User remapping hooks ImWchar src_codepoint = codepoint; - ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint); + int src_font_idx = -1, src_glyph_idx = -1; + ImFontAtlas_FontHookRemapCodepoint(atlas, font, codepoint, &src_codepoint, &src_font_idx, &src_glyph_idx); //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); @@ -4583,35 +6100,47 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // Call backend char* loader_user_data_p = (char*)baked->FontLoaderDatas; - int src_n = 0; - for (ImFontConfig* src : font->Sources) + char* loader_user_data_p_next = NULL; + for (int src_n = 0; src_n < font->Sources.Size; src_n++, loader_user_data_p = loader_user_data_p_next) { + ImFontConfig* src = font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) + loader_user_data_p_next = loader_user_data_p + loader->FontBakedSrcLoaderDataSize; + + int glyph_index; + if (src_codepoint != (ImWchar)-1) { - if (only_load_advance_x == NULL) - { - ImFontGlyph glyph_buf; - if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf, NULL)) - { - // FIXME: Add hooks for e.g. #7962 - glyph_buf.Codepoint = src_codepoint; - glyph_buf.SourceIdx = src_n; - return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); - } - } - else - { - // Special mode but only loading glyphs metrics. Will rasterize and pack later. - if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x)) - { - ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x); - return NULL; - } - } + if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, src_codepoint)) + continue; + glyph_index = loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, src_codepoint); + } + else + { + if (src_n != src_font_idx) + continue; + glyph_index = src_glyph_idx; + } + if (glyph_index == 0) + continue; + + if (only_load_advance_x == NULL) + { + ImFontGlyph glyph_buf; + glyph_buf.Codepoint = codepoint; + if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, glyph_index, &glyph_buf, NULL)) + continue; + // FIXME: Add hooks for e.g. #7962 + glyph_buf.SourceIdx = src_n; + return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); + } + else + { + // Special mode but only loading glyphs metrics. Will rasterize and pack later. + if (!loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, glyph_index, NULL, only_load_advance_x)) + continue; + ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x); + return NULL; } - loader_user_data_p += loader->FontBakedSrcLoaderDataSize; - src_n++; } // Lazily load fallback glyph @@ -4695,10 +6224,8 @@ struct ImGui_ImplStbTrueType_FontSrcData float ScaleFactor; }; -static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) +static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas*, ImFontConfig* src) { - IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData); IM_ASSERT(src->FontLoaderData == NULL); @@ -4730,29 +6257,27 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* return true; } -static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) +static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas*, ImFontConfig* src) { - IM_UNUSED(atlas); ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; IM_DELETE(bd_font_data); src->FontLoaderData = NULL; } -static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) +static int ImGui_ImplStbTrueType_FontSrcGetGlyphIndexFromCodepoint(ImFontAtlas*, ImFontConfig* src, ImWchar codepoint) { - IM_UNUSED(atlas); - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; - IM_ASSERT(bd_font_data != NULL); - - int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); - return glyph_index != 0; + return stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); } -static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*) +static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas*, ImFontConfig* src, int glyph_index) { - IM_UNUSED(atlas); + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + return glyph_index > 0 && glyph_index < bd_font_data->FontInfo.numGlyphs; +} +static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void*) +{ ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; if (src->MergeMode == false) { @@ -4763,18 +6288,17 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); + // FIXME: round to rasterizer density? (#9348) } return true; } -static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x) +static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; IM_ASSERT(bd_font_data); - int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); - if (glyph_index == 0) - return false; + IM_ASSERT(glyph_index != 0); // Fonts unit to pixels int oversample_h, oversample_v; @@ -4799,7 +6323,6 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC } // Prepare glyph - out_glyph->Codepoint = codepoint; out_glyph->AdvanceX = advance * scale_for_layout; // Pack and retrieve position inside texture atlas @@ -4861,6 +6384,7 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() loader.Name = "stb_truetype"; loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit; loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy; + loader.FontSrcGetGlyphIndexFromCodepoint = ImGui_ImplStbTrueType_FontSrcGetGlyphIndexFromCodepoint; loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph; loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit; loader.FontBakedDestroy = NULL; @@ -5334,11 +6858,6 @@ void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } -void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) -{ - RemapPairs.SetInt((ImGuiID)from_codepoint, (int)to_codepoint); -} - // Find glyph, load if necessary, return fallback if missing ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c) { @@ -5388,11 +6907,19 @@ bool ImFontBaked::IsGlyphLoaded(ImWchar c) bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = OwnerAtlas; - ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c); + ImWchar src_codepoint = c; + int src_font_idx = -1, src_glyph_idx = -1; + ImFontAtlas_FontHookRemapCodepoint(atlas, this, c, &src_codepoint, &src_font_idx, &src_glyph_idx); + if (src_font_idx != -1) + { + ImFontConfig* src = Sources[src_font_idx]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + return loader->FontSrcContainsGlyph ? loader->FontSrcContainsGlyph(atlas, src, src_glyph_idx) : false; + } for (ImFontConfig* src : Sources) { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c)) + if (loader->FontSrcGetGlyphIndexFromCodepoint(atlas, src, c) != 0) return true; } return false; @@ -5772,7 +7299,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f; float x = pos.x; float y = pos.y; - if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0) + if ((draw_list->Flags & ImDrawFlags_TextNoPixelSnap) == 0) { x = IM_TRUNC(x); y = IM_TRUNC(y); @@ -5814,7 +7341,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im float y = pos.y; if (y > clip_rect.w) return; - if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0) + flags |= draw_list->Flags; + if ((flags & ImDrawFlags_TextNoPixelSnap) == 0) { x = IM_TRUNC(x); y = IM_TRUNC(y); @@ -6082,7 +7610,7 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float draw_list->PathLineTo(ImVec2(bx - third, by - third)); draw_list->PathLineTo(ImVec2(bx, by)); draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); - draw_list->PathStroke(col, thickness); + draw_list->PathStroke(col, thickness, ImDrawFlags_AALineEnds); } // Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. @@ -6164,7 +7692,7 @@ void ImGui::RenderRectFilledInRangeH(ImDrawList* draw_list, const ImRect& rect, draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e); // BR } } - draw_list->PathFillConvex(col); + draw_list->PathFillConvex(col, ImDrawFlags_JoinMiter); } void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding) @@ -6173,14 +7701,14 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const bool fill_R = (inner.Max.x < outer.Max.x); const bool fill_U = (inner.Min.y > outer.Min.y); const bool fill_D = (inner.Max.y < outer.Max.y); - if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); - if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); - if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); - if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); - if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); - if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); - if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft); - if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundNone | (fill_U ? 0 : ImDrawFlags_RoundTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundNone | (fill_U ? 0 : ImDrawFlags_RoundTopRight) | (fill_D ? 0 : ImDrawFlags_RoundBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundNone | (fill_L ? 0 : ImDrawFlags_RoundTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundNone | (fill_L ? 0 : ImDrawFlags_RoundBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundBottomRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundTopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundTopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundBottomLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundBottomRight); } ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold) @@ -6189,43 +7717,51 @@ ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRe bool round_r = r_in.Max.x >= r_outer.Max.x - threshold; bool round_t = r_in.Min.y <= r_outer.Min.y + threshold; bool round_b = r_in.Max.y >= r_outer.Max.y - threshold; - return ImDrawFlags_RoundCornersNone - | ((round_t && round_l) ? ImDrawFlags_RoundCornersTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundCornersTopRight : 0) - | ((round_b && round_l) ? ImDrawFlags_RoundCornersBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundCornersBottomRight : 0); + return ImDrawFlags_RoundNone + | ((round_t && round_l) ? ImDrawFlags_RoundTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundTopRight : 0) + | ((round_b && round_l) ? ImDrawFlags_RoundBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundBottomRight : 0); } // Helper for ColorPicker4() // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. -// FIXME: uses ImGui::GetColorU32 -void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float alpha, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) { - if ((flags & ImDrawFlags_RoundCornersMask_) == 0) - flags = ImDrawFlags_RoundCornersDefault_; + if ((flags & ImDrawFlags_RoundMask_) == 0) + flags = ImDrawFlags_RoundAll; if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) { - ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); - ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); - draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); + IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f); + const ImU32 a_mask = (ImU32)(alpha * 255.0f) << IM_COL32_A_SHIFT; + ImU32 col_bg1 = (ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col) & ~IM_COL32_A_MASK) | a_mask; + ImU32 col_bg2 = (ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col) & ~IM_COL32_A_MASK) | a_mask; + const bool dual_layer = (alpha == 1.0f); // Dual layer is faster but incorrect if blending. + if (dual_layer) + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); int yi = 0; for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) { - float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + float y1 = ImClamp((float)(int)y, p_min.y, p_max.y), y2 = ImMin((float)(int)(y + grid_step), p_max.y); if (y2 <= y1) continue; - for (float x = p_min.x + grid_off.x + ((yi ^ 1) & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + + const float x_start_off = dual_layer ? (((yi ^ 1) & 1) * grid_step) : 0.0f; + const float x_step = dual_layer ? (grid_step * 2.0f) : (grid_step); + int xi = 0; + for (float x = p_min.x + grid_off.x + x_start_off; x < p_max.x; x += x_step, xi++) { - float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + float x1 = ImClamp((float)(int)x, p_min.x, p_max.x), x2 = ImMin((float)(int)(x + grid_step), p_max.x); if (x2 <= x1) continue; - ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; // FIXME: Could use CalcRoundingFlagsForRectInRect() - if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } - if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } + ImDrawFlags cell_flags = ImDrawFlags_RoundNone; // FIXME: Could use CalcRoundingFlagsForRectInRect() + if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundTopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundBottomRight; } // Combine flags - cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags); - draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags); + cell_flags = (flags == ImDrawFlags_RoundNone || cell_flags == ImDrawFlags_RoundNone) ? ImDrawFlags_RoundNone : (cell_flags & flags); + ImU32 col_bg = dual_layer ? col_bg2 : (((yi + xi) & 1) ? col_bg2 : col_bg1); + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg, rounding, cell_flags); } } } diff --git a/include/imgui/imgui_internal.h b/include/imgui/imgui_internal.h index d2a8595..420f070 100644 --- a/include/imgui/imgui_internal.h +++ b/include/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. @@ -126,7 +126,7 @@ Index of this file: // Enable stb_truetype by default unless FreeType is enabled. // You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together. -#ifndef IMGUI_ENABLE_FREETYPE +#if !defined(IMGUI_ENABLE_FREETYPE) && !defined(IMGUI_ENABLE_STB_TRUETYPE) && !defined(IMGUI_DISABLE_STB_TRUETYPE) #define IMGUI_ENABLE_STB_TRUETYPE #endif @@ -189,6 +189,7 @@ struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aim struct ImGuiWindow; // Storage for one window struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) +struct ImGuiWindowStackData; // Storage for each window pushed into the stack // Enumerations // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. @@ -284,7 +285,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 #define IM_TRUNC(_VAL) ((float)(int)(_VAL)) // Positive values only! ImTrunc() is not inlined in MSVC debug builds -#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // Positive values only! +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // Positive values only! //#define IM_FLOOR IM_TRUNC // [OBSOLETE] Renamed in 1.90.0 (Sept 2023) // Hint for branch prediction @@ -367,6 +368,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer // - Helper: ImPool<> // - Helper: ImChunkStream<> // - Helper: ImGuiTextIndex +// - Helper: ImGuiTextFilterItem // - Helper: ImGuiStorage //----------------------------------------------------------------------------- @@ -406,7 +408,7 @@ IMGUI_API const char* ImStrSkipBlank(const char* str); IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string) IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line IM_MSVC_RUNTIME_CHECKS_OFF -inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } +inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c & ~32 : c; } inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } @@ -504,13 +506,23 @@ inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } #ifdef IMGUI_ENABLE_SSE inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +// Converge to more precise solution using single step of Newton-Raphson method, repeating increases precision +inline float ImRsqrtPrecise(float x) { const float r = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); return r * (1.5f - x * 0.5f * r * r); } #else inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +inline float ImRsqrtPrecise(float x) { return 1.0f / sqrtf(x); } #endif -inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } +inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } #endif + // - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double -// (Exceptionally using templates here but we could also redefine them for those types) +// (Specialized version ensure that runtime-check pragmas/macros are applied with caller settings. Template version are less reliable in this regards) +inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } +inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } +inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; } +inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; } +inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } template T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } template T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } template T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } @@ -535,8 +547,9 @@ inline ImVec2 ImTrunc(const ImVec2& v) { return inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } inline float ImTrunc64(float f) { return (float)(ImS64)(f); } -inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only. -inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the the bit-hack version (search for "0x1p120f"). +inline float ImRoundPositive64(float f) { return (float)(ImS64)(f + 0.5f); } // Positive values only. +inline float ImRoundSigned64(float f) { return (float)(ImS64)(f >= 0.0f ? f + 0.5f : f - 0.5f); } +inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the bit-hack version (search for "0x1p120f"). inline int ImModPositive(int a, int b) { return (a + b) % b; } inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } @@ -545,12 +558,29 @@ inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / (float)n; avg += sample / (float)n; return avg; } + +inline bool ImIsTruncated(float x) { return (float)(int)x == x; } +#ifdef IMGUI_ENABLE_SSE +// Returns true if all parameters are whole numbers. +inline bool ImIsTruncated4(float x, float y, float z, float w) +{ + __m128 v = _mm_set_ps(x, y, z, w); + __m128i i = _mm_cvttps_epi32(v); + return _mm_movemask_ps(_mm_cmpeq_ps(v, _mm_cvtepi32_ps(i))) == 0xF; +} +#else +inline bool ImIsTruncated4(float x, float y, float z, float w) +{ + return (float)(int)x == x && (float)(int)y == y && (float)(int)z == z && (float)(int)w == w; +} +#endif + IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); -IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments -IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol +IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments +IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float max_error);// For auto-tessellated curves you can use max_error = style.CurveTessellationMaxError IMGUI_API ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t); IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); @@ -565,25 +595,25 @@ IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec1 { float x; - constexpr ImVec1() : x(0.0f) { } - constexpr ImVec1(float _x) : x(_x) { } + IM_NODEBUGSTEP constexpr inline ImVec1() : x(0.0f) { } + IM_NODEBUGSTEP constexpr inline ImVec1(float _x) : x(_x) { } }; // Helper: ImVec2i (2D vector, integer) struct ImVec2i { int x, y; - constexpr ImVec2i() : x(0), y(0) {} - constexpr ImVec2i(int _x, int _y) : x(_x), y(_y) {} + IM_NODEBUGSTEP constexpr inline ImVec2i() : x(0), y(0) {} + IM_NODEBUGSTEP constexpr inline ImVec2i(int _x, int _y) : x(_x), y(_y) {} }; // Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) struct ImVec2ih { short x, y; - constexpr ImVec2ih() : x(0), y(0) {} - constexpr ImVec2ih(short _x, short _y) : x(_x), y(_y) {} - constexpr explicit ImVec2ih(const ImVec2& rhs) : x((short)rhs.x), y((short)rhs.y) {} + IM_NODEBUGSTEP constexpr inline ImVec2ih() : x(0), y(0) {} + IM_NODEBUGSTEP constexpr inline ImVec2ih(short _x, short _y) : x(_x), y(_y) {} + IM_NODEBUGSTEP constexpr inline explicit ImVec2ih(const ImVec2& rhs) : x((short)rhs.x), y((short)rhs.y) {} }; // Helper: ImRect (2D axis aligned bounding-box) @@ -593,10 +623,10 @@ struct IMGUI_API ImRect ImVec2 Min; // Upper-left ImVec2 Max; // Lower-right - constexpr ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} - constexpr ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} - constexpr ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} - constexpr ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + IM_NODEBUGSTEP constexpr inline ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + IM_NODEBUGSTEP constexpr inline ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + IM_NODEBUGSTEP constexpr inline ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + IM_NODEBUGSTEP constexpr inline ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } @@ -698,13 +728,13 @@ struct ImSpan inline bool empty() const { return Data == DataEnd; } inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } - inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } - inline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } - inline T* begin() { return Data; } - inline const T* begin() const { return Data; } - inline T* end() { return DataEnd; } - inline const T* end() const { return DataEnd; } + IM_NODEBUGSTEP inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + IM_NODEBUGSTEP inline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + IM_NODEBUGSTEP inline T* begin() { return Data; } + IM_NODEBUGSTEP inline const T* begin() const { return Data; } + IM_NODEBUGSTEP inline T* end() { return DataEnd; } + IM_NODEBUGSTEP inline const T* end() const { return DataEnd; } // Utilities inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; } @@ -835,6 +865,16 @@ struct ImGuiTextIndex void append(const char* base, int old_size, int new_size); }; +// [Internal] Types +struct ImGuiTextFilterItem +{ + const char* Begin; // Pointer within parent's buffer + int Len; // Length of text (non-zero terminated) + short CountInclude; // Number of consecutive items forming an end chain. >0 when beginning of an AND chain, =0 otherwise. + unsigned short MatchIncludesMask; // Storage for multi-sources versions of PassFilter(). Unused by core library. + ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; MatchIncludesMask = 0; } +}; + // Helper: ImGuiPackedDate (sizeof() == 2) // Store a date in a way that is efficient to read/write in text form. If we stored e.g. number of days since Epoch we'd need costlier back and forth. // This is specifically designed to be able to prune old .ini data. @@ -877,11 +917,28 @@ IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStorag #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR) ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI)))) #define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD) ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD)) -// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle. +// ImDrawList: Lookup tables #ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE -#define IM_DRAWLIST_ARCFAST_TABLE_SIZE 48 // Number of samples in lookup table. +#define IM_DRAWLIST_ARCFAST_TABLE_SIZE (48) // Number of samples in adaptive arc drawing lookup table. #endif -#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. +#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. + +#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) // The maximum line width to bake anti-aliased textures for. +#endif +#ifndef IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH +#define IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH (4) // Calculate detailed textures for width [1..IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH] +#endif +#ifndef IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT +#define IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT (4) // How many samples per integer thickness level. +#endif +#ifndef IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX +#define IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX (16) +#endif +#ifndef IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX +#define IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX (4) // 0: fill, 1-3: strokes thickness +#endif +#define IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT ((IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH - 1) * IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT + 1) // Data shared between all ImDrawList instances // Conceptually this could have been called e.g. ImDrawListSharedContext @@ -890,15 +947,15 @@ IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStorag struct IMGUI_API ImDrawListSharedData { ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel) - const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->Builder->TexUvLines) + const ImVec4* TexUvCorners; // UV of rounded corner (== FontAtlas->Builder->TexUvCorners) ImFontAtlas* FontAtlas; // Current font atlas ImFont* Font; // Current font (used for simplified AddText overload) - float FontSize; // Current font size (used for for simplified AddText overload) + float FontSize; // Current font size (used for simplified AddText overload) float FontScale; // Current font scale (== FontSize / Font->FontSize) - float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() + float CurveTessellationMaxError; // Tessellation tolerance when using PathBezierCurveTo() float CircleTessellationMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc - float InitialFringeScale; // Initial scale to apply to AA fringe - ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + ImDrawFlags InitialDrawFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() ImVector TempBuffer; // Temporary write buffer ImVector DrawLists; // All draw lists associated to this ImDrawListSharedData @@ -933,6 +990,8 @@ struct ImFontStackData // [SECTION] Style support //----------------------------------------------------------------------------- +#define ImGuiCol_TextMixedValue ImGuiCol_TextDisabled + struct ImGuiStyleVarInfo { ImU32 Count : 8; // 1+ @@ -994,7 +1053,6 @@ enum ImGuiItemFlagsPrivate_ { // Controlled by user ImGuiItemFlags_ReadOnly = 1 << 11, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. - ImGuiItemFlags_MixedValue = 1 << 12, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable() ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover highlight (behave as if NavHighlightItemUnderNav==false). @@ -1030,7 +1088,7 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_HasShortcut = 1 << 10, // g.LastItemData.Shortcut valid. Set by SetNextItemShortcut() -> ItemAdd(). //ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Removed IN 1.90.1 (Dec 2023). The trigger is part of g.NavActivateId. See commit 54c1bdeceb. ImGuiItemStatusFlags_EditedInternal = 1 << 11, // Similar to ImGuiItemStatusFlags_Edited but bypassing ImGuiItemFlags_NoMarkEdited. - + // Additional status + semantic for ImGuiTestEngine #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiItemStatusFlags_Openable = 1 << 20, // Item is an openable (e.g. TreeNode) @@ -1084,12 +1142,6 @@ enum ImGuiButtonFlagsPrivate_ //ImGuiButtonFlags_NoKeyModifiers = ImGuiButtonFlags_NoKeyModsAllowed, // Renamed in 1.91.4 }; -// Extend ImGuiComboFlags_ -enum ImGuiComboFlagsPrivate_ -{ - ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview() -}; - // Extend ImGuiSliderFlags_ enum ImGuiSliderFlagsPrivate_ { @@ -1184,6 +1236,10 @@ enum ImGuiPlotType ImGuiPlotType_Histogram, }; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview() // [Obsoleted in 1.93.0] Unnecessary: can now use BeginComboPreview() without a flag. +#endif + // Storage data for BeginComboPreview()/EndComboPreview() struct IMGUI_API ImGuiComboPreviewData { @@ -1192,7 +1248,10 @@ struct IMGUI_API ImGuiComboPreviewData ImVec2 BackupCursorMaxPos; ImVec2 BackupCursorPosPrevLine; float BackupPrevLineTextBaseOffset; - ImGuiLayoutType BackupLayout; + float BackupWorkRectMaxX; + float BackupContentRectMaxX; + ImGuiLayoutType BackupLayout : 8; + int WithinPreview : 2; ImGuiComboPreviewData() { memset((void*)this, 0, sizeof(*this)); } }; @@ -1281,6 +1340,7 @@ struct IMGUI_API ImGuiInputTextState bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool EditedBefore; // edited since activated bool EditedThisFrame; // edited this frame + bool ValidatedThisFrame; bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. ImS8 LastMoveDirectionLR; // ImGuiDir_Left or ImGuiDir_Right. track last movement direction so when cursor cross over a word-wrapping boundaries we can display it on either line depending on last move.s int ReloadSelectionStart; @@ -1361,8 +1421,10 @@ struct ImGuiNextWindowData ImVec2 SizeVal; ImVec2 ContentSizeVal; ImVec2 ScrollVal; - ImGuiWindowFlags WindowFlags; // Only honored by BeginTable() - ImGuiChildFlags ChildFlags; + ImGuiWindowFlags WindowFlagsSet; // Flags to set. Use SetNextWindowFlags()! + ImGuiWindowFlags WindowFlagsClear; + ImGuiChildFlags ChildFlagsSet; // Flags to set. Use SetNextWindowChildFlags(). + ImGuiChildFlags ChildFlagsClear; bool CollapsedVal; ImRect SizeConstraintRect; ImGuiSizeCallback SizeCallback; @@ -1456,7 +1518,7 @@ struct IMGUI_API ImGuiErrorRecoveryState ImGuiErrorRecoveryState() { memset((void*)this, 0, sizeof(*this)); } }; -// Data saved for each window pushed into the stack +// Storage for each window pushed into the stack. struct ImGuiWindowStackData { ImGuiWindow* Window; @@ -1464,6 +1526,7 @@ struct ImGuiWindowStackData ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting bool DisabledOverrideReenable; // Non-child window override disabled flag float DisabledOverrideReenableAlphaBackup; + ImRect ParentLastComboPreviewRect; }; struct ImGuiShrinkWidthItem @@ -1998,8 +2061,9 @@ struct IMGUI_API ImGuiMultiSelectState // Every instance of ImGuiViewport is in fact a ImGuiViewportP. struct ImGuiViewportP : public ImGuiViewport { - float BgFgDrawListsLastTimeActive[2]; // Last frame number the background (0) and foreground (1) draw lists were used ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + int BgFgDrawListsLastFrameActive[2]; // Last frame the background (0) and foreground (1) draw lists were used. + float BgFgDrawListsLastTimeActive[2]; // Timestamps for Gc. ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData @@ -2012,7 +2076,7 @@ struct ImGuiViewportP : public ImGuiViewport ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset ImVec2 BuildWorkInsetMax; // " - ImGuiViewportP() { BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; } + ImGuiViewportP() { BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; BgFgDrawListsLastFrameActive[0] = BgFgDrawListsLastFrameActive[1] = -1; BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0; } ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) @@ -2267,7 +2331,7 @@ struct ImGuiContext float FontSize; // Currently bound font size == line height (== FontSizeBase + externals scales applied in the UpdateCurrentFontSize() function). float FontSizeBase; // Font size before scaling == style.FontSizeBase == value passed to PushFont() when specified. float FontBakedScale; // == FontBaked->Size / FontSize. Scale factor over baked size. Rarely used nowadays, very often == 1.0f. - float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). + float CurrentPixelDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; ImGuiID WithinEndChildID; // Set within EndChild() @@ -2303,6 +2367,7 @@ struct ImGuiContext ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information + const char* MixedValueLabel; // Value replacement when displaying a mixed value. Default to "-" (Unreal uses "Multiple values", Unity uses "---"). May be interpreted as a format: must not contain single %. Set to NULL to display original value. ImGuiID DebugDrawIdConflictsId; // Set when we detect multiple items with the same identifier ImGuiID DebugHookIdInfoId; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID HoveredId; // Hovered widget, filled during the frame @@ -2437,6 +2502,7 @@ struct ImGuiContext ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). ImGuiKeyChord NavJustMovedToKeyMods; bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags. + bool NavJustMovedToIsInit; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags. bool NavJustMovedToHasSelectionData; // Copy of move result's ItemFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. // Navigation: extra config options (will be made public eventually) @@ -2690,7 +2756,7 @@ struct IMGUI_API ImGuiWindowTempData ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement int TreeDepth; // Current tree depth. - ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary. + ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary. Sync any changes with TREE_NODE_MAX_DEPTH/TREE_NODE_GET_DEPTH_MASK! ImU32 TreeRecordsClippedNodesY2Mask; // Store whether we should keep recording Y2. Cleared when passing clip max. Equivalent TreeHasStackDataDepthMask value should always be set. ImVector ChildWindows; ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) @@ -3117,9 +3183,9 @@ struct IMGUI_API ImGuiTable ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly ImGuiTableInstanceData InstanceDataFirst; ImVector InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good. - ImGuiTableColumnSortSpecs SortSpecsSingle; - ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableColumnSortSpecs SortSpecsSingle; ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns using fixed width (<= ColumnsCount) @@ -3151,6 +3217,7 @@ struct IMGUI_API ImGuiTable ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable(). bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsNewTable; bool IsInitializing; bool IsReconcileMode; bool IsSortSpecsDirty; @@ -3252,7 +3319,7 @@ struct ImGuiTableSettings }; namespace ImGui -{ +{ // Tables: Candidates for public API IMGUI_API void TableOpenContextMenu(int column_n = -1); IMGUI_API void TableSetColumnWidth(int column_n, float width); @@ -3346,7 +3413,7 @@ namespace ImGui // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx); IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx); - inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: I don't want to formalize this just yet. Because reasons. Please don't use. + inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: PLEASE DO NOT USE. I don't want to formalize this just yet. Because reasons. inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); @@ -3369,6 +3436,8 @@ namespace ImGui inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); } inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } + IMGUI_API void SetNextWindowFlags(ImGuiWindowFlags flags, bool enabled); + IMGUI_API void SetNextWindowChildFlags(ImGuiChildFlags flags, bool enabled); // Windows: Display Order and Focus Order IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); @@ -3390,8 +3459,8 @@ namespace ImGui IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void SetCurrentFont(ImFont* font, float font_size_before_scaling, float font_size_after_scaling); IMGUI_API void UpdateCurrentFontSize(float restore_font_size_after_scaling); - IMGUI_API void SetFontRasterizerDensity(float rasterizer_density); - inline float GetFontRasterizerDensity() { return GImGui->FontRasterizerDensity; } + IMGUI_API void SetPixelDensity(float pixel_density); // was SetFontRasterizerDensity() + inline float GetPixelDensity() { return GImGui->CurrentPixelDensity; } inline float GetRoundedFontSize(float size) { return IM_ROUND(size); } IMGUI_API ImFont* GetDefaultFont(); IMGUI_API void PushPasswordFont(); @@ -3531,7 +3600,7 @@ namespace ImGui // Combos IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); - IMGUI_API bool BeginComboPreview(); + IMGUI_API bool BeginComboPreview(); // Submit preview contents a combo. Call this after EndCombo() to display contents that's more than just a text label. IMGUI_API void EndComboPreview(); // Keyboard/Gamepad Navigation @@ -3664,6 +3733,7 @@ namespace ImGui IMGUI_API void ClearDragDrop(); IMGUI_API bool IsDragDropPayloadBeingAccepted(); IMGUI_API void RenderDragDropTargetRectForItem(const ImRect& bb); + IMGUI_API void RenderDragDropTargetRectForViewport(ImGuiID viewport_id, const ImRect& bb); IMGUI_API void RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding); // Typing-Select API @@ -3696,6 +3766,7 @@ namespace ImGui IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar); inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); } IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API ImVec2 TabBarGetTabPos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); @@ -3721,7 +3792,7 @@ namespace ImGui IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorComponentMarker(const ImRect& bb, ImU32 col, float rounding); - IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float alpha, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None, float rounding = -1.0f); // Navigation highlight #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4 @@ -3740,8 +3811,8 @@ namespace ImGui // Widgets: Text IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); - IMGUI_API void TextAligned(float align_x, float size_x, const char* fmt, ...); // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) - IMGUI_API void TextAlignedV(float align_x, float size_x, const char* fmt, va_list args); + IMGUI_API void TextAligned(float align_x, float width, const char* fmt, ...) IM_FMTARGS(3); // FIXME-WIP: Works but API is likely to be reworked. + IMGUI_API void TextAlignedV(float align_x, float width, const char* fmt, va_list args) IM_FMTLIST(3); // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); @@ -3906,10 +3977,11 @@ struct ImFontLoader void (*LoaderShutdown)(ImFontAtlas* atlas); bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); - bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); + int (*FontSrcGetGlyphIndexFromCodepoint)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); // Required + bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, int glyph_index); bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); - bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x); + bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x); // Required // Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations. // FIXME: At this point the two other types of buffers may be managed by core to be consistent? @@ -4011,8 +4083,14 @@ struct ImFontAtlasBuilder // Custom rectangle identifiers ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. ImFontAtlasRectId PackIdLinesTexData; + ImFontAtlasRectId PackIdLineFractTexData; + ImFontAtlasRectId PackIdCornersTexData; + + // Cached UV coordinates + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1 + IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT]; // UVs for baked anti-aliased lines (u0, u1, v, 1/thickness) + ImVec4 TexUvCorners[IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX * IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX]; // UVs for baked anti-aliased corners (0= fill, 1> stroke thickness) - ImFontAtlasBuilder() { memset((void*)this, 0, sizeof(*this)); FrameCount = -1; RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; } + ImFontAtlasBuilder() { memset((void*)this, 0, sizeof(*this)); FrameCount = -1; RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = PackIdLineFractTexData = PackIdCornersTexData = -1; } }; IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); diff --git a/include/imgui/imgui_tables.cpp b/include/imgui/imgui_tables.cpp index f8fab37..a1757ed 100644 --- a/include/imgui/imgui_tables.cpp +++ b/include/imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (tables and columns code) /* @@ -375,7 +375,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG const int previous_frame_active = table->LastFrameActive; const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1; const ImGuiTableFlags previous_flags = table->Flags; - const bool is_new_table = (previous_frame_active == -1); table->ID = id; table->Flags = flags; table->LastFrameActive = g.FrameCount; @@ -384,6 +383,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->IsLayoutLocked = false; table->InnerWidth = inner_width; table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent; + table->IsNewTable = (previous_frame_active == -1); temp_data->UserOuterSize = outer_size; // Instance data (for instance 0, TableID == TableInstanceID) @@ -428,11 +428,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG SetNextWindowScroll(ImVec2(0.0f, 0.0f)); // Create scrolling region (without border and zero window padding) - ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None; - ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None; - if (flags & ImGuiTableFlags_ScrollX) - child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar; - BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags); + ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; + BeginChildEx(name, instance_id, outer_rect.GetSize(), ImGuiChildFlags_None, child_window_flags); table->InnerWindow = g.CurrentWindow; table->WorkRect = table->InnerWindow->WorkRect; table->OuterRect = table->InnerWindow->Rect(); @@ -588,7 +585,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if (table->IsInitializing) { // Initialize - if (is_new_table) + if (table->IsNewTable) { table->SettingsOffset = -1; table->IsSettingsRequestLoad = true; @@ -634,7 +631,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() if (table->ColumnsNames.Buf.Size > 0) table->ColumnsNames.Buf.resize(0); - + return true; } @@ -1759,7 +1756,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo ImGuiTableColumn* column = &table->Columns[column_idx]; // If topology change goes into reconcile mode - if (table->IsReconcileMode == false && column->ID != column_id) + if (table->IsReconcileMode == false && column->ID != column_id && !table->IsNewTable) { table->IsReconcileMode = true; table->TempData->ReconcileColumnsRequests.reserve(table->ColumnsCount - column_idx); @@ -2964,7 +2961,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) // Draw inner border and resizing feedback ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); const float border_size = TABLE_BORDER_SIZE; - const float draw_y1 = ImMax(table->InnerRect.Min.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table->AngledHeadersHeight) + ((table->Flags & ImGuiTableFlags_BordersOuterH) ? 1.0f : 0.0f); + const float draw_y1 = ImMax(table->InnerRect.Min.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table->AngledHeadersHeight) + ((table->Flags & ImGuiTableFlags_BordersOuterH) ? border_size : 0.0f); const float draw_y2_body = table->InnerRect.Max.y; const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastTopHeadersRowHeight) : draw_y1; if (table->Flags & ImGuiTableFlags_BordersInnerV) @@ -3021,7 +3018,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) else if (table->Flags & ImGuiTableFlags_BordersOuterV) { inner_drawlist->AddLineV(outer_border.Min.x, outer_border.Min.y, outer_border.Max.y, outer_col, border_size); - inner_drawlist->AddLineV(outer_border.Max.x, outer_border.Min.y, outer_border.Max.y, outer_col, border_size); + inner_drawlist->AddLineV(outer_border.Max.x - border_size, outer_border.Min.y, outer_border.Max.y, outer_col, border_size); } else if (table->Flags & ImGuiTableFlags_BordersOuterH) { @@ -3032,9 +3029,10 @@ void ImGui::TableDrawBorders(ImGuiTable* table) if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y) { // Draw bottom-most row border between it is above outer border. + const float h_inset = (table->Flags & ImGuiTableFlags_BordersOuterV) ? border_size : 0.0f; const float border_y = table->RowPosY2; if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y) - inner_drawlist->AddLineH(table->BorderX1, table->BorderX2, border_y, table->BorderColorLight, border_size); + inner_drawlist->AddLineH(table->BorderX1 + h_inset, table->BorderX2 - h_inset, border_y, table->BorderColorLight, border_size); } inner_drawlist->PopClipRect(); @@ -3627,7 +3625,8 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label if (pass == 1) { // Draw border - draw_list->AddLine(bg_shape[0] - ImVec2(TABLE_BORDER_SIZE * 0.5f, 0.0f), bg_shape[3] - ImVec2(TABLE_BORDER_SIZE * 0.5f, 0.0f), TableGetColumnBorderCol(table, order_n, column_n), TABLE_BORDER_SIZE); + const float border_size = TABLE_BORDER_SIZE; + draw_list->AddLine(bg_shape[0] + ImVec2(border_size * 0.5f, 0.0f), bg_shape[3] + ImVec2(border_size * 0.5f, 0.0f), TableGetColumnBorderCol(table, order_n, column_n), border_size); } } PopClipRect(); @@ -3973,7 +3972,7 @@ void ImGui::TableSaveSettings(ImGuiTable* table) if (column->DisplayOrder != n) settings->SaveFlags |= ImGuiTableFlags_Reorderable; if (column->SortOrder != -1) - settings->SaveFlags |= ImGuiTableFlags_Sortable; + settings->SaveFlags |= ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable; // Because SortOrder saving itself is gated, make sure every column is saved (#9519) if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) settings->SaveFlags |= ImGuiTableFlags_Hideable; } @@ -4110,6 +4109,12 @@ static int IMGUI_CDECL TableFixDisplayOrderComparer(const void* lhs, const void* // Fix invalid display order data: compact values (0,1,3 -> 0,1,2); preserve relative order (0,3,1 -> 0,2,1); deduplicate (0,4,1,1 -> 0,3,1,2) void ImGui::TableFixDisplayOrder(ImGuiTable* table) { + if ((table->Flags & ImGuiTableFlags_Reorderable) == 0) + { + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[n] = table->Columns[n].DisplayOrder = (ImGuiTableColumnIdx)n; + return; + } ImGuiContext& g = *GImGui; g.TempBuffer.reserve((int)(sizeof(ImGuiTableFixDisplayOrderColumnData) * table->ColumnsCount)); // FIXME: Maybe wrap those two lines as a helper. ImGuiTableFixDisplayOrderColumnData* fdo_columns = (ImGuiTableFixDisplayOrderColumnData*)(void*)g.TempBuffer.Data; diff --git a/include/imgui/imgui_widgets.cpp b/include/imgui/imgui_widgets.cpp index 5ed7d6f..821b15f 100644 --- a/include/imgui/imgui_widgets.cpp +++ b/include/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.9b +// dear imgui, v1.93.0 // (widgets code) /* @@ -342,18 +342,18 @@ void ImGui::TextWrappedV(const char* fmt, va_list args) PopTextWrapPos(); } -void ImGui::TextAligned(float align_x, float size_x, const char* fmt, ...) +void ImGui::TextAligned(float align_x, float width, const char* fmt, ...) { va_list args; va_start(args, fmt); - TextAlignedV(align_x, size_x, fmt, args); + TextAlignedV(align_x, width, fmt, args); va_end(args); } // align_x: 0.0f = left, 0.5f = center, 1.0f = right. -// size_x : 0.0f = shortcut for GetContentRegionAvail().x -// FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) -void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list args) +// width < 0.0f (e.g. -FLT_MIN): shortcut for GetContentRegionAvail().x +// FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024, #9455) +void ImGui::TextAlignedV(float align_x, float width, const char* fmt, va_list args) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -362,23 +362,25 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a const char* text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); const ImVec2 text_size = CalcTextSize(text, text_end); - size_x = CalcItemSize(ImVec2(size_x, 0.0f), 0.0f, text_size.y).x; + const ImVec2 size = CalcItemSize(ImVec2(width, 0.0f), 0.0f, text_size.y); ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - ImVec2 pos_max(pos.x + size_x, window->ClipRect.Max.y); - ImVec2 size(ImMin(size_x, text_size.x), text_size.y); + ImVec2 pos_max(pos.x + size.x, window->ClipRect.Max.y); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, pos.x + text_size.x); window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, pos.x + text_size.x); - if (align_x > 0.0f && text_size.x < size_x) - pos.x += ImTrunc((size_x - text_size.x) * align_x); - RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size); - const ImVec2 backup_max_pos = window->DC.CursorMaxPos; ItemSize(size); - ItemAdd(ImRect(pos, pos + size), 0); - window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up. + const bool is_visible = ItemAdd(ImRect(pos, pos + size), 0); + window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content to 'size' to use 'text_size' allowing auto-resize to function with align_x > 0.0f + if (!is_visible) + return; + + if (align_x > 0.0f && text_size.x < size.x) + pos.x += ImTrunc((size.x - text_size.x) * align_x); + RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size); - if (size_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) + if (size.x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) SetTooltip("%.*s", (int)(text_end - text), text); } @@ -930,7 +932,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); const ImU32 cross_col = GetColorU32(ImGuiCol_Text); - const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); + const ImVec2 cross_center = bb.GetCenter(); const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; const float cross_thickness = 1.0f * (float)(int)g.Style._MainScale; // FIXME-DPI window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); @@ -1396,7 +1398,7 @@ bool ImGui::RadioButton(const char* label, bool active) RenderNavCursor(total_bb, id); const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); - if (active) + if (active && (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) == 0) { const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f)); window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark)); @@ -1755,7 +1757,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end const float sep1_x1 = pos.x; const float sep2_x2 = bb.Max.x; - const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.999f); + float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f) + 1.0f; const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN @@ -1769,9 +1771,9 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end const float sep1_x2 = label_pos.x - style.ItemSpacing.x; const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) - window->DrawList->AddLineH(sep1_x1, sep1_x2, seps_y, separator_col, separator_thickness); + window->DrawList->AddLineH(sep1_x1, sep1_x2, seps_y, separator_col, separator_thickness, ImDrawFlags_StrokeCenterBiased); if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) - window->DrawList->AddLineH(sep2_x1, sep2_x2, seps_y, separator_col, separator_thickness); + window->DrawList->AddLineH(sep2_x1, sep2_x2, seps_y, separator_col, separator_thickness, ImDrawFlags_StrokeCenterBiased); if (g.LogEnabled) LogSetNextTextDecoration("---", NULL); RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, &label_size); @@ -1781,7 +1783,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end if (g.LogEnabled) LogText("---"); if (separator_thickness > 0.0f) - window->DrawList->AddLineH(sep1_x1, sep2_x2, seps_y, separator_col, separator_thickness); + window->DrawList->AddLineH(sep1_x1, sep2_x2, seps_y, separator_col, separator_thickness, ImDrawFlags_StrokeCenterBiased); } } @@ -1949,7 +1951,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF const ImGuiID id = window->GetID(label); IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together if (flags & ImGuiComboFlags_WidthFitPreview) - IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0); + IM_ASSERT((flags & ImGuiComboFlags_NoPreview) == 0); const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const char* label_end = FindRenderedTextEnd(label); @@ -1978,24 +1980,19 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); RenderNavCursor(bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) - window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); + window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundAll : ImDrawFlags_RoundLeft); if (!(flags & ImGuiComboFlags_NoArrowButton)) { ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); - window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundAll : ImDrawFlags_RoundRight); if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); } RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); - // Custom preview - if (flags & ImGuiComboFlags_CustomPreview) - { - g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); - IM_ASSERT(preview_value == NULL || preview_value[0] == 0); - preview_value = NULL; - } + // Store geometry for BeginComboPreview() - only necessary when visible. + g.ComboPreviewData.PreviewRect = (flags & ImGuiComboFlags_NoPreview) ? ImRect() : ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); // Render preview and label if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) @@ -2077,6 +2074,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags return false; } g.BeginComboDepth++; + g.CurrentWindowStack.back().ParentLastComboPreviewRect = g.ComboPreviewData.PreviewRect; return true; } @@ -2084,6 +2082,7 @@ void ImGui::EndCombo() { ImGuiContext& g = *GImGui; g.BeginComboDepth--; + g.ComboPreviewData.PreviewRect = g.CurrentWindowStack.back().ParentLastComboPreviewRect; char name[16]; ImFormatString(name, IM_COUNTOF(name), "##Combo_%02d", g.BeginComboDepth); // FIXME: Move those to helpers? if (strcmp(g.CurrentWindow->Name, name) != 0) @@ -2091,19 +2090,26 @@ void ImGui::EndCombo() EndPopup(); } -// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements -// (Experimental, see GitHub issues: #1658, #4168) +// Submit preview contents for BeginCombo()/EndCombo(), to display contents that's more than just a text label. +// - [BETA] See GitHub issues: #1658, #4168. +// - Make sure you call this after EndCombo(). +// - The preview is designed to only host non-interactive elements. +// - Not compatible with ImGuiComboFlags_WidthFitPreview. +// - 2026-09-08 (1.93.0): removed ImGuiComboFlags_CustomPreview. You can use BeginComboPreview()/EndComboPreview() without an extra flag. bool ImGui::BeginComboPreview() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)) return false; - IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? - if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional) + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + if (!window->ClipRect.Overlaps(preview_data->PreviewRect) || preview_data->PreviewRect.GetWidth() <= 0.0f) // Narrower test (optional) + handle _NoPreview return false; + IM_ASSERT_USER_ERROR_RETV(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y, false, + "Call BeginComboPreview() after BeginCombo(), not after EndCombo()!"); // Calling after EndCombo() works only if you don't nest combos. + IM_ASSERT_USER_ERROR_RETV(preview_data->WithinPreview == false, false, + "Cannot recurse BeginComboPreview(): call EndComboPreview() before opening another combo."); // FIXME: This could be contained in a PushWorkRect() api preview_data->BackupCursorPos = window->DC.CursorPos; @@ -2111,6 +2117,10 @@ bool ImGui::BeginComboPreview() preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; preview_data->BackupLayout = window->DC.LayoutType; + preview_data->WithinPreview = true; + preview_data->BackupWorkRectMaxX = window->WorkRect.Max.x; + preview_data->BackupContentRectMaxX = window->ContentRegionRect.Max.x; + window->WorkRect.Max.x = window->ContentRegionRect.Max.x = preview_data->PreviewRect.Max.x - g.Style.FramePadding.x; window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding; window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.LayoutType = ImGuiLayoutType_Horizontal; @@ -2136,12 +2146,14 @@ void ImGui::EndComboPreview() } PopClipRect(); window->DC.CursorPos = preview_data->BackupCursorPos; - window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); // No need to do the same with IdealMaxPos window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine; window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset; + window->WorkRect.Max.x = preview_data->BackupWorkRectMaxX; + window->ContentRegionRect.Max.x = preview_data->BackupContentRectMaxX; window->DC.LayoutType = preview_data->BackupLayout; window->DC.IsSameLine = false; - preview_data->PreviewRect = ImRect(); + preview_data->WithinPreview = false; } // Getter for the old Combo() API: const char*[] @@ -2174,7 +2186,9 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo // Call the getter to obtain the preview string which is a parameter to BeginCombo() const char* preview_value = NULL; - if (*current_item >= 0 && *current_item < items_count) + if ((g.NextItemData.ItemFlagsSet | g.CurrentItemFlags) & ImGuiItemFlags_MixedValue) + preview_value = ""; + else if (*current_item >= 0 && *current_item < items_count) preview_value = getter(user_data, *current_item); // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. @@ -2658,19 +2672,39 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const return true; } +static bool ShortcutsForCancel(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + bool is_cancel_with_keyboard = ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_None, id); + bool is_cancel_with_gamepad = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0 && ImGui::Shortcut(ImGuiKey_NavGamepadCancel, ImGuiInputFlags_None, id); + bool is_cancel_with_mouse = ImGui::IsMouseReleased(ImGuiMouseButton_Right, id); + if (is_cancel_with_mouse) + ImGui::SetKeyOwner(ImGuiKey_MouseRight, id); + return is_cancel_with_keyboard || is_cancel_with_gamepad || is_cancel_with_mouse; +} + bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) { // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + // Things we can do easily outside the DragBehaviorT<> template, saves code generation. ImGuiContext& g = *GImGui; if (g.ActiveId == id) { - // Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation. if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) ClearActiveID(); else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) ClearActiveID(); + if (ShortcutsForCancel(id) && g.ActiveId == id) //-V560 + { + // Canceling action reverts to initial value + size_t data_size = DataTypeGetInfo(data_type)->Size; + bool value_changed = memcmp(p_v, &g.ActiveIdValueOnActivation, data_size); + memcpy(p_v, &g.ActiveIdValueOnActivation, data_size); + ClearActiveID(); + return value_changed; + } } if (g.ActiveId != id) return false; @@ -2793,11 +2827,16 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, MarkItemEdited(id); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format); if (g.LogEnabled) LogSetNextTextDecoration("{", "}"); + if (is_mixed) + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + if (is_mixed) + PopStyleColor(); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false); @@ -3004,7 +3043,7 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T result = 0.0f; // Workaround for values that are in-range but below our fudge else if (v_clamped >= v_max_fudged) result = 1.0f; // Workaround for values that are in-range but above our fudge - else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions + else if (((FLOATTYPE)v_min * (FLOATTYPE)v_max) < 0.0f) // Range crosses zero, so split into two portions { float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; @@ -3058,7 +3097,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range - if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts + if (((FLOATTYPE)v_min * (FLOATTYPE)v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts { float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; @@ -3083,13 +3122,13 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T { result = ImLerp(v_min, v_max, t); } - else if (t < 1.0) + else // t is already < 1.0 here { // - For integer values we want the clicking position to match the grab box so we round above // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. - FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; + FLOATTYPE v_new_off_f = (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min) * (FLOATTYPE)t; result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); } } @@ -3138,37 +3177,24 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ float clicked_t = 0.0f; if (g.ActiveIdSource == ImGuiInputSource_Mouse) { - if (!g.IO.MouseDown[0]) - { - ClearActiveID(); - } - else + const float mouse_pos = g.IO.MousePos[axis]; + if (g.ActiveIdIsJustActivated) { - const float mouse_abs_pos = g.IO.MousePos[axis]; - if (g.ActiveIdIsJustActivated) - { - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); - if (axis == ImGuiAxis_Y) - grab_t = 1.0f - grab_t; - const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); - const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. - g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f; - } - if (slider_usable_sz > 0.0f) - clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) - clicked_t = 1.0f - clicked_t; - set_new_value = true; + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + const bool clicked_around_grab = (mouse_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. + g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_pos - grab_pos : 0.0f; } + if (slider_usable_sz > 0.0f) + clicked_t = ImSaturate((mouse_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz); + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { - if (g.ActiveIdIsJustActivated) - { - g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation - g.SliderCurrentAccumDirty = false; - } - float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis); if (input_delta != 0.0f) { @@ -3196,11 +3222,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } float delta = g.SliderCurrentAccum; - if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) - { - ClearActiveID(); - } - else if (g.SliderCurrentAccumDirty) + if (g.SliderCurrentAccumDirty) { clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); @@ -3226,7 +3248,6 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta); } - g.SliderCurrentAccumDirty = false; } } @@ -3281,6 +3302,33 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); IM_ASSERT((flags & ImGuiSliderFlags_WrapAround) == 0); // Not supported by SliderXXX(), only by DragXXX() + // Things we can do easily outside the SliderBehaviorT<> template, saves code generation. + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + { + if (g.ActiveIdIsJustActivated) + { + g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation + g.SliderCurrentAccumDirty = false; + } + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (ShortcutsForCancel(id) && g.ActiveId == id) //-V560 + { + // Canceling action reverts to initial value + size_t data_size = DataTypeGetInfo(data_type)->Size; + bool value_changed = memcmp(p_v, &g.ActiveIdValueOnActivation, data_size); + memcpy(p_v, &g.ActiveIdValueOnActivation, data_size); + ClearActiveID(); + return value_changed; + } + } + switch (data_type) { case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } @@ -3391,11 +3439,16 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format); if (g.LogEnabled) LogSetNextTextDecoration("{", "}"); + if (is_mixed) + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + if (is_mixed) + PopStyleColor(); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false); @@ -3545,9 +3598,15 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. // For the vertical slider we allow centered text to overlap the frame padding + const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; char value_buf[64]; - const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format); + if (is_mixed) + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]); RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); + if (is_mixed) + PopStyleColor(); + if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false); @@ -3633,6 +3692,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_ const char* fmt_end = ImParseFormatFindEnd(fmt_start); if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. return fmt_start; + buf[0] = 0; // Fix false positive with caller assuming that buf could be non-initialized (#9508) ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); return buf; } @@ -3784,6 +3844,10 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG // Only mark as edited if new value is different g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) + if (ImGuiInputTextState* state = GetInputTextState(g.LastItemData.ID)) + value_changed |= (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputScalar) ? (state->EditedThisFrame | state->ValidatedThisFrame) : state->ValidatedThisFrame; + if (value_changed) MarkItemEdited(id); return value_changed; @@ -3860,6 +3924,9 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL); } } + if (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) + if (ImGuiInputTextState* state = GetInputTextState(g.LastItemData.ID)) + value_changed |= (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputScalar) ? (state->EditedThisFrame | state->ValidatedThisFrame) : state->ValidatedThisFrame; // Step buttons if (has_step_buttons) @@ -4165,7 +4232,7 @@ static int STB_TEXTEDIT_MOVELINESTART_IMPL(ImGuiInputTextState* obj, ImStb::STB_ const char* p_eol = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, p, text_end, obj->WrapWidth, ImDrawTextFlags_WrapKeepBlanks); if (p == p_cursor) // If we are already on a visible beginning-of-line, return real beginning-of-line (would be same as regular handler below) return (int)(p_bol - obj->TextSrc); - if (p_eol == p_cursor && obj->TextA[cursor] != '\n' && obj->LastMoveDirectionLR == ImGuiDir_Left) + if (p_eol == p_cursor && obj->TextSrc[cursor] != '\n' && obj->LastMoveDirectionLR == ImGuiDir_Left) return (int)(p_bol - obj->TextSrc); if (p_eol >= p_cursor) return (int)(p - obj->TextSrc); @@ -4728,7 +4795,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not not work with left-trimming + IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not work with left-trimming IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Password) == 0); // WordWrap does not work with Password mode. IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Multiline) != 0); // WordWrap does not work in single-line mode. @@ -4825,6 +4892,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; + const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! @@ -4911,7 +4979,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!is_multiline) { - if (flags & ImGuiInputTextFlags_AutoSelectAll) + if ((flags & ImGuiInputTextFlags_AutoSelectAll) || is_mixed) select_all = true; if (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) select_all = true; @@ -4989,7 +5057,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Select the buffer to render. const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state; - bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextSrc : buf)[0] == 0) && !is_mixed; // Password pushes a temporary font with only a fallback glyph if (is_password && !is_displaying_hint) @@ -4998,6 +5066,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (state != NULL && state->ID == id) { state->Flags = flags; + state->EditedThisFrame = state->ValidatedThisFrame = false; //state->LastFrameActive = g.FrameCount; // Word-wrapping: attempt to keep cursor in view while resizing frame/parent (FIXME-WORDWRAP: would be better to preserve same relative offset) @@ -5013,7 +5082,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.ActiveId == id) { IM_ASSERT(state != NULL); - state->EditedThisFrame = false; state->BufCapacity = buf_size; state->WrapWidth = wrap_width; @@ -5215,7 +5283,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { if (flags & ImGuiInputTextFlags_EscapeClearsAll) { - if (state->TextA.Data[0] != 0) + if (state->TextSrc[0] != 0) { revert_edit = true; } @@ -5308,14 +5376,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (flags & ImGuiInputTextFlags_EscapeClearsAll) { // Clear input - IM_ASSERT(state->TextA.Data[0] != 0); + IM_ASSERT(state->TextSrc[0] != 0); apply_new_text = ""; apply_new_text_length = 0; value_changed = true; char empty_string = 0; stb_textedit_replace(state, state->Stb, &empty_string, 0); } - else if (strcmp(state->TextA.Data, state->TextToRevertTo.Data) != 0) + else if (strcmp(state->TextSrc, state->TextToRevertTo.Data) != 0) { apply_new_text = state->TextToRevertTo.Data; apply_new_text_length = state->TextToRevertTo.Size - 1; @@ -5416,7 +5484,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputText) { // Apply when modified - if (strcmp(state->TextSrc, buf) != 0) + if (strcmp(state->TextSrc, buf) != 0 || (is_mixed && (state->EditedThisFrame || validated))) { apply_new_text = state->TextSrc; apply_new_text_length = state->TextLen; @@ -5426,7 +5494,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else { // Apply on validation/deactivation, otherwise cancel out previous apply attempts (e.g. revert) - value_changed = ((validated || clear_active_id || revert_edit) && strcmp(state->TextSrc, buf) != 0); + value_changed = (validated || clear_active_id || revert_edit) && (strcmp(state->TextSrc, buf) != 0 || (is_mixed && validated)); apply_new_text = value_changed ? state->TextSrc : NULL; apply_new_text_length = value_changed ? state->TextLen : 0; } @@ -5511,7 +5579,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Display hint when contents is empty // At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368) - const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0) && !is_mixed; if (new_is_displaying_hint != is_displaying_hint) { if (is_password && !is_displaying_hint) @@ -5520,10 +5588,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_password && !is_displaying_hint) PushPasswordFont(); } - if (is_displaying_hint) + const bool is_displaying_mixed = is_mixed && g.ActiveId != id && apply_new_text == NULL; + if (is_displaying_mixed && g.MixedValueLabel != NULL) + { + buf_display = g.MixedValueLabel; + buf_display_end = buf_display + strlen(g.MixedValueLabel); + render_cursor = render_selection = false; + } + else if (is_displaying_hint) { buf_display = hint; - buf_display_end = hint + ImStrlen(hint); + buf_display_end = buf_display + ImStrlen(buf_display); } else { @@ -5563,7 +5638,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 draw_scroll; // Render text. We currently only render selection when the widget is active or while scrolling. - const ImU32 text_col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + const ImU32 text_col = GetColorU32(is_displaying_mixed ? ImGuiCol_TextMixedValue : is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); if (render_cursor || render_selection) { // Render text (with cursor and selection) @@ -5684,9 +5759,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->CursorAnim += io.DeltaTime; bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); - ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + ImRect cursor_screen_rect = ImRect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 1.0f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.0f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), style.InputTextCursorSize); + draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), style.InputTextCursorSize, ImDrawFlags_StrokeInside); // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) // This is required for some backends (SDL3) to start emitting character/text inputs. @@ -5736,6 +5811,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false); + if (state && validated) + state->ValidatedThisFrame = true; if (value_changed) MarkItemEdited(id); @@ -6012,7 +6089,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + PushItemFlag(ImGuiItemFlags_MixedValue, false); value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + PopItemFlag(); } EndPopup(); } @@ -6126,6 +6205,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl const bool is_readonly = ((g.NextItemData.ItemFlagsSet | g.CurrentItemFlags) & ImGuiItemFlags_ReadOnly) != 0; g.NextItemData.ClearFlags(); + const float backup_alpha = g.Style.Alpha; + if (g.DisabledStackSize > 0) + g.Style.Alpha = g.DisabledAlphaBackup; // Cancel out effect of BeginDisabled() for color swatches. + PushID(label); const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); if (set_current_color_edit_id) @@ -6283,6 +6366,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if (!(flags & ImGuiColorEditFlags_NoSidePreview)) { PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + PushItemFlag(ImGuiItemFlags_MixedValue, false); ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); if ((flags & ImGuiColorEditFlags_NoLabel)) Text("Current"); @@ -6300,6 +6384,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } } PopItemFlag(); + PopItemFlag(); EndGroup(); } @@ -6465,7 +6550,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { float alpha = ImSaturate(col[3]); ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); - RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), style.Alpha, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); @@ -6483,6 +6568,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl g.ColorEditCurrentID = 0; PopID(); + if (g.DisabledStackSize > 0) + g.Style.Alpha = backup_alpha; + return value_changed; } @@ -6515,34 +6603,42 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (flags & ImGuiColorEditFlags_InputHSV) ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z); - ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); - float grid_step = ImMin(size.x, size.y) / 2.99f; - float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); - ImRect bb_inner = bb; - float off = 0.0f; - if ((flags & ImGuiColorEditFlags_NoBorder) == 0) - { - off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. - bb_inner.Expand(off); + const ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); + const float grid_step = ImMin(size.x, size.y) / 2.99f; + const float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); + const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; + + const float backup_alpha = g.Style.Alpha; + if (g.DisabledStackSize > 0) + g.Style.Alpha = g.DisabledAlphaBackup; // Cancel out effect of BeginDisabled() for color swatches. + if (is_mixed) + { + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]); + if (g.MixedValueLabel != NULL) + RenderTextClipped(ImVec2(bb.Min.x, bb.Min.y + g.Style.FramePadding.y), bb.Max, g.MixedValueLabel, NULL, NULL, ImVec2(0.5f, 0.0f)); + PopStyleColor(); } - if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) + else if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { - float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); + float mid_x = IM_ROUND((bb.Min.x + bb.Max.x) * 0.5f); if ((flags & ImGuiColorEditFlags_AlphaNoBg) == 0) - RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb.Min.x + grid_step, bb.Min.y), bb.Max, ColorConvertFloat4ToU32(col_rgb), g.Style.Alpha, grid_step, ImVec2(-grid_step, 0.0f), rounding, ImDrawFlags_RoundRight); else - window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundCornersRight); - window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); + window->DrawList->AddRectFilled(ImVec2(bb.Min.x + grid_step, bb.Min.y), bb.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundRight); + window->DrawList->AddRectFilled(bb.Min, ImVec2(mid_x, bb.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundLeft); } else { // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaOpaque) ? col_rgb_without_alpha : col_rgb; if (col_source.w < 1.0f && (flags & ImGuiColorEditFlags_AlphaNoBg) == 0) - RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + RenderColorRectWithAlphaCheckerboard(window->DrawList, bb.Min, bb.Max, ColorConvertFloat4ToU32(col_source), g.Style.Alpha, grid_step, ImVec2(0.0f, 0.0f), rounding); else - window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(col_source), rounding); } + if (g.DisabledStackSize > 0) + g.Style.Alpha = backup_alpha; RenderNavCursor(bb, id); if ((flags & ImGuiColorEditFlags_NoBorder) == 0) { @@ -6560,7 +6656,9 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once); else SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once); + PushItemFlag(ImGuiItemFlags_MixedValue, false); ColorButton(desc_id, col, flags); + PopItemFlag(); SameLine(); TextEx("Color"); EndDragDropSource(); @@ -6604,7 +6702,9 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_; + PushItemFlag(ImGuiItemFlags_MixedValue, false); ColorButton("##preview", cf, (flags & flags_to_forward) | ImGuiColorEditFlags_NoTooltip, sz); + PopItemFlag(); SameLine(); if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) { @@ -6886,7 +6986,7 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) } // Store ImGuiTreeNodeStackData for just submitted node. -// Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase. +// Currently only supports 32 level deep. Easy to increase to e.g. 64. static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) { ImGuiContext& g = *GImGui; @@ -6909,6 +7009,9 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) window->DC.TreeRecordsClippedNodesY2Mask |= (1 << window->DC.TreeDepth); } +#define TREE_NODE_MAX_DEPTH 32 +#define TREE_NODE_GET_DEPTH_MASK(_DEPTH) (((ImU32)(_DEPTH) < TREE_NODE_MAX_DEPTH) ? (1u << (_DEPTH)) : 0u) + bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) { ImGuiWindow* window = GetCurrentWindow(); @@ -6985,7 +7088,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); - if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen) && window->DC.TreeDepth < TREE_NODE_MAX_DEPTH) { store_tree_node_stack_data = draw_tree_lines; if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) && !g.NavIdIsAlive) @@ -6996,12 +7099,16 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; if (!is_visible) { - if ((flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeRecordsClippedNodesY2Mask & (1 << (window->DC.TreeDepth - 1)))) + if (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) { - ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. - if (frame_bb.Min.y >= window->ClipRect.Max.y) - window->DC.TreeRecordsClippedNodesY2Mask &= ~(1 << (window->DC.TreeDepth - 1)); // Done + const ImU32 tree_depth_mask = TREE_NODE_GET_DEPTH_MASK(window->DC.TreeDepth - 1); + if (window->DC.TreeRecordsClippedNodesY2Mask & tree_depth_mask) + { + ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. + if (frame_bb.Min.y >= window->ClipRect.Max.y) + window->DC.TreeRecordsClippedNodesY2Mask &= ~tree_depth_mask; // Done + } } if (is_open && store_tree_node_stack_data) TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() @@ -7198,20 +7305,22 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (window->DC.TreeDepth == 0 || (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) + if ((window->DC.TreeHasStackDataDepthMask & TREE_NODE_GET_DEPTH_MASK(window->DC.TreeDepth - 1)) == 0) return; + // FIXME: Could this be simplified using new stroke flags? ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - float x1 = ImTrunc(parent_data->DrawLinesX1); + const float half_size = g.Style.TreeLinesSize * 0.5f; + float x1 = ImTrunc(parent_data->DrawLinesX1 - half_size) + half_size; // Draw line centered at X1, but snap to pixels boundary. float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); - float y = ImTrunc(target_pos.y); + float y = ImTrunc(target_pos.y - half_size) + half_size; float rounding = (g.Style.TreeLinesRounding > 0.0f) ? ImMin(x2 - x1, g.Style.TreeLinesRounding) : 0.0f; parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y - rounding); if (x1 >= x2) return; - if (rounding > 0.0f) + if (rounding > 0.0f && rounding > half_size) { - x1 += 0.5f + rounding; + x1 += rounding; window->DrawList->PathArcToFast(ImVec2(x1, y - rounding), rounding, 6, 3); if (x1 < x2) window->DrawList->PathLineTo(ImVec2(x2, y)); @@ -7219,7 +7328,10 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) } else { - window->DrawList->AddLineH(x1, x2, y, GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + // We use AddLine() instead of AddLineH() as we provide coordinates for line center, + // in order to make the code use same coordinates for both rounded and non-rounded version. (FIXME-OPT) + x1 += half_size; // Avoid overdraw + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } } @@ -7242,10 +7354,12 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) y2 = ImMin(y2, window->ClipRect.Max.y); if (y2 <= y1) return; - float x = ImTrunc(data->DrawLinesX1); + float x = ImTrunc(data->DrawLinesX1 - g.Style.TreeLinesSize * 0.5f) + g.Style.TreeLinesSize * 0.5f; // Draw line centered at X1, but snap to pixels boundary. if (data->DrawLinesTableColumn != -1) TablePushColumnChannel(data->DrawLinesTableColumn); - window->DrawList->AddLineV(x, y1, y2, GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + + // We use AddLine() instead of AddLineV() as we provide coordinates for line center (FIXME-OPT) + window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); if (data->DrawLinesTableColumn != -1) TablePopColumnChannel(); } @@ -7282,8 +7396,7 @@ void ImGui::TreePop() Unindent(); window->DC.TreeDepth--; - ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); - + ImU32 tree_depth_mask = TREE_NODE_GET_DEPTH_MASK(window->DC.TreeDepth); if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) { const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; @@ -7510,7 +7623,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) // - (2) usage will fail with clipped items // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. - if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId) + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId && !g.NavJustMovedToIsInit) if (g.NavJustMovedToId == id && (g.NavJustMovedToKeyMods & ImGuiMod_Ctrl) == 0) selected = pressed = auto_selected = true; } @@ -9031,7 +9144,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); - // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + // We could render lower-level to save a bit of CPU. ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); if (plot_type == ImGuiPlotType_Lines) @@ -9042,6 +9155,8 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get { if (pos1.x >= pos0.x + 2.0f) pos1.x -= 1.0f; + if (pos0.y > pos1.y) + ImSwap(pos0.y, pos1.y); window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); } @@ -10114,16 +10229,17 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) } // Horizontal scrolling buttons - // Important: note that TabBarScrollButtons() will alter BarRect.Max.x. + // - Important: note that TabBarScrollButtons() will alter BarRect.Max.x. + // - Selection skips buttons and might cross through sections if there are Tabs in Leading/Trailing sections. const bool can_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) || (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed); const float width_all_tabs_to_use_for_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) ? tab_bar->WidthAllTabs : width_all_tabs_after_min_width_shrink; tab_bar->ScrollButtonEnabled = ((width_all_tabs_to_use_for_scroll > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && can_scroll); if (tab_bar->ScrollButtonEnabled) if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) { - scroll_to_tab_id = scroll_and_select_tab->ID; if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) - tab_bar->SelectedTabId = scroll_to_tab_id; + tab_bar->SelectedTabId = scroll_and_select_tab->ID; + scroll_to_tab_id = scroll_and_select_tab->ID; } if (scroll_to_tab_id == 0 && scroll_to_selected_tab) scroll_to_tab_id = tab_bar->SelectedTabId; @@ -10296,6 +10412,14 @@ const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) return tab_bar->TabsNames.Buf.Data + tab->NameOffset; } +ImVec2 ImGui::TabBarGetTabPos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if ((tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0) + return tab_bar->BarRect.Min + ImVec2(IM_TRUNC(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + else + return tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); +} + // The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) { @@ -10343,11 +10467,20 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); if (tab == NULL) return; + + // Clamp attempt to scroll to leading/trailing sections items. + // This could be done at the TabBarScrollingButtons() call site as well, but here works. + if (tab->Flags & ImGuiTabItemFlags_Leading) + tab = &tab_bar->Tabs[sections[0].TabCount]; + else if (tab->Flags & ImGuiTabItemFlags_Trailing) + tab = &tab_bar->Tabs[sections[0].TabCount + sections[1].TabCount]; if (tab->Flags & ImGuiTabItemFlags_SectionMask_) return; + // When scrolling to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + // Disable the margin if the scrolling section is too small for the target tab: prefer displaying a maximum of the label. ImGuiContext& g = *GImGui; - float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + float margin = ImClamp(tab_bar->ScrollingRectMaxX - tab_bar->ScrollingRectMinX - tab->Width, g.Style.ItemInnerSpacing.x, g.FontSize * 1.0f); int order = TabBarGetTabOrder(tab_bar, tab); // Scrolling happens only in the central section (leading/trailing sections are not scrolling) @@ -10749,10 +10882,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Layout const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; size.x = tab->Width; - if (is_central_section) - window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_TRUNC(tab->Offset - tab_bar->ScrollingAnim), 0.0f); - else - window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); + window->DC.CursorPos = TabBarGetTabPos(tab_bar, tab); ImVec2 pos = window->DC.CursorPos; ImRect bb(pos, pos + size); @@ -10823,8 +10953,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) { // Might be moved to TabItemBackground() ? - ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); + ImVec2 tl = bb.GetTL() + ImVec2(0, style.TabBarOverlineSize * 0.5f); + ImVec2 tr = bb.GetTR() + ImVec2(0, style.TabBarOverlineSize * 0.5f); ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); if (style.TabRounding > 0.0f) { @@ -10835,7 +10965,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } else { - display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); + display_draw_list->AddLine(tl, tr, overline_col, style.TabBarOverlineSize); } } RenderNavCursor(bb, id); @@ -10924,14 +11054,14 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); const float y1 = bb.Min.y + 1.0f; // Leave a bit of room in title bars. const float y2 = bb.Max.y - g.Style.TabBarBorderSize; - draw_list->AddRectFilled(bb.Min, ImVec2(bb.Max.x, y2), col, rounding, ImDrawFlags_RoundCornersTop); + draw_list->AddRectFilled(ImVec2(bb.Min.x, y1), ImVec2(bb.Max.x, y2), col, rounding, ImDrawFlags_RoundTop); if (g.Style.TabBorderSize > 0.0f) { - draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); - draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); - draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); - draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); - draw_list->PathStroke(GetColorU32(ImGuiCol_Border), g.Style.TabBorderSize); + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), g.Style.TabBorderSize, ImDrawFlags_StrokeCenterBiased); // Use _StrokeInside? } } diff --git a/include/imgui/misc/debuggers/README.txt b/include/imgui/misc/debuggers/README.txt index ad6f491..22a66a0 100644 --- a/include/imgui/misc/debuggers/README.txt +++ b/include/imgui/misc/debuggers/README.txt @@ -1,12 +1,14 @@ -HELPER FILES FOR POPULAR DEBUGGERS +----------------------------------------------------------------------------- + HELPER FILES FOR POPULAR DEBUGGERS +----------------------------------------------------------------------------- imgui.gdb - GDB: disable stepping into trivial functions. + GDB: disable stepping into trivial functions (*1). (read comments inside file for details) imgui.natstepfilter - Visual Studio Debugger: disable stepping into trivial functions. + Visual Studio Debugger: disable stepping into trivial functions (*1). (read comments inside file for details) imgui.natvis @@ -15,7 +17,23 @@ imgui.natvis (read comments inside file for details) imgui_lldb.py - LLDB-based debuggers (*): synthetic children provider and summaries for Dear ImGui types. + LLDB-based debuggers (*2): synthetic children provider and summaries for Dear ImGui types. With this, types like ImVector<> will be displayed nicely in the debugger. (read comments inside file for details) - (*) Xcode, Android Studio, may be used from VS Code, C++Builder, CLion, Eclipse etc. + (*2) Xcode, Android Studio, may be used from VS Code, C++Builder, CLion, Eclipse etc. + +----------------------------------------------------------------------------- + NEW! DISABLED STEPPING INTO TRIVIAL FUNCTIONS +----------------------------------------------------------------------------- + +Since 1.93.0 WIP (September 2026), +Dear ImGui uses a IM_NODEBUGSTEP macro to tag functions with __declspec(non_user_code) +or [[gnu::artificial]] to automatically tell debuggers to skip them. + +(*1) Assuming the new IM_NODEBUGSTEP macro works, using imgui.natstepfilter etc. +may become unnecessary. Exact side effects on user experience yet to be clarified. + +Additional references: + https://maskray.me/blog/skipping-boring-functions-in-debuggers + and https://news.ycombinator.com/item?id=42547576 + diff --git a/include/imgui/misc/debuggers/imgui.gdb b/include/imgui/misc/debuggers/imgui.gdb index 000ff6e..1229d05 100644 --- a/include/imgui/misc/debuggers/imgui.gdb +++ b/include/imgui/misc/debuggers/imgui.gdb @@ -9,4 +9,5 @@ # * https://sourceware.org/gdb/current/onlinedocs/gdb/Init-File-in-the-Current-Directory.html#Init-File-in-the-Current-Directory # Disable stepping into trivial functions +# ...since Dear ImGui 1.93.0 WIP (September 2026): we use a IM_NODEBUGSTEP() macro to provide the equivalent feature via [[gnu::artificial]]. skip -rfunction Im(Vec2|Vec4|Strv|Vector|Span)::.+ diff --git a/include/imgui/misc/debuggers/imgui.natstepfilter b/include/imgui/misc/debuggers/imgui.natstepfilter index 6825c93..82a30aa 100644 --- a/include/imgui/misc/debuggers/imgui.natstepfilter +++ b/include/imgui/misc/debuggers/imgui.natstepfilter @@ -14,6 +14,8 @@ If you have multiple VS version installed, the version that matters is the one y of (not the compiling toolset). This is supported since Visual Studio 2012. More information at: https://docs.microsoft.com/en-us/visualstudio/debugger/just-my-code?view=vs-2019#BKMK_C___Just_My_Code + +Since Dear ImGui 1.93.0 WIP (September 2026): we use a IM_NODEBUGSTEP() macro to provide the equivalent feature via __declspec(non_user_code). --> diff --git a/include/imgui/misc/freetype/imgui_freetype.cpp b/include/imgui/misc/freetype/imgui_freetype.cpp index 3c817d2..375863f 100644 --- a/include/imgui/misc/freetype/imgui_freetype.cpp +++ b/include/imgui/misc/freetype/imgui_freetype.cpp @@ -7,6 +7,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026/09/25: fixed handling of ExtraSizeScale. // 2025/06/11: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. // 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. @@ -220,17 +221,14 @@ void ImGui_ImplFreeType_FontSrcData::CloseFont() } } -static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_FontSrcData* src_data, uint32_t codepoint) +static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_FontSrcData* src_data, uint32_t glyph_index) { - uint32_t glyph_index = FT_Get_Char_Index(src_data->FtFace, codepoint); - if (glyph_index == 0) - return nullptr; - // If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts. // - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 // - https://github.com/ocornut/imgui/issues/4567 // - https://github.com/ocornut/imgui/issues/4566 // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. + IM_ASSERT(glyph_index != 0); FT_Error error = FT_Load_Glyph(src_data->FtFace, glyph_index, src_data->LoadFlags); if (error) return nullptr; @@ -416,17 +414,15 @@ static bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src return true; } -static void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) +static void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas*, ImFontConfig* src) { - IM_UNUSED(atlas); ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; IM_DELETE(bd_font_data); src->FontLoaderData = nullptr; } -static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) +static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { - IM_UNUSED(atlas); float size = baked->Size; const float ref_size = baked->OwnerFont->Sources[0]->SizePixels; if (src->MergeMode && src->SizePixels != 0.0f) @@ -463,18 +459,19 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; const float scale = 1.0f / (rasterizer_density * src->ExtraSizeScale); - baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). - baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). + baked->Ascent = ((float)metrics.ascender / FT_SCALEFACTOR) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Descent = ((float)metrics.descender / FT_SCALEFACTOR) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. + baked->Ascent = ImRoundSigned64(baked->Ascent * rasterizer_density) / rasterizer_density; + baked->Descent = ImRoundSigned64(baked->Descent * rasterizer_density) / rasterizer_density; } return true; } -static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) +static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas*, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { - IM_UNUSED(atlas); IM_UNUSED(baked); IM_UNUSED(src); ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; @@ -483,13 +480,9 @@ static void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } -static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x) +static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, int glyph_index, ImFontGlyph* out_glyph, float* out_advance_x) { ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; - uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); - if (glyph_index == 0) - return false; - if (bd_font_data->BakedLastActivated != baked) // <-- could use id { // Activate current size @@ -498,7 +491,7 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf bd_font_data->BakedLastActivated = baked; } - const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, codepoint); + const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, glyph_index); if (metrics == nullptr) return false; @@ -508,9 +501,9 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf // Load metrics only mode const float advance_x = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; - if (out_advance_x != NULL) + if (out_advance_x != nullptr) { - IM_ASSERT(out_glyph == NULL); + IM_ASSERT(out_glyph == nullptr); *out_advance_x = advance_x; return true; } @@ -527,7 +520,6 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf const bool is_visible = (w != 0 && h != 0); // Prepare glyph - out_glyph->Codepoint = codepoint; out_glyph->AdvanceX = advance_x; // Pack and retrieve position inside texture atlas @@ -570,12 +562,16 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf return true; } -static bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) +static int ImGui_ImplFreetype_FontSrcGetGlyphIndexFromCodepoint(ImFontAtlas*, ImFontConfig* src, ImWchar codepoint) +{ + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + return (int)FT_Get_Char_Index(bd_font_data->FtFace, codepoint); +} + +static bool ImGui_ImplFreeType_FontSrcContainsGlyph(ImFontAtlas*, ImFontConfig* src, int glyph_index) { - IM_UNUSED(atlas); ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; - int glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); - return glyph_index != 0; + return glyph_index > 0 && glyph_index < bd_font_data->FtFace->num_glyphs; } const ImFontLoader* ImGuiFreeType::GetFontLoader() @@ -586,7 +582,8 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader() loader->LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown; loader->FontSrcInit = ImGui_ImplFreeType_FontSrcInit; loader->FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy; - loader->FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph; + loader->FontSrcGetGlyphIndexFromCodepoint = ImGui_ImplFreetype_FontSrcGetGlyphIndexFromCodepoint; + loader->FontSrcContainsGlyph = ImGui_ImplFreeType_FontSrcContainsGlyph; loader->FontBakedInit = ImGui_ImplFreeType_FontBakedInit; loader->FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy; loader->FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph; diff --git a/include/imgui/misc/single_file/imgui_single_file.h b/include/imgui/misc/single_file/imgui_single_file.h index 7ca31e0..bea1cb6 100644 --- a/include/imgui/misc/single_file/imgui_single_file.h +++ b/include/imgui/misc/single_file/imgui_single_file.h @@ -1,14 +1,14 @@ // dear imgui: single-file wrapper include // We use this to validate compiling all *.cpp files in a same compilation unit. -// Users of that technique (also called "Unity builds") can generally provide this themselves, -// so we don't really recommend you use this in your projects. +// Users of that technique (also called "Unity builds") can generally provide this themselves easily. // Do this: // #define IMGUI_IMPLEMENTATION -// Before you include this file in *one* C++ file to create the implementation. +// #include "imgui_single_file.h" +// In *one* C++ file to create the implementation. // Using this in your project will leak the contents of imgui_internal.h and ImVec2 operators in this compilation unit. -#ifdef IMGUI_IMPLEMENTATION +#if defined(IMGUI_IMPLEMENTATION) && !defined(IMGUI_DEFINE_MATH_OPERATORS) #define IMGUI_DEFINE_MATH_OPERATORS #endif diff --git a/include/implot/.github/CMakeLists.txt b/include/implot/.github/CMakeLists.txt index 67bf4b5..8ec6ac6 100644 --- a/include/implot/.github/CMakeLists.txt +++ b/include/implot/.github/CMakeLists.txt @@ -73,7 +73,7 @@ endif() # Define supported types via command line: # - With no choice all types are supported (so that the CI provides support for all known types) -# - with -DIMPLOT_CUSTOM_NUMERIC_TYPES="default" the default set defined in implot_items.cpp is used +# - with -DIMPLOT_CUSTOM_NUMERIC_TYPES="default" the default set defined in implot_internal.h is used # - with -DIMPLOT_CUSTOM_NUMERIC_TYPES="(int)(float)(double)" only int, float and double are supported if (NOT DEFINED IMPLOT_CUSTOM_NUMERIC_TYPES) set(IMPLOT_CUSTOM_NUMERIC_TYPES "all") diff --git a/include/implot/.github/workflows/build.yml b/include/implot/.github/workflows/build.yml index d401e43..3b829af 100644 --- a/include/implot/.github/workflows/build.yml +++ b/include/implot/.github/workflows/build.yml @@ -45,6 +45,26 @@ jobs: file cmake-build/example_implot cmake-build/example_implot + Linux-custom-types: + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v3 + + - uses: actions/checkout@v3 + with: + repository: ocornut/imgui + path: imgui + + - name: Configure + run: cmake -DCMAKE_BUILD_TYPE=release "-DIMPLOT_CUSTOM_NUMERIC_TYPES=(float)(double)" -B cmake-build -S .github + + - name: Build + run: cmake --build cmake-build --parallel $(nproc) + + - name: Run + run: cmake-build/example_implot + MacOS: runs-on: macos-latest diff --git a/include/implot/README.md b/include/implot/README.md index 54249b4..3769e99 100644 --- a/include/implot/README.md +++ b/include/implot/README.md @@ -135,7 +135,7 @@ A: Yes, within reason. You can plot tens to hundreds of thousands of points with **Q: What data types can I plot?** A: ImPlot plotting functions accept most scalar types: -`float`, `double`, `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`. Arrays of custom structs or classes (e.g. `Vector2f` or similar) are easily passed to ImPlot functions using the built-in striding features (see `implot.h` for documentation), and many plotters provide a "getter" overload which accepts data generating callbacks. You can fully customize the list of accepted types by defining `IMPLOT_CUSTOM_NUMERIC_TYPES` at compile time: see doc in `implot_items.cpp`. +`float`, `double`, `int8`, `uint8`, `int16`, `uint16`, `int32`, `uint32`, `int64`, `uint64`. Arrays of custom structs or classes (e.g. `Vector2f` or similar) are easily passed to ImPlot functions using the built-in striding features (see `implot.h` for documentation), and many plotters provide a "getter" overload which accepts data generating callbacks. You can fully customize the list of accepted types by defining `IMPLOT_CUSTOM_NUMERIC_TYPES` at compile time: see doc in `implot_internal.h` (the define must be visible to every ImPlot source file, including `implot_demo.cpp`, or be set in `imconfig.h`). **Q: Can plot styles be modified?** diff --git a/include/implot/example/CMakeLists.txt b/include/implot/example/CMakeLists.txt index 8246a59..313b728 100644 --- a/include/implot/example/CMakeLists.txt +++ b/include/implot/example/CMakeLists.txt @@ -24,7 +24,7 @@ FetchContent_MakeAvailable(glfw) FetchContent_Declare( imgui GIT_REPOSITORY "https://github.com/ocornut/imgui" - GIT_TAG "v1.92.4" + GIT_TAG "v1.93.0" GIT_PROGRESS TRUE GIT_SHALLOW TRUE ) diff --git a/include/implot/implot.cpp b/include/implot/implot.cpp index 032d2ad..5246972 100644 --- a/include/implot/implot.cpp +++ b/include/implot/implot.cpp @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v1.1 WIP +// ImPlot v1.2 WIP /* @@ -215,8 +215,6 @@ You can read releases logs https://github.com/epezent/implot/releases for more d // Clang/GCC warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked #endif @@ -307,6 +305,8 @@ const char* GetMarkerName(ImPlotMarker marker) { case ImPlotMarker_Cross: return "Cross"; case ImPlotMarker_Plus: return "Plus"; case ImPlotMarker_Asterisk: return "Asterisk"; + case ImPlotMarker_Vertical: return "Vertical"; + case ImPlotMarker_Horizontal: return "Horizontal"; default: return ""; } } @@ -763,7 +763,12 @@ void Locator_Default(ImPlotTicker& ticker, const ImPlotRange& range, float pixel const int nMinor = 10; const int nMajor = ImMax(2, (int)IM_ROUND(pixels / (vertical ? 300.0f : 400.0f))); const double nice_range = NiceNum(range.Size() * 0.99, false); - const double interval = NiceNum(nice_range / (nMajor - 1), true); + double interval = NiceNum(nice_range / (nMajor - 1), true); + // keep interval >= one ULP so `major += interval` always advances (e.g. range from SetupAxisLimits(v, v)) + const double magnitude = ImMax(ImAbs(range.Min), ImAbs(range.Max)); + const double min_interval = nextafter(magnitude, HUGE_VAL) - magnitude; + if (interval < min_interval) + interval = min_interval; const double graphmin = floor(range.Min / interval) * interval; const double graphmax = ceil(range.Max / interval) * interval; bool first_major_set = false; @@ -1390,6 +1395,7 @@ void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool /*time_a bool grid = axis.HasGridLines(); bool ticks = axis.HasTickMarks(); bool labels = axis.HasTickLabels(); + bool labelsInside = axis.HasTickLabelsInside(); double drag_speed = (axis.Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * axis.Range.Size(); // recover from almost equal axis limits. if (axis.Scale == ImPlotScale_Time) { @@ -1494,7 +1500,8 @@ void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool /*time_a ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks); if (ImGui::Checkbox("Tick Labels", &labels)) ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels); - + if (ImGui::Checkbox("Tick Labels Inside", &labelsInside)) + ImFlipFlag(axis.Flags, ImPlotAxisFlags_TickLabelsInside); } bool ShowLegendContextMenu(ImPlotLegend& legend, bool visible) { @@ -1664,7 +1671,42 @@ void UpdateAxisColors(ImPlotAxis& axis) { // axis.ColorHiLi = IM_COL32_BLACK_TRANS; } -void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignmentData* align) { +static void FindInnermostAxesX(ImPlotPlot& plot, int& innermost_T, int& innermost_B) { + innermost_T = innermost_B = -1; + for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) { + ImPlotAxis& axis = plot.XAxis(i); + if (!axis.Enabled) + continue; + const bool opp = axis.IsOpposite(); + if (opp && innermost_T == -1) + innermost_T = i; + if (!opp && innermost_B == -1) + innermost_B = i; + } +} + +static void FindInnermostAxesY(ImPlotPlot& plot, int& innermost_L, int& innermost_R) { + innermost_L = innermost_R = -1; + for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) { + ImPlotAxis& axis = plot.YAxis(i); + if (!axis.Enabled) + continue; + const bool opp = axis.IsOpposite(); + if (opp && innermost_R == -1) + innermost_R = i; + if (!opp && innermost_L == -1) + innermost_L = i; + } +} + +static bool IsInnermostAxis(int i, bool opp, int innermost, int innermost_opp) { + if (opp) + return i == innermost_opp; + else + return i == innermost; +} + +void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, int innermost_T, int innermost_B, ImPlotAlignmentData* align) { ImPlotContext& gp = *GImPlot; @@ -1684,6 +1726,7 @@ void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignm const bool label = axis.HasLabel(); const bool ticks = axis.HasTickLabels(); const bool opp = axis.IsOpposite(); + const bool ins = axis.HasTickLabelsInside() && IsInnermostAxis(i, opp, innermost_B, innermost_T); const bool time = axis.Scale == ImPlotScale_Time; if (opp) { if (count_T++ > 0) @@ -1692,8 +1735,11 @@ void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignm ImVec2 label_size = ImGui::CalcTextSize(plot.GetAxisLabel(axis)); pad_T += label_size.y + P; } - if (ticks) + if (ticks && !ins) pad_T += ImMax(T, axis.Ticker.MaxSize.y) + P + (time ? T + P : 0); + // fix ins axis rect overlapping plot title if no label is present and there are no other axes above + if (ins && !label && count_T == 1 && plot.HasTitle()) + pad_T += K + P; axis.Datum1 = plot.CanvasRect.Min.y + pad_T; axis.Datum2 = last_T; last_T = axis.Datum1; @@ -1705,7 +1751,7 @@ void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignm ImVec2 label_size = ImGui::CalcTextSize(plot.GetAxisLabel(axis)); pad_B += label_size.y + P; } - if (ticks) + if (ticks && !ins) pad_B += ImMax(T, axis.Ticker.MaxSize.y) + P + (time ? T + P : 0); axis.Datum1 = plot.CanvasRect.Max.y - pad_B; axis.Datum2 = last_B; @@ -1733,7 +1779,7 @@ void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignm } } -void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, ImPlotAlignmentData* align) { +void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, int innermost_L, int innermost_R, ImPlotAlignmentData* align) { // [ pad_L ] [ pad_R ] // .................CanvasRect................ @@ -1768,12 +1814,13 @@ void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, ImPlotAlignm const bool label = axis.HasLabel(); const bool ticks = axis.HasTickLabels(); const bool opp = axis.IsOpposite(); + const bool ins = axis.HasTickLabelsInside() && IsInnermostAxis(i, opp, innermost_L, innermost_R); if (opp) { if (count_R++ > 0) pad_R += K + P; if (label) pad_R += T + P; - if (ticks) + if (ticks && !ins) pad_R += axis.Ticker.MaxSize.x + P; axis.Datum1 = plot.CanvasRect.Max.x - pad_R; axis.Datum2 = last_R; @@ -1784,7 +1831,7 @@ void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, ImPlotAlignm pad_L += K + P; if (label) pad_L += T + P; - if (ticks) + if (ticks && !ins) pad_L += axis.Ticker.MaxSize.x + P; axis.Datum1 = plot.CanvasRect.Min.x + pad_L; axis.Datum2 = last_L; @@ -1830,9 +1877,9 @@ static inline void RenderGridLinesX(ImDrawList& DrawList, const ImPlotTicker& ti continue; if (xt.Level == 0) { if (xt.Major) - DrawList.AddLine(ImVec2(xt.PixelPos, rect.Min.y), ImVec2(xt.PixelPos, rect.Max.y), col_maj, size_maj); + AddLineV(&DrawList, xt.PixelPos, rect.Min.y, rect.Max.y, col_maj, size_maj); else if (density < 0.2f) - DrawList.AddLine(ImVec2(xt.PixelPos, rect.Min.y), ImVec2(xt.PixelPos, rect.Max.y), col_min, size_min); + AddLineV(&DrawList, xt.PixelPos, rect.Min.y, rect.Max.y, col_min, size_min); } } } @@ -1847,9 +1894,9 @@ static inline void RenderGridLinesY(ImDrawList& DrawList, const ImPlotTicker& ti if (yt.PixelPos < rect.Min.y || yt.PixelPos > rect.Max.y) continue; if (yt.Major) - DrawList.AddLine(ImVec2(rect.Min.x, yt.PixelPos), ImVec2(rect.Max.x, yt.PixelPos), col_maj, size_maj); + AddLineH(&DrawList, rect.Min.x, rect.Max.x, yt.PixelPos, col_maj, size_maj); else if (density < 0.2f) - DrawList.AddLine(ImVec2(rect.Min.x, yt.PixelPos), ImVec2(rect.Max.x, yt.PixelPos), col_min, size_min); + AddLineH(&DrawList, rect.Min.x, rect.Max.x, yt.PixelPos, col_min, size_min); } } @@ -1876,7 +1923,7 @@ bool UpdateInput(ImPlotPlot& plot) { // BUTTON STATE ----------------------------------------------------------- - const ImGuiButtonFlags plot_button_flags = ImGuiButtonFlags_AllowOverlap + const ImGuiButtonFlags plot_button_flags = (ImGuiButtonFlags)ImGuiButtonFlags_AllowOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_MouseButtonLeft @@ -2449,6 +2496,8 @@ bool BeginPlot(const char* title_id, const ImVec2& size, ImPlotFlags flags) { plot.Items.ID = ID - 1; plot.JustCreated = just_created; plot.SetupLocked = false; + // the last item belongs to another plot (or to the previous frame) + gp.PreviousItem = nullptr; // check flags if (plot.JustCreated) @@ -2602,6 +2651,7 @@ void SetupFinish() { // plot bb float pad_top = 0, pad_bot = 0, pad_left = 0, pad_right = 0; + int innermost_top = -1, innermost_bot = -1, innermost_left = -1, innermost_right = -1; // (0) calc top padding form title ImVec2 title_size(0.0f, 0.0f); @@ -2613,7 +2663,8 @@ void SetupFinish() { } // (1) calc addition top padding and bot padding - PadAndDatumAxesX(plot,pad_top,pad_bot,gp.CurrentAlignmentH); + FindInnermostAxesX(plot, innermost_top, innermost_bot); + PadAndDatumAxesX(plot,pad_top,pad_bot,innermost_top,innermost_bot,gp.CurrentAlignmentH); const float plot_height = plot.CanvasRect.GetHeight() - pad_top - pad_bot; @@ -2626,7 +2677,8 @@ void SetupFinish() { } // (3) calc left/right pad - PadAndDatumAxesY(plot,pad_left,pad_right,gp.CurrentAlignmentV); + FindInnermostAxesY(plot, innermost_left, innermost_right); + PadAndDatumAxesY(plot,pad_left,pad_right,innermost_left,innermost_right,gp.CurrentAlignmentV); const float plot_width = plot.CanvasRect.GetWidth() - pad_left - pad_right; @@ -2643,7 +2695,7 @@ void SetupFinish() { const float title_pad = (title_size.x > 0) ? (title_size.y + gp.Style.LabelPadding.y) : 0.0f; pad_top = title_pad; pad_bot = 0; - PadAndDatumAxesX(plot,pad_top,pad_bot,gp.CurrentAlignmentH); + PadAndDatumAxesX(plot,pad_top,pad_bot,innermost_top,innermost_bot,gp.CurrentAlignmentH); // Update AxesRect to account for title padding (was done in step 0) if (title_size.x > 0) { plot.AxesRect.Min.y = plot.FrameRect.Min.y + gp.Style.PlotPadding.y + title_pad; @@ -2737,6 +2789,10 @@ void SetupFinish() { RenderGridLinesY(DrawList, y_axis.Ticker, plot.PlotRect, y_axis.ColorMaj, y_axis.ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y); } + // rects of the inside x tick labels drawn below, so inside y tick labels can skip the ones they overlap + ImVector& x_inside_label_rects = gp.TempRect1; + x_inside_label_rects.resize(0); + // render x axis button, label, tick labels for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) { ImPlotAxis& ax = plot.XAxis(i); @@ -2753,23 +2809,33 @@ void SetupFinish() { } const ImPlotTicker& tkr = ax.Ticker; const bool opp = ax.IsOpposite(); + const bool ins = ax.HasTickLabelsInside() && IsInnermostAxis(i, opp, innermost_bot, innermost_top); if (ax.HasLabel()) { const char* label = plot.GetAxisLabel(ax); const ImVec2 label_size = ImGui::CalcTextSize(label); - const float label_offset = (ax.HasTickLabels() ? tkr.MaxSize.y + gp.Style.LabelPadding.y : 0.0f) - + (tkr.Levels - 1) * (txt_height + gp.Style.LabelPadding.y) + const float label_offset = (ax.HasTickLabels() && !ins ? tkr.MaxSize.y + gp.Style.LabelPadding.y + + (tkr.Levels - 1) * (txt_height + gp.Style.LabelPadding.y) : 0.0f) + gp.Style.LabelPadding.y; const ImVec2 label_pos(plot.PlotRect.GetCenter().x - label_size.x * 0.5f, opp ? ax.Datum1 - label_offset - label_size.y : ax.Datum1 + label_offset); DrawList.AddText(label_pos, ax.ColorTxt, label); } if (ax.HasTickLabels()) { + const bool labels_opp = opp ^ ins; + // inside labels start past the tick marks, which are drawn inward from the plot edge + const float label_pad = ins && ax.HasTickMarks() ? gp.Style.MajorTickLen.x : gp.Style.LabelPadding.y; + const float level_pad = txt_height + gp.Style.LabelPadding.y; for (int j = 0; j < tkr.TickCount(); ++j) { const ImPlotTick& tk = tkr.Ticks[j]; - const float datum = ax.Datum1 + (opp ? (-gp.Style.LabelPadding.y -txt_height -tk.Level * (txt_height + gp.Style.LabelPadding.y)) - : gp.Style.LabelPadding.y + tk.Level * (txt_height + gp.Style.LabelPadding.y)); + const float pad = label_pad + (labels_opp ? tk.LabelSize.y : 0) + (tk.Level * level_pad); + const float datum = ax.Datum1 + pad * (labels_opp ? -1.0f : 1.0f); if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.x - 1 && tk.PixelPos <= plot.PlotRect.Max.x + 1) { ImVec2 start(tk.PixelPos - 0.5f * tk.LabelSize.x, datum); + // keep inside labels within the plot, shifting the ones at the ends along the axis + if (ins) { + start.x = ImMax(plot.PlotRect.Min.x, ImMin(start.x, plot.PlotRect.Max.x - tk.LabelSize.x)); + x_inside_label_rects.push_back(ImRect(start, start + tk.LabelSize)); + } DrawList.AddText(start, ax.ColorTxt, tkr.GetText(j)); } } @@ -2792,22 +2858,35 @@ void SetupFinish() { } const ImPlotTicker& tkr = ax.Ticker; const bool opp = ax.IsOpposite(); + const bool ins = ax.HasTickLabelsInside() && IsInnermostAxis(i, opp, innermost_left, innermost_right); if (ax.HasLabel()) { const char* label = plot.GetAxisLabel(ax); const ImVec2 label_size = CalcTextSizeVertical(label); - const float label_offset = (ax.HasTickLabels() ? tkr.MaxSize.x + gp.Style.LabelPadding.x : 0.0f) + const float label_offset = (ax.HasTickLabels() && !ins ? tkr.MaxSize.x + gp.Style.LabelPadding.x : 0.0f) + gp.Style.LabelPadding.x; const ImVec2 label_pos(opp ? ax.Datum1 + label_offset : ax.Datum1 - label_offset - label_size.x, plot.PlotRect.GetCenter().y + label_size.y * 0.5f); AddTextVertical(&DrawList, label_pos, ax.ColorTxt, label); } if (ax.HasTickLabels()) { + const bool labels_opp = opp ^ ins; + const float label_pad = ins && ax.HasTickMarks() ? gp.Style.MajorTickLen.y : gp.Style.LabelPadding.x; for (int j = 0; j < tkr.TickCount(); ++j) { const ImPlotTick& tk = tkr.Ticks[j]; - const float datum = ax.Datum1 + (opp ? gp.Style.LabelPadding.x : (-gp.Style.LabelPadding.x - tk.LabelSize.x)); + const float pad = label_pad + (labels_opp ? 0 : tk.LabelSize.x); + const float datum = ax.Datum1 + pad * (labels_opp ? 1.0f : -1.0f); if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.y - 1 && tk.PixelPos <= plot.PlotRect.Max.y + 1) { ImVec2 start(datum, tk.PixelPos - 0.5f * tk.LabelSize.y); - DrawList.AddText(start, ax.ColorTxt, tkr.GetText(j)); + bool hidden = false; + if (ins) { + start.y = ImMax(plot.PlotRect.Min.y, ImMin(start.y, plot.PlotRect.Max.y - tk.LabelSize.y)); + // at the corners, inside x tick labels win over the inside y tick labels they overlap + const ImRect rect(start, start + tk.LabelSize); + for (int k = 0; k < x_inside_label_rects.Size && !hidden; ++k) + hidden = x_inside_label_rects[k].Overlaps(rect); + } + if (!hidden) + DrawList.AddText(start, ax.ColorTxt, tkr.GetText(j)); } } } @@ -2882,10 +2961,10 @@ void EndPlot() { const ImVec2 start(tk.PixelPos, ax.Datum1); const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x; const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x; - DrawList.AddLine(start, start + ImVec2(0,direction*len), ax.ColorTick, thk); + AddLineV(&DrawList, start.x, start.y, start.y + direction*len, ax.ColorTick, thk); } if (aux || !render_border) - DrawList.AddLine(ImVec2(plot.PlotRect.Min.x,ax.Datum1), ImVec2(plot.PlotRect.Max.x,ax.Datum1), ax.ColorTick, gp.Style.MinorTickSize.x); + AddLineH(&DrawList, plot.PlotRect.Min.x,plot.PlotRect.Max.x,ax.Datum1, ax.ColorTick, gp.Style.MinorTickSize.x); } count_B += !opp; count_T += opp; @@ -2909,10 +2988,10 @@ void EndPlot() { const ImVec2 start(ax.Datum1, tk.PixelPos); const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y; const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y; - DrawList.AddLine(start, start + ImVec2(direction*len,0), ax.ColorTick, thk); + AddLineH(&DrawList, start.x, start.x + direction*len, start.y, ax.ColorTick, thk); } if (aux || !render_border) - DrawList.AddLine(ImVec2(ax.Datum1, plot.PlotRect.Min.y), ImVec2(ax.Datum1, plot.PlotRect.Max.y), ax.ColorTick, gp.Style.MinorTickSize.y); + AddLineV(&DrawList, ax.Datum1, plot.PlotRect.Min.y, plot.PlotRect.Max.y, ax.ColorTick, gp.Style.MinorTickSize.y); } count_L += !opp; count_R += opp; @@ -2967,23 +3046,15 @@ void EndPlot() { if (ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs) && plot.Hovered && !(any_x_held || any_y_held) && !plot.Selecting && !plot.Items.Legend.Hovered) { ImGui::SetMouseCursor(ImGuiMouseCursor_None); ImVec2 xy = IO.MousePos; - ImVec2 h1(plot.PlotRect.Min.x, xy.y); - ImVec2 h2(xy.x - 5, xy.y); - ImVec2 h3(xy.x + 5, xy.y); - ImVec2 h4(plot.PlotRect.Max.x, xy.y); - ImVec2 v1(xy.x, plot.PlotRect.Min.y); - ImVec2 v2(xy.x, xy.y - 5); - ImVec2 v3(xy.x, xy.y + 5); - ImVec2 v4(xy.x, plot.PlotRect.Max.y); ImU32 col = GetStyleColorU32(ImPlotCol_Crosshairs); - DrawList.AddLine(h1, h2, col); - DrawList.AddLine(h3, h4, col); - DrawList.AddLine(v1, v2, col); - DrawList.AddLine(v3, v4, col); + AddLineH(&DrawList, plot.PlotRect.Min.x, xy.x - 5, xy.y, col); + AddLineH(&DrawList, xy.x + 5, plot.PlotRect.Max.x, xy.y, col); + AddLineV(&DrawList, xy.x, plot.PlotRect.Min.y, xy.y - 5, col); + AddLineV(&DrawList, xy.x, xy.y + 5, plot.PlotRect.Max.y, col); } // render mouse pos - if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText) && (plot.Hovered || ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_ShowAlways))) { + if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText) && (plot.Hovered || plot.Held || plot.Selecting || ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_ShowAlways))) { const bool no_aux = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoAuxAxes); const bool no_fmt = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoFormat); @@ -3109,7 +3180,7 @@ void EndPlot() { legend_out ? plot.FrameRect : plot.PlotRect, legend_out ? gp.Style.PlotPadding : gp.Style.LegendPadding ); - const ImGuiButtonFlags legend_button_flags = ImGuiButtonFlags_AllowOverlap + const ImGuiButtonFlags legend_button_flags = (ImGuiButtonFlags)ImGuiButtonFlags_AllowOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_MouseButtonLeft @@ -3537,8 +3608,7 @@ bool BeginSubplots(const char* title, int rows, int cols, const ImVec2& size, Im subplot.RowRatios[r+1] = subplot.TempSizes[1] - dp; } } - DrawList.AddLine(ImVec2(IM_ROUND(subplot.GridRect.Min.x),IM_ROUND(ypos)), - ImVec2(IM_ROUND(subplot.GridRect.Max.x),IM_ROUND(ypos)), + AddLineH(&DrawList, IM_ROUND(subplot.GridRect.Min.x), IM_ROUND(subplot.GridRect.Max.x),IM_ROUND(ypos), sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE); ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); } @@ -3567,8 +3637,7 @@ bool BeginSubplots(const char* title, int rows, int cols, const ImVec2& size, Im subplot.ColRatios[c+1] = subplot.TempSizes[1] - dp; } } - DrawList.AddLine(ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Min.y)), - ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Max.y)), + AddLineV(&DrawList, IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Min.y),IM_ROUND(subplot.GridRect.Max.y), sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE); ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); } @@ -3637,7 +3706,7 @@ void EndSubplots() { legend.Rect = ImRect(legend_pos, legend_pos + legend_size); legend.RectClamped = legend.Rect; const bool legend_scrollable = ClampLegendRect(legend.RectClamped,subplot.FrameRect, gp.Style.PlotPadding); - const ImGuiButtonFlags legend_button_flags = ImGuiButtonFlags_AllowOverlap + const ImGuiButtonFlags legend_button_flags = (ImGuiButtonFlags)ImGuiButtonFlags_AllowOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_MouseButtonLeft @@ -3980,6 +4049,7 @@ bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs); const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors); const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed); + const bool move_allowed = !ImHasFlag(flags, ImPlotDragToolFlags_NoMove); const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, radius); const ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col; const ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color); @@ -3991,6 +4061,7 @@ bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, ImGui::KeepAliveID(id); if (input) { + rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); bool clicked = ImGui::ButtonBehavior(rect,id,&hovered,&held); if (out_clicked) *out_clicked = clicked; if (out_hovered) *out_hovered = hovered; @@ -3998,7 +4069,7 @@ bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, } bool modified = false; - if (held && ImGui::IsMouseDragging(0)) { + if (move_allowed && held && ImGui::IsMouseDragging(0)) { *x = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x; *y = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y; modified = true; @@ -4006,7 +4077,7 @@ bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, PushPlotClipRect(); ImDrawList& DrawList = *GetPlotDrawList(); - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && move_allowed) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); if (modified && no_delay) pos = PlotToPixels(*x,*y,IMPLOT_AUTO,IMPLOT_AUTO); @@ -4030,6 +4101,8 @@ bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPl const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs); const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors); const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed); + const bool move_allowed = !ImHasFlag(flags, ImPlotDragToolFlags_NoMove); + const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2); float yt = gp.CurrentPlot->PlotRect.Min.y; float yb = gp.CurrentPlot->PlotRect.Max.y; @@ -4040,13 +4113,14 @@ bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImGui::KeepAliveID(id); if (input) { + rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); bool clicked = ImGui::ButtonBehavior(rect,id,&hovered,&held); if (out_clicked) *out_clicked = clicked; if (out_hovered) *out_hovered = hovered; if (out_held) *out_held = held; } - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && move_allowed) ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); float len = gp.Style.MajorTickLen.x; @@ -4054,7 +4128,7 @@ bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color); bool modified = false; - if (held && ImGui::IsMouseDragging(0)) { + if (move_allowed && held && ImGui::IsMouseDragging(0)) { *value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x; modified = true; } @@ -4063,9 +4137,9 @@ bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImDrawList& DrawList = *GetPlotDrawList(); if (modified && no_delay) x = IM_ROUND(PlotToPixels(*value,0,IMPLOT_AUTO,IMPLOT_AUTO).x); - DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yb), col32, thickness); - DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yt+len), col32, 3*thickness); - DrawList.AddLine(ImVec2(x,yb), ImVec2(x,yb-len), col32, 3*thickness); + AddLineV(&DrawList,x,yt,yb, col32, thickness); + AddLineV(&DrawList,x,yt,yt+len, col32, 3*thickness); + AddLineV(&DrawList,x,yb,yb-len, col32, 3*thickness); PopPlotClipRect(); // ImGui::PopID(); @@ -4085,6 +4159,8 @@ bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPl const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs); const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors); const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed); + const bool move_allowed = !ImHasFlag(flags, ImPlotDragToolFlags_NoMove); + const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2); float xl = gp.CurrentPlot->PlotRect.Min.x; float xr = gp.CurrentPlot->PlotRect.Max.x; @@ -4096,13 +4172,14 @@ bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImGui::KeepAliveID(id); if (input) { + rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); bool clicked = ImGui::ButtonBehavior(rect,id,&hovered,&held); if (out_clicked) *out_clicked = clicked; if (out_hovered) *out_hovered = hovered; if (out_held) *out_held = held; } - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && move_allowed) ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); float len = gp.Style.MajorTickLen.y; @@ -4110,7 +4187,7 @@ bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color); bool modified = false; - if (held && ImGui::IsMouseDragging(0)) { + if (move_allowed && held && ImGui::IsMouseDragging(0)) { *value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y; modified = true; } @@ -4119,9 +4196,9 @@ bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPl ImDrawList& DrawList = *GetPlotDrawList(); if (modified && no_delay) y = IM_ROUND(PlotToPixels(0, *value,IMPLOT_AUTO,IMPLOT_AUTO).y); - DrawList.AddLine(ImVec2(xl,y), ImVec2(xr,y), col32, thickness); - DrawList.AddLine(ImVec2(xl,y), ImVec2(xl+len,y), col32, 3*thickness); - DrawList.AddLine(ImVec2(xr,y), ImVec2(xr-len,y), col32, 3*thickness); + AddLineH(&DrawList,xl,xr,y, col32, thickness); + AddLineH(&DrawList,xl,xl+len,y, col32, 3*thickness); + AddLineH(&DrawList,xr,xr-len,y, col32, 3*thickness); PopPlotClipRect(); ImGui::PopID(); @@ -4141,6 +4218,9 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs); const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors); const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed); + const bool move_allowed = !ImHasFlag(flags, ImPlotDragToolFlags_NoMove); + const bool resize_allowed = !ImHasFlag(flags, ImPlotDragToolFlags_NoResize); + bool h[] = {true,false,true,false}; double* x[] = {x_min,x_max,x_max,x_min}; double* y[] = {y_min,y_min,y_max,y_max}; @@ -4150,6 +4230,7 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m ImVec2 pc = PlotToPixels((*x_min+*x_max)/2,(*y_min+*y_max)/2,IMPLOT_AUTO,IMPLOT_AUTO); ImRect rect(ImMin(p[0],p[2]),ImMax(p[0],p[2])); ImRect rect_grab = rect; rect_grab.Expand(DRAG_GRAB_HALF_SIZE); + rect_grab.ClipWithFull(GImPlot->CurrentPlot->PlotRect); ImGuiMouseCursor cur[4]; if (show_curs) { @@ -4174,15 +4255,16 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m if (input) { // middle point ImRect b_rect(pc.x-DRAG_GRAB_HALF_SIZE,pc.y-DRAG_GRAB_HALF_SIZE,pc.x+DRAG_GRAB_HALF_SIZE,pc.y+DRAG_GRAB_HALF_SIZE); + b_rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); clicked = ImGui::ButtonBehavior(b_rect,id,&hovered,&held); if (out_clicked) *out_clicked = clicked; if (out_hovered) *out_hovered = hovered; if (out_held) *out_held = held; } - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && move_allowed) ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); - if (held && ImGui::IsMouseDragging(0)) { + if (move_allowed && held && ImGui::IsMouseDragging(0)) { for (int i = 0; i < 4; ++i) { ImPlotPoint pp = PixelsToPlot(p[i] + ImGui::GetIO().MouseDelta,IMPLOT_AUTO,IMPLOT_AUTO); *y[i] = pp.y; @@ -4195,6 +4277,7 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m for (int i = 0; i < 4; ++i) { // points ImRect b_rect(p[i].x - DRAG_GRAB_HALF_SIZE, p[i].y - DRAG_GRAB_HALF_SIZE, p[i].x + DRAG_GRAB_HALF_SIZE, p[i].y + DRAG_GRAB_HALF_SIZE); + b_rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); ImGuiID p_id = id + i + 1; ImGui::KeepAliveID(p_id); if (input) { @@ -4203,10 +4286,10 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m if (out_hovered) *out_hovered = *out_hovered || hovered; if (out_held) *out_held = *out_held || held; } - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && resize_allowed) ImGui::SetMouseCursor(cur[i]); - if (held && ImGui::IsMouseDragging(0)) { + if (resize_allowed && held && ImGui::IsMouseDragging(0)) { *x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x; *y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y; modified = true; @@ -4217,6 +4300,7 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m ImVec2 e_max = ImMax(p[i],p[(i+1)%4]); b_rect = h[i] ? ImRect(e_min.x + DRAG_GRAB_HALF_SIZE, e_min.y - DRAG_GRAB_HALF_SIZE, e_max.x - DRAG_GRAB_HALF_SIZE, e_max.y + DRAG_GRAB_HALF_SIZE) : ImRect(e_min.x - DRAG_GRAB_HALF_SIZE, e_min.y + DRAG_GRAB_HALF_SIZE, e_max.x + DRAG_GRAB_HALF_SIZE, e_max.y - DRAG_GRAB_HALF_SIZE); + b_rect.ClipWithFull(GImPlot->CurrentPlot->PlotRect); ImGuiID e_id = id + i + 5; ImGui::KeepAliveID(e_id); if (input) { @@ -4225,16 +4309,16 @@ bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_m if (out_hovered) *out_hovered = *out_hovered || hovered; if (out_held) *out_held = *out_held || held; } - if ((hovered || held) && show_curs) + if ((hovered || held) && show_curs && resize_allowed) h[i] ? ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); - if (held && ImGui::IsMouseDragging(0)) { + if (resize_allowed && held && ImGui::IsMouseDragging(0)) { if (h[i]) *y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y; else *x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x; modified = true; } - if (hovered && ImGui::IsMouseDoubleClicked(0)) + if (resize_allowed && hovered && ImGui::IsMouseDoubleClicked(0)) { ImPlotRect b = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); if (h[i]) @@ -4775,8 +4859,10 @@ void ColormapScale(const char* label, double scale_min, double scale_max, const const float tick_t = (float)((y_pos_plt - scale_min) / (scale_max - scale_min)); const ImU32 tick_col = CalcTextColor(gp.ColormapData.LerpTable(cmap,tick_t)); if (y_pos < bb_grad.Max.y - 2 && y_pos > bb_grad.Min.y + 2) { - DrawList.AddLine(opposite ? ImVec2(bb_grad.Min.x+1, y_pos) : ImVec2(bb_grad.Max.x-1, y_pos), - opposite ? ImVec2(bb_grad.Min.x + tick_width, y_pos) : ImVec2(bb_grad.Max.x - tick_width, y_pos), + AddLineH(&DrawList, + opposite ? (bb_grad.Min.x+1) : (bb_grad.Max.x-1), + opposite ? (bb_grad.Min.x + tick_width) : (bb_grad.Max.x - tick_width), + y_pos, tick_col, tick_thick); } @@ -5084,7 +5170,8 @@ void ShowStyleEditor(ImPlotStyle* ref) { ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); static ImGuiTextFilter filter; - filter.Draw("Filter colors", ImGui::GetFontSize() * 16); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 16); + filter.Draw("Filter colors"); static ImGuiColorEditFlags alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; #if IMGUI_VERSION_NUM < 19173 diff --git a/include/implot/implot.h b/include/implot/implot.h index 0dcb9e9..1c96ec7 100644 --- a/include/implot/implot.h +++ b/include/implot/implot.h @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v1.1 WIP +// ImPlot v1.2 WIP // Table of Contents: // @@ -62,9 +62,9 @@ #endif // ImPlot version string. -#define IMPLOT_VERSION "1.1 WIP" +#define IMPLOT_VERSION "1.2 WIP" // ImPlot version integer encoded as XYYZZ (X=major, YY=minor, ZZ=patch). -#define IMPLOT_VERSION_NUM 10100 +#define IMPLOT_VERSION_NUM 10200 // Macro for templated plotting functions; keeps header clean. #define IMPLOT_TMP template IMPLOT_API @@ -173,26 +173,27 @@ enum ImPlotFlags_ { // Options for plot axes (see SetupAxis). enum ImPlotAxisFlags_ { - ImPlotAxisFlags_None = 0, // default - ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels are also hidden if the supplied string name is nullptr) - ImPlotAxisFlags_NoGridLines = 1 << 1, // no grid lines will be displayed - ImPlotAxisFlags_NoTickMarks = 1 << 2, // no tick marks will be displayed - ImPlotAxisFlags_NoTickLabels = 1 << 3, // no text labels will be displayed - ImPlotAxisFlags_NoInitialFit = 1 << 4, // axis will not be initially fit to data extents on the first rendered frame - ImPlotAxisFlags_NoMenus = 1 << 5, // the user will not be able to open context menus with right-click - ImPlotAxisFlags_NoSideSwitch = 1 << 6, // the user will not be able to switch the axis side by dragging it - ImPlotAxisFlags_NoHighlight = 1 << 7, // the axis will not have its background highlighted when hovered or held - ImPlotAxisFlags_Opposite = 1 << 8, // axis ticks and labels will be rendered on the conventionally opposite side (i.e, right or top) - ImPlotAxisFlags_Foreground = 1 << 9, // grid lines will be displayed in the foreground (i.e. on top of data) instead of the background - ImPlotAxisFlags_Invert = 1 << 10, // the axis will be inverted - ImPlotAxisFlags_AutoFit = 1 << 11, // axis will be auto-fitting to data extents - ImPlotAxisFlags_RangeFit = 1 << 12, // axis will only fit points if the point is in the visible range of the **orthogonal** axis - ImPlotAxisFlags_PanStretch = 1 << 13, // panning in a locked or constrained state will cause the axis to stretch if possible - ImPlotAxisFlags_LockMin = 1 << 14, // the axis minimum value will be locked when panning/zooming - ImPlotAxisFlags_LockMax = 1 << 15, // the axis maximum value will be locked when panning/zooming - ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax, - ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels, - ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite + ImPlotAxisFlags_None = 0, // default + ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels are also hidden if the supplied string name is nullptr) + ImPlotAxisFlags_NoGridLines = 1 << 1, // no grid lines will be displayed + ImPlotAxisFlags_NoTickMarks = 1 << 2, // no tick marks will be displayed + ImPlotAxisFlags_NoTickLabels = 1 << 3, // no text labels will be displayed + ImPlotAxisFlags_NoInitialFit = 1 << 4, // axis will not be initially fit to data extents on the first rendered frame + ImPlotAxisFlags_NoMenus = 1 << 5, // the user will not be able to open context menus with right-click + ImPlotAxisFlags_NoSideSwitch = 1 << 6, // the user will not be able to switch the axis side by dragging it + ImPlotAxisFlags_NoHighlight = 1 << 7, // the axis will not have its background highlighted when hovered or held + ImPlotAxisFlags_Opposite = 1 << 8, // axis ticks and labels will be rendered on the conventionally opposite side (i.e, right or top) + ImPlotAxisFlags_Foreground = 1 << 9, // grid lines will be displayed in the foreground (i.e. on top of data) instead of the background + ImPlotAxisFlags_Invert = 1 << 10, // the axis will be inverted + ImPlotAxisFlags_AutoFit = 1 << 11, // axis will be auto-fitting to data extents + ImPlotAxisFlags_RangeFit = 1 << 12, // axis will only fit points if the point is in the visible range of the **orthogonal** axis + ImPlotAxisFlags_PanStretch = 1 << 13, // panning in a locked or constrained state will cause the axis to stretch if possible + ImPlotAxisFlags_LockMin = 1 << 14, // the axis minimum value will be locked when panning/zooming + ImPlotAxisFlags_LockMax = 1 << 15, // the axis maximum value will be locked when panning/zooming + ImPlotAxisFlags_TickLabelsInside = 1 << 16, // axis tick labels will be drawn inside the plot area (applies only to the innermost axes) + ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax, + ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels, + ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite }; // Options for subplots (see BeginSubplot) @@ -239,6 +240,8 @@ enum ImPlotDragToolFlags_ { ImPlotDragToolFlags_NoFit = 1 << 1, // the drag tool won't be considered for plot fits ImPlotDragToolFlags_NoInputs = 1 << 2, // lock the tool from user inputs ImPlotDragToolFlags_Delayed = 1 << 3, // tool rendering will be delayed one frame; useful when applying position-constraints + ImPlotDragToolFlags_NoMove = 1 << 4, // the tool can't be moved; it still catches and reports clicks and hovers, but shows no move cursor + ImPlotDragToolFlags_NoResize = 1 << 5, // DragRect's corners and edges can't resize it; they still catch and report clicks and hovers, but show no resize cursor }; // Flags for ColormapScale @@ -448,6 +451,8 @@ enum ImPlotMarker_ { ImPlotMarker_Cross, // a cross marker (not fill-able) ImPlotMarker_Plus, // a plus marker (not fill-able) ImPlotMarker_Asterisk, // a asterisk marker (not fill-able) + ImPlotMarker_Vertical, // a vertical line marker (not fill-able) + ImPlotMarker_Horizontal, // a horizontal line marker (not fill-able) ImPlotMarker_COUNT }; @@ -501,7 +506,7 @@ enum ImPlotBin_ { // spec.LineColor = ImVec4(1,0,0,1); // spec.LineWeight = 2.0f; // spec.Marker = ImPlotMarker_Circle; -// spec.Flags = ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments; +// spec.Flags = (ImPlotItemFlags)ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments; // ImPlot::PlotLine("MyLine", xs, ys, 100, spec); // // 2. Inline using (ImPlotProp,value) pairs (order does NOT matter): @@ -510,7 +515,7 @@ enum ImPlotBin_ { // ImPlotProp_LineColor, ImVec4(1,0,0,1), // ImPlotProp_LineWeight, 2.0f, // ImPlotProp_Marker, ImPlotMarker_Circle, -// ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments +// ImPlotProp_Flags, (ImPlotItemFlags)ImPlotItemFlags_NoLegend | ImPlotLineFlags_Segments // }); struct ImPlotSpec { ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar edges); IMPLOT_AUTO_COL will use next Colormap color or current item color @@ -1141,6 +1146,10 @@ IMPLOT_API void CancelPlotSelection(); // Hides or shows the next plot item (i.e. as if it were toggled from the legend). // Use ImPlotCond_Always if you need to forcefully set this every frame. IMPLOT_API void HideNextItem(bool hidden = true, ImPlotCond cond = ImPlotCond_Once); +// Returns true if the plot item #label_id in the current plot is hidden (i.e. toggled off from the legend or by HideNextItem). +// Can be called before the item is submitted (e.g. to skip expensive work for a hidden item), in which case it reports +// the state from the previous frame. Returns false for items that have never been submitted. See also IsLastItemHidden. +IMPLOT_API bool IsItemHidden(const char* label_id); // Use the following around calls to Begin/EndPlot to align l/r/t/b padding. // Consider using Begin/EndSubplots first. They are more feature rich and @@ -1238,6 +1247,8 @@ IMPLOT_API void PopStyleVar(int count = 1); // Gets the last item primary color (i.e. its legend icon color) IMPLOT_API ImVec4 GetLastItemColor(); +// Returns true if the last plot item is hidden (i.e. toggled off from the legend or by HideNextItem). +IMPLOT_API bool IsLastItemHidden(); // Returns the null terminated string name for an ImPlotCol. IMPLOT_API const char* GetStyleColorName(ImPlotCol idx); diff --git a/include/implot/implot_demo.cpp b/include/implot/implot_demo.cpp index ea72a65..107bfea 100644 --- a/include/implot/implot_demo.cpp +++ b/include/implot/implot_demo.cpp @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v1.1 WIP +// ImPlot v1.2 WIP // We define this so that the demo does not accidentally use deprecated API #ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS @@ -30,17 +30,12 @@ #include "implot.h" #ifndef IMGUI_DISABLE +#include "implot_internal.h" #include #include #include #include -// Clang warnings with -Weverything -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#endif - #ifdef _MSC_VER #define sprintf sprintf_s #endif @@ -197,6 +192,59 @@ struct HugeTimeData { static const int Size = 60*60*24*366; }; +//----------------------------------------------------------------------------- +// [SECTION] Numeric Type Gating +//----------------------------------------------------------------------------- + +// A few demos below hardcode their data as a type other than float/double (e.g. ImS8, int). ImPlot +// only instantiates PlotXxx for the types in IMPLOT_NUMERIC_TYPES (see implot_internal.h), which +// can be restricted with IMPLOT_CUSTOM_NUMERIC_TYPES. Calling PlotXxx for an excluded type still +// compiles but fails to link, so those demos are compiled out for it. +// +// A demo that plots data of a type other than float/double must be declared with +// IMPLOT_DEMO_TYPE_GATED (below). + +// Walks IMPLOT_NUMERIC_TYPES, expanding IMPLOT_DEMO_TYPE_MACRO(T) once per listed type. +#define IMPLOT_DEMO_CAT(x, y) IMPLOT_DEMO_CAT_(x, y) +#define IMPLOT_DEMO_CAT_(x, y) x ## y +#define IMPLOT_DEMO_WALK_TYPES(chain) IMPLOT_DEMO_CAT(IMPLOT_DEMO_WALK_TYPES_1 chain, _END) +#define IMPLOT_DEMO_WALK_TYPES_1(T) IMPLOT_DEMO_TYPE_MACRO(T) IMPLOT_DEMO_WALK_TYPES_2 +#define IMPLOT_DEMO_WALK_TYPES_2(T) IMPLOT_DEMO_TYPE_MACRO(T) IMPLOT_DEMO_WALK_TYPES_1 +#define IMPLOT_DEMO_WALK_TYPES_1_END +#define IMPLOT_DEMO_WALK_TYPES_2_END + +namespace Demo { + +// IsTypeEnabled::Value is true iff ImPlot explicitly instantiates PlotXxx. +template struct IsTypeEnabled { enum { Value = 0 }; }; +#define IMPLOT_DEMO_TYPE_MACRO(T) template <> struct IsTypeEnabled { enum { Value = 1 }; }; +IMPLOT_DEMO_WALK_TYPES(IMPLOT_NUMERIC_TYPES) +#undef IMPLOT_DEMO_TYPE_MACRO + +// A tiny local enable_if, so this doesn't need to pull in for its one use below. +template struct EnableIf {}; +template struct EnableIf { typedef T type; }; + +void ShowTypeDisabledNotice() { + ImGui::TextDisabled("(this demo needs a numeric type excluded via IMPLOT_CUSTOM_NUMERIC_TYPES)"); +} + +} // namespace Demo + +// Declares Name() such that exactly one of two bodies is ever compiled for a given T: the one +// written immediately after this macro if T is one of IMPLOT_NUMERIC_TYPES, or an automatic +// fallback that calls ShowTypeDisabledNotice() otherwise. Since the two are separate function +// template overloads selected via SFINAE, the one that doesn't apply to T is never instantiated, +// so it can safely reference PlotXxx without ever actually calling it (and without the linker +// ever looking for a definition of it) when T was excluded via IMPLOT_CUSTOM_NUMERIC_TYPES. +#define IMPLOT_DEMO_TYPE_GATED(Name) \ + template \ + typename Demo::EnableIf::Value>::type Name() { \ + Demo::ShowTypeDisabledNotice(); \ + } \ + template \ + typename Demo::EnableIf::Value>::type Name() + //----------------------------------------------------------------------------- // [SECTION] Demo Functions //----------------------------------------------------------------------------- @@ -541,9 +589,8 @@ void Demo_StairstepPlots() { //----------------------------------------------------------------------------- -void Demo_BarPlots() { - IMGUI_DEMO_MARKER("Plots/Bar Plots"); - static ImS8 data[10] = {1,2,3,4,5,6,7,8,9,10}; +IMPLOT_DEMO_TYPE_GATED(Demo_BarPlots_) { + static T data[10] = {1,2,3,4,5,6,7,8,9,10}; if (ImPlot::BeginPlot("Bar Plot")) { ImPlot::PlotBars("Vertical",data,10,0.7,1); ImPlot::PlotBars("Horizontal",data,10,0.4,1,{ImPlotProp_Flags, ImPlotBarsFlags_Horizontal}); @@ -551,13 +598,17 @@ void Demo_BarPlots() { } } +void Demo_BarPlots() { + IMGUI_DEMO_MARKER("Plots/Bar Plots"); + Demo_BarPlots_(); +} + //----------------------------------------------------------------------------- -void Demo_BarGroups() { - IMGUI_DEMO_MARKER("Plots/Bar Groups"); - static ImS8 data[30] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90, // midterm - 80, 62, 56, 99, 55, 78, 88, 78, 90, 100, // final - 80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; // course +IMPLOT_DEMO_TYPE_GATED(Demo_BarGroups_) { + static T data[30] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90, // midterm + 80, 62, 56, 99, 55, 78, 88, 78, 90, 100, // final + 80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; // course static const char* ilabels[] = {"Midterm Exam","Final Exam","Course Grade"}; static const char* glabels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"}; @@ -593,11 +644,14 @@ void Demo_BarGroups() { } } -//----------------------------------------------------------------------------- +void Demo_BarGroups() { + IMGUI_DEMO_MARKER("Plots/Bar Groups"); + Demo_BarGroups_(); +} -void Demo_BarStacks() { - IMGUI_DEMO_MARKER("Plots/Bar Stacks"); +//----------------------------------------------------------------------------- +IMPLOT_DEMO_TYPE_GATED(Demo_BarStacks_) { static ImPlotColormap Liars = -1; if (Liars == -1) { static const ImU32 Liars_Data[6] = { 4282515870, 4282609140, 4287357182, 4294630301, 4294945280, 4294921472 }; @@ -608,24 +662,24 @@ void Demo_BarStacks() { ImGui::Checkbox("Diverging",&diverging); static const char* politicians[] = {"Trump","Bachman","Cruz","Gingrich","Palin","Santorum","Walker","Perry","Ryan","McCain","Rubio","Romney","Rand Paul","Christie","Biden","Kasich","Sanders","J Bush","H Clinton","Obama"}; - static int data_reg[] = {18,26,7,14,10,8,6,11,4,4,3,8,6,8,6,5,0,3,1,2, // Pants on Fire - 43,36,30,21,30,27,25,17,11,22,15,16,16,17,12,12,14,6,13,12, // False - 16,13,28,22,15,21,15,18,30,17,24,18,13,10,14,15,17,22,14,12, // Mostly False - 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True - 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True - 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True + static T data_reg[] = {18,26,7,14,10,8,6,11,4,4,3,8,6,8,6,5,0,3,1,2, // Pants on Fire + 43,36,30,21,30,27,25,17,11,22,15,16,16,17,12,12,14,6,13,12, // False + 16,13,28,22,15,21,15,18,30,17,24,18,13,10,14,15,17,22,14,12, // Mostly False + 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True + 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True + 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True static const char* labels_reg[] = {"Pants on Fire","False","Mostly False","Half True","Mostly True","True"}; - static int data_div[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Pants on Fire (dummy, to order legend logically) - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // False (dummy, to order legend logically) - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Mostly False (dummy, to order legend logically) - -16,-13,-28,-22,-15,-21,-15,-18,-30,-17,-24,-18,-13,-10,-14,-15,-17,-22,-14,-12, // Mostly False - -43,-36,-30,-21,-30,-27,-25,-17,-11,-22,-15,-16,-16,-17,-12,-12,-14,-6,-13,-12, // False - -18,-26,-7,-14,-10,-8,-6,-11,-4,-4,-3,-8,-6,-8,-6,-5,0,-3,-1,-2, // Pants on Fire - 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True - 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True - 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True + static T data_div[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Pants on Fire (dummy, to order legend logically) + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // False (dummy, to order legend logically) + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Mostly False (dummy, to order legend logically) + -16,-13,-28,-22,-15,-21,-15,-18,-30,-17,-24,-18,-13,-10,-14,-15,-17,-22,-14,-12, // Mostly False + -43,-36,-30,-21,-30,-27,-25,-17,-11,-22,-15,-16,-16,-17,-12,-12,-14,-6,-13,-12, // False + -18,-26,-7,-14,-10,-8,-6,-11,-4,-4,-3,-8,-6,-8,-6,-5,0,-3,-1,-2, // Pants on Fire + 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True + 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True + 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True static const char* labels_div[] = {"Pants on Fire","False","Mostly False","Mostly False","False","Pants on Fire","Half True","Mostly True","True"}; ImPlot::PushColormap(Liars); @@ -643,6 +697,11 @@ void Demo_BarStacks() { ImPlot::PopColormap(); } +void Demo_BarStacks() { + IMGUI_DEMO_MARKER("Plots/Bar Stacks"); + Demo_BarStacks_(); +} + //----------------------------------------------------------------------------- void Demo_ErrorBars() { @@ -703,9 +762,16 @@ void Demo_StemPlots() { void Demo_InfiniteLines() { IMGUI_DEMO_MARKER("Plots/Infinite Lines"); static double vals[] = {0.25, 0.5, 0.75}; + static const char* labels[] = {"x = 0.25", "x = 0.50", "x = 0.75"}; + ImGui::BulletText("Toggle \"Vertical\" in the legend: its text labels hide with it."); if (ImPlot::BeginPlot("##Infinite")) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoInitialFit,ImPlotAxisFlags_NoInitialFit); ImPlot::PlotInfLines("Vertical",vals,3); + // PlotText is not a legend item, so skip it when its lines are hidden + if (!ImPlot::IsLastItemHidden()) { + for (int i = 0; i < 3; ++i) + ImPlot::PlotText(labels[i],vals[i],0.9,ImVec2(36,0),{ImPlotProp_Flags, ImPlotItemFlags_NoFit}); + } ImPlot::PlotInfLines("Horizontal",vals,3,{ImPlotProp_Flags, ImPlotInfLinesFlags_Horizontal}); ImPlot::EndPlot(); } @@ -713,6 +779,29 @@ void Demo_InfiniteLines() { //----------------------------------------------------------------------------- +// Second pie chart's data is an int array (purely to show PlotPieChart() isn't limited to +// float/double); it needs its own type-gated helper since int (ImS32) may have been excluded via +// IMPLOT_CUSTOM_NUMERIC_TYPES. +template +typename Demo::EnableIf::Value>::type +Demo_PieCharts_Pie2(ImPlotPieChartFlags flags) { + static const char* labels2[] = {"A","B","C","D","E"}; + static T data2[] = {1,1,2,3,5}; + ImPlot::PushColormap(ImPlotColormap_Pastel); + if (ImPlot::BeginPlot("##Pie2", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) { + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); + ImPlot::SetupAxesLimits(0, 1, 0, 1); + ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, {ImPlotProp_Flags, flags}); + ImPlot::EndPlot(); + } + ImPlot::PopColormap(); +} +template +typename Demo::EnableIf::Value>::type +Demo_PieCharts_Pie2(ImPlotPieChartFlags) { + Demo::ShowTypeDisabledNotice(); +} + void Demo_PieCharts() { IMGUI_DEMO_MARKER("Plots/Pie Charts"); static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"}; @@ -734,17 +823,7 @@ void Demo_PieCharts() { ImGui::SameLine(); - static const char* labels2[] = {"A","B","C","D","E"}; - static int data2[] = {1,1,2,3,5}; - - ImPlot::PushColormap(ImPlotColormap_Pastel); - if (ImPlot::BeginPlot("##Pie2", ImVec2(ImGui::GetTextLineHeight()*16,ImGui::GetTextLineHeight()*16), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) { - ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); - ImPlot::SetupAxesLimits(0, 1, 0, 1); - ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, "%.0f", 180, {ImPlotProp_Flags, flags}); - ImPlot::EndPlot(); - } - ImPlot::PopColormap(); + Demo_PieCharts_Pie2(flags); } //----------------------------------------------------------------------------- @@ -1069,8 +1148,7 @@ void Demo_RealtimePlots() { //----------------------------------------------------------------------------- -void Demo_MarkersAndText() { - IMGUI_DEMO_MARKER("Plots/Markers and Text"); +IMPLOT_DEMO_TYPE_GATED(Demo_MarkersAndText_) { static ImPlotSpec spec(ImPlotProp_Marker, ImPlotMarker_Auto); ImGui::DragFloat("Marker Size",&spec.MarkerSize,0.1f,2.0f,10.0f,"%.2f px"); ImGui::DragFloat("Marker Weight", &spec.LineWeight,0.05f,0.5f,3.0f,"%.2f px"); @@ -1078,10 +1156,10 @@ void Demo_MarkersAndText() { if (ImPlot::BeginPlot("##MarkerStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) { ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations); - ImPlot::SetupAxesLimits(0, 10, 0, 12); + ImPlot::SetupAxesLimits(0, 10, -2, 12); - ImS8 xs[2] = {1,4}; - ImS8 ys[2] = {10,11}; + T xs[2] = {1,4}; + T ys[2] = {10,11}; // filled markers for (int m = 0; m < ImPlotMarker_COUNT; ++m) { @@ -1101,17 +1179,22 @@ void Demo_MarkersAndText() { ys[0]--; ys[1]--; } - ImPlot::PlotText("Filled Markers", 2.5f, 6.0f); - ImPlot::PlotText("Open Markers", 7.5f, 6.0f); + ImPlot::PlotText("Filled Markers", 2.5f, 5.0f); + ImPlot::PlotText("Open Markers", 7.5f, 5.0f); ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1)); - ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, ImVec2(0,0), {ImPlotProp_Flags, ImPlotTextFlags_Vertical}); + ImPlot::PlotText("Vertical Text", 5.0f, 5.0f, ImVec2(0,0), {ImPlotProp_Flags, ImPlotTextFlags_Vertical}); ImPlot::PopStyleColor(); ImPlot::EndPlot(); } } +void Demo_MarkersAndText() { + IMGUI_DEMO_MARKER("Plots/Markers and Text"); + Demo_MarkersAndText_(); +} + //----------------------------------------------------------------------------- void Demo_NaNValues() { @@ -1142,6 +1225,37 @@ void Demo_NaNValues() { //----------------------------------------------------------------------------- +// The "Colorful Bar Plots" bit of Demo_PerIndexColors() below plots an ImS8 array purely to show +// that PlotBars() isn't limited to float/double, so it needs its own type-gated helper in case +// ImS8 was excluded via IMPLOT_CUSTOM_NUMERIC_TYPES. +IMPLOT_DEMO_TYPE_GATED(Demo_PerIndexColors_ColorfulBars_) { + static T data_bars[10] = {1,2,3,4,5,6,7,8,9,10}; + static ImU32 colors_bars_v[10], colors_bars_h[10]; + for (int i = 0; i < 10; ++i) { + // Rainbow colors for Vertical + float hue = i / 9.0f; + colors_bars_v[i] = ImColor::HSV(hue, 0.8f, 0.9f); + + // Colormap colors for Horizontal + float t = i / 9.0f; + ImVec4 color = ImPlot::SampleColormap(t, ImPlotColormap_Viridis); + colors_bars_h[i] = ImGui::GetColorU32(color); + } + + if (ImPlot::BeginPlot("Colorful Bar Plot")) { + ImPlot::PlotBars("Vertical", data_bars, 10, 0.7, 1, { + ImPlotProp_FillColors, colors_bars_v, + ImPlotProp_LineColors, colors_bars_v + }); + ImPlot::PlotBars("Horizontal", data_bars, 10, 0.4, 1, { + ImPlotProp_Flags, ImPlotBarsFlags_Horizontal, + ImPlotProp_FillColors, colors_bars_h, + ImPlotProp_LineColors, colors_bars_h + }); + ImPlot::EndPlot(); + } +} + void Demo_PerIndexColors() { // Colorful Lines static float xs1[1001], ys1[1001]; @@ -1358,31 +1472,7 @@ void Demo_PerIndexColors() { } // Colorful Bar Plots - static ImS8 data_bars[10] = {1,2,3,4,5,6,7,8,9,10}; - static ImU32 colors_bars_v[10], colors_bars_h[10]; - for (int i = 0; i < 10; ++i) { - // Rainbow colors for Vertical - float hue = i / 9.0f; - colors_bars_v[i] = ImColor::HSV(hue, 0.8f, 0.9f); - - // Colormap colors for Horizontal - float t = i / 9.0f; - ImVec4 color = ImPlot::SampleColormap(t, ImPlotColormap_Viridis); - colors_bars_h[i] = ImGui::GetColorU32(color); - } - - if (ImPlot::BeginPlot("Colorful Bar Plot")) { - ImPlot::PlotBars("Vertical", data_bars, 10, 0.7, 1, { - ImPlotProp_FillColors, colors_bars_v, - ImPlotProp_LineColors, colors_bars_v - }); - ImPlot::PlotBars("Horizontal", data_bars, 10, 0.4, 1, { - ImPlotProp_Flags, ImPlotBarsFlags_Horizontal, - ImPlotProp_FillColors, colors_bars_h, - ImPlotProp_LineColors, colors_bars_h - }); - ImPlot::EndPlot(); - } + Demo_PerIndexColors_ColorfulBars_(); // Colorful Stem Plots static double xs_stems[51], ys1_stems[51], ys2_stems[51]; @@ -1638,11 +1728,10 @@ void Demo_MultipleAxes() { //----------------------------------------------------------------------------- -void Demo_LinkedAxes() { - IMGUI_DEMO_MARKER("Axes/Linked Axes"); +IMPLOT_DEMO_TYPE_GATED(Demo_LinkedAxes_) { static ImPlotRect lims(0,1,0,1); static bool linkx = true, linky = true; - int data[2] = {0,1}; + T data[2] = {0,1}; ImGui::Checkbox("Link X", &linkx); ImGui::SameLine(); ImGui::Checkbox("Link Y", &linky); @@ -1666,6 +1755,11 @@ void Demo_LinkedAxes() { } } +void Demo_LinkedAxes() { + IMGUI_DEMO_MARKER("Axes/Linked Axes"); + Demo_LinkedAxes_(); +} + //----------------------------------------------------------------------------- void Demo_AxisConstraints() { @@ -1895,7 +1989,7 @@ void Demo_LegendOptions() { ImPlot::PlotLineG("Item 003", MyImPlot::SawWave, &data5, 1000); // combined with previous "Item C" for (int i = 0; i < num_dummy_items; ++i) { - char label[16]; + char label[32]; snprintf(label, sizeof(label), "Item %03d", i+4); ImPlot::PlotDummy(label); } @@ -1911,7 +2005,8 @@ void Demo_DragPoints() { static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None; ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine(); ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine(); - ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); + ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); ImGui::SameLine(); + ImGui::CheckboxFlags("NoMove", (unsigned int*)&flags, ImPlotDragToolFlags_NoMove); ImPlotAxisFlags ax_flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoTickMarks; bool clicked[4] = {false, false, false, false}; bool hovered[4] = {false, false, false, false}; @@ -1973,7 +2068,8 @@ void Demo_DragLines() { static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None; ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine(); ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine(); - ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); + ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); ImGui::SameLine(); + ImGui::CheckboxFlags("NoMove", (unsigned int*)&flags, ImPlotDragToolFlags_NoMove); if (ImPlot::BeginPlot("##lines",ImVec2(-1,0))) { ImPlot::SetupAxesLimits(0,1,0,1); ImPlot::DragLineX(0,&x1,ImVec4(1,1,1,1),1,flags); @@ -2019,7 +2115,9 @@ void Demo_DragRects() { static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None; ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine(); ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine(); - ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); + ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs); ImGui::SameLine(); + ImGui::CheckboxFlags("NoMove", (unsigned int*)&flags, ImPlotDragToolFlags_NoMove); ImGui::SameLine(); + ImGui::CheckboxFlags("NoResize", (unsigned int*)&flags, ImPlotDragToolFlags_NoResize); if (ImPlot::BeginPlot("##Main",ImVec2(-1,ImGui::GetTextLineHeight()*10))) { ImPlot::SetupAxes(nullptr,nullptr,ImPlotAxisFlags_NoTickLabels,ImPlotAxisFlags_NoTickLabels); @@ -2430,7 +2528,7 @@ void Demo_ItemStylingAndSpec() { spec.Marker = ImPlotMarker_Square; spec.MarkerSize = 6; spec.Stride = sizeof(ImVec2); - spec.Flags = ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded; + spec.Flags = (ImPlotItemFlags)ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded; ImPlot::PlotLine("Line 1", &data1[0].x, &data1[0].y, 20, spec); // 2. Inline using ImPlotProp,value pairs (order does NOT matter): @@ -2442,7 +2540,7 @@ void Demo_ItemStylingAndSpec() { ImPlotProp_Marker, ImPlotMarker_Diamond, ImPlotProp_Size, 6, ImPlotProp_Stride, sizeof(ImVec2), - ImPlotProp_Flags, ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded + ImPlotProp_Flags, (ImPlotItemFlags)ImPlotItemFlags_NoLegend | ImPlotLineFlags_Shaded }); ImPlot::EndPlot(); @@ -2550,6 +2648,11 @@ void Demo_TickLabels() { ImGui::SameLine(); ImGui::Checkbox("Show Custom Labels", &custom_labels); } + static bool labels_inside = false; + ImGui::Checkbox("Labels Inside", &labels_inside); + ImGui::SameLine(); + ImGui::TextDisabled("(only the innermost axis on each side: X1, Y1 and Y2, not Y3)"); + const ImPlotAxisFlags inside = labels_inside ? ImPlotAxisFlags_TickLabelsInside : ImPlotAxisFlags_None; const double pi = 3.14; const char* pi_str[] = {"PI"}; static double yticks[] = {100,300,700,900}; @@ -2557,9 +2660,10 @@ void Demo_TickLabels() { static double yticks_aux[] = {0.2,0.4,0.6}; static const char* ylabels_aux[] = {"A","B","C","D","E","F"}; if (ImPlot::BeginPlot("##Ticks")) { + ImPlot::SetupAxes(nullptr, nullptr, inside, inside); ImPlot::SetupAxesLimits(2.5,5,0,1000); - ImPlot::SetupAxis(ImAxis_Y2, nullptr, ImPlotAxisFlags_AuxDefault); - ImPlot::SetupAxis(ImAxis_Y3, nullptr, ImPlotAxisFlags_AuxDefault); + ImPlot::SetupAxis(ImAxis_Y2, nullptr, ImPlotAxisFlags_AuxDefault | inside); + ImPlot::SetupAxis(ImAxis_Y3, nullptr, ImPlotAxisFlags_AuxDefault | inside); if (custom_fmt) { ImPlot::SetupAxisFormat(ImAxis_X1, "%g ms"); ImPlot::SetupAxisFormat(ImAxis_Y1, MetricFormatter, (void*)"Hz"); @@ -2578,6 +2682,19 @@ void Demo_TickLabels() { //----------------------------------------------------------------------------- +// This bit of Demo_CustomStyles() below plots an unsigned int array purely to show that PlotXxx() +// isn't limited to float/double, so it needs its own type-gated helper in case unsigned int +// (ImU32) was excluded via IMPLOT_CUSTOM_NUMERIC_TYPES. +IMPLOT_DEMO_TYPE_GATED(Demo_CustomStyles_SeabornPlots_) { + T lin[10] = {8,8,9,7,8,8,8,9,7,8}; + T bar[10] = {1,2,5,3,4,1,2,5,3,4}; + T dot[10] = {7,6,6,7,8,5,6,5,8,7}; + ImPlot::PlotBars("Bars", bar, 10, 0.5f); + ImPlot::PlotLine("Line", lin, 10); + ImPlot::NextColormapColor(); // skip green + ImPlot::PlotScatter("Scatter", dot, 10); +} + void Demo_CustomStyles() { IMGUI_DEMO_MARKER("Custom/Custom Styles"); ImPlot::PushColormap(ImPlotColormap_Deep); @@ -2587,13 +2704,7 @@ void Demo_CustomStyles() { if (ImPlot::BeginPlot("seaborn style")) { ImPlot::SetupAxes( "x-axis", "y-axis"); ImPlot::SetupAxesLimits(-0.5f, 9.5f, 0, 10); - unsigned int lin[10] = {8,8,9,7,8,8,8,9,7,8}; - unsigned int bar[10] = {1,2,5,3,4,1,2,5,3,4}; - unsigned int dot[10] = {7,6,6,7,8,5,6,5,8,7}; - ImPlot::PlotBars("Bars", bar, 10, 0.5f); - ImPlot::PlotLine("Line", lin, 10); - ImPlot::NextColormapColor(); // skip green - ImPlot::PlotScatter("Scatter", dot, 10); + Demo_CustomStyles_SeabornPlots_(); ImPlot::EndPlot(); } ImPlot::GetStyle() = backup; @@ -3043,10 +3154,8 @@ void PlotCandlestick(const char* label_id, const double* xs, const double* opens for (int i = 0; i < count; ++i) { ImVec2 open_pos = ImPlot::PlotToPixels(xs[i] - half_width, opens[i]); ImVec2 close_pos = ImPlot::PlotToPixels(xs[i] + half_width, closes[i]); - ImVec2 low_pos = ImPlot::PlotToPixels(xs[i], lows[i]); - ImVec2 high_pos = ImPlot::PlotToPixels(xs[i], highs[i]); ImU32 color = ImGui::GetColorU32(opens[i] > closes[i] ? bearCol : bullCol); - draw_list->AddLine(low_pos, high_pos, color); + ImPlot::AddLineV(draw_list, (float)xs[i], (float)lows[i], (float)highs[i], color); draw_list->AddRectFilled(open_pos, close_pos, color); } diff --git a/include/implot/implot_internal.h b/include/implot/implot_internal.h index e778327..586d7f7 100644 --- a/include/implot/implot_internal.h +++ b/include/implot/implot_internal.h @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v1.1 WIP +// ImPlot v1.2 WIP // You may use this file to debug, understand or extend ImPlot features but we // don't provide any guarantee of forward compatibility! @@ -71,6 +71,32 @@ constexpr int IMPLOT_NUM_Y_AXES = ImAxis_COUNT - IMPLOT_NUM_X_AXES; // [SECTION] Macros //----------------------------------------------------------------------------- +// By default, templates are instantiated for `float`, `double`, and for the following integer types, which are defined in imgui.h: +// signed char ImS8; // 8-bit signed integer +// unsigned char ImU8; // 8-bit unsigned integer +// signed short ImS16; // 16-bit signed integer +// unsigned short ImU16; // 16-bit unsigned integer +// signed int ImS32; // 32-bit signed integer == int +// unsigned int ImU32; // 32-bit unsigned integer +// signed long long ImS64; // 64-bit signed integer +// unsigned long long ImU64; // 64-bit unsigned integer +// (note: this list does *not* include `long`, `unsigned long` and `long double`) +// +// You can customize the supported types by defining IMPLOT_CUSTOM_NUMERIC_TYPES at compile time to define your own type list. +// As an example, you could use the compile time define given by the line below in order to support only float and double. +// -DIMPLOT_CUSTOM_NUMERIC_TYPES="(float)(double)" +// Note that the demo (implot_demo.cpp) plots float and double data, so those two must stay in the list for it to link +// (e.g. "(double)" alone fails with an undefined PlotBars). The define must also reach implot_demo.cpp, not only +// implot_items.cpp (or go in imconfig.h); otherwise the demo falls back to the default list and may fail to link. +// In order to support all known C++ types, use: +// -DIMPLOT_CUSTOM_NUMERIC_TYPES="(signed char)(unsigned char)(signed short)(unsigned short)(signed int)(unsigned int)(signed long)(unsigned long)(signed long long)(unsigned long long)(float)(double)(long double)" + +#ifdef IMPLOT_CUSTOM_NUMERIC_TYPES + #define IMPLOT_NUMERIC_TYPES IMPLOT_CUSTOM_NUMERIC_TYPES +#else + #define IMPLOT_NUMERIC_TYPES (ImS8)(ImU8)(ImS16)(ImU16)(ImS32)(ImU32)(ImS64)(ImU64)(float)(double) +#endif + // Split ImU32 color into RGB components [0 255] #define IM_COL32_SPLIT_RGB(col,r,g,b) \ ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \ @@ -123,10 +149,22 @@ template static inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); } // Returns always positive modulo (assumes r != 0) static inline int ImPosMod(int l, int r) { return (l % r + r) % r; } +// Returns the IEEE-754 bit pattern of val. NaN and infinity are tested on these bits rather than with isnan() or +// comparisons, so the tests need no , don't depend on whether isnan is a macro or a function, and keep +// working when -ffast-math (-ffinite-math-only) or /fp:fast lets the compiler assume floats are never NaN or infinite. +static inline ImU64 ImDoubleBits(double val) { + static_assert(sizeof(ImU64) == sizeof(double), "ImDoubleBits expects a 64-bit double"); + ImU64 bits; + memcpy(&bits, &val, sizeof(bits)); +#if defined(__FINITE_MATH_ONLY__) && __FINITE_MATH_ONLY__ && (defined(__GNUC__) || defined(__clang__)) + __asm__("" : "+r"(bits)); // hide the bits from the optimizer, which would otherwise fold these tests to false +#endif + return bits; +} // Returns true if val is NAN -static inline bool ImNan(double val) { return isnan(val); } +static inline bool ImNan(double val) { return (ImDoubleBits(val) & 0x7FFFFFFFFFFFFFFFull) > 0x7FF0000000000000ull; } // Returns true if val is NAN or INFINITY -static inline bool ImNanOrInf(double val) { return !(val >= -DBL_MAX && val <= DBL_MAX) || ImNan(val); } +static inline bool ImNanOrInf(double val) { return (ImDoubleBits(val) & 0x7FF0000000000000ull) == 0x7FF0000000000000ull; } // Turns NANs to 0s static inline double ImConstrainNan(double val) { return ImNan(val) ? 0 : val; } // Turns infinity to floating point maximums @@ -899,24 +937,25 @@ struct ImPlotAxis UpdateTransformCache(); } - inline bool HasLabel() const { return LabelOffset != -1 && !ImHasFlag(Flags, ImPlotAxisFlags_NoLabel); } - inline bool HasGridLines() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoGridLines); } - inline bool HasTickLabels() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); } - inline bool HasTickMarks() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickMarks); } - inline bool WillRender() const { return Enabled && (HasGridLines() || HasTickLabels() || HasTickMarks()); } - inline bool IsOpposite() const { return ImHasFlag(Flags, ImPlotAxisFlags_Opposite); } - inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); } - inline bool IsForeground() const { return ImHasFlag(Flags, ImPlotAxisFlags_Foreground); } - inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); } - inline bool CanInitFit() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoInitialFit) && !HasRange && !LinkedMin && !LinkedMax; } - inline bool IsRangeLocked() const { return HasRange && RangeCond == ImPlotCond_Always; } - inline bool IsLockedMin() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMin); } - inline bool IsLockedMax() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMax); } - inline bool IsLocked() const { return IsLockedMin() && IsLockedMax(); } - inline bool IsInputLockedMin() const { return IsLockedMin() || IsAutoFitting(); } - inline bool IsInputLockedMax() const { return IsLockedMax() || IsAutoFitting(); } - inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); } - inline bool HasMenus() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoMenus); } + inline bool HasLabel() const { return LabelOffset != -1 && !ImHasFlag(Flags, ImPlotAxisFlags_NoLabel); } + inline bool HasGridLines() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoGridLines); } + inline bool HasTickLabels() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); } + inline bool HasTickLabelsInside() const { return ImHasFlag(Flags, ImPlotAxisFlags_TickLabelsInside); } + inline bool HasTickMarks() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickMarks); } + inline bool WillRender() const { return Enabled && (HasGridLines() || HasTickLabels() || HasTickMarks()); } + inline bool IsOpposite() const { return ImHasFlag(Flags, ImPlotAxisFlags_Opposite); } + inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); } + inline bool IsForeground() const { return ImHasFlag(Flags, ImPlotAxisFlags_Foreground); } + inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); } + inline bool CanInitFit() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoInitialFit) && !HasRange && !LinkedMin && !LinkedMax; } + inline bool IsRangeLocked() const { return HasRange && RangeCond == ImPlotCond_Always; } + inline bool IsLockedMin() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMin); } + inline bool IsLockedMax() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMax); } + inline bool IsLocked() const { return IsLockedMin() && IsLockedMax(); } + inline bool IsInputLockedMin() const { return IsLockedMin() || IsAutoFitting(); } + inline bool IsInputLockedMax() const { return IsLockedMax() || IsAutoFitting(); } + inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); } + inline bool HasMenus() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoMenus); } inline bool IsPanLocked(bool increasing) { if (ImHasFlag(Flags, ImPlotAxisFlags_PanStretch)) { @@ -1255,6 +1294,7 @@ struct ImPlotContext { // Temp data for general use ImVector TempDouble1, TempDouble2; ImVector TempInt1; + ImVector TempRect1; // Misc int DigitalPlotItemCnt; @@ -1508,6 +1548,15 @@ IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap); // Render a colormap bar IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous); +// Render Horizontal/Vertical lines +#if (IMGUI_VERSION_NUM < 19275) +static inline void AddLineH(ImDrawList *draw_list, float x1, float x2, float y, ImU32 col, float thickness = 1.0f) { draw_list->AddLine(ImVec2(x1, y), ImVec2(x2, y), col, thickness); } +static inline void AddLineV(ImDrawList* draw_list, float x, float y1, float y2, ImU32 col, float thickness = 1.0f) { draw_list->AddLine(ImVec2(x, y1), ImVec2(x, y2), col, thickness); } +#else +static inline void AddLineH(ImDrawList *draw_list, float x1, float x2, float y, ImU32 col, float thickness = 1.0f) { draw_list->AddLineH(x1, x2, y, col, thickness); } +static inline void AddLineV(ImDrawList *draw_list, float x, float y1, float y2, ImU32 col, float thickness = 1.0f) { draw_list->AddLineV(x, y1, y2, col, thickness); } +#endif + //----------------------------------------------------------------------------- // [SECTION] Math and Misc Utils //----------------------------------------------------------------------------- diff --git a/include/implot/implot_items.cpp b/include/implot/implot_items.cpp index 41a09b5..e58296d 100644 --- a/include/implot/implot_items.cpp +++ b/include/implot/implot_items.cpp @@ -21,7 +21,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v1.1 WIP +// ImPlot v1.2 WIP #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS @@ -75,28 +75,7 @@ static IMPLOT_INLINE float ImInvSqrt(float x) { return 1.0f / sqrtf(x); } // [SECTION] Template instantiation utility //----------------------------------------------------------------------------- -// By default, templates are instantiated for `float`, `double`, and for the following integer types, which are defined in imgui.h: -// signed char ImS8; // 8-bit signed integer -// unsigned char ImU8; // 8-bit unsigned integer -// signed short ImS16; // 16-bit signed integer -// unsigned short ImU16; // 16-bit unsigned integer -// signed int ImS32; // 32-bit signed integer == int -// unsigned int ImU32; // 32-bit unsigned integer -// signed long long ImS64; // 64-bit signed integer -// unsigned long long ImU64; // 64-bit unsigned integer -// (note: this list does *not* include `long`, `unsigned long` and `long double`) -// -// You can customize the supported types by defining IMPLOT_CUSTOM_NUMERIC_TYPES at compile time to define your own type list. -// As an example, you could use the compile time define given by the line below in order to support only float and double. -// -DIMPLOT_CUSTOM_NUMERIC_TYPES="(float)(double)" -// In order to support all known C++ types, use: -// -DIMPLOT_CUSTOM_NUMERIC_TYPES="(signed char)(unsigned char)(signed short)(unsigned short)(signed int)(unsigned int)(signed long)(unsigned long)(signed long long)(unsigned long long)(float)(double)(long double)" - -#ifdef IMPLOT_CUSTOM_NUMERIC_TYPES - #define IMPLOT_NUMERIC_TYPES IMPLOT_CUSTOM_NUMERIC_TYPES -#else - #define IMPLOT_NUMERIC_TYPES (ImS8)(ImU8)(ImS16)(ImU16)(ImS32)(ImU32)(ImS64)(ImU64)(float)(double) -#endif +// The list of supported types, IMPLOT_NUMERIC_TYPES, is defined in implot_internal.h. // CALL_INSTANTIATE_FOR_NUMERIC_TYPES will duplicate the template instantiation code `INSTANTIATE_MACRO(T)` on supported types. #define _CAT(x, y) _CAT_(x, y) @@ -157,7 +136,14 @@ static inline double ImStdDev(const TContainer& values, int count) { return sqrt(x); } -IMPLOT_INLINE void GetLineRenderProps(const ImDrawList& draw_list, float& half_weight, ImVec2& tex_uv0, ImVec2& tex_uv1) { +IMPLOT_INLINE void GetLineRenderProps(ImDrawList& draw_list, float& half_weight, ImVec2& tex_uv0, ImVec2& tex_uv1) { +#if IMGUI_VERSION_NUM >= 19299 || defined(IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT) + float fringe; + draw_list._SelectLineTexture(half_weight * 2.0f, &tex_uv0, &tex_uv1, &fringe, draw_list.Flags); + //tex_uv0.x -= 0.5f * draw_list._Data->FontAtlas->TexUvScale.x; // Changed in features/drawlist_v193 but seems unncessary? + //tex_uv1.x -= 0.5f * draw_list._Data->FontAtlas->TexUvScale.x; + half_weight += fringe * 0.5f; +#else const bool aa = ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLines) && ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLinesUseTex); if (aa) { @@ -169,6 +155,7 @@ IMPLOT_INLINE void GetLineRenderProps(const ImDrawList& draw_list, float& half_w else { tex_uv0 = tex_uv1 = draw_list._Data->TexUvWhitePixel; } +#endif } IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, const ImVec2& tex_uv0, const ImVec2 tex_uv1) { @@ -351,6 +338,7 @@ ImPlotItem* GetItem(const char* label_id) { } bool IsItemHidden(const char* label_id) { + IM_ASSERT_USER_ERROR(GImPlot->CurrentItems != nullptr, "IsItemHidden() needs to be called within an itemized context!"); ImPlotItem* item = GetItem(label_id); return item != nullptr && !item->Show; } @@ -367,8 +355,16 @@ ImVec4 GetLastItemColor() { return ImVec4(); } +bool IsLastItemHidden() { + ImPlotContext& gp = *GImPlot; + if (gp.PreviousItem) + return !gp.PreviousItem->Show; + return false; +} + void BustItemCache() { ImPlotContext& gp = *GImPlot; + gp.PreviousItem = nullptr; // it points into the item pools freed below for (int p = 0; p < gp.Plots.GetBufSize(); ++p) { ImPlotPlot& plot = *gp.Plots.GetByIndex(p); plot.Items.Reset(); @@ -386,6 +382,7 @@ void BustColorCache(const char* plot_title_id) { } else { ImGuiID id = ImGui::GetCurrentWindow()->GetID(plot_title_id); + gp.PreviousItem = nullptr; // it may point into the item pool freed below ImPlotPlot* plot = gp.Plots.GetByKey(id); if (plot != nullptr) plot->Items.Reset(); @@ -689,15 +686,7 @@ struct GetterError { //----------------------------------------------------------------------------- struct GetterConstColor { - GetterConstColor(ImU32 color, float alpha = 1.0f) { - ImU32 col = color; - if (alpha < 1.0f) { - ImVec4 col_vec = ImGui::ColorConvertU32ToFloat4(col); - col_vec.w *= alpha; - col = ImGui::GetColorU32(col_vec); - } - Color = col; - } + GetterConstColor(ImU32 color) : Color(color) { } template IMPLOT_INLINE ImU32 operator[](I) const { return Color; } ImU32 Color; }; @@ -1821,6 +1810,8 @@ constexpr ImVec2 MARKER_LINE_RIGHT[6] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2) constexpr ImVec2 MARKER_LINE_ASTERISK[6] = {ImVec2(-SQRT_3_2, -0.5f), ImVec2(SQRT_3_2, 0.5f), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, -1), ImVec2(0, 1)}; constexpr ImVec2 MARKER_LINE_PLUS[4] = {ImVec2(-1, 0), ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, 1)}; constexpr ImVec2 MARKER_LINE_CROSS[4] = {ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)}; +constexpr ImVec2 MARKER_LINE_VERTICAL[2] = {ImVec2(0, -1), ImVec2(0, 1)}; +constexpr ImVec2 MARKER_LINE_HORIZONTAL[2] = {ImVec2(-1, 0), ImVec2(1, 0)}; template void RenderMarkers(const _Getter& getter, ImPlotMarker marker, bool rend_fill, const _GetterFillColor& col_fill_getter, bool rend_line, const _GetterLineColor& col_line_getter, const _GetterSize& size_getter, float weight) { @@ -1847,6 +1838,8 @@ void RenderMarkers(const _Getter& getter, ImPlotMarker marker, bool rend_fill, c case ImPlotMarker_Asterisk : RenderPrimitives3(getter,col_line_getter,size_getter,MARKER_LINE_ASTERISK,6,weight); break; case ImPlotMarker_Plus : RenderPrimitives3(getter,col_line_getter,size_getter,MARKER_LINE_PLUS, 4,weight); break; case ImPlotMarker_Cross : RenderPrimitives3(getter,col_line_getter,size_getter,MARKER_LINE_CROSS, 4,weight); break; + case ImPlotMarker_Vertical : RenderPrimitives3(getter,col_line_getter,size_getter,MARKER_LINE_VERTICAL,2,weight); break; + case ImPlotMarker_Horizontal: RenderPrimitives3(getter,col_line_getter,size_getter,MARKER_LINE_HORIZONTAL,2,weight); break; } } } @@ -1917,7 +1910,7 @@ void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlotSpec& s RenderPrimitives3(getter,getter2,color_getter); } else { const ImU32 col_fill = ImGui::GetColorU32(s.Spec.FillColor); - GetterConstColor color_getter(col_fill, s.Spec.FillAlpha); + GetterConstColor color_getter(col_fill); RenderPrimitives3(getter,getter2,color_getter); } } @@ -2188,7 +2181,7 @@ void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& GetterIdxColor color_getter(s.Spec.FillColors, getter.Count, s.Spec.FillAlpha); RenderPrimitives2(getter, color_getter); } else { - GetterConstColor color_getter(col_fill, s.Spec.FillAlpha); + GetterConstColor color_getter(col_fill); RenderPrimitives2(getter, color_getter); } } else { @@ -2196,7 +2189,7 @@ void PlotStairsEx(const char* label_id, const Getter& getter, const ImPlotSpec& GetterIdxColor color_getter(s.Spec.FillColors, getter.Count, s.Spec.FillAlpha); RenderPrimitives2(getter, color_getter); } else { - GetterConstColor color_getter(col_fill, s.Spec.FillAlpha); + GetterConstColor color_getter(col_fill); RenderPrimitives2(getter, color_getter); } } @@ -2274,7 +2267,7 @@ void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& g RenderPrimitives3(getter1,getter2,color_getter); } else { const ImU32 col = ImGui::GetColorU32(s.Spec.FillColor); - GetterConstColor color_getter(col, s.Spec.FillAlpha); + GetterConstColor color_getter(col); RenderPrimitives3(getter1,getter2,color_getter); } } @@ -2347,7 +2340,7 @@ void PlotBarsVEx(const char* label_id, const Getter1& getter1, const Getter2 get GetterIdxColor fill_getter(s.Spec.FillColors, getter1.Count, s.Spec.FillAlpha); RenderPrimitives3(getter1, getter2, fill_getter, width); } else { - GetterConstColor fill_getter(col_fill, s.Spec.FillAlpha); + GetterConstColor fill_getter(col_fill); RenderPrimitives3(getter1, getter2, fill_getter, width); } if (rend_line && col_fill == col_line) @@ -2383,7 +2376,7 @@ void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& ge GetterIdxColor fill_getter(s.Spec.FillColors, getter1.Count, s.Spec.FillAlpha); RenderPrimitives3(getter1, getter2, fill_getter, height); } else { - GetterConstColor fill_getter(col_fill, s.Spec.FillAlpha); + GetterConstColor fill_getter(col_fill); RenderPrimitives3(getter1, getter2, fill_getter, height); } if (rend_line && col_fill == col_line) @@ -2557,10 +2550,10 @@ void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const for (int i = 0; i < getter_pos.Count; ++i) { ImVec2 p1 = PlotToPixels(getter_neg[i],IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 p2 = PlotToPixels(getter_pos[i],IMPLOT_AUTO,IMPLOT_AUTO); - draw_list.AddLine(p1,p2,col, s.Spec.LineWeight); + draw_list.AddLine(p1, p2, col, s.Spec.LineWeight); if (rend_whisker) { - draw_list.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.Spec.LineWeight); - draw_list.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, s.Spec.LineWeight); + AddLineH(&draw_list, p1.x - half_whisker, p1.x + half_whisker, p1.y, col, s.Spec.LineWeight); + AddLineH(&draw_list, p2.x - half_whisker, p2.x + half_whisker, p2.y, col, s.Spec.LineWeight); } } EndItem(); @@ -2584,8 +2577,8 @@ void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const ImVec2 p2 = PlotToPixels(getter_pos[i],IMPLOT_AUTO,IMPLOT_AUTO); draw_list.AddLine(p1, p2, col, s.Spec.LineWeight); if (rend_whisker) { - draw_list.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.Spec.LineWeight); - draw_list.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, s.Spec.LineWeight); + AddLineV(&draw_list, p1.x, p1.y - half_whisker, p1.y + half_whisker, col, s.Spec.LineWeight); + AddLineV(&draw_list, p2.x, p2.y - half_whisker, p2.y + half_whisker, col, s.Spec.LineWeight); } } EndItem(); diff --git a/scripts/publish_generated_branch.py b/scripts/publish_generated_branch.py new file mode 100644 index 0000000..860afa7 --- /dev/null +++ b/scripts/publish_generated_branch.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""Push staged generated files only when their tree differs from the existing proposal. + +The caller stages the distribution files over a clean target default branch. +No-op runs leave both the local commit and remote proposal untouched; real +updates use the observed remote revision as an explicit force-with-lease. +""" + +import argparse +import os +from pathlib import Path +import subprocess + + +def git(repo, *args): + return subprocess.check_output(['git', *args], cwd=repo, text=True).strip() + + +def publish(repo, branch, message): + ref = 'refs/heads/' + branch + git(repo, 'check-ref-format', ref) + # ls-remote without --exit-code succeeds with empty output for a missing ref, + # but still propagates authentication/network failures. + remote = git(repo, 'ls-remote', '--heads', 'origin', ref) + remote_sha = remote.split()[0] if remote else None + desired_tree = git(repo, 'write-tree') + if remote_sha: + git(repo, 'fetch', '--no-tags', 'origin', ref) + if git(repo, 'rev-parse', 'FETCH_HEAD') != remote_sha: + raise RuntimeError('Proposal moved during comparison; retry later') + if desired_tree == git(repo, 'rev-parse', remote_sha + '^{tree}'): + print('Generated files already match the existing proposal; no commit or push.') + return False + if desired_tree == git(repo, 'rev-parse', 'HEAD^{tree}'): + print('Generated files already match the default branch; no commit or push.') + return False + git(repo, '-c', 'user.name=github-actions[bot]', '-c', + 'user.email=41898282+github-actions[bot]@users.noreply.github.com', + 'commit', '-m', message) + # An empty expected revision also protects creation against a concurrent push. + git(repo, 'push', '--force-with-lease=' + ref + ':' + (remote_sha or ''), + 'origin', 'HEAD:' + ref) + return True + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('branch') + parser.add_argument('message') + args = parser.parse_args() + pushed = publish(Path.cwd(), args.branch, args.message) + if output := os.environ.get('GITHUB_OUTPUT'): + with open(output, 'a', encoding='utf-8') as stream: + stream.write('pushed=' + str(pushed).lower() + '\n') + + +if __name__ == '__main__': + main() diff --git a/scripts/test_publish_generated_branch.py b/scripts/test_publish_generated_branch.py new file mode 100644 index 0000000..5b4616b --- /dev/null +++ b/scripts/test_publish_generated_branch.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +"""Exercise proposal idempotency, real updates and lease races against local Git remotes.""" + +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import textwrap +import unittest +from unittest.mock import patch + +import publish_generated_branch as publisher + + +SCRIPT = Path(publisher.__file__).resolve() +BRANCH = 'automation/generated-update' + + +class PublishTests(unittest.TestCase): + def setUp(self): + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + self.root = Path(self.temporary.name) + self.remote = self.root / 'remote.git' + self.work = self.root / 'work' + self.work.mkdir() + self.command('git', 'init', '--bare', str(self.remote)) + self.git('init', '--initial-branch=master') + self.git('config', 'user.name', 'Fixture') + self.git('config', 'user.email', 'fixture@example.invalid') + (self.work / 'generated.txt').write_text('old bindings\n') + self.git('add', '.') + self.git('commit', '-m', 'base') + self.git('remote', 'add', 'origin', str(self.remote)) + self.git('push', 'origin', 'master') + self.base = self.git('rev-parse', 'HEAD') + + def command(self, *args, **kwargs): + return subprocess.check_output(args, cwd=self.work, text=True, + stderr=subprocess.PIPE, **kwargs).strip() + + def git(self, *args): + return self.command('git', *args) + + def revision(self): + return self.git('ls-remote', 'origin', 'refs/heads/' + BRANCH).split()[0] + + def stage(self, text='new bindings\n'): + (self.work / 'generated.txt').write_text(text) + self.git('add', 'generated.txt') + + def run_publisher(self): + output = self.root / 'output' + output.unlink(missing_ok=True) + self.command(sys.executable, str(SCRIPT), BRANCH, 'Generated bindings', + env={**os.environ, 'GITHUB_OUTPUT': str(output)}) + return output.read_text() + + def reset_to_base(self): + # Destructive only inside this test's own temporary fixture checkout. + self.git('reset', '--hard', self.base) + + def test_first_proposal_is_pushed(self): + self.stage() + self.assertEqual(self.run_publisher(), 'pushed=true\n') + self.assertNotEqual(self.revision(), self.base) + + def test_repeat_preserves_remote_head_and_creates_no_local_commit(self): + self.stage() + self.run_publisher() + previous = self.revision() + self.reset_to_base() + self.stage() + self.assertEqual(self.run_publisher(), 'pushed=false\n') + self.assertEqual(self.revision(), previous) + self.assertEqual(self.git('rev-parse', 'HEAD'), self.base) + + def test_changed_output_updates_same_version_branch(self): + self.stage() + self.run_publisher() + previous = self.revision() + self.reset_to_base() + self.stage('corrected generator output\n') + self.assertEqual(self.run_publisher(), 'pushed=true\n') + self.assertNotEqual(self.revision(), previous) + + def test_real_base_file_change_is_retained(self): + self.stage() + self.run_publisher() + previous = self.revision() + self.reset_to_base() + (self.work / 'loader.v').write_text('updated loader\n') + self.git('add', '.') + self.git('commit', '-m', 'base update') + self.stage() + self.assertEqual(self.run_publisher(), 'pushed=true\n') + self.assertNotEqual(self.revision(), previous) + self.assertEqual(self.git('show', 'HEAD:loader.v'), 'updated loader') + + def test_default_branch_noop_does_not_create_a_proposal(self): + self.assertEqual(self.run_publisher(), 'pushed=false\n') + self.assertEqual(self.git('ls-remote', 'origin', 'refs/heads/' + BRANCH), '') + + def test_concurrent_remote_update_is_not_overwritten(self): + self.stage() + self.run_publisher() + previous = self.revision() + self.reset_to_base() + self.stage('another update\n') + original_git = publisher.git + + def race(repo, *args): + if args[0] == 'push': + self.command('git', '--git-dir', str(self.remote), 'update-ref', + 'refs/heads/' + BRANCH, self.base, previous) + return original_git(repo, *args) + + with patch.object(publisher, 'git', side_effect=race): + with self.assertRaises(subprocess.CalledProcessError): + publisher.publish(self.work, BRANCH, 'Generated bindings') + self.assertEqual(self.revision(), self.base) + + + +if __name__ == '__main__': + unittest.main() diff --git a/v.mod b/v.mod index f7602ed..e9cbeda 100644 --- a/v.mod +++ b/v.mod @@ -1,7 +1,7 @@ Module { name: 'antono2.imgui' description: 'Dear ImGui bindings for V. https://github.com/ocornut/imgui' - version: '0.3.2' + version: '0.4.0' author: 'Anton Oreskin' license: 'MIT' repo_url: 'https://github.com/antono2/imgui'