diff --git a/src/olympic/studio/modlib/include/studio/editor.hpp b/src/olympic/studio/modlib/include/studio/editor.hpp index 20ddb0c3..59b7e2f0 100644 --- a/src/olympic/studio/modlib/include/studio/editor.hpp +++ b/src/olympic/studio/modlib/include/studio/editor.hpp @@ -131,6 +131,17 @@ class Editor: public studio::BaseEditor { [[nodiscard]] UndoStack *undoStack() noexcept final; + void pushCommand(ox::UPtr &&cmd) noexcept; + + template + void pushCommand(Args&&... args) noexcept { + try { + m_undoStack.push(ox::make_unique(ox::forward(args)...)); + } catch (ox::Exception const&ex) { + oxLogError(ex.toError()); + } + } + private: ox::Error markUnsavedChanges(UndoCommand const*) noexcept; }; diff --git a/src/olympic/studio/modlib/include/studio/imguiutil.hpp b/src/olympic/studio/modlib/include/studio/imguiutil.hpp index 9f4aea25..a77c4e3b 100644 --- a/src/olympic/studio/modlib/include/studio/imguiutil.hpp +++ b/src/olympic/studio/modlib/include/studio/imguiutil.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace studio::ig { @@ -52,4 +53,41 @@ bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, Im */ bool ComboBox(ox::CStringView lbl, ox::SpanView list, size_t &selectedIdx) noexcept; +bool FileComboBox( + ox::CStringView lbl, + studio::StudioContext &sctx, + ox::StringView fileExt, + size_t &selectedIdx) noexcept; + +/** + * + * @param name + * @param list + * @param selIdx + * @return true if new value selected, false otherwise + */ +bool ListBox(ox::CStringView name, ox::SpanView const&list, size_t &selIdx) noexcept; + +class FilePicker { + private: + bool m_show{}; + studio::StudioContext &m_sctx; + ox::String const m_title; + ox::String const m_fileExt; + ImVec2 const m_size; + public: + ox::Signal filePicked; + + FilePicker( + studio::StudioContext &sctx, + ox::String title, + ox::String fileExt, + ImVec2 const&size = {}) noexcept; + + void draw() noexcept; + + void show() noexcept; + +}; + } \ No newline at end of file diff --git a/src/olympic/studio/modlib/src/editor.cpp b/src/olympic/studio/modlib/src/editor.cpp index 61a74e8c..1c78de60 100644 --- a/src/olympic/studio/modlib/src/editor.cpp +++ b/src/olympic/studio/modlib/src/editor.cpp @@ -127,6 +127,10 @@ ox::CStringView Editor::itemDisplayName() const noexcept { return m_itemName; } +void Editor::pushCommand(ox::UPtr &&cmd) noexcept { + m_undoStack.push(std::move(cmd)); +} + UndoStack *Editor::undoStack() noexcept { return &m_undoStack; } diff --git a/src/olympic/studio/modlib/src/imguiutil.cpp b/src/olympic/studio/modlib/src/imguiutil.cpp index 67eca2bf..fbccc985 100644 --- a/src/olympic/studio/modlib/src/imguiutil.cpp +++ b/src/olympic/studio/modlib/src/imguiutil.cpp @@ -92,4 +92,76 @@ bool ComboBox( return out; } +bool FileComboBox( + ox::CStringView lbl, + studio::StudioContext &sctx, + ox::StringView fileExt, + size_t &selectedIdx) noexcept { + auto const&list = sctx.project->fileList(fileExt); + bool out{}; + auto const first = selectedIdx < list.size() ? list[selectedIdx].c_str() : ""; + if (ImGui::BeginCombo(lbl.c_str(), first, 0)) { + for (auto i = 0u; i < list.size(); ++i) { + const auto selected = (selectedIdx == i); + if (ImGui::Selectable(list[i].c_str(), selected) && selectedIdx != i) { + selectedIdx = i; + out = true; + } + } + ImGui::EndCombo(); + } + return out; +} + +bool ListBox(ox::CStringView name, ox::SpanView const&list, size_t &selIdx) noexcept { + auto out = false; + if (ImGui::BeginListBox(name.c_str())) { + for (auto i = 0u; auto const&obj : list) { + ig::IDStackItem const idStackItem2(static_cast(i)); + if (ImGui::Selectable(obj.c_str(), selIdx == i)) { + if (i != selIdx) { + selIdx = i; + out = true; + } + } + ++i; + } + ImGui::EndListBox(); + } + return out; +} + + +FilePicker::FilePicker( + studio::StudioContext &sctx, + ox::String title, + ox::String fileExt, + ImVec2 const&size) noexcept: + m_sctx(sctx), + m_title(std::move(title)), + m_fileExt(std::move(fileExt)), + m_size(size) { +} + +void FilePicker::draw() noexcept { + if (!m_show) { + return; + } + auto constexpr popupSz = ImVec2{450.f, 0}; + ig::IDStackItem const idStackItem(m_title.c_str()); + if (ig::BeginPopup(m_sctx.tctx, m_title.c_str(), m_show, popupSz)) { + auto const&list = m_sctx.project->fileList(m_fileExt); + size_t selIdx{}; + ig::ComboBox(m_title.c_str(), list, selIdx); + if (ig::PopupControlsOkCancel(popupSz.x, m_show) == ig::PopupResponse::OK) { + filePicked.emit(list[selIdx]); + } + ImGui::EndPopup(); + } +} + +void FilePicker::show() noexcept { + m_show = true; +} + }