[nostalgia] Add start for Scene editor in Studio

This commit is contained in:
2023-03-11 16:59:26 -06:00
parent 19d5641c6e
commit ae9272841f
37 changed files with 357 additions and 295 deletions

View File

@@ -19,6 +19,7 @@ target_link_libraries(
NostalgiaAppModules
NostalgiaStudio
NostalgiaCore-Studio
NostalgiaScene-Studio
)
if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32)

View File

@@ -7,13 +7,17 @@
#include <ox/std/memory.hpp>
#include <nostalgia/core/studio/module.hpp>
#include <nostalgia/scene/studio/module.hpp>
namespace nostalgia {
[[maybe_unused]] // GCC warns about the existence of this "unused" constexpr list in a header file...
constexpr auto BuiltinModules = {
[] {
return ox::make_unique<core::StudioModule>();
[[maybe_unused]] // GCC warns about the existence of this "unused" inline list in a header file...
inline ox::Vector<std::function<ox::UPtr<studio::Module>()>, 2> BuiltinModules = {
[]() -> ox::UPtr<studio::Module> {
return ox::UPtr<studio::Module>(new core::StudioModule());
},
[]() -> ox::UPtr<studio::Module> {
return ox::UPtr<studio::Module>(new scene::StudioModule());
},
};

View File

@@ -23,7 +23,7 @@ constexpr auto ConfigDir = [] {
}
}();
ox::String configPath(const core::Context *ctx) noexcept {
ox::String configPath(const foundation::Context *ctx) noexcept {
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
return ox::sfmt(ConfigDir, homeDir, ctx->appName);
}

View File

@@ -18,10 +18,10 @@
namespace nostalgia::studio {
[[nodiscard]]
ox::String configPath(const core::Context *ctx) noexcept;
ox::String configPath(const foundation::Context *ctx) noexcept;
template<typename T>
ox::Result<T> readConfig(core::Context *ctx, ox::CRStringView name) noexcept {
ox::Result<T> readConfig(foundation::Context *ctx, ox::CRStringView name) noexcept {
oxAssert(name != "", "Config type has no TypeName");
const auto path = ox::sfmt("/{}.json", name);
ox::PassThroughFS fs(configPath(ctx));
@@ -34,13 +34,13 @@ ox::Result<T> readConfig(core::Context *ctx, ox::CRStringView name) noexcept {
}
template<typename T>
ox::Result<T> readConfig(core::Context *ctx) noexcept {
ox::Result<T> readConfig(foundation::Context *ctx) noexcept {
constexpr auto TypeName = ox::requireModelTypeName<T>();
return readConfig<T>(ctx, TypeName);
}
template<typename T>
ox::Error writeConfig(core::Context *ctx, ox::CRStringView name, T *data) noexcept {
ox::Error writeConfig(foundation::Context *ctx, ox::CRStringView name, T *data) noexcept {
oxAssert(name != "", "Config type has no TypeName");
const auto path = ox::sfmt("/{}.json", name);
ox::PassThroughFS fs(configPath(ctx));
@@ -58,13 +58,13 @@ ox::Error writeConfig(core::Context *ctx, ox::CRStringView name, T *data) noexce
}
template<typename T>
ox::Error writeConfig(core::Context *ctx, T *data) noexcept {
ox::Error writeConfig(foundation::Context *ctx, T *data) noexcept {
constexpr auto TypeName = ox::requireModelTypeName<T>();
return writeConfig(ctx, TypeName, data);
}
template<typename T, typename Func>
void openConfig(core::Context *ctx, const auto &name, Func f) noexcept {
void openConfig(foundation::Context *ctx, const auto &name, Func f) noexcept {
oxAssert(name != "", "Config type has no TypeName");
const auto [c, err] = readConfig<T>(ctx, name);
oxLogError(err);
@@ -72,13 +72,13 @@ void openConfig(core::Context *ctx, const auto &name, Func f) noexcept {
}
template<typename T, typename Func>
void openConfig(core::Context *ctx, Func f) noexcept {
void openConfig(foundation::Context *ctx, Func f) noexcept {
constexpr auto TypeName = ox::requireModelTypeName<T>();
openConfig<T>(ctx, TypeName, f);
}
template<typename T, typename Func>
void editConfig(core::Context *ctx, const auto &name, Func f) noexcept {
void editConfig(foundation::Context *ctx, const auto &name, Func f) noexcept {
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
auto [c, err] = readConfig<T>(ctx, name);
oxLogError(err);
@@ -87,7 +87,7 @@ void editConfig(core::Context *ctx, const auto &name, Func f) noexcept {
}
template<typename T, typename Func>
void editConfig(core::Context *ctx, Func f) noexcept {
void editConfig(foundation::Context *ctx, Func f) noexcept {
constexpr auto TypeName = ox::requireModelTypeName<T>();
editConfig<T>(ctx, TypeName, f);
}

View File

@@ -29,6 +29,13 @@ void BaseEditor::exportFile() {
void BaseEditor::keyStateChanged(core::Key, bool) {
}
void BaseEditor::onActivated() noexcept {
}
bool BaseEditor::requiresConstantRefresh() const noexcept {
return m_requiresConstantRefresh;
}
void BaseEditor::close() const {
this->closed.emit(itemName());
}
@@ -100,6 +107,11 @@ ox::StringView BaseEditor::pathToItemName(ox::CRStringView path) noexcept {
return path.substr(lastSlash + 1);
}
void BaseEditor::setRequiresConstantRefresh(bool value) noexcept {
m_requiresConstantRefresh = value;
}
Editor::Editor() noexcept {
m_undoStack.changeTriggered.connect(this, &Editor::markUnsavedChanges);
}

View File

@@ -27,6 +27,7 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
bool m_cutEnabled = false;
bool m_copyEnabled = false;
bool m_pasteEnabled = false;
bool m_requiresConstantRefresh = false;
public:
~BaseEditor() override = default;
@@ -50,6 +51,11 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
virtual void keyStateChanged(core::Key key, bool down);
virtual void onActivated() noexcept;
[[nodiscard]]
bool requiresConstantRefresh() const noexcept;
void close() const;
/**
@@ -102,6 +108,8 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
static ox::StringView pathToItemName(ox::CRStringView path) noexcept;
void setRequiresConstantRefresh(bool value) noexcept;
// signals
public:
ox::Signal<ox::Error(bool)> unsavedChangesChanged;

View File

@@ -14,7 +14,7 @@
namespace nostalgia::studio {
static void generateTypes(ox::TypeStore *ts) noexcept {
for (const auto mod : *foundation::modules()) {
for (const auto mod : foundation::modules()) {
for (auto gen : mod->types()) {
oxLogError(gen(ts));
}

View File

@@ -48,13 +48,16 @@ static ox::Error run(ox::UniquePtr<ox::FileSystem> fs) noexcept {
core::setUpdateHandler(ctx.get(), updateHandler);
core::setKeyEventHandler(ctx.get(), keyEventHandler);
core::setConstantRefresh(ctx.get(), false);
core::gl::setMainViewEnabled(false);
studio::StudioContext studioCtx;
core::setApplicationData(ctx.get(), &studioCtx);
StudioUI ui(ctx.get());
studioCtx.ui = &ui;
StudioUIDrawer drawer(&ui);
ctx->drawers.emplace_back(&drawer);
return core::run(ctx.get());
core::addCustomDrawer(ctx.get(), &drawer);
auto err = core::run(ctx.get());
core::removeCustomDrawer(ctx.get(), &drawer);
return err;
}
static ox::Error run(int, const char**) noexcept {

View File

@@ -217,7 +217,12 @@ void StudioUI::drawTabs() noexcept {
if (m_activeEditorUpdatePending == e.get()) {
m_activeEditorUpdatePending = nullptr;
}
if (m_activeEditorOnLastDraw != e.get()) [[unlikely]] {
m_activeEditor->onActivated();
core::setConstantRefresh(m_ctx, m_activeEditor->requiresConstantRefresh());
}
e->draw(m_ctx);
m_activeEditorOnLastDraw = e.get();
ImGui::EndTabItem();
}
if (!open) {
@@ -346,7 +351,7 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
}
// save to config
studio::editConfig<StudioConfig>(m_ctx, [&](StudioConfig *config) {
if (!config->openFiles.contains((path))) {
if (!config->openFiles.contains(path)) {
config->openFiles.emplace_back(path);
}
});

View File

@@ -31,6 +31,7 @@ class StudioUI: public ox::SignalHandler {
ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
ox::UniquePtr<ProjectExplorer> m_projectExplorer;
ox::Vector<ox::String> m_openFiles;
studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
studio::BaseEditor *m_activeEditor = nullptr;
studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
NewMenu m_newMenu;