yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
palette_controls_panel.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <string>
5
6#include "absl/strings/str_format.h"
11#include "app/gui/core/color.h"
13#include "imgui/imgui.h"
14#include "util/i18n/tr.h"
15#include "zelda3/game_data.h"
16
17namespace yaze::editor {
18namespace {
19
21 const char* name;
22 const char* label;
23};
24constexpr PreviewGroup kGroups[] = {{"ow_main", "Overworld"},
25 {"ow_aux", "Overworld auxiliary"},
26 {"ow_animated", "Overworld animated"},
27 {"hud", "HUD"},
28 {"global_sprites", "Global sprites"},
29 {"armors", "Link"},
30 {"swords", "Swords"},
31 {"shields", "Shields"},
32 {"sprites_aux1", "Sprites"},
33 {"sprites_aux2", "Sprites auxiliary 2"},
34 {"sprites_aux3", "Sprites auxiliary 3"},
35 {"dungeon_main", "Dungeon"},
36 {"grass", "Grass"},
37 {"3d_object", "3D objects"},
38 {"ow_mini_map", "Overworld map"}};
39
40const char* GroupLabel(const std::string& name) {
41 for (const auto& group : kGroups) {
42 if (name == group.name)
43 return group.label;
44 }
45 return name.c_str();
46}
47
48bool CanPreview(const GraphicsEditorState& state) {
49 return state.game_data &&
51}
52
54 std::optional<GraphicsPaletteSelection> selection) {
55 SetGraphicsPreviewPalette(state, state.current_sheet_id, selection)
56 .IgnoreError();
57}
58
59} // namespace
60
63 const bool inline_controls = layout == GraphicsPaletteSelectorLayout::kInline;
64 const float font = ImGui::GetFontSize();
65 const float right =
66 ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
67 const auto next_control = [inline_controls, right](float width) {
68 if (inline_controls &&
69 ImGui::GetItemRectMax().x + ImGui::GetStyle().ItemSpacing.x + width <=
70 right) {
71 ImGui::SameLine();
72 }
73 ImGui::SetNextItemWidth(inline_controls ? width : -1);
74 };
75 const auto* selected = state.PreviewPalette(state.current_sheet_id);
76 const std::string selected_group = selected ? selected->group : "";
77 const char* label =
78 selected ? GroupLabel(selected->group) : tr("Loaded colors");
79 if (!inline_controls)
80 ImGui::TextUnformatted(tr("Preview palette"));
81 ImGui::BeginDisabled(!CanPreview(state));
82 ImGui::SetNextItemWidth(inline_controls ? 11 * font : -1);
83 const bool open = ImGui::BeginCombo("##PreviewPalette", label);
84 gui::AutoRegisterLastItem("combo", "Preview palette");
85 if (open) {
86 if (ImGui::Selectable(tr("Loaded colors"), !selected))
87 Choose(state, std::nullopt);
88 gui::AutoRegisterLastItem("selectable", "Loaded colors");
89 for (const auto& group : kGroups) {
90 const auto* palettes =
91 state.game_data
92 ? state.game_data->palette_groups.get_group(group.name)
93 : nullptr;
94 if (!palettes || palettes->empty())
95 continue;
96 if (ImGui::Selectable(tr(group.label), selected_group == group.name)) {
97 Choose(state, GraphicsPaletteSelection{group.name});
98 }
100 "selectable", absl::StrFormat("Preview group %s", group.name));
101 }
102 ImGui::EndCombo();
103 }
104 ImGui::EndDisabled();
105 // A choice above can erase or replace the selected entry.
106 selected = state.PreviewPalette(state.current_sheet_id);
107 if (!selected || !CanPreview(state))
108 return;
109 auto choice = *selected;
110 const auto resolved = ResolveGraphicsPreviewPalette(*state.game_data, choice);
111 if (!resolved.ok()) {
112 ImGui::TextWrapped("%s",
113 tr("Preview unavailable; choose another palette."));
114 return;
115 }
116 if (resolved->palette_count > 1) {
117 int index = choice.palette;
118 next_control(6 * font);
119 if (ImGui::InputInt("##PreviewPaletteIndex", &index)) {
120 choice.palette = std::clamp(index, 0, resolved->palette_count - 1);
121 choice.row = 0;
122 Choose(state, choice);
123 }
124 // InputInt's step buttons form a group with ID zero while idle. Register
125 // the visible group explicitly so automation can discover it before focus.
126 const auto min = ImGui::GetItemRectMin();
127 const auto max = ImGui::GetItemRectMax();
129 metadata.label = "Preview palette index";
130 metadata.visible = ImGui::IsItemVisible();
131 metadata.bounds = {min.x, min.y, max.x, max.y, true};
133 "input:preview_palette_index", "input",
134 ImGui::GetID("##PreviewPaletteIndex"), "", metadata);
136 "Palette index in the selected group; changes only this preview");
137 }
138 if (resolved->row_count > 1) {
139 const auto row_label = absl::StrFormat("%s %d/%d", tr("Row"),
140 choice.row + 1, resolved->row_count);
141 next_control(
142 ImGui::CalcTextSize(row_label.c_str()).x +
143 2 * (ImGui::GetFrameHeight() + ImGui::GetStyle().ItemSpacing.x));
144 ImGui::BeginGroup();
145 ImGui::BeginDisabled(choice.row == 0);
146 const bool previous = ImGui::ArrowButton("##RowDown", ImGuiDir_Left);
147 gui::AutoRegisterLastItem("button", "Previous palette row");
148 ImGui::EndDisabled();
149 ImGui::SameLine();
150 ImGui::TextUnformatted(row_label.c_str());
151 ImGui::SameLine();
152 ImGui::BeginDisabled(choice.row + 1 >= resolved->row_count);
153 const bool next = ImGui::ArrowButton("##RowUp", ImGuiDir_Right);
154 gui::AutoRegisterLastItem("button", "Next palette row");
155 ImGui::EndDisabled();
156 if (previous || next) {
157 choice.row += next ? 1 : -1;
158 Choose(state, choice);
159 }
160 ImGui::EndGroup();
161 }
162}
163
164void PaletteControlsPanel::Draw(bool* p_open) {
165 Update().IgnoreError();
166}
167
169 if (!CanPreview(*state_)) {
170 ImGui::TextDisabled(tr("Load this ROM's graphics to preview palettes"));
171 return absl::OkStatus();
172 }
173 if (state_->SourceTarget()) {
174 ImGui::TextWrapped("%s", tr("The source editor controls these colors."));
175 if (ImGui::Button(tr("Use manual palette")))
177 else
178 return absl::OkStatus();
179 }
180 DrawPresets();
181 ImGui::Separator();
183 ImGui::Separator();
185 ImGui::Separator();
187 return absl::OkStatus();
188}
189
191 constexpr PreviewGroup presets[] = {{"ow_main", "Overworld"},
192 {"dungeon_main", "Dungeon"},
193 {"sprites_aux1", "Sprites"},
194 {"armors", "Link"},
195 {"hud", "HUD"}};
196 for (size_t i = 0; i < std::size(presets); ++i) {
197 if (i != 0 && i != 3)
198 ImGui::SameLine();
199 const auto& preset = presets[i];
200 const auto* group =
202 ImGui::BeginDisabled(!group || group->empty());
203 if (ImGui::Button(tr(preset.label))) {
204 Choose(*state_, GraphicsPaletteSelection{preset.name});
205 }
207 absl::StrFormat("%s preview", preset.label));
208 ImGui::EndDisabled();
209 HOVER_HINT("Apply this palette to the current sheet preview");
210 }
211}
212
216
218 const auto* selected = state_->PreviewPalette(state_->current_sheet_id);
219 if (!selected) {
220 ImGui::TextWrapped("%s", tr("Showing this sheet's loaded colors. Choose a "
221 "group to preview another palette."));
222 return;
223 }
224 const auto resolved =
226 if (!resolved.ok())
227 return;
228 auto choice = *selected;
229 const auto& palette =
231 ->palette_ref(choice.palette);
232 const auto layout =
233 internal::GetPaletteRowLayout(choice.group, palette.size());
234 ImGui::TextDisabled(tr("Preview only; source colors are unchanged"));
235 for (size_t i = 0; i < palette.size(); ++i) {
236 if (i % layout.colors_per_row != 0)
237 ImGui::SameLine();
238 ImGui::PushID(static_cast<int>(i));
239 if (ImGui::ColorButton("##PaletteColor",
241 ImGuiColorEditFlags_NoTooltip, ImVec2(18, 18))) {
242 choice.row = static_cast<int>(i) / layout.colors_per_row;
243 Choose(*state_, choice);
244 }
245 if (ImGui::IsItemHovered()) {
246 ImGui::SetTooltip(
247 tr("Row %d, slot %d: $%04X. Click to preview this row."),
248 static_cast<int>(i) / layout.colors_per_row + 1,
249 static_cast<int>(i) % layout.colors_per_row, palette[i].snes());
250 }
251 ImGui::PopID();
252 }
253}
254
256 if (ImGui::Button(tr("Restore loaded colors")))
257 Choose(*state_, std::nullopt);
258 gui::AutoRegisterLastItem("button", "Restore loaded colors");
259 const auto* selected = state_->PreviewPalette(state_->current_sheet_id);
260 if (!selected)
261 return;
262 const auto choice = *selected;
263 if (!state_->selected_sheets.empty() &&
264 ImGui::Button(tr("Preview on selected sheets"))) {
265 for (uint16_t sheet : state_->selected_sheets) {
266 SetGraphicsPreviewPalette(*state_, sheet, choice).IgnoreError();
267 }
268 }
269 if (ImGui::Button(tr("Preview on all sheets"))) {
270 for (uint16_t sheet = 0; sheet < zelda3::kNumGfxSheets; ++sheet) {
271 SetGraphicsPreviewPalette(*state_, sheet, choice).IgnoreError();
272 }
273 }
274}
275
276} // namespace yaze::editor
Shared state between GraphicsEditor panel components.
const GraphicsEditTarget * SourceTarget() const
const GraphicsPaletteSelection * PreviewPalette(uint16_t sheet) const
absl::Status Update()
Legacy Update method for backward compatibility.
void DrawPresets()
Draw quick preset buttons.
void Draw(bool *p_open) override
Draw the palette controls UI (WindowContent interface)
void DrawPaletteDisplay()
Draw the current palette display.
void DrawPaletteGroupSelector()
Draw palette group selection.
const void * gfx_sheets_owner() const
Definition arena.h:216
static Arena & Get()
Definition arena.cc:24
void RegisterWidget(const std::string &full_path, const std::string &type, ImGuiID imgui_id, const std::string &description="", const WidgetMetadata &metadata=WidgetMetadata())
static WidgetIdRegistry & Instance()
#define HOVER_HINT(string)
Definition macro.h:24
void Choose(GraphicsEditorState &state, std::optional< GraphicsPaletteSelection > selection)
PaletteRowLayout GetPaletteRowLayout(std::string_view group_name, std::size_t palette_size)
Editors are the view controllers for the application.
absl::Status SetGraphicsPreviewPalette(GraphicsEditorState &state, uint16_t sheet, std::optional< GraphicsPaletteSelection > selection)
absl::StatusOr< GraphicsPalettePreview > ResolveGraphicsPreviewPalette(zelda3::GameData &data, const GraphicsPaletteSelection &selection)
void DrawGraphicsPreviewPaletteSelector(GraphicsEditorState &state, GraphicsPaletteSelectorLayout layout)
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
constexpr uint32_t kNumGfxSheets
Definition game_data.h:28
PaletteGroup * get_group(const std::string &group_name)
const SnesPalette & palette_ref(int i) const
gfx::PaletteGroupMap palette_groups
Definition game_data.h:95
Automatic widget registration helpers for ImGui Test Engine integration.