|
|
@@ -128,7 +128,6 @@ CODE
|
|
|
- CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
|
|
|
- CTRL+Z,CTRL+Y to undo/redo.
|
|
|
- ESCAPE to revert text to its original value.
|
|
|
- - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
|
|
|
- Controls are automatically adjusted for OSX to match standard OSX text editing operations.
|
|
|
- General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
|
|
|
- General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets
|
|
|
@@ -255,9 +254,9 @@ CODE
|
|
|
io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
|
|
|
io.DisplaySize.x = 1920.0f; // set the current display width
|
|
|
io.DisplaySize.y = 1280.0f; // set the current display height here
|
|
|
- io.MousePos = my_mouse_pos; // set the mouse position
|
|
|
- io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states
|
|
|
- io.MouseDown[1] = my_mouse_buttons[1];
|
|
|
+ io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
|
|
|
+ io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
|
|
|
+ io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
|
|
|
|
|
|
// Call NewFrame(), after this point you can use ImGui::* functions anytime
|
|
|
// (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
|
|
|
@@ -347,27 +346,26 @@ CODE
|
|
|
- You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
|
|
|
- The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
|
|
|
- Keyboard:
|
|
|
- - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
|
|
|
- NewFrame() will automatically fill io.NavInputs[] based on your io.AddKeyEvent() calls.
|
|
|
- - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
|
|
|
- will be set. For more advanced uses, you may want to read from:
|
|
|
+ - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
|
|
|
+ - Internally: NewFrame() will automatically fill io.NavInputs[] based on backend's io.AddKeyEvent() calls.
|
|
|
+ - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard),
|
|
|
+ the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from:
|
|
|
- io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
|
|
|
- io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
|
|
|
- or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
|
|
|
Please reach out if you think the game vs navigation input sharing could be improved.
|
|
|
- Gamepad:
|
|
|
- - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
|
|
|
- - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
|
|
|
- Note that io.NavInputs[] is cleared by EndFrame().
|
|
|
- - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
|
|
|
- 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
|
|
|
- - We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
|
|
|
- Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
|
|
|
+ - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
|
|
|
+ - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
|
|
|
+ For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.
|
|
|
+ Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
|
|
|
+ - Internally: NewFrame() will automatically fill io.NavInputs[] based on backend's io.AddKeyEvent() + io.AddKeyAnalogEvent() calls.
|
|
|
+ - BEFORE 1.87, BACKENDS USED TO WRITE DIRECTLY TO io.NavInputs[]. This is going to be obsoleted in the future. Please call io functions instead!
|
|
|
- You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets
|
|
|
- - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo
|
|
|
- to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
|
|
|
+ - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,
|
|
|
+ with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
|
|
|
- Mouse:
|
|
|
- - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
|
|
|
+ - PS4/PS5 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
|
|
|
- Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard.
|
|
|
- On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
|
|
|
Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
|
|
|
@@ -386,12 +384,21 @@ CODE
|
|
|
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
|
|
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
|
|
|
|
|
+ - 2022/01/20 (1.87) - inputs: reworded gamepad IO.
|
|
|
+ - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
|
|
|
+ - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
|
|
|
+ - 2022/01/17 (1.87) - inputs: reworked mouse IO.
|
|
|
+ - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent()
|
|
|
+ - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
|
|
|
+ - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
|
|
|
+ - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]
|
|
|
- 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
|
|
|
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
|
|
|
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
|
|
|
- Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent()
|
|
|
+ - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiKey_ModXXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiKey_ModXXX values.*
|
|
|
- one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
|
|
|
- - inputs: added io.AddKeyModsEvent() instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
|
|
|
+ - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
|
|
|
- 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.
|
|
|
- 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
|
|
|
- 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
|
|
|
@@ -1138,6 +1145,7 @@ ImGuiIO::ImGuiIO()
|
|
|
#else
|
|
|
ConfigMacOSXBehaviors = false;
|
|
|
#endif
|
|
|
+ ConfigInputTrickleEventQueue = true;
|
|
|
ConfigInputTextCursorBlink = true;
|
|
|
ConfigWindowsResizeFromEdges = true;
|
|
|
ConfigWindowsMoveFromTitleBarOnly = false;
|
|
|
@@ -1159,15 +1167,25 @@ ImGuiIO::ImGuiIO()
|
|
|
for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
|
|
|
for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
|
|
|
BackendUsingLegacyKeyArrays = (ImS8)-1;
|
|
|
+ BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong
|
|
|
}
|
|
|
|
|
|
// Pass in translated ASCII characters for text input.
|
|
|
// - with glfw you can get those from the callback set in glfwSetCharCallback()
|
|
|
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
|
|
|
+// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
|
|
|
void ImGuiIO::AddInputCharacter(unsigned int c)
|
|
|
{
|
|
|
- if (c != 0)
|
|
|
- InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
+ if (c == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_Char;
|
|
|
+ e.Source = ImGuiInputSource_Keyboard;
|
|
|
+ e.Text.Char = c;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
}
|
|
|
|
|
|
// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
|
|
|
@@ -1180,7 +1198,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
|
|
if ((c & 0xFC00) == 0xD800) // High surrogate, must save
|
|
|
{
|
|
|
if (InputQueueSurrogate != 0)
|
|
|
- InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
|
|
+ AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
|
|
|
InputQueueSurrogate = c;
|
|
|
return;
|
|
|
}
|
|
|
@@ -1190,7 +1208,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
|
|
{
|
|
|
if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
|
|
|
{
|
|
|
- InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
|
|
+ AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -1203,7 +1221,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
|
|
|
|
|
InputQueueSurrogate = 0;
|
|
|
}
|
|
|
- InputQueueCharacters.push_back(cp);
|
|
|
+ AddInputCharacter((unsigned)cp);
|
|
|
}
|
|
|
|
|
|
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
|
|
@@ -1213,7 +1231,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
|
|
unsigned int c = 0;
|
|
|
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
|
|
|
if (c != 0)
|
|
|
- InputQueueCharacters.push_back((ImWchar)c);
|
|
|
+ AddInputCharacter(c);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1240,14 +1258,16 @@ void ImGuiIO::ClearInputKeys()
|
|
|
}
|
|
|
|
|
|
// 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.
|
|
|
-// FIXME: In the current version this is setting key data immediately. This will evolve into a trickling queue.
|
|
|
-void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
|
|
|
+// - 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
|
|
|
+void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
|
|
|
{
|
|
|
//if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
|
|
|
if (key == ImGuiKey_None)
|
|
|
return;
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
IM_ASSERT(ImGui::IsNamedKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
|
|
|
|
|
|
// Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
|
|
|
@@ -1256,15 +1276,39 @@ void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
|
|
|
if (BackendUsingLegacyKeyArrays == -1)
|
|
|
for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
|
|
|
IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
|
|
|
-#endif
|
|
|
BackendUsingLegacyKeyArrays = 0;
|
|
|
+#endif
|
|
|
+ if (ImGui::IsGamepadKey(key))
|
|
|
+ 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)
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // Write key
|
|
|
- const int keydata_index = (key - ImGuiKey_KeysData_OFFSET);
|
|
|
- KeysData[keydata_index].Down = down;
|
|
|
+ // Add event
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_Key;
|
|
|
+ e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard;
|
|
|
+ e.Key.Key = key;
|
|
|
+ e.Key.Down = down;
|
|
|
+ e.Key.AnalogValue = analog_value;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
}
|
|
|
|
|
|
-// [Optional] Call add AddKeyEvent().
|
|
|
+void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
|
|
|
+{
|
|
|
+ AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
|
|
|
+}
|
|
|
+
|
|
|
+// [Optional] Call after AddKeyEvent().
|
|
|
// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
|
|
|
// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
|
|
|
void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)
|
|
|
@@ -1287,20 +1331,59 @@ void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-void ImGuiIO::AddKeyModsEvent(ImGuiKeyModFlags modifiers)
|
|
|
+// Queue a mouse move event
|
|
|
+void ImGuiIO::AddMousePosEvent(float x, float y)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
+
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_MousePos;
|
|
|
+ e.Source = ImGuiInputSource_Mouse;
|
|
|
+ e.MousePos.PosX = x;
|
|
|
+ e.MousePos.PosY = y;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
+}
|
|
|
+
|
|
|
+void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
+ IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
|
|
|
+
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_MouseButton;
|
|
|
+ e.Source = ImGuiInputSource_Mouse;
|
|
|
+ e.MouseButton.Button = mouse_button;
|
|
|
+ e.MouseButton.Down = down;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
+}
|
|
|
+
|
|
|
+// Queue a mouse wheel event (most mouse/API will only have a Y component)
|
|
|
+void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
|
|
|
{
|
|
|
- KeyMods = modifiers;
|
|
|
- KeyCtrl = (modifiers & ImGuiKeyModFlags_Ctrl) != 0;
|
|
|
- KeyShift = (modifiers & ImGuiKeyModFlags_Shift) != 0;
|
|
|
- KeyAlt = (modifiers & ImGuiKeyModFlags_Alt) != 0;
|
|
|
- KeySuper = (modifiers & ImGuiKeyModFlags_Super) != 0;
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
+ if (wheel_x == 0.0f && wheel_y == 0.0f)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_MouseWheel;
|
|
|
+ e.Source = ImGuiInputSource_Mouse;
|
|
|
+ e.MouseWheel.WheelX = wheel_x;
|
|
|
+ e.MouseWheel.WheelY = wheel_y;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
}
|
|
|
|
|
|
void ImGuiIO::AddFocusEvent(bool focused)
|
|
|
{
|
|
|
- // We intentionally overwrite this and process in NewFrame(), in order to give a chance
|
|
|
- // to multi-viewports backends to queue AddFocusEvent(false),AddFocusEvent(true) in same frame.
|
|
|
- AppFocusLost = !focused;
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
|
|
+
|
|
|
+ ImGuiInputEvent e;
|
|
|
+ e.Type = ImGuiInputEventType_Focus;
|
|
|
+ e.AppFocused.Focused = focused;
|
|
|
+ g.InputEventsQueue.push_back(e);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -3287,7 +3370,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
|
|
if (id)
|
|
|
{
|
|
|
g.ActiveIdIsAlive = id;
|
|
|
- g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
|
|
+ g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? (ImGuiInputSource)ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
|
|
}
|
|
|
|
|
|
// Clear declaration of inputs claimed by the widget
|
|
|
@@ -3865,9 +3948,24 @@ static void ImGui::UpdateKeyboardInputs()
|
|
|
io.KeysData[key].Down = io.KeysDown[n];
|
|
|
io.BackendUsingLegacyKeyArrays = 1;
|
|
|
}
|
|
|
+ if (io.BackendUsingLegacyKeyArrays == 1)
|
|
|
+ {
|
|
|
+ io.KeysData[ImGuiKey_ModCtrl].Down = io.KeyCtrl;
|
|
|
+ io.KeysData[ImGuiKey_ModShift].Down = io.KeyShift;
|
|
|
+ io.KeysData[ImGuiKey_ModAlt].Down = io.KeyAlt;
|
|
|
+ io.KeysData[ImGuiKey_ModSuper].Down = io.KeySuper;
|
|
|
+ }
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+ // Clear gamepad data if disabled
|
|
|
+ if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)
|
|
|
+ for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
|
|
|
+ {
|
|
|
+ io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false;
|
|
|
+ io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
// Update keys
|
|
|
for (int i = 0; i < IM_ARRAYSIZE(io.KeysData); i++)
|
|
|
{
|
|
|
@@ -3884,7 +3982,7 @@ static void ImGui::UpdateMouseInputs()
|
|
|
|
|
|
// Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
|
|
|
if (IsMousePosValid(&io.MousePos))
|
|
|
- io.MousePos = g.MouseLastValidPos = ImFloor(io.MousePos);
|
|
|
+ io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);
|
|
|
|
|
|
// If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
|
|
|
if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev))
|
|
|
@@ -4237,17 +4335,18 @@ void ImGui::NewFrame()
|
|
|
//if (g.IO.AppFocusLost)
|
|
|
// ClosePopupsExceptModals();
|
|
|
|
|
|
- // Clear buttons state when focus is lost
|
|
|
- // (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle)
|
|
|
- if (g.IO.AppFocusLost)
|
|
|
- {
|
|
|
- g.IO.ClearInputKeys();
|
|
|
- g.IO.AppFocusLost = false;
|
|
|
- }
|
|
|
+ // Process input queue (trickle as many events as possible)
|
|
|
+ g.InputEventsTrail.resize(0);
|
|
|
+ UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue);
|
|
|
|
|
|
// Update keyboard input state
|
|
|
UpdateKeyboardInputs();
|
|
|
|
|
|
+ //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl));
|
|
|
+ //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift));
|
|
|
+ //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt));
|
|
|
+ //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper));
|
|
|
+
|
|
|
// Update gamepad/keyboard navigation
|
|
|
NavUpdate();
|
|
|
|
|
|
@@ -4468,11 +4567,10 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, Im
|
|
|
|
|
|
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
|
|
|
{
|
|
|
- // Remove trailing command if unused.
|
|
|
- // Technically we could return directly instead of popping, but this make things looks neat in Metrics/Debugger window as well.
|
|
|
- draw_list->_PopUnusedDrawCmd();
|
|
|
if (draw_list->CmdBuffer.Size == 0)
|
|
|
return;
|
|
|
+ if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)
|
|
|
+ return;
|
|
|
|
|
|
// Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
|
|
|
// May trigger for you if you are using PrimXXX functions incorrectly.
|
|
|
@@ -4558,8 +4656,10 @@ static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector<ImDrawList*
|
|
|
draw_data->FramebufferScale = io.DisplayFramebufferScale;
|
|
|
for (int n = 0; n < draw_lists->Size; n++)
|
|
|
{
|
|
|
- draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
|
|
|
- draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
|
|
|
+ ImDrawList* draw_list = draw_lists->Data[n];
|
|
|
+ draw_list->_PopUnusedDrawCmd();
|
|
|
+ draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
|
|
|
+ draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -4595,6 +4695,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
|
|
|
{
|
|
|
// We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows,
|
|
|
// and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
|
|
|
+ // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
|
|
|
ImDrawList* draw_list = window->RootWindow->DrawList;
|
|
|
if (draw_list->CmdBuffer.Size == 0)
|
|
|
draw_list->AddDrawCmd();
|
|
|
@@ -4605,7 +4706,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
|
|
|
draw_list->CmdBuffer.pop_back();
|
|
|
draw_list->CmdBuffer.push_front(cmd);
|
|
|
draw_list->PopClipRect();
|
|
|
- draw_list->_PopUnusedDrawCmd(); // Since are past the calls to AddDrawListToDrawData() we don't have a _PopUnusedDrawCmd() running on commands.
|
|
|
+ draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -4630,6 +4731,8 @@ static void ImGui::RenderDimmedBackgrounds()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();
|
|
|
+ if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
|
|
|
+ return;
|
|
|
const bool dim_bg_for_modal = (modal_window != NULL);
|
|
|
const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);
|
|
|
if (!dim_bg_for_modal && !dim_bg_for_window_list)
|
|
|
@@ -4659,7 +4762,6 @@ static void ImGui::RenderDimmedBackgrounds()
|
|
|
window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
|
|
|
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f);
|
|
|
window->DrawList->PopClipRect();
|
|
|
- window->DrawList->_PopUnusedDrawCmd(); // Since are past the calls to AddDrawListToDrawData() we don't have a _PopUnusedDrawCmd() running on commands.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -5826,7 +5928,9 @@ static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
|
|
|
for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
|
|
|
{
|
|
|
ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
|
|
|
- if (popup_window == NULL || !popup_window->WasActive || !(popup_window->Flags & ImGuiWindowFlags_Modal)) // Check WasActive, because this code may run before popup renders on current frame.
|
|
|
+ if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
|
|
|
+ continue;
|
|
|
+ if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
|
|
|
continue;
|
|
|
if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
|
|
|
break;
|
|
|
@@ -5988,6 +6092,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
// Initialize
|
|
|
const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
|
|
|
+ const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
|
|
|
window->Active = true;
|
|
|
window->HasCloseButton = (p_open != NULL);
|
|
|
window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
|
|
|
@@ -6014,7 +6119,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
|
|
|
|
|
|
// Update contents size from last frame for auto-fitting (or use explicit size)
|
|
|
- const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
|
|
|
CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
|
|
|
if (window->HiddenFramesCanSkipItems > 0)
|
|
|
window->HiddenFramesCanSkipItems--;
|
|
|
@@ -7380,7 +7484,7 @@ bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-const ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key)
|
|
|
+ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
int index;
|
|
|
@@ -7412,22 +7516,28 @@ static const char* const GKeyNames[] =
|
|
|
{
|
|
|
"Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown",
|
|
|
"Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape",
|
|
|
+ "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu",
|
|
|
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
|
|
|
+ "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
|
+ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
|
"Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket",
|
|
|
"Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen",
|
|
|
"Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6",
|
|
|
"Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply",
|
|
|
- "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", "LeftShift", "LeftControl",
|
|
|
- "LeftAlt", "LeftSuper", "RightShift", "RightControl", "RightAlt", "RightSuper", "Menu",
|
|
|
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
|
|
|
- "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
|
|
- "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"
|
|
|
+ "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual",
|
|
|
+ "GamepadStart", "GamepadBack", "GamepadFaceUp", "GamepadFaceDown", "GamepadFaceLeft", "GamepadFaceRight",
|
|
|
+ "GamepadDpadUp", "GamepadDpadDown", "GamepadDpadLeft", "GamepadDpadRight",
|
|
|
+ "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3",
|
|
|
+ "GamepadLStickUp", "GamepadLStickDown", "GamepadLStickLeft", "GamepadLStickRight",
|
|
|
+ "GamepadRStickUp", "GamepadRStickDown", "GamepadRStickLeft", "GamepadRStickRight",
|
|
|
+ "ModCtrl", "ModShift", "ModAlt", "ModSuper"
|
|
|
};
|
|
|
IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames));
|
|
|
|
|
|
const char* ImGui::GetKeyName(ImGuiKey key)
|
|
|
{
|
|
|
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
|
|
|
- IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
|
|
|
+ IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
|
|
|
#else
|
|
|
if (IsLegacyKey(key))
|
|
|
{
|
|
|
@@ -7656,6 +7766,129 @@ static const char* GetInputSourceName(ImGuiInputSource source)
|
|
|
}
|
|
|
|
|
|
|
|
|
+// Process input queue
|
|
|
+// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)
|
|
|
+// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)
|
|
|
+void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiIO& io = g.IO;
|
|
|
+
|
|
|
+ bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputed = false;
|
|
|
+ int mouse_button_changed = 0x00;
|
|
|
+ ImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;
|
|
|
+
|
|
|
+ int event_n = 0;
|
|
|
+ for (; event_n < g.InputEventsQueue.Size; event_n++)
|
|
|
+ {
|
|
|
+ const ImGuiInputEvent* e = &g.InputEventsQueue[event_n];
|
|
|
+ if (e->Type == ImGuiInputEventType_MousePos)
|
|
|
+ {
|
|
|
+ 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()
|
|
|
+ if (io.MousePos.x != event_pos.x || io.MousePos.y != event_pos.y)
|
|
|
+ {
|
|
|
+ // 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_inputed))
|
|
|
+ break;
|
|
|
+ io.MousePos = event_pos;
|
|
|
+ mouse_moved = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (e->Type == ImGuiInputEventType_MouseButton)
|
|
|
+ {
|
|
|
+ const ImGuiMouseButton button = e->MouseButton.Button;
|
|
|
+ IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);
|
|
|
+ if (io.MouseDown[button] != e->MouseButton.Down)
|
|
|
+ {
|
|
|
+ // 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)
|
|
|
+ {
|
|
|
+ if (e->MouseWheel.WheelX != 0.0f || e->MouseWheel.WheelY != 0.0f)
|
|
|
+ {
|
|
|
+ // Trickling Rule: Stop processing queued events if we got multiple action on the event
|
|
|
+ if (trickle_fast_inputs && (mouse_wheeled || mouse_button_changed != 0))
|
|
|
+ break;
|
|
|
+ io.MouseWheelH += e->MouseWheel.WheelX;
|
|
|
+ io.MouseWheel += e->MouseWheel.WheelY;
|
|
|
+ mouse_wheeled = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (e->Type == ImGuiInputEventType_Key)
|
|
|
+ {
|
|
|
+ ImGuiKey key = e->Key.Key;
|
|
|
+ IM_ASSERT(key != ImGuiKey_None);
|
|
|
+ const int keydata_index = (key - ImGuiKey_KeysData_OFFSET);
|
|
|
+ ImGuiKeyData* keydata = &io.KeysData[keydata_index];
|
|
|
+ if (keydata->Down != e->Key.Down || keydata->AnalogValue != e->Key.AnalogValue)
|
|
|
+ {
|
|
|
+ // Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
|
|
+ if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0))
|
|
|
+ break;
|
|
|
+ keydata->Down = e->Key.Down;
|
|
|
+ keydata->AnalogValue = e->Key.AnalogValue;
|
|
|
+ key_changed = true;
|
|
|
+ key_changed_mask.SetBit(keydata_index);
|
|
|
+
|
|
|
+ if (key == ImGuiKey_ModCtrl || key == ImGuiKey_ModShift || key == ImGuiKey_ModAlt || key == ImGuiKey_ModSuper)
|
|
|
+ {
|
|
|
+ if (key == ImGuiKey_ModCtrl) { io.KeyCtrl = keydata->Down; }
|
|
|
+ if (key == ImGuiKey_ModShift) { io.KeyShift = keydata->Down; }
|
|
|
+ if (key == ImGuiKey_ModAlt) { io.KeyAlt = keydata->Down; }
|
|
|
+ if (key == ImGuiKey_ModSuper) { io.KeySuper = keydata->Down; }
|
|
|
+ io.KeyMods = GetMergedKeyModFlags();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (e->Type == ImGuiInputEventType_Char)
|
|
|
+ {
|
|
|
+ // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
|
|
|
+ if (trickle_fast_inputs && (key_changed || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
|
|
|
+ break;
|
|
|
+ unsigned int c = e->Text.Char;
|
|
|
+ io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
|
|
|
+ text_inputed = true;
|
|
|
+ }
|
|
|
+ else if (e->Type == ImGuiInputEventType_Focus)
|
|
|
+ {
|
|
|
+ // 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.
|
|
|
+ io.AppFocusLost = !e->AppFocused.Focused;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ IM_ASSERT(0 && "Unknown event!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Record trail (for domain-specific applications wanting to access a precise trail)
|
|
|
+ //if (event_n != 0) IMGUI_DEBUG_LOG("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
|
|
|
+ for (int n = 0; n < event_n; n++)
|
|
|
+ g.InputEventsTrail.push_back(g.InputEventsQueue[n]);
|
|
|
+
|
|
|
+ // Remaining events will be processed on the next frame
|
|
|
+ if (event_n == g.InputEventsQueue.Size)
|
|
|
+ g.InputEventsQueue.resize(0);
|
|
|
+ else
|
|
|
+ g.InputEventsQueue.erase(g.InputEventsQueue.Data, g.InputEventsQueue.Data + event_n);
|
|
|
+
|
|
|
+ // Clear buttons state when focus is lost
|
|
|
+ // (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle)
|
|
|
+ if (g.IO.AppFocusLost)
|
|
|
+ {
|
|
|
+ g.IO.ClearInputKeys();
|
|
|
+ g.IO.AppFocusLost = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
//-----------------------------------------------------------------------------
|
|
|
// [SECTION] ERROR CHECKING
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -8962,7 +9195,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
|
|
return false;
|
|
|
}
|
|
|
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
|
|
|
- return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
|
|
|
+ ImGuiID id = g.CurrentWindow->GetID(str_id);
|
|
|
+ return BeginPopupEx(id, flags);
|
|
|
}
|
|
|
|
|
|
// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
|
|
|
@@ -9041,7 +9275,7 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags
|
|
|
// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
|
|
|
// This is essentially the same as:
|
|
|
// id = str_id ? GetID(str_id) : GetItemID();
|
|
|
-// OpenPopupOnItemClick(str_id);
|
|
|
+// OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight);
|
|
|
// return BeginPopup(id);
|
|
|
// Which is essentially the same as:
|
|
|
// id = str_id ? GetID(str_id) : GetItemID();
|
|
|
@@ -9202,8 +9436,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
|
|
}
|
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
|
{
|
|
|
- ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
|
|
|
- return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
|
|
|
+ return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here
|
|
|
}
|
|
|
if (window->Flags & ImGuiWindowFlags_Tooltip)
|
|
|
{
|
|
|
@@ -9712,9 +9945,10 @@ static ImVec2 ImGui::NavCalcPreferredRefPos()
|
|
|
if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window)
|
|
|
{
|
|
|
// Mouse (we need a fallback in case the mouse becomes invalid after being used)
|
|
|
- if (IsMousePosValid(&g.IO.MousePos))
|
|
|
- return g.IO.MousePos;
|
|
|
- return g.MouseLastValidPos;
|
|
|
+ // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard.
|
|
|
+ // In theory we could move that +1.0f offset in OpenPopupEx()
|
|
|
+ ImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLastValidPos;
|
|
|
+ return ImVec2(p.x + 1.0f, p.y);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -9792,18 +10026,35 @@ static void ImGui::NavUpdate()
|
|
|
io.WantSetMousePos = false;
|
|
|
//if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
|
|
|
|
|
|
+ // Update Gamepad->Nav inputs mapping
|
|
|
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
|
|
|
- // (do it before we map Keyboard input!)
|
|
|
- const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
|
|
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
|
|
- if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
|
|
|
- {
|
|
|
- if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
|
|
|
- || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f)
|
|
|
- g.NavInputSource = ImGuiInputSource_Gamepad;
|
|
|
+ if (nav_gamepad_active && g.IO.BackendUsingLegacyNavInputArray == false)
|
|
|
+ {
|
|
|
+ for (int n = 0; n < ImGuiNavInput_COUNT; n++)
|
|
|
+ IM_ASSERT(io.NavInputs[n] == 0.0f && "Backend needs to either only use io.AddKeyEvent()/io.AddKeyAnalogEvent(), either only fill legacy io.NavInputs[]. Not both!");
|
|
|
+ #define NAV_MAP_KEY(_KEY, _NAV_INPUT, _ACTIVATE_NAV) do { io.NavInputs[_NAV_INPUT] = io.KeysData[_KEY - ImGuiKey_KeysData_OFFSET].AnalogValue; if (_ACTIVATE_NAV && io.NavInputs[_NAV_INPUT] > 0.0f) { g.NavInputSource = ImGuiInputSource_Gamepad; } } while (0)
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown, true);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_TweakSlow, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_TweakFast, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp, false);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown, false);
|
|
|
+ #undef NAV_MAP_KEY
|
|
|
}
|
|
|
|
|
|
// Update Keyboard->Nav inputs mapping
|
|
|
+ const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
|
|
if (nav_keyboard_active)
|
|
|
{
|
|
|
#define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(_KEY)) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0)
|
|
|
@@ -10050,15 +10301,21 @@ void ImGui::NavUpdateCreateMoveRequest()
|
|
|
// When using gamepad, we project the reference nav bounding box into window visible area.
|
|
|
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
|
|
|
// (can't focus a visible object like we can with the mouse).
|
|
|
- if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)
|
|
|
- {
|
|
|
- ImRect window_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
|
|
|
- if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
|
|
- {
|
|
|
- IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
|
|
|
- float pad = window->CalcFontSize() * 0.5f;
|
|
|
- window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
|
|
|
- window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
|
|
|
+ if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
|
|
|
+ {
|
|
|
+ bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
|
|
|
+ bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
|
|
|
+ ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
|
|
|
+ if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
|
|
+ {
|
|
|
+ IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
|
|
|
+ float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f);
|
|
|
+ float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
|
|
|
+ inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;
|
|
|
+ inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX;
|
|
|
+ inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;
|
|
|
+ inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX;
|
|
|
+ window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
|
|
|
g.NavId = g.NavFocusScopeId = 0;
|
|
|
}
|
|
|
}
|
|
|
@@ -12134,8 +12391,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|
|
Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
|
|
|
|
|
|
int active_id_using_key_input_count = 0;
|
|
|
- for (int n = 0; n < g.ActiveIdUsingKeyInputMask.Size; n++)
|
|
|
- active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask.TestBit(n) ? 1 : 0;
|
|
|
+ for (int n = 0; n < ImGuiKey_NamedKey_COUNT; n++)
|
|
|
+ active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask[n] ? 1 : 0;
|
|
|
Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInputMask: %d key(s)", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdUsingNavInputMask, active_id_using_key_input_count);
|
|
|
Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
|
|
|
Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
|