Compare commits

..

No commits in common. "135f0e4ce8f2b65c49e862c54c419da955034719" and "1f6fefdb68d0638da774c1a7c37173e589ea65a8" have entirely different histories.

13 changed files with 73 additions and 90 deletions

View File

@ -41,10 +41,31 @@ PaletteEditorImGui::PaletteEditorImGui(studio::StudioContext &sctx, ox::StringPa
m_sctx(sctx), m_sctx(sctx),
m_tctx(sctx.tctx), m_tctx(sctx.tctx),
m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) { m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) {
if (keel::ensureValid(m_pal).errCode) {
throw OxException(1, "PaletteEditorImGui: invalid Palette object");
}
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand); undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRename.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage); m_pageRename.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
} }
void PaletteEditorImGui::keyStateChanged(turbine::Key key, bool down) {
if (!down || m_pageRename.isOpen()) {
return;
}
if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) {
if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
m_page = ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1), m_pal.pages.size() - 1);
}
} else if (key == turbine::Key::Num_0) {
if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
m_selectedColorRow =
ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), m_pal.pages.size() - 1);
}
}
}
void PaletteEditorImGui::draw(studio::StudioContext&) noexcept { void PaletteEditorImGui::draw(studio::StudioContext&) noexcept {
auto const paneSize = ImGui::GetContentRegionAvail(); auto const paneSize = ImGui::GetContentRegionAvail();
{ {
@ -77,19 +98,6 @@ void PaletteEditorImGui::drawColumn(ox::CStringView txt) noexcept {
ImGui::Text("%s", txt.c_str()); ImGui::Text("%s", txt.c_str());
} }
void PaletteEditorImGui::numShortcuts(size_t &val, size_t const sizeRange) noexcept {
auto const lastElem = sizeRange - 1;
if (ImGui::IsKeyPressed(ImGuiKey_0)) {
val = ox::min<size_t>(9, lastElem);
} else for (auto i = 9u; i < 10; --i) {
auto const key = static_cast<ImGuiKey>(ImGuiKey_1 + i);
if (ImGui::IsKeyPressed(key)) {
val = ox::min<size_t>(i, lastElem);
break;
}
}
}
void PaletteEditorImGui::colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept { void PaletteEditorImGui::colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept {
ImGui::InputInt(label.c_str(), &v, 1, 5); ImGui::InputInt(label.c_str(), &v, 1, 5);
inputFocused = inputFocused || ImGui::IsItemFocused(); inputFocused = inputFocused || ImGui::IsItemFocused();
@ -232,8 +240,10 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
int g = green16(c); int g = green16(c);
int b = blue16(c); int b = blue16(c);
int const a = alpha16(c); int const a = alpha16(c);
auto const newName = ig::InputText<50>( auto const&currentName = m_pal.colorNames[m_selectedColorRow];
"Name", m_pal.colorNames[m_selectedColorRow]); ox::IString<50> name;
name = currentName;
auto const nameUpdated = ImGui::InputText("Name", name.data(), name.cap() + 1);
bool inputFocused = ImGui::IsItemFocused(); bool inputFocused = ImGui::IsItemFocused();
ImGui::Separator(); ImGui::Separator();
colorInput("Red", r, inputFocused); colorInput("Red", r, inputFocused);
@ -244,19 +254,24 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
m_pal, m_page, m_selectedColorRow); m_pal, m_page, m_selectedColorRow);
} }
if (!inputFocused && !m_pageRename.isOpen()) { if (!inputFocused && !m_pageRename.isOpen()) {
if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) { auto const lastColor = largestPage(m_pal) - 1;
numShortcuts(m_selectedColorRow, largestPage(m_pal)); if (ImGui::IsKeyPressed(ImGuiKey_0, false)) {
} else { m_selectedColorRow = ox::min<size_t>(9, lastColor);
numShortcuts(m_page, m_pal.pages.size()); } else for (auto i = 9u; i < 10; --i) {
auto const key = static_cast<ImGuiKey>(ImGuiKey_1 + i);
if (ImGui::IsKeyPressed(key, false)) {
m_selectedColorRow = ox::min<size_t>(i, lastColor);
break;
}
} }
} }
auto const newColor = color16(r, g, b, a); auto const newColor = color16(r, g, b, a);
if (c != newColor) { if (c != newColor) {
std::ignore = pushCommand<UpdateColorCommand>(m_pal, m_page, m_selectedColorRow, newColor); std::ignore = pushCommand<UpdateColorCommand>(m_pal, m_page, m_selectedColorRow, newColor);
} }
if (newName) { if (nameUpdated) {
std::ignore = pushCommand<UpdateColorInfoCommand>( std::ignore = pushCommand<UpdateColorInfoCommand>(
m_pal, m_selectedColorRow, ox::String{newName}); m_pal, m_selectedColorRow, ox::String{name.data()});
} }
} }

