9#include "absl/status/status.h"
10#include "absl/strings/str_format.h"
27#include "imgui/imgui.h"
74 if (MenuItem(tr(
"Copy Current Tile16"))) {
77 SetItemTooltip(
"%s", tr(
"Ctrl+C in the Tile16 panel"));
78 if (MenuItem(tr(
"Paste to Current Tile16"))) {
81 SetItemTooltip(
"%s", tr(
"Ctrl+V in the Tile16 panel"));
83 if (MenuItem(tr(
"Flip Tile16 Horizontal"))) {
86 SetItemTooltip(
"%s", tr(
"H in the Tile16 panel"));
87 if (MenuItem(tr(
"Flip Tile16 Vertical"))) {
90 SetItemTooltip(
"%s", tr(
"V in the Tile16 panel"));
91 if (MenuItem(tr(
"Rotate Tile16"))) {
94 SetItemTooltip(
"%s", tr(
"R in the Tile16 panel"));
95 if (MenuItem(tr(
"Clear Tile16"))) {
98 SetItemTooltip(
"%s", tr(
"Delete in the Tile16 panel"));
105 if (MenuItem(tr(
"Show Collision IDs"),
nullptr,
113 if (BeginMenu(tr(
"Scratch Slots"))) {
114 for (
int i = 0; i < 4; i++) {
115 std::string slot_name =
"Slot " + std::to_string(i + 1);
117 if (MenuItem((slot_name +
" (Load)").c_str())) {
120 if (MenuItem((slot_name +
" (Save)").c_str())) {
123 if (MenuItem((slot_name +
" (Clear)").c_str())) {
127 if (MenuItem((slot_name +
" (Save)").c_str())) {
139 absl::Status draw_status;
140 static bool show_advanced_controls =
false;
141 static bool show_debug_info =
false;
144 {{ImGuiStyleVar_FramePadding, ImVec2(8, 4)},
145 {ImGuiStyleVar_ItemSpacing, ImVec2(8, 4)}});
152 const int total_tiles =
154 const float layout_width = ImGui::GetContentRegionAvail().x;
155 const bool compact_layout = layout_width < 900.0f;
156 const int layout_columns = compact_layout ? 1 : 2;
158 if (ImGui::BeginTable(
159 "##Tile16EditLayout", layout_columns,
160 ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchProp)) {
161 if (compact_layout) {
162 ImGui::TableSetupColumn(
"Tile16 Workbench",
163 ImGuiTableColumnFlags_WidthStretch, 1.0f);
165 ImGui::TableSetupColumn(
"Tile8 Source",
166 ImGuiTableColumnFlags_WidthStretch, 0.58f);
167 ImGui::TableSetupColumn(
"Editor", ImGuiTableColumnFlags_WidthStretch,
171 if (compact_layout) {
172 ImGui::TableNextRow();
173 ImGui::TableNextColumn();
178 show_debug_info, show_advanced_controls));
181 ImGui::TableNextRow();
182 ImGui::TableNextColumn();
188 ImGui::TableNextRow();
189 ImGui::TableNextColumn();
195 ImGui::TableNextColumn();
200 show_debug_info, show_advanced_controls));
223 std::max(0, total_tiles - 1));
226 ImGui::SetNextItemWidth(80);
236 if (ImGui::IsItemHovered()) {
237 ImGui::SetTooltip(tr(
"Tile ID (0-%d) - navigates as you type"),
247 if (ImGui::Button(
"<<")) {
251 if (ImGui::IsItemHovered())
252 ImGui::SetTooltip(tr(
"First page"));
255 if (ImGui::Button(
"<")) {
256 int new_tile = std::max(
261 if (ImGui::IsItemHovered())
262 ImGui::SetTooltip(tr(
"Previous page (PageUp)"));
269 if (ImGui::Button(
">")) {
271 std::min(total_tiles - 1,
276 if (ImGui::IsItemHovered())
277 ImGui::SetTooltip(tr(
"Next page (PageDown)"));
280 if (ImGui::Button(
">>")) {
284 if (ImGui::IsItemHovered())
285 ImGui::SetTooltip(tr(
"Last page"));
287 if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
288 if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
289 int new_tile = std::max(
294 if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
301 if (ImGui::IsKeyPressed(ImGuiKey_Home)) {
305 if (ImGui::IsKeyPressed(ImGuiKey_End)) {
310 if (!ImGui::GetIO().KeyCtrl) {
311 if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow) &&
316 if (ImGui::IsKeyPressed(ImGuiKey_RightArrow) &&
321 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow) &&
327 if (ImGui::IsKeyPressed(ImGuiKey_DownArrow) &&
337 return absl::OkStatus();
341 bool show_debug_info,
bool show_advanced_controls) {
342 absl::Status draw_status;
345 if (ImGui::BeginChild(
346 "##Tile16FixedCanvas", ImVec2(preview_size + 26, preview_size + 26),
348 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
351 tile16_edit_frame_opts.
canvas_size = ImVec2(preview_size, preview_size);
361 auto tile16_edit_rt =
390 preview_data.begin());
404 if (display_palette && !display_palette->
empty()) {
415 for (
int y = 0; y < 8; ++y) {
416 for (
int x = 0; x < 4; ++x) {
417 std::swap(data[y * 8 + x], data[y * 8 + (7 - x)]);
423 for (
int y = 0; y < 4; ++y) {
424 for (
int x = 0; x < 8; ++x) {
425 std::swap(data[y * 8 + x], data[(7 - y) * 8 + x]);
436 const auto preview_command =
445 if (tile16_edit_rt.hovered &&
448 const auto mouse = ImGui::GetIO().MousePos;
453 draw_status.Update(preview_status);
454 if (preview_status.ok()) {
465 const bool left_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
466 const bool right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
468 if (left_clicked || right_clicked) {
469 const ImGuiIO& io = ImGui::GetIO();
472 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
476 const ImVec2 tile_position =
478 int tile_x =
static_cast<int>(tile_position.x);
479 int tile_y =
static_cast<int>(tile_position.y);
482 tile_x = std::max(0, std::min(15, tile_x));
483 tile_y = std::max(0, std::min(15, tile_y));
486 "Tile16 canvas click: (%.2f, %.2f) -> Tile16: (%d, %d), mode=%s",
487 mouse_pos.x, mouse_pos.y, tile_x, tile_y,
491 ImVec2(tile_x, tile_y), left_clicked, right_clicked));
511 ImGui::Image((ImTextureID)(intptr_t)tile8_texture, ImVec2(24, 24));
516 ImGui::TextDisabled(tr(
"G%d"), sheet_idx);
517 if (ImGui::IsItemHovered()) {
518 ImGui::BeginTooltip();
519 ImGui::Text(tr(
"Graphics chunk: %d"), sheet_idx);
545 "1x: paint one quadrant\n2x: fill current tile16 from a 2x2 tile8 "
546 "block\n4x: stamp a 2x2 tile16 patch from a 4x4 tile8 block");
548 Text(tr(
"Edit Mode:"));
549 if (ImGui::RadioButton(tr(
"Paint (P)"),
554 if (ImGui::RadioButton(tr(
"Pick (I)"),
559 if (ImGui::RadioButton(tr(
"Usage (U)"),
565 "Paint: left-click places Tile8 into Tile16.\n"
566 "Pick: left-click samples Tile8 from Tile16.\n"
567 "Usage: keeps usage overlay visible and samples on click.\n"
568 "Right-click on Tile16 preview always samples.");
572 if (ImGui::CollapsingHeader(tr(
"Usage Navigator"),
573 ImGuiTreeNodeFlags_DefaultOpen)) {
574 const float nav_height = 220.0f;
575 if (BeginChild(
"##UsageBlocksetNav", ImVec2(0, nav_height),
true,
576 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
591 if (result.selection_changed) {
611 if (show_advanced_controls) {
613 Text(tr(
"Advanced:"));
615 if (Button(tr(
"Palette Settings"), ImVec2(-1, 0))) {
620 if (Button(tr(
"Analyze Data"), ImVec2(-1, 0))) {
623 HOVER_HINT(
"Analyze tile8 source data format and palette state");
625 if (Button(tr(
"Manual Edit"), ImVec2(-1, 0))) {
626 ImGui::OpenPopup(
"ManualTile8Editor");
629 if (Button(tr(
"Refresh Blockset"), ImVec2(-1, 0))) {
634 Text(tr(
"Scratch:"));
642 if (show_debug_info) {
652 ImGui::TextDisabled(tr(
"Sheet:%d Slot:%d"), sheet_index, actual_slot);
656 if (ImGui::CollapsingHeader(tr(
"Palette Map"),
657 ImGuiTreeNodeFlags_DefaultOpen)) {
658 ImGui::BeginChild(
"##PaletteMappingScroll", ImVec2(0, 120),
true);
659 if (ImGui::BeginTable(
"##PalMap", 2,
660 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
661 ImGuiTableFlags_SizingFixedFit)) {
662 ImGui::TableSetupColumn(
"Btn", ImGuiTableColumnFlags_WidthFixed, 30);
663 ImGui::TableSetupColumn(
"CGRAM", ImGuiTableColumnFlags_WidthFixed, 70);
664 ImGui::TableHeadersRow();
666 for (
int i = 0; i < 8; ++i) {
667 ImGui::TableNextRow();
668 ImGui::TableNextColumn();
669 ImGui::Text(
"%d", i);
670 ImGui::TableNextColumn();
679 if (ImGui::CollapsingHeader(tr(
"Colors"))) {
682 ImGui::Text(tr(
"Slot %d:"), actual_slot);
685 i < 8 && (actual_slot + i) <
688 int color_index = actual_slot + i;
690 ImVec4 display_color = color.rgb();
692 ImGui::ColorButton(absl::StrFormat(
"##c%d", i).c_str(), display_color,
693 ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
694 if (ImGui::IsItemHovered()) {
695 ImGui::SetTooltip(tr(
"%d:0x%04X"), color_index, color.snes());
698 if ((i + 1) % 4 != 0)
709 bool* show_debug_info,
bool* show_advanced_controls) {
710 const float available_width = ImGui::GetContentRegionAvail().x;
711 const int action_count = 4;
714 const float row_height = ImGui::GetTextLineHeightWithSpacing() +
715 rows * ImGui::GetFrameHeightWithSpacing() +
716 ImGui::GetStyle().FramePadding.y * 2.0f;
717 absl::Status action_status = absl::OkStatus();
719 if (ImGui::BeginChild(
720 "##Tile16CompactStatus", ImVec2(0, row_height),
false,
721 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
724 ImGui::TextDisabled(
"| %s | Live edits",
726 if (ImGui::IsItemHovered()) {
728 "Edits update every use of this Tile16 in the document.\n"
729 "Use Undo/Redo to revise edits and Save to write the ROM.");
732 if (ImGui::BeginTable(
"##Tile16CompactActions", columns,
733 ImGuiTableFlags_SizingStretchProp)) {
734 int action_index = 0;
735 auto next_action_cell = [&]() {
736 if (action_index % columns == 0) {
737 ImGui::TableNextRow();
739 ImGui::TableNextColumn();
745 ImGui::BeginDisabled();
747 if (ImGui::Button(tr(
"Undo"),
748 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
749 action_status =
Undo();
752 ImGui::EndDisabled();
757 ImGui::BeginDisabled();
759 if (ImGui::Button(tr(
"Redo"),
760 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
761 action_status =
Redo();
764 ImGui::EndDisabled();
768 const char* advanced_label = *show_advanced_controls
769 ?
"Advanced*##Tile16AdvancedToggle"
770 :
"Advanced##Tile16AdvancedToggle";
771 if (ImGui::Button(advanced_label,
772 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
773 *show_advanced_controls = !*show_advanced_controls;
777 const char* debug_label = *show_debug_info ?
"Debug*##Tile16DebugToggle"
778 :
"Debug##Tile16DebugToggle";
779 if (ImGui::Button(debug_label,
780 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
781 *show_debug_info = !*show_debug_info;
788 return action_status;
792 bool show_debug_info) {
793 absl::Status draw_status;
795 Text(tr(
"Brush Palette:"));
796 if (show_debug_info) {
799 ImGui::TextDisabled(tr(
"(Slot %d)"), actual_slot);
801 ImGui::TextDisabled(tr(
"Used for new tile8 placements"));
805 float available_width = ImGui::GetContentRegionAvail().x;
815 for (
int row = 0; row < 2; ++row) {
816 for (
int col = 0; col < 4; ++col) {
820 int i = row * 4 + col;
827 is_current ? selected_button_colors : default_button_colors;
828 const ImVec4 palette_button_border =
832 {{ImGuiCol_Button, palette_button_colors.
button},
833 {ImGuiCol_ButtonHovered, palette_button_colors.
hovered},
834 {ImGuiCol_ButtonActive, palette_button_colors.
active},
835 {ImGuiCol_Border, palette_button_border}});
839 if (ImGui::Button(absl::StrFormat(
"%d", i).c_str(),
840 ImVec2(button_size, button_size))) {
846 status.message().data());
848 util::logf(
"Palette successfully changed to %d",
859 std::vector<gui::MenuItemSpec> items;
860 items.emplace_back(
"Use Palette",
ICON_MD_BRUSH, [
this, i]() {
868 status.message().data());
873 [
this, i, &draw_status]() {
877 items.back().tooltip =
"Sets all four quadrants to this palette.";
878 items.back().separator_after =
true;
884 c < slot + 16 && c < static_cast<int>(ow_palette.size()); ++c) {
885 colors += absl::StrFormat(
"%s$%04X", colors.empty() ?
"" :
",",
886 ow_palette[c].snes());
890 copy_item.enabled_condition = [has = !colors.empty()]() {
893 items.push_back(std::move(copy_item));
898 if (ImGui::IsItemHovered()) {
899 ImGui::BeginTooltip();
900 if (show_debug_info) {
901 ImGui::Text(tr(
"Palette %d -> CGRAM 0x%02X"), i,
904 ImGui::Text(tr(
"Brush Palette %d"), i);
905 ImGui::TextDisabled(tr(
"Applied to new tile8 placements"));
906 ImGui::TextDisabled(tr(
"Right-click: palette actions"));
907 ImGui::TextDisabled(tr(
"Quadrant metadata is shown in strip below"));
909 tr(
"Hotkeys: Ctrl+1..8 palette, 1..4 quadrant focus"));
922 Text(tr(
"Quadrant Focus:"));
924 ImGui::TextDisabled(
"1-4");
925 static constexpr std::array<const char*, 4> kQuadrantLabels = {
"TL",
"TR",
927 const float quadrant_button_width = std::max(58.0f, button_size + 24.0f);
930 for (
int q = 0; q < 4; ++q) {
936 const uint8_t quadrant_palette = info.
palette_;
938 const bool matches_brush =
941 ImGui::PushID(100 + q);
943 is_active_quadrant ? active_quadrant_colors
944 : (matches_brush ? selected_button_colors
945 : default_button_colors);
946 const ImVec4 quadrant_border =
952 {{ImGuiCol_Button, quadrant_button_colors.
button},
953 {ImGuiCol_ButtonHovered, quadrant_button_colors.
hovered},
954 {ImGuiCol_ButtonActive, quadrant_button_colors.
active},
955 {ImGuiCol_Border, quadrant_border}});
957 is_active_quadrant ? 2.0f : 1.0f);
959 if (ImGui::Button(absl::StrFormat(
"%d %s:%d", q + 1, kQuadrantLabels[q],
962 ImVec2(quadrant_button_width, 0))) {
969 status.message().data());
974 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
980 if (ImGui::IsItemHovered()) {
981 ImGui::BeginTooltip();
982 ImGui::Text(tr(
"Quadrant %s metadata"), kQuadrantLabels[q]);
984 ImGui::Text(tr(
"Tile8: %02X"), info.
id_);
985 ImGui::Text(tr(
"Palette: %d"), quadrant_palette);
988 ImGui::Text(tr(
"Priority: %s"), info.
over_ ?
"Y" :
"N");
989 ImGui::TextDisabled(tr(
"LMB: set brush palette from this quadrant"));
991 tr(
"RMB: apply current brush palette to this quadrant"));
992 ImGui::TextDisabled(tr(
"Keys 1..4: focus TL/TR/BL/BR"));
1001 ImGui::TextDisabled(tr(
"Active %s: Tile8 %02X | P%d | H:%s V:%s | Pri:%s"),
1006 active_info.
over_ ?
"Y" :
"N");
1008 if (Button(tr(
"Apply Brush to Active Quadrant"), ImVec2(-1, 0))) {
1013 "Copy the Brush Palette into the selected quadrant metadata.\n"
1014 "Use keys 1..4 to change active quadrant quickly.");
1018 if (Button(tr(
"Apply Brush to All Quadrants"), ImVec2(-1, 0))) {
1022 "Copy the Brush Palette into Tile Palette metadata for all 4 "
1024 "Tip: right-click any brush palette button above for a one-step apply.");
1029 absl::Status draw_status;
1032 ImGui::Text(tr(
"Tile8 Source"));
1034 ImGui::Checkbox(tr(
"Grid##Tile16GridToggle"),
1037 if (ImGui::Checkbox(tr(
"IDs##Tile16CollisionIds"),
1043 int source_bitmap_height = 0;
1063 ImGui::GetContentRegionAvail().y, source_bitmap_height,
1066 if (BeginChild(
"##Tile8SourceScrollable", ImVec2(0, panel_height),
true,
1067 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1082 const bool left_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
1083 const bool right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
1087 ImGui::IsItemHovered(), ImGui::IsMouseDown(ImGuiMouseButton_Right));
1092 if (left_clicked || right_clicked) {
1110 float display_scale) {
1111 const ImGuiIO& io = ImGui::GetIO();
1114 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
1121 return absl::OkStatus();
1126 if (right_clicked) {
1131 return absl::OkStatus();
1136 if (Button(tr(
"Clear"), ImVec2(-1, 0))) {
1140 if (Button(tr(
"Copy"), ImVec2(-1, 0))) {
1144 if (Button(tr(
"Paste"), ImVec2(-1, 0))) {
1148 return absl::OkStatus();
1159 if (!cache_status.ok()) {
1160 util::logf(
"Tile8 usage cache rebuild failed: %s",
1161 cache_status.message().data());
1171 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1174 const float tile16_display = 32.0f * scale;
1175 const float quadrant_display = 16.0f * scale;
1176 const int tiles_per_row =
1179 for (
const auto& hit : hits) {
1180 const int tile_x = hit.tile16_id % tiles_per_row;
1181 const int tile_y = hit.tile16_id / tiles_per_row;
1182 const int quad_x = hit.quadrant % 2;
1183 const int quad_y = hit.quadrant / 2;
1186 canvas_pos.x + (tile_x * tile16_display) + (quad_x * quadrant_display),
1187 canvas_pos.y + (tile_y * tile16_display) + (quad_y * quadrant_display));
1188 const ImVec2 max(min.x + quadrant_display, min.y + quadrant_display);
1191 draw_list->AddRectFilled(min, max, IM_COL32(150, 0, 210, 80));
1192 draw_list->AddRect(min, max, IM_COL32(215, 170, 255, 180));
1198 if (Begin(
"Advanced Palette Settings",
1200 Text(tr(
"Pixel Normalization & Color Correction:"));
1203 if (SliderInt(tr(
"Normalization Mask"), &mask_value, 1, 255,
"0x%02X")) {
1205 static_cast<uint8_t
>(mask_value);
1208 Checkbox(tr(
"Auto Normalize Pixels"),
1211 if (Button(tr(
"Apply to All Graphics"))) {
1213 if (!reload_result.ok()) {
1214 Text(tr(
"Error: %s"), reload_result.message().data());
1219 if (Button(tr(
"Reset Defaults"))) {
1223 (void)reload_result;
1227 Text(tr(
"Current State:"));
1228 static constexpr std::array<const char*, 7> palette_group_names = {
1229 "OW Main",
"OW Aux",
"OW Anim",
"Dungeon",
1230 "Sprites",
"Armor",
"Sword"};
1238 Text(tr(
"Sheet-Specific Fixes:"));
1241 static bool fix_sheet_0 =
true;
1242 static bool fix_sprite_sheets =
true;
1243 static bool use_transparent_for_terrain =
false;
1245 if (Checkbox(tr(
"Fix Sheet 0 (Trees)"), &fix_sheet_0)) {
1247 if (!reload_result.ok()) {
1248 Text(tr(
"Error reloading: %s"), reload_result.message().data());
1252 "Use direct palette for sheet 0 instead of transparent palette");
1254 if (Checkbox(tr(
"Fix Sprite Sheets"), &fix_sprite_sheets)) {
1256 if (!reload_result.ok()) {
1257 Text(tr(
"Error reloading: %s"), reload_result.message().data());
1260 HOVER_HINT(
"Use direct palette for sprite graphics sheets");
1262 if (Checkbox(tr(
"Transparent for Terrain"),
1263 &use_transparent_for_terrain)) {
1265 if (!reload_result.ok()) {
1266 Text(tr(
"Error reloading: %s"), reload_result.message().data());
1269 HOVER_HINT(
"Force transparent palette for terrain graphics");
1272 Text(tr(
"Color Analysis:"));
1277 Text(tr(
"Selected Tile8 Analysis:"));
1278 const auto& tile_data =
1280 std::map<uint8_t, int> pixel_counts;
1281 for (uint8_t pixel : tile_data) {
1282 pixel_counts[pixel & 0x0F]++;
1285 Text(tr(
"Pixel Value Distribution:"));
1286 for (
const auto& pair : pixel_counts) {
1287 int value = pair.first;
1288 int count = pair.second;
1289 Text(tr(
" Value %d (0x%X): %d pixels"), value, value, count);
1292 Text(tr(
"Palette Colors Used:"));
1295 if (analysis_palette ==
nullptr || analysis_palette->
empty()) {
1300 for (
const auto& pair : pixel_counts) {
1301 int value = pair.first;
1302 int count = pair.second;
1303 if (value <
static_cast<int>(analysis_palette->
size())) {
1304 auto color = (*analysis_palette)[value];
1305 ImVec4 display_color = color.rgb();
1306 ImGui::ColorButton((
"##analysis" + std::to_string(value)).c_str(),
1307 display_color, ImGuiColorEditFlags_NoTooltip,
1309 if (ImGui::IsItemHovered()) {
1310 ImGui::SetTooltip(tr(
"Index %d: 0x%04X (%d pixels)"), value,
1311 color.snes(), count);
1321 if (CollapsingHeader(tr(
"ROM Palette Manager")) &&
session_.
rom()) {
1322 Text(tr(
"Experimental ROM Palette Selection:"));
1324 "Use ROM palettes to experiment with different color schemes");
1326 if (Button(tr(
"Open Enhanced Palette Editor"))) {
1330 if (Button(tr(
"Show Color Analysis"))) {
1335 static int quick_group = 0;
1336 static int quick_index = 0;
1338 SliderInt(tr(
"ROM Group"), &quick_group, 0, 6);
1339 SliderInt(tr(
"Palette Index"), &quick_index, 0, 7);
1341 if (Button(tr(
"Apply to Tile8 Source"))) {
1343 util::logf(
"Applied ROM palette group %d, index %d to Tile8 source",
1344 quick_group, quick_index);
1348 if (Button(tr(
"Apply to Tile16 Editor"))) {
1351 "Applied ROM palette group %d, index %d to Tile16 editor",
1352 quick_group, quick_index);
1362 Text(tr(
"Layout Scratch:"));
1363 for (
int i = 0; i < 4; ++i) {
1365 std::string slot_name =
"S" + std::to_string(i + 1);
1367 if (Button((slot_name +
" Save").c_str(), ImVec2(70, 20))) {
1374 ImGui::BeginDisabled();
1376 if (Button((slot_name +
" Load").c_str(), ImVec2(70, 20)) && can_load) {
1380 ImGui::EndDisabled();
1389 if (ImGui::BeginPopupModal(
"ManualTile8Editor",
nullptr,
1390 ImGuiWindowFlags_AlwaysAutoResize)) {
1393 ImGui::Text(
"Tile16 0x%03X — quadrant properties",
1396 bool changed =
false;
1397 const char* names[] = {
"Top left",
"Top right",
"Bottom left",
1399 for (
int q = 0; q < 4; ++q) {
1401 ImGui::SeparatorText(names[q]);
1402 auto& info = TileInfoForQuadrant(&edited, q);
1404 if (ImGui::InputInt(
"Tile8", &
id)) {
1405 info.id_ = std::clamp(
id, 0, 1023);
1408 int palette = info.palette_;
1409 if (ImGui::SliderInt(
"Palette", &palette, 0, 7)) {
1410 info.palette_ = palette;
1413 changed |= ImGui::Checkbox(
"X Flip", &info.horizontal_mirror_);
1415 changed |= ImGui::Checkbox(
"Y Flip", &info.vertical_mirror_);
1417 changed |= ImGui::Checkbox(
"Priority", &info.over_);
1422 if (ImGui::Button(
"Close"))
1423 ImGui::CloseCurrentPopup();
void set_tile8_stamp_size(int size)
int current_tile8() const
void set_scroll_to_current(bool scroll)
gfx::Bitmap * tile16_blockset_bmp()
bool * mutable_show_tile_grid()
gfx::Tilemap * tile16_blockset()
int current_tile16() const
float tile8_source_display_scale() const
uint8_t * mutable_palette_normalization_mask()
int current_palette_group() const
float * mutable_tile8_source_display_scale()
const gfx::SnesPalette & overworld_palette() const
static constexpr int kTilesPerRow
bool * mutable_show_tile_collision_ids()
Tile16ScratchData & scratch_slot(int i)
absl::Status BuildStampPreview(Tile16LocalPos pos, gfx::Bitmap *output) const
void set_current_palette(int palette)
bool tile8_usage_cache_dirty() const
void set_tile8_usage_cache_dirty(bool dirty)
bool * mutable_highlight_tile8_usage()
gfx::Tile16 & current_tile16_data()
bool * mutable_auto_normalize_pixels()
gfx::Bitmap * current_gfx_bmp()
int current_palette() const
absl::Status RebuildTile8UsageCache()
Tile16EditMode edit_mode() const
int active_quadrant() const
void set_current_tile8(int id)
Tile16LayoutScratch & layout_scratch(int i)
void set_current_page(int page)
bool * mutable_priority_tile()
gfx::Bitmap & mutable_tile8_preview_bitmap()
bool highlight_tile8_usage() const
uint8_t palette_normalization_mask() const
int * mutable_jump_to_tile_id()
bool * mutable_show_palette_settings()
std::vector< zelda3::Tile8PixelData > & mutable_current_gfx_individual()
int jump_to_tile_id() const
bool show_palette_settings() const
const gfx::SnesPalette & palette() const
bool show_tile_collision_ids() const
bool show_tile_grid() const
const gfx::SnesPalette * ResolveDisplayPalette() const
static constexpr int kTilesPerPage
int tile8_stamp_size() const
const zelda3::Tile8UsageIndex & tile8_usage_cache() const
void set_active_quadrant(int quadrant)
gfx::Bitmap & current_tile16_bmp()
void set_edit_mode(Tile16EditMode mode)
absl::Status SaveTile16ToScratchSpace(int slot)
absl::Status LoadLayoutFromScratch(int slot)
static ImVec2 Tile16PreviewDisplayPixelToTilePosition(const ImVec2 &display_position)
absl::Status DrawTile16EditorWorkbenchColumn(bool show_debug_info, bool show_advanced_controls)
absl::Status HandleTile16CanvasClick(const ImVec2 &tile_position, bool left_click, bool right_click)
absl::Status ClearTile16()
void AnalyzeTile8SourceData() const
absl::Status ApplyPaletteToAll(uint8_t palette_id)
int GetActualPaletteSlotForCurrentTile16() const
absl::Status HandleTile8SourceSelection(bool right_clicked, float display_scale)
absl::Status PasteTile16FromClipboard()
gui::TileSelectorWidget blockset_selector_
absl::Status SaveLayoutToScratch(int slot)
absl::Status LoadTile16FromScratchSpace(int slot)
gfx::SnesPalette CreateRemappedPaletteForViewing(const gfx::SnesPalette &source, int target_row) const
int GetActualPaletteSlot(int palette_button, int sheet_index) const
absl::Status FlipTile16Horizontal()
absl::Status UpdateTile16Edit()
absl::Status DrawBrushAndTilePaletteControls(bool show_debug_info)
void DrawTile8UsageOverlay()
gfx::Bitmap stamp_preview_bitmap_
absl::Status DrawTile8SourcePanel(float preferred_height=0.0f)
absl::Status UpdateTile8Palette(int tile8_id)
absl::Status RefreshTile16Blockset()
void DrawManualTile8Inputs()
absl::Status RefreshAllPalettes()
void DrawPaletteSettings()
absl::Status ApplyPaletteToQuadrant(int quadrant, uint8_t palette_id)
absl::Status DrawTile16NavigationHeader(int total_tiles)
absl::Status RotateTile16()
gui::Canvas tile16_edit_canvas_
void DrawOverworldMenuItems()
gui::Canvas blockset_canvas_
gui::Canvas tile8_source_canvas_
gfx::Tile16 * GetCurrentTile16Data()
absl::Status DrawCompactActionStatusRow(bool *show_debug_info, bool *show_advanced_controls)
void RequestTileSwitch(int target_tile_id)
absl::Status ReplaceCurrentTile(const gfx::Tile16 &data, uint64_t edit_group=0)
absl::Status CopyTile16ToClipboard(int tile_id)
absl::Status DrawPrimaryActionControls()
absl::Status ClearScratchSpace(int slot)
int GetSheetIndexForTile8(int tile8_id) const
absl::Status FlipTile16Vertical()
Tile16EditSession session_
uint64_t manual_edit_group_
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
const SnesPalette & palette() const
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
TextureHandle texture() const
void UpdateSurfacePixels()
Update SDL surface with current pixel data from data_ vector Call this after modifying pixel data via...
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
std::vector< uint8_t > & mutable_data()
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
Tile composition of four 8x8 tiles.
SNES 16-bit tile metadata container.
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
void ShowScalingControls()
void ShowAdvancedCanvasProperties()
bool DrawTileSelector(int size, int size_y=0)
auto custom_labels_enabled()
void SetCanvasSize(ImVec2 canvas_size)
void set_draggable(bool draggable)
float GetGlobalScale() const
bool ApplyROMPalette(int group_index, int palette_index)
static void SectionHeader(const char *label)
RAII guard for ImGui style colors.
RAII guard for ImGui style vars.
#define ICON_MD_FORMAT_COLOR_FILL
#define HOVER_HINT(string)
const char * EditModeLabel(Tile16EditMode mode)
float ComputeTile8SourcePanelHeight(float available_height_px, int source_bitmap_height_px, float display_scale, float preferred_height_px=0.0f, float min_height_px=220.0f, float max_height_px=520.0f)
constexpr int kTile8PixelCount
int ComputeTile16CompactActionColumnCount(float available_width_px)
constexpr float kTile8DisplayScale
float ComputeTile16PaletteButtonSize(float available_width_px)
bool ComputeTile8UsageHighlight(bool source_hovered, bool right_mouse_down)
int ComputeTile16ActionRowCount(int action_count, int column_count)
constexpr int kTile16Size
int ComputeTile8IndexFromCanvasMouse(float mouse_x, float mouse_y, int source_bitmap_width_px, int max_tile_count, float display_scale)
float ComputeTile8SourceDisplayScale(float available_width_px, int source_bitmap_width_px, float min_scale=1.0f, float max_scale=4.0f)
void EndCanvas(Canvas &canvas)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
bool ItemContextMenu(const char *id, const std::function< std::vector< MenuItemSpec >()> &build, ImGuiPopupFlags flags)
Right-click menu for the last submitted ImGui item.
ButtonColorSet GetSuccessButtonColors()
MenuItemSpec CopyToClipboardItem(const std::string &label, const std::string &text)
Color GetThemeColor(const std::string &color_name)
void ThemedText(const char *text, SemanticColor color)
ButtonColorSet GetPrimaryButtonColors()
void logf(const absl::FormatSpec< Args... > &format, Args &&... args)
gfx::TileInfo & MutableTile16QuadrantInfo(gfx::Tile16 &tile, int quadrant)
void SyncTile16TilesInfo(gfx::Tile16 *tile)
int ComputeTile16Count(const gfx::Tilemap *tile16_blockset)
const gfx::TileInfo & Tile16QuadrantInfo(const gfx::Tile16 &tile, int quadrant)
constexpr int kMaxTile8UsageId
#define RETURN_IF_ERROR(expr)
std::optional< float > grid_step