|
@@ -380,6 +380,7 @@ 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.
|
|
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.
|
|
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
|
|
|
|
|
|
|
|
|
+ - 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.
|
|
- 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.
|
|
|
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
|
|
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
|
|
|
- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
|
|
- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
|
|
@@ -917,6 +918,7 @@ static void NavUpdateWindowing();
|
|
|
static void NavUpdateWindowingOverlay();
|
|
static void NavUpdateWindowingOverlay();
|
|
|
static void NavUpdateCancelRequest();
|
|
static void NavUpdateCancelRequest();
|
|
|
static void NavUpdateCreateMoveRequest();
|
|
static void NavUpdateCreateMoveRequest();
|
|
|
|
|
+static void NavUpdateCreateTabbingRequest();
|
|
|
static float NavUpdatePageUpPageDown();
|
|
static float NavUpdatePageUpPageDown();
|
|
|
static inline void NavUpdateAnyRequestFlag();
|
|
static inline void NavUpdateAnyRequestFlag();
|
|
|
static void NavUpdateCreateWrappingRequest();
|
|
static void NavUpdateCreateWrappingRequest();
|
|
@@ -924,10 +926,12 @@ static void NavEndFrame();
|
|
|
static bool NavScoreItem(ImGuiNavItemData* result);
|
|
static bool NavScoreItem(ImGuiNavItemData* result);
|
|
|
static void NavApplyItemToResult(ImGuiNavItemData* result);
|
|
static void NavApplyItemToResult(ImGuiNavItemData* result);
|
|
|
static void NavProcessItem();
|
|
static void NavProcessItem();
|
|
|
|
|
+static void NavProcessItemForTabbingRequest(ImGuiWindow* window, ImGuiID id);
|
|
|
static ImVec2 NavCalcPreferredRefPos();
|
|
static ImVec2 NavCalcPreferredRefPos();
|
|
|
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
|
|
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
|
|
|
static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
|
|
static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
|
|
|
static void NavRestoreLayer(ImGuiNavLayer layer);
|
|
static void NavRestoreLayer(ImGuiNavLayer layer);
|
|
|
|
|
+static void NavRestoreHighlightAfterMove();
|
|
|
static int FindWindowFocusIndex(ImGuiWindow* window);
|
|
static int FindWindowFocusIndex(ImGuiWindow* window);
|
|
|
|
|
|
|
|
// Error Checking and Debug Tools
|
|
// Error Checking and Debug Tools
|
|
@@ -940,7 +944,6 @@ static void UpdateDebugToolStackQueries();
|
|
|
static void UpdateSettings();
|
|
static void UpdateSettings();
|
|
|
static void UpdateMouseInputs();
|
|
static void UpdateMouseInputs();
|
|
|
static void UpdateMouseWheel();
|
|
static void UpdateMouseWheel();
|
|
|
-static void UpdateTabFocus();
|
|
|
|
|
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);
|
|
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);
|
|
|
static void RenderWindowOuterBorders(ImGuiWindow* window);
|
|
static void RenderWindowOuterBorders(ImGuiWindow* window);
|
|
|
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
|
|
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
|
|
@@ -2246,9 +2249,10 @@ static bool GetSkipItemForListClipping()
|
|
|
return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
|
|
return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Helper to calculate coarse clipping of large list of evenly sized items.
|
|
|
|
|
-// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
|
|
|
|
|
-// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
|
|
|
|
|
|
|
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
|
|
|
|
+// Legacy helper to calculate coarse clipping of large list of evenly sized items.
|
|
|
|
|
+// This legacy API is not ideal because it assume we will return a single contiguous rectangle.
|
|
|
|
|
+// Prefer using ImGuiListClipper which can returns non-contiguous ranges.
|
|
|
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
|
|
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
|
|
|
{
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -2267,20 +2271,23 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect
|
|
// We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect
|
|
|
- ImRect unclipped_rect = window->ClipRect;
|
|
|
|
|
|
|
+ // We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly.
|
|
|
|
|
+ ImRect rect = window->ClipRect;
|
|
|
if (g.NavMoveScoringItems)
|
|
if (g.NavMoveScoringItems)
|
|
|
- unclipped_rect.Add(g.NavScoringRect);
|
|
|
|
|
|
|
+ rect.Add(g.NavScoringNoClipRect);
|
|
|
if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
|
|
if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
|
|
|
- unclipped_rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel
|
|
|
|
|
|
|
+ rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel
|
|
|
|
|
|
|
|
const ImVec2 pos = window->DC.CursorPos;
|
|
const ImVec2 pos = window->DC.CursorPos;
|
|
|
- int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
|
|
|
|
|
- int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
|
|
|
|
|
|
|
+ int start = (int)((rect.Min.y - pos.y) / items_height);
|
|
|
|
|
+ int end = (int)((rect.Max.y - pos.y) / items_height);
|
|
|
|
|
|
|
|
// When performing a navigation request, ensure we have one item extra in the direction we are moving to
|
|
// When performing a navigation request, ensure we have one item extra in the direction we are moving to
|
|
|
- if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Up)
|
|
|
|
|
|
|
+ // FIXME: Verify this works with tabbing
|
|
|
|
|
+ const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
|
|
|
|
|
+ if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up)
|
|
|
start--;
|
|
start--;
|
|
|
- if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Down)
|
|
|
|
|
|
|
+ if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down)
|
|
|
end++;
|
|
end++;
|
|
|
|
|
|
|
|
start = ImClamp(start, 0, items_count);
|
|
start = ImClamp(start, 0, items_count);
|
|
@@ -2288,17 +2295,42 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
|
|
|
*out_items_display_start = start;
|
|
*out_items_display_start = start;
|
|
|
*out_items_display_end = end;
|
|
*out_items_display_end = end;
|
|
|
}
|
|
}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0)
|
|
|
|
|
+{
|
|
|
|
|
+ if (ranges.Size - offset <= 1)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries)
|
|
|
|
|
+ for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end)
|
|
|
|
|
+ for (int i = offset; i < sort_end + offset; ++i)
|
|
|
|
|
+ if (ranges[i].Min > ranges[i + 1].Min)
|
|
|
|
|
+ ImSwap(ranges[i], ranges[i + 1]);
|
|
|
|
|
+
|
|
|
|
|
+ // Now fuse ranges together as much as possible.
|
|
|
|
|
+ for (int i = 1 + offset; i < ranges.Size; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert);
|
|
|
|
|
+ if (ranges[i - 1].Max < ranges[i].Min)
|
|
|
|
|
+ continue;
|
|
|
|
|
+ ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min);
|
|
|
|
|
+ ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max);
|
|
|
|
|
+ ranges.erase(ranges.Data + i);
|
|
|
|
|
+ i--;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
|
|
|
|
|
|
|
+static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
|
|
|
{
|
|
{
|
|
|
// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
|
|
// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
|
|
|
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
|
|
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
|
|
|
- // The clipper should probably have a 4th step to display the last item in a regular manner.
|
|
|
|
|
|
|
+ // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek?
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
float off_y = pos_y - window->DC.CursorPos.y;
|
|
float off_y = pos_y - window->DC.CursorPos.y;
|
|
|
window->DC.CursorPos.y = pos_y;
|
|
window->DC.CursorPos.y = pos_y;
|
|
|
- window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
|
|
|
|
|
|
|
+ window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y);
|
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
|
|
|
window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
|
|
window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
|
|
|
if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
|
|
if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
|
|
@@ -2314,6 +2346,14 @@ static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)
|
|
|
|
|
+{
|
|
|
|
|
+ // StartPosY starts from ItemsFrozen hence the subtraction
|
|
|
|
|
+ ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
|
|
|
|
|
+ float pos_y = clipper->StartPosY + (item_n - data->ItemsFrozen) * clipper->ItemsHeight;
|
|
|
|
|
+ ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
ImGuiListClipper::ImGuiListClipper()
|
|
ImGuiListClipper::ImGuiListClipper()
|
|
|
{
|
|
{
|
|
|
memset(this, 0, sizeof(*this));
|
|
memset(this, 0, sizeof(*this));
|
|
@@ -2322,7 +2362,7 @@ ImGuiListClipper::ImGuiListClipper()
|
|
|
|
|
|
|
|
ImGuiListClipper::~ImGuiListClipper()
|
|
ImGuiListClipper::~ImGuiListClipper()
|
|
|
{
|
|
{
|
|
|
- IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?");
|
|
|
|
|
|
|
+ End();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1
|
|
// Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1
|
|
@@ -2340,28 +2380,44 @@ void ImGuiListClipper::Begin(int items_count, float items_height)
|
|
|
StartPosY = window->DC.CursorPos.y;
|
|
StartPosY = window->DC.CursorPos.y;
|
|
|
ItemsHeight = items_height;
|
|
ItemsHeight = items_height;
|
|
|
ItemsCount = items_count;
|
|
ItemsCount = items_count;
|
|
|
- ItemsFrozen = 0;
|
|
|
|
|
- StepNo = 0;
|
|
|
|
|
DisplayStart = -1;
|
|
DisplayStart = -1;
|
|
|
DisplayEnd = 0;
|
|
DisplayEnd = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // Acquire temporary buffer
|
|
|
|
|
+ if (++g.ClipperTempDataStacked > g.ClipperTempData.Size)
|
|
|
|
|
+ g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData());
|
|
|
|
|
+ ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
|
|
|
|
|
+ data->Reset(this);
|
|
|
|
|
+ TempData = data;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImGuiListClipper::End()
|
|
void ImGuiListClipper::End()
|
|
|
{
|
|
{
|
|
|
- if (ItemsCount < 0) // Already ended
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user.
|
|
|
|
|
- if (ItemsCount < INT_MAX && DisplayStart >= 0)
|
|
|
|
|
- SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight);
|
|
|
|
|
|
|
+ // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
|
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
|
|
+ if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
|
|
|
|
|
+ ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
|
|
|
ItemsCount = -1;
|
|
ItemsCount = -1;
|
|
|
- StepNo = 3;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Restore temporary buffer and fix back pointers which may be invalidated when nesting
|
|
|
|
|
+ if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
|
|
|
|
|
+ {
|
|
|
|
|
+ IM_ASSERT(data->ListClipper == this);
|
|
|
|
|
+ data->StepNo = data->Ranges.Size;
|
|
|
|
|
+ if (--g.ClipperTempDataStacked > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
|
|
|
|
|
+ data->ListClipper->TempData = data;
|
|
|
|
|
+ }
|
|
|
|
|
+ TempData = NULL;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool ImGuiListClipper::Step()
|
|
bool ImGuiListClipper::Step()
|
|
|
{
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
|
+ ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
|
|
|
|
|
|
|
|
ImGuiTable* table = g.CurrentTable;
|
|
ImGuiTable* table = g.CurrentTable;
|
|
|
if (table && table->IsInsideRow)
|
|
if (table && table->IsInsideRow)
|
|
@@ -2374,90 +2430,112 @@ bool ImGuiListClipper::Step()
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
|
|
|
|
|
- if (StepNo == 0)
|
|
|
|
|
|
|
+ // While we are in frozen row state, keep displaying items one by one, unclipped
|
|
|
|
|
+ // FIXME: Could be stored as a table-agnostic state.
|
|
|
|
|
+ if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows)
|
|
|
{
|
|
{
|
|
|
- // While we are in frozen row state, keep displaying items one by one, unclipped
|
|
|
|
|
- // FIXME: Could be stored as a table-agnostic state.
|
|
|
|
|
- if (table != NULL && !table->IsUnfrozenRows)
|
|
|
|
|
- {
|
|
|
|
|
- DisplayStart = ItemsFrozen;
|
|
|
|
|
- DisplayEnd = ItemsFrozen + 1;
|
|
|
|
|
- ItemsFrozen++;
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ DisplayStart = data->ItemsFrozen;
|
|
|
|
|
+ DisplayEnd = data->ItemsFrozen + 1;
|
|
|
|
|
+ data->ItemsFrozen++;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
|
|
|
|
|
+ bool calc_clipping = false;
|
|
|
|
|
+ if (data->StepNo == 0)
|
|
|
|
|
+ {
|
|
|
StartPosY = window->DC.CursorPos.y;
|
|
StartPosY = window->DC.CursorPos.y;
|
|
|
if (ItemsHeight <= 0.0f)
|
|
if (ItemsHeight <= 0.0f)
|
|
|
{
|
|
{
|
|
|
- // Submit the first item so we can measure its height (generally it is 0..1)
|
|
|
|
|
- DisplayStart = ItemsFrozen;
|
|
|
|
|
- DisplayEnd = ItemsFrozen + 1;
|
|
|
|
|
- StepNo = 1;
|
|
|
|
|
|
|
+ // Submit the first item (or range) so we can measure its height (generally the first range is 0..1)
|
|
|
|
|
+ data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1));
|
|
|
|
|
+ DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);
|
|
|
|
|
+ DisplayEnd = ImMin(data->Ranges[0].Max, ItemsCount);
|
|
|
|
|
+ data->StepNo = 1;
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Already has item height (given by user in Begin): skip to calculating step
|
|
|
|
|
- DisplayStart = DisplayEnd;
|
|
|
|
|
- StepNo = 2;
|
|
|
|
|
|
|
+ calc_clipping = true; // If on the first step with known item height, calculate clipping.
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Step 1: the clipper infer height from first element
|
|
|
|
|
- if (StepNo == 1)
|
|
|
|
|
|
|
+ // Step 1: Let the clipper infer height from first range
|
|
|
|
|
+ if (ItemsHeight <= 0.0f)
|
|
|
{
|
|
{
|
|
|
- IM_ASSERT(ItemsHeight <= 0.0f);
|
|
|
|
|
|
|
+ IM_ASSERT(data->StepNo == 1);
|
|
|
if (table)
|
|
if (table)
|
|
|
{
|
|
{
|
|
|
- const float pos_y1 = table->RowPosY1; // Using this instead of StartPosY to handle clipper straddling the frozen row
|
|
|
|
|
- const float pos_y2 = table->RowPosY2; // Using this instead of CursorPos.y to take account of tallest cell.
|
|
|
|
|
|
|
+ const float pos_y1 = table->RowPosY1; // Using RowPosY1 instead of StartPosY to handle clipper straddling the frozen row
|
|
|
|
|
+ const float pos_y2 = table->RowPosY2; // Using RowPosY2 instead of CursorPos.y to take account of tallest cell.
|
|
|
ItemsHeight = pos_y2 - pos_y1;
|
|
ItemsHeight = pos_y2 - pos_y1;
|
|
|
window->DC.CursorPos.y = pos_y2;
|
|
window->DC.CursorPos.y = pos_y2;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- ItemsHeight = window->DC.CursorPos.y - StartPosY;
|
|
|
|
|
|
|
+ ItemsHeight = (window->DC.CursorPos.y - StartPosY) / (float)(DisplayEnd - DisplayStart);
|
|
|
}
|
|
}
|
|
|
IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
|
|
IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
|
|
|
- StepNo = 2;
|
|
|
|
|
|
|
+ calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Reached end of list
|
|
|
|
|
- if (DisplayEnd >= ItemsCount)
|
|
|
|
|
|
|
+ // Step 0 or 1: Calculate the actual ranges of visible elements.
|
|
|
|
|
+ const int already_submitted = DisplayEnd;
|
|
|
|
|
+ if (calc_clipping)
|
|
|
{
|
|
{
|
|
|
- End();
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ if (g.LogEnabled)
|
|
|
|
|
+ {
|
|
|
|
|
+ // If logging is active, do not perform any clipping
|
|
|
|
|
+ data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, ItemsCount));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Add range selected to be included for navigation
|
|
|
|
|
+ const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
|
|
|
|
|
+ if (is_nav_request)
|
|
|
|
|
+ data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0));
|
|
|
|
|
+ if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1)
|
|
|
|
|
+ data->Ranges.push_back(ImGuiListClipperRange::FromIndices(ItemsCount - 1, ItemsCount));
|
|
|
|
|
+
|
|
|
|
|
+ // Add focused/active item
|
|
|
|
|
+ ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]);
|
|
|
|
|
+ if (g.NavId != 0 && window->NavLastIds[0] == g.NavId)
|
|
|
|
|
+ data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
|
|
|
|
|
+
|
|
|
|
|
+ // Add visible range
|
|
|
|
|
+ const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
|
|
|
|
|
+ const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
|
|
|
|
|
+ data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Convert position ranges to item index ranges
|
|
|
|
|
+ // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
|
|
|
|
|
+ // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
|
|
|
|
|
+ // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
|
|
|
|
|
+ for (int i = 0; i < data->Ranges.Size; i++)
|
|
|
|
|
+ if (data->Ranges[i].PosToIndexConvert)
|
|
|
|
|
+ {
|
|
|
|
|
+ data->Ranges[i].Min = ImClamp(already_submitted + (int)ImFloor((data->Ranges[i].Min - window->DC.CursorPos.y) / ItemsHeight) + data->Ranges[i].PosToIndexOffsetMin, already_submitted, ItemsCount - 1);
|
|
|
|
|
+ data->Ranges[i].Max = ImClamp(already_submitted + (int)ImCeil((data->Ranges[i].Max - window->DC.CursorPos.y) / ItemsHeight) + 0 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, ItemsCount);
|
|
|
|
|
+ data->Ranges[i].PosToIndexConvert = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Step 2: calculate the actual range of elements to display, and position the cursor before the first element
|
|
|
|
|
- if (StepNo == 2)
|
|
|
|
|
|
|
+ // Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
|
|
|
|
|
+ if (data->StepNo < data->Ranges.Size)
|
|
|
{
|
|
{
|
|
|
- IM_ASSERT(ItemsHeight > 0.0f);
|
|
|
|
|
-
|
|
|
|
|
- int already_submitted = DisplayEnd;
|
|
|
|
|
- ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd);
|
|
|
|
|
- DisplayStart += already_submitted;
|
|
|
|
|
- DisplayEnd += already_submitted;
|
|
|
|
|
-
|
|
|
|
|
- // Seek cursor
|
|
|
|
|
- if (DisplayStart > already_submitted)
|
|
|
|
|
- SetCursorPosYAndSetupForPrevLine(StartPosY + (DisplayStart - ItemsFrozen) * ItemsHeight, ItemsHeight);
|
|
|
|
|
-
|
|
|
|
|
- StepNo = 3;
|
|
|
|
|
|
|
+ DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
|
|
|
|
|
+ DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, ItemsCount);
|
|
|
|
|
+ if (DisplayStart > already_submitted) //-V1051
|
|
|
|
|
+ ImGuiListClipper_SeekCursorForItem(this, DisplayStart);
|
|
|
|
|
+ data->StepNo++;
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
|
|
|
|
|
|
|
+ // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
|
|
|
// Advance the cursor to the end of the list and then returns 'false' to end the loop.
|
|
// Advance the cursor to the end of the list and then returns 'false' to end the loop.
|
|
|
- if (StepNo == 3)
|
|
|
|
|
- {
|
|
|
|
|
- // Seek cursor
|
|
|
|
|
- if (ItemsCount < INT_MAX)
|
|
|
|
|
- SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight); // advance cursor
|
|
|
|
|
- ItemsCount = -1;
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (ItemsCount < INT_MAX)
|
|
|
|
|
+ ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
|
|
|
|
|
+ ItemsCount = -1;
|
|
|
|
|
|
|
|
- IM_ASSERT(0);
|
|
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -3109,7 +3187,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
|
|
if (id)
|
|
if (id)
|
|
|
{
|
|
{
|
|
|
g.ActiveIdIsAlive = id;
|
|
g.ActiveIdIsAlive = id;
|
|
|
- g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
|
|
|
|
|
|
+ g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Clear declaration of inputs claimed by the widget
|
|
// Clear declaration of inputs claimed by the widget
|
|
@@ -3297,48 +3375,6 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Called by ItemAdd()
|
|
|
|
|
-// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
|
|
|
|
|
-// [WIP] This will eventually be refactored and moved into NavProcessItem()
|
|
|
|
|
-void ImGui::ItemInputable(ImGuiWindow* window, ImGuiID id)
|
|
|
|
|
-{
|
|
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
|
- IM_ASSERT(id != 0 && id == g.LastItemData.ID);
|
|
|
|
|
-
|
|
|
|
|
- // Increment counters
|
|
|
|
|
- // FIXME: ImGuiItemFlags_Disabled should disable more.
|
|
|
|
|
- const bool is_tab_stop = (g.LastItemData.InFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
|
|
|
|
|
- if (is_tab_stop)
|
|
|
|
|
- {
|
|
|
|
|
- window->DC.FocusCounterTabStop++;
|
|
|
|
|
- if (g.NavId == id)
|
|
|
|
|
- g.NavIdTabCounter = window->DC.FocusCounterTabStop;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 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)
|
|
|
|
|
- if (g.ActiveId == id && g.TabFocusPressed && g.TabFocusRequestNextWindow == NULL)
|
|
|
|
|
- {
|
|
|
|
|
- g.TabFocusRequestNextWindow = window;
|
|
|
|
|
- g.TabFocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (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.
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Handle focus requests
|
|
|
|
|
- if (g.TabFocusRequestCurrWindow == window)
|
|
|
|
|
- {
|
|
|
|
|
- if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
|
|
|
|
|
- {
|
|
|
|
|
- g.NavJustTabbedId = id; // FIXME-NAV: aim to eventually set in NavUpdate() once we finish the refactor
|
|
|
|
|
- g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // If another item is about to be focused, we clear our own active id
|
|
|
|
|
- if (g.ActiveId == id)
|
|
|
|
|
- ClearActiveID();
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
|
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
|
|
{
|
|
{
|
|
|
if (wrap_pos_x < 0.0f)
|
|
if (wrap_pos_x < 0.0f)
|
|
@@ -3833,44 +3869,6 @@ void ImGui::UpdateMouseWheel()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImGui::UpdateTabFocus()
|
|
|
|
|
-{
|
|
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
|
|
-
|
|
|
|
|
- // Pressing TAB activate widget focus
|
|
|
|
|
- g.TabFocusPressed = false;
|
|
|
|
|
- if (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
|
|
- if (!g.IO.KeyCtrl && !g.IO.KeyAlt && IsKeyPressedMap(ImGuiKey_Tab) && !IsActiveIdUsingKey(ImGuiKey_Tab))
|
|
|
|
|
- g.TabFocusPressed = true;
|
|
|
|
|
- if (g.ActiveId == 0 && g.TabFocusPressed)
|
|
|
|
|
- {
|
|
|
|
|
- // - This path is only taken when no widget are active/tabbed-into yet.
|
|
|
|
|
- // Subsequent tabbing will be processed by FocusableItemRegister()
|
|
|
|
|
- // - Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
|
|
|
|
|
- // manipulate the Next fields here even though they will be turned into Curr fields below.
|
|
|
|
|
- g.TabFocusRequestNextWindow = g.NavWindow;
|
|
|
|
|
- if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
|
|
|
|
|
- g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + (g.IO.KeyShift ? -1 : 0);
|
|
|
|
|
- else
|
|
|
|
|
- g.TabFocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Turn queued focus request into current one
|
|
|
|
|
- g.TabFocusRequestCurrWindow = NULL;
|
|
|
|
|
- g.TabFocusRequestCurrCounterTabStop = INT_MAX;
|
|
|
|
|
- if (g.TabFocusRequestNextWindow != NULL)
|
|
|
|
|
- {
|
|
|
|
|
- ImGuiWindow* window = g.TabFocusRequestNextWindow;
|
|
|
|
|
- g.TabFocusRequestCurrWindow = window;
|
|
|
|
|
- if (g.TabFocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
|
|
|
|
|
- g.TabFocusRequestCurrCounterTabStop = ImModPositive(g.TabFocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
|
|
|
|
|
- g.TabFocusRequestNextWindow = NULL;
|
|
|
|
|
- g.TabFocusRequestNextCounterTabStop = INT_MAX;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- g.NavIdTabCounter = INT_MAX;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
|
|
// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
|
|
|
void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|
void ImGui::UpdateHoveredWindowAndCaptureFlags()
|
|
|
{
|
|
{
|
|
@@ -4116,9 +4114,6 @@ void ImGui::NewFrame()
|
|
|
// Mouse wheel scrolling, scale
|
|
// Mouse wheel scrolling, scale
|
|
|
UpdateMouseWheel();
|
|
UpdateMouseWheel();
|
|
|
|
|
|
|
|
- // Update legacy TAB focus
|
|
|
|
|
- UpdateTabFocus();
|
|
|
|
|
-
|
|
|
|
|
// Mark all windows as not visible and compact unused memory.
|
|
// Mark all windows as not visible and compact unused memory.
|
|
|
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
|
|
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
|
|
|
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
|
|
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
|
|
@@ -4254,6 +4249,8 @@ void ImGui::Shutdown(ImGuiContext* context)
|
|
|
g.CurrentTabBarStack.clear();
|
|
g.CurrentTabBarStack.clear();
|
|
|
g.ShrinkWidthBuffer.clear();
|
|
g.ShrinkWidthBuffer.clear();
|
|
|
|
|
|
|
|
|
|
+ g.ClipperTempData.clear_destruct();
|
|
|
|
|
+
|
|
|
g.Tables.Clear();
|
|
g.Tables.Clear();
|
|
|
g.TablesTempData.clear_destruct();
|
|
g.TablesTempData.clear_destruct();
|
|
|
g.DrawChannelsTempMergeBuffer.clear();
|
|
g.DrawChannelsTempMergeBuffer.clear();
|
|
@@ -5491,7 +5488,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
|
|
|
bool hovered, held;
|
|
bool hovered, held;
|
|
|
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
|
|
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
|
|
|
ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
|
|
ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
|
|
|
- ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren);
|
|
|
|
|
|
|
+ ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
|
|
|
//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
|
|
//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
|
|
|
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
|
|
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
|
|
|
{
|
|
{
|
|
@@ -5680,6 +5677,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
|
|
|
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
|
|
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
|
|
|
|
|
|
|
|
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
|
|
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
|
|
|
|
|
+ // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref?
|
|
|
const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
|
|
const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
|
|
|
g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
|
|
g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
|
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
|
|
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
|
|
@@ -6166,7 +6164,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
// Inner rectangle
|
|
// Inner rectangle
|
|
|
// Not affected by window border size. Used by:
|
|
// Not affected by window border size. Used by:
|
|
|
// - InnerClipRect
|
|
// - InnerClipRect
|
|
|
- // - ScrollToBringRectIntoView()
|
|
|
|
|
|
|
+ // - ScrollToRectEx()
|
|
|
// - NavUpdatePageUpPageDown()
|
|
// - NavUpdatePageUpPageDown()
|
|
|
// - Scrollbar()
|
|
// - Scrollbar()
|
|
|
window->InnerRect.Min.x = window->Pos.x;
|
|
window->InnerRect.Min.x = window->Pos.x;
|
|
@@ -6326,7 +6324,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->DC.CurrentColumns = NULL;
|
|
window->DC.CurrentColumns = NULL;
|
|
|
window->DC.LayoutType = ImGuiLayoutType_Vertical;
|
|
window->DC.LayoutType = ImGuiLayoutType_Vertical;
|
|
|
window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
|
|
window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
|
|
|
- window->DC.FocusCounterTabStop = -1;
|
|
|
|
|
|
|
|
|
|
window->DC.ItemWidth = window->ItemWidthDefault;
|
|
window->DC.ItemWidth = window->ItemWidthDefault;
|
|
|
window->DC.TextWrapPos = -1.0f; // disabled
|
|
window->DC.TextWrapPos = -1.0f; // disabled
|
|
@@ -7112,11 +7109,16 @@ void ImGui::SetKeyboardFocusHere(int offset)
|
|
|
IM_ASSERT(offset >= -1); // -1 is allowed but not below
|
|
IM_ASSERT(offset >= -1); // -1 is allowed but not below
|
|
|
g.NavWindow = window;
|
|
g.NavWindow = window;
|
|
|
ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
|
|
ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
|
|
|
- NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_None, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
|
|
|
|
|
|
|
+ NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
|
|
|
if (offset == -1)
|
|
if (offset == -1)
|
|
|
- NavMoveRequestResolveWithLastItem();
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal);
|
|
|
|
|
+ }
|
|
|
else
|
|
else
|
|
|
- g.NavTabbingInputableRemaining = offset + 1;
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ g.NavTabbingDir = 1;
|
|
|
|
|
+ g.NavTabbingCounter = offset + 1;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImGui::SetItemDefaultFocus()
|
|
void ImGui::SetItemDefaultFocus()
|
|
@@ -7598,11 +7600,6 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
|
|
return false;
|
|
return false;
|
|
|
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
|
|
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
|
|
|
|
|
|
|
|
- // [WIP] Tab stop handling (previously was using internal FocusableItemRegister() api)
|
|
|
|
|
- // FIXME-NAV: We would now want to move this before the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343)
|
|
|
|
|
- if (extra_flags & ImGuiItemFlags_Inputable)
|
|
|
|
|
- ItemInputable(window, id);
|
|
|
|
|
-
|
|
|
|
|
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
|
|
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
|
|
|
if (IsMouseHoveringRect(bb.Min, bb.Max))
|
|
if (IsMouseHoveringRect(bb.Min, bb.Max))
|
|
|
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
|
|
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
|
|
@@ -8044,8 +8041,8 @@ ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGui
|
|
|
|
|
|
|
|
const bool fully_visible_x = item_rect.Min.x >= window_rect.Min.x && item_rect.Max.x <= window_rect.Max.x;
|
|
const bool fully_visible_x = item_rect.Min.x >= window_rect.Min.x && item_rect.Max.x <= window_rect.Max.x;
|
|
|
const bool fully_visible_y = item_rect.Min.y >= window_rect.Min.y && item_rect.Max.y <= window_rect.Max.y;
|
|
const bool fully_visible_y = item_rect.Min.y >= window_rect.Min.y && item_rect.Max.y <= window_rect.Max.y;
|
|
|
- const bool can_be_fully_visible_x = item_rect.GetWidth() <= window_rect.GetWidth();
|
|
|
|
|
- const bool can_be_fully_visible_y = item_rect.GetHeight() <= window_rect.GetHeight();
|
|
|
|
|
|
|
+ const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= window_rect.GetWidth();
|
|
|
|
|
+ const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= window_rect.GetHeight();
|
|
|
|
|
|
|
|
if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)
|
|
if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)
|
|
|
{
|
|
{
|
|
@@ -8812,8 +8809,6 @@ void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id
|
|
|
g.NavFocusScopeId = focus_scope_id;
|
|
g.NavFocusScopeId = focus_scope_id;
|
|
|
g.NavWindow->NavLastIds[nav_layer] = id;
|
|
g.NavWindow->NavLastIds[nav_layer] = id;
|
|
|
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
|
|
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
|
|
|
- //g.NavDisableHighlight = false;
|
|
|
|
|
- //g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
|
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
|
@@ -9046,19 +9041,17 @@ static void ImGui::NavProcessItem()
|
|
|
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)
|
|
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)
|
|
|
if (g.NavMoveScoringItems)
|
|
if (g.NavMoveScoringItems)
|
|
|
{
|
|
{
|
|
|
- if (item_flags & ImGuiItemFlags_Inputable)
|
|
|
|
|
- g.NavTabbingInputableRemaining--;
|
|
|
|
|
-
|
|
|
|
|
- if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
|
|
|
|
|
|
+ const bool is_tab_stop = (item_flags & ImGuiItemFlags_Inputable) && (item_flags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
|
|
|
|
|
+ const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) != 0;
|
|
|
|
|
+ if (is_tabbing)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (is_tab_stop || (g.NavMoveFlags & ImGuiNavMoveFlags_FocusApi))
|
|
|
|
|
+ NavProcessItemForTabbingRequest(window, id);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
|
|
{
|
|
{
|
|
|
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
-
|
|
|
|
|
- if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing)
|
|
|
|
|
- {
|
|
|
|
|
- if (g.NavTabbingInputableRemaining == 0)
|
|
|
|
|
- NavMoveRequestResolveWithLastItem();
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
|
|
+ if (!is_tabbing)
|
|
|
{
|
|
{
|
|
|
if (NavScoreItem(result))
|
|
if (NavScoreItem(result))
|
|
|
NavApplyItemToResult(result);
|
|
NavApplyItemToResult(result);
|
|
@@ -9084,6 +9077,52 @@ static void ImGui::NavProcessItem()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest().
|
|
|
|
|
+// Note that SetKeyboardFocusHere() API calls are considered tabbing requests!
|
|
|
|
|
+// - Case 1: no nav/active id: set result to first eligible item, stop storing.
|
|
|
|
|
+// - Case 2: tab forward: on ref id set counter, on counter elapse store result
|
|
|
|
|
+// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request
|
|
|
|
|
+// - Case 4: tab backward: store all results, on ref id pick prev, stop storing
|
|
|
|
|
+// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested
|
|
|
|
|
+void ImGui::NavProcessItemForTabbingRequest(ImGuiWindow* window, ImGuiID id)
|
|
|
|
|
+{
|
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
|
|
+
|
|
|
|
|
+ ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
|
|
|
|
+ if (g.NavTabbingDir == +1)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Tab Forward or SetKeyboardFocusHere() with >= 0
|
|
|
|
|
+ if (g.NavTabbingResultFirst.ID == 0)
|
|
|
|
|
+ NavApplyItemToResult(&g.NavTabbingResultFirst);
|
|
|
|
|
+ if (--g.NavTabbingCounter == 0)
|
|
|
|
|
+ NavMoveRequestResolveWithLastItem(result);
|
|
|
|
|
+ else if (g.NavId == id)
|
|
|
|
|
+ g.NavTabbingCounter = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (g.NavTabbingDir == -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Tab Backward
|
|
|
|
|
+ if (g.NavId == id)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (result->ID)
|
|
|
|
|
+ {
|
|
|
|
|
+ g.NavMoveScoringItems = false;
|
|
|
|
|
+ NavUpdateAnyRequestFlag();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ NavApplyItemToResult(result);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (g.NavTabbingDir == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Tab Init
|
|
|
|
|
+ if (g.NavTabbingResultFirst.ID == 0)
|
|
|
|
|
+ NavMoveRequestResolveWithLastItem(&g.NavTabbingResultFirst);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
bool ImGui::NavMoveRequestButNoResultYet()
|
|
bool ImGui::NavMoveRequestButNoResultYet()
|
|
|
{
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -9107,18 +9146,18 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM
|
|
|
g.NavMoveScrollFlags = scroll_flags;
|
|
g.NavMoveScrollFlags = scroll_flags;
|
|
|
g.NavMoveForwardToNextFrame = false;
|
|
g.NavMoveForwardToNextFrame = false;
|
|
|
g.NavMoveKeyMods = g.IO.KeyMods;
|
|
g.NavMoveKeyMods = g.IO.KeyMods;
|
|
|
- g.NavTabbingInputableRemaining = 0;
|
|
|
|
|
|
|
+ g.NavTabbingCounter = 0;
|
|
|
g.NavMoveResultLocal.Clear();
|
|
g.NavMoveResultLocal.Clear();
|
|
|
g.NavMoveResultLocalVisible.Clear();
|
|
g.NavMoveResultLocalVisible.Clear();
|
|
|
g.NavMoveResultOther.Clear();
|
|
g.NavMoveResultOther.Clear();
|
|
|
NavUpdateAnyRequestFlag();
|
|
NavUpdateAnyRequestFlag();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImGui::NavMoveRequestResolveWithLastItem()
|
|
|
|
|
|
|
+void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
|
|
|
{
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
ImGuiContext& g = *GImGui;
|
|
|
g.NavMoveScoringItems = false; // Ensure request doesn't need more processing
|
|
g.NavMoveScoringItems = false; // Ensure request doesn't need more processing
|
|
|
- NavApplyItemToResult(&g.NavMoveResultLocal);
|
|
|
|
|
|
|
+ NavApplyItemToResult(result);
|
|
|
NavUpdateAnyRequestFlag();
|
|
NavUpdateAnyRequestFlag();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -9188,6 +9227,11 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
|
|
|
g.NavLayer = layer;
|
|
g.NavLayer = layer;
|
|
|
NavInitWindow(window, true);
|
|
NavInitWindow(window, true);
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void ImGui::NavRestoreHighlightAfterMove()
|
|
|
|
|
+{
|
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
g.NavDisableHighlight = false;
|
|
g.NavDisableHighlight = false;
|
|
|
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
|
}
|
|
}
|
|
@@ -9348,7 +9392,7 @@ static void ImGui::NavUpdate()
|
|
|
// Process navigation move request
|
|
// Process navigation move request
|
|
|
if (g.NavMoveSubmitted)
|
|
if (g.NavMoveSubmitted)
|
|
|
NavMoveRequestApplyResult();
|
|
NavMoveRequestApplyResult();
|
|
|
- g.NavTabbingInputableRemaining = 0;
|
|
|
|
|
|
|
+ g.NavTabbingCounter = 0;
|
|
|
g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
|
g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
|
|
|
|
|
|
|
// Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)
|
|
// Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)
|
|
@@ -9357,8 +9401,6 @@ static void ImGui::NavUpdate()
|
|
|
if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
|
|
if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
|
|
|
set_mouse_pos = true;
|
|
set_mouse_pos = true;
|
|
|
g.NavMousePosDirty = false;
|
|
g.NavMousePosDirty = false;
|
|
|
- g.NavIdIsAlive = false;
|
|
|
|
|
- g.NavJustTabbedId = 0;
|
|
|
|
|
IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu);
|
|
IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu);
|
|
|
|
|
|
|
|
// Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
|
|
// Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
|
|
@@ -9420,7 +9462,10 @@ static void ImGui::NavUpdate()
|
|
|
|
|
|
|
|
// Process move requests
|
|
// Process move requests
|
|
|
NavUpdateCreateMoveRequest();
|
|
NavUpdateCreateMoveRequest();
|
|
|
|
|
+ if (g.NavMoveDir == ImGuiDir_None)
|
|
|
|
|
+ NavUpdateCreateTabbingRequest();
|
|
|
NavUpdateAnyRequestFlag();
|
|
NavUpdateAnyRequestFlag();
|
|
|
|
|
+ g.NavIdIsAlive = false;
|
|
|
|
|
|
|
|
// Scrolling
|
|
// Scrolling
|
|
|
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
|
|
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
|
|
@@ -9487,10 +9532,7 @@ void ImGui::NavInitRequestApplyResult()
|
|
|
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
|
|
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
|
|
|
g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
|
|
g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
|
|
|
if (g.NavInitRequestFromMove)
|
|
if (g.NavInitRequestFromMove)
|
|
|
- {
|
|
|
|
|
- g.NavDisableHighlight = false;
|
|
|
|
|
- g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImGui::NavUpdateCreateMoveRequest()
|
|
void ImGui::NavUpdateCreateMoveRequest()
|
|
@@ -9522,6 +9564,7 @@ void ImGui::NavUpdateCreateMoveRequest()
|
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
|
|
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
|
|
|
}
|
|
}
|
|
|
g.NavMoveClipDir = g.NavMoveDir;
|
|
g.NavMoveClipDir = g.NavMoveDir;
|
|
|
|
|
+ g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Update PageUp/PageDown/Home/End scroll
|
|
// Update PageUp/PageDown/Home/End scroll
|
|
@@ -9530,6 +9573,11 @@ void ImGui::NavUpdateCreateMoveRequest()
|
|
|
float scoring_rect_offset_y = 0.0f;
|
|
float scoring_rect_offset_y = 0.0f;
|
|
|
if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
|
|
if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
|
|
|
scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
|
scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
|
|
|
|
+ if (scoring_rect_offset_y != 0.0f)
|
|
|
|
|
+ {
|
|
|
|
|
+ g.NavScoringNoClipRect = window->InnerRect;
|
|
|
|
|
+ g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// [DEBUG] Always send a request
|
|
// [DEBUG] Always send a request
|
|
|
#if IMGUI_DEBUG_NAV_SCORING
|
|
#if IMGUI_DEBUG_NAV_SCORING
|
|
@@ -9583,8 +9631,35 @@ void ImGui::NavUpdateCreateMoveRequest()
|
|
|
scoring_rect.Max.x = scoring_rect.Min.x;
|
|
scoring_rect.Max.x = scoring_rect.Min.x;
|
|
|
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
|
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
|
|
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
|
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
|
|
|
|
+ //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
|
|
|
}
|
|
}
|
|
|
g.NavScoringRect = scoring_rect;
|
|
g.NavScoringRect = scoring_rect;
|
|
|
|
|
+ g.NavScoringNoClipRect.Add(scoring_rect);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void ImGui::NavUpdateCreateTabbingRequest()
|
|
|
|
|
+{
|
|
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
|
|
+ ImGuiWindow* window = g.NavWindow;
|
|
|
|
|
+ IM_ASSERT(g.NavMoveDir == ImGuiDir_None);
|
|
|
|
|
+ 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;
|
|
|
|
|
+ if (!tab_pressed)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // Initiate tabbing request
|
|
|
|
|
+ // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!)
|
|
|
|
|
+ // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests.
|
|
|
|
|
+ // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping.
|
|
|
|
|
+ //// FIXME: We use (g.ActiveId == 0) but (g.NavDisableHighlight == false) might be righter once we can tab through anything
|
|
|
|
|
+ g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1;
|
|
|
|
|
+ ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
|
|
|
|
|
+ ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down;
|
|
|
|
|
+ NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
|
|
|
|
|
+ g.NavTabbingResultFirst.Clear();
|
|
|
|
|
+ g.NavTabbingCounter = -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
|
|
// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
|
|
@@ -9599,16 +9674,21 @@ void ImGui::NavMoveRequestApplyResult()
|
|
|
// Select which result to use
|
|
// Select which result to use
|
|
|
ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL;
|
|
ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL;
|
|
|
|
|
|
|
|
|
|
+ // Tabbing forward wrap
|
|
|
|
|
+ if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing)
|
|
|
|
|
+ if (g.NavTabbingCounter == 1 || g.NavTabbingDir == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ IM_ASSERT(g.NavTabbingResultFirst.ID != 0);
|
|
|
|
|
+ result = &g.NavTabbingResultFirst;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
|
|
// In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
|
|
|
if (result == NULL)
|
|
if (result == NULL)
|
|
|
{
|
|
{
|
|
|
if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing)
|
|
if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing)
|
|
|
g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight;
|
|
g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight;
|
|
|
if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0)
|
|
if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0)
|
|
|
- {
|
|
|
|
|
- g.NavDisableHighlight = false;
|
|
|
|
|
- g.NavDisableMouseHover = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -9639,8 +9719,9 @@ void ImGui::NavMoveRequestApplyResult()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ClearActiveID();
|
|
|
|
|
g.NavWindow = result->Window;
|
|
g.NavWindow = result->Window;
|
|
|
|
|
+ if (g.ActiveId != result->ID)
|
|
|
|
|
+ ClearActiveID();
|
|
|
if (g.NavId != result->ID)
|
|
if (g.NavId != result->ID)
|
|
|
{
|
|
{
|
|
|
// Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
|
|
// Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
|
|
@@ -9670,10 +9751,7 @@ void ImGui::NavMoveRequestApplyResult()
|
|
|
|
|
|
|
|
// Enable nav highlight
|
|
// Enable nav highlight
|
|
|
if ((g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0)
|
|
if ((g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0)
|
|
|
- {
|
|
|
|
|
- g.NavDisableHighlight = false;
|
|
|
|
|
- g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Process NavCancel input (to close a popup, get back to parent, clear focus)
|
|
// Process NavCancel input (to close a popup, get back to parent, clear focus)
|
|
@@ -9696,6 +9774,7 @@ static void ImGui::NavUpdateCancelRequest()
|
|
|
{
|
|
{
|
|
|
// Leave the "menu" layer
|
|
// Leave the "menu" layer
|
|
|
NavRestoreLayer(ImGuiNavLayer_Main);
|
|
NavRestoreLayer(ImGuiNavLayer_Main);
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
}
|
|
}
|
|
|
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
|
{
|
|
{
|
|
@@ -9706,6 +9785,7 @@ static void ImGui::NavUpdateCancelRequest()
|
|
|
ImRect child_rect = child_window->Rect();
|
|
ImRect child_rect = child_window->Rect();
|
|
|
FocusWindow(parent_window);
|
|
FocusWindow(parent_window);
|
|
|
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
|
|
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
}
|
|
}
|
|
|
else if (g.OpenPopupStack.Size > 0)
|
|
else if (g.OpenPopupStack.Size > 0)
|
|
|
{
|
|
{
|
|
@@ -9732,7 +9812,7 @@ static float ImGui::NavUpdatePageUpPageDown()
|
|
|
ImGuiIO& io = g.IO;
|
|
ImGuiIO& io = g.IO;
|
|
|
|
|
|
|
|
ImGuiWindow* window = g.NavWindow;
|
|
ImGuiWindow* window = g.NavWindow;
|
|
|
- if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
|
|
|
|
|
|
|
+ if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL)
|
|
|
return 0.0f;
|
|
return 0.0f;
|
|
|
|
|
|
|
|
const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
|
|
const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
|
|
@@ -9742,6 +9822,9 @@ static float ImGui::NavUpdatePageUpPageDown()
|
|
|
if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
|
|
if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
|
|
|
return 0.0f;
|
|
return 0.0f;
|
|
|
|
|
|
|
|
|
|
+ if (g.NavLayer != ImGuiNavLayer_Main)
|
|
|
|
|
+ NavRestoreLayer(ImGuiNavLayer_Main);
|
|
|
|
|
+
|
|
|
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
|
|
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
|
|
|
{
|
|
{
|
|
|
// Fallback manual-scroll when window has no navigable item
|
|
// Fallback manual-scroll when window has no navigable item
|
|
@@ -10029,8 +10112,7 @@ static void ImGui::NavUpdateWindowing()
|
|
|
if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
|
|
if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
|
|
|
{
|
|
{
|
|
|
ClearActiveID();
|
|
ClearActiveID();
|
|
|
- g.NavDisableHighlight = false;
|
|
|
|
|
- g.NavDisableMouseHover = true;
|
|
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
|
|
apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
|
|
|
ClosePopupsOverWindow(apply_focus_window, false);
|
|
ClosePopupsOverWindow(apply_focus_window, false);
|
|
|
FocusWindow(apply_focus_window);
|
|
FocusWindow(apply_focus_window);
|
|
@@ -10077,6 +10159,7 @@ static void ImGui::NavUpdateWindowing()
|
|
|
if (new_nav_layer == ImGuiNavLayer_Menu)
|
|
if (new_nav_layer == ImGuiNavLayer_Menu)
|
|
|
g.NavWindow->NavLastIds[new_nav_layer] = 0;
|
|
g.NavWindow->NavLastIds[new_nav_layer] = 0;
|
|
|
NavRestoreLayer(new_nav_layer);
|
|
NavRestoreLayer(new_nav_layer);
|
|
|
|
|
+ NavRestoreHighlightAfterMove();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -12108,7 +12191,7 @@ void ImGui::UpdateDebugToolStackQueries()
|
|
|
|
|
|
|
|
// Update queries. The steps are: -1: query Stack, >= 0: query each stack item
|
|
// Update queries. The steps are: -1: query Stack, >= 0: query each stack item
|
|
|
// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
|
|
// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
|
|
|
- const ImGuiID query_id = g.ActiveId ? g.ActiveId : g.HoveredIdPreviousFrame;
|
|
|
|
|
|
|
+ const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId;
|
|
|
if (tool->QueryId != query_id)
|
|
if (tool->QueryId != query_id)
|
|
|
{
|
|
{
|
|
|
tool->QueryId = query_id;
|
|
tool->QueryId = query_id;
|