5#include "absl/status/status.h"
6#include "absl/strings/str_cat.h"
7#include "absl/strings/str_format.h"
21#include "imgui/imgui.h"
26using ImGui::AcceptDragDropPayload;
27using ImGui::BeginChild;
28using ImGui::BeginDragDropTarget;
29using ImGui::BeginGroup;
30using ImGui::BeginPopup;
31using ImGui::BeginPopupContextItem;
33using ImGui::ColorButton;
34using ImGui::ColorPicker4;
36using ImGui::EndDragDropTarget;
40using ImGui::OpenPopup;
44using ImGui::Selectable;
45using ImGui::Separator;
46using ImGui::SetClipboardText;
52 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable |
53 ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Hideable;
55constexpr ImGuiColorEditFlags
kPalNoAlpha = ImGuiColorEditFlags_NoAlpha;
58 ImGuiColorEditFlags_NoPicker |
59 ImGuiColorEditFlags_NoTooltip;
62 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha |
63 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV |
64 ImGuiColorEditFlags_DisplayHex;
70#ifdef IMGUI_USE_STB_SPRINTF
71 int w = stbsp_vsnprintf(buf, (
int)buf_size, fmt, args);
73 int w = vsnprintf(buf, buf_size, fmt, args);
78 if (w == -1 || w >= (
int)buf_size)
79 w = (int)buf_size - 1;
84static inline float color_saturate(
float f) {
85 return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f;
88#define F32_TO_INT8_SAT(_VAL) \
89 ((int)(color_saturate(_VAL) * 255.0f + \
111 static ImVec4 color = ImVec4(0, 0, 0, 1.0f);
112 static ImVec4 current_palette[256] = {};
113 static int current_palette_count = 0;
114 ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
115 ImGuiColorEditFlags_NoDragDrop |
116 ImGuiColorEditFlags_NoOptions;
120 current_palette_count =
121 std::min<int>(
static_cast<int>(palette.
size()),
122 static_cast<int>(IM_ARRAYSIZE(current_palette)));
124 for (
int n = 0; n < current_palette_count; ++n) {
125 const auto palette_color = palette[
static_cast<size_t>(n)];
126 current_palette[n].x = palette_color.rgb().x / 255.0f;
127 current_palette[n].y = palette_color.rgb().y / 255.0f;
128 current_palette[n].z = palette_color.rgb().z / 255.0f;
129 current_palette[n].w = 1.0f;
131 for (
int n = current_palette_count;
132 n < static_cast<int>(IM_ARRAYSIZE(current_palette)); ++n) {
133 current_palette[n] = ImVec4(0, 0, 0, 1.0f);
136 current_palette_count = 0;
139 static ImVec4 backup_color;
140 bool open_popup = ColorButton(
"MyColor##3b", color, misc_flags);
141 SameLine(0, GetStyle().ItemInnerSpacing.x);
142 open_popup |= Button(
"Palette");
147 backup_color = color;
154 ColorPicker4(
"##picker", (
float*)&color,
155 misc_flags | ImGuiColorEditFlags_NoSidePreview |
156 ImGuiColorEditFlags_NoSmallPreview);
164 if (Button(
"Update Map Palette")) {}
168 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
173 "##previous", backup_color,
174 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
176 color = backup_color;
181 if (current_palette_count <= 0) {
182 ImGui::TextDisabled(
"No palette entries loaded.");
184 for (
int n = 0; n < current_palette_count; n++) {
187 SameLine(0.0f, GetStyle().ItemSpacing.y);
191 color = ImVec4(current_palette[n].x, current_palette[n].y,
192 current_palette[n].z, color.w);
194 if (BeginDragDropTarget()) {
195 if (
const ImGuiPayload* payload =
196 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
197 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 3);
198 if (
const ImGuiPayload* payload =
199 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
200 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 4);
210 return absl::OkStatus();
221 panel_manager->RegisterPanel(
222 {.card_id =
"palette.control_panel",
223 .display_name =
"Palette Controls",
224 .window_title =
" Palette Controls",
226 .category =
"Palette",
227 .shortcut_hint =
"Ctrl+Shift+P",
231 .disabled_tooltip =
"Load a ROM first"});
233 panel_manager->RegisterPanel(
234 {.card_id =
"palette.ow_main",
235 .display_name =
"Overworld Main",
236 .window_title =
" Overworld Main",
238 .category =
"Palette",
239 .shortcut_hint =
"Ctrl+Alt+1",
243 .disabled_tooltip =
"Load a ROM first"});
245 panel_manager->RegisterPanel(
246 {.card_id =
"palette.ow_animated",
247 .display_name =
"Overworld Animated",
248 .window_title =
" Overworld Animated",
250 .category =
"Palette",
251 .shortcut_hint =
"Ctrl+Alt+2",
255 .disabled_tooltip =
"Load a ROM first"});
257 panel_manager->RegisterPanel(
258 {.card_id =
"palette.dungeon_main",
259 .display_name =
"Dungeon Main",
260 .window_title =
" Dungeon Main",
262 .category =
"Palette",
263 .shortcut_hint =
"Ctrl+Alt+3",
267 .disabled_tooltip =
"Load a ROM first"});
269 panel_manager->RegisterPanel(
270 {.card_id =
"palette.sprites",
271 .display_name =
"Global Sprite Palettes",
272 .window_title =
" SNES Palette",
274 .category =
"Palette",
275 .shortcut_hint =
"Ctrl+Alt+4",
279 .disabled_tooltip =
"Load a ROM first"});
281 panel_manager->RegisterPanel(
282 {.card_id =
"palette.sprites_aux1",
283 .display_name =
"Sprites Aux 1",
284 .window_title =
" Sprites Aux 1",
286 .category =
"Palette",
287 .shortcut_hint =
"Ctrl+Alt+7",
291 .disabled_tooltip =
"Load a ROM first"});
293 panel_manager->RegisterPanel(
294 {.card_id =
"palette.sprites_aux2",
295 .display_name =
"Sprites Aux 2",
296 .window_title =
" Sprites Aux 2",
298 .category =
"Palette",
299 .shortcut_hint =
"Ctrl+Alt+8",
303 .disabled_tooltip =
"Load a ROM first"});
305 panel_manager->RegisterPanel(
306 {.card_id =
"palette.sprites_aux3",
307 .display_name =
"Sprites Aux 3",
308 .window_title =
" Sprites Aux 3",
310 .category =
"Palette",
311 .shortcut_hint =
"Ctrl+Alt+9",
315 .disabled_tooltip =
"Load a ROM first"});
317 panel_manager->RegisterPanel(
318 {.card_id =
"palette.equipment",
319 .display_name =
"Equipment Palettes",
320 .window_title =
" Equipment Palettes",
322 .category =
"Palette",
323 .shortcut_hint =
"Ctrl+Alt+5",
327 .disabled_tooltip =
"Load a ROM first"});
329 panel_manager->RegisterPanel(
330 {.card_id =
"palette.quick_access",
331 .display_name =
"Quick Access",
332 .window_title =
" Color Harmony",
334 .category =
"Palette",
335 .shortcut_hint =
"Ctrl+Alt+Q",
339 .disabled_tooltip =
"Load a ROM first"});
341 panel_manager->RegisterPanel(
342 {.card_id =
"palette.custom",
343 .display_name =
"Custom Palette",
344 .window_title =
" Palette Editor",
346 .category =
"Palette",
347 .shortcut_hint =
"Ctrl+Alt+C",
351 .disabled_tooltip =
"Load a ROM first"});
354 panel_manager->ShowPanel(session_id,
"palette.control_panel");
366 std::string
GetId()
const override {
return "palette.control_panel"; }
373 void Draw(
bool* p_open)
override {
374 if (p_open && !*p_open)
389 std::string
GetId()
const override {
return "palette.quick_access"; }
396 void Draw(
bool* p_open)
override {
397 if (p_open && !*p_open)
412 std::string
GetId()
const override {
return "palette.custom"; }
419 void Draw(
bool* p_open)
override {
420 if (p_open && !*p_open)
433 if (!
rom() || !
rom()->is_loaded()) {
434 return absl::NotFoundError(
"ROM not open, no palettes to display");
440 "Palette Group Name", std::to_string(i),
441 std::string(kPaletteGroupNames[i]));
466 std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
468 panel_manager->RegisterEditorPanel(std::move(ow_main));
472 std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
474 panel_manager->RegisterEditorPanel(std::move(ow_anim));
478 std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
480 panel_manager->RegisterEditorPanel(std::move(dungeon_main));
486 panel_manager->RegisterEditorPanel(std::move(sprite_global));
490 std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
492 panel_manager->RegisterEditorPanel(std::move(sprite_aux1));
496 std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
498 panel_manager->RegisterEditorPanel(std::move(sprite_aux2));
502 std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
504 panel_manager->RegisterEditorPanel(std::move(sprite_aux3));
507 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
509 panel_manager->RegisterEditorPanel(std::move(equipment));
525 panel_manager->RegisterEditorPanel(std::make_unique<PaletteControlPanel>(
527 panel_manager->RegisterEditorPanel(
528 std::make_unique<QuickAccessPalettePanel>(
530 panel_manager->RegisterEditorPanel(std::make_unique<CustomPalettePanel>(
534 return absl::OkStatus();
539 return absl::FailedPreconditionError(
"ROM not loaded");
548 return absl::OkStatus();
553 return absl::FailedPreconditionError(
"PaletteManager not initialized");
557 return absl::OkStatus();
562 return absl::FailedPreconditionError(
"PaletteManager not initialized");
566 return absl::OkStatus();
573 return absl::OkStatus();
577 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
579 Text(
"Custom Palette");
586 Text(
"Current Color");
596 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
599 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
603 if (Button(
"Copy to Clipboard")) {
604 SetClipboardText(buf);
611 Text(
"Recently Used Colors");
616 ImVec4 displayColor =
618 if (ImGui::ColorButton(
"##recent", displayColor)) {
644 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
645 ImGuiWindowFlags_HorizontalScrollbar)) {
649 SameLine(0.0f, GetStyle().ItemSpacing.y);
653 bool open_color_picker = ImGui::ColorButton(
654 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
656 if (open_color_picker) {
660 "CustomPaletteColorEdit")
664 if (BeginPopupContextItem()) {
673 if (Button(
"Delete", ImVec2(-1, 0))) {
679 if (BeginDragDropTarget()) {
680 if (
const ImGuiPayload* payload =
681 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
683 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
695 if (ImGui::Button(
"+")) {
700 if (ImGui::Button(
"Clear")) {
705 if (ImGui::Button(
"Export")) {
706 std::string clipboard;
708 clipboard += absl::StrFormat(
"$%04X,", color.snes());
710 SetClipboardText(clipboard.c_str());
716 if (ImGui::BeginPopup(
736 return absl::NotFoundError(
"ROM not open, no palettes to display");
739 auto palette_group_name = kPaletteGroupNames[category];
742 const auto size = palette_group->
size();
744 for (
int j = 0; j < size; j++) {
746 auto pal_size = palette->
size();
753 false, palette_group_name.data(), std::to_string(j),
757 for (
int n = 0; n < pal_size; n++) {
759 if (n > 0 && n % 8 != 0)
760 SameLine(0.0f, 2.0f);
763 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
766 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
771 if (BeginPopupContextItem(popup_id.c_str())) {
783 return absl::OkStatus();
788 auto it = std::find_if(
790 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
809 auto original_color = palette[n];
814 original_color, palette[n]);
815 palette[n].set_modified(
true);
827 Text(
"RGB: %d, %d, %d", cr, cg, cb);
828 Text(
"SNES: $%04X", palette[n].snes());
832 if (Button(
"Copy as..", ImVec2(-1, 0)))
839 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
842 SetClipboardText(buf);
844 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d)", cr, cg, cb);
846 SetClipboardText(buf);
848 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
850 SetClipboardText(buf);
853 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"$%04X",
856 SetClipboardText(buf);
862 if (Button(
"Add to Custom Palette", ImVec2(-1, 0))) {
867 return absl::OkStatus();
872 if (index >= palette.
size()) {
873 return absl::InvalidArgumentError(
"Index out of bounds");
877 auto color = palette[index];
878 auto currentColor = color.rgb();
879 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
886 return absl::OkStatus();
892 if (index >= palette.
size() || index >= originalPalette.
size()) {
893 return absl::InvalidArgumentError(
"Index out of bounds");
895 auto color = originalPalette[index];
896 auto originalColor = color.rgb();
898 return absl::OkStatus();
923 bool any_modified =
false;
926 ImGui::BulletText(
"Overworld Main");
930 ImGui::BulletText(
"Overworld Animated");
934 ImGui::BulletText(
"Dungeon Main");
938 ImGui::BulletText(
"Global Sprite Palettes");
942 ImGui::BulletText(
"Sprites Aux 1");
946 ImGui::BulletText(
"Sprites Aux 2");
950 ImGui::BulletText(
"Sprites Aux 3");
954 ImGui::BulletText(
"Equipment Palettes");
959 ImGui::TextDisabled(
"No unsaved changes");
965 ImGui::Text(
"Quick Actions:");
971 ImGui::BeginDisabled(!has_unsaved);
973 absl::StrFormat(
ICON_MD_SAVE " Save All (%zu colors)", modified_count)
980 absl::StrFormat(
"Failed to save palettes: %s", status.message()),
985 ImGui::EndDisabled();
987 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
989 ImGui::SetTooltip(
"Save all modified colors to ROM");
991 ImGui::SetTooltip(
"No unsaved changes");
996 ImGui::BeginDisabled(!has_unsaved);
1005 ImGui::EndDisabled();
1007 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1010 "Preview palette changes in other editors without saving to ROM");
1012 ImGui::SetTooltip(
"No changes to preview");
1016 ImGui::BeginDisabled(!has_unsaved);
1017 if (ImGui::Button(
ICON_MD_UNDO " Discard All Changes", ImVec2(-1, 0))) {
1022 ImGui::EndDisabled();
1024 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1026 ImGui::SetTooltip(
"Discard all unsaved changes");
1028 ImGui::SetTooltip(
"No changes to discard");
1033 if (ImGui::BeginPopupModal(
1037 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1038 ImGui::Text(
"Discard all unsaved changes?");
1040 "This will revert %zu modified colors.", modified_count);
1043 if (ImGui::Button(
"Discard", ImVec2(120, 0))) {
1045 ImGui::CloseCurrentPopup();
1048 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
1049 ImGui::CloseCurrentPopup();
1058 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1060 ImGui::Text(
"An error occurred while saving to ROM.");
1063 if (ImGui::Button(
"OK", ImVec2(120, 0))) {
1064 ImGui::CloseCurrentPopup();
1076 ImGui::BeginGroup();
1077 ImGui::Text(
"Current Color");
1087 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1088 ImGui::Text(
"%s", buf);
1090 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1092 ImGui::Text(
"%s", buf);
1094 if (ImGui::Button(
"Copy to Clipboard", ImVec2(-1, 0))) {
1095 SetClipboardText(buf);
1102 ImGui::Text(
"Recently Used Colors");
1104 ImGui::TextDisabled(
"No recently used colors yet");
1110 ImVec4 displayColor =
1117 if (ImGui::IsItemHovered()) {
1127 "Create your own custom color palette for reference. "
1128 "Colors can be added from any palette group or created from scratch.");
1134 ImGui::TextDisabled(
"Your custom palette is empty.");
1135 ImGui::Text(
"Click + to add colors or drag colors from any palette.");
1139 if (i > 0 && i % 16 != 0)
1140 SameLine(0.0f, 2.0f);
1144 bool open_color_picker =
1145 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1148 if (open_color_picker) {
1152 "PanelCustomPaletteColorEdit")
1156 if (BeginPopupContextItem()) {
1165 if (ImGui::Button(
"Delete", ImVec2(-1, 0))) {
1167 ImGui::CloseCurrentPopup();
1173 if (BeginDragDropTarget()) {
1174 if (
const ImGuiPayload* payload =
1175 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
1177 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
1182 EndDragDropTarget();
1203 std::string clipboard;
1205 clipboard += absl::StrFormat(
"$%04X,", color.snes());
1207 if (!clipboard.empty()) {
1208 clipboard.pop_back();
1210 SetClipboardText(clipboard.c_str());
1212 if (ImGui::IsItemHovered()) {
1213 ImGui::SetTooltip(
"Copy palette as comma-separated SNES values");
1218 "PanelCustomPaletteColorEdit")
1235 int palette_index) {
1243 if (group_name ==
"ow_main") {
1244 panel_manager->ShowPanel(session_id,
"palette.ow_main");
1249 }
else if (group_name ==
"ow_animated") {
1250 panel_manager->ShowPanel(session_id,
"palette.ow_animated");
1255 }
else if (group_name ==
"dungeon_main") {
1256 panel_manager->ShowPanel(session_id,
"palette.dungeon_main");
1261 }
else if (group_name ==
"global_sprites") {
1262 panel_manager->ShowPanel(session_id,
"palette.sprites");
1267 }
else if (group_name ==
"sprites_aux1") {
1268 panel_manager->ShowPanel(session_id,
"palette.sprites_aux1");
1273 }
else if (group_name ==
"sprites_aux2") {
1274 panel_manager->ShowPanel(session_id,
"palette.sprites_aux2");
1279 }
else if (group_name ==
"sprites_aux3") {
1280 panel_manager->ShowPanel(session_id,
"palette.sprites_aux3");
1285 }
else if (group_name ==
"armors") {
1286 panel_manager->ShowPanel(session_id,
"palette.equipment");
1294 panel_manager->ShowPanel(session_id,
"palette.control_panel");
1302 ImGui::SetNextItemWidth(-1);
1303 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1320 if (group_name ==
"ow_main")
1322 if (group_name ==
"ow_animated")
1324 if (group_name ==
"dungeon_main")
1326 if (group_name ==
"global_sprites")
1328 if (group_name ==
"sprites_aux1")
1330 if (group_name ==
"sprites_aux2")
1332 if (group_name ==
"sprites_aux3")
1334 if (group_name ==
"armors")
1346 for (
size_t cat_idx = 0; cat_idx < categories.size(); cat_idx++) {
1347 const auto& cat = categories[cat_idx];
1350 bool has_visible_items =
false;
1351 for (
const auto& group_name : cat.group_names) {
1353 has_visible_items =
true;
1358 if (!has_visible_items)
1361 ImGui::PushID(
static_cast<int>(cat_idx));
1364 std::string header_text =
1365 absl::StrFormat(
"%s %s", cat.icon, cat.display_name);
1366 bool open = ImGui::CollapsingHeader(header_text.c_str(),
1367 ImGuiTreeNodeFlags_DefaultOpen);
1370 ImGui::Indent(10.0f);
1371 for (
const auto& group_name : cat.group_names) {
1385 std::optional<gui::StyleColorGuard> mod_guard;
1387 mod_guard.emplace(ImGuiCol_Text, ImVec4(1.0f, 0.6f, 0.0f, 1.0f));
1390 ImGui::Checkbox(label.c_str(), show_flag);
1394 ImGui::Unindent(10.0f);
1402 ImGui::Text(
"Utilities:");
1403 ImGui::Indent(10.0f);
1406 ImGui::Unindent(10.0f);
#define F32_TO_INT8_SAT(_VAL)
project::ResourceLabelManager * resource_label()
void set_dirty(bool dirty)
std::function< void()> draw_callback_
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
std::string GetId() const override
Unique identifier for this panel.
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
void Draw(bool *p_open) override
Draw the panel content.
CustomPalettePanel(std::function< void()> draw_callback)
std::string GetEditorCategory() const override
Editor category this panel belongs to.
int GetPriority() const override
Get display priority for menu ordering.
std::string GetIcon() const override
Material Design icon for this panel.
Base interface for all logical panel components.
zelda3::GameData * game_data() const
EditorDependencies dependencies_
void SetGameData(zelda3::GameData *data)
std::string GetIcon() const override
Material Design icon for this panel.
std::function< void()> draw_callback_
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
std::string GetId() const override
Unique identifier for this panel.
void Draw(bool *p_open) override
Draw the panel content.
int GetPriority() const override
Get display priority for menu ordering.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
PaletteControlPanel(std::function< void()> draw_callback)
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
void DrawCategorizedPaletteList()
void Initialize() override
absl::Status DrawPaletteGroup(int category, bool right_side=false)
void DrawCustomPalettePanel()
bool * GetShowFlagForGroup(const std::string &group_name)
OverworldAnimatedPalettePanel * ow_anim_panel_
absl::Status ResetColorToOriginal(gfx::SnesPalette &palette, int index, const gfx::SnesPalette &originalPalette)
std::vector< gfx::SnesColor > custom_palette_
SpritesAux1PalettePanel * sprite_aux1_panel_
void DrawCustomPalette()
Draw custom palette editor with enhanced ROM hacking features.
bool show_sprites_aux3_panel_
bool show_sprites_aux1_panel_
void AddRecentlyUsedColor(const gfx::SnesColor &color)
absl::Status Update() override
bool PassesSearchFilter(const std::string &group_name) const
absl::Status Undo() override
bool show_dungeon_main_panel_
bool show_equipment_panel_
EquipmentPalettePanel * equipment_panel_
bool show_custom_palette_
SpritePalettePanel * sprite_global_panel_
absl::Status HandleColorPopup(gfx::SnesPalette &palette, int i, int j, int n)
bool show_ow_animated_panel_
gfx::SnesColor current_color_
void DrawQuickAccessPanel()
SpritesAux2PalettePanel * sprite_aux2_panel_
void DrawQuickAccessTab()
std::vector< gfx::SnesColor > recently_used_colors_
palette_internal::PaletteEditorHistory history_
absl::Status Save() override
bool show_sprites_aux2_panel_
absl::Status Load() override
GfxGroupEditor gfx_group_editor_
void JumpToPalette(const std::string &group_name, int palette_index)
Jump to a specific palette by group and index.
DungeonMainPalettePanel * dungeon_main_panel_
SpritesAux3PalettePanel * sprite_aux3_panel_
OverworldMainPalettePanel * ow_main_panel_
absl::Status Redo() override
absl::Status EditColorInPalette(gfx::SnesPalette &palette, int index)
bool HasUnsavedChanges() const
void SetSelectedPaletteIndex(int index)
void SetToastManager(ToastManager *toast_manager)
QuickAccessPalettePanel(std::function< void()> draw_callback)
std::string GetId() const override
Unique identifier for this panel.
void Draw(bool *p_open) override
Draw the panel content.
std::string GetIcon() const override
Material Design icon for this panel.
std::string GetEditorCategory() const override
Editor category this panel belongs to.
int GetPriority() const override
Get display priority for menu ordering.
std::function< void()> draw_callback_
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
float GetPreferredWidth() const override
Get preferred width for this panel (optional)
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f)
void RecordChange(const std::string &group_name, size_t palette_index, size_t color_index, const gfx::SnesColor &original_color, const gfx::SnesColor &new_color)
bool HasUnsavedChanges() const
Check if there are ANY unsaved changes.
bool IsGroupModified(const std::string &group_name) const
Check if a specific palette group has modifications.
void Undo()
Undo the most recent change.
void Initialize(zelda3::GameData *game_data)
Initialize the palette manager with GameData.
void DiscardAllChanges()
Discard ALL unsaved changes.
size_t GetModifiedColorCount() const
Get count of modified colors across all groups.
static PaletteManager & Get()
Get the singleton instance.
absl::Status SaveAllToRom()
Save ALL modified palettes to ROM.
absl::Status ApplyPreviewChanges()
Apply preview changes to other editors without saving to ROM.
void Redo()
Redo the most recently undone change.
RAII timer for automatic timing management.
constexpr ImVec4 rgb() const
Get RGB values (WARNING: stored as 0-255 in ImVec4)
constexpr uint16_t snes() const
Get SNES 15-bit color.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
#define ICON_MD_LANDSCAPE
#define ICON_MD_VISIBILITY
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define TEXT_WITH_SEPARATOR(text)
int CustomFormatString(char *buf, size_t buf_size, const char *fmt,...)
constexpr ImGuiTableFlags kPaletteTableFlags
constexpr ImGuiColorEditFlags kPalNoAlpha
const std::vector< PaletteCategoryInfo > & GetPaletteCategories()
Get all palette categories with their associated groups.
absl::Status DisplayPalette(gfx::SnesPalette &palette, bool loaded)
Display SNES palette with enhanced ROM hacking features.
constexpr ImGuiColorEditFlags kColorPopupFlags
constexpr ImGuiColorEditFlags kPalButtonFlags
constexpr int kNumPalettes
std::string GetGroupDisplayName(const std::string &group_name)
Get display name for a palette group.
uint16_t ConvertRgbToSnes(const snes_color &color)
Convert RGB (0-255) to SNES 15-bit color.
std::array< float, 4 > ToFloatArray(const SnesColor &color)
constexpr const char * kPalette
bool FuzzyMatch(const std::string &pattern, const std::string &str)
Simple fuzzy match - returns true if all chars in pattern appear in str in order.
ImVec4 ConvertSnesColorToImVec4(const gfx::SnesColor &color)
Convert SnesColor to standard ImVec4 for display.
IMGUI_API bool SnesColorEdit4(absl::string_view label, gfx::SnesColor *color, ImGuiColorEditFlags flags)
std::string MakePopupId(size_t session_id, const std::string &editor_name, const std::string &popup_name)
Generate session-aware popup IDs to prevent conflicts in multi-editor layouts.
gfx::SnesColor ConvertImVec4ToSnesColor(const ImVec4 &color)
Convert standard ImVec4 to SnesColor.
#define RETURN_IF_ERROR(expr)
ToastManager * toast_manager
PanelManager * panel_manager
PaletteGroup * get_group(const std::string &group_name)
Represents a group of palettes.
auto mutable_palette(int i)
std::string CreateOrGetLabel(const std::string &type, const std::string &key, const std::string &defaultValue)
void SelectableLabelWithNameEdit(bool selected, const std::string &type, const std::string &key, const std::string &defaultValue)
gfx::PaletteGroupMap palette_groups