refactor: Migrate DungeonEditor to V2 and update related components

- Replaced the deprecated DungeonEditor with DungeonEditorV2, implementing a card-based architecture for improved UI management.
- Updated CMakeLists.txt to reflect changes in source file organization, including renaming dungeon_editor files to their V2 counterparts.
- Refactored DungeonCanvasViewer to support per-room layer visibility settings and updated related methods for rendering and layer management.
- Enhanced testing framework to accommodate the new DungeonEditorV2 structure, including updates to smoke tests and integration tests.
- Removed legacy dungeon_editor files to streamline the codebase and prevent confusion with the new implementation.
This commit is contained in:
scawful
2025-10-09 18:00:27 -04:00
parent 9675050b78
commit 418695188a
15 changed files with 242 additions and 1627 deletions

View File

@@ -5,7 +5,6 @@
#include "app/gfx/snes_palette.h"
#include "app/gui/input.h"
#include "app/rom.h"
#include "app/zelda3/dungeon/object_renderer.h"
#include "app/zelda3/dungeon/room.h"
#include "app/zelda3/sprite/sprite.h"
#include "imgui/imgui.h"
@@ -13,7 +12,6 @@
namespace yaze::editor {
using ImGui::Button;
using ImGui::Separator;
void DungeonCanvasViewer::DrawDungeonTabView() {
@@ -59,7 +57,7 @@ void DungeonCanvasViewer::Draw(int room_id) {
void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) {
// Validate room_id and ROM
if (room_id < 0 || room_id >= 128) {
if (room_id < 0 || room_id >= 0x128) {
ImGui::Text("Invalid room ID: %d", room_id);
return;
}
@@ -94,12 +92,13 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) {
ImGui::SameLine();
gui::InputHexWord("Message ID", &room.message_id_);
// Layer visibility controls
// Per-room layer visibility controls
ImGui::Separator();
ImGui::Text("Layer Controls:");
ImGui::Checkbox("Show BG1", &bg1_visible_);
ImGui::Text("Layer Controls (Per-Room):");
auto& layer_settings = GetRoomLayerSettings(room_id);
ImGui::Checkbox("Show BG1", &layer_settings.bg1_visible);
ImGui::SameLine();
ImGui::Checkbox("Show BG2", &bg2_visible_);
ImGui::Checkbox("Show BG2", &layer_settings.bg2_visible);
// BG2 layer type dropdown
const char* bg2_layer_types[] = {
@@ -107,7 +106,7 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) {
};
const int bg2_alpha_values[] = {255, 191, 127, 64, 0};
if (ImGui::Combo("BG2 Layer Type", &bg2_layer_type_, bg2_layer_types,
if (ImGui::Combo("BG2 Layer Type", &layer_settings.bg2_layer_type, bg2_layer_types,
sizeof(bg2_layer_types) / sizeof(bg2_layer_types[0]))) {
// BG2 layer type changed, no need to reload graphics
}
@@ -122,8 +121,8 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) {
room.LoadRoomGraphics(room.blockset);
room.RenderRoomGraphics();
// Update background layers
UpdateRoomBackgroundLayers(room_id);
// Render palettes to graphics sheets
RenderGraphicsSheetPalettes(room_id);
}
prev_blockset = room.blockset;
@@ -163,9 +162,9 @@ void DungeonCanvasViewer::DrawDungeonCanvas(int room_id) {
room.LoadObjects();
}
// Render the room's background layers
// This already includes objects drawn by ObjectDrawer in Room::RenderObjectsToBackground()
RenderRoomBackgroundLayers(room_id);
// Draw the room's background layers to canvas
// This already includes objects rendered by ObjectDrawer in Room::RenderObjectsToBackground()
DrawRoomBackgroundLayers(room_id);
// Render sprites as simple 16x16 squares with labels
// (Sprites are not part of the background buffers)
@@ -385,15 +384,15 @@ absl::Status DungeonCanvasViewer::LoadAndRenderRoomGraphics(int room_id) {
LOG_DEBUG("[LoadAndRender]", "RenderRoomGraphics() complete");
// Update the background layers with proper palette
LOG_DEBUG("[LoadAndRender]", "Updating background layers...");
RETURN_IF_ERROR(UpdateRoomBackgroundLayers(room_id));
LOG_DEBUG("[LoadAndRender]", "UpdateRoomBackgroundLayers() complete");
LOG_DEBUG("[LoadAndRender]", "Rendering palettes to graphics sheets...");
RETURN_IF_ERROR(RenderGraphicsSheetPalettes(room_id));
LOG_DEBUG("[LoadAndRender]", "RenderGraphicsSheetPalettes() complete");
LOG_DEBUG("[LoadAndRender]", "SUCCESS");
return absl::OkStatus();
}
absl::Status DungeonCanvasViewer::UpdateRoomBackgroundLayers(int room_id) {
absl::Status DungeonCanvasViewer::RenderGraphicsSheetPalettes(int room_id) {
if (room_id < 0 || room_id >= 128) {
return absl::InvalidArgumentError("Invalid room ID");
}
@@ -454,17 +453,18 @@ absl::Status DungeonCanvasViewer::UpdateRoomBackgroundLayers(int room_id) {
return absl::OkStatus();
}
void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) {
void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) {
if (room_id < 0 || room_id >= 128 || !rooms_) return;
auto& room = (*rooms_)[room_id];
auto& layer_settings = GetRoomLayerSettings(room_id);
// Use THIS room's own buffers, not global arena!
auto& bg1_bitmap = room.bg1_buffer().bitmap();
auto& bg2_bitmap = room.bg2_buffer().bitmap();
// Draw BG1 layer if visible and active
if (bg1_visible_ && bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) {
if (layer_settings.bg1_visible && bg1_bitmap.is_active() && bg1_bitmap.width() > 0 && bg1_bitmap.height() > 0) {
if (!bg1_bitmap.texture()) {
// Queue texture creation for background layer 1 via Arena's deferred system
gfx::Arena::Get().QueueTextureCommand(
@@ -484,7 +484,7 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) {
}
// Draw BG2 layer if visible and active
if (bg2_visible_ && bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) {
if (layer_settings.bg2_visible && bg2_bitmap.is_active() && bg2_bitmap.width() > 0 && bg2_bitmap.height() > 0) {
if (!bg2_bitmap.texture()) {
// Queue texture creation for background layer 2 via Arena's deferred system
gfx::Arena::Get().QueueTextureCommand(
@@ -498,7 +498,7 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) {
if (bg2_bitmap.texture()) {
// Use the selected BG2 layer type alpha value
const int bg2_alpha_values[] = {255, 191, 127, 64, 0};
int alpha_value = bg2_alpha_values[std::min(bg2_layer_type_, 4)];
int alpha_value = bg2_alpha_values[std::min(layer_settings.bg2_layer_type, 4)];
LOG_DEBUG("DungeonCanvasViewer", "Drawing BG2 bitmap to canvas with texture %p, alpha=%d", bg2_bitmap.texture(), alpha_value);
canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, alpha_value);
} else {
@@ -509,7 +509,7 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) {
// DEBUG: Check if background buffers have content
if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0) {
LOG_DEBUG("DungeonCanvasViewer", "BG1 bitmap: %dx%d, active=%d, visible=%d, texture=%p",
bg1_bitmap.width(), bg1_bitmap.height(), bg1_bitmap.is_active(), bg1_visible_, bg1_bitmap.texture());
bg1_bitmap.width(), bg1_bitmap.height(), bg1_bitmap.is_active(), layer_settings.bg1_visible, bg1_bitmap.texture());
// Check bitmap data content
auto& bg1_data = bg1_bitmap.mutable_data();
@@ -522,7 +522,7 @@ void DungeonCanvasViewer::RenderRoomBackgroundLayers(int room_id) {
}
if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0) {
LOG_DEBUG("DungeonCanvasViewer", "BG2 bitmap: %dx%d, active=%d, visible=%d, layer_type=%d, texture=%p",
bg2_bitmap.width(), bg2_bitmap.height(), bg2_bitmap.is_active(), bg2_visible_, bg2_layer_type_, bg2_bitmap.texture());
bg2_bitmap.width(), bg2_bitmap.height(), bg2_bitmap.is_active(), layer_settings.bg2_visible, layer_settings.bg2_layer_type, bg2_bitmap.texture());
// Check bitmap data content
auto& bg2_data = bg2_bitmap.mutable_data();

View File

@@ -1,6 +1,8 @@
#ifndef YAZE_APP_EDITOR_DUNGEON_DUNGEON_CANVAS_VIEWER_H
#define YAZE_APP_EDITOR_DUNGEON_DUNGEON_CANVAS_VIEWER_H
#include <map>
#include "app/gui/canvas.h"
#include "app/rom.h"
#include "app/zelda3/dungeon/object_renderer.h"
@@ -56,15 +58,30 @@ class DungeonCanvasViewer {
void SetObjectInteractionEnabled(bool enabled) { object_interaction_enabled_ = enabled; }
bool IsObjectInteractionEnabled() const { return object_interaction_enabled_; }
// Layer visibility controls
void SetBG1Visible(bool visible) { bg1_visible_ = visible; }
void SetBG2Visible(bool visible) { bg2_visible_ = visible; }
bool IsBG1Visible() const { return bg1_visible_; }
bool IsBG2Visible() const { return bg2_visible_; }
// Layer visibility controls (per-room)
void SetBG1Visible(int room_id, bool visible) {
GetRoomLayerSettings(room_id).bg1_visible = visible;
}
void SetBG2Visible(int room_id, bool visible) {
GetRoomLayerSettings(room_id).bg2_visible = visible;
}
bool IsBG1Visible(int room_id) const {
auto it = room_layer_settings_.find(room_id);
return it != room_layer_settings_.end() ? it->second.bg1_visible : true;
}
bool IsBG2Visible(int room_id) const {
auto it = room_layer_settings_.find(room_id);
return it != room_layer_settings_.end() ? it->second.bg2_visible : true;
}
// BG2 layer type controls
void SetBG2LayerType(int type) { bg2_layer_type_ = type; }
int GetBG2LayerType() const { return bg2_layer_type_; }
// BG2 layer type controls (per-room)
void SetBG2LayerType(int room_id, int type) {
GetRoomLayerSettings(room_id).bg2_layer_type = type;
}
int GetBG2LayerType(int room_id) const {
auto it = room_layer_settings_.find(room_id);
return it != room_layer_settings_.end() ? it->second.bg2_layer_type : 0;
}
// Set the object to be placed
void SetPreviewObject(const zelda3::RoomObject& object) {
@@ -88,9 +105,10 @@ class DungeonCanvasViewer {
void CalculateWallDimensions(const zelda3::RoomObject& object, int& width, int& height);
// Room graphics management
// Load: Read from ROM, Render: Process pixels, Draw: Display on canvas
absl::Status LoadAndRenderRoomGraphics(int room_id);
absl::Status UpdateRoomBackgroundLayers(int room_id);
void RenderRoomBackgroundLayers(int room_id);
absl::Status RenderGraphicsSheetPalettes(int room_id); // Renamed from UpdateRoomBackgroundLayers
void DrawRoomBackgroundLayers(int room_id); // Renamed from RenderRoomBackgroundLayers
Rom* rom_ = nullptr;
gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
@@ -105,10 +123,18 @@ class DungeonCanvasViewer {
// Object interaction state
bool object_interaction_enabled_ = true;
// Layer visibility controls
bool bg1_visible_ = true;
bool bg2_visible_ = true;
int bg2_layer_type_ = 0; // 0=Normal, 1=Translucent, 2=Addition, etc.
// Per-room layer visibility settings
struct RoomLayerSettings {
bool bg1_visible = true;
bool bg2_visible = true;
int bg2_layer_type = 0; // 0=Normal, 1=Translucent, 2=Addition, etc.
};
std::map<int, RoomLayerSettings> room_layer_settings_;
// Helper to get settings for a room (creates default if not exists)
RoomLayerSettings& GetRoomLayerSettings(int room_id) {
return room_layer_settings_[room_id];
}
// Palette data
uint64_t current_palette_group_id_ = 0;

View File

@@ -1,866 +0,0 @@
#include "dungeon_editor.h"
/**
* @file dungeon_editor.cc
* @deprecated This file is deprecated in favor of dungeon_editor_v2.cc
*
* Migration notes:
* ✅ ManualObjectRenderer - Migrated to V2
* ✅ ProcessDeferredTextures() - Migrated to V2
* ✅ Object interaction - Already in DungeonObjectInteraction component
* ✅ Primitive rendering - Already in DungeonRenderer component
*
* All critical features have been migrated. This file should be removed
* once DungeonEditorV2 is confirmed working in production.
*/
#include "absl/strings/str_format.h"
#include "app/gfx/performance_profiler.h"
#include "app/core/window.h"
#include "app/gfx/arena.h"
#include "app/gfx/snes_palette.h"
#include "app/gui/canvas.h"
#include "app/gui/color.h"
#include "app/gui/icons.h"
#include "app/gui/input.h"
#include "app/rom.h"
#include "app/zelda3/dungeon/dungeon_editor_system.h"
#include "app/zelda3/dungeon/dungeon_object_editor.h"
#include "app/zelda3/dungeon/room.h"
#include "app/zelda3/dungeon/room_visual_diagnostic.h"
#include "imgui/imgui.h"
namespace yaze::editor {
using ImGui::BeginTabBar;
using ImGui::BeginTabItem;
using ImGui::BeginTable;
using ImGui::Button;
using ImGui::EndTabBar;
using ImGui::EndTabItem;
using ImGui::RadioButton;
using ImGui::SameLine;
using ImGui::TableHeadersRow;
using ImGui::TableNextColumn;
using ImGui::TableNextRow;
using ImGui::TableSetupColumn;
using ImGui::Text;
constexpr ImGuiTableFlags kDungeonObjectTableFlags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
ImGuiTableFlags_BordersV;
void DungeonEditor::Initialize() {
if (rom_ && !dungeon_editor_system_) {
dungeon_editor_system_ =
std::make_unique<zelda3::DungeonEditorSystem>(rom_);
}
// Phase 5: Initialize integrated object editor
if (rom_ && !object_editor_) {
object_editor_ = std::make_unique<zelda3::DungeonObjectEditor>(rom_);
// Configure editor for dungeon editing
auto config = object_editor_->GetConfig();
config.show_selection_highlight = enable_selection_highlight_;
config.show_layer_colors = enable_layer_visualization_;
config.show_property_panel = show_object_property_panel_;
config.snap_to_grid = true;
config.grid_size = 16; // 16x16 tiles
object_editor_->SetConfig(config);
}
}
absl::Status DungeonEditor::Load() {
gfx::ScopedTimer timer("DungeonEditor::Load");
if (!rom_ || !rom_->is_loaded()) {
return absl::FailedPreconditionError("ROM not loaded");
}
auto dungeon_man_pal_group = rom()->palette_group().dungeon_main;
// Use room loader component for loading rooms
{
gfx::ScopedTimer rooms_timer("DungeonEditor::LoadAllRooms");
RETURN_IF_ERROR(room_loader_.LoadAllRooms(rooms_));
}
{
gfx::ScopedTimer entrances_timer("DungeonEditor::LoadRoomEntrances");
RETURN_IF_ERROR(room_loader_.LoadRoomEntrances(entrances_));
}
// Load the palette group and palette for the dungeon
{
gfx::ScopedTimer palette_timer("DungeonEditor::LoadPalettes");
full_palette_ = dungeon_man_pal_group[current_palette_group_id_];
ASSIGN_OR_RETURN(current_palette_group_,
gfx::CreatePaletteGroupFromLargePalette(full_palette_));
}
// Calculate usage statistics
{
gfx::ScopedTimer usage_timer("DungeonEditor::CalculateUsageStats");
usage_tracker_.CalculateUsageStats(rooms_);
}
// Initialize the new editor system
{
gfx::ScopedTimer init_timer("DungeonEditor::InitializeSystem");
if (dungeon_editor_system_) {
auto status = dungeon_editor_system_->Initialize();
if (!status.ok()) {
return status;
}
}
}
// Initialize the new UI components with loaded data
room_selector_.set_rom(rom_);
room_selector_.set_rooms(&rooms_);
room_selector_.set_entrances(&entrances_);
room_selector_.set_active_rooms(active_rooms_);
room_selector_.set_room_selected_callback(
[this](int room_id) { OnRoomSelected(room_id); });
canvas_viewer_.SetRom(rom_);
canvas_viewer_.SetRooms(&rooms_);
canvas_viewer_.SetCurrentPaletteGroup(current_palette_group_);
canvas_viewer_.SetCurrentPaletteId(current_palette_id_);
object_selector_.SetRom(rom_);
object_selector_.SetCurrentPaletteGroup(current_palette_group_);
object_selector_.SetCurrentPaletteId(current_palette_id_);
object_selector_.set_dungeon_editor_system(&dungeon_editor_system_);
object_selector_.set_object_editor(&object_editor_);
object_selector_.set_rooms(&rooms_);
// Set up object selection callback
object_selector_.SetObjectSelectedCallback(
[this](const zelda3::RoomObject& object) {
preview_object_ = object;
object_loaded_ = true;
toolset_.set_placement_type(DungeonToolset::kObject);
object_interaction_.SetPreviewObject(object, true);
});
// Set up component callbacks
object_interaction_.SetCurrentRoom(&rooms_, current_room_id_);
// Set up toolset callbacks
toolset_.SetUndoCallback([this]() { PRINT_IF_ERROR(Undo()); });
toolset_.SetRedoCallback([this]() { PRINT_IF_ERROR(Redo()); });
toolset_.SetPaletteToggleCallback([this]() { palette_showing_ = !palette_showing_; });
is_loaded_ = true;
return absl::OkStatus();
}
absl::Status DungeonEditor::Update() {
if (refresh_graphics_) {
RETURN_IF_ERROR(RefreshGraphics());
refresh_graphics_ = false;
}
status_ = UpdateDungeonRoomView();
return absl::OkStatus();
}
absl::Status DungeonEditor::Undo() {
if (dungeon_editor_system_) {
return dungeon_editor_system_->Undo();
}
return absl::UnimplementedError("Undo not available");
}
absl::Status DungeonEditor::Redo() {
if (dungeon_editor_system_) {
return dungeon_editor_system_->Redo();
}
return absl::UnimplementedError("Redo not available");
}
absl::Status DungeonEditor::Save() {
if (dungeon_editor_system_) {
return dungeon_editor_system_->SaveDungeon();
}
return absl::UnimplementedError("Save not available");
}
absl::Status DungeonEditor::RefreshGraphics() {
// Update graphics sheet textures via Arena's deferred texture queue
std::for_each_n(
rooms_[current_room_id_].blocks().begin(), 8, [this](int block) {
gfx::Arena::Get().gfx_sheets()[block].SetPaletteWithTransparent(
current_palette_group_[current_palette_id_], 0);
// Queue texture update for the modified graphics sheet
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
&gfx::Arena::Get().gfx_sheets()[block]);
});
auto sprites_aux1_pal_group = rom()->palette_group().sprites_aux1;
std::for_each_n(
rooms_[current_room_id_].blocks().begin() + 8, 8,
[this, &sprites_aux1_pal_group](int block) {
gfx::Arena::Get().gfx_sheets()[block].SetPaletteWithTransparent(
sprites_aux1_pal_group[current_palette_id_], 0);
// Queue texture update for the modified graphics sheet
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE,
&gfx::Arena::Get().gfx_sheets()[block]);
});
return absl::OkStatus();
}
// LoadDungeonRoomSize moved to DungeonRoomLoader component
absl::Status DungeonEditor::UpdateDungeonRoomView() {
toolset_.Draw();
if (palette_showing_) {
ImGui::Begin("Palette Editor", &palette_showing_, 0);
auto dungeon_main_pal_group = rom()->palette_group().dungeon_main;
current_palette_ = dungeon_main_pal_group[current_palette_group_id_];
gui::SelectablePalettePipeline(current_palette_id_, refresh_graphics_,
current_palette_);
ImGui::End();
}
// Correct 3-column layout as specified
if (BeginTable("#DungeonEditTable", 3, kDungeonTableFlags, ImVec2(0, 0))) {
TableSetupColumn("Room/Entrance Selector", ImGuiTableColumnFlags_WidthFixed,
250);
TableSetupColumn("Canvas & Properties", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Object Selector/Editor", ImGuiTableColumnFlags_WidthFixed,
300);
TableHeadersRow();
TableNextRow();
// Column 1: Room and Entrance Selector (unchanged)
TableNextColumn();
room_selector_.Draw();
// Column 2: Canvas and room properties with tabs
TableNextColumn();
DrawCanvasAndPropertiesPanel();
// Column 3: Object selector, room graphics, and object editor
TableNextColumn();
object_selector_.Draw();
// Phase 5: Draw integrated object editor panels below object selector
ImGui::Separator();
DrawObjectEditorPanels();
ImGui::EndTable();
}
return absl::OkStatus();
}
void DungeonEditor::OnRoomSelected(int room_id) {
// Update current room ID
current_room_id_ = room_id;
// Check if room is already open in a tab
int existing_tab_index = -1;
for (int i = 0; i < active_rooms_.Size; i++) {
if (active_rooms_[i] == room_id) {
existing_tab_index = i;
break;
}
}
if (existing_tab_index >= 0) {
// Room is already open, switch to that tab
current_active_room_tab_ = existing_tab_index;
} else {
// Room is not open, add it as a new tab
active_rooms_.push_back(room_id);
current_active_room_tab_ = active_rooms_.Size - 1;
}
// Update the room selector's active rooms list
room_selector_.set_active_rooms(active_rooms_);
}
// DrawToolset() method moved to DungeonToolset component
void DungeonEditor::DrawCanvasAndPropertiesPanel() {
if (ImGui::BeginTabBar("CanvasPropertiesTabBar")) {
// Canvas tab - main editing view
if (ImGui::BeginTabItem("Canvas")) {
DrawDungeonTabView();
ImGui::EndTabItem();
}
// Visual Diagnostic tab - for debugging rendering
if (ImGui::BeginTabItem("Visual Diagnostic")) {
if (!active_rooms_.empty()) {
int room_id = active_rooms_[current_active_room_tab_];
auto& room = rooms_[room_id];
// Show button to toggle diagnostic window
if (ImGui::Button("Open Diagnostic Window")) {
show_visual_diagnostic_ = true;
}
// Render visual diagnostic
if (show_visual_diagnostic_) {
// Get the global graphics buffer for tile decoding
static std::vector<uint8_t> empty_gfx;
const auto& gfx_buffer = rom()->graphics_buffer();
// Get the actual palette being used by this room
const auto& dungeon_pal_group = rom()->palette_group().dungeon_main;
int room_palette_id = rooms_[room_id].palette;
// Validate and clamp palette ID
if (room_palette_id < 0 || room_palette_id >= static_cast<int>(dungeon_pal_group.size())) {
room_palette_id = 0;
}
auto room_palette = dungeon_pal_group[room_palette_id];
zelda3::dungeon::RoomVisualDiagnostic::DrawDiagnosticWindow(
&show_visual_diagnostic_,
gfx::Arena::Get().bg1(),
gfx::Arena::Get().bg2(),
room_palette,
gfx_buffer.empty() ? empty_gfx : gfx_buffer);
}
} else {
ImGui::TextColored(ImVec4(1, 1, 0, 1), "No room selected. Open a room to see diagnostics.");
}
ImGui::EndTabItem();
}
// Room Properties tab - debug and editing controls
if (ImGui::BeginTabItem("Room Properties")) {
if (ImGui::Button("Room Debug Info")) {
ImGui::OpenPopup("RoomDebugPopup");
}
// Room properties popup
if (ImGui::BeginPopup("RoomDebugPopup")) {
DrawRoomPropertiesDebugPopup();
ImGui::EndPopup();
}
// Quick room info display
int current_room = current_room_id_;
if (!active_rooms_.empty() &&
current_active_room_tab_ < active_rooms_.Size) {
current_room = active_rooms_[current_active_room_tab_];
}
if (current_room >= 0 && current_room < rooms_.size()) {
auto& room = rooms_[current_room];
ImGui::Text("Current Room: %03X (%d)", current_room, current_room);
ImGui::Text("Objects: %zu", room.GetTileObjects().size());
ImGui::Text("Sprites: %zu", room.GetSprites().size());
ImGui::Text("Chests: %zu", room.GetChests().size());
// Selection info
const auto& selected_indices = object_interaction_.GetSelectedObjectIndices();
if (!selected_indices.empty()) {
ImGui::Separator();
ImGui::Text("Selected Objects: %zu", selected_indices.size());
if (ImGui::Button("Clear Selection")) {
object_interaction_.ClearSelection();
}
}
ImGui::Separator();
// Quick edit controls
gui::InputHexByte("Layout", &room.layout);
gui::InputHexByte("Blockset", &room.blockset);
gui::InputHexByte("Spriteset", &room.spriteset);
gui::InputHexByte("Palette", &room.palette);
if (ImGui::Button("Reload Room Graphics")) {
(void)LoadAndRenderRoomGraphics(room);
}
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void DungeonEditor::DrawRoomPropertiesDebugPopup() {
int current_room = current_room_id_;
if (!active_rooms_.empty() && current_active_room_tab_ < active_rooms_.Size) {
current_room = active_rooms_[current_active_room_tab_];
}
if (current_room < 0 || current_room >= rooms_.size()) {
ImGui::Text("Invalid room");
return;
}
auto& room = rooms_[current_room];
ImGui::Text("Room %03X Debug Information", current_room);
ImGui::Separator();
// Room properties table
if (ImGui::BeginTable("RoomPropertiesPopup", 2,
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 120);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Room ID");
ImGui::TableNextColumn();
ImGui::Text("%03X (%d)", current_room, current_room);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Layout");
ImGui::TableNextColumn();
gui::InputHexByte("##layout", &room.layout);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Blockset");
ImGui::TableNextColumn();
gui::InputHexByte("##blockset", &room.blockset);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Spriteset");
ImGui::TableNextColumn();
gui::InputHexByte("##spriteset", &room.spriteset);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Palette");
ImGui::TableNextColumn();
gui::InputHexByte("##palette", &room.palette);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Floor 1");
ImGui::TableNextColumn();
gui::InputHexByte("##floor1", &room.floor1);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Floor 2");
ImGui::TableNextColumn();
gui::InputHexByte("##floor2", &room.floor2);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Message ID");
ImGui::TableNextColumn();
gui::InputHexWord("##message_id", &room.message_id_);
ImGui::EndTable();
}
ImGui::Separator();
// Object statistics
ImGui::Text("Object Statistics:");
ImGui::Text("Total Objects: %zu", room.GetTileObjects().size());
ImGui::Text("Layout Objects: %zu", room.GetLayout().GetObjects().size());
ImGui::Text("Sprites: %zu", room.GetSprites().size());
ImGui::Text("Chests: %zu", room.GetChests().size());
ImGui::Separator();
if (ImGui::Button("Reload Objects")) {
room.LoadObjects();
}
ImGui::SameLine();
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
}
void DungeonEditor::DrawDungeonTabView() {
static int next_tab_id = 0;
if (BeginTabBar("MyTabBar", kDungeonTabBarFlags)) {
if (ImGui::TabItemButton(ICON_MD_ADD, kDungeonTabFlags)) {
if (std::find(active_rooms_.begin(), active_rooms_.end(),
current_room_id_) != active_rooms_.end()) {
// Room is already open
next_tab_id++;
}
active_rooms_.push_back(next_tab_id++); // Add new tab
}
// Submit our regular tabs
for (int n = 0; n < active_rooms_.Size;) {
bool open = true;
if (active_rooms_[n] > sizeof(zelda3::kRoomNames) / 4) {
active_rooms_.erase(active_rooms_.Data + n);
continue;
}
if (BeginTabItem(zelda3::kRoomNames[active_rooms_[n]].data(), &open,
ImGuiTabItemFlags_None)) {
current_active_room_tab_ = n; // Track which tab is currently active
DrawDungeonCanvas(active_rooms_[n]);
EndTabItem();
}
if (!open)
active_rooms_.erase(active_rooms_.Data + n);
else
n++;
}
EndTabBar();
}
ImGui::Separator();
}
void DungeonEditor::DrawDungeonCanvas(int room_id) {
// Validate room_id and ROM
if (room_id < 0 || room_id >= rooms_.size()) {
ImGui::Text("Invalid room ID: %d", room_id);
return;
}
if (!rom_ || !rom_->is_loaded()) {
ImGui::Text("ROM not loaded");
return;
}
ImGui::BeginGroup();
gui::InputHexByte("Layout", &rooms_[room_id].layout);
SameLine();
gui::InputHexByte("Blockset", &rooms_[room_id].blockset);
SameLine();
gui::InputHexByte("Spriteset", &rooms_[room_id].spriteset);
SameLine();
gui::InputHexByte("Palette", &rooms_[room_id].palette);
gui::InputHexByte("Floor1", &rooms_[room_id].floor1);
SameLine();
gui::InputHexByte("Floor2", &rooms_[room_id].floor2);
SameLine();
gui::InputHexWord("Message ID", &rooms_[room_id].message_id_);
SameLine();
if (Button("Load Room Graphics")) {
(void)LoadAndRenderRoomGraphics(rooms_[room_id]);
}
ImGui::SameLine();
if (ImGui::Button("Reload All Graphics")) {
(void)ReloadAllRoomGraphics();
}
// Debug and control popup
static bool show_debug_popup = false;
if (ImGui::Button("Room Debug Info")) {
show_debug_popup = true;
}
if (show_debug_popup) {
ImGui::OpenPopup("Room Debug Info");
show_debug_popup = false;
}
if (ImGui::BeginPopupModal("Room Debug Info", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
static bool show_objects = false;
ImGui::Checkbox("Show Object Outlines", &show_objects);
static bool render_objects = true;
ImGui::Checkbox("Render Objects", &render_objects);
static bool show_object_info = false;
ImGui::Checkbox("Show Object Info", &show_object_info);
static bool show_layout_objects = false;
ImGui::Checkbox("Show Layout Objects", &show_layout_objects);
// Object statistics and metadata
ImGui::Separator();
ImGui::Text("Room Statistics:");
ImGui::Text("Objects: %zu", rooms_[room_id].GetTileObjects().size());
ImGui::Text("Layout Objects: %zu",
rooms_[room_id].GetLayout().GetObjects().size());
ImGui::Text("Sprites: %llu", static_cast<unsigned long long>(
rooms_[room_id].GetSprites().size()));
ImGui::Text("Chests: %zu", rooms_[room_id].GetChests().size());
// Palette information
ImGui::Text("Current Palette Group: %llu",
static_cast<unsigned long long>(current_palette_group_id_));
// Object type breakdown
ImGui::Separator();
ImGui::Text("Object Type Breakdown:");
std::map<int, int> object_type_counts;
for (const auto& obj : rooms_[room_id].GetTileObjects()) {
object_type_counts[obj.id_]++;
}
for (const auto& [type, count] : object_type_counts) {
ImGui::Text("Type 0x%02X: %d objects", type, count);
}
// Layout object type breakdown
ImGui::Separator();
ImGui::Text("Layout Object Types:");
auto walls = rooms_[room_id].GetLayout().GetObjectsByType(
zelda3::RoomLayoutObject::Type::kWall);
auto floors = rooms_[room_id].GetLayout().GetObjectsByType(
zelda3::RoomLayoutObject::Type::kFloor);
auto doors = rooms_[room_id].GetLayout().GetObjectsByType(
zelda3::RoomLayoutObject::Type::kDoor);
ImGui::Text("Walls: %zu", walls.size());
ImGui::Text("Floors: %zu", floors.size());
ImGui::Text("Doors: %zu", doors.size());
// Object selection and editing
static int selected_object_id = -1;
if (ImGui::Button("Select Object")) {
// This would open an object selection dialog
// For now, just cycle through objects
if (!rooms_[room_id].GetTileObjects().empty()) {
selected_object_id =
(selected_object_id + 1) % rooms_[room_id].GetTileObjects().size();
}
}
if (selected_object_id >= 0 &&
selected_object_id < (int)rooms_[room_id].GetTileObjects().size()) {
const auto& selected_obj =
rooms_[room_id].GetTileObjects()[selected_object_id];
ImGui::Separator();
ImGui::Text("Selected Object:");
ImGui::Text("ID: 0x%02X", selected_obj.id_);
ImGui::Text("Position: (%d, %d)", selected_obj.x_, selected_obj.y_);
ImGui::Text("Size: 0x%02X", selected_obj.size_);
ImGui::Text("Layer: %d", static_cast<int>(selected_obj.layer_));
ImGui::Text("Tile Count: %d", selected_obj.GetTileCount());
// Object editing controls
if (ImGui::Button("Edit Object")) {
// This would open an object editing dialog
}
ImGui::SameLine();
if (ImGui::Button("Delete Object")) {
// This would remove the object from the room
}
}
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::EndGroup();
canvas_.DrawBackground();
canvas_.DrawContextMenu();
// Handle object selection and placement using component
object_interaction_.CheckForObjectSelection();
// Handle mouse input for drag and select functionality
object_interaction_.HandleCanvasMouseInput();
// Update preview object position based on mouse cursor
if (object_loaded_ && preview_object_.id_ >= 0 && canvas_.IsMouseHovering()) {
const ImGuiIO& io = ImGui::GetIO();
ImVec2 mouse_pos = io.MousePos;
ImVec2 canvas_pos = canvas_.zero_point();
ImVec2 canvas_mouse_pos =
ImVec2(mouse_pos.x - canvas_pos.x, mouse_pos.y - canvas_pos.y);
auto [room_x, room_y] =
object_interaction_.CanvasToRoomCoordinates(static_cast<int>(canvas_mouse_pos.x),
static_cast<int>(canvas_mouse_pos.y));
preview_object_.x_ = room_x;
preview_object_.y_ = room_y;
}
if (is_loaded_) {
// Automatically load room graphics if not already loaded
if (rooms_[room_id].blocks().empty()) {
(void)LoadAndRenderRoomGraphics(rooms_[room_id]);
}
// Load room objects if not already loaded
if (rooms_[room_id].GetTileObjects().empty()) {
rooms_[room_id].LoadObjects();
}
// Render background layers with proper positioning
// This uses per-room buffers which already include objects drawn by ObjectDrawer
auto& room = rooms_[room_id];
auto& bg1_bitmap = room.bg1_buffer().bitmap();
auto& bg2_bitmap = room.bg2_buffer().bitmap();
if (bg1_bitmap.is_active() && bg1_bitmap.width() > 0) {
if (!bg1_bitmap.texture()) {
// Queue texture creation for background layer 1
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &bg1_bitmap);
}
canvas_.DrawBitmap(bg1_bitmap, 0, 0, 1.0f, 255);
}
if (bg2_bitmap.is_active() && bg2_bitmap.width() > 0) {
if (!bg2_bitmap.texture()) {
// Queue texture creation for background layer 2
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::CREATE, &bg2_bitmap);
}
canvas_.DrawBitmap(bg2_bitmap, 0, 0, 1.0f, 200);
}
}
// Phase 5: Render with integrated object editor
RenderRoomWithObjects(room_id);
// Draw selection box and drag preview using component
object_interaction_.DrawSelectBox();
object_interaction_.DrawDragPreview();
canvas_.DrawGrid();
canvas_.DrawOverlay();
// Process queued texture commands
ProcessDeferredTextures();
}
// ============================================================================
// Phase 5: Integrated Object Editor Methods
// ============================================================================
void DungeonEditor::UpdateObjectEditor() {
if (!object_editor_ || !rom_ || !rom_->is_loaded()) {
return;
}
// Get current room ID
int room_id = current_room_id_;
if (!active_rooms_.empty() && current_active_room_tab_ < active_rooms_.Size) {
room_id = active_rooms_[current_active_room_tab_];
}
if (room_id < 0 || room_id >= rooms_.size()) {
return;
}
// Ensure room graphics and objects are loaded
auto& room = rooms_[room_id];
// Load room graphics if not already loaded (this populates arena buffers)
if (room.blocks().empty()) {
auto status = LoadAndRenderRoomGraphics(room);
if (!status.ok()) {
// Log error but continue
return;
}
}
// Load room objects if not already loaded
if (room.GetTileObjects().empty()) {
room.LoadObjects();
}
// Sync object editor with current room's objects
// The object editor should work with the room's tile_objects_ directly
// rather than maintaining its own copy
}
void DungeonEditor::RenderRoomWithObjects(int room_id) {
if (!object_editor_ || room_id < 0 || room_id >= rooms_.size()) {
return;
}
// Ensure room graphics are loaded and rendered to arena buffers first
if (rooms_[room_id].blocks().empty()) {
// Room graphics not loaded yet, will be loaded by LoadAndRenderRoomGraphics
return;
}
// Get the arena buffers for rendering - these should already be populated
// by Room::RenderRoomGraphics() which was called in LoadAndRenderRoomGraphics
auto& bg1_bitmap = gfx::Arena::Get().bg1().bitmap();
auto& bg2_bitmap = gfx::Arena::Get().bg2().bitmap();
if (!bg1_bitmap.is_active() || !bg2_bitmap.is_active()) {
// Arena bitmaps not initialized, this means RenderRoomGraphics wasn't called
return;
}
// Render layer visualization if enabled (draws on top of existing bitmap)
if (enable_layer_visualization_) {
object_editor_->RenderLayerVisualization(bg1_bitmap);
}
// Render selection highlights if enabled (draws on top of existing bitmap)
if (enable_selection_highlight_) {
object_editor_->RenderSelectionHighlight(bg1_bitmap);
}
}
void DungeonEditor::DrawObjectEditorPanels() {
if (!object_editor_) {
return;
}
// Update editor state
UpdateObjectEditor();
// Render ImGui panels
if (show_object_property_panel_) {
object_editor_->RenderObjectPropertyPanel();
}
if (show_layer_controls_) {
object_editor_->RenderLayerControls();
}
}
// Legacy method implementations that delegate to components
absl::Status DungeonEditor::LoadAndRenderRoomGraphics(zelda3::Room& room) {
return room_loader_.LoadAndRenderRoomGraphics(room);
}
absl::Status DungeonEditor::ReloadAllRoomGraphics() {
return room_loader_.ReloadAllRoomGraphics(rooms_);
}
absl::Status DungeonEditor::UpdateRoomBackgroundLayers(int /*room_id*/) {
// This method is deprecated - rendering is handled by DungeonRenderer component
return absl::OkStatus();
}
void DungeonEditor::ProcessDeferredTextures() {
// Process queued texture commands via Arena's deferred system
// Note: Arena uses its stored renderer reference (initialized in EditorManager)
// The parameter is ignored, but we pass nullptr to indicate we're using the stored renderer
gfx::Arena::Get().ProcessTextureQueue(nullptr);
// NOTE: This is deprecated - use DungeonEditorV2 instead
}
} // namespace yaze::editor

View File

@@ -1,210 +0,0 @@
#ifndef YAZE_APP_EDITOR_DUNGEONEDITOR_H
#define YAZE_APP_EDITOR_DUNGEONEDITOR_H
/**
* @deprecated This file is deprecated in favor of dungeon_editor_v2.h
*
* DungeonEditorV2 uses a cleaner component-based architecture with:
* - Card-based UI for better UX
* - Lazy loading for performance
* - Proper component delegation
* - Simplified state management
*
* This file is kept temporarily for reference during migration.
* TODO: Remove once all functionality is verified in V2.
*/
#include "absl/container/flat_hash_map.h"
#include "app/editor/editor.h"
#include "app/editor/graphics/gfx_group_editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/gui/canvas.h"
#include "app/rom.h"
#include "imgui/imgui.h"
#include "zelda3/dungeon/object_renderer.h"
#include "zelda3/dungeon/dungeon_editor_system.h"
#include "zelda3/dungeon/dungeon_object_editor.h"
#include "zelda3/dungeon/room.h"
#include "zelda3/dungeon/room_entrance.h"
#include "zelda3/dungeon/room_object.h"
#include "dungeon_room_selector.h"
#include "dungeon_canvas_viewer.h"
#include "dungeon_object_selector.h"
#include "dungeon_toolset.h"
#include "dungeon_object_interaction.h"
#include "dungeon_room_loader.h"
#include "dungeon_usage_tracker.h"
namespace yaze {
namespace editor {
constexpr ImGuiTabItemFlags kDungeonTabFlags =
ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip;
constexpr ImGuiTabBarFlags kDungeonTabBarFlags =
ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable |
ImGuiTabBarFlags_FittingPolicyResizeDown |
ImGuiTabBarFlags_TabListPopupButton;
constexpr ImGuiTableFlags kDungeonTableFlags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable |
ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter |
ImGuiTableFlags_BordersV;
/**
* @brief DungeonEditor class for editing dungeons.
*
* This class provides a comprehensive dungeon editing interface that integrates
* with the new unified dungeon editing system. It includes object editing with
* scroll wheel support, sprite management, item placement, entrance/exit editing,
* and advanced dungeon features.
*/
class DungeonEditor : public Editor {
public:
explicit DungeonEditor(Rom* rom = nullptr)
: rom_(rom), object_renderer_(rom), preview_object_(0, 0, 0, 0, 0),
room_selector_(rom), canvas_viewer_(rom), object_selector_(rom),
object_interaction_(&canvas_), room_loader_(rom) {
type_ = EditorType::kDungeon;
// Initialize the new dungeon editor system
if (rom) {
dungeon_editor_system_ = std::make_unique<zelda3::DungeonEditorSystem>(rom);
object_editor_ = std::make_unique<zelda3::DungeonObjectEditor>(rom);
}
}
void Initialize() override;
absl::Status Load() override;
absl::Status Update() override;
absl::Status Undo() override;
absl::Status Redo() override;
absl::Status Cut() override { return absl::UnimplementedError("Cut"); }
absl::Status Copy() override { return absl::UnimplementedError("Copy"); }
absl::Status Paste() override { return absl::UnimplementedError("Paste"); }
absl::Status Find() override { return absl::UnimplementedError("Find"); }
absl::Status Save() override;
void add_room(int i) { active_rooms_.push_back(i); }
void set_rom(Rom* rom) {
rom_ = rom;
// Update the new UI components with the new ROM
room_selector_.set_rom(rom_);
canvas_viewer_.SetRom(rom_);
object_selector_.SetRom(rom_);
}
Rom* rom() const { return rom_; }
// ROM state methods (from Editor base class)
bool IsRomLoaded() const override { return rom_ && rom_->is_loaded(); }
std::string GetRomStatus() const override {
if (!rom_) return "No ROM loaded";
if (!rom_->is_loaded()) return "ROM failed to load";
return absl::StrFormat("ROM loaded: %s", rom_->title());
}
private:
absl::Status RefreshGraphics();
void LoadDungeonRoomSize();
absl::Status UpdateDungeonRoomView();
void DrawDungeonTabView();
void DrawDungeonCanvas(int room_id);
// Enhanced UI methods
void DrawCanvasAndPropertiesPanel();
void DrawRoomPropertiesDebugPopup();
// Phase 5: Integrated editor panels
void DrawObjectEditorPanels();
void RenderRoomWithObjects(int room_id);
void UpdateObjectEditor();
// Texture processing
void ProcessDeferredTextures();
// Room selection management
void OnRoomSelected(int room_id);
void DrawRoomGraphics();
void DrawTileSelector();
void DrawObjectRenderer();
// Legacy methods (delegated to components)
absl::Status LoadAndRenderRoomGraphics(zelda3::Room& room);
absl::Status ReloadAllRoomGraphics();
absl::Status UpdateRoomBackgroundLayers(int room_id);
// Object preview system
zelda3::RoomObject preview_object_;
gfx::SnesPalette preview_palette_;
bool is_loaded_ = false;
bool object_loaded_ = false;
bool palette_showing_ = false;
bool refresh_graphics_ = false;
// Phase 5: Integrated object editor system
std::unique_ptr<zelda3::DungeonObjectEditor> object_editor_;
bool show_object_property_panel_ = true;
bool show_layer_controls_ = true;
bool enable_selection_highlight_ = true;
bool enable_layer_visualization_ = true;
// Legacy editor system (deprecated)
std::unique_ptr<zelda3::DungeonEditorSystem> dungeon_editor_system_;
bool show_sprite_editor_ = false;
bool show_item_editor_ = false;
bool show_entrance_editor_ = false;
bool show_door_editor_ = false;
bool show_chest_editor_ = false;
bool show_properties_editor_ = false;
bool show_visual_diagnostic_ = false;
uint16_t current_entrance_id_ = 0;
uint16_t current_room_id_ = 0;
uint64_t current_palette_id_ = 0;
uint64_t current_palette_group_id_ = 0;
ImVector<int> active_rooms_;
int current_active_room_tab_ = 0; // Track which room tab is currently active
GfxGroupEditor gfx_group_editor_;
PaletteEditor palette_editor_;
gfx::SnesPalette current_palette_;
gfx::SnesPalette full_palette_;
gfx::PaletteGroup current_palette_group_;
gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
gui::Canvas room_gfx_canvas_{"##RoomGfxCanvas",
ImVec2(0x100 + 1, 0x10 * 0x40 + 1)};
gui::Canvas object_canvas_;
std::array<gfx::Bitmap, kNumGfxSheets> graphics_bin_;
std::array<zelda3::Room, 0x128> rooms_ = {};
std::array<zelda3::RoomEntrance, 0x8C> entrances_ = {};
zelda3::ObjectRenderer object_renderer_;
// UI components
DungeonRoomSelector room_selector_;
DungeonCanvasViewer canvas_viewer_;
DungeonObjectSelector object_selector_;
// Refactored components
DungeonToolset toolset_;
DungeonObjectInteraction object_interaction_;
DungeonRoomLoader room_loader_;
DungeonUsageTracker usage_tracker_;
absl::Status status_;
Rom* rom_;
};
} // namespace editor
} // namespace yaze
#endif

View File

@@ -24,7 +24,8 @@ void DungeonEditorV2::Initialize(gfx::IRenderer* renderer, Rom* rom) {
// Setup docking class for room windows
room_window_class_.ClassId = ImGui::GetID("DungeonRoomClass");
room_window_class_.DockingAllowUnclassed = false; // Room windows dock together
room_window_class_.DockingAllowUnclassed = true; // Room windows can dock with anything
room_window_class_.DockingAlwaysTabBar = true; // Always show tabs when multiple rooms
// Register all cards with the card manager (done once during initialization)
auto& card_manager = gui::EditorCardManager::Get();

View File

@@ -7,7 +7,6 @@ set(
app/editor/ui/workspace_manager.cc
app/editor/system/user_settings.cc
app/editor/ui/background_renderer.cc
app/editor/dungeon/dungeon_editor.cc
app/editor/dungeon/dungeon_editor_v2.cc
app/editor/dungeon/dungeon_room_selector.cc
app/editor/dungeon/dungeon_canvas_viewer.cc

View File

@@ -19,7 +19,7 @@
#include "util/platform_paths.h"
#include "app/core/project.h"
#include "app/editor/code/assembly_editor.h"
#include "app/editor/dungeon/dungeon_editor.h"
#include "app/editor/dungeon/dungeon_editor_v2.h"
#include "app/editor/graphics/graphics_editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/graphics/screen_editor.h"