View File

@ -40,6 +40,8 @@ class PaletteEditorImGui: public studio::Editor {
public: public:
PaletteEditorImGui(studio::StudioContext &sctx, ox::StringParam path); PaletteEditorImGui(studio::StudioContext &sctx, ox::StringParam path);
void keyStateChanged(turbine::Key key, bool down) override;
void draw(studio::StudioContext&) noexcept final; void draw(studio::StudioContext&) noexcept final;
protected: protected:
@ -54,8 +56,6 @@ class PaletteEditorImGui: public studio::Editor {
drawColumn(ox::itoa(i)); drawColumn(ox::itoa(i));
} }
static void numShortcuts(size_t &val, size_t sizeRange) noexcept;
static void colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept; static void colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept;
void drawColorsEditor() noexcept; void drawColorsEditor() noexcept;

View File

@ -188,21 +188,19 @@ UpdateColorInfoCommand::UpdateColorInfoCommand(
} }
} }
bool UpdateColorInfoCommand::mergeWith(UndoCommand &cmd) noexcept { bool UpdateColorInfoCommand::mergeWith(UndoCommand const&cmd) noexcept {
if (cmd.commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColorInfo)) { if (cmd.commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColor)) {
return false; return false;
} }
auto ucCmd = dynamic_cast<UpdateColorInfoCommand const*>(&cmd); auto ucCmd = static_cast<UpdateColorInfoCommand const*>(&cmd);
if (m_idx != ucCmd->m_idx) { if (m_idx != ucCmd->m_idx) {
return false; return false;
} }
m_pal.colorNames[m_idx] = std::move(ucCmd->m_pal.colorNames[m_idx]);
setObsolete(m_altColorInfo == m_pal.colorNames[m_idx]);
return true; return true;
} }
int UpdateColorInfoCommand::commandId() const noexcept { int UpdateColorInfoCommand::commandId() const noexcept {
return static_cast<int>(PaletteEditorCommandId::UpdateColorInfo); return static_cast<int>(PaletteEditorCommandId::UpdateColor);
} }
ox::Error UpdateColorInfoCommand::redo() noexcept { ox::Error UpdateColorInfoCommand::redo() noexcept {
@ -234,11 +232,11 @@ UpdateColorCommand::UpdateColorCommand(
} }
} }
bool UpdateColorCommand::mergeWith(UndoCommand &cmd) noexcept { bool UpdateColorCommand::mergeWith(UndoCommand const&cmd) noexcept {
if (cmd.commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColor)) { if (cmd.commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColor)) {
return false; return false;
} }
auto ucCmd = dynamic_cast<UpdateColorCommand const*>(&cmd); auto ucCmd = static_cast<UpdateColorCommand const*>(&cmd);
if (m_idx != ucCmd->m_idx) { if (m_idx != ucCmd->m_idx) {
return false; return false;
} }

View File

