From 727ddeb450b76861150c34f9011487c780b65e39 Mon Sep 17 00:00:00 2001 From: fangshun Date: Fri, 30 Sep 2022 05:52:11 +0800 Subject: [PATCH] Squashed commit of the following: commit cc5058e5d7dcbf94f28277d6bee5face7f8b0a63 Author: ocornut Date: Thu Sep 29 21:59:32 2022 +0200 IO: Filter duplicate input events during the AddXXX() calls. (#5599, #4921) commit fac8295d6e7f5356d77ac1c92a1c9205cef11733 Author: ocornut Date: Thu Sep 29 21:31:36 2022 +0200 IO: remove ImGuiInputEvent::IgnoredAsSame (revert part of 839c3100), will filter earlier in next commit. (#5599) Making it a separate commit as this leads to much indentation change. commit 9e7f460c0934370a32065eed97af453afeada590 Author: ocornut Date: Thu Sep 29 20:42:45 2022 +0200 Fixed GetKeyName() for ImGuiMod_XXX values, made invalid MousePos display in log nicer. (#4921, #456) Amend fd408c9 commit 0749453355a8fd47e79b2cc2e6bbbfa06eda5860 Author: ocornut Date: Thu Sep 29 19:51:54 2022 +0200 Menus, Nav: Fixed not being able to close a menu with Left arrow when parent is not a popup. (#5730) commit 9f6aae3bf267c4fb7ac2941f000393dc8341eaa8 Author: ocornut Date: Thu Sep 29 19:48:27 2022 +0200 Nav: Fixed race condition pressing Esc during popup opening frame causing crash. commit bd2355a047570c2cc1ff0a31c40a526484f3709e Author: ocornut Date: Thu Sep 29 19:25:26 2022 +0200 Menus, Nav: Fixed using left/right navigation when appending to an existing menu (multiple BeginMenu() call with same names). (#1207) commit 3532ed1621171647ce4a969be40fd69c58e47b75 Author: ocornut Date: Thu Sep 29 18:07:35 2022 +0200 Menus, Nav: Fixed keyboard/gamepad navigation occasionally erroneously landing on menu-item in parent when the parent is not a popup. (#5730) Replace BeginMenu/MenuItem swapping g.NavWindow with a more adequate ImGuiItemFlags_NoWindowHoverableCheck. Expecting more subtle issues to stem from this. Note that NoWindowHoverableCheck is not supported by IsItemHovered() but then IsItemHovered() on BeginMenu() never worked: fix should be easy in BeginMenu() + add test is IsItemHovered(), will do later commit d5d705069dafc8f26b9d8b0e4a16a54321f56376 Author: ocornut Date: Thu Sep 29 17:26:52 2022 +0200 Various comments As it turns out, functions like IsItemHovered() won't work on an open BeginMenu() because LastItemData is overriden by BeginPopup(). Probably an easy fix. commit e74a50f525e880f3a121ecd5b9ff0b33025d5778 Author: Andrew D. Zonenberg Date: Wed Sep 28 08:19:34 2022 -0700 Added GetGlyphRangesGreek() helper for Greek & Coptic glyph range. (#5676, #5727) commit d17627b9c6f3162cebe8285e3048418bd730d8a8 Author: ocornut Date: Wed Sep 28 17:38:41 2022 +0200 InputText: leave state->Flags uncleared for the purpose of backends emitting an on-screen keyboard for passwords. (#5724) commit 0a7054c7e448457cad37a6904dff1d044aeb3b2b Author: ocornut Date: Wed Sep 28 17:00:45 2022 +0200 Backends: Win32: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode). (#5725, #1807, #471, #2815, #1060) commit a229a7f39fece2ec40308e47684792a9ceb519cd Author: ocornut Date: Wed Sep 28 16:57:09 2022 +0200 Examples: Win32: Always use RegisterClassW() to ensure windows are Unicode. (#5725) commit e0330c1696b8fcb4b5ffb10db27410d02ea5c6d4 Author: ocornut Date: Wed Sep 28 14:54:38 2022 +0200 Fonts, Text: Fixed wrapped-text not doing a fast-forward on lines above the clipping region. (#5720) which would result in an abnormal number of vertices created. commit 4d4889bf1b201fbe81e3ff05bd3a63a2c913832f Author: ocornut Date: Wed Sep 28 12:42:06 2022 +0200 Refactor CalcWordWrapPositionA() to take on the responsability of minimum character display. Add CalcWordWrapNextLineStartA(), simplify caller code. Should be no-op but incrementing IMGUI_VERSION_NUM just in case. Preparing for #5720 commit 5c4426c5b8103782d8df74464a4cf43804b8d793 Author: ocornut Date: Wed Sep 28 12:22:34 2022 +0200 Demo: Fixed Log & Console from losing scrolling position with Auto-Scroll when child is clipped. (#5721) commit 12c024689023bd5dcd5905bf96ad6e1694b8c043 Author: ocornut Date: Wed Sep 28 12:07:43 2022 +0200 Removed support for 1.42-era IMGUI_DISABLE_INCLUDE_IMCONFIG_H / IMGUI_INCLUDE_IMCONFIG_H. (#255) commit 73efcec564adc18d5618471ecb1a6e352787c510 Author: ocornut Date: Tue Sep 27 22:21:47 2022 +0200 Examples: disable GL related warnings on Mac + amend to ignore list. commit a725db17b7632f93f655327c49b55878be309315 Author: ocornut Date: Tue Sep 27 18:47:20 2022 +0200 Comments for flags discoverability + add to debug log (#3795, #4559) commit 325299f94220ac1f556815a42aea3d101beed4a7 Author: ocornut Date: Wed Sep 14 15:46:27 2022 +0200 Backends: OpenGL: Add ability to #define IMGUI_IMPL_OPENGL_DEBUG. (#4468, #4825, #4832, #5127, #5655, #5709) commit 56c3eaed20fc664c556790f3dba2b8f016c9509c Author: ocornut Date: Tue Sep 27 14:24:21 2022 +0200 ImDrawList: asserting on incorrect value for CurveTessellationTol (#5713) commit 04316bd223f98e4c40bd82dc5f2a35c4891e4e5f Author: ocornut Date: Mon Sep 26 16:32:09 2022 +0200 ColorEdit3: fixed id collision leading to an assertion. (#5707) commit c261dac02fbf105f1b3d1da2e4660fe5bdba5ff4 Author: ocornut Date: Mon Sep 26 14:50:46 2022 +0200 Demo: moved ShowUserGuide() lower in the file, to make main demo entry point more visible + fix using IMGUI_DEBUG_LOG() macros in if/else. commit 51bbc70652cb380ca89981a7f46d9794b108ffdb Author: ocornut Date: Mon Sep 26 14:44:26 2022 +0200 Backends: SDL: Disable SDL 2.0.22 new "auto capture" which prevents drag and drop across windows, and don't capture mouse when drag and dropping. (#5710) commit 7a9045dd777e5b92bc04923831982937821d563b Author: ocornut Date: Mon Sep 26 11:55:07 2022 +0200 Backends: WGPU: removed Emscripten version check (currently failing on CI, ensure why, and tbh its redundant/unnecessary with changes of wgpu api nowadays) commit 83a0030c0a70042a84c3896be810607e0b1673ec Author: ocornut Date: Mon Sep 26 10:33:44 2022 +0200 Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (#456) commit fd408c97904fbf9f3b4c786318e8389de11bc681 Author: ocornut Date: Thu Sep 22 18:58:33 2022 +0200 Renamed and merged keyboard modifiers key enums and flags into a same set:. ImGuiKey_ModXXX -> ImGuiMod_XXX and ImGuiModFlags_XXX -> ImGuiMod_XXX. (#4921, #456) Changed signature of GetKeyChordName() to use ImGuiKeyChord. Additionally SetActiveIdUsingAllKeyboardKeys() doesn't set ImGuiKey_ModXXX but we never need/use those and the system will be changed in upcoming commits. # Conflicts: # imgui.cpp # imgui.h # imgui_demo.cpp --- docs/CHANGELOG.txt | 6 +++ imgui.cpp | 122 ++++++++++++++++++++++++++++----------------- imgui.h | 2 +- imgui_demo.cpp | 62 ++++++----------------- imgui_internal.h | 19 ++++--- imgui_widgets.cpp | 37 +++++++------- 6 files changed, 128 insertions(+), 120 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9bb793476b55..f0a2fb5a3157 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -130,11 +130,17 @@ Other Changes: - IO: Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (#456) - IO: Added ImGuiKey_MouseXXX aliases for mouse buttons/wheel so all operations done on ImGuiKey can apply to mouse data as well. (#4921) +- IO: Filter duplicate input events during the AddXXX() calls. (#5599, #4921) - Menus: Fixed incorrect sub-menu parent association when opening a menu by closing another. Among other things, it would accidentally break part of the closing heuristic logic when moving towards a sub-menu. (#2517, #5614). [@rokups] - Menus: Fixed gaps in closing logic which would make child-menu erroneously close when crossing the gap between a menu item inside a window and a child-menu in a secondary viewport. (#5614) +- Menus, Nav: Fixed keyboard/gamepad navigation occasionally erroneously landing on menu-item + in parent window when the parent is not a popup. (#5730) +- Menus, Nav: Fixed not being able to close a menu with Left arrow when parent is not a popup. (#5730) +- Menus, Nav: Fixed using left/right navigation when appending to an existing menu (multiple + BeginMenu() call with same names). (#1207) - Nav: Fixed moving/resizing window with gamepad or keyboard when running at very high framerate. - Nav: Pressing Space/GamepadFaceDown on a repeating button uses the same repeating rate as a mouse hold. - Nav: Fixed an issue opening a menu with Right key from a non-menu window. diff --git a/imgui.cpp b/imgui.cpp index 04b43a31578d..6dffb59d725d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1282,11 +1282,13 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) } } +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputCharacters() { InputQueueCharacters.resize(0); } +// FIXME: Perhaps we could clear queued events as well? void ImGuiIO::ClearInputKeys() { #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO @@ -1302,10 +1304,27 @@ void ImGuiIO::ClearInputKeys() KeyMods = ImGuiMod_None; } +static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1) +{ + ImGuiContext& g = *GImGui; + for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--) + { + ImGuiInputEvent* e = &g.InputEventsQueue[n]; + if (e->Type != type) + continue; + if (type == ImGuiInputEventType_Key && e->Key.Key != arg) + continue; + if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg) + continue; + return e; + } + return NULL; +} // Queue a new key down/up event. // - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) // - bool down: Is the key down? use false to signify a key release. // - float analog_value: 0.0f..1.0f +// - float analog_value: 0.0f..1.0f void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) { //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } @@ -1328,16 +1347,12 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) BackendUsingLegacyNavInputArray = false; // Partial filter of duplicates (not strictly needed, but makes data neater in particular for key mods and gamepad values which are most commonly spmamed) - ImGuiKeyData* key_data = ImGui::GetKeyData(key); - if (key_data->Down == down && key_data->AnalogValue == analog_value) - { - bool found = false; - for (int n = g.InputEventsQueue.Size - 1; n >= 0 && !found; n--) - if (g.InputEventsQueue[n].Type == ImGuiInputEventType_Key && g.InputEventsQueue[n].Key.Key == key) - found = true; - if (!found) + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key); + const ImGuiKeyData* key_data = ImGui::GetKeyData(key); + const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; + const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue; + if (latest_key_down == down && latest_key_analog == analog_value) return; - } // Add event ImGuiInputEvent e; @@ -1395,11 +1410,20 @@ void ImGuiIO::AddMousePosEvent(float x, float y) if (!AppAcceptingEvents) return; + // Apply same flooring as UpdateMouseInputs() + ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y); + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos); + const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos; + if (latest_pos.x == pos.x && latest_pos.y == pos.y) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_MousePos; e.Source = ImGuiInputSource_Mouse; - e.MousePos.PosX = x; - e.MousePos.PosY = y; + e.MousePos.PosX = pos.x; + e.MousePos.PosY = pos.y; g.InputEventsQueue.push_back(e); } @@ -1411,6 +1435,12 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) if (!AppAcceptingEvents) return; + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button); + const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button]; + if (latest_button_down == down) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_MouseButton; e.Source = ImGuiInputSource_Mouse; @@ -1424,7 +1454,9 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) { ImGuiContext& g = *GImGui; IM_ASSERT(&g.IO == this && "Can only add events to current context."); - if ((wheel_x == 0.0f && wheel_y == 0.0f) || !AppAcceptingEvents) + + // Filter duplicate (unlike most events, wheel values are relative and easy to filter) + if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) return; ImGuiInputEvent e; @@ -1440,6 +1472,12 @@ void ImGuiIO::AddFocusEvent(bool focused) ImGuiContext& g = *GImGui; IM_ASSERT(&g.IO == this && "Can only add events to current context."); + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus); + const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost; + if (latest_focused == focused) + return; + ImGuiInputEvent e; e.Type = ImGuiInputEventType_Focus; e.AppFocused.Focused = focused; @@ -3589,6 +3627,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was // the test that has been running for a long while. + // the test that has been running for a long while. if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) return false; @@ -3648,7 +3687,10 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) return false; - if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + + // Done with rectangle culling so we can perform heavier checks now. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) { g.HoveredIdDisabled = true; return false; @@ -3660,7 +3702,6 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) SetHoveredID(id); // When disabled we'll return false but still set HoveredId - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (item_flags & ImGuiItemFlags_Disabled) { // Release active id if turning disabled @@ -4605,9 +4646,10 @@ void ImGui::NewFrame() { ImGuiWindow* window = g.Windows[i]; window->WasActive = window->Active; - window->BeginCount = 0; window->Active = false; window->WriteAccessed = false; + window->BeginCountPreviousFrame = window->BeginCount; + window->BeginCount = 0; // Garbage collect transient buffers of recently unused windows if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) @@ -7813,6 +7855,8 @@ const char* ImGui::GetKeyName(ImGuiKey key) #endif if (key == ImGuiKey_None) return "None"; + if (key & ImGuiMod_Mask_) + key = ConvertSingleModFlagToKey(key); if (!IsNamedKey(key)) return "Unknown"; @@ -8082,7 +8126,7 @@ static const char* GetInputSourceName(ImGuiInputSource source) static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) { ImGuiContext& g = *GImGui; - if (e->Type == ImGuiInputEventType_MousePos) { IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; } + 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_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } @@ -8115,38 +8159,25 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) ImGuiInputEvent* e = &g.InputEventsQueue[event_n]; if (e->Type == ImGuiInputEventType_MousePos) { + // Trickling Rule: Stop processing queued events if we already handled a mouse button change ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); - if (IsMousePosValid(&event_pos)) - event_pos = ImVec2(ImFloorSigned(event_pos.x), ImFloorSigned(event_pos.y)); // Apply same flooring as UpdateMouseInputs() - e->IgnoredAsSame = (io.MousePos.x == event_pos.x && io.MousePos.y == event_pos.y); - if (!e->IgnoredAsSame) - { - // Trickling Rule: Stop processing queued events if we already handled a mouse button change if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) break; io.MousePos = event_pos; mouse_moved = true; } - } else if (e->Type == ImGuiInputEventType_MouseButton) { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button const ImGuiMouseButton button = e->MouseButton.Button; IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); - e->IgnoredAsSame = (io.MouseDown[button] == e->MouseButton.Down); - if (!e->IgnoredAsSame) - { - // Trickling Rule: Stop processing queued events if we got multiple action on the same button if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled)) break; io.MouseDown[button] = e->MouseButton.Down; mouse_button_changed |= (1 << button); } - } else if (e->Type == ImGuiInputEventType_MouseWheel) { - e->IgnoredAsSame = (e->MouseWheel.WheelX == 0.0f && e->MouseWheel.WheelY == 0.0f); - if (!e->IgnoredAsSame) - { // Trickling Rule: Stop processing queued events if we got multiple action on the event if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0)) break; @@ -8154,13 +8185,15 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) io.MouseWheel += e->MouseWheel.WheelY; mouse_wheeled = true; } - } else if (e->Type == ImGuiInputEventType_Key) { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button ImGuiKey key = e->Key.Key; IM_ASSERT(key != ImGuiKey_None); ImGuiKeyData* key_data = GetKeyData(key); const int key_data_index = (int)(key_data - g.IO.KeysData); + ImGuiKeyData* key_data = GetKeyData(key); + const int key_data_index = (int)(key_data - g.IO.KeysData); e->IgnoredAsSame = (key_data->Down == e->Key.Down && key_data->AnalogValue == e->Key.AnalogValue); if (!e->IgnoredAsSame) { @@ -8172,23 +8205,22 @@ 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 || 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(); + 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; - if (io.KeyMap[key_data_index] != -1) - io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; + io.KeysDown[key_data_index] = key_data->Down; + if (io.KeyMap[key_data_index] != -1) + io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; #endif } - } else if (e->Type == ImGuiInputEventType_Text) { // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with @@ -8204,8 +8236,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) // We intentionally overwrite this and process lower, in order to give a chance // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame. const bool focus_lost = !e->AppFocused.Focused; - e->IgnoredAsSame = (io.AppFocusLost == focus_lost); - if (!e->IgnoredAsSame) io.AppFocusLost = focus_lost; } else @@ -8223,7 +8253,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) #ifndef IMGUI_DISABLE_DEBUG_TOOLS if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO)) for (int n = 0; n < g.InputEventsQueue.Size; n++) - DebugPrintInputEvent(n < event_n ? (g.InputEventsQueue[n].IgnoredAsSame ? "Processed (Same)" : "Processed") : "Remaining", &g.InputEventsQueue[n]); + DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]); #endif // Remaining events will be processed on the next frame @@ -10855,7 +10885,7 @@ static void ImGui::NavUpdateCancelRequest() SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect)); NavRestoreHighlightAfterMove(); } - else if (g.OpenPopupStack.Size > 0 && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) { // Close open popup/menu ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); diff --git a/imgui.h b/imgui.h index 7a3fab7ef0de..acdb73edc2c7 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 WIP" -#define IMGUI_VERSION_NUM 18825 +#define IMGUI_VERSION_NUM 18828 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6eb933d161a8..baf35d0ad50f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -230,55 +230,21 @@ void* GImGuiDemoMarkerCallbackUserData = NULL; #define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) // Helper to display basic user controls. -<<<<<<< .mine -void ImGui::ShowUserGuide() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui::BulletText("双击标题栏以折叠窗口。."); - ImGui::BulletText( - "单击并拖动下角以调整窗口大小\n" - "(双击以自动使窗口适应其内容)."); - ImGui::BulletText("按住 Ctrl 键并单击滑块或拖动框以文本形式输入值."); - ImGui::BulletText("TAB/SHIFT+TAB 在键盘可编辑的字段中循环切换."); - ImGui::BulletText("CTRL+Tab 以选择窗口."); - if (io.FontAllowUserScaling) - ImGui::BulletText("CTRL+Mouse 滚轮缩放窗口内容."); - ImGui::BulletText("输入文本时:\n"); - ImGui::Indent(); - ImGui::BulletText("CTRL+左/右跳转."); - ImGui::BulletText("CTRL+A 或双击以全选."); - ImGui::BulletText("CTRL+X/C/V 以使用剪贴板剪切/复制/粘贴."); - ImGui::BulletText("CTRL+Z,CTRL+Y 以撤消/重做."); - ImGui::BulletText("ESCAPE 以恢复."); - ImGui::Unindent(); - ImGui::BulletText("启用键盘导航:"); - ImGui::Indent(); - ImGui::BulletText("用于导航的箭头键."); - ImGui::BulletText("用于激活小部件的空间."); - ImGui::BulletText("返回到微件中的输入文本."); - ImGui::BulletText("Escape 以停用小部件,关闭弹出窗口,退出子窗口."); - ImGui::BulletText("Alt 用于跳转到窗口菜单图层."); - ImGui::Unindent(); -} -======= - - - - - - - - - - - - - - - - - +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] Demo Window / ShowDemoWindow() +//----------------------------------------------------------------------------- +// - ShowDemoWindow() +// - ShowDemoWindowWidgets() +// - ShowDemoWindowLayout() +// - ShowDemoWindowPopups() +// - ShowDemoWindowTables() +// - ShowDemoWindowColumns() +// - ShowDemoWindowInputs() +//----------------------------------------------------------------------------- +// Demonstrate most Dear ImGui features (this is big function!) +// You may execute this function to experiment with the UI and understand what it does. +// You may then search for keywords in the code when you are interested by a specific feature. diff --git a/imgui_internal.h b/imgui_internal.h index 6f591478f911..204040fb60b2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -149,8 +149,8 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for IsKeyPressedEx() -typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() -typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests @@ -758,7 +758,10 @@ struct ImDrawDataBuilder // [SECTION] Widgets support: flags, enums, data structures //----------------------------------------------------------------------------- -// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +// Flags used by upcoming items +// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags. +// - output: stored in g.LastItemData.InFlags +// Current window shared by all windows. // This is going to be exposed in imgui.h when stabilized enough. enum ImGuiItemFlags_ { @@ -772,12 +775,14 @@ enum ImGuiItemFlags_ ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. + ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() // Controlled by widget code - ImGuiItemFlags_Inputable = 1 << 8, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. + ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. }; -// Storage for LastItem data +// Status flags for an already submitted item +// - output: stored in g.LastItemData.StatusFlags enum ImGuiItemStatusFlags_ { ImGuiItemStatusFlags_None = 0, @@ -1240,7 +1245,6 @@ struct ImGuiInputEvent ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus }; - bool IgnoredAsSame; bool AddedByTestEngine; ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } @@ -2107,6 +2111,7 @@ struct IMGUI_API ImGuiWindow bool HasCloseButton; // Set when the window has a close button (p_open != NULL) signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginCountPreviousFrame; // Number of Begin() during the previous frame short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. @@ -2650,7 +2655,7 @@ namespace ImGui IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); - // Parameter stacks + // Parameter stacks (shared) IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e71c4b1c03e3..dc7d0aa811e0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7018,10 +7018,10 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) ImVec2 label_size = CalcTextSize(label, NULL, true); // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) + // This is only done for items for the menu set and not the full parent window. const bool menuset_is_open = IsRootOfOpenMenuSet(); - ImGuiWindow* backed_nav_window = g.NavWindow; if (menuset_is_open) - g.NavWindow = window; + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). @@ -7070,7 +7070,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover; if (menuset_is_open) - g.NavWindow = backed_nav_window; + PopItemFlag(); bool want_open = false; bool want_close = false; @@ -7156,9 +7156,10 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) if (menu_is_open) { - SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: this is super misleading! The value will serve as reference for FindBestWindowPosForPopup(), not actual pos. + // FIXME: This technically breaks functions relying on LastItemData, somehow nobody complained yet. Should backup/restore LastItemData. + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos. PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding - menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) PopStyleVar(); } else @@ -7176,18 +7177,18 @@ bool ImGui::BeginMenu(const char* label, bool enabled) void ImGui::EndMenu() { - // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). - // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. - // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. - // FIXME: This doesn't work if the parent BeginMenu() is not on a menu. + // Nav: When a left move request our menu failed, close ourselves. ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) - if (g.NavWindow && (g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow == window) - { - ClosePopupToLevel(g.BeginPopupStack.Size, true); - NavMoveRequestCancel(); - } + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls + ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. + if (window->BeginCount == window->BeginCountPreviousFrame) + if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) + if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size - 1, true); + NavMoveRequestCancel(); + } EndPopup(); } @@ -7203,10 +7204,10 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut ImVec2 pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); + // See BeginMenuEx() for comments about this. const bool menuset_is_open = IsRootOfOpenMenuSet(); - ImGuiWindow* backed_nav_window = g.NavWindow; if (menuset_is_open) - g.NavWindow = window; + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. @@ -7258,7 +7259,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut EndDisabled(); PopID(); if (menuset_is_open) - g.NavWindow = backed_nav_window; + PopItemFlag(); return pressed; }