973 static bool show_advanced_controls =
false;
974 static bool show_debug_info =
false;
977 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 4));
978 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4));
982 ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f),
"Tile16 Editor");
986 ImGui::TextDisabled(
"|");
993 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f),
"| %d pending",
998 if (show_debug_info) {
1001 ImGui::TextDisabled(
"(Slot: %d)", actual_slot);
1008 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 340);
1009 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.2f, 1.0f));
1010 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1011 ImVec4(0.3f, 0.7f, 0.3f, 1.0f));
1012 if (ImGui::Button(
"Apply All", ImVec2(70, 0))) {
1015 util::logf(
"Failed to commit changes: %s", status.message().data());
1018 ImGui::PopStyleColor(2);
1019 if (ImGui::IsItemHovered()) {
1020 ImGui::SetTooltip(
"Commit all %d pending changes to ROM",
1025 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.2f, 0.2f, 1.0f));
1026 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1027 ImVec4(0.7f, 0.3f, 0.3f, 1.0f));
1028 if (ImGui::Button(
"Discard All", ImVec2(70, 0))) {
1031 ImGui::PopStyleColor(2);
1032 if (ImGui::IsItemHovered()) {
1033 ImGui::SetTooltip(
"Discard all %d pending changes",
1041 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 180);
1042 if (ImGui::Button(
"Debug Info", ImVec2(80, 0))) {
1043 show_debug_info = !show_debug_info;
1046 if (ImGui::Button(
"Advanced", ImVec2(80, 0))) {
1047 show_advanced_controls = !show_advanced_controls;
1050 ImGui::PopStyleVar(2);
1055 if (ImGui::BeginTable(
"##Tile16EditLayout", 3,
1056 ImGuiTableFlags_Resizable |
1057 ImGuiTableFlags_BordersInnerV |
1058 ImGuiTableFlags_SizingStretchProp)) {
1059 ImGui::TableSetupColumn(
"Tile16 Blockset",
1060 ImGuiTableColumnFlags_WidthStretch, 0.35f);
1061 ImGui::TableSetupColumn(
"Tile8 Source", ImGuiTableColumnFlags_WidthStretch,
1063 ImGui::TableSetupColumn(
"Editor & Controls",
1064 ImGuiTableColumnFlags_WidthStretch, 0.30f);
1066 ImGui::TableHeadersRow();
1067 ImGui::TableNextRow();
1070 ImGui::TableNextColumn();
1071 ImGui::BeginGroup();
1074 ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.9f, 1.0f),
"Tile16 Blockset");
1080 if (total_tiles == 0)
1085 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
1088 ImGui::SetNextItemWidth(80);
1097 if (ImGui::IsItemHovered()) {
1098 ImGui::SetTooltip(
"Tile ID (0-%d) - navigates as you type",
1103 ImGui::TextDisabled(
"|");
1110 if (ImGui::Button(
"<<")) {
1114 if (ImGui::IsItemHovered())
1115 ImGui::SetTooltip(
"First page");
1118 if (ImGui::Button(
"<")) {
1123 if (ImGui::IsItemHovered())
1124 ImGui::SetTooltip(
"Previous page (PageUp)");
1127 ImGui::TextDisabled(
"Page %d/%d",
current_page_ + 1, total_pages);
1130 if (ImGui::Button(
">")) {
1135 if (ImGui::IsItemHovered())
1136 ImGui::SetTooltip(
"Next page (PageDown)");
1139 if (ImGui::Button(
">>")) {
1143 if (ImGui::IsItemHovered())
1144 ImGui::SetTooltip(
"Last page");
1148 ImGui::TextDisabled(
"|");
1154 if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
1155 if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
1160 if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
1166 if (ImGui::IsKeyPressed(ImGuiKey_Home)) {
1170 if (ImGui::IsKeyPressed(ImGuiKey_End)) {
1176 if (!ImGui::GetIO().KeyCtrl) {
1177 if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
1183 if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
1189 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
1195 if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
1204 ImGui::PopStyleVar();
1207 if (BeginChild(
"##BlocksetScrollable",
1208 ImVec2(0, ImGui::GetContentRegionAvail().y),
true,
1209 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1214 ImGui::SetScrollY(tile_y);
1231 bool tile_selected =
false;
1234 if (ImGui::IsItemClicked(ImGuiMouseButton_Left) &&
1236 tile_selected =
true;
1239 if (tile_selected) {
1240 const ImGuiIO& io = ImGui::GetIO();
1243 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
1245 int grid_x =
static_cast<int>(mouse_pos.x /
1247 int grid_y =
static_cast<int>(mouse_pos.y /
1249 int selected_tile = grid_x + grid_y * 8;
1254 util::logf(
"Selected Tile16 from blockset: %d", selected_tile);
1266 ImGui::TableNextColumn();
1267 ImGui::BeginGroup();
1269 ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.9f, 1.0f),
"Tile8 Source");
1274 if (BeginChild(
"##Tile8SourceScrollable", ImVec2(0, 0),
true,
1275 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1288 bool tile8_selected =
false;
1292 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
1293 tile8_selected =
true;
1296 if (tile8_selected) {
1297 const ImGuiIO& io = ImGui::GetIO();
1300 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
1303 int tile_x =
static_cast<int>(
1309 int new_tile8 = tile_x + (tile_y * tiles_per_row);
1330 ImGui::BeginGroup();
1333 if (ImGui::BeginChild(
"##Tile16FixedCanvas", ImVec2(90, 90),
true,
1334 ImGuiWindowFlags_NoScrollbar |
1335 ImGuiWindowFlags_NoScrollWithMouse)) {
1338 tile16_edit_frame_opts.
canvas_size = ImVec2(64, 64);
1339 tile16_edit_frame_opts.
draw_grid =
true;
1340 tile16_edit_frame_opts.
grid_step = 8.0f;
1346 auto tile16_edit_rt =
1379 if (display_palette && !display_palette->
empty()) {
1389 if (palette_slot >= 0 &&
static_cast<size_t>(palette_slot + 16) <=
1390 display_palette->
size()) {
1392 *display_palette,
static_cast<size_t>(palette_slot + 1), 15);
1407 for (
int y = 0; y < 8; ++y) {
1408 for (
int x = 0; x < 4; ++x) {
1409 std::swap(data[y * 8 + x], data[y * 8 + (7 - x)]);
1415 for (
int y = 0; y < 4; ++y) {
1416 for (
int x = 0; x < 8; ++x) {
1417 std::swap(data[y * 8 + x], data[(7 - y) * 8 + x]);
1428 const auto preview_command =
1441 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
1442 const ImGuiIO& io = ImGui::GetIO();
1444 ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x,
1445 io.MousePos.y - canvas_pos.y);
1449 constexpr float kBitmapOffset = 2.0f;
1450 constexpr float kBitmapScale = 4.0f;
1452 static_cast<int>((mouse_pos.x - kBitmapOffset) / kBitmapScale);
1454 static_cast<int>((mouse_pos.y - kBitmapOffset) / kBitmapScale);
1457 tile_x = std::max(0, std::min(15, tile_x));
1458 tile_y = std::max(0, std::min(15, tile_y));
1460 util::logf(
"Tile16 canvas click: (%.2f, %.2f) -> Tile16: (%d, %d)",
1461 mouse_pos.x, mouse_pos.y, tile_x, tile_y);
1470 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
1471 const ImGuiIO& io = ImGui::GetIO();
1473 ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x,
1474 io.MousePos.y - canvas_pos.y);
1478 constexpr float kBitmapOffset = 2.0f;
1479 constexpr float kBitmapScale = 4.0f;
1481 static_cast<int>((mouse_pos.x - kBitmapOffset) / kBitmapScale);
1483 static_cast<int>((mouse_pos.y - kBitmapOffset) / kBitmapScale);
1486 tile_x = std::max(0, std::min(15, tile_x));
1487 tile_y = std::max(0, std::min(15, tile_y));
1490 util::logf(
"Right-clicked to pick tile8 from tile16 at (%d, %d)",
1496 tile16_edit_frame_opts);
1511 if (tile8_texture) {
1512 ImGui::Image((ImTextureID)(intptr_t)tile8_texture, ImVec2(24, 24));
1518 int encoded_row = -1;
1523 switch (sheet_idx) {
1537 ImGui::TextDisabled(
"S%d", sheet_idx);
1538 if (ImGui::IsItemHovered()) {
1539 ImGui::BeginTooltip();
1540 ImGui::Text(
"Sheet: %d", sheet_idx);
1541 ImGui::Text(
"Encoded Palette Row: %d", encoded_row);
1544 "Graphics sheets have different palette encodings:\n"
1545 "- Sheets 0,3,4,5: Row 8 (offset 0x88)\n"
1546 "- Sheets 1,2,6,7: Row 0 (raw)");
1547 ImGui::EndTooltip();
1552 Checkbox(
"X Flip", &
x_flip);
1554 Checkbox(
"Y Flip", &
y_flip);
1562 if (show_debug_info) {
1565 ImGui::TextDisabled(
"(Slot %d)", actual_slot);
1569 ImGui::BeginGroup();
1570 float available_width = ImGui::GetContentRegionAvail().x;
1571 float button_size = std::min(32.0f, (available_width - 16.0f) / 4.0f);
1573 for (
int row = 0; row < 2; ++row) {
1574 for (
int col = 0; col < 4; ++col) {
1578 int i = row * 4 + col;
1585 ImGui::PushStyleColor(ImGuiCol_Button,
1586 ImVec4(0.2f, 0.7f, 0.3f, 1.0f));
1587 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1588 ImVec4(0.3f, 0.8f, 0.4f, 1.0f));
1589 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
1590 ImVec4(0.1f, 0.6f, 0.2f, 1.0f));
1592 ImGui::PushStyleColor(ImGuiCol_Button,
1593 ImVec4(0.3f, 0.3f, 0.35f, 1.0f));
1594 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1595 ImVec4(0.4f, 0.4f, 0.45f, 1.0f));
1596 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
1597 ImVec4(0.25f, 0.25f, 0.3f, 1.0f));
1601 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
1602 ImGui::PushStyleColor(ImGuiCol_Border,
1603 is_current ? ImVec4(0.4f, 0.9f, 0.5f, 1.0f)
1604 : ImVec4(0.5f, 0.5f, 0.5f, 0.3f));
1606 if (ImGui::Button(absl::StrFormat(
"%d", i).c_str(),
1607 ImVec2(button_size, button_size))) {
1613 status.message().data());
1615 util::logf(
"Palette successfully changed to %d",
1621 ImGui::PopStyleColor(4);
1622 ImGui::PopStyleVar(1);
1626 if (ImGui::IsItemHovered()) {
1627 ImGui::BeginTooltip();
1628 if (show_debug_info) {
1629 ImGui::Text(
"Palette %d → Slots:", i);
1635 ImGui::Text(
"Palette %d", i);
1637 ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f),
"Active");
1640 ImGui::EndTooltip();
1649 if (Button(
"Clear", ImVec2(-1, 0))) {
1653 if (Button(
"Copy", ImVec2(-1, 0))) {
1657 if (Button(
"Paste", ImVec2(-1, 0))) {
1664 if (Button(
"Save Changes", ImVec2(-1, 0))) {
1667 HOVER_HINT(
"Apply changes to overworld and regenerate blockset");
1669 if (Button(
"Discard Changes", ImVec2(-1, 0))) {
1672 HOVER_HINT(
"Reload tile16 from ROM, discarding local changes");
1679 if (Button(
"Undo", ImVec2(-1, 0))) {
1686 if (show_advanced_controls) {
1690 if (Button(
"Palette Settings", ImVec2(-1, 0))) {
1694 if (Button(
"Analyze Data", ImVec2(-1, 0))) {
1697 HOVER_HINT(
"Analyze tile8 source data format and palette state");
1699 if (Button(
"Manual Edit", ImVec2(-1, 0))) {
1700 ImGui::OpenPopup(
"ManualTile8Editor");
1703 if (Button(
"Refresh Blockset", ImVec2(-1, 0))) {
1716 if (show_debug_info) {
1725 ImGui::TextDisabled(
"Sheet:%d Slot:%d", sheet_index, actual_slot);
1729 if (ImGui::CollapsingHeader(
"Palette Map",
1730 ImGuiTreeNodeFlags_DefaultOpen)) {
1731 ImGui::BeginChild(
"##PaletteMappingScroll", ImVec2(0, 120),
true);
1732 if (ImGui::BeginTable(
"##PalMap", 3,
1733 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
1734 ImGuiTableFlags_SizingFixedFit)) {
1735 ImGui::TableSetupColumn(
"Btn", ImGuiTableColumnFlags_WidthFixed, 30);
1736 ImGui::TableSetupColumn(
"S0,3-4", ImGuiTableColumnFlags_WidthFixed,
1738 ImGui::TableSetupColumn(
"S1-2", ImGuiTableColumnFlags_WidthFixed, 50);
1739 ImGui::TableHeadersRow();
1741 for (
int i = 0; i < 8; ++i) {
1742 ImGui::TableNextRow();
1743 ImGui::TableNextColumn();
1744 ImGui::Text(
"%d", i);
1745 ImGui::TableNextColumn();
1747 ImGui::TableNextColumn();
1756 if (ImGui::CollapsingHeader(
"Colors")) {
1759 ImGui::Text(
"Slot %d:", actual_slot);
1765 int color_index = actual_slot + i;
1767 ImVec4 display_color = color.rgb();
1769 ImGui::ColorButton(absl::StrFormat(
"##c%d", i).c_str(),
1770 display_color, ImGuiColorEditFlags_NoTooltip,
1772 if (ImGui::IsItemHovered()) {
1773 ImGui::SetTooltip(
"%d:0x%04X", color_index, color.snes());
1776 if ((i + 1) % 4 != 0)
1798 return absl::OkStatus();