mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 13:11:05 +01:00 
			
		
		
		
	Nav: Draft internal api to forward move request with loop/wrap options. Will rework for parallel scoring of two paths (as a generalization of the NavFlattened concept). (#787)
This commit is contained in:
		
							
								
								
									
										66
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -2251,7 +2251,7 @@ static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) | ||||
|  | ||||
|     // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) | ||||
|     // For example, this ensure that items in one column are not reached when moving vertically from items in another column. | ||||
|     NavClampRectToVisibleAreaForMoveDir(g.NavMoveDir, cand, window->ClipRect); | ||||
|     NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); | ||||
|  | ||||
|     // Compute distance between boxes | ||||
|     // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. | ||||
| @@ -3227,6 +3227,7 @@ static void ImGui::NavUpdate() | ||||
|     if (g.NavMoveRequestForward == ImGuiNavForward_None) | ||||
|     { | ||||
|         g.NavMoveDir = ImGuiDir_None; | ||||
|         g.NavMoveRequestFlags = 0; | ||||
|         if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) | ||||
|         { | ||||
|             if ((allowed_dir_flags & (1<<ImGuiDir_Left))  && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left; | ||||
| @@ -3234,11 +3235,13 @@ static void ImGui::NavUpdate() | ||||
|             if ((allowed_dir_flags & (1<<ImGuiDir_Up))    && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp,   ImGuiNavInput_KeyUp_,   ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up; | ||||
|             if ((allowed_dir_flags & (1<<ImGuiDir_Down))  && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down; | ||||
|         } | ||||
|         g.NavMoveClipDir = g.NavMoveDir; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // 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) | ||||
|         IM_ASSERT(g.NavMoveDir != ImGuiDir_None); | ||||
|         // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) | ||||
|         IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); | ||||
|         IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); | ||||
|         g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; | ||||
|     } | ||||
| @@ -4547,9 +4550,11 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items | ||||
|     const ImVec2 pos = window->DC.CursorPos; | ||||
|     int start = (int)((window->ClipRect.Min.y - pos.y) / items_height); | ||||
|     int end = (int)((window->ClipRect.Max.y - pos.y) / items_height); | ||||
|     if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Up) // 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.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) | ||||
|         start--; | ||||
|     if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) | ||||
|     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) | ||||
|         end++; | ||||
|  | ||||
|     start = ImClamp(start, 0, items_count); | ||||
| @@ -5101,16 +5106,51 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla | ||||
|     return is_open; | ||||
| } | ||||
|  | ||||
| static void NavProcessMoveRequestWrapAround(ImGuiWindow* window) | ||||
| void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     if (g.NavWindow == window && NavMoveRequestButNoResultYet()) | ||||
|         if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0) | ||||
|         { | ||||
|             g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; | ||||
|             ImGui::NavMoveRequestCancel(); | ||||
|             g.NavWindow->NavRectRel[0].Min.y = g.NavWindow->NavRectRel[0].Max.y = ((g.NavMoveDir == ImGuiDir_Up) ? ImMax(window->SizeFull.y, window->SizeContents.y) : 0.0f) - window->Scroll.y; | ||||
|         } | ||||
|     IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); | ||||
|     ImGui::NavMoveRequestCancel(); | ||||
|     g.NavMoveDir = move_dir; | ||||
|     g.NavMoveClipDir = clip_dir; | ||||
|     g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; | ||||
|     g.NavMoveRequestFlags = move_flags; | ||||
|     g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; | ||||
| } | ||||
|  | ||||
| void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != 0) | ||||
|         return; | ||||
|     IM_ASSERT(move_flags != 0); // No points calling this with no wrapping | ||||
|     ImRect bb_rel = window->NavRectRel[0]; | ||||
|  | ||||
|     ImGuiDir clip_dir = g.NavMoveDir; | ||||
|     if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) | ||||
|     { | ||||
|         bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x; | ||||
|         if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; } | ||||
|         NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); | ||||
|     } | ||||
|     if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) | ||||
|     { | ||||
|         bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; | ||||
|         if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; } | ||||
|         NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); | ||||
|     } | ||||
|     if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) | ||||
|     { | ||||
|         bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y; | ||||
|         if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; } | ||||
|         NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); | ||||
|     } | ||||
|     if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) | ||||
|     { | ||||
|         bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; | ||||
|         if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; } | ||||
|         NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ImGui::EndPopup() | ||||
| @@ -5120,7 +5160,7 @@ void ImGui::EndPopup() | ||||
|     IM_ASSERT(g.CurrentPopupStack.Size > 0); | ||||
|  | ||||
|     // Make all menus and popups wrap around for now, may need to expose that policy. | ||||
|     NavProcessMoveRequestWrapAround(g.CurrentWindow); | ||||
|     NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); | ||||
|      | ||||
|     End(); | ||||
| } | ||||
|   | ||||
| @@ -50,6 +50,7 @@ typedef int ImGuiItemFlags;         // flags: for PushItemFlag() | ||||
| typedef int ImGuiItemStatusFlags;   // flags: storage for DC.LastItemXXX        // enum ImGuiItemStatusFlags_ | ||||
| typedef int ImGuiNavHighlightFlags; // flags: for RenderNavHighlight()          // enum ImGuiNavHighlightFlags_ | ||||
| typedef int ImGuiNavDirSourceFlags; // flags: for GetNavInputAmount2d()         // enum ImGuiNavDirSourceFlags_ | ||||
| typedef int ImGuiNavMoveFlags;      // flags: for navigation requests           // enum ImGuiNavMoveFlags_ | ||||
| typedef int ImGuiSeparatorFlags;    // flags: for Separator() - internal        // enum ImGuiSeparatorFlags_ | ||||
| typedef int ImGuiSliderFlags;       // flags: for SliderBehavior()              // enum ImGuiSliderFlags_ | ||||
|  | ||||
| @@ -302,6 +303,14 @@ enum ImGuiNavDirSourceFlags_ | ||||
|     ImGuiNavDirSourceFlags_PadLStick    = 1 << 2 | ||||
| }; | ||||
|  | ||||
| enum ImGuiNavMoveFlags_ | ||||
| { | ||||
|     ImGuiNavMoveFlags_LoopX     = 1 << 0,   // On failed request, restart from opposite side | ||||
|     ImGuiNavMoveFlags_LoopY     = 1 << 1, | ||||
|     ImGuiNavMoveFlags_WrapX     = 1 << 2,   // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) | ||||
|     ImGuiNavMoveFlags_WrapY     = 1 << 3    // This is not super useful for provided for completeness | ||||
| }; | ||||
|  | ||||
| enum ImGuiNavForward | ||||
| { | ||||
|     ImGuiNavForward_None, | ||||
| @@ -337,6 +346,8 @@ struct IMGUI_API ImRect | ||||
|     void        Expand(const float amount)          { Min.x -= amount;   Min.y -= amount;   Max.x += amount;   Max.y += amount; } | ||||
|     void        Expand(const ImVec2& amount)        { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } | ||||
|     void        Translate(const ImVec2& d)          { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } | ||||
|     void        TranslateX(float dx)                { Min.x += dx; Max.x += dx; } | ||||
|     void        TranslateY(float dy)                { Min.y += dy; Max.y += dy; } | ||||
|     void        ClipWith(const ImRect& r)           { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); }                   // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. | ||||
|     void        ClipWithFull(const ImRect& r)       { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. | ||||
|     void        Floor()                             { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } | ||||
| @@ -645,8 +656,10 @@ struct ImGuiContext | ||||
|     ImRect                  NavInitResultRectRel; | ||||
|     bool                    NavMoveFromClampedRefRect;          // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items | ||||
|     bool                    NavMoveRequest;                     // Move request for this frame | ||||
|     ImGuiNavMoveFlags       NavMoveRequestFlags; | ||||
|     ImGuiNavForward         NavMoveRequestForward;              // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) | ||||
|     ImGuiDir                NavMoveDir, NavMoveDirLast;         // Direction of the move request (left/right/up/down), direction of the previous move request | ||||
|     ImGuiDir                NavMoveClipDir; | ||||
|     ImGuiNavMoveResult      NavMoveResultLocal;                 // Best move request candidate within NavWindow | ||||
|     ImGuiNavMoveResult      NavMoveResultOther;                 // Best move request candidate within NavWindow's flattened hierarchy (when using the NavFlattened flag) | ||||
|  | ||||
| @@ -762,8 +775,9 @@ struct ImGuiContext | ||||
|         NavInitResultId = 0; | ||||
|         NavMoveFromClampedRefRect = false; | ||||
|         NavMoveRequest = false; | ||||
|         NavMoveRequestFlags = 0; | ||||
|         NavMoveRequestForward = ImGuiNavForward_None; | ||||
|         NavMoveDir = NavMoveDirLast = ImGuiDir_None; | ||||
|         NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; | ||||
|  | ||||
|         ModalWindowDarkeningRatio = 0.0f; | ||||
|         OverlayDrawList._Data = &DrawListSharedData; | ||||
| @@ -1069,6 +1083,8 @@ namespace ImGui | ||||
|  | ||||
|     IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit); | ||||
|     IMGUI_API void          NavMoveRequestCancel(); | ||||
|     IMGUI_API void          NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); | ||||
|     IMGUI_API void          NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); | ||||
|     IMGUI_API void          ActivateItem(ImGuiID id);   // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. | ||||
|  | ||||
|     IMGUI_API float         GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user