@ -163,7 +163,7 @@ class UpdateColorInfoCommand: public studio::UndoCommand {
~UpdateColorInfoCommand() noexcept override = default; ~UpdateColorInfoCommand() noexcept override = default;
[[nodiscard]] [[nodiscard]]
bool mergeWith(UndoCommand &cmd) noexcept final; bool mergeWith(const UndoCommand &cmd) noexcept final;
[[nodiscard]] [[nodiscard]]
int commandId() const noexcept final; int commandId() const noexcept final;
@ -194,7 +194,7 @@ class UpdateColorCommand: public studio::UndoCommand {
~UpdateColorCommand() noexcept override = default; ~UpdateColorCommand() noexcept override = default;
[[nodiscard]] [[nodiscard]]
bool mergeWith(UndoCommand &cmd) noexcept final; bool mergeWith(const UndoCommand &cmd) noexcept final;
[[nodiscard]] [[nodiscard]]
int commandId() const noexcept final; int commandId() const noexcept final;

View File

@ -158,25 +158,21 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
} else if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) { } else if (key >= turbine::Key::Num_1 && key <= turbine::Key::Num_9) {
if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) { if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
auto const idx = ox::min<std::size_t>( auto const idx = ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1), static_cast<uint32_t>(key - turbine::Key::Num_1), m_model.pal().pages.size() - 1);
m_model.pal().pages.size() - 1);
m_model.setPalettePage(idx); m_model.setPalettePage(idx);
} else if (key <= turbine::Key::Num_9) { } else if (key <= turbine::Key::Num_0 + colorCnt) {
auto const idx = ox::min<std::size_t>( auto const idx = ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1), static_cast<uint32_t>(key - turbine::Key::Num_1), colorCnt - 1);
colorCnt - 1);
m_view.setPalIdx(idx); m_view.setPalIdx(idx);
} }
} else if (key == turbine::Key::Num_0) { } else if (key == turbine::Key::Num_0) {
if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) { if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Alt)) {
auto const idx = ox::min<std::size_t>( auto const idx = ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), m_model.pal().pages.size() - 1);
m_model.pal().pages.size() - 1);
m_model.setPalettePage(idx); m_model.setPalettePage(idx);
} else { } else if (colorCnt >= 10) {
auto const idx = ox::min<std::size_t>( auto const idx = ox::min<std::size_t>(
static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), static_cast<uint32_t>(key - turbine::Key::Num_1 + 9), colorCnt - 1);
colorCnt - 1);
m_view.setPalIdx(idx); m_view.setPalIdx(idx);
} }
} }

View File

