7#include "absl/status/status.h"
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
29#include "imgui/imgui.h"
37using ImGui::AcceptDragDropPayload;
38using ImGui::BeginChild;
39using ImGui::BeginDragDropTarget;
40using ImGui::BeginGroup;
41using ImGui::BeginPopup;
42using ImGui::BeginPopupContextItem;
44using ImGui::ColorButton;
45using ImGui::ColorPicker4;
47using ImGui::EndDragDropTarget;
51using ImGui::OpenPopup;
55using ImGui::Selectable;
56using ImGui::Separator;
57using ImGui::SetClipboardText;
63 ImGuiTableFlags_Reorderable | ImGuiTableFlags_Resizable |
64 ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Hideable;
66constexpr ImGuiColorEditFlags
kPalNoAlpha = ImGuiColorEditFlags_NoAlpha;
69 ImGuiColorEditFlags_NoPicker |
70 ImGuiColorEditFlags_NoTooltip;
73 ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha |
74 ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV |
75 ImGuiColorEditFlags_DisplayHex;
80 ImGui::GetForegroundDrawList()->AddRect(
86 if (!color || !BeginDragDropTarget()) {
91 constexpr ImGuiDragDropFlags kFlags =
92 ImGuiDragDropFlags_AcceptBeforeDelivery |
93 ImGuiDragDropFlags_AcceptNoDrawDefaultRect |
94 ImGuiDragDropFlags_AcceptNoPreviewTooltip;
95 auto accept = [&](
const char* type,
size_t components) {
99 if (
const ImGuiPayload* payload = AcceptDragDropPayload(type, kFlags)) {
101 if (payload->IsDelivery()) {
102 ImVec4 dropped(0, 0, 0, 1);
103 std::memcpy(&dropped.x, payload->Data,
sizeof(
float) * components);
104 if (components == 3) {
113 accept(IMGUI_PAYLOAD_TYPE_COLOR_3F, 3);
114 accept(IMGUI_PAYLOAD_TYPE_COLOR_4F, 4);
122#ifdef IMGUI_USE_STB_SPRINTF
123 int w = stbsp_vsnprintf(buf, (
int)buf_size, fmt, args);
125 int w = vsnprintf(buf, buf_size, fmt, args);
130 if (w == -1 || w >= (
int)buf_size)
131 w = (int)buf_size - 1;
136static inline float color_saturate(
float f) {
137 return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f;
140#define F32_TO_INT8_SAT(_VAL) \
141 ((int)(color_saturate(_VAL) * 255.0f + \
147 std::vector<gfx::SnesColor>& colors,
int index,
149 if (!BeginPopupContextItem()) {
154 on_edited(colors[index]);
159 bool removed =
false;
162 [&removed]() { removed =
true; },
166 colors.erase(colors.begin() + index);
190 static ImVec4 color = ImVec4(0, 0, 0, 1.0f);
191 static ImVec4 current_palette[256] = {};
192 static int current_palette_count = 0;
193 ImGuiColorEditFlags misc_flags = ImGuiColorEditFlags_AlphaPreview |
194 ImGuiColorEditFlags_NoDragDrop |
195 ImGuiColorEditFlags_NoOptions;
199 current_palette_count =
200 std::min<int>(
static_cast<int>(palette.
size()),
201 static_cast<int>(IM_ARRAYSIZE(current_palette)));
203 for (
int n = 0; n < current_palette_count; ++n) {
204 const auto palette_color = palette[
static_cast<size_t>(n)];
205 current_palette[n].x = palette_color.rgb().x / 255.0f;
206 current_palette[n].y = palette_color.rgb().y / 255.0f;
207 current_palette[n].z = palette_color.rgb().z / 255.0f;
208 current_palette[n].w = 1.0f;
210 for (
int n = current_palette_count;
211 n < static_cast<int>(IM_ARRAYSIZE(current_palette)); ++n) {
212 current_palette[n] = ImVec4(0, 0, 0, 1.0f);
215 current_palette_count = 0;
218 static ImVec4 backup_color;
219 bool open_popup = ColorButton(
"MyColor##3b", color, misc_flags);
220 SameLine(0, GetStyle().ItemInnerSpacing.x);
221 open_popup |= Button(tr(
"Palette"));
226 backup_color = color;
233 ColorPicker4(
"##picker", (
float*)&color,
234 misc_flags | ImGuiColorEditFlags_NoSidePreview |
235 ImGuiColorEditFlags_NoSmallPreview);
239 Text(tr(
"Current ==>"));
241 Text(tr(
"Previous"));
243 if (Button(tr(
"Update Map Palette"))) {}
247 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
252 "##previous", backup_color,
253 ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf,
255 color = backup_color;
260 if (current_palette_count <= 0) {
261 ImGui::TextDisabled(tr(
"No palette entries loaded."));
263 for (
int n = 0; n < current_palette_count; n++) {
266 SameLine(0.0f, GetStyle().ItemSpacing.y);
270 color = ImVec4(current_palette[n].x, current_palette[n].y,
271 current_palette[n].z, color.w);
273 if (BeginDragDropTarget()) {
274 if (
const ImGuiPayload* payload =
275 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
276 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 3);
277 if (
const ImGuiPayload* payload =
278 AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
279 memcpy((
float*)¤t_palette[n], payload->Data,
sizeof(
float) * 4);
289 return absl::OkStatus();
300 window_manager->RegisterPanel(
301 {.card_id =
"palette.control_panel",
302 .display_name =
"Palette",
303 .window_title =
" Palette",
305 .category =
"Palette",
307 .shortcut_hint =
"Ctrl+Shift+P",
311 .disabled_tooltip =
"Load a ROM first"});
313 window_manager->RegisterPanel(
314 {.card_id =
"palette.ow_main",
315 .display_name =
"Overworld Main",
316 .window_title =
" Overworld Main",
318 .category =
"Palette",
320 .shortcut_hint =
"Ctrl+Alt+1",
324 .disabled_tooltip =
"Load a ROM first"});
326 window_manager->RegisterPanel(
327 {.card_id =
"palette.ow_animated",
328 .display_name =
"Overworld Animated",
329 .window_title =
" Overworld Animated",
331 .category =
"Palette",
333 .shortcut_hint =
"Ctrl+Alt+2",
337 .disabled_tooltip =
"Load a ROM first"});
339 window_manager->RegisterPanel(
340 {.card_id =
"palette.dungeon_main",
341 .display_name =
"Dungeon Main",
342 .window_title =
" Dungeon Main",
344 .category =
"Palette",
346 .shortcut_hint =
"Ctrl+Alt+3",
350 .disabled_tooltip =
"Load a ROM first"});
352 window_manager->RegisterPanel(
353 {.card_id =
"palette.sprites",
354 .display_name =
"Global Sprite Palettes",
355 .window_title =
" SNES Palette",
357 .category =
"Palette",
359 .shortcut_hint =
"Ctrl+Alt+4",
363 .disabled_tooltip =
"Load a ROM first"});
365 window_manager->RegisterPanel(
366 {.card_id =
"palette.sprites_aux1",
367 .display_name =
"Sprites Aux 1",
368 .window_title =
" Sprites Aux 1",
370 .category =
"Palette",
372 .shortcut_hint =
"Ctrl+Alt+7",
376 .disabled_tooltip =
"Load a ROM first"});
378 window_manager->RegisterPanel(
379 {.card_id =
"palette.sprites_aux2",
380 .display_name =
"Sprites Aux 2",
381 .window_title =
" Sprites Aux 2",
383 .category =
"Palette",
385 .shortcut_hint =
"Ctrl+Alt+8",
389 .disabled_tooltip =
"Load a ROM first"});
391 window_manager->RegisterPanel(
392 {.card_id =
"palette.sprites_aux3",
393 .display_name =
"Sprites Aux 3",
394 .window_title =
" Sprites Aux 3",
396 .category =
"Palette",
398 .shortcut_hint =
"Ctrl+Alt+9",
402 .disabled_tooltip =
"Load a ROM first"});
404 window_manager->RegisterPanel(
405 {.card_id =
"palette.equipment",
406 .display_name =
"Equipment Palettes",
407 .window_title =
" Equipment Palettes",
409 .category =
"Palette",
411 .shortcut_hint =
"Ctrl+Alt+5",
415 .disabled_tooltip =
"Load a ROM first"});
417 window_manager->RegisterPanel(
418 {.card_id =
"palette.quick_access",
419 .display_name =
"Quick Access",
420 .window_title =
" Color Harmony",
422 .category =
"Palette",
424 .shortcut_hint =
"Ctrl+Alt+Q",
428 .disabled_tooltip =
"Load a ROM first"});
430 window_manager->RegisterPanel(
431 {.card_id =
"palette.custom",
432 .display_name =
"Custom Palette",
433 .window_title =
" Palette Editor",
435 .category =
"Palette",
437 .shortcut_hint =
"Ctrl+Alt+C",
441 .disabled_tooltip =
"Load a ROM first"});
444 window_manager->OpenWindow(session_id,
"palette.control_panel");
456 std::string
GetId()
const override {
return "palette.control_panel"; }
466 void Draw(
bool* p_open)
override {
467 if (p_open && !*p_open)
482 std::string
GetId()
const override {
return "palette.quick_access"; }
492 void Draw(
bool* p_open)
override {
493 if (p_open && !*p_open)
508 std::string
GetId()
const override {
return "palette.custom"; }
518 void Draw(
bool* p_open)
override {
519 if (p_open && !*p_open)
536template <
typename Panel>
538 size_t session_id,
const char* panel_id,
540 auto* panel =
dynamic_cast<Panel*
>(
542 return panel !=
nullptr && panel->IsOwnedByRom(rom) ? panel :
nullptr;
548 if (window_manager ==
nullptr) {
561 ow_main_panel_ = ResolveSessionPalettePanel<OverworldMainPalettePanel>(
562 window_manager, session_id,
"palette.ow_main",
rom_);
563 ow_anim_panel_ = ResolveSessionPalettePanel<OverworldAnimatedPalettePanel>(
564 window_manager, session_id,
"palette.ow_animated",
rom_);
566 window_manager, session_id,
"palette.dungeon_main",
rom_);
568 window_manager, session_id,
"palette.global_sprites",
rom_);
570 window_manager, session_id,
"palette.sprites_aux1",
rom_);
572 window_manager, session_id,
"palette.sprites_aux2",
rom_);
574 window_manager, session_id,
"palette.sprites_aux3",
rom_);
576 window_manager, session_id,
"palette.armors",
rom_);
584 if (panel ==
nullptr) {
603 if (!
rom() || !
rom()->is_loaded()) {
604 return absl::NotFoundError(
"ROM not open, no palettes to display");
610 "Palette Group Name", std::to_string(i),
611 std::string(kPaletteGroupNames[i]));
632 std::make_unique<OverworldMainPalettePanel>(
rom_,
game_data());
634 window_manager->RegisterWindowContent(std::move(ow_main));
638 std::make_unique<OverworldAnimatedPalettePanel>(
rom_,
game_data());
640 window_manager->RegisterWindowContent(std::move(ow_anim));
644 std::make_unique<DungeonMainPalettePanel>(
rom_,
game_data());
646 window_manager->RegisterWindowContent(std::move(dungeon_main));
652 window_manager->RegisterWindowContent(std::move(sprite_global));
656 std::make_unique<SpritesAux1PalettePanel>(
rom_,
game_data());
658 window_manager->RegisterWindowContent(std::move(sprite_aux1));
662 std::make_unique<SpritesAux2PalettePanel>(
rom_,
game_data());
664 window_manager->RegisterWindowContent(std::move(sprite_aux2));
668 std::make_unique<SpritesAux3PalettePanel>(
rom_,
game_data());
670 window_manager->RegisterWindowContent(std::move(sprite_aux3));
673 auto equipment = std::make_unique<EquipmentPalettePanel>(
rom_,
game_data());
675 window_manager->RegisterWindowContent(std::move(equipment));
680 window_manager->RegisterWindowContent(std::make_unique<PaletteControlPanel>(
682 window_manager->RegisterWindowContent(
683 std::make_unique<QuickAccessPalettePanel>(
685 window_manager->RegisterWindowContent(std::make_unique<CustomPalettePanel>(
689 return absl::OkStatus();
695 return absl::FailedPreconditionError(
696 "Cannot save palettes from an inactive ROM session");
698 return manager.BeginSaveTransaction();
711 return absl::FailedPreconditionError(
"ROM not loaded");
714 return absl::FailedPreconditionError(
715 "Cannot save palettes from an inactive ROM session");
720 palette_manager.GetModifiedColorWriteRanges(
game_data()));
723 if (!ranges.empty()) {
737 return absl::OkStatus();
752 return absl::FailedPreconditionError(
753 "Cannot undo palettes from an inactive ROM session");
757 return absl::OkStatus();
762 return absl::FailedPreconditionError(
763 "Cannot redo palettes from an inactive ROM session");
767 return absl::OkStatus();
774 return absl::OkStatus();
778 BeginChild(
"QuickAccessPalettes", ImVec2(0, 0),
true);
780 Text(tr(
"Custom Palette"));
787 Text(tr(
"Current Color"));
797 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
800 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
804 if (Button(tr(
"Copy to Clipboard"))) {
805 SetClipboardText(buf);
812 Text(tr(
"Recently Used Colors"));
817 ImVec4 displayColor =
819 if (ImGui::ColorButton(
"##recent", displayColor)) {
845 if (BeginChild(
"ColorPalette", ImVec2(0, 40), ImGuiChildFlags_None,
846 ImGuiWindowFlags_HorizontalScrollbar)) {
850 SameLine(0.0f, GetStyle().ItemSpacing.y);
854 bool open_color_picker = ImGui::ColorButton(
855 absl::StrFormat(
"##customPal%d", i).c_str(), displayColor);
856 const ImVec2 swatch_min = ImGui::GetItemRectMin();
857 const ImVec2 swatch_max = ImGui::GetItemRectMax();
858 if (ImGui::IsItemHovered() &&
859 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
860 open_color_picker =
true;
863 if (open_color_picker) {
867 "CustomPaletteColorEdit")
871 if (DrawCustomColorContextMenu(
878 if (AcceptImGuiColorDrop(&
custom_palette_[i], swatch_min, swatch_max)) {
886 if (ImGui::Button(
"+")) {
891 if (ImGui::Button(tr(
"Clear"))) {
896 if (ImGui::Button(tr(
"Export"))) {
897 std::string clipboard;
899 clipboard += absl::StrFormat(
"$%04X,", color.snes());
901 SetClipboardText(clipboard.c_str());
907 if (ImGui::BeginPopup(
927 return absl::NotFoundError(
"ROM not open, no palettes to display");
930 auto palette_group_name = kPaletteGroupNames[category];
933 const auto size = palette_group->
size();
935 for (
int j = 0; j < size; j++) {
937 auto pal_size = palette->
size();
944 false, palette_group_name.data(), std::to_string(j),
948 for (
int n = 0; n < pal_size; n++) {
950 if (n > 0 && n % 8 != 0)
951 SameLine(0.0f, 2.0f);
954 absl::StrCat(kPaletteCategoryNames[category].data(), j,
"_", n);
957 if (ImGui::ColorButton(popup_id.c_str(), displayColor)) {
961 const ImVec2 swatch_min = ImGui::GetItemRectMin();
962 const ImVec2 swatch_max = ImGui::GetItemRectMax();
963 if (ImGui::IsItemHovered() &&
964 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
967 OpenPopup(popup_id.c_str());
970 const SnesColor original_color = (*palette)[n];
971 if (AcceptImGuiColorDrop(&(*palette)[n], swatch_min, swatch_max)) {
973 std::string(kPaletteGroupNames[category]),
974 j, n, original_color,
976 (*palette)[n].set_modified(
true);
981 if (BeginPopupContextItem(popup_id.c_str())) {
993 return absl::OkStatus();
998 auto it = std::find_if(
1000 [&color](
const SnesColor& c) { return c.snes() == color.snes(); });
1019 auto original_color = palette[n];
1024 original_color, palette[n]);
1025 palette[n].set_modified(
true);
1037 Text(tr(
"RGB: %d, %d, %d"), cr, cg, cb);
1038 Text(tr(
"SNES: $%04X"), palette[n].snes());
1044 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff)", col[0],
1047 SetClipboardText(buf);
1053 if (ImGui::MenuItem(
ICON_MD_ADD " Add to Custom Palette")) {
1058 return absl::OkStatus();
1063 if (index >= palette.
size()) {
1064 return absl::InvalidArgumentError(
"Index out of bounds");
1068 auto color = palette[index];
1069 auto currentColor = color.rgb();
1070 if (ColorPicker4(
"Color Picker", (
float*)&palette[index])) {
1077 return absl::OkStatus();
1083 if (index >= palette.
size() || index >= originalPalette.
size()) {
1084 return absl::InvalidArgumentError(
"Index out of bounds");
1086 auto color = originalPalette[index];
1087 auto originalColor = color.rgb();
1089 return absl::OkStatus();
1099 ImGui::TextDisabled(
1100 tr(
"Palette controls are unavailable for an inactive ROM session."));
1105 const size_t modified_count = manager.GetModifiedColorCount();
1106 const bool pending = manager.HasUnsavedChanges() || (
rom_ &&
rom_->
dirty());
1108 const bool save = ImGui::Button(
ICON_MD_SAVE " Save ROM");
1112 ImGui::EndDisabled();
1113 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
1115 tr(
"Save through the application, including pending editor changes."));
1117 ImGui::BeginDisabled(!
CanUndo());
1121 ImGui::EndDisabled();
1123 ImGui::BeginDisabled(!
CanRedo());
1127 ImGui::EndDisabled();
1130 ImGui::OpenPopup(
"PaletteTools");
1132 bool discard_requested =
false;
1133 if (ImGui::BeginPopup(
"PaletteTools")) {
1134 if (ImGui::MenuItem(tr(
"Refresh editor previews"))) {
1135 const auto result = manager.ApplyPreviewChanges();
1140 if (ImGui::MenuItem(tr(
"Discard palette changes..."),
nullptr,
false,
1141 manager.HasUnsavedChanges()))
1142 discard_requested =
true;
1145 if (ImGui::MenuItem(tr(
"Color reference")))
1147 "palette.quick_access");
1148 if (ImGui::MenuItem(tr(
"Custom swatches")))
1153 if (discard_requested)
1154 ImGui::OpenPopup(
"Discard palette changes?###ConfirmPaletteDiscard");
1155 if (ImGui::BeginPopupModal(
"Discard palette changes?###ConfirmPaletteDiscard",
1156 nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1157 ImGui::Text(tr(
"Discard changes to %zu colors?"), modified_count);
1158 if (ImGui::Button(tr(
"Discard"))) {
1159 manager.DiscardAllChanges();
1160 ImGui::CloseCurrentPopup();
1163 if (ImGui::Button(tr(
"Cancel")))
1164 ImGui::CloseCurrentPopup();
1170 ImGui::TextDisabled(tr(
"%zu edited colors"), modified_count);
1172 ImGui::TextDisabled(pending ? tr(
"ROM has unsaved changes")
1173 : tr(
"No pending palette edits"));
1187 const float nav_width =
1188 std::clamp(ImGui::GetContentRegionAvail().x * 0.22f,
1189 ImGui::GetFontSize() * 11, ImGui::GetFontSize() * 16);
1190 ImGui::BeginChild(
"PaletteGroups", ImVec2(nav_width, 0));
1194 ImGui::BeginChild(
"PaletteSelection", ImVec2(0, 0));
1203 panel->DrawEmbedded();
1211 ImGui::BeginGroup();
1212 ImGui::Text(tr(
"Current Color"));
1222 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"RGB: %d, %d, %d", cr, cg, cb);
1223 ImGui::Text(
"%s", buf);
1225 CustomFormatString(buf, IM_ARRAYSIZE(buf),
"SNES: $%04X",
1227 ImGui::Text(
"%s", buf);
1229 if (ImGui::Button(tr(
"Copy to Clipboard"), ImVec2(-1, 0))) {
1230 SetClipboardText(buf);
1237 ImGui::Text(tr(
"Recently Used Colors"));
1239 ImGui::TextDisabled(tr(
"No recently used colors yet"));
1245 ImVec4 displayColor =
1252 if (ImGui::IsItemHovered()) {
1261 ImGui::TextWrapped(tr(
1262 "Create your own custom color palette for reference. "
1263 "Colors can be added from any palette group or created from scratch."));
1269 ImGui::TextDisabled(tr(
"Your custom palette is empty."));
1270 ImGui::Text(tr(
"Click + to add colors or drag colors from any palette."));
1274 if (i > 0 && i % 16 != 0)
1275 SameLine(0.0f, 2.0f);
1279 bool open_color_picker =
1280 ImGui::ColorButton(absl::StrFormat(
"##customPal%d", i).c_str(),
1282 const ImVec2 swatch_min = ImGui::GetItemRectMin();
1283 const ImVec2 swatch_max = ImGui::GetItemRectMax();
1284 if (ImGui::IsItemHovered() &&
1285 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
1286 open_color_picker =
true;
1289 if (open_color_picker) {
1293 "PanelCustomPaletteColorEdit")
1297 if (DrawCustomColorContextMenu(
1304 if (AcceptImGuiColorDrop(&
custom_palette_[i], swatch_min, swatch_max)) {
1326 std::string clipboard;
1328 clipboard += absl::StrFormat(
"$%04X,", color.snes());
1330 if (!clipboard.empty()) {
1331 clipboard.pop_back();
1333 SetClipboardText(clipboard.c_str());
1335 if (ImGui::IsItemHovered()) {
1336 ImGui::SetTooltip(tr(
"Copy palette as comma-separated SNES values"));
1341 "PanelCustomPaletteColorEdit")
1358 if (group ==
"ow_main")
1360 if (group ==
"ow_animated")
1362 if (group ==
"dungeon_main")
1364 if (group ==
"global_sprites")
1366 if (group ==
"sprites_aux1")
1368 if (group ==
"sprites_aux2")
1370 if (group ==
"sprites_aux3")
1372 if (group ==
"armors")
1378 int palette_index) {
1384 panel->SetSelectedPaletteIndex(palette_index);
1386 "palette.control_panel");
1395 ImGui::SetNextItemWidth(-1);
1396 if (ImGui::InputTextWithHint(
"##PaletteSearch",
1415 bool heading_drawn =
false;
1416 for (
const auto& group : category.group_names) {
1419 if (!heading_drawn) {
1421 ImGui::TextDisabled(
"%s", category.display_name.c_str());
1422 heading_drawn =
true;
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.
WindowPresentationPolicy GetPresentationPolicy() const override
How this content is hosted and advertised by workspace chrome.
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.
WindowPresentationPolicy GetPresentationPolicy() const override
How this content is hosted and advertised by workspace chrome.
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()
OverworldAnimatedPalettePanel * ow_anim_panel_
bool CanUndo() const override
absl::Status ResetColorToOriginal(gfx::SnesPalette &palette, int index, const gfx::SnesPalette &originalPalette)
std::vector< gfx::SnesColor > custom_palette_
SpritesAux1PalettePanel * sprite_aux1_panel_
void CommitSaveTransaction() override
void RollbackSaveTransaction() override
void DrawCustomPalette()
Draw custom palette editor with enhanced ROM hacking features.
bool show_sprites_aux3_panel_
absl::Status BeginSaveTransaction() override
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_
std::string selected_group_
void RefreshPanelReferences()
bool show_custom_palette_
void RefreshPaletteCatalogIfChanged()
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_
bool CanRedo() const override
void DrawQuickAccessTab()
std::vector< gfx::SnesColor > recently_used_colors_
palette_internal::PaletteEditorHistory history_
PaletteGroupPanel * GetPanelForGroup(const std::string &group_name)
absl::Status Save() override
bool show_sprites_aux2_panel_
absl::Status Load() override
void DrawPaletteCatalog()
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.
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)
WindowPresentationPolicy GetPresentationPolicy() const override
How this content is hosted and advertised by workspace chrome.
void Show(const std::string &message, ToastType type=ToastType::kInfo, float ttl_seconds=3.0f, std::string action_label={}, std::function< void()> on_action=nullptr)
Base interface for all logical window content components.
Central registry for all editor cards with session awareness and dependency injection.
bool OpenWindow(size_t session_id, const std::string &base_window_id)
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)
void RollbackSaveTransaction()
void Undo()
Undo the most recent change.
void CommitSaveTransaction()
void Initialize(zelda3::GameData *game_data)
Initialize the palette manager with GameData.
static PaletteManager & Get()
Get the singleton instance.
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_MORE_HORIZ
#define ICON_MD_OPEN_IN_NEW
#define ICON_MD_CONTENT_COPY
#define ICON_MD_COLOR_LENS
#define TEXT_WITH_SEPARATOR(text)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
bool DrawCustomColorContextMenu(std::vector< gfx::SnesColor > &colors, int index, const std::function< void(const gfx::SnesColor &)> &on_edited)
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
std::string GetGroupDisplayName(const std::string &group_name)
Get display name for a palette group.
std::array< float, 4 > ToFloatArray(const SnesColor &color)
constexpr int kNumPalettes
constexpr const char * kPalette
bool ThemedIconButton(const char *icon, const char *tooltip, const ImVec2 &size, bool is_active, bool is_disabled, const char *panel_id, const char *anim_id)
Draw a standard icon button with theme-aware colors.
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.
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
void SnesColorCopyMenuItems(const gfx::SnesColor &color)
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)
void RenderMenuItem(const CanvasMenuItem &item, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a single menu item.
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 F32_TO_INT8_SAT(_VAL)
#define RETURN_IF_ERROR(expr)
Unified dependency container for all editor types.
project::YazeProject * project
ToastManager * toast_manager
WorkspaceWindowManager * window_manager
static WindowPresentationPolicy CoreWorkspace()
static WindowPresentationPolicy OptionalPopOut()
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