Enhance editor UI and functionality with improved command palette and display settings
- Updated the command palette UI to include a search input with focus management, allowing users to filter and categorize commands more effectively. - Enhanced the global search UI with tabbed results for recent files and labels, improving organization and accessibility. - Refactored the display settings to be accessible via a popup, allowing customization without needing to load a ROM. - Improved the welcome screen with enhanced particle effects and customization options, making it more visually appealing and user-friendly. - Added functionality for global font scaling and theme management within the display settings, enhancing user experience.
This commit is contained in:
@@ -780,7 +780,8 @@ absl::Status EditorManager::Update() {
|
||||
}
|
||||
|
||||
// Show welcome screen if no editors are active (ROM loaded but editors not opened)
|
||||
if (!any_editor_active) {
|
||||
// Only show if explicitly requested to avoid stacking with manual welcome screen
|
||||
if (!any_editor_active && !show_welcome_screen_) {
|
||||
DrawWelcomeScreen();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
@@ -1070,18 +1071,9 @@ void EditorManager::DrawMenuBar() {
|
||||
}
|
||||
|
||||
if (show_display_settings) {
|
||||
Begin("Display Settings", &show_display_settings, ImGuiWindowFlags_None);
|
||||
gui::DrawDisplaySettings();
|
||||
gui::TextWithSeparators("Font Manager");
|
||||
gui::DrawFontManager();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
Separator();
|
||||
Text("Global Scale");
|
||||
if (SliderFloat("##global_scale", &font_global_scale_, 0.5f, 1.8f, "%.2f")) {
|
||||
io.FontGlobalScale = font_global_scale_;
|
||||
SaveUserSettings();
|
||||
}
|
||||
End();
|
||||
// Use the popup manager instead of a separate window
|
||||
popup_manager_->Show("Display Settings");
|
||||
show_display_settings = false; // Close the old-style window
|
||||
}
|
||||
|
||||
if (show_imgui_demo_) ShowDemoWindow(&show_imgui_demo_);
|
||||
@@ -1111,60 +1103,247 @@ void EditorManager::DrawMenuBar() {
|
||||
End();
|
||||
}
|
||||
|
||||
// Command Palette UI
|
||||
// Enhanced Command Palette UI
|
||||
if (show_command_palette_) {
|
||||
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Once);
|
||||
if (Begin("Command Palette", &show_command_palette_, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) {
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(700, 500), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (Begin(absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), &show_command_palette_,
|
||||
ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
// Search input with focus management
|
||||
static char query[256] = {};
|
||||
InputTextWithHint("##cmd_query", "Type a command or search...", query, IM_ARRAYSIZE(query));
|
||||
ImGui::SetNextItemWidth(-100);
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
}
|
||||
|
||||
bool input_changed = InputTextWithHint("##cmd_query",
|
||||
absl::StrFormat("%s Type a command or search...", ICON_MD_SEARCH).c_str(),
|
||||
query, IM_ARRAYSIZE(query));
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
|
||||
query[0] = '\0';
|
||||
input_changed = true;
|
||||
}
|
||||
|
||||
Separator();
|
||||
// List registered shortcuts as commands
|
||||
|
||||
// Filter and categorize commands
|
||||
std::vector<std::pair<std::string, std::string>> filtered_commands;
|
||||
for (const auto &entry : context_.shortcut_manager.GetShortcuts()) {
|
||||
const auto &name = entry.first;
|
||||
const auto &shortcut = entry.second;
|
||||
if (query[0] != '\0' && name.find(query) == std::string::npos) continue;
|
||||
if (Selectable(name.c_str())) {
|
||||
if (shortcut.callback) shortcut.callback();
|
||||
show_command_palette_ = false;
|
||||
|
||||
if (query[0] == '\0' || name.find(query) != std::string::npos) {
|
||||
std::string shortcut_text = shortcut.keys.empty() ? "" :
|
||||
absl::StrFormat("(%s)", PrintShortcut(shortcut.keys).c_str());
|
||||
filtered_commands.emplace_back(name, shortcut_text);
|
||||
}
|
||||
}
|
||||
|
||||
// Display results in a table for better organization
|
||||
if (ImGui::BeginTable("CommandPaletteTable", 2,
|
||||
ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_SizingStretchProp,
|
||||
ImVec2(0, -30))) { // Reserve space for status bar
|
||||
|
||||
ImGui::TableSetupColumn("Command", ImGuiTableColumnFlags_WidthStretch, 0.7f);
|
||||
ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthStretch, 0.3f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (size_t i = 0; i < filtered_commands.size(); ++i) {
|
||||
const auto& [command_name, shortcut_text] = filtered_commands[i];
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
if (Selectable(command_name.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
// Execute the command
|
||||
const auto& shortcuts = context_.shortcut_manager.GetShortcuts();
|
||||
auto it = shortcuts.find(command_name);
|
||||
if (it != shortcuts.end() && it->second.callback) {
|
||||
it->second.callback();
|
||||
show_command_palette_ = false;
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextDisabled("%s", shortcut_text.c_str());
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
// Status bar
|
||||
ImGui::Separator();
|
||||
ImGui::Text("%s %zu commands found", ICON_MD_INFO, filtered_commands.size());
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("| Press Enter to execute selected command");
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
||||
// Global Search UI (labels and recent files for now)
|
||||
// Enhanced Global Search UI
|
||||
if (show_global_search_) {
|
||||
ImGui::SetNextWindowSize(ImVec2(700, 500), ImGuiCond_Once);
|
||||
if (Begin("Global Search", &show_global_search_, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize)) {
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (Begin(absl::StrFormat("%s Global Search", ICON_MD_MANAGE_SEARCH).c_str(), &show_global_search_,
|
||||
ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
// Enhanced search input with focus management
|
||||
static char query[256] = {};
|
||||
InputTextWithHint("##global_query", ICON_MD_SEARCH " Search labels, files...", query, IM_ARRAYSIZE(query));
|
||||
ImGui::SetNextItemWidth(-100);
|
||||
if (ImGui::IsWindowAppearing()) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
}
|
||||
|
||||
bool input_changed = InputTextWithHint("##global_query",
|
||||
absl::StrFormat("%s Search everything...", ICON_MD_SEARCH).c_str(),
|
||||
query, IM_ARRAYSIZE(query));
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(absl::StrFormat("%s Clear", ICON_MD_CLEAR).c_str())) {
|
||||
query[0] = '\0';
|
||||
input_changed = true;
|
||||
}
|
||||
|
||||
Separator();
|
||||
if (current_rom_ && current_rom_->resource_label()) {
|
||||
Text(ICON_MD_LABEL " Labels");
|
||||
Indent();
|
||||
auto &labels = current_rom_->resource_label()->labels_;
|
||||
for (const auto &type_pair : labels) {
|
||||
for (const auto &kv : type_pair.second) {
|
||||
if (query[0] != '\0' && kv.first.find(query) == std::string::npos && kv.second.find(query) == std::string::npos) continue;
|
||||
if (Selectable((type_pair.first + ": " + kv.first + " -> " + kv.second).c_str())) {
|
||||
// Future: navigate to related editor/location
|
||||
|
||||
// Tabbed search results for better organization
|
||||
if (ImGui::BeginTabBar("SearchResultTabs")) {
|
||||
|
||||
// Recent Files Tab
|
||||
if (ImGui::BeginTabItem(absl::StrFormat("%s Recent Files", ICON_MD_HISTORY).c_str())) {
|
||||
static core::RecentFilesManager manager("recent_files.txt");
|
||||
manager.Load();
|
||||
auto recent_files = manager.GetRecentFiles();
|
||||
|
||||
if (ImGui::BeginTable("RecentFilesTable", 3,
|
||||
ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_SizingStretchProp)) {
|
||||
|
||||
ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 0.6f);
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 80.0f);
|
||||
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed, 100.0f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (const auto &file : recent_files) {
|
||||
if (query[0] != '\0' && file.find(query) == std::string::npos) continue;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", core::GetFileName(file).c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
std::string ext = core::GetFileExtension(file);
|
||||
if (ext == "sfc" || ext == "smc") {
|
||||
ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s ROM", ICON_MD_VIDEOGAME_ASSET);
|
||||
} else if (ext == "yaze") {
|
||||
ImGui::TextColored(ImVec4(0.2f, 0.6f, 0.8f, 1.0f), "%s Project", ICON_MD_FOLDER);
|
||||
} else {
|
||||
ImGui::Text("%s File", ICON_MD_DESCRIPTION);
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushID(file.c_str());
|
||||
if (ImGui::Button("Open")) {
|
||||
status_ = OpenRomOrProject(file);
|
||||
show_global_search_ = false;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// Labels Tab (only if ROM is loaded)
|
||||
if (current_rom_ && current_rom_->resource_label()) {
|
||||
if (ImGui::BeginTabItem(absl::StrFormat("%s Labels", ICON_MD_LABEL).c_str())) {
|
||||
auto &labels = current_rom_->resource_label()->labels_;
|
||||
|
||||
if (ImGui::BeginTable("LabelsTable", 3,
|
||||
ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_SizingStretchProp)) {
|
||||
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 100.0f);
|
||||
ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthStretch, 0.4f);
|
||||
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.6f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (const auto &type_pair : labels) {
|
||||
for (const auto &kv : type_pair.second) {
|
||||
if (query[0] != '\0' &&
|
||||
kv.first.find(query) == std::string::npos &&
|
||||
kv.second.find(query) == std::string::npos) continue;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", type_pair.first.c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (Selectable(kv.first.c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
// Future: navigate to related editor/location
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextDisabled("%s", kv.second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
Unindent();
|
||||
}
|
||||
Text(ICON_MD_HISTORY " Recent Files");
|
||||
Indent();
|
||||
static core::RecentFilesManager manager("recent_files.txt");
|
||||
manager.Load();
|
||||
for (const auto &file : manager.GetRecentFiles()) {
|
||||
if (query[0] != '\0' && file.find(query) == std::string::npos) continue;
|
||||
if (Selectable(file.c_str())) {
|
||||
status_ = OpenRomOrProject(file);
|
||||
show_global_search_ = false;
|
||||
|
||||
// Sessions Tab
|
||||
if (GetActiveSessionCount() > 1) {
|
||||
if (ImGui::BeginTabItem(absl::StrFormat("%s Sessions", ICON_MD_TAB).c_str())) {
|
||||
ImGui::Text("Search and switch between active sessions:");
|
||||
|
||||
for (size_t i = 0; i < sessions_.size(); ++i) {
|
||||
auto& session = sessions_[i];
|
||||
if (session.custom_name == "[CLOSED SESSION]") continue;
|
||||
|
||||
std::string session_info = session.GetDisplayName();
|
||||
if (query[0] != '\0' && session_info.find(query) == std::string::npos) continue;
|
||||
|
||||
bool is_current = (&session.rom == current_rom_);
|
||||
if (is_current) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 0.8f, 0.2f, 1.0f));
|
||||
}
|
||||
|
||||
if (Selectable(absl::StrFormat("%s %s %s",
|
||||
ICON_MD_TAB,
|
||||
session_info.c_str(),
|
||||
is_current ? "(Current)" : "").c_str())) {
|
||||
if (!is_current) {
|
||||
SwitchToSession(i);
|
||||
show_global_search_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_current) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
Unindent();
|
||||
|
||||
// Status bar
|
||||
ImGui::Separator();
|
||||
ImGui::Text("%s Global search across all YAZE data", ICON_MD_INFO);
|
||||
}
|
||||
End();
|
||||
}
|
||||
@@ -2450,18 +2629,22 @@ void EditorManager::DrawSessionRenameDialog() {
|
||||
}
|
||||
|
||||
void EditorManager::DrawWelcomeScreen() {
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(750, 550), ImGuiCond_Always);
|
||||
// Make welcome screen moveable but with a good default position
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
|
||||
|
||||
// Create a subtle animated background effect
|
||||
static float animation_time = 0.0f;
|
||||
animation_time += ImGui::GetIO().DeltaTime;
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoBackground;
|
||||
// Make it moveable and resizable but keep the custom styling
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground;
|
||||
|
||||
if (ImGui::Begin("Welcome to Yaze", nullptr, flags)) {
|
||||
// Use a unique window name to prevent stacking
|
||||
static int welcome_window_id = 0;
|
||||
std::string window_name = absl::StrFormat("Welcome to YAZE##welcome_%d", welcome_window_id);
|
||||
|
||||
if (ImGui::Begin(window_name.c_str(), &show_welcome_screen_, flags)) {
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
ImVec2 window_size = ImGui::GetWindowSize();
|
||||
@@ -2489,18 +2672,39 @@ void EditorManager::DrawWelcomeScreen() {
|
||||
ImVec2(window_pos.x + window_size.x, window_pos.y + window_size.y),
|
||||
themed_border, 12.0f, 0, border_thickness);
|
||||
|
||||
// Themed floating particles effect
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
float offset_x = sinf(animation_time * 0.5f + i * 0.8f) * 20.0f;
|
||||
float offset_y = cosf(animation_time * 0.3f + i * 1.2f) * 15.0f;
|
||||
ImVec2 particle_pos = ImVec2(
|
||||
window_pos.x + 50 + (i * 80) + offset_x,
|
||||
window_pos.y + 100 + offset_y);
|
||||
// Enhanced floating particles effect with multiple layers
|
||||
for (int layer = 0; layer < 2; ++layer) {
|
||||
int particle_count = layer == 0 ? 12 : 8;
|
||||
float layer_speed = layer == 0 ? 1.0f : 0.6f;
|
||||
float layer_alpha = layer == 0 ? 0.4f : 0.2f;
|
||||
|
||||
float alpha = 0.3f + 0.2f * sinf(animation_time * 1.5f + i);
|
||||
ImU32 particle_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
accent_color.red, accent_color.green, accent_color.blue, alpha * 0.4f));
|
||||
draw_list->AddCircleFilled(particle_pos, 2.0f + sinf(animation_time + i) * 0.5f, particle_color);
|
||||
for (int i = 0; i < particle_count; ++i) {
|
||||
float time_offset = layer * 3.14159f + i * 0.8f;
|
||||
float offset_x = sinf(animation_time * 0.5f * layer_speed + time_offset) * (30.0f + layer * 10.0f);
|
||||
float offset_y = cosf(animation_time * 0.3f * layer_speed + time_offset) * (20.0f + layer * 8.0f);
|
||||
|
||||
// Distribute particles across the window
|
||||
float base_x = window_pos.x + (window_size.x / particle_count) * i + 40;
|
||||
float base_y = window_pos.y + 80 + layer * 30;
|
||||
|
||||
ImVec2 particle_pos = ImVec2(base_x + offset_x, base_y + offset_y);
|
||||
|
||||
// Pulsing alpha effect
|
||||
float alpha = layer_alpha + 0.3f * sinf(animation_time * 1.5f + time_offset);
|
||||
ImU32 particle_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
accent_color.red, accent_color.green, accent_color.blue, alpha));
|
||||
|
||||
// Varying particle sizes
|
||||
float radius = 1.5f + layer * 0.5f + sinf(animation_time * 2.0f + time_offset) * 0.8f;
|
||||
draw_list->AddCircleFilled(particle_pos, radius, particle_color);
|
||||
|
||||
// Add subtle glow effect for layer 0
|
||||
if (layer == 0) {
|
||||
ImU32 glow_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
accent_color.red, accent_color.green, accent_color.blue, alpha * 0.3f));
|
||||
draw_list->AddCircleFilled(particle_pos, radius + 1.0f, glow_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Header with themed styling
|
||||
@@ -2520,7 +2724,7 @@ void EditorManager::DrawWelcomeScreen() {
|
||||
ImGui::Spacing();
|
||||
|
||||
// Themed decorative line with glow effect (positioned closer to header)
|
||||
float line_y = window_pos.y + 65; // Move even higher for tighter header integration
|
||||
float line_y = window_pos.y + 35; // Move even higher for tighter header integration
|
||||
float line_margin = 80; // Maintain good horizontal balance
|
||||
ImVec2 line_start = ImVec2(window_pos.x + line_margin, line_y);
|
||||
ImVec2 line_end = ImVec2(window_pos.x + window_size.x - line_margin, line_y);
|
||||
@@ -2698,15 +2902,32 @@ void EditorManager::DrawWelcomeScreen() {
|
||||
ImGui::Spacing();
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, 1.0f), ICON_MD_TIPS_AND_UPDATES " Tip: Drag and drop ROM files onto the window");
|
||||
|
||||
// Add close button in the bottom right corner
|
||||
// Add settings and customization section (accessible before ROM loading)
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
float close_button_width = 100.0f;
|
||||
float offset = ImGui::GetContentRegionAvail().x - close_button_width;
|
||||
if (offset > 0) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset);
|
||||
ImGui::Text("%s Customization & Settings", ICON_MD_SETTINGS);
|
||||
|
||||
if (ImGui::Button(absl::StrFormat("%s Close Welcome", ICON_MD_CLOSE).c_str(), ImVec2(close_button_width, 0))) {
|
||||
show_welcome_screen_ = false;
|
||||
// Theme and display settings buttons (always accessible)
|
||||
static bool show_welcome_theme_selector = false;
|
||||
if (ImGui::Button(absl::StrFormat("%s Theme Settings", ICON_MD_PALETTE).c_str(), ImVec2(180, 35))) {
|
||||
show_welcome_theme_selector = true;
|
||||
}
|
||||
|
||||
// Show theme selector if requested
|
||||
if (show_welcome_theme_selector) {
|
||||
auto& theme_manager = gui::ThemeManager::Get();
|
||||
theme_manager.ShowThemeSelector(&show_welcome_theme_selector);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(absl::StrFormat("%s Display Settings", ICON_MD_DISPLAY_SETTINGS).c_str(), ImVec2(180, 35))) {
|
||||
// Open display settings popup (make it accessible without ROM)
|
||||
popup_manager_->Show("Display Settings");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(absl::StrFormat("%s Command Palette", ICON_MD_TERMINAL).c_str(), ImVec2(180, 35))) {
|
||||
show_command_palette_ = true;
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/features.h"
|
||||
#include "app/core/project.h"
|
||||
#include "app/editor/code/assembly_editor.h"
|
||||
#include "app/editor/code/memory_editor.h"
|
||||
@@ -19,10 +20,9 @@
|
||||
#include "app/editor/overworld/overworld_editor.h"
|
||||
#include "app/editor/sprite/sprite_editor.h"
|
||||
#include "app/editor/system/popup_manager.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/editor/system/settings_editor.h"
|
||||
#include "app/editor/system/toast_manager.h"
|
||||
#include "app/emu/emulator.h"
|
||||
#include "app/core/features.h"
|
||||
#include "app/rom.h"
|
||||
#include "yaze_config.h"
|
||||
|
||||
@@ -100,14 +100,20 @@ class EditorManager {
|
||||
absl::Status SetCurrentRom(Rom* rom);
|
||||
auto GetCurrentRom() -> Rom* { return current_rom_; }
|
||||
auto GetCurrentEditorSet() -> EditorSet* { return current_editor_set_; }
|
||||
|
||||
|
||||
// Get current session's feature flags (falls back to global if no session)
|
||||
core::FeatureFlags::Flags* GetCurrentFeatureFlags() {
|
||||
size_t current_index = GetCurrentSessionIndex();
|
||||
if (current_index < sessions_.size()) {
|
||||
return &sessions_[current_index].feature_flags;
|
||||
}
|
||||
return &core::FeatureFlags::get(); // Fallback to global
|
||||
return &core::FeatureFlags::get(); // Fallback to global
|
||||
}
|
||||
|
||||
void SetFontGlobalScale(float scale) {
|
||||
font_global_scale_ = scale;
|
||||
ImGui::GetIO().FontGlobalScale = scale;
|
||||
SaveUserSettings();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -119,16 +125,17 @@ class EditorManager {
|
||||
absl::Status SaveRom();
|
||||
absl::Status SaveRomAs(const std::string& filename);
|
||||
absl::Status OpenRomOrProject(const std::string& filename);
|
||||
|
||||
|
||||
// Enhanced project management
|
||||
absl::Status CreateNewProject(const std::string& template_name = "Basic ROM Hack");
|
||||
absl::Status CreateNewProject(
|
||||
const std::string& template_name = "Basic ROM Hack");
|
||||
absl::Status OpenProject();
|
||||
absl::Status SaveProject();
|
||||
absl::Status SaveProjectAs();
|
||||
absl::Status ImportProject(const std::string& project_path);
|
||||
absl::Status RepairCurrentProject();
|
||||
void ShowProjectHelp();
|
||||
|
||||
|
||||
// Testing system
|
||||
void InitializeTestSuites();
|
||||
|
||||
@@ -160,7 +167,7 @@ class EditorManager {
|
||||
bool show_welcome_screen_ = false;
|
||||
size_t session_to_rename_ = 0;
|
||||
char session_rename_buffer_[256] = {};
|
||||
|
||||
|
||||
// Testing interface
|
||||
bool show_test_dashboard_ = false;
|
||||
|
||||
@@ -178,18 +185,17 @@ class EditorManager {
|
||||
struct RomSession {
|
||||
Rom rom;
|
||||
EditorSet editors;
|
||||
std::string custom_name; // User-defined session name
|
||||
std::string filepath; // ROM filepath for duplicate detection
|
||||
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
|
||||
std::string custom_name; // User-defined session name
|
||||
std::string filepath; // ROM filepath for duplicate detection
|
||||
core::FeatureFlags::Flags feature_flags; // Per-session feature flags
|
||||
|
||||
RomSession() = default;
|
||||
explicit RomSession(Rom&& r)
|
||||
: rom(std::move(r)), editors(&rom) {
|
||||
explicit RomSession(Rom&& r) : rom(std::move(r)), editors(&rom) {
|
||||
filepath = rom.filename();
|
||||
// Initialize with default feature flags
|
||||
feature_flags = core::FeatureFlags::Flags{};
|
||||
}
|
||||
|
||||
|
||||
// Get display name (custom name or ROM title)
|
||||
std::string GetDisplayName() const {
|
||||
if (!custom_name.empty()) {
|
||||
@@ -213,10 +219,11 @@ class EditorManager {
|
||||
// Settings helpers
|
||||
void LoadUserSettings();
|
||||
void SaveUserSettings();
|
||||
|
||||
void RefreshWorkspacePresets();
|
||||
void SaveWorkspacePreset(const std::string& name);
|
||||
void LoadWorkspacePreset(const std::string& name);
|
||||
|
||||
|
||||
// Workspace management
|
||||
void CreateNewSession();
|
||||
void DuplicateCurrentSession();
|
||||
@@ -226,9 +233,10 @@ class EditorManager {
|
||||
size_t GetCurrentSessionIndex() const;
|
||||
size_t GetActiveSessionCount() const;
|
||||
void ResetWorkspaceLayout();
|
||||
|
||||
|
||||
// Multi-session editor management
|
||||
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index) const;
|
||||
std::string GenerateUniqueEditorTitle(EditorType type,
|
||||
size_t session_index) const;
|
||||
void SaveWorkspaceLayout();
|
||||
void LoadWorkspaceLayout();
|
||||
void ShowAllWindows();
|
||||
@@ -239,12 +247,12 @@ class EditorManager {
|
||||
void LoadDeveloperLayout();
|
||||
void LoadDesignerLayout();
|
||||
void LoadModderLayout();
|
||||
|
||||
|
||||
// Session management helpers
|
||||
bool HasDuplicateSession(const std::string& filepath);
|
||||
void RenameSession(size_t index, const std::string& new_name);
|
||||
std::string GenerateUniqueEditorTitle(EditorType type, size_t session_index);
|
||||
|
||||
|
||||
// UI drawing helpers
|
||||
void DrawSessionSwitcher();
|
||||
void DrawSessionManager();
|
||||
|
||||
@@ -38,6 +38,9 @@ void PopupManager::Initialize() {
|
||||
popups_["Workspace Help"] = {"Workspace Help", false, [this]() { DrawWorkspaceHelpPopup(); }};
|
||||
popups_["Session Limit Warning"] = {"Session Limit Warning", false, [this]() { DrawSessionLimitWarningPopup(); }};
|
||||
popups_["Layout Reset Confirm"] = {"Reset Layout Confirmation", false, [this]() { DrawLayoutResetConfirmPopup(); }};
|
||||
|
||||
// Settings popups (accessible without ROM)
|
||||
popups_["Display Settings"] = {"Display Settings", false, [this]() { DrawDisplaySettingsPopup(); }};
|
||||
}
|
||||
|
||||
void PopupManager::DrawPopups() {
|
||||
@@ -48,7 +51,14 @@ void PopupManager::DrawPopups() {
|
||||
for (auto& [name, params] : popups_) {
|
||||
if (params.is_visible) {
|
||||
OpenPopup(name.c_str());
|
||||
if (BeginPopupModal(name.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
// Special handling for Display Settings popup to make it resizable
|
||||
ImGuiWindowFlags popup_flags = ImGuiWindowFlags_AlwaysAutoResize;
|
||||
if (name == "Display Settings") {
|
||||
popup_flags = ImGuiWindowFlags_None; // Allow resizing for display settings
|
||||
}
|
||||
|
||||
if (BeginPopupModal(name.c_str(), nullptr, popup_flags)) {
|
||||
params.draw_function();
|
||||
EndPopup();
|
||||
}
|
||||
@@ -491,5 +501,46 @@ void PopupManager::DrawLayoutResetConfirmPopup() {
|
||||
}
|
||||
}
|
||||
|
||||
void PopupManager::DrawDisplaySettingsPopup() {
|
||||
// Set a comfortable default size with natural constraints
|
||||
SetNextWindowSize(ImVec2(900, 700), ImGuiCond_FirstUseEver);
|
||||
SetNextWindowSizeConstraints(ImVec2(600, 400), ImVec2(FLT_MAX, FLT_MAX));
|
||||
|
||||
Text("%s Display & Theme Settings", ICON_MD_DISPLAY_SETTINGS);
|
||||
TextWrapped("Customize your YAZE experience - accessible anytime!");
|
||||
Separator();
|
||||
|
||||
// Create a child window for scrollable content to avoid table conflicts
|
||||
// Use remaining space minus the close button area
|
||||
float available_height = GetContentRegionAvail().y - 60; // Reserve space for close button
|
||||
if (BeginChild("DisplaySettingsContent", ImVec2(0, available_height), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
// Use the popup-safe version to avoid table conflicts
|
||||
gui::DrawDisplaySettingsForPopup();
|
||||
|
||||
Separator();
|
||||
gui::TextWithSeparators("Font Manager");
|
||||
gui::DrawFontManager();
|
||||
|
||||
// Global font scale (moved from the old display settings window)
|
||||
ImGuiIO &io = GetIO();
|
||||
Separator();
|
||||
Text("Global Font Scale");
|
||||
static float font_global_scale = io.FontGlobalScale;
|
||||
if (SliderFloat("##global_scale", &font_global_scale, 0.5f, 1.8f, "%.2f")) {
|
||||
if (editor_manager_) {
|
||||
editor_manager_->SetFontGlobalScale(font_global_scale);
|
||||
} else {
|
||||
io.FontGlobalScale = font_global_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
EndChild();
|
||||
|
||||
Separator();
|
||||
if (Button("Close", gui::kDefaultModalSize)) {
|
||||
Hide("Display Settings");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace editor
|
||||
} // namespace yaze
|
||||
|
||||
@@ -86,6 +86,9 @@ class PopupManager {
|
||||
void DrawWorkspaceHelpPopup();
|
||||
void DrawSessionLimitWarningPopup();
|
||||
void DrawLayoutResetConfirmPopup();
|
||||
|
||||
// Settings popups (accessible without ROM)
|
||||
void DrawDisplaySettingsPopup();
|
||||
|
||||
EditorManager* editor_manager_;
|
||||
std::unordered_map<std::string, PopupParams> popups_;
|
||||
|
||||
@@ -925,6 +925,444 @@ void DrawDisplaySettings(ImGuiStyle *ref) {
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void DrawDisplaySettingsForPopup(ImGuiStyle *ref) {
|
||||
// Popup-safe version of DrawDisplaySettings without problematic tables
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
static ImGuiStyle ref_saved_style;
|
||||
|
||||
// Default to using internal storage as reference
|
||||
static bool init = true;
|
||||
if (init && ref == NULL) ref_saved_style = style;
|
||||
init = false;
|
||||
if (ref == NULL) ref = &ref_saved_style;
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
|
||||
|
||||
// Enhanced theme management section (simplified for popup)
|
||||
if (ImGui::CollapsingHeader("Theme Management", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
auto& theme_manager = ThemeManager::Get();
|
||||
|
||||
ImGui::Text("%s Current Theme:", ICON_MD_PALETTE);
|
||||
ImGui::SameLine();
|
||||
|
||||
std::string current_theme_name = theme_manager.GetCurrentThemeName();
|
||||
bool is_classic_active = (current_theme_name == "Classic YAZE");
|
||||
|
||||
// Current theme display with color preview
|
||||
if (is_classic_active) {
|
||||
ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", current_theme_name.c_str());
|
||||
} else {
|
||||
ImGui::Text("%s", current_theme_name.c_str());
|
||||
}
|
||||
|
||||
// Theme color preview
|
||||
auto current_theme = theme_manager.GetCurrentTheme();
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorButton("##primary_preview", gui::ConvertColorToImVec4(current_theme.primary),
|
||||
ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorButton("##secondary_preview", gui::ConvertColorToImVec4(current_theme.secondary),
|
||||
ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorButton("##accent_preview", gui::ConvertColorToImVec4(current_theme.accent),
|
||||
ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20));
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// Simplified theme selection (no table to avoid popup conflicts)
|
||||
if (is_classic_active) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.2f, 1.0f));
|
||||
}
|
||||
|
||||
if (ImGui::Button("Classic YAZE")) {
|
||||
theme_manager.ApplyClassicYazeTheme();
|
||||
ref_saved_style = style;
|
||||
}
|
||||
|
||||
if (is_classic_active) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reset ColorsYaze")) {
|
||||
gui::ColorsYaze();
|
||||
ref_saved_style = style;
|
||||
}
|
||||
|
||||
// File themes dropdown
|
||||
auto available_themes = theme_manager.GetAvailableThemes();
|
||||
const char* current_file_theme = "";
|
||||
|
||||
// Find current file theme for display
|
||||
for (const auto& theme_name : available_themes) {
|
||||
if (theme_name == current_theme_name) {
|
||||
current_file_theme = theme_name.c_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Text("File Themes:");
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::BeginCombo("##FileThemes", current_file_theme)) {
|
||||
for (const auto& theme_name : available_themes) {
|
||||
bool is_selected = (theme_name == current_theme_name);
|
||||
if (ImGui::Selectable(theme_name.c_str(), is_selected)) {
|
||||
theme_manager.LoadTheme(theme_name);
|
||||
ref_saved_style = style;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Refresh Themes")) {
|
||||
theme_manager.RefreshAvailableThemes();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Open Theme Editor")) {
|
||||
static bool show_theme_editor = true;
|
||||
theme_manager.ShowSimpleThemeEditor(&show_theme_editor);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Background effects settings
|
||||
auto& bg_renderer = gui::BackgroundRenderer::Get();
|
||||
bg_renderer.DrawSettingsUI();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::ShowStyleSelector("Colors##Selector")) ref_saved_style = style;
|
||||
ImGui::ShowFontSelector("Fonts##Selector");
|
||||
|
||||
// Quick style controls before the tabbed section
|
||||
if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
|
||||
style.GrabRounding = style.FrameRounding;
|
||||
|
||||
// Border checkboxes (simplified layout)
|
||||
bool window_border = (style.WindowBorderSize > 0.0f);
|
||||
if (ImGui::Checkbox("WindowBorder", &window_border)) {
|
||||
style.WindowBorderSize = window_border ? 1.0f : 0.0f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
bool frame_border = (style.FrameBorderSize > 0.0f);
|
||||
if (ImGui::Checkbox("FrameBorder", &frame_border)) {
|
||||
style.FrameBorderSize = frame_border ? 1.0f : 0.0f;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
bool popup_border = (style.PopupBorderSize > 0.0f);
|
||||
if (ImGui::Checkbox("PopupBorder", &popup_border)) {
|
||||
style.PopupBorderSize = popup_border ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
// Save/Revert buttons
|
||||
if (ImGui::Button("Save Ref")) *ref = ref_saved_style = style;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Revert Ref")) style = *ref;
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Add the comprehensive tabbed settings from the original DrawDisplaySettings
|
||||
if (ImGui::BeginTabBar("DisplaySettingsTabs", ImGuiTabBarFlags_None)) {
|
||||
|
||||
if (ImGui::BeginTabItem("Sizes")) {
|
||||
ImGui::SeparatorText("Main");
|
||||
ImGui::SliderFloat2("WindowPadding", (float *)&style.WindowPadding, 0.0f,
|
||||
20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("FramePadding", (float *)&style.FramePadding, 0.0f,
|
||||
20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("ItemSpacing", (float *)&style.ItemSpacing, 0.0f,
|
||||
20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("ItemInnerSpacing", (float *)&style.ItemInnerSpacing,
|
||||
0.0f, 20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("TouchExtraPadding",
|
||||
(float *)&style.TouchExtraPadding, 0.0f, 10.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f,
|
||||
"%.0f");
|
||||
|
||||
ImGui::SeparatorText("Borders");
|
||||
ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f,
|
||||
1.0f, "%.0f");
|
||||
ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f,
|
||||
2.0f, "%.0f");
|
||||
|
||||
ImGui::SeparatorText("Rounding");
|
||||
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f,
|
||||
12.0f, "%.0f");
|
||||
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f,
|
||||
"%.0f");
|
||||
|
||||
ImGui::SeparatorText("Tables");
|
||||
ImGui::SliderFloat2("CellPadding", (float *)&style.CellPadding, 0.0f,
|
||||
20.0f, "%.0f");
|
||||
ImGui::SliderAngle("TableAngledHeadersAngle",
|
||||
&style.TableAngledHeadersAngle, -50.0f, +50.0f);
|
||||
|
||||
ImGui::SeparatorText("Widgets");
|
||||
ImGui::SliderFloat2("WindowTitleAlign", (float *)&style.WindowTitleAlign,
|
||||
0.0f, 1.0f, "%.2f");
|
||||
ImGui::Combo("ColorButtonPosition", (int *)&style.ColorButtonPosition,
|
||||
"Left\0Right\0");
|
||||
ImGui::SliderFloat2("ButtonTextAlign", (float *)&style.ButtonTextAlign,
|
||||
0.0f, 1.0f, "%.2f");
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SliderFloat2("SelectableTextAlign",
|
||||
(float *)&style.SelectableTextAlign, 0.0f, 1.0f,
|
||||
"%.2f");
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SliderFloat("SeparatorTextBorderSize",
|
||||
&style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
|
||||
ImGui::SliderFloat2("SeparatorTextAlign",
|
||||
(float *)&style.SeparatorTextAlign, 0.0f, 1.0f,
|
||||
"%.2f");
|
||||
ImGui::SliderFloat2("SeparatorTextPadding",
|
||||
(float *)&style.SeparatorTextPadding, 0.0f, 40.0f,
|
||||
"%.0f");
|
||||
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f,
|
||||
12.0f, "%.0f");
|
||||
|
||||
ImGui::SeparatorText("Tooltips");
|
||||
for (int n = 0; n < 2; n++)
|
||||
if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse"
|
||||
: "HoverFlagsForTooltipNav")) {
|
||||
ImGuiHoveredFlags *p = (n == 0) ? &style.HoverFlagsForTooltipMouse
|
||||
: &style.HoverFlagsForTooltipNav;
|
||||
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p,
|
||||
ImGuiHoveredFlags_DelayNone);
|
||||
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p,
|
||||
ImGuiHoveredFlags_DelayShort);
|
||||
ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p,
|
||||
ImGuiHoveredFlags_DelayNormal);
|
||||
ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p,
|
||||
ImGuiHoveredFlags_Stationary);
|
||||
ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p,
|
||||
ImGuiHoveredFlags_NoSharedDelay);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Misc");
|
||||
ImGui::SliderFloat2("DisplaySafeAreaPadding",
|
||||
(float *)&style.DisplaySafeAreaPadding, 0.0f, 30.0f,
|
||||
"%.0f");
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Colors")) {
|
||||
static int output_dest = 0;
|
||||
static bool output_only_modified = true;
|
||||
if (ImGui::Button("Export")) {
|
||||
if (output_dest == 0)
|
||||
ImGui::LogToClipboard();
|
||||
else
|
||||
ImGui::LogToTTY();
|
||||
ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
|
||||
for (int i = 0; i < ImGuiCol_COUNT; i++) {
|
||||
const ImVec4 &col = style.Colors[i];
|
||||
const char *name = ImGui::GetStyleColorName(i);
|
||||
if (!output_only_modified ||
|
||||
memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
|
||||
ImGui::LogText(
|
||||
"colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, "
|
||||
"%.2ff);" IM_NEWLINE,
|
||||
name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
|
||||
}
|
||||
ImGui::LogFinish();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(120);
|
||||
ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Only Modified Colors", &output_only_modified);
|
||||
|
||||
static ImGuiTextFilter filter;
|
||||
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
|
||||
|
||||
static ImGuiColorEditFlags alpha_flags = 0;
|
||||
if (ImGui::RadioButton("Opaque",
|
||||
alpha_flags == ImGuiColorEditFlags_None)) {
|
||||
alpha_flags = ImGuiColorEditFlags_None;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Alpha",
|
||||
alpha_flags == ImGuiColorEditFlags_AlphaPreview)) {
|
||||
alpha_flags = ImGuiColorEditFlags_AlphaPreview;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton(
|
||||
"Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) {
|
||||
alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(
|
||||
ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10),
|
||||
ImVec2(FLT_MAX, FLT_MAX));
|
||||
ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar |
|
||||
ImGuiWindowFlags_AlwaysHorizontalScrollbar |
|
||||
ImGuiWindowFlags_NavFlattened);
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
|
||||
for (int i = 0; i < ImGuiCol_COUNT; i++) {
|
||||
const char *name = ImGui::GetStyleColorName(i);
|
||||
if (!filter.PassFilter(name)) continue;
|
||||
ImGui::PushID(i);
|
||||
ImGui::ColorEdit4("##color", (float *)&style.Colors[i],
|
||||
ImGuiColorEditFlags_AlphaBar | alpha_flags);
|
||||
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) {
|
||||
// Tips: in a real user application, you may want to merge and use
|
||||
// an icon font into the main font, so instead of "Save"/"Revert"
|
||||
// you'd use icons! Read the FAQ and docs/FONTS.md about using icon
|
||||
// fonts. It's really easy and super convenient!
|
||||
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
|
||||
if (ImGui::Button("Save")) {
|
||||
ref->Colors[i] = style.Colors[i];
|
||||
}
|
||||
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
|
||||
if (ImGui::Button("Revert")) {
|
||||
style.Colors[i] = ref->Colors[i];
|
||||
}
|
||||
}
|
||||
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
|
||||
ImGui::TextUnformatted(name);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Fonts")) {
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
ImFontAtlas *atlas = io.Fonts;
|
||||
ImGui::ShowFontAtlas(atlas);
|
||||
|
||||
// Post-baking font scaling. Note that this is NOT the nice way of
|
||||
// scaling fonts, read below. (we enforce hard clamping manually as by
|
||||
// default DragFloat/SliderFloat allows CTRL+Click text to get out of
|
||||
// bounds).
|
||||
const float MIN_SCALE = 0.3f;
|
||||
const float MAX_SCALE = 2.0f;
|
||||
|
||||
static float window_scale = 1.0f;
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
|
||||
if (ImGui::DragFloat(
|
||||
"window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE,
|
||||
"%.2f",
|
||||
ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
|
||||
ImGui::SetWindowFontScale(window_scale);
|
||||
ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE,
|
||||
MAX_SCALE, "%.2f",
|
||||
ImGuiSliderFlags_AlwaysClamp); // Scale everything
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Rendering")) {
|
||||
ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("Anti-aliased lines use texture",
|
||||
&style.AntiAliasedLinesUseTex);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
|
||||
ImGui::DragFloat("Curve Tessellation Tolerance",
|
||||
&style.CurveTessellationTol, 0.02f, 0.10f, 10.0f,
|
||||
"%.2f");
|
||||
if (style.CurveTessellationTol < 0.10f)
|
||||
style.CurveTessellationTol = 0.10f;
|
||||
|
||||
// When editing the "Circle Segment Max Error" value, draw a preview of
|
||||
// its effect on auto-tessellated circles.
|
||||
ImGui::DragFloat("Circle Tessellation Max Error",
|
||||
&style.CircleTessellationMaxError, 0.005f, 0.10f, 5.0f,
|
||||
"%.2f", ImGuiSliderFlags_AlwaysClamp);
|
||||
const bool show_samples = ImGui::IsItemActive();
|
||||
if (show_samples) ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
|
||||
if (show_samples && ImGui::BeginTooltip()) {
|
||||
ImGui::TextUnformatted("(R = radius, N = number of segments)");
|
||||
ImGui::Spacing();
|
||||
ImDrawList *draw_list = ImGui::GetWindowDrawList();
|
||||
const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
|
||||
for (int n = 0; n < 8; n++) {
|
||||
const float RAD_MIN = 5.0f;
|
||||
const float RAD_MAX = 70.0f;
|
||||
const float rad =
|
||||
RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::Text("R: %.f\nN: %d", rad,
|
||||
draw_list->_CalcCircleAutoSegmentCount(rad));
|
||||
|
||||
const float canvas_width = std::max(min_widget_width, rad * 2.0f);
|
||||
const float offset_x = floorf(canvas_width * 0.5f);
|
||||
const float offset_y = floorf(RAD_MAX);
|
||||
|
||||
const ImVec2 p1 = ImGui::GetCursorScreenPos();
|
||||
draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad,
|
||||
ImGui::GetColorU32(ImGuiCol_Text));
|
||||
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
|
||||
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f,
|
||||
"%.2f"); // Not exposing zero here so user doesn't
|
||||
// "lose" the UI (zero alpha clips all
|
||||
// widgets). But application code could have a
|
||||
// toggle to switch between zero and non-zero.
|
||||
ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f,
|
||||
1.0f, "%.2f");
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void TextWithSeparators(const absl::string_view &text) {
|
||||
ImGui::Separator();
|
||||
ImGui::Text("%s", text.data());
|
||||
|
||||
@@ -73,6 +73,7 @@ void SetupCanvasTableColumn(const char* label, float width_ratio = 0.0f);
|
||||
void BeginCanvasTableCell(ImVec2 min_size = ImVec2(0, 0));
|
||||
|
||||
void DrawDisplaySettings(ImGuiStyle *ref = nullptr);
|
||||
void DrawDisplaySettingsForPopup(ImGuiStyle *ref = nullptr); // Popup-safe version
|
||||
|
||||
void TextWithSeparators(const absl::string_view &text);
|
||||
|
||||
|
||||
@@ -356,6 +356,29 @@ void ThemeManager::ShowThemeSelector(bool* p_open) {
|
||||
if (!p_open || !*p_open) return;
|
||||
|
||||
if (ImGui::Begin(absl::StrFormat("%s Theme Selector", ICON_MD_PALETTE).c_str(), p_open)) {
|
||||
|
||||
// Add subtle particle effects to theme selector
|
||||
static float theme_animation_time = 0.0f;
|
||||
theme_animation_time += ImGui::GetIO().DeltaTime;
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
ImVec2 window_size = ImGui::GetWindowSize();
|
||||
|
||||
// Subtle corner particles for theme selector
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float corner_offset = i * 1.57f; // 90 degrees apart
|
||||
float x = window_pos.x + window_size.x * 0.5f + cosf(theme_animation_time * 0.8f + corner_offset) * (window_size.x * 0.4f);
|
||||
float y = window_pos.y + window_size.y * 0.5f + sinf(theme_animation_time * 0.8f + corner_offset) * (window_size.y * 0.4f);
|
||||
|
||||
float alpha = 0.1f + 0.1f * sinf(theme_animation_time * 1.2f + corner_offset);
|
||||
auto current_theme = GetCurrentTheme();
|
||||
ImU32 particle_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
current_theme.accent.red, current_theme.accent.green, current_theme.accent.blue, alpha));
|
||||
|
||||
draw_list->AddCircleFilled(ImVec2(x, y), 3.0f, particle_color);
|
||||
}
|
||||
|
||||
ImGui::Text("%s Available Themes", ICON_MD_COLOR_LENS);
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -901,6 +924,35 @@ void ThemeManager::ShowSimpleThemeEditor(bool* p_open) {
|
||||
if (ImGui::Begin(absl::StrFormat("%s Theme Editor", ICON_MD_PALETTE).c_str(), p_open,
|
||||
ImGuiWindowFlags_MenuBar)) {
|
||||
|
||||
// Add gentle particle effects to theme editor background
|
||||
static float editor_animation_time = 0.0f;
|
||||
editor_animation_time += ImGui::GetIO().DeltaTime;
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
ImVec2 window_size = ImGui::GetWindowSize();
|
||||
|
||||
// Floating color orbs representing different color categories
|
||||
auto current_theme = GetCurrentTheme();
|
||||
std::vector<gui::Color> theme_colors = {
|
||||
current_theme.primary, current_theme.secondary, current_theme.accent,
|
||||
current_theme.success, current_theme.warning, current_theme.error
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < theme_colors.size(); ++i) {
|
||||
float time_offset = i * 1.0f;
|
||||
float orbit_radius = 60.0f + i * 8.0f;
|
||||
float x = window_pos.x + window_size.x * 0.8f + cosf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
|
||||
float y = window_pos.y + window_size.y * 0.3f + sinf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
|
||||
|
||||
float alpha = 0.15f + 0.1f * sinf(editor_animation_time * 1.5f + time_offset);
|
||||
ImU32 orb_color = ImGui::ColorConvertFloat4ToU32(ImVec4(
|
||||
theme_colors[i].red, theme_colors[i].green, theme_colors[i].blue, alpha));
|
||||
|
||||
float radius = 4.0f + sinf(editor_animation_time * 2.0f + time_offset) * 1.0f;
|
||||
draw_list->AddCircleFilled(ImVec2(x, y), radius, orb_color);
|
||||
}
|
||||
|
||||
// Menu bar for theme operations
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
|
||||
Reference in New Issue
Block a user