Squashed 'deps/nostalgia/' changes from e78c4050..857587c1
857587c1 [studio] Cleanup eb3d53c9 [studio] Cleanup 14d58f3f [studio] Fix Navigation shortcuts for non-Mac systems 5f239790 [studio,nostalgia/gfx/studio/tilesheet] Fix copy/cut/paste enablement when there is no selection 58e0ecb4 [studio] Make FilePickerPopup accept on double click of a file 8838bf42 [studio] Fix to properly copy file that has the same name as deleted file bddc544d [nostalgia] Update release notes a9437191 [studio,turbine] Add support for mouse back/forward buttons 9d8da7cc [ox/std] Make strToInt return error for empty string 394b568e [studio] Add Back/Forward navigation 78e9f70d [nostalgia] Update release notes 12e5623f [ox/logconn] Add exception handling for logger thread cfdfb0a8 [studio] Fix file deletion to close file even if not active 56e66530 [studio] Cleanup 7415ce4b [nostalgia/gfx/studio] Cleanup 05f42150 [olympic] Add new loc command to Makefile 8ea2bc69 [nostalgia] Update release notes c7809241 [studio] Add [DEBUG] tag to About in debug builds 8c538560 [nostalgia/gfx/studio/palette] Make RGB key shortcuts work when color channel inputs are focused c3e75bdb [nostalgia/gfx/studio/tilesheet] Cleanup git-subtree-dir: deps/nostalgia git-subtree-split: 857587c18b4695eacd31457e3c30b4971b4e46e8
This commit is contained in:
@@ -28,10 +28,15 @@ class StudioUIDrawer: public turbine::gl::Drawer {
|
||||
};
|
||||
|
||||
static void keyEventHandler(turbine::Context &ctx, turbine::Key key, bool down) noexcept {
|
||||
auto sctx = turbine::applicationData<studio::Context>(ctx);
|
||||
auto const sctx = turbine::applicationData<studio::Context>(ctx);
|
||||
sctx->ui.handleKeyEvent(key, down);
|
||||
}
|
||||
|
||||
static void mouseButtonEventHandler(turbine::Context &ctx, int const btn, bool const down) noexcept {
|
||||
auto const sctx = turbine::applicationData<studio::Context>(ctx);
|
||||
sctx->ui.handleMouseButtonEvent(btn, down);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::Vector<ox::SpanView<uint8_t>> WindowIcons() noexcept;
|
||||
|
||||
@@ -43,6 +48,7 @@ static ox::Error runApp(
|
||||
oxLogError(turbine::setWindowIcon(*ctx, WindowIcons()));
|
||||
turbine::setWindowTitle(*ctx, keelCtx(*ctx).appName);
|
||||
turbine::setKeyEventHandler(*ctx, keyEventHandler);
|
||||
turbine::setMouseButtonEventHandler(*ctx, mouseButtonEventHandler);
|
||||
turbine::requireRefreshWithin(*ctx, 0);
|
||||
StudioUI ui(*ctx, projectDataDir);
|
||||
StudioUIDrawer drawer(ui);
|
||||
|
@@ -15,7 +15,11 @@ namespace studio {
|
||||
|
||||
AboutPopup::AboutPopup(turbine::Context &ctx) noexcept:
|
||||
Popup("About"),
|
||||
#ifdef DEBUG
|
||||
m_text{sfmt("{} [DEBUG] - {}", keelCtx(ctx).appName, olympic::appVersion)} {
|
||||
#else
|
||||
m_text{sfmt("{} - {}", keelCtx(ctx).appName, olympic::appVersion)} {
|
||||
#endif
|
||||
}
|
||||
|
||||
void AboutPopup::draw(Context &sctx) noexcept {
|
||||
|
@@ -80,9 +80,9 @@ void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
|
||||
});
|
||||
}
|
||||
|
||||
void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept {
|
||||
void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &&tmplt) noexcept {
|
||||
for (auto const&im : m_types) {
|
||||
if (im->installTemplate(tmplt)) {
|
||||
if (im->installTemplate(std::move(tmplt))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@ class NewMenu final: public Popup {
|
||||
|
||||
void addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept;
|
||||
|
||||
void installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept;
|
||||
void installItemTemplate(ox::UPtr<ItemTemplate> &&tmplt) noexcept;
|
||||
|
||||
private:
|
||||
void drawNewItemType(Context const&sctx) noexcept;
|
||||
|
@@ -34,18 +34,6 @@ static bool shutdownHandler(turbine::Context &ctx) {
|
||||
return sctx->ui.handleShutdown();
|
||||
}
|
||||
|
||||
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept {
|
||||
ox::String path = std::move(filePath);
|
||||
if (beginsWith(path, "uuid://")) {
|
||||
auto [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path);
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
path = p;
|
||||
}
|
||||
ctx.ui.navigateTo(std::move(path), std::move(navArgs));
|
||||
}
|
||||
|
||||
namespace ig {
|
||||
extern bool s_mainWinHasFocus;
|
||||
}
|
||||
@@ -126,9 +114,8 @@ static ox::Error convertStudioConfigV1ToStudioConfigV2(
|
||||
using StudioConfig = StudioConfigV2;
|
||||
|
||||
|
||||
StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept:
|
||||
m_sctx{*this, ctx},
|
||||
m_tctx{ctx},
|
||||
StudioUI::StudioUI(turbine::Context &tctx, ox::StringParam projectDataDir) noexcept:
|
||||
m_sctx{*this, tctx},
|
||||
m_projectDataDir{std::move(projectDataDir)} {
|
||||
{
|
||||
ImFontConfig fontCfg;
|
||||
@@ -139,7 +126,7 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
|
||||
// but AddFontFromMemoryTTF requires a mutable buffer.
|
||||
// However, setting fontCfg.FontDataOwnedByAtlas ensures
|
||||
// that it will still be treated as const.
|
||||
// ImGui documentation recognize that this is a bad design,
|
||||
// ImGui documentation recognizes that this is a bad design,
|
||||
// and hopefully it will change at some point.
|
||||
io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font.data()), static_cast<int>(font.size()), 13, &fontCfg);
|
||||
}
|
||||
@@ -148,6 +135,9 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
|
||||
oxLogError(headerizeConfigFile<StudioConfigV1>(kctx));
|
||||
turbine::setApplicationData(m_tctx, &m_sctx);
|
||||
turbine::setShutdownHandler(m_tctx, shutdownHandler);
|
||||
m_sctx.navCallback = [this](ox::StringParam filePath, ox::StringParam navArgs) {
|
||||
handleNavigationChange(std::move(filePath), std::move(navArgs));
|
||||
};
|
||||
m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
|
||||
m_projectExplorer.addDir.connect(this, &StudioUI::addDir);
|
||||
m_projectExplorer.addItem.connect(this, &StudioUI::addFile);
|
||||
@@ -187,7 +177,17 @@ void StudioUI::handleKeyEvent(turbine::Key const key, bool const down) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void StudioUI::navigateTo(ox::StringParam path, ox::StringParam navArgs) noexcept {
|
||||
void StudioUI::handleMouseButtonEvent(int const btn, bool const down) noexcept {
|
||||
if (down) {
|
||||
if (btn == 3) { // back button
|
||||
navigateBack(m_sctx);
|
||||
} else if (btn == 4) { // forward button
|
||||
navigateForward(m_sctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StudioUI::handleNavigationChange(ox::StringParam path, ox::StringParam navArgs) noexcept {
|
||||
m_navAction.emplace(std::move(path), std::move(navArgs));
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ void StudioUI::drawMenu() noexcept {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Edit")) {
|
||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||
if (ImGui::MenuItem(
|
||||
"Undo", STUDIO_CTRL "+Z", false, undoStack && undoStack->canUndo())) {
|
||||
oxLogError(undoStack->undo());
|
||||
@@ -311,6 +311,19 @@ void StudioUI::drawMenu() noexcept {
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
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)) {
|
||||
navigateBack(m_sctx);
|
||||
}
|
||||
if (ImGui::MenuItem(
|
||||
"Forward", fwdShortcut, false,
|
||||
m_sctx.navIdx < m_sctx.navStack.size())) {
|
||||
navigateForward(m_sctx);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("About")) {
|
||||
m_aboutPopup.open();
|
||||
@@ -354,10 +367,16 @@ 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{""});
|
||||
}
|
||||
}
|
||||
if (m_closeActiveTab) [[unlikely]] {
|
||||
ImGui::SetTabItemClosed(e->itemDisplayName().c_str());
|
||||
|
||||
} else if (open) [[likely]] {
|
||||
e->draw(m_sctx);
|
||||
}
|
||||
@@ -397,9 +416,10 @@ void StudioUI::drawTabs() noexcept {
|
||||
m_closeActiveTab = false;
|
||||
}
|
||||
if (m_navAction) {
|
||||
oxLogError(openFile(m_navAction->path));
|
||||
m_activeEditor->navigateTo(m_navAction->args);
|
||||
m_navAction.reset();
|
||||
if (!openFile(m_navAction->path)) {
|
||||
m_activeEditor->navigateTo(m_navAction->args);
|
||||
m_navAction.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +438,7 @@ void StudioUI::loadModule(Module const &mod) noexcept {
|
||||
}
|
||||
auto tmplts = mod.itemTemplates(m_sctx);
|
||||
for (auto &t : tmplts) {
|
||||
m_newMenu.installItemTemplate(t);
|
||||
m_newMenu.installItemTemplate(std::move(t));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,6 +528,22 @@ void StudioUI::handleKeyInput() noexcept {
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (ox::defines::OS == ox::OS::Darwin) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_LeftBracket)) {
|
||||
navigateBack(m_sctx);
|
||||
} else if (ImGui::IsKeyPressed(ImGuiKey_RightBracket)) {
|
||||
navigateForward(m_sctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (ox::defines::OS != ox::OS::Darwin) {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_ModAlt)) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
|
||||
navigateBack(m_sctx);
|
||||
} else if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
|
||||
navigateForward(m_sctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,24 +589,36 @@ ox::Error StudioUI::handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR ne
|
||||
|
||||
ox::Error StudioUI::handleDeleteDir(ox::StringViewCR path) noexcept {
|
||||
auto const p = sfmt("{}/", path);
|
||||
for (auto &e : m_editors) {
|
||||
if (beginsWith(e->itemPath(), p)) {
|
||||
oxLogError(closeFile(path));
|
||||
m_closeActiveTab = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::ignore = m_editors.erase(
|
||||
std::remove_if(
|
||||
m_editors.begin(), m_editors.end(),
|
||||
[&](ox::UPtr<BaseEditor> const &e) {
|
||||
if (beginsWith(e->itemPath(), p)) {
|
||||
oxLogError(closeFile(path));
|
||||
if (e.get() != m_activeEditor) {
|
||||
return true;
|
||||
}
|
||||
m_closeActiveTab = true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
return m_projectExplorer.refreshProjectTreeModel();
|
||||
}
|
||||
|
||||
ox::Error StudioUI::handleDeleteFile(ox::StringViewCR path) noexcept {
|
||||
for (auto &e : m_editors) {
|
||||
if (path == e->itemPath()) {
|
||||
oxLogError(closeFile(path));
|
||||
m_closeActiveTab = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::ignore = m_editors.erase(
|
||||
std::remove_if(
|
||||
m_editors.begin(), m_editors.end(),
|
||||
[&](ox::UPtr<BaseEditor> const &e) {
|
||||
if (path == e->itemPath()) {
|
||||
oxLogError(closeFile(path));
|
||||
if (e.get() != m_activeEditor) {
|
||||
return true;
|
||||
}
|
||||
m_closeActiveTab = true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
return m_projectExplorer.refreshProjectTreeModel();
|
||||
}
|
||||
|
||||
@@ -654,7 +702,10 @@ ox::Error StudioUI::openFile(ox::StringViewCR path) noexcept {
|
||||
|
||||
ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActiveTab) noexcept {
|
||||
if (!m_project) {
|
||||
return ox::Error(1, "No project open to open a file from");
|
||||
return ox::Error(1, "no project open to open a file from");
|
||||
}
|
||||
if (!m_project->romFs().exists(path)) {
|
||||
return ox::Error{1, "file does note exist"};
|
||||
}
|
||||
if (m_openFiles.contains(path)) {
|
||||
for (auto &e : m_editors) {
|
||||
@@ -668,10 +719,10 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActi
|
||||
}
|
||||
OX_REQUIRE(ext, fileExt(path));
|
||||
// create Editor
|
||||
BaseEditor *editor = nullptr;
|
||||
ox::UPtr<BaseEditor> editor;
|
||||
auto const err = m_editorMakers.contains(ext) ?
|
||||
m_editorMakers[ext](path).moveTo(editor) :
|
||||
ox::makeCatch<ClawEditor>(m_sctx, path).moveTo(editor);
|
||||
m_editorMakers[ext](path).to<ox::UPtr<BaseEditor>>().moveTo(editor) :
|
||||
ox::make_unique_catch<ClawEditor>(m_sctx, path).moveTo(editor);
|
||||
if (err) {
|
||||
if constexpr(!ox::defines::Debug) {
|
||||
oxErrf("Could not open Editor: {}\n", toStr(err));
|
||||
@@ -681,11 +732,11 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActi
|
||||
return err;
|
||||
}
|
||||
editor->closed.connect(this, &StudioUI::closeFile);
|
||||
m_editors.emplace_back(editor);
|
||||
auto const &e = m_editors.emplace_back(std::move(editor));
|
||||
m_openFiles.emplace_back(path);
|
||||
if (makeActiveTab) {
|
||||
m_activeEditor = m_editors.back().value->get();
|
||||
m_activeEditorUpdatePending = editor;
|
||||
m_activeEditorUpdatePending = e.get();
|
||||
}
|
||||
// save to config
|
||||
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&path](StudioConfig &config) {
|
||||
|
@@ -25,12 +25,12 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
class StudioUI: public ox::SignalHandler {
|
||||
class StudioUI final: public ox::SignalHandler {
|
||||
friend class StudioUIDrawer;
|
||||
|
||||
private:
|
||||
Context m_sctx;
|
||||
turbine::Context &m_tctx;
|
||||
turbine::Context &m_tctx{m_sctx.tctx};
|
||||
ox::String m_projectDataDir;
|
||||
ox::UPtr<Project> m_project;
|
||||
TaskRunner m_taskRunner;
|
||||
@@ -83,11 +83,13 @@ class StudioUI: public ox::SignalHandler {
|
||||
ox::Optional<NavAction> m_navAction;
|
||||
|
||||
public:
|
||||
explicit StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept;
|
||||
explicit StudioUI(turbine::Context &tctx, ox::StringParam projectDataDir) noexcept;
|
||||
|
||||
void handleKeyEvent(turbine::Key, bool down) noexcept;
|
||||
|
||||
void navigateTo(ox::StringParam path, ox::StringParam navArgs) noexcept;
|
||||
void handleMouseButtonEvent(int btn, bool down) noexcept;
|
||||
|
||||
void handleNavigationChange(ox::StringParam path, ox::StringParam navArgs) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr Project *project() noexcept {
|
||||
|
Reference in New Issue
Block a user