From dcff032429c3afbca0d59e3ed68c37b60f1328a4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Aug 2016 23:23:04 +0200 Subject: [PATCH] Nav: Moving all nav inputs to io.NavInputs[] float array, new enum labelled for gamepad. (#323) --- imgui.cpp | 188 ++++++++++++++++++++++++++--------------------- imgui.h | 50 +++++++------ imgui_demo.cpp | 3 + imgui_internal.h | 3 +- 4 files changed, 136 insertions(+), 108 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2efa6f899..52cab7054 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -873,10 +873,9 @@ ImGuiIO::ImGuiIO() MousePos = ImVec2(-1,-1); MousePosPrev = ImVec2(-1,-1); 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(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(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; // Set OS X style defaults based on __APPLE__ compile time flag #ifdef __APPLE__ @@ -2378,6 +2377,60 @@ static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIX return NULL; } +enum ImGuiNavReadMode +{ + ImGuiNavReadMode_Down, + ImGuiNavReadMode_Pressed, + ImGuiNavReadMode_Repeat, + ImGuiNavReadMode_RepeatSlow, + ImGuiNavReadMode_RepeatFast +}; + +// FIXME-NAVIGATION: Expose navigation repeat delay/rate +static float GetNavInputAmount(ImGuiNavInput n, ImGuiNavReadMode mode) +{ + ImGuiContext& g = *GImGui; + if (mode == ImGuiNavReadMode_Down) + return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) + const float t = g.IO.NavInputsDownDuration[n]; // Duration pressed + if (mode == ImGuiNavReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input (we don't need it for Pressed logic) + return (t == 0.0f) ? 1.0f : 0.0f; + if (mode == ImGuiNavReadMode_Repeat) + return (float)ImGui::CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f); + if (mode == ImGuiNavReadMode_RepeatSlow) + return (float)ImGui::CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f); + if (mode == ImGuiNavReadMode_RepeatFast) + return (float)ImGui::CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f); + return 0.0f; +} + +// Equivalent of IsKeyDown() for NavInputs[] +static bool IsNavInputDown(ImGuiNavInput n) +{ + return GImGui->IO.NavInputs[n] > 0.0f; +} + +// Equivalent of IsKeyPressed() for NavInputs[] +static bool IsNavInputPressed(ImGuiNavInput n, ImGuiNavReadMode mode)// = ImGuiNavReadMode_Re) +{ + return GetNavInputAmount(n, mode) > 0.0f; +} + +static ImVec2 GetNavInputAmount2d(int stick_no, ImGuiNavReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f) +{ + IM_ASSERT(ImGuiNavInput_PadScrollUp == ImGuiNavInput_PadUp + 4); + IM_ASSERT(stick_no >= 0 && stick_no < 2); + + ImVec2 delta; + delta.x = GetNavInputAmount(ImGuiNavInput_PadRight + stick_no*4, mode) - GetNavInputAmount(ImGuiNavInput_PadLeft + stick_no*4, mode); + delta.y = GetNavInputAmount(ImGuiNavInput_PadDown + stick_no*4, mode) - GetNavInputAmount(ImGuiNavInput_PadUp + stick_no*4, mode); + if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_PadTweakSlow)) + delta *= slow_factor; + if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_PadTweakFast)) + delta *= fast_factor; + return delta; +} + static void NavUpdate() { ImGuiContext& g = *GImGui; @@ -2452,7 +2505,7 @@ static void NavUpdate() } // Navigation windowing mode (change focus, move/resize window) - if (!g.NavWindowingTarget && IsKeyPressedMap(ImGuiKey_NavMenu, false)) + if (!g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_PadMenu, ImGuiNavReadMode_Pressed)) { ImGuiWindow* window = g.NavWindow; if (!window) @@ -2467,13 +2520,13 @@ static void NavUpdate() if (g.NavWindowingTarget) { // Visuals only appears after a brief time holding the button, so that a fast tap (to toggle NavLayer) doesn't add visual noise - const float pressed_duration = g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_NavMenu]]; + const float pressed_duration = g.IO.NavInputsDownDuration[ImGuiNavInput_PadMenu]; g.NavWindowingDisplayAlpha = ImMax(g.NavWindowingDisplayAlpha, ImSaturate((pressed_duration - 0.20f) / 0.05f)); g.NavWindowingToggleLayer &= (g.NavWindowingDisplayAlpha < 1.0f); // Once button is held long enough we don't consider it a tag-to-toggle-layer press anymore. // Select window to focus // FIXME-NAVIGATION: Need to clarify input semantic, naming is misleading/incorrect here. - int focus_change_dir = IsKeyPressedMap(ImGuiKey_NavTweakFaster, true) ? -1 : IsKeyPressedMap(ImGuiKey_NavTweakSlower, true) ? +1 : 0; + const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_PadFocusPrev, ImGuiNavReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_PadFocusNext, ImGuiNavReadMode_RepeatSlow); if (focus_change_dir != 0 && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)) { const int i_current = FindWindowIndex(g.NavWindowingTarget); @@ -2488,7 +2541,7 @@ static void NavUpdate() // Move window if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) { - const ImVec2 move_delta = ImGui::NavGetMovingDir(1); + const ImVec2 move_delta = GetNavInputAmount2d(1, ImGuiNavReadMode_Down); if (move_delta.x != 0.0f || move_delta.y != 0.0f) { const float move_speed = ImFloor(600 * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); @@ -2498,7 +2551,7 @@ static void NavUpdate() } } - if (!IsKeyDownMap(ImGuiKey_NavMenu)) + if (!IsNavInputDown(ImGuiNavInput_PadMenu)) { // Apply actual focus only when releasing the NavMenu button (until then the window was merely rendered front-most) if (g.NavWindowingTarget && !g.NavWindowingToggleLayer && (!g.NavWindow || g.NavWindowingTarget != g.NavWindow->RootNonPopupWindow)) @@ -2532,7 +2585,7 @@ static void NavUpdate() g.IO.NavActive = (g.IO.NavUsable && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitDefaultRequest; // Process NavCancel input (to close a popup, get back to parent, clear focus) - if (IsKeyPressedMap(ImGuiKey_NavCancel)) + if (IsNavInputPressed(ImGuiNavInput_PadCancel, ImGuiNavReadMode_Pressed)) { if (g.ActiveId != 0) { @@ -2577,8 +2630,8 @@ static void NavUpdate() } } - g.NavActivateId = (g.NavId && !g.NavDisableHighlight && !g.NavWindowingTarget && g.ActiveId == 0 && IsKeyPressedMap(ImGuiKey_NavActivate)) ? g.NavId : 0; - g.NavInputId = (g.NavId && !g.NavDisableHighlight && !g.NavWindowingTarget && g.ActiveId == 0 && IsKeyPressedMap(ImGuiKey_NavInput)) ? g.NavId : 0; + g.NavActivateId = (g.NavId && !g.NavDisableHighlight && !g.NavWindowingTarget && g.ActiveId == 0 && IsNavInputPressed(ImGuiNavInput_PadActivate, ImGuiNavReadMode_Repeat)) ? g.NavId : 0; + g.NavInputId = (g.NavId && !g.NavDisableHighlight && !g.NavWindowingTarget && g.ActiveId == 0 && IsNavInputPressed(ImGuiNavInput_PadInput, ImGuiNavReadMode_Repeat)) ? g.NavId : 0; if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { g.NavActivateId = g.NavInputId = 0; @@ -2591,10 +2644,10 @@ static void NavUpdate() g.NavMoveDir = ImGuiNavDir_None; if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { - if ((allowed_dir_flags & (1<Scroll.y + ((g.NavMoveDir == ImGuiNavDir_Up) ? -1.0f : +1.0f) * scroll_speed)); // Manual scroll with NavScrollXXX keys - ImVec2 scroll_dir = ImGui::NavGetMovingDir(1, 1.0f/10.0f, 10.0f); + ImVec2 scroll_dir = GetNavInputAmount2d(1, ImGuiNavReadMode_Down, 1.0f/10.0f, 10.0f); if (scroll_dir.x != 0.0f && g.NavWindow->ScrollbarX) { SetWindowScrollX(g.NavWindow, ImFloor(g.NavWindow->Scroll.x + scroll_dir.x * scroll_speed)); @@ -2695,6 +2748,9 @@ void ImGui::NewFrame() 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; + memcpy(g.IO.NavInputsPrev, g.IO.NavInputs, sizeof(g.IO.NavInputs)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) + g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; // Update directional navigation which may override MousePos if 'NavMovesMouse=true' NavUpdate(); @@ -3708,20 +3764,23 @@ bool ImGui::IsKeyDown(int key_index) return GImGui->IO.KeysDown[key_index]; } +int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate) +{ + if (t == 0.0f) + return 1; + if (t <= repeat_delay || repeat_rate <= 0.0f) + return 0; + const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate); + return (count > 0) ? count : 0; +} + int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) { ImGuiContext& g = *GImGui; if (key_index < 0) return false; IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); const float t = g.IO.KeysDownDuration[key_index]; - if (t == 0.0f) - return 1; - if (t > repeat_delay && repeat_rate > 0.0f) - { - int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t - repeat_delay - g.IO.DeltaTime) / repeat_rate); - return (count > 0) ? count : 0; - } - return 0; + return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate); } bool ImGui::IsKeyPressed(int key_index, bool repeat) @@ -4823,9 +4882,13 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us ImVec2 nav_resize_delta(0.0f, 0.0f); if (g.NavWindowingTarget == window) { - const float resize_speed = ImFloor(600 * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); - nav_resize_delta = NavGetMovingDir(0) * resize_speed; - held |= (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f); // For coloring + nav_resize_delta = GetNavInputAmount2d(0, ImGuiNavReadMode_Down); + if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + { + nav_resize_delta *= ImFloor(600 * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + g.NavDisableMouseHover = true; + held = true; // For coloring + } } ImVec2 size_target(FLT_MAX,FLT_MAX); @@ -6267,13 +6330,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse hovered = true; - if (!g.NavWindowingTarget && IsKeyDownMap(ImGuiKey_NavActivate)) + if (!g.NavWindowingTarget && IsNavInputDown(ImGuiNavInput_PadActivate)) { // Set active id so it can be queried by user via IsItemActive(), etc. but don't react to it ourselves - g.NavActivateId = g.NavId; - SetActiveID(g.NavId, window); + g.NavActivateId = id; + SetActiveID(id, window); g.ActiveIdAllowNavDirFlags = (1 << ImGuiNavDir_Left) | (1 << ImGuiNavDir_Right) | (1 << ImGuiNavDir_Up) | (1 << ImGuiNavDir_Down); - if (IsKeyPressedMap(ImGuiKey_NavActivate, (flags & ImGuiButtonFlags_Repeat) != 0)) + if (IsNavInputPressed(ImGuiNavInput_PadActivate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiNavReadMode_Repeat : ImGuiNavReadMode_Pressed)) pressed = true; } } @@ -6296,7 +6359,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.NavDisableHighlight = true; } if (g.ActiveId == id && g.ActiveIdSource == ImGuiInputSource_Nav) - if (!IsKeyDownMap(ImGuiKey_NavActivate)) + if (!IsNavInputDown(ImGuiNavInput_PadActivate)) SetActiveID(0); // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. @@ -7136,47 +7199,6 @@ int ImGui::ParseFormatPrecision(const char* fmt, int default_precision) return precision; } -ImVec2 ImGui::NavGetMovingDir(int stick_no, float slow_factor, float fast_factor) -{ - IM_ASSERT(stick_no >= 0 && stick_no < 2); - ImVec2 dir(0.0f, 0.0f); - if (stick_no == 0) - { - if (IsKeyDownMap(ImGuiKey_NavLeft)) dir.x -= 1.0f; - if (IsKeyDownMap(ImGuiKey_NavRight)) dir.x += 1.0f; - if (IsKeyDownMap(ImGuiKey_NavUp)) dir.y -= 1.0f; - if (IsKeyDownMap(ImGuiKey_NavDown)) dir.y += 1.0f; - } - if (stick_no == 1) - { - if (IsKeyDownMap(ImGuiKey_NavScrollLeft)) dir.x -= 1.0f; - if (IsKeyDownMap(ImGuiKey_NavScrollRight)) dir.x += 1.0f; - if (IsKeyDownMap(ImGuiKey_NavScrollUp)) dir.y -= 1.0f; - if (IsKeyDownMap(ImGuiKey_NavScrollDown)) dir.y += 1.0f; - } - if (slow_factor != 0.0f && IsKeyDownMap(ImGuiKey_NavTweakSlower)) - dir *= slow_factor; - if (fast_factor != 0.0f && IsKeyDownMap(ImGuiKey_NavTweakFaster)) - dir *= fast_factor; - return dir; -} - -// Adjustment delta for slider/drag/etc. -// FIXME-NAVIGATION: Accelerate over time? Expose more settings? Handle faster/slower modifiers here instead of widget level? -ImVec2 ImGui::NavGetTweakDelta() -{ - ImGuiContext& g = *GImGui; - float repeat_delay = g.IO.KeyRepeatDelay * 0.80f; - float repeat_rate = g.IO.KeyRepeatRate * 0.30f; - - ImVec2 delta(0.0f, 0.0f); - if (int count = GetKeyPressedAmount(g.IO.KeyMap[ImGuiKey_NavLeft], repeat_delay, repeat_rate)) delta.x = (float)-count; - if (int count = GetKeyPressedAmount(g.IO.KeyMap[ImGuiKey_NavRight], repeat_delay, repeat_rate)) delta.x = (float)+count; - if (int count = GetKeyPressedAmount(g.IO.KeyMap[ImGuiKey_NavUp], repeat_delay, repeat_rate)) delta.y = (float)-count; - if (int count = GetKeyPressedAmount(g.IO.KeyMap[ImGuiKey_NavDown], repeat_delay, repeat_rate)) delta.y = (float)+count; - return delta; -} - static float GetMinimumStepAtDecimalPrecision(int decimal_precision) { static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; @@ -7275,15 +7297,15 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v normalized_pos = 1.0f - normalized_pos; set_new_value = true; } - else if (g.ActiveIdSource == ImGuiInputSource_Nav && IsKeyDownMap(ImGuiKey_NavActivate)) + else if (g.ActiveIdSource == ImGuiInputSource_Nav && IsNavInputDown(ImGuiNavInput_PadActivate)) { - const ImVec2 delta2 = NavGetTweakDelta(); + const ImVec2 delta2 = GetNavInputAmount2d(0, ImGuiNavReadMode_RepeatFast, 0.0f, 0.0f); if (float delta = is_horizontal ? delta2.x : -delta2.y) { normalized_pos = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); if (decimal_precision == 0 && !is_non_linear) { - if (fabsf(v_max - v_min) <= 100.0f || IsKeyDownMap(ImGuiKey_NavTweakSlower)) + if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_PadTweakSlow)) delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps else delta /= 100.0f; @@ -7291,10 +7313,10 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v else { delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds - if (IsKeyDownMap(ImGuiKey_NavTweakSlower)) + if (IsNavInputDown(ImGuiNavInput_PadTweakSlow)) delta /= 10.0f; } - if (IsKeyDownMap(ImGuiKey_NavTweakFaster)) + if (IsNavInputDown(ImGuiNavInput_PadTweakFast)) delta *= 10.0f; normalized_pos = ImSaturate(normalized_pos + delta); // FIXME-NAVIGATION: todo: cancel adjustment if current value already past edge and we are moving in edge direction, to avoid clamping value to edge. set_new_value = true; @@ -7602,7 +7624,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s // Process clicking on the drag if (g.ActiveId == id) { - if (g.IO.MouseDown[0] || IsKeyDownMap(ImGuiKey_NavActivate)) + if (g.IO.MouseDown[0] || IsNavInputDown(ImGuiNavInput_PadActivate)) { if (g.ActiveIdIsJustActivated) { @@ -7627,11 +7649,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s } if (g.ActiveIdSource == ImGuiInputSource_Nav) { - adjust_delta = NavGetTweakDelta().x; - if (IsKeyDownMap(ImGuiKey_NavTweakFaster)) - adjust_delta *= 10.0f; - if (IsKeyDownMap(ImGuiKey_NavTweakSlower)) - adjust_delta /= 10.0f; + adjust_delta = GetNavInputAmount2d(0, ImGuiNavReadMode_RepeatFast, 1.0f/10.0f, 1.0f).x; } adjust_delta *= v_speed; g.DragLastMouseDelta.x = mouse_drag_delta.x; diff --git a/imgui.h b/imgui.h index d43cd8cd2..c34d68c69 100644 --- a/imgui.h +++ b/imgui.h @@ -70,6 +70,7 @@ typedef void* ImTextureID; // user data to identify a texture (this is typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_ +typedef int ImGuiNavInput; // an input identifier for gamepad nav // enum ImGuiNavInput_ typedef int ImGuiAlign; // alignment // enum ImGuiAlign_ typedef int ImGuiColorEditMode; // color edit mode for ColorEdit*() // enum ImGuiColorEditMode_ typedef int ImGuiMouseCursor; // a mouse cursor identifier // enum ImGuiMouseCursor_ @@ -437,7 +438,7 @@ namespace ImGui IMGUI_API bool IsKeyDown(int key_index); // key_index into the keys_down[] array, imgui doesn't know the semantic of each entry, uses your own indices! IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // uses user's key indices as stored in the keys_down[] array. if repeat=true. uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(int key_index); // " - IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, typically 0 or 1 but may be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + 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 IMGUI_API bool IsMouseDown(int button); // is mouse button held IMGUI_API bool IsMouseClicked(int button, bool repeat = false); // did mouse button clicked (went from !Down to Down) IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. @@ -576,10 +577,10 @@ enum ImGuiSelectableFlags_ enum ImGuiKey_ { ImGuiKey_Tab, // for tabbing through fields - ImGuiKey_LeftArrow, // for text edit - ImGuiKey_RightArrow,// for text edit ImGuiKey_UpArrow, // for text edit ImGuiKey_DownArrow, // for text edit + ImGuiKey_LeftArrow, // for text edit + ImGuiKey_RightArrow,// for text edit ImGuiKey_PageUp, ImGuiKey_PageDown, ImGuiKey_Home, // for text edit @@ -594,27 +595,31 @@ enum ImGuiKey_ ImGuiKey_X, // for text edit CTRL+X: cut ImGuiKey_Y, // for text edit CTRL+Y: redo ImGuiKey_Z, // for text edit CTRL+Z: undo - - // Inputs for Gamepad/Keyboard navigation. Feed those buttons with the input of either or both peripherals involved. - ImGuiKey_NavActivate, // press button, tweak value // e.g. Space key, Circle button - ImGuiKey_NavCancel, // close menu/popup/child, unselect // e.g. Escape key, Cross button - ImGuiKey_NavInput, // text input // e.g. Enter key, Triangle button - ImGuiKey_NavMenu, // access menu, focus, move, resize // e.g. Square button - ImGuiKey_NavLeft, // e.g. Left arrow, D-Pad left - ImGuiKey_NavRight, // e.g. Right arrow, D-Pad right - ImGuiKey_NavUp, // e.g. Up arrow, D-Pad up - ImGuiKey_NavDown, // e.g. Down arrow, D-Pad down - ImGuiKey_NavScrollLeft, // e.g. Analog left - ImGuiKey_NavScrollRight,// e.g. Analog right - ImGuiKey_NavScrollUp, // e.g. Analog up - ImGuiKey_NavScrollDown, // e.g. Analog down - ImGuiKey_NavTweakFaster,// e.g. Shift key, R-trigger - ImGuiKey_NavTweakSlower,// e.g. Alt key, L-trigger - ImGuiKey_NavLast_, - ImGuiKey_COUNT }; +enum ImGuiNavInput_ +{ + ImGuiNavInput_PadActivate, // press button, tweak value // e.g. Circle button + ImGuiNavInput_PadCancel, // close menu/popup/child, lose selection // e.g. Cross button + ImGuiNavInput_PadInput, // text input // e.g. Triangle button + ImGuiNavInput_PadMenu, // access menu, focus, move, resize // e.g. Square button + ImGuiNavInput_PadUp, // move up, resize window (with PadMenu held) // e.g. D-pad up/down/left/right + ImGuiNavInput_PadDown, // move down + ImGuiNavInput_PadLeft, // move left + ImGuiNavInput_PadRight, // move right + ImGuiNavInput_PadScrollUp, // scroll up, move window (with PadMenu held) // e.g. right stick up/down/left/right + ImGuiNavInput_PadScrollDown, // " + ImGuiNavInput_PadScrollLeft, // + ImGuiNavInput_PadScrollRight, // + ImGuiNavInput_PadFocusPrev, // next window (with PadMenu held) // e.g. L-trigger + ImGuiNavInput_PadFocusNext, // prev window (with PadMenu held) // e.g. R-trigger + ImGuiNavInput_PadTweakSlow, // slower tweaks // e.g. L-trigger + ImGuiNavInput_PadTweakFast, // faster tweaks // e.g. R-trigger + + ImGuiNavInput_COUNT, +}; + // Enumeration for PushStyleColor() / PopStyleColor() enum ImGuiCol_ { @@ -824,6 +829,7 @@ struct ImGuiIO bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows bool KeysDown[512]; // Keyboard keys that are pressed (in whatever storage order you naturally have access to keyboard data) ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. + float NavInputs[ImGuiNavInput_COUNT]; // Functions IMGUI_API void AddInputCharacter(ImWchar c); // Helper to add a new character into InputCharacters[] @@ -863,6 +869,8 @@ struct ImGuiIO float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the click 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 + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsPrev[ImGuiNavInput_COUNT]; IMGUI_API ImGuiIO(); }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3050a2c43..6f0f7135a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1528,6 +1528,9 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("NavUsable: %d, NavActive: %d", io.NavUsable, io.NavActive); + 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", i, io.NavInputs[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); } + ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } ImGui::Button("Hovering me sets the\nkeyboard capture flag"); if (ImGui::IsItemHovered()) diff --git a/imgui_internal.h b/imgui_internal.h index 35a206f18..deb4cf37d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -784,8 +784,7 @@ namespace ImGui IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); - IMGUI_API ImVec2 NavGetTweakDelta(); - IMGUI_API ImVec2 NavGetMovingDir(int stick_no, float slow_factor = 0.0f, float fast_factor = 0.0f); + IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate); inline IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; return ImGui::ColorConvertFloat4ToU32(c); } inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }