mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-06 13:08:47 +02:00
Merge branch 'master' into docking
# Conflicts: # imgui.cpp
This commit is contained in:
366
imgui.cpp
366
imgui.cpp
@ -923,15 +923,14 @@ namespace ImGui
|
||||
static void NavUpdate();
|
||||
static void NavUpdateWindowing();
|
||||
static void NavUpdateWindowingOverlay();
|
||||
static void NavUpdateInitResult();
|
||||
static void NavUpdateCancelRequest();
|
||||
static void NavUpdateCreateMoveRequest();
|
||||
static float NavUpdatePageUpPageDown();
|
||||
static inline void NavUpdateAnyRequestFlag();
|
||||
static void NavEndFrame();
|
||||
static bool NavScoreItem(ImGuiNavItemData* result, ImRect cand);
|
||||
static void NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
|
||||
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
|
||||
static bool NavScoreItem(ImGuiNavItemData* result);
|
||||
static void NavApplyItemToResult(ImGuiNavItemData* result);
|
||||
static void NavProcessItem();
|
||||
static ImVec2 NavCalcPreferredRefPos();
|
||||
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
|
||||
static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
|
||||
@ -2294,21 +2293,21 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
|
||||
return;
|
||||
}
|
||||
|
||||
// We create the union of the ClipRect and the NavScoringRect 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;
|
||||
if (g.NavMoveRequest)
|
||||
if (g.NavMoveScoringItems)
|
||||
unclipped_rect.Add(g.NavScoringRect);
|
||||
if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
|
||||
unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
|
||||
unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); // Could store and use NavJustMovedToRectRel
|
||||
|
||||
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);
|
||||
|
||||
// When performing a navigation request, ensure we have one item extra in the direction we are moving to
|
||||
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
|
||||
if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Up)
|
||||
start--;
|
||||
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
|
||||
if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Down)
|
||||
end++;
|
||||
|
||||
start = ImClamp(start, 0, items_count);
|
||||
@ -3154,7 +3153,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
||||
if (id)
|
||||
{
|
||||
g.ActiveIdIsAlive = id;
|
||||
g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
||||
g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
||||
}
|
||||
|
||||
// Clear declaration of inputs claimed by the widget
|
||||
@ -3361,7 +3360,8 @@ void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemS
|
||||
|
||||
// Called by ItemAdd()
|
||||
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
|
||||
void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
|
||||
// [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);
|
||||
@ -3395,7 +3395,7 @@ void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
|
||||
}
|
||||
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
|
||||
{
|
||||
g.NavJustTabbedId = id;
|
||||
g.NavJustTabbedId = id; // FIXME-NAV: aim to eventually set in NavUpdate() once we finish the refactor
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
|
||||
return;
|
||||
}
|
||||
@ -3821,13 +3821,15 @@ static void ImGui::UpdateMouseInputs()
|
||||
|
||||
// Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
|
||||
if (IsMousePosValid(&g.IO.MousePos))
|
||||
g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
|
||||
g.IO.MousePos = g.MouseLastValidPos = ImFloor(g.IO.MousePos);
|
||||
|
||||
// If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
|
||||
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
|
||||
g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
|
||||
else
|
||||
g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
|
||||
|
||||
// If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true.
|
||||
if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
|
||||
g.NavDisableMouseHover = false;
|
||||
|
||||
@ -7066,7 +7068,7 @@ void ImGui::FocusWindow(ImGuiWindow* window)
|
||||
g.NavFocusScopeId = 0;
|
||||
g.NavIdIsAlive = false;
|
||||
g.NavLayer = ImGuiNavLayer_Main;
|
||||
g.NavInitRequest = g.NavMoveRequest = false;
|
||||
g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
||||
NavUpdateAnyRequestFlag();
|
||||
//IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
|
||||
}
|
||||
@ -7656,6 +7658,7 @@ void ImGui::ActivateItem(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NavNextActivateId = id;
|
||||
g.NavNextActivateFlags = ImGuiActivateFlags_None;
|
||||
}
|
||||
|
||||
void ImGui::PushFocusScope(ImGuiID id)
|
||||
@ -8124,15 +8127,17 @@ void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
|
||||
// Declare item bounding box for clipping and interaction.
|
||||
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
|
||||
// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
|
||||
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags)
|
||||
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
// Set item data
|
||||
// (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set)
|
||||
g.LastItemData.ID = id;
|
||||
g.LastItemData.Rect = bb;
|
||||
g.LastItemData.InFlags = g.CurrentItemFlags;
|
||||
g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb;
|
||||
g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags;
|
||||
g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;
|
||||
|
||||
// Directional navigation processing
|
||||
@ -8151,7 +8156,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
||||
if (g.NavId == id || g.NavAnyRequest)
|
||||
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
|
||||
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
|
||||
NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
|
||||
NavProcessItem();
|
||||
|
||||
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
|
||||
#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
@ -8175,10 +8180,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
||||
return false;
|
||||
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
|
||||
|
||||
// Tab stop handling (previously was using internal ItemFocusable() api)
|
||||
// FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343)
|
||||
if (flags & ImGuiItemAddFlags_Focusable)
|
||||
ItemFocusable(window, id);
|
||||
// [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)
|
||||
if (IsMouseHoveringRect(bb.Min, bb.Max))
|
||||
@ -8444,6 +8449,7 @@ ImVec2 ImGui::GetWindowContentRegionMax()
|
||||
|
||||
// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
|
||||
// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
|
||||
// FIXME-OPT: Could we safely early out on ->SkipItems?
|
||||
void ImGui::BeginGroup()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -9324,6 +9330,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
|
||||
// In our terminology those should be interchangeable. Those two functions are merely a legacy artifact, so at minimum naming should be clarified.
|
||||
void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -9354,7 +9361,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
||||
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
||||
window->NavLastIds[nav_layer] = id;
|
||||
if (g.LastItemData.ID == id)
|
||||
window->NavRectRel[nav_layer] = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos);
|
||||
window->NavRectRel[nav_layer] = ImRect(g.LastItemData.NavRect.Min - window->Pos, g.LastItemData.NavRect.Max - window->Pos);
|
||||
|
||||
if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
g.NavDisableMouseHover = true;
|
||||
@ -9385,7 +9392,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
|
||||
r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
|
||||
r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
|
||||
}
|
||||
else
|
||||
else // FIXME: PageUp/PageDown are leaving move_dir == None
|
||||
{
|
||||
r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
|
||||
r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
|
||||
@ -9393,15 +9400,17 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
|
||||
}
|
||||
|
||||
// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
|
||||
static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
||||
static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (g.NavLayer != window->DC.NavLayerCurrent)
|
||||
return false;
|
||||
|
||||
const ImRect& curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
|
||||
g.NavScoringCount++;
|
||||
// FIXME: Those are not good variables names
|
||||
ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle
|
||||
const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
|
||||
g.NavScoringDebugCount++;
|
||||
|
||||
// When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
|
||||
if (window->ParentWindow == g.NavWindow)
|
||||
@ -9463,24 +9472,24 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
||||
draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
|
||||
draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
|
||||
draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
|
||||
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
|
||||
draw_list->AddText(cand.Max, ~0U, buf);
|
||||
}
|
||||
else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
|
||||
{
|
||||
if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
|
||||
if (quadrant == g.NavMoveDir)
|
||||
{
|
||||
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
|
||||
ImDrawList* draw_list = GetForegroundDrawList(window);
|
||||
draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
|
||||
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
|
||||
draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Is it in the quadrant we're interesting in moving to?
|
||||
bool new_best = false;
|
||||
if (quadrant == g.NavMoveDir)
|
||||
const ImGuiDir move_dir = g.NavMoveDir;
|
||||
if (quadrant == move_dir)
|
||||
{
|
||||
// Does it beat the current best candidate?
|
||||
if (dist_box < result->DistBox)
|
||||
@ -9502,7 +9511,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
||||
// Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
|
||||
// (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
|
||||
// this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
|
||||
if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
|
||||
if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
|
||||
new_best = true;
|
||||
}
|
||||
}
|
||||
@ -9515,7 +9524,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
||||
// Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
|
||||
if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
|
||||
if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
|
||||
if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f))
|
||||
if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f))
|
||||
{
|
||||
result->DistAxial = dist_axial;
|
||||
new_best = true;
|
||||
@ -9524,23 +9533,25 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
|
||||
return new_best;
|
||||
}
|
||||
|
||||
static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
|
||||
static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
result->Window = window;
|
||||
result->ID = id;
|
||||
result->ID = g.LastItemData.ID;
|
||||
result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
||||
result->RectRel = nav_bb_rel;
|
||||
result->RectRel = ImRect(g.LastItemData.NavRect.Min - window->Pos, g.LastItemData.NavRect.Max - window->Pos);
|
||||
}
|
||||
|
||||
// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
|
||||
static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
|
||||
// This is called after LastItemData is set.
|
||||
static void ImGui::NavProcessItem()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
//if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
|
||||
// return;
|
||||
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
const ImGuiID id = g.LastItemData.ID;
|
||||
const ImRect nav_bb = g.LastItemData.NavRect;
|
||||
const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
|
||||
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
|
||||
|
||||
// Process Init Request
|
||||
if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
|
||||
@ -9550,7 +9561,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
|
||||
if (candidate_for_nav_default_focus || g.NavInitResultId == 0)
|
||||
{
|
||||
g.NavInitResultId = id;
|
||||
g.NavInitResultRectRel = nav_bb_rel;
|
||||
g.NavInitResultRectRel = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
|
||||
}
|
||||
if (candidate_for_nav_default_focus)
|
||||
{
|
||||
@ -9560,27 +9571,22 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
|
||||
}
|
||||
|
||||
// Process Move Request (scoring for navigation)
|
||||
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
|
||||
if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
||||
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)
|
||||
if (g.NavMoveScoringItems)
|
||||
{
|
||||
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
||||
#if IMGUI_DEBUG_NAV_SCORING
|
||||
// [DEBUG] Score all items in NavWindow at all times
|
||||
if (!g.NavMoveRequest)
|
||||
g.NavMoveDir = g.NavMoveDirLast;
|
||||
bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
|
||||
#else
|
||||
bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
|
||||
#endif
|
||||
if (new_best)
|
||||
NavApplyItemToResult(result, window, id, nav_bb_rel);
|
||||
if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
|
||||
{
|
||||
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
||||
if (NavScoreItem(result))
|
||||
NavApplyItemToResult(result);
|
||||
|
||||
// Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
|
||||
const float VISIBLE_RATIO = 0.70f;
|
||||
if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
|
||||
if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
|
||||
if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
|
||||
NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel);
|
||||
// Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
|
||||
const float VISIBLE_RATIO = 0.70f;
|
||||
if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
|
||||
if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
|
||||
if (NavScoreItem(&g.NavMoveResultLocalVisible))
|
||||
NavApplyItemToResult(&g.NavMoveResultLocalVisible);
|
||||
}
|
||||
}
|
||||
|
||||
// Update window-relative bounding box of navigated item
|
||||
@ -9590,20 +9596,38 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
|
||||
g.NavLayer = window->DC.NavLayerCurrent;
|
||||
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
|
||||
g.NavIdIsAlive = true;
|
||||
window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
|
||||
window->NavRectRel[window->DC.NavLayerCurrent] = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); // Store item bounding box (relative to window position)
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui::NavMoveRequestButNoResultYet()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
|
||||
return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
|
||||
}
|
||||
|
||||
// FIXME: ScoringRect is not set
|
||||
void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.NavWindow != NULL);
|
||||
g.NavMoveSubmitted = g.NavMoveScoringItems = true;
|
||||
g.NavMoveDir = move_dir;
|
||||
g.NavMoveDirForDebug = move_dir;
|
||||
g.NavMoveClipDir = clip_dir;
|
||||
g.NavMoveFlags = move_flags;
|
||||
g.NavMoveForwardToNextFrame = false;
|
||||
g.NavMoveKeyMods = g.IO.KeyMods;
|
||||
g.NavMoveResultLocal.Clear();
|
||||
g.NavMoveResultLocalVisible.Clear();
|
||||
g.NavMoveResultOther.Clear();
|
||||
NavUpdateAnyRequestFlag();
|
||||
}
|
||||
|
||||
void ImGui::NavMoveRequestCancel()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NavMoveRequest = false;
|
||||
g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
||||
NavUpdateAnyRequestFlag();
|
||||
}
|
||||
|
||||
@ -9611,12 +9635,12 @@ void ImGui::NavMoveRequestCancel()
|
||||
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.NavMoveRequestForwardToNextFrame == false);
|
||||
IM_ASSERT(g.NavMoveForwardToNextFrame == false);
|
||||
NavMoveRequestCancel();
|
||||
g.NavMoveRequestForwardToNextFrame = true;
|
||||
g.NavMoveForwardToNextFrame = true;
|
||||
g.NavMoveDir = move_dir;
|
||||
g.NavMoveClipDir = clip_dir;
|
||||
g.NavMoveRequestFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
|
||||
g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
|
||||
}
|
||||
|
||||
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
|
||||
@ -9625,8 +9649,9 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wra
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY
|
||||
if (g.NavWindow == window && g.NavMoveRequest && g.NavLayer == ImGuiNavLayer_Main)
|
||||
g.NavMoveRequestFlags |= wrap_flags;
|
||||
// In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it, NavEndFrame() will do the same test
|
||||
if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main)
|
||||
g.NavMoveFlags |= wrap_flags;
|
||||
}
|
||||
|
||||
// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
|
||||
@ -9661,20 +9686,20 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
|
||||
if (window->NavLastIds[layer] != 0)
|
||||
{
|
||||
SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
|
||||
g.NavDisableHighlight = false;
|
||||
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
g.NavLayer = layer;
|
||||
NavInitWindow(window, true);
|
||||
}
|
||||
g.NavDisableHighlight = false;
|
||||
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
||||
}
|
||||
|
||||
static inline void ImGui::NavUpdateAnyRequestFlag()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
|
||||
g.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
|
||||
if (g.NavAnyRequest)
|
||||
IM_ASSERT(g.NavWindow != NULL);
|
||||
}
|
||||
@ -9720,7 +9745,7 @@ static ImVec2 ImGui::NavCalcPreferredRefPos()
|
||||
// Mouse (we need a fallback in case the mouse becomes invalid after being used)
|
||||
if (IsMousePosValid(&g.IO.MousePos))
|
||||
return g.IO.MousePos;
|
||||
return g.LastValidMousePos;
|
||||
return g.MouseLastValidPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -9776,9 +9801,7 @@ static void ImGui::NavUpdate()
|
||||
ImGuiIO& io = g.IO;
|
||||
|
||||
io.WantSetMousePos = false;
|
||||
#if 0
|
||||
if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
|
||||
#endif
|
||||
//if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
|
||||
|
||||
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
|
||||
// (do it before we map Keyboard input!)
|
||||
@ -9814,16 +9837,16 @@ static void ImGui::NavUpdate()
|
||||
|
||||
// Process navigation init request (select first/default focus)
|
||||
if (g.NavInitResultId != 0)
|
||||
NavUpdateInitResult();
|
||||
NavInitRequestApplyResult();
|
||||
g.NavInitRequest = false;
|
||||
g.NavInitRequestFromMove = false;
|
||||
g.NavInitResultId = 0;
|
||||
g.NavJustMovedToId = 0;
|
||||
|
||||
// Process navigation move request
|
||||
if (g.NavMoveRequest)
|
||||
if (g.NavMoveSubmitted)
|
||||
NavMoveRequestApplyResult();
|
||||
g.NavMoveRequest = false;
|
||||
g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
||||
|
||||
// Apply application mouse position movement, after we had a chance to process move request result.
|
||||
if (g.NavMousePosDirty && g.NavIdIsAlive)
|
||||
@ -9834,6 +9857,7 @@ static void ImGui::NavUpdate()
|
||||
{
|
||||
io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
|
||||
io.WantSetMousePos = true;
|
||||
//IMGUI_DEBUG_LOG("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y);
|
||||
}
|
||||
g.NavMousePosDirty = false;
|
||||
}
|
||||
@ -9858,19 +9882,28 @@ static void ImGui::NavUpdate()
|
||||
NavUpdateCancelRequest();
|
||||
|
||||
// Process manual activation request
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavActivateInputId = 0;
|
||||
g.NavActivateFlags = ImGuiActivateFlags_None;
|
||||
if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
|
||||
bool input_down = IsNavInputDown(ImGuiNavInput_Input);
|
||||
bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
|
||||
bool input_pressed = input_down && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed);
|
||||
if (g.ActiveId == 0 && activate_pressed)
|
||||
{
|
||||
g.NavActivateId = g.NavId;
|
||||
g.NavActivateFlags = ImGuiActivateFlags_PreferTweak;
|
||||
}
|
||||
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed)
|
||||
{
|
||||
g.NavActivateInputId = g.NavId;
|
||||
g.NavActivateFlags = ImGuiActivateFlags_PreferInput;
|
||||
}
|
||||
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
|
||||
g.NavActivateDownId = g.NavId;
|
||||
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
|
||||
g.NavActivatePressedId = g.NavId;
|
||||
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
|
||||
g.NavInputId = g.NavId;
|
||||
}
|
||||
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
g.NavDisableHighlight = true;
|
||||
@ -9878,8 +9911,15 @@ static void ImGui::NavUpdate()
|
||||
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
|
||||
|
||||
// Process programmatic activation request
|
||||
// FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others)
|
||||
if (g.NavNextActivateId != 0)
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
|
||||
{
|
||||
if (g.NavNextActivateFlags & ImGuiActivateFlags_PreferInput)
|
||||
g.NavActivateInputId = g.NavNextActivateId;
|
||||
else
|
||||
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId;
|
||||
g.NavActivateFlags = g.NavNextActivateFlags;
|
||||
}
|
||||
g.NavNextActivateId = 0;
|
||||
|
||||
// Process move requests
|
||||
@ -9892,12 +9932,13 @@ static void ImGui::NavUpdate()
|
||||
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
||||
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) //-V560
|
||||
const ImGuiDir move_dir = g.NavMoveDir;
|
||||
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None)
|
||||
{
|
||||
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
|
||||
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
||||
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
|
||||
SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
||||
if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
|
||||
SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
||||
if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down)
|
||||
SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
||||
}
|
||||
|
||||
// *Normal* Manual scroll with NavScrollXXX keys
|
||||
@ -9909,8 +9950,15 @@ static void ImGui::NavUpdate()
|
||||
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
|
||||
}
|
||||
|
||||
// Always prioritize mouse highlight if navigation is disabled
|
||||
if (!nav_keyboard_active && !nav_gamepad_active)
|
||||
{
|
||||
g.NavDisableHighlight = true;
|
||||
g.NavDisableMouseHover = g.NavMousePosDirty = false;
|
||||
}
|
||||
|
||||
// [DEBUG]
|
||||
g.NavScoringCount = 0;
|
||||
g.NavScoringDebugCount = 0;
|
||||
#if IMGUI_DEBUG_NAV_RECTS
|
||||
if (g.NavWindow)
|
||||
{
|
||||
@ -9921,7 +9969,7 @@ static void ImGui::NavUpdate()
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ImGui::NavUpdateInitResult()
|
||||
void ImGui::NavInitRequestApplyResult()
|
||||
{
|
||||
// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -9932,6 +9980,7 @@ static void ImGui::NavUpdateInitResult()
|
||||
// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
|
||||
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
|
||||
g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
|
||||
if (g.NavInitRequestFromMove)
|
||||
{
|
||||
g.NavDisableHighlight = false;
|
||||
@ -9945,20 +9994,19 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
ImGuiIO& io = g.IO;
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
|
||||
if (g.NavMoveRequestForwardToNextFrame)
|
||||
if (g.NavMoveForwardToNextFrame && window != NULL)
|
||||
{
|
||||
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
|
||||
// (preserve most state, which were already set by the NavMoveRequestForward() function)
|
||||
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
||||
IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded);
|
||||
IM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded);
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
|
||||
g.NavMoveRequestForwardToNextFrame = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initiate directional inputs request
|
||||
g.NavMoveDir = ImGuiDir_None;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_None;
|
||||
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
|
||||
@ -9973,24 +10021,28 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
// Update PageUp/PageDown/Home/End scroll
|
||||
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
|
||||
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
|
||||
float nav_scoring_rect_offset_y = 0.0f;
|
||||
if (nav_keyboard_active)
|
||||
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
||||
float scoring_rect_offset_y = 0.0f;
|
||||
if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
|
||||
scoring_rect_offset_y = NavUpdatePageUpPageDown();
|
||||
|
||||
// If we initiate a movement request and have no current NavId, we initiate a InitDefaultRequest that will be used as a fallback if the direction fails to find a match
|
||||
if (g.NavMoveDir != ImGuiDir_None)
|
||||
// [DEBUG] Always send a request
|
||||
#if IMGUI_DEBUG_NAV_SCORING
|
||||
if (io.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
|
||||
g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3);
|
||||
if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None)
|
||||
{
|
||||
IM_ASSERT(window != NULL);
|
||||
g.NavMoveRequest = true;
|
||||
g.NavMoveRequestKeyMods = io.KeyMods;
|
||||
g.NavMoveDirLast = g.NavMoveDir;
|
||||
g.NavMoveResultLocal.Clear();
|
||||
g.NavMoveResultLocalVisibleSet.Clear();
|
||||
g.NavMoveResultOther.Clear();
|
||||
g.NavMoveDir = g.NavMoveDirForDebug;
|
||||
g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Moving with no reference triggers a init request
|
||||
if (g.NavMoveRequest && g.NavId == 0)
|
||||
// Submit
|
||||
g.NavMoveForwardToNextFrame = false;
|
||||
if (g.NavMoveDir != ImGuiDir_None)
|
||||
NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags);
|
||||
|
||||
// Moving with no reference triggers a init request (will be used as a fallback if the direction fails to find a match)
|
||||
if (g.NavMoveSubmitted && g.NavId == 0)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
|
||||
g.NavInitRequest = g.NavInitRequestFromMove = true;
|
||||
@ -10001,7 +10053,7 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
// When using gamepad, we project the reference nav bounding box into window visible area.
|
||||
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
|
||||
// (can't focus a visible object like we can with the mouse).
|
||||
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)
|
||||
if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)
|
||||
{
|
||||
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
|
||||
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
||||
@ -10015,27 +10067,35 @@ void ImGui::NavUpdateCreateMoveRequest()
|
||||
}
|
||||
|
||||
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
|
||||
g.NavScoringRect = ImRect();
|
||||
if (window)
|
||||
ImRect scoring_rect;
|
||||
if (window != NULL)
|
||||
{
|
||||
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
|
||||
g.NavScoringRect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max);
|
||||
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
|
||||
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
|
||||
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
|
||||
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
||||
//GetForegroundDrawList()->AddRect(g.NavScoringRect.Min, g.NavScoringRect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
||||
scoring_rect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max);
|
||||
scoring_rect.TranslateY(scoring_rect_offset_y);
|
||||
scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.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().
|
||||
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
||||
}
|
||||
g.NavScoringRect = scoring_rect;
|
||||
}
|
||||
|
||||
// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
|
||||
void ImGui::NavMoveRequestApplyResult()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
#if IMGUI_DEBUG_NAV_SCORING
|
||||
if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
||||
// Select which result to use
|
||||
ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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 (g.NavId != 0)
|
||||
{
|
||||
g.NavDisableHighlight = false;
|
||||
@ -10044,13 +10104,10 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
return;
|
||||
}
|
||||
|
||||
// Select which result to use
|
||||
ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
|
||||
|
||||
// PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
|
||||
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
|
||||
if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
|
||||
result = &g.NavMoveResultLocalVisibleSet;
|
||||
if (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
|
||||
if (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId)
|
||||
result = &g.NavMoveResultLocalVisible;
|
||||
|
||||
// Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
|
||||
if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
|
||||
@ -10062,7 +10119,7 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
if (g.NavLayer == ImGuiNavLayer_Main)
|
||||
{
|
||||
ImVec2 delta_scroll;
|
||||
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
|
||||
if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdge)
|
||||
{
|
||||
float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
|
||||
delta_scroll.y = result->Window->Scroll.y - scroll_target;
|
||||
@ -10086,10 +10143,14 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
// Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
|
||||
g.NavJustMovedToId = result->ID;
|
||||
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
|
||||
g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
|
||||
g.NavJustMovedToKeyMods = g.NavMoveKeyMods;
|
||||
}
|
||||
|
||||
// Focus
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
|
||||
SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
|
||||
|
||||
// Enable nav highlight
|
||||
g.NavDisableHighlight = false;
|
||||
g.NavDisableMouseHover = g.NavMousePosDirty = true;
|
||||
}
|
||||
@ -10141,18 +10202,18 @@ static void ImGui::NavUpdateCancelRequest()
|
||||
}
|
||||
|
||||
// Handle PageUp/PageDown/Home/End keys
|
||||
// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request
|
||||
// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference
|
||||
// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
|
||||
static float ImGui::NavUpdatePageUpPageDown()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
|
||||
if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
|
||||
return 0.0f;
|
||||
if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
|
||||
return 0.0f;
|
||||
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
|
||||
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
|
||||
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
|
||||
@ -10182,14 +10243,14 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
nav_scoring_rect_offset_y = -page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
|
||||
{
|
||||
nav_scoring_rect_offset_y = +page_offset_y;
|
||||
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
|
||||
g.NavMoveClipDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
|
||||
}
|
||||
else if (home_pressed)
|
||||
{
|
||||
@ -10200,7 +10261,8 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Down;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
// FIXME-NAV: MoveClipDir left to _None, intentional?
|
||||
}
|
||||
else if (end_pressed)
|
||||
{
|
||||
@ -10208,7 +10270,8 @@ static float ImGui::NavUpdatePageUpPageDown()
|
||||
if (nav_rect_rel.IsInverted())
|
||||
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
|
||||
g.NavMoveDir = ImGuiDir_Up;
|
||||
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
|
||||
// FIXME-NAV: MoveClipDir left to _None, intentional?
|
||||
}
|
||||
return nav_scoring_rect_offset_y;
|
||||
}
|
||||
@ -10226,9 +10289,9 @@ static void ImGui::NavEndFrame()
|
||||
// Perform wrap-around in menus
|
||||
// FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.
|
||||
ImGuiWindow* window = g.NavWindow;
|
||||
const ImGuiNavMoveFlags move_flags = g.NavMoveRequestFlags;
|
||||
const ImGuiNavMoveFlags move_flags = g.NavMoveFlags;
|
||||
const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY;
|
||||
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
|
||||
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & wanted_flags) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0)
|
||||
{
|
||||
bool do_forward = false;
|
||||
ImRect bb_rel = window->NavRectRel[g.NavLayer];
|
||||
@ -10484,15 +10547,17 @@ static void ImGui::NavUpdateWindowing()
|
||||
FocusWindow(new_nav_window);
|
||||
new_nav_window->NavLastChildNavWindow = old_nav_window;
|
||||
}
|
||||
g.NavDisableHighlight = false;
|
||||
g.NavDisableMouseHover = true;
|
||||
|
||||
// Reinitialize navigation when entering menu bar with the Alt key.
|
||||
// Toggle layer
|
||||
const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
|
||||
const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
|
||||
if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
|
||||
g.NavWindow->NavLastIds[new_nav_layer] = 0;
|
||||
NavRestoreLayer(new_nav_layer);
|
||||
if (new_nav_layer != g.NavLayer)
|
||||
{
|
||||
// Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?)
|
||||
const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
|
||||
if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
|
||||
g.NavWindow->NavLastIds[new_nav_layer] = 0;
|
||||
NavRestoreLayer(new_nav_layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10587,14 +10652,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
|
||||
return false;
|
||||
if (g.ActiveIdMouseButton != -1)
|
||||
mouse_button = g.ActiveIdMouseButton;
|
||||
if (g.IO.MouseDown[mouse_button] == false)
|
||||
if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
|
||||
return false;
|
||||
g.ActiveIdAllowOverlap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Uncommon path: items without ID
|
||||
if (g.IO.MouseDown[mouse_button] == false)
|
||||
if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
|
||||
return false;
|
||||
if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
|
||||
return false;
|
||||
|
||||
// If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
|
||||
@ -10605,10 +10672,6 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early out
|
||||
if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
|
||||
return false;
|
||||
|
||||
// Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
|
||||
// We build a throwaway ID based on current ID stack + relative AABB of items in window.
|
||||
// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
|
||||
@ -10774,7 +10837,7 @@ bool ImGui::BeginDragDropTarget()
|
||||
if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect))
|
||||
return false;
|
||||
ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
|
||||
if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree)
|
||||
if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree || window->SkipItems)
|
||||
return false;
|
||||
|
||||
const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;
|
||||
@ -16716,7 +16779,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
|
||||
Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
|
||||
Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
|
||||
Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
|
||||
Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId);
|
||||
Text("NavActivateFlags: %04X", g.NavActivateFlags);
|
||||
Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
|
||||
Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
|
||||
Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
|
||||
|
Reference in New Issue
Block a user