From 51c940acd473e3ad86895267fac015e651c55011 Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Mon, 14 Feb 2022 23:33:52 +0100 Subject: [PATCH] Updated to ImGui 1.87 to cleanup UI code --- .../android/imgui/imgui_impl_android.cpp | 193 ++- .../android/imgui/imgui_impl_android.h | 5 +- core/backends/android/keybinds.h | 27 - core/backends/glfw/imgui/imgui_impl_glfw.cpp | 454 ++++-- core/backends/glfw/imgui/imgui_impl_glfw.h | 19 +- core/backends/glfw/keybinds.h | 27 - core/src/gui/main_window.cpp | 13 +- core/src/gui/menus/bandplan.cpp | 2 +- core/src/gui/menus/display.cpp | 5 +- core/src/gui/menus/module_manager.cpp | 4 +- core/src/gui/menus/source.cpp | 2 +- core/src/gui/menus/theme.cpp | 2 +- core/src/gui/menus/vfo_color.cpp | 4 +- core/src/gui/smgui.cpp | 4 +- core/src/gui/style.cpp | 2 +- core/src/gui/widgets/file_select.cpp | 2 +- core/src/gui/widgets/folder_select.cpp | 2 +- core/src/gui/widgets/frequency_select.cpp | 11 +- core/src/gui/widgets/menu.cpp | 2 +- core/src/gui/widgets/waterfall.cpp | 11 +- core/src/imgui/imgui.cpp | 1286 ++++++++++++----- core/src/imgui/imgui.h | 446 ++++-- core/src/imgui/imgui_demo.cpp | 95 +- core/src/imgui/imgui_draw.cpp | 28 +- core/src/imgui/imgui_impl_opengl3.cpp | 22 +- core/src/imgui/imgui_impl_opengl3_loader.h | 2 +- core/src/imgui/imgui_internal.h | 161 ++- core/src/imgui/imgui_tables.cpp | 21 +- core/src/imgui/imgui_widgets.cpp | 167 +-- core/src/signal_path/sink.cpp | 2 +- decoder_modules/falcon9_decoder/src/main.cpp | 2 +- decoder_modules/m17_decoder/src/main.cpp | 2 +- .../meteor_demodulator/src/main.cpp | 2 +- decoder_modules/radio/src/radio_module.h | 2 +- .../weather_sat_decoder/src/main.cpp | 2 +- .../src/noaa_hrpt_decoder.h | 12 +- misc_modules/frequency_manager/src/main.cpp | 20 +- misc_modules/recorder/src/main.cpp | 2 +- misc_modules/rigctl_server/src/main.cpp | 2 +- misc_modules/scheduler/src/main.cpp | 4 +- misc_modules/scheduler/src/sched_task.h | 4 +- sink_modules/audio_sink/src/main.cpp | 2 +- sink_modules/network_sink/src/main.cpp | 2 +- sink_modules/new_portaudio_sink/src/main.cpp | 2 +- sink_modules/portaudio_sink/src/main.cpp | 2 +- source_modules/sddc_source/src/main.cpp | 2 +- .../sdrpp_server_source/src/main.cpp | 2 +- 47 files changed, 2018 insertions(+), 1069 deletions(-) delete mode 100644 core/backends/android/keybinds.h delete mode 100644 core/backends/glfw/keybinds.h diff --git a/core/backends/android/imgui/imgui_impl_android.cpp b/core/backends/android/imgui/imgui_impl_android.cpp index 3201bee2..bb8de811 100644 --- a/core/backends/android/imgui/imgui_impl_android.cpp +++ b/core/backends/android/imgui/imgui_impl_android.cpp @@ -2,29 +2,31 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: +// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2021-03-04: Initial version. #include "imgui.h" #include "imgui_impl_android.h" #include -#include -#include #include #include #include @@ -34,7 +36,119 @@ static double g_Time = 0.0; static ANativeWindow* g_Window; static char g_LogTag[] = "ImGuiExample"; -static std::map> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue. + +static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code) +{ + switch (key_code) + { + case AKEYCODE_TAB: return ImGuiKey_Tab; + case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow; + case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow; + case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow; + case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow; + case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp; + case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown; + case AKEYCODE_MOVE_HOME: return ImGuiKey_Home; + case AKEYCODE_MOVE_END: return ImGuiKey_End; + case AKEYCODE_INSERT: return ImGuiKey_Insert; + case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete; + case AKEYCODE_DEL: return ImGuiKey_Backspace; + case AKEYCODE_SPACE: return ImGuiKey_Space; + case AKEYCODE_ENTER: return ImGuiKey_Enter; + case AKEYCODE_ESCAPE: return ImGuiKey_Escape; + case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; + case AKEYCODE_COMMA: return ImGuiKey_Comma; + case AKEYCODE_MINUS: return ImGuiKey_Minus; + case AKEYCODE_PERIOD: return ImGuiKey_Period; + case AKEYCODE_SLASH: return ImGuiKey_Slash; + case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon; + case AKEYCODE_EQUALS: return ImGuiKey_Equal; + case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash; + case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent; + case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; + case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock; + case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen; + case AKEYCODE_BREAK: return ImGuiKey_Pause; + case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0; + case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1; + case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2; + case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3; + case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4; + case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5; + case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6; + case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7; + case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8; + case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9; + case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal; + case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide; + case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply; + case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract; + case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd; + case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter; + case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual; + case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl; + case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift; + case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt; + case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper; + case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl; + case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift; + case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt; + case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper; + case AKEYCODE_MENU: return ImGuiKey_Menu; + case AKEYCODE_0: return ImGuiKey_0; + case AKEYCODE_1: return ImGuiKey_1; + case AKEYCODE_2: return ImGuiKey_2; + case AKEYCODE_3: return ImGuiKey_3; + case AKEYCODE_4: return ImGuiKey_4; + case AKEYCODE_5: return ImGuiKey_5; + case AKEYCODE_6: return ImGuiKey_6; + case AKEYCODE_7: return ImGuiKey_7; + case AKEYCODE_8: return ImGuiKey_8; + case AKEYCODE_9: return ImGuiKey_9; + case AKEYCODE_A: return ImGuiKey_A; + case AKEYCODE_B: return ImGuiKey_B; + case AKEYCODE_C: return ImGuiKey_C; + case AKEYCODE_D: return ImGuiKey_D; + case AKEYCODE_E: return ImGuiKey_E; + case AKEYCODE_F: return ImGuiKey_F; + case AKEYCODE_G: return ImGuiKey_G; + case AKEYCODE_H: return ImGuiKey_H; + case AKEYCODE_I: return ImGuiKey_I; + case AKEYCODE_J: return ImGuiKey_J; + case AKEYCODE_K: return ImGuiKey_K; + case AKEYCODE_L: return ImGuiKey_L; + case AKEYCODE_M: return ImGuiKey_M; + case AKEYCODE_N: return ImGuiKey_N; + case AKEYCODE_O: return ImGuiKey_O; + case AKEYCODE_P: return ImGuiKey_P; + case AKEYCODE_Q: return ImGuiKey_Q; + case AKEYCODE_R: return ImGuiKey_R; + case AKEYCODE_S: return ImGuiKey_S; + case AKEYCODE_T: return ImGuiKey_T; + case AKEYCODE_U: return ImGuiKey_U; + case AKEYCODE_V: return ImGuiKey_V; + case AKEYCODE_W: return ImGuiKey_W; + case AKEYCODE_X: return ImGuiKey_X; + case AKEYCODE_Y: return ImGuiKey_Y; + case AKEYCODE_Z: return ImGuiKey_Z; + case AKEYCODE_F1: return ImGuiKey_F1; + case AKEYCODE_F2: return ImGuiKey_F2; + case AKEYCODE_F3: return ImGuiKey_F3; + case AKEYCODE_F4: return ImGuiKey_F4; + case AKEYCODE_F5: return ImGuiKey_F5; + case AKEYCODE_F6: return ImGuiKey_F6; + case AKEYCODE_F7: return ImGuiKey_F7; + case AKEYCODE_F8: return ImGuiKey_F8; + case AKEYCODE_F9: return ImGuiKey_F9; + case AKEYCODE_F10: return ImGuiKey_F10; + case AKEYCODE_F11: return ImGuiKey_F11; + case AKEYCODE_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) { @@ -45,12 +159,14 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) case AINPUT_EVENT_TYPE_KEY: { int32_t event_key_code = AKeyEvent_getKeyCode(input_event); + int32_t event_scan_code = AKeyEvent_getScanCode(input_event); int32_t event_action = AKeyEvent_getAction(input_event); int32_t event_meta_state = AKeyEvent_getMetaState(input_event); - io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0); - io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0); - io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0); + io.AddKeyEvent(ImGuiKey_ModCtrl, (event_meta_state & AMETA_CTRL_ON) != 0); + io.AddKeyEvent(ImGuiKey_ModShift, (event_meta_state & AMETA_SHIFT_ON) != 0); + io.AddKeyEvent(ImGuiKey_ModAlt, (event_meta_state & AMETA_ALT_ON) != 0); + io.AddKeyEvent(ImGuiKey_ModSuper, (event_meta_state & AMETA_META_ON) != 0); switch (event_action) { @@ -59,8 +175,16 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_UP: - g_KeyEventQueues[event_key_code].push(event_action); + { + ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code); + if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP)) + { + io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN); + io.SetKeyEventNativeData(key, event_key_code, event_scan_code); + } + break; + } default: break; } @@ -79,28 +203,27 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) // but we have to process them separately to identify the actual button pressed. This is done below via // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback). if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) - || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_STYLUS) || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) + || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) { - io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN); - io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); + io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); + io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN); } break; case AMOTION_EVENT_ACTION_BUTTON_PRESS: case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { int32_t button_state = AMotionEvent_getButtonState(input_event); - io.MouseDown[0] = ((button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0); - io.MouseDown[1] = ((button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0); - io.MouseDown[2] = ((button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0); + io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0); + io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0); + io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0); } break; case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse) case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN - io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); + io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index)); break; case AMOTION_EVENT_ACTION_SCROLL: - io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index); - io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index); + io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index)); break; default: break; @@ -123,30 +246,6 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window) ImGuiIO& io = ImGui::GetIO(); io.BackendPlatformName = "imgui_impl_android"; - // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. - io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key - io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP; - io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN; - io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME; - io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END; - io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT; - io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL; - io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL; - io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE; - io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER; - io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE; - io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER; - io.KeyMap[ImGuiKey_A] = AKEYCODE_A; - io.KeyMap[ImGuiKey_C] = AKEYCODE_C; - io.KeyMap[ImGuiKey_V] = AKEYCODE_V; - io.KeyMap[ImGuiKey_X] = AKEYCODE_X; - io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y; - io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z; - return true; } @@ -158,16 +257,6 @@ void ImGui_ImplAndroid_NewFrame() { ImGuiIO& io = ImGui::GetIO(); - // Process queued key events - // FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue. - for (auto& key_queue : g_KeyEventQueues) - { - if (key_queue.second.empty()) - continue; - io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN); - key_queue.second.pop(); - } - // Setup display size (every frame to accommodate for window resizing) int32_t window_width = ANativeWindow_getWidth(g_Window); int32_t window_height = ANativeWindow_getHeight(g_Window); diff --git a/core/backends/android/imgui/imgui_impl_android.h b/core/backends/android/imgui/imgui_impl_android.h index 92b466b6..8bfa1860 100644 --- a/core/backends/android/imgui/imgui_impl_android.h +++ b/core/backends/android/imgui/imgui_impl_android.h @@ -2,16 +2,17 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE). +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: +// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs diff --git a/core/backends/android/keybinds.h b/core/backends/android/keybinds.h deleted file mode 100644 index 83bc6a66..00000000 --- a/core/backends/android/keybinds.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -// No keyboard controls -#define KB_KEY_HOME -1 -#define KB_KEY_MENU -1 -#define KB_KEY_END -1 -#define KB_KEY_ESC -1 -#define KB_KEY_PG_UP -1 -#define KB_KEY_PG_DOWN -1 - -#define KB_KEY_ENTER -1 -#define KB_KEY_KP_ENTER -1 -#define KB_KEY_DEL -1 -#define KB_KEY_BACKSPACE -1 - -#define KB_KEY_LEFT -1 -#define KB_KEY_RIGHT -1 -#define KB_KEY_UP -1 -#define KB_KEY_DOWN -1 - -#define KB_KEY_LCTRL -1 -#define KB_KEY_RCTRL -1 -#define KB_KEY_LSHIFT -1 -#define KB_KEY_RSHIFT -1 - -#define KB_KEY_A -1 -#define KB_KEY_R -1 \ No newline at end of file diff --git a/core/backends/glfw/imgui/imgui_impl_glfw.cpp b/core/backends/glfw/imgui/imgui_impl_glfw.cpp index 1be2c524..516aa3c2 100644 --- a/core/backends/glfw/imgui/imgui_impl_glfw.cpp +++ b/core/backends/glfw/imgui/imgui_impl_glfw.cpp @@ -5,9 +5,9 @@ // Implemented features: // [X] Platform: Clipboard support. +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). -// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -16,6 +16,14 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after iniitializing backend. +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates. +// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. +// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. // 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback(). // 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback(). // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). @@ -44,6 +52,16 @@ #include "imgui.h" #include "imgui_impl_glfw.h" +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif + // GLFW #include #ifdef _WIN32 @@ -51,16 +69,13 @@ #define GLFW_EXPOSE_NATIVE_WIN32 #include // for glfwGetWin32Window #endif -#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING -#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED -#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity -#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale -#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR #else #define GLFW_HAS_NEW_CURSORS (0) #endif +#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api +#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName() // GLFW data enum GlfwClientApi @@ -76,12 +91,13 @@ struct ImGui_ImplGlfw_Data GlfwClientApi ClientApi; double Time; GLFWwindow* MouseWindow; - bool MouseJustPressed[ImGuiMouseButton_COUNT]; GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; + ImVec2 LastValidMousePos; bool InstalledCallbacks; // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. GLFWwindowfocusfun PrevUserCallbackWindowFocus; + GLFWcursorposfun PrevUserCallbackCursorPos; GLFWcursorenterfun PrevUserCallbackCursorEnter; GLFWmousebuttonfun PrevUserCallbackMousebutton; GLFWscrollfun PrevUserCallbackScroll; @@ -115,14 +131,139 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) glfwSetClipboardString((GLFWwindow*)user_data, text); } +static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) +{ + switch (key) + { + case GLFW_KEY_TAB: return ImGuiKey_Tab; + case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; + case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow; + case GLFW_KEY_UP: return ImGuiKey_UpArrow; + case GLFW_KEY_DOWN: return ImGuiKey_DownArrow; + case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp; + case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown; + case GLFW_KEY_HOME: return ImGuiKey_Home; + case GLFW_KEY_END: return ImGuiKey_End; + case GLFW_KEY_INSERT: return ImGuiKey_Insert; + case GLFW_KEY_DELETE: return ImGuiKey_Delete; + case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace; + case GLFW_KEY_SPACE: return ImGuiKey_Space; + case GLFW_KEY_ENTER: return ImGuiKey_Enter; + case GLFW_KEY_ESCAPE: return ImGuiKey_Escape; + case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe; + case GLFW_KEY_COMMA: return ImGuiKey_Comma; + case GLFW_KEY_MINUS: return ImGuiKey_Minus; + case GLFW_KEY_PERIOD: return ImGuiKey_Period; + case GLFW_KEY_SLASH: return ImGuiKey_Slash; + case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon; + case GLFW_KEY_EQUAL: return ImGuiKey_Equal; + case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket; + case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash; + case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket; + case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent; + case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock; + case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock; + case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock; + case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen; + case GLFW_KEY_PAUSE: return ImGuiKey_Pause; + case GLFW_KEY_KP_0: return ImGuiKey_Keypad0; + case GLFW_KEY_KP_1: return ImGuiKey_Keypad1; + case GLFW_KEY_KP_2: return ImGuiKey_Keypad2; + case GLFW_KEY_KP_3: return ImGuiKey_Keypad3; + case GLFW_KEY_KP_4: return ImGuiKey_Keypad4; + case GLFW_KEY_KP_5: return ImGuiKey_Keypad5; + case GLFW_KEY_KP_6: return ImGuiKey_Keypad6; + case GLFW_KEY_KP_7: return ImGuiKey_Keypad7; + case GLFW_KEY_KP_8: return ImGuiKey_Keypad8; + case GLFW_KEY_KP_9: return ImGuiKey_Keypad9; + case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal; + case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide; + case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; + case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract; + case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd; + case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter; + case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual; + case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift; + case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl; + case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt; + case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper; + case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift; + case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl; + case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt; + case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper; + case GLFW_KEY_MENU: return ImGuiKey_Menu; + case GLFW_KEY_0: return ImGuiKey_0; + case GLFW_KEY_1: return ImGuiKey_1; + case GLFW_KEY_2: return ImGuiKey_2; + case GLFW_KEY_3: return ImGuiKey_3; + case GLFW_KEY_4: return ImGuiKey_4; + case GLFW_KEY_5: return ImGuiKey_5; + case GLFW_KEY_6: return ImGuiKey_6; + case GLFW_KEY_7: return ImGuiKey_7; + case GLFW_KEY_8: return ImGuiKey_8; + case GLFW_KEY_9: return ImGuiKey_9; + case GLFW_KEY_A: return ImGuiKey_A; + case GLFW_KEY_B: return ImGuiKey_B; + case GLFW_KEY_C: return ImGuiKey_C; + case GLFW_KEY_D: return ImGuiKey_D; + case GLFW_KEY_E: return ImGuiKey_E; + case GLFW_KEY_F: return ImGuiKey_F; + case GLFW_KEY_G: return ImGuiKey_G; + case GLFW_KEY_H: return ImGuiKey_H; + case GLFW_KEY_I: return ImGuiKey_I; + case GLFW_KEY_J: return ImGuiKey_J; + case GLFW_KEY_K: return ImGuiKey_K; + case GLFW_KEY_L: return ImGuiKey_L; + case GLFW_KEY_M: return ImGuiKey_M; + case GLFW_KEY_N: return ImGuiKey_N; + case GLFW_KEY_O: return ImGuiKey_O; + case GLFW_KEY_P: return ImGuiKey_P; + case GLFW_KEY_Q: return ImGuiKey_Q; + case GLFW_KEY_R: return ImGuiKey_R; + case GLFW_KEY_S: return ImGuiKey_S; + case GLFW_KEY_T: return ImGuiKey_T; + case GLFW_KEY_U: return ImGuiKey_U; + case GLFW_KEY_V: return ImGuiKey_V; + case GLFW_KEY_W: return ImGuiKey_W; + case GLFW_KEY_X: return ImGuiKey_X; + case GLFW_KEY_Y: return ImGuiKey_Y; + case GLFW_KEY_Z: return ImGuiKey_Z; + case GLFW_KEY_F1: return ImGuiKey_F1; + case GLFW_KEY_F2: return ImGuiKey_F2; + case GLFW_KEY_F3: return ImGuiKey_F3; + case GLFW_KEY_F4: return ImGuiKey_F4; + case GLFW_KEY_F5: return ImGuiKey_F5; + case GLFW_KEY_F6: return ImGuiKey_F6; + case GLFW_KEY_F7: return ImGuiKey_F7; + case GLFW_KEY_F8: return ImGuiKey_F8; + case GLFW_KEY_F9: return ImGuiKey_F9; + case GLFW_KEY_F10: return ImGuiKey_F10; + case GLFW_KEY_F11: return ImGuiKey_F11; + case GLFW_KEY_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} + +static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0); + io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0); + io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0); + io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0); +} + void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window) bd->PrevUserCallbackMousebutton(window, button, action, mods); - if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed)) - bd->MouseJustPressed[button] = true; + ImGui_ImplGlfw_UpdateKeyModifiers(mods); + + ImGuiIO& io = ImGui::GetIO(); + if (button >= 0 && button < ImGuiMouseButton_COUNT) + io.AddMouseButtonEvent(button, action == GLFW_PRESS); } void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) @@ -132,34 +273,53 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo bd->PrevUserCallbackScroll(window, xoffset, yoffset); ImGuiIO& io = ImGui::GetIO(); - io.MouseWheelH += (float)xoffset; - io.MouseWheel += (float)yoffset; + io.AddMouseWheelEvent((float)xoffset, (float)yoffset); } -void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) +{ +#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__) + // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult. + // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently) + // See https://github.com/glfw/glfw/issues/1502 for details. + // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process). + // This won't cover edge cases but this is at least going to cover common cases. + if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL) + return key; + const char* key_name = glfwGetKeyName(key, scancode); + if (key_name && key_name[0] != 0 && key_name[1] == 0) + { + const char char_names[] = "`-=[]\\,;\'./"; + const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 }; + IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys)); + if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); } + else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); } + else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; } + } + // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name); +#else + IM_UNUSED(scancode); +#endif + return key; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); if (bd->PrevUserCallbackKey != NULL && window == bd->Window) - bd->PrevUserCallbackKey(window, key, scancode, action, mods); + bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); + + if (action != GLFW_PRESS && action != GLFW_RELEASE) + return; + + ImGui_ImplGlfw_UpdateKeyModifiers(mods); + + keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); ImGuiIO& io = ImGui::GetIO(); - if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)) - { - if (action == GLFW_PRESS) - io.KeysDown[key] = true; - if (action == GLFW_RELEASE) - io.KeysDown[key] = false; - } - - // Modifiers are not reliable across systems - io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; - io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; - io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; -#ifdef _WIN32 - io.KeySuper = false; -#else - io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; -#endif + ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode); + io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); + io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) } void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) @@ -172,16 +332,37 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) io.AddFocusEvent(focused != 0); } +void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window) + bd->PrevUserCallbackCursorPos(window, x, y); + + ImGuiIO& io = ImGui::GetIO(); + io.AddMousePosEvent((float)x, (float)y); + bd->LastValidMousePos = ImVec2((float)x, (float)y); +} + +// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position, +// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984) void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window) bd->PrevUserCallbackCursorEnter(window, entered); + ImGuiIO& io = ImGui::GetIO(); if (entered) + { bd->MouseWindow = window; - if (!entered && bd->MouseWindow == window) + io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y); + } + else if (!entered && bd->MouseWindow == window) + { + bd->LastValidMousePos = io.MousePos; bd->MouseWindow = NULL; + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + } } void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) @@ -199,6 +380,48 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. } +void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!"); + IM_ASSERT(bd->Window == window); + + bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); + bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); + bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback); + bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); + bd->InstalledCallbacks = true; +} + +void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!"); + IM_ASSERT(bd->Window == window); + + glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus); + glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter); + glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos); + glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton); + glfwSetScrollCallback(window, bd->PrevUserCallbackScroll); + glfwSetKeyCallback(window, bd->PrevUserCallbackKey); + glfwSetCharCallback(window, bd->PrevUserCallbackChar); + glfwSetMonitorCallback(bd->PrevUserCallbackMonitor); + bd->InstalledCallbacks = false; + bd->PrevUserCallbackWindowFocus = NULL; + bd->PrevUserCallbackCursorEnter = NULL; + bd->PrevUserCallbackCursorPos = NULL; + bd->PrevUserCallbackMousebutton = NULL; + bd->PrevUserCallbackScroll = NULL; + bd->PrevUserCallbackKey = NULL; + bd->PrevUserCallbackChar = NULL; + bd->PrevUserCallbackMonitor = NULL; +} + static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) { ImGuiIO& io = ImGui::GetIO(); @@ -214,35 +437,13 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Window = window; bd->Time = 0.0; - // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. - io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; - io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; - io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; - io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; - io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; - io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; - io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; - io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; - io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; - io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; - io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; - io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; - io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; - io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; - io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; - io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; - io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; - io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; - io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; - io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; io.ClipboardUserData = bd->Window; + + // Set platform dependent data in viewport #if defined(_WIN32) - io.ImeWindowHandle = (void*)glfwGetWin32Window(bd->Window); + ImGui::GetMainViewport()->PlatformHandleRaw = (void*)glfwGetWin32Window(bd->Window); #endif // Create mouse cursors @@ -269,24 +470,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw glfwSetErrorCallback(prev_error_callback); // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. - bd->PrevUserCallbackWindowFocus = NULL; - bd->PrevUserCallbackCursorEnter = NULL; - bd->PrevUserCallbackMousebutton = NULL; - bd->PrevUserCallbackScroll = NULL; - bd->PrevUserCallbackKey = NULL; - bd->PrevUserCallbackChar = NULL; - bd->PrevUserCallbackMonitor = NULL; if (install_callbacks) - { - bd->InstalledCallbacks = true; - bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); - bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); - bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); - bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); - bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); - bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); - bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); - } + ImGui_ImplGlfw_InstallCallbacks(window); bd->ClientApi = client_api; return true; @@ -314,15 +499,7 @@ void ImGui_ImplGlfw_Shutdown() ImGuiIO& io = ImGui::GetIO(); if (bd->InstalledCallbacks) - { - glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus); - glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter); - glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton); - glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll); - glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey); - glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar); - glfwSetMonitorCallback(bd->PrevUserCallbackMonitor); - } + ImGui_ImplGlfw_RestoreCallbacks(bd->Window); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) glfwDestroyCursor(bd->MouseCursors[cursor_n]); @@ -332,39 +509,30 @@ void ImGui_ImplGlfw_Shutdown() IM_DELETE(bd); } -static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +static void ImGui_ImplGlfw_UpdateMouseData() { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); - const ImVec2 mouse_pos_prev = io.MousePos; - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - - // Update mouse buttons - // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame) - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) - { - io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0; - bd->MouseJustPressed[i] = false; - } - #ifdef __EMSCRIPTEN__ - const bool focused = true; + const bool is_app_focused = true; #else - const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0; + const bool is_app_focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0; #endif - GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL; - - // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - if (io.WantSetMousePos && focused) - glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y); - - // Set Dear ImGui mouse position from OS position - if (mouse_window != NULL) + if (is_app_focused) { - double mouse_x, mouse_y; - glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y); - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + glfwSetCursorPos(bd->Window, (double)io.MousePos.x, (double)io.MousePos.y); + + // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) + if (is_app_focused && bd->MouseWindow == NULL) + { + double mouse_x, mouse_y; + glfwGetCursorPos(bd->Window, &mouse_x, &mouse_y); + io.AddMousePosEvent((float)mouse_x, (float)mouse_y); + bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); + } } } @@ -390,41 +558,57 @@ static void ImGui_ImplGlfw_UpdateMouseCursor() } } +// Update gamepad inputs +static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } static void ImGui_ImplGlfw_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - memset(io.NavInputs, 0, sizeof(io.NavInputs)); if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) return; - // Update gamepad inputs - #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } - #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +#if GLFW_HAS_GAMEPAD_API + GLFWgamepadstate gamepad; + if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad)) + return; + #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0) + #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#else int axes_count = 0, buttons_count = 0; const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); - MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A - MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B - MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X - MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y - MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left - MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right - MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up - MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down - MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB - MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB - MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB - MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB - MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); - MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); - MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); - MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); + if (axes_count == 0 || buttons_count == 0) + return; + #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0) + #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0) +#endif + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7); + MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6); + MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross + MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle + MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square + MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle + MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13); + MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11); + MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10); + MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12); + MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4); + MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5); + MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f); + MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8); + MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9); + MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f); + MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f); #undef MAP_BUTTON #undef MAP_ANALOG - if (axes_count > 0 && buttons_count > 0) - io.BackendFlags |= ImGuiBackendFlags_HasGamepad; - else - io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; } void ImGui_ImplGlfw_NewFrame() @@ -440,16 +624,20 @@ void ImGui_ImplGlfw_NewFrame() glfwGetFramebufferSize(bd->Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h); // Setup time step double current_time = glfwGetTime(); io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); bd->Time = current_time; - ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseData(); ImGui_ImplGlfw_UpdateMouseCursor(); // Update game controllers (if enabled and available) ImGui_ImplGlfw_UpdateGamepads(); } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/core/backends/glfw/imgui/imgui_impl_glfw.h b/core/backends/glfw/imgui/imgui_impl_glfw.h index 5e1fb06d..58712dee 100644 --- a/core/backends/glfw/imgui/imgui_impl_glfw.h +++ b/core/backends/glfw/imgui/imgui_impl_glfw.h @@ -4,9 +4,9 @@ // Implemented features: // [X] Platform: Clipboard support. +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. -// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -29,11 +29,16 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); -// GLFW callbacks -// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any. -// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks. -IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); -IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); +// GLFW callbacks (installer) +// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any. +// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks. +IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window); +IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window); + +// GLFW callbacks (individual callbacks to call if you didn't install callbacks) +IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87 IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); diff --git a/core/backends/glfw/keybinds.h b/core/backends/glfw/keybinds.h deleted file mode 100644 index fccc5a73..00000000 --- a/core/backends/glfw/keybinds.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -#define KB_KEY_HOME GLFW_KEY_HOME -#define KB_KEY_MENU GLFW_KEY_MENU -#define KB_KEY_END GLFW_KEY_END -#define KB_KEY_ESC GLFW_KEY_ESCAPE -#define KB_KEY_PG_UP GLFW_KEY_PAGE_UP -#define KB_KEY_PG_DOWN GLFW_KEY_PAGE_DOWN - -#define KB_KEY_ENTER GLFW_KEY_ENTER -#define KB_KEY_KP_ENTER GLFW_KEY_KP_ENTER -#define KB_KEY_DEL GLFW_KEY_DELETE -#define KB_KEY_BACKSPACE GLFW_KEY_BACKSPACE - -#define KB_KEY_LEFT GLFW_KEY_LEFT -#define KB_KEY_RIGHT GLFW_KEY_RIGHT -#define KB_KEY_UP GLFW_KEY_UP -#define KB_KEY_DOWN GLFW_KEY_DOWN - -#define KB_KEY_LCTRL GLFW_KEY_LEFT_CONTROL -#define KB_KEY_RCTRL GLFW_KEY_RIGHT_CONTROL -#define KB_KEY_LSHIFT GLFW_KEY_LEFT_SHIFT -#define KB_KEY_RSHIFT GLFW_KEY_RIGHT_SHIFT - -#define KB_KEY_A GLFW_KEY_A -#define KB_KEY_R GLFW_KEY_R \ No newline at end of file diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index bf60b635..5b910aa1 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -28,7 +28,6 @@ #include #include #include -#include void MainWindow::init() { LoadingScreen::show("Initializing UI"); @@ -358,7 +357,7 @@ void MainWindow::draw() { // To Bar ImVec2 btnSize(30 * style::uiScale, 30 * style::uiScale); ImGui::PushID(ImGui::GetID("sdrpp_menu_btn")); - if (ImGui::ImageButton(icons::MENU, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(KB_KEY_MENU, false)) { + if (ImGui::ImageButton(icons::MENU, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_Menu, false)) { showMenu = !showMenu; core::configManager.acquire(); core::configManager.conf["showMenu"] = showMenu; @@ -372,14 +371,14 @@ void MainWindow::draw() { if (playButtonLocked && !tmpPlaySate) { style::beginDisabled(); } if (playing) { ImGui::PushID(ImGui::GetID("sdrpp_stop_btn")); - if (ImGui::ImageButton(icons::STOP, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(KB_KEY_END, false)) { + if (ImGui::ImageButton(icons::STOP, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { setPlayState(false); } ImGui::PopID(); } else { // TODO: Might need to check if there even is a device ImGui::PushID(ImGui::GetID("sdrpp_play_btn")); - if (ImGui::ImageButton(icons::PLAY, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(KB_KEY_END, false)) { + if (ImGui::ImageButton(icons::PLAY, btnSize, ImVec2(0, 0), ImVec2(1, 1), 5) || ImGui::IsKeyPressed(ImGuiKey_End, false)) { setPlayState(true); } ImGui::PopID(); @@ -444,7 +443,7 @@ void MainWindow::draw() { if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) { showCredits = false; } - if (ImGui::IsKeyPressed(KB_KEY_ESC)) { + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { showCredits = false; } @@ -562,12 +561,12 @@ void MainWindow::draw() { if (!lockWaterfallControls) { // Handle arrow keys if (vfo != NULL && (gui::waterfall.mouseInFFT || gui::waterfall.mouseInWaterfall)) { - if (ImGui::IsKeyPressed(KB_KEY_LEFT) && !gui::freqSelect.digitHovered) { + if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow) && !gui::freqSelect.digitHovered) { double nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset - vfo->snapInterval; nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval; tuner::tune(tuningMode, gui::waterfall.selectedVFO, nfreq); } - if (ImGui::IsKeyPressed(KB_KEY_RIGHT) && !gui::freqSelect.digitHovered) { + if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) && !gui::freqSelect.digitHovered) { double nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset + vfo->snapInterval; nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval; tuner::tune(tuningMode, gui::waterfall.selectedVFO, nfreq); diff --git a/core/src/gui/menus/bandplan.cpp b/core/src/gui/menus/bandplan.cpp index 5c138d06..63353791 100644 --- a/core/src/gui/menus/bandplan.cpp +++ b/core/src/gui/menus/bandplan.cpp @@ -35,7 +35,7 @@ namespace bandplanmenu { } void draw(void* ctx) { - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + float menuColumnWidth = ImGui::GetContentRegionAvail().x; ImGui::PushItemWidth(menuColumnWidth); if (ImGui::Combo("##_bandplan_name_", &bandplanId, bandplan::bandplanNameTxt.c_str())) { gui::waterfall.bandplan = &bandplan::bandplans[bandplan::bandplanNames[bandplanId]]; diff --git a/core/src/gui/menus/display.cpp b/core/src/gui/menus/display.cpp index 387dd03a..91853bca 100644 --- a/core/src/gui/menus/display.cpp +++ b/core/src/gui/menus/display.cpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace displaymenu { bool showWaterfall; @@ -89,8 +88,8 @@ namespace displaymenu { } void draw(void* ctx) { - float menuWidth = ImGui::GetContentRegionAvailWidth(); - bool homePressed = ImGui::IsKeyPressed(KB_KEY_HOME, false); + float menuWidth = ImGui::GetContentRegionAvail().x; + bool homePressed = ImGui::IsKeyPressed(ImGuiKey_Home, false); if (ImGui::Checkbox("Show Waterfall##_sdrpp", &showWaterfall) || homePressed) { if (homePressed) { showWaterfall = !showWaterfall; } showWaterfall ? gui::waterfall.showWaterfall() : gui::waterfall.hideWaterfall(); diff --git a/core/src/gui/menus/module_manager.cpp b/core/src/gui/menus/module_manager.cpp index 9ecdb494..a7a3f85f 100644 --- a/core/src/gui/menus/module_manager.cpp +++ b/core/src/gui/menus/module_manager.cpp @@ -80,11 +80,11 @@ namespace module_manager_menu { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputText("##module_mod_name", modName, 1000); ImGui::TableSetColumnIndex(1); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##module_mgr_type", &modTypeId, modTypesTxt.c_str()); ImGui::TableSetColumnIndex(2); diff --git a/core/src/gui/menus/source.cpp b/core/src/gui/menus/source.cpp index 03124297..c4809de7 100644 --- a/core/src/gui/menus/source.cpp +++ b/core/src/gui/menus/source.cpp @@ -156,7 +156,7 @@ namespace sourcemenu { } void draw(void* ctx) { - float itemWidth = ImGui::GetContentRegionAvailWidth(); + float itemWidth = ImGui::GetContentRegionAvail().x; bool running = gui::mainWindow.sdrIsRunning(); if (running) { style::beginDisabled(); } diff --git a/core/src/gui/menus/theme.cpp b/core/src/gui/menus/theme.cpp index 45a40b7c..fa161b30 100644 --- a/core/src/gui/menus/theme.cpp +++ b/core/src/gui/menus/theme.cpp @@ -41,7 +41,7 @@ namespace thememenu { } void draw(void* ctx) { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::LeftLabel("Theme"); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::Combo("##theme_select_combo", &themeId, themeNamesTxt.c_str())) { diff --git a/core/src/gui/menus/vfo_color.cpp b/core/src/gui/menus/vfo_color.cpp index 4b8faa75..dd0401d0 100644 --- a/core/src/gui/menus/vfo_color.cpp +++ b/core/src/gui/menus/vfo_color.cpp @@ -81,7 +81,7 @@ namespace vfo_color_menu { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - if (ImGui::Button("Auto Color##vfo_color", ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { + if (ImGui::Button("Auto Color##vfo_color", ImVec2(ImGui::GetContentRegionAvail().x, 0))) { float delta = 1.0f / (float)gui::waterfall.vfos.size(); float hue = 0; for (auto& [name, vfo] : gui::waterfall.vfos) { @@ -99,7 +99,7 @@ namespace vfo_color_menu { } ImGui::TableSetColumnIndex(1); - if (ImGui::Button("Clear All##vfo_color", ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { + if (ImGui::Button("Clear All##vfo_color", ImVec2(ImGui::GetContentRegionAvail().x, 0))) { for (auto& [name, vfo] : gui::waterfall.vfos) { vfoColors[name] = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); vfo->color = IM_COL32(255, 255, 255, 50); diff --git a/core/src/gui/smgui.cpp b/core/src/gui/smgui.cpp index f7a8e282..aa6d596f 100644 --- a/core/src/gui/smgui.cpp +++ b/core/src/gui/smgui.cpp @@ -459,7 +459,7 @@ namespace SmGui { void FillWidth() { if (!options::opts.serverMode) { nextItemFillWidth = true; - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); return; } if (rdl) { rdl->pushStep(DRAW_STEP_FILL_WIDTH, false); } @@ -504,7 +504,7 @@ namespace SmGui { if (!options::opts.serverMode) { if (nextItemFillWidth) { nextItemFillWidth = false; - size.x = ImGui::GetContentRegionAvailWidth(); + size.x = ImGui::GetContentRegionAvail().x; } return ImGui::Button(label, size); } diff --git a/core/src/gui/style.cpp b/core/src/gui/style.cpp index c796dc65..efa0beb8 100644 --- a/core/src/gui/style.cpp +++ b/core/src/gui/style.cpp @@ -70,6 +70,6 @@ namespace ImGui { } void FillWidth() { - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); } } diff --git a/core/src/gui/widgets/file_select.cpp b/core/src/gui/widgets/file_select.cpp index 520b5cd4..c1c64d86 100644 --- a/core/src/gui/widgets/file_select.cpp +++ b/core/src/gui/widgets/file_select.cpp @@ -11,7 +11,7 @@ FileSelect::FileSelect(std::string defaultPath, std::vector filter) bool FileSelect::render(std::string id) { bool _pathChanged = false; - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + float menuColumnWidth = ImGui::GetContentRegionAvail().x; float buttonWidth = ImGui::CalcTextSize("...").x + 20.0f; bool lastPathValid = pathValid; diff --git a/core/src/gui/widgets/folder_select.cpp b/core/src/gui/widgets/folder_select.cpp index 8cb668c2..1a1cd722 100644 --- a/core/src/gui/widgets/folder_select.cpp +++ b/core/src/gui/widgets/folder_select.cpp @@ -10,7 +10,7 @@ FolderSelect::FolderSelect(std::string defaultPath) { bool FolderSelect::render(std::string id) { bool _pathChanged = false; - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + float menuColumnWidth = ImGui::GetContentRegionAvail().x; float buttonWidth = ImGui::CalcTextSize("...").x + 20.0f; bool lastPathValid = pathValid; diff --git a/core/src/gui/widgets/frequency_select.cpp b/core/src/gui/widgets/frequency_select.cpp index a885e3f3..5b691455 100644 --- a/core/src/gui/widgets/frequency_select.cpp +++ b/core/src/gui/widgets/frequency_select.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS @@ -155,23 +154,23 @@ void FrequencySelect::draw() { } if (onDigit) { hovered = true; - if (rightClick || (ImGui::IsKeyPressed(KB_KEY_DEL) || ImGui::IsKeyPressed(KB_KEY_ENTER) || ImGui::IsKeyPressed(KB_KEY_KP_ENTER))) { + if (rightClick || (ImGui::IsKeyPressed(ImGuiKey_Delete) || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))) { for (int j = i; j < 12; j++) { digits[j] = 0; } frequencyChanged = true; } - if (ImGui::IsKeyPressed(KB_KEY_UP)) { + if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) { incrementDigit(i); } - if (ImGui::IsKeyPressed(KB_KEY_DOWN)) { + if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) { decrementDigit(i); } - if ((ImGui::IsKeyPressed(KB_KEY_LEFT) || ImGui::IsKeyPressed(KB_KEY_BACKSPACE)) && i > 0) { + if ((ImGui::IsKeyPressed(ImGuiKey_LeftArrow) || ImGui::IsKeyPressed(ImGuiKey_Backspace)) && i > 0) { moveCursorToDigit(i - 1); } - if (ImGui::IsKeyPressed(KB_KEY_RIGHT) && i < 11) { + if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) && i < 11) { moveCursorToDigit(i + 1); } diff --git a/core/src/gui/widgets/menu.cpp b/core/src/gui/widgets/menu.cpp index 384ad5d3..29eecbd2 100644 --- a/core/src/gui/widgets/menu.cpp +++ b/core/src/gui/widgets/menu.cpp @@ -26,7 +26,7 @@ void Menu::removeEntry(std::string name) { bool Menu::draw(bool updateStates) { bool changed = false; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; ImGuiWindow* window = ImGui::GetCurrentWindow(); ImVec2 checkboxOffset = ImVec2(menuWidth - ImGui::GetTextLineHeight() - (6.0f * style::uiScale), - ImGui::GetTextLineHeight() - (10.0f * style::uiScale)); diff --git a/core/src/gui/widgets/waterfall.cpp b/core/src/gui/widgets/waterfall.cpp index 0dae66d6..975fa8d1 100644 --- a/core/src/gui/widgets/waterfall.cpp +++ b/core/src/gui/widgets/waterfall.cpp @@ -7,7 +7,6 @@ #include #include #include -#include float DEFAULT_COLOR_MAP[][3] = { { 0x00, 0x00, 0x20 }, @@ -390,8 +389,8 @@ namespace ImGui { } // If the left and right keys are pressed while hovering the freq scale, move it too - bool leftKeyPressed = ImGui::IsKeyPressed(KB_KEY_LEFT); - if ((leftKeyPressed || ImGui::IsKeyPressed(KB_KEY_RIGHT)) && mouseInFreq) { + bool leftKeyPressed = ImGui::IsKeyPressed(ImGuiKey_LeftArrow); + if ((leftKeyPressed || ImGui::IsKeyPressed(ImGuiKey_RightArrow)) && mouseInFreq) { viewOffset += leftKeyPressed ? (viewBandwidth / 20.0) : (-viewBandwidth / 20.0); if (viewOffset + (viewBandwidth / 2.0) > wholeBandwidth / 2.0) { @@ -438,7 +437,7 @@ namespace ImGui { ImGui::TextUnformatted(name.c_str()); - if (ImGui::IsKeyDown(KB_KEY_LCTRL) || ImGui::IsKeyDown(KB_KEY_RCTRL)) { + if (ImGui::GetIO().KeyCtrl) { ImGui::Separator(); printAndScale(_vfo->generalOffset + centerFreq, buf); ImGui::Text("Frequency: %sHz", buf); @@ -464,7 +463,7 @@ namespace ImGui { } // Handle Page Up to cycle through VFOs - if (ImGui::IsKeyPressed(KB_KEY_PG_UP) && selVfo != NULL) { + if (ImGui::IsKeyPressed(ImGuiKey_PageUp) && selVfo != NULL) { std::string next = (--vfos.end())->first; std::string lowest = ""; double lowestOffset = INFINITY; @@ -487,7 +486,7 @@ namespace ImGui { } // Handle Page Down to cycle through VFOs - if (ImGui::IsKeyPressed(KB_KEY_PG_DOWN) && selVfo != NULL) { + if (ImGui::IsKeyPressed(ImGuiKey_PageDown) && selVfo != NULL) { std::string next = (--vfos.end())->first; std::string highest = ""; double highestOffset = -INFINITY; diff --git a/core/src/imgui/imgui.cpp b/core/src/imgui/imgui.cpp index d7653d41..efa69604 100644 --- a/core/src/imgui/imgui.cpp +++ b/core/src/imgui/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (main code and documentation) // Help: @@ -70,6 +70,7 @@ CODE // [SECTION] STYLING // [SECTION] RENDER HELPERS // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] INPUTS // [SECTION] ERROR CHECKING // [SECTION] LAYOUT // [SECTION] SCROLLING @@ -127,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 @@ -254,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) @@ -294,6 +294,7 @@ CODE // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -308,9 +309,11 @@ CODE } else { - // The texture for the draw call is specified by pcmd->GetTexID(). - // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. - MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); + ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; // We are using scissoring to clip some objects. All low-level graphics API should support it. // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches @@ -321,14 +324,16 @@ CODE // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) - ImVec2 pos = draw_data->DisplayPos; - MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); + MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y); + + // The texture for the draw call is specified by pcmd->GetTexID(). + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); // Render 'pcmd->ElemCount/3' indexed triangles. // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. - MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset); } - idx_buffer += pcmd->ElemCount; } } } @@ -341,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.KeysDown[] + io.KeyMap[] arrays. - - 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. @@ -380,6 +384,29 @@ 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 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) + - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen() + - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x + - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing()); + - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect + - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function. - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful. @@ -907,7 +934,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSetti // Platform Dependents default implementation for IO functions static const char* GetClipboardTextFn_DefaultImpl(void* user_data); static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data); namespace ImGui { @@ -941,6 +968,7 @@ static void UpdateDebugToolStackQueries(); // Misc static void UpdateSettings(); +static void UpdateKeyboardInputs(); static void UpdateMouseInputs(); static void UpdateMouseWheel(); static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); @@ -1082,7 +1110,7 @@ ImGuiIO::ImGuiIO() { // Most fields are initialized with zero memset(this, 0, sizeof(*this)); - IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it here. + IM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Settings ConfigFlags = ImGuiConfigFlags_None; @@ -1094,8 +1122,10 @@ ImGuiIO::ImGuiIO() LogFilename = "imgui_log.txt"; MouseDoubleClickTime = 0.30f; MouseDoubleClickMaxDist = 6.0f; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO for (int i = 0; i < ImGuiKey_COUNT; i++) KeyMap[i] = -1; +#endif KeyRepeatDelay = 0.275f; KeyRepeatRate = 0.050f; UserData = NULL; @@ -1113,6 +1143,7 @@ ImGuiIO::ImGuiIO() #else ConfigMacOSXBehaviors = false; #endif + ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; @@ -1124,25 +1155,35 @@ ImGuiIO::ImGuiIO() GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; ClipboardUserData = NULL; - ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; - ImeWindowHandle = NULL; + SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl; // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); MouseDragThreshold = 6.0f; for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; - for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; + 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 @@ -1155,7 +1196,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; } @@ -1165,7 +1206,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 { @@ -1178,7 +1219,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) InputQueueSurrogate = 0; } - InputQueueCharacters.push_back(cp); + AddInputCharacter((unsigned)cp); } void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) @@ -1188,7 +1229,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); } } @@ -1199,20 +1240,148 @@ void ImGuiIO::ClearInputCharacters() void ImGuiIO::ClearInputKeys() { +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO memset(KeysDown, 0, sizeof(KeysDown)); - for (int n = 0; n < IM_ARRAYSIZE(KeysDownDuration); n++) - KeysDownDuration[n] = KeysDownDurationPrev[n] = -1.0f; +#endif + for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) + { + KeysData[n].Down = false; + KeysData[n].DownDuration = -1.0f; + KeysData[n].DownDurationPrev = -1.0f; + } KeyCtrl = KeyShift = KeyAlt = KeySuper = false; KeyMods = KeyModsPrev = ImGuiKeyModFlags_None; for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++) NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f; } +// 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 +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. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + 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!"); + 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; + } + + // 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); +} + +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) +{ + if (key == ImGuiKey_None) + return; + IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512 + IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey(native_legacy_index)); // >= 0 && <= 511 + IM_UNUSED(native_keycode); // Yet unused + IM_UNUSED(native_scancode); // Yet unused + + // Build native->imgui map so old user code can still call key functions with native 0..511 values. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode; + if (ImGui::IsLegacyKey(legacy_key)) + KeyMap[legacy_key] = key; +#else + IM_UNUSED(key); + IM_UNUSED(native_legacy_index); +#endif +} + +// 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) +{ + 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); } //----------------------------------------------------------------------------- @@ -3199,7 +3368,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 @@ -3207,7 +3376,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) g.ActiveIdUsingMouseWheel = false; g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingNavInputMask = 0x00; - g.ActiveIdUsingKeyInputMask = 0x00; + g.ActiveIdUsingKeyInputMask.ClearAllBits(); } void ImGui::ClearActiveID() @@ -3738,65 +3907,129 @@ static bool IsWindowActiveAndVisible(ImGuiWindow* window) return (window->Active) && (!window->Hidden); } +static void ImGui::UpdateKeyboardInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools + io.KeyMods = GetMergedKeyModFlags(); + + // Import legacy keys or verify they are not used +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (io.BackendUsingLegacyKeyArrays == 0) + { + // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written too. + for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++) + IM_ASSERT(io.KeysDown[n] == false && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + } + else + { + if (g.FrameCount == 0) + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); + + // Build reverse KeyMap (Named -> Legacy) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + if (io.KeyMap[n] != -1) + { + IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); + io.KeyMap[io.KeyMap[n]] = n; + } + + // Import legacy keys into new ones + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) + { + const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); + IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); + 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++) + { + ImGuiKeyData& key_data = io.KeysData[i]; + key_data.DownDurationPrev = key_data.DownDuration; + key_data.DownDuration = key_data.Down ? (key_data.DownDuration < 0.0f ? 0.0f : key_data.DownDuration + io.DeltaTime) : -1.0f; + } +} + static void ImGui::UpdateMouseInputs() { ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) - if (IsMousePosValid(&g.IO.MousePos)) - g.IO.MousePos = g.MouseLastValidPos = ImFloor(g.IO.MousePos); + if (IsMousePosValid(&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(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) - g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; + if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev)) + io.MouseDelta = io.MousePos - io.MousePosPrev; else - g.IO.MouseDelta = ImVec2(0.0f, 0.0f); + io.MouseDelta = ImVec2(0.0f, 0.0f); // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. - if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) g.NavDisableMouseHover = false; - g.IO.MousePosPrev = g.IO.MousePos; - for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + io.MousePosPrev = io.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) { - g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; - g.IO.MouseClickedCount[i] = 0; // Will be filled below - g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; - g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; - g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; - if (g.IO.MouseClicked[i]) + io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; + io.MouseClickedCount[i] = 0; // Will be filled below + io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; + io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; + io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; + if (io.MouseClicked[i]) { bool is_repeated_click = false; - if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) + if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime) { - ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); - if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) + ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist) is_repeated_click = true; } if (is_repeated_click) - g.IO.MouseClickedLastCount[i]++; + io.MouseClickedLastCount[i]++; else - g.IO.MouseClickedLastCount[i] = 1; - g.IO.MouseClickedTime[i] = g.Time; - g.IO.MouseClickedPos[i] = g.IO.MousePos; - g.IO.MouseClickedCount[i] = g.IO.MouseClickedLastCount[i]; - g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); - g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + io.MouseClickedLastCount[i] = 1; + io.MouseClickedTime[i] = g.Time; + io.MouseClickedPos[i] = io.MousePos; + io.MouseClickedCount[i] = io.MouseClickedLastCount[i]; + io.MouseDragMaxDistanceSqr[i] = 0.0f; } - else if (g.IO.MouseDown[i]) + else if (io.MouseDown[i]) { // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold - ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); - g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); - g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); - g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); + float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f; + io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos); } // We provide io.MouseDoubleClicked[] as a legacy service - g.IO.MouseDoubleClicked[i] = (g.IO.MouseClickedCount[i] == 2); + io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation - if (g.IO.MouseClicked[i]) + if (io.MouseClicked[i]) g.NavDisableMouseHover = false; } } @@ -4085,7 +4318,7 @@ void ImGui::NewFrame() { g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingNavInputMask = 0x00; - g.ActiveIdUsingKeyInputMask = 0x00; + g.ActiveIdUsingKeyInputMask.ClearAllBits(); } // Drag and drop @@ -4100,20 +4333,17 @@ 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 - // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools - g.IO.KeyMods = GetMergedKeyModFlags(); - memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); - for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) - g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + 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(); @@ -4136,7 +4366,10 @@ void ImGui::NewFrame() g.MouseCursor = ImGuiMouseCursor_Arrow; g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; - g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + + // Platform IME data: reset for the frame + g.PlatformImeDataPrev = g.PlatformImeData; + g.PlatformImeData.WantVisible = false; // Mouse wheel scrolling, scale UpdateMouseWheel(); @@ -4332,11 +4565,10 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im static void AddDrawListToDrawData(ImVector* 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. @@ -4422,8 +4654,10 @@ static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVectorFramebufferScale = 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; } } @@ -4459,6 +4693,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(); @@ -4469,6 +4704,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 draw_list->CmdBuffer.pop_back(); draw_list->CmdBuffer.push_front(cmd); draw_list->PopClipRect(); + draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command. } } @@ -4493,6 +4729,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) @@ -4540,12 +4778,9 @@ void ImGui::EndFrame() ErrorCheckEndFrameSanityChecks(); - // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) - { - g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); - g.PlatformImeLastPos = g.PlatformImePos; - } + // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + if (g.IO.SetPlatformImeDataFn && memcmp(&g.PlatformImeData, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + g.IO.SetPlatformImeDataFn(GetMainViewport(), &g.PlatformImeData); // Hide implicit/fallback "Debug" window if it hasn't been used g.WithinFrameScopeWithImplicitWindow = false; @@ -4761,238 +4996,6 @@ static void FindHoveredWindow() g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; } -// Test if mouse cursor is hovering given rectangle -// NB- Rectangle is clipped by our current clip setting -// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) -{ - ImGuiContext& g = *GImGui; - - // Clip - ImRect rect_clipped(r_min, r_max); - if (clip) - rect_clipped.ClipWith(g.CurrentWindow->ClipRect); - - // Expand for touch input - const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); - if (!rect_for_touch.Contains(g.IO.MousePos)) - return false; - return true; -} - -int ImGui::GetKeyIndex(ImGuiKey imgui_key) -{ - IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); - ImGuiContext& g = *GImGui; - return g.IO.KeyMap[imgui_key]; -} - -// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]! -// Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]! -bool ImGui::IsKeyDown(int user_key_index) -{ - if (user_key_index < 0) - return false; - ImGuiContext& g = *GImGui; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - return g.IO.KeysDown[user_key_index]; -} - -// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) -// t1 = current time (e.g.: g.Time) -// An event is triggered at: -// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N -int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) -{ - if (t1 == 0.0f) - return 1; - if (t0 >= t1) - return 0; - if (repeat_rate <= 0.0f) - return (t0 < repeat_delay) && (t1 >= repeat_delay); - const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); - const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); - const int count = count_t1 - count_t0; - return count; -} - -int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) -{ - ImGuiContext& g = *GImGui; - if (key_index < 0) - return 0; - IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - const float t = g.IO.KeysDownDuration[key_index]; - return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); -} - -bool ImGui::IsKeyPressed(int user_key_index, bool repeat) -{ - ImGuiContext& g = *GImGui; - if (user_key_index < 0) - return false; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - const float t = g.IO.KeysDownDuration[user_key_index]; - if (t == 0.0f) - return true; - if (repeat && t > g.IO.KeyRepeatDelay) - return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; - return false; -} - -bool ImGui::IsKeyReleased(int user_key_index) -{ - ImGuiContext& g = *GImGui; - if (user_key_index < 0) return false; - IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; -} - -bool ImGui::IsMouseDown(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseDown[button]; -} - -bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - const float t = g.IO.MouseDownDuration[button]; - if (t == 0.0f) - return true; - - if (repeat && t > g.IO.KeyRepeatDelay) - { - // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. - int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); - if (amount > 0) - return true; - } - return false; -} - -bool ImGui::IsMouseReleased(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseReleased[button]; -} - -bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseClickedCount[button] == 2; -} - -int ImGui::GetMouseClickedCount(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseClickedCount[button]; -} - -// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. -// [Internal] This doesn't test if the button is pressed -bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; -} - -bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (!g.IO.MouseDown[button]) - return false; - return IsMouseDragPastThreshold(button, lock_threshold); -} - -ImVec2 ImGui::GetMousePos() -{ - ImGuiContext& g = *GImGui; - return g.IO.MousePos; -} - -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! -ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() -{ - ImGuiContext& g = *GImGui; - if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; - return g.IO.MousePos; -} - -// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. -bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) -{ - // The assert is only to silence a false-positive in XCode Static Analysis. - // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). - IM_ASSERT(GImGui != NULL); - const float MOUSE_INVALID = -256000.0f; - ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; - return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; -} - -bool ImGui::IsAnyMouseDown() -{ - ImGuiContext& g = *GImGui; - for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) - if (g.IO.MouseDown[n]) - return true; - return false; -} - -// Return the delta from the initial clicking position while the mouse button is clicked or was just released. -// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. -// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. -ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - if (lock_threshold < 0.0f) - lock_threshold = g.IO.MouseDragThreshold; - if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) - if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) - if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) - return g.IO.MousePos - g.IO.MouseClickedPos[button]; - return ImVec2(0.0f, 0.0f); -} - -void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr - g.IO.MouseClickedPos[button] = g.IO.MousePos; -} - -ImGuiMouseCursor ImGui::GetMouseCursor() -{ - return GImGui->MouseCursor; -} - -void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) -{ - GImGui->MouseCursor = cursor_type; -} - -void ImGui::CaptureKeyboardFromApp(bool capture) -{ - GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; -} - -void ImGui::CaptureMouseFromApp(bool capture) -{ - GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; -} - bool ImGui::IsItemActive() { ImGuiContext& g = *GImGui; @@ -5110,7 +5113,7 @@ void ImGui::SetActiveIdUsingNavAndKeys() IM_ASSERT(g.ActiveId != 0); g.ActiveIdUsingNavDirMask = ~(ImU32)0; g.ActiveIdUsingNavInputMask = ~(ImU32)0; - g.ActiveIdUsingKeyInputMask = ~(ImU64)0; + g.ActiveIdUsingKeyInputMask.SetAllBits(); NavMoveRequestCancel(); } @@ -5923,7 +5926,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; @@ -6085,6 +6090,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); @@ -6111,7 +6117,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--; @@ -6301,6 +6306,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } + // [Test Engine] Register whole window in the item system +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (g.TestEngineHookItems) + { + IM_ASSERT(window->IDStack.Size == 1); + window->IDStack.Size = 0; + IMGUI_TEST_ENGINE_ITEM_ADD(window->Rect(), window->ID); + IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); + window->IDStack.Size = 1; + } +#endif + // Handle manual resize: Resize Grips, Borders, Gamepad int border_held = -1; ImU32 resize_grip_col[4] = {}; @@ -6522,10 +6539,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // This is useful to allow creating context menus on title bar only, etc. SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); -#ifdef IMGUI_ENABLE_TEST_ENGINE + // [Test Engine] Register title bar / tab if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID); -#endif } else { @@ -7454,6 +7470,434 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) } +//----------------------------------------------------------------------------- +// [SECTION] INPUTS +//----------------------------------------------------------------------------- + +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; +} + +ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; + int index; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); + if (IsLegacyKey(key)) + index = (g.IO.KeyMap[key] != -1) ? g.IO.KeyMap[key] : key; // Remap native->imgui or imgui->native + else + index = key; +#else + IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); + index = key - ImGuiKey_NamedKey_BEGIN; +#endif + return &g.IO.KeysData[index]; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +int ImGui::GetKeyIndex(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(IsNamedKey(key)); + const ImGuiKeyData* key_data = GetKeyData(key); + return (int)(key_data - g.IO.KeysData); +} +#endif + +// Those names a provided for debugging purpose and are not meant to be saved persistently not compared. +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", + "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) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); +#else + if (IsLegacyKey(key)) + { + ImGuiIO& io = GetIO(); + if (io.KeyMap[key] == -1) + return "N/A"; + IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key])); + key = (ImGuiKey)io.KeyMap[key]; + } +#endif + if (key == ImGuiKey_None) + return "None"; + if (!IsNamedKey(key)) + return "Unknown"; + + return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; +} + +// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes. +// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87) +bool ImGui::IsKeyDown(ImGuiKey key) +{ + const ImGuiKeyData* key_data = GetKeyData(key); + return key_data->Down; +} + +// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) +// t1 = current time (e.g.: g.Time) +// An event is triggered at: +// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N +int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) +{ + if (t1 == 0.0f) + return 1; + if (t0 >= t1) + return 0; + if (repeat_rate <= 0.0f) + return (t0 < repeat_delay) && (t1 >= repeat_delay); + const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); + const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); + const int count = count_t1 - count_t0; + return count; +} + +int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + const ImGuiKeyData* key_data = GetKeyData(key); + const float t = key_data->DownDuration; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); +} + +bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) +{ + ImGuiContext& g = *GImGui; + const ImGuiKeyData* key_data = GetKeyData(key); + const float t = key_data->DownDuration; + if (t == 0.0f) + return true; + if (repeat && t > g.IO.KeyRepeatDelay) + return GetKeyPressedAmount(key, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + return false; +} + +bool ImGui::IsKeyReleased(ImGuiKey key) +{ + const ImGuiKeyData* key_data = GetKeyData(key); + return key_data->DownDurationPrev >= 0.0f && !key_data->Down; +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float t = g.IO.MouseDownDuration[button]; + if (t == 0.0f) + return true; + + if (repeat && t > g.IO.KeyRepeatDelay) + { + // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. + int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); + if (amount > 0) + return true; + } + return false; +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button]; +} + +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2; +} + +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button]; +} + +// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); +} + +ImVec2 ImGui::GetMousePos() +{ + ImGuiContext& g = *GImGui; + return g.IO.MousePos; +} + +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} + +// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. +bool ImGui::IsAnyMouseDown() +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} + +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + ImGuiContext& g = *GImGui; + return g.MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + ImGuiContext& g = *GImGui; + g.MouseCursor = cursor_type; +} + +void ImGui::CaptureKeyboardFromApp(bool capture) +{ + ImGuiContext& g = *GImGui; + g.WantCaptureKeyboardNextFrame = capture ? 1 : 0; +} + +void ImGui::CaptureMouseFromApp(bool capture) +{ + ImGuiContext& g = *GImGui; + g.WantCaptureMouseNextFrame = capture ? 1 : 0; +} + +static const char* GetInputSourceName(ImGuiInputSource source) +{ + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; + IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); + return input_source_names[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 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 //----------------------------------------------------------------------------- @@ -7500,12 +7944,14 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); - for (int n = 0; n < ImGuiKey_COUNT; n++) - IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)"); // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) - if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); +#endif // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) @@ -8758,7 +9204,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. @@ -8837,7 +9284,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(); @@ -8998,8 +9445,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) { @@ -9508,9 +9954,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 { @@ -9528,6 +9975,18 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() } } +const char* ImGui::GetNavInputName(ImGuiNavInput n) +{ + static const char* names[] = + { + "Activate", "Cancel", "Input", "Menu", "DpadLeft", "DpadRight", "DpadUp", "DpadDown", "LStickLeft", "LStickRight", "LStickUp", "LStickDown", + "FocusPrev", "FocusNext", "TweakSlow", "TweakFast", "KeyLeft", "KeyRight", "KeyUp", "KeyDown" + }; + IM_ASSERT(IM_ARRAYSIZE(names) == ImGuiNavInput_COUNT); + IM_ASSERT(n >= 0 && n < ImGuiNavInput_COUNT); + return names[n]; +} + float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) { ImGuiContext& g = *GImGui; @@ -9554,7 +10013,7 @@ ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput { ImVec2 delta(0.0f, 0.0f); if (dir_sources & ImGuiNavDirSourceFlags_RawKeyboard) - delta += ImVec2((float)IsKeyDown(GetKeyIndex(ImGuiKey_RightArrow)) - (float)IsKeyDown(GetKeyIndex(ImGuiKey_LeftArrow)), (float)IsKeyDown(GetKeyIndex(ImGuiKey_DownArrow)) - (float)IsKeyDown(GetKeyIndex(ImGuiKey_UpArrow))); + delta += ImVec2((float)IsKeyDown(ImGuiKey_RightArrow) - (float)IsKeyDown(ImGuiKey_LeftArrow), (float)IsKeyDown(ImGuiKey_DownArrow) - (float)IsKeyDown(ImGuiKey_UpArrow)); if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) @@ -9576,21 +10035,38 @@ 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 (nav_gamepad_active && g.IO.BackendUsingLegacyNavInputArray == false) { - 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; + 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(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0) + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(_KEY)) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0) NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); @@ -9808,7 +10284,7 @@ void ImGui::NavUpdateCreateMoveRequest() // [DEBUG] Always send a request #if IMGUI_DEBUG_NAV_SCORING - if (io.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C)) g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None) { @@ -9834,15 +10310,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) + if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded)) { - 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])) + 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\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); + 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; } } @@ -9872,7 +10354,7 @@ void ImGui::NavUpdateCreateTabbingRequest() if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs)) return; - const bool tab_pressed = IsKeyPressedMap(ImGuiKey_Tab, true) && !IsActiveIdUsingKey(ImGuiKey_Tab) && !g.IO.KeyCtrl && !g.IO.KeyAlt; + const bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, true) && !IsActiveIdUsingKey(ImGuiKey_Tab) && !g.IO.KeyCtrl && !g.IO.KeyAlt; if (!tab_pressed) return; @@ -10033,16 +10515,14 @@ static void ImGui::NavUpdateCancelRequest() static float ImGui::NavUpdatePageUpPageDown() { ImGuiContext& g = *GImGui; - ImGuiIO& io = g.IO; - ImGuiWindow* window = g.NavWindow; if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL) return 0.0f; - const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); - const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); - const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); - const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); + const bool page_up_held = IsKeyDown(ImGuiKey_PageUp) && !IsActiveIdUsingKey(ImGuiKey_PageUp); + const bool page_down_held = IsKeyDown(ImGuiKey_PageDown) && !IsActiveIdUsingKey(ImGuiKey_PageDown); + const bool home_pressed = IsKeyPressed(ImGuiKey_Home) && !IsActiveIdUsingKey(ImGuiKey_Home); + const bool end_pressed = IsKeyPressed(ImGuiKey_End) && !IsActiveIdUsingKey(ImGuiKey_End); if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out return 0.0f; @@ -10052,9 +10532,9 @@ static float ImGui::NavUpdatePageUpPageDown() if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) { // Fallback manual-scroll when window has no navigable item - if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) + if (IsKeyPressed(ImGuiKey_PageUp, true)) SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); - else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + else if (IsKeyPressed(ImGuiKey_PageDown, true)) SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); else if (home_pressed) SetScrollY(window, 0.0f); @@ -10066,14 +10546,14 @@ static float ImGui::NavUpdatePageUpPageDown() ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); float nav_scoring_rect_offset_y = 0.0f; - if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) + if (IsKeyPressed(ImGuiKey_PageUp, true)) { nav_scoring_rect_offset_y = -page_offset_y; g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) g.NavMoveClipDir = ImGuiDir_Up; g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; } - else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) + else if (IsKeyPressed(ImGuiKey_PageDown, true)) { nav_scoring_rect_offset_y = +page_offset_y; g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) @@ -10238,7 +10718,7 @@ static void ImGui::NavUpdateWindowing() // Start CTRL+Tab or Square+L/R window selection const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); - const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && io.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab); + const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && io.KeyCtrl && IsKeyPressed(ImGuiKey_Tab); if (start_windowing_with_gamepad || start_windowing_with_keyboard) if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) { @@ -10280,7 +10760,7 @@ static void ImGui::NavUpdateWindowing() { // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f - if (IsKeyPressedMap(ImGuiKey_Tab, true)) + if (IsKeyPressed(ImGuiKey_Tab, true)) NavUpdateWindowingHighlightWindow(io.KeyShift ? +1 : -1); if (!io.KeyCtrl) apply_focus_window = g.NavWindowingTarget; @@ -10622,6 +11102,7 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s } payload.DataFrameCount = g.FrameCount; + // Return whether the payload has been accepted return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); } @@ -11478,25 +11959,38 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text) #pragma comment(lib, "imm32") #endif -static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data) { // Notify OS Input Method Editor of text input position - ImGuiIO& io = ImGui::GetIO(); - if (HWND hwnd = (HWND)io.ImeWindowHandle) - if (HIMC himc = ::ImmGetContext(hwnd)) - { - COMPOSITIONFORM cf; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - cf.dwStyle = CFS_FORCE_POSITION; - ::ImmSetCompositionWindow(himc, &cf); - ::ImmReleaseContext(hwnd, himc); - } + HWND hwnd = (HWND)viewport->PlatformHandleRaw; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (hwnd == 0) + hwnd = (HWND)ImGui::GetIO().ImeWindowHandle; +#endif + if (hwnd == 0) + return; + + ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); + + if (HIMC himc = ::ImmGetContext(hwnd)) + { + COMPOSITIONFORM composition_form = {}; + composition_form.ptCurrentPos.x = (LONG)data->InputPos.x; + composition_form.ptCurrentPos.y = (LONG)data->InputPos.y; + composition_form.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &composition_form); + CANDIDATEFORM candidate_form = {}; + candidate_form.dwStyle = CFS_CANDIDATEPOS; + candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x; + candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y; + ::ImmSetCandidateWindow(himc, &candidate_form); + ::ImmReleaseContext(hwnd, himc); + } } #else -static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {} #endif @@ -11892,8 +12386,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) // Misc Details if (TreeNode("Internal state")) { - const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); - Text("WINDOWING"); Indent(); Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); @@ -11904,9 +12396,13 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("ITEMS"); Indent(); - Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); + Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource)); Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); - Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInputMask: %llX", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdUsingNavInputMask, g.ActiveIdUsingKeyInputMask); + + int active_id_using_key_input_count = 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); Unindent(); @@ -11915,7 +12411,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Indent(); Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); - Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource)); Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); Text("NavActivateFlags: %04X", g.NavActivateFlags); @@ -12424,7 +12920,7 @@ void ImGui::UpdateDebugToolItemPicker() const ImGuiID hovered_id = g.HoveredIdPreviousFrame; SetMouseCursor(ImGuiMouseCursor_Hand); - if (IsKeyPressedMap(ImGuiKey_Escape)) + if (IsKeyPressed(ImGuiKey_Escape)) g.DebugItemPickerActive = false; if (IsMouseClicked(0) && hovered_id) { diff --git a/core/src/imgui/imgui.h b/core/src/imgui/imgui.h index e986e6c0..871b75f0 100644 --- a/core/src/imgui/imgui.h +++ b/core/src/imgui/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (headers) // Help: @@ -35,6 +35,7 @@ Index of this file: // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) +// [SECTION] Platform Dependent Interfaces (ImGuiPlatformImeData) // [SECTION] Obsolete functions and types */ @@ -63,8 +64,8 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) -#define IMGUI_VERSION "1.86" -#define IMGUI_VERSION_NUM 18600 +#define IMGUI_VERSION "1.87" +#define IMGUI_VERSION_NUM 18700 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -85,11 +86,7 @@ Index of this file: #endif #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! #define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. -#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) #define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 -#else -#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. -#endif // Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. #if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) @@ -104,7 +101,7 @@ Index of this file: #endif // Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) -#if defined(_MSC_VER) && !defined(__clang__) && !defined(IMGUI_DEBUG_PARANOID) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID) #define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) #define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) #else @@ -151,9 +148,11 @@ struct ImColor; // Helper functions to create a color that c struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformImeData; // Platform IME data for io.SetPlatformImeDataFn() function. struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) struct ImGuiStorage; // Helper for key->value storage struct ImGuiStyle; // Runtime data for styling/colors @@ -171,7 +170,7 @@ typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction -typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) +typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier @@ -225,17 +224,8 @@ typedef signed short ImS16; // 16-bit signed integer typedef unsigned short ImU16; // 16-bit unsigned integer typedef signed int ImS32; // 32-bit signed integer == int typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) -#if defined(_MSC_VER) && !defined(__clang__) -typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) -typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) -#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) -#include -typedef int64_t ImS64; // 64-bit signed integer (pre C++11) -typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) -#else -typedef signed long long ImS64; // 64-bit signed integer (post C++11) -typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) -#endif +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer // Character types // (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) @@ -524,7 +514,8 @@ namespace ImGui // Widgets: Drag Sliders // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. - // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', + // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. // - Format string may also be set to NULL or use the default format ("%f" or "%d"). // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). @@ -690,6 +681,7 @@ namespace ImGui // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. + // - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) @@ -699,7 +691,7 @@ namespace ImGui // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. // - They are convenient to easily create context menus, hence the name. // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. - // - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. + // - IMPORTANT: Notice that we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). @@ -711,7 +703,6 @@ namespace ImGui IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. // Tables - // [BETA API] API may evolve slightly! If you use this, please update to the next version when it comes out! // - Full-featured replacement for old Columns API. // - See Demo->Tables for demo code. // - See top of imgui_tables.cpp for general commentary. @@ -807,7 +798,7 @@ namespace ImGui // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) // - An item can be both drag source and drop target. IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource() - IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. Return true when payload has been accepted. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. @@ -882,13 +873,16 @@ namespace ImGui IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); // Inputs Utilities: Keyboard - // - For 'int user_key_index' you can use your own indices/enums according to how your backend/engine stored them in io.KeysDown[]. - // - We don't know the meaning of those value. You can use GetKeyIndex() to map a ImGuiKey_ value into the user index. - IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] - IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. - IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate - IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down)? - IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + // Without IMGUI_DISABLE_OBSOLETE_KEYIO: (legacy support) + // - For 'ImGuiKey key' you can still use your legacy native/user indices according to how your backend/engine stored them in io.KeysDown[]. + // With IMGUI_DISABLE_OBSOLETE_KEYIO: (this is the way forward) + // - Any use of 'ImGuiKey' will assert when key < 512 will be passed, previously reserved as native/user keys indices + // - GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined) + IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. + IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? + IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. // Inputs Utilities: Mouse @@ -902,7 +896,7 @@ namespace ImGui IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available - IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? + IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) @@ -980,9 +974,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu() - - // [Obsolete] - //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by backend (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) + //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // [Obsolete] --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by backend (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) }; // Flags for ImGui::InputText() @@ -1117,8 +1109,7 @@ enum ImGuiTabItemFlags_ }; // Flags for ImGui::BeginTable() -// [BETA API] API may evolve slightly! If you use this, please update to the next version when it comes out! -// - Important! Sizing policies have complex and subtle side effects, more so than you would expect. +// - Important! Sizing policies have complex and subtle side effects, much more so than you would expect. // Read comments/demos carefully + experiment with live demos to get acquainted with them. // - The DEFAULT sizing policies are: // - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. @@ -1126,8 +1117,8 @@ enum ImGuiTabItemFlags_ // - When ScrollX is off: // - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. // - Columns sizing policy allowed: Stretch (default), Fixed/Auto. -// - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all). -// - Stretch Columns will share the remaining width. +// - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all). +// - Stretch Columns will share the remaining width according to their respective weight. // - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. // The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. // (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). @@ -1241,7 +1232,7 @@ enum ImGuiTableColumnFlags_ enum ImGuiTableRowFlags_ { ImGuiTableRowFlags_None = 0, - ImGuiTableRowFlags_Headers = 1 << 0 // Identify header row (set default background color + width of its contents accounted different for auto column width) + ImGuiTableRowFlags_Headers = 1 << 0 // Identify header row (set default background color + width of its contents accounted differently for auto column width) }; // Enum for ImGui::TableSetBgColor() @@ -1350,10 +1341,11 @@ enum ImGuiSortDirection_ ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. }; -// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array enum ImGuiKey_ { - ImGuiKey_Tab, + // Keyboard + ImGuiKey_None = 0, + ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, @@ -1368,65 +1360,148 @@ enum ImGuiKey_ ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, - ImGuiKey_KeyPadEnter, - ImGuiKey_A, // for text edit CTRL+A: select all - ImGuiKey_C, // for text edit CTRL+C: copy - ImGuiKey_V, // for text edit CTRL+V: paste - ImGuiKey_X, // for text edit CTRL+X: cut - ImGuiKey_Y, // for text edit CTRL+Y: redo - ImGuiKey_Z, // for text edit CTRL+Z: undo - ImGuiKey_COUNT + ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, + ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, + ImGuiKey_Menu, + ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, + ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J, + ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T, + ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, + ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6, + ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12, + ImGuiKey_Apostrophe, // ' + ImGuiKey_Comma, // , + ImGuiKey_Minus, // - + ImGuiKey_Period, // . + ImGuiKey_Slash, // / + ImGuiKey_Semicolon, // ; + ImGuiKey_Equal, // = + ImGuiKey_LeftBracket, // [ + ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) + ImGuiKey_RightBracket, // ] + ImGuiKey_GraveAccent, // ` + ImGuiKey_CapsLock, + ImGuiKey_ScrollLock, + ImGuiKey_NumLock, + ImGuiKey_PrintScreen, + ImGuiKey_Pause, + ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4, + ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9, + ImGuiKey_KeypadDecimal, + ImGuiKey_KeypadDivide, + ImGuiKey_KeypadMultiply, + ImGuiKey_KeypadSubtract, + ImGuiKey_KeypadAdd, + ImGuiKey_KeypadEnter, + ImGuiKey_KeypadEqual, + + // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION action + ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) // -- + ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) // -- + ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // -> ImGuiNavInput_Input + ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // -> ImGuiNavInput_Activate + ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // -> ImGuiNavInput_Menu + ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // -> ImGuiNavInput_Cancel + ImGuiKey_GamepadDpadUp, // D-pad Up // -> ImGuiNavInput_DpadUp + ImGuiKey_GamepadDpadDown, // D-pad Down // -> ImGuiNavInput_DpadDown + ImGuiKey_GamepadDpadLeft, // D-pad Left // -> ImGuiNavInput_DpadLeft + ImGuiKey_GamepadDpadRight, // D-pad Right // -> ImGuiNavInput_DpadRight + ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // -> ImGuiNavInput_FocusPrev + ImGuiNavInput_TweakSlow + ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // -> ImGuiNavInput_FocusNext + ImGuiNavInput_TweakFast + ImGuiKey_GamepadL2, // L Trigger (Xbox) ZL (Switch) L2 (PS) [Analog] + ImGuiKey_GamepadR2, // R Trigger (Xbox) ZR (Switch) R2 (PS) [Analog] + ImGuiKey_GamepadL3, // L Thumbstick (Xbox) L3 (Switch) L3 (PS) + ImGuiKey_GamepadR3, // R Thumbstick (Xbox) R3 (Switch) R3 (PS) + ImGuiKey_GamepadLStickUp, // [Analog] // -> ImGuiNavInput_LStickUp + ImGuiKey_GamepadLStickDown, // [Analog] // -> ImGuiNavInput_LStickDown + ImGuiKey_GamepadLStickLeft, // [Analog] // -> ImGuiNavInput_LStickLeft + ImGuiKey_GamepadLStickRight, // [Analog] // -> ImGuiNavInput_LStickRight + ImGuiKey_GamepadRStickUp, // [Analog] + ImGuiKey_GamepadRStickDown, // [Analog] + ImGuiKey_GamepadRStickLeft, // [Analog] + ImGuiKey_GamepadRStickRight, // [Analog] + + // Keyboard Modifiers + // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing + // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - Code polling every keys (e.g. an interface to detect a key press for input mapping) might want to ignore those + // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiKey_ModCtrl). + // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. + // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and + // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... + ImGuiKey_ModCtrl, + ImGuiKey_ModShift, + ImGuiKey_ModAlt, + ImGuiKey_ModSuper, + + ImGuiKey_COUNT, // No valid ImGuiKey is ever greater than this value + + // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + a io.KeyMap[] array. + // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) + ImGuiKey_NamedKey_BEGIN = 512, + ImGuiKey_NamedKey_END = ImGuiKey_COUNT, + ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN // First key stored in KeysData[0] +#else + ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys + ImGuiKey_KeysData_OFFSET = 0 // First key stored in KeysData[0] +#endif + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter // Renamed in 1.87 +#endif }; -// To test io.KeyMods (which is a combination of individual fields io.KeyCtrl, io.KeyShift, io.KeyAlt set by user/backend) +// Helper "flags" version of key-mods to store and compare multiple key-mods easily. Sometimes used for storage (e.g. io.KeyMods) but otherwise not much used in public API. enum ImGuiKeyModFlags_ { - ImGuiKeyModFlags_None = 0, - ImGuiKeyModFlags_Ctrl = 1 << 0, - ImGuiKeyModFlags_Shift = 1 << 1, - ImGuiKeyModFlags_Alt = 1 << 2, - ImGuiKeyModFlags_Super = 1 << 3 + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 // Cmd/Super/Windows key }; // Gamepad/Keyboard navigation -// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. +// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.AddKeyEvent() calls. // Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Backend: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). // Read instructions in imgui.cpp for more details. Download PNG/PSD at http://dearimgui.org/controls_sheets. enum ImGuiNavInput_ { // Gamepad Mapping - ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) - ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) - ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) - ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) - ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) + ImGuiNavInput_Activate, // Activate / Open / Toggle / Tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) + ImGuiNavInput_Cancel, // Cancel / Close / Exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) + ImGuiNavInput_Input, // Text input / On-Screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) + ImGuiNavInput_Menu, // Tap: Toggle menu / Hold: Focus, Move, Resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) + ImGuiNavInput_DpadLeft, // Move / Tweak / Resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) ImGuiNavInput_DpadRight, // ImGuiNavInput_DpadUp, // ImGuiNavInput_DpadDown, // - ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down + ImGuiNavInput_LStickLeft, // Scroll / Move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down ImGuiNavInput_LStickRight, // ImGuiNavInput_LStickUp, // ImGuiNavInput_LStickDown, // - ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) - ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) - ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) - ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + ImGuiNavInput_FocusPrev, // Focus Next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_FocusNext, // Focus Prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + ImGuiNavInput_TweakSlow, // Slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_TweakFast, // Faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. - // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. - ImGuiNavInput_KeyLeft_, // move left // = Arrow keys - ImGuiNavInput_KeyRight_, // move right - ImGuiNavInput_KeyUp_, // move up - ImGuiNavInput_KeyDown_, // move down - ImGuiNavInput_COUNT, - ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyLeft_ + // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from keyboard keys instead of io.NavInputs[]. + ImGuiNavInput_KeyLeft_, // Move left // = Arrow keys + ImGuiNavInput_KeyRight_, // Move right + ImGuiNavInput_KeyUp_, // Move up + ImGuiNavInput_KeyDown_, // Move down + ImGuiNavInput_COUNT }; // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { ImGuiConfigFlags_None = 0, - ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.AddKeyEvent() calls ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui backend to fill io.NavInputs[]. Backend also needs to set ImGuiBackendFlags_HasGamepad. ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. @@ -1599,9 +1674,7 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV // Obsolete names (will be removed) -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] -#endif + // ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] }; // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. @@ -1817,6 +1890,16 @@ struct ImGuiStyle // Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. //----------------------------------------------------------------------------- +// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. +// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and not io.KeysData[key]->DownDuration. +struct ImGuiKeyData +{ + bool Down; // True for if key is down + float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) + float DownDurationPrev; // Last frame duration the key has been down + float AnalogValue; // 0.0f..1.0f for gamepad values +}; + struct ImGuiIO { //------------------------------------------------------------------ @@ -1833,7 +1916,6 @@ struct ImGuiIO float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. void* UserData; // = NULL // Store your own data for retrieval by callbacks. @@ -1847,6 +1929,7 @@ struct ImGuiIO // Miscellaneous options bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) @@ -1873,31 +1956,31 @@ struct ImGuiIO // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) - void (*ImeSetInputScreenPosFn)(int x, int y); - void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. + void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + void* ImeWindowHandle; // = NULL // [Obsolete] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. +#else + void* _UnusedPadding; // Unused field to keep data structure the same size. +#endif //------------------------------------------------------------------ - // Input - Fill before calling NewFrame() + // Input - Call before calling NewFrame() //------------------------------------------------------------------ - ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) - bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. - float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. - float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends. - bool KeyCtrl; // Keyboard modifier pressed: Control - bool KeyShift; // Keyboard modifier pressed: Shift - bool KeyAlt; // Keyboard modifier pressed: Alt - bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows - bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). - float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). + // Input Functions + IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) + IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. + IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) + IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change + IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update + IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) + IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from an UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue a new characters input from an UTF-8 string - // Functions - IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input - IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate - IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string - IMGUI_API void AddFocusEvent(bool focused); // Notifies Dear ImGui when hosting platform windows lose or gain input focus - IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually - IMGUI_API void ClearInputKeys(); // [Internal] Release all keys + IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually + IMGUI_API void ClearInputKeys(); // [Internal] Release all keys + IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. //------------------------------------------------------------------ // Output - Updated by NewFrame() or EndFrame()/Render() @@ -1905,50 +1988,71 @@ struct ImGuiIO // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) //------------------------------------------------------------------ - bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). - bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). - bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). - bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. - bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! - bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. - bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). - float Framerate; // Rough estimate of application framerate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. - int MetricsRenderVertices; // Vertices output during last call to Render() - int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 - int MetricsRenderWindows; // Number of visible windows - int MetricsActiveWindows; // Number of active windows - int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. - ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Rough estimate of application framerate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. + // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. + bool KeysDown[512]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). +#endif //------------------------------------------------------------------ // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - bool WantCaptureMouseUnlessPopupClose;// Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. - ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() - ImGuiKeyModFlags KeyModsPrev; // Previous key mods - ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) - ImVec2 MouseClickedPos[5]; // Position at time of clicking - double MouseClickedTime[5]; // Time of last click (used to figure out double-click) - bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) - bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) - ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down - ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. - bool MouseReleased[5]; // Mouse button went from Down to !Down - bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. - bool MouseDownOwnedUnlessPopupClose[5];//Track if button was clicked inside a dear imgui window. - float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) - float MouseDownDurationPrev[5]; // Previous time the mouse button has been down - ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point - float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point - float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) - float KeysDownDurationPrev[512]; // Previous duration the key has been down + // Main Input State + // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) + // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. + float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends. + bool KeyCtrl; // Keyboard modifier down: Control + bool KeyShift; // Keyboard modifier down: Shift + bool KeyAlt; // Keyboard modifier down: Alt + bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows + float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). + + // Other state maintained from data above + IO function calls + ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() + ImGuiKeyModFlags KeyModsPrev; // Key mods flags (from previous frame) + 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) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down + ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownOwnedUnlessPopupClose[5]; //Track if button was clicked inside a dear imgui window. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) float NavInputsDownDuration[ImGuiNavInput_COUNT]; float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; - float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. + float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. bool AppFocusLost; - ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16 - ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. + ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] + bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. IMGUI_API ImGuiIO(); }; @@ -2283,16 +2387,16 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c #define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) // Typically, 1 command = 1 GPU draw call (unless command is a callback) -// - VtxOffset/IdxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, -// those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. -// Pre-1.71 backends will typically ignore the VtxOffset/IdxOffset fields. +// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Backends made for <1.71. will typically ignore the VtxOffset fields. // - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). struct ImDrawCmd { ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. - unsigned int IdxOffset; // 4 // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. + unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. void* UserCallbackData; // 4-8 // The draw callback code can access this. @@ -2498,8 +2602,8 @@ struct ImDrawList inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } - inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } + inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) #endif // [Internal helpers] @@ -2728,10 +2832,9 @@ struct ImFontAtlas int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + // [Obsolete] + //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ -#endif }; // Font runtime data and rendering @@ -2815,6 +2918,9 @@ struct ImGuiViewport ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + // Platform/Backend Dependent Data + void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms) + ImGuiViewport() { memset(this, 0, sizeof(*this)); } // Helpers @@ -2822,12 +2928,35 @@ struct ImGuiViewport ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } }; +//----------------------------------------------------------------------------- +// [SECTION] Platform Dependent Interfaces +//----------------------------------------------------------------------------- + +// (Optional) Support for IME (Input Method Editor) via the io.SetPlatformImeDataFn() function. +struct ImGuiPlatformImeData +{ + bool WantVisible; // A widget wants the IME to be visible + ImVec2 InputPos; // Position of the input cursor + float InputLineHeight; // Line height + + ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } +}; + //----------------------------------------------------------------------------- // [SECTION] Obsolete functions and types // (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) // Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. //----------------------------------------------------------------------------- +namespace ImGui +{ +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IMGUI_API int GetKeyIndex(ImGuiKey key); // map ImGuiKey_* values into legacy native key index. == io.KeyMap[key] +#else + static inline int GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END && "ImGuiKey and native_index was merged together and native_index is disabled by IMGUI_DISABLE_OBSOLETE_KEYIO. Please switch to ImGuiKey."); return key; } +#endif +} + #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { @@ -2858,24 +2987,21 @@ namespace ImGui static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } // OBSOLETED in 1.77 (from June 2020) static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } - // OBSOLETED in 1.72 (from April 2019) - static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } - // OBSOLETED in 1.71 (from June 2019) - static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } - // OBSOLETED in 1.70 (from May 2019) - static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) - //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) - //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) - //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) - //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) - //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) - //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) - //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } // OBSOLETED in 1.72 (from July 2019) + //static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } // OBSOLETED in 1.71 (from June 2019) + //static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.70 (from May 2019) + //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) + //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) + //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) + //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) + //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) } // OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() diff --git a/core/src/imgui/imgui_demo.cpp b/core/src/imgui/imgui_demo.cpp index 9cbc503a..72d98caa 100644 --- a/core/src/imgui/imgui_demo.cpp +++ b/core/src/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (demo code) // Help: @@ -92,6 +92,7 @@ Index of this file: // Visual Studio warnings #ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen #pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). #endif @@ -228,7 +229,6 @@ void ImGui::ShowUserGuide() ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); ImGui::BulletText("ESCAPE to revert."); - ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); ImGui::Unindent(); ImGui::BulletText("With keyboard navigation enabled:"); ImGui::Indent(); @@ -454,13 +454,15 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); ImGui::Text("<>"); } - if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + if (ImGui::IsKeyPressed(ImGuiKey_Space)) io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; } ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); + ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); + ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); - ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)"); + ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); @@ -481,6 +483,7 @@ void ImGui::ShowDemoWindow(bool* p_open) "Here we expose them as read-only fields to avoid breaking interactions with your backend."); // Make a local copy to avoid modifying actual backend flags. + // FIXME: We don't use BeginDisabled() to keep label bright, maybe we need a BeginReadonly() equivalent.. ImGuiBackendFlags backend_flags = io.BackendFlags; ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); @@ -673,10 +676,6 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); static int i0 = 123; ImGui::InputInt("input int", &i0); - ImGui::SameLine(); HelpMarker( - "You can apply arithmetic operators +,*,/ on numerical values.\n" - " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" - "Use +- to subtract."); static float f0 = 0.001f; ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); @@ -5639,6 +5638,8 @@ static void ShowDemoWindowColumns() ImGui::TreePop(); } +namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); } + static void ShowDemoWindowMisc() { IMGUI_DEMO_MARKER("Filtering"); @@ -5692,18 +5693,75 @@ static void ShowDemoWindowMisc() } // Display Keyboard/Mouse state - IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard & Navigation State"); - if (ImGui::TreeNode("Keyboard & Navigation State")) + IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard, Gamepad & Navigation State"); + if (ImGui::TreeNode("Keyboard, Gamepad & Navigation State")) { - ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyDown(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } - ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } - ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allow 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_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 = 0; +#endif + ImGui::Text("Keys down:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (%.02f secs)", ImGui::GetKeyName(key), key, ImGui::GetKeyData(key)->DownDuration); } } + ImGui::Text("Keys pressed:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { 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++) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } } 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. - ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); } ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } + // 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; + + 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); + + 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 } + }; + + 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(); + ImGui::Dummy(ImVec2(board_max.x - board_min.x, board_max.y - board_min.y)); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Capture override")) + { ImGui::Button("Hovering me sets the\nkeyboard capture flag"); if (ImGui::IsItemHovered()) ImGui::CaptureKeyboardFromApp(true); @@ -5868,6 +5926,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); #endif +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO"); +#endif #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); #endif @@ -5981,7 +6042,7 @@ void ImGui::ShowAboutWindow(bool* p_open) namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } // Demo helper function to select among loaded fonts. -// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. void ImGui::ShowFontSelector(const char* label) { ImGuiIO& io = ImGui::GetIO(); @@ -7509,8 +7570,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) // Context menu (under default mouse threshold) ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); - if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f) - ImGui::OpenPopupOnItemClick("context"); + if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f) + ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (ImGui::BeginPopup("context")) { if (adding_line) diff --git a/core/src/imgui/imgui_draw.cpp b/core/src/imgui/imgui_draw.cpp index bf1da15b..a99e6b24 100644 --- a/core/src/imgui/imgui_draw.cpp +++ b/core/src/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (drawing and font code) /* @@ -402,10 +402,9 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) void ImDrawList::_ResetForNewFrame() { // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. - // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC) - IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); - IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); - IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); CmdBuffer.resize(0); IdxBuffer.resize(0); @@ -488,9 +487,10 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) } // Compare ClipRect, TextureId and VtxOffset with a single memcmp() -#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) -#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset -#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) // Try to merge two last draw commands void ImDrawList::_TryMergeDrawCmds() @@ -498,7 +498,7 @@ void ImDrawList::_TryMergeDrawCmds() IM_ASSERT_PARANOID(CmdBuffer.Size > 0); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; ImDrawCmd* prev_cmd = curr_cmd - 1; - if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) { prev_cmd->ElemCount += curr_cmd->ElemCount; CmdBuffer.pop_back(); @@ -521,7 +521,7 @@ void ImDrawList::_OnChangedClipRect() // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) { CmdBuffer.pop_back(); return; @@ -544,7 +544,7 @@ void ImDrawList::_OnChangedTextureID() // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) { CmdBuffer.pop_back(); return; @@ -1733,13 +1733,13 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) for (int i = 1; i < _Count; i++) { ImDrawChannel& ch = _Channels[i]; - - // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback. - if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() ch._CmdBuffer.pop_back(); if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { + // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. + // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) { diff --git a/core/src/imgui/imgui_impl_opengl3.cpp b/core/src/imgui/imgui_impl_opengl3.cpp index 0ed8348d..0d3489ce 100644 --- a/core/src/imgui/imgui_impl_opengl3.cpp +++ b/core/src/imgui/imgui_impl_opengl3.cpp @@ -96,9 +96,23 @@ #include // intptr_t #endif +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif + // GL includes #if defined(IMGUI_IMPL_OPENGL_ES2) -#include +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include // Use GL ES 2 +#else +#include // Use GL ES 2 +#endif #if defined(__EMSCRIPTEN__) #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES @@ -464,7 +478,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) continue; // Apply scissor/clipping rectangle (Y is inverted in OpenGL) - glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); + glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); // Bind texture, Draw glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()); @@ -791,3 +805,7 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; } ImGui_ImplOpenGL3_DestroyFontsTexture(); } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/core/src/imgui/imgui_impl_opengl3_loader.h b/core/src/imgui/imgui_impl_opengl3_loader.h index 8452301e..e24760df 100644 --- a/core/src/imgui/imgui_impl_opengl3_loader.h +++ b/core/src/imgui/imgui_impl_opengl3_loader.h @@ -437,7 +437,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc); /* gl3w internal state */ union GL3WProcs { - GL3WglProc ptr[53]; + GL3WglProc ptr[54]; struct { PFNGLACTIVETEXTUREPROC ActiveTexture; PFNGLATTACHSHADERPROC AttachShader; diff --git a/core/src/imgui/imgui_internal.h b/core/src/imgui/imgui_internal.h index 73d58f6b..baa4a4de 100644 --- a/core/src/imgui/imgui_internal.h +++ b/core/src/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (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! @@ -18,6 +18,7 @@ Index of this file: // [SECTION] Generic helpers // [SECTION] ImDrawList support // [SECTION] Widgets support: flags, enums, data structures +// [SECTION] Inputs support // [SECTION] Clipper support // [SECTION] Navigation support // [SECTION] Columns support @@ -199,15 +200,13 @@ namespace ImStb // Debug Logging for selected systems. Remove the '((void)0) //' to enable. //#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log //#define IMGUI_DEBUG_LOG_NAV IMGUI_DEBUG_LOG // Enable log +//#define IMGUI_DEBUG_LOG_IO IMGUI_DEBUG_LOG // Enable log #define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log #define IMGUI_DEBUG_LOG_NAV(...) ((void)0) // Disable log +#define IMGUI_DEBUG_LOG_IO(...) ((void)0) // Disable log // Static Asserts -#if (__cplusplus >= 201100) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201100) #define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") -#else -#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] -#endif // "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. // We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. @@ -441,8 +440,9 @@ static inline float ImLengthSqr(const ImVec2& lhs) static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } static inline float ImFloor(float f) { return (float)(int)(f); } -static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +static inline ImVec2 ImFloorSigned(const ImVec2& v) { return ImVec2(ImFloorSigned(v.x), ImFloorSigned(v.y)); } static inline int ImModPositive(int a, int b) { return (a + b) % b; } static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } @@ -540,17 +540,18 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran // Helper: ImBitArray class (wrapper over ImBitArray functions) // Store 1-bit per value. -template -struct IMGUI_API ImBitArray +template +struct ImBitArray { ImU32 Storage[(BITCOUNT + 31) >> 5]; ImBitArray() { ClearAllBits(); } void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } - bool TestBit(int n) const { IM_ASSERT(n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } - void SetBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArraySetBit(Storage, n); } - void ClearBit(int n) { IM_ASSERT(n < BITCOUNT); ImBitArrayClearBit(Storage, n); } - void SetBitRange(int n, int n2) { ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) + bool TestBit(int n) const { IM_ASSERT(n + OFFSET < BITCOUNT); return ImBitArrayTestBit(Storage, n + OFFSET); } + void SetBit(int n) { IM_ASSERT(n + OFFSET < BITCOUNT); ImBitArraySetBit(Storage, n + OFFSET); } + void ClearBit(int n) { IM_ASSERT(n + OFFSET < BITCOUNT); ImBitArrayClearBit(Storage, n + OFFSET); } + void SetBitRange(int n, int n2) { ImBitArraySetBitRange(Storage, n + OFFSET, n2 + OFFSET); } // Works on range [n..n2) + bool operator[](int n) const { IM_ASSERT(n + OFFSET < BITCOUNT); return ImBitArrayTestBit(Storage, n + OFFSET); } }; // Helper: ImBitVector @@ -621,7 +622,7 @@ struct ImSpanAllocator // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. typedef int ImPoolIdx; template -struct IMGUI_API ImPool +struct ImPool { ImVector Buf; // Contiguous data ImGuiStorage Map; // ID->Index @@ -658,7 +659,7 @@ struct IMGUI_API ImPool // We store the chunk size first, and align the final size on 4 bytes boundaries. // The tedious/zealous amount of casting is to avoid -Wcast-align warnings. template -struct IMGUI_API ImChunkStream +struct ImChunkStream { ImVector Buf; @@ -897,28 +898,6 @@ enum ImGuiPlotType ImGuiPlotType_Histogram }; -enum ImGuiInputSource -{ - ImGuiInputSource_None = 0, - ImGuiInputSource_Mouse, - ImGuiInputSource_Keyboard, - ImGuiInputSource_Gamepad, - ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only - ImGuiInputSource_Clipboard, // Currently only used by InputText() - ImGuiInputSource_COUNT -}; - -// FIXME-NAV: Clarify/expose various repeat delay/rate -enum ImGuiInputReadMode -{ - ImGuiInputReadMode_Down, - ImGuiInputReadMode_Pressed, - ImGuiInputReadMode_Released, - ImGuiInputReadMode_Repeat, - ImGuiInputReadMode_RepeatSlow, - ImGuiInputReadMode_RepeatFast -}; - enum ImGuiPopupPositionPolicy { ImGuiPopupPositionPolicy_Default, @@ -1171,6 +1150,81 @@ struct ImGuiPtrOrIndex ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } }; +//----------------------------------------------------------------------------- +// [SECTION] Inputs support +//----------------------------------------------------------------------------- + +typedef ImBitArray ImBitArrayForNamedKeys; + +enum ImGuiKeyPrivate_ +{ + ImGuiKey_LegacyNativeKey_BEGIN = 0, + ImGuiKey_LegacyNativeKey_END = 512, + ImGuiKey_Gamepad_BEGIN = ImGuiKey_GamepadStart, + ImGuiKey_Gamepad_END = ImGuiKey_GamepadRStickRight + 1 +}; + +enum ImGuiInputEventType +{ + ImGuiInputEventType_None = 0, + ImGuiInputEventType_MousePos, + ImGuiInputEventType_MouseWheel, + ImGuiInputEventType_MouseButton, + ImGuiInputEventType_Key, + ImGuiInputEventType_Char, + ImGuiInputEventType_Focus, + ImGuiInputEventType_COUNT +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Clipboard, // Currently only used by InputText() + ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only + ImGuiInputSource_COUNT +}; + +// FIXME: Structures in the union below need to be declared as anonymous unions appears to be an extension? +// Using ImVec2() would fail on Clang 'union member 'MousePos' has a non-trivial default constructor' +struct ImGuiInputEventMousePos { float PosX, PosY; }; +struct ImGuiInputEventMouseWheel { float WheelX, WheelY; }; +struct ImGuiInputEventMouseButton { int Button; bool Down; }; +struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; }; +struct ImGuiInputEventText { unsigned int Char; }; +struct ImGuiInputEventAppFocused { bool Focused; }; + +struct ImGuiInputEvent +{ + ImGuiInputEventType Type; + ImGuiInputSource Source; + union + { + ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos + ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel + ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton + ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key + ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text + ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus + }; + bool AddedByTestEngine; + + ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } +}; + +// FIXME-NAV: Clarify/expose various repeat delay/rate +enum ImGuiInputReadMode +{ + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}; + //----------------------------------------------------------------------------- // [SECTION] Clipper support //----------------------------------------------------------------------------- @@ -1499,6 +1553,8 @@ struct ImGuiContext bool Initialized; bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; + ImVector InputEventsQueue; // Input events which will be tricked/written into IO structure. + ImVector InputEventsTrail; // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail. ImGuiStyle Style; ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. @@ -1553,7 +1609,7 @@ struct ImGuiContext bool ActiveIdUsingMouseWheel; // Active widget will want to read mouse wheel. Blocks scrolling the underlying window. ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs. - ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. + ImBitArrayForNamedKeys ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) @@ -1705,8 +1761,8 @@ struct ImGuiContext ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once // Platform support - ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor - ImVec2 PlatformImeLastPos; + ImGuiPlatformImeData PlatformImeData; // Data updated by current frame + ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point // Settings @@ -1789,7 +1845,7 @@ struct ImGuiContext ActiveIdUsingMouseWheel = false; ActiveIdUsingNavDirMask = 0x00; ActiveIdUsingNavInputMask = 0x00; - ActiveIdUsingKeyInputMask = 0x00; + ActiveIdUsingKeyInputMask.ClearAllBits(); ActiveIdClickOffset = ImVec2(-1, -1); ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; @@ -1870,7 +1926,8 @@ struct ImGuiContext TooltipOverrideCount = 0; TooltipSlowDelay = 0.50f; - PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); + PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission PlatformLocaleDecimalPoint = '.'; SettingsLoaded = false; @@ -2284,7 +2341,7 @@ struct IMGUI_API ImGuiTable ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is ImRect WorkRect; ImRect InnerClipRect; - ImRect BgClipRect; // We use this to cpu-clip cell background color fill + ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. @@ -2453,6 +2510,7 @@ namespace ImGui IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). // NewFrame + IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); IMGUI_API void UpdateMouseMovingWindowNewFrame(); @@ -2573,6 +2631,7 @@ namespace ImGui IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API const char* GetNavInputName(ImGuiNavInput n); IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); @@ -2589,16 +2648,23 @@ 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 IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } + inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } + IMGUI_API ImGuiKeyData* GetKeyData(ImGuiKey key); IMGUI_API void SetItemUsingMouseWheel(); IMGUI_API void SetActiveIdUsingNavAndKeys(); inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } - inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } + inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; return g.ActiveIdUsingKeyInputMask[key]; } + inline void SetActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; g.ActiveIdUsingKeyInputMask.SetBit(key); } IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); - inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags(); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } +#endif // Drag and Drop IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); @@ -2750,7 +2816,7 @@ namespace ImGui IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); - IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format); IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); @@ -2815,7 +2881,9 @@ struct ImFontBuilderIO }; // Helper for font builder +#ifdef IMGUI_ENABLE_STB_TRUETYPE IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +#endif IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); @@ -2839,7 +2907,8 @@ extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiI #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) #define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #else -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0) +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) #endif //----------------------------------------------------------------------------- diff --git a/core/src/imgui/imgui_tables.cpp b/core/src/imgui/imgui_tables.cpp index 8a3fe93c..27f1d538 100644 --- a/core/src/imgui/imgui_tables.cpp +++ b/core/src/imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (tables and columns code) /* @@ -1569,18 +1569,21 @@ ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) // Return the cell rectangle based on currently known height. // - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. -// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height. // - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right // columns report a small offset so their CellBgRect can extend up to the outer border. +// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling. ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) { const ImGuiTableColumn* column = &table->Columns[column_n]; float x1 = column->MinX; float x2 = column->MaxX; - if (column->PrevEnabledColumn == -1) - x1 -= table->CellSpacingX1; - if (column->NextEnabledColumn == -1) - x2 += table->CellSpacingX2; + //if (column->PrevEnabledColumn == -1) + // x1 -= table->OuterPaddingX; + //if (column->NextEnabledColumn == -1) + // x2 += table->OuterPaddingX; + x1 = ImMax(x1, table->WorkRect.Min.x); + x2 = ImMin(x2, table->WorkRect.Max.x); return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); } @@ -1797,10 +1800,12 @@ void ImGui::TableEndRow(ImGuiTable* table) ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) { + // As we render the BG here we need to clip things (for layout we would not) + // FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling. const ImGuiTableColumn* column = &table->Columns[cell_data->Column]; ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); cell_bg_rect.ClipWith(table->BgClipRect); - cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped + cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); } @@ -2353,7 +2358,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) // Don't attempt to merge if there are multiple draw calls within the column ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; - if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0) + if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback != NULL) // Equivalent of PopUnusedDrawCmd() src_channel->_CmdBuffer.pop_back(); if (src_channel->_CmdBuffer.Size != 1) continue; diff --git a/core/src/imgui/imgui_widgets.cpp b/core/src/imgui/imgui_widgets.cpp index f199ad40..56723cdd 100644 --- a/core/src/imgui/imgui_widgets.cpp +++ b/core/src/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.86 +// dear imgui, v1.87 // (widgets code) /* @@ -731,6 +731,7 @@ bool ImGui::SmallButton(const char* label) // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; @@ -748,16 +749,17 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; } bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - ImGuiContext& g = *GImGui; const ImGuiID id = window->GetID(str_id); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); const float default_size = GetFrameHeight(); @@ -778,6 +780,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; } @@ -1992,24 +1995,10 @@ void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const // User can input math operators (e.g. +100) to edit a numerical values. // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. -bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) +bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format) { while (ImCharIsBlankA(*buf)) buf++; - - // We don't support '-' op because it would conflict with inputing negative value. - // Instead you can use +-100 to subtract from an existing value - char op = buf[0]; - if (op == '+' || op == '*' || op == '/') - { - buf++; - while (ImCharIsBlankA(*buf)) - buf++; - } - else - { - op = 0; - } if (!buf[0]) return false; @@ -2021,54 +2010,11 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b if (format == NULL) format = type_info->ScanFmt; - // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. - int arg1i = 0; - if (data_type == ImGuiDataType_S32) + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64 || data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) { - int* v = (int*)p_data; - int arg0i = *v; - float arg1f = 0.0f; - if (op && sscanf(initial_value_buf, format, &arg0i) < 1) - return false; - // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision - if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) - else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply - else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide - else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant - } - else if (data_type == ImGuiDataType_Float) - { - // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in - format = "%f"; - float* v = (float*)p_data; - float arg0f = *v, arg1f = 0.0f; - if (op && sscanf(initial_value_buf, format, &arg0f) < 1) - return false; - if (sscanf(buf, format, &arg1f) < 1) - return false; - if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) - else if (op == '*') { *v = arg0f * arg1f; } // Multiply - else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide - else { *v = arg1f; } // Assign constant - } - else if (data_type == ImGuiDataType_Double) - { - format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis - double* v = (double*)p_data; - double arg0f = *v, arg1f = 0.0; - if (op && sscanf(initial_value_buf, format, &arg0f) < 1) - return false; - if (sscanf(buf, format, &arg1f) < 1) - return false; - if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) - else if (op == '*') { *v = arg0f * arg1f; } // Multiply - else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide - else { *v = arg1f; } // Assign constant - } - else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) - { - // All other types assign constant - // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. + // For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + format = type_info->ScanFmt; if (sscanf(buf, format, p_data) < 1) return false; } @@ -3387,8 +3333,6 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* // However this may not be ideal for all uses, as some user code may break on out of bound values. bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) { - ImGuiContext& g = *GImGui; - char fmt_buf[32]; char data_buf[32]; format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); @@ -3406,7 +3350,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG memcpy(&data_backup, p_data, data_type_size); // Apply new value (or operations) then clamp - DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); + DataTypeApplyFromText(data_buf, data_type, p_data, NULL); if (p_clamp_min || p_clamp_max) { if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) @@ -3453,7 +3397,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PushID(label); SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; @@ -3490,7 +3434,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data else { if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); } if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -4117,11 +4061,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End); + SetActiveIdUsingKey(ImGuiKey_Home); + SetActiveIdUsingKey(ImGuiKey_End); if (is_multiline) - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); - if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. - g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); + { + SetActiveIdUsingKey(ImGuiKey_PageUp); + SetActiveIdUsingKey(ImGuiKey_PageDown); + } + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. + { + SetActiveIdUsingKey(ImGuiKey_Tab); + } } // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) @@ -4251,7 +4201,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // It is ill-defined whether the backend needs to send a \t character when pressing the TAB keys. // Win32 and GLFW naturally do it but not SDL. const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); - if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressed(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) if (!io.InputQueueCharacters.contains('\t')) { unsigned int c = '\t'; // Insert TAB @@ -4298,27 +4248,27 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); - const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); - const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); - const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; - const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); - const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; + const bool is_cut = ((is_shortcut_key && IsKeyPressed(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressed(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = ((is_shortcut_key && IsKeyPressed(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = ((is_shortcut_key && IsKeyPressed(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_readonly; + const bool is_undo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Z)) && !is_readonly && is_undoable); + const bool is_redo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressed(ImGuiKey_Z))) && !is_readonly && is_undoable; // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. - const bool is_validate_enter = IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter); - const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed) && !IsKeyPressedMap(ImGuiKey_Space)) || IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); - const bool is_cancel = IsKeyPressedMap(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); + const bool is_validate_enter = IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_KeypadEnter); + const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed) && !IsKeyPressed(ImGuiKey_Space)) || IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); + const bool is_cancel = IsKeyPressed(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); - if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } - else if (IsKeyPressedMap(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } - else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) + if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } + else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) { if (!state->HasSelection()) { @@ -4357,7 +4307,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); state->ClearSelection(); } - else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + else if (is_shortcut_key && IsKeyPressed(ImGuiKey_A)) { state->SelectAll(); state->CursorFollow = true; @@ -4463,18 +4413,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. ImGuiInputTextFlags event_flag = 0; - ImGuiKey event_key = ImGuiKey_COUNT; - if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + ImGuiKey event_key = ImGuiKey_None; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressed(ImGuiKey_Tab)) { event_flag = ImGuiInputTextFlags_CallbackCompletion; event_key = ImGuiKey_Tab; } - else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow)) { event_flag = ImGuiInputTextFlags_CallbackHistory; event_key = ImGuiKey_UpArrow; } - else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow)) { event_flag = ImGuiInputTextFlags_CallbackHistory; event_key = ImGuiKey_DownArrow; @@ -4760,7 +4710,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (!is_readonly) - g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + { + g.PlatformImeData.WantVisible = true; + g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + g.PlatformImeData.InputLineHeight = g.FontSize; + } } } else @@ -4973,7 +4927,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } } else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) @@ -5001,7 +4955,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } ImGuiWindow* picker_active_window = NULL; @@ -5018,11 +4972,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Store current color and open a picker g.ColorPickerRef = col_v4; OpenPopup("picker"); - SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(-1, style.ItemSpacing.y)); + SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(0.0f, style.ItemSpacing.y)); } } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); if (BeginPopup("picker")) { @@ -5236,7 +5190,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); } else if (flags & ImGuiColorEditFlags_PickerHueBar) { @@ -5253,7 +5207,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl value_changed = value_changed_sv = true; } if (!(flags & ImGuiColorEditFlags_NoOptions)) - OpenPopupOnItemClick("context"); + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); // Hue bar logic SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); @@ -6934,6 +6888,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) BeginDisabled(); const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; bool pressed; + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { // Menu inside an horizontal menu bar @@ -6944,7 +6899,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); float w = label_size.x; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups, ImVec2(w, 0.0f)); + pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, 0.0f)); RenderText(text_pos, label); PopStyleVar(); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). @@ -6960,7 +6915,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); + pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); diff --git a/core/src/signal_path/sink.cpp b/core/src/signal_path/sink.cpp index 5435d2f9..729f60ad 100644 --- a/core/src/signal_path/sink.cpp +++ b/core/src/signal_path/sink.cpp @@ -342,7 +342,7 @@ void SinkManager::loadSinksFromConfig() { } void SinkManager::showMenu() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; int count = 0; int maxCount = streams.size(); diff --git a/decoder_modules/falcon9_decoder/src/main.cpp b/decoder_modules/falcon9_decoder/src/main.cpp index 151ac351..f7f4f1e3 100644 --- a/decoder_modules/falcon9_decoder/src/main.cpp +++ b/decoder_modules/falcon9_decoder/src/main.cpp @@ -131,7 +131,7 @@ private: static void menuHandler(void* ctx) { Falcon9DecoderModule* _this = (Falcon9DecoderModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; if (!_this->enabled) { style::beginDisabled(); } diff --git a/decoder_modules/m17_decoder/src/main.cpp b/decoder_modules/m17_decoder/src/main.cpp index ca4fd84f..068a2184 100644 --- a/decoder_modules/m17_decoder/src/main.cpp +++ b/decoder_modules/m17_decoder/src/main.cpp @@ -141,7 +141,7 @@ private: static void menuHandler(void* ctx) { M17DecoderModule* _this = (M17DecoderModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; if (!_this->enabled) { style::beginDisabled(); } diff --git a/decoder_modules/meteor_demodulator/src/main.cpp b/decoder_modules/meteor_demodulator/src/main.cpp index 559a46f1..1f675880 100644 --- a/decoder_modules/meteor_demodulator/src/main.cpp +++ b/decoder_modules/meteor_demodulator/src/main.cpp @@ -130,7 +130,7 @@ private: static void menuHandler(void* ctx) { MeteorDemodulatorModule* _this = (MeteorDemodulatorModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; if (!_this->enabled) { style::beginDisabled(); } diff --git a/decoder_modules/radio/src/radio_module.h b/decoder_modules/radio/src/radio_module.h index f1a57f38..30a34e3e 100644 --- a/decoder_modules/radio/src/radio_module.h +++ b/decoder_modules/radio/src/radio_module.h @@ -204,7 +204,7 @@ private: if (!_this->enabled) { style::beginDisabled(); } - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::BeginGroup(); ImGui::Columns(4, CONCAT("RadioModeColumns##_", _this->name), false); diff --git a/decoder_modules/weather_sat_decoder/src/main.cpp b/decoder_modules/weather_sat_decoder/src/main.cpp index 193268f6..e83f868d 100644 --- a/decoder_modules/weather_sat_decoder/src/main.cpp +++ b/decoder_modules/weather_sat_decoder/src/main.cpp @@ -102,7 +102,7 @@ private: static void menuHandler(void* ctx) { WeatherSatDecoderModule* _this = (WeatherSatDecoderModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; if (!_this->enabled) { style::beginDisabled(); } diff --git a/decoder_modules/weather_sat_decoder/src/noaa_hrpt_decoder.h b/decoder_modules/weather_sat_decoder/src/noaa_hrpt_decoder.h index 8584f9f1..a30edb25 100644 --- a/decoder_modules/weather_sat_decoder/src/noaa_hrpt_decoder.h +++ b/decoder_modules/weather_sat_decoder/src/noaa_hrpt_decoder.h @@ -220,7 +220,7 @@ public: if (ImGui::BeginTabItem("AVHRR RGB(221)")) { ImGui::BeginChild("AVHRRRGBChild"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrrRGBImage.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); @@ -229,7 +229,7 @@ public: if (ImGui::BeginTabItem("AVHRR 1")) { ImGui::BeginChild("AVHRR1Child"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrr1Image.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); @@ -238,7 +238,7 @@ public: if (ImGui::BeginTabItem("AVHRR 2")) { ImGui::BeginChild("AVHRR2Child"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrr2Image.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); @@ -247,7 +247,7 @@ public: if (ImGui::BeginTabItem("AVHRR 3")) { ImGui::BeginChild("AVHRR3Child"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrr3Image.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); @@ -256,7 +256,7 @@ public: if (ImGui::BeginTabItem("AVHRR 4")) { ImGui::BeginChild("AVHRR4Child"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrr4Image.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); @@ -265,7 +265,7 @@ public: if (ImGui::BeginTabItem("AVHRR 5")) { ImGui::BeginChild("AVHRR5Child"); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); avhrr5Image.draw(); ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); diff --git a/misc_modules/frequency_manager/src/main.cpp b/misc_modules/frequency_manager/src/main.cpp index 43274c02..98dcd5e8 100644 --- a/misc_modules/frequency_manager/src/main.cpp +++ b/misc_modules/frequency_manager/src/main.cpp @@ -13,7 +13,6 @@ #include #include #include -#include SDRPP_MOD_INFO{ /* Name: */ "frequency_manager", @@ -197,7 +196,7 @@ private: bool open = true; gui::mainWindow.lockWaterfallControls = true; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; std::string id = "New##freq_manager_new_popup_" + name; ImGui::OpenPopup(id.c_str()); @@ -245,7 +244,7 @@ private: bool selectListsDialog() { gui::mainWindow.lockWaterfallControls = true; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; std::string id = "Select lists##freq_manager_sel_popup_" + name; ImGui::OpenPopup(id.c_str()); @@ -349,7 +348,7 @@ private: static void menuHandler(void* ctx) { FrequencyManagerModule* _this = (FrequencyManagerModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; // TODO: Replace with something that won't iterate every frame std::vector selectedNames; @@ -422,7 +421,7 @@ private: ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - if (ImGui::Button(("Add##_freq_mgr_add_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { + if (ImGui::Button(("Add##_freq_mgr_add_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) { // If there's no VFO selected, just save the center freq if (gui::waterfall.selectedVFO == "") { _this->editedBookmark.frequency = gui::waterfall.getCenterFrequency(); @@ -460,13 +459,13 @@ private: ImGui::TableSetColumnIndex(1); if (selectedNames.size() == 0 && _this->selectedListName != "") { style::beginDisabled(); } - if (ImGui::Button(("Remove##_freq_mgr_rem_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { + if (ImGui::Button(("Remove##_freq_mgr_rem_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) { _this->deleteBookmarksOpen = true; } if (selectedNames.size() == 0 && _this->selectedListName != "") { style::endDisabled(); } ImGui::TableSetColumnIndex(2); if (selectedNames.size() != 1 && _this->selectedListName != "") { style::beginDisabled(); } - if (ImGui::Button(("Edit##_freq_mgr_edt_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0))) { + if (ImGui::Button(("Edit##_freq_mgr_edt_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) { _this->editOpen = true; _this->editedBookmark = _this->bookmarks[selectedNames[0]]; _this->editedBookmarkName = selectedNames[0]; @@ -498,8 +497,7 @@ private: if (ImGui::Selectable((name + "##_freq_mgr_bkm_name_" + _this->name).c_str(), &bm.selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) { // if shift or control isn't pressed, deselect all others - if (!ImGui::IsKeyDown(KB_KEY_LSHIFT) && !ImGui::IsKeyDown(KB_KEY_RSHIFT) && - !ImGui::IsKeyDown(KB_KEY_LCTRL) && !ImGui::IsKeyDown(KB_KEY_RCTRL)) { + if (!ImGui::GetIO().KeyShift && !ImGui::GetIO().KeyCtrl) { for (auto& [_name, _bm] : _this->bookmarks) { if (name == _name) { continue; } _bm.selected = false; @@ -531,14 +529,14 @@ private: ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - if (ImGui::Button(("Import##_freq_mgr_imp_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0)) && !_this->importOpen) { + if (ImGui::Button(("Import##_freq_mgr_imp_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)) && !_this->importOpen) { _this->importOpen = true; _this->importDialog = new pfd::open_file("Import bookmarks", "", { "JSON Files (*.json)", "*.json", "All Files", "*" }, true); } ImGui::TableSetColumnIndex(1); if (selectedNames.size() == 0 && _this->selectedListName != "") { style::beginDisabled(); } - if (ImGui::Button(("Export##_freq_mgr_exp_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvailWidth(), 0)) && !_this->exportOpen) { + if (ImGui::Button(("Export##_freq_mgr_exp_" + _this->name).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)) && !_this->exportOpen) { _this->exportedBookmarks = json::object(); config.acquire(); for (auto& _name : selectedNames) { diff --git a/misc_modules/recorder/src/main.cpp b/misc_modules/recorder/src/main.cpp index ddbcecd4..4684e6cc 100644 --- a/misc_modules/recorder/src/main.cpp +++ b/misc_modules/recorder/src/main.cpp @@ -193,7 +193,7 @@ private: static void menuHandler(void* ctx) { RecorderModule* _this = (RecorderModule*)ctx; - float menuColumnWidth = ImGui::GetContentRegionAvailWidth(); + float menuColumnWidth = ImGui::GetContentRegionAvail().x; // Recording mode if (_this->recording) { style::beginDisabled(); } diff --git a/misc_modules/rigctl_server/src/main.cpp b/misc_modules/rigctl_server/src/main.cpp index 87315596..504e86d0 100644 --- a/misc_modules/rigctl_server/src/main.cpp +++ b/misc_modules/rigctl_server/src/main.cpp @@ -107,7 +107,7 @@ public: private: static void menuHandler(void* ctx) { SigctlServerModule* _this = (SigctlServerModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; bool listening = (_this->listener && _this->listener->isListening()); diff --git a/misc_modules/scheduler/src/main.cpp b/misc_modules/scheduler/src/main.cpp index 4dea23b6..015b00eb 100644 --- a/misc_modules/scheduler/src/main.cpp +++ b/misc_modules/scheduler/src/main.cpp @@ -3,7 +3,6 @@ #include #include #include -#include SDRPP_MOD_INFO{ /* Name: */ "scheduler", @@ -101,8 +100,7 @@ private: if (ImGui::Selectable((name + "##_freq_mgr_bkm_name_" + _this->name).c_str(), &bm.selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) { // if shift or control isn't pressed, deselect all others - if (!ImGui::IsKeyDown(KB_KEY_LSHIFT) && !ImGui::IsKeyDown(KB_KEY_RSHIFT) && - !ImGui::IsKeyDown(KB_KEY_LCTRL) && !ImGui::IsKeyDown(KB_KEY_RCTRL)) { + if (!ImGui::GetIO().KeyShift && !ImGui::GetIO().KeyCtrl) { for (auto& [_name, _bm] : _this->tasks) { if (name == _name) { continue; } _bm.selected = false; diff --git a/misc_modules/scheduler/src/sched_task.h b/misc_modules/scheduler/src/sched_task.h index 25bffc9f..df50772c 100644 --- a/misc_modules/scheduler/src/sched_task.h +++ b/misc_modules/scheduler/src/sched_task.h @@ -3,7 +3,6 @@ #include #include #include -#include class Task { public: @@ -78,8 +77,7 @@ public: if (ImGui::Selectable((act->getName() + "##scheduler_task_actions_entry").c_str(), &act->selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) { // if shift or control isn't pressed, deselect all others - if (!ImGui::IsKeyDown(KB_KEY_LSHIFT) && !ImGui::IsKeyDown(KB_KEY_RSHIFT) && - !ImGui::IsKeyDown(KB_KEY_LCTRL) && !ImGui::IsKeyDown(KB_KEY_RCTRL)) { + if (!ImGui::GetIO().KeyShift && !ImGui::GetIO().KeyCtrl) { int _id = 0; for (auto& _act : actions) { if (_id == id) { continue; } diff --git a/sink_modules/audio_sink/src/main.cpp b/sink_modules/audio_sink/src/main.cpp index fff558cf..257cf4c2 100644 --- a/sink_modules/audio_sink/src/main.cpp +++ b/sink_modules/audio_sink/src/main.cpp @@ -132,7 +132,7 @@ public: } void menuHandler() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(menuWidth); if (ImGui::Combo(("##_audio_sink_dev_" + _streamName).c_str(), &devId, txtDevList.c_str())) { diff --git a/sink_modules/network_sink/src/main.cpp b/sink_modules/network_sink/src/main.cpp index d714bc78..f642afc8 100644 --- a/sink_modules/network_sink/src/main.cpp +++ b/sink_modules/network_sink/src/main.cpp @@ -122,7 +122,7 @@ public: } void menuHandler() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; bool listening = (listener && listener->isListening()) || (conn && conn->isOpen()); diff --git a/sink_modules/new_portaudio_sink/src/main.cpp b/sink_modules/new_portaudio_sink/src/main.cpp index ca7252d2..864df852 100644 --- a/sink_modules/new_portaudio_sink/src/main.cpp +++ b/sink_modules/new_portaudio_sink/src/main.cpp @@ -137,7 +137,7 @@ public: } void menuHandler() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; // Select device ImGui::SetNextItemWidth(menuWidth); diff --git a/sink_modules/portaudio_sink/src/main.cpp b/sink_modules/portaudio_sink/src/main.cpp index 508286a4..a0835b6f 100644 --- a/sink_modules/portaudio_sink/src/main.cpp +++ b/sink_modules/portaudio_sink/src/main.cpp @@ -116,7 +116,7 @@ public: } void menuHandler() { - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(menuWidth); if (ImGui::Combo(("##_audio_sink_dev_" + _streamName).c_str(), &devListId, txtDevList.c_str())) { diff --git a/source_modules/sddc_source/src/main.cpp b/source_modules/sddc_source/src/main.cpp index b0499111..142b3a3d 100644 --- a/source_modules/sddc_source/src/main.cpp +++ b/source_modules/sddc_source/src/main.cpp @@ -179,7 +179,7 @@ private: static void menuHandler(void* ctx) { AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; if (_this->running) { style::beginDisabled(); } diff --git a/source_modules/sdrpp_server_source/src/main.cpp b/source_modules/sdrpp_server_source/src/main.cpp index 7a6f3214..d7a737f2 100644 --- a/source_modules/sdrpp_server_source/src/main.cpp +++ b/source_modules/sdrpp_server_source/src/main.cpp @@ -141,7 +141,7 @@ private: static void menuHandler(void* ctx) { SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; - float menuWidth = ImGui::GetContentRegionAvailWidth(); + float menuWidth = ImGui::GetContentRegionAvail().x; bool connected = (_this->client && _this->client->isOpen()); gui::mainWindow.playButtonLocked = !connected;