refactor: Rename CompactToolbar to Toolset and Enhance Toolbar Functionality
- Renamed CompactToolbar class to Toolset for improved clarity and consistency in naming. - Introduced WidgetMeasurement for tracking widget dimensions, enabling debugging and test automation. - Updated toolbar methods to include measurement functionality, logging overflow warnings, and improved layout handling. - Removed the deprecated SettingsBar and Toolset classes to streamline the codebase. - Adjusted CMake configuration to reflect the new file structure and included widget measurement source files.
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
#include "app/gui/icons.h"
|
#include "app/gui/icons.h"
|
||||||
#include "app/gui/input.h"
|
#include "app/gui/input.h"
|
||||||
#include "app/gui/ui_helpers.h"
|
#include "app/gui/ui_helpers.h"
|
||||||
|
#include "app/gui/widget_measurement.h"
|
||||||
#include "app/gui/widgets/widget_id_registry.h"
|
#include "app/gui/widgets/widget_id_registry.h"
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "imgui/imgui_internal.h"
|
#include "imgui/imgui_internal.h"
|
||||||
@@ -14,35 +15,60 @@ namespace yaze {
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// CompactToolbar Implementation
|
// Toolset Implementation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
void CompactToolbar::Begin() {
|
void Toolset::Begin() {
|
||||||
// Ultra-compact toolbar with no padding waste
|
// Ultra-compact toolbar with no padding waste
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 3));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 3));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 6));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 6));
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
// Don't use BeginGroup - it causes stretching. Just use direct layout.
|
||||||
in_toolbar_ = true;
|
in_toolbar_ = true;
|
||||||
button_count_ = 0;
|
button_count_ = 0;
|
||||||
|
current_line_width_ = 0.0f;
|
||||||
|
|
||||||
|
// Begin measurement for debugging and test automation
|
||||||
|
WidgetMeasurement::Instance().BeginToolbarMeasurement("OverworldToolbar");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::End() {
|
void Toolset::End() {
|
||||||
ImGui::EndGroup();
|
// End the current line
|
||||||
|
ImGui::NewLine();
|
||||||
|
|
||||||
|
// End measurement and check for overflow
|
||||||
|
WidgetMeasurement::Instance().EndToolbarMeasurement();
|
||||||
|
|
||||||
|
float toolbar_width = WidgetMeasurement::Instance().GetToolbarWidth("OverworldToolbar");
|
||||||
|
float available_width = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
|
// Log warning if toolbar overflows (for debugging)
|
||||||
|
if (toolbar_width > available_width && toolbar_width > 0) {
|
||||||
|
// Only log once per second to avoid spam
|
||||||
|
static float last_warning_time = 0.0f;
|
||||||
|
float current_time = ImGui::GetTime();
|
||||||
|
if (current_time - last_warning_time > 1.0f) {
|
||||||
|
ImGui::SetTooltip("⚠️ Toolbar overflow: %.0fpx / %.0fpx available",
|
||||||
|
toolbar_width, available_width);
|
||||||
|
last_warning_time = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PopStyleVar(3);
|
ImGui::PopStyleVar(3);
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
in_toolbar_ = false;
|
in_toolbar_ = false;
|
||||||
|
current_line_width_ = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::BeginModeGroup() {
|
void Toolset::BeginModeGroup() {
|
||||||
// Visual grouping with subtle background - taller for better button visibility
|
// Visual grouping with subtle background - taller for better button visibility
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.17f, 0.5f));
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.17f, 0.5f));
|
||||||
ImGui::BeginChild("##ModeGroup", ImVec2(0, 40), true,
|
ImGui::BeginChild("##ModeGroup", ImVec2(0, 40), true,
|
||||||
ImGuiWindowFlags_NoScrollbar);
|
ImGuiWindowFlags_NoScrollbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::ModeButton(const char* icon, bool selected, const char* tooltip) {
|
bool Toolset::ModeButton(const char* icon, bool selected, const char* tooltip) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
|
ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
|
||||||
}
|
}
|
||||||
@@ -53,6 +79,10 @@ bool CompactToolbar::ModeButton(const char* icon, bool selected, const char* too
|
|||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Measure this widget
|
||||||
|
std::string widget_id = tooltip ? tooltip : absl::StrFormat("Button_%d", button_count_);
|
||||||
|
WidgetMeasurement::Instance().MeasureLastItem(widget_id, "mode_button");
|
||||||
|
|
||||||
// Register for test automation
|
// Register for test automation
|
||||||
if (ImGui::GetItemID() != 0 && tooltip) {
|
if (ImGui::GetItemID() != 0 && tooltip) {
|
||||||
std::string button_path = absl::StrFormat("ModeButton:%s", tooltip);
|
std::string button_path = absl::StrFormat("ModeButton:%s", tooltip);
|
||||||
@@ -70,25 +100,26 @@ bool CompactToolbar::ModeButton(const char* icon, bool selected, const char* too
|
|||||||
return clicked;
|
return clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::EndModeGroup() {
|
void Toolset::EndModeGroup() {
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
AddSeparator();
|
AddSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::AddSeparator() {
|
void Toolset::AddSeparator() {
|
||||||
ImGui::TextDisabled("|");
|
// Use a proper separator that doesn't stretch
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::AddRomBadge(uint8_t version, std::function<void()> on_upgrade) {
|
void Toolset::AddRomBadge(uint8_t version, std::function<void()> on_upgrade) {
|
||||||
RomVersionBadge(version == 0xFF ? "Vanilla" :
|
RomVersionBadge(version == 0xFF ? "Vanilla" :
|
||||||
absl::StrFormat("v%d", version).c_str(),
|
absl::StrFormat("v%d", version).c_str(),
|
||||||
version == 0xFF);
|
version == 0xFF);
|
||||||
|
|
||||||
if (on_upgrade && (version == 0xFF || version < 3)) {
|
if (on_upgrade && (version == 0xFF || version < 3)) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine(0, 2); // Tighter spacing
|
||||||
if (ImGui::SmallButton(ICON_MD_UPGRADE)) {
|
if (ImGui::SmallButton(ICON_MD_UPGRADE)) {
|
||||||
on_upgrade();
|
on_upgrade();
|
||||||
}
|
}
|
||||||
@@ -98,12 +129,11 @@ void CompactToolbar::AddRomBadge(uint8_t version, std::function<void()> on_upgra
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
AddSeparator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
bool Toolset::AddProperty(const char* icon, const char* label,
|
||||||
uint8_t* value,
|
uint8_t* value,
|
||||||
std::function<void()> on_change) {
|
std::function<void()> on_change) {
|
||||||
ImGui::Text("%s", icon);
|
ImGui::Text("%s", icon);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(55);
|
ImGui::SetNextItemWidth(55);
|
||||||
@@ -117,9 +147,9 @@ bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
bool Toolset::AddProperty(const char* icon, const char* label,
|
||||||
uint16_t* value,
|
uint16_t* value,
|
||||||
std::function<void()> on_change) {
|
std::function<void()> on_change) {
|
||||||
ImGui::Text("%s", icon);
|
ImGui::Text("%s", icon);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(70);
|
ImGui::SetNextItemWidth(70);
|
||||||
@@ -133,25 +163,29 @@ bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddCombo(const char* icon, int* current,
|
bool Toolset::AddCombo(const char* icon, int* current,
|
||||||
const char* const items[], int count) {
|
const char* const items[], int count) {
|
||||||
ImGui::Text("%s", icon);
|
ImGui::Text("%s", icon);
|
||||||
ImGui::SameLine();
|
WidgetMeasurement::Instance().MeasureLastItem("combo_icon", "text");
|
||||||
ImGui::SetNextItemWidth(110);
|
|
||||||
|
ImGui::SameLine(0, 2); // Reduce spacing between icon and combo
|
||||||
|
ImGui::SetNextItemWidth(100); // Slightly narrower for better fit
|
||||||
|
|
||||||
bool changed = ImGui::Combo("##combo", current, items, count);
|
bool changed = ImGui::Combo("##combo", current, items, count);
|
||||||
|
WidgetMeasurement::Instance().MeasureLastItem("combo_selector", "combo");
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddToggle(const char* icon, bool* state, const char* tooltip) {
|
bool Toolset::AddToggle(const char* icon, bool* state, const char* tooltip) {
|
||||||
bool result = ToggleIconButton(icon, icon, state, tooltip);
|
bool result = ToggleIconButton(icon, icon, state, tooltip);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddAction(const char* icon, const char* tooltip) {
|
bool Toolset::AddAction(const char* icon, const char* tooltip) {
|
||||||
bool clicked = ImGui::SmallButton(icon);
|
bool clicked = ImGui::SmallButton(icon);
|
||||||
|
|
||||||
// Register for test automation
|
// Register for test automation
|
||||||
@@ -169,7 +203,7 @@ bool CompactToolbar::AddAction(const char* icon, const char* tooltip) {
|
|||||||
return clicked;
|
return clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::BeginCollapsibleSection(const char* label, bool* p_open) {
|
bool Toolset::BeginCollapsibleSection(const char* label, bool* p_open) {
|
||||||
ImGui::NewLine(); // Start on new line
|
ImGui::NewLine(); // Start on new line
|
||||||
bool is_open = ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_None);
|
bool is_open = ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_None);
|
||||||
if (p_open) *p_open = is_open;
|
if (p_open) *p_open = is_open;
|
||||||
@@ -177,11 +211,11 @@ bool CompactToolbar::BeginCollapsibleSection(const char* label, bool* p_open) {
|
|||||||
return is_open;
|
return is_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::EndCollapsibleSection() {
|
void Toolset::EndCollapsibleSection() {
|
||||||
in_section_ = false;
|
in_section_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactToolbar::AddV3StatusBadge(uint8_t version, std::function<void()> on_settings) {
|
void Toolset::AddV3StatusBadge(uint8_t version, std::function<void()> on_settings) {
|
||||||
if (version >= 3 && version != 0xFF) {
|
if (version >= 3 && version != 0xFF) {
|
||||||
StatusBadge("v3 Active", ButtonType::Success);
|
StatusBadge("v3 Active", ButtonType::Success);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -198,7 +232,7 @@ void CompactToolbar::AddV3StatusBadge(uint8_t version, std::function<void()> on_
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompactToolbar::AddUsageStatsButton(const char* tooltip) {
|
bool Toolset::AddUsageStatsButton(const char* tooltip) {
|
||||||
bool clicked = ImGui::SmallButton(ICON_MD_ANALYTICS " Usage");
|
bool clicked = ImGui::SmallButton(ICON_MD_ANALYTICS " Usage");
|
||||||
if (tooltip && ImGui::IsItemHovered()) {
|
if (tooltip && ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("%s", tooltip);
|
ImGui::SetTooltip("%s", tooltip);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace yaze {
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class CompactToolbar
|
* @class Toolset
|
||||||
* @brief Ultra-compact toolbar that merges mode buttons with settings
|
* @brief Ultra-compact toolbar that merges mode buttons with settings
|
||||||
*
|
*
|
||||||
* Design Philosophy:
|
* Design Philosophy:
|
||||||
@@ -23,9 +23,9 @@ namespace gui {
|
|||||||
*
|
*
|
||||||
* Layout: [Mode Icons] | [ROM Badge] [World] [GFX] [Pal] [Spr] ... | [Quick Actions]
|
* Layout: [Mode Icons] | [ROM Badge] [World] [GFX] [Pal] [Spr] ... | [Quick Actions]
|
||||||
*/
|
*/
|
||||||
class CompactToolbar {
|
class Toolset {
|
||||||
public:
|
public:
|
||||||
CompactToolbar() = default;
|
Toolset() = default;
|
||||||
|
|
||||||
// Begin the toolbar
|
// Begin the toolbar
|
||||||
void Begin();
|
void Begin();
|
||||||
@@ -76,6 +76,7 @@ class CompactToolbar {
|
|||||||
bool in_toolbar_ = false;
|
bool in_toolbar_ = false;
|
||||||
bool in_section_ = false;
|
bool in_section_ = false;
|
||||||
int button_count_ = 0;
|
int button_count_ = 0;
|
||||||
|
float current_line_width_ = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,7 +163,7 @@ class EditorLayout {
|
|||||||
void End();
|
void End();
|
||||||
|
|
||||||
// Get toolbar reference
|
// Get toolbar reference
|
||||||
CompactToolbar& GetToolbar() { return toolbar_; }
|
Toolset& GetToolbar() { return toolbar_; }
|
||||||
|
|
||||||
// Begin main canvas area
|
// Begin main canvas area
|
||||||
void BeginMainCanvas();
|
void BeginMainCanvas();
|
||||||
@@ -172,7 +173,7 @@ class EditorLayout {
|
|||||||
void RegisterCard(EditorCard* card);
|
void RegisterCard(EditorCard* card);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CompactToolbar toolbar_;
|
Toolset toolbar_;
|
||||||
std::vector<EditorCard*> cards_;
|
std::vector<EditorCard*> cards_;
|
||||||
bool in_layout_ = false;
|
bool in_layout_ = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,9 +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
|
|
||||||
app/gui/editor_layout.cc
|
app/gui/editor_layout.cc
|
||||||
|
app/gui/widget_measurement.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
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
#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
|
|
||||||
140
src/app/gui/widget_measurement.cc
Normal file
140
src/app/gui/widget_measurement.cc
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include "app/gui/widget_measurement.h"
|
||||||
|
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
#include "imgui/imgui_internal.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
|
WidgetMetrics WidgetMeasurement::MeasureLastItem(const std::string& widget_id,
|
||||||
|
const std::string& type) {
|
||||||
|
if (!enabled_) {
|
||||||
|
return WidgetMetrics{};
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetMetrics metrics;
|
||||||
|
metrics.widget_id = widget_id;
|
||||||
|
metrics.type = type;
|
||||||
|
|
||||||
|
// Get item rect (bounding box)
|
||||||
|
metrics.rect_min = ImGui::GetItemRectMin();
|
||||||
|
metrics.rect_max = ImGui::GetItemRectMax();
|
||||||
|
|
||||||
|
// Calculate size
|
||||||
|
metrics.size = ImVec2(metrics.rect_max.x - metrics.rect_min.x,
|
||||||
|
metrics.rect_max.y - metrics.rect_min.y);
|
||||||
|
|
||||||
|
// Store position
|
||||||
|
metrics.position = metrics.rect_min;
|
||||||
|
|
||||||
|
// Get content region
|
||||||
|
metrics.content_size = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
// Get cursor position after item
|
||||||
|
metrics.cursor_pos_x = ImGui::GetCursorPosX();
|
||||||
|
|
||||||
|
// Store in current toolbar if active
|
||||||
|
if (!current_toolbar_id_.empty()) {
|
||||||
|
toolbar_metrics_[current_toolbar_id_].push_back(metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store in frame metrics
|
||||||
|
frame_metrics_.push_back(metrics);
|
||||||
|
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetMeasurement::BeginToolbarMeasurement(const std::string& toolbar_id) {
|
||||||
|
current_toolbar_id_ = toolbar_id;
|
||||||
|
current_toolbar_start_x_ = ImGui::GetCursorPosX();
|
||||||
|
current_toolbar_width_ = 0.0f;
|
||||||
|
|
||||||
|
// Clear previous measurements for this toolbar
|
||||||
|
toolbar_metrics_[toolbar_id].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetMeasurement::EndToolbarMeasurement() {
|
||||||
|
if (current_toolbar_id_.empty()) return;
|
||||||
|
|
||||||
|
// Calculate total width from cursor movement
|
||||||
|
float end_x = ImGui::GetCursorPosX();
|
||||||
|
current_toolbar_width_ = end_x - current_toolbar_start_x_;
|
||||||
|
|
||||||
|
// Store the width
|
||||||
|
toolbar_widths_[current_toolbar_id_] = current_toolbar_width_;
|
||||||
|
|
||||||
|
// Reset state
|
||||||
|
current_toolbar_id_.clear();
|
||||||
|
current_toolbar_width_ = 0.0f;
|
||||||
|
current_toolbar_start_x_ = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WidgetMeasurement::GetToolbarWidth(const std::string& toolbar_id) const {
|
||||||
|
auto it = toolbar_widths_.find(toolbar_id);
|
||||||
|
if (it != toolbar_widths_.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WidgetMeasurement::WouldToolbarOverflow(const std::string& toolbar_id,
|
||||||
|
float available_width) const {
|
||||||
|
float toolbar_width = GetToolbarWidth(toolbar_id);
|
||||||
|
return toolbar_width > available_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<WidgetMetrics>& WidgetMeasurement::GetToolbarMetrics(
|
||||||
|
const std::string& toolbar_id) const {
|
||||||
|
static const std::vector<WidgetMetrics> empty;
|
||||||
|
auto it = toolbar_metrics_.find(toolbar_id);
|
||||||
|
if (it != toolbar_metrics_.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetMeasurement::ClearFrame() {
|
||||||
|
frame_metrics_.clear();
|
||||||
|
// Don't clear toolbar metrics - they persist across frames for debugging
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WidgetMeasurement::ExportMetricsJSON() const {
|
||||||
|
std::string json = "{\n \"toolbars\": {\n";
|
||||||
|
|
||||||
|
bool first_toolbar = true;
|
||||||
|
for (const auto& [toolbar_id, metrics] : toolbar_metrics_) {
|
||||||
|
if (!first_toolbar) json += ",\n";
|
||||||
|
first_toolbar = false;
|
||||||
|
|
||||||
|
json += absl::StrFormat(" \"%s\": {\n", toolbar_id);
|
||||||
|
json += absl::StrFormat(" \"total_width\": %.1f,\n",
|
||||||
|
GetToolbarWidth(toolbar_id));
|
||||||
|
json += " \"widgets\": [\n";
|
||||||
|
|
||||||
|
bool first_widget = true;
|
||||||
|
for (const auto& metric : metrics) {
|
||||||
|
if (!first_widget) json += ",\n";
|
||||||
|
first_widget = false;
|
||||||
|
|
||||||
|
json += " {\n";
|
||||||
|
json += absl::StrFormat(" \"id\": \"%s\",\n", metric.widget_id);
|
||||||
|
json += absl::StrFormat(" \"type\": \"%s\",\n", metric.type);
|
||||||
|
json += absl::StrFormat(" \"width\": %.1f,\n", metric.size.x);
|
||||||
|
json += absl::StrFormat(" \"height\": %.1f,\n", metric.size.y);
|
||||||
|
json += absl::StrFormat(" \"x\": %.1f,\n", metric.position.x);
|
||||||
|
json += absl::StrFormat(" \"y\": %.1f\n", metric.position.y);
|
||||||
|
json += " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
json += "\n ]\n";
|
||||||
|
json += " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
json += "\n }\n}\n";
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gui
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
119
src/app/gui/widget_measurement.h
Normal file
119
src/app/gui/widget_measurement.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#ifndef YAZE_APP_GUI_WIDGET_MEASUREMENT_H
|
||||||
|
#define YAZE_APP_GUI_WIDGET_MEASUREMENT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "absl/strings/str_format.h"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
|
namespace yaze {
|
||||||
|
namespace gui {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class WidgetMeasurement
|
||||||
|
* @brief Tracks widget dimensions for debugging and test automation
|
||||||
|
*
|
||||||
|
* Integrates with ImGui Test Engine to provide accurate measurements
|
||||||
|
* of UI elements, helping prevent layout issues and enabling automated
|
||||||
|
* testing of widget sizes and positions.
|
||||||
|
*/
|
||||||
|
struct WidgetMetrics {
|
||||||
|
ImVec2 size; // Width and height
|
||||||
|
ImVec2 position; // Screen position
|
||||||
|
ImVec2 content_size; // Available content region
|
||||||
|
ImVec2 rect_min; // Bounding box min
|
||||||
|
ImVec2 rect_max; // Bounding box max
|
||||||
|
float cursor_pos_x; // Cursor X after rendering
|
||||||
|
std::string widget_id; // Widget identifier
|
||||||
|
std::string type; // Widget type (button, input, combo, etc.)
|
||||||
|
|
||||||
|
std::string ToString() const {
|
||||||
|
return absl::StrFormat(
|
||||||
|
"Widget '%s' (%s): size=(%.1f,%.1f) pos=(%.1f,%.1f) content=(%.1f,%.1f) cursor_x=%.1f",
|
||||||
|
widget_id, type, size.x, size.y, position.x, position.y,
|
||||||
|
content_size.x, content_size.y, cursor_pos_x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WidgetMeasurement {
|
||||||
|
public:
|
||||||
|
static WidgetMeasurement& Instance() {
|
||||||
|
static WidgetMeasurement instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Measure the last rendered ImGui item
|
||||||
|
* @param widget_id Unique identifier for this widget
|
||||||
|
* @param type Widget type (button, input, etc.)
|
||||||
|
* @return WidgetMetrics containing all measurements
|
||||||
|
*/
|
||||||
|
WidgetMetrics MeasureLastItem(const std::string& widget_id,
|
||||||
|
const std::string& type = "unknown");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Begin measuring a toolbar section
|
||||||
|
*/
|
||||||
|
void BeginToolbarMeasurement(const std::string& toolbar_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief End measuring a toolbar section and store total width
|
||||||
|
*/
|
||||||
|
void EndToolbarMeasurement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get total measured width of a toolbar
|
||||||
|
*/
|
||||||
|
float GetToolbarWidth(const std::string& toolbar_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if toolbar would overflow given window width
|
||||||
|
*/
|
||||||
|
bool WouldToolbarOverflow(const std::string& toolbar_id,
|
||||||
|
float available_width) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all measurements for a specific toolbar
|
||||||
|
*/
|
||||||
|
const std::vector<WidgetMetrics>& GetToolbarMetrics(
|
||||||
|
const std::string& toolbar_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all measurements (call once per frame)
|
||||||
|
*/
|
||||||
|
void ClearFrame();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Export measurements for test automation
|
||||||
|
*/
|
||||||
|
std::string ExportMetricsJSON() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable/disable measurement (performance option)
|
||||||
|
*/
|
||||||
|
void SetEnabled(bool enabled) { enabled_ = enabled; }
|
||||||
|
bool IsEnabled() const { return enabled_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
WidgetMeasurement() = default;
|
||||||
|
|
||||||
|
bool enabled_ = true;
|
||||||
|
std::string current_toolbar_id_;
|
||||||
|
float current_toolbar_width_ = 0.0f;
|
||||||
|
float current_toolbar_start_x_ = 0.0f;
|
||||||
|
|
||||||
|
// Store measurements per toolbar
|
||||||
|
std::unordered_map<std::string, std::vector<WidgetMetrics>> toolbar_metrics_;
|
||||||
|
std::unordered_map<std::string, float> toolbar_widths_;
|
||||||
|
|
||||||
|
// All measurements from current frame
|
||||||
|
std::vector<WidgetMetrics> frame_metrics_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gui
|
||||||
|
} // namespace yaze
|
||||||
|
|
||||||
|
#endif // YAZE_APP_GUI_WIDGET_MEASUREMENT_H
|
||||||
|
|
||||||
Reference in New Issue
Block a user