From 1057a3f037fe0ef08da328d43719f821cdef7404 Mon Sep 17 00:00:00 2001 From: scawful Date: Fri, 26 Sep 2025 20:42:48 -0400 Subject: [PATCH] Implement welcome screen and enhance session management in EditorManager - Added a welcome screen that can be accessed from the View menu, improving user experience for new users. - Enhanced session management by allowing the reuse of empty sessions when loading ROMs, reducing unnecessary session creation. - Improved the session table layout for better readability and added a custom overworld feature flag for each session. - Updated the DrawWelcomeScreen method for better visual integration and added a glow effect to the decorative line. --- assets/themes/yaze_tre.theme | 103 ++++++------- src/app/editor/editor_manager.cc | 106 ++++++++++--- src/app/editor/editor_manager.h | 1 + src/app/editor/system/settings_editor.h | 2 + src/app/gui/input.cc | 29 +++- src/app/gui/style.cc | 71 +++++---- src/app/gui/theme_manager.cc | 188 ++++++++++++++++++++++-- src/app/gui/theme_manager.h | 4 +- 8 files changed, 384 insertions(+), 120 deletions(-) diff --git a/assets/themes/yaze_tre.theme b/assets/themes/yaze_tre.theme index a6d1a817..0168aae8 100644 --- a/assets/themes/yaze_tre.theme +++ b/assets/themes/yaze_tre.theme @@ -1,53 +1,53 @@ -# YAZE Tre Theme -# Theme resource edition based on original ColorsYaze() function +# YAZE Tre Theme - Enhanced Edition +# Premium theme resource edition with improved colors and contrast name=YAZE Tre -description=YAZE theme resource edition (file-based) +description=Enhanced YAZE theme with improved readability and modern colors author=YAZE Team -version=1.0 +version=2.0 [colors] -# Primary colors (exact ALTTP colors from original code) -primary=92,115,92,255 # 0.36f, 0.45f, 0.36f - allttpLightGreen -secondary=71,92,71,255 # 0.28f, 0.36f, 0.28f - alttpMidGreen -accent=89,119,89,255 # 0.347f, 0.466f, 0.347f - TabActive exact -background=8,8,8,255 # Very dark gray for better grid visibility -surface=12,12,12,255 # Slightly lighter dark gray surface +# Primary colors (enhanced ALTTP colors with better contrast) +primary=105,135,105,255 # Brighter green for better visibility +secondary=85,110,85,255 # Mid-tone green with more saturation +accent=110,145,110,255 # Vibrant accent green for highlights +background=12,12,15,255 # Slightly blue-tinted dark background +surface=18,18,22,255 # Warmer surface color -# Status colors -error=220,50,47,255 -warning=255,193,7,255 -success=92,115,92,255 -info=52,152,219,255 +# Status colors (enhanced for better visibility) +error=235,75,75,255 # Brighter red for better visibility +warning=255,200,50,255 # Warmer yellow-orange +success=105,135,105,255 # Match primary green +info=70,170,255,255 # Brighter blue -# Text colors (exact from original) -text_primary=230,230,230,255 # 0.90f, 0.90f, 0.90f -text_secondary=180,180,180,255 -text_disabled=153,153,153,255 # 0.60f, 0.60f, 0.60f +# Text colors (enhanced contrast) +text_primary=245,245,245,255 # Brighter white for better readability +text_secondary=200,200,200,255 # Higher contrast secondary text +text_disabled=140,140,140,255 # Slightly brighter disabled text -# Window colors (exact from original) -window_bg=8,8,8,217 # Very dark gray with same alpha -child_bg=0,0,0,0 # 0.00f, 0.00f, 0.00f, 0.00f - transparent -popup_bg=28,28,36,235 # 0.11f, 0.11f, 0.14f, 0.92f +# Window colors (enhanced backgrounds) +window_bg=12,12,15,230 # Slightly blue-tinted with transparency +child_bg=0,0,0,0 # Transparent child backgrounds +popup_bg=20,20,25,240 # Warmer popup background -# Interactive elements (exact from original) -button=71,92,71,255 # alttpMidGreen -button_hovered=125,145,125,255 # allttpLightestGreen (exact) -button_active=92,115,92,255 # allttpLightGreen -frame_bg=110,110,110,99 # 0.43f, 0.43f, 0.43f, 0.39f -frame_bg_hovered=71,92,71,102 # 0.28f, 0.36f, 0.28f, 0.40f -frame_bg_active=71,92,71,176 # 0.28f, 0.36f, 0.28f, 0.69f +# Interactive elements (enhanced for better UX) +button=85,110,85,255 # Enhanced mid-green for better visibility +button_hovered=135,160,135,255 # Brighter hover state +button_active=105,135,105,255 # Active state matches primary +frame_bg=25,25,30,150 # Darker frames with transparency +frame_bg_hovered=85,110,85,120 # Green tint on hover +frame_bg_active=105,135,105,180 # Primary green when active -# Navigation (exact from original) -header=46,66,46,255 # alttpDarkGreen -header_hovered=92,115,92,255 # allttpLightGreen -header_active=71,92,71,255 # alttpMidGreen -tab=46,66,46,255 # alttpDarkGreen -tab_hovered=71,92,71,255 # alttpMidGreen -tab_active=89,119,89,255 # TabActive exact color -menu_bar_bg=46,66,46,255 # alttpDarkGreen -title_bg=71,92,71,255 # alttpMidGreen -title_bg_active=46,66,46,255 # alttpDarkGreen -title_bg_collapsed=71,92,71,255 # alttpMidGreen +# Navigation (enhanced contrast) +header=55,75,55,255 # Slightly brighter header +header_hovered=105,135,105,255 # Primary green on hover +header_active=85,110,85,255 # Secondary green when active +tab=45,60,45,255 # Darker tab background +tab_hovered=85,110,85,255 # Secondary green on hover +tab_active=110,145,110,255 # Accent green for active tab +menu_bar_bg=55,75,55,255 # Match header background +title_bg=85,110,85,255 # Secondary green +title_bg_active=55,75,55,255 # Darker when active +title_bg_collapsed=85,110,85,255 # Secondary green when collapsed # Borders and separators (exact from original) border=92,115,92,255 # allttpLightGreen @@ -67,17 +67,20 @@ resize_grip=255,255,255,26 # 1.00f, 1.00f, 1.00f, 0.10f resize_grip_hovered=199,209,255,153 # 0.78f, 0.82f, 1.00f, 0.60f (light blue!) resize_grip_active=199,209,255,230 # 0.78f, 0.82f, 1.00f, 0.90f (light blue!) -# Additional controls (missing from theme) -check_mark=230,230,230,128 # 0.90f, 0.90f, 0.90f, 0.50f -slider_grab=255,255,255,77 # 1.00f, 1.00f, 1.00f, 0.30f -slider_grab_active=92,115,92,153 # 0.36f, 0.45f, 0.36f, 0.60f +# Additional controls (enhanced) +check_mark=245,245,245,200 # Brighter check marks for visibility +slider_grab=180,180,180,120 # More visible slider grab +slider_grab_active=110,145,110,200 # Accent color when active -# Table colors (from original) -table_header_bg=46,66,46,255 # alttpDarkGreen -table_border_strong=71,92,71,255 # alttpMidGreen -table_border_light=66,66,71,255 # 0.26f, 0.26f, 0.28f +# Table colors (enhanced) +table_header_bg=55,75,55,255 # Slightly brighter header +table_border_strong=85,110,85,255 # Secondary green borders +table_border_light=70,70,75,255 # Better contrast light borders table_row_bg=0,0,0,0 # Transparent -table_row_bg_alt=255,255,255,18 # 1.00f, 1.00f, 1.00f, 0.07f +table_row_bg_alt=255,255,255,25 # Slightly more visible alternating rows + +# Link colors (high contrast for better visibility) +text_link=120,200,255,255 # Bright blue for links - high contrast against dark backgrounds [style] window_rounding=0.0 diff --git a/src/app/editor/editor_manager.cc b/src/app/editor/editor_manager.cc index 35624151..1b3555b6 100644 --- a/src/app/editor/editor_manager.cc +++ b/src/app/editor/editor_manager.cc @@ -455,6 +455,8 @@ void EditorManager::Initialize(const std::string &filename) { [&]() { current_editor_set_->settings_editor_.set_active(true); }, [&]() { return *current_editor_set_->settings_editor_.active(); }}, {gui::kSeparator, "", nullptr, []() { return true; }}, + {absl::StrCat(ICON_MD_HOME, " Welcome Screen"), "", + [&]() { show_welcome_screen_ = true; }}, {absl::StrCat(ICON_MD_GAMEPAD, " Emulator"), "", [&]() { show_emulator_ = true; }}, }}, @@ -1098,6 +1100,11 @@ void EditorManager::DrawMenuBar() { test_manager.UpdateResourceStats(); // Update monitoring data test_manager.DrawTestDashboard(&show_test_dashboard_); } + + // Welcome screen (accessible from View menu) + if (show_welcome_screen_) { + DrawWelcomeScreen(); + } if (show_emulator_) { Begin("Emulator", &show_emulator_, ImGuiWindowFlags_MenuBar); @@ -1290,16 +1297,35 @@ absl::Status EditorManager::LoadRom() { Rom temp_rom; RETURN_IF_ERROR(temp_rom.LoadFromFile(file_name)); - sessions_.emplace_back(std::move(temp_rom)); - RomSession &session = sessions_.back(); - session.filepath = file_name; // Store filepath for duplicate detection - - // Wire editor contexts - for (auto *editor : session.editors.active_editors_) { - editor->set_context(&context_); + // Check if there's an empty session we can populate instead of creating new one + RomSession* target_session = nullptr; + for (auto& session : sessions_) { + if (!session.rom.is_loaded()) { + target_session = &session; + util::logf("Found empty session to populate with ROM: %s", file_name.c_str()); + break; + } + } + + if (target_session) { + // Populate existing empty session + target_session->rom = std::move(temp_rom); + target_session->filepath = file_name; + current_rom_ = &target_session->rom; + current_editor_set_ = &target_session->editors; + } else { + // Create new session only if no empty ones exist + sessions_.emplace_back(std::move(temp_rom)); + RomSession &session = sessions_.back(); + session.filepath = file_name; // Store filepath for duplicate detection + + // Wire editor contexts + for (auto *editor : session.editors.active_editors_) { + editor->set_context(&context_); + } + current_rom_ = &session.rom; + current_editor_set_ = &session.editors; } - current_rom_ = &session.rom; - current_editor_set_ = &session.editors; // Update test manager with current ROM for ROM-dependent tests util::logf("EditorManager: Setting ROM in TestManager - %p ('%s')", @@ -1942,22 +1968,26 @@ void EditorManager::DrawSessionManager() { ImGui::Separator(); ImGui::Text("%s Active Sessions (%zu)", ICON_MD_TAB, sessions_.size()); - // Session list with controls (improved sizing) - if (ImGui::BeginTable("SessionTable", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | - ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY)) { + // Session list with controls (wider table for better readability) + if (ImGui::BeginTable("SessionTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ScrollY)) { ImGui::TableSetupColumn("Session", ImGuiTableColumnFlags_WidthStretch, 120.0f); - ImGui::TableSetupColumn("ROM", ImGuiTableColumnFlags_WidthStretch, 200.0f); - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 90.0f); - ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 200.0f); + ImGui::TableSetupColumn("ROM", ImGuiTableColumnFlags_WidthStretch, 250.0f); + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("Custom OW", ImGuiTableColumnFlags_WidthFixed, 110.0f); + ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, 220.0f); ImGui::TableHeadersRow(); for (size_t i = 0; i < sessions_.size(); ++i) { auto& session = sessions_[i]; bool is_current = (&session.rom == current_rom_); - ImGui::TableNextRow(); + ImGui::TableNextRow(ImGuiTableRowFlags_None, 45.0f); // Increase row height for better spacing ImGui::TableNextColumn(); + // Add vertical centering for text + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f); + if (is_current) { ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s Session %zu", ICON_MD_STAR, i + 1); @@ -1966,6 +1996,7 @@ void EditorManager::DrawSessionManager() { } ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f); // Vertical centering std::string display_name = session.GetDisplayName(); if (!session.custom_name.empty()) { ImGui::TextColored(ImVec4(0.7f, 0.9f, 1.0f, 1.0f), "%s %s", ICON_MD_EDIT, display_name.c_str()); @@ -1974,6 +2005,7 @@ void EditorManager::DrawSessionManager() { } ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f); // Vertical centering if (session.rom.is_loaded()) { if (session.rom.dirty()) { ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s Modified", ICON_MD_EDIT); @@ -1985,6 +2017,27 @@ void EditorManager::DrawSessionManager() { } ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f); // Vertical centering + // Custom Overworld flag (per-session) + ImGui::PushID(static_cast(i + 100)); // Different ID to avoid conflicts + bool custom_ow_enabled = session.feature_flags.overworld.kLoadCustomOverworld; + if (ImGui::Checkbox("##CustomOW", &custom_ow_enabled)) { + session.feature_flags.overworld.kLoadCustomOverworld = custom_ow_enabled; + if (is_current) { + // Update global flags if this is the current session + core::FeatureFlags::get().overworld.kLoadCustomOverworld = custom_ow_enabled; + } + toast_manager_.Show(absl::StrFormat("Session %zu: Custom Overworld %s", + i + 1, custom_ow_enabled ? "Enabled" : "Disabled"), + editor::ToastType::kInfo); + } + ImGui::PopID(); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enable/disable custom overworld features for this session"); + } + + ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f); // Slightly less offset for buttons ImGui::PushID(static_cast(i)); if (!is_current && ImGui::Button(absl::StrCat(ICON_MD_SWITCH_ACCESS_SHORTCUT, " Switch").c_str())) { @@ -2164,7 +2217,7 @@ void EditorManager::DrawWelcomeScreen() { ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground; - if (ImGui::Begin("Welcome to Yaze", nullptr, flags)) { + if (ImGui::Begin("Welcome to Yaze", &show_welcome_screen_, flags)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImVec2 window_pos = ImGui::GetWindowPos(); ImVec2 window_size = ImGui::GetWindowSize(); @@ -2222,13 +2275,22 @@ void EditorManager::DrawWelcomeScreen() { ImGui::Spacing(); - // Themed decorative line with glow effect - ImVec2 line_start = ImVec2(window_pos.x + 50, window_pos.y + 120); - ImVec2 line_end = ImVec2(window_pos.x + window_size.x - 50, window_pos.y + 120); - float glow_alpha = 0.5f + 0.3f * sinf(animation_time * 1.5f); + // 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_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); + + // Enhanced glow effect with multiple line layers for depth + float glow_alpha = 0.6f + 0.4f * sinf(animation_time * 1.5f); ImU32 line_color = ImGui::ColorConvertFloat4ToU32(ImVec4( accent_color.red, accent_color.green, accent_color.blue, glow_alpha)); - draw_list->AddLine(line_start, line_end, line_color, 2.0f); + + // Draw main line with glow effect + draw_list->AddLine(line_start, line_end, + ImGui::ColorConvertFloat4ToU32(ImVec4(accent_color.red, accent_color.green, accent_color.blue, 0.3f)), + 4.0f); // Glow layer + draw_list->AddLine(line_start, line_end, line_color, 2.0f); // Main line ImGui::Spacing(); ImGui::Spacing(); diff --git a/src/app/editor/editor_manager.h b/src/app/editor/editor_manager.h index 8e95b766..e196030f 100644 --- a/src/app/editor/editor_manager.h +++ b/src/app/editor/editor_manager.h @@ -156,6 +156,7 @@ class EditorManager { bool show_command_palette_ = false; bool show_global_search_ = false; bool show_session_rename_dialog_ = false; + bool show_welcome_screen_ = false; size_t session_to_rename_ = 0; char session_rename_buffer_[256] = {}; diff --git a/src/app/editor/system/settings_editor.h b/src/app/editor/system/settings_editor.h index 5f4a5f59..ec74fc7f 100644 --- a/src/app/editor/system/settings_editor.h +++ b/src/app/editor/system/settings_editor.h @@ -228,6 +228,8 @@ class SettingsEditor : public Editor { // Get the ROM pointer Rom* rom() const { return rom_; } + bool IsRomLoaded() const override { return true; } // Allow access without ROM for global settings + private: Rom* rom_; void DrawGeneralSettings(); diff --git a/src/app/gui/input.cc b/src/app/gui/input.cc index 18fe1877..06e7a49b 100644 --- a/src/app/gui/input.cc +++ b/src/app/gui/input.cc @@ -216,9 +216,32 @@ bool ClickableText(const std::string& text) { bool hovered = ImGui::IsItemHovered(); bool clicked = ImGui::IsItemClicked(); - // Render text with appropriate color - ImVec4 color = hovered ? ImGui::GetStyleColorVec4(ImGuiCol_Text) - : ImGui::GetStyleColorVec4(ImGuiCol_TextLink); + // Render text with high-contrast appropriate color + ImVec4 link_color = ImGui::GetStyleColorVec4(ImGuiCol_TextLink); + ImVec4 bg_color = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); + + // Ensure good contrast against background + float contrast_factor = (bg_color.x + bg_color.y + bg_color.z) < 1.5f ? 1.0f : 0.3f; + + ImVec4 color; + if (hovered) { + // Brighter color on hover for better visibility + color = ImVec4( + std::min(1.0f, link_color.x + 0.3f), + std::min(1.0f, link_color.y + 0.3f), + std::min(1.0f, link_color.z + 0.3f), + 1.0f + ); + } else { + // Ensure link color has good contrast + color = ImVec4( + std::max(contrast_factor, link_color.x), + std::max(contrast_factor, link_color.y), + std::max(contrast_factor, link_color.z), + 1.0f + ); + } + ImGui::GetWindowDrawList()->AddText( pos, ImGui::ColorConvertFloat4ToU32(color), text.c_str()); diff --git a/src/app/gui/style.cc b/src/app/gui/style.cc index 96712a01..686ff0e3 100644 --- a/src/app/gui/style.cc +++ b/src/app/gui/style.cc @@ -1,5 +1,7 @@ #include "style.h" +#include + #include "app/core/platform/file_dialog.h" #include "app/gui/theme_manager.h" #include "app/gui/background_renderer.h" @@ -7,6 +9,7 @@ #include "gui/color.h" #include "imgui/imgui.h" #include "imgui/imgui_internal.h" +#include "util/log.h" namespace yaze { namespace gui { @@ -416,40 +419,48 @@ void DrawDisplaySettings(ImGuiStyle *ref) { ImGui::Text("Theme Selection:"); - // Add special "Classic YAZE" option first - std::string current_display_name = theme_manager.GetCurrentTheme().name; - if (current_display_name == "Classic YAZE") { - current_display_name = "Classic YAZE (Original)"; + // Classic YAZE button + std::string current_theme_name = theme_manager.GetCurrentThemeName(); + bool is_classic_active = (current_theme_name == "Classic YAZE"); + + if (is_classic_active) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.6f, 0.2f, 1.0f)); } - if (ImGui::BeginCombo("##ThemeSelector", current_display_name.c_str())) { - // Classic YAZE option (direct ColorsYaze() function) - bool is_classic_selected = (theme_manager.GetCurrentTheme().name == "Classic YAZE"); - if (ImGui::Selectable("Classic YAZE (Original)", is_classic_selected)) { - theme_manager.ApplyClassicYazeTheme(); - ref_saved_style = style; // Update reference when theme changes + if (ImGui::Button("Classic YAZE")) { + theme_manager.ApplyClassicYazeTheme(); + ref_saved_style = style; + } + + if (ImGui::Button("ColorsYaze")) { + gui::ColorsYaze(); + } + + if (is_classic_active) { + ImGui::PopStyleColor(); + } + + ImGui::SameLine(); + ImGui::Text(" | "); + ImGui::SameLine(); + + // File themes dropdown - just the raw list, no sorting + 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; } - if (is_classic_selected) { - ImGui::SetItemDefaultFocus(); - } - - ImGui::Separator(); - - // File-based themes (sorted) - auto available_themes = theme_manager.GetAvailableThemes(); - std::sort(available_themes.begin(), available_themes.end()); - + } + + if (ImGui::BeginCombo("File Themes", current_file_theme)) { for (const auto& theme_name : available_themes) { - bool is_selected = (theme_name == theme_manager.GetCurrentTheme().name); - if (ImGui::Selectable(theme_name.c_str(), is_selected)) { - auto status = theme_manager.LoadTheme(theme_name); // Use LoadTheme for consistency - if (!status.ok()) { - // Could show error message to user here - } - ref_saved_style = style; // Update reference when theme changes - } - if (is_selected) { - ImGui::SetItemDefaultFocus(); + if (ImGui::Selectable(theme_name.c_str())) { + theme_manager.LoadTheme(theme_name); + ref_saved_style = style; } } ImGui::EndCombo(); diff --git a/src/app/gui/theme_manager.cc b/src/app/gui/theme_manager.cc index a0017880..0edce8e1 100644 --- a/src/app/gui/theme_manager.cc +++ b/src/app/gui/theme_manager.cc @@ -110,19 +110,22 @@ void ThemeManager::InitializeBuiltInThemes() { // Always create fallback theme first CreateFallbackYazeClassic(); + // Create the Classic YAZE theme during initialization + ApplyClassicYazeTheme(); + // Load all available theme files dynamically auto status = LoadAllAvailableThemes(); if (!status.ok()) { util::logf("Warning: Failed to load some theme files: %s", status.message().data()); } - // Ensure we have a valid current theme (prefer file-based theme) - if (themes_.find("YAZE Classic") != themes_.end()) { - current_theme_ = themes_["YAZE Classic"]; - current_theme_name_ = "YAZE Classic"; - } else if (themes_.find("YAZE Tre") != themes_.end()) { - current_theme_ = themes_["YAZE Tre"]; - current_theme_name_ = "YAZE Tre"; + // Ensure we have a valid current theme (Classic is already set above) + // Only fallback to file themes if Classic creation failed + if (current_theme_name_ != "Classic YAZE") { + if (themes_.find("YAZE Tre") != themes_.end()) { + current_theme_ = themes_["YAZE Tre"]; + current_theme_name_ = "YAZE Tre"; + } } } @@ -315,6 +318,7 @@ void ThemeManager::ApplyTheme(const std::string& theme_name) { void ThemeManager::ApplyTheme(const EnhancedTheme& theme) { current_theme_ = theme; + current_theme_name_ = theme.name; // CRITICAL: Update the name tracking current_theme_.ApplyToImGui(); } @@ -704,19 +708,94 @@ void ThemeManager::ApplyClassicYazeTheme() { ColorsYaze(); current_theme_name_ = "Classic YAZE"; - // Update current_theme_ to reflect the applied colors for consistency - // (This creates a temporary theme object that matches what ColorsYaze() sets) + // Create a complete Classic theme object that matches what ColorsYaze() sets EnhancedTheme classic_theme; classic_theme.name = "Classic YAZE"; classic_theme.description = "Original YAZE theme (direct ColorsYaze() function)"; classic_theme.author = "YAZE Team"; - // Extract the basic colors that ColorsYaze() sets (adjusted for grid visibility) - classic_theme.primary = RGBA(92, 115, 92); // allttpLightGreen - classic_theme.secondary = RGBA(71, 92, 71); // alttpMidGreen - classic_theme.accent = RGBA(89, 119, 89); // TabActive color - classic_theme.background = RGBA(8, 8, 8); // Very dark gray for better grid visibility + // Extract ALL the colors that ColorsYaze() sets (copy from CreateFallbackYazeClassic) + classic_theme.primary = RGBA(92, 115, 92); // allttpLightGreen + classic_theme.secondary = RGBA(71, 92, 71); // alttpMidGreen + classic_theme.accent = RGBA(89, 119, 89); // TabActive + classic_theme.background = RGBA(8, 8, 8); // Very dark gray for better grid visibility + classic_theme.text_primary = RGBA(230, 230, 230); // 0.90f, 0.90f, 0.90f + classic_theme.text_disabled = RGBA(153, 153, 153); // 0.60f, 0.60f, 0.60f + classic_theme.window_bg = RGBA(8, 8, 8, 217); // Very dark gray with same alpha + classic_theme.child_bg = RGBA(0, 0, 0, 0); // Transparent + classic_theme.popup_bg = RGBA(28, 28, 36, 235); // 0.11f, 0.11f, 0.14f, 0.92f + + classic_theme.button = RGBA(71, 92, 71); // alttpMidGreen + classic_theme.button_hovered = RGBA(125, 146, 125); // allttpLightestGreen + classic_theme.button_active = RGBA(92, 115, 92); // allttpLightGreen + + classic_theme.header = RGBA(46, 66, 46); // alttpDarkGreen + classic_theme.header_hovered = RGBA(92, 115, 92); // allttpLightGreen + classic_theme.header_active = RGBA(71, 92, 71); // alttpMidGreen + + classic_theme.menu_bar_bg = RGBA(46, 66, 46); // alttpDarkGreen + classic_theme.tab = RGBA(46, 66, 46); // alttpDarkGreen + classic_theme.tab_hovered = RGBA(71, 92, 71); // alttpMidGreen + classic_theme.tab_active = RGBA(89, 119, 89); // TabActive + + // Complete all remaining ImGui colors from original ColorsYaze() function + classic_theme.title_bg = RGBA(71, 92, 71); // alttpMidGreen + classic_theme.title_bg_active = RGBA(46, 66, 46); // alttpDarkGreen + classic_theme.title_bg_collapsed = RGBA(71, 92, 71); // alttpMidGreen + + // Borders and separators + classic_theme.border = RGBA(92, 115, 92); // allttpLightGreen + classic_theme.border_shadow = RGBA(0, 0, 0, 0); // Transparent + classic_theme.separator = RGBA(128, 128, 128, 153); // 0.50f, 0.50f, 0.50f, 0.60f + classic_theme.separator_hovered = RGBA(153, 153, 178); // 0.60f, 0.60f, 0.70f + classic_theme.separator_active = RGBA(178, 178, 230); // 0.70f, 0.70f, 0.90f + + // Scrollbars + classic_theme.scrollbar_bg = RGBA(92, 115, 92, 153); // 0.36f, 0.45f, 0.36f, 0.60f + classic_theme.scrollbar_grab = RGBA(92, 115, 92, 76); // 0.36f, 0.45f, 0.36f, 0.30f + classic_theme.scrollbar_grab_hovered = RGBA(92, 115, 92, 102); // 0.36f, 0.45f, 0.36f, 0.40f + classic_theme.scrollbar_grab_active = RGBA(92, 115, 92, 153); // 0.36f, 0.45f, 0.36f, 0.60f + + // Add all the missing colors that CreateFallbackYazeClassic has + classic_theme.frame_bg = classic_theme.window_bg; + classic_theme.frame_bg_hovered = classic_theme.button_hovered; + classic_theme.frame_bg_active = classic_theme.button_active; + classic_theme.resize_grip = RGBA(255, 255, 255, 26); + classic_theme.resize_grip_hovered = RGBA(199, 209, 255, 153); + classic_theme.resize_grip_active = RGBA(199, 209, 255, 230); + classic_theme.check_mark = RGBA(230, 230, 230, 128); + classic_theme.slider_grab = RGBA(255, 255, 255, 77); + classic_theme.slider_grab_active = RGBA(92, 115, 92, 153); + classic_theme.input_text_cursor = classic_theme.text_primary; + classic_theme.nav_cursor = classic_theme.accent; + classic_theme.nav_windowing_highlight = classic_theme.accent; + classic_theme.nav_windowing_dim_bg = RGBA(0, 0, 0, 128); + classic_theme.modal_window_dim_bg = RGBA(0, 0, 0, 89); + classic_theme.text_selected_bg = RGBA(89, 119, 89, 89); + classic_theme.drag_drop_target = classic_theme.accent; + classic_theme.table_header_bg = RGBA(46, 66, 46); + classic_theme.table_border_strong = RGBA(71, 92, 71); + classic_theme.table_border_light = RGBA(66, 66, 71); + classic_theme.table_row_bg = RGBA(0, 0, 0, 0); + classic_theme.table_row_bg_alt = RGBA(255, 255, 255, 18); + classic_theme.text_link = classic_theme.accent; + classic_theme.plot_lines = RGBA(255, 255, 255); + classic_theme.plot_lines_hovered = RGBA(230, 178, 0); + classic_theme.plot_histogram = RGBA(230, 178, 0); + classic_theme.plot_histogram_hovered = RGBA(255, 153, 0); + classic_theme.docking_preview = RGBA(92, 115, 92, 180); + classic_theme.docking_empty_bg = RGBA(46, 66, 46, 255); + + // Apply original style settings + classic_theme.window_rounding = 0.0f; + classic_theme.frame_rounding = 5.0f; + classic_theme.scrollbar_rounding = 5.0f; + classic_theme.tab_rounding = 0.0f; + classic_theme.enable_glow_effects = false; + + // DON'T add Classic theme to themes map - keep it as a special case + // themes_["Classic YAZE"] = classic_theme; // REMOVED to prevent off-by-one current_theme_ = classic_theme; } @@ -765,6 +844,7 @@ void ThemeManager::ShowSimpleThemeEditor(bool* p_open) { ImVec4 text_primary = ConvertColorToImVec4(edit_theme.text_primary); ImVec4 text_secondary = ConvertColorToImVec4(edit_theme.text_secondary); ImVec4 text_disabled = ConvertColorToImVec4(edit_theme.text_disabled); + ImVec4 text_link = ConvertColorToImVec4(edit_theme.text_link); if (ImGui::ColorEdit3("Primary Text", &text_primary.x)) { edit_theme.text_primary = {text_primary.x, text_primary.y, text_primary.z, text_primary.w}; @@ -775,6 +855,16 @@ void ThemeManager::ShowSimpleThemeEditor(bool* p_open) { if (ImGui::ColorEdit3("Disabled Text", &text_disabled.x)) { edit_theme.text_disabled = {text_disabled.x, text_disabled.y, text_disabled.z, text_disabled.w}; } + if (ImGui::ColorEdit3("Link Text", &text_link.x)) { + edit_theme.text_link = {text_link.x, text_link.y, text_link.z, text_link.w}; + } + + // Show contrast preview against current background + ImGui::Text("Link Preview:"); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, text_link); + ImGui::Text("Sample clickable link"); + ImGui::PopStyleColor(); } // Window Colors @@ -832,6 +922,48 @@ void ThemeManager::ShowSimpleThemeEditor(bool* p_open) { ApplyTheme(edit_theme); } + ImGui::SameLine(); + + // Save Over Current button - overwrites the current theme file + std::string current_file_path = GetCurrentThemeFilePath(); + bool can_save_over = !current_file_path.empty(); + + if (!can_save_over) { + ImGui::BeginDisabled(); + } + + if (ImGui::Button("Save Over Current")) { + edit_theme.name = std::string(theme_name); + edit_theme.description = std::string(theme_description); + edit_theme.author = std::string(theme_author); + + auto status = SaveThemeToFile(edit_theme, current_file_path); + if (status.ok()) { + // Update themes map and apply + themes_[edit_theme.name] = edit_theme; + ApplyTheme(edit_theme); + util::logf("Theme saved over current file: %s", current_file_path.c_str()); + } else { + util::logf("Failed to save over current theme: %s", status.message().data()); + } + } + + if (!can_save_over) { + ImGui::EndDisabled(); + } + + if (ImGui::IsItemHovered() && can_save_over) { + ImGui::BeginTooltip(); + ImGui::Text("Save over current theme file:"); + ImGui::Text("%s", current_file_path.c_str()); + ImGui::EndTooltip(); + } else if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("No current theme file to overwrite"); + ImGui::Text("Use 'Save to File...' to create a new theme file"); + ImGui::EndTooltip(); + } + ImGui::SameLine(); if (ImGui::Button("Save to File...")) { edit_theme.name = std::string(theme_name); @@ -1032,5 +1164,33 @@ absl::Status ThemeManager::RefreshAvailableThemes() { return LoadAllAvailableThemes(); } +std::string ThemeManager::GetCurrentThemeFilePath() const { + if (current_theme_name_ == "Classic YAZE") { + return ""; // Classic theme doesn't have a file + } + + // Try to find the current theme file in the search paths + auto search_paths = GetThemeSearchPaths(); + std::string theme_filename = current_theme_name_ + ".theme"; + + // Convert theme name to safe filename (replace spaces and special chars) + for (char& c : theme_filename) { + if (!std::isalnum(c) && c != '.' && c != '_') { + c = '_'; + } + } + + for (const auto& search_path : search_paths) { + std::string full_path = search_path + theme_filename; + std::ifstream test_file(full_path); + if (test_file.good()) { + return full_path; + } + } + + // If not found, return path in the first search directory (for new saves) + return search_paths.empty() ? theme_filename : search_paths[0] + theme_filename; +} + } // namespace gui } // namespace yaze diff --git a/src/app/gui/theme_manager.h b/src/app/gui/theme_manager.h index 48a35c02..73346329 100644 --- a/src/app/gui/theme_manager.h +++ b/src/app/gui/theme_manager.h @@ -149,6 +149,7 @@ public: std::vector GetAvailableThemes() const; const EnhancedTheme* GetTheme(const std::string& name) const; const EnhancedTheme& GetCurrentTheme() const { return current_theme_; } + const std::string& GetCurrentThemeName() const { return current_theme_name_; } // Theme application void ApplyTheme(const std::string& theme_name); @@ -171,7 +172,7 @@ private: std::map themes_; EnhancedTheme current_theme_; - std::string current_theme_name_ = "YAZE Classic"; + std::string current_theme_name_ = "Classic YAZE"; void CreateFallbackYazeClassic(); absl::Status ParseThemeFile(const std::string& content, EnhancedTheme& theme); @@ -181,6 +182,7 @@ private: // Helper methods for path resolution std::vector GetThemeSearchPaths() const; std::string GetThemesDirectory() const; + std::string GetCurrentThemeFilePath() const; }; } // namespace gui