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 window_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 window_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 window_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 window_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 window_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 window_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 window_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 window_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 window_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 window_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 window_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 window_manager->OpenWindow(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]));
462 std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
464 window_manager->RegisterWindowContent(std::move(ow_main));
468 std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
470 window_manager->RegisterWindowContent(std::move(ow_anim));
474 std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
476 window_manager->RegisterWindowContent(std::move(dungeon_main));
482 window_manager->RegisterWindowContent(std::move(sprite_global));
486 std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
488 window_manager->RegisterWindowContent(std::move(sprite_aux1));
492 std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
494 window_manager->RegisterWindowContent(std::move(sprite_aux2));
498 std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
500 window_manager->RegisterWindowContent(std::move(sprite_aux3));
503 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
505 window_manager->RegisterWindowContent(std::move(equipment));
521 window_manager->RegisterWindowContent(std::make_unique<PaletteControlPanel>(
523 window_manager->RegisterWindowContent(
524 std::make_unique<QuickAccessPalettePanel>(
526 window_manager->RegisterWindowContent(std::make_unique<CustomPalettePanel>(
530 return absl::OkStatus();
535 return absl::FailedPreconditionError(
"ROM not loaded");
544 return absl::OkStatus();
549 return absl::FailedPreconditionError(
"PaletteManager not initialized");
553 return absl::OkStatus();
558 return absl::FailedPreconditionError(
"PaletteManager not initialized");
562 return absl::OkStatus();
569 return absl::OkStatus();
573 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
575 Text(
"Custom Palette");
582 Text(
"Current Color");
592 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
595 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
599 if (Button(
"Copy to Clipboard")) {
600 SetClipboardText(buf);
607 Text(
"Recently Used Colors");
612 ImVec4 displayColor =
614 if (ImGui::ColorButton(
"##recent", displayColor)) {
640 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
641 ImGuiWindowFlags_HorizontalScrollbar)) {
645 SameLine(0.0f, GetStyle().ItemSpacing.y);
649 bool open_color_picker = ImGui::ColorButton(
650 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
652 if (open_color_picker) {
656 "CustomPaletteColorEdit")
660 if (BeginPopupContextItem()) {
669 if (Button(
"Delete", ImVec2(-1, 0))) {
675 if (BeginDragDropTarget()) {
676 if (
const ImGuiPayload* payload =
677 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
679 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
691 if (ImGui::Button(
"+")) {
696 if (ImGui::Button(
"Clear")) {
701 if (ImGui::Button(
"Export")) {
702 std::string clipboard;
704 clipboard += absl::StrFormat(
"$%04X,", color.snes());
706 SetClipboardText(clipboard.c_str());
712 if (ImGui::BeginPopup(
732 return absl::NotFoundError(
"ROM not open, no palettes to display");
735 auto palette_group_name = kPaletteGroupNames[category];
738 const auto size = palette_group->
size();
740 for (
int j = 0; j < size; j++) {
742 auto pal_size = palette->
size();
749 false, palette_group_name.data(), std::to_string(j),
753 for (
int n = 0; n < pal_size; n++) {
755 if (n > 0 && n % 8 != 0)
756 SameLine(0.0f, 2.0f);
759 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
762 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
767 if (BeginPopupContextItem(popup_id.c_str())) {
779 return absl::OkStatus();
784 auto it = std::find_if(
786 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
805 auto original_color = palette[n];
810 original_color, palette[n]);
811 palette[n].set_modified(
true);
823 Text(
"RGB: %d, %d, %d", cr, cg, cb);
824 Text(
"SNES: $%04X", palette[n].snes());
828 if (Button(
"Copy as..", ImVec2(-1, 0)))
835 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
838 SetClipboardText(buf);
840 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d)", cr, cg, cb);
842 SetClipboardText(buf);
844 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
846 SetClipboardText(buf);
849 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"$%04X",
852 SetClipboardText(buf);
858 if (Button(
"Add to Custom Palette", ImVec2(-1, 0))) {
863 return absl::OkStatus();
868 if (index >= palette.
size()) {
869 return absl::InvalidArgumentError(
"Index out of bounds");
873 auto color = palette[index];
874 auto currentColor = color.rgb();
875 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
882 return absl::OkStatus();
888 if (index >= palette.
size() || index >= originalPalette.
size()) {
889 return absl::InvalidArgumentError(
"Index out of bounds");
891 auto color = originalPalette[index];
892 auto originalColor = color.rgb();
894 return absl::OkStatus();
919 bool any_modified =
false;
922 ImGui::BulletText(
"Overworld Main");
926 ImGui::BulletText(
"Overworld Animated");
930 ImGui::BulletText(
"Dungeon Main");
934 ImGui::BulletText(
"Global Sprite Palettes");
938 ImGui::BulletText(
"Sprites Aux 1");
942 ImGui::BulletText(
"Sprites Aux 2");
946 ImGui::BulletText(
"Sprites Aux 3");
950 ImGui::BulletText(
"Equipment Palettes");
955 ImGui::TextDisabled(
"No unsaved changes");
961 ImGui::Text(
"Quick Actions:");
967 ImGui::BeginDisabled(!has_unsaved);
969 absl::StrFormat(
ICON_MD_SAVE " Save All (%zu colors)", modified_count)
976 absl::StrFormat(
"Failed to save palettes: %s", status.message()),
981 ImGui::EndDisabled();
983 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
985 ImGui::SetTooltip(
"Save all modified colors to ROM");
987 ImGui::SetTooltip(
"No unsaved changes");
992 ImGui::BeginDisabled(!has_unsaved);
1001 ImGui::EndDisabled();
1003 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1006 "Preview palette changes in other editors without saving to ROM");
1008 ImGui::SetTooltip(
"No changes to preview");
1012 ImGui::BeginDisabled(!has_unsaved);
1013 if (ImGui::Button(
ICON_MD_UNDO " Discard All Changes", ImVec2(-1, 0))) {
1018 ImGui::EndDisabled();
1020 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1022 ImGui::SetTooltip(
"Discard all unsaved changes");
1024 ImGui::SetTooltip(
"No changes to discard");
1029 if (ImGui::BeginPopupModal(
1033 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1034 ImGui::Text(
"Discard all unsaved changes?");
1036 "This will revert %zu modified colors.", modified_count);
1039 if (ImGui::Button(
"Discard", ImVec2(120, 0))) {
1041 ImGui::CloseCurrentPopup();
1044 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
1045 ImGui::CloseCurrentPopup();
1054 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1056 ImGui::Text(
"An error occurred while saving to ROM.");
1059 if (ImGui::Button(
"OK", ImVec2(120, 0))) {
1060 ImGui::CloseCurrentPopup();
1072 ImGui::BeginGroup();
1073 ImGui::Text(
"Current Color");
1083 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1084 ImGui::Text(
"%s", buf);
1086 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1088 ImGui::Text(
"%s", buf);
1090 if (ImGui::Button(
"Copy to Clipboard", ImVec2(-1, 0))) {
1091 SetClipboardText(buf);
1098 ImGui::Text(
"Recently Used Colors");
1100 ImGui::TextDisabled(
"No recently used colors yet");
1106 ImVec4 displayColor =
1113 if (ImGui::IsItemHovered()) {
1123 "Create your own custom color palette for reference. "
1124 "Colors can be added from any palette group or created from scratch.");
1130 ImGui::TextDisabled(
"Your custom palette is empty.");
1131 ImGui::Text(
"Click + to add colors or drag colors from any palette.");
1135 if (i > 0 && i % 16 != 0)
1136 SameLine(0.0f, 2.0f);
1140 bool open_color_picker =
1141 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1144 if (open_color_picker) {
1148 "PanelCustomPaletteColorEdit")
1152 if (BeginPopupContextItem()) {
1161 if (ImGui::Button(
"Delete", ImVec2(-1, 0))) {
1163 ImGui::CloseCurrentPopup();
1169 if (BeginDragDropTarget()) {
1170 if (
const ImGuiPayload* payload =
1171 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
1173 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
1178 EndDragDropTarget();
1199 std::string clipboard;
1201 clipboard += absl::StrFormat(
"$%04X,", color.snes());
1203 if (!clipboard.empty()) {
1204 clipboard.pop_back();
1206 SetClipboardText(clipboard.c_str());
1208 if (ImGui::IsItemHovered()) {
1209 ImGui::SetTooltip(
"Copy palette as comma-separated SNES values");
1214 "PanelCustomPaletteColorEdit")
1231 int palette_index) {
1239 if (group_name ==
"ow_main") {
1240 window_manager->OpenWindow(session_id,
"palette.ow_main");
1245 }
else if (group_name ==
"ow_animated") {
1246 window_manager->OpenWindow(session_id,
"palette.ow_animated");
1251 }
else if (group_name ==
"dungeon_main") {
1252 window_manager->OpenWindow(session_id,
"palette.dungeon_main");
1257 }
else if (group_name ==
"global_sprites") {
1258 window_manager->OpenWindow(session_id,
"palette.sprites");
1263 }
else if (group_name ==
"sprites_aux1") {
1264 window_manager->OpenWindow(session_id,
"palette.sprites_aux1");
1269 }
else if (group_name ==
"sprites_aux2") {
1270 window_manager->OpenWindow(session_id,
"palette.sprites_aux2");
1275 }
else if (group_name ==
"sprites_aux3") {
1276 window_manager->OpenWindow(session_id,
"palette.sprites_aux3");
1281 }
else if (group_name ==
"armors") {
1282 window_manager->OpenWindow(session_id,
"palette.equipment");
1290 window_manager->OpenWindow(session_id,
"palette.control_panel");
1298 ImGui::SetNextItemWidth(-1);
1299 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1316 if (group_name ==
"ow_main")
1318 if (group_name ==
"ow_animated")
1320 if (group_name ==
"dungeon_main")
1322 if (group_name ==
"global_sprites")
1324 if (group_name ==
"sprites_aux1")
1326 if (group_name ==
"sprites_aux2")
1328 if (group_name ==
"sprites_aux3")
1330 if (group_name ==
"armors")
1342 for (
size_t cat_idx = 0; cat_idx < categories.size(); cat_idx++) {
1343 const auto& cat = categories[cat_idx];
1346 bool has_visible_items =
false;
1347 for (
const auto& group_name : cat.group_names) {
1349 has_visible_items =
true;
1354 if (!has_visible_items)
1357 ImGui::PushID(
static_cast<int>(cat_idx));
1360 std::string header_text =
1361 absl::StrFormat(
"%s %s", cat.icon, cat.display_name);
1362 bool open = ImGui::CollapsingHeader(header_text.c_str(),
1363 ImGuiTreeNodeFlags_DefaultOpen);
1366 ImGui::Indent(10.0f);
1367 for (
const auto& group_name : cat.group_names) {
1381 std::optional<gui::StyleColorGuard> mod_guard;
1386 ImGui::Checkbox(label.c_str(), show_flag);
1390 ImGui::Unindent(10.0f);
1398 ImGui::Text(
"Utilities:");
1399 ImGui::Indent(10.0f);
1402 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.
zelda3::GameData * game_data() const
EditorDependencies dependencies_
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
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)
Base interface for all logical window content components.
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
WorkspaceWindowManager * window_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