[nostalgia/core/studio] Add Palette page names to editor
All checks were successful
Build / build (push) Successful in 2m33s
All checks were successful
Build / build (push) Successful in 2m33s
This commit is contained in:
parent
ba4540e43f
commit
52533c8c44
@ -4,8 +4,6 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <ox/std/memory.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
@ -17,6 +15,27 @@ namespace nostalgia::core {
|
||||
|
||||
namespace ig = studio::ig;
|
||||
|
||||
|
||||
void PaletteEditorImGui::PageRename::draw(turbine::Context &tctx) noexcept {
|
||||
if (!m_show) {
|
||||
return;
|
||||
}
|
||||
if (ig::BeginPopup(tctx, "Rename Page", m_show)) {
|
||||
ig::InputText("Name", m_name);
|
||||
switch (ig::PopupControlsOkCancel(m_show)) {
|
||||
case ig::PopupResponse::OK:
|
||||
inputSubmitted.emit(m_name);
|
||||
[[fallthrough]];
|
||||
case ig::PopupResponse::Cancel:
|
||||
close();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PaletteEditorImGui::PaletteEditorImGui(studio::StudioContext &sctx, ox::StringParam path):
|
||||
Editor(std::move(path)),
|
||||
m_sctx(sctx),
|
||||
@ -26,6 +45,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::StudioContext &sctx, ox::StringPa
|
||||
throw OxException(1, "PaletteEditorImGui: invalid Palette object");
|
||||
}
|
||||
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
|
||||
m_pageRename.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
|
||||
}
|
||||
|
||||
void PaletteEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
||||
@ -49,7 +69,7 @@ void PaletteEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
||||
void PaletteEditorImGui::draw(studio::StudioContext&) noexcept {
|
||||
auto const paneSize = ImGui::GetContentRegionAvail();
|
||||
{
|
||||
ImGui::BeginChild("Pages", {250, paneSize.y}, true);
|
||||
ImGui::BeginChild("Pages", {280, paneSize.y}, true);
|
||||
drawPagesEditor();
|
||||
ImGui::EndChild();
|
||||
}
|
||||
@ -59,6 +79,7 @@ void PaletteEditorImGui::draw(studio::StudioContext&) noexcept {
|
||||
drawColorsEditor();
|
||||
ImGui::EndChild();
|
||||
}
|
||||
m_pageRename.draw(m_tctx);
|
||||
}
|
||||
|
||||
ox::Error PaletteEditorImGui::saveItem() noexcept {
|
||||
@ -166,7 +187,7 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
|
||||
constexpr auto tableFlags = ImGuiTableFlags_RowBg;
|
||||
auto const paneSz = ImGui::GetContentRegionAvail();
|
||||
constexpr auto toolbarHeight = 40;
|
||||
auto const btnSz = ImVec2{paneSz.x / 3 - 5.5f, 24};
|
||||
auto const btnSz = ImVec2{paneSz.x / 4 - 5.5f, 24};
|
||||
if (ImGui::Button("Add", btnSz)) {
|
||||
std::ignore = pushCommand<DuplicatePageCommand>(m_pal, 0u, m_pal.pages.size());
|
||||
m_page = m_pal.pages.size() - 1;
|
||||
@ -177,9 +198,13 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
|
||||
m_page = std::min(m_page, m_pal.pages.size() - 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Duplicate", btnSz)) {
|
||||
if (ImGui::Button("Clone", btnSz)) {
|
||||
std::ignore = pushCommand<DuplicatePageCommand>(m_pal, m_page, m_pal.pages.size());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Rename", btnSz)) {
|
||||
m_pageRename.show(m_pal.pages[m_page].name);
|
||||
}
|
||||
ImGui::BeginTable(
|
||||
"PageSelect",
|
||||
2,
|
||||
@ -187,11 +212,13 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
|
||||
{paneSz.x, paneSz.y - (toolbarHeight + 5)});
|
||||
{
|
||||
ImGui::TableSetupColumn("Page", ImGuiTableColumnFlags_WidthFixed, 60);
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 200);
|
||||
ImGui::TableHeadersRow();
|
||||
for (auto i = 0u; i < m_pal.pages.size(); ++i) {
|
||||
ig::IDStackItem const idStackItem(static_cast<int>(i));
|
||||
ImGui::TableNextRow();
|
||||
drawColumn(i + 1);
|
||||
drawColumnLeftAlign(m_pal.pages[i].name);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Selectable("##PageRow", i == m_page, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
m_page = i;
|
||||
@ -232,6 +259,10 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error PaletteEditorImGui::renamePage(ox::StringView name) noexcept {
|
||||
return pushCommand<RenamePageCommand>(m_pal, m_page, name);
|
||||
}
|
||||
|
||||
ox::Error PaletteEditorImGui::handleCommand(studio::UndoCommand const*cmd) noexcept {
|
||||
if (dynamic_cast<RemovePageCommand const*>(cmd)) {
|
||||
m_page = ox::min(m_page, m_pal.pages.size() - 1);
|
||||
|
@ -14,6 +14,23 @@ namespace nostalgia::core {
|
||||
class PaletteEditorImGui: public studio::Editor {
|
||||
|
||||
private:
|
||||
class PageRename {
|
||||
private:
|
||||
ox::IString<50> m_name;
|
||||
bool m_show = false;
|
||||
public:
|
||||
ox::Signal<ox::Error(ox::StringView name)> inputSubmitted;
|
||||
constexpr void show(ox::StringView const&name) noexcept {
|
||||
m_show = true;
|
||||
m_name = name;
|
||||
}
|
||||
constexpr void close() noexcept {
|
||||
m_show = false;
|
||||
}
|
||||
[[nodiscard]]
|
||||
constexpr bool isOpen() const noexcept { return m_show; }
|
||||
void draw(turbine::Context &tctx) noexcept;
|
||||
} m_pageRename;
|
||||
studio::StudioContext &m_sctx;
|
||||
turbine::Context &m_tctx;
|
||||
Palette m_pal;
|
||||
@ -45,6 +62,8 @@ class PaletteEditorImGui: public studio::Editor {
|
||||
|
||||
void drawColorEditor() noexcept;
|
||||
|
||||
ox::Error renamePage(ox::StringView name) noexcept;
|
||||
|
||||
ox::Error handleCommand(studio::UndoCommand const*) noexcept;
|
||||
};
|
||||
|
||||
|
@ -47,6 +47,26 @@ ox::Error ApplyColorAllPagesCommand::undo() noexcept {
|
||||
}
|
||||
|
||||
|
||||
RenamePageCommand::RenamePageCommand(Palette &pal, size_t const page, ox::StringParam name) noexcept:
|
||||
m_pal(pal),
|
||||
m_page(page),
|
||||
m_name{std::move(name)} {}
|
||||
|
||||
int RenamePageCommand::commandId() const noexcept {
|
||||
return static_cast<int>(PaletteEditorCommandId::RenamePage);
|
||||
}
|
||||
|
||||
ox::Error RenamePageCommand::redo() noexcept {
|
||||
std::swap(m_pal.pages[m_page].name, m_name);
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error RenamePageCommand::undo() noexcept {
|
||||
std::swap(m_pal.pages[m_page].name, m_name);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
DuplicatePageCommand::DuplicatePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept:
|
||||
m_pal(pal),
|
||||
m_dstIdx(dstIdx) {
|
||||
|
@ -13,6 +13,7 @@ namespace nostalgia::core {
|
||||
|
||||
enum class PaletteEditorCommandId {
|
||||
ApplyColorAllPages,
|
||||
RenamePage,
|
||||
DuplicatePage,
|
||||
RemovePage,
|
||||
AddColor,
|
||||
@ -43,6 +44,26 @@ class ApplyColorAllPagesCommand: public studio::UndoCommand {
|
||||
ox::Error undo() noexcept final;
|
||||
};
|
||||
|
||||
class RenamePageCommand: public studio::UndoCommand {
|
||||
private:
|
||||
Palette &m_pal;
|
||||
size_t m_page = 0;
|
||||
ox::String m_name;
|
||||
|
||||
public:
|
||||
RenamePageCommand(Palette &pal, size_t page, ox::StringParam name) noexcept;
|
||||
|
||||
~RenamePageCommand() noexcept override = default;
|
||||
|
||||
[[nodiscard]]
|
||||
int commandId() const noexcept final;
|
||||
|
||||
ox::Error redo() noexcept final;
|
||||
|
||||
ox::Error undo() noexcept final;
|
||||
|
||||
};
|
||||
|
||||
class DuplicatePageCommand: public studio::UndoCommand {
|
||||
private:
|
||||
Palette &m_pal;
|
||||
|
@ -29,7 +29,7 @@ bool AboutPopup::isOpen() const noexcept {
|
||||
return m_stage == Stage::Open;
|
||||
}
|
||||
|
||||
void AboutPopup::draw(studio::StudioContext &sctx) noexcept {
|
||||
void AboutPopup::draw(StudioContext &sctx) noexcept {
|
||||
switch (m_stage) {
|
||||
case Stage::Closed:
|
||||
break;
|
||||
@ -40,15 +40,14 @@ void AboutPopup::draw(studio::StudioContext &sctx) noexcept {
|
||||
case Stage::Open: {
|
||||
constexpr auto modalFlags =
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
ImGui::SetNextWindowSize(ImVec2(215, 90));
|
||||
studio::ig::centerNextWindow(sctx.tctx);
|
||||
ig::centerNextWindow(sctx.tctx);
|
||||
auto open = true;
|
||||
if (ImGui::BeginPopupModal("About", &open, modalFlags)) {
|
||||
ImGui::Text("%s", m_text.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Dummy(ImVec2(148.0f, 0.0f));
|
||||
ImGui::Dummy({148.0f, 0.0f});
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Close")) {
|
||||
if (ig::PushButton("Close")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
open = false;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ struct StudioContext {
|
||||
StudioUI &ui;
|
||||
Project *project = nullptr;
|
||||
turbine::Context &tctx;
|
||||
inline StudioContext(StudioUI &pUi, turbine::Context &pTctx) noexcept:
|
||||
StudioContext(StudioUI &pUi, turbine::Context &pTctx) noexcept:
|
||||
ui(pUi), tctx(pTctx) {}
|
||||
};
|
||||
|
||||
|
@ -45,10 +45,10 @@ class DragDropSource {
|
||||
private:
|
||||
bool const m_active{};
|
||||
public:
|
||||
inline DragDropSource() noexcept:
|
||||
DragDropSource() noexcept:
|
||||
m_active(ImGui::BeginDragDropSource()) {
|
||||
}
|
||||
inline ~DragDropSource() noexcept {
|
||||
~DragDropSource() noexcept {
|
||||
if (m_active) {
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
@ -58,7 +58,7 @@ class DragDropSource {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto dragDropSource(auto const&cb) noexcept {
|
||||
auto dragDropSource(auto const&cb) noexcept {
|
||||
if constexpr(ox::is_same_v<decltype(cb()), ox::Error>) {
|
||||
if (ig::DragDropSource const tgt; tgt) [[unlikely]] {
|
||||
return cb();
|
||||
@ -75,10 +75,10 @@ class DragDropTarget {
|
||||
private:
|
||||
bool const m_active{};
|
||||
public:
|
||||
inline DragDropTarget() noexcept:
|
||||
DragDropTarget() noexcept:
|
||||
m_active(ImGui::BeginDragDropTarget()) {
|
||||
}
|
||||
inline ~DragDropTarget() noexcept {
|
||||
~DragDropTarget() noexcept {
|
||||
if (m_active) {
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
@ -128,6 +128,21 @@ void centerNextWindow(turbine::Context &ctx) noexcept;
|
||||
|
||||
bool PushButton(ox::CStringView lbl, ImVec2 const&btnSz = BtnSz) noexcept;
|
||||
|
||||
template<size_t StrCap>
|
||||
bool InputText(
|
||||
ox::CStringView label,
|
||||
ox::IString<StrCap> &text,
|
||||
ImGuiInputTextFlags const flags = 0,
|
||||
ImGuiInputTextCallback const callback = nullptr,
|
||||
void *user_data = nullptr) noexcept {
|
||||
auto const out = ImGui::InputText(
|
||||
label.c_str(), text.data(), StrCap + 1, flags, callback, user_data);
|
||||
if (out) {
|
||||
std::ignore = text.unsafeResize(ox::strlen(text.c_str()));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
enum class PopupResponse {
|
||||
None,
|
||||
OK,
|
||||
@ -136,6 +151,8 @@ enum class PopupResponse {
|
||||
|
||||
PopupResponse PopupControlsOkCancel(float popupWidth, bool &popupOpen);
|
||||
|
||||
PopupResponse PopupControlsOkCancel(bool &popupOpen);
|
||||
|
||||
[[nodiscard]]
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, ImVec2 const&sz = {285, 0});
|
||||
|
||||
|
@ -73,9 +73,13 @@ PopupResponse PopupControlsOkCancel(float popupWidth, bool &popupOpen) {
|
||||
return out;
|
||||
}
|
||||
|
||||
PopupResponse PopupControlsOkCancel(bool &popupOpen) {
|
||||
return PopupControlsOkCancel(ImGui::GetContentRegionAvail().x + 17, popupOpen);
|
||||
}
|
||||
|
||||
bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, ImVec2 const&sz) {
|
||||
constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
|
||||
ig::centerNextWindow(ctx);
|
||||
centerNextWindow(ctx);
|
||||
ImGui::OpenPopup(popupName.c_str());
|
||||
ImGui::SetNextWindowSize(sz);
|
||||
return ImGui::BeginPopupModal(popupName.c_str(), &show, modalFlags);
|
||||
@ -122,23 +126,11 @@ bool ComboBox(
|
||||
|
||||
bool FileComboBox(
|
||||
ox::CStringView lbl,
|
||||
studio::StudioContext &sctx,
|
||||
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;
|
||||
return ComboBox(lbl, list, selectedIdx);
|
||||
}
|
||||
|
||||
bool ListBox(
|
||||
@ -164,14 +156,14 @@ bool ListBox(
|
||||
}
|
||||
|
||||
bool ListBox(ox::CStringView name, ox::SpanView<ox::String> const&list, size_t &selIdx) noexcept {
|
||||
return ig::ListBox(name, [list](size_t i) -> ox::CStringView {
|
||||
return ListBox(name, [list](size_t i) -> ox::CStringView {
|
||||
return list[i];
|
||||
}, list.size(), selIdx);
|
||||
}
|
||||
|
||||
|
||||
FilePicker::FilePicker(
|
||||
studio::StudioContext &sctx,
|
||||
StudioContext &sctx,
|
||||
ox::String title,
|
||||
ox::String fileExt,
|
||||
ImVec2 const&size) noexcept:
|
||||
@ -186,12 +178,12 @@ void FilePicker::draw() noexcept {
|
||||
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)) {
|
||||
IDStackItem const idStackItem(m_title);
|
||||
if (BeginPopup(m_sctx.tctx, m_title, 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) {
|
||||
ComboBox(m_title, list, selIdx);
|
||||
if (PopupControlsOkCancel(popupSz.x, m_show) == ig::PopupResponse::OK) {
|
||||
filePicked.emit(list[selIdx]);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
|
Loading…
Reference in New Issue
Block a user