yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
palette_reorder_control.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <numeric>
5
6#include "absl/strings/str_format.h"
10#include "imgui/imgui.h"
11#include "util/i18n/tr.h"
12#include "zelda3/game_data.h"
13
14namespace yaze::editor {
15
17 source_ = state.source_context;
20 sheet_revisions_.clear();
21 for (const auto& target : source_->targets) {
22 sheet_revisions_[target.sheet_id] =
23 state.game_data->sheet_store.Revision(target.sheet_id);
24 }
25 order_ = {0, 1, 2, 3, 4, 5, 6, 7};
26 selected_slot_ = -1;
27 whole_pattern_ = false;
28 error_.clear();
29}
30
32 const GraphicsEditorState& state) const {
33 if (!source_ || !state.source_context || !state.game_data ||
34 source_->owner != state.game_data ||
36 source_->selected_target != state.source_context->selected_target ||
39 return true;
40 }
41 for (const auto& [sheet, revision] : sheet_revisions_) {
42 if (state.game_data->sheet_store.Revision(sheet) != revision)
43 return true;
44 }
45 return false;
46}
47
49 bool busy) {
50 const auto* target = state.SourceTarget();
51 if (!target) {
52 source_.reset();
53 if (ImGui::BeginPopup("Reorder source colors")) {
54 ImGui::CloseCurrentPopup();
55 ImGui::EndPopup();
56 }
57 return;
58 }
59 const float width = ImGui::CalcTextSize(tr("Reorder")).x +
60 ImGui::GetStyle().FramePadding.x * 2;
61 const float right =
62 ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
63 if (ImGui::GetItemRectMax().x + width + ImGui::GetStyle().ItemSpacing.x <=
64 right) {
65 ImGui::SameLine();
66 }
67 ImGui::BeginDisabled(busy || state.selection.is_floating || !apply);
68 if (ImGui::Button(tr("Reorder"))) {
69 Begin(state);
70 ImGui::OpenPopup("Reorder source colors");
71 }
72 gui::AutoRegisterLastItem("button", "Reorder source colors");
73 ImGui::EndDisabled();
74 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
75 ImGui::SetTooltip("%s", busy
76 ? tr("Finish the pixel stroke first")
77 : tr("Reorder colors and remap source pixels"));
78 }
79
80 ImGui::SetNextWindowSizeConstraints(
81 ImVec2(25 * ImGui::GetFontSize(), 0),
82 ImVec2(29 * ImGui::GetFontSize(), ImGui::GetIO().DisplaySize.y * 0.85f));
83 if (!ImGui::BeginPopup("Reorder source colors"))
84 return;
85 ImGui::PushTextWrapPos(ImGui::GetCursorPosX() + 25 * ImGui::GetFontSize());
86 const bool changed = SourceChanged(state);
87 if (changed) {
88 ImGui::TextWrapped("%s", tr("Source changed. Close and reopen Reorder."));
89 } else {
90 ImGui::TextUnformatted(tr("Remap pixels in:"));
91 if (ImGui::RadioButton(tr("Current tile"), !whole_pattern_))
92 whole_pattern_ = false;
93 gui::AutoRegisterLastItem("radio", "Reorder current tile");
94 ImGui::SameLine();
95 if (ImGui::RadioButton(tr("Source pattern"), whole_pattern_))
96 whole_pattern_ = true;
97 gui::AutoRegisterLastItem("radio", "Reorder source pattern");
98 ImGui::TextWrapped("%s", tr("Click two colors below to swap their slots. "
99 "Slot 0 stays transparent."));
100 const auto& palette = source_->targets[source_->selected_target].palette;
101 const float size = ImGui::GetFrameHeight();
102 for (int row = 0; row < 2; ++row) {
103 ImGui::TextUnformatted(row == 0 ? tr("Before") : tr("After"));
104 for (int slot = 0; slot < 8 && palette.size() == 8; ++slot) {
105 if (slot != 0)
106 ImGui::SameLine();
108 palette[row == 0 ? slot : order_[slot]]);
109 color.w = slot == 0 ? 0.0f : 1.0f;
110 ImGui::PushID(row * 8 + slot);
111 const bool clicked = ImGui::ColorButton(
112 "##Slot", color,
113 ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaPreview,
114 ImVec2(size, size));
116 "color", absl::StrFormat("Reorder %s slot %d",
117 row == 0 ? "before" : "after", slot));
118 if (clicked && row == 1 && slot != 0) {
119 if (selected_slot_ < 0) {
120 selected_slot_ = slot;
121 } else {
122 std::swap(order_[selected_slot_], order_[slot]);
123 selected_slot_ = -1;
124 error_.clear();
125 }
126 }
127 if (row == 1 && slot == selected_slot_) {
128 ImGui::GetWindowDrawList()->AddRect(
129 ImGui::GetItemRectMin(), ImGui::GetItemRectMax(),
130 ImGui::GetColorU32(ImGuiCol_Text), 0, 0, 2);
131 }
132 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
133 ImGui::SetTooltip(tr("Slot %d"), slot);
134 ImGui::PopID();
135 }
136 }
137 if (ImGui::SmallButton(tr("Reset order"))) {
138 order_ = {0, 1, 2, 3, 4, 5, 6, 7};
139 selected_slot_ = -1;
140 error_.clear();
141 }
142 gui::AutoRegisterLastItem("button", "Reset palette order");
143
144 std::vector<size_t> targets{source_->selected_target};
145 if (whole_pattern_) {
146 targets.resize(source_->targets.size());
147 std::iota(targets.begin(), targets.end(), 0);
148 }
149 PalettePermutation permutation{};
150 for (int slot = 0; slot < 8; ++slot)
151 permutation[order_[slot]] = slot;
152 const auto plan =
153 PlanPalettePixelPermutation(*source_, targets, permutation);
154 const bool supported = source_->resolve_live_source && plan.ok();
155 if (supported) {
156 ImGui::Text(tr("%zu source tiles; %zu changed colors"),
157 plan->physical_tiles, plan->colors.size());
158 ImGui::TextWrapped("%s", tr("Selected artwork keeps its appearance. "
159 "Other uses of these shared tiles or "
160 "palette slots can change."));
161 } else {
162 ImGui::TextWrapped(
163 "%s", plan.ok() ? tr("This source cannot resolve live edits.")
164 : std::string(plan.status().message()).c_str());
165 }
166 if (!error_.empty())
167 ImGui::TextWrapped("%s", error_.c_str());
168 ImGui::BeginDisabled(!supported || busy || state.selection.is_floating ||
169 !apply ||
170 (plan->colors.empty() && plan->sheets.empty()));
171 if (ImGui::Button(tr("Apply"))) {
172 const auto status = apply(targets, permutation);
173 if (status.ok()) {
174 ImGui::CloseCurrentPopup();
175 } else {
176 error_ = std::string(status.message());
177 }
178 }
179 gui::AutoRegisterLastItem("button", "Apply palette reorder");
180 ImGui::EndDisabled();
181 ImGui::SameLine();
182 }
183 if (ImGui::Button(tr("Cancel")))
184 ImGui::CloseCurrentPopup();
185 gui::AutoRegisterLastItem("button", "Cancel palette reorder");
186 ImGui::PopTextWrapPos();
187 ImGui::EndPopup();
188}
189
190} // namespace yaze::editor
Shared state between GraphicsEditor panel components.
std::optional< GraphicsEditContext > source_context
const GraphicsEditTarget * SourceTarget() const
std::function< absl::Status(const std::vector< size_t > &, const PalettePermutation &)> Apply
std::map< uint16_t, uint64_t > sheet_revisions_
std::optional< GraphicsEditContext > source_
bool SourceChanged(const GraphicsEditorState &state) const
void Draw(GraphicsEditorState &state, const Apply &apply, bool busy)
void Begin(const GraphicsEditorState &state)
uint64_t ColorRevision(const zelda3::GameData *game_data) const
static PaletteManager & Get()
Get the singleton instance.
uint64_t Revision(uint16_t sheet) const
Editors are the view controllers for the application.
std::array< uint8_t, 8 > PalettePermutation
absl::StatusOr< PalettePixelPlan > PlanPalettePixelPermutation(const GraphicsEditContext &source, const std::vector< size_t > &targets, const PalettePermutation &permutation)
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
Definition color.cc:24
Automatic widget registration helpers for ImGui Test Engine integration.