3#include "absl/status/status.h"
4#include "absl/strings/str_cat.h"
5#include "absl/strings/str_format.h"
16#include "imgui/imgui.h"
21using ImGui::AcceptDragDropPayload;
22using ImGui::BeginChild;
23using ImGui::BeginDragDropTarget;
24using ImGui::BeginGroup;
25using ImGui::BeginPopup;
26using ImGui::BeginPopupContextItem;
28using ImGui::ColorButton;
29using ImGui::ColorPicker4;
31using ImGui::EndDragDropTarget;
35using ImGui::OpenPopup;
39using ImGui::Selectable;
40using ImGui::Separator;
41using ImGui::SetClipboardText;
47 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable |
48 ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Hideable;
50constexpr ImGuiColorEditFlags
kPalNoAlpha = ImGuiColorEditFlags_NoAlpha;
53 ImGuiColorEditFlags_NoPicker |
54 ImGuiColorEditFlags_NoTooltip;
57 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha |
58 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV |
59 ImGuiColorEditFlags_DisplayHex;
65#ifdef IMGUI_USE_STB_SPRINTF
66 int w = stbsp_vsnprintf(buf, (
int)buf_size, fmt, args);
68 int w = vsnprintf(buf, buf_size, fmt, args);
73 if (w == -1 || w >= (
int)buf_size)
74 w = (int)buf_size - 1;
79static inline float color_saturate(
float f) {
80 return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f;
83#define F32_TO_INT8_SAT(_VAL) \
84 ((int)(color_saturate(_VAL) * 255.0f + \
106 static ImVec4 color = ImVec4(0, 0, 0, 255.f);
107 static ImVec4 current_palette[256] = {};
108 ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
109 ImGuiColorEditFlags_NoDragDrop |
110 ImGuiColorEditFlags_NoOptions;
113 static bool init =
false;
114 if (loaded && !init) {
115 for (
int n = 0; n < palette.
size(); n++) {
116 auto color = palette[n];
117 current_palette[n].x = color.rgb().x / 255;
118 current_palette[n].y = color.rgb().y / 255;
119 current_palette[n].z = color.rgb().z / 255;
120 current_palette[n].w = 255;
125 static ImVec4 backup_color;
126 bool open_popup = ColorButton(
"MyColor##3b", color, misc_flags);
127 SameLine(0, GetStyle().ItemInnerSpacing.x);
128 open_popup |= Button(
"Palette");
133 backup_color = color;
140 ColorPicker4(
"##picker", (
float*)&color,
141 misc_flags | ImGuiColorEditFlags_NoSidePreview |
142 ImGuiColorEditFlags_NoSmallPreview);
150 if (Button(
"Update Map Palette")) {}
154 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
159 "##previous", backup_color,
160 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
162 color = backup_color;
167 for (
int n = 0; n < IM_ARRAYSIZE(current_palette); n++) {
170 SameLine(0.0f, GetStyle().ItemSpacing.y);
174 color = ImVec4(current_palette[n].x, current_palette[n].y,
175 current_palette[n].z, color.w);
177 if (BeginDragDropTarget()) {
178 if (
const ImGuiPayload* payload =
179 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
180 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 3);
181 if (
const ImGuiPayload* payload =
182 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
183 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 4);
193 return absl::OkStatus();
204 panel_manager->RegisterPanel(
205 {.card_id =
"palette.control_panel",
206 .display_name =
"Palette Controls",
207 .window_title =
" Group Manager",
209 .category =
"Palette",
210 .shortcut_hint =
"Ctrl+Shift+P",
214 .disabled_tooltip =
"Load a ROM first"});
216 panel_manager->RegisterPanel(
217 {.card_id =
"palette.ow_main",
218 .display_name =
"Overworld Main",
219 .window_title =
" Overworld Main",
221 .category =
"Palette",
222 .shortcut_hint =
"Ctrl+Alt+1",
226 .disabled_tooltip =
"Load a ROM first"});
228 panel_manager->RegisterPanel(
229 {.card_id =
"palette.ow_animated",
230 .display_name =
"Overworld Animated",
231 .window_title =
" Overworld Animated",
233 .category =
"Palette",
234 .shortcut_hint =
"Ctrl+Alt+2",
238 .disabled_tooltip =
"Load a ROM first"});
240 panel_manager->RegisterPanel(
241 {.card_id =
"palette.dungeon_main",
242 .display_name =
"Dungeon Main",
243 .window_title =
" Dungeon Main",
245 .category =
"Palette",
246 .shortcut_hint =
"Ctrl+Alt+3",
250 .disabled_tooltip =
"Load a ROM first"});
252 panel_manager->RegisterPanel(
253 {.card_id =
"palette.sprites",
254 .display_name =
"Global Sprite Palettes",
255 .window_title =
" SNES Palette",
257 .category =
"Palette",
258 .shortcut_hint =
"Ctrl+Alt+4",
262 .disabled_tooltip =
"Load a ROM first"});
264 panel_manager->RegisterPanel(
265 {.card_id =
"palette.sprites_aux1",
266 .display_name =
"Sprites Aux 1",
267 .window_title =
" Sprites Aux 1",
269 .category =
"Palette",
270 .shortcut_hint =
"Ctrl+Alt+7",
274 .disabled_tooltip =
"Load a ROM first"});
276 panel_manager->RegisterPanel(
277 {.card_id =
"palette.sprites_aux2",
278 .display_name =
"Sprites Aux 2",
279 .window_title =
" Sprites Aux 2",
281 .category =
"Palette",
282 .shortcut_hint =
"Ctrl+Alt+8",
286 .disabled_tooltip =
"Load a ROM first"});
288 panel_manager->RegisterPanel(
289 {.card_id =
"palette.sprites_aux3",
290 .display_name =
"Sprites Aux 3",
291 .window_title =
" Sprites Aux 3",
293 .category =
"Palette",
294 .shortcut_hint =
"Ctrl+Alt+9",
298 .disabled_tooltip =
"Load a ROM first"});
300 panel_manager->RegisterPanel(
301 {.card_id =
"palette.equipment",
302 .display_name =
"Equipment Palettes",
303 .window_title =
" Equipment Palettes",
305 .category =
"Palette",
306 .shortcut_hint =
"Ctrl+Alt+5",
310 .disabled_tooltip =
"Load a ROM first"});
312 panel_manager->RegisterPanel(
313 {.card_id =
"palette.quick_access",
314 .display_name =
"Quick Access",
315 .window_title =
" Color Harmony",
317 .category =
"Palette",
318 .shortcut_hint =
"Ctrl+Alt+Q",
322 .disabled_tooltip =
"Load a ROM first"});
324 panel_manager->RegisterPanel(
325 {.card_id =
"palette.custom",
326 .display_name =
"Custom Palette",
327 .window_title =
" Palette Editor",
329 .category =
"Palette",
330 .shortcut_hint =
"Ctrl+Alt+C",
334 .disabled_tooltip =
"Load a ROM first"});
337 panel_manager->ShowPanel(session_id,
"palette.control_panel");
349 std::string
GetId()
const override {
return "palette.control_panel"; }
355 void Draw(
bool* p_open)
override {
356 if (p_open && !*p_open)
371 std::string
GetId()
const override {
return "palette.quick_access"; }
377 void Draw(
bool* p_open)
override {
378 if (p_open && !*p_open)
393 std::string
GetId()
const override {
return "palette.custom"; }
399 void Draw(
bool* p_open)
override {
400 if (p_open && !*p_open)
413 if (!
rom() || !
rom()->is_loaded()) {
414 return absl::NotFoundError(
"ROM not open, no palettes to display");
420 "Palette Group Name", std::to_string(i),
421 std::string(kPaletteGroupNames[i]));
446 std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
448 panel_manager->RegisterEditorPanel(std::move(ow_main));
452 std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
454 panel_manager->RegisterEditorPanel(std::move(ow_anim));
458 std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
460 panel_manager->RegisterEditorPanel(std::move(dungeon_main));
466 panel_manager->RegisterEditorPanel(std::move(sprite_global));
470 std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
472 panel_manager->RegisterEditorPanel(std::move(sprite_aux1));
476 std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
478 panel_manager->RegisterEditorPanel(std::move(sprite_aux2));
482 std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
484 panel_manager->RegisterEditorPanel(std::move(sprite_aux3));
487 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
489 panel_manager->RegisterEditorPanel(std::move(equipment));
492 panel_manager->RegisterEditorPanel(std::make_unique<PaletteControlPanel>(
494 panel_manager->RegisterEditorPanel(
495 std::make_unique<QuickAccessPalettePanel>(
497 panel_manager->RegisterEditorPanel(std::make_unique<CustomPalettePanel>(
501 return absl::OkStatus();
506 return absl::FailedPreconditionError(
"ROM not loaded");
515 return absl::OkStatus();
520 return absl::FailedPreconditionError(
"PaletteManager not initialized");
524 return absl::OkStatus();
529 return absl::FailedPreconditionError(
"PaletteManager not initialized");
533 return absl::OkStatus();
540 return absl::OkStatus();
544 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
546 Text(
"Custom Palette");
553 Text(
"Current Color");
563 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
566 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
570 if (Button(
"Copy to Clipboard")) {
571 SetClipboardText(buf);
578 Text(
"Recently Used Colors");
583 ImVec4 displayColor =
585 if (ImGui::ColorButton(
"##recent", displayColor)) {
611 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
612 ImGuiWindowFlags_HorizontalScrollbar)) {
616 SameLine(0.0f, GetStyle().ItemSpacing.y);
620 bool open_color_picker = ImGui::ColorButton(
621 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
623 if (open_color_picker) {
627 "CustomPaletteColorEdit")
631 if (BeginPopupContextItem()) {
640 if (Button(
"Delete", ImVec2(-1, 0))) {
646 if (BeginDragDropTarget()) {
647 if (
const ImGuiPayload* payload =
648 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
650 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
662 if (ImGui::Button(
"+")) {
667 if (ImGui::Button(
"Clear")) {
672 if (ImGui::Button(
"Export")) {
673 std::string clipboard;
675 clipboard += absl::StrFormat(
"$%04X,", color.snes());
677 SetClipboardText(clipboard.c_str());
683 if (ImGui::BeginPopup(
703 return absl::NotFoundError(
"ROM not open, no palettes to display");
706 auto palette_group_name = kPaletteGroupNames[category];
709 const auto size = palette_group->
size();
711 for (
int j = 0; j < size; j++) {
713 auto pal_size = palette->
size();
720 false, palette_group_name.data(), std::to_string(j),
724 for (
int n = 0; n < pal_size; n++) {
726 if (n > 0 && n % 8 != 0)
727 SameLine(0.0f, 2.0f);
730 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
733 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
738 if (BeginPopupContextItem(popup_id.c_str())) {
750 return absl::OkStatus();
755 auto it = std::find_if(
757 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
776 auto original_color = palette[n];
781 original_color, palette[n]);
782 palette[n].set_modified(
true);
794 Text(
"RGB: %d, %d, %d", cr, cg, cb);
795 Text(
"SNES: $%04X", palette[n].snes());
799 if (Button(
"Copy as..", ImVec2(-1, 0)))
806 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
809 SetClipboardText(buf);
811 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d)", cr, cg, cb);
813 SetClipboardText(buf);
815 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
817 SetClipboardText(buf);
820 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"$%04X",
823 SetClipboardText(buf);
829 if (Button(
"Add to Custom Palette", ImVec2(-1, 0))) {
834 return absl::OkStatus();
839 if (index >= palette.
size()) {
840 return absl::InvalidArgumentError(
"Index out of bounds");
844 auto color = palette[index];
845 auto currentColor = color.rgb();
846 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
853 return absl::OkStatus();
859 if (index >= palette.
size() || index >= originalPalette.
size()) {
860 return absl::InvalidArgumentError(
"Index out of bounds");
862 auto color = originalPalette[index];
863 auto originalColor = color.rgb();
865 return absl::OkStatus();
878 ImGui::SetNextWindowSize(ImVec2(320, 420), ImGuiCond_FirstUseEver);
879 ImGui::SetNextWindowPos(ImVec2(10, 100), ImGuiCond_FirstUseEver);
881 ImGuiWindowFlags flags = ImGuiWindowFlags_None;
896 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f),
"Modified Panels:");
897 bool any_modified =
false;
900 ImGui::BulletText(
"Overworld Main");
904 ImGui::BulletText(
"Overworld Animated");
908 ImGui::BulletText(
"Dungeon Main");
912 ImGui::BulletText(
"Global Sprite Palettes");
916 ImGui::BulletText(
"Sprites Aux 1");
920 ImGui::BulletText(
"Sprites Aux 2");
924 ImGui::BulletText(
"Sprites Aux 3");
928 ImGui::BulletText(
"Equipment Palettes");
933 ImGui::TextDisabled(
"No unsaved changes");
939 ImGui::Text(
"Quick Actions:");
945 ImGui::BeginDisabled(!has_unsaved);
946 if (ImGui::Button(absl::StrFormat(
ICON_MD_SAVE " Save All (%zu colors)",
958 ImGui::EndDisabled();
960 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
962 ImGui::SetTooltip(
"Save all modified colors to ROM");
964 ImGui::SetTooltip(
"No unsaved changes");
969 ImGui::BeginDisabled(!has_unsaved);
978 ImGui::EndDisabled();
980 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
983 "Preview palette changes in other editors without saving to ROM");
985 ImGui::SetTooltip(
"No changes to preview");
989 ImGui::BeginDisabled(!has_unsaved);
990 if (ImGui::Button(
ICON_MD_UNDO " Discard All Changes", ImVec2(-1, 0))) {
995 ImGui::EndDisabled();
997 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
999 ImGui::SetTooltip(
"Discard all unsaved changes");
1001 ImGui::SetTooltip(
"No changes to discard");
1006 if (ImGui::BeginPopupModal(
1010 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1011 ImGui::Text(
"Discard all unsaved changes?");
1012 ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f),
1013 "This will revert %zu modified colors.",
1017 if (ImGui::Button(
"Discard", ImVec2(120, 0))) {
1019 ImGui::CloseCurrentPopup();
1022 if (ImGui::Button(
"Cancel", ImVec2(120, 0))) {
1023 ImGui::CloseCurrentPopup();
1032 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1033 ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
1034 "Failed to save changes");
1035 ImGui::Text(
"An error occurred while saving to ROM.");
1038 if (ImGui::Button(
"OK", ImVec2(120, 0))) {
1039 ImGui::CloseCurrentPopup();
1053 if (ImGui::BeginPopup(
1057 ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f),
1088 ImGui::BeginGroup();
1089 ImGui::Text(
"Current Color");
1099 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1100 ImGui::Text(
"%s", buf);
1102 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1104 ImGui::Text(
"%s", buf);
1106 if (ImGui::Button(
"Copy to Clipboard", ImVec2(-1, 0))) {
1107 SetClipboardText(buf);
1114 ImGui::Text(
"Recently Used Colors");
1116 ImGui::TextDisabled(
"No recently used colors yet");
1122 ImVec4 displayColor =
1129 if (ImGui::IsItemHovered()) {
1146 "Create your own custom color palette for reference. "
1147 "Colors can be added from any palette group or created from scratch.");
1153 ImGui::TextDisabled(
"Your custom palette is empty.");
1154 ImGui::Text(
"Click + to add colors or drag colors from any palette.");
1158 if (i > 0 && i % 16 != 0)
1159 SameLine(0.0f, 2.0f);
1163 bool open_color_picker =
1164 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1167 if (open_color_picker) {
1171 "PanelCustomPaletteColorEdit")
1175 if (BeginPopupContextItem()) {
1184 if (ImGui::Button(
"Delete", ImVec2(-1, 0))) {
1186 ImGui::CloseCurrentPopup();
1192 if (BeginDragDropTarget()) {
1193 if (
const ImGuiPayload* payload =
1194 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) {
1196 memcpy((
float*)&color, payload->Data,
sizeof(
float) * 3);
1201 EndDragDropTarget();
1222 std::string clipboard;
1224 clipboard += absl::StrFormat(
"$%04X,", color.snes());
1226 if (!clipboard.empty()) {
1227 clipboard.pop_back();
1229 SetClipboardText(clipboard.c_str());
1231 if (ImGui::IsItemHovered()) {
1232 ImGui::SetTooltip(
"Copy palette as comma-separated SNES values");
1239 "PanelCustomPaletteColorEdit")
1256 int palette_index) {
1264 if (group_name ==
"ow_main") {
1265 panel_manager->ShowPanel(session_id,
"palette.ow_main");
1270 }
else if (group_name ==
"ow_animated") {
1271 panel_manager->ShowPanel(session_id,
"palette.ow_animated");
1276 }
else if (group_name ==
"dungeon_main") {
1277 panel_manager->ShowPanel(session_id,
"palette.dungeon_main");
1282 }
else if (group_name ==
"global_sprites") {
1283 panel_manager->ShowPanel(session_id,
"palette.sprites");
1288 }
else if (group_name ==
"sprites_aux1") {
1289 panel_manager->ShowPanel(session_id,
"palette.sprites_aux1");
1294 }
else if (group_name ==
"sprites_aux2") {
1295 panel_manager->ShowPanel(session_id,
"palette.sprites_aux2");
1300 }
else if (group_name ==
"sprites_aux3") {
1301 panel_manager->ShowPanel(session_id,
"palette.sprites_aux3");
1306 }
else if (group_name ==
"armors") {
1307 panel_manager->ShowPanel(session_id,
"palette.equipment");
1315 panel_manager->ShowPanel(session_id,
"palette.control_panel");
1323 ImGui::SetNextItemWidth(-1);
1324 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1341 if (group_name ==
"ow_main")
1343 if (group_name ==
"ow_animated")
1345 if (group_name ==
"dungeon_main")
1347 if (group_name ==
"global_sprites")
1349 if (group_name ==
"sprites_aux1")
1351 if (group_name ==
"sprites_aux2")
1353 if (group_name ==
"sprites_aux3")
1355 if (group_name ==
"armors")
1367 for (
size_t cat_idx = 0; cat_idx < categories.size(); cat_idx++) {
1368 const auto& cat = categories[cat_idx];
1371 bool has_visible_items =
false;
1372 for (
const auto& group_name : cat.group_names) {
1374 has_visible_items =
true;
1379 if (!has_visible_items)
1382 ImGui::PushID(
static_cast<int>(cat_idx));
1385 std::string header_text =
1386 absl::StrFormat(
"%s %s", cat.icon, cat.display_name);
1387 bool open = ImGui::CollapsingHeader(header_text.c_str(),
1388 ImGuiTreeNodeFlags_DefaultOpen);
1391 ImGui::Indent(10.0f);
1392 for (
const auto& group_name : cat.group_names) {
1403 ImGui::PushStyleColor(ImGuiCol_Text,
1404 ImVec4(1.0f, 0.6f, 0.0f, 1.0f));
1407 ImGui::Checkbox(label.c_str(), show_flag);
1410 ImGui::PopStyleColor();
1414 ImGui::Unindent(10.0f);
1422 ImGui::Text(
"Utilities:");
1423 ImGui::Indent(10.0f);
1426 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