refactor(gui): reorganize GUI includes and introduce new components

- Updated include paths for various GUI-related headers to improve organization and clarity.
- Introduced new components for better modularity, including PaletteEditorWidget and EditorCardManager.
- Refactored existing code to utilize the new components, ensuring consistency across the GUI subsystem.

Benefits:
- Enhances maintainability and readability of the GUI code.
- Facilitates future enhancements and optimizations within the GUI subsystem.
This commit is contained in:
scawful
2025-10-13 10:21:03 -04:00
parent 6374da6194
commit 58f3213c62
139 changed files with 890 additions and 1006 deletions

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/agent_chat_widget.h"
#include "app/gui/app/agent_chat_widget.h"
#include <algorithm>
#include <iostream>

View File

@@ -1,10 +1,10 @@
#include "app/gui/background_renderer.h"
#include "app/gui/app/background_renderer.h"
#include <algorithm>
#include <cmath>
#include "app/core/timing.h"
#include "app/gui/theme_manager.h"
#include "app/gui/core/theme_manager.h"
#include "imgui/imgui.h"
#ifndef M_PI

View File

@@ -2,7 +2,11 @@
#define YAZE_APP_EDITOR_UI_BACKGROUND_RENDERER_H
#include "imgui/imgui.h"
#include "app/gui/color.h"
#include <memory>
#include <vector>
#include "app/gui/core/color.h"
#include "app/rom.h"
namespace yaze {
namespace gui {

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/collaboration_panel.h"
#include "app/gui/app/collaboration_panel.h"
#include <algorithm>
#include <ctime>

View File

@@ -4,8 +4,8 @@
#include <cstdio>
#include "absl/strings/str_format.h"
#include "app/gui/icons.h"
#include "app/gui/theme_manager.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/theme_manager.h"
#include "imgui/imgui.h"
namespace yaze {

View File

@@ -1,13 +1,13 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include "app/gui/editor_layout.h"
#include "app/gui/app/editor_layout.h"
#include "absl/strings/str_format.h"
#include "app/gui/icons.h"
#include "app/gui/input.h"
#include "app/gui/ui_helpers.h"
#include "app/gui/widgets/widget_measurement.h"
#include "app/gui/widgets/widget_id_registry.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/input.h"
#include "app/gui/core/ui_helpers.h"
#include "app/gui/automation/widget_measurement.h"
#include "app/gui/automation/widget_id_registry.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/widget_auto_register.h"
#include "app/gui/automation/widget_auto_register.h"
#include <vector>

View File

@@ -1,10 +1,10 @@
#ifndef YAZE_APP_GUI_WIDGETS_WIDGET_AUTO_REGISTER_H_
#define YAZE_APP_GUI_WIDGETS_WIDGET_AUTO_REGISTER_H_
#ifndef YAZE_APP_GUI_AUTOMATION_WIDGET_AUTO_REGISTER_H_
#define YAZE_APP_GUI_AUTOMATION_WIDGET_AUTO_REGISTER_H_
#include <string>
#include "imgui/imgui.h"
#include "app/gui/widgets/widget_id_registry.h"
#include "app/gui/automation/widget_id_registry.h"
#include "absl/strings/str_cat.h"
/**
@@ -260,5 +260,5 @@ inline void RegisterTable(const char* table_name, const std::string& description
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_WIDGETS_WIDGET_AUTO_REGISTER_H_
#endif // YAZE_APP_GUI_AUTOMATION_WIDGET_AUTO_REGISTER_H_

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/widget_id_registry.h"
#include "app/gui/automation/widget_id_registry.h"
#include <algorithm>
#include <chrono>

View File

@@ -1,5 +1,5 @@
#ifndef YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
#define YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
#ifndef YAZE_APP_GUI_AUTOMATION_WIDGET_ID_REGISTRY_H_
#define YAZE_APP_GUI_AUTOMATION_WIDGET_ID_REGISTRY_H_
#include <cstdint>
#include <optional>
@@ -173,4 +173,4 @@ class WidgetIdRegistry {
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_WIDGETS_WIDGET_ID_REGISTRY_H_
#endif // YAZE_APP_GUI_AUTOMATION_WIDGET_ID_REGISTRY_H_

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/widget_measurement.h"
#include "app/gui/automation/widget_measurement.h"
#include "absl/strings/str_format.h"
#include "imgui/imgui.h"

View File

@@ -1,4 +1,4 @@
#include "app/gui/widgets/widget_state_capture.h"
#include "app/gui/automation/widget_state_capture.h"
#include "absl/strings/str_format.h"
#if defined(YAZE_ENABLE_IMGUI_TEST_ENGINE) && YAZE_ENABLE_IMGUI_TEST_ENGINE

View File

@@ -5,7 +5,7 @@
#include "app/gfx/util/bpp_format_manager.h"
#include "app/gfx/core/bitmap.h"
#include "app/gui/ui_helpers.h"
#include "app/gui/core/ui_helpers.h"
#include "imgui/imgui.h"
namespace yaze {

View File

@@ -5,9 +5,9 @@
#include "app/gfx/util/bpp_format_manager.h"
#include "app/gfx/core/bitmap.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gui/style.h"
#include "canvas/canvas_utils.h"
#include "canvas/canvas_automation_api.h"
#include "app/gui/core/style.h"
#include "app/gui/canvas/canvas_utils.h"
#include "app/gui/canvas/canvas_automation_api.h"
#include "imgui/imgui.h"
namespace yaze::gui {
@@ -124,7 +124,7 @@ void Canvas::InitializeDefaults() {
selection_.Clear();
// Initialize palette editor
palette_editor_ = std::make_unique<PaletteWidget>();
palette_editor_ = std::make_unique<PaletteEditorWidget>();
// Initialize interaction handler
interaction_handler_.Initialize(canvas_id_);

View File

@@ -11,10 +11,10 @@
#include "app/gfx/core/bitmap.h"
#include "app/rom.h"
#include "canvas/canvas_utils.h"
#include "app/gui/widgets/palette_widget.h"
#include "app/gui/canvas/canvas_utils.h"
#include "app/gui/widgets/palette_editor_widget.h"
#include "app/gfx/util/bpp_format_manager.h"
#include "canvas/bpp_format_ui.h"
#include "app/gui/canvas/bpp_format_ui.h"
#include "app/gui/canvas/canvas_modals.h"
#include "app/gui/canvas/canvas_context_menu.h"
#include "app/gui/canvas/canvas_usage_tracker.h"
@@ -411,7 +411,7 @@ class Canvas {
gfx::IRenderer* renderer_ = nullptr;
CanvasConfig config_;
CanvasSelection selection_;
std::unique_ptr<PaletteWidget> palette_editor_;
std::unique_ptr<PaletteEditorWidget> palette_editor_;
// Automation API (lazy-initialized on first access)
std::unique_ptr<CanvasAutomationAPI> automation_api_;

View File

@@ -3,7 +3,7 @@
#include <algorithm>
#include <cmath>
#include "app/gui/canvas.h"
#include "app/gui/canvas/canvas.h"
namespace yaze {
namespace gui {

View File

@@ -3,10 +3,11 @@
#include "app/gfx/resource/arena.h"
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gfx/debug/performance/performance_dashboard.h"
#include "app/gui/widgets/palette_widget.h"
#include "app/gui/icons.h"
#include "app/gui/color.h"
#include "app/gui/widgets/palette_editor_widget.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/color.h"
#include "app/gui/canvas/canvas_modals.h"
#include "app/gui/widgets/palette_editor_widget.h"
#include "imgui/imgui.h"
namespace yaze {
@@ -27,7 +28,7 @@ void CanvasContextMenu::Initialize(const std::string& canvas_id) {
canvas_id_ = canvas_id;
enabled_ = true;
current_usage_ = CanvasUsage::kTilePainting;
palette_editor_ = std::make_unique<PaletteWidget>();
palette_editor_ = std::make_unique<PaletteEditorWidget>();
// Initialize canvas state
canvas_size_ = ImVec2(0, 0);

View File

@@ -8,7 +8,7 @@
#include "app/gfx/core/bitmap.h"
#include "app/gfx/types/snes_palette.h"
#include "app/gui/icons.h"
#include "app/gui/core/icons.h"
#include "app/gui/canvas/canvas_modals.h"
#include "canvas_usage_tracker.h"
#include "imgui/imgui.h"
@@ -17,7 +17,7 @@ namespace yaze {
namespace gui {
// Forward declarations
class PaletteWidget;
class PaletteEditorWidget;
namespace canvas {
@@ -108,7 +108,7 @@ class CanvasContextMenu {
bool auto_resize_ = false;
ImVec2 scrolling_;
std::unique_ptr<PaletteWidget> palette_editor_;
std::unique_ptr<PaletteEditorWidget> palette_editor_;
uint64_t edit_palette_group_name_index_ = 0;
uint64_t edit_palette_index_ = 0;
uint64_t edit_palette_sub_index_ = 0;

View File

@@ -6,9 +6,9 @@
#include "app/gfx/debug/performance/performance_profiler.h"
#include "app/gfx/debug/performance/performance_dashboard.h"
#include "app/gui/widgets/palette_widget.h"
#include "app/gui/widgets/palette_editor_widget.h"
#include "app/gui/canvas/bpp_format_ui.h"
#include "app/gui/icons.h"
#include "app/gui/core/icons.h"
#include "imgui/imgui.h"
namespace yaze {
@@ -422,8 +422,8 @@ void CanvasModals::RenderPaletteEditorModal(const std::string& canvas_id,
ImGui::Separator();
// Use the existing PaletteWidget
static std::unique_ptr<gui::PaletteWidget> palette_editor =
std::make_unique<gui::PaletteWidget>();
static std::unique_ptr<gui::PaletteEditorWidget> palette_editor =
std::make_unique<gui::PaletteEditorWidget>();
if (options.palette) {
palette_editor->ShowPaletteEditor(*options.palette, modal_title);
@@ -455,8 +455,8 @@ void CanvasModals::RenderColorAnalysisModal(const std::string& canvas_id,
ImGui::Separator();
// Use the existing PaletteWidget for color analysis
static std::unique_ptr<gui::PaletteWidget> palette_editor =
std::make_unique<gui::PaletteWidget>();
static std::unique_ptr<gui::PaletteEditorWidget> palette_editor =
std::make_unique<gui::PaletteEditorWidget>();
if (options.bitmap) {
palette_editor->ShowColorAnalysis(*options.bitmap, modal_title);

View File

@@ -1,9 +1,13 @@
#include "app/gui/layout_helpers.h"
#include "app/gui/core/layout_helpers.h"
#include <vector>
#include "absl/strings/str_format.h"
#include "app/gui/core/icons.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#include "app/gui/theme_manager.h"
#include "app/gui/color.h"
#include "app/gui/core/theme_manager.h"
#include "app/gui/core/color.h"
namespace yaze {
namespace gui {

View File

@@ -1,8 +1,11 @@
#ifndef YAZE_APP_GUI_LAYOUT_HELPERS_H
#define YAZE_APP_GUI_LAYOUT_HELPERS_H
#include <vector>
#include "absl/strings/str_format.h"
#include "app/gui/core/theme_manager.h"
#include "imgui/imgui.h"
#include "app/gui/theme_manager.h"
namespace yaze {
namespace gui {

View File

@@ -1,13 +1,13 @@
#include "style.h"
#include "app/gui/core/style.h"
#include <algorithm>
#include "util/file_util.h"
#include "app/gui/theme_manager.h"
#include "app/gui/background_renderer.h"
#include "app/gui/core/theme_manager.h"
#include "app/gui/app/background_renderer.h"
#include "app/platform/font_loader.h"
#include "app/gui/color.h"
#include "app/gui/icons.h"
#include "app/gui/core/color.h"
#include "app/gui/core/icons.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#include "util/log.h"

View File

@@ -7,8 +7,8 @@
#include "absl/strings/string_view.h"
#include "app/gfx/core/bitmap.h"
#include "app/gui/color.h"
#include "app/gui/modules/text_editor.h"
#include "app/gui/core/color.h"
#include "app/gui/widgets/text_editor.h"
#include "imgui/imgui.h"
namespace yaze {

View File

@@ -11,10 +11,11 @@
#include "absl/strings/str_split.h"
#include "util/file_util.h"
#include "util/platform_paths.h"
#include "app/gui/icons.h"
#include "app/gui/style.h" // For ColorsYaze function
#include "app/gui/core/icons.h"
#include "app/gui/core/style.h" // For ColorsYaze function
#include "imgui/imgui.h"
#include "util/log.h"
#include "nlohmann/json.hpp"
namespace yaze {
namespace gui {

View File

@@ -7,7 +7,7 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "app/gui/color.h"
#include "app/gui/core/color.h"
#include "imgui/imgui.h"
namespace yaze {

View File

@@ -1,8 +1,9 @@
#include "app/gui/ui_helpers.h"
#include "app/gui/core/ui_helpers.h"
#include "app/gui/color.h"
#include "app/gui/icons.h"
#include "app/gui/theme_manager.h"
#include "absl/strings/str_format.h"
#include "app/gui/core/icons.h"
#include "app/gui/core/color.h"
#include "app/gui/core/theme_manager.h"
#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"

View File

@@ -1,7 +1,25 @@
set(
YAZE_GUI_SRC
app/gui/canvas.cc
# ==============================================================================
# GUI Library Refactoring (see docs/gui-refactor.md)
# ==============================================================================
# The monolithic yaze_gui has been decomposed into smaller, layered libraries
# to improve build times and code organization. The yaze_gui target is now
# an INTERFACE library that aggregates these components for backward
# compatibility.
# ==============================================================================
# 1. Define Source Groups for each sub-library
set(GUI_CORE_SRC
app/gui/core/color.cc
app/gui/core/input.cc
app/gui/core/layout_helpers.cc
app/gui/core/style.cc
app/gui/core/theme_manager.cc
app/gui/core/ui_helpers.cc
)
set(CANVAS_SRC
app/gui/canvas/bpp_format_ui.cc
app/gui/canvas/canvas.cc
app/gui/canvas/canvas_automation_api.cc
app/gui/canvas/canvas_context_menu.cc
app/gui/canvas/canvas_interaction_handler.cc
@@ -9,61 +27,89 @@ set(
app/gui/canvas/canvas_performance_integration.cc
app/gui/canvas/canvas_usage_tracker.cc
app/gui/canvas/canvas_utils.cc
app/gui/color.cc
app/gui/editor_card_manager.cc
app/gui/editor_layout.cc
app/gui/input.cc
app/gui/layout_helpers.cc
app/gui/themed_widgets.cc
app/gui/modules/asset_browser.cc
app/gui/modules/text_editor.cc
app/gui/style.cc
app/gui/theme_manager.cc
app/gui/ui_helpers.cc
app/gui/background_renderer.cc # Moved from yaze_editor (used by style.cc)
app/gui/widgets/agent_chat_widget.cc
app/gui/widgets/collaboration_panel.cc
)
set(GUI_WIDGETS_SRC
app/gui/widgets/asset_browser.cc
app/gui/widgets/dungeon_object_emulator_preview.cc
app/gui/widgets/palette_editor_widget.cc
app/gui/widgets/palette_widget.cc
app/gui/widgets/text_editor.cc
app/gui/widgets/themed_widgets.cc
app/gui/widgets/tile_selector_widget.cc
app/gui/widgets/widget_auto_register.cc
app/gui/widgets/widget_id_registry.cc
app/gui/widgets/widget_measurement.cc
app/gui/widgets/widget_state_capture.cc
# Canvas system components
)
# ==============================================================================
# Yaze GUI Library
# ==============================================================================
# This library contains all GUI-related functionality:
# - Canvas system
# - ImGui widgets and utilities
# - Input handling
# - Theme management
# - Color utilities
# - Background rendering
#
# Dependencies: yaze_gfx, yaze_util, ImGui, SDL2
# ==============================================================================
add_library(yaze_gui STATIC ${YAZE_GUI_SRC})
target_precompile_headers(yaze_gui PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/src/yaze_pch.h>"
set(GUI_AUTOMATION_SRC
app/gui/automation/widget_auto_register.cc
app/gui/automation/widget_id_registry.cc
app/gui/automation/widget_measurement.cc
app/gui/automation/widget_state_capture.cc
)
target_include_directories(yaze_gui PUBLIC
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/lib
${CMAKE_SOURCE_DIR}/src/lib/imgui
${CMAKE_SOURCE_DIR}/incl
${SDL2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
set(GUI_APP_SRC
app/gui/app/agent_chat_widget.cc
app/gui/app/background_renderer.cc
app/gui/app/collaboration_panel.cc
app/gui/app/editor_card_manager.cc
app/gui/app/editor_layout.cc
)
target_link_libraries(yaze_gui PUBLIC
# 2. Create Static Libraries and Establish Link Dependencies
add_library(yaze_gui_core STATIC ${GUI_CORE_SRC})
add_library(yaze_canvas STATIC ${CANVAS_SRC})
add_library(yaze_gui_widgets STATIC ${GUI_WIDGETS_SRC})
add_library(yaze_gui_automation STATIC ${GUI_AUTOMATION_SRC})
add_library(yaze_gui_app STATIC ${GUI_APP_SRC})
# Link dependencies between the new libraries
target_link_libraries(yaze_gui_core PUBLIC yaze_util ImGui nlohmann_json::nlohmann_json)
target_link_libraries(yaze_canvas PUBLIC yaze_gui_core yaze_gfx)
target_link_libraries(yaze_gui_widgets PUBLIC yaze_gui_core yaze_gfx)
target_link_libraries(yaze_gui_automation PUBLIC yaze_gui_core)
target_link_libraries(yaze_gui_app PUBLIC yaze_gui_core yaze_gui_widgets yaze_gui_automation)
set(GUI_SUB_LIBS
yaze_gui_core
yaze_canvas
yaze_gui_widgets
yaze_gui_automation
yaze_gui_app
)
# Apply common properties to all new sub-libraries
foreach(LIB ${GUI_SUB_LIBS})
target_precompile_headers(${LIB} PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_SOURCE_DIR}/src/yaze_pch.h>"
)
target_include_directories(${LIB} PUBLIC
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/incl
${CMAKE_SOURCE_DIR}/src/app/gui
${SDL2_INCLUDE_DIR}
${PROJECT_BINARY_DIR}
)
set_target_properties(${LIB} PROPERTIES
POSITION_INDEPENDENT_CODE ON
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
)
if(UNIX AND NOT APPLE)
target_compile_definitions(${LIB} PRIVATE linux stricmp=strcasecmp)
elseif(APPLE)
target_compile_definitions(${LIB} PRIVATE MACOS)
elseif(WIN32)
target_compile_definitions(${LIB} PRIVATE WINDOWS)
endif()
endforeach()
# 3. Create Aggregate INTERFACE library
add_library(yaze_gui INTERFACE)
target_link_libraries(yaze_gui INTERFACE
yaze_gui_core
yaze_canvas
yaze_gui_widgets
yaze_gui_automation
yaze_gui_app
# Link original public dependencies so downstream targets receive them
yaze_gfx
yaze_util
yaze_common
@@ -72,19 +118,4 @@ target_link_libraries(yaze_gui PUBLIC
${SDL_TARGETS}
)
set_target_properties(yaze_gui PROPERTIES
POSITION_INDEPENDENT_CODE ON
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
)
# Platform-specific compile definitions
if(UNIX AND NOT APPLE)
target_compile_definitions(yaze_gui PRIVATE linux stricmp=strcasecmp)
elseif(APPLE)
target_compile_definitions(yaze_gui PRIVATE MACOS)
elseif(WIN32)
target_compile_definitions(yaze_gui PRIVATE WINDOWS)
endif()
message(STATUS "✓ yaze_gui library configured")
message(STATUS "✓ yaze_gui library refactored and configured")

View File

@@ -3,7 +3,7 @@
#include "zelda3/dungeon/room.h"
#include "zelda3/dungeon/room_object.h"
#include "app/gui/widgets/widget_auto_register.h"
#include "app/gui/automation/widget_auto_register.h"
#include "app/core/window.h"
#include <cstdio>

View File

@@ -1,59 +1,75 @@
#include "palette_editor_widget.h"
#include "app/gui/widgets/palette_editor_widget.h"
#include <algorithm>
#include <map>
#include "absl/strings/str_format.h"
#include "imgui/imgui.h"
#include "app/gfx/resource/arena.h"
#include "app/gui/core/color.h"
#include "util/log.h"
namespace yaze {
namespace gui {
void PaletteEditorWidget::Initialize(Rom* rom) {
// Merged implementation from PaletteWidget and PaletteEditorWidget
void PaletteEditorWidget::Initialize(Rom *rom) {
rom_ = rom;
rom_palettes_loaded_ = false;
if (rom_) {
LoadROMPalettes();
}
current_palette_id_ = 0;
selected_color_index_ = -1;
}
// --- Embedded Draw Method (from simple editor) ---
void PaletteEditorWidget::Draw() {
if (!rom_ || !rom_->is_loaded()) {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "ROM not loaded");
return;
}
ImGui::BeginGroup();
// Palette selector dropdown
DrawPaletteSelector();
ImGui::Separator();
// Color grid display
DrawColorGrid();
auto &dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
if (current_palette_id_ >= 0 &&
current_palette_id_ < (int)dungeon_pal_group.size()) {
auto palette = dungeon_pal_group[current_palette_id_];
DrawPaletteGrid(palette, 15);
dungeon_pal_group[current_palette_id_] = palette;
}
ImGui::Separator();
// Color picker for selected color
if (selected_color_index_ >= 0) {
DrawColorPicker();
} else {
ImGui::TextDisabled("Select a color to edit");
}
ImGui::EndGroup();
}
void PaletteEditorWidget::DrawPaletteSelector() {
auto& dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
auto &dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
int num_palettes = dungeon_pal_group.size();
ImGui::Text("Dungeon Palette:");
ImGui::SameLine();
if (ImGui::BeginCombo("##PaletteSelect",
absl::StrFormat("Palette %d", current_palette_id_).c_str())) {
if (ImGui::BeginCombo(
"##PaletteSelect",
absl::StrFormat("Palette %d", current_palette_id_).c_str())) {
for (int i = 0; i < num_palettes; i++) {
bool is_selected = (current_palette_id_ == i);
if (ImGui::Selectable(absl::StrFormat("Palette %d", i).c_str(), is_selected)) {
if (ImGui::Selectable(absl::StrFormat("Palette %d", i).c_str(),
is_selected)) {
current_palette_id_ = i;
selected_color_index_ = -1; // Reset color selection
selected_color_index_ = -1;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
@@ -63,111 +79,453 @@ void PaletteEditorWidget::DrawPaletteSelector() {
}
}
void PaletteEditorWidget::DrawColorGrid() {
auto& dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
if (current_palette_id_ < 0 || current_palette_id_ >= (int)dungeon_pal_group.size()) {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Invalid palette ID");
return;
}
auto palette = dungeon_pal_group[current_palette_id_];
int num_colors = palette.size();
ImGui::Text("Colors (%d):", num_colors);
// Draw color grid (15 colors per row for good layout)
const int colors_per_row = 15;
const float color_button_size = 24.0f;
for (int i = 0; i < num_colors; i++) {
ImGui::PushID(i);
// Get color as RGB (0-255)
auto color = palette[i];
ImVec4 col(color.rgb().x / 255.0f,
color.rgb().y / 255.0f,
color.rgb().z / 255.0f,
1.0f);
// Color button
bool is_selected = (i == selected_color_index_);
if (is_selected) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1, 1, 0, 1)); // Yellow border
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f);
}
if (ImGui::ColorButton(absl::StrFormat("##color%d", i).c_str(), col,
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker,
ImVec2(color_button_size, color_button_size))) {
selected_color_index_ = i;
editing_color_ = col;
}
if (is_selected) {
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}
// Tooltip showing color index and SNES value
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)",
i, color.snes(),
(int)color.rgb().x, (int)color.rgb().y, (int)color.rgb().z);
}
// Layout: 15 per row
if ((i + 1) % colors_per_row != 0 && i < num_colors - 1) {
ImGui::SameLine();
}
ImGui::PopID();
}
}
void PaletteEditorWidget::DrawColorPicker() {
ImGui::SeparatorText(absl::StrFormat("Edit Color %d", selected_color_index_).c_str());
auto& dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
auto palette = dungeon_pal_group[current_palette_id_]; // Get copy, not reference
ImGui::SeparatorText(
absl::StrFormat("Edit Color %d", selected_color_index_).c_str());
auto &dungeon_pal_group = rom_->mutable_palette_group()->dungeon_main;
auto palette = dungeon_pal_group[current_palette_id_];
auto original_color = palette[selected_color_index_];
// Color picker
if (ImGui::ColorEdit3("Color", &editing_color_.x,
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_PickerHueWheel)) {
// Convert ImGui color (0-1) to SNES color (0-31 per channel)
if (ImGui::ColorEdit3("Color", &editing_color_.x,
ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_PickerHueWheel)) {
int r = static_cast<int>(editing_color_.x * 31.0f);
int g = static_cast<int>(editing_color_.y * 31.0f);
int b = static_cast<int>(editing_color_.z * 31.0f);
// Create SNES color (15-bit BGR555 format)
uint16_t snes_color = (b << 10) | (g << 5) | r;
// Update palette in ROM (need to write back through the group)
palette[selected_color_index_] = gfx::SnesColor(snes_color);
dungeon_pal_group[current_palette_id_] = palette; // Write back
// Notify that palette changed
dungeon_pal_group[current_palette_id_] = palette;
if (on_palette_changed_) {
on_palette_changed_(current_palette_id_);
}
}
// Show RGB values
ImGui::Text("RGB (0-255): (%d, %d, %d)",
(int)(editing_color_.x * 255),
(int)(editing_color_.y * 255),
(int)(editing_color_.z * 255));
// Show SNES BGR555 value
ImGui::Text("RGB (0-255): (%d, %d, %d)", (int)(editing_color_.x * 255),
(int)(editing_color_.y * 255), (int)(editing_color_.z * 255));
ImGui::Text("SNES BGR555: 0x%04X", original_color.snes());
// Reset button
if (ImGui::Button("Reset to Original")) {
editing_color_ = ImVec4(original_color.rgb().x / 255.0f,
original_color.rgb().y / 255.0f,
original_color.rgb().z / 255.0f,
1.0f);
original_color.rgb().y / 255.0f,
original_color.rgb().z / 255.0f, 1.0f);
}
}
// --- Modal/Popup Methods (from feature-rich widget) ---
void PaletteEditorWidget::ShowPaletteEditor(gfx::SnesPalette &palette,
const std::string &title) {
if (ImGui::BeginPopupModal(title.c_str(), nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Enhanced Palette Editor");
ImGui::Separator();
DrawPaletteGrid(palette);
ImGui::Separator();
if (ImGui::CollapsingHeader("Palette Analysis")) {
DrawPaletteAnalysis(palette);
}
if (ImGui::CollapsingHeader("ROM Palette Manager") && rom_) {
DrawROMPaletteSelector();
if (ImGui::Button("Apply ROM Palette") && !rom_palette_groups_.empty()) {
if (current_group_index_ <
static_cast<int>(rom_palette_groups_.size())) {
palette = rom_palette_groups_[current_group_index_];
}
}
}
ImGui::Separator();
if (ImGui::Button("Save Backup")) {
SavePaletteBackup(palette);
}
ImGui::SameLine();
if (ImGui::Button("Restore Backup")) {
RestorePaletteBackup(palette);
}
ImGui::SameLine();
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void PaletteEditorWidget::ShowROMPaletteManager() {
if (!show_rom_manager_) return;
if (ImGui::Begin("ROM Palette Manager", &show_rom_manager_)) {
if (!rom_) {
ImGui::Text("No ROM loaded");
ImGui::End();
return;
}
if (!rom_palettes_loaded_) {
LoadROMPalettes();
}
DrawROMPaletteSelector();
if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
ImGui::Separator();
ImGui::Text("Preview of %s:",
palette_group_names_[current_group_index_].c_str());
const auto &preview_palette = rom_palette_groups_[current_group_index_];
DrawPaletteGrid(const_cast<gfx::SnesPalette &>(preview_palette));
DrawPaletteAnalysis(preview_palette);
}
}
ImGui::End();
}
void PaletteEditorWidget::ShowColorAnalysis(const gfx::Bitmap &bitmap,
const std::string &title) {
if (!show_color_analysis_) return;
if (ImGui::Begin(title.c_str(), &show_color_analysis_)) {
ImGui::Text("Bitmap Color Analysis");
ImGui::Separator();
if (!bitmap.is_active()) {
ImGui::Text("Bitmap is not active");
ImGui::End();
return;
}
std::map<uint8_t, int> pixel_counts;
const auto &data = bitmap.vector();
for (uint8_t pixel : data) {
uint8_t palette_index = pixel & 0x0F;
pixel_counts[palette_index]++;
}
ImGui::Text("Bitmap Size: %d x %d (%zu pixels)", bitmap.width(),
bitmap.height(), data.size());
ImGui::Separator();
ImGui::Text("Pixel Distribution:");
int total_pixels = static_cast<int>(data.size());
for (const auto &[index, count] : pixel_counts) {
float percentage = (static_cast<float>(count) / total_pixels) * 100.0f;
ImGui::Text("Index %d: %d pixels (%.1f%%)", index, count, percentage);
ImGui::SameLine();
ImGui::ProgressBar(percentage / 100.0f, ImVec2(100, 0));
if (index < static_cast<int>(bitmap.palette().size())) {
ImGui::SameLine();
auto color = bitmap.palette()[index];
ImVec4 display_color = color.rgb();
ImGui::ColorButton(("##color" + std::to_string(index)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip,
ImVec2(20, 20));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("SNES Color: 0x%04X\nRGB: (%d, %d, %d)",
color.snes(),
static_cast<int>(display_color.x * 255),
static_cast<int>(display_color.y * 255),
static_cast<int>(display_color.z * 255));
}
}
}
}
ImGui::End();
}
bool PaletteEditorWidget::ApplyROMPalette(gfx::Bitmap *bitmap, int group_index,
int palette_index) {
if (!bitmap || !rom_palettes_loaded_ || group_index < 0 ||
group_index >= static_cast<int>(rom_palette_groups_.size())) {
return false;
}
try {
const auto &selected_palette = rom_palette_groups_[group_index];
SavePaletteBackup(bitmap->palette());
if (palette_index >= 0 && palette_index < 8) {
bitmap->SetPaletteWithTransparent(selected_palette, palette_index);
} else {
bitmap->SetPalette(selected_palette);
}
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, bitmap);
current_group_index_ = group_index;
current_palette_index_ = palette_index;
return true;
} catch (const std::exception &e) {
return false;
}
}
const gfx::SnesPalette *PaletteEditorWidget::GetSelectedROMPalette() const {
if (!rom_palettes_loaded_ || current_group_index_ < 0 ||
current_group_index_ >= static_cast<int>(rom_palette_groups_.size())) {
return nullptr;
}
return &rom_palette_groups_[current_group_index_];
}
void PaletteEditorWidget::SavePaletteBackup(const gfx::SnesPalette &palette) {
backup_palette_ = palette;
}
bool PaletteEditorWidget::RestorePaletteBackup(gfx::SnesPalette &palette) {
if (backup_palette_.size() == 0) {
return false;
}
palette = backup_palette_;
return true;
}
// Unified grid drawing function
void PaletteEditorWidget::DrawPaletteGrid(gfx::SnesPalette &palette, int cols) {
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
if (i % cols != 0) ImGui::SameLine();
auto color = palette[i];
ImVec4 display_color = color.rgb();
ImGui::PushID(i);
if (ImGui::ColorButton("##color", display_color,
ImGuiColorEditFlags_NoTooltip, ImVec2(30, 30))) {
editing_color_index_ = i;
selected_color_index_ = i;
temp_color_ = display_color;
editing_color_ = display_color;
}
if (ImGui::BeginPopupContextItem()) {
ImGui::Text("Color %d (0x%04X)", i, color.snes());
ImGui::Separator();
if (ImGui::MenuItem("Edit Color")) {
editing_color_index_ = i;
selected_color_index_ = i;
temp_color_ = display_color;
editing_color_ = display_color;
}
if (ImGui::MenuItem("Reset to Black")) {
palette[i] = gfx::SnesColor(0);
}
ImGui::EndPopup();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)", i,
color.snes(), static_cast<int>(display_color.x * 255),
static_cast<int>(display_color.y * 255),
static_cast<int>(display_color.z * 255));
}
ImGui::PopID();
}
if (editing_color_index_ >= 0) {
ImGui::OpenPopup("Edit Color");
if (ImGui::BeginPopupModal("Edit Color", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Editing Color %d", editing_color_index_);
if (ImGui::ColorEdit4("Color", &temp_color_.x,
ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_DisplayRGB)) {
auto new_snes_color = gfx::SnesColor(temp_color_);
palette[editing_color_index_] = new_snes_color;
}
if (ImGui::Button("Apply")) {
editing_color_index_ = -1;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
editing_color_index_ = -1;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
}
void PaletteEditorWidget::DrawROMPaletteSelector() {
if (!rom_palettes_loaded_) {
LoadROMPalettes();
}
if (rom_palette_groups_.empty()) {
ImGui::Text("No ROM palettes available");
return;
}
ImGui::Text("Palette Group:");
if (ImGui::Combo(
"##PaletteGroup", &current_group_index_,
[](void *data, int idx, const char **out_text) -> bool {
auto *names = static_cast<std::vector<std::string> *>(data);
if (idx < 0 || idx >= static_cast<int>(names->size())) return false;
*out_text = (*names)[idx].c_str();
return true;
},
&palette_group_names_,
static_cast<int>(palette_group_names_.size()))) {
}
ImGui::Text("Palette Index:");
ImGui::SliderInt("##PaletteIndex", &current_palette_index_, 0, 7, "%d");
if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
ImGui::Text("Preview:");
const auto &preview_palette = rom_palette_groups_[current_group_index_];
for (int i = 0; i < 8 && i < static_cast<int>(preview_palette.size());
i++) {
if (i > 0) ImGui::SameLine();
auto color = preview_palette[i];
ImVec4 display_color = color.rgb();
ImGui::ColorButton(("##preview" + std::to_string(i)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip,
ImVec2(20, 20));
}
}
}
void PaletteEditorWidget::DrawColorEditControls(gfx::SnesColor &color,
int color_index) {
ImVec4 rgba = color.rgb();
ImGui::PushID(color_index);
if (ImGui::ColorEdit4("##color_edit", &rgba.x,
ImGuiColorEditFlags_NoAlpha |
ImGuiColorEditFlags_DisplayRGB)) {
color = gfx::SnesColor(rgba);
}
ImGui::Text("SNES Color: 0x%04X", color.snes());
int r = (color.snes() & 0x1F);
int g = (color.snes() >> 5) & 0x1F;
int b = (color.snes() >> 10) & 0x1F;
if (ImGui::SliderInt("Red", &r, 0, 31)) {
uint16_t new_color = (color.snes() & 0xFFE0) | (r & 0x1F);
color = gfx::SnesColor(new_color);
}
if (ImGui::SliderInt("Green", &g, 0, 31)) {
uint16_t new_color = (color.snes() & 0xFC1F) | ((g & 0x1F) << 5);
color = gfx::SnesColor(new_color);
}
if (ImGui::SliderInt("Blue", &b, 0, 31)) {
uint16_t new_color = (color.snes() & 0x83FF) | ((b & 0x1F) << 10);
color = gfx::SnesColor(new_color);
}
ImGui::PopID();
}
void PaletteEditorWidget::DrawPaletteAnalysis(
const gfx::SnesPalette &palette) {
ImGui::Text("Palette Information:");
ImGui::Text("Size: %zu colors", palette.size());
std::map<uint16_t, int> color_frequency;
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
color_frequency[palette[i].snes()]++;
}
ImGui::Text("Unique Colors: %zu", color_frequency.size());
if (color_frequency.size() < palette.size()) {
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Warning: Duplicate colors detected!");
if (ImGui::TreeNode("Duplicate Colors")) {
for (const auto &[snes_color, count] : color_frequency) {
if (count > 1) {
ImVec4 display_color = gfx::SnesColor(snes_color).rgb();
ImGui::ColorButton(("##dup" + std::to_string(snes_color)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip,
ImVec2(16, 16));
ImGui::SameLine();
ImGui::Text("0x%04X appears %d times", snes_color, count);
}
}
ImGui::TreePop();
}
}
float total_brightness = 0.0f;
float min_brightness = 1.0f;
float max_brightness = 0.0f;
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
ImVec4 color = palette[i].rgb();
float brightness = (color.x + color.y + color.z) / 3.0f;
total_brightness += brightness;
min_brightness = std::min(min_brightness, brightness);
max_brightness = std::max(max_brightness, brightness);
}
float avg_brightness = total_brightness / palette.size();
ImGui::Separator();
ImGui::Text("Brightness Analysis:");
ImGui::Text("Average: %.2f", avg_brightness);
ImGui::Text("Range: %.2f - %.2f", min_brightness, max_brightness);
ImGui::Text("Brightness Distribution:");
ImGui::ProgressBar(avg_brightness, ImVec2(-1, 0), "Avg");
}
void PaletteEditorWidget::LoadROMPalettes() {
if (!rom_ || rom_palettes_loaded_) return;
try {
const auto &palette_groups = rom_->palette_group();
rom_palette_groups_.clear();
palette_group_names_.clear();
if (palette_groups.overworld_main.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_main[0]);
palette_group_names_.push_back("Overworld Main");
}
if (palette_groups.overworld_aux.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_aux[0]);
palette_group_names_.push_back("Overworld Aux");
}
if (palette_groups.overworld_animated.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_animated[0]);
palette_group_names_.push_back("Overworld Animated");
}
if (palette_groups.dungeon_main.size() > 0) {
rom_palette_groups_.push_back(palette_groups.dungeon_main[0]);
palette_group_names_.push_back("Dungeon Main");
}
if (palette_groups.global_sprites.size() > 0) {
rom_palette_groups_.push_back(palette_groups.global_sprites[0]);
palette_group_names_.push_back("Global Sprites");
}
if (palette_groups.armors.size() > 0) {
rom_palette_groups_.push_back(palette_groups.armors[0]);
palette_group_names_.push_back("Armor");
}
if (palette_groups.swords.size() > 0) {
rom_palette_groups_.push_back(palette_groups.swords[0]);
palette_group_names_.push_back("Swords");
}
rom_palettes_loaded_ = true;
} catch (const std::exception &e) {
LOG_ERROR("Enhanced Palette Editor", "Failed to load ROM palettes");
}
}

View File

@@ -2,8 +2,10 @@
#define YAZE_APP_GUI_WIDGETS_PALETTE_EDITOR_WIDGET_H
#include <functional>
#include <map>
#include <vector>
#include "app/gfx/core/bitmap.h"
#include "app/gfx/types/snes_palette.h"
#include "app/rom.h"
#include "imgui/imgui.h"
@@ -11,42 +13,72 @@
namespace yaze {
namespace gui {
/**
* @brief Simple visual palette editor with color picker
*
* Displays dungeon palettes in a grid, allows editing colors,
* and notifies when palettes change so rooms can re-render.
*/
class PaletteEditorWidget {
public:
PaletteEditorWidget() = default;
void Initialize(Rom* rom);
void Initialize(Rom *rom);
// Embedded drawing function, like the old PaletteEditorWidget
void Draw();
// Modal dialogs from the more feature-rich PaletteWidget
void ShowPaletteEditor(gfx::SnesPalette &palette,
const std::string &title = "Palette Editor");
void ShowROMPaletteManager();
void ShowColorAnalysis(const gfx::Bitmap &bitmap,
const std::string &title = "Color Analysis");
bool ApplyROMPalette(gfx::Bitmap *bitmap, int group_index, int palette_index);
const gfx::SnesPalette *GetSelectedROMPalette() const;
void SavePaletteBackup(const gfx::SnesPalette &palette);
bool RestorePaletteBackup(gfx::SnesPalette &palette);
// Callback when palette is modified
void SetOnPaletteChanged(std::function<void(int palette_id)> callback) {
on_palette_changed_ = callback;
}
// Get/Set current editing palette
int current_palette_id() const { return current_palette_id_; }
void set_current_palette_id(int id) { current_palette_id_ = id; }
int GetCurrentPaletteId() const { return current_palette_id_; }
void SetCurrentPaletteId(int id) { current_palette_id_ = id; }
bool IsROMLoaded() const { return rom_ != nullptr; }
int GetCurrentGroupIndex() const { return current_group_index_; }
void DrawROMPaletteSelector();
private:
void DrawPaletteGrid(gfx::SnesPalette &palette, int cols = 15);
void DrawColorEditControls(gfx::SnesColor &color, int color_index);
void DrawPaletteAnalysis(const gfx::SnesPalette &palette);
void LoadROMPalettes();
// For embedded view
void DrawPaletteSelector();
void DrawColorGrid();
void DrawColorPicker();
Rom* rom_ = nullptr;
Rom *rom_ = nullptr;
std::vector<gfx::SnesPalette> rom_palette_groups_;
std::vector<std::string> palette_group_names_;
gfx::SnesPalette backup_palette_;
int current_group_index_ = 0;
int current_palette_index_ = 0; // used by ROM palette selector
bool rom_palettes_loaded_ = false;
bool show_color_analysis_ = false;
bool show_rom_manager_ = false;
// State for embedded editor
int current_palette_id_ = 0;
int selected_color_index_ = -1;
ImVec4 editing_color_{0, 0, 0, 1};
// Callback for palette changes
std::function<void(int palette_id)> on_palette_changed_;
// Temp color for editing (RGB 0-1 range for ImGui)
ImVec4 editing_color_{0, 0, 0, 1};
// Color editing state
int editing_color_index_ = -1;
ImVec4 temp_color_ = ImVec4(0, 0, 0, 1);
};
} // namespace gui

View File

@@ -1,462 +0,0 @@
#include "app/gui/widgets/palette_widget.h"
#include <algorithm>
#include <map>
#include "app/gfx/resource/arena.h"
#include "app/gui/color.h"
#include "util/log.h"
namespace yaze {
namespace gui {
void PaletteWidget::Initialize(Rom* rom) {
rom_ = rom;
rom_palettes_loaded_ = false;
if (rom_) {
LoadROMPalettes();
}
}
void PaletteWidget::ShowPaletteEditor(gfx::SnesPalette& palette, const std::string& title) {
if (ImGui::BeginPopupModal(title.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Enhanced Palette Editor");
ImGui::Separator();
// Palette grid editor
DrawPaletteGrid(palette);
ImGui::Separator();
// Analysis and tools
if (ImGui::CollapsingHeader("Palette Analysis")) {
DrawPaletteAnalysis(palette);
}
if (ImGui::CollapsingHeader("ROM Palette Manager") && rom_) {
DrawROMPaletteSelector();
if (ImGui::Button("Apply ROM Palette") && !rom_palette_groups_.empty()) {
if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
palette = rom_palette_groups_[current_group_index_];
}
}
}
ImGui::Separator();
// Action buttons
if (ImGui::Button("Save Backup")) {
SavePaletteBackup(palette);
}
ImGui::SameLine();
if (ImGui::Button("Restore Backup")) {
RestorePaletteBackup(palette);
}
ImGui::SameLine();
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void PaletteWidget::ShowROMPaletteManager() {
if (!show_rom_manager_) return;
if (ImGui::Begin("ROM Palette Manager", &show_rom_manager_)) {
if (!rom_) {
ImGui::Text("No ROM loaded");
ImGui::End();
return;
}
if (!rom_palettes_loaded_) {
LoadROMPalettes();
}
DrawROMPaletteSelector();
if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
ImGui::Separator();
ImGui::Text("Preview of %s:", palette_group_names_[current_group_index_].c_str());
const auto& preview_palette = rom_palette_groups_[current_group_index_];
DrawPaletteGrid(const_cast<gfx::SnesPalette&>(preview_palette));
DrawPaletteAnalysis(preview_palette);
}
}
ImGui::End();
}
void PaletteWidget::ShowColorAnalysis(const gfx::Bitmap& bitmap, const std::string& title) {
if (!show_color_analysis_) return;
if (ImGui::Begin(title.c_str(), &show_color_analysis_)) {
ImGui::Text("Bitmap Color Analysis");
ImGui::Separator();
if (!bitmap.is_active()) {
ImGui::Text("Bitmap is not active");
ImGui::End();
return;
}
// Analyze pixel distribution
std::map<uint8_t, int> pixel_counts;
const auto& data = bitmap.vector();
for (uint8_t pixel : data) {
uint8_t palette_index = pixel & 0x0F; // 4-bit palette index
pixel_counts[palette_index]++;
}
ImGui::Text("Bitmap Size: %d x %d (%zu pixels)",
bitmap.width(), bitmap.height(), data.size());
ImGui::Separator();
ImGui::Text("Pixel Distribution:");
// Show distribution as bars
int total_pixels = static_cast<int>(data.size());
for (const auto& [index, count] : pixel_counts) {
float percentage = (static_cast<float>(count) / total_pixels) * 100.0f;
ImGui::Text("Index %d: %d pixels (%.1f%%)", index, count, percentage);
// Progress bar visualization
ImGui::SameLine();
ImGui::ProgressBar(percentage / 100.0f, ImVec2(100, 0));
// Color swatch if palette is available
if (index < static_cast<int>(bitmap.palette().size())) {
ImGui::SameLine();
auto color = bitmap.palette()[index];
ImVec4 display_color = color.rgb();
ImGui::ColorButton(("##color" + std::to_string(index)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("SNES Color: 0x%04X\nRGB: (%d, %d, %d)",
color.snes(),
static_cast<int>(display_color.x * 255),
static_cast<int>(display_color.y * 255),
static_cast<int>(display_color.z * 255));
}
}
}
}
ImGui::End();
}
bool PaletteWidget::ApplyROMPalette(gfx::Bitmap* bitmap, int group_index, int palette_index) {
if (!bitmap || !rom_palettes_loaded_ ||
group_index < 0 || group_index >= static_cast<int>(rom_palette_groups_.size())) {
return false;
}
try {
const auto& selected_palette = rom_palette_groups_[group_index];
// Save current palette as backup
SavePaletteBackup(bitmap->palette());
// Apply new palette
if (palette_index >= 0 && palette_index < 8) {
bitmap->SetPaletteWithTransparent(selected_palette, palette_index);
} else {
bitmap->SetPalette(selected_palette);
}
// Queue texture update via Arena's deferred system
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, bitmap);
current_group_index_ = group_index;
current_palette_index_ = palette_index;
return true;
} catch (const std::exception& e) {
return false;
}
}
const gfx::SnesPalette* PaletteWidget::GetSelectedROMPalette() const {
if (!rom_palettes_loaded_ || current_group_index_ < 0 ||
current_group_index_ >= static_cast<int>(rom_palette_groups_.size())) {
return nullptr;
}
return &rom_palette_groups_[current_group_index_];
}
void PaletteWidget::SavePaletteBackup(const gfx::SnesPalette& palette) {
backup_palette_ = palette;
}
bool PaletteWidget::RestorePaletteBackup(gfx::SnesPalette& palette) {
if (backup_palette_.size() == 0) {
return false;
}
palette = backup_palette_;
return true;
}
void PaletteWidget::DrawPaletteGrid(gfx::SnesPalette& palette, int cols) {
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
if (i % cols != 0) ImGui::SameLine();
auto color = palette[i];
ImVec4 display_color = color.rgb();
ImGui::PushID(i);
// Color button with editing capability
if (ImGui::ColorButton("##color", display_color,
ImGuiColorEditFlags_NoTooltip, ImVec2(30, 30))) {
editing_color_index_ = i;
temp_color_ = display_color;
}
// Context menu for individual colors
if (ImGui::BeginPopupContextItem()) {
ImGui::Text("Color %d (0x%04X)", i, color.snes());
ImGui::Separator();
if (ImGui::MenuItem("Edit Color")) {
editing_color_index_ = i;
temp_color_ = display_color;
}
if (ImGui::MenuItem("Copy Color")) {
// Could implement color clipboard here
}
if (ImGui::MenuItem("Reset to Black")) {
palette[i] = gfx::SnesColor(0);
}
ImGui::EndPopup();
}
// Tooltip with detailed info
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Color %d\nSNES: 0x%04X\nRGB: (%d, %d, %d)\nClick to edit",
i, color.snes(),
static_cast<int>(display_color.x * 255),
static_cast<int>(display_color.y * 255),
static_cast<int>(display_color.z * 255));
}
ImGui::PopID();
}
// Color editor popup
if (editing_color_index_ >= 0) {
ImGui::OpenPopup("Edit Color");
if (ImGui::BeginPopupModal("Edit Color", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Editing Color %d", editing_color_index_);
if (ImGui::ColorEdit4("Color", &temp_color_.x,
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
// Update the palette color in real-time
auto new_snes_color = gfx::SnesColor(temp_color_);
palette[editing_color_index_] = new_snes_color;
}
if (ImGui::Button("Apply")) {
editing_color_index_ = -1;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
editing_color_index_ = -1;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
}
void PaletteWidget::DrawROMPaletteSelector() {
if (!rom_palettes_loaded_) {
LoadROMPalettes();
}
if (rom_palette_groups_.empty()) {
ImGui::Text("No ROM palettes available");
return;
}
// Group selector
ImGui::Text("Palette Group:");
if (ImGui::Combo("##PaletteGroup", &current_group_index_,
[](void* data, int idx, const char** out_text) -> bool {
auto* names = static_cast<std::vector<std::string>*>(data);
if (idx < 0 || idx >= static_cast<int>(names->size())) return false;
*out_text = (*names)[idx].c_str();
return true;
}, &palette_group_names_, static_cast<int>(palette_group_names_.size()))) {
// Group changed - could trigger preview update
}
// Palette index selector
ImGui::Text("Palette Index:");
ImGui::SliderInt("##PaletteIndex", &current_palette_index_, 0, 7, "%d");
// Quick palette preview
if (current_group_index_ < static_cast<int>(rom_palette_groups_.size())) {
ImGui::Text("Preview:");
const auto& preview_palette = rom_palette_groups_[current_group_index_];
// Show just first 8 colors in a row
for (int i = 0; i < 8 && i < static_cast<int>(preview_palette.size()); i++) {
if (i > 0) ImGui::SameLine();
auto color = preview_palette[i];
ImVec4 display_color = color.rgb();
ImGui::ColorButton(("##preview" + std::to_string(i)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
}
}
}
void PaletteWidget::DrawColorEditControls(gfx::SnesColor& color, int color_index) {
ImVec4 rgba = color.rgb();
ImGui::PushID(color_index);
if (ImGui::ColorEdit4("##color_edit", &rgba.x,
ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_DisplayRGB)) {
color = gfx::SnesColor(rgba);
}
// SNES-specific controls
ImGui::Text("SNES Color: 0x%04X", color.snes());
// Individual RGB component sliders (0-31 for SNES)
int r = (color.snes() & 0x1F);
int g = (color.snes() >> 5) & 0x1F;
int b = (color.snes() >> 10) & 0x1F;
if (ImGui::SliderInt("Red", &r, 0, 31)) {
uint16_t new_color = (color.snes() & 0xFFE0) | (r & 0x1F);
color = gfx::SnesColor(new_color);
}
if (ImGui::SliderInt("Green", &g, 0, 31)) {
uint16_t new_color = (color.snes() & 0xFC1F) | ((g & 0x1F) << 5);
color = gfx::SnesColor(new_color);
}
if (ImGui::SliderInt("Blue", &b, 0, 31)) {
uint16_t new_color = (color.snes() & 0x83FF) | ((b & 0x1F) << 10);
color = gfx::SnesColor(new_color);
}
ImGui::PopID();
}
void PaletteWidget::DrawPaletteAnalysis(const gfx::SnesPalette& palette) {
ImGui::Text("Palette Information:");
ImGui::Text("Size: %zu colors", palette.size());
// Color distribution analysis
std::map<uint16_t, int> color_frequency;
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
color_frequency[palette[i].snes()]++;
}
ImGui::Text("Unique Colors: %zu", color_frequency.size());
if (color_frequency.size() < palette.size()) {
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Warning: Duplicate colors detected!");
if (ImGui::TreeNode("Duplicate Colors")) {
for (const auto& [snes_color, count] : color_frequency) {
if (count > 1) {
ImVec4 display_color = gfx::SnesColor(snes_color).rgb();
ImGui::ColorButton(("##dup" + std::to_string(snes_color)).c_str(),
display_color, ImGuiColorEditFlags_NoTooltip, ImVec2(16, 16));
ImGui::SameLine();
ImGui::Text("0x%04X appears %d times", snes_color, count);
}
}
ImGui::TreePop();
}
}
// Brightness analysis
float total_brightness = 0.0f;
float min_brightness = 1.0f;
float max_brightness = 0.0f;
for (int i = 0; i < static_cast<int>(palette.size()); i++) {
ImVec4 color = palette[i].rgb();
float brightness = (color.x + color.y + color.z) / 3.0f;
total_brightness += brightness;
min_brightness = std::min(min_brightness, brightness);
max_brightness = std::max(max_brightness, brightness);
}
float avg_brightness = total_brightness / palette.size();
ImGui::Separator();
ImGui::Text("Brightness Analysis:");
ImGui::Text("Average: %.2f", avg_brightness);
ImGui::Text("Range: %.2f - %.2f", min_brightness, max_brightness);
// Show brightness as progress bar
ImGui::Text("Brightness Distribution:");
ImGui::ProgressBar(avg_brightness, ImVec2(-1, 0), "Avg");
}
void PaletteWidget::LoadROMPalettes() {
if (!rom_ || rom_palettes_loaded_) return;
try {
const auto& palette_groups = rom_->palette_group();
rom_palette_groups_.clear();
palette_group_names_.clear();
// Load all available palette groups
if (palette_groups.overworld_main.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_main[0]);
palette_group_names_.push_back("Overworld Main");
}
if (palette_groups.overworld_aux.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_aux[0]);
palette_group_names_.push_back("Overworld Aux");
}
if (palette_groups.overworld_animated.size() > 0) {
rom_palette_groups_.push_back(palette_groups.overworld_animated[0]);
palette_group_names_.push_back("Overworld Animated");
}
if (palette_groups.dungeon_main.size() > 0) {
rom_palette_groups_.push_back(palette_groups.dungeon_main[0]);
palette_group_names_.push_back("Dungeon Main");
}
if (palette_groups.global_sprites.size() > 0) {
rom_palette_groups_.push_back(palette_groups.global_sprites[0]);
palette_group_names_.push_back("Global Sprites");
}
if (palette_groups.armors.size() > 0) {
rom_palette_groups_.push_back(palette_groups.armors[0]);
palette_group_names_.push_back("Armor");
}
if (palette_groups.swords.size() > 0) {
rom_palette_groups_.push_back(palette_groups.swords[0]);
palette_group_names_.push_back("Swords");
}
rom_palettes_loaded_ = true;
} catch (const std::exception& e) {
LOG_ERROR("Enhanced Palette Editor", "Failed to load ROM palettes");
}
}
} // namespace gui
} // namespace yaze

View File

@@ -1,99 +0,0 @@
#ifndef YAZE_APP_GUI_PALETTE_WIDGET_H
#define YAZE_APP_GUI_PALETTE_WIDGET_H
#include <vector>
#include <map>
#include "app/gfx/types/snes_palette.h"
#include "app/gfx/core/bitmap.h"
#include "app/rom.h"
#include "imgui/imgui.h"
namespace yaze {
namespace gui {
/**
* @brief Palette widget with ROM integration, analysis tools, and AI tool call support
*
* This widget provides comprehensive palette editing capabilities including:
* - Grid-based color editing with preview
* - ROM palette browser and manager
* - Color analysis and statistics
* - Export/import functionality
* - AI agent tool call integration for programmatic palette access
*/
class PaletteWidget {
public:
PaletteWidget() = default;
/**
* @brief Initialize the palette editor with ROM data
*/
void Initialize(Rom* rom);
/**
* @brief Show the main palette editor window
*/
void ShowPaletteEditor(gfx::SnesPalette& palette, const std::string& title = "Palette Editor");
/**
* @brief Show the ROM palette manager window
*/
void ShowROMPaletteManager();
/**
* @brief Show color analysis window for a bitmap
*/
void ShowColorAnalysis(const gfx::Bitmap& bitmap, const std::string& title = "Color Analysis");
/**
* @brief Apply a ROM palette group to a bitmap
*/
bool ApplyROMPalette(gfx::Bitmap* bitmap, int group_index, int palette_index);
/**
* @brief Get the currently selected ROM palette
*/
const gfx::SnesPalette* GetSelectedROMPalette() const;
/**
* @brief Save current palette as backup
*/
void SavePaletteBackup(const gfx::SnesPalette& palette);
/**
* @brief Restore palette from backup
*/
bool RestorePaletteBackup(gfx::SnesPalette& palette);
// Accessors
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 DrawColorEditControls(gfx::SnesColor& color, int color_index);
void DrawPaletteAnalysis(const gfx::SnesPalette& palette);
void LoadROMPalettes();
Rom* rom_ = nullptr;
std::vector<gfx::SnesPalette> rom_palette_groups_;
std::vector<std::string> palette_group_names_;
gfx::SnesPalette backup_palette_;
int current_group_index_ = 0;
int current_palette_index_ = 0;
bool rom_palettes_loaded_ = false;
bool show_color_analysis_ = false;
bool show_rom_manager_ = false;
// Color editing state
int editing_color_index_ = -1;
ImVec4 temp_color_ = ImVec4(0, 0, 0, 1);
};
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_WIDGETS_PALETTE_WIDGET_H

View File

@@ -1,6 +1,6 @@
#include "app/gui/themed_widgets.h"
#include "app/gui/widgets/themed_widgets.h"
#include "app/gui/color.h"
#include "app/gui/core/color.h"
#include "app/gfx/types/snes_color.h"
namespace yaze {

View File

@@ -1,9 +1,9 @@
#ifndef YAZE_APP_GUI_THEMED_WIDGETS_H
#define YAZE_APP_GUI_THEMED_WIDGETS_H
#include "app/gui/color.h"
#include "app/gui/layout_helpers.h"
#include "app/gui/theme_manager.h"
#include "app/gui/core/color.h"
#include "app/gui/core/layout_helpers.h"
#include "app/gui/core/theme_manager.h"
#include "imgui/imgui.h"
namespace yaze {

View File

@@ -4,7 +4,7 @@
#include <string>
#include "app/gfx/core/bitmap.h"
#include "app/gui/canvas.h"
#include "app/gui/canvas/canvas.h"
#include "imgui/imgui.h"
namespace yaze::gui {