Internal: Tabbing: Tweaks to FocusableItemRegister and using the standard mechanism to allow/block Tab being interpreting by tabbing instead of InputText() widget.

This commit is contained in:
omar 2019-03-05 17:38:36 +01:00
parent 1ed3c4cf4a
commit ce4e62649a
4 changed files with 24 additions and 10 deletions

View File

@ -2895,19 +2895,21 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged
return false; return false;
} }
bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop) bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
// Increment counters
const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
window->FocusIdxAllCounter++; window->FocusIdxAllCounter++;
if (is_tab_stop) if (is_tab_stop)
window->FocusIdxTabCounter++; window->FocusIdxTabCounter++;
// Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item. // Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
// Note that we can always TAB out of a widget that doesn't allow tabbing in. // (Note that we can always TAB out of a widget that doesn't allow tabbing in)
if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)) if (g.ActiveId == id && g.FocusTabPressed && !(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_KeyTab_)))
window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. if (window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX)
window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent) if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
return true; return true;
@ -3513,7 +3515,9 @@ void ImGui::NewFrame()
UpdateMouseWheel(); UpdateMouseWheel();
// Pressing TAB activate widget focus // Pressing TAB activate widget focus
if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false)) // (This code is old and will be redesigned for Nav. In the meanwhile we use g.NavTabRequest as storage but this doesn't need ImGuiConfigFlags_NavEnableKeyboard to work!)
g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
if (g.ActiveId == 0 && g.FocusTabPressed)
{ {
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
@ -5167,8 +5171,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
// Prepare for item focus requests // Prepare for item focus requests
window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : ImModPositive(window->FocusIdxAllRequestNext, window->FocusIdxAllCounter + 1);
window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : ImModPositive(window->FocusIdxTabRequestNext, window->FocusIdxTabCounter + 1);
window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
@ -7609,6 +7613,7 @@ static void ImGui::NavUpdate()
NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
NAV_MAP_KEY(ImGuiKey_Tab, ImGuiNavInput_KeyTab_ );
if (g.IO.KeyCtrl) if (g.IO.KeyCtrl)
g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (g.IO.KeyShift) if (g.IO.KeyShift)

View File

@ -967,6 +967,7 @@ enum ImGuiNavInput_
// [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. // [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[]. // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[].
ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt
ImGuiNavInput_KeyTab_, // tab // = Tab key
ImGuiNavInput_KeyLeft_, // move left // = Arrow keys ImGuiNavInput_KeyLeft_, // move left // = Arrow keys
ImGuiNavInput_KeyRight_, // move right ImGuiNavInput_KeyRight_, // move right
ImGuiNavInput_KeyUp_, // move up ImGuiNavInput_KeyUp_, // move up

View File

@ -248,6 +248,7 @@ static inline float ImLengthSqr(const ImVec4& lhs)
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 1.0f / ImSqrt(d); return fail_value; } 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 1.0f / ImSqrt(d); return fail_value; }
static inline float ImFloor(float f) { return (float)(int)f; } static inline float ImFloor(float f) { return (float)(int)f; }
static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)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 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); } 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); }
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
@ -891,6 +892,9 @@ struct ImGuiContext
ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
// Tabbing system (older than Nav, active when Nav is disabled. Probably needs a redesign)
bool FocusTabPressed; //
// Render // Render
ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user
ImDrawDataBuilder DrawDataBuilder; ImDrawDataBuilder DrawDataBuilder;
@ -1036,6 +1040,7 @@ struct ImGuiContext
NavMoveRequestFlags = 0; NavMoveRequestFlags = 0;
NavMoveRequestForward = ImGuiNavForward_None; NavMoveRequestForward = ImGuiNavForward_None;
NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None;
FocusTabPressed = false;
DimBgRatio = 0.0f; DimBgRatio = 0.0f;
BackgroundDrawList._Data = &DrawListSharedData; BackgroundDrawList._Data = &DrawListSharedData;
@ -1421,7 +1426,7 @@ namespace ImGui
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true); // Return true if focus is requested IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);

View File

@ -3274,7 +3274,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (g.InputTextState.ID == id) if (g.InputTextState.ID == id)
state = &g.InputTextState; state = &g.InputTextState;
const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing const bool focus_requested = FocusableItemRegister(window, id);
const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent); const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
@ -3337,7 +3337,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
SetActiveID(id, window); SetActiveID(id, window);
SetFocusID(id, window); SetFocusID(id, window);
FocusWindow(window); FocusWindow(window);
IM_ASSERT(ImGuiNavInput_COUNT < 32);
g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel);
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out
g.ActiveIdBlockNavInputFlags |= (1 << ImGuiNavInput_KeyTab_);
if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
} }