From cd6a6d9478a28d2dcebf2a7fad6e769514161f95 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 5 Oct 2025 15:19:18 -0400 Subject: [PATCH] feat: Introduce UI Helper Functions and Refactor Color Management - Added ui_helpers.cc and ui_helpers.h to centralize UI-related helper functions, improving code organization and reducing boilerplate in ImGui usage. - Refactored color management in BppFormatUI to utilize new helper functions for success, warning, and error colors, enhancing theming consistency. - Updated AgentChatWidget and CanvasContextMenu to streamline UI rendering and improve maintainability by removing redundant code and enhancing functionality. - Removed canvas_utils_moved.cc and canvas_utils_moved.h to clean up the project structure, consolidating utility functions into more appropriate locations. --- src/app/editor/agent/agent_chat_widget.cc | 9 +- src/app/gui/bpp_format_ui.cc | 23 +- src/app/gui/canvas.cc | 182 +--------- src/app/gui/canvas/canvas_context_menu.cc | 115 ++++--- src/app/gui/canvas/canvas_context_menu.h | 17 +- src/app/gui/canvas/canvas_utils_moved.cc | 398 ---------------------- src/app/gui/canvas/canvas_utils_moved.h | 198 ----------- src/app/gui/gui_library.cmake | 1 + src/app/gui/ui_helpers.cc | 72 ++++ src/app/gui/ui_helpers.h | 46 +++ src/app/gui/widgets/palette_widget.h | 4 +- 11 files changed, 227 insertions(+), 838 deletions(-) delete mode 100644 src/app/gui/canvas/canvas_utils_moved.cc delete mode 100644 src/app/gui/canvas/canvas_utils_moved.h create mode 100644 src/app/gui/ui_helpers.cc create mode 100644 src/app/gui/ui_helpers.h diff --git a/src/app/editor/agent/agent_chat_widget.cc b/src/app/editor/agent/agent_chat_widget.cc index 01034ff0..421c318f 100644 --- a/src/app/editor/agent/agent_chat_widget.cc +++ b/src/app/editor/agent/agent_chat_widget.cc @@ -1045,8 +1045,7 @@ void AgentChatWidget::Draw() { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 3)); // Compact padding - // Removed RenderAgentConfigPanel - duplicates connection header - if (ImGui::BeginTable("##commands_and_multimodal", 2, ImGuiTableFlags_BordersInnerV)) { + if (ImGui::BeginTable("##commands_and_multimodal", 2)) { ImGui::TableSetupColumn("Commands", ImGuiTableColumnFlags_WidthFixed, 180); ImGui::TableSetupColumn("Multimodal", ImGuiTableColumnFlags_WidthFixed, ImGui::GetContentRegionAvail().x - 180); ImGui::TableNextRow(); @@ -1674,8 +1673,8 @@ void AgentChatWidget::RenderZ3EDCommandPanel() { // Dense header (no collapsing) ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.14f, 0.12f, 0.18f, 0.95f)); - ImGui::BeginChild("Z3ED_CommandsChild", ImVec2(0, 90), - true); // Reduced from 120 + ImGui::BeginChild("Z3ED_CommandsChild", ImVec2(0, 100), + true); ImGui::TextColored(command_color, ICON_MD_TERMINAL " Commands"); ImGui::Separator(); @@ -1755,7 +1754,7 @@ void AgentChatWidget::RenderZ3EDCommandPanel() { void AgentChatWidget::RenderRomSyncPanel() { ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.18f, 0.14f, 0.12f, 1.0f)); - ImGui::BeginChild("RomSync", ImVec2(0, 100), true); + ImGui::BeginChild("RomSync", ImVec2(0, 130), true); ImGui::Text(ICON_MD_STORAGE " ROM State"); ImGui::Separator(); diff --git a/src/app/gui/bpp_format_ui.cc b/src/app/gui/bpp_format_ui.cc index 105c6897..a19b3ded 100644 --- a/src/app/gui/bpp_format_ui.cc +++ b/src/app/gui/bpp_format_ui.cc @@ -5,6 +5,7 @@ #include "app/gfx/bpp_format_manager.h" #include "app/gfx/bitmap.h" +#include "app/gui/ui_helpers.h" #include "imgui/imgui.h" namespace yaze { @@ -58,11 +59,11 @@ bool BppFormatUI::RenderFormatSelector(gfx::Bitmap* bitmap, const gfx::SnesPalet ImVec4 efficiency_color; if (efficiency >= 80) { - efficiency_color = ImVec4(0, 1, 0, 1); // Green + efficiency_color = GetSuccessColor(); // Green } else if (efficiency >= 60) { - efficiency_color = ImVec4(1, 1, 0, 1); // Yellow + efficiency_color = GetWarningColor(); // Yellow } else { - efficiency_color = ImVec4(1, 0, 0, 1); // Red + efficiency_color = GetErrorColor(); // Red } ImGui::TextColored(efficiency_color, "Quality: %s", efficiency >= 80 ? "Excellent" : @@ -140,13 +141,13 @@ void BppFormatUI::RenderAnalysisPanel(const gfx::Bitmap& bitmap, const gfx::Snes ImGui::Text("Format Recommendations:"); if (used_colors <= 4) { - ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ 2BPP format would be optimal"); + ImGui::TextColored(GetSuccessColor(), "✓ 2BPP format would be optimal"); } else if (used_colors <= 8) { - ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ 3BPP format would be optimal"); + ImGui::TextColored(GetSuccessColor(), "✓ 3BPP format would be optimal"); } else if (used_colors <= 16) { - ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ 4BPP format would be optimal"); + ImGui::TextColored(GetSuccessColor(), "✓ 4BPP format would be optimal"); } else { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "⚠ 8BPP format is necessary"); + ImGui::TextColored(GetWarningColor(), "⚠ 8BPP format is necessary"); } // Memory usage comparison @@ -257,10 +258,10 @@ void BppFormatUI::RenderSheetAnalysis(const std::vector& sheet_data, in gfx::BppFormatManager::Get().GetFormatInfo(analysis.current_format).name.c_str()); if (analysis.was_converted) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "⚠ This sheet was converted"); + ImGui::TextColored(GetWarningColor(), "⚠ This sheet was converted"); ImGui::Text("Conversion History: %s", analysis.conversion_history.c_str()); } else { - ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ Original format preserved"); + ImGui::TextColored(GetSuccessColor(), "✓ Original format preserved"); } ImGui::Separator(); @@ -295,13 +296,13 @@ void BppFormatUI::RenderSheetAnalysis(const std::vector& sheet_data, in ImGui::Text("Recommendations:"); if (analysis.was_converted && analysis.palette_entries_used <= 16) { - ImGui::TextColored(ImVec4(0, 1, 0, 1), + ImGui::TextColored(GetSuccessColor(), "✓ Consider reverting to %s format for better compression", gfx::BppFormatManager::Get().GetFormatInfo(analysis.original_format).name.c_str()); } if (analysis.palette_entries_used < static_cast(palette.size()) / 2) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), + ImGui::TextColored(GetWarningColor(), "⚠ Palette is underutilized - consider optimization"); } diff --git a/src/app/gui/canvas.cc b/src/app/gui/canvas.cc index f3f3c8a5..b032190e 100644 --- a/src/app/gui/canvas.cc +++ b/src/app/gui/canvas.cc @@ -405,7 +405,7 @@ void Canvas::DrawContextMenu() { enable_context_menu_, draggable_, config_.auto_resize, scrolling_); context_menu_->Render( - context_id_, mouse_pos, bitmap_, + context_id_, mouse_pos, rom_, bitmap_, bitmap_ ? bitmap_->mutable_palette() : nullptr, [this](canvas::CanvasContextMenu::Command command, const canvas::CanvasConfig& updated_config) { @@ -497,187 +497,7 @@ void Canvas::DrawContextMenu() { return; } - static bool show_bitmap_data = false; - if (show_bitmap_data && bitmap_ != nullptr) { - static MemoryEditor mem_edit; - mem_edit.DrawWindow("Bitmap Data", (void*)bitmap_->data(), bitmap_->size(), - 0); - } - // Context menu (under default mouse threshold) - if (ImVec2 drag_delta = GetMouseDragDelta(ImGuiMouseButton_Right); - enable_context_menu_ && drag_delta.x == 0.0f && drag_delta.y == 0.0f) - OpenPopupOnItemClick(context_id_.c_str(), ImGuiPopupFlags_MouseButtonRight); - - // Contents of the Context Menu - if (ImGui::BeginPopup(context_id_.c_str())) { - // Draw custom context menu items first - for (const auto& item : context_menu_items_) { - DrawContextMenuItem(item); - } - - // Add separator if there are custom items - if (!context_menu_items_.empty()) { - ImGui::Separator(); - } - - // Default canvas menu items - if (MenuItem("Reset View", nullptr, false)) { - ResetView(); - } - if (MenuItem("Zoom to Fit", nullptr, false) && bitmap_) { - SetZoomToFit(*bitmap_); - } - if (MenuItem("Advanced Properties", nullptr, false)) { - ImGui::OpenPopup("Advanced Canvas Properties"); - } - ImGui::Separator(); - MenuItem("Show Grid", nullptr, &enable_grid_); - Selectable("Show Position Labels", &enable_hex_tile_labels_); - if (MenuItem("Edit Palette", nullptr, false) && bitmap_) { - ShowPaletteEditor(); - } - if (MenuItem("Color Analysis", nullptr, false) && bitmap_) { - ShowColorAnalysis(); - } - if (MenuItem("Scaling Controls", nullptr, false)) { - ImGui::OpenPopup("Scaling Controls"); - } - if (BeginMenu("Canvas Properties")) { - Text("Canvas Size: %.0f x %.0f", canvas_sz_.x, canvas_sz_.y); - Text("Global Scale: %.1f", global_scale_); - Text("Mouse Position: %.0f x %.0f", mouse_pos.x, mouse_pos.y); - EndMenu(); - } - if (bitmap_ != nullptr) { - if (BeginMenu("Bitmap Properties")) { - Text("Size: %.0f x %.0f", scaled_sz.x, scaled_sz.y); - Text("Pitch: %d", bitmap_->surface()->pitch); - Text("BitsPerPixel: %d", bitmap_->surface()->format->BitsPerPixel); - Text("BytesPerPixel: %d", bitmap_->surface()->format->BytesPerPixel); - MenuItem("Data", nullptr, &show_bitmap_data); - if (BeginMenu("Format")) { - if (MenuItem("Indexed")) { - bitmap_->Reformat(gfx::BitmapFormat::kIndexed); - Renderer::Get().UpdateBitmap(bitmap_); - } - if (MenuItem("4BPP")) { - bitmap_->Reformat(gfx::BitmapFormat::k4bpp); - Renderer::Get().UpdateBitmap(bitmap_); - } - if (MenuItem("8BPP")) { - bitmap_->Reformat(gfx::BitmapFormat::k8bpp); - Renderer::Get().UpdateBitmap(bitmap_); - } - - EndMenu(); - } - if (BeginMenu("ROM Palette Selection") && rom_) { - Text("Select ROM Palette Group:"); - - // Enhanced ROM palette group selection - if (palette_editor_) { - // Use our enhanced palette editor's ROM selection - if (MenuItem("Open Enhanced Palette Manager")) { - palette_editor_->ShowROMPaletteManager(); - } - - ImGui::Separator(); - - // Quick palette group selection - const char* palette_groups[] = { - "Overworld Main", "Overworld Aux", "Overworld Animated", - "Dungeon Main", "Global Sprites", "Armor", - "Swords"}; - - if (ImGui::Combo("Quick Palette Group", - (int*)&edit_palette_group_name_index_, - palette_groups, IM_ARRAYSIZE(palette_groups))) { - // Group selection changed - } - - ImGui::SetNextItemWidth(100.f); - if (ImGui::SliderInt("Palette Index", (int*)&edit_palette_index_, 0, - 7)) { - // Palette index changed - } - - // Apply button with enhanced functionality - if (ImGui::Button("Apply to Canvas") && bitmap_) { - if (palette_editor_->ApplyROMPalette( - bitmap_, edit_palette_group_name_index_, - edit_palette_index_)) { - // LOG_INFO( - // "Applied ROM palette group %d, index %d via context menu", - // edit_palette_group_name_index_, edit_palette_index_); - } - } - - // Direct palette editing with SelectablePalettePipeline - if (ImGui::TreeNode("Interactive Palette Editor")) { - if (rom_ && bitmap_) { - ImGui::Text("Interactive ROM Palette Editing"); - ImGui::Text("Selected Group: %s", - palette_groups[edit_palette_group_name_index_]); - - // Get the enhanced palette editor's ROM palette if available - if (const auto* rom_palette = - palette_editor_->GetSelectedROMPalette()) { - auto editable_palette = - const_cast(*rom_palette); - - if (ImGui::BeginChild("SelectablePalette", ImVec2(0, 200), - true)) { - // Use the existing SelectablePalettePipeline for interactive editing - gui::SelectablePalettePipeline(edit_palette_sub_index_, - refresh_graphics_, - editable_palette); - - if (refresh_graphics_) { - bitmap_->SetPaletteWithTransparent( - editable_palette, edit_palette_sub_index_); - Renderer::Get().UpdateBitmap(bitmap_); - refresh_graphics_ = false; - // LOG_INFO is undefined or missing required arguments; removed or fix as needed. - } - ImGui::Text( - "Load ROM palettes first using Enhanced Palette " - "Manager"); - } - } - } - ImGui::TreePop(); - } - } - EndMenu(); - } - if (BeginMenu("View Palette")) { - (void)DisplayEditablePalette(*bitmap_->mutable_palette(), "Palette", - true, 8); - EndMenu(); - } - EndMenu(); - } - } - ImGui::Separator(); - if (BeginMenu("Grid Tile Size")) { - if (MenuItem("8x8", nullptr, custom_step_ == 8.0f)) { - custom_step_ = 8.0f; - } - if (MenuItem("16x16", nullptr, custom_step_ == 16.0f)) { - custom_step_ = 16.0f; - } - if (MenuItem("32x32", nullptr, custom_step_ == 32.0f)) { - custom_step_ = 32.0f; - } - if (MenuItem("64x64", nullptr, custom_step_ == 64.0f)) { - custom_step_ = 64.0f; - } - EndMenu(); - } - - ImGui::EndPopup(); - } // Draw enhanced property dialogs ShowAdvancedCanvasProperties(); diff --git a/src/app/gui/canvas/canvas_context_menu.cc b/src/app/gui/canvas/canvas_context_menu.cc index 471d43fc..e7f0ea0f 100644 --- a/src/app/gui/canvas/canvas_context_menu.cc +++ b/src/app/gui/canvas/canvas_context_menu.cc @@ -4,11 +4,13 @@ #include #include +#include "app/core/window.h" #include "app/gfx/performance_profiler.h" #include "app/gfx/performance_dashboard.h" #include "app/gui/widgets/palette_widget.h" #include "app/gui/bpp_format_ui.h" #include "app/gui/icons.h" +#include "app/gui/color.h" #include "app/gui/canvas/canvas_modals.h" #include "imgui/imgui.h" @@ -30,6 +32,7 @@ void CanvasContextMenu::Initialize(const std::string& canvas_id) { canvas_id_ = canvas_id; enabled_ = true; current_usage_ = CanvasUsage::kTilePainting; + palette_editor_ = std::make_unique(); // Initialize canvas state canvas_size_ = ImVec2(0, 0); @@ -65,11 +68,10 @@ void CanvasContextMenu::ClearMenuItems() { usage_specific_items_.clear(); } -void CanvasContextMenu::Render( - const std::string& context_id, const ImVec2& mouse_pos, - const gfx::Bitmap* bitmap, const gfx::SnesPalette* palette, - const std::function& command_handler, - CanvasConfig current_config) { +void CanvasContextMenu::Render(const std::string& context_id, const ImVec2& mouse_pos, Rom* rom, + const gfx::Bitmap* bitmap, const gfx::SnesPalette* palette, + const std::function& command_handler, + CanvasConfig current_config) { if (!enabled_) return; // Context menu (under default mouse threshold) @@ -98,13 +100,13 @@ void CanvasContextMenu::Render( // Render bitmap operations if bitmap is available if (bitmap) { - RenderBitmapOperationsMenu(bitmap); + RenderBitmapOperationsMenu(const_cast(bitmap)); ImGui::Separator(); } - // Render palette operations if palette is available - if (palette) { - RenderPaletteOperationsMenu(palette); + // Render palette operations if bitmap is available + if (bitmap) { + RenderPaletteOperationsMenu(rom, const_cast(bitmap)); ImGui::Separator(); } @@ -151,11 +153,11 @@ void CanvasContextMenu::SetCanvasState(const ImVec2& canvas_size, global_scale_ = global_scale; grid_step_ = grid_step; enable_grid_ = enable_grid; - enable_hex_labels_ = enable_hex_labels; - enable_custom_labels_ = enable_custom_labels; - enable_context_menu_ = enable_context_menu; - is_draggable_ = is_draggable; - auto_resize_ = auto_resize; + enable_hex_labels_ = enable_hex_labels_; + enable_custom_labels_ = enable_custom_labels_; + enable_context_menu_ = enable_context_menu_; + is_draggable_ = is_draggable_; + auto_resize_ = auto_resize_; scrolling_ = scrolling; } @@ -289,43 +291,74 @@ void CanvasContextMenu::RenderCanvasPropertiesMenu( } } -void CanvasContextMenu::RenderBitmapOperationsMenu(const gfx::Bitmap* bitmap) { - if (ImGui::BeginMenu(ICON_MD_IMAGE " Bitmap Operations")) { +void CanvasContextMenu::RenderBitmapOperationsMenu(gfx::Bitmap* bitmap) { + if (!bitmap) return; + + if (ImGui::BeginMenu(ICON_MD_IMAGE " Bitmap Properties")) { ImGui::Text("Size: %d x %d", bitmap->width(), bitmap->height()); - ImGui::Text("Format: %s", "Unknown"); // Would need format detection - - if (ImGui::MenuItem("Edit Bitmap Data...")) { - // Open bitmap data editor + ImGui::Text("Pitch: %d", bitmap->surface()->pitch); + ImGui::Text("BitsPerPixel: %d", bitmap->surface()->format->BitsPerPixel); + ImGui::Text("BytesPerPixel: %d", bitmap->surface()->format->BytesPerPixel); + + if (ImGui::BeginMenu("Format")) { + if (ImGui::MenuItem("Indexed")) { + bitmap->Reformat(gfx::BitmapFormat::kIndexed); + core::Renderer::Get().UpdateBitmap(bitmap); + } + if (ImGui::MenuItem("4BPP")) { + bitmap->Reformat(gfx::BitmapFormat::k4bpp); + core::Renderer::Get().UpdateBitmap(bitmap); + } + if (ImGui::MenuItem("8BPP")) { + bitmap->Reformat(gfx::BitmapFormat::k8bpp); + core::Renderer::Get().UpdateBitmap(bitmap); + } + ImGui::EndMenu(); } - if (ImGui::MenuItem("Export Bitmap...")) { - // Export bitmap - } - if (ImGui::MenuItem("Import Bitmap...")) { - // Import bitmap - } - ImGui::EndMenu(); } } -void CanvasContextMenu::RenderPaletteOperationsMenu(const gfx::SnesPalette* palette) { +void CanvasContextMenu::RenderPaletteOperationsMenu(Rom* rom, gfx::Bitmap* bitmap) { + if (!bitmap) return; + if (ImGui::BeginMenu(ICON_MD_PALETTE " Palette Operations")) { - ImGui::Text("Colors: %zu", palette->size()); - if (ImGui::MenuItem("Edit Palette...")) { - // Open palette editor + palette_editor_->ShowPaletteEditor(*bitmap->mutable_palette(), "Palette Editor"); } if (ImGui::MenuItem("Color Analysis...")) { - // Open color analysis + palette_editor_->ShowColorAnalysis(*bitmap, "Color Analysis"); } - if (ImGui::MenuItem("Apply ROM Palette...")) { - // Apply ROM palette + + if (rom && ImGui::BeginMenu("ROM Palette Selection")) { + palette_editor_->Initialize(rom); + + // Render palette selector inline + ImGui::Text("Group:"); ImGui::SameLine(); + ImGui::InputScalar("##group", ImGuiDataType_U64, &edit_palette_group_name_index_); + ImGui::Text("Palette:"); ImGui::SameLine(); + ImGui::InputScalar("##palette", ImGuiDataType_U64, &edit_palette_index_); + + if (ImGui::Button("Apply to Canvas")) { + palette_editor_->ApplyROMPalette(bitmap, edit_palette_group_name_index_, edit_palette_index_); + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("View Palette")) { + DisplayEditablePalette(*bitmap->mutable_palette(), "Palette", true, 8); + ImGui::EndMenu(); } - ImGui::EndMenu(); } } +void CanvasContextMenu::DrawROMPaletteSelector() { + if (!palette_editor_) return; + + palette_editor_->DrawROMPaletteSelector(); +} + void CanvasContextMenu::RenderBppOperationsMenu(const gfx::Bitmap* bitmap) { if (ImGui::BeginMenu(ICON_MD_SWAP_HORIZ " BPP Operations")) { if (ImGui::MenuItem("Format Analysis...")) { @@ -506,31 +539,31 @@ void CanvasContextMenu::CreateDefaultMenuItems() { usage_specific_items_[CanvasUsage::kPerformanceMode].push_back(perf_item); } -CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateViewMenuItem(const std::string& label, +canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateViewMenuItem(const std::string& label, const std::string& icon, std::function callback) { return ContextMenuItem(label, icon, callback); } -CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateBitmapMenuItem(const std::string& label, +canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateBitmapMenuItem(const std::string& label, const std::string& icon, std::function callback) { return ContextMenuItem(label, icon, callback); } -CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreatePaletteMenuItem(const std::string& label, +canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreatePaletteMenuItem(const std::string& label, const std::string& icon, std::function callback) { return ContextMenuItem(label, icon, callback); } -CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreateBppMenuItem(const std::string& label, +canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreateBppMenuItem(const std::string& label, const std::string& icon, std::function callback) { return ContextMenuItem(label, icon, callback); } -CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreatePerformanceMenuItem(const std::string& label, +canvas::CanvasContextMenu::ContextMenuItem canvas::CanvasContextMenu::CreatePerformanceMenuItem(const std::string& label, const std::string& icon, std::function callback) { return ContextMenuItem(label, icon, callback); @@ -538,4 +571,4 @@ CanvasContextMenu::ContextMenuItem CanvasContextMenu::CreatePerformanceMenuItem( } // namespace canvas } // namespace gui -} // namespace yaze +} // namespace yaze \ No newline at end of file diff --git a/src/app/gui/canvas/canvas_context_menu.h b/src/app/gui/canvas/canvas_context_menu.h index f73156c4..4a7edef8 100644 --- a/src/app/gui/canvas/canvas_context_menu.h +++ b/src/app/gui/canvas/canvas_context_menu.h @@ -15,6 +15,10 @@ namespace yaze { namespace gui { + +// Forward declarations +class PaletteWidget; + namespace canvas { class CanvasContextMenu { @@ -64,6 +68,7 @@ class CanvasContextMenu { void Render(const std::string& context_id, const ImVec2& mouse_pos, + Rom* rom, const gfx::Bitmap* bitmap, const gfx::SnesPalette* palette, const std::function& command_handler, @@ -103,6 +108,14 @@ class CanvasContextMenu { bool auto_resize_ = false; ImVec2 scrolling_; + std::unique_ptr palette_editor_; + uint64_t edit_palette_group_name_index_ = 0; + uint64_t edit_palette_index_ = 0; + uint64_t edit_palette_sub_index_ = 0; + bool refresh_graphics_ = false; + + void DrawROMPaletteSelector(); + std::unordered_map> usage_specific_items_; std::vector global_items_; @@ -114,8 +127,8 @@ class CanvasContextMenu { CanvasConfig current_config); void RenderCanvasPropertiesMenu(const std::function& command_handler, CanvasConfig current_config); - void RenderBitmapOperationsMenu(const gfx::Bitmap* bitmap); - void RenderPaletteOperationsMenu(const gfx::SnesPalette* palette); + void RenderBitmapOperationsMenu(gfx::Bitmap* bitmap); + void RenderPaletteOperationsMenu(Rom* rom, gfx::Bitmap* bitmap); void RenderBppOperationsMenu(const gfx::Bitmap* bitmap); void RenderPerformanceMenu(); void RenderGridControlsMenu(const std::function& command_handler, diff --git a/src/app/gui/canvas/canvas_utils_moved.cc b/src/app/gui/canvas/canvas_utils_moved.cc deleted file mode 100644 index f035f0a7..00000000 --- a/src/app/gui/canvas/canvas_utils_moved.cc +++ /dev/null @@ -1,398 +0,0 @@ -#include "canvas_utils_moved.h" - -#include -#include "app/core/window.h" -#include "app/gfx/snes_palette.h" -#include "util/log.h" - -namespace yaze { -namespace gui { -namespace canvas { -namespace CanvasUtils { - -using core::Renderer; - -ImVec2 AlignToGrid(ImVec2 pos, float grid_step) { - return ImVec2(std::floor(pos.x / grid_step) * grid_step, - std::floor(pos.y / grid_step) * grid_step); -} - -float CalculateEffectiveScale(ImVec2 canvas_size, ImVec2 content_size, - float global_scale) { - if (content_size.x <= 0 || content_size.y <= 0) - return global_scale; - - float scale_x = (canvas_size.x * global_scale) / content_size.x; - float scale_y = (canvas_size.y * global_scale) / content_size.y; - return std::min(scale_x, scale_y); -} - -int GetTileIdFromPosition(ImVec2 mouse_pos, float tile_size, float scale, - int tiles_per_row) { - float scaled_tile_size = tile_size * scale; - int tile_x = static_cast(mouse_pos.x / scaled_tile_size); - int tile_y = static_cast(mouse_pos.y / scaled_tile_size); - - return tile_x + (tile_y * tiles_per_row); -} - -bool LoadROMPaletteGroups(Rom* rom, CanvasPaletteManager& palette_manager) { - if (!rom || palette_manager.palettes_loaded) { - return palette_manager.palettes_loaded; - } - - try { - const auto& palette_groups = rom->palette_group(); - palette_manager.rom_palette_groups.clear(); - palette_manager.palette_group_names.clear(); - - // Overworld palettes - if (palette_groups.overworld_main.size() > 0) { - palette_manager.rom_palette_groups.push_back( - palette_groups.overworld_main[0]); - palette_manager.palette_group_names.push_back("Overworld Main"); - } - if (palette_groups.overworld_aux.size() > 0) { - palette_manager.rom_palette_groups.push_back( - palette_groups.overworld_aux[0]); - palette_manager.palette_group_names.push_back("Overworld Aux"); - } - if (palette_groups.overworld_animated.size() > 0) { - palette_manager.rom_palette_groups.push_back( - palette_groups.overworld_animated[0]); - palette_manager.palette_group_names.push_back("Overworld Animated"); - } - - // Dungeon palettes - if (palette_groups.dungeon_main.size() > 0) { - palette_manager.rom_palette_groups.push_back( - palette_groups.dungeon_main[0]); - palette_manager.palette_group_names.push_back("Dungeon Main"); - } - - // Sprite palettes - if (palette_groups.global_sprites.size() > 0) { - palette_manager.rom_palette_groups.push_back( - palette_groups.global_sprites[0]); - palette_manager.palette_group_names.push_back("Global Sprites"); - } - if (palette_groups.armors.size() > 0) { - palette_manager.rom_palette_groups.push_back(palette_groups.armors[0]); - palette_manager.palette_group_names.push_back("Armor"); - } - if (palette_groups.swords.size() > 0) { - palette_manager.rom_palette_groups.push_back(palette_groups.swords[0]); - palette_manager.palette_group_names.push_back("Swords"); - } - - palette_manager.palettes_loaded = true; - LOG_INFO("Canvas", "Loaded %zu ROM palette groups", - palette_manager.rom_palette_groups.size()); - return true; - - } catch (const std::exception& e) { - LOG_ERROR("Canvas", "Failed to load ROM palette groups"); - return false; - } -} - -bool ApplyPaletteGroup(gfx::Bitmap* bitmap, - const CanvasPaletteManager& palette_manager, - int group_index, int palette_index) { - if (!bitmap || group_index < 0 || - group_index >= - static_cast(palette_manager.rom_palette_groups.size())) { - return false; - } - - try { - const auto& selected_palette = - palette_manager.rom_palette_groups[group_index]; - - // Apply the palette based on the index - if (palette_index >= 0 && palette_index < 8) { - bitmap->SetPaletteWithTransparent(selected_palette, palette_index); - } else { - bitmap->SetPalette(selected_palette); - } - - Renderer::Get().UpdateBitmap(bitmap); - LOG_INFO("Canvas", "Applied palette group %d, index %d to bitmap", - group_index, palette_index); - return true; - - } catch (const std::exception& e) { - LOG_ERROR("Canvas", "Failed to apply palette"); - return false; - } -} - -// Drawing utility functions -void DrawCanvasRect(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - int x, int y, int w, int h, ImVec4 color, - float global_scale) { - // Apply global scale to position and size - float scaled_x = x * global_scale; - float scaled_y = y * global_scale; - float scaled_w = w * global_scale; - float scaled_h = h * global_scale; - - ImVec2 origin(canvas_p0.x + scrolling.x + scaled_x, - canvas_p0.y + scrolling.y + scaled_y); - ImVec2 size(canvas_p0.x + scrolling.x + scaled_x + scaled_w, - canvas_p0.y + scrolling.y + scaled_y + scaled_h); - - uint32_t color_u32 = IM_COL32(color.x, color.y, color.z, color.w); - draw_list->AddRectFilled(origin, size, color_u32); - - // Add a black outline - ImVec2 outline_origin(origin.x - 1, origin.y - 1); - ImVec2 outline_size(size.x + 1, size.y + 1); - draw_list->AddRect(outline_origin, outline_size, IM_COL32(0, 0, 0, 255)); -} - -void DrawCanvasText(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - const std::string& text, int x, int y, float global_scale) { - // Apply global scale to text position - float scaled_x = x * global_scale; - float scaled_y = y * global_scale; - - ImVec2 text_pos(canvas_p0.x + scrolling.x + scaled_x, - canvas_p0.y + scrolling.y + scaled_y); - - // Draw text with black shadow for better visibility - draw_list->AddText(ImVec2(text_pos.x + 1, text_pos.y + 1), - IM_COL32(0, 0, 0, 255), text.c_str()); - draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 255), text.c_str()); -} - -void DrawCanvasOutline(ImDrawList* draw_list, ImVec2 canvas_p0, - ImVec2 scrolling, int x, int y, int w, int h, - uint32_t color) { - ImVec2 origin(canvas_p0.x + scrolling.x + x, canvas_p0.y + scrolling.y + y); - ImVec2 size(canvas_p0.x + scrolling.x + x + w, - canvas_p0.y + scrolling.y + y + h); - draw_list->AddRect(origin, size, color, 0, 0, 1.5f); -} - -void DrawCanvasOutlineWithColor(ImDrawList* draw_list, ImVec2 canvas_p0, - ImVec2 scrolling, int x, int y, int w, int h, - ImVec4 color) { - uint32_t color_u32 = - IM_COL32(color.x * 255, color.y * 255, color.z * 255, color.w * 255); - DrawCanvasOutline(draw_list, canvas_p0, scrolling, x, y, w, h, color_u32); -} - -// Grid utility functions -void DrawCanvasGridLines(ImDrawList* draw_list, ImVec2 canvas_p0, - ImVec2 canvas_p1, ImVec2 scrolling, float grid_step, - float global_scale) { - const uint32_t grid_color = IM_COL32(200, 200, 200, 50); - const float grid_thickness = 0.5f; - - float scaled_grid_step = grid_step * global_scale; - - for (float x = fmodf(scrolling.x, scaled_grid_step); - x < (canvas_p1.x - canvas_p0.x); x += scaled_grid_step) { - draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), - ImVec2(canvas_p0.x + x, canvas_p1.y), grid_color, - grid_thickness); - } - - for (float y = fmodf(scrolling.y, scaled_grid_step); - y < (canvas_p1.y - canvas_p0.y); y += scaled_grid_step) { - draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), - ImVec2(canvas_p1.x, canvas_p0.y + y), grid_color, - grid_thickness); - } -} - -void DrawCustomHighlight(ImDrawList* draw_list, ImVec2 canvas_p0, - ImVec2 scrolling, int highlight_tile_id, - float grid_step) { - if (highlight_tile_id == -1) - return; - - int tile_x = highlight_tile_id % 8; - int tile_y = highlight_tile_id / 8; - ImVec2 tile_pos(canvas_p0.x + scrolling.x + tile_x * grid_step, - canvas_p0.y + scrolling.y + tile_y * grid_step); - ImVec2 tile_pos_end(tile_pos.x + grid_step, tile_pos.y + grid_step); - - draw_list->AddRectFilled(tile_pos, tile_pos_end, IM_COL32(255, 0, 255, 255)); -} - -void DrawHexTileLabels(ImDrawList* draw_list, ImVec2 canvas_p0, - ImVec2 scrolling, ImVec2 canvas_sz, float grid_step, - float global_scale) { - float scaled_grid_step = grid_step * global_scale; - - for (float x = fmodf(scrolling.x, scaled_grid_step); - x < canvas_sz.x * global_scale; x += scaled_grid_step) { - for (float y = fmodf(scrolling.y, scaled_grid_step); - y < canvas_sz.y * global_scale; y += scaled_grid_step) { - int tile_x = (x - scrolling.x) / scaled_grid_step; - int tile_y = (y - scrolling.y) / scaled_grid_step; - int tile_id = tile_x + (tile_y * 16); - - char hex_id[8]; - snprintf(hex_id, sizeof(hex_id), "%02X", tile_id); - - draw_list->AddText(ImVec2(canvas_p0.x + x + (scaled_grid_step / 2) - 4, - canvas_p0.y + y + (scaled_grid_step / 2) - 4), - IM_COL32(255, 255, 255, 255), hex_id); - } - } -} - -// Layout and interaction utilities -ImVec2 CalculateCanvasSize(ImVec2 content_region, ImVec2 custom_size, - bool use_custom) { - return use_custom ? custom_size : content_region; -} - -ImVec2 CalculateScaledCanvasSize(ImVec2 canvas_size, float global_scale) { - return ImVec2(canvas_size.x * global_scale, canvas_size.y * global_scale); -} - -bool IsPointInCanvas(ImVec2 point, ImVec2 canvas_p0, ImVec2 canvas_p1) { - return point.x >= canvas_p0.x && point.x <= canvas_p1.x && - point.y >= canvas_p0.y && point.y <= canvas_p1.y; -} - -// Size reporting for ImGui table integration -ImVec2 CalculateMinimumCanvasSize(ImVec2 content_size, float global_scale, - float padding) { - // Calculate minimum size needed to display content with padding - ImVec2 min_size = ImVec2(content_size.x * global_scale + padding * 2, - content_size.y * global_scale + padding * 2); - - // Ensure minimum practical size - min_size.x = std::max(min_size.x, 64.0f); - min_size.y = std::max(min_size.y, 64.0f); - - return min_size; -} - -ImVec2 CalculatePreferredCanvasSize(ImVec2 content_size, float global_scale, - float min_scale) { - // Calculate preferred size with minimum scale constraint - float effective_scale = std::max(global_scale, min_scale); - ImVec2 preferred_size = ImVec2(content_size.x * effective_scale + 8.0f, - content_size.y * effective_scale + 8.0f); - - // Cap to reasonable maximum sizes for table integration - preferred_size.x = std::min(preferred_size.x, 800.0f); - preferred_size.y = std::min(preferred_size.y, 600.0f); - - return preferred_size; -} - -void ReserveCanvasSpace(ImVec2 canvas_size, const std::string& label) { - // Reserve space in ImGui layout so tables know the size - if (!label.empty()) { - ImGui::Text("%s", label.c_str()); - } - ImGui::Dummy(canvas_size); - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - - canvas_size.x); // Move back to start -} - -void SetNextCanvasSize(ImVec2 size, bool auto_resize) { - if (auto_resize) { - // Use auto-sizing child window for table integration - ImGui::SetNextWindowContentSize(size); - } else { - // Fixed size - ImGui::SetNextWindowSize(size); - } -} - -// High-level composite operations -void DrawCanvasGrid(const CanvasRenderContext& ctx, int highlight_tile_id) { - if (!ctx.enable_grid) - return; - - ctx.draw_list->PushClipRect(ctx.canvas_p0, ctx.canvas_p1, true); - - // Draw grid lines - DrawCanvasGridLines(ctx.draw_list, ctx.canvas_p0, ctx.canvas_p1, - ctx.scrolling, ctx.grid_step, ctx.global_scale); - - // Draw highlight if specified - if (highlight_tile_id != -1) { - DrawCustomHighlight(ctx.draw_list, ctx.canvas_p0, ctx.scrolling, - highlight_tile_id, ctx.grid_step * ctx.global_scale); - } - - // Draw hex labels if enabled - if (ctx.enable_hex_labels) { - DrawHexTileLabels(ctx.draw_list, ctx.canvas_p0, ctx.scrolling, - ImVec2(ctx.canvas_p1.x - ctx.canvas_p0.x, - ctx.canvas_p1.y - ctx.canvas_p0.y), - ctx.grid_step, ctx.global_scale); - } - - ctx.draw_list->PopClipRect(); -} - -void DrawCanvasOverlay(const CanvasRenderContext& ctx, - const ImVector& points, - const ImVector& selected_points) { - const ImVec2 origin(ctx.canvas_p0.x + ctx.scrolling.x, - ctx.canvas_p0.y + ctx.scrolling.y); - - // Draw hover points - for (int n = 0; n < points.Size; n += 2) { - ctx.draw_list->AddRect( - ImVec2(origin.x + points[n].x, origin.y + points[n].y), - ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), - IM_COL32(255, 255, 255, 255), 1.0f); - } - - // Draw selection rectangles - if (!selected_points.empty()) { - for (int n = 0; n < selected_points.size(); n += 2) { - ctx.draw_list->AddRect(ImVec2(origin.x + selected_points[n].x, - origin.y + selected_points[n].y), - ImVec2(origin.x + selected_points[n + 1].x + 0x10, - origin.y + selected_points[n + 1].y + 0x10), - IM_COL32(255, 255, 255, 255), 1.0f); - } - } -} - -void DrawCanvasLabels(const CanvasRenderContext& ctx, - const ImVector>& labels, - int current_labels, int tile_id_offset) { - if (current_labels >= labels.size()) - return; - - float scaled_grid_step = ctx.grid_step * ctx.global_scale; - - for (float x = fmodf(ctx.scrolling.x, scaled_grid_step); - x < (ctx.canvas_p1.x - ctx.canvas_p0.x); x += scaled_grid_step) { - for (float y = fmodf(ctx.scrolling.y, scaled_grid_step); - y < (ctx.canvas_p1.y - ctx.canvas_p0.y); y += scaled_grid_step) { - int tile_x = (x - ctx.scrolling.x) / scaled_grid_step; - int tile_y = (y - ctx.scrolling.y) / scaled_grid_step; - int tile_id = tile_x + (tile_y * tile_id_offset); - - if (tile_id >= labels[current_labels].size()) { - break; - } - - const std::string& label = labels[current_labels][tile_id]; - ctx.draw_list->AddText( - ImVec2(ctx.canvas_p0.x + x + (scaled_grid_step / 2) - tile_id_offset, - ctx.canvas_p0.y + y + (scaled_grid_step / 2) - tile_id_offset), - IM_COL32(255, 255, 255, 255), label.c_str()); - } - } -} - -} // namespace CanvasUtils -} // namespace canvas -} // namespace gui -} // namespace yaze diff --git a/src/app/gui/canvas/canvas_utils_moved.h b/src/app/gui/canvas/canvas_utils_moved.h deleted file mode 100644 index bbb64a7d..00000000 --- a/src/app/gui/canvas/canvas_utils_moved.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef YAZE_APP_GUI_CANVAS_CANVAS_UTILS_H -#define YAZE_APP_GUI_CANVAS_CANVAS_UTILS_H - -#include -#include -#include -#include "app/gfx/snes_palette.h" -#include "app/rom.h" -#include "imgui/imgui.h" - -namespace yaze { -namespace gui { -namespace canvas { - -/** - * @brief Configuration for canvas display and interaction - * - * Modern single-source-of-truth configuration structure. - * Replaces the dual state management pattern. - */ -struct CanvasConfig { - 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; - 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.) - bool custom_canvas_size = false; - ImVec2 scrolling = ImVec2(0, 0); - - // Modern callbacks for config updates - std::function on_config_changed; - std::function on_scale_changed; -}; - -/** - * @brief Selection state for canvas interactions - */ -struct CanvasSelection { - std::vector selected_tiles; - std::vector selected_points; - ImVec2 selected_tile_pos = ImVec2(-1, -1); - bool select_rect_active = false; - - void Clear() { - selected_tiles.clear(); - selected_points.clear(); - selected_tile_pos = ImVec2(-1, -1); - select_rect_active = false; - } -}; - -/** - * @brief Palette management state for canvas - */ -struct CanvasPaletteManager { - std::vector rom_palette_groups; - std::vector palette_group_names; - gfx::SnesPalette original_palette; - bool palettes_loaded = false; - int current_group_index = 0; - int current_palette_index = 0; - - void Clear() { - rom_palette_groups.clear(); - palette_group_names.clear(); - original_palette.clear(); - palettes_loaded = false; - current_group_index = 0; - current_palette_index = 0; - } -}; - -/** - * @brief Context menu item configuration - */ -struct CanvasContextMenuItem { - std::string label; - std::string shortcut; - std::function callback; - std::function enabled_condition = []() { return true; }; - std::vector subitems; -}; - -/** - * @brief Render context for canvas drawing operations - */ -struct CanvasRenderContext { - ImDrawList* draw_list; - ImVec2 canvas_p0; - ImVec2 canvas_p1; - ImVec2 scrolling; - float global_scale; - bool enable_grid; - bool enable_hex_labels; - float grid_step; -}; - -/** - * @brief Utility functions for canvas operations - * - * Stateless utilities for common canvas operations. - * Following ImGui design pattern of pure helper functions. - */ -namespace CanvasUtils { - -// ==================== Core Utilities (Stateless) ==================== - -/** - * @brief Align position to grid - * Pure function - no side effects - */ -ImVec2 AlignToGrid(ImVec2 pos, float grid_step); - -/** - * @brief Calculate effective scale for content - */ -float CalculateEffectiveScale(ImVec2 canvas_size, ImVec2 content_size, float global_scale); - -/** - * @brief Get tile ID from mouse position - */ -int GetTileIdFromPosition(ImVec2 mouse_pos, float tile_size, float scale, int tiles_per_row); - -// ==================== Palette Management ==================== - -bool LoadROMPaletteGroups(Rom* rom, CanvasPaletteManager& palette_manager); -bool ApplyPaletteGroup(gfx::Bitmap* bitmap, const CanvasPaletteManager& palette_manager, - int group_index, int palette_index); - -// ==================== Drawing Utilities ==================== - -void DrawCanvasRect(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - int x, int y, int w, int h, ImVec4 color, float global_scale); - -void DrawCanvasText(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - const std::string& text, int x, int y, float global_scale); - -void DrawCanvasOutline(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - int x, int y, int w, int h, uint32_t color = IM_COL32(255, 255, 255, 200)); - -void DrawCanvasOutlineWithColor(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - int x, int y, int w, int h, ImVec4 color); - -// ==================== Grid Utilities ==================== - -void DrawCanvasGridLines(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 canvas_p1, - ImVec2 scrolling, float grid_step, float global_scale); - -void DrawCustomHighlight(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - int highlight_tile_id, float grid_step); - -void DrawHexTileLabels(ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling, - ImVec2 canvas_sz, float grid_step, float global_scale); - -// ==================== Layout Utilities ==================== - -ImVec2 CalculateCanvasSize(ImVec2 content_region, ImVec2 custom_size, bool use_custom); -ImVec2 CalculateScaledCanvasSize(ImVec2 canvas_size, float global_scale); -bool IsPointInCanvas(ImVec2 point, ImVec2 canvas_p0, ImVec2 canvas_p1); - -// ==================== Size Reporting for Tables ==================== - -ImVec2 CalculateMinimumCanvasSize(ImVec2 content_size, float global_scale, float padding = 4.0f); -ImVec2 CalculatePreferredCanvasSize(ImVec2 content_size, float global_scale, float min_scale = 1.0f); -void ReserveCanvasSpace(ImVec2 canvas_size, const std::string& label = ""); -void SetNextCanvasSize(ImVec2 size, bool auto_resize = false); - -// ==================== Composite Operations ==================== - -void DrawCanvasGrid(const CanvasRenderContext& ctx, int highlight_tile_id = -1); -void DrawCanvasOverlay(const CanvasRenderContext& ctx, const ImVector& points, - const ImVector& selected_points); -void DrawCanvasLabels(const CanvasRenderContext& ctx, const ImVector>& labels, - int current_labels, int tile_id_offset); - -} // namespace CanvasUtils - -} // namespace canvas - -// ==================== Compatibility Aliases (gui namespace) ==================== - -// For backward compatibility, provide aliases in gui namespace -using CanvasConfig = canvas::CanvasConfig; -using CanvasSelection = canvas::CanvasSelection; -using CanvasPaletteManager = canvas::CanvasPaletteManager; -using CanvasContextMenuItem = canvas::CanvasContextMenuItem; - -namespace CanvasUtils = canvas::CanvasUtils; - -} // namespace gui -} // namespace yaze - -#endif // YAZE_APP_GUI_CANVAS_CANVAS_UTILS_H diff --git a/src/app/gui/gui_library.cmake b/src/app/gui/gui_library.cmake index b7c5d22e..9c4fc616 100644 --- a/src/app/gui/gui_library.cmake +++ b/src/app/gui/gui_library.cmake @@ -15,6 +15,7 @@ set( app/gui/widgets/widget_id_registry.cc app/gui/widgets/widget_auto_register.cc app/gui/widgets/widget_state_capture.cc + app/gui/ui_helpers.cc # Canvas system components app/gui/canvas/canvas_modals.cc app/gui/canvas/canvas_context_menu.cc diff --git a/src/app/gui/ui_helpers.cc b/src/app/gui/ui_helpers.cc new file mode 100644 index 00000000..06e59f41 --- /dev/null +++ b/src/app/gui/ui_helpers.cc @@ -0,0 +1,72 @@ +#include "app/gui/ui_helpers.h" +#include "app/gui/theme_manager.h" +#include "app/gui/icons.h" +#include "imgui/imgui.h" +#include "imgui/imgui_internal.h" + +namespace yaze { +namespace gui { + +ImVec4 GetThemeColor(ImGuiCol idx) { + return ImGui::GetStyle().Colors[idx]; +} + +ImVec4 GetSuccessColor() { + const auto& theme = ThemeManager::Get().GetCurrentTheme(); + return ConvertColorToImVec4(theme.success); +} + +ImVec4 GetWarningColor() { + const auto& theme = ThemeManager::Get().GetCurrentTheme(); + return ConvertColorToImVec4(theme.warning); +} + +ImVec4 GetErrorColor() { + const auto& theme = ThemeManager::Get().GetCurrentTheme(); + return ConvertColorToImVec4(theme.error); +} + +ImVec4 GetInfoColor() { + const auto& theme = ThemeManager::Get().GetCurrentTheme(); + return ConvertColorToImVec4(theme.info); +} + +ImVec4 GetAccentColor() { + const auto& theme = ThemeManager::Get().GetCurrentTheme(); + return ConvertColorToImVec4(theme.accent); +} + +void BeginField(const char* label) { + ImGui::BeginGroup(); + ImGui::TextUnformatted(label); + ImGui::SameLine(); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.6f); +} + +void EndField() { + ImGui::PopItemWidth(); + ImGui::EndGroup(); +} + +bool IconButton(const char* icon, const char* label, const ImVec2& size) { + std::string button_text = std::string(icon) + " " + std::string(label); + return ImGui::Button(button_text.c_str(), size); +} + +void HelpMarker(const char* desc) { + ImGui::TextDisabled(ICON_MD_HELP_OUTLINE); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +void SeparatorText(const char* label) { + ImGui::SeparatorText(label); +} + +} // namespace gui +} // namespace yaze diff --git a/src/app/gui/ui_helpers.h b/src/app/gui/ui_helpers.h new file mode 100644 index 00000000..8e681d16 --- /dev/null +++ b/src/app/gui/ui_helpers.h @@ -0,0 +1,46 @@ +#ifndef YAZE_APP_GUI_UI_HELPERS_H +#define YAZE_APP_GUI_UI_HELPERS_H + +#include "imgui/imgui.h" +#include + +namespace yaze { +namespace gui { + +// A collection of helper functions and widgets to standardize UI development +// and reduce boilerplate ImGui code. + +// --- Theming and Colors --- + +// Gets a color from the current theme. +ImVec4 GetThemeColor(ImGuiCol idx); + +// Gets a semantic color from the current theme. +ImVec4 GetSuccessColor(); +ImVec4 GetWarningColor(); +ImVec4 GetErrorColor(); +ImVec4 GetInfoColor(); +ImVec4 GetAccentColor(); + +// --- Layout Helpers --- + +// Begins a standard row for a label and a widget. +void BeginField(const char* label); +// Ends a field row. +void EndField(); + +// --- Widget Wrappers --- + +// A button with an icon from the Material Design icon font. +bool IconButton(const char* icon, const char* label, const ImVec2& size = ImVec2(0, 0)); + +// A help marker that shows a tooltip on hover. +void HelpMarker(const char* desc); + +// A separator with centered text. +void SeparatorText(const char* label); + +} // namespace gui +} // namespace yaze + +#endif // YAZE_APP_GUI_UI_HELPERS_H diff --git a/src/app/gui/widgets/palette_widget.h b/src/app/gui/widgets/palette_widget.h index 91b6d296..23a2bd12 100644 --- a/src/app/gui/widgets/palette_widget.h +++ b/src/app/gui/widgets/palette_widget.h @@ -69,10 +69,10 @@ public: bool IsROMLoaded() const { return rom_ != nullptr; } int GetCurrentGroupIndex() const { return current_group_index_; } int GetCurrentPaletteIndex() const { return current_palette_index_; } - + void DrawROMPaletteSelector(); + private: void DrawPaletteGrid(gfx::SnesPalette& palette, int cols = 8); - void DrawROMPaletteSelector(); void DrawColorEditControls(gfx::SnesColor& color, int color_index); void DrawPaletteAnalysis(const gfx::SnesPalette& palette); void LoadROMPalettes();