/* Copyright 2025 flyinghead This file is part of Flycast. Flycast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Flycast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ #include "settings.h" #include "gui.h" #include "IconsFontAwesome6.h" #include "mainui.h" #include "oslib/storage.h" #include "stdclass.h" #include "achievements/achievements.h" #include "imgui_stdlib.h" static void addContentPathCallback(const std::string& path) { auto& contentPath = config::ContentPath.get(); if (std::count(contentPath.begin(), contentPath.end(), path) == 0) { scanner.stop(); contentPath.push_back(path); if (gui_state == GuiState::Main) // when adding content path from empty game list SaveSettings(); scanner.refresh(); } } void addContentPath(bool start) { const char *title = "Select a Content Folder"; select_file_popup(title, [](bool cancelled, std::string selection) { if (!cancelled) addContentPathCallback(selection); return true; }); #ifdef __ANDROID__ if (start) { bool supported = hostfs::addStorage(true, false, title, [](bool cancelled, std::string selection) { if (!cancelled) addContentPathCallback(selection); }); if (!supported) ImGui::OpenPopup(title); } #else if (start) ImGui::OpenPopup(title); #endif } void gui_settings_general() { { DisabledScope scope(settings.platform.isArcade()); const char *languages[] = { "Japanese", "English", "German", "French", "Spanish", "Italian", "Default" }; OptionComboBox("Language", config::Language, languages, std::size(languages), "The language as configured in the Dreamcast BIOS"); const char *broadcast[] = { "NTSC", "PAL", "PAL/M", "PAL/N", "Default" }; OptionComboBox("Broadcast", config::Broadcast, broadcast, std::size(broadcast), "TV broadcasting standard for non-VGA modes"); } const char *consoleRegion[] = { "Japan", "USA", "Europe", "Default" }; const char *arcadeRegion[] = { "Japan", "USA", "Export", "Korea" }; const char **region = settings.platform.isArcade() ? arcadeRegion : consoleRegion; OptionComboBox("Region", config::Region, region, std::size(consoleRegion), "BIOS region"); const char *cable[] = { "VGA", "RGB Component", "TV Composite" }; { DisabledScope scope(config::Cable.isReadOnly() || settings.platform.isArcade()); const char *value = config::Cable == 0 ? cable[0] : config::Cable > 0 && config::Cable <= (int)std::size(cable) ? cable[config::Cable - 1] : "?"; if (ImGui::BeginCombo("Cable", value, ImGuiComboFlags_None)) { for (int i = 0; i < IM_ARRAYSIZE(cable); i++) { bool is_selected = i == 0 ? config::Cable <= 1 : config::Cable - 1 == i; if (ImGui::Selectable(cable[i], &is_selected)) config::Cable = i == 0 ? 0 : i + 1; if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } ImGui::SameLine(); ShowHelpMarker("Video connection type"); } #if !defined(TARGET_IPHONE) ImVec2 size; size.x = 0.0f; size.y = (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y * 2.f) * (config::ContentPath.get().size() + 1); if (BeginListBox("Content Location", size, ImGuiWindowFlags_NavFlattened)) { int to_delete = -1; for (u32 i = 0; i < config::ContentPath.get().size(); i++) { ImguiID _(config::ContentPath.get()[i].c_str()); ImGui::AlignTextToFramePadding(); float maxW = ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(ICON_FA_TRASH_CAN).x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x; std::string s = middleEllipsis(config::ContentPath.get()[i], maxW); ImGui::Text("%s", s.c_str()); ImGui::SameLine(0, maxW - ImGui::CalcTextSize(s.c_str()).x + ImGui::GetStyle().ItemSpacing.x); if (ImGui::Button(ICON_FA_TRASH_CAN)) to_delete = i; } ImguiStyleVar _(ImGuiStyleVar_FramePadding, ScaledVec2(24, 3)); const bool addContent = ImGui::Button("Add"); addContentPath(addContent); ImGui::SameLine(); if (ImGui::Button("Rescan Content")) scanner.refresh(); scrollWhenDraggingOnVoid(); ImGui::EndListBox(); if (to_delete >= 0) { scanner.stop(); config::ContentPath.get().erase(config::ContentPath.get().begin() + to_delete); scanner.refresh(); } } ImGui::SameLine(); ShowHelpMarker("The folders where your games are stored"); size.y = ImGui::GetTextLineHeightWithSpacing() * 1.25f + ImGui::GetStyle().FramePadding.y * 2.0f; #if defined(__linux__) && !defined(__ANDROID__) if (BeginListBox("Data Folder", size, ImGuiWindowFlags_NavFlattened)) { ImGui::AlignTextToFramePadding(); float w = ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x; std::string s = middleEllipsis(get_writable_data_path(""), w); ImGui::Text("%s", s.c_str()); ImGui::EndListBox(); } ImGui::SameLine(); ShowHelpMarker("The folder containing BIOS files, as well as saved VMUs and states"); #else #if defined(__ANDROID__) || defined(TARGET_MAC) size.y += ImGui::GetTextLineHeightWithSpacing() * 1.25f; #endif if (BeginListBox("Home Folder", size, ImGuiWindowFlags_NavFlattened)) { ImGui::AlignTextToFramePadding(); float w = ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x; std::string s = middleEllipsis(get_writable_config_path(""), w); ImGui::Text("%s", s.c_str()); ImguiStyleVar _(ImGuiStyleVar_FramePadding, ScaledVec2(24, 3)); #ifdef __ANDROID__ { DisabledScope _(!config::UseSafFilePicker); if (ImGui::Button("Import")) hostfs::importHomeDirectory(); ImGui::SameLine(); if (ImGui::Button("Export")) hostfs::exportHomeDirectory(); } #endif #ifdef TARGET_MAC if (ImGui::Button("Reveal in Finder")) { char temp[512]; snprintf(temp, sizeof(temp), "open \"%s\"", get_writable_config_path("").c_str()); system(temp); } #endif ImGui::EndListBox(); } ImGui::SameLine(); ShowHelpMarker("The folder where Flycast saves configuration files and VMUs. BIOS files should be in a subfolder named \"data\""); #endif // !linux #else // TARGET_IPHONE { ImguiStyleVar _(ImGuiStyleVar_FramePadding, ScaledVec2(24, 3)); if (ImGui::Button("Rescan Content")) scanner.refresh(); } #endif OptionCheckbox("Box Art Game List", config::BoxartDisplayMode, "Display game cover art in the game list."); OptionCheckbox("Fetch Box Art", config::FetchBoxart, "Fetch cover images from TheGamesDB.net."); if (OptionSlider("UI Scaling", config::UIScaling, 50, 200, "Adjust the size of UI elements and fonts.", "%d%%")) uiUserScaleUpdated = true; if (uiUserScaleUpdated) { ImGui::SameLine(); if (ImGui::Button("Apply")) { mainui_reinit(); uiUserScaleUpdated = false; } } const char *themes[] = { "Dark", "Light", "Dreamcast", "High Contrast", "Nintendo", "Aqua Chill" }; int previousUITheme = config::UITheme; OptionComboBox("UI Theme", config::UITheme, themes, std::size(themes), "Select the UI color theme."); // Auto-apply theme when selection changes if (previousUITheme != config::UITheme) { applyCurrentTheme(); } if (OptionCheckbox("Hide Legacy Naomi Roms", config::HideLegacyNaomiRoms, "Hide .bin, .dat and .lst files from the content browser")) scanner.refresh(); #ifdef __ANDROID__ OptionCheckbox("Use SAF File Picker", config::UseSafFilePicker, "Use Android Storage Access Framework file picker to select folders and files. Ignored on Android 10 and later."); #endif ImGui::Text("Automatic State:"); OptionCheckbox("Load", config::AutoLoadState, "Load the last saved state of the game when starting"); ImGui::SameLine(); OptionCheckbox("Save", config::AutoSaveState, "Save the state of the game when stopping"); OptionCheckbox("Naomi Free Play", config::ForceFreePlay, "Configure Naomi games in Free Play mode."); #if USE_DISCORD OptionCheckbox("Discord Presence", config::DiscordPresence, "Show which game you are playing on Discord"); #endif #ifdef USE_RACHIEVEMENTS OptionCheckbox("Enable RetroAchievements", config::EnableAchievements, "Track your game achievements using RetroAchievements.org"); { DisabledScope _(!config::EnableAchievements); ImGui::Indent(); OptionCheckbox("Hardcore Mode", config::AchievementsHardcoreMode, "Enable RetroAchievements hardcore mode. Using cheats and loading a state are not allowed in this mode."); ImGui::InputText("Username", &config::AchievementsUserName.get(), achievements::isLoggedOn() ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_None, nullptr, nullptr); if (config::EnableAchievements) { static std::future futureLogin; achievements::init(); if (achievements::isLoggedOn()) { ImGui::Text("Authentication successful"); if (futureLogin.valid()) futureLogin.get(); if (ImGui::Button("Logout", ScaledVec2(100, 0))) achievements::logout(); } else { static char password[256]; ImGui::InputText("Password", password, sizeof(password), ImGuiInputTextFlags_Password, nullptr, nullptr); if (futureLogin.valid()) { if (futureLogin.wait_for(std::chrono::seconds::zero()) == std::future_status::timeout) { ImGui::Text("Authenticating..."); } else { try { futureLogin.get(); } catch (const FlycastException& e) { gui_error(e.what()); } } } { DisabledScope _(config::AchievementsUserName.get().empty() || password[0] == '\0'); if (ImGui::Button("Login", ScaledVec2(100, 0)) && !futureLogin.valid()) { futureLogin = achievements::login(config::AchievementsUserName.get().c_str(), password); memset(password, 0, sizeof(password)); } } } } ImGui::Unindent(); } #endif } static void applyDarkTheme() { // Reset style first, then apply dark colors - exactly like original Flycast ImGui::GetStyle() = ImGuiStyle{}; ImGui::StyleColorsDark(); // Apply original Flycast styling to match exactly how it was ImGuiStyle& style = ImGui::GetStyle(); style.TabRounding = 5.0f; style.FrameRounding = 3.0f; style.ItemSpacing = ImVec2(8, 8); // from 8,4 style.ItemInnerSpacing = ImVec2(4, 6); // from 4,4 // Reset style properties to defaults to ensure clean theme switching style.TabBorderSize = 0.0f; // Revert to default style.FrameBorderSize = 0.0f; // Revert to default } static void applyLightTheme() { ImGui::StyleColorsLight(); ImGuiStyle& style = ImGui::GetStyle(); // Improved light theme with better contrast style.Colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); // Black text style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); // Darker gray for disabled text style.Colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.97f, 1.00f); // Very light blue-gray style.Colors[ImGuiCol_PopupBg] = ImVec4(0.98f, 0.98f, 1.00f, 1.00f); // Almost white for popups (fully opaque) style.Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.80f, 0.50f); // Medium blue-gray borders (semi-transparent ok) style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); // No border shadows // Darker frame backgrounds (unchecked boxes, etc.) style.Colors[ImGuiCol_FrameBg] = ImVec4(0.70f, 0.70f, 0.80f, 1.00f); // Darker blue-gray backgrounds style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.60f, 0.60f, 0.75f, 1.00f); // Slightly darker when hovered style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.50f, 0.50f, 0.70f, 1.00f); // Even darker when active style.Colors[ImGuiCol_TitleBg] = ImVec4(0.70f, 0.70f, 0.85f, 1.00f); // Light blue-gray title bar style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.60f, 0.60f, 0.80f, 1.00f); // Darker title bar when active style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.80f, 0.80f, 0.90f, 0.75f); // Lighter when collapsed (transparency ok) style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.80f, 0.80f, 0.90f, 1.00f); // Light blue-gray menu bar style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.85f, 0.85f, 0.90f, 1.00f); // Very light scrollbar background style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.65f, 0.65f, 0.80f, 1.00f); // Medium blue-gray scrollbar (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.55f, 0.55f, 0.75f, 1.00f); // Darker when hovered (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.45f, 0.45f, 0.70f, 1.00f); // Even darker when active (fully opaque) style.Colors[ImGuiCol_CheckMark] = ImVec4(0.00f, 0.45f, 0.90f, 1.00f); // Bright blue checkmarks style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.50f, 0.50f, 0.80f, 1.00f); // Medium blue-gray slider (fully opaque) style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.40f, 0.40f, 0.70f, 1.00f); // Darker when active (fully opaque) style.Colors[ImGuiCol_Button] = ImVec4(0.67f, 0.67f, 0.83f, 1.00f); // Medium blue-gray buttons (fully opaque) style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.57f, 0.57f, 0.77f, 1.00f); // Darker when hovered (fully opaque) style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.47f, 0.47f, 0.73f, 1.00f); // Even darker when active (fully opaque) style.Colors[ImGuiCol_Header] = ImVec4(0.60f, 0.60f, 0.80f, 0.80f); // Medium blue-gray headers (semi-transparent ok) style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.50f, 0.50f, 0.75f, 1.00f); // Darker when hovered (fully opaque) style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.45f, 0.45f, 0.70f, 1.00f); // Even darker when active (fully opaque) style.Colors[ImGuiCol_Separator] = ImVec4(0.60f, 0.60f, 0.70f, 0.60f); // Visible separators (semi-transparent ok) style.Colors[ImGuiCol_Tab] = ImVec4(0.65f, 0.65f, 0.80f, 1.00f); // Medium blue-gray tabs (fully opaque) style.Colors[ImGuiCol_TabHovered] = ImVec4(0.55f, 0.55f, 0.75f, 1.00f); // Darker when hovered (fully opaque) style.Colors[ImGuiCol_TabActive] = ImVec4(0.50f, 0.50f, 0.70f, 1.00f); // Even darker when active (fully opaque) style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.75f, 0.75f, 0.85f, 1.00f); // Lighter when unfocused (fully opaque) style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.65f, 0.65f, 0.80f, 1.00f); // Medium when unfocused but active (fully opaque) style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.45f, 0.45f, 0.85f, 0.35f); // Visible selection background (transparency ok) style.TabBorderSize = 0.0f; // Revert to default style.FrameBorderSize = 0.0f; // Revert to default } static void applyDreamcastTheme() { ImGui::StyleColorsDark(); ImGuiStyle& style = ImGui::GetStyle(); // Dreamcast-inspired theme with higher contrast // Pure white text - maximum brightness style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); // Pure white text style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.70f, 0.70f, 0.70f, 0.50f); // More transparent for disabled text (transparency ok) // Darker backgrounds for higher contrast style.Colors[ImGuiCol_WindowBg] = ImVec4(0.05f, 0.07f, 0.10f, 1.00f); // Much darker DC Menu Background for contrast style.Colors[ImGuiCol_ChildBg] = ImVec4(0.05f, 0.07f, 0.10f, 1.00f); // Match window background style.Colors[ImGuiCol_TitleBg] = ImVec4(0.13f, 0.16f, 0.40f, 1.00f); // DC Logo Blue (fully opaque) style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.18f, 0.22f, 0.50f, 1.00f); // Brighter DC Blue when active style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.43f, 0.73f, 0.70f); // More transparent when collapsed (transparency ok) style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.12f, 0.15f, 1.00f); // Dark but slightly lighter than window style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.05f, 0.07f, 0.10f, 1.00f); // Darker, same as window background style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.95f, 0.95f, 0.95f, 1.00f); // DC Shell White (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.95f, 0.95f, 0.95f, 1.00f); // Fully opaque when hovered style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.95f, 0.95f, 0.95f, 1.00f); // Fully opaque when active // Controller button colors - more vibrant style.Colors[ImGuiCol_Button] = ImVec4(0.90f, 0.50f, 0.10f, 1.00f); // Brighter orange buttons style.Colors[ImGuiCol_ButtonHovered] = ImVec4(1.00f, 0.70f, 0.40f, 1.00f); // Brighter when hovered style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.95f, 0.45f, 0.00f, 1.00f); // Brighter when active style.Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.07f, 0.10f, 1.00f); // Darker DC Menu Background (100% opaque) style.Colors[ImGuiCol_FrameBg] = ImVec4(0.15f, 0.17f, 0.22f, 1.00f); // Darker DC Menu (fully opaque) style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.10f, 0.70f, 0.50f, 1.00f); // Brighter Y Button (Green) (fully opaque) style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.06f, 0.60f, 0.35f, 1.00f); // Y Button (Green) (fully opaque) style.Colors[ImGuiCol_Header] = ImVec4(0.15f, 0.18f, 0.45f, 1.00f); // Brighter B Button (Blue) (fully opaque) style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.20f, 0.23f, 0.55f, 1.00f); // Even brighter B Button (Blue) (fully opaque) style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.10f, 0.13f, 0.33f, 1.00f); // B Button darker // A Button Red - more vibrant style.Colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 0.30f, 0.30f, 1.00f); // Brighter A Button (Red) - fully opaque style.Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.30f, 0.30f, 1.00f); // Brighter A Button (Red) (fully opaque) style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.90f, 0.20f, 0.20f, 1.00f); // A Button darker // Tabs - using X Button Blue - more vibrant style.Colors[ImGuiCol_Tab] = ImVec4(0.13f, 0.16f, 0.40f, 1.00f); // X Button Blue style.Colors[ImGuiCol_TabHovered] = ImVec4(0.25f, 0.30f, 0.60f, 1.00f); // Brighter when hovered (fully opaque) style.Colors[ImGuiCol_TabActive] = ImVec4(0.30f, 0.35f, 0.65f, 1.00f); // Much brighter & whiter when active style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.13f, 0.16f, 0.40f, 1.00f); // Same blue but fully opaque style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.25f, 0.30f, 0.60f, 1.00f); // Brighter for unfocused active (fully opaque) // Other elements - more vibrant style.Colors[ImGuiCol_Border] = ImVec4(1.00f, 0.85f, 0.25f, 0.70f); // Brighter DC "X" yellow borders (some transparency ok) style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); // No border shadows style.Colors[ImGuiCol_Separator] = ImVec4(0.00f, 0.50f, 0.80f, 0.75f); // Brighter DC Logo Blue separators (some transparency ok) style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(1.00f, 0.50f, 0.00f, 0.35f); // DC Swirl Orange selection (transparency ok) // Table colors - more vibrant style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.15f, 0.18f, 0.45f, 1.00f); // Brighter X Button Blue for headers (fully opaque) style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.50f, 0.80f, 1.00f); // Brighter DC Logo Blue borders style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.00f, 0.50f, 0.80f, 0.70f); // Brighter borders (some transparency ok) style.Colors[ImGuiCol_TableRowBg] = ImVec4(0.05f, 0.07f, 0.10f, 1.00f); // Same as window bg style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.10f, 0.12f, 0.15f, 1.00f); // Slightly lighter for alt rows } static void applyHighContrastTheme() { ImGui::StyleColorsDark(); ImGuiStyle& style = ImGui::GetStyle(); // High contrast theme with Dreamcast color accents // Base colors - extreme contrast style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); // Pure white text style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.75f, 0.75f, 0.75f, 1.00f); // Light gray for disabled text style.Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); // Pure black background style.Colors[ImGuiCol_ChildBg] = ImVec4(0.05f, 0.05f, 0.05f, 1.00f); // Very dark gray child windows style.Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); // Very dark for popups style.Colors[ImGuiCol_Border] = ImVec4(0.00f, 0.43f, 0.73f, 0.50f); // DC Logo Blue borders (semi-transparent ok) style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); // No shadows // Frame elements (checkboxes, input fields) style.Colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); // Dark gray frame backgrounds style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.30f, 0.30f, 0.30f, 1.00f); // Medium gray when hovered style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Darker gray when active // Title bars style.Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); // Dark gray title bar style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // DC Logo Blue active title style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.43f, 0.73f, 0.50f); // Semi-transparent when collapsed (transparency ok) style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); // Dark gray menu bar // Scrollbars style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); // Dark scrollbar background style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); // Medium gray scrollbar style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.56f, 0.56f, 0.56f, 1.00f); // Lighter when hovered style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.00f, 0.65f, 0.90f, 1.00f); // DC Highlight Blue when active // Interactive elements style.Colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 0.50f, 0.00f, 1.00f); // DC Swirl Orange for checkmarks style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.00f, 0.65f, 0.90f, 1.00f); // DC Highlight Blue for sliders style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(1.00f, 0.50f, 0.00f, 1.00f); // DC Swirl Orange when active // Buttons style.Colors[ImGuiCol_Button] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // DC Logo Blue buttons style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.00f, 0.65f, 0.90f, 1.00f); // DC Highlight Blue when hovered style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.00f, 0.33f, 0.60f, 1.00f); // Darker blue when active // Headers (collapsing headers, tree nodes) style.Colors[ImGuiCol_Header] = ImVec4(0.00f, 0.43f, 0.73f, 0.80f); // Semi-transparent DC Logo Blue (some transparency ok) style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.65f, 0.90f, 1.00f); // DC Highlight Blue when hovered (fully opaque) style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // Solid DC Logo Blue when active // Tables style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Dark gray table headers style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // DC Logo Blue table borders style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.00f, 0.43f, 0.73f, 0.50f); // Lighter DC Logo Blue inner borders (semi-transparent ok) // Tabs style.Colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Dark gray tabs style.Colors[ImGuiCol_TabHovered] = ImVec4(0.00f, 0.65f, 0.90f, 1.00f); // DC Highlight Blue when hovered style.Colors[ImGuiCol_TabActive] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // DC Logo Blue when active style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f); // Dark gray when unfocused style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.00f, 0.43f, 0.73f, 1.00f); // DC Logo Blue when unfocused but active (fully opaque) // Other UI elements style.Colors[ImGuiCol_Separator] = ImVec4(1.00f, 1.00f, 1.00f, 0.40f); // Semi-transparent white separators (transparency ok) style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(1.00f, 0.50f, 0.00f, 0.35f); // Semi-transparent DC Swirl Orange selection (transparency ok) // Increase contrast even more style.Alpha = 1.0f; // No transparency style.FrameBorderSize = 1.0f; // Add borders to frames style.WindowBorderSize = 1.0f; // Add borders to windows style.PopupBorderSize = 1.0f; // Add borders to popups style.TabBorderSize = 1.0f; // Add borders to tabs } static void applyNintendoTheme() { ImGui::StyleColorsDark(); ImGuiStyle& style = ImGui::GetStyle(); // Nintendo color palette ImVec4 nintendoRed = ImVec4(0.90f, 0.10f, 0.10f, 1.00f); // Nintendo logo/Switch red ImVec4 nintendoRedLight = ImVec4(1.00f, 0.30f, 0.30f, 1.00f); // Lighter red ImVec4 nintendoRedDark = ImVec4(0.65f, 0.05f, 0.05f, 1.00f); // Darker red ImVec4 luigiGreen = ImVec4(0.00f, 0.65f, 0.00f, 1.00f); // Luigi green ImVec4 luigiGreenLight = ImVec4(0.30f, 0.85f, 0.30f, 1.00f); // Lighter green ImVec4 gameboy = ImVec4(0.70f, 0.80f, 0.15f, 1.00f); // GameBoy screen color ImVec4 gamecubePurple = ImVec4(0.35f, 0.20f, 0.65f, 1.00f); // GameCube purple // Text colors style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); // Pure white text style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.70f, 0.70f, 0.70f, 0.65f); // Light gray for disabled (keep transparency) // Window background and elements - darker blue-black like classic consoles style.Colors[ImGuiCol_WindowBg] = ImVec4(0.03f, 0.03f, 0.10f, 1.00f); // Dark blue-black background (fully opaque) style.Colors[ImGuiCol_ChildBg] = ImVec4(0.03f, 0.03f, 0.10f, 1.00f); // Match window background (fully opaque) style.Colors[ImGuiCol_PopupBg] = ImVec4(0.02f, 0.02f, 0.08f, 1.00f); // Slightly darker for popup (fully opaque) // Frame elements - using GameCube purple for frames style.Colors[ImGuiCol_FrameBg] = ImVec4(0.12f, 0.08f, 0.20f, 1.00f); // Dark purple-ish background (fully opaque) style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.20f, 0.14f, 0.35f, 1.00f); // Lighter purple when hovered (fully opaque) style.Colors[ImGuiCol_FrameBgActive] = gamecubePurple; // GameCube purple when active // Title elements - using Nintendo red style.Colors[ImGuiCol_TitleBg] = ImVec4(0.05f, 0.05f, 0.12f, 1.00f); // Dark blue background (fully opaque) style.Colors[ImGuiCol_TitleBgActive] = nintendoRed; // Nintendo red for active title style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.05f, 0.05f, 0.12f, 0.75f); // Keep semi-transparent when collapsed style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.08f, 0.08f, 0.15f, 1.00f); // Dark menu bar (fully opaque) // Scrollbars - GameBoy inspired style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.04f, 0.04f, 0.10f, 1.00f); // Dark scrollbar background (fully opaque) style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.30f, 0.40f, 0.10f, 1.00f); // GameBoy green-yellow (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.50f, 0.60f, 0.15f, 1.00f); // Brighter GameBoy color (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabActive] = gameboy; // Full GameBoy color when active // Button elements - Nintendo red style.Colors[ImGuiCol_Button] = nintendoRed; // Nintendo red button style.Colors[ImGuiCol_ButtonHovered] = nintendoRedLight; // Lighter red when hovered style.Colors[ImGuiCol_ButtonActive] = nintendoRedDark; // Darker red when active // Interactive elements - Luigi green for checkmarks and sliders style.Colors[ImGuiCol_CheckMark] = luigiGreenLight; // Bright Luigi green for checkmarks style.Colors[ImGuiCol_SliderGrab] = luigiGreen; // Luigi green for sliders style.Colors[ImGuiCol_SliderGrabActive] = luigiGreenLight; // Lighter when active // Headers (collapsing headers, tree nodes) - GameCube purple style.Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.12f, 0.35f, 1.00f); // GameCube purple (fully opaque) style.Colors[ImGuiCol_HeaderHovered] = gamecubePurple; // Full purple when hovered style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.45f, 0.25f, 0.75f, 1.00f); // Brighter purple when active // Tab elements - Red/green for Mario/Luigi contrast style.Colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.10f, 0.30f, 1.00f); // Dark purple tabs (fully opaque) style.Colors[ImGuiCol_TabHovered] = luigiGreenLight; // Luigi green when hovered style.Colors[ImGuiCol_TabActive] = nintendoRed; // Mario red when active style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.10f, 0.08f, 0.20f, 1.00f); // Darker when unfocused (fully opaque) style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.40f, 0.10f, 0.10f, 1.00f); // Darker red when unfocused but active (fully opaque) // Border and separator style.Colors[ImGuiCol_Border] = ImVec4(0.40f, 0.40f, 0.50f, 0.50f); // Keep subtle border transparency style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); // No shadows style.Colors[ImGuiCol_Separator] = nintendoRed; // Nintendo red separators // Table elements style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.15f, 0.10f, 0.25f, 1.00f); // Dark purple headers (fully opaque) style.Colors[ImGuiCol_TableBorderStrong] = nintendoRed; // Nintendo red strong borders style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.40f, 0.10f, 0.10f, 0.70f); // Lighter red inner borders (keep transparency) style.Colors[ImGuiCol_TableRowBg] = ImVec4(0.03f, 0.03f, 0.10f, 1.00f); // Match window background (fully opaque) style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.06f, 0.06f, 0.14f, 1.00f); // Slightly lighter for alt rows (fully opaque) // Selected text - keep transparency for selection highlight style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(luigiGreen.x, luigiGreen.y, luigiGreen.z, 0.35f); // Semi-transparent Luigi green // Reset to defaults for these style.TabBorderSize = 0.0f; style.FrameBorderSize = 0.0f; } static void applySoftTheme() { ImGui::StyleColorsDark(); ImGuiStyle& style = ImGui::GetStyle(); // Soft, blue/turquoise theme that's easy on the eyes // Soft text colors style.Colors[ImGuiCol_Text] = ImVec4(0.85f, 0.90f, 0.92f, 1.00f); // Soft blue-white text style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.55f, 0.60f, 0.65f, 0.70f); // Muted blue-gray for disabled text (some transparency) // Soft dark backgrounds with turquoise tint style.Colors[ImGuiCol_WindowBg] = ImVec4(0.15f, 0.18f, 0.20f, 1.00f); // Soft dark background with blue tint (fully opaque) style.Colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.20f, 1.00f); // Match window background (fully opaque) style.Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.25f, 0.30f, 1.00f); // Deep turquoise title bar (fully opaque) style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.15f, 0.35f, 0.45f, 1.00f); // Brighter turquoise when active (fully opaque) style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.10f, 0.25f, 0.30f, 0.75f); // Keep some transparency when collapsed style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.17f, 0.21f, 0.24f, 1.00f); // Slightly lighter than background (fully opaque) // Soft scrollbars style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.15f, 0.18f, 0.20f, 1.00f); // Match window background (fully opaque) style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.25f, 0.45f, 0.50f, 1.00f); // Soft turquoise (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.30f, 0.55f, 1.00f, 1.00f); // Brighter when hovered (fully opaque) style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.35f, 0.65f, 1.00f, 1.00f); // Even brighter when active (fully opaque) // Soft, muted button colors style.Colors[ImGuiCol_Button] = ImVec4(0.20f, 0.40f, 0.45f, 1.00f); // Muted turquoise (fully opaque) style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.25f, 0.50f, 0.55f, 1.00f); // Slightly brighter when hovered (fully opaque) style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.30f, 0.60f, 0.65f, 1.00f); // Even brighter when active (fully opaque) style.Colors[ImGuiCol_PopupBg] = ImVec4(0.15f, 0.18f, 0.20f, 1.00f); // Match window background (fully opaque) // Frames (checkboxes, input fields) style.Colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.28f, 0.33f, 1.00f); // Soft blue-gray frames (fully opaque) style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.25f, 0.35f, 0.40f, 1.00f); // Slightly brighter when hovered (fully opaque) style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.45f, 0.50f, 1.00f); // Even brighter when active (fully opaque) // Headers (collapsing headers, tree nodes) style.Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.35f, 0.45f, 1.00f); // Soft blue headers (fully opaque) style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.40f, 0.50f, 1.00f); // Slightly brighter when hovered (fully opaque) style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.30f, 0.50f, 0.60f, 1.00f); // Even brighter when active (fully opaque) // Accent colors - light turquoise style.Colors[ImGuiCol_CheckMark] = ImVec4(0.40f, 0.80f, 0.90f, 1.00f); // Light turquoise checkmarks (fully opaque) style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.35f, 0.65f, 0.75f, 1.00f); // Turquoise sliders (fully opaque) style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.45f, 0.75f, 0.85f, 1.00f); // Brighter when active (fully opaque) // Tabs - soft blue palette style.Colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.30f, 0.40f, 1.00f); // Soft blue tabs (fully opaque) style.Colors[ImGuiCol_TabHovered] = ImVec4(0.25f, 0.40f, 0.50f, 1.00f); // Slightly brighter when hovered (fully opaque) style.Colors[ImGuiCol_TabActive] = ImVec4(0.30f, 0.50f, 0.60f, 1.00f); // Turquoise blue when active (fully opaque) style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.10f, 0.25f, 0.35f, 1.00f); // More muted when unfocused (fully opaque) style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.20f, 0.35f, 0.45f, 1.00f); // In-between for unfocused active (fully opaque) // Other elements style.Colors[ImGuiCol_Border] = ImVec4(0.20f, 0.35f, 0.45f, 0.60f); // Soft blue borders (some transparency ok) style.Colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.35f, 0.45f, 0.75f); // Soft blue separators (some transparency ok) style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.30f, 0.50f, 0.60f, 0.35f); // Soft blue selection (keep transparency) // Table colors style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.15f, 0.30f, 0.40f, 1.00f); // Soft blue headers (fully opaque) style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.20f, 0.35f, 0.45f, 1.00f); // Soft blue borders (fully opaque) style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.20f, 0.35f, 0.45f, 0.70f); // Lighter borders (some transparency) style.Colors[ImGuiCol_TableRowBg] = ImVec4(0.15f, 0.18f, 0.20f, 1.00f); // Match window bg (fully opaque) style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.17f, 0.21f, 0.24f, 1.00f); // Slightly lighter for alt rows (fully opaque) // Reset to defaults for these style.TabBorderSize = 0.0f; style.FrameBorderSize = 0.0f; } // Add the common function before gui_initFonts void applyCurrentTheme() { if (config::UITheme == 0) applyDarkTheme(); else if (config::UITheme == 1) applyLightTheme(); else if (config::UITheme == 2) applyDreamcastTheme(); else if (config::UITheme == 3) applyHighContrastTheme(); else if (config::UITheme == 4) applyNintendoTheme(); // Fixed ordering - was High Contrast else if (config::UITheme == 5) applySoftTheme(); // New "Aqua Chill" theme else applyDarkTheme(); }