SetKeyboardFocusHere() sets focus on next widget instead of previous + works on tabbing-disabled widgets

This commit is contained in:
ocornut 2014-09-30 12:22:58 +01:00
parent ffc8264e9d
commit f1ea630dd0
2 changed files with 42 additions and 33 deletions

View File

@ -185,13 +185,13 @@
- filters: set a current filter that tree node can automatically query to hide themselves - filters: set a current filter that tree node can automatically query to hide themselves
- filters: handle wildcards (with implicit leading/trailing *), regexps - filters: handle wildcards (with implicit leading/trailing *), regexps
- shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus)
- keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing ! keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing
- keyboard: full keyboard navigation and focus. - keyboard: full keyboard navigation and focus.
- input: support trackpad style scrolling & slider edit. - input: support trackpad style scrolling & slider edit.
- tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen). - tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen).
- misc: not thread-safe - misc: not thread-safe
- misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon?
- style editor: add a button to print C code. - style editor: add a button to output C code.
- optimisation/render: use indexed rendering - optimisation/render: use indexed rendering
- optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: move clip-rect to vertex data? would allow merging all commands
- optimisation/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimisation/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)?
@ -763,9 +763,12 @@ struct ImGuiWindow
ImGuiStorage StateStorage; ImGuiStorage StateStorage;
float FontWindowScale; // Scale multipler per-window float FontWindowScale; // Scale multipler per-window
int FocusIdxCounter; // Start at -1 and increase as assigned via FocusItemRegister() int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister()
int FocusIdxRequestCurrent; // Item being requested for focus, rely on layout to be stable between the frame pressing TAB and the next frame int FocusIdxTabCounter; // (same, but only include widgets which you can Tab through)
int FocusIdxRequestNext; // Item being requested for focus, for next update int FocusIdxAllRequestCurrent; // Item being requested for focus, rely on layout to be stable between the frame pressing TAB and the next frame
int FocusIdxTabRequestCurrent;
int FocusIdxAllRequestNext; // Item being requested for focus, for next update
int FocusIdxTabRequestNext;
ImDrawList* DrawList; ImDrawList* DrawList;
@ -1019,9 +1022,9 @@ ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_si
if (ImLength(Size) < 0.001f) if (ImLength(Size) < 0.001f)
AutoFitFrames = 3; AutoFitFrames = 3;
FocusIdxCounter = -1; FocusIdxAllCounter = FocusIdxTabCounter = -1;
FocusIdxRequestCurrent = IM_INT_MAX; FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = IM_INT_MAX;
FocusIdxRequestNext = IM_INT_MAX; FocusIdxAllRequestNext = FocusIdxTabRequestNext = IM_INT_MAX;
DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList));
new(DrawList) ImDrawList(); new(DrawList) ImDrawList();
@ -1058,27 +1061,32 @@ bool ImGuiWindow::FocusItemRegister(bool is_active)
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus.back(); const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus.back();
FocusIdxAllCounter++;
if (allow_keyboard_focus) if (allow_keyboard_focus)
FocusIdxCounter++; FocusIdxTabCounter++;
// Process input at this point: TAB, Shift-TAB switch focus // Process keyboard input at this point: TAB, Shift-TAB switch focus
// We can always TAB out of a widget that doesn't allow tabbing in. // We can always TAB out of a widget that doesn't allow tabbing in.
if (FocusIdxRequestNext == IM_INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab)) if (FocusIdxAllRequestNext == IM_INT_MAX && FocusIdxTabRequestNext == IM_INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab))
{ {
// Modulo on index will be applied at the end of frame once we've got the total counter of items. // Modulo on index will be applied at the end of frame once we've got the total counter of items.
FocusIdxRequestNext = FocusIdxCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); FocusIdxTabRequestNext = FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1);
} }
if (!allow_keyboard_focus) if (FocusIdxAllCounter == FocusIdxAllRequestCurrent)
return false; return true;
const bool focus_requested = (FocusIdxCounter == FocusIdxRequestCurrent); if (allow_keyboard_focus)
return focus_requested; if (FocusIdxTabCounter == FocusIdxTabRequestCurrent)
return true;
return false;
} }
void ImGuiWindow::FocusItemUnregister() void ImGuiWindow::FocusItemUnregister()
{ {
FocusIdxCounter--; FocusIdxAllCounter--;
FocusIdxTabCounter--;
} }
void ImGuiWindow::AddToRenderList() void ImGuiWindow::AddToRenderList()
@ -1391,7 +1399,7 @@ void NewFrame()
// NB: Don't discard FocusedWindow if it isn't active, so that a window that go on/off programatically won't lose its keyboard focus. // NB: Don't discard FocusedWindow if it isn't active, so that a window that go on/off programatically won't lose its keyboard focus.
if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Visible && IsKeyPressedMap(ImGuiKey_Tab, false)) if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Visible && IsKeyPressedMap(ImGuiKey_Tab, false))
{ {
g.FocusedWindow->FocusIdxRequestNext = 0; g.FocusedWindow->FocusIdxTabRequestNext = 0;
} }
// Mark all windows as not visible // Mark all windows as not visible
@ -2098,18 +2106,19 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
else else
window->ItemWidthDefault = 200.0f; window->ItemWidthDefault = 200.0f;
// Prepare for keyboard focus requests // Prepare for keyboard TAB focus requests
if (window->FocusIdxRequestNext == IM_INT_MAX || window->FocusIdxCounter == -1) if (window->FocusIdxTabRequestNext == IM_INT_MAX || window->FocusIdxTabCounter == -1)
{ {
window->FocusIdxRequestCurrent = IM_INT_MAX; window->FocusIdxTabRequestCurrent = IM_INT_MAX;
} }
else else
{ {
const int mod = window->FocusIdxCounter+1; const int mod = window->FocusIdxTabCounter+1;
window->FocusIdxRequestCurrent = (window->FocusIdxRequestNext + mod) % mod; window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext + mod) % mod;
} }
window->FocusIdxCounter = -1; window->FocusIdxAllRequestCurrent = window->FocusIdxAllRequestNext;
window->FocusIdxRequestNext = IM_INT_MAX; window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX;
ImGuiAabb title_bar_aabb = window->TitleBarAabb(); ImGuiAabb title_bar_aabb = window->TitleBarAabb();
@ -2634,7 +2643,8 @@ void SetScrollPosHere()
void SetKeyboardFocusHere() void SetKeyboardFocusHere()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->FocusIdxRequestNext = window->FocusIdxCounter; window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1;
window->FocusIdxTabRequestNext = IM_INT_MAX;
} }
void SetTreeStateStorage(ImGuiStorage* tree) void SetTreeStateStorage(ImGuiStorage* tree)
@ -6406,15 +6416,14 @@ void ShowTestWindow(bool* open)
bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
bool focus_3 = ImGui::Button("Focus on 3"); bool focus_3 = ImGui::Button("Focus on 3");
static char buf[128] = "click on a button to set focus"; static char buf[128] = "click on a button to set focus";
ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
if (focus_1) ImGui::SetKeyboardFocusHere(); if (focus_1) ImGui::SetKeyboardFocusHere();
ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
if (focus_2) ImGui::SetKeyboardFocusHere(); if (focus_2) ImGui::SetKeyboardFocusHere();
//ImGui::PushAllowKeyboardFocus(false); ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
//ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); ImGui::PushAllowKeyboardFocus(false);
ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
if (focus_3) ImGui::SetKeyboardFocusHere(); if (focus_3) ImGui::SetKeyboardFocusHere();
//ImGui::PopAllowKeyboardFocus(); ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
ImGui::PopAllowKeyboardFocus();
ImGui::TreePop(); ImGui::TreePop();
} }
} }

View File

@ -153,7 +153,7 @@ namespace ImGui
ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives. ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives.
void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontBaseScale if you want to scale all windows together. void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontBaseScale if you want to scale all windows together.
void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position. void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position.
void SetKeyboardFocusHere(); void SetKeyboardFocusHere(); // focus keyboard on the next widget
void SetTreeStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it). void SetTreeStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it).
ImGuiStorage* GetTreeStateStorage(); ImGuiStorage* GetTreeStateStorage();
void PushItemWidth(float item_width); void PushItemWidth(float item_width);