refactor: Update File Paths and Introduce New GUI Components

- Modified file paths in verify-build-environment scripts to reflect the new directory structure for agent-related files, enhancing clarity and organization.
- Added new SettingsBar and Toolset classes to improve the editor's UI, providing a modern, compact interface for managing settings and tools.
- Implemented helper functions for animations and responsive layouts in ui_helpers, enhancing the overall user experience and visual appeal.
- Updated CMake configuration to include new source files, ensuring a seamless build process.
This commit is contained in:
scawful
2025-10-05 16:24:29 -04:00
parent 409cf357af
commit 951e7891b4
9 changed files with 735 additions and 9 deletions

View File

@@ -182,8 +182,8 @@ function Test-AgentFolderStructure {
)
$oldSystemFiles = @(
"src/app/editor/system/agent_chat_widget.h",
"src/app/editor/system/agent_collaboration_coordinator.h"
"src/app/editor/agent/agent_chat_widget.h",
"src/app/editor/agent/agent_collaboration_coordinator.h"
)
$allPresent = $true

View File

@@ -148,8 +148,8 @@ function test_agent_folder_structure() {
)
local old_system_files=(
"src/app/editor/system/agent_chat_widget.h"
"src/app/editor/system/agent_collaboration_coordinator.h"
"src/app/editor/agent/agent_chat_widget.h"
"src/app/editor/agent/agent_collaboration_coordinator.h"
)
local all_present=1

View File

@@ -16,6 +16,8 @@ set(
app/gui/widgets/widget_auto_register.cc
app/gui/widgets/widget_state_capture.cc
app/gui/ui_helpers.cc
app/gui/toolset.cc
app/gui/settings_bar.cc
# Canvas system components
app/gui/canvas/canvas_modals.cc
app/gui/canvas/canvas_context_menu.cc

157
src/app/gui/settings_bar.cc Normal file
View File

@@ -0,0 +1,157 @@
#include "app/gui/settings_bar.h"
#include "absl/strings/str_format.h"
#include "app/gui/icons.h"
#include "app/gui/input.h"
#include "app/gui/ui_helpers.h"
#include "imgui/imgui.h"
namespace yaze {
namespace gui {
void SettingsBar::SetRomVersion(uint8_t version) {
rom_version_ = version;
}
void SettingsBar::BeginDraw() {
// Compact, modern settings bar
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 6));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 4));
// Single row layout using columns for alignment
ImGui::BeginGroup();
in_settings_bar_ = true;
current_column_ = 0;
}
void SettingsBar::EndDraw() {
ImGui::EndGroup();
ImGui::PopStyleVar(2);
ImGui::Separator();
in_settings_bar_ = false;
}
void SettingsBar::AddVersionBadge(std::function<void()> on_upgrade) {
if (IsVanilla()) {
RomVersionBadge("Vanilla ROM", true);
if (on_upgrade) {
ImGui::SameLine();
if (IconButton(ICON_MD_UPGRADE, "Upgrade to v3", ImVec2(0, 0))) {
on_upgrade();
}
}
} else {
std::string version_text = absl::StrFormat("v%d", rom_version_);
RomVersionBadge(version_text.c_str(), false);
if (rom_version_ < 3 && on_upgrade) {
ImGui::SameLine();
if (IconButton(ICON_MD_UPGRADE, "Upgrade to v3", ImVec2(0, 0))) {
on_upgrade();
}
}
}
ImGui::SameLine();
AddSeparator();
}
void SettingsBar::AddWorldSelector(int* current_world) {
ImGui::Text(ICON_MD_PUBLIC);
ImGui::SameLine();
ImGui::SetNextItemWidth(120);
const char* worlds[] = {"Light World", "Dark World", "Extra World"};
ImGui::Combo("##world", current_world, worlds, 3);
ImGui::SameLine();
}
void SettingsBar::AddHexByteInput(const char* icon, const char* label,
uint8_t* value,
std::function<void()> on_change) {
ImGui::Text("%s", icon);
ImGui::SameLine();
ImGui::SetNextItemWidth(60);
if (InputHexByte(label, value)) {
if (on_change) on_change();
}
ImGui::SameLine();
}
void SettingsBar::AddHexWordInput(const char* icon, const char* label,
uint16_t* value,
std::function<void()> on_change) {
ImGui::Text("%s", icon);
ImGui::SameLine();
ImGui::SetNextItemWidth(80);
if (InputHexWord(label, value)) {
if (on_change) on_change();
}
ImGui::SameLine();
}
void SettingsBar::AddCheckbox(const char* icon, const char* label, bool* value,
std::function<void()> on_change) {
ImGui::Text("%s", icon);
ImGui::SameLine();
if (ImGui::Checkbox(label, value)) {
if (on_change) on_change();
}
ImGui::SameLine();
}
void SettingsBar::AddCombo(const char* icon, const char* label, int* current,
const char* const items[], int count,
std::function<void()> on_change) {
ImGui::Text("%s", icon);
ImGui::SameLine();
ImGui::SetNextItemWidth(120);
if (ImGui::Combo(label, current, items, count)) {
if (on_change) on_change();
}
ImGui::SameLine();
}
void SettingsBar::AddAreaSizeSelector(int* area_size,
std::function<void()> on_change) {
if (!IsV3()) return;
const char* sizes[] = {"Small (1x1)", "Large (2x2)", "Wide (2x1)", "Tall (1x2)"};
ImGui::Text(ICON_MD_ASPECT_RATIO);
ImGui::SameLine();
ImGui::SetNextItemWidth(110);
if (ImGui::Combo("##areasize", area_size, sizes, 4)) {
if (on_change) on_change();
}
ImGui::SameLine();
}
void SettingsBar::AddButton(const char* icon, const char* label,
std::function<void()> callback) {
if (IconButton(icon, label)) {
if (callback) callback();
}
ImGui::SameLine();
}
void SettingsBar::AddSeparator() {
ImGui::TextDisabled("|");
ImGui::SameLine();
}
} // namespace gui
} // namespace yaze

