Nav: Refactor NavMoveResult** flags into ImGuiNavMoveResult structure as we are going to want two instances of it. (#787) (+1 squashed commits)

+ store window inside result.
This commit is contained in:
omar 2018-01-29 18:28:46 +01:00
parent 1cf38d0334
commit 72485a5d04
2 changed files with 45 additions and 36 deletions

View File

@ -2132,7 +2132,7 @@ static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
}
// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
static bool NavScoreItem(ImRect cand)
static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.NavWindow;
@ -2207,21 +2207,21 @@ static bool NavScoreItem(ImRect cand)
if (quadrant == g.NavMoveDir)
{
// Does it beat the current best candidate?
if (dist_box < g.NavMoveResultDistBox)
if (dist_box < result->DistBox)
{
g.NavMoveResultDistBox = dist_box;
g.NavMoveResultDistCenter = dist_center;
result->DistBox = dist_box;
result->DistCenter = dist_center;
return true;
}
if (dist_box == g.NavMoveResultDistBox)
if (dist_box == result->DistBox)
{
// Try using distance between center points to break ties
if (dist_center < g.NavMoveResultDistCenter)
if (dist_center < result->DistCenter)
{
g.NavMoveResultDistCenter = dist_center;
result->DistCenter = dist_center;
new_best = true;
}
else if (dist_center == g.NavMoveResultDistCenter)
else if (dist_center == result->DistCenter)
{
// 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),
@ -2237,11 +2237,11 @@ static bool NavScoreItem(ImRect cand)
// This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
// 2017/09/29: FIXME: This now currently only enabled inside menubars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
// Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
if (g.NavMoveResultDistBox == FLT_MAX && dist_axial < g.NavMoveResultDistAxial) // Check axial match
if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
if (g.NavLayer == 1 && !(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))
{
g.NavMoveResultDistAxial = dist_axial;
result->DistAxial = dist_axial;
new_best = true;
}
@ -2288,19 +2288,21 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
// Scoring for navigation
if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
{
ImGuiNavMoveResult* result = &g.NavMoveResult;
#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(nav_bb) && g.NavMoveRequest;
bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
#else
bool new_best = g.NavMoveRequest && NavScoreItem(nav_bb);
bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
#endif
if (new_best)
{
g.NavMoveResultId = id;
g.NavMoveResultParentId = window->IDStack.back();
g.NavMoveResultRectRel = nav_bb_rel;
result->ID = id;
result->ParentID = window->IDStack.back();
result->Window = window;
result->RectRel = nav_bb_rel;
}
}
@ -2881,17 +2883,18 @@ static void ImGui::NavUpdate()
g.NavJustMovedToId = 0;
// Process navigation move request
if (g.NavMoveRequest && g.NavMoveResultId != 0)
if (g.NavMoveRequest && g.NavMoveResult.ID != 0)
{
// Scroll to keep newly navigated item fully into view
IM_ASSERT(g.NavWindow);
ImGuiNavMoveResult* result = &g.NavMoveResult;
IM_ASSERT(g.NavWindow && result->Window);
if (g.NavLayer == 0)
NavScrollToBringItemIntoView(g.NavWindow, g.NavMoveResultRectRel);
NavScrollToBringItemIntoView(result->Window, result->RectRel);
// Apply result from previous frame navigation directional move request
ClearActiveID();
SetNavIDAndMoveMouse(g.NavMoveResultId, g.NavLayer, g.NavMoveResultRectRel);
g.NavJustMovedToId = g.NavMoveResultId;
SetNavIDAndMoveMouse(result->ID, g.NavLayer, result->RectRel);
g.NavJustMovedToId = result->ID;
g.NavMoveFromClampedRefRect = false;
}
@ -2899,7 +2902,7 @@ static void ImGui::NavUpdate()
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
{
IM_ASSERT(g.NavMoveRequest);
if (g.NavMoveResultId == 0)
if (g.NavMoveResult.ID == 0)
g.NavDisableHighlight = false;
g.NavMoveRequestForward = ImGuiNavForward_None;
}
@ -3058,9 +3061,10 @@ static void ImGui::NavUpdate()
}
// Reset search
g.NavMoveResultId = 0;
g.NavMoveResultParentId = 0;
g.NavMoveResultDistAxial = g.NavMoveResultDistBox = g.NavMoveResultDistCenter = FLT_MAX;
ImGuiNavMoveResult* result = &g.NavMoveResult;
result->ID = result->ParentID = 0;
result->Window = NULL;
result->DistAxial = result->DistBox = result->DistCenter = FLT_MAX;
// When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
@ -4821,7 +4825,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
static void NavProcessMoveRequestWrapAround(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
if (g.NavMoveRequest && g.NavWindow == window && g.NavMoveResultId == 0)
if (g.NavMoveRequest && g.NavWindow == window && g.NavMoveResult.ID == 0)
if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0)
{
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
@ -10856,7 +10860,7 @@ void ImGui::EndMenuBar()
ImGuiContext& g = *GImGui;
// Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
if (g.NavMoveRequest && g.NavMoveResultId == 0 && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
if (g.NavMoveRequest && g.NavMoveResult.ID == 0 && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
{
ImGuiWindow* nav_earliest_child = g.NavWindow;
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
@ -11024,7 +11028,7 @@ void ImGui::EndMenu()
// Nav: When a left move request within our child menu failed, close the menu
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveRequest && g.NavMoveResultId == 0 && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical)
if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveRequest && g.NavMoveResult.ID == 0 && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical)
{
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
g.NavMoveRequest = false;

View File

@ -504,6 +504,19 @@ struct ImDrawDataBuilder
IMGUI_API void FlattenIntoSingleLayer();
};
struct ImGuiNavMoveResult
{
ImGuiID ID; // Best candidate
ImGuiID ParentID; // Best candidate window->IDStack.back() - to compare context
ImGuiWindow* Window; // Best candidate window
float DistBox; // Best candidate box distance to current NavId
float DistCenter; // Best candidate center distance to current NavId
float DistAxial; // Best candidate selected distance (box/center) to current NavId
ImRect RectRel; // Best candidate bounding box in window relative space
ImGuiNavMoveResult() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = 0.0f; }
};
// Storage for SetNexWindow** functions
struct ImGuiNextWindowData
{
@ -620,12 +633,7 @@ struct ImGuiContext
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down)
ImGuiDir NavMoveDirLast; // Direction of the previous move request
ImGuiID NavMoveResultId; // Best move request candidate
ImGuiID NavMoveResultParentId; // Best move request candidate window->IDStack.back() - to compare context
float NavMoveResultDistBox; // Best move request candidate box distance to current NavId
float NavMoveResultDistCenter; // Best move request candidate center distance to current NavId
float NavMoveResultDistAxial;
ImRect NavMoveResultRectRel; // Best move request candidate bounding box in window relative space
ImGuiNavMoveResult NavMoveResult; // Best move request candidate
// Render
ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user
@ -738,9 +746,6 @@ struct ImGuiContext
NavMoveRequest = false;
NavMoveRequestForward = ImGuiNavForward_None;
NavMoveDir = NavMoveDirLast = ImGuiDir_None;
NavMoveResultId = 0;
NavMoveResultParentId = 0;
NavMoveResultDistBox = NavMoveResultDistCenter = NavMoveResultDistAxial = 0.0f;
ModalWindowDarkeningRatio = 0.0f;
OverlayDrawList._Data = &DrawListSharedData;