From 6af38b1a431eafda4cd9a3ad5d2e6c35425c1a14 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2022 14:42:30 +0100 Subject: [PATCH 01/15] Fixed version string for consistency (#5918) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 03eb0ca9..c3dc0ca2 100644 --- a/imgui.h +++ b/imgui.h @@ -22,7 +22,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') -#define IMGUI_VERSION "1.89.1 WIP" +#define IMGUI_VERSION "1.89.1" #define IMGUI_VERSION_NUM 18910 #define IMGUI_HAS_TABLE From bd96f6eac4ad544efb265d7e6bcdb30f99a841c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2022 14:59:13 +0100 Subject: [PATCH 02/15] Text: Fixed layouting of wrapped-text block when the last source line is above the clipping region. Regression added in 1.89. (#5720, #5919) + Update version marker --- docs/CHANGELOG.txt | 14 ++++++++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 7 ++++--- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 46f4fde0..123000bb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -31,12 +31,26 @@ HOW TO UPDATE? - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.89.2 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + - Text: Fixed layouting of wrapped-text block when the last source line is above the + clipping region. Regression added in 1.89. (#5720, #5919) + + ----------------------------------------------------------------------- VERSION 1.89.1 (Released 2022-11-24) ----------------------------------------------------------------------- Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.89.1 +Other changes: + - Scrolling, Focus: fixed SetKeyboardFocusHere()/SetItemDefaultFocus() during a window-appearing frame (and associated lower-level functions e.g. ScrollToRectEx()) from not centering item. (#5902) - Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code diff --git a/imgui.cpp b/imgui.cpp index d1790390..19b6f770 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index c3dc0ca2..aa58b32c 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (headers) // Help: @@ -22,8 +22,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') -#define IMGUI_VERSION "1.89.1" -#define IMGUI_VERSION_NUM 18910 +#define IMGUI_VERSION "1.89.2 WIP" +#define IMGUI_VERSION_NUM 18911 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 636c7b87..0e4aa729 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1203af8e..03b0e70e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (drawing and font code) /* @@ -3565,17 +3565,18 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im while (y + line_height < clip_rect.y && s < text_end) { const char* line_end = (const char*)memchr(s, '\n', text_end - s); + const char* line_next = line_end ? line_end + 1 : text_end; if (word_wrap_enabled) { // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. // However it is still better than nothing performing the fast-forward! - s = CalcWordWrapPositionA(scale, s, line_end, wrap_width); + s = CalcWordWrapPositionA(scale, s, line_next, wrap_width); s = CalcWordWrapNextLineStartA(s, text_end); } else { - s = line_end ? line_end + 1 : text_end; + s = line_next; } y += line_height; } diff --git a/imgui_internal.h b/imgui_internal.h index 816141e4..a42fa836 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (internal structures/api) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 503c098e..dab3ae4c 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5ecb182e..3c001098 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.89.1 +// dear imgui, v1.89.2 WIP // (widgets code) /* From 969af7c77369ddf2e8da23f1d4335270d8ac75be Mon Sep 17 00:00:00 2001 From: Teselka Date: Sun, 20 Nov 2022 23:45:55 +0200 Subject: [PATCH 03/15] Internal: Disable debug logs macro if IMGUI_DISABLE_DEBUG_TOOLS is defined. (#5901) + needed to rework clipper code to avoid "The 'then' statement is equivalent to the 'else' statement." PVS Studio warning. --- docs/CHANGELOG.txt | 6 ++++-- imgui.cpp | 5 ++++- imgui_internal.h | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 123000bb..00acc1dd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,8 +39,10 @@ Breaking changes: Other changes: - - Text: Fixed layouting of wrapped-text block when the last source line is above the - clipping region. Regression added in 1.89. (#5720, #5919) +- Text: fixed layouting of wrapped-text block when the last source line is above the + clipping region. Regression added in 1.89. (#5720, #5919) +- Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building + with IMGUI_DISABLE_DEBUG_TOOLS is used. (#5901) [@Teselka] ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 19b6f770..4eded91d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2871,11 +2871,14 @@ bool ImGuiListClipper::Step() if (need_items_height && ItemsHeight > 0.0f) IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight); if (ret) + { IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd); + } else + { IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n"); - if (!ret) End(); + } return ret; } diff --git a/imgui_internal.h b/imgui_internal.h index a42fa836..7fd26e54 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -211,7 +211,11 @@ namespace ImStb #endif // Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. +#ifndef IMGUI_DISABLE_DEBUG_TOOLS #define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#else +#define IMGUI_DEBUG_LOG(...) ((void)0) +#endif #define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) From 1a497c249958ab24fb471216b7747716709db62c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2022 18:11:09 +0100 Subject: [PATCH 04/15] Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of compile-time. (#5923, #456) --- backends/imgui_impl_win32.cpp | 2 +- backends/imgui_impl_win32.h | 2 +- docs/CHANGELOG.txt | 3 +++ docs/TODO.txt | 2 +- imgui.cpp | 15 +++++++++++---- imgui.h | 14 +++++--------- imgui_internal.h | 7 +++++-- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index a4660afd..b7b941fd 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -1,4 +1,4 @@ -// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // Implemented features: diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 082461dd..b74b4387 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -1,4 +1,4 @@ -// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // Implemented features: diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 00acc1dd..441b29ee 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,9 @@ Other changes: frame (and associated lower-level functions e.g. ScrollToRectEx()) from not centering item. (#5902) - Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code from accessing keys. (#5888, #4921, #456) +- Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of + compile-time, being consistent with our support for io.ConfigMacOSXBehaviors and making it + easier for bindings generators to process that value. (#5923, #456) - Inputs: fixed moving a window or drag and dropping from capturing mods. (#5888, #4921, #456) - Layout: fixed End()/EndChild() incorrectly asserting if users manipulates cursor position inside a collapsed/culled window and IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. (#5548, #5911) diff --git a/docs/TODO.txt b/docs/TODO.txt index cb7e6be7..b2d35c27 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -294,7 +294,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: fix AddRemapChar() to work before atlas has been built. - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer? - - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? + - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) ! nav: never clear NavId on some setup (e.g. gamepad centric) diff --git a/imgui.cpp b/imgui.cpp index 4eded91d..03ea973d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1343,6 +1343,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) IM_ASSERT(&g.IO == this && "Can only add events to current context."); IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API. IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. + IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself) // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -4241,7 +4242,6 @@ static void ImGui::UpdateKeyboardInputs() #undef NAV_MAP_KEY } #endif - #endif // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases @@ -7959,9 +7959,12 @@ const char* ImGui::GetKeyName(ImGuiKey key) return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; } +// ImGuiMod_Shortcut is translated to either Ctrl or Super. void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size) { ImGuiContext& g = *GImGui; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "", @@ -8037,6 +8040,8 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) ImGuiContext& g = *GImGui; ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; ImGuiKeyRoutingData* routing_data; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (key == ImGuiKey_None) @@ -8154,7 +8159,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) { const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); - ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry. return routing_data->RoutingCurr == routing_id; } @@ -8645,12 +8650,14 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags if (!SetShortcutRouting(key_chord, owner_id, flags)) return false; - ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); if (g.IO.KeyMods != mods) return false; // Special storage location for mods + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); if (key == ImGuiKey_None) key = ConvertSingleModFlagToKey(mods); @@ -8766,7 +8773,7 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. - // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. const ImGuiKeyChord key_mods = GetMergedModsFromBools(); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); diff --git a/imgui.h b/imgui.h index aa58b32c..ac5fed93 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.2 WIP" -#define IMGUI_VERSION_NUM 18911 +#define IMGUI_VERSION_NUM 18912 #define IMGUI_HAS_TABLE /* @@ -1431,7 +1431,7 @@ enum ImGuiKey : int ImGuiKey_GamepadRStickUp, // [Analog] ImGuiKey_GamepadRStickDown, // [Analog] - // Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, @@ -1452,12 +1452,8 @@ enum ImGuiKey : int ImGuiMod_Shift = 1 << 13, ImGuiMod_Alt = 1 << 14, // Option/Menu ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows - ImGuiMod_Mask_ = 0xF000, -#if defined(__APPLE__) - ImGuiMod_Shortcut = ImGuiMod_Super, -#else - ImGuiMod_Shortcut = ImGuiMod_Ctrl, -#endif + ImGuiMod_Shortcut = 1 << 11, // [Internal, read-only] Alias of ImGuiMod_Super (macOS) or ImGuiMod_Ctrl (otherwise), decided by io.ConfigMacOSXBehaviors. + ImGuiMod_Mask_ = 0xF800, // 5-bits // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) @@ -2028,7 +2024,7 @@ struct ImGuiIO bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows // Other state maintained from data above + IO function calls - ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame() + ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame() ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) diff --git a/imgui_internal.h b/imgui_internal.h index 7fd26e54..9a26f3f1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1295,7 +1295,7 @@ typedef ImS16 ImGuiKeyRoutingIndex; struct ImGuiKeyRoutingData { ImGuiKeyRoutingIndex NextEntryIndex; - ImU16 Mods; // Technically we'd only need 4 bits but for simplify we store ImGuiMod_ values which need 16 bits. + ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super. ImU8 RoutingNextScore; // Lower is better (0: perfect score) ImGuiID RoutingCurr; ImGuiID RoutingNext; @@ -2864,18 +2864,21 @@ namespace ImGui // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } - inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super; } + inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; } inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; } inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } + inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); } inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) { + ImGuiContext& g = *GImGui; if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; + if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl); return key; } From cc3a2200a9443974b998ef88d0054600f5afe147 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2022 18:57:38 +0100 Subject: [PATCH 05/15] Internals: invert logic of mods key<>bool translation to facilitate other experiments and put emphasis on new API. (#5923, #4921) Should be no-op, this is mostly to make it easier to store state for ImGuiMod_Shortcut. --- imgui.cpp | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 03ea973d..6e8f6957 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4160,16 +4160,15 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes } -// [Internal] Do not use directly (should read io.KeyMods instead) -static ImGuiKeyChord GetMergedModsFromBools() +// [Internal] Do not use directly +static ImGuiKeyChord GetMergedModsFromKeys() { - ImGuiContext& g = *GImGui; - ImGuiKeyChord key_chord = 0; - if (g.IO.KeyCtrl) { key_chord |= ImGuiMod_Ctrl; } - if (g.IO.KeyShift) { key_chord |= ImGuiMod_Shift; } - if (g.IO.KeyAlt) { key_chord |= ImGuiMod_Alt; } - if (g.IO.KeySuper) { key_chord |= ImGuiMod_Super; } - return key_chord; + ImGuiKeyChord mods = 0; + if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; } + if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; } + if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; } + if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; } + return mods; } static void ImGui::UpdateKeyboardInputs() @@ -4244,13 +4243,22 @@ static void ImGui::UpdateKeyboardInputs() #endif #endif - // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases - io.KeyMods = GetMergedModsFromBools(); + // Update aliases for (int n = 0; n < ImGuiMouseButton_COUNT; n++) UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH); UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel); + // Synchronize io.KeyMods and io.KeyXXX values. + // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing. + io.KeyMods = GetMergedModsFromKeys(); + io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0; + io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0; + io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0; + io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0; + // Clear gamepad data if disabled if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) @@ -8485,15 +8493,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) key_changed = true; key_changed_mask.SetBit(key_data_index); - if (key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super) - { - if (key == ImGuiMod_Ctrl) { io.KeyCtrl = key_data->Down; } - if (key == ImGuiMod_Shift) { io.KeyShift = key_data->Down; } - if (key == ImGuiMod_Alt) { io.KeyAlt = key_data->Down; } - if (key == ImGuiMod_Super) { io.KeySuper = key_data->Down; } - io.KeyMods = GetMergedModsFromBools(); - } - // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO io.KeysDown[key_data_index] = key_data->Down; @@ -8775,7 +8774,7 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. - const ImGuiKeyChord key_mods = GetMergedModsFromBools(); + const ImGuiKeyChord key_mods = GetMergedModsFromKeys(); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); IM_UNUSED(key_mods); From bf4c2e00c09384a56fa1a4df30443e56ebcb85fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2022 21:36:59 +0100 Subject: [PATCH 06/15] Docs: retroactively update 1.89 changelog/docs to clarify that strong typing ImGuiKey was technically a breaking change for users of legacy indices. (#4921) Amend 4b522e145 --- docs/CHANGELOG.txt | 6 +++++- imgui.cpp | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 441b29ee..93f788c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -95,6 +95,11 @@ Breaking changes: Without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it. (This incorrect pattern has been mentioned or suggested in: #4510, #3355, #1760, #1490, #4152, #150, threads have been amended to refer to this issue). +- Inputs: ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. (#4921) + This will require uses of legacy backend-dependent indices to be casted, e.g. + - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A); + - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A') + - etc. however if you are upgrading code you might as well use the backend-agnostic IsKeyPressed(ImGuiKey_A) now. - Renamed and merged keyboard modifiers key enums and flags into a same set: (#4921, #456) - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift @@ -223,7 +228,6 @@ Other Changes: - ImDrawList: Not using alloca() anymore, lift single polygon size limits. (#5704, #1811) - Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups. (#2589, #5535, #5264, #4972) -- Misc: ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. (#4921) - Misc: better error reporting for PopStyleColor()/PopStyleVar() + easier to recover. (#1651) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) - Debug Tools: Debug Log: Visually locate items when hovering a 0xXXXXXXXX value. (#5855) diff --git a/imgui.cpp b/imgui.cpp index 6e8f6957..ef24afdc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,6 +395,11 @@ CODE the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends. the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions. exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway. + - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. + this will require uses of legacy backend-dependent indices to be casted, e.g. + - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A); + - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A') + - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now! - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr); - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020): - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. From 50aeeff96c6369084c23a157fe8490c97676dea2 Mon Sep 17 00:00:00 2001 From: Espyo Date: Tue, 29 Nov 2022 20:56:10 +0000 Subject: [PATCH 07/15] Backends: Allegro5: Brough back al_draw_indexed_prim when available. (#5937) Amend 185b4dde --- backends/imgui_impl_allegro5.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 82826cf3..4a48a2bb 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -7,7 +7,7 @@ // [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Issues: -// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. +// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually. // [ ] Platform: Missing gamepad support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -132,13 +132,12 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - // Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves. // FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well.. static ImVector vertices; - vertices.resize(cmd_list->IdxBuffer.Size); - for (int i = 0; i < cmd_list->IdxBuffer.Size; i++) + vertices.resize(cmd_list->VtxBuffer.Size); + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { - const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]]; + const ImDrawVert* src_v = &cmd_list->VtxBuffer[i]; ImDrawVertAllegro* dst_v = &vertices[i]; dst_v->pos = src_v->pos; dst_v->uv = src_v->uv; @@ -187,7 +186,9 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Apply scissor/clipping rectangle, Draw ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID(); al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y); - al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); + if(pcmd->ElemCount > 0) { + al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); + } } } } From a5f3596e6cbbda1a275ac4eb66b00a8a60ecd408 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Nov 2022 14:43:00 +0100 Subject: [PATCH 08/15] Backends: Allegro5: use al_draw_indexed_prim() or al_draw_prim() depending on version. (#5937) + OSX comments (#5938) Amend 185b4dde + 50aeeff --- backends/imgui_impl_allegro5.cpp | 66 +++++++++++++++++++++----------- backends/imgui_impl_osx.h | 3 +- backends/imgui_impl_osx.mm | 3 +- docs/CHANGELOG.txt | 1 + 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 4a48a2bb..bf7f141e 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). // 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. @@ -37,6 +38,7 @@ // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window. // 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12). // 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-06-13: Renderer: Stopped using al_draw_indexed_prim() as it is buggy in Allegro's DX9 backend. // 2018-06-13: Renderer: Backup/restore transform and clipping rectangle. // 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. // 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp. @@ -56,13 +58,27 @@ #ifdef _WIN32 #include #endif -#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12 +#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12 +#define ALLEGRO_HAS_DRAW_INDEXED_PRIM (ALLEGRO_VERSION_INT >= ((5 << 24) | (2 << 16) | ( 5 << 8))) // DX9 implementation of al_draw_indexed_prim() got fixed in Allegro 5.2.5 // Visual Studio warnings #ifdef _MSC_VER #pragma warning (disable: 4127) // condition expression is constant #endif +struct ImDrawVertAllegro +{ + ImVec2 pos; + ImVec2 uv; + ALLEGRO_COLOR col; +}; + +// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well.. +// FIXME-OPT: Consider inlining al_map_rgba()? +// see https://github.com/liballeg/allegro5/blob/master/src/pixels.c#L554 +// and https://github.com/liballeg/allegro5/blob/master/include/allegro5/internal/aintern_pixels.h +#define DRAW_VERT_IMGUI_TO_ALLEGRO(DST, SRC) { (DST)->pos = (SRC)->pos; (DST)->uv = (SRC)->uv; unsigned char* c = (unsigned char*)&(SRC)->col; (DST)->col = al_map_rgba(c[0], c[1], c[2], c[3]); } + // Allegro Data struct ImGui_ImplAllegro5_Data { @@ -73,6 +89,9 @@ struct ImGui_ImplAllegro5_Data ALLEGRO_VERTEX_DECL* VertexDecl; char* ClipboardTextData; + ImVector BufVertices; + ImVector BufIndices; + ImGui_ImplAllegro5_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -81,13 +100,6 @@ struct ImGui_ImplAllegro5_Data // FIXME: multi-context support is not well tested and probably dysfunctional in this backend. static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } -struct ImDrawVertAllegro -{ - ImVec2 pos; - ImVec2 uv; - ALLEGRO_COLOR col; -}; - static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data) { // Setup blending @@ -132,34 +144,40 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - // FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well.. - static ImVector vertices; + ImVector& vertices = bd->BufVertices; +#if ALLEGRO_HAS_DRAW_INDEXED_PRIM vertices.resize(cmd_list->VtxBuffer.Size); for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { const ImDrawVert* src_v = &cmd_list->VtxBuffer[i]; ImDrawVertAllegro* dst_v = &vertices[i]; - dst_v->pos = src_v->pos; - dst_v->uv = src_v->uv; - unsigned char* c = (unsigned char*)&src_v->col; - dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]); + DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v); } - const int* indices = nullptr; if (sizeof(ImDrawIdx) == 2) { - // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices. + // FIXME-OPT: Allegro doesn't support 16-bit indices. + // You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices. // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful. - static ImVector indices_converted; - indices_converted.resize(cmd_list->IdxBuffer.Size); + bd->BufIndices.resize(cmd_list->IdxBuffer.Size); for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) - indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i]; - indices = indices_converted.Data; + bd->BufIndices[i] = (int)cmd_list->IdxBuffer.Data[i]; + indices = bd->BufIndices.Data; } else if (sizeof(ImDrawIdx) == 4) { indices = (const int*)cmd_list->IdxBuffer.Data; } +#else + // Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format. + vertices.resize(cmd_list->IdxBuffer.Size); + for (int i = 0; i < cmd_list->IdxBuffer.Size; i++) + { + const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]]; + ImDrawVertAllegro* dst_v = &vertices[i]; + DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v); + } +#endif // Render command lists ImVec2 clip_off = draw_data->DisplayPos; @@ -186,9 +204,11 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Apply scissor/clipping rectangle, Draw ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID(); al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y); - if(pcmd->ElemCount > 0) { - al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); - } +#if ALLEGRO_HAS_DRAW_INDEXED_PRIM + al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); +#else + al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); +#endif } } } diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 70619e39..fd8755b6 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -1,6 +1,7 @@ // dear imgui: Platform Backend for OSX / Cocoa // This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..) -// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac. +// - Not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac. +// - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 2505bbd3..aa65d713 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -1,6 +1,7 @@ // dear imgui: Platform Backend for OSX / Cocoa // This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..) -// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac. +// - Not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac. +// - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 93f788c2..c4720e78 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,7 @@ Other changes: clipping region. Regression added in 1.89. (#5720, #5919) - Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building with IMGUI_DISABLE_DEBUG_TOOLS is used. (#5901) [@Teselka] +- Backends: Allegro5: restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. (#5937) [@Espyo] ----------------------------------------------------------------------- From 87caf27ac40fb451103a5899b347dc569ee58e44 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Nov 2022 17:46:57 +0100 Subject: [PATCH 09/15] Inputs, Scrolling: better selection of scrolling window when hovering nested windows and backend/OS is emitting dual-axis wheeling inputs. (#3795, #4559) --- docs/CHANGELOG.txt | 4 ++ imgui.cpp | 118 ++++++++++++++++++++++++++++++++------------- imgui.h | 2 +- imgui_internal.h | 5 ++ 4 files changed, 95 insertions(+), 34 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c4720e78..a0fe8a0d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,10 @@ Breaking changes: Other changes: +- Inputs, Scrolling: better selection of scrolling window when hovering nested windows + and when backend/OS is emitting dual-axis wheeling inputs (typically touch pads on macOS). + We now select a primary axis based on recent events, and select a target window based on it. + We expect this behavior to be further improved/tweaked. (#3795, #4559) [@ocornut, @folays] - Text: fixed layouting of wrapped-text block when the last source line is above the clipping region. Regression added in 1.89. (#5720, #5919) - Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building diff --git a/imgui.cpp b/imgui.cpp index ef24afdc..ba057dfc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4367,13 +4367,58 @@ static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount) IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL"); g.WheelingWindow = window; g.WheelingWindowRefMousePos = g.IO.MousePos; + if (window == NULL) + { + g.WheelingWindowStartFrame = -1; + g.WheelingAxisAvg = ImVec2(0.0f, 0.0f); + } +} + +static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel) +{ + // For each axis, find window in the hierarchy that may want to use scrolling + ImGuiContext& g = *GImGui; + ImGuiWindow* windows[2] = { NULL, NULL }; + for (int axis = 0; axis < 2; axis++) + if (wheel[axis] != 0.0f) + for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow) + { + // Bubble up into parent window if: + // - a child window doesn't allow any scrolling. + // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. + //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP) + const bool has_scrolling = (window->ScrollMax[axis] != 0.0f); + const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs); + //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]); + if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits) + break; // select this window + } + if (windows[0] == NULL && windows[1] == NULL) + return NULL; + + // If there's only one window or only one axis then there's no ambiguity + if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL) + return windows[1] ? windows[1] : windows[0]; + + // If candidate are different windows we need to decide which one to prioritize + // - First frame: only find a winner if one axis is zero. + // - Subsequent frames: only find a winner when one is more than the other. + if (g.WheelingWindowStartFrame == -1) + g.WheelingWindowStartFrame = g.FrameCount; + if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y)) + { + g.WheelingWindowWheelRemainder = wheel; + return NULL; + } + return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1]; } void ImGui::UpdateMouseWheel() { ImGuiContext& g = *GImGui; - // Reset the locked window if we move the mouse or after the timer elapses + // Reset the locked window if we move the mouse or after the timer elapses. + // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795) if (g.WheelingWindow != NULL) { g.WheelingWindowReleaseTimer -= g.IO.DeltaTime; @@ -4386,8 +4431,6 @@ void ImGui::UpdateMouseWheel() ImVec2 wheel; wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f; wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f; - if (wheel.x == 0.0f && wheel.y == 0.0f) - return; //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y); ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; @@ -4425,39 +4468,41 @@ void ImGui::UpdateMouseWheel() wheel.y = 0.0f; } - // Vertical Mouse Wheel scrolling - // Bubble up into parent window if: - // - a child window doesn't allow any scrolling. - // - a child window doesn't need scrolling because it is already at the edge for the direction we are going in. - // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. - if (wheel.y != 0.0f) - { - ImGuiWindow* window = mouse_window; - while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) - window = window->ParentWindow; - if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) - { - LockWheelingWindow(mouse_window, wheel.y); - float max_step = window->InnerRect.GetHeight() * 0.67f; - float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); - SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); - } - } + // Maintain a rough average of moving magnitude on both axises + // FIXME: should by based on wall clock time rather than frame-counter + g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30); + g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30); - // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held - if (wheel.x != 0.0f) - { - ImGuiWindow* window = mouse_window; - while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) - window = window->ParentWindow; + // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now. + wheel += g.WheelingWindowWheelRemainder; + g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f); + if (wheel.x == 0.0f && wheel.y == 0.0f) + return; + + // Mouse wheel scrolling: find target and apply + // - don't renew lock if axis doesn't apply on the window. + // - select a main axis when both axises are being moved. + if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel))) if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) { - LockWheelingWindow(mouse_window, wheel.x); - float max_step = window->InnerRect.GetWidth() * 0.67f; - float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); - SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f }; + if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y]) + do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false; + if (do_scroll[ImGuiAxis_X]) + { + LockWheelingWindow(window, wheel.x); + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + } + if (do_scroll[ImGuiAxis_Y]) + { + LockWheelingWindow(window, wheel.y); + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); + } } - } } // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) @@ -8427,7 +8472,7 @@ static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) ImGuiContext& g = *GImGui; if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("%s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; } if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; } - if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f, %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; } + if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.3f, %.3f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; } if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("%s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } @@ -13409,6 +13454,13 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); Unindent(); + Text("MOUSE WHEELING"); + Indent(); + Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); + Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); + Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); + Unindent(); + TreePop(); } diff --git a/imgui.h b/imgui.h index ac5fed93..de13e113 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.2 WIP" -#define IMGUI_VERSION_NUM 18912 +#define IMGUI_VERSION_NUM 18913 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 9a26f3f1..e23ec7b4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -477,6 +477,7 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } +static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry @@ -1764,7 +1765,10 @@ struct ImGuiContext ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; + int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL float WheelingWindowReleaseTimer; + ImVec2 WheelingWindowWheelRemainder; + ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] @@ -2030,6 +2034,7 @@ struct ImGuiContext HoveredWindowUnderMovingWindow = NULL; MovingWindow = NULL; WheelingWindow = NULL; + WheelingWindowStartFrame = -1; WheelingWindowReleaseTimer = 0.0f; DebugHookIdInfo = 0; From 45736443be1e18a2441e599395dd12a4928eed5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Nov 2022 20:08:57 +0100 Subject: [PATCH 10/15] Debug Tools: Metrics: added "Inputs" section, moved from Demo for consistency. --- docs/CHANGELOG.txt | 2 + imgui.cpp | 158 ++++++++++++++++++++++++++++++++-------- imgui_demo.cpp | 178 +++++++++++++++------------------------------ imgui_internal.h | 1 + 4 files changed, 190 insertions(+), 149 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a0fe8a0d..3868a2ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -75,6 +75,8 @@ Other changes: - Drag and Drop: fixed GetDragDropPayload() returning a non-NULL value if a drag source is active but a payload hasn't been submitted yet. This is convenient to detect new payload from within a drag source handler. (#5910, #143) +- Demo: simplified "Inputs" section, moved contents to Metrics->Inputs. +- Debug Tools: Metrics: added "Inputs" section, moved from Demo for consistency. - Backends: GLFW: cancel out errors emitted by glfwGetKeyName() when a name is missing. (#5908) - Backends: WebGPU: fixed validation error with default depth buffer settings. (#5869, #5914) [@kdchambers] diff --git a/imgui.cpp b/imgui.cpp index ba057dfc..b8a24fec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12982,6 +12982,55 @@ static void RenderViewportsThumbnails() ImGui::Dummy(bb_full.GetSize() * SCALE); } +// Draw an arbitrary US keyboard layout to visualize translated keys +void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list) +{ + const ImVec2 key_size = ImVec2(35.0f, 35.0f); + const float key_rounding = 3.0f; + const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); + const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); + const float key_face_rounding = 2.0f; + const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); + const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); + const float key_row_offset = 9.0f; + + ImVec2 board_min = GetCursorScreenPos(); + ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); + ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); + + struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; + const KeyLayoutData keys_to_display[] = + { + { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, + { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, + { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } + }; + + // Elements rendered manually via ImDrawList API are not clipped automatically. + // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. + Dummy(board_max - board_min); + if (!IsItemVisible()) + return; + draw_list->PushClipRect(board_min, board_max, true); + for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) + { + const KeyLayoutData* key_data = &keys_to_display[n]; + ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); + ImVec2 key_max = key_min + key_size; + draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); + draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); + ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); + ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); + draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); + draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); + ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); + draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); + if (ImGui::IsKeyDown(key_data->Key)) + draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); + } + draw_list->PopClipRect(); +} + // Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct. void ImGui::DebugTextEncoding(const char* str) { @@ -13380,41 +13429,95 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } - if (TreeNode("Key Owners & Shortcut Routing")) + if (TreeNode("Inputs")) { - TextUnformatted("Key Owners:"); - if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8))) + Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); + { + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. + // User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes. + Indent(); +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } +#endif + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + DebugRenderKeyboardPreview(GetWindowDrawList()); + Unindent(); + } + + Text("MOUSE STATE"); + { + Indent(); + if (IsMousePosValid()) + Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + Text("Mouse pos: "); + Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + int count = IM_ARRAYSIZE(io.MouseDown); + Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); } + Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); } + Text("Mouse wheel: %.1f", io.MouseWheel); + Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused + Unindent(); + } + + Text("MOUSE WHEELING"); { - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + Indent(); + Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); + Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); + Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); + Unindent(); + } + + Text("KEY OWNERS"); + { + Indent(); + if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) { - ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); - if (owner_data->OwnerCurr == ImGuiKeyOwner_None) - continue; - Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, - owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); - DebugLocateItemOnHover(owner_data->OwnerCurr); + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + continue; + Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, + owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); + DebugLocateItemOnHover(owner_data->OwnerCurr); + } + EndListBox(); } - EndListBox(); + Unindent(); } - TextUnformatted("Shortcut Routing:"); - if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8))) + Text("SHORTCUT ROUTING"); { - for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + Indent(); + if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) { - ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; - for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - char key_chord_name[64]; - ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; - GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); - Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); - DebugLocateItemOnHover(routing_data->RoutingCurr); - idx = routing_data->NextEntryIndex; + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) + { + char key_chord_name[64]; + ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; + GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); + Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); + DebugLocateItemOnHover(routing_data->RoutingCurr); + idx = routing_data->NextEntryIndex; + } } + EndListBox(); } - EndListBox(); + Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); + Unindent(); } - Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); TreePop(); } @@ -13454,13 +13557,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); Unindent(); - Text("MOUSE WHEELING"); - Indent(); - Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); - Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); - Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); - Unindent(); - TreePop(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0e4aa729..6892d2d6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -5686,146 +5686,59 @@ namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); } static void ShowDemoWindowInputs() { - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus"); - if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) + IMGUI_DEMO_MARKER("Inputs & Focus"); + if (ImGui::CollapsingHeader("Inputs & Focus")) { ImGuiIO& io = ImGui::GetIO(); - // Display ImGuiIO output flags - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Output"); + // Display inputs submitted to ImGuiIO + IMGUI_DEMO_MARKER("Inputs & Focus/Inputs"); ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Output")) - { - ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse); - ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); - ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard); - ImGui::Text("io.WantTextInput: %d", io.WantTextInput); - ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos); - ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible); - ImGui::TreePop(); - } - - // Display Mouse state - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse State"); - if (ImGui::TreeNode("Mouse State")) + if (ImGui::TreeNode("Inputs")) { + HelpMarker( + "This is a simplified view. See more detailed input state:\n" + "- in 'Tools->Metrics/Debugger->Inputs'.\n" + "- in 'Tools->Debug Log->IO'."); if (ImGui::IsMousePosValid()) ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse pos: "); ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - - int count = IM_ARRAYSIZE(io.MouseDown); - ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, ImGui::GetMouseClickedCount(i)); } - ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse down:"); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); - ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused - ImGui::TreePop(); - } - - // Display mouse cursors - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse Cursors"); - if (ImGui::TreeNode("Mouse Cursors")) - { - const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; - IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); - - ImGuiMouseCursor current = ImGui::GetMouseCursor(); - ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); - ImGui::BeginDisabled(true); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); - ImGui::EndDisabled(); - ImGui::Text("Hover to see mouse cursors:"); - ImGui::SameLine(); HelpMarker( - "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " - "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " - "otherwise your backend needs to handle it."); - for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) - { - char label[32]; - sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); - ImGui::Bullet(); ImGui::Selectable(label, false); - if (ImGui::IsItemHovered()) - ImGui::SetMouseCursor(i); - } - ImGui::TreePop(); - } - - // Display Keyboard/Mouse state - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard, Gamepad & Navigation State"); - if (ImGui::TreeNode("Keyboard, Gamepad & Navigation State")) - { // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. // User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes. #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; - const ImGuiKey key_first = (ImGuiKey)ImGuiKey_NamedKey_BEGIN; #else struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array - const ImGuiKey key_first = (ImGuiKey)0; - //ImGui::Text("Legacy raw:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } #endif - ImGui::Text("Keys down:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (%.02f)", ImGui::GetKeyName(key), key, ImGui::GetKeyData(key)->DownDuration); } } - ImGui::Text("Keys pressed:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyPressed(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } - ImGui::Text("Keys released:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } + ImGui::Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); ImGui::SameLine(); ImGui::Text("(%.02f)", ImGui::GetKeyData(key)->DownDuration); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - - // Draw an arbitrary US keyboard layout to visualize translated keys - { - const ImVec2 key_size = ImVec2(35.0f, 35.0f); - const float key_rounding = 3.0f; - const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); - const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); - const float key_face_rounding = 2.0f; - const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); - const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); - const float key_row_offset = 9.0f; + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. - ImVec2 board_min = ImGui::GetCursorScreenPos(); - ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); - ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); + ImGui::TreePop(); + } - struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; - const KeyLayoutData keys_to_display[] = - { - { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, - { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, - { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } - }; - - // Elements rendered manually via ImDrawList API are not clipped automatically. - // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. - ImGui::Dummy(ImVec2(board_max.x - board_min.x, board_max.y - board_min.y)); - if (ImGui::IsItemVisible()) - { - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - draw_list->PushClipRect(board_min, board_max, true); - for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) - { - const KeyLayoutData* key_data = &keys_to_display[n]; - ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); - ImVec2 key_max = ImVec2(key_min.x + key_size.x, key_min.y + key_size.y); - draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); - draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); - ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); - ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); - draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); - draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); - ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); - draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); - if (ImGui::IsKeyDown(key_data->Key)) - draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); - } - draw_list->PopClipRect(); - } - } + // Display ImGuiIO output flags + IMGUI_DEMO_MARKER("Inputs & Focus/Outputs"); + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode("Outputs")) + { + ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose); + ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + ImGui::Text("io.WantTextInput: %d", io.WantTextInput); + ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos); + ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible); ImGui::TreePop(); } - if (ImGui::TreeNode("Capture override")) + IMGUI_DEMO_MARKER("Inputs & Focus/IO Output: Capture override"); + if (ImGui::TreeNode("IO Output: Capture override")) { HelpMarker( "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " @@ -5859,7 +5772,36 @@ static void ShowDemoWindowInputs() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Tabbing"); + // Display mouse cursors + IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); + if (ImGui::TreeNode("Mouse Cursors")) + { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); + + ImGuiMouseCursor current = ImGui::GetMouseCursor(); + ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); + ImGui::BeginDisabled(true); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); + ImGui::EndDisabled(); + + ImGui::Text("Hover to see mouse cursors:"); + ImGui::SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " + "otherwise your backend needs to handle it."); + for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered()) + ImGui::SetMouseCursor(i); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing"); if (ImGui::TreeNode("Tabbing")) { ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); @@ -5875,7 +5817,7 @@ static void ShowDemoWindowInputs() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Focus from code"); + IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code"); if (ImGui::TreeNode("Focus from code")) { bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); @@ -5917,7 +5859,7 @@ static void ShowDemoWindowInputs() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Dragging"); + IMGUI_DEMO_MARKER("Inputs & Focus/Dragging"); if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); diff --git a/imgui_internal.h b/imgui_internal.h index e23ec7b4..6be43ccb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3162,6 +3162,7 @@ namespace ImGui IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); + IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); // Obsolete functions From a5e96ff99e50f25d5188ebff2addafaecd847137 Mon Sep 17 00:00:00 2001 From: Marc Delorme Date: Tue, 1 Nov 2022 21:56:10 +0900 Subject: [PATCH 11/15] Make ImGuiInputTextState not depend on the implicit GImGui context. (#5856) This commit is a preparation toward adding ImGui apis with explicit context and making ImGui applications being able to use multiple context at the same time whatever their concurrency model. -- Prior to this commit ImGuiInputTextState::OnKeyPressed was depending on the global context to know which font and font size to use, and if it should follow MacOSX behaviors or not (c.f ConfigMacOSXBehaviors). Instead of using the global context, this commit store the context as attribute of ImGuiInputTextState. Since this state is forwarded to most of text edit related function, it possible to access font, font size and ConfigMacOSXBehaviors from everywhere. NOTE: I have noticed a bug prior to that commit: if the font or font size change while editing the same widget, the ImGuiInputTextState become invalid and there is no code to handle this invalidation. Fixing this bug is out of scope of current pull request. # Conflicts: # imgui_internal.h --- imgui_internal.h | 4 +++- imgui_widgets.cpp | 18 +++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 6be43ccb..be018421 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1051,6 +1051,7 @@ struct IMGUI_API ImGuiMenuColumns // For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState { + ImGuiContext* Ctx; // parent dear imgui context ImGuiID ID; // widget id owning the text state int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. @@ -1066,7 +1067,7 @@ struct IMGUI_API ImGuiInputTextState bool Edited; // edited this frame ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. - ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + ImGuiInputTextState(ImGuiContext* ctx) { memset(this, 0, sizeof(*this)); Ctx = ctx;} void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } int GetUndoAvailCount() const { return Stb.undostate.undo_point; } @@ -2014,6 +2015,7 @@ struct ImGuiContext ImVector TempBuffer; // Temporary text buffer ImGuiContext(ImFontAtlas* shared_font_atlas) + : InputTextState(this) { Initialized = false; FontAtlasOwnedByContext = shared_font_atlas ? false : true; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3c001098..5cbd39d9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -126,7 +126,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); // For InputTextEx() static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); -static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); //------------------------------------------------------------------------- // [SECTION] Widgets: Text, etc. @@ -3563,9 +3563,9 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** return line_count; } -static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) { - ImGuiContext& g = *GImGui; + ImGuiContext& g = *ctx; ImFont* font = g.Font; const float line_height = g.FontSize; const float scale = line_height / font->FontSize; @@ -3614,14 +3614,14 @@ namespace ImStb static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { const ImWchar* text = obj->TextW.Data; const ImWchar* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -3637,7 +3637,7 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { if (ImGui::GetIO().ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL @@ -4675,11 +4675,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ searches_result_line_no[1] = line_count; // Calculate 2d position by finding the beginning of the line and measuring distance - cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; cursor_offset.y = searches_result_line_no[0] * g.FontSize; if (searches_result_line_no[1] >= 0) { - select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; select_start_offset.y = searches_result_line_no[1] * g.FontSize; } @@ -4748,7 +4748,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true); if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); From 66ad2ad5398cb61433009553e10fd326d13acb84 Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 30 Nov 2022 11:57:54 -0800 Subject: [PATCH 12/15] Properly detect SSE instruction support in 32-bit MSVC build. (#5943) --- docs/CHANGELOG.txt | 1 + imgui_internal.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3868a2ec..71d30d40 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,7 @@ Other changes: clipping region. Regression added in 1.89. (#5720, #5919) - Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building with IMGUI_DISABLE_DEBUG_TOOLS is used. (#5901) [@Teselka] +- Misc: fixed compile-time detection of SSE features on MSVC 32-bits builds. (#5943) [@TheMostDiligent] - Backends: Allegro5: restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. (#5937) [@Espyo] diff --git a/imgui_internal.h b/imgui_internal.h index be018421..dbd76377 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -56,7 +56,7 @@ Index of this file: #include // INT_MIN, INT_MAX // Enable SSE intrinsics if available -#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE) +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) #define IMGUI_ENABLE_SSE #include #endif From 9825f7fa87308011c49422065c5e0816bde9fbd2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Dec 2022 18:40:36 +0100 Subject: [PATCH 13/15] Fixed cases where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with zero triangles. (#4857, #5937) Amend b0a6cd6 --- docs/CHANGELOG.txt | 3 +++ imgui_draw.cpp | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 71d30d40..0ed0a53b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,9 @@ Breaking changes: Other changes: +- Fixed cases where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with + zero triangles, which would makes the render loop of some backends assert (e.g. Metal with + debugging, Allegro). (#4857, #5937) - Inputs, Scrolling: better selection of scrolling window when hovering nested windows and when backend/OS is emitting dual-axis wheeling inputs (typically touch pads on macOS). We now select a primary axis based on recent events, and select a target window based on it. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 03b0e70e..349891dc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -449,8 +449,7 @@ void ImDrawList::_PopUnusedDrawCmd() { if (CmdBuffer.Size == 0) return; - ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) + for (ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL; curr_cmd--) CmdBuffer.pop_back(); } From 0e2a167bdb8f494179c6c5ab8df5768fb3440017 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Dec 2022 20:08:43 +0100 Subject: [PATCH 14/15] Fonts: added a 'void* UserData' field in ImFontAtlas, as a convenience for use by applications using multiple font atlases. + fixed mislocated Changelog entries added recently. --- docs/CHANGELOG.txt | 6 ++++-- imgui.h | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0ed0a53b..ac6a1726 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,10 @@ Other changes: We expect this behavior to be further improved/tweaked. (#3795, #4559) [@ocornut, @folays] - Text: fixed layouting of wrapped-text block when the last source line is above the clipping region. Regression added in 1.89. (#5720, #5919) +- Fonts: added a 'void* UserData' field in ImFontAtlas, as a convenience for use by + applications using multiple font atlases. +- Demo: simplified "Inputs" section, moved contents to Metrics->Inputs. +- Debug Tools: Metrics: added "Inputs" section, moved from Demo for consistency. - Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building with IMGUI_DISABLE_DEBUG_TOOLS is used. (#5901) [@Teselka] - Misc: fixed compile-time detection of SSE features on MSVC 32-bits builds. (#5943) [@TheMostDiligent] @@ -79,8 +83,6 @@ Other changes: - Drag and Drop: fixed GetDragDropPayload() returning a non-NULL value if a drag source is active but a payload hasn't been submitted yet. This is convenient to detect new payload from within a drag source handler. (#5910, #143) -- Demo: simplified "Inputs" section, moved contents to Metrics->Inputs. -- Debug Tools: Metrics: added "Inputs" section, moved from Demo for consistency. - Backends: GLFW: cancel out errors emitted by glfwGetKeyName() when a name is missing. (#5908) - Backends: WebGPU: fixed validation error with default depth buffer settings. (#5869, #5914) [@kdchambers] diff --git a/imgui.h b/imgui.h index de13e113..8d8fdc5c 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.2 WIP" -#define IMGUI_VERSION_NUM 18913 +#define IMGUI_VERSION_NUM 18914 #define IMGUI_HAS_TABLE /* @@ -1911,7 +1911,7 @@ struct ImGuiIO float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. float HoverDelayNormal; // = 0.30 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayNormal) returns true. float HoverDelayShort; // = 0.10 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayShort) returns true. - void* UserData; // = NULL // Store your own data for retrieval by callbacks. + void* UserData; // = NULL // Store your own data. ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. float FontGlobalScale; // = 1.0f // Global scale all fonts @@ -2808,6 +2808,7 @@ struct ImFontAtlas int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // 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). bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. From 844e0ae6884e6481b77fcce3339ac0fbaf659cdf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 1 Dec 2022 20:18:32 +0100 Subject: [PATCH 15/15] Fixes/amend 9825f7f + amend Changelog (#4857, #5937) --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ac6a1726..4817c9ba 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,7 @@ Other changes: - Fixed cases where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with zero triangles, which would makes the render loop of some backends assert (e.g. Metal with debugging, Allegro). (#4857, #5937) +- Tables, Columns: Fixed cases where empty columns may lead to empty ImDrawCmd. (#4857, #5937) - Inputs, Scrolling: better selection of scrolling window when hovering nested windows and when backend/OS is emitting dual-axis wheeling inputs (typically touch pads on macOS). We now select a primary axis based on recent events, and select a target window based on it. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 349891dc..7cd9c7c1 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -447,10 +447,13 @@ void ImDrawList::AddDrawCmd() // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL void ImDrawList::_PopUnusedDrawCmd() { - if (CmdBuffer.Size == 0) - return; - for (ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL; curr_cmd--) + while (CmdBuffer.Size > 0) + { + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) + return;// break; CmdBuffer.pop_back(); + } } void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)