From 1432e2c3f96add273dd892db3d0879b924cc1455 Mon Sep 17 00:00:00 2001 From: scawful Date: Mon, 29 Sep 2025 10:34:28 -0400 Subject: [PATCH] Enhance tile selection and editing functionality in OverworldEditor and Tile16Editor - Improved handling of single and double clicks for tile selection and editing in OverworldEditor, allowing for more intuitive user interactions. - Added logging for tile selection actions to aid debugging and user feedback. - Updated Tile16Editor to ensure proper synchronization with the overworld editor during tile changes, enhancing workflow reliability. - Implemented critical fixes in Canvas to prevent ImGui assertions by ensuring minimum canvas size during rendering. --- src/app/editor/overworld/overworld_editor.cc | 20 ++++- src/app/editor/overworld/tile16_editor.cc | 94 +++++++++++++------- src/app/gui/canvas.cc | 6 ++ 3 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/app/editor/overworld/overworld_editor.cc b/src/app/editor/overworld/overworld_editor.cc index 5cebe517..f5078c38 100644 --- a/src/app/editor/overworld/overworld_editor.cc +++ b/src/app/editor/overworld/overworld_editor.cc @@ -1287,10 +1287,17 @@ absl::Status OverworldEditor::DrawTile16Selector() { // First, call DrawTileSelector to handle the visual feedback blockset_canvas_.DrawTileSelector(32.0f); - // Then check for single click to update tile selection - if (ImGui::IsItemClicked(ImGuiMouseButton_Left) && blockset_canvas_.IsMouseHovering()) { + // Handle both single click (select) and double click (edit) properly + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && blockset_canvas_.IsMouseHovering()) { tile_selected = true; } + + // Check for double click to open tile16 editor + bool open_tile16_editor = false; + if (blockset_canvas_.IsMouseHovering() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + tile_selected = true; + open_tile16_editor = true; + } if (tile_selected) { // Get mouse position relative to canvas @@ -1305,8 +1312,15 @@ absl::Status OverworldEditor::DrawTile16Selector() { if (id != current_tile16_ && id >= 0 && id < 512) { current_tile16_ = id; + // CRITICAL FIX: Always sync tile16 editor with overworld editor selection RETURN_IF_ERROR(tile16_editor_.SetCurrentTile(id)); - show_tile16_editor_ = true; + + if (open_tile16_editor) { + show_tile16_editor_ = true; + util::logf("Opened Tile16 editor for tile %d (double-click)", id); + } else { + util::logf("Selected Tile16: %d (single-click)", id); + } } } diff --git a/src/app/editor/overworld/tile16_editor.cc b/src/app/editor/overworld/tile16_editor.cc index 53fc933b..28827ae7 100644 --- a/src/app/editor/overworld/tile16_editor.cc +++ b/src/app/editor/overworld/tile16_editor.cc @@ -53,15 +53,13 @@ absl::Status Tile16Editor::Initialize( current_tile16_bmp_.SetPalette(tile16_blockset_bmp.palette()); core::Renderer::Get().RenderBitmap(¤t_tile16_bmp_); - // Initialize enhanced canvas features + // Initialize enhanced canvas features with proper sizing tile16_edit_canvas_.InitializeDefaults(); tile8_source_canvas_.InitializeDefaults(); - // Configure canvases for table integration - keep fixed sizes but ensure proper content reporting - tile16_edit_canvas_.SetAutoResize( - false); // Keep fixed size for precise editing - tile8_source_canvas_.SetAutoResize( - false); // Keep fixed size for consistent layout + // Configure canvases with proper initialization + tile16_edit_canvas_.SetAutoResize(false); + tile8_source_canvas_.SetAutoResize(false); // Initialize enhanced palette editors if ROM is available if (rom_) { @@ -280,19 +278,33 @@ absl::Status Tile16Editor::UpdateBlockset() { gui::EndPadding(); blockset_canvas_.DrawContextMenu(); - if (blockset_canvas_.DrawTileSelector(32)) { - auto tile_pos = blockset_canvas_.GetLastClickPosition(); - int clicked_x = - static_cast(tile_pos.x / blockset_canvas_.GetGridStep()); - int clicked_y = - static_cast(tile_pos.y / blockset_canvas_.GetGridStep()); - int selected_tile = - clicked_x + (clicked_y * 8); // 8 tiles per row in blockset - if (selected_tile != current_tile16_ && selected_tile >= 0 && - selected_tile < 512) { + + // CRITICAL FIX: Handle single clicks properly like the overworld editor + bool tile_selected = false; + + // First, call DrawTileSelector for visual feedback + blockset_canvas_.DrawTileSelector(32.0f); + + // Then check for single click to update tile selection + if (ImGui::IsItemClicked(ImGuiMouseButton_Left) && blockset_canvas_.IsMouseHovering()) { + tile_selected = true; + } + + if (tile_selected) { + // Get mouse position relative to canvas + const ImGuiIO& io = ImGui::GetIO(); + ImVec2 canvas_pos = blockset_canvas_.zero_point(); + ImVec2 mouse_pos = ImVec2(io.MousePos.x - canvas_pos.x, io.MousePos.y - canvas_pos.y); + + // Calculate grid position (32x32 tiles in blockset) + int grid_x = static_cast(mouse_pos.x / 32); + int grid_y = static_cast(mouse_pos.y / 32); + int selected_tile = grid_x + grid_y * 8; // 8 tiles per row in blockset + + if (selected_tile != current_tile16_ && selected_tile >= 0 && selected_tile < 512) { RETURN_IF_ERROR(SetCurrentTile(selected_tile)); util::logf("Selected Tile16 from blockset: %d (grid: %d,%d)", - selected_tile, clicked_x, clicked_y); + selected_tile, grid_x, grid_y); } } blockset_canvas_.DrawBitmap(tile16_blockset_bmp_, 0, true, 2.0f); @@ -695,7 +707,7 @@ absl::Status Tile16Editor::UpdateTile16Edit() { ImVec2(tile8_source_canvas_.width(), tile8_source_canvas_.height()), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - // Enable dragging for scrolling behavior + // Enable dragging for scrolling behavior tile8_source_canvas_.set_draggable(true); tile8_source_canvas_.DrawBackground(); tile8_source_canvas_.DrawContextMenu(); @@ -735,8 +747,7 @@ absl::Status Tile16Editor::UpdateTile16Edit() { ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { - tile16_edit_canvas_.DrawBackground( - ImVec2(64, 64)); // Fixed 64x64 display size + tile16_edit_canvas_.DrawBackground(ImVec2(64, 64)); tile16_edit_canvas_.DrawContextMenu(); // Draw current tile16 bitmap at 4x scale for clarity (16x16 pixels -> 64x64 display) @@ -1547,21 +1558,44 @@ absl::Status Tile16Editor::CommitChangesToBlockset() { } absl::Status Tile16Editor::CommitChangesToOverworld() { - // Write all tile16 changes to ROM - RETURN_IF_ERROR(SaveTile16ToROM()); + // CRITICAL FIX: Complete workflow for tile16 changes + + // Step 1: Update ROM data with current tile16 changes + RETURN_IF_ERROR(UpdateROMTile16Data()); + + // Step 2: Update the local blockset to reflect changes + RETURN_IF_ERROR(UpdateBlocksetBitmap()); + + // Step 3: Update the atlas directly (bypass problematic tile cache) + if (tile16_blockset_->atlas.is_active()) { + // Calculate the position of this tile in the blockset atlas + constexpr int kTilesPerRow = 8; + int tile_x = (current_tile16_ % kTilesPerRow) * kTile16Size; + int tile_y = (current_tile16_ / kTilesPerRow) * kTile16Size; + + // Copy current tile16 bitmap data directly to atlas + for (int ty = 0; ty < kTile16Size; ++ty) { + for (int tx = 0; tx < kTile16Size; ++tx) { + int src_index = ty * kTile16Size + tx; + int dst_index = (tile_y + ty) * tile16_blockset_->atlas.width() + (tile_x + tx); + + if (src_index < static_cast(current_tile16_bmp_.size()) && + dst_index < static_cast(tile16_blockset_->atlas.size())) { + tile16_blockset_->atlas.WriteToPixel(dst_index, current_tile16_bmp_.data()[src_index]); + } + } + } + + tile16_blockset_->atlas.set_modified(true); + core::Renderer::Get().UpdateBitmap(&tile16_blockset_->atlas); + } - // Regenerate the tile16 blockset to reflect changes - RETURN_IF_ERROR(RefreshTile16Blockset()); - - // Update the overworld tilemap to use the new tile16 data - RETURN_IF_ERROR(UpdateOverworldTilemap()); - - // Notify the parent editor (overworld editor) to regenerate its blockset + // Step 4: Notify the parent editor (overworld editor) to regenerate its blockset if (on_changes_committed_) { RETURN_IF_ERROR(on_changes_committed_()); } - util::logf("Committed all Tile16 changes to overworld system"); + util::logf("Committed Tile16 %d changes to overworld system", current_tile16_); return absl::OkStatus(); } diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index 3c457470..1358d0f4 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -211,6 +211,11 @@ void Canvas::DrawBackground(ImVec2 canvas_size) { // Calculate scaled canvas bounds ImVec2 scaled_size = CanvasUtils::CalculateScaledCanvasSize(canvas_sz_, config_.global_scale); + + // CRITICAL FIX: Ensure minimum size to prevent ImGui assertions + if (scaled_size.x <= 0.0f) scaled_size.x = 1.0f; + if (scaled_size.y <= 0.0f) scaled_size.y = 1.0f; + canvas_p1_ = ImVec2(canvas_p0_.x + scaled_size.x, canvas_p0_.y + scaled_size.y); // Draw border and background color @@ -672,6 +677,7 @@ void Canvas::DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, bool Canvas::DrawTileSelector(int size, int size_y) { const ImGuiIO &io = GetIO(); const bool is_hovered = IsItemHovered(); + is_hovered_ = is_hovered; const ImVec2 origin(canvas_p0_.x + scrolling_.x, canvas_p0_.y + scrolling_.y); const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y); if (size_y == 0) {