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:
@@ -182,8 +182,8 @@ function Test-AgentFolderStructure {
|
|||||||
)
|
)
|
||||||
|
|
||||||
$oldSystemFiles = @(
|
$oldSystemFiles = @(
|
||||||
"src/app/editor/system/agent_chat_widget.h",
|
"src/app/editor/agent/agent_chat_widget.h",
|
||||||
"src/app/editor/system/agent_collaboration_coordinator.h"
|
"src/app/editor/agent/agent_collaboration_coordinator.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
$allPresent = $true
|
$allPresent = $true
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ function test_agent_folder_structure() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
local old_system_files=(
|
local old_system_files=(
|
||||||
"src/app/editor/system/agent_chat_widget.h"
|
"src/app/editor/agent/agent_chat_widget.h"
|
||||||
"src/app/editor/system/agent_collaboration_coordinator.h"
|
"src/app/editor/agent/agent_collaboration_coordinator.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
local all_present=1
|
local all_present=1
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ set(
|
|||||||
app/gui/widgets/widget_auto_register.cc
|
app/gui/widgets/widget_auto_register.cc
|
||||||
app/gui/widgets/widget_state_capture.cc
|
app/gui/widgets/widget_state_capture.cc
|
||||||
app/gui/ui_helpers.cc
|
app/gui/ui_helpers.cc
|
||||||
|
app/gui/toolset.cc
|
||||||
|
app/gui/settings_bar.cc
|
||||||
# Canvas system components
|
# Canvas system components
|
||||||
app/gui/canvas/canvas_modals.cc
|
app/gui/canvas/canvas_modals.cc
|
||||||
app/gui/canvas/canvas_context_menu.cc
|
app/gui/canvas/canvas_context_menu.cc
|
||||||
|
|||||||
157
src/app/gui/settings_bar.cc
Normal file
157
src/app/gui/settings_bar.cc
Normal 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
111
src/app/gui/settings_bar.h
Normal 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(¤t_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
199
src/app/gui/toolset.cc
Normal 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
111
src/app/gui/toolset.h
Normal 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
|
||||||
@@ -43,21 +43,21 @@ ImVec4 GetAccentColor() {
|
|||||||
return ConvertColorToImVec4(theme.accent);
|
return ConvertColorToImVec4(theme.accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entity/Map marker colors
|
// Entity/Map marker colors (normalized RGB + proper alpha)
|
||||||
ImVec4 GetEntranceColor() {
|
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() {
|
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() {
|
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() {
|
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() {
|
ImVec4 GetSelectedColor() {
|
||||||
@@ -378,6 +378,120 @@ void RightAlign(float width) {
|
|||||||
ImGui::GetContentRegionAvail().x - 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
|
// Input Helpers
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -132,6 +132,38 @@ void HorizontalSpacing(float pixels = 8.0f);
|
|||||||
void CenterText(const char* text);
|
void CenterText(const char* text);
|
||||||
void RightAlign(float width);
|
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)
|
// Input Helpers (complement existing gui::InputHex functions)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user