@ -15,6 +15,7 @@ SceneEditorImGui::SceneEditorImGui(studio::StudioContext &ctx, ox::StringView pa
m_ctx(ctx.tctx), m_ctx(ctx.tctx),
m_editor(m_ctx, path), m_editor(m_ctx, path),
m_view(m_ctx, m_editor.scene()) { m_view(m_ctx, m_editor.scene()) {
setRequiresConstantRefresh(false);
} }
void SceneEditorImGui::draw(studio::StudioContext&) noexcept { void SceneEditorImGui::draw(studio::StudioContext&) noexcept {

View File

@ -23,6 +23,7 @@ class BaseEditor: public Widget {
bool m_cutEnabled = false; bool m_cutEnabled = false;
bool m_copyEnabled = false; bool m_copyEnabled = false;
bool m_pasteEnabled = false; bool m_pasteEnabled = false;
bool m_requiresConstantRefresh = false;
public: public:
~BaseEditor() override = default; ~BaseEditor() override = default;
@ -51,6 +52,9 @@ class BaseEditor: public Widget {
virtual void onActivated() noexcept; virtual void onActivated() noexcept;
[[nodiscard]]
bool requiresConstantRefresh() const noexcept;
void close() const; void close() const;
/** /**
@ -67,10 +71,10 @@ class BaseEditor: public Widget {
[[nodiscard]] [[nodiscard]]
bool unsavedChanges() const noexcept; bool unsavedChanges() const noexcept;
void setExportable(bool) noexcept; void setExportable(bool);
[[nodiscard]] [[nodiscard]]
bool exportable() const noexcept; bool exportable() const;
void setCutEnabled(bool); void setCutEnabled(bool);

View File

@ -128,35 +128,9 @@ void centerNextWindow(turbine::Context &ctx) noexcept;
bool PushButton(ox::CStringView lbl, ImVec2 const&btnSz = BtnSz) noexcept; bool PushButton(ox::CStringView lbl, ImVec2 const&btnSz = BtnSz) noexcept;
template<typename Str>
struct TextInput {
bool changed{};
Str text;
explicit constexpr operator ox::String() const noexcept { return ox::String{text}; }
constexpr operator ox::CStringView() const noexcept { return text; }
constexpr operator ox::StringView() const noexcept { return text; }
constexpr operator bool() const noexcept { return changed; }
};
template<size_t MaxChars = 50>
TextInput<ox::IString<MaxChars>> InputText(
ox::CStringViewCR label,
ox::StringViewCR currentText,
ImGuiInputTextFlags const flags = 0,
ImGuiInputTextCallback const callback = nullptr,
void *user_data = nullptr) noexcept {
TextInput<ox::IString<MaxChars>> out = {.text = currentText};
out.changed = ImGui::InputText(
label.c_str(), out.text.data(), MaxChars + 1, flags, callback, user_data);
if (out.changed) {
std::ignore = out.text.unsafeResize(ox::strlen(out.text.c_str()));
}
return out;
}
template<size_t StrCap> template<size_t StrCap>
bool InputText( bool InputText(
ox::CStringViewCR label, ox::CStringView label,
ox::IString<StrCap> &text, ox::IString<StrCap> &text,
ImGuiInputTextFlags const flags = 0, ImGuiInputTextFlags const flags = 0,
ImGuiInputTextCallback const callback = nullptr, ImGuiInputTextCallback const callback = nullptr,

View File

@ -17,22 +17,13 @@ class NoChangesException: public ox::Exception {
}; };
class UndoCommand { class UndoCommand {
private:
bool m_obsolete{};
public: public:
virtual ~UndoCommand() noexcept = default; virtual ~UndoCommand() noexcept = default;
virtual ox::Error redo() noexcept = 0; virtual ox::Error redo() noexcept = 0;
virtual ox::Error undo() noexcept = 0; virtual ox::Error undo() noexcept = 0;
[[nodiscard]] [[nodiscard]]
virtual int commandId() const noexcept = 0; virtual int commandId() const noexcept = 0;
virtual bool mergeWith(UndoCommand &cmd) noexcept; virtual bool mergeWith(UndoCommand const&cmd) noexcept;
constexpr void setObsolete(bool obsolete) noexcept {
m_obsolete = obsolete;
}
[[nodiscard]]
constexpr bool isObsolete() const noexcept {
return m_obsolete;
}
}; };
} }

View File

@ -36,6 +36,10 @@ void BaseEditor::keyStateChanged(turbine::Key, bool) {
void BaseEditor::onActivated() noexcept { void BaseEditor::onActivated() noexcept {
} }
bool BaseEditor::requiresConstantRefresh() const noexcept {
return m_requiresConstantRefresh;
}
void BaseEditor::close() const { void BaseEditor::close() const {
this->closed.emit(itemPath()); this->closed.emit(itemPath());
} }
@ -62,12 +66,12 @@ bool BaseEditor::unsavedChanges() const noexcept {
return m_unsavedChanges; return m_unsavedChanges;
} }
void BaseEditor::setExportable(bool exportable) noexcept { void BaseEditor::setExportable(bool exportable) {
m_exportable = exportable; m_exportable = exportable;
exportableChanged.emit(exportable); exportableChanged.emit(exportable);
} }
bool BaseEditor::exportable() const noexcept { bool BaseEditor::exportable() const {
return m_exportable; return m_exportable;
} }
@ -106,6 +110,10 @@ UndoStack *BaseEditor::undoStack() noexcept {
return nullptr; return nullptr;
} }
void BaseEditor::setRequiresConstantRefresh(bool value) noexcept {
m_requiresConstantRefresh = value;
}
Editor::Editor(ox::StringParam itemPath) noexcept: Editor::Editor(ox::StringParam itemPath) noexcept:
m_itemPath(std::move(itemPath)), m_itemPath(std::move(itemPath)),

View File

@ -3,7 +3,7 @@
namespace studio { namespace studio {
bool UndoCommand::mergeWith(UndoCommand&) noexcept { bool UndoCommand::mergeWith(UndoCommand const&) noexcept {
return false; return false;
} }

View File

@ -17,10 +17,6 @@ ox::Error UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
m_stack.emplace_back(std::move(cmd)); m_stack.emplace_back(std::move(cmd));
++m_stackIdx; ++m_stackIdx;
} }
if ((*m_stack.back().unwrap())->isObsolete()) {
m_stack.pop_back();
--m_stackIdx;
}
return {}; return {};
} }