feat(editor): enhance EditorManager with card-based editor functionality
- Introduced methods to determine if an editor is card-based and to retrieve its category. - Implemented a sidebar toggle shortcut (Ctrl+B) for managing card visibility. - Added functionality to hide current editor cards when switching editors. - Updated editor initialization to register global shortcuts for activating specific editors. - Enhanced the Update method to draw a sidebar for the current category editor. Benefits: - Improved user experience by organizing editor cards and providing quick access to editor categories. - Streamlined editor management, making it easier to switch between different editing contexts.
This commit is contained in:
@@ -260,5 +260,54 @@ absl::Status DisplayEditablePalette(gfx::SnesPalette& palette,
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
IMGUI_API bool PaletteColorButton(const char* id, const gfx::SnesColor& color,
|
||||
bool is_selected, bool is_modified,
|
||||
const ImVec2& size,
|
||||
ImGuiColorEditFlags flags) {
|
||||
ImVec4 display_color = ConvertSnesColorToImVec4(color);
|
||||
|
||||
// Add visual indicators for selection and modification
|
||||
ImGui::PushID(id);
|
||||
|
||||
// Selection border
|
||||
if (is_selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 0.8f, 0.0f, 1.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f);
|
||||
}
|
||||
|
||||
bool clicked = ImGui::ColorButton(id, display_color, flags, size);
|
||||
|
||||
if (is_selected) {
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
// Modification indicator (small dot in corner)
|
||||
if (is_modified) {
|
||||
ImVec2 pos = ImGui::GetItemRectMin();
|
||||
ImVec2 dot_pos = ImVec2(pos.x + size.x - 6, pos.y + 2);
|
||||
ImGui::GetWindowDrawList()->AddCircleFilled(dot_pos, 3.0f,
|
||||
IM_COL32(255, 128, 0, 255));
|
||||
}
|
||||
|
||||
// Tooltip with color info
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("SNES: $%04X", color.snes());
|
||||
auto rgb = color.rgb();
|
||||
ImGui::Text("RGB: (%d, %d, %d)",
|
||||
static_cast<int>(rgb.x),
|
||||
static_cast<int>(rgb.y),
|
||||
static_cast<int>(rgb.z));
|
||||
if (is_modified) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "Modified");
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
return clicked;
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
@@ -56,6 +56,12 @@ IMGUI_API absl::Status DisplayEditablePalette(gfx::SnesPalette &palette,
|
||||
void SelectablePalettePipeline(uint64_t &palette_id, bool &refresh_graphics,
|
||||
gfx::SnesPalette &palette);
|
||||
|
||||
// Palette color button with selection and modification indicators
|
||||
IMGUI_API bool PaletteColorButton(const char* id, const gfx::SnesColor& color,
|
||||
bool is_selected, bool is_modified,
|
||||
const ImVec2& size = ImVec2(28, 28),
|
||||
ImGuiColorEditFlags flags = 0);
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/theme_manager.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "util/file_util.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace gui {
|
||||
@@ -34,11 +34,54 @@ void EditorCardManager::RegisterCard(const CardInfo& info) {
|
||||
info.card_id.c_str(), info.display_name.c_str());
|
||||
}
|
||||
|
||||
void EditorCardManager::RegisterCard(const std::string& card_id,
|
||||
const std::string& display_name,
|
||||
const std::string& icon,
|
||||
const std::string& category,
|
||||
const std::string& shortcut_hint,
|
||||
int priority,
|
||||
std::function<void()> on_show,
|
||||
std::function<void()> on_hide,
|
||||
bool visible_by_default) {
|
||||
if (card_id.empty()) {
|
||||
printf("[EditorCardManager] Warning: Attempted to register card with empty ID\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already registered
|
||||
if (cards_.find(card_id) != cards_.end()) {
|
||||
printf("[EditorCardManager] WARNING: Card '%s' already registered, skipping duplicate\n",
|
||||
card_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create centralized visibility flag
|
||||
centralized_visibility_[card_id] = visible_by_default;
|
||||
|
||||
// Register card with pointer to centralized flag
|
||||
CardInfo info;
|
||||
info.card_id = card_id;
|
||||
info.display_name = display_name;
|
||||
info.icon = icon;
|
||||
info.category = category;
|
||||
info.shortcut_hint = shortcut_hint;
|
||||
info.priority = priority;
|
||||
info.visibility_flag = ¢ralized_visibility_[card_id];
|
||||
info.on_show = on_show;
|
||||
info.on_hide = on_hide;
|
||||
|
||||
cards_[card_id] = info;
|
||||
printf("[EditorCardManager] Registered card with centralized visibility: %s (%s) [default: %s]\n",
|
||||
card_id.c_str(), display_name.c_str(), visible_by_default ? "visible" : "hidden");
|
||||
}
|
||||
|
||||
void EditorCardManager::UnregisterCard(const std::string& card_id) {
|
||||
auto it = cards_.find(card_id);
|
||||
if (it != cards_.end()) {
|
||||
printf("[EditorCardManager] Unregistered card: %s\n", card_id.c_str());
|
||||
cards_.erase(it);
|
||||
// Also remove centralized visibility if it exists
|
||||
centralized_visibility_.erase(card_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +99,9 @@ bool EditorCardManager::ShowCard(const std::string& card_id) {
|
||||
if (it->second.visibility_flag) {
|
||||
*it->second.visibility_flag = true;
|
||||
|
||||
// Set active category when showing a card
|
||||
SetActiveCategory(it->second.category);
|
||||
|
||||
if (it->second.on_show) {
|
||||
it->second.on_show();
|
||||
}
|
||||
@@ -669,6 +715,107 @@ void EditorCardManager::LoadPresetsFromFile() {
|
||||
printf("[EditorCardManager] Loading presets from file\n");
|
||||
}
|
||||
|
||||
void EditorCardManager::SetActiveCategory(const std::string& category) {
|
||||
if (active_category_ != category) {
|
||||
active_category_ = category;
|
||||
printf("[EditorCardManager] Active category changed to: %s\n", category.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorCardManager::DrawSidebar(const std::string& category) {
|
||||
// Set this category as active when sidebar is drawn
|
||||
SetActiveCategory(category);
|
||||
|
||||
// Use ThemeManager for consistent theming
|
||||
const auto& theme = ThemeManager::Get().GetCurrentTheme();
|
||||
|
||||
const float sidebar_width = GetSidebarWidth();
|
||||
|
||||
// Fixed sidebar window on the left edge of screen
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetFrameHeight())); // Below menu bar
|
||||
ImGui::SetNextWindowSize(ImVec2(sidebar_width, -1)); // Full height below menu
|
||||
|
||||
ImGuiWindowFlags sidebar_flags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse |
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ConvertColorToImVec4(theme.child_bg));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f, 8.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 6.0f));
|
||||
|
||||
if (ImGui::Begin(absl::StrFormat("##%s_Sidebar", category).c_str(), nullptr, sidebar_flags)) {
|
||||
// Get cards for this category
|
||||
auto cards = GetCardsInCategory(category);
|
||||
|
||||
// Close All button at top
|
||||
ImVec4 error_color = ConvertColorToImVec4(theme.error);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(
|
||||
error_color.x * 0.6f, error_color.y * 0.6f, error_color.z * 0.6f, 0.7f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, error_color);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(
|
||||
error_color.x * 1.2f, error_color.y * 1.2f, error_color.z * 1.2f, 1.0f));
|
||||
|
||||
if (ImGui::Button(ICON_MD_CLOSE, ImVec2(40.0f, 40.0f))) {
|
||||
HideAllCardsInCategory(category);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Close All %s Cards", category.c_str());
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, 4.0f));
|
||||
|
||||
// Draw card buttons
|
||||
ImVec4 accent_color = ConvertColorToImVec4(theme.accent);
|
||||
ImVec4 button_bg = ConvertColorToImVec4(theme.button);
|
||||
|
||||
for (const auto& card : cards) {
|
||||
ImGui::PushID(card.card_id.c_str());
|
||||
|
||||
bool is_active = card.visibility_flag && *card.visibility_flag;
|
||||
|
||||
if (is_active) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(
|
||||
accent_color.x, accent_color.y, accent_color.z, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(
|
||||
accent_color.x, accent_color.y, accent_color.z, 0.7f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, accent_color);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, button_bg);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ConvertColorToImVec4(theme.button_hovered));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ConvertColorToImVec4(theme.button_active));
|
||||
}
|
||||
|
||||
if (ImGui::Button(card.icon.c_str(), ImVec2(40.0f, 40.0f))) {
|
||||
ToggleCard(card.card_id);
|
||||
SetActiveCategory(category);
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
|
||||
SetActiveCategory(category);
|
||||
|
||||
ImGui::SetTooltip("%s\n%s", card.display_name.c_str(),
|
||||
card.shortcut_hint.empty() ? "" : card.shortcut_hint.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
|
||||
|
||||
@@ -75,6 +75,18 @@ class EditorCardManager {
|
||||
|
||||
// Registration
|
||||
void RegisterCard(const CardInfo& info);
|
||||
|
||||
// Register card with centralized visibility management (preferred method)
|
||||
void RegisterCard(const std::string& card_id,
|
||||
const std::string& display_name,
|
||||
const std::string& icon,
|
||||
const std::string& category,
|
||||
const std::string& shortcut_hint = "",
|
||||
int priority = 50,
|
||||
std::function<void()> on_show = nullptr,
|
||||
std::function<void()> on_hide = nullptr,
|
||||
bool visible_by_default = false);
|
||||
|
||||
void UnregisterCard(const std::string& card_id);
|
||||
void ClearAllCards();
|
||||
|
||||
@@ -98,6 +110,15 @@ class EditorCardManager {
|
||||
void DrawViewMenuSection(const std::string& category);
|
||||
void DrawViewMenuAll(); // Draw all categories as submenus
|
||||
|
||||
// VSCode-style sidebar (replaces Toolset)
|
||||
void DrawSidebar(const std::string& category); // Icon-only sidebar for category
|
||||
static constexpr float GetSidebarWidth() { return 48.0f; }
|
||||
|
||||
// Active editor tracking (based on most recently interacted card)
|
||||
void SetActiveCategory(const std::string& category);
|
||||
std::string GetActiveCategory() const { return active_category_; }
|
||||
bool IsCategoryActive(const std::string& category) const { return active_category_ == category; }
|
||||
|
||||
// Compact inline card control for menu bar
|
||||
void DrawCompactCardControl(const std::string& category); // Shows only active editor's cards
|
||||
void DrawInlineCardToggles(const std::string& category); // Minimal inline checkboxes
|
||||
@@ -135,7 +156,9 @@ class EditorCardManager {
|
||||
EditorCardManager& operator=(const EditorCardManager&) = delete;
|
||||
|
||||
std::unordered_map<std::string, CardInfo> cards_;
|
||||
std::unordered_map<std::string, bool> centralized_visibility_; // Centralized card visibility flags
|
||||
std::unordered_map<std::string, WorkspacePreset> presets_;
|
||||
std::string active_category_; // Currently active editor category (based on last card interaction)
|
||||
|
||||
// Helper methods
|
||||
void SavePresetsToFile();
|
||||
|
||||
@@ -254,50 +254,7 @@ void ThemedProgressBar(float fraction, const ImVec2& size, const char* overlay)
|
||||
// ============================================================================
|
||||
// Palette Editor Widgets
|
||||
// ============================================================================
|
||||
|
||||
bool PaletteColorButton(const char* label, const yaze::gfx::SnesColor& color,
|
||||
bool is_selected, bool is_modified,
|
||||
const ImVec2& size) {
|
||||
const auto& theme = GetTheme();
|
||||
|
||||
int style_count = 0;
|
||||
|
||||
// Draw modified indicator with warning border
|
||||
if (is_modified) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ConvertColorToImVec4(theme.warning));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f);
|
||||
style_count++;
|
||||
}
|
||||
|
||||
// Draw selection border (overrides modified if both)
|
||||
if (is_selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, ConvertColorToImVec4(theme.accent));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 3.0f);
|
||||
if (is_modified) {
|
||||
ImGui::PopStyleVar(); // Remove modified border style
|
||||
ImGui::PopStyleColor(); // Remove modified border color
|
||||
}
|
||||
style_count = 1; // Override count
|
||||
}
|
||||
|
||||
// Convert SNES color to ImGui format
|
||||
ImVec4 col = ConvertSnesColorToImVec4(color);
|
||||
|
||||
// Draw color button
|
||||
bool clicked = ImGui::ColorButton(label, col,
|
||||
ImGuiColorEditFlags_NoAlpha |
|
||||
ImGuiColorEditFlags_NoPicker |
|
||||
ImGuiColorEditFlags_NoTooltip,
|
||||
size);
|
||||
|
||||
// Cleanup styles
|
||||
if (style_count > 0) {
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
return clicked;
|
||||
}
|
||||
// NOTE: PaletteColorButton moved to color.cc
|
||||
|
||||
void ColorInfoPanel(const yaze::gfx::SnesColor& color,
|
||||
bool show_snes_format,
|
||||
|
||||
@@ -181,18 +181,7 @@ void ThemedProgressBar(float fraction, const ImVec2& size = ImVec2(-1, 0),
|
||||
// Palette Editor Widgets
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief Palette color button with modified and selection indicators
|
||||
* @param label Widget ID
|
||||
* @param color SNES color to display
|
||||
* @param is_selected Whether this color is currently selected
|
||||
* @param is_modified Whether this color has unsaved changes
|
||||
* @param size Button size (default 24x24)
|
||||
* @return true if clicked
|
||||
*/
|
||||
bool PaletteColorButton(const char* label, const yaze::gfx::SnesColor& color,
|
||||
bool is_selected, bool is_modified,
|
||||
const ImVec2& size = ImVec2(24, 24));
|
||||
// NOTE: PaletteColorButton moved to color.h for consistency with other color utilities
|
||||
|
||||
/**
|
||||
* @brief Display color information with copy-to-clipboard functionality
|
||||
|
||||
Reference in New Issue
Block a user