feat: Introduce CompactToolbar and EditorCard for Enhanced Editor Layout
- Added CompactToolbar class to provide a modern, ultra-compact toolbar for the editor, featuring mode buttons, property editing, and quick actions. - Implemented EditorCard class for draggable, dockable editor sub-windows, enhancing the user interface with responsive and themed cards. - Introduced EditorLayout class to manage the overall editor layout, integrating the toolbar and main canvas for a cohesive user experience. - Updated CMake configuration to include new source files, ensuring proper build integration.
This commit is contained in:
316
src/app/gui/editor_layout.cc
Normal file
316
src/app/gui/editor_layout.cc
Normal file
@@ -0,0 +1,316 @@
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
|
||||
#include "app/gui/editor_layout.h"
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/ui_helpers.h"
|
||||
#include "app/gui/widgets/widget_id_registry.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
|
||||
// ============================================================================
|
||||
// CompactToolbar Implementation
|
||||
// ============================================================================
|
||||
|
||||
void CompactToolbar::Begin() {
|
||||
// Ultra-compact toolbar with no padding waste
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 3));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 4));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 6));
|
||||
|
||||
ImGui::BeginGroup();
|
||||
in_toolbar_ = true;
|
||||
button_count_ = 0;
|
||||
}
|
||||
|
||||
void CompactToolbar::End() {
|
||||
ImGui::EndGroup();
|
||||
ImGui::PopStyleVar(3);
|
||||
ImGui::Separator();
|
||||
in_toolbar_ = false;
|
||||
}
|
||||
|
||||
void CompactToolbar::BeginModeGroup() {
|
||||
// Visual grouping with subtle background - taller for better button visibility
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.17f, 0.5f));
|
||||
ImGui::BeginChild("##ModeGroup", ImVec2(0, 40), true,
|
||||
ImGuiWindowFlags_NoScrollbar);
|
||||
}
|
||||
|
||||
bool CompactToolbar::ModeButton(const char* icon, bool selected, const char* tooltip) {
|
||||
if (selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, GetAccentColor());
|
||||
}
|
||||
|
||||
bool clicked = ImGui::Button(icon, ImVec2(32, 32)); // Larger buttons for better usability
|
||||
|
||||
if (selected) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
// Register for test automation
|
||||
if (ImGui::GetItemID() != 0 && tooltip) {
|
||||
std::string button_path = absl::StrFormat("ModeButton:%s", tooltip);
|
||||
WidgetIdRegistry::Instance().RegisterWidget(
|
||||
button_path, "button", ImGui::GetItemID(), tooltip);
|
||||
}
|
||||
|
||||
if (tooltip && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", tooltip);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
button_count_++;
|
||||
|
||||
return clicked;
|
||||
}
|
||||
|
||||
void CompactToolbar::EndModeGroup() {
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
AddSeparator();
|
||||
}
|
||||
|
||||
void CompactToolbar::AddSeparator() {
|
||||
ImGui::TextDisabled("|");
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
void CompactToolbar::AddRomBadge(uint8_t version, std::function<void()> on_upgrade) {
|
||||
RomVersionBadge(version == 0xFF ? "Vanilla" :
|
||||
absl::StrFormat("v%d", version).c_str(),
|
||||
version == 0xFF);
|
||||
|
||||
if (on_upgrade && (version == 0xFF || version < 3)) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(ICON_MD_UPGRADE)) {
|
||||
on_upgrade();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Upgrade to ZSCustomOverworld v3");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
AddSeparator();
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
||||
uint8_t* value,
|
||||
std::function<void()> on_change) {
|
||||
ImGui::Text("%s", icon);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(55);
|
||||
|
||||
bool changed = InputHexByte(label, value);
|
||||
if (changed && on_change) {
|
||||
on_change();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddProperty(const char* icon, const char* label,
|
||||
uint16_t* value,
|
||||
std::function<void()> on_change) {
|
||||
ImGui::Text("%s", icon);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(70);
|
||||
|
||||
bool changed = InputHexWord(label, value);
|
||||
if (changed && on_change) {
|
||||
on_change();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddCombo(const char* icon, int* current,
|
||||
const char* const items[], int count) {
|
||||
ImGui::Text("%s", icon);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(110);
|
||||
|
||||
bool changed = ImGui::Combo("##combo", current, items, count);
|
||||
ImGui::SameLine();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddToggle(const char* icon, bool* state, const char* tooltip) {
|
||||
bool result = ToggleIconButton(icon, icon, state, tooltip);
|
||||
ImGui::SameLine();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddAction(const char* icon, const char* tooltip) {
|
||||
bool clicked = ImGui::SmallButton(icon);
|
||||
|
||||
// Register for test automation
|
||||
if (ImGui::GetItemID() != 0 && tooltip) {
|
||||
std::string button_path = absl::StrFormat("ToolbarAction:%s", tooltip);
|
||||
WidgetIdRegistry::Instance().RegisterWidget(
|
||||
button_path, "button", ImGui::GetItemID(), tooltip);
|
||||
}
|
||||
|
||||
if (tooltip && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", tooltip);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
return clicked;
|
||||
}
|
||||
|
||||
bool CompactToolbar::BeginCollapsibleSection(const char* label, bool* p_open) {
|
||||
ImGui::NewLine(); // Start on new line
|
||||
bool is_open = ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_None);
|
||||
if (p_open) *p_open = is_open;
|
||||
in_section_ = is_open;
|
||||
return is_open;
|
||||
}
|
||||
|
||||
void CompactToolbar::EndCollapsibleSection() {
|
||||
in_section_ = false;
|
||||
}
|
||||
|
||||
void CompactToolbar::AddV3StatusBadge(uint8_t version, std::function<void()> on_settings) {
|
||||
if (version >= 3 && version != 0xFF) {
|
||||
StatusBadge("v3 Active", ButtonType::Success);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(ICON_MD_TUNE " Settings") && on_settings) {
|
||||
on_settings();
|
||||
}
|
||||
} else {
|
||||
StatusBadge("v3 Available", ButtonType::Default);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(ICON_MD_UPGRADE " Upgrade")) {
|
||||
ImGui::OpenPopup("UpgradeROMVersion");
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
bool CompactToolbar::AddUsageStatsButton(const char* tooltip) {
|
||||
bool clicked = ImGui::SmallButton(ICON_MD_ANALYTICS " Usage");
|
||||
if (tooltip && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", tooltip);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
return clicked;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EditorCard Implementation
|
||||
// ============================================================================
|
||||
|
||||
EditorCard::EditorCard(const char* title, const char* icon)
|
||||
: title_(title), icon_(icon ? icon : ""), default_size_(400, 300) {}
|
||||
|
||||
void EditorCard::SetDefaultSize(float width, float height) {
|
||||
default_size_ = ImVec2(width, height);
|
||||
}
|
||||
|
||||
void EditorCard::SetPosition(Position pos) {
|
||||
position_ = pos;
|
||||
}
|
||||
|
||||
bool EditorCard::Begin(bool* p_open) {
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_None;
|
||||
|
||||
// Set initial position based on position enum
|
||||
if (first_draw_) {
|
||||
float display_width = ImGui::GetIO().DisplaySize.x;
|
||||
float display_height = ImGui::GetIO().DisplaySize.y;
|
||||
|
||||
switch (position_) {
|
||||
case Position::Right:
|
||||
ImGui::SetNextWindowPos(ImVec2(display_width - default_size_.x - 10, 30),
|
||||
ImGuiCond_FirstUseEver);
|
||||
break;
|
||||
case Position::Left:
|
||||
ImGui::SetNextWindowPos(ImVec2(10, 30), ImGuiCond_FirstUseEver);
|
||||
break;
|
||||
case Position::Bottom:
|
||||
ImGui::SetNextWindowPos(
|
||||
ImVec2(10, display_height - default_size_.y - 10),
|
||||
ImGuiCond_FirstUseEver);
|
||||
break;
|
||||
case Position::Floating:
|
||||
case Position::Free:
|
||||
ImGui::SetNextWindowPos(
|
||||
ImVec2(display_width * 0.5f - default_size_.x * 0.5f,
|
||||
display_height * 0.3f),
|
||||
ImGuiCond_FirstUseEver);
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSize(default_size_, ImGuiCond_FirstUseEver);
|
||||
first_draw_ = false;
|
||||
}
|
||||
|
||||
// Create window title with icon
|
||||
std::string window_title = icon_.empty() ? title_ : icon_ + " " + title_;
|
||||
|
||||
// Modern card styling
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, GetThemeColor(ImGuiCol_TitleBg));
|
||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, GetAccentColor());
|
||||
|
||||
bool visible = ImGui::Begin(window_title.c_str(), p_open, flags);
|
||||
|
||||
// Register card window for test automation
|
||||
if (ImGui::GetCurrentWindow() && ImGui::GetCurrentWindow()->ID != 0) {
|
||||
std::string card_path = absl::StrFormat("EditorCard:%s", title_.c_str());
|
||||
WidgetIdRegistry::Instance().RegisterWidget(
|
||||
card_path, "window", ImGui::GetCurrentWindow()->ID,
|
||||
absl::StrFormat("Editor card: %s", title_.c_str()));
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
|
||||
void EditorCard::End() {
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EditorLayout Implementation
|
||||
// ============================================================================
|
||||
|
||||
void EditorLayout::Begin() {
|
||||
toolbar_.Begin();
|
||||
in_layout_ = true;
|
||||
}
|
||||
|
||||
void EditorLayout::End() {
|
||||
toolbar_.End();
|
||||
in_layout_ = false;
|
||||
}
|
||||
|
||||
void EditorLayout::BeginMainCanvas() {
|
||||
// Main canvas takes remaining space
|
||||
ImGui::BeginChild("##MainCanvas", ImVec2(0, 0), false);
|
||||
}
|
||||
|
||||
void EditorLayout::EndMainCanvas() {
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void EditorLayout::RegisterCard(EditorCard* card) {
|
||||
cards_.push_back(card);
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
Reference in New Issue
Block a user