111
src/app/gui/settings_bar.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef YAZE_APP_GUI_SETTINGS_BAR_H
#define YAZE_APP_GUI_SETTINGS_BAR_H
#include <functional>
#include <string>
#include <vector>
#include "imgui/imgui.h"
namespace yaze {
namespace gui {
/**
* @class SettingsBar
* @brief Modern, compact settings bar for editor properties
*
* A horizontal bar that consolidates mode selection, property editing,
* and quick actions into a single, space-efficient component.
*
* Design Philosophy:
* - Inline property editing with InputHex widgets
* - Compact layout saves vertical space
* - Visual ROM version indicator
* - Theme-aware styling
* - Responsive to different ROM versions
*
* Features:
* - World selector
* - Map properties (GFX, Palette, Sprites, Message ID)
* - Version-specific properties (v2: Main Palette, v3: Animated GFX, Area Size)
* - Visual ROM version badge
* - Upgrade prompts for vanilla ROMs
* - Mosaic effect toggle
*
* Usage:
* ```cpp
* SettingsBar settings;
* settings.SetRomVersion(asm_version);
* settings.BeginDraw();
*
* settings.AddWorldSelector(&current_world);
* settings.AddHexInput("Graphics", &map->area_graphics);
* settings.AddHexInput("Palette", &map->area_palette);
*
* if (settings.IsV3()) {
* settings.AddAreaSizeSelector(&map->area_size);
* }
*
* settings.EndDraw();
* ```
*/
class SettingsBar {
public:
SettingsBar() = default;
// Set ROM version to enable version-specific features
void SetRomVersion(uint8_t version);
// Check ROM version
bool IsVanilla() const { return rom_version_ == 0xFF; }
bool IsV2() const { return rom_version_ >= 2 && rom_version_ != 0xFF; }
bool IsV3() const { return rom_version_ >= 3 && rom_version_ != 0xFF; }
// Begin drawing the settings bar
void BeginDraw();
// End drawing the settings bar
void EndDraw();
// Add ROM version badge
void AddVersionBadge(std::function<void()> on_upgrade = nullptr);
// Add world selector dropdown
void AddWorldSelector(int* current_world);
// Add hex input for a property
void AddHexByteInput(const char* icon, const char* label, uint8_t* value,
std::function<void()> on_change = nullptr);
void AddHexWordInput(const char* icon, const char* label, uint16_t* value,
std::function<void()> on_change = nullptr);
// Add checkbox
void AddCheckbox(const char* icon, const char* label, bool* value,
std::function<void()> on_change = nullptr);
// Add combo box
void AddCombo(const char* icon, const char* label, int* current,
const char* const items[], int count,
std::function<void()> on_change = nullptr);
// Add area size selector (v3+ only)
void AddAreaSizeSelector(int* area_size,
std::function<void()> on_change = nullptr);
// Add custom button
void AddButton(const char* icon, const char* label,
std::function<void()> callback);
// Add spacing
void AddSeparator();
private:
uint8_t rom_version_ = 0xFF;
int current_column_ = 0;
bool in_settings_bar_ = false;
};
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_SETTINGS_BAR_H

199
src/app/gui/toolset.cc Normal file
View File

@@ -0,0 +1,199 @@
#include "app/gui/toolset.h"
#include "absl/strings/str_format.h"
#include "app/gui/icons.h"
#include "app/gui/ui_helpers.h"
#include "imgui/imgui.h"
namespace yaze {
namespace gui {
void Toolset::AddTool(const std::string& id, const char* icon,
const char* shortcut, std::function<void()> callback,
const char* tooltip) {
Tool tool;
tool.id = id;
tool.icon = icon;
tool.shortcut = shortcut;
tool.callback = callback;
if (tooltip) {
tool.tooltip = std::string(icon) + " " + tooltip;
if (shortcut && strlen(shortcut) > 0) {
tool.tooltip += " (" + std::string(shortcut) + ")";
}
} else {
tool.tooltip = id;
if (shortcut && strlen(shortcut) > 0) {
tool.tooltip += " (" + std::string(shortcut) + ")";
}
}
tools_.push_back(tool);
}
void Toolset::AddSeparator() {
if (!tools_.empty()) {
tools_.back().separator_after = true;
}
}
void Toolset::SetSelected(const std::string& id) {
selected_ = id;
}
bool Toolset::Draw() {
bool clicked = false;
// Calculate columns based on mode
int columns = max_columns_;
if (columns == 0) {
// Auto-fit to available width
float button_width = compact_mode_ ? 32.0f : 80.0f;
columns = static_cast<int>(ImGui::GetContentRegionAvail().x / button_width);
if (columns < 1) columns = 1;
if (columns > static_cast<int>(tools_.size()))
columns = static_cast<int>(tools_.size());
}
// Modern toolset with reduced padding
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(2, 2));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
if (ImGui::BeginTable("##Toolset", columns,
ImGuiTableFlags_SizingFixedFit |
ImGuiTableFlags_BordersInnerV)) {
for (const auto& tool : tools_) {
if (!tool.enabled) continue;
ImGui::TableNextColumn();
bool is_selected = (tool.id == selected_);
DrawTool(tool, is_selected);
if (tool.separator_after) {
ImGui::TableNextColumn();
ImGui::Dummy(ImVec2(1, 1)); // Small separator space
}
}
ImGui::EndTable();
}
ImGui::PopStyleVar(2);
return clicked;
}
void Toolset::DrawTool(const Tool& tool, bool is_selected) {
ImVec2 button_size = compact_mode_ ? ImVec2(28, 28) : ImVec2(0, 0);
if (is_selected) {
ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(GetAccentColor().x * 1.1f, GetAccentColor().y * 1.1f,
GetAccentColor().z * 1.1f, GetAccentColor().w));
}
bool clicked = false;
if (compact_mode_) {
clicked = ImGui::Button(tool.icon.c_str(), button_size);
} else {
std::string label = tool.icon + " " + tool.id;
clicked = ImGui::Button(label.c_str(), button_size);
}
if (is_selected) {
ImGui::PopStyleColor(2);
}
if (clicked && tool.callback) {
tool.callback();
selected_ = tool.id;
}
if (ImGui::IsItemHovered() && !tool.tooltip.empty()) {
ImGui::SetTooltip("%s", tool.tooltip.c_str());
}
}
void Toolset::Clear() {
tools_.clear();
selected_.clear();
}
// ============================================================================
// Editor Toolset Factories
// ============================================================================
namespace EditorToolset {
Toolset CreateOverworldToolset() {
Toolset toolset;
toolset.SetCompactMode(true);
// Editing tools
toolset.AddTool("Pan", ICON_MD_PAN_TOOL_ALT, "1", nullptr,
"Pan - Middle click and drag");
toolset.AddTool("Draw", ICON_MD_DRAW, "2", nullptr,
"Draw Tile");
toolset.AddTool("Entrances", ICON_MD_DOOR_FRONT, "3", nullptr,
"Entrances");
toolset.AddTool("Exits", ICON_MD_DOOR_BACK, "4", nullptr,
"Exits");
toolset.AddTool("Items", ICON_MD_GRASS, "5", nullptr,
"Items");
toolset.AddTool("Sprites", ICON_MD_PEST_CONTROL_RODENT, "6", nullptr,
"Sprites");
toolset.AddTool("Transports", ICON_MD_ADD_LOCATION, "7", nullptr,
"Transports");
toolset.AddTool("Music", ICON_MD_MUSIC_NOTE, "8", nullptr,
"Music");
toolset.AddSeparator();
// View controls
toolset.AddTool("ZoomOut", ICON_MD_ZOOM_OUT, "", nullptr,
"Zoom Out");
toolset.AddTool("ZoomIn", ICON_MD_ZOOM_IN, "", nullptr,
"Zoom In");
toolset.AddTool("Fullscreen", ICON_MD_OPEN_IN_FULL, "F11", nullptr,
"Fullscreen Canvas");
toolset.AddSeparator();
// Quick access
toolset.AddTool("Tile16", ICON_MD_GRID_VIEW, "Ctrl+T", nullptr,
"Tile16 Editor");
toolset.AddTool("Copy", ICON_MD_CONTENT_COPY, "", nullptr,
"Copy Map");
return toolset;
}
Toolset CreateDungeonToolset() {
Toolset toolset;
toolset.SetCompactMode(true);
toolset.AddTool("Pan", ICON_MD_PAN_TOOL_ALT, "1", nullptr,
"Pan");
toolset.AddTool("Draw", ICON_MD_DRAW, "2", nullptr,
"Draw Object");
toolset.AddTool("Select", ICON_MD_SELECT_ALL, "3", nullptr,
"Select");
toolset.AddSeparator();
toolset.AddTool("ZoomOut", ICON_MD_ZOOM_OUT, "", nullptr,
"Zoom Out");
toolset.AddTool("ZoomIn", ICON_MD_ZOOM_IN, "", nullptr,
"Zoom In");
return toolset;
}
} // namespace EditorToolset
} // namespace gui
} // namespace yaze

