Nav: first committed pass for manual moving and manual scrolling (after a bunch of attempts) (#323)
This commit is contained in:
parent
4309b8c1ed
commit
04157da291
92
imgui.cpp
92
imgui.cpp
@ -662,6 +662,7 @@ static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
|
||||
|
||||
static void SetCurrentFont(ImFont* font);
|
||||
static void SetCurrentWindow(ImGuiWindow* window);
|
||||
static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
|
||||
static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
|
||||
static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond cond);
|
||||
static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiSetCond cond);
|
||||
@ -2364,8 +2365,7 @@ static void NavUpdate()
|
||||
IM_ASSERT(g.NavWindow);
|
||||
|
||||
// Scroll to keep newly navigated item fully into view
|
||||
ImRect window_rect_rel(g.NavWindow->InnerRect.Min - g.NavWindow->Pos, g.NavWindow->InnerRect.Max - g.NavWindow->Pos);
|
||||
window_rect_rel.Expand(1.0f);
|
||||
ImRect window_rect_rel(g.NavWindow->InnerRect.Min - g.NavWindow->Pos - ImVec2(1,1), g.NavWindow->InnerRect.Max - g.NavWindow->Pos + ImVec2(1,1));
|
||||
//g.OverlayDrawList.AddRect(g.NavWindow->Pos + window_rect_rel.Min, g.NavWindow->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG]
|
||||
if (g.NavLayer == 0 && !window_rect_rel.Contains(g.NavMoveResultRectRel))
|
||||
{
|
||||
@ -2394,6 +2394,7 @@ static void NavUpdate()
|
||||
// Apply result from previous navigation directional move request
|
||||
ImGui::SetActiveID(0);
|
||||
SetNavIdMoveMouse(g.NavMoveResultId, g.NavMoveResultRectRel);
|
||||
g.NavMoveFromClampedRefRect = false;
|
||||
}
|
||||
|
||||
// Navigation windowing mode (change focus, move/resize window)
|
||||
@ -2433,6 +2434,19 @@ static void NavUpdate()
|
||||
g.NavWindowingDisplayAlpha = 1.0f;
|
||||
}
|
||||
|
||||
// Move window
|
||||
if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
const ImVec2 move_delta = ImGui::NavGetMovingDir(1);
|
||||
if (move_delta.x != 0.0f || move_delta.y != 0.0f)
|
||||
{
|
||||
const float move_speed = ImFloor(600 * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
|
||||
g.NavWindowingTarget->PosFloat += move_delta * move_speed;
|
||||
if (!(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoSavedSettings))
|
||||
MarkSettingsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsKeyDownMap(ImGuiKey_NavMenu))
|
||||
{
|
||||
// Apply actual focus only when releasing the NavMenu button (until then the window was merely rendered front-most)
|
||||
@ -2537,16 +2551,44 @@ static void NavUpdate()
|
||||
g.NavWindow = g.FocusedWindow;
|
||||
}
|
||||
|
||||
// Fallback manual-scroll with NavUp/NavDown when window has no navigable item
|
||||
if (g.FocusedWindow && !g.FocusedWindow->DC.NavLayerActiveFlags && g.FocusedWindow->DC.NavHasScroll && !(g.FocusedWindow->Flags & ImGuiWindowFlags_NoNav) && g.NavMoveRequest && (g.NavMoveDir == ImGuiNavDir_Up || g.NavMoveDir == ImGuiNavDir_Down))
|
||||
// Scrolling
|
||||
if (g.FocusedWindow && !(g.FocusedWindow->Flags & ImGuiWindowFlags_NoNav))
|
||||
{
|
||||
float scroll_speed = ImFloor(g.FocusedWindow->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
||||
SetWindowScrollY(g.FocusedWindow, ImFloor(g.FocusedWindow->Scroll.y + ((g.NavMoveDir == ImGuiNavDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
||||
// Fallback manual-scroll with NavUp/NavDown when window has no navigable item
|
||||
const float scroll_speed = ImFloor(g.FocusedWindow->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
||||
if (!g.FocusedWindow->DC.NavLayerActiveFlags && g.FocusedWindow->DC.NavHasScroll && g.NavMoveRequest && (g.NavMoveDir == ImGuiNavDir_Up || g.NavMoveDir == ImGuiNavDir_Down))
|
||||
SetWindowScrollY(g.FocusedWindow, ImFloor(g.FocusedWindow->Scroll.y + ((g.NavMoveDir == ImGuiNavDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
||||
|
||||
// Manual scroll with NavScrollXXX keys
|
||||
ImVec2 scroll_dir = ImGui::NavGetMovingDir(1, 1.0f/10.0f, 10.0f);
|
||||
if (scroll_dir.x != 0.0f && g.NavWindow->ScrollbarX)
|
||||
{
|
||||
SetWindowScrollX(g.FocusedWindow, ImFloor(g.FocusedWindow->Scroll.x + scroll_dir.x * scroll_speed));
|
||||
g.NavMoveFromClampedRefRect = true;
|
||||
}
|
||||
if (scroll_dir.y != 0.0f)
|
||||
{
|
||||
SetWindowScrollY(g.FocusedWindow, ImFloor(g.FocusedWindow->Scroll.y + scroll_dir.y * scroll_speed));
|
||||
g.NavMoveFromClampedRefRect = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset search
|
||||
g.NavMoveResultId = 0;
|
||||
g.NavMoveResultDistAxial = g.NavMoveResultDistBox = g.NavMoveResultDistCenter = FLT_MAX;
|
||||
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
|
||||
{
|
||||
// When we have manually scrolled and NavId is out of bounds, we clamp its bounding box (used for search) to the visible area to restart navigation within visible items
|
||||
ImRect window_rect_rel(g.NavWindow->InnerRect.Min - g.NavWindow->Pos - ImVec2(1,1), g.NavWindow->InnerRect.Max - g.NavWindow->Pos + ImVec2(1,1));
|
||||
if (!window_rect_rel.Contains(g.NavRefRectRel))
|
||||
{
|
||||
float pad = g.NavWindow->CalcFontSize() * 0.5f;
|
||||
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intend of starting navigation from first fully visible item
|
||||
window_rect_rel.Clip(g.NavRefRectRel);
|
||||
g.NavId = 0;
|
||||
}
|
||||
g.NavMoveFromClampedRefRect = false;
|
||||
}
|
||||
|
||||
// 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.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + g.NavRefRectRel.Min, g.NavWindow->Pos + g.NavRefRectRel.Max) : ImRect();
|
||||
@ -4737,7 +4779,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
||||
if (g.NavWindowingTarget == window)
|
||||
{
|
||||
const float resize_speed = ImFloor(600 * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
|
||||
nav_resize_delta = NavGetMovingDir() * resize_speed;
|
||||
nav_resize_delta = NavGetMovingDir(0) * resize_speed;
|
||||
held |= (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f); // For coloring
|
||||
}
|
||||
|
||||
@ -5469,6 +5511,13 @@ ImVec2 ImGui::GetWindowPos()
|
||||
return window->Pos;
|
||||
}
|
||||
|
||||
static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
|
||||
{
|
||||
window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
|
||||
window->Scroll.x = new_scroll_x;
|
||||
window->DC.CursorMaxPos.x -= window->Scroll.x;
|
||||
}
|
||||
|
||||
static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
|
||||
{
|
||||
window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
|
||||
@ -7043,13 +7092,28 @@ int ImGui::ParseFormatPrecision(const char* fmt, int default_precision)
|
||||
return precision;
|
||||
}
|
||||
|
||||
ImVec2 ImGui::NavGetMovingDir()
|
||||
ImVec2 ImGui::NavGetMovingDir(int stick_no, float slow_factor, float fast_factor)
|
||||
{
|
||||
IM_ASSERT(stick_no >= 0 && stick_no < 2);
|
||||
ImVec2 dir(0.0f, 0.0f);
|
||||
if (IsKeyDownMap(ImGuiKey_NavLeft)) dir.x -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavRight)) dir.x += 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavUp)) dir.y -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavDown)) dir.y += 1.0f;
|
||||
if (stick_no == 0)
|
||||
{
|
||||
if (IsKeyDownMap(ImGuiKey_NavLeft)) dir.x -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavRight)) dir.x += 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavUp)) dir.y -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavDown)) dir.y += 1.0f;
|
||||
}
|
||||
if (stick_no == 1)
|
||||
{
|
||||
if (IsKeyDownMap(ImGuiKey_NavScrollLeft)) dir.x -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavScrollRight)) dir.x += 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavScrollUp)) dir.y -= 1.0f;
|
||||
if (IsKeyDownMap(ImGuiKey_NavScrollDown)) dir.y += 1.0f;
|
||||
}
|
||||
if (slow_factor != 0.0f && IsKeyDownMap(ImGuiKey_NavTweakSlower))
|
||||
dir *= slow_factor;
|
||||
if (fast_factor != 0.0f && IsKeyDownMap(ImGuiKey_NavTweakFaster))
|
||||
dir *= fast_factor;
|
||||
return dir;
|
||||
}
|
||||
|
||||
@ -10458,7 +10522,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
}
|
||||
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
|
||||
bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
|
||||
if (show_clip_rects && ImGui::IsItemHovered())
|
||||
if (show_clip_rects && (ImGui::IsItemHovered() || ImGui::IsItemFocused()))
|
||||
{
|
||||
ImRect clip_rect = pcmd->ClipRect;
|
||||
ImRect vtxs_rect;
|
||||
@ -10482,7 +10546,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
|
||||
}
|
||||
ImGui::Selectable(buf, false);
|
||||
if (ImGui::IsItemHovered())
|
||||
if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
|
||||
overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle
|
||||
}
|
||||
ImGui::TreePop();
|
||||
|
5
imgui.h
5
imgui.h
@ -604,8 +604,13 @@ enum ImGuiKey_
|
||||
ImGuiKey_NavRight, // e.g. Right arrow, D-Pad right
|
||||
ImGuiKey_NavUp, // e.g. Up arrow, D-Pad up
|
||||
ImGuiKey_NavDown, // e.g. Down arrow, D-Pad down
|
||||
ImGuiKey_NavScrollLeft, // e.g. Analog left
|
||||
ImGuiKey_NavScrollRight,// e.g. Analog right
|
||||
ImGuiKey_NavScrollUp, // e.g. Analog up
|
||||
ImGuiKey_NavScrollDown, // e.g. Analog down
|
||||
ImGuiKey_NavTweakFaster,// e.g. Shift key, R-trigger
|
||||
ImGuiKey_NavTweakSlower,// e.g. Alt key, L-trigger
|
||||
ImGuiKey_NavLast_,
|
||||
|
||||
ImGuiKey_COUNT
|
||||
};
|
||||
|
@ -1904,7 +1904,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
|
||||
static void ShowExampleAppFixedOverlay(bool* p_open)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(10,10));
|
||||
if (!ImGui::Begin("Example: Fixed Overlay", p_open, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings))
|
||||
if (!ImGui::Begin("Example: Fixed Overlay", p_open, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_NoNav))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
|
@ -423,6 +423,7 @@ struct ImGuiContext
|
||||
ImRect NavInitDefaultResultRectRel;
|
||||
bool NavInitDefaultResultExplicit; // Whether the result was explicitly requested with SetItemDefaultFocus()
|
||||
bool NavMoveRequest; // Move request for this frame
|
||||
bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items
|
||||
ImGuiNavDir NavMoveDir; // West/East/North/South
|
||||
ImGuiID NavMoveResultId; // Best move request candidate
|
||||
float NavMoveResultDistBox; // Best move request candidate box distance to current NavId
|
||||
@ -784,7 +785,7 @@ namespace ImGui
|
||||
IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing);
|
||||
|
||||
IMGUI_API ImVec2 NavGetTweakDelta();
|
||||
IMGUI_API ImVec2 NavGetMovingDir();
|
||||
IMGUI_API ImVec2 NavGetMovingDir(int stick_no, float slow_factor = 0.0f, float fast_factor = 0.0f);
|
||||
|
||||
inline IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; return ImGui::ColorConvertFloat4ToU32(c); }
|
||||
inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
|
||||
|
Loading…
Reference in New Issue
Block a user