969 static bool show_advanced_controls =
false;
970 static bool show_debug_info =
false;
973 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 4));
974 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4));
978 ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f),
"Tile16 Editor");
982 ImGui::TextDisabled(
"|");
989 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f),
"| %d pending",
994 if (show_debug_info) {
997 ImGui::TextDisabled(
"(Slot: %d)", actual_slot);
1004 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 340);
1005 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.2f, 1.0f));
1006 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.7f, 0.3f, 1.0f));
1007 if (ImGui::Button(
"Apply All", ImVec2(70, 0))) {
1010 util::logf(
"Failed to commit changes: %s", status.message().data());
1013 ImGui::PopStyleColor(2);
1014 if (ImGui::IsItemHovered()) {
1015 ImGui::SetTooltip(
"Commit all %d pending changes to ROM",
1020 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.6f, 0.2f, 0.2f, 1.0f));
1021 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.7f, 0.3f, 0.3f, 1.0f));
1022 if (ImGui::Button(
"Discard All", ImVec2(70, 0))) {
1025 ImGui::PopStyleColor(2);
1026 if (ImGui::IsItemHovered()) {
1034 ImGui::SameLine(ImGui::GetContentRegionAvail().x - 180);
1035 if (ImGui::Button(
"Debug Info", ImVec2(80, 0))) {
1036 show_debug_info = !show_debug_info;
1039 if (ImGui::Button(
"Advanced", ImVec2(80, 0))) {
1040 show_advanced_controls = !show_advanced_controls;
1043 ImGui::PopStyleVar(2);
1048 if (ImGui::BeginTable(
"##Tile16EditLayout", 3,
1049 ImGuiTableFlags_Resizable |
1050 ImGuiTableFlags_BordersInnerV |
1051 ImGuiTableFlags_SizingStretchProp)) {
1052 ImGui::TableSetupColumn(
"Tile16 Blockset",
1053 ImGuiTableColumnFlags_WidthStretch, 0.35f);
1054 ImGui::TableSetupColumn(
"Tile8 Source", ImGuiTableColumnFlags_WidthStretch,
1056 ImGui::TableSetupColumn(
"Editor & Controls",
1057 ImGuiTableColumnFlags_WidthStretch, 0.30f);
1059 ImGui::TableHeadersRow();
1060 ImGui::TableNextRow();
1063 ImGui::TableNextColumn();
1064 ImGui::BeginGroup();
1067 ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.9f, 1.0f),
"Tile16 Blockset");
1076 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
1079 ImGui::SetNextItemWidth(80);
1088 if (ImGui::IsItemHovered()) {
1089 ImGui::SetTooltip(
"Tile ID (0-%d) - navigates as you type", total_tiles - 1);
1093 ImGui::TextDisabled(
"|");
1100 if (ImGui::Button(
"<<")) {
1104 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"First page");
1107 if (ImGui::Button(
"<")) {
1112 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"Previous page (PageUp)");
1115 ImGui::TextDisabled(
"Page %d/%d",
current_page_ + 1, total_pages);
1118 if (ImGui::Button(
">")) {
1123 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"Next page (PageDown)");
1126 if (ImGui::Button(
">>")) {
1130 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"Last page");
1134 ImGui::TextDisabled(
"|");
1140 if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
1141 if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
1146 if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
1151 if (ImGui::IsKeyPressed(ImGuiKey_Home)) {
1155 if (ImGui::IsKeyPressed(ImGuiKey_End)) {
1161 if (!ImGui::GetIO().KeyCtrl) {
1162 if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
1168 if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
1174 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
1180 if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
1189 ImGui::PopStyleVar();
1192 if (BeginChild(
"##BlocksetScrollable",
1193 ImVec2(0, ImGui::GetContentRegionAvail().y),
true,
1194 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1199 ImGui::SetScrollY(tile_y);
1215 bool tile_selected =
false;
1218 if (ImGui::IsItemClicked(ImGuiMouseButton_Left) &&
1220 tile_selected =
true;
1223 if (tile_selected) {
1224 const ImGuiIO& io = ImGui::GetIO();
1227 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
1229 int grid_x =
static_cast<int>(mouse_pos.x /
1231 int grid_y =
static_cast<int>(mouse_pos.y /
1233 int selected_tile = grid_x + grid_y * 8;
1238 util::logf(
"Selected Tile16 from blockset: %d", selected_tile);
1250 ImGui::TableNextColumn();
1251 ImGui::BeginGroup();
1253 ImGui::TextColored(ImVec4(0.9f, 0.9f, 0.9f, 1.0f),
"Tile8 Source");
1258 if (BeginChild(
"##Tile8SourceScrollable", ImVec2(0, 0),
true,
1259 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
1272 bool tile8_selected =
false;
1276 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
1277 tile8_selected =
true;
1280 if (tile8_selected) {
1281 const ImGuiIO& io = ImGui::GetIO();
1284 ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y);
1287 int tile_x =
static_cast<int>(
1294 int new_tile8 = tile_x + (tile_y * tiles_per_row);
1315 ImGui::BeginGroup();
1318 if (ImGui::BeginChild(
"##Tile16FixedCanvas", ImVec2(90, 90),
true,
1319 ImGuiWindowFlags_NoScrollbar |
1320 ImGuiWindowFlags_NoScrollWithMouse)) {
1323 tile16_edit_frame_opts.
canvas_size = ImVec2(64, 64);
1324 tile16_edit_frame_opts.
draw_grid =
true;
1325 tile16_edit_frame_opts.
grid_step = 8.0f;
1363 if (display_palette && !display_palette->
empty()) {
1371 if (palette_slot >= 0 &&
1372 static_cast<size_t>(palette_slot + 16) <= display_palette->
size()) {
1374 *display_palette,
static_cast<size_t>(palette_slot + 1), 15);
1385 for (
int y = 0; y < 8; ++y) {
1386 for (
int x = 0; x < 4; ++x) {
1387 std::swap(data[y * 8 + x], data[y * 8 + (7 - x)]);
1393 for (
int y = 0; y < 4; ++y) {
1394 for (
int x = 0; x < 8; ++x) {
1395 std::swap(data[y * 8 + x], data[(7 - y) * 8 + x]);
1406 const auto preview_command =
1419 if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
1420 const ImGuiIO& io = ImGui::GetIO();
1422 ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x,
1423 io.MousePos.y - canvas_pos.y);
1427 constexpr float kBitmapOffset = 2.0f;
1428 constexpr float kBitmapScale = 4.0f;
1429 int tile_x =
static_cast<int>((mouse_pos.x - kBitmapOffset) / kBitmapScale);
1430 int tile_y =
static_cast<int>((mouse_pos.y - kBitmapOffset) / kBitmapScale);
1433 tile_x = std::max(0, std::min(15, tile_x));
1434 tile_y = std::max(0, std::min(15, tile_y));
1436 util::logf(
"Tile16 canvas click: (%.2f, %.2f) -> Tile16: (%d, %d)",
1437 mouse_pos.x, mouse_pos.y, tile_x, tile_y);
1446 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
1447 const ImGuiIO& io = ImGui::GetIO();
1449 ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x,
1450 io.MousePos.y - canvas_pos.y);
1454 constexpr float kBitmapOffset = 2.0f;
1455 constexpr float kBitmapScale = 4.0f;
1456 int tile_x =
static_cast<int>((mouse_pos.x - kBitmapOffset) / kBitmapScale);
1457 int tile_y =
static_cast<int>((mouse_pos.y - kBitmapOffset) / kBitmapScale);
1460 tile_x = std::max(0, std::min(15, tile_x));
1461 tile_y = std::max(0, std::min(15, tile_y));
1464 util::logf(
"Right-clicked to pick tile8 from tile16 at (%d, %d)",
1484 if (tile8_texture) {
1485 ImGui::Image((ImTextureID)(intptr_t)tile8_texture, ImVec2(24, 24));
1491 int encoded_row = -1;
1496 switch (sheet_idx) {
1510 ImGui::TextDisabled(
"S%d", sheet_idx);
1511 if (ImGui::IsItemHovered()) {
1512 ImGui::BeginTooltip();
1513 ImGui::Text(
"Sheet: %d", sheet_idx);
1514 ImGui::Text(
"Encoded Palette Row: %d", encoded_row);
1517 "Graphics sheets have different palette encodings:\n"
1518 "- Sheets 0,3,4,5: Row 8 (offset 0x88)\n"
1519 "- Sheets 1,2,6,7: Row 0 (raw)");
1520 ImGui::EndTooltip();
1525 Checkbox(
"X Flip", &
x_flip);
1527 Checkbox(
"Y Flip", &
y_flip);
1535 if (show_debug_info) {
1538 ImGui::TextDisabled(
"(Slot %d)", actual_slot);
1542 ImGui::BeginGroup();
1543 float available_width = ImGui::GetContentRegionAvail().x;
1544 float button_size = std::min(32.0f, (available_width - 16.0f) / 4.0f);
1546 for (
int row = 0; row < 2; ++row) {
1547 for (
int col = 0; col < 4; ++col) {
1551 int i = row * 4 + col;
1558 ImGui::PushStyleColor(ImGuiCol_Button,
1559 ImVec4(0.2f, 0.7f, 0.3f, 1.0f));
1560 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1561 ImVec4(0.3f, 0.8f, 0.4f, 1.0f));
1562 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
1563 ImVec4(0.1f, 0.6f, 0.2f, 1.0f));
1565 ImGui::PushStyleColor(ImGuiCol_Button,
1566 ImVec4(0.3f, 0.3f, 0.35f, 1.0f));
1567 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
1568 ImVec4(0.4f, 0.4f, 0.45f, 1.0f));
1569 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
1570 ImVec4(0.25f, 0.25f, 0.3f, 1.0f));
1574 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
1575 ImGui::PushStyleColor(ImGuiCol_Border,
1576 is_current ? ImVec4(0.4f, 0.9f, 0.5f, 1.0f)
1577 : ImVec4(0.5f, 0.5f, 0.5f, 0.3f));
1579 if (ImGui::Button(absl::StrFormat(
"%d", i).c_str(),
1580 ImVec2(button_size, button_size))) {
1586 status.message().data());
1588 util::logf(
"Palette successfully changed to %d",
1594 ImGui::PopStyleColor(4);
1595 ImGui::PopStyleVar(1);
1599 if (ImGui::IsItemHovered()) {
1600 ImGui::BeginTooltip();
1601 if (show_debug_info) {
1602 ImGui::Text(
"Palette %d → Slots:", i);
1608 ImGui::Text(
"Palette %d", i);
1610 ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f),
"Active");
1613 ImGui::EndTooltip();
1622 if (Button(
"Clear", ImVec2(-1, 0))) {
1626 if (Button(
"Copy", ImVec2(-1, 0))) {
1630 if (Button(
"Paste", ImVec2(-1, 0))) {
1637 if (Button(
"Save Changes", ImVec2(-1, 0))) {
1640 HOVER_HINT(
"Apply changes to overworld and regenerate blockset");
1642 if (Button(
"Discard Changes", ImVec2(-1, 0))) {
1645 HOVER_HINT(
"Reload tile16 from ROM, discarding local changes");
1652 if (Button(
"Undo", ImVec2(-1, 0))) {
1659 if (show_advanced_controls) {
1663 if (Button(
"Palette Settings", ImVec2(-1, 0))) {
1667 if (Button(
"Analyze Data", ImVec2(-1, 0))) {
1670 HOVER_HINT(
"Analyze tile8 source data format and palette state");
1672 if (Button(
"Manual Edit", ImVec2(-1, 0))) {
1673 ImGui::OpenPopup(
"ManualTile8Editor");
1676 if (Button(
"Refresh Blockset", ImVec2(-1, 0))) {
1689 if (show_debug_info) {
1698 ImGui::TextDisabled(
"Sheet:%d Slot:%d", sheet_index, actual_slot);
1702 if (ImGui::CollapsingHeader(
"Palette Map",
1703 ImGuiTreeNodeFlags_DefaultOpen)) {
1704 ImGui::BeginChild(
"##PaletteMappingScroll", ImVec2(0, 120),
true);
1705 if (ImGui::BeginTable(
"##PalMap", 3,
1706 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
1707 ImGuiTableFlags_SizingFixedFit)) {
1708 ImGui::TableSetupColumn(
"Btn", ImGuiTableColumnFlags_WidthFixed, 30);
1709 ImGui::TableSetupColumn(
"S0,3-4", ImGuiTableColumnFlags_WidthFixed,
1711 ImGui::TableSetupColumn(
"S1-2", ImGuiTableColumnFlags_WidthFixed, 50);
1712 ImGui::TableHeadersRow();
1714 for (
int i = 0; i < 8; ++i) {
1715 ImGui::TableNextRow();
1716 ImGui::TableNextColumn();
1717 ImGui::Text(
"%d", i);
1718 ImGui::TableNextColumn();
1720 ImGui::TableNextColumn();
1729 if (ImGui::CollapsingHeader(
"Colors")) {
1732 ImGui::Text(
"Slot %d:", actual_slot);
1738 int color_index = actual_slot + i;
1740 ImVec4 display_color = color.rgb();
1742 ImGui::ColorButton(absl::StrFormat(
"##c%d", i).c_str(),
1743 display_color, ImGuiColorEditFlags_NoTooltip,
1745 if (ImGui::IsItemHovered()) {
1746 ImGui::SetTooltip(
"%d:0x%04X", color_index, color.snes());
1749 if ((i + 1) % 4 != 0)
1771 return absl::OkStatus();