111
src/app/gui/toolset.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef YAZE_APP_GUI_TOOLSET_H
#define YAZE_APP_GUI_TOOLSET_H
#include <functional>
#include <string>
#include <vector>
#include "imgui/imgui.h"
namespace yaze {
namespace gui {
/**
* @class Toolset
* @brief Modern, space-efficient toolset for editor mode switching
*
* A toolset is a horizontal bar of icon buttons for switching between
* editor modes (Pan, Draw, Select, etc.). This provides a consistent,
* beautiful interface across all editors.
*
* Features:
* - Compact, icon-based design
* - Visual selection indicator
* - Keyboard shortcut hints
* - Automatic tooltips
* - Theme-aware styling
* - Separators for logical grouping
*
* Usage:
* ```cpp
* Toolset toolset;
* toolset.AddTool("Pan", ICON_MD_PAN_TOOL, "1", []() { mode = PAN; });
* toolset.AddTool("Draw", ICON_MD_DRAW, "2", []() { mode = DRAW; });
* toolset.AddSeparator();
* toolset.AddTool("Zoom+", ICON_MD_ZOOM_IN, "", []() { ZoomIn(); });
*
* if (toolset.Draw()) {
* // A tool was clicked
* }
* ```
*/
class Toolset {
public:
struct Tool {
std::string id;
std::string icon;
std::string tooltip;
std::string shortcut;
std::function<void()> callback;
bool enabled = true;
bool separator_after = false;
};
Toolset() = default;
// Add a tool to the toolset
void AddTool(const std::string& id, const char* icon,
const char* shortcut, std::function<void()> callback,
const char* tooltip = nullptr);
// Add a separator for visual grouping
void AddSeparator();
// Set the currently selected tool
void SetSelected(const std::string& id);
// Get the currently selected tool ID
const std::string& GetSelected() const { return selected_; }
// Draw the toolset (returns true if a tool was clicked)
bool Draw();
// Compact mode (smaller buttons, no labels)
void SetCompactMode(bool compact) { compact_mode_ = compact; }
// Set the number of columns (0 = auto-fit to window width)
void SetMaxColumns(int columns) { max_columns_ = columns; }
// Clear all tools
void Clear();
private:
void DrawTool(const Tool& tool, bool is_selected);
std::vector<Tool> tools_;
std::string selected_;
bool compact_mode_ = true;
int max_columns_ = 0; // 0 = auto-fit
};
/**
* @namespace EditorToolset
* @brief Helper functions for creating common editor toolsets
*/
namespace EditorToolset {
// Create standard editing mode toolset
Toolset CreateStandardToolset();
// Create overworld-specific toolset
Toolset CreateOverworldToolset();
// Create dungeon-specific toolset
Toolset CreateDungeonToolset();
} // namespace EditorToolset
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_TOOLSET_H

View File

@@ -43,21 +43,21 @@ ImVec4 GetAccentColor() {
return ConvertColorToImVec4(theme.accent);
}
// Entity/Map marker colors
// Entity/Map marker colors (normalized RGB + proper alpha)
ImVec4 GetEntranceColor() {
return ImVec4(1.0f, 1.0f, 0.0f, 0.6f); // Yellow with transparency
return ImVec4(1.0f, 1.0f, 0.0f, 0.39f); // Yellow, 100/255 alpha
}
ImVec4 GetExitColor() {
return ImVec4(1.0f, 1.0f, 1.0f, 0.6f); // White with transparency
return ImVec4(1.0f, 1.0f, 1.0f, 0.59f); // White, 150/255 alpha
}
ImVec4 GetItemColor() {
return ImVec4(1.0f, 0.0f, 0.0f, 0.6f); // Red with transparency
return ImVec4(1.0f, 0.0f, 0.0f, 0.59f); // Red, 150/255 alpha
}
ImVec4 GetSpriteColor() {
return ImVec4(1.0f, 0.0f, 1.0f, 0.6f); // Magenta with transparency
return ImVec4(1.0f, 0.0f, 1.0f, 0.59f); // Magenta, 150/255 alpha
}
ImVec4 GetSelectedColor() {
@@ -378,6 +378,120 @@ void RightAlign(float width) {
ImGui::GetContentRegionAvail().x - width);
}
// ============================================================================
// Animation Helpers
// ============================================================================
float GetPulseAlpha(float speed) {
return 0.5f + 0.5f * sinf(static_cast<float>(ImGui::GetTime()) * speed * 2.0f);
}
float GetFadeIn(float duration) {
static double start_time = 0.0;
double current_time = ImGui::GetTime();
if (start_time == 0.0) {
start_time = current_time;
}
float elapsed = static_cast<float>(current_time - start_time);
float alpha = ImClamp(elapsed / duration, 0.0f, 1.0f);
// Reset after complete
if (alpha >= 1.0f) {
start_time = 0.0;
}
return alpha;
}
void PushPulseEffect(float speed) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha,
ImGui::GetStyle().Alpha * GetPulseAlpha(speed));
}
void PopPulseEffect() {
ImGui::PopStyleVar();
}
void LoadingSpinner(const char* label, float radius) {
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetCursorScreenPos();
pos.x += radius + 4;
pos.y += radius + 4;
const float rotation = static_cast<float>(ImGui::GetTime()) * 3.0f;
const int segments = 16;
const float thickness = 3.0f;
const float start_angle = rotation;
const float end_angle = rotation + IM_PI * 1.5f;
draw_list->PathArcTo(pos, radius, start_angle, end_angle, segments);
draw_list->PathStroke(ImGui::GetColorU32(GetAccentColor()), 0, thickness);
if (label) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + radius * 2 + 8);
ImGui::Text("%s", label);
} else {
ImGui::Dummy(ImVec2(radius * 2 + 8, radius * 2 + 8));
}
}
// ============================================================================
// Responsive Layout Helpers
// ============================================================================
float GetResponsiveWidth(float min_width, float max_width, float ratio) {
float available = ImGui::GetContentRegionAvail().x;
float target = available * ratio;
if (target < min_width) return min_width;
if (target > max_width) return max_width;
return target;
}
void SetupResponsiveColumns(int count, float min_col_width) {
float available = ImGui::GetContentRegionAvail().x;
float col_width = available / count;
if (col_width < min_col_width) {
col_width = min_col_width;
}
for (int i = 0; i < count; ++i) {
ImGui::TableSetupColumn("##col", ImGuiTableColumnFlags_WidthFixed, col_width);
}
}
static int g_two_col_table_active = 0;
void BeginTwoColumns(const char* id, float split_ratio) {
ImGuiTableFlags flags = ImGuiTableFlags_Resizable |
ImGuiTableFlags_BordersInnerV |
ImGuiTableFlags_SizingStretchProp;
if (ImGui::BeginTable(id, 2, flags)) {
float available = ImGui::GetContentRegionAvail().x;
ImGui::TableSetupColumn("##left", ImGuiTableColumnFlags_None,
available * split_ratio);
ImGui::TableSetupColumn("##right", ImGuiTableColumnFlags_None,
available * (1.0f - split_ratio));
ImGui::TableNextRow();
ImGui::TableNextColumn();
g_two_col_table_active++;
}
}
void SwitchColumn() {
ImGui::TableNextColumn();
}
void EndTwoColumns() {
ImGui::EndTable();
g_two_col_table_active--;
}
// ============================================================================
// Input Helpers
// ============================================================================

View File

@@ -132,6 +132,38 @@ void HorizontalSpacing(float pixels = 8.0f);
void CenterText(const char* text);
void RightAlign(float width);
// ============================================================================
// Animation Helpers
// ============================================================================
// Pulsing alpha animation (for loading indicators, etc.)
float GetPulseAlpha(float speed = 1.0f);
// Fade-in animation (for panel transitions)
float GetFadeIn(float duration = 0.3f);
// Apply pulsing effect to next widget
void PushPulseEffect(float speed = 1.0f);
void PopPulseEffect();
// Loading spinner (animated circle)
void LoadingSpinner(const char* label = nullptr, float radius = 10.0f);
// ============================================================================
// Responsive Layout Helpers
// ============================================================================
// Get responsive width based on available space
float GetResponsiveWidth(float min_width, float max_width, float ratio = 0.5f);
// Auto-fit table columns
void SetupResponsiveColumns(int count, float min_col_width = 100.0f);
// Responsive two-column layout
void BeginTwoColumns(const char* id, float split_ratio = 0.6f);
void SwitchColumn();
void EndTwoColumns();
// ============================================================================
// Input Helpers (complement existing gui::InputHex functions)
// ============================================================================