From 1948a1e701956d148b8d9da589695dc5b7efd913 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 31 May 2026 01:01:32 -0500 Subject: [PATCH] [studio] Fix Back/Forward navigation actions --- src/olympic/studio/applib/src/app.cpp | 9 ++--- src/olympic/studio/applib/src/studioui.cpp | 22 +++++++---- .../studio/modlib/include/studio/context.hpp | 2 +- src/olympic/studio/modlib/src/context.cpp | 37 ++++++++++++------- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/olympic/studio/applib/src/app.cpp b/src/olympic/studio/applib/src/app.cpp index 75b1ebd1..831a03b7 100644 --- a/src/olympic/studio/applib/src/app.cpp +++ b/src/olympic/studio/applib/src/app.cpp @@ -155,13 +155,10 @@ static ox::Error run( if (m->id() == moduleId) { for (auto const &c : m->commands()) { if (c.name == subCmd) { - auto const kctx = keel::init( + OX_REQUIRE(kctx, keel::init( ox::make_unique(projectDir), - c.name); - if (kctx.error) { - return ox::Error{2, "failed to load project directory"}; - } - Project project{*kctx.value, projectDir, projectDataDir}; + c.name).reoriginate(2, "failed to load project directory")); + Project project{*kctx, projectDir, projectDataDir}; return c.func( project, args.size() > numCmdArgs ? diff --git a/src/olympic/studio/applib/src/studioui.cpp b/src/olympic/studio/applib/src/studioui.cpp index b7630455..a8b8ee7c 100644 --- a/src/olympic/studio/applib/src/studioui.cpp +++ b/src/olympic/studio/applib/src/studioui.cpp @@ -341,12 +341,14 @@ void StudioUI::drawMenu() noexcept { if (ImGui::BeginMenu("Navigate")) { constexpr auto backShortcut = ox::defines::OS == ox::OS::Darwin ? "Cmd+[" : "Alt+Left Arrow"; constexpr auto fwdShortcut = ox::defines::OS == ox::OS::Darwin ? "Cmd+]" : "Alt+Right Arrow"; - if (ImGui::MenuItem("Back", backShortcut, false, m_sctx.navIdx > 1)) { + if (ImGui::MenuItem( + "Back", backShortcut, false, + m_sctx.navIdx && *m_sctx.navIdx > 1)) { navigateBack(m_sctx); } if (ImGui::MenuItem( "Forward", fwdShortcut, false, - m_sctx.navIdx < m_sctx.navStack.size())) { + m_sctx.navIdx && *m_sctx.navIdx < m_sctx.navStack.size())) { navigateForward(m_sctx); } ImGui::EndMenu(); @@ -377,7 +379,7 @@ void StudioUI::drawTabs() noexcept { auto const &e = *it; auto open = true; auto const unsavedChanges = e->unsavedChanges() ? ImGuiTabItemFlags_UnsavedDocument : 0; - auto const selected = m_activeEditorUpdatePending == e.get() ? ImGuiTabItemFlags_SetSelected : 0; + auto const selected = m_activeEditorUpdatePending == e.get() ? ImGuiTabItemFlags_SetSelected : 0; auto const flags = unsavedChanges | selected | ImGuiTabItemFlags_NoAssumedClosure; if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) { if (m_activeEditor != e.get()) [[unlikely]] { @@ -395,11 +397,15 @@ void StudioUI::drawTabs() noexcept { if (m_activeEditorOnLastDraw != e.get()) [[unlikely]] { m_activeEditor->onActivated(); if (!m_sctx.navIdx || - (m_sctx.navIdx <= m_sctx.navStack.size() && - m_sctx.navStack[m_sctx.navIdx - 1].filePath != m_activeEditor->itemPath())) { - m_sctx.navStack.resize(m_sctx.navIdx); - ++m_sctx.navIdx; - m_sctx.navStack.emplace_back(ox::String{m_activeEditor->itemPath()}, ox::String{""}); + *m_sctx.navIdx == m_sctx.navStack.size() || + (*m_sctx.navIdx < m_sctx.navStack.size() && + m_sctx.navStack[*m_sctx.navIdx].filePath != m_activeEditor->itemPath())) { + auto &navIdx = m_sctx.navIdx.emplace(m_sctx.navIdx.or_value(0u)); + m_sctx.navStack.resize(navIdx); + ++navIdx; + m_sctx.navStack.emplace_back( + ox::String{m_activeEditor->itemPath()}, + ox::String{}); } } if (m_closeActiveTab) [[unlikely]] { diff --git a/src/olympic/studio/modlib/include/studio/context.hpp b/src/olympic/studio/modlib/include/studio/context.hpp index 3efccceb..ae898ae9 100644 --- a/src/olympic/studio/modlib/include/studio/context.hpp +++ b/src/olympic/studio/modlib/include/studio/context.hpp @@ -28,7 +28,7 @@ struct Context { ox::String filePath; ox::String navArgs; }; - size_t navIdx{}; + ox::Optional navIdx{}; ox::Vector navStack; std::function navCallback; Context(StudioUI &pUi, turbine::Context &pTctx) noexcept: diff --git a/src/olympic/studio/modlib/src/context.cpp b/src/olympic/studio/modlib/src/context.cpp index b9010c61..d883ddc9 100644 --- a/src/olympic/studio/modlib/src/context.cpp +++ b/src/olympic/studio/modlib/src/context.cpp @@ -20,7 +20,7 @@ void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) // !err && np->filePath == path && np->navArgs == navArgs.view()) { // return; //} - ctx.navStack.resize(ctx.navIdx + 1); + ctx.navStack.resize(ctx.navIdx.or_value(0) + 1); ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()}); try { ctx.navCallback(std::move(path), std::move(navArgs)); @@ -30,31 +30,42 @@ void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) } } +static void validateNavStack(Context &ctx, auto &navStack) noexcept { + for (size_t i{}; i < navStack.size(); ++i) { + auto const &n = navStack[i]; + if (!ctx.project->exists(n.filePath)) { + std::ignore = navStack.erase(i); + continue; + } + ++i; + } +} + void navigateBack(Context &ctx) noexcept { if (!ctx.navIdx) { return; } - --ctx.navIdx; - while (ctx.navIdx < ctx.navStack.size() && ctx.navIdx) { - auto const i = ctx.navIdx - 1; - auto const &n = ctx.navStack[i]; - if (!ctx.project->exists(n.filePath)) { - std::ignore = ctx.navStack.erase(i); - --ctx.navIdx; - continue; - } + validateNavStack(ctx, ctx.navStack); + auto &navIdx = *ctx.navIdx; + navIdx = ox::min(navIdx, ctx.navStack.size() - 1); + if (navIdx) { + --navIdx; + auto const &n = ctx.navStack[navIdx]; try { ctx.navCallback(n.filePath, n.navArgs); } catch (std::exception const &e) { oxAssert(ctx.navCallback != nullptr, "navCallback is null"); oxErrf("navigateForward failed: {}", e.what()); } - break; } } void navigateForward(Context &ctx) noexcept { - auto const nextIdx = ctx.navIdx + 1; + if (!ctx.navIdx) { + ctx.navIdx.emplace(0u); + } + auto &navIdx = *ctx.navIdx; + auto const nextIdx = navIdx + 1; while (nextIdx < ctx.navStack.size()) { auto const &n = ctx.navStack[nextIdx]; try { @@ -67,7 +78,7 @@ void navigateForward(Context &ctx) noexcept { std::ignore = ctx.navStack.erase(nextIdx); continue; } - ++ctx.navIdx; + ++navIdx; break; } }