feat(editor): add entity operations for overworld editing
- Introduced new `entity_operations.cc` and `entity_operations.h` files to handle the insertion of entrances, exits, sprites, and items in the overworld editor. - Updated `map_properties.cc` to include a context menu for entity insertion, allowing users to add various entities directly from the canvas. - Enhanced `overworld_editor.cc` to manage entity insertion callbacks and streamline the editing process. Benefits: - Improves the functionality of the overworld editor by enabling direct manipulation of entities. - Provides a more intuitive user experience with context-sensitive menus for entity operations.
This commit is contained in:
@@ -23,6 +23,7 @@ set(
|
||||
app/editor/message/message_preview.cc
|
||||
app/editor/music/music_editor.cc
|
||||
app/editor/overworld/entity.cc
|
||||
app/editor/overworld/entity_operations.cc
|
||||
app/editor/overworld/map_properties.cc
|
||||
app/editor/overworld/overworld_editor.cc
|
||||
app/editor/overworld/overworld_entity_renderer.cc
|
||||
|
||||
235
src/app/editor/overworld/entity_operations.cc
Normal file
235
src/app/editor/overworld/entity_operations.cc
Normal file
@@ -0,0 +1,235 @@
|
||||
#include "entity_operations.h"
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "util/log.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
absl::StatusOr<zelda3::OverworldEntrance*> InsertEntrance(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
bool is_hole) {
|
||||
|
||||
if (!overworld || !overworld->is_loaded()) {
|
||||
return absl::FailedPreconditionError("Overworld not loaded");
|
||||
}
|
||||
|
||||
// Snap to 16x16 grid and clamp to bounds (ZScream: EntranceMode.cs:86-87)
|
||||
ImVec2 snapped_pos = ClampToOverworldBounds(SnapToEntityGrid(mouse_pos));
|
||||
|
||||
// Get parent map ID (ZScream: EntranceMode.cs:78-82)
|
||||
auto* current_ow_map = overworld->overworld_map(current_map);
|
||||
uint8_t map_id = GetParentMapId(current_ow_map, current_map);
|
||||
|
||||
if (is_hole) {
|
||||
// Search for first deleted hole slot (ZScream: EntranceMode.cs:74-100)
|
||||
auto& holes = overworld->holes();
|
||||
for (size_t i = 0; i < holes.size(); ++i) {
|
||||
if (holes[i].deleted) {
|
||||
// Reuse deleted slot
|
||||
holes[i].deleted = false;
|
||||
holes[i].map_id_ = map_id;
|
||||
holes[i].x_ = static_cast<int>(snapped_pos.x);
|
||||
holes[i].y_ = static_cast<int>(snapped_pos.y);
|
||||
holes[i].entrance_id_ = 0; // Default, user configures in popup
|
||||
holes[i].is_hole_ = true;
|
||||
|
||||
// Update map properties (ZScream: EntranceMode.cs:90)
|
||||
holes[i].UpdateMapProperties(map_id);
|
||||
|
||||
LOG_DEBUG("EntityOps", "Inserted hole at slot %zu: pos=(%d,%d) map=0x%02X",
|
||||
i, holes[i].x_, holes[i].y_, map_id);
|
||||
|
||||
return &holes[i];
|
||||
}
|
||||
}
|
||||
return absl::ResourceExhaustedError(
|
||||
"No space available for new hole. Delete one first.");
|
||||
|
||||
} else {
|
||||
// Search for first deleted entrance slot (ZScream: EntranceMode.cs:104-130)
|
||||
auto* entrances = overworld->mutable_entrances();
|
||||
for (size_t i = 0; i < entrances->size(); ++i) {
|
||||
if (entrances->at(i).deleted) {
|
||||
// Reuse deleted slot
|
||||
entrances->at(i).deleted = false;
|
||||
entrances->at(i).map_id_ = map_id;
|
||||
entrances->at(i).x_ = static_cast<int>(snapped_pos.x);
|
||||
entrances->at(i).y_ = static_cast<int>(snapped_pos.y);
|
||||
entrances->at(i).entrance_id_ = 0; // Default, user configures in popup
|
||||
entrances->at(i).is_hole_ = false;
|
||||
|
||||
// Update map properties (ZScream: EntranceMode.cs:120)
|
||||
entrances->at(i).UpdateMapProperties(map_id);
|
||||
|
||||
LOG_DEBUG("EntityOps", "Inserted entrance at slot %zu: pos=(%d,%d) map=0x%02X",
|
||||
i, entrances->at(i).x_, entrances->at(i).y_, map_id);
|
||||
|
||||
return &entrances->at(i);
|
||||
}
|
||||
}
|
||||
return absl::ResourceExhaustedError(
|
||||
"No space available for new entrance. Delete one first.");
|
||||
}
|
||||
}
|
||||
|
||||
absl::StatusOr<zelda3::OverworldExit*> InsertExit(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map) {
|
||||
|
||||
if (!overworld || !overworld->is_loaded()) {
|
||||
return absl::FailedPreconditionError("Overworld not loaded");
|
||||
}
|
||||
|
||||
// Snap to 16x16 grid and clamp to bounds (ZScream: ExitMode.cs:71-72)
|
||||
ImVec2 snapped_pos = ClampToOverworldBounds(SnapToEntityGrid(mouse_pos));
|
||||
|
||||
// Get parent map ID (ZScream: ExitMode.cs:63-67)
|
||||
auto* current_ow_map = overworld->overworld_map(current_map);
|
||||
uint8_t map_id = GetParentMapId(current_ow_map, current_map);
|
||||
|
||||
// Search for first deleted exit slot (ZScream: ExitMode.cs:59-124)
|
||||
auto& exits = *overworld->mutable_exits();
|
||||
for (size_t i = 0; i < exits.size(); ++i) {
|
||||
if (exits[i].deleted_) {
|
||||
// Reuse deleted slot
|
||||
exits[i].deleted_ = false;
|
||||
exits[i].map_id_ = map_id;
|
||||
exits[i].x_ = static_cast<int>(snapped_pos.x);
|
||||
exits[i].y_ = static_cast<int>(snapped_pos.y);
|
||||
|
||||
// Initialize with default values (ZScream: ExitMode.cs:95-112)
|
||||
// User will configure room_id, scroll, camera in popup
|
||||
exits[i].room_id_ = 0;
|
||||
exits[i].x_scroll_ = 0;
|
||||
exits[i].y_scroll_ = 0;
|
||||
exits[i].x_camera_ = 0;
|
||||
exits[i].y_camera_ = 0;
|
||||
exits[i].x_player_ = static_cast<uint16_t>(snapped_pos.x);
|
||||
exits[i].y_player_ = static_cast<uint16_t>(snapped_pos.y);
|
||||
exits[i].scroll_mod_x_ = 0;
|
||||
exits[i].scroll_mod_y_ = 0;
|
||||
exits[i].door_type_1_ = 0;
|
||||
exits[i].door_type_2_ = 0;
|
||||
|
||||
// Update map properties
|
||||
exits[i].UpdateMapProperties(map_id);
|
||||
|
||||
LOG_DEBUG("EntityOps", "Inserted exit at slot %zu: pos=(%d,%d) map=0x%02X",
|
||||
i, exits[i].x_, exits[i].y_, map_id);
|
||||
|
||||
return &exits[i];
|
||||
}
|
||||
}
|
||||
|
||||
return absl::ResourceExhaustedError(
|
||||
"No space available for new exit. Delete one first.");
|
||||
}
|
||||
|
||||
absl::StatusOr<zelda3::Sprite*> InsertSprite(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
int game_state, uint8_t sprite_id) {
|
||||
|
||||
if (!overworld || !overworld->is_loaded()) {
|
||||
return absl::FailedPreconditionError("Overworld not loaded");
|
||||
}
|
||||
|
||||
if (game_state < 0 || game_state > 2) {
|
||||
return absl::InvalidArgumentError("Invalid game state (must be 0-2)");
|
||||
}
|
||||
|
||||
// Snap to 16x16 grid and clamp to bounds (ZScream: SpriteMode.cs similar logic)
|
||||
ImVec2 snapped_pos = ClampToOverworldBounds(SnapToEntityGrid(mouse_pos));
|
||||
|
||||
// Get parent map ID (ZScream: SpriteMode.cs:90-95)
|
||||
auto* current_ow_map = overworld->overworld_map(current_map);
|
||||
uint8_t map_id = GetParentMapId(current_ow_map, current_map);
|
||||
|
||||
// Calculate map position (ZScream uses mapHover for parent tracking)
|
||||
// For sprites, we need the actual map coordinates within the 512x512 map
|
||||
int map_local_x = static_cast<int>(snapped_pos.x) % 512;
|
||||
int map_local_y = static_cast<int>(snapped_pos.y) % 512;
|
||||
|
||||
// Convert to game coordinates (0-63 for X/Y within map)
|
||||
uint8_t game_x = static_cast<uint8_t>(map_local_x / 16);
|
||||
uint8_t game_y = static_cast<uint8_t>(map_local_y / 16);
|
||||
|
||||
// Add new sprite to the game state array (ZScream: SpriteMode.cs:34-35)
|
||||
auto& sprites = *overworld->mutable_sprites(game_state);
|
||||
|
||||
// Create new sprite
|
||||
zelda3::Sprite new_sprite(
|
||||
current_ow_map->current_graphics(),
|
||||
static_cast<uint8_t>(map_id),
|
||||
sprite_id, // Sprite ID (user will configure in popup)
|
||||
game_x, // X position in map coordinates
|
||||
game_y, // Y position in map coordinates
|
||||
static_cast<int>(snapped_pos.x), // Real X (world coordinates)
|
||||
static_cast<int>(snapped_pos.y) // Real Y (world coordinates)
|
||||
);
|
||||
|
||||
sprites.push_back(new_sprite);
|
||||
|
||||
// Return pointer to the newly added sprite
|
||||
zelda3::Sprite* inserted_sprite = &sprites.back();
|
||||
|
||||
LOG_DEBUG("EntityOps", "Inserted sprite at game_state=%d: pos=(%d,%d) map=0x%02X id=0x%02X",
|
||||
game_state, inserted_sprite->x_, inserted_sprite->y_, map_id, sprite_id);
|
||||
|
||||
return inserted_sprite;
|
||||
}
|
||||
|
||||
absl::StatusOr<zelda3::OverworldItem*> InsertItem(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
uint8_t item_id) {
|
||||
|
||||
if (!overworld || !overworld->is_loaded()) {
|
||||
return absl::FailedPreconditionError("Overworld not loaded");
|
||||
}
|
||||
|
||||
// Snap to 16x16 grid and clamp to bounds (ZScream: ItemMode.cs similar logic)
|
||||
ImVec2 snapped_pos = ClampToOverworldBounds(SnapToEntityGrid(mouse_pos));
|
||||
|
||||
// Get parent map ID (ZScream: ItemMode.cs:60-64)
|
||||
auto* current_ow_map = overworld->overworld_map(current_map);
|
||||
uint8_t map_id = GetParentMapId(current_ow_map, current_map);
|
||||
|
||||
// Calculate game coordinates (0-63 for X/Y within map)
|
||||
// Following LoadItems logic in overworld.cc:840-854
|
||||
int fake_id = current_map % 0x40;
|
||||
int sy = fake_id / 8;
|
||||
int sx = fake_id - (sy * 8);
|
||||
|
||||
// Calculate map-local coordinates
|
||||
int map_local_x = static_cast<int>(snapped_pos.x) % 512;
|
||||
int map_local_y = static_cast<int>(snapped_pos.y) % 512;
|
||||
|
||||
// Game coordinates (0-63 range)
|
||||
uint8_t game_x = static_cast<uint8_t>(map_local_x / 16);
|
||||
uint8_t game_y = static_cast<uint8_t>(map_local_y / 16);
|
||||
|
||||
// Add new item to the all_items array (ZScream: ItemMode.cs:92-108)
|
||||
auto& items = *overworld->mutable_all_items();
|
||||
|
||||
// Create new item with calculated coordinates
|
||||
items.emplace_back(
|
||||
item_id, // Item ID
|
||||
static_cast<uint16_t>(map_id), // Room map ID
|
||||
static_cast<int>(snapped_pos.x), // X (world coordinates)
|
||||
static_cast<int>(snapped_pos.y), // Y (world coordinates)
|
||||
false // Not deleted
|
||||
);
|
||||
|
||||
// Set game coordinates
|
||||
zelda3::OverworldItem* inserted_item = &items.back();
|
||||
inserted_item->game_x_ = game_x;
|
||||
inserted_item->game_y_ = game_y;
|
||||
|
||||
LOG_DEBUG("EntityOps", "Inserted item: pos=(%d,%d) game=(%d,%d) map=0x%02X id=0x%02X",
|
||||
inserted_item->x_, inserted_item->y_, game_x, game_y, map_id, item_id);
|
||||
|
||||
return inserted_item;
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
136
src/app/editor/overworld/entity_operations.h
Normal file
136
src/app/editor/overworld/entity_operations.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef YAZE_APP_EDITOR_OVERWORLD_ENTITY_OPERATIONS_H
|
||||
#define YAZE_APP_EDITOR_OVERWORLD_ENTITY_OPERATIONS_H
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "zelda3/overworld/overworld.h"
|
||||
#include "zelda3/overworld/overworld_entrance.h"
|
||||
#include "zelda3/overworld/overworld_exit.h"
|
||||
#include "zelda3/overworld/overworld_item.h"
|
||||
#include "zelda3/sprite/sprite.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
/**
|
||||
* @brief Flat helper functions for entity insertion/manipulation
|
||||
*
|
||||
* Following ZScream's entity management pattern (EntranceMode.cs, ExitMode.cs, etc.)
|
||||
* but implemented as free functions to minimize state management.
|
||||
*
|
||||
* Key concepts from ZScream:
|
||||
* - Find first deleted slot for insertion
|
||||
* - Calculate map position from mouse coordinates
|
||||
* - Use parent map ID for multi-area maps
|
||||
* - Call UpdateMapProperties to sync position data
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Insert a new entrance at the specified position
|
||||
*
|
||||
* Follows ZScream's EntranceMode.AddEntrance() logic (EntranceMode.cs:53-148):
|
||||
* - Finds first deleted entrance slot
|
||||
* - Snaps position to 16x16 grid
|
||||
* - Uses parent map ID for multi-area maps
|
||||
* - Calls UpdateMapProperties to calculate game coordinates
|
||||
*
|
||||
* @param overworld Overworld data containing entrance arrays
|
||||
* @param mouse_pos Mouse position in canvas coordinates (world space)
|
||||
* @param current_map Current map index being edited
|
||||
* @param is_hole True to insert a hole instead of entrance
|
||||
* @return Pointer to newly inserted entrance, or error if no slots available
|
||||
*/
|
||||
absl::StatusOr<zelda3::OverworldEntrance*> InsertEntrance(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
bool is_hole = false);
|
||||
|
||||
/**
|
||||
* @brief Insert a new exit at the specified position
|
||||
*
|
||||
* Follows ZScream's ExitMode.AddExit() logic (ExitMode.cs:59-124):
|
||||
* - Finds first deleted exit slot
|
||||
* - Snaps position to 16x16 grid
|
||||
* - Initializes exit with default scroll/camera values
|
||||
* - Sets room ID to 0 (needs to be configured by user)
|
||||
*
|
||||
* @param overworld Overworld data containing exit arrays
|
||||
* @param mouse_pos Mouse position in canvas coordinates
|
||||
* @param current_map Current map index being edited
|
||||
* @return Pointer to newly inserted exit, or error if no slots available
|
||||
*/
|
||||
absl::StatusOr<zelda3::OverworldExit*> InsertExit(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map);
|
||||
|
||||
/**
|
||||
* @brief Insert a new sprite at the specified position
|
||||
*
|
||||
* Follows ZScream's SpriteMode sprite insertion (SpriteMode.cs:27-100):
|
||||
* - Adds new sprite to game state array
|
||||
* - Calculates map position and game coordinates
|
||||
* - Sets sprite ID (default 0, user configures in popup)
|
||||
*
|
||||
* @param overworld Overworld data containing sprite arrays
|
||||
* @param mouse_pos Mouse position in canvas coordinates
|
||||
* @param current_map Current map index being edited
|
||||
* @param game_state Current game state (0=beginning, 1=zelda, 2=agahnim)
|
||||
* @param sprite_id Sprite ID to insert (default 0)
|
||||
* @return Pointer to newly inserted sprite
|
||||
*/
|
||||
absl::StatusOr<zelda3::Sprite*> InsertSprite(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
int game_state, uint8_t sprite_id = 0);
|
||||
|
||||
/**
|
||||
* @brief Insert a new item at the specified position
|
||||
*
|
||||
* Follows ZScream's ItemMode item insertion (ItemMode.cs:54-113):
|
||||
* - Adds new item to all_items array
|
||||
* - Calculates map position and game coordinates
|
||||
* - Sets item ID (default 0, user configures in popup)
|
||||
*
|
||||
* @param overworld Overworld data containing item arrays
|
||||
* @param mouse_pos Mouse position in canvas coordinates
|
||||
* @param current_map Current map index being edited
|
||||
* @param item_id Item ID to insert (default 0x00 - Nothing)
|
||||
* @return Pointer to newly inserted item
|
||||
*/
|
||||
absl::StatusOr<zelda3::OverworldItem*> InsertItem(
|
||||
zelda3::Overworld* overworld, ImVec2 mouse_pos, int current_map,
|
||||
uint8_t item_id = 0);
|
||||
|
||||
/**
|
||||
* @brief Helper to get parent map ID for multi-area maps
|
||||
*
|
||||
* Returns the parent map ID, handling the case where a map is its own parent.
|
||||
* Matches ZScream logic where ParentID == 255 means use current map.
|
||||
*/
|
||||
inline uint8_t GetParentMapId(const zelda3::OverworldMap* map, int current_map) {
|
||||
uint8_t parent = map->parent();
|
||||
return (parent == 0xFF) ? static_cast<uint8_t>(current_map) : parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Snap position to 16x16 grid (standard entity positioning)
|
||||
*/
|
||||
inline ImVec2 SnapToEntityGrid(ImVec2 pos) {
|
||||
return ImVec2(
|
||||
static_cast<float>(static_cast<int>(pos.x / 16) * 16),
|
||||
static_cast<float>(static_cast<int>(pos.y / 16) * 16)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clamp position to valid overworld bounds
|
||||
*/
|
||||
inline ImVec2 ClampToOverworldBounds(ImVec2 pos) {
|
||||
return ImVec2(
|
||||
std::clamp(pos.x, 0.0f, 4080.0f), // 4096 - 16
|
||||
std::clamp(pos.y, 0.0f, 4080.0f)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_APP_EDITOR_OVERWORLD_ENTITY_OPERATIONS_H
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "app/gui/core/color.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
#include "app/gui/core/input.h"
|
||||
#include "app/gui/core/layout_helpers.h"
|
||||
#include "zelda3/overworld/overworld_map.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
@@ -410,10 +411,68 @@ void MapPropertiesSystem::DrawOverlayEditor(int current_map,
|
||||
void MapPropertiesSystem::SetupCanvasContextMenu(
|
||||
gui::Canvas& canvas, int current_map, bool current_map_lock,
|
||||
bool& show_map_properties_panel, bool& show_custom_bg_color_editor,
|
||||
bool& show_overlay_editor) {
|
||||
bool& show_overlay_editor, int current_mode) {
|
||||
(void)current_map; // Used for future context-sensitive menu items
|
||||
// Clear any existing context menu items
|
||||
canvas.ClearContextMenuItems();
|
||||
|
||||
// Add entity insertion submenu (only in MOUSE mode)
|
||||
if (current_mode == 0 && entity_insert_callback_) { // 0 = EditingMode::MOUSE
|
||||
gui::Canvas::ContextMenuItem entity_menu;
|
||||
entity_menu.label = ICON_MD_ADD_LOCATION " Insert Entity";
|
||||
|
||||
// Entrance submenu item
|
||||
gui::Canvas::ContextMenuItem entrance_item;
|
||||
entrance_item.label = ICON_MD_DOOR_FRONT " Entrance";
|
||||
entrance_item.callback = [this]() {
|
||||
if (entity_insert_callback_) {
|
||||
entity_insert_callback_("entrance");
|
||||
}
|
||||
};
|
||||
entity_menu.subitems.push_back(entrance_item);
|
||||
|
||||
// Hole submenu item
|
||||
gui::Canvas::ContextMenuItem hole_item;
|
||||
hole_item.label = ICON_MD_CYCLONE " Hole";
|
||||
hole_item.callback = [this]() {
|
||||
if (entity_insert_callback_) {
|
||||
entity_insert_callback_("hole");
|
||||
}
|
||||
};
|
||||
entity_menu.subitems.push_back(hole_item);
|
||||
|
||||
// Exit submenu item
|
||||
gui::Canvas::ContextMenuItem exit_item;
|
||||
exit_item.label = ICON_MD_DOOR_BACK " Exit";
|
||||
exit_item.callback = [this]() {
|
||||
if (entity_insert_callback_) {
|
||||
entity_insert_callback_("exit");
|
||||
}
|
||||
};
|
||||
entity_menu.subitems.push_back(exit_item);
|
||||
|
||||
// Item submenu item
|
||||
gui::Canvas::ContextMenuItem item_item;
|
||||
item_item.label = ICON_MD_GRASS " Item";
|
||||
item_item.callback = [this]() {
|
||||
if (entity_insert_callback_) {
|
||||
entity_insert_callback_("item");
|
||||
}
|
||||
};
|
||||
entity_menu.subitems.push_back(item_item);
|
||||
|
||||
// Sprite submenu item
|
||||
gui::Canvas::ContextMenuItem sprite_item;
|
||||
sprite_item.label = ICON_MD_PEST_CONTROL_RODENT " Sprite";
|
||||
sprite_item.callback = [this]() {
|
||||
if (entity_insert_callback_) {
|
||||
entity_insert_callback_("sprite");
|
||||
}
|
||||
};
|
||||
entity_menu.subitems.push_back(sprite_item);
|
||||
|
||||
canvas.AddContextMenuItem(entity_menu);
|
||||
}
|
||||
|
||||
// Add overworld-specific context menu items
|
||||
gui::Canvas::ContextMenuItem lock_item;
|
||||
@@ -476,18 +535,16 @@ void MapPropertiesSystem::SetupCanvasContextMenu(
|
||||
canvas.set_global_scale(scale);
|
||||
};
|
||||
canvas.AddContextMenuItem(zoom_out_item);
|
||||
|
||||
// Entity Operations submenu will be added in future iteration
|
||||
// For now, users can use keyboard shortcuts (3-8) to activate entity editing
|
||||
}
|
||||
|
||||
// Private method implementations
|
||||
void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
|
||||
if (ImGui::BeginPopup("GraphicsPopup")) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
// Use theme-aware spacing instead of hardcoded constants
|
||||
float spacing = gui::LayoutHelpers::GetStandardSpacing();
|
||||
float padding = gui::LayoutHelpers::GetButtonPadding();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
|
||||
|
||||
ImGui::Text("Graphics Settings");
|
||||
ImGui::Separator();
|
||||
@@ -589,10 +646,11 @@ void MapPropertiesSystem::DrawGraphicsPopup(int current_map, int game_state) {
|
||||
void MapPropertiesSystem::DrawPalettesPopup(int current_map, int game_state,
|
||||
bool& show_custom_bg_color_editor) {
|
||||
if (ImGui::BeginPopup("PalettesPopup")) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
// Use theme-aware spacing instead of hardcoded constants
|
||||
float spacing = gui::LayoutHelpers::GetStandardSpacing();
|
||||
float padding = gui::LayoutHelpers::GetButtonPadding();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
|
||||
|
||||
ImGui::Text("Palette Settings");
|
||||
ImGui::Separator();
|
||||
@@ -651,10 +709,11 @@ void MapPropertiesSystem::DrawPropertiesPopup(int current_map,
|
||||
bool& show_overlay_preview,
|
||||
int& game_state) {
|
||||
if (ImGui::BeginPopup("ConfigPopup")) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
// Use theme-aware spacing instead of hardcoded constants
|
||||
float spacing = gui::LayoutHelpers::GetStandardSpacing();
|
||||
float padding = gui::LayoutHelpers::GetButtonPadding();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
|
||||
|
||||
ImGui::Text(ICON_MD_TUNE " Area Configuration");
|
||||
ImGui::Separator();
|
||||
@@ -1590,10 +1649,11 @@ void MapPropertiesSystem::DrawOverlayPreviewOnMap(int current_map,
|
||||
|
||||
void MapPropertiesSystem::DrawViewPopup() {
|
||||
if (ImGui::BeginPopup("ViewPopup")) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
// Use theme-aware spacing instead of hardcoded constants
|
||||
float spacing = gui::LayoutHelpers::GetStandardSpacing();
|
||||
float padding = gui::LayoutHelpers::GetButtonPadding();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
|
||||
|
||||
ImGui::Text("View Controls");
|
||||
ImGui::Separator();
|
||||
@@ -1624,10 +1684,11 @@ void MapPropertiesSystem::DrawViewPopup() {
|
||||
|
||||
void MapPropertiesSystem::DrawQuickAccessPopup() {
|
||||
if (ImGui::BeginPopup("QuickPopup")) {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
ImVec2(kCompactItemSpacing, kCompactFramePadding));
|
||||
// Use theme-aware spacing instead of hardcoded constants
|
||||
float spacing = gui::LayoutHelpers::GetStandardSpacing();
|
||||
float padding = gui::LayoutHelpers::GetButtonPadding();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(padding, padding));
|
||||
|
||||
ImGui::Text("Quick Access");
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -41,6 +41,12 @@ class MapPropertiesSystem {
|
||||
refresh_tile16_blockset_ = std::move(refresh_tile16_blockset);
|
||||
force_refresh_graphics_ = std::move(force_refresh_graphics);
|
||||
}
|
||||
|
||||
// Set callbacks for entity operations
|
||||
void SetEntityCallbacks(
|
||||
std::function<void(const std::string&)> insert_callback) {
|
||||
entity_insert_callback_ = std::move(insert_callback);
|
||||
}
|
||||
|
||||
// Main interface methods
|
||||
void DrawSimplifiedMapSettings(int& current_world, int& current_map,
|
||||
@@ -60,7 +66,7 @@ class MapPropertiesSystem {
|
||||
// Context menu integration
|
||||
void SetupCanvasContextMenu(gui::Canvas& canvas, int current_map, bool current_map_lock,
|
||||
bool& show_map_properties_panel, bool& show_custom_bg_color_editor,
|
||||
bool& show_overlay_editor);
|
||||
bool& show_overlay_editor, int current_mode = 0);
|
||||
|
||||
private:
|
||||
// Property category drawers
|
||||
@@ -108,6 +114,9 @@ class MapPropertiesSystem {
|
||||
RefreshPaletteCallback refresh_tile16_blockset_;
|
||||
ForceRefreshGraphicsCallback force_refresh_graphics_;
|
||||
|
||||
// Callback for entity insertion (generic, editor handles entity types)
|
||||
std::function<void(const std::string&)> entity_insert_callback_;
|
||||
|
||||
// Using centralized UI constants from ui_constants.h
|
||||
};
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "core/features.h"
|
||||
#include "app/editor/overworld/map_properties.h"
|
||||
#include "app/editor/overworld/entity.h"
|
||||
#include "app/editor/overworld/entity_operations.h"
|
||||
#include "app/editor/overworld/tile16_editor.h"
|
||||
#include "app/gfx/resource/arena.h"
|
||||
#include "app/gfx/core/bitmap.h"
|
||||
@@ -189,6 +190,14 @@ absl::Status OverworldEditor::Load() {
|
||||
LOG_DEBUG("OverworldEditor", "Overworld editor refreshed after Tile16 changes");
|
||||
return absl::OkStatus();
|
||||
});
|
||||
|
||||
// Set up entity insertion callback for MapPropertiesSystem
|
||||
if (map_properties_system_) {
|
||||
map_properties_system_->SetEntityCallbacks(
|
||||
[this](const std::string& entity_type) {
|
||||
HandleEntityInsertion(entity_type);
|
||||
});
|
||||
}
|
||||
|
||||
ASSIGN_OR_RETURN(entrance_tiletypes_, zelda3::LoadEntranceTileTypes(rom_));
|
||||
all_gfx_loaded_ = true;
|
||||
@@ -476,11 +485,17 @@ void OverworldEditor::DrawToolset() {
|
||||
toolbar.BeginModeGroup();
|
||||
|
||||
if (toolbar.ModeButton(ICON_MD_MOUSE, current_mode == EditingMode::MOUSE, "Mouse Mode (1)\nNavigate, pan, and manage entities")) {
|
||||
current_mode = EditingMode::MOUSE;
|
||||
if (current_mode != EditingMode::MOUSE) {
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
}
|
||||
}
|
||||
|
||||
if (toolbar.ModeButton(ICON_MD_DRAW, current_mode == EditingMode::DRAW_TILE, "Tile Paint Mode (2)\nDraw tiles on the map")) {
|
||||
current_mode = EditingMode::DRAW_TILE;
|
||||
if (current_mode != EditingMode::DRAW_TILE) {
|
||||
current_mode = EditingMode::DRAW_TILE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kTilePainting);
|
||||
}
|
||||
}
|
||||
|
||||
toolbar.EndModeGroup();
|
||||
@@ -647,6 +662,8 @@ void OverworldEditor::DrawToolset() {
|
||||
// Keyboard shortcuts for the Overworld Editor
|
||||
if (!ImGui::IsAnyItemActive()) {
|
||||
using enum EditingMode;
|
||||
|
||||
EditingMode old_mode = current_mode;
|
||||
|
||||
// Tool shortcuts (simplified)
|
||||
if (ImGui::IsKeyDown(ImGuiKey_1)) {
|
||||
@@ -655,25 +672,40 @@ void OverworldEditor::DrawToolset() {
|
||||
current_mode = EditingMode::DRAW_TILE;
|
||||
}
|
||||
|
||||
// Update canvas usage mode when mode changes
|
||||
if (old_mode != current_mode) {
|
||||
if (current_mode == EditingMode::MOUSE) {
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (current_mode == EditingMode::DRAW_TILE) {
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kTilePainting);
|
||||
}
|
||||
}
|
||||
|
||||
// Entity editing shortcuts (3-8)
|
||||
if (ImGui::IsKeyDown(ImGuiKey_3)) {
|
||||
entity_edit_mode_ = EntityEditMode::ENTRANCES;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (ImGui::IsKeyDown(ImGuiKey_4)) {
|
||||
entity_edit_mode_ = EntityEditMode::EXITS;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (ImGui::IsKeyDown(ImGuiKey_5)) {
|
||||
entity_edit_mode_ = EntityEditMode::ITEMS;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (ImGui::IsKeyDown(ImGuiKey_6)) {
|
||||
entity_edit_mode_ = EntityEditMode::SPRITES;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (ImGui::IsKeyDown(ImGuiKey_7)) {
|
||||
entity_edit_mode_ = EntityEditMode::TRANSPORTS;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
} else if (ImGui::IsKeyDown(ImGuiKey_8)) {
|
||||
entity_edit_mode_ = EntityEditMode::MUSIC;
|
||||
current_mode = EditingMode::MOUSE;
|
||||
ow_map_canvas_.SetUsageMode(gui::CanvasUsage::kEntityManipulation);
|
||||
}
|
||||
|
||||
// View shortcuts
|
||||
@@ -1455,7 +1487,7 @@ void OverworldEditor::DrawOverworldCanvas() {
|
||||
map_properties_system_->SetupCanvasContextMenu(
|
||||
ow_map_canvas_, current_map_, current_map_lock_,
|
||||
show_map_properties_panel_, show_custom_bg_color_editor_,
|
||||
show_overlay_editor_);
|
||||
show_overlay_editor_, static_cast<int>(current_mode));
|
||||
}
|
||||
|
||||
// Handle pan and zoom (works in all modes)
|
||||
@@ -2971,4 +3003,81 @@ int OverworldEditor::AutomationGetTile(int x, int y) {
|
||||
return overworld_.GetTile(x, y);
|
||||
}
|
||||
|
||||
void OverworldEditor::HandleEntityInsertion(const std::string& entity_type) {
|
||||
if (!overworld_.is_loaded()) {
|
||||
LOG_ERROR("OverworldEditor", "Cannot insert entity: overworld not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get mouse position from canvas (in world coordinates)
|
||||
ImVec2 mouse_pos = ow_map_canvas_.hover_mouse_pos();
|
||||
|
||||
LOG_DEBUG("OverworldEditor", "Inserting entity type='%s' at pos=(%f,%f) map=%d",
|
||||
entity_type.c_str(), mouse_pos.x, mouse_pos.y, current_map_);
|
||||
|
||||
if (entity_type == "entrance") {
|
||||
auto result = InsertEntrance(&overworld_, mouse_pos, current_map_, false);
|
||||
if (result.ok()) {
|
||||
current_entrance_ = **result;
|
||||
current_entity_ = *result;
|
||||
ImGui::OpenPopup("Entrance Editor");
|
||||
rom_->set_dirty(true);
|
||||
} else {
|
||||
LOG_ERROR("OverworldEditor", "Failed to insert entrance: %s",
|
||||
result.status().message().data());
|
||||
}
|
||||
|
||||
} else if (entity_type == "hole") {
|
||||
auto result = InsertEntrance(&overworld_, mouse_pos, current_map_, true);
|
||||
if (result.ok()) {
|
||||
current_entrance_ = **result;
|
||||
current_entity_ = *result;
|
||||
ImGui::OpenPopup("Entrance Editor");
|
||||
rom_->set_dirty(true);
|
||||
} else {
|
||||
LOG_ERROR("OverworldEditor", "Failed to insert hole: %s",
|
||||
result.status().message().data());
|
||||
}
|
||||
|
||||
} else if (entity_type == "exit") {
|
||||
auto result = InsertExit(&overworld_, mouse_pos, current_map_);
|
||||
if (result.ok()) {
|
||||
current_exit_ = **result;
|
||||
current_entity_ = *result;
|
||||
ImGui::OpenPopup("Exit editor");
|
||||
rom_->set_dirty(true);
|
||||
} else {
|
||||
LOG_ERROR("OverworldEditor", "Failed to insert exit: %s",
|
||||
result.status().message().data());
|
||||
}
|
||||
|
||||
} else if (entity_type == "item") {
|
||||
auto result = InsertItem(&overworld_, mouse_pos, current_map_, 0x00);
|
||||
if (result.ok()) {
|
||||
current_item_ = **result;
|
||||
current_entity_ = *result;
|
||||
ImGui::OpenPopup("Item editor");
|
||||
rom_->set_dirty(true);
|
||||
} else {
|
||||
LOG_ERROR("OverworldEditor", "Failed to insert item: %s",
|
||||
result.status().message().data());
|
||||
}
|
||||
|
||||
} else if (entity_type == "sprite") {
|
||||
auto result = InsertSprite(&overworld_, mouse_pos, current_map_, game_state_, 0x00);
|
||||
if (result.ok()) {
|
||||
current_sprite_ = **result;
|
||||
current_entity_ = *result;
|
||||
ImGui::OpenPopup("Sprite editor");
|
||||
rom_->set_dirty(true);
|
||||
} else {
|
||||
LOG_ERROR("OverworldEditor", "Failed to insert sprite: %s",
|
||||
result.status().message().data());
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_WARN("OverworldEditor", "Unknown entity type: %s", entity_type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace yaze::editor
|
||||
@@ -126,6 +126,16 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
|
||||
* assembling the OverworldMap Bitmap objects.
|
||||
*/
|
||||
absl::Status LoadGraphics();
|
||||
|
||||
/**
|
||||
* @brief Handle entity insertion from context menu
|
||||
*
|
||||
* Delegates to flat helper functions in entity_operations.cc
|
||||
* following ZScream's pattern for entity management.
|
||||
*
|
||||
* @param entity_type Type of entity to insert ("entrance", "hole", "exit", "item", "sprite")
|
||||
*/
|
||||
void HandleEntityInsertion(const std::string& entity_type);
|
||||
|
||||
private:
|
||||
void DrawFullscreenCanvas();
|
||||
|
||||
@@ -163,44 +163,35 @@ void Canvas::Cleanup() {
|
||||
|
||||
void Canvas::InitializeEnhancedComponents() {
|
||||
// Initialize modals system
|
||||
modals_ = std::make_unique<canvas::CanvasModals>();
|
||||
modals_ = std::make_unique<CanvasModals>();
|
||||
|
||||
// Initialize context menu system
|
||||
context_menu_ = std::make_unique<canvas::CanvasContextMenu>();
|
||||
context_menu_ = std::make_unique<CanvasContextMenu>();
|
||||
context_menu_->Initialize(canvas_id_);
|
||||
|
||||
// Initialize usage tracker
|
||||
usage_tracker_ = std::make_shared<canvas::CanvasUsageTracker>();
|
||||
usage_tracker_->Initialize(canvas_id_);
|
||||
canvas::CanvasUsageManager::Get().RegisterTracker(canvas_id_, usage_tracker_);
|
||||
// Initialize usage tracker (optional, controlled by config.enable_metrics)
|
||||
if (config_.enable_metrics) {
|
||||
usage_tracker_ = std::make_shared<CanvasUsageTracker>();
|
||||
usage_tracker_->Initialize(canvas_id_);
|
||||
usage_tracker_->StartSession();
|
||||
|
||||
// Initialize performance integration
|
||||
performance_integration_ =
|
||||
std::make_shared<canvas::CanvasPerformanceIntegration>();
|
||||
performance_integration_->Initialize(canvas_id_);
|
||||
performance_integration_->SetUsageTracker(usage_tracker_);
|
||||
canvas::CanvasPerformanceManager::Get().RegisterIntegration(
|
||||
canvas_id_, performance_integration_);
|
||||
|
||||
// Start performance monitoring
|
||||
performance_integration_->StartMonitoring();
|
||||
usage_tracker_->StartSession();
|
||||
// Initialize performance integration
|
||||
performance_integration_ =
|
||||
std::make_shared<CanvasPerformanceIntegration>();
|
||||
performance_integration_->Initialize(canvas_id_);
|
||||
performance_integration_->SetUsageTracker(usage_tracker_);
|
||||
performance_integration_->StartMonitoring();
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::SetUsageMode(canvas::CanvasUsage usage) {
|
||||
void Canvas::SetUsageMode(CanvasUsage usage) {
|
||||
if (usage_tracker_) {
|
||||
usage_tracker_->SetUsageMode(usage);
|
||||
}
|
||||
if (context_menu_) {
|
||||
context_menu_->SetUsageMode(usage);
|
||||
}
|
||||
}
|
||||
|
||||
canvas::CanvasUsage Canvas::GetUsageMode() const {
|
||||
if (usage_tracker_) {
|
||||
return usage_tracker_->GetCurrentStats().usage_mode;
|
||||
}
|
||||
return canvas::CanvasUsage::kUnknown;
|
||||
config_.usage_mode = usage;
|
||||
}
|
||||
|
||||
void Canvas::RecordCanvasOperation(const std::string& operation_name,
|
||||
@@ -210,7 +201,7 @@ void Canvas::RecordCanvasOperation(const std::string& operation_name,
|
||||
}
|
||||
if (performance_integration_) {
|
||||
performance_integration_->RecordOperation(operation_name, time_ms,
|
||||
GetUsageMode());
|
||||
usage_mode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +446,7 @@ void Canvas::DrawContextMenu() {
|
||||
|
||||
// Use enhanced context menu if available
|
||||
if (context_menu_) {
|
||||
canvas::CanvasConfig snapshot;
|
||||
CanvasConfig snapshot;
|
||||
snapshot.canvas_size = canvas_sz_;
|
||||
snapshot.content_size = config_.content_size;
|
||||
snapshot.global_scale = global_scale_;
|
||||
@@ -476,78 +467,78 @@ void Canvas::DrawContextMenu() {
|
||||
context_menu_->Render(
|
||||
context_id_, mouse_pos, rom_, bitmap_,
|
||||
bitmap_ ? bitmap_->mutable_palette() : nullptr,
|
||||
[this](canvas::CanvasContextMenu::Command command,
|
||||
const canvas::CanvasConfig& updated_config) {
|
||||
[this](CanvasContextMenu::Command command,
|
||||
const CanvasConfig& updated_config) {
|
||||
switch (command) {
|
||||
case canvas::CanvasContextMenu::Command::kResetView:
|
||||
case CanvasContextMenu::Command::kResetView:
|
||||
ResetView();
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kZoomToFit:
|
||||
case CanvasContextMenu::Command::kZoomToFit:
|
||||
if (bitmap_) {
|
||||
SetZoomToFit(*bitmap_);
|
||||
}
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kZoomIn:
|
||||
case CanvasContextMenu::Command::kZoomIn:
|
||||
SetGlobalScale(config_.global_scale * 1.25f);
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kZoomOut:
|
||||
case CanvasContextMenu::Command::kZoomOut:
|
||||
SetGlobalScale(config_.global_scale * 0.8f);
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleGrid:
|
||||
case CanvasContextMenu::Command::kToggleGrid:
|
||||
config_.enable_grid = !config_.enable_grid;
|
||||
enable_grid_ = config_.enable_grid;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleHexLabels:
|
||||
case CanvasContextMenu::Command::kToggleHexLabels:
|
||||
config_.enable_hex_labels = !config_.enable_hex_labels;
|
||||
enable_hex_tile_labels_ = config_.enable_hex_labels;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleCustomLabels:
|
||||
case CanvasContextMenu::Command::kToggleCustomLabels:
|
||||
config_.enable_custom_labels = !config_.enable_custom_labels;
|
||||
enable_custom_labels_ = config_.enable_custom_labels;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleContextMenu:
|
||||
case CanvasContextMenu::Command::kToggleContextMenu:
|
||||
config_.enable_context_menu = !config_.enable_context_menu;
|
||||
enable_context_menu_ = config_.enable_context_menu;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleAutoResize:
|
||||
case CanvasContextMenu::Command::kToggleAutoResize:
|
||||
config_.auto_resize = !config_.auto_resize;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kToggleDraggable:
|
||||
case CanvasContextMenu::Command::kToggleDraggable:
|
||||
config_.is_draggable = !config_.is_draggable;
|
||||
draggable_ = config_.is_draggable;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kSetGridStep:
|
||||
case CanvasContextMenu::Command::kSetGridStep:
|
||||
config_.grid_step = updated_config.grid_step;
|
||||
custom_step_ = config_.grid_step;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kSetScale:
|
||||
case CanvasContextMenu::Command::kSetScale:
|
||||
config_.global_scale = updated_config.global_scale;
|
||||
global_scale_ = config_.global_scale;
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kOpenAdvancedProperties:
|
||||
case CanvasContextMenu::Command::kOpenAdvancedProperties:
|
||||
if (modals_) {
|
||||
canvas::CanvasConfig modal_config = updated_config;
|
||||
CanvasConfig modal_config = updated_config;
|
||||
modal_config.on_config_changed =
|
||||
[this](const canvas::CanvasConfig& cfg) {
|
||||
[this](const CanvasConfig& cfg) {
|
||||
ApplyConfigSnapshot(cfg);
|
||||
};
|
||||
modal_config.on_scale_changed =
|
||||
[this](const canvas::CanvasConfig& cfg) {
|
||||
[this](const CanvasConfig& cfg) {
|
||||
ApplyScaleSnapshot(cfg);
|
||||
};
|
||||
modals_->ShowAdvancedProperties(canvas_id_, modal_config,
|
||||
bitmap_);
|
||||
}
|
||||
break;
|
||||
case canvas::CanvasContextMenu::Command::kOpenScalingControls:
|
||||
case CanvasContextMenu::Command::kOpenScalingControls:
|
||||
if (modals_) {
|
||||
canvas::CanvasConfig modal_config = updated_config;
|
||||
CanvasConfig modal_config = updated_config;
|
||||
modal_config.on_config_changed =
|
||||
[this](const canvas::CanvasConfig& cfg) {
|
||||
[this](const CanvasConfig& cfg) {
|
||||
ApplyConfigSnapshot(cfg);
|
||||
};
|
||||
modal_config.on_scale_changed =
|
||||
[this](const canvas::CanvasConfig& cfg) {
|
||||
[this](const CanvasConfig& cfg) {
|
||||
ApplyScaleSnapshot(cfg);
|
||||
};
|
||||
modals_->ShowScalingControls(canvas_id_, modal_config, bitmap_);
|
||||
@@ -695,7 +686,7 @@ void Canvas::ResetView() {
|
||||
scrolling_ = ImVec2(0, 0);
|
||||
}
|
||||
|
||||
void Canvas::ApplyConfigSnapshot(const canvas::CanvasConfig& snapshot) {
|
||||
void Canvas::ApplyConfigSnapshot(const CanvasConfig& snapshot) {
|
||||
config_.enable_grid = snapshot.enable_grid;
|
||||
config_.enable_hex_labels = snapshot.enable_hex_labels;
|
||||
config_.enable_custom_labels = snapshot.enable_custom_labels;
|
||||
@@ -719,7 +710,7 @@ void Canvas::ApplyConfigSnapshot(const canvas::CanvasConfig& snapshot) {
|
||||
scrolling_ = snapshot.scrolling;
|
||||
}
|
||||
|
||||
void Canvas::ApplyScaleSnapshot(const canvas::CanvasConfig& snapshot) {
|
||||
void Canvas::ApplyScaleSnapshot(const CanvasConfig& snapshot) {
|
||||
config_.global_scale = snapshot.global_scale;
|
||||
global_scale_ = config_.global_scale;
|
||||
scrolling_ = snapshot.scrolling;
|
||||
@@ -1586,7 +1577,7 @@ void TableCanvasPipeline(gui::Canvas& canvas, gfx::Bitmap& bitmap,
|
||||
void Canvas::ShowAdvancedCanvasProperties() {
|
||||
// Use the new modal system if available
|
||||
if (modals_) {
|
||||
canvas::CanvasConfig modal_config;
|
||||
CanvasConfig modal_config;
|
||||
modal_config.canvas_size = canvas_sz_;
|
||||
modal_config.content_size = config_.content_size;
|
||||
modal_config.global_scale = global_scale_;
|
||||
@@ -1599,14 +1590,14 @@ void Canvas::ShowAdvancedCanvasProperties() {
|
||||
modal_config.auto_resize = config_.auto_resize;
|
||||
modal_config.scrolling = scrolling_;
|
||||
modal_config.on_config_changed =
|
||||
[this](const canvas::CanvasConfig& updated_config) {
|
||||
[this](const CanvasConfig& updated_config) {
|
||||
// Update legacy variables when config changes
|
||||
enable_grid_ = updated_config.enable_grid;
|
||||
enable_hex_tile_labels_ = updated_config.enable_hex_labels;
|
||||
enable_custom_labels_ = updated_config.enable_custom_labels;
|
||||
};
|
||||
modal_config.on_scale_changed =
|
||||
[this](const canvas::CanvasConfig& updated_config) {
|
||||
[this](const CanvasConfig& updated_config) {
|
||||
global_scale_ = updated_config.global_scale;
|
||||
scrolling_ = updated_config.scrolling;
|
||||
};
|
||||
@@ -1709,7 +1700,7 @@ void Canvas::ShowAdvancedCanvasProperties() {
|
||||
void Canvas::ShowScalingControls() {
|
||||
// Use the new modal system if available
|
||||
if (modals_) {
|
||||
canvas::CanvasConfig modal_config;
|
||||
CanvasConfig modal_config;
|
||||
modal_config.canvas_size = canvas_sz_;
|
||||
modal_config.content_size = config_.content_size;
|
||||
modal_config.global_scale = global_scale_;
|
||||
@@ -1722,7 +1713,7 @@ void Canvas::ShowScalingControls() {
|
||||
modal_config.auto_resize = config_.auto_resize;
|
||||
modal_config.scrolling = scrolling_;
|
||||
modal_config.on_config_changed =
|
||||
[this](const canvas::CanvasConfig& updated_config) {
|
||||
[this](const CanvasConfig& updated_config) {
|
||||
// Update legacy variables when config changes
|
||||
enable_grid_ = updated_config.enable_grid;
|
||||
enable_hex_tile_labels_ = updated_config.enable_hex_labels;
|
||||
@@ -1730,7 +1721,7 @@ void Canvas::ShowScalingControls() {
|
||||
enable_context_menu_ = updated_config.enable_context_menu;
|
||||
};
|
||||
modal_config.on_scale_changed =
|
||||
[this](const canvas::CanvasConfig& updated_config) {
|
||||
[this](const CanvasConfig& updated_config) {
|
||||
draggable_ = updated_config.is_draggable;
|
||||
custom_step_ = updated_config.grid_step;
|
||||
global_scale_ = updated_config.global_scale;
|
||||
|
||||
@@ -187,11 +187,11 @@ class Canvas {
|
||||
std::unique_ptr<gui::BppComparisonTool> bpp_comparison_tool_;
|
||||
|
||||
// Enhanced canvas components
|
||||
std::unique_ptr<canvas::CanvasModals> modals_;
|
||||
std::unique_ptr<canvas::CanvasContextMenu> context_menu_;
|
||||
std::shared_ptr<canvas::CanvasUsageTracker> usage_tracker_;
|
||||
std::shared_ptr<canvas::CanvasPerformanceIntegration> performance_integration_;
|
||||
canvas::CanvasInteractionHandler interaction_handler_;
|
||||
std::unique_ptr<CanvasModals> modals_;
|
||||
std::unique_ptr<CanvasContextMenu> context_menu_;
|
||||
std::shared_ptr<CanvasUsageTracker> usage_tracker_;
|
||||
std::shared_ptr<CanvasPerformanceIntegration> performance_integration_;
|
||||
CanvasInteractionHandler interaction_handler_;
|
||||
|
||||
void AddContextMenuItem(const ContextMenuItem& item);
|
||||
void ClearContextMenuItems();
|
||||
@@ -207,8 +207,8 @@ class Canvas {
|
||||
void ShowScalingControls();
|
||||
void SetZoomToFit(const gfx::Bitmap& bitmap);
|
||||
void ResetView();
|
||||
void ApplyConfigSnapshot(const canvas::CanvasConfig& snapshot);
|
||||
void ApplyScaleSnapshot(const canvas::CanvasConfig& snapshot);
|
||||
void ApplyConfigSnapshot(const CanvasConfig& snapshot);
|
||||
void ApplyScaleSnapshot(const CanvasConfig& snapshot);
|
||||
|
||||
// Modular component access
|
||||
CanvasConfig& GetConfig() { return config_; }
|
||||
@@ -231,15 +231,16 @@ class Canvas {
|
||||
|
||||
// Enhanced canvas management
|
||||
void InitializeEnhancedComponents();
|
||||
void SetUsageMode(canvas::CanvasUsage usage);
|
||||
canvas::CanvasUsage GetUsageMode() const;
|
||||
void SetUsageMode(CanvasUsage usage);
|
||||
auto usage_mode() const { return config_.usage_mode; }
|
||||
|
||||
void RecordCanvasOperation(const std::string& operation_name, double time_ms);
|
||||
void ShowPerformanceUI();
|
||||
void ShowUsageReport();
|
||||
|
||||
// Interaction handler access
|
||||
canvas::CanvasInteractionHandler& GetInteractionHandler() { return interaction_handler_; }
|
||||
const canvas::CanvasInteractionHandler& GetInteractionHandler() const { return interaction_handler_; }
|
||||
CanvasInteractionHandler& GetInteractionHandler() { return interaction_handler_; }
|
||||
const CanvasInteractionHandler& GetInteractionHandler() const { return interaction_handler_; }
|
||||
|
||||
// Automation API access (Phase 4A)
|
||||
CanvasAutomationAPI* GetAutomationAPI();
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
namespace {
|
||||
inline void Dispatch(
|
||||
@@ -506,6 +505,7 @@ std::string CanvasContextMenu::GetUsageModeName(CanvasUsage usage) const {
|
||||
case CanvasUsage::kPaletteEditing: return "Palette Editing";
|
||||
case CanvasUsage::kBppConversion: return "BPP Conversion";
|
||||
case CanvasUsage::kPerformanceMode: return "Performance Mode";
|
||||
case CanvasUsage::kEntityManipulation: return "Entity Manipulation";
|
||||
case CanvasUsage::kUnknown: return "Unknown";
|
||||
default: return "Unknown";
|
||||
}
|
||||
@@ -521,6 +521,7 @@ ImVec4 CanvasContextMenu::GetUsageModeColor(CanvasUsage usage) const {
|
||||
case CanvasUsage::kPaletteEditing: return ImVec4(0.8F, 0.2F, 1.0F, 1.0F); // Purple
|
||||
case CanvasUsage::kBppConversion: return ImVec4(0.2F, 1.0F, 1.0F, 1.0F); // Cyan
|
||||
case CanvasUsage::kPerformanceMode: return ImVec4(1.0F, 0.2F, 0.2F, 1.0F); // Red
|
||||
case CanvasUsage::kEntityManipulation: return ImVec4(0.4F, 0.8F, 1.0F, 1.0F); // Light Blue
|
||||
case CanvasUsage::kUnknown: return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
|
||||
default: return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
|
||||
}
|
||||
@@ -578,36 +579,35 @@ void CanvasContextMenu::CreateDefaultMenuItems() {
|
||||
usage_specific_items_[CanvasUsage::kPerformanceMode].push_back(perf_item);
|
||||
}
|
||||
|
||||
canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateViewMenuItem(const std::string& label,
|
||||
CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateViewMenuItem(const std::string& label,
|
||||
const std::string& icon,
|
||||
std::function<void()> callback) {
|
||||
return ContextMenuItem(label, icon, callback);
|
||||
}
|
||||
|
||||
canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateBitmapMenuItem(const std::string& label,
|
||||
CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateBitmapMenuItem(const std::string& label,
|
||||
const std::string& icon,
|
||||
std::function<void()> callback) {
|
||||
return ContextMenuItem(label, icon, callback);
|
||||
}
|
||||
|
||||
canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreatePaletteMenuItem(const std::string& label,
|
||||
CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreatePaletteMenuItem(const std::string& label,
|
||||
const std::string& icon,
|
||||
std::function<void()> callback) {
|
||||
return ContextMenuItem(label, icon, callback);
|
||||
}
|
||||
|
||||
canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateBppMenuItem(const std::string& label,
|
||||
CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateBppMenuItem(const std::string& label,
|
||||
const std::string& icon,
|
||||
std::function<void()> callback) {
|
||||
return ContextMenuItem(label, icon, callback);
|
||||
}
|
||||
|
||||
canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreatePerformanceMenuItem(const std::string& label,
|
||||
CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreatePerformanceMenuItem(const std::string& label,
|
||||
const std::string& icon,
|
||||
std::function<void()> callback) {
|
||||
return ContextMenuItem(label, icon, callback);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
@@ -19,8 +19,6 @@ namespace gui {
|
||||
// Forward declarations
|
||||
class PaletteEditorWidget;
|
||||
|
||||
namespace canvas {
|
||||
|
||||
class CanvasContextMenu {
|
||||
public:
|
||||
enum class Command {
|
||||
@@ -71,7 +69,7 @@ class CanvasContextMenu {
|
||||
Rom* rom,
|
||||
const gfx::Bitmap* bitmap,
|
||||
const gfx::SnesPalette* palette,
|
||||
const std::function<void(Command, const canvas::CanvasConfig&)>& command_handler,
|
||||
const std::function<void(Command, const CanvasConfig&)>& command_handler,
|
||||
CanvasConfig current_config);
|
||||
|
||||
bool ShouldShowContextMenu() const;
|
||||
@@ -159,7 +157,6 @@ class CanvasContextMenu {
|
||||
std::function<void()> callback);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -364,6 +363,5 @@ bool CanvasInteractionHandler::IsMouseReleased(ImGuiMouseButton button) {
|
||||
return ImGui::IsMouseReleased(button);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
/**
|
||||
* @brief Tile interaction mode for canvas
|
||||
@@ -201,7 +200,6 @@ class CanvasInteractionHandler {
|
||||
bool IsMouseReleased(ImGuiMouseButton button);
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -13,21 +13,17 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
// Helper functions for dispatching config callbacks
|
||||
namespace {
|
||||
void DispatchConfigCallback(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config) {
|
||||
if (callback) {
|
||||
callback(config);
|
||||
}
|
||||
inline void DispatchConfig(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config) {
|
||||
if (callback) callback(config);
|
||||
}
|
||||
|
||||
void DispatchScaleCallback(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config) {
|
||||
if (callback) {
|
||||
callback(config);
|
||||
}
|
||||
inline void DispatchScale(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config) {
|
||||
if (callback) callback(config);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -214,7 +210,7 @@ void CanvasModals::RenderAdvancedPropertiesModal(const std::string& canvas_id,
|
||||
if (i > 0) ImGui::SameLine();
|
||||
if (ImGui::Button(preset_labels[i])) {
|
||||
config.global_scale = preset_values[i];
|
||||
DispatchConfigCallback(config.on_config_changed, config);
|
||||
DispatchConfig(config.on_config_changed, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,14 +221,14 @@ void CanvasModals::RenderAdvancedPropertiesModal(const std::string& canvas_id,
|
||||
|
||||
if (ImGui::Button("Reset Scroll")) {
|
||||
config.scrolling = ImVec2(0, 0);
|
||||
DispatchConfigCallback(config.on_config_changed, config);
|
||||
DispatchConfig(config.on_config_changed, config);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Center View") && bitmap) {
|
||||
config.scrolling = ImVec2(-(bitmap->width() * config.global_scale - config.canvas_size.x) / 2.0f,
|
||||
-(bitmap->height() * config.global_scale - config.canvas_size.y) / 2.0f);
|
||||
DispatchConfigCallback(config.on_config_changed, config);
|
||||
DispatchConfig(config.on_config_changed, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +258,7 @@ void CanvasModals::RenderAdvancedPropertiesModal(const std::string& canvas_id,
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::Button("Apply Changes", ImVec2(120, 0))) {
|
||||
DispatchConfigCallback(config.on_config_changed, config);
|
||||
DispatchConfig(config.on_config_changed, config);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@@ -282,7 +278,7 @@ void CanvasModals::RenderAdvancedPropertiesModal(const std::string& canvas_id,
|
||||
config.is_draggable = false;
|
||||
config.auto_resize = false;
|
||||
config.scrolling = ImVec2(0, 0);
|
||||
DispatchConfigCallback(config.on_config_changed, config);
|
||||
DispatchConfig(config.on_config_changed, config);
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
@@ -316,7 +312,7 @@ void CanvasModals::RenderScalingControlsModal(const std::string& canvas_id,
|
||||
if (i > 0) ImGui::SameLine();
|
||||
if (ImGui::Button(preset_labels[i])) {
|
||||
config.global_scale = preset_values[i];
|
||||
DispatchScaleCallback(config.on_scale_changed, config);
|
||||
DispatchScale(config.on_scale_changed, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +331,7 @@ void CanvasModals::RenderScalingControlsModal(const std::string& canvas_id,
|
||||
if (i > 0) ImGui::SameLine();
|
||||
if (ImGui::Button(grid_labels[i])) {
|
||||
config.grid_step = grid_values[i];
|
||||
DispatchScaleCallback(config.on_scale_changed, config);
|
||||
DispatchScale(config.on_scale_changed, config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +356,7 @@ void CanvasModals::RenderScalingControlsModal(const std::string& canvas_id,
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::Button("Apply", ImVec2(120, 0))) {
|
||||
DispatchScaleCallback(config.on_scale_changed, config);
|
||||
DispatchScale(config.on_scale_changed, config);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
@@ -586,6 +582,5 @@ void CanvasModals::RenderSliderWithIcon(const std::string& label, const std::str
|
||||
ImGui::SliderFloat(("##" + label).c_str(), value, min_val, max_val, format);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
@@ -12,33 +12,9 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
void DispatchConfigCallback(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config);
|
||||
void DispatchScaleCallback(const std::function<void(const CanvasConfig&)>& callback,
|
||||
const CanvasConfig& config);
|
||||
|
||||
/**
|
||||
* @brief Canvas configuration options for modals
|
||||
*/
|
||||
struct CanvasConfig {
|
||||
ImVec2 canvas_size = ImVec2(0, 0);
|
||||
ImVec2 content_size = ImVec2(0, 0);
|
||||
float global_scale = 1.0f;
|
||||
float grid_step = 32.0f;
|
||||
bool enable_grid = true;
|
||||
bool enable_hex_labels = false;
|
||||
bool enable_custom_labels = false;
|
||||
bool enable_context_menu = true;
|
||||
bool is_draggable = false;
|
||||
bool auto_resize = false;
|
||||
ImVec2 scrolling = ImVec2(0, 0);
|
||||
|
||||
// Callbacks provide updated configuration state
|
||||
std::function<void(const CanvasConfig&)> on_config_changed;
|
||||
std::function<void(const CanvasConfig&)> on_scale_changed;
|
||||
};
|
||||
// Note: DispatchConfigCallback and DispatchScaleCallback are internal helpers
|
||||
// defined in canvas_modals.cc (not part of public API)
|
||||
|
||||
/**
|
||||
* @brief BPP conversion options
|
||||
@@ -175,7 +151,6 @@ class CanvasModals {
|
||||
const char* format = "%.2f");
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
void CanvasPerformanceIntegration::Initialize(const std::string& canvas_id) {
|
||||
canvas_id_ = canvas_id;
|
||||
@@ -607,6 +606,5 @@ void CanvasPerformanceManager::ClearAllIntegrations() {
|
||||
LOG_DEBUG("CanvasPerformance", "Cleared all canvas performance integrations");
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
/**
|
||||
* @brief Canvas performance metrics
|
||||
@@ -262,7 +261,6 @@ class CanvasPerformanceManager {
|
||||
std::unordered_map<std::string, std::shared_ptr<CanvasPerformanceIntegration>> integrations_;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
void CanvasUsageTracker::Initialize(const std::string& canvas_id) {
|
||||
canvas_id_ = canvas_id;
|
||||
@@ -127,6 +126,7 @@ std::string CanvasUsageTracker::GetUsageModeName(CanvasUsage usage) const {
|
||||
case CanvasUsage::kPaletteEditing: return "Palette Editing";
|
||||
case CanvasUsage::kBppConversion: return "BPP Conversion";
|
||||
case CanvasUsage::kPerformanceMode: return "Performance Mode";
|
||||
case CanvasUsage::kEntityManipulation: return "Entity Manipulation";
|
||||
case CanvasUsage::kUnknown: return "Unknown";
|
||||
default: return "Unknown";
|
||||
}
|
||||
@@ -142,6 +142,7 @@ ImVec4 CanvasUsageTracker::GetUsageModeColor(CanvasUsage usage) const {
|
||||
case CanvasUsage::kPaletteEditing: return ImVec4(0.8F, 0.2F, 1.0F, 1.0F); // Purple
|
||||
case CanvasUsage::kBppConversion: return ImVec4(0.2F, 1.0F, 1.0F, 1.0F); // Cyan
|
||||
case CanvasUsage::kPerformanceMode: return ImVec4(1.0F, 0.2F, 0.2F, 1.0F); // Red
|
||||
case CanvasUsage::kEntityManipulation: return ImVec4(0.4F, 0.8F, 1.0F, 1.0F); // Light Blue
|
||||
case CanvasUsage::kUnknown: return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
|
||||
default: return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
|
||||
}
|
||||
@@ -424,6 +425,5 @@ void CanvasUsageManager::ClearAllTrackers() {
|
||||
LOG_DEBUG("CanvasUsage", "Cleared all canvas usage trackers");
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
namespace canvas {
|
||||
|
||||
/**
|
||||
* @brief Canvas usage patterns and tracking
|
||||
@@ -24,6 +23,7 @@ enum class CanvasUsage {
|
||||
kPaletteEditing, // Palette editing mode
|
||||
kBppConversion, // BPP format conversion
|
||||
kPerformanceMode, // Performance monitoring mode
|
||||
kEntityManipulation, // Generic entity manipulation (insertion/editing/deletion)
|
||||
kUnknown // Unknown or mixed usage
|
||||
};
|
||||
|
||||
@@ -242,7 +242,6 @@ class CanvasUsageManager {
|
||||
std::unordered_map<std::string, std::shared_ptr<CanvasUsageTracker>> trackers_;
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -6,15 +6,20 @@
|
||||
#include "app/gfx/resource/arena.h"
|
||||
#include "app/gfx/types/snes_palette.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/gui/canvas/canvas_usage_tracker.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
|
||||
/**
|
||||
* @brief Configuration for canvas display and interaction
|
||||
* @brief Unified configuration for canvas display and interaction
|
||||
*
|
||||
* Consolidates all canvas configuration into a single struct, including
|
||||
* display settings, interaction state, and optional callbacks for updates.
|
||||
*/
|
||||
struct CanvasConfig {
|
||||
// Display settings
|
||||
bool enable_grid = true;
|
||||
bool enable_hex_labels = false;
|
||||
bool enable_custom_labels = false;
|
||||
@@ -23,11 +28,22 @@ struct CanvasConfig {
|
||||
bool auto_resize = false;
|
||||
bool clamp_rect_to_local_maps = true; // Prevent rectangle wrap across 512x512 boundaries
|
||||
bool use_theme_sizing = true; // Use theme-aware sizing instead of fixed sizes
|
||||
bool enable_metrics = false; // Enable performance/usage tracking
|
||||
|
||||
// Sizing and scale
|
||||
float grid_step = 32.0f;
|
||||
float global_scale = 1.0f;
|
||||
ImVec2 canvas_size = ImVec2(0, 0);
|
||||
ImVec2 content_size = ImVec2(0, 0); // Size of actual content (bitmap, etc.)
|
||||
ImVec2 scrolling = ImVec2(0, 0);
|
||||
bool custom_canvas_size = false;
|
||||
|
||||
// Usage tracking
|
||||
CanvasUsage usage_mode = CanvasUsage::kUnknown;
|
||||
|
||||
// Callbacks for configuration changes (used by modals)
|
||||
std::function<void(const CanvasConfig&)> on_config_changed;
|
||||
std::function<void(const CanvasConfig&)> on_scale_changed;
|
||||
|
||||
// Get theme-aware canvas toolbar height (when use_theme_sizing is true)
|
||||
float GetToolbarHeight() const;
|
||||
|
||||
Reference in New Issue
Block a user