feat(editor): reorganize palette editor structure and enhance linking

- Moved palette_editor and palette_group_card files to a dedicated palette directory for better organization.
- Updated CMake configuration to link the new palette editor files and added support for the yaze_agent library when not in minimal build.
- Refactored include paths in various editor files to reflect the new structure, ensuring proper linkage and modularity.

Benefits:
- Improved code organization and maintainability by grouping related files.
- Enhanced functionality with the integration of AI features through the yaze_agent library.
This commit is contained in:
scawful
2025-10-12 08:05:56 -04:00
parent ea9e8d2498
commit 4fe23b9af2
12 changed files with 1809 additions and 119 deletions

View File

@@ -23,8 +23,9 @@ set(
app/editor/editor_manager.cc
app/editor/graphics/gfx_group_editor.cc
app/editor/graphics/graphics_editor.cc
app/editor/graphics/palette_editor.cc
app/editor/graphics/screen_editor.cc
app/editor/palette/palette_editor.cc
app/editor/palette/palette_group_card.cc
app/editor/message/message_data.cc
app/editor/message/message_editor.cc
app/editor/message/message_preview.cc
@@ -101,11 +102,20 @@ target_link_libraries(yaze_editor PUBLIC
yaze_gfx
yaze_gui
yaze_zelda3
yaze_emulator # Needed for emulator integration (APU, PPU, SNES)
yaze_util
yaze_common
ImGui
)
# Link agent library for AI features (always available when not in minimal build)
if(NOT YAZE_MINIMAL_BUILD)
if(TARGET yaze_agent)
target_link_libraries(yaze_editor PUBLIC yaze_agent)
message(STATUS "✓ yaze_editor linked to yaze_agent")
endif()
endif()
# Note: yaze_test_support linking is deferred to test.cmake to ensure proper ordering
if(YAZE_WITH_JSON)

View File

@@ -21,7 +21,7 @@
#include "app/editor/code/assembly_editor.h"
#include "app/editor/dungeon/dungeon_editor_v2.h"
#include "app/editor/graphics/graphics_editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/editor/graphics/screen_editor.h"
#include "app/editor/music/music_editor.h"
#include "app/editor/overworld/overworld_editor.h"

View File

@@ -20,7 +20,7 @@
#include "app/editor/code/project_file_editor.h"
#include "app/editor/dungeon/dungeon_editor_v2.h"
#include "app/editor/graphics/graphics_editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/editor/graphics/screen_editor.h"
#include "app/editor/message/message_editor.h"
#include "app/editor/music/music_editor.h"

View File

@@ -5,7 +5,7 @@
#include "absl/status/status.h"
#include "app/editor/editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/gfx/bitmap.h"
#include "app/gui/editor_card_manager.h"
#include "app/gfx/snes_tile.h"

View File

@@ -4,7 +4,7 @@
#include "absl/status/status.h"
#include "app/editor/editor.h"
#include "app/editor/graphics/gfx_group_editor.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/gui/editor_card_manager.h"
#include "app/editor/overworld/tile16_editor.h"
#include "app/editor/overworld/map_properties.h"

View File

@@ -7,7 +7,7 @@
#include <vector>
#include "absl/status/status.h"
#include "app/editor/graphics/palette_editor.h"
#include "app/editor/palette/palette_editor.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"

View File

@@ -187,6 +187,14 @@ absl::Status DisplayPalette(gfx::SnesPalette& palette, bool loaded) {
}
void PaletteEditor::Initialize() {
// Initialize palette cards
if (rom_ && rom_->is_loaded()) {
ow_main_card_ = std::make_unique<OverworldMainPaletteCard>(rom_);
ow_animated_card_ = std::make_unique<OverworldAnimatedPaletteCard>(rom_);
dungeon_main_card_ = std::make_unique<DungeonMainPaletteCard>(rom_);
sprite_card_ = std::make_unique<SpritePaletteCard>(rom_);
equipment_card_ = std::make_unique<EquipmentPaletteCard>(rom_);
}
}
absl::Status PaletteEditor::Load() {
@@ -206,48 +214,88 @@ absl::Status PaletteEditor::Load() {
}
absl::Status PaletteEditor::Update() {
static int current_palette_group = 0;
if (BeginTable("paletteGroupsTable", 3, kPaletteTableFlags)) {
TableSetupColumn("Categories", ImGuiTableColumnFlags_WidthFixed, 200);
TableSetupColumn("Palette Editor", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Quick Access", ImGuiTableColumnFlags_WidthStretch);
TableHeadersRow();
static bool use_legacy_view = false;
TableNextRow();
TableNextColumn();
static int selected_category = 0;
BeginChild("CategoryList", ImVec2(0, GetContentRegionAvail().y), true);
for (int i = 0; i < kNumPalettes; i++) {
const bool is_selected = (selected_category == i);
if (Selectable(std::string(kPaletteCategoryNames[i]).c_str(),
is_selected)) {
selected_category = i;
}
}
EndChild();
TableNextColumn();
BeginChild("PaletteEditor", ImVec2(0, 0), true);
Text("%s", std::string(kPaletteCategoryNames[selected_category]).c_str());
Separator();
if (rom()->is_loaded()) {
status_ = DrawPaletteGroup(selected_category, true);
}
EndChild();
TableNextColumn();
DrawQuickAccessTab();
EndTable();
// Toolbar with view selector
if (ImGui::Button(use_legacy_view ? "Switch to Card View" : "Switch to Legacy View")) {
use_legacy_view = !use_legacy_view;
}
ImGui::SameLine();
ImGui::TextDisabled("|");
ImGui::SameLine();
if (use_legacy_view) {
// Original table-based view
static int current_palette_group = 0;
if (BeginTable("paletteGroupsTable", 3, kPaletteTableFlags)) {
TableSetupColumn("Categories", ImGuiTableColumnFlags_WidthFixed, 200);
TableSetupColumn("Palette Editor", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Quick Access", ImGuiTableColumnFlags_WidthStretch);
TableHeadersRow();
TableNextRow();
TableNextColumn();
static int selected_category = 0;
BeginChild("CategoryList", ImVec2(0, GetContentRegionAvail().y), true);
for (int i = 0; i < kNumPalettes; i++) {
const bool is_selected = (selected_category == i);
if (Selectable(std::string(kPaletteCategoryNames[i]).c_str(),
is_selected)) {
selected_category = i;
}
}
EndChild();
TableNextColumn();
BeginChild("PaletteEditor", ImVec2(0, 0), true);
Text("%s", std::string(kPaletteCategoryNames[selected_category]).c_str());
Separator();
if (rom()->is_loaded()) {
status_ = DrawPaletteGroup(selected_category, true);
}
EndChild();
TableNextColumn();
DrawQuickAccessTab();
EndTable();
}
} else {
// New card-based view with quick access sidebar
if (BeginTable("paletteCardsTable", 2, kPaletteTableFlags)) {
TableSetupColumn("Palette Cards", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Quick Access", ImGuiTableColumnFlags_WidthFixed, 300);
TableHeadersRow();
TableNextRow();
TableNextColumn();
BeginChild("PaletteCardsView", ImVec2(0, 0), true);
DrawPaletteCards();
EndChild();
TableNextColumn();
DrawQuickAccessTab();
EndTable();
}
}
// Draw palette card windows (dockable/floating)
if (ow_main_card_) ow_main_card_->Draw();
if (ow_animated_card_) ow_animated_card_->Draw();
if (dungeon_main_card_) dungeon_main_card_->Draw();
if (sprite_card_) sprite_card_->Draw();
if (equipment_card_) equipment_card_->Draw();
return absl::OkStatus();
}
@@ -559,5 +607,71 @@ absl::Status PaletteEditor::ResetColorToOriginal(
return absl::OkStatus();
}
void PaletteEditor::DrawPaletteCards() {
ImGui::TextWrapped(
"Click a palette card below to open it as a dockable/floating window. "
"Each card provides full editing capabilities with undo/redo, "
"save/discard workflow, and detailed metadata.");
ImGui::Separator();
// Draw card launcher buttons
ImGui::Text("Overworld Palettes");
if (ImGui::Button("Open Overworld Main", ImVec2(-1, 0))) {
if (ow_main_card_) ow_main_card_->Show();
}
if (ImGui::Button("Open Overworld Animated", ImVec2(-1, 0))) {
if (ow_animated_card_) ow_animated_card_->Show();
}
ImGui::Separator();
ImGui::Text("Dungeon Palettes");
if (ImGui::Button("Open Dungeon Main", ImVec2(-1, 0))) {
if (dungeon_main_card_) dungeon_main_card_->Show();
}
ImGui::Separator();
ImGui::Text("Sprite & Equipment Palettes");
if (ImGui::Button("Open Sprite Palettes", ImVec2(-1, 0))) {
if (sprite_card_) sprite_card_->Show();
}
if (ImGui::Button("Open Equipment Palettes", ImVec2(-1, 0))) {
if (equipment_card_) equipment_card_->Show();
}
ImGui::Separator();
// Show modified status for each card
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "Modified Cards:");
bool any_modified = false;
if (ow_main_card_ && ow_main_card_->HasUnsavedChanges()) {
ImGui::BulletText("Overworld Main");
any_modified = true;
}
if (ow_animated_card_ && ow_animated_card_->HasUnsavedChanges()) {
ImGui::BulletText("Overworld Animated");
any_modified = true;
}
if (dungeon_main_card_ && dungeon_main_card_->HasUnsavedChanges()) {
ImGui::BulletText("Dungeon Main");
any_modified = true;
}
if (sprite_card_ && sprite_card_->HasUnsavedChanges()) {
ImGui::BulletText("Sprite Palettes");
any_modified = true;
}
if (equipment_card_ && equipment_card_->HasUnsavedChanges()) {
ImGui::BulletText("Equipment Palettes");
any_modified = true;
}
if (!any_modified) {
ImGui::TextDisabled("No unsaved changes");
}
}
} // namespace editor
} // namespace yaze

View File

@@ -8,6 +8,7 @@
#include "absl/status/status.h"
#include "app/editor/editor.h"
#include "app/editor/graphics/gfx_group_editor.h"
#include "app/editor/palette/palette_group_card.h"
#include "app/gfx/snes_color.h"
#include "app/gui/editor_card_manager.h"
#include "app/gfx/snes_palette.h"
@@ -112,6 +113,8 @@ class PaletteEditor : public Editor {
private:
absl::Status HandleColorPopup(gfx::SnesPalette& palette, int i, int j, int n);
void DrawPaletteCards();
absl::Status status_;
gfx::SnesColor current_color_;
@@ -127,6 +130,13 @@ class PaletteEditor : public Editor {
palette_internal::PaletteEditorHistory history_;
Rom* rom_;
// Palette card instances
std::unique_ptr<OverworldMainPaletteCard> ow_main_card_;
std::unique_ptr<OverworldAnimatedPaletteCard> ow_animated_card_;
std::unique_ptr<DungeonMainPaletteCard> dungeon_main_card_;
std::unique_ptr<SpritePaletteCard> sprite_card_;
std::unique_ptr<EquipmentPaletteCard> equipment_card_;
};
} // namespace editor

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,403 @@
#ifndef YAZE_APP_EDITOR_GRAPHICS_PALETTE_GROUP_CARD_H
#define YAZE_APP_EDITOR_GRAPHICS_PALETTE_GROUP_CARD_H
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "absl/status/status.h"
#include "app/gfx/snes_color.h"
#include "app/gfx/snes_palette.h"
#include "app/gui/editor_card_manager.h"
#include "app/rom.h"
#include "imgui/imgui.h"
namespace yaze {
namespace editor {
/**
* @brief Represents a single color change for undo/redo
*/
struct ColorChange {
int palette_index;
int color_index;
gfx::SnesColor original_color;
gfx::SnesColor new_color;
uint64_t timestamp; // For history ordering
};
/**
* @brief Metadata for a single palette in a group
*/
struct PaletteMetadata {
int palette_id; // Palette ID in ROM
std::string name; // Display name (e.g., "Light World Main")
std::string description; // Usage description
uint32_t rom_address; // Base ROM address for this palette
uint32_t vram_address; // VRAM address (for sprite palettes, 0 if N/A)
std::string usage_notes; // Additional usage information
};
/**
* @brief Metadata for an entire palette group
*/
struct PaletteGroupMetadata {
std::string group_name; // Internal group name
std::string display_name; // Display name for UI
std::vector<PaletteMetadata> palettes; // Metadata for each palette
int colors_per_palette; // Number of colors per palette (usually 8 or 16)
int colors_per_row; // Colors per row for grid layout
};
/**
* @brief Base class for palette group editing cards
*
* Provides common functionality for all palette group editors:
* - ROM persistence with transaction-based writes
* - Undo/redo history management
* - Modified state tracking with visual indicators
* - Save/discard workflow
* - Common toolbar and color picker UI
* - EditorCardManager integration
*
* Derived classes implement specific grid layouts and palette access.
*/
class PaletteGroupCard {
public:
/**
* @brief Construct a new Palette Group Card
* @param group_name Internal palette group name (e.g., "ow_main", "dungeon_main")
* @param display_name Human-readable name for UI
* @param rom ROM instance for reading/writing palettes
*/
PaletteGroupCard(const std::string& group_name,
const std::string& display_name,
Rom* rom);
virtual ~PaletteGroupCard() = default;
// ========== Main Rendering ==========
/**
* @brief Draw the card's ImGui UI
*/
void Draw();
// ========== Card Control ==========
void Show() { show_ = true; }
void Hide() { show_ = false; }
bool IsVisible() const { return show_; }
bool* visibility_flag() { return &show_; }
// ========== Palette Operations ==========
/**
* @brief Save all modified palettes to ROM
*/
absl::Status SaveToRom();
/**
* @brief Discard all unsaved changes
*/
void DiscardChanges();
/**
* @brief Reset a specific palette to original ROM values
*/
void ResetPalette(int palette_index);
/**
* @brief Reset a specific color to original ROM value
*/
void ResetColor(int palette_index, int color_index);
/**
* @brief Set a color value (records change for undo)
*/
void SetColor(int palette_index, int color_index, const gfx::SnesColor& new_color);
// ========== History Management ==========
void Undo();
void Redo();
bool CanUndo() const { return !undo_stack_.empty(); }
bool CanRedo() const { return !redo_stack_.empty(); }
void ClearHistory();
// ========== State Queries ==========
bool HasUnsavedChanges() const { return !modified_palettes_.empty(); }
bool IsPaletteModified(int palette_index) const;
bool IsColorModified(int palette_index, int color_index) const;
int GetSelectedPaletteIndex() const { return selected_palette_; }
void SetSelectedPaletteIndex(int index) { selected_palette_ = index; }
int GetSelectedColorIndex() const { return selected_color_; }
void SetSelectedColorIndex(int index) { selected_color_ = index; }
// ========== Export/Import ==========
std::string ExportToJson() const;
absl::Status ImportFromJson(const std::string& json);
std::string ExportToClipboard() const;
absl::Status ImportFromClipboard();
protected:
// ========== Pure Virtual Methods (Implemented by Derived Classes) ==========
/**
* @brief Get the palette group for this card
*/
virtual gfx::PaletteGroup* GetPaletteGroup() = 0;
virtual const gfx::PaletteGroup* GetPaletteGroup() const = 0;
/**
* @brief Get metadata for this palette group
*/
virtual const PaletteGroupMetadata& GetMetadata() const = 0;
/**
* @brief Draw the palette grid specific to this palette type
*/
virtual void DrawPaletteGrid() = 0;
/**
* @brief Get the number of colors per row for grid layout
*/
virtual int GetColorsPerRow() const = 0;
// ========== Optional Overrides ==========
/**
* @brief Draw additional toolbar buttons (called after standard buttons)
*/
virtual void DrawCustomToolbarButtons() {}
/**
* @brief Draw additional panels (called after main content)
*/
virtual void DrawCustomPanels() {}
// ========== Common UI Components ==========
/**
* @brief Draw standard toolbar with save/discard/undo/redo
*/
void DrawToolbar();
/**
* @brief Draw palette selector dropdown
*/
void DrawPaletteSelector();
/**
* @brief Draw color picker for selected color
*/
void DrawColorPicker();
/**
* @brief Draw color info panel with RGB/SNES/Hex values
*/
void DrawColorInfo();
/**
* @brief Draw palette metadata info panel
*/
void DrawMetadataInfo();
/**
* @brief Draw batch operations popup
*/
void DrawBatchOperationsPopup();
// ========== Helper Methods ==========
/**
* @brief Get mutable palette by index
*/
gfx::SnesPalette* GetMutablePalette(int index);
/**
* @brief Get original color from ROM (for reset/comparison)
*/
gfx::SnesColor GetOriginalColor(int palette_index, int color_index) const;
/**
* @brief Write a single color to ROM
*/
absl::Status WriteColorToRom(int palette_index, int color_index,
const gfx::SnesColor& color);
/**
* @brief Mark palette as modified
*/
void MarkModified(int palette_index, int color_index);
/**
* @brief Clear modified flags for palette
*/
void ClearModified(int palette_index);
// ========== Member Variables ==========
std::string group_name_; // Internal name (e.g., "ow_main")
std::string display_name_; // Display name (e.g., "Overworld Main")
Rom* rom_; // ROM instance
bool show_ = false; // Visibility flag
// Selection state
int selected_palette_ = 0; // Currently selected palette index
int selected_color_ = -1; // Currently selected color (-1 = none)
gfx::SnesColor editing_color_; // Color being edited in picker
// Modified tracking
std::unordered_set<int> modified_palettes_;
std::unordered_map<int, std::unordered_set<int>> modified_colors_;
// Undo/Redo
std::vector<ColorChange> undo_stack_;
std::vector<ColorChange> redo_stack_;
static constexpr size_t kMaxUndoHistory = 100;
// Settings
bool auto_save_enabled_ = false; // Auto-save to ROM on every change
bool show_snes_format_ = true; // Show SNES $xxxx format in info
bool show_hex_format_ = true; // Show #xxxxxx hex in info
// Original palettes (loaded from ROM for reset/comparison)
std::vector<gfx::SnesPalette> original_palettes_;
// Card registration
gui::CardRegistration card_registration_;
};
// ============================================================================
// Concrete Palette Card Implementations
// ============================================================================
/**
* @brief Overworld Main palette group card
*
* Manages palettes used for overworld rendering:
* - Light World palettes (0-19)
* - Dark World palettes (20-39)
* - Special World palettes (40-59)
*/
class OverworldMainPaletteCard : public PaletteGroupCard {
public:
explicit OverworldMainPaletteCard(Rom* rom);
~OverworldMainPaletteCard() override = default;
protected:
gfx::PaletteGroup* GetPaletteGroup() override;
const gfx::PaletteGroup* GetPaletteGroup() const override;
const PaletteGroupMetadata& GetMetadata() const override { return metadata_; }
void DrawPaletteGrid() override;
int GetColorsPerRow() const override { return 8; }
private:
static PaletteGroupMetadata InitializeMetadata();
static const PaletteGroupMetadata metadata_;
};
/**
* @brief Overworld Animated palette group card
*
* Manages animated palettes for water, lava, and other effects
*/
class OverworldAnimatedPaletteCard : public PaletteGroupCard {
public:
explicit OverworldAnimatedPaletteCard(Rom* rom);
~OverworldAnimatedPaletteCard() override = default;
protected:
gfx::PaletteGroup* GetPaletteGroup() override;
const gfx::PaletteGroup* GetPaletteGroup() const override;
const PaletteGroupMetadata& GetMetadata() const override { return metadata_; }
void DrawPaletteGrid() override;
int GetColorsPerRow() const override { return 8; }
private:
static PaletteGroupMetadata InitializeMetadata();
static const PaletteGroupMetadata metadata_;
};
/**
* @brief Dungeon Main palette group card
*
* Manages palettes for dungeon rooms (0-19)
*/
class DungeonMainPaletteCard : public PaletteGroupCard {
public:
explicit DungeonMainPaletteCard(Rom* rom);
~DungeonMainPaletteCard() override = default;
protected:
gfx::PaletteGroup* GetPaletteGroup() override;
const gfx::PaletteGroup* GetPaletteGroup() const override;
const PaletteGroupMetadata& GetMetadata() const override { return metadata_; }
void DrawPaletteGrid() override;
int GetColorsPerRow() const override { return 16; }
private:
static PaletteGroupMetadata InitializeMetadata();
static const PaletteGroupMetadata metadata_;
};
/**
* @brief Sprite palette group card
*
* Manages sprite palettes with VRAM locations
* - Global sprites (palettes 0-3)
* - Auxiliary sprites (palettes 4-5)
*/
class SpritePaletteCard : public PaletteGroupCard {
public:
explicit SpritePaletteCard(Rom* rom);
~SpritePaletteCard() override = default;
protected:
gfx::PaletteGroup* GetPaletteGroup() override;
const gfx::PaletteGroup* GetPaletteGroup() const override;
const PaletteGroupMetadata& GetMetadata() const override { return metadata_; }
void DrawPaletteGrid() override;
int GetColorsPerRow() const override { return 8; }
void DrawCustomPanels() override; // Show VRAM info
private:
static PaletteGroupMetadata InitializeMetadata();
static const PaletteGroupMetadata metadata_;
};
/**
* @brief Equipment/Armor palette group card
*
* Manages Link's equipment color palettes (green, blue, red tunics)
*/
class EquipmentPaletteCard : public PaletteGroupCard {
public:
explicit EquipmentPaletteCard(Rom* rom);
~EquipmentPaletteCard() override = default;
protected:
gfx::PaletteGroup* GetPaletteGroup() override;
const gfx::PaletteGroup* GetPaletteGroup() const override;
const PaletteGroupMetadata& GetMetadata() const override { return metadata_; }
void DrawPaletteGrid() override;
int GetColorsPerRow() const override { return 8; }
private:
static PaletteGroupMetadata InitializeMetadata();
static const PaletteGroupMetadata metadata_;
};
} // namespace editor
} // namespace yaze
#endif // YAZE_APP_EDITOR_GRAPHICS_PALETTE_GROUP_CARD_H