6#include "absl/status/status.h"
7#include "absl/strings/str_cat.h"
8#include "absl/strings/str_format.h"
24#include "imgui/imgui.h"
31using ImGui::AcceptDragDropPayload;
32using ImGui::BeginChild;
33using ImGui::BeginDragDropTarget;
34using ImGui::BeginGroup;
35using ImGui::BeginPopup;
36using ImGui::BeginPopupContextItem;
38using ImGui::ColorButton;
39using ImGui::ColorPicker4;
41using ImGui::EndDragDropTarget;
45using ImGui::OpenPopup;
49using ImGui::Selectable;
50using ImGui::Separator;
51using ImGui::SetClipboardText;
57 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable |
58 ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Hideable;
60constexpr ImGuiColorEditFlags
kPalNoAlpha = ImGuiColorEditFlags_NoAlpha;
63 ImGuiColorEditFlags_NoPicker |
64 ImGuiColorEditFlags_NoTooltip;
67 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha |
68 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV |
69 ImGuiColorEditFlags_DisplayHex;
74 ImGui::GetForegroundDrawList()->AddRect(
80 if (!color || !BeginDragDropTarget()) {
85 constexpr ImGuiDragDropFlags kFlags =
86 ImGuiDragDropFlags_AcceptBeforeDelivery |
87 ImGuiDragDropFlags_AcceptNoDrawDefaultRect |
88 ImGuiDragDropFlags_AcceptNoPreviewTooltip;
89 auto accept = [&](
const char* type,
size_t components) {
93 if (
const ImGuiPayload* payload = AcceptDragDropPayload(type, kFlags)) {
95 if (payload->IsDelivery()) {
96 ImVec4 dropped(0, 0, 0, 1);
97 std::memcpy(&dropped.x, payload->Data,
sizeof(
float) * components);
98 if (components == 3) {
107 accept(IMGUI_PAYLOAD_TYPE_COLOR_3F, 3);
108 accept(IMGUI_PAYLOAD_TYPE_COLOR_4F, 4);
116#ifdef IMGUI_USE_STB_SPRINTF
117 int w = stbsp_vsnprintf(buf, (
int)buf_size, fmt, args);
119 int w = vsnprintf(buf, buf_size, fmt, args);
124 if (w == -1 || w >= (
int)buf_size)
125 w = (int)buf_size - 1;
130static inline float color_saturate(
float f) {
131 return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f;
134#define F32_TO_INT8_SAT(_VAL) \
135 ((int)(color_saturate(_VAL) * 255.0f + \
157 static ImVec4 color = ImVec4(0, 0, 0, 1.0f);
158 static ImVec4 current_palette[256] = {};
159 static int current_palette_count = 0;
160 ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
161 ImGuiColorEditFlags_NoDragDrop |
162 ImGuiColorEditFlags_NoOptions;
166 current_palette_count =
167 std::min<int>(
static_cast<int>(palette.
size()),
168 static_cast<int>(IM_ARRAYSIZE(current_palette)));
170 for (
int n = 0; n < current_palette_count; ++n) {
171 const auto palette_color = palette[
static_cast<size_t>(n)];
172 current_palette[n].x = palette_color.rgb().x / 255.0f;
173 current_palette[n].y = palette_color.rgb().y / 255.0f;
174 current_palette[n].z = palette_color.rgb().z / 255.0f;
175 current_palette[n].w = 1.0f;
177 for (
int n = current_palette_count;
178 n < static_cast<int>(IM_ARRAYSIZE(current_palette)); ++n) {
179 current_palette[n] = ImVec4(0, 0, 0, 1.0f);
182 current_palette_count = 0;
185 static ImVec4 backup_color;
186 bool open_popup = ColorButton(
"MyColor##3b", color, misc_flags);
187 SameLine(0, GetStyle().ItemInnerSpacing.x);
188 open_popup |= Button(tr(
"Palette"));
193 backup_color = color;
200 ColorPicker4(
"##picker", (
float*)&color,
201 misc_flags | ImGuiColorEditFlags_NoSidePreview |
202 ImGuiColorEditFlags_NoSmallPreview);
206 Text(tr(
"Current ==>"));
208 Text(tr(
"Previous"));
210 if (Button(tr(
"Update Map Palette"))) {}
214 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
219 "##previous", backup_color,
220 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
222 color = backup_color;
227 if (current_palette_count <= 0) {
228 ImGui::TextDisabled(tr(
"No palette entries loaded."));
230 for (
int n = 0; n < current_palette_count; n++) {
233 SameLine(0.0f, GetStyle().ItemSpacing.y);
237 color = ImVec4(current_palette[n].x, current_palette[n].y,
238 current_palette[n].z, color.w);
240 if (BeginDragDropTarget()) {
241 if (
const ImGuiPayload* payload =
242 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
243 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 3);
244 if (
const ImGuiPayload* payload =
245 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
246 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 4);
256 return absl::OkStatus();
267 window_manager->RegisterPanel(
268 {.card_id =
"palette.control_panel",
269 .display_name =
"Palette Controls",
270 .window_title =
" Palette Controls",
272 .category =
"Palette",
273 .shortcut_hint =
"Ctrl+Shift+P",
277 .disabled_tooltip =
"Load a ROM first"});
279 window_manager->RegisterPanel(
280 {.card_id =
"palette.ow_main",
281 .display_name =
"Overworld Main",
282 .window_title =
" Overworld Main",
284 .category =
"Palette",
285 .shortcut_hint =
"Ctrl+Alt+1",
289 .disabled_tooltip =
"Load a ROM first"});
291 window_manager->RegisterPanel(
292 {.card_id =
"palette.ow_animated",
293 .display_name =
"Overworld Animated",
294 .window_title =
" Overworld Animated",
296 .category =
"Palette",
297 .shortcut_hint =
"Ctrl+Alt+2",
301 .disabled_tooltip =
"Load a ROM first"});
303 window_manager->RegisterPanel(
304 {.card_id =
"palette.dungeon_main",
305 .display_name =
"Dungeon Main",
306 .window_title =
" Dungeon Main",
308 .category =
"Palette",
309 .shortcut_hint =
"Ctrl+Alt+3",
313 .disabled_tooltip =
"Load a ROM first"});
315 window_manager->RegisterPanel(
316 {.card_id =
"palette.sprites",
317 .display_name =
"Global Sprite Palettes",
318 .window_title =
" SNES Palette",
320 .category =
"Palette",
321 .shortcut_hint =
"Ctrl+Alt+4",
325 .disabled_tooltip =
"Load a ROM first"});
327 window_manager->RegisterPanel(
328 {.card_id =
"palette.sprites_aux1",
329 .display_name =
"Sprites Aux 1",
330 .window_title =
" Sprites Aux 1",
332 .category =
"Palette",
333 .shortcut_hint =
"Ctrl+Alt+7",
337 .disabled_tooltip =
"Load a ROM first"});
339 window_manager->RegisterPanel(
340 {.card_id =
"palette.sprites_aux2",
341 .display_name =
"Sprites Aux 2",
342 .window_title =
" Sprites Aux 2",
344 .category =
"Palette",
345 .shortcut_hint =
"Ctrl+Alt+8",
349 .disabled_tooltip =
"Load a ROM first"});
351 window_manager->RegisterPanel(
352 {.card_id =
"palette.sprites_aux3",
353 .display_name =
"Sprites Aux 3",
354 .window_title =
" Sprites Aux 3",
356 .category =
"Palette",
357 .shortcut_hint =
"Ctrl+Alt+9",
361 .disabled_tooltip =
"Load a ROM first"});
363 window_manager->RegisterPanel(
364 {.card_id =
"palette.equipment",
365 .display_name =
"Equipment Palettes",
366 .window_title =
" Equipment Palettes",
368 .category =
"Palette",
369 .shortcut_hint =
"Ctrl+Alt+5",
373 .disabled_tooltip =
"Load a ROM first"});
375 window_manager->RegisterPanel(
376 {.card_id =
"palette.quick_access",
377 .display_name =
"Quick Access",
378 .window_title =
" Color Harmony",
380 .category =
"Palette",
381 .shortcut_hint =
"Ctrl+Alt+Q",
385 .disabled_tooltip =
"Load a ROM first"});
387 window_manager->RegisterPanel(
388 {.card_id =
"palette.custom",
389 .display_name =
"Custom Palette",
390 .window_title =
" Palette Editor",
392 .category =
"Palette",
393 .shortcut_hint =
"Ctrl+Alt+C",
397 .disabled_tooltip =
"Load a ROM first"});
400 window_manager->OpenWindow(session_id,
"palette.control_panel");
412 std::string
GetId()
const override {
return "palette.control_panel"; }
419 void Draw(
bool* p_open)
override {
420 if (p_open && !*p_open)
435 std::string
GetId()
const override {
return "palette.quick_access"; }
442 void Draw(
bool* p_open)
override {
443 if (p_open && !*p_open)
458 std::string
GetId()
const override {
return "palette.custom"; }
465 void Draw(
bool* p_open)
override {
466 if (p_open && !*p_open)
482template <
typename Panel>
484 size_t session_id,
const char* panel_id,
486 auto* panel =
dynamic_cast<Panel*
>(
488 return panel !=
nullptr && panel->IsOwnedByRom(rom) ? panel :
nullptr;
494 if (window_manager ==
nullptr) {
507 ow_main_panel_ = ResolveSessionPalettePanel<OverworldMainPalettePanel>(
508 window_manager, session_id,
"palette.ow_main",
rom_);
509 ow_anim_panel_ = ResolveSessionPalettePanel<OverworldAnimatedPalettePanel>(
510 window_manager, session_id,
"palette.ow_animated",
rom_);
512 window_manager, session_id,
"palette.dungeon_main",
rom_);
514 window_manager, session_id,
"palette.global_sprites",
rom_);
516 window_manager, session_id,
"palette.sprites_aux1",
rom_);
518 window_manager, session_id,
"palette.sprites_aux2",
rom_);
520 window_manager, session_id,
"palette.sprites_aux3",
rom_);
522 window_manager, session_id,
"palette.armors",
rom_);
530 if (panel ==
nullptr) {
549 if (!
rom() || !
rom()->is_loaded()) {
550 return absl::NotFoundError(
"ROM not open, no palettes to display");
556 "Palette Group Name", std::to_string(i),
557 std::string(kPaletteGroupNames[i]));
578 std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
580 window_manager->RegisterWindowContent(std::move(ow_main));
584 std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
586 window_manager->RegisterWindowContent(std::move(ow_anim));
590 std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
592 window_manager->RegisterWindowContent(std::move(dungeon_main));
598 window_manager->RegisterWindowContent(std::move(sprite_global));
602 std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
604 window_manager->RegisterWindowContent(std::move(sprite_aux1));
608 std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
610 window_manager->RegisterWindowContent(std::move(sprite_aux2));
614 std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
616 window_manager->RegisterWindowContent(std::move(sprite_aux3));
619 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
621 window_manager->RegisterWindowContent(std::move(equipment));
626 window_manager->RegisterWindowContent(std::make_unique<PaletteControlPanel>(
628 window_manager->RegisterWindowContent(
629 std::make_unique<QuickAccessPalettePanel>(
631 window_manager->RegisterWindowContent(std::make_unique<CustomPalettePanel>(
635 return absl::OkStatus();
640 return absl::FailedPreconditionError(
"ROM not loaded");
643 return absl::FailedPreconditionError(
644 "Cannot save palettes from an inactive ROM session");
651 palette_manager.GetModifiedColorWriteRanges(
game_data());
652 if (!ranges.empty()) {
666 return absl::OkStatus();
671 return absl::FailedPreconditionError(
672 "Cannot undo palettes from an inactive ROM session");
676 return absl::OkStatus();
681 return absl::FailedPreconditionError(
682 "Cannot redo palettes from an inactive ROM session");
686 return absl::OkStatus();
693 return absl::OkStatus();
697 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
699 Text(tr(
"Custom Palette"));
706 Text(tr(
"Current Color"));
716 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
719 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
723 if (Button(tr(
"Copy to Clipboard"))) {
724 SetClipboardText(buf);
731 Text(tr(
"Recently Used Colors"));
736 ImVec4 displayColor =
738 if (ImGui::ColorButton(
"##recent", displayColor)) {
764 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
765 ImGuiWindowFlags_HorizontalScrollbar)) {
769 SameLine(0.0f, GetStyle().ItemSpacing.y);
773 bool open_color_picker = ImGui::ColorButton(
774 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
775 const ImVec2 swatch_min = ImGui::GetItemRectMin();
776 const ImVec2 swatch_max = ImGui::GetItemRectMax();
777 if (ImGui::IsItemHovered() &&
778 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
779 open_color_picker =
true;
782 if (open_color_picker) {
786 "CustomPaletteColorEdit")
790 if (BeginPopupContextItem()) {
799 if (Button(tr(
"Delete"), ImVec2(-1, 0))) {
804 if (AcceptImGuiColorDrop(&
custom_palette_[i], swatch_min, swatch_max)) {
812 if (ImGui::Button(
"+")) {
817 if (ImGui::Button(tr(
"Clear"))) {
822 if (ImGui::Button(tr(
"Export"))) {
823 std::string clipboard;
825 clipboard += absl::StrFormat(
"$%04X,", color.snes());
827 SetClipboardText(clipboard.c_str());
833 if (ImGui::BeginPopup(
853 return absl::NotFoundError(
"ROM not open, no palettes to display");
856 auto palette_group_name = kPaletteGroupNames[category];
859 const auto size = palette_group->
size();
861 for (
int j = 0; j < size; j++) {
863 auto pal_size = palette->
size();
870 false, palette_group_name.data(), std::to_string(j),
874 for (
int n = 0; n < pal_size; n++) {
876 if (n > 0 && n % 8 != 0)
877 SameLine(0.0f, 2.0f);
880 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
883 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
887 const ImVec2 swatch_min = ImGui::GetItemRectMin();
888 const ImVec2 swatch_max = ImGui::GetItemRectMax();
889 if (ImGui::IsItemHovered() &&
890 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
893 OpenPopup(popup_id.c_str());
896 const SnesColor original_color = (*palette)[n];
897 if (AcceptImGuiColorDrop(&(*palette)[n], swatch_min, swatch_max)) {
899 std::string(kPaletteGroupNames[category]),
900 j, n, original_color,
902 (*palette)[n].set_modified(
true);
907 if (BeginPopupContextItem(popup_id.c_str())) {
919 return absl::OkStatus();
924 auto it = std::find_if(
926 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
945 auto original_color = palette[n];
950 original_color, palette[n]);
951 palette[n].set_modified(
true);
963 Text(tr(
"RGB: %d, %d, %d"), cr, cg, cb);
964 Text(tr(
"SNES: $%04X"), palette[n].snes());
968 if (Button(tr(
"Copy as.."), ImVec2(-1, 0)))
975 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
978 SetClipboardText(buf);
980 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d)", cr, cg, cb);
982 SetClipboardText(buf);
984 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
986 SetClipboardText(buf);
989 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"$%04X",
992 SetClipboardText(buf);
998 if (Button(tr(
"Add to Custom Palette"), ImVec2(-1, 0))) {
1003 return absl::OkStatus();
1008 if (index >= palette.
size()) {
1009 return absl::InvalidArgumentError(
"Index out of bounds");
1013 auto color = palette[index];
1014 auto currentColor = color.rgb();
1015 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
1022 return absl::OkStatus();
1028 if (index >= palette.
size() || index >= originalPalette.
size()) {
1029 return absl::InvalidArgumentError(
"Index out of bounds");
1031 auto color = originalPalette[index];
1032 auto originalColor = color.rgb();
1034 return absl::OkStatus();
1048 ImGui::TextDisabled(
1049 tr(
"Palette controls are unavailable for an inactive ROM session."));
1067 bool any_modified =
false;
1070 ImGui::BulletText(tr(
"Overworld Main"));
1071 any_modified =
true;
1074 ImGui::BulletText(tr(
"Overworld Animated"));
1075 any_modified =
true;
1078 ImGui::BulletText(tr(
"Dungeon Main"));
1079 any_modified =
true;
1082 ImGui::BulletText(tr(
"Global Sprite Palettes"));
1083 any_modified =
true;
1086 ImGui::BulletText(tr(
"Sprites Aux 1"));
1087 any_modified =
true;
1090 ImGui::BulletText(tr(
"Sprites Aux 2"));
1091 any_modified =
true;
1094 ImGui::BulletText(tr(
"Sprites Aux 3"));
1095 any_modified =
true;
1098 ImGui::BulletText(tr(
"Equipment Palettes"));
1099 any_modified =
true;
1102 if (!any_modified) {
1103 ImGui::TextDisabled(tr(
"No unsaved changes"));
1109 ImGui::Text(tr(
"Quick Actions:"));
1115 ImGui::BeginDisabled(!has_unsaved);
1117 absl::StrFormat(
ICON_MD_SAVE " Save All (%zu colors)", modified_count)
1120 auto status =
Save();
1124 absl::StrFormat(
"Failed to save palettes: %s", status.message()),
1129 ImGui::EndDisabled();
1131 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1133 ImGui::SetTooltip(tr(
"Save all modified colors to ROM"));
1135 ImGui::SetTooltip(tr(
"No unsaved changes"));
1140 ImGui::BeginDisabled(!has_unsaved);
1149 ImGui::EndDisabled();
1151 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1154 tr(
"Preview palette changes in other editors without saving to ROM"));
1156 ImGui::SetTooltip(tr(
"No changes to preview"));
1160 ImGui::BeginDisabled(!has_unsaved);
1161 if (ImGui::Button(
ICON_MD_UNDO " Discard All Changes", ImVec2(-1, 0))) {
1166 ImGui::EndDisabled();
1168 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
1170 ImGui::SetTooltip(tr(
"Discard all unsaved changes"));
1172 ImGui::SetTooltip(tr(
"No changes to discard"));
1177 if (ImGui::BeginPopupModal(
1181 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1182 ImGui::Text(tr(
"Discard all unsaved changes?"));
1184 tr(
"This will revert %zu modified colors."),
1188 if (ImGui::Button(tr(
"Discard"), ImVec2(120, 0))) {
1190 ImGui::CloseCurrentPopup();
1193 if (ImGui::Button(tr(
"Cancel"), ImVec2(120, 0))) {
1194 ImGui::CloseCurrentPopup();
1203 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1205 ImGui::Text(tr(
"An error occurred while saving to ROM."));
1208 if (ImGui::Button(tr(
"OK"), ImVec2(120, 0))) {
1209 ImGui::CloseCurrentPopup();
1221 ImGui::BeginGroup();
1222 ImGui::Text(tr(
"Current Color"));
1232 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1233 ImGui::Text(
"%s", buf);
1235 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1237 ImGui::Text(
"%s", buf);
1239 if (ImGui::Button(tr(
"Copy to Clipboard"), ImVec2(-1, 0))) {
1240 SetClipboardText(buf);
1247 ImGui::Text(tr(
"Recently Used Colors"));
1249 ImGui::TextDisabled(tr(
"No recently used colors yet"));
1255 ImVec4 displayColor =
1262 if (ImGui::IsItemHovered()) {
1271 ImGui::TextWrapped(tr(
1272 "Create your own custom color palette for reference. "
1273 "Colors can be added from any palette group or created from scratch."));
1279 ImGui::TextDisabled(tr(
"Your custom palette is empty."));
1280 ImGui::Text(tr(
"Click + to add colors or drag colors from any palette."));
1284 if (i > 0 && i % 16 != 0)
1285 SameLine(0.0f, 2.0f);
1289 bool open_color_picker =
1290 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1292 const ImVec2 swatch_min = ImGui::GetItemRectMin();
1293 const ImVec2 swatch_max = ImGui::GetItemRectMax();
1294 if (ImGui::IsItemHovered() &&
1295 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
1296 open_color_picker =
true;
1299 if (open_color_picker) {
1303 "PanelCustomPaletteColorEdit")
1307 if (BeginPopupContextItem()) {
1316 if (ImGui::Button(tr(
"Delete"), ImVec2(-1, 0))) {
1318 ImGui::CloseCurrentPopup();
1323 if (AcceptImGuiColorDrop(&
custom_palette_[i], swatch_min, swatch_max)) {
1345 std::string clipboard;
1347 clipboard += absl::StrFormat(
"$%04X,", color.snes());
1349 if (!clipboard.empty()) {
1350 clipboard.pop_back();
1352 SetClipboardText(clipboard.c_str());
1354 if (ImGui::IsItemHovered()) {
1355 ImGui::SetTooltip(tr(
"Copy palette as comma-separated SNES values"));
1360 "PanelCustomPaletteColorEdit")
1377 int palette_index) {
1386 if (group_name ==
"ow_main") {
1387 window_manager->OpenWindow(session_id,
"palette.ow_main");
1392 }
else if (group_name ==
"ow_animated") {
1393 window_manager->OpenWindow(session_id,
"palette.ow_animated");
1398 }
else if (group_name ==
"dungeon_main") {
1399 window_manager->OpenWindow(session_id,
"palette.dungeon_main");
1404 }
else if (group_name ==
"global_sprites") {
1405 window_manager->OpenWindow(session_id,
"palette.sprites");
1410 }
else if (group_name ==
"sprites_aux1") {
1411 window_manager->OpenWindow(session_id,
"palette.sprites_aux1");
1416 }
else if (group_name ==
"sprites_aux2") {
1417 window_manager->OpenWindow(session_id,
"palette.sprites_aux2");
1422 }
else if (group_name ==
"sprites_aux3") {
1423 window_manager->OpenWindow(session_id,
"palette.sprites_aux3");
1428 }
else if (group_name ==
"armors") {
1429 window_manager->OpenWindow(session_id,
"palette.equipment");
1437 window_manager->OpenWindow(session_id,
"palette.control_panel");
1445 ImGui::SetNextItemWidth(-1);
1446 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1463 if (group_name ==
"ow_main")
1465 if (group_name ==
"ow_animated")
1467 if (group_name ==
"dungeon_main")
1469 if (group_name ==
"global_sprites")
1471 if (group_name ==
"sprites_aux1")
1473 if (group_name ==
"sprites_aux2")
1475 if (group_name ==
"sprites_aux3")
1477 if (group_name ==
"armors")
1489 for (
size_t cat_idx = 0; cat_idx < categories.size(); cat_idx++) {
1490 const auto& cat = categories[cat_idx];
1493 bool has_visible_items =
false;
1494 for (
const auto& group_name : cat.group_names) {
1496 has_visible_items =
true;
1501 if (!has_visible_items)
1504 ImGui::PushID(
static_cast<int>(cat_idx));
1507 std::string header_text =
1508 absl::StrFormat(
"%s %s", cat.icon, cat.display_name);
1509 bool open = ImGui::CollapsingHeader(header_text.c_str(),
1510 ImGuiTreeNodeFlags_DefaultOpen);
1513 ImGui::Indent(10.0f);
1514 for (
const auto& group_name : cat.group_names) {
1528 std::optional<gui::StyleColorGuard> mod_guard;
1533 ImGui::Checkbox(label.c_str(), show_flag);
1537 ImGui::Unindent(10.0f);
1545 ImGui::Text(tr(
"Utilities:"));
1546 ImGui::Indent(10.0f);
1549 ImGui::Unindent(10.0f);
#define F32_TO_INT8_SAT(_VAL)
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
project::ResourceLabelManager * resource_label()
void set_dirty(bool dirty)
bool loaded() const
Check if the manifest has been loaded.
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.
virtual void SetDependencies(const EditorDependencies &deps)
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 SetDependencies(const EditorDependencies &deps) override
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_
void RefreshPanelReferences()
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 ApplyPanelDependencies()
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)
Base class for palette group editing cards.
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.
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.
Central registry for all editor cards with session awareness and dependency injection.
WindowContent * GetWindowContent(const std::string &window_id)
Get a WindowContent instance by ID.
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 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).
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_LANDSCAPE
#define ICON_MD_VISIBILITY
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define TEXT_WITH_SEPARATOR(text)
bool AcceptImGuiColorDrop(SnesColor *color, ImVec2 min, ImVec2 max)
Panel * ResolveSessionPalettePanel(WorkspaceWindowManager *window_manager, size_t session_id, const char *panel_id, Rom *rom)
int CustomFormatString(char *buf, size_t buf_size, const char *fmt,...)
void DrawColorDropTargetOutline(ImVec2 min, ImVec2 max)
absl::Status ValidateHackManifestSaveConflicts(const core::HackManifest &manifest, project::RomWritePolicy write_policy, const std::vector< std::pair< uint32_t, uint32_t > > &ranges, absl::string_view save_scope, const char *log_tag, ToastManager *toast_manager)
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
ImVec4 ConvertColorToImVec4(const Color &color)
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)
Unified dependency container for all editor types.
project::YazeProject * project
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)
core::HackManifest hack_manifest
gfx::PaletteGroupMap palette_groups