3#include "absl/status/status.h"
4#include "absl/strings/str_cat.h"
15#include "imgui/imgui.h"
20using ImGui::AcceptDragDropPayload;
21using ImGui::BeginChild;
22using ImGui::BeginDragDropTarget;
23using ImGui::BeginGroup;
24using ImGui::BeginPopup;
25using ImGui::BeginPopupContextItem;
27using ImGui::ColorButton;
28using ImGui::ColorPicker4;
30using ImGui::EndDragDropTarget;
34using ImGui::OpenPopup;
38using ImGui::Selectable;
39using ImGui::Separator;
40using ImGui::SetClipboardText;
46 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable |
47 ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Hideable;
49constexpr ImGuiColorEditFlags
kPalNoAlpha = ImGuiColorEditFlags_NoAlpha;
52 ImGuiColorEditFlags_NoPicker |
53 ImGuiColorEditFlags_NoTooltip;
56 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha |
57 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV |
58 ImGuiColorEditFlags_DisplayHex;
64#ifdef IMGUI_USE_STB_SPRINTF
65 int w = stbsp_vsnprintf(buf, (
int)buf_size, fmt, args);
67 int w = vsnprintf(buf, buf_size, fmt, args);
72 if (w == -1 || w >= (
int)buf_size)
73 w = (int)buf_size - 1;
78static inline float color_saturate(
float f) {
79 return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f;
82#define F32_TO_INT8_SAT(_VAL) \
83 ((int)(color_saturate(_VAL) * 255.0f + \
105 static ImVec4 color = ImVec4(0, 0, 0, 255.f);
106 static ImVec4 current_palette[256] = {};
107 ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
108 ImGuiColorEditFlags_NoDragDrop |
109 ImGuiColorEditFlags_NoOptions;
112 static bool init =
false;
113 if (loaded && !init) {
114 for (
int n = 0; n < palette.
size(); n++) {
115 auto color = palette[n];
116 current_palette[n].x = color.rgb().x / 255;
117 current_palette[n].y = color.rgb().y / 255;
118 current_palette[n].z = color.rgb().z / 255;
119 current_palette[n].w = 255;
124 static ImVec4 backup_color;
125 bool open_popup = ColorButton(
"MyColor##3b", color, misc_flags);
126 SameLine(0, GetStyle().ItemInnerSpacing.x);
127 open_popup |= Button(
"Palette");
132 backup_color = color;
139 ColorPicker4(
"##picker", (
float*)&color,
140 misc_flags | ImGuiColorEditFlags_NoSidePreview |
141 ImGuiColorEditFlags_NoSmallPreview);
149 if (Button(
"Update Map Palette")) {}
153 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
158 "##previous", backup_color,
159 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
161 color = backup_color;
166 for (
int n = 0; n < IM_ARRAYSIZE(current_palette); n++) {
169 SameLine(0.0f, GetStyle().ItemSpacing.y);
173 color = ImVec4(current_palette[n].x, current_palette[n].y,
174 current_palette[n].z, color.w);
176 if (BeginDragDropTarget()) {
177 if (
const ImGuiPayload* payload =
178 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
179 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 3);
180 if (
const ImGuiPayload* payload =
181 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
182 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 4);
192 return absl::OkStatus();
203 panel_manager->RegisterPanel({.card_id =
"palette.control_panel",
204 .display_name =
"Palette Controls",
205 .window_title =
" Group Manager",
207 .category =
"Palette",
208 .shortcut_hint =
"Ctrl+Shift+P",
211 .disabled_tooltip =
"Load a ROM first",
214 panel_manager->RegisterPanel({.card_id =
"palette.ow_main",
215 .display_name =
"Overworld Main",
216 .window_title =
" Overworld Main",
218 .category =
"Palette",
219 .shortcut_hint =
"Ctrl+Alt+1",
222 .disabled_tooltip =
"Load a ROM first",
225 panel_manager->RegisterPanel({.card_id =
"palette.ow_animated",
226 .display_name =
"Overworld Animated",
227 .window_title =
" Overworld Animated",
229 .category =
"Palette",
230 .shortcut_hint =
"Ctrl+Alt+2",
233 .disabled_tooltip =
"Load a ROM first",
236 panel_manager->RegisterPanel({.card_id =
"palette.dungeon_main",
237 .display_name =
"Dungeon Main",
238 .window_title =
" Dungeon Main",
240 .category =
"Palette",
241 .shortcut_hint =
"Ctrl+Alt+3",
244 .disabled_tooltip =
"Load a ROM first",
247 panel_manager->RegisterPanel({.card_id =
"palette.sprites",
248 .display_name =
"Global Sprite Palettes",
249 .window_title =
" SNES Palette",
251 .category =
"Palette",
252 .shortcut_hint =
"Ctrl+Alt+4",
255 .disabled_tooltip =
"Load a ROM first",
258 panel_manager->RegisterPanel({.card_id =
"palette.sprites_aux1",
259 .display_name =
"Sprites Aux 1",
260 .window_title =
" Sprites Aux 1",
262 .category =
"Palette",
263 .shortcut_hint =
"Ctrl+Alt+7",
266 .disabled_tooltip =
"Load a ROM first",
269 panel_manager->RegisterPanel({.card_id =
"palette.sprites_aux2",
270 .display_name =
"Sprites Aux 2",
271 .window_title =
" Sprites Aux 2",
273 .category =
"Palette",
274 .shortcut_hint =
"Ctrl+Alt+8",
277 .disabled_tooltip =
"Load a ROM first",
280 panel_manager->RegisterPanel({.card_id =
"palette.sprites_aux3",
281 .display_name =
"Sprites Aux 3",
282 .window_title =
" Sprites Aux 3",
284 .category =
"Palette",
285 .shortcut_hint =
"Ctrl+Alt+9",
288 .disabled_tooltip =
"Load a ROM first",
291 panel_manager->RegisterPanel({.card_id =
"palette.equipment",
292 .display_name =
"Equipment Palettes",
293 .window_title =
" Equipment Palettes",
295 .category =
"Palette",
296 .shortcut_hint =
"Ctrl+Alt+5",
299 .disabled_tooltip =
"Load a ROM first",
302 panel_manager->RegisterPanel({.card_id =
"palette.quick_access",
303 .display_name =
"Quick Access",
304 .window_title =
" Color Harmony",
306 .category =
"Palette",
307 .shortcut_hint =
"Ctrl+Alt+Q",
310 .disabled_tooltip =
"Load a ROM first",
313 panel_manager->RegisterPanel({.card_id =
"palette.custom",
314 .display_name =
"Custom Palette",
315 .window_title =
" Palette Editor",
317 .category =
"Palette",
318 .shortcut_hint =
"Ctrl+Alt+C",
321 .disabled_tooltip =
"Load a ROM first",
325 panel_manager->ShowPanel(session_id,
"palette.control_panel");
337 std::string
GetId()
const override {
return "palette.control_panel"; }
343 void Draw(
bool* p_open)
override {
344 if (p_open && !*p_open)
return;
357 std::string
GetId()
const override {
return "palette.quick_access"; }
363 void Draw(
bool* p_open)
override {
364 if (p_open && !*p_open)
return;
377 std::string
GetId()
const override {
return "palette.custom"; }
383 void Draw(
bool* p_open)
override {
384 if (p_open && !*p_open)
return;
395 if (!
rom() || !
rom()->is_loaded()) {
396 return absl::NotFoundError(
"ROM not open, no palettes to display");
402 "Palette Group Name", std::to_string(i),
403 std::string(kPaletteGroupNames[i]));
427 auto ow_main = std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
429 panel_manager->RegisterEditorPanel(std::move(ow_main));
432 auto ow_anim = std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
434 panel_manager->RegisterEditorPanel(std::move(ow_anim));
437 auto dungeon_main = std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
439 panel_manager->RegisterEditorPanel(std::move(dungeon_main));
442 auto sprite_global = std::make_unique<SpritePalettePanel>(
rom_,
game_data());
444 panel_manager->RegisterEditorPanel(std::move(sprite_global));
447 auto sprite_aux1 = std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
449 panel_manager->RegisterEditorPanel(std::move(sprite_aux1));
452 auto sprite_aux2 = std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
454 panel_manager->RegisterEditorPanel(std::move(sprite_aux2));
457 auto sprite_aux3 = std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
459 panel_manager->RegisterEditorPanel(std::move(sprite_aux3));
462 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
464 panel_manager->RegisterEditorPanel(std::move(equipment));
467 panel_manager->RegisterEditorPanel(std::make_unique<PaletteControlPanel>(
469 panel_manager->RegisterEditorPanel(std::make_unique<QuickAccessPalettePanel>(
471 panel_manager->RegisterEditorPanel(std::make_unique<CustomPalettePanel>(
475 return absl::OkStatus();
480 return absl::FailedPreconditionError(
"ROM not loaded");
489 return absl::OkStatus();
494 return absl::FailedPreconditionError(
"PaletteManager not initialized");
498 return absl::OkStatus();
503 return absl::FailedPreconditionError(
"PaletteManager not initialized");
507 return absl::OkStatus();
514 return absl::OkStatus();
518 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
520 Text(
"Custom Palette");
527 Text(
"Current Color");
537 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
540 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
544 if (Button(
"Copy to Clipboard")) {
545 SetClipboardText(buf);
552 Text(
"Recently Used Colors");
557 ImVec4 displayColor =
559 if (ImGui::ColorButton(
"##recent", displayColor)) {
585 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
586 ImGuiWindowFlags_HorizontalScrollbar)) {
590 SameLine(0.0f, GetStyle().ItemSpacing.y);
594 bool open_color_picker = ImGui::ColorButton(
595 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
597 if (open_color_picker) {
605 if (BeginPopupContextItem()) {
614 if (Button(
"Delete", ImVec2(-1, 0))) {
620 if (BeginDragDropTarget()) {
621 if (
const ImGuiPayload* payload =
622 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
624 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
636 if (ImGui::Button(
"+")) {
641 if (ImGui::Button(
"Clear")) {
646 if (ImGui::Button(
"Export")) {
647 std::string clipboard;
649 clipboard += absl::StrFormat(
"$%04X,", color.snes());
651 SetClipboardText(clipboard.c_str());
657 if (ImGui::BeginPopup(
677 return absl::NotFoundError(
"ROM not open, no palettes to display");
680 auto palette_group_name = kPaletteGroupNames[category];
683 const auto size = palette_group->
size();
685 for (
int j = 0; j < size; j++) {
687 auto pal_size = palette->
size();
694 false, palette_group_name.data(), std::to_string(j),
698 for (
int n = 0; n < pal_size; n++) {
700 if (n > 0 && n % 8 != 0)
701 SameLine(0.0f, 2.0f);
704 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
707 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
712 if (BeginPopupContextItem(popup_id.c_str())) {
724 return absl::OkStatus();
729 auto it = std::find_if(
731 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
750 auto original_color = palette[n];
755 original_color, palette[n]);
756 palette[n].set_modified(
true);
768 Text(
"RGB: %d, %d, %d", cr, cg, cb);
769 Text(
"SNES: $%04X", palette[n].snes());
773 if (Button(
"Copy as..", ImVec2(-1, 0)))
780 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
783 SetClipboardText(buf);
785 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d)", cr, cg, cb);
787 SetClipboardText(buf);
789 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
791 SetClipboardText(buf);
794 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"$%04X",
797 SetClipboardText(buf);
803 if (Button(
"Add to Custom Palette", ImVec2(-1, 0))) {
808 return absl::OkStatus();
813 if (index >= palette.
size()) {
814 return absl::InvalidArgumentError(
"Index out of bounds");
818 auto color = palette[index];
819 auto currentColor = color.rgb();
820 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
827 return absl::OkStatus();
833 if (index >= palette.
size() || index >= originalPalette.
size()) {
834 return absl::InvalidArgumentError(
"Index out of bounds");
836 auto color = originalPalette[index];
837 auto originalColor = color.rgb();
839 return absl::OkStatus();
852 ImGui::SetNextWindowSize(ImVec2(320, 420), ImGuiCond_FirstUseEver);
853 ImGui::SetNextWindowPos(ImVec2(10, 100), ImGuiCond_FirstUseEver);
855 ImGuiWindowFlags flags = ImGuiWindowFlags_None;
870 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f),
"Modified Panels:");
871 bool any_modified =
false;
874 ImGui::BulletText(
"Overworld Main");
878 ImGui::BulletText(
"Overworld Animated");
882 ImGui::BulletText(
"Dungeon Main");
886 ImGui::BulletText(
"Global Sprite Palettes");
890 ImGui::BulletText(
"Sprites Aux 1");
894 ImGui::BulletText(
"Sprites Aux 2");
898 ImGui::BulletText(
"Sprites Aux 3");
902 ImGui::BulletText(
"Equipment Palettes");
907 ImGui::TextDisabled(
"No unsaved changes");
913 ImGui::Text(
"Quick Actions:");
919 ImGui::BeginDisabled(!has_unsaved);
934 ImGui::EndDisabled();
936 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
938 ImGui::SetTooltip(
"Save all modified colors to ROM");
940 ImGui::SetTooltip(
"No unsaved changes");
945 ImGui::BeginDisabled(!has_unsaved);
955 ImGui::EndDisabled();
957 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
960 "Preview palette changes in other editors without saving to ROM");
962 ImGui::SetTooltip(
"No changes to preview");
966 ImGui::BeginDisabled(!has_unsaved);
967 if (ImGui::Button(
ICON_MD_UNDO " Discard All Changes", ImVec2(-1, 0))) {
973 ImGui::EndDisabled();
975 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
977 ImGui::SetTooltip(
"Discard all unsaved changes");
979 ImGui::SetTooltip(
"No changes to discard");
984 if (ImGui::BeginPopupModal(
988 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
989 ImGui::Text(
"Discard all unsaved changes?");
990 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f),
991 "This will revert %zu modified colors.",
995 if (ImGui::Button(
"Discard", ImVec2(120, 0))) {
997 ImGui::CloseCurrentPopup();
1000 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
1001 ImGui::CloseCurrentPopup();
1007 if (ImGui::BeginPopupModal(
1011 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1012 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
1013 "Failed to save changes");
1014 ImGui::Text(
"An error occurred while saving to ROM.");
1017 if (ImGui::Button(
"OK", ImVec2(120, 0))) {
1018 ImGui::CloseCurrentPopup();
1033 if (ImGui::BeginPopup(
1037 ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
1068 ImGui::BeginGroup();
1069 ImGui::Text(
"Current Color");
1079 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1080 ImGui::Text(
"%s", buf);
1082 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1084 ImGui::Text(
"%s", buf);
1086 if (ImGui::Button(
"Copy to Clipboard", ImVec2(-1, 0))) {
1087 SetClipboardText(buf);
1094 ImGui::Text(
"Recently Used Colors");
1096 ImGui::TextDisabled(
"No recently used colors yet");
1102 ImVec4 displayColor =
1109 if (ImGui::IsItemHovered()) {
1126 "Create your own custom color palette for reference. "
1127 "Colors can be added from any palette group or created from scratch.");
1133 ImGui::TextDisabled(
"Your custom palette is empty.");
1134 ImGui::Text(
"Click + to add colors or drag colors from any palette.");
1138 if (i > 0 && i % 16 != 0)
1139 SameLine(0.0f, 2.0f);
1143 bool open_color_picker =
1144 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1147 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");
1220 "PanelCustomPaletteColorEdit")
1237 int palette_index) {
1245 if (group_name ==
"ow_main") {
1246 panel_manager->ShowPanel(session_id,
"palette.ow_main");
1251 }
else if (group_name ==
"ow_animated") {
1252 panel_manager->ShowPanel(session_id,
"palette.ow_animated");
1257 }
else if (group_name ==
"dungeon_main") {
1258 panel_manager->ShowPanel(session_id,
"palette.dungeon_main");
1263 }
else if (group_name ==
"global_sprites") {
1264 panel_manager->ShowPanel(session_id,
"palette.sprites");
1269 }
else if (group_name ==
"sprites_aux1") {
1270 panel_manager->ShowPanel(session_id,
"palette.sprites_aux1");
1275 }
else if (group_name ==
"sprites_aux2") {
1276 panel_manager->ShowPanel(session_id,
"palette.sprites_aux2");
1281 }
else if (group_name ==
"sprites_aux3") {
1282 panel_manager->ShowPanel(session_id,
"palette.sprites_aux3");
1287 }
else if (group_name ==
"armors") {
1288 panel_manager->ShowPanel(session_id,
"palette.equipment");
1296 panel_manager->ShowPanel(session_id,
"palette.control_panel");
1304 ImGui::SetNextItemWidth(-1);
1305 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1339 for (
size_t cat_idx = 0; cat_idx < categories.size(); cat_idx++) {
1340 const auto& cat = categories[cat_idx];
1343 bool has_visible_items =
false;
1344 for (
const auto& group_name : cat.group_names) {
1346 has_visible_items =
true;
1351 if (!has_visible_items)
continue;
1353 ImGui::PushID(
static_cast<int>(cat_idx));
1356 std::string header_text =
1357 absl::StrFormat(
"%s %s", cat.icon, cat.display_name);
1358 bool open = ImGui::CollapsingHeader(header_text.c_str(),
1359 ImGuiTreeNodeFlags_DefaultOpen);
1362 ImGui::Indent(10.0f);
1363 for (
const auto& group_name : cat.group_names) {
1373 ImGui::PushStyleColor(ImGuiCol_Text,
1374 ImVec4(1.0f, 0.6f, 0.0f, 1.0f));
1377 ImGui::Checkbox(label.c_str(), show_flag);
1380 ImGui::PopStyleColor();
1384 ImGui::Unindent(10.0f);
1392 ImGui::Text(
"Utilities:");
1393 ImGui::Indent(10.0f);
1396 ImGui::Unindent(10.0f);
#define F32_TO_INT8_SAT(_VAL)
project::ResourceLabelManager * resource_label()
void set_dirty(bool dirty)
std::function< void()> draw_callback_
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_
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_
bool control_panel_minimized_
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)
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.
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.
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).
Draggable, dockable panel for editor sub-windows.
void SetPosition(Position pos)
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
#define ICON_MD_LANDSCAPE
#define ICON_MD_VISIBILITY
#define ICON_MD_DASHBOARD
#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)
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