2228 if (!p_open || !*p_open)
2231 ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
2233 if (ImGui::Begin(absl::StrFormat(
"%s Theme Editor",
ICON_MD_PALETTE).c_str(),
2234 p_open, ImGuiWindowFlags_MenuBar)) {
2236 static float editor_animation_time = 0.0f;
2237 editor_animation_time += ImGui::GetIO().DeltaTime;
2239 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2240 ImVec2 window_pos = ImGui::GetWindowPos();
2241 ImVec2 window_size = ImGui::GetWindowSize();
2245 std::vector<gui::Color> theme_colors = {
2246 current_theme.primary, current_theme.secondary, current_theme.accent,
2247 current_theme.success, current_theme.warning, current_theme.error};
2249 for (
size_t i = 0; i < theme_colors.size(); ++i) {
2250 float time_offset = i * 1.0f;
2251 float orbit_radius = 60.0f + i * 8.0f;
2252 float x = window_pos.x + window_size.x * 0.8f +
2253 cosf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
2254 float y = window_pos.y + window_size.y * 0.3f +
2255 sinf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
2258 0.15f + 0.1f * sinf(editor_animation_time * 1.5f + time_offset);
2259 ImU32 orb_color = ImGui::ColorConvertFloat4ToU32(
2260 ImVec4(theme_colors[i].red, theme_colors[i].green,
2261 theme_colors[i].blue, alpha));
2264 4.0f + sinf(editor_animation_time * 2.0f + time_offset) * 1.0f;
2265 draw_list->AddCircleFilled(ImVec2(x, y), radius, orb_color);
2269 if (ImGui::BeginMenuBar()) {
2270 if (ImGui::BeginMenu(tr(
"File"))) {
2271 if (ImGui::MenuItem(
2272 absl::StrFormat(
"%s New Theme",
ICON_MD_ADD).c_str())) {
2276 if (ImGui::MenuItem(
2280 if (!file_path.empty()) {
2285 if (ImGui::MenuItem(
2286 absl::StrFormat(
"%s Save Theme",
ICON_MD_SAVE).c_str())) {
2289 if (!current_file_path.empty()) {
2292 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2298 if (!file_path.empty()) {
2301 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2306 if (ImGui::MenuItem(
2311 if (!file_path.empty()) {
2314 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2319 if (ImGui::MenuItem(
2328 for (
char& c : safe_name) {
2329 if (c ==
' ' || c ==
'/' || c ==
'\\' || c ==
':' || c ==
'*' ||
2330 c ==
'?' || c ==
'"' || c ==
'<' || c ==
'>' || c ==
'|') {
2334 std::string file_path = user_themes_dir + safe_name +
".theme";
2338 LOG_INFO(
"Theme Manager",
"Exported theme to: %s",
2341 LOG_ERROR(
"Theme Manager",
"Failed to export theme to user themes");
2347 if (ImGui::BeginMenu(tr(
"Presets"))) {
2348 if (ImGui::MenuItem(tr(
"YAZE Classic"))) {
2353 if (!available_themes.empty()) {
2355 for (
const auto& theme_name : available_themes) {
2356 if (theme_name ==
"Classic YAZE") {
2359 if (ImGui::MenuItem(theme_name.c_str())) {
2367 ImGui::EndMenuBar();
2371 static char theme_name[128];
2372 static char theme_description[256];
2373 static char theme_author[128];
2374 static bool live_preview =
true;
2375 static Theme original_theme;
2376 static bool theme_backup_made =
false;
2379 auto apply_live_preview = [&]() {
2381 if (!theme_backup_made) {
2383 theme_backup_made =
true;
2392 ImGui::Checkbox(tr(
"Live Preview"), &live_preview);
2394 ImGui::Text(tr(
"| Changes apply immediately when enabled"));
2397 static bool prev_live_preview = live_preview;
2398 if (prev_live_preview && !live_preview && theme_backup_made) {
2400 theme_backup_made =
false;
2402 prev_live_preview = live_preview;
2407 if (ImGui::BeginTable(
"ThemeMetadata", 2,
2408 ImGuiTableFlags_SizingStretchProp)) {
2409 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed,
2411 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
2413 ImGui::TableNextRow();
2414 ImGui::TableNextColumn();
2415 ImGui::AlignTextToFramePadding();
2416 ImGui::Text(tr(
"Name:"));
2417 ImGui::TableNextColumn();
2418 if (ImGui::InputText(
"##theme_name", theme_name,
sizeof(theme_name))) {
2419 edit_theme.
name = std::string(theme_name);
2422 ImGui::TableNextRow();
2423 ImGui::TableNextColumn();
2424 ImGui::AlignTextToFramePadding();
2425 ImGui::Text(tr(
"Description:"));
2426 ImGui::TableNextColumn();
2427 if (ImGui::InputText(
"##theme_description", theme_description,
2428 sizeof(theme_description))) {
2429 edit_theme.
description = std::string(theme_description);
2432 ImGui::TableNextRow();
2433 ImGui::TableNextColumn();
2434 ImGui::AlignTextToFramePadding();
2435 ImGui::Text(tr(
"Author:"));
2436 ImGui::TableNextColumn();
2437 if (ImGui::InputText(
"##theme_author", theme_author,
2438 sizeof(theme_author))) {
2439 edit_theme.
author = std::string(theme_author);
2448 if (ImGui::BeginTabBar(
"ThemeEditorTabs", ImGuiTabBarFlags_None)) {
2450 static bool first_frame =
true;
2451 if (first_frame && live_preview) {
2452 apply_live_preview();
2453 first_frame =
false;
2457 if (ImGui::BeginTabItem(
2461 ImGui::PushStyleColor(ImGuiCol_ChildBg,
2462 ImVec4(0.1f, 0.1f, 0.12f, 0.5f));
2463 ImGui::BeginChild(
"AccentGenerator", ImVec2(0, 120),
true);
2465 ImGui::TextColored(ImVec4(0.7f, 0.8f, 1.0f, 1.0f),
2466 tr(
"%s Generate Theme from Accent Color"),
2470 static Color accent_picker_color = {0.4f, 0.6f, 0.9f, 1.0f};
2471 static bool dark_mode_generate =
true;
2473 ImGui::Text(tr(
"Accent Color:"));
2476 if (ImGui::ColorEdit3(
"##AccentPicker", &accent_vec.x,
2477 ImGuiColorEditFlags_NoInputs)) {
2478 accent_picker_color = {accent_vec.x, accent_vec.y, accent_vec.z,
2483 ImGui::Checkbox(tr(
"Dark Mode"), &dark_mode_generate);
2486 if (ImGui::Button(absl::StrFormat(
"%s Generate",
ICON_MD_BOLT).c_str(),
2491 edit_theme = generated;
2492 apply_live_preview();
2496 ImGui::Text(tr(
"Preview: "));
2500 Theme preview_theme =
2507 ImGui::ColorButton(
"##prev_primary", prev_primary, 0, ImVec2(24, 24));
2508 ImGui::SameLine(0, 2);
2509 ImGui::ColorButton(
"##prev_secondary", prev_secondary, 0,
2511 ImGui::SameLine(0, 2);
2512 ImGui::ColorButton(
"##prev_bg", prev_bg, 0, ImVec2(24, 24));
2513 ImGui::SameLine(0, 2);
2514 ImGui::ColorButton(
"##prev_surface", prev_surface, 0, ImVec2(24, 24));
2517 ImGui::PopStyleColor();
2521 if (ImGui::BeginTable(
"PrimaryColorsTable", 3,
2522 ImGuiTableFlags_SizingStretchProp)) {
2523 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
2525 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2527 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2529 ImGui::TableHeadersRow();
2532 ImGui::TableNextRow();
2533 ImGui::TableNextColumn();
2534 ImGui::AlignTextToFramePadding();
2535 ImGui::Text(tr(
"Primary:"));
2536 ImGui::TableNextColumn();
2538 if (ImGui::ColorEdit3(
"##primary", &primary.x)) {
2539 edit_theme.
primary = {primary.x, primary.y, primary.z, primary.w};
2540 apply_live_preview();
2542 ImGui::TableNextColumn();
2543 ImGui::Button(tr(
"Primary Preview"), ImVec2(-1, 30));
2546 ImGui::TableNextRow();
2547 ImGui::TableNextColumn();
2548 ImGui::AlignTextToFramePadding();
2549 ImGui::Text(tr(
"Secondary:"));
2550 ImGui::TableNextColumn();
2552 if (ImGui::ColorEdit3(
"##secondary", &secondary.x)) {
2553 edit_theme.
secondary = {secondary.x, secondary.y, secondary.z,
2555 apply_live_preview();
2557 ImGui::TableNextColumn();
2558 ImGui::PushStyleColor(ImGuiCol_Button, secondary);
2559 ImGui::Button(tr(
"Secondary Preview"), ImVec2(-1, 30));
2560 ImGui::PopStyleColor();
2563 ImGui::TableNextRow();
2564 ImGui::TableNextColumn();
2565 ImGui::AlignTextToFramePadding();
2566 ImGui::Text(tr(
"Accent:"));
2567 ImGui::TableNextColumn();
2569 if (ImGui::ColorEdit3(
"##accent", &accent.x)) {
2570 edit_theme.
accent = {accent.x, accent.y, accent.z, accent.w};
2571 apply_live_preview();
2573 ImGui::TableNextColumn();
2574 ImGui::PushStyleColor(ImGuiCol_Button, accent);
2575 ImGui::Button(tr(
"Accent Preview"), ImVec2(-1, 30));
2576 ImGui::PopStyleColor();
2579 ImGui::TableNextRow();
2580 ImGui::TableNextColumn();
2581 ImGui::AlignTextToFramePadding();
2582 ImGui::Text(tr(
"Background:"));
2583 ImGui::TableNextColumn();
2585 if (ImGui::ColorEdit4(
"##background", &background.x)) {
2586 edit_theme.
background = {background.x, background.y, background.z,
2588 apply_live_preview();
2590 ImGui::TableNextColumn();
2591 ImGui::Text(tr(
"Background preview shown in window"));
2595 ImGui::EndTabItem();
2599 if (ImGui::BeginTabItem(
2601 if (ImGui::BeginTable(
"TextColorsTable", 3,
2602 ImGuiTableFlags_SizingStretchProp)) {
2603 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
2605 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2607 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2609 ImGui::TableHeadersRow();
2612 auto text_colors = std::vector<std::pair<const char*, Color*>>{
2622 for (
auto& [label, color_ptr] : text_colors) {
2623 ImGui::TableNextRow();
2624 ImGui::TableNextColumn();
2625 ImGui::AlignTextToFramePadding();
2626 ImGui::Text(
"%s:", label);
2628 ImGui::TableNextColumn();
2630 std::string
id = absl::StrFormat(
"##%s", label);
2631 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2632 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2633 apply_live_preview();
2636 ImGui::TableNextColumn();
2637 ImGui::PushStyleColor(ImGuiCol_Text, color_vec);
2638 ImGui::Text(tr(
"Sample %s"), label);
2639 ImGui::PopStyleColor();
2644 ImGui::EndTabItem();
2648 if (ImGui::BeginTabItem(
2650 if (ImGui::BeginTable(
"InteractiveColorsTable", 3,
2651 ImGuiTableFlags_SizingStretchProp)) {
2652 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2654 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2656 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2658 ImGui::TableHeadersRow();
2661 auto interactive_colors =
2662 std::vector<std::tuple<const char*, Color*, ImGuiCol>>{
2663 {
"Button", &edit_theme.
button, ImGuiCol_Button},
2665 ImGuiCol_ButtonHovered},
2667 ImGuiCol_ButtonActive},
2668 {
"Frame Background", &edit_theme.
frame_bg, ImGuiCol_FrameBg},
2670 ImGuiCol_FrameBgHovered},
2672 ImGuiCol_FrameBgActive},
2673 {
"Check Mark", &edit_theme.
check_mark, ImGuiCol_CheckMark},
2674 {
"Slider Grab", &edit_theme.
slider_grab, ImGuiCol_SliderGrab},
2676 ImGuiCol_SliderGrabActive}};
2678 for (
auto& [label, color_ptr, imgui_col] : interactive_colors) {
2679 ImGui::TableNextRow();
2680 ImGui::TableNextColumn();
2681 ImGui::AlignTextToFramePadding();
2682 ImGui::Text(
"%s:", label);
2684 ImGui::TableNextColumn();
2686 std::string
id = absl::StrFormat(
"##%s", label);
2687 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2688 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2689 apply_live_preview();
2692 ImGui::TableNextColumn();
2693 ImGui::PushStyleColor(imgui_col, color_vec);
2694 ImGui::Button(absl::StrFormat(
"Preview %s", label).c_str(),
2696 ImGui::PopStyleColor();
2701 ImGui::EndTabItem();
2705 if (ImGui::BeginTabItem(
2707 ImGui::Text(tr(
"Rounding and Border Settings:"));
2709 if (ImGui::SliderFloat(tr(
"Window Rounding"),
2714 if (ImGui::SliderFloat(tr(
"Frame Rounding"), &edit_theme.
frame_rounding,
2719 if (ImGui::SliderFloat(tr(
"Scrollbar Rounding"),
2724 if (ImGui::SliderFloat(tr(
"Tab Rounding"), &edit_theme.
tab_rounding,
2729 if (ImGui::SliderFloat(tr(
"Grab Rounding"), &edit_theme.
grab_rounding,
2736 ImGui::Text(tr(
"Border Sizes:"));
2738 if (ImGui::SliderFloat(tr(
"Window Border Size"),
2743 if (ImGui::SliderFloat(tr(
"Frame Border Size"),
2750 ImGui::Text(tr(
"Animation & Effects:"));
2752 if (ImGui::Checkbox(tr(
"Enable Animations"),
2758 if (ImGui::SliderFloat(tr(
"Animation Speed"),
2760 apply_live_preview();
2763 if (ImGui::Checkbox(tr(
"Enable Glow Effects"),
2769 ImGui::EndTabItem();
2773 if (ImGui::BeginTabItem(
2775 if (ImGui::BeginTable(
"NavigationTable", 3,
2776 ImGuiTableFlags_SizingStretchProp)) {
2777 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2779 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2781 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2783 ImGui::TableHeadersRow();
2786 auto window_colors =
2787 std::vector<std::tuple<const char*, Color*, const char*>>{
2788 {
"Window Background", &edit_theme.
window_bg,
2789 "Main window background"},
2790 {
"Child Background", &edit_theme.
child_bg,
2791 "Child window background"},
2792 {
"Popup Background", &edit_theme.
popup_bg,
2793 "Popup window background"},
2794 {
"Modal Background", &edit_theme.
modal_bg,
2795 "Modal window background"},
2797 "Menu bar background"}};
2799 for (
auto& [label, color_ptr, description] : window_colors) {
2800 ImGui::TableNextRow();
2801 ImGui::TableNextColumn();
2802 ImGui::AlignTextToFramePadding();
2803 ImGui::Text(
"%s:", label);
2805 ImGui::TableNextColumn();
2807 std::string
id = absl::StrFormat(
"##window_%s", label);
2808 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2809 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2810 apply_live_preview();
2813 ImGui::TableNextColumn();
2814 ImGui::TextWrapped(
"%s", description);
2823 if (ImGui::CollapsingHeader(tr(
"Headers & Tabs"),
2824 ImGuiTreeNodeFlags_DefaultOpen)) {
2825 if (ImGui::BeginTable(
"HeaderTabTable", 3,
2826 ImGuiTableFlags_SizingStretchProp)) {
2827 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2829 ImGui::TableSetupColumn(
"Picker",
2830 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2831 ImGui::TableSetupColumn(
"Preview",
2832 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2833 ImGui::TableHeadersRow();
2835 auto header_tab_colors =
2836 std::vector<std::pair<const char*, Color*>>{
2837 {
"Header", &edit_theme.
header},
2840 {
"Tab", &edit_theme.
tab},
2847 {
"Title Background", &edit_theme.
title_bg},
2851 for (
auto& [label, color_ptr] : header_tab_colors) {
2852 ImGui::TableNextRow();
2853 ImGui::TableNextColumn();
2854 ImGui::AlignTextToFramePadding();
2855 ImGui::Text(
"%s:", label);
2857 ImGui::TableNextColumn();
2859 std::string
id = absl::StrFormat(
"##header_%s", label);
2860 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2861 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
2863 apply_live_preview();
2866 ImGui::TableNextColumn();
2867 ImGui::PushStyleColor(ImGuiCol_Button, color_vec);
2868 ImGui::Button(absl::StrFormat(
"Preview %s", label).c_str(),
2870 ImGui::PopStyleColor();
2878 if (ImGui::CollapsingHeader(tr(
"Navigation & Special"))) {
2879 if (ImGui::BeginTable(
"NavSpecialTable", 3,
2880 ImGuiTableFlags_SizingStretchProp)) {
2881 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2883 ImGui::TableSetupColumn(
"Picker",
2884 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2885 ImGui::TableSetupColumn(
"Description",
2886 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2887 ImGui::TableHeadersRow();
2889 auto nav_special_colors =
2890 std::vector<std::tuple<const char*, Color*, const char*>>{
2892 "Navigation cursor color"},
2894 "Window selection highlight"},
2896 "Background dimming for navigation"},
2898 "Background dimming for modals"},
2900 "Drag and drop target highlight"},
2902 "Docking area preview"},
2904 "Empty docking space background"}};
2906 for (
auto& [label, color_ptr, description] : nav_special_colors) {
2907 ImGui::TableNextRow();
2908 ImGui::TableNextColumn();
2909 ImGui::AlignTextToFramePadding();
2910 ImGui::Text(
"%s:", label);
2912 ImGui::TableNextColumn();
2914 std::string
id = absl::StrFormat(
"##nav_%s", label);
2915 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2916 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
2918 apply_live_preview();
2921 ImGui::TableNextColumn();
2922 ImGui::TextWrapped(
"%s", description);
2929 ImGui::EndTabItem();
2933 if (ImGui::BeginTabItem(
2935 if (ImGui::BeginTable(
"TablesDataTable", 3,
2936 ImGuiTableFlags_SizingStretchProp)) {
2937 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2939 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2941 ImGui::TableSetupColumn(
"Description",
2942 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2943 ImGui::TableHeadersRow();
2946 std::vector<std::tuple<const char*, Color*, const char*>>{
2948 "Table column headers"},
2950 "Outer table borders"},
2952 "Inner table borders"},
2954 "Normal table rows"},
2956 "Alternating table rows"},
2958 "Tree view connection lines"}};
2960 for (
auto& [label, color_ptr, description] : table_colors) {
2961 ImGui::TableNextRow();
2962 ImGui::TableNextColumn();
2963 ImGui::AlignTextToFramePadding();
2964 ImGui::Text(
"%s:", label);
2966 ImGui::TableNextColumn();
2968 std::string
id = absl::StrFormat(
"##table_%s", label);
2969 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2970 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2971 apply_live_preview();
2974 ImGui::TableNextColumn();
2975 ImGui::TextWrapped(
"%s", description);
2984 if (ImGui::CollapsingHeader(tr(
"Plots & Graphs"))) {
2985 if (ImGui::BeginTable(
"PlotsTable", 3,
2986 ImGuiTableFlags_SizingStretchProp)) {
2987 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2989 ImGui::TableSetupColumn(
"Picker",
2990 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2991 ImGui::TableSetupColumn(
"Description",
2992 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2993 ImGui::TableHeadersRow();
2996 std::vector<std::tuple<const char*, Color*, const char*>>{
2997 {
"Plot Lines", &edit_theme.
plot_lines,
"Line plot color"},
2999 "Line plot hover color"},
3001 "Histogram fill color"},
3002 {
"Plot Histogram Hovered",
3004 "Histogram hover color"}};
3006 for (
auto& [label, color_ptr, description] : plot_colors) {
3007 ImGui::TableNextRow();
3008 ImGui::TableNextColumn();
3009 ImGui::AlignTextToFramePadding();
3010 ImGui::Text(
"%s:", label);
3012 ImGui::TableNextColumn();
3014 std::string
id = absl::StrFormat(
"##plot_%s", label);
3015 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
3016 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
3018 apply_live_preview();
3021 ImGui::TableNextColumn();
3022 ImGui::TextWrapped(
"%s", description);
3029 ImGui::EndTabItem();
3033 if (ImGui::BeginTabItem(
3035 if (ImGui::BeginTable(
"BordersControlsTable", 3,
3036 ImGuiTableFlags_SizingStretchProp)) {
3037 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
3039 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
3041 ImGui::TableSetupColumn(
"Description",
3042 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3043 ImGui::TableHeadersRow();
3045 auto border_control_colors =
3046 std::vector<std::tuple<const char*, Color*, const char*>>{
3047 {
"Border", &edit_theme.
border,
"General border color"},
3049 "Border shadow/depth"},
3051 "Horizontal/vertical separators"},
3053 "Separator hover state"},
3055 "Separator active/dragged state"},
3057 "Scrollbar track background"},
3059 "Scrollbar handle"},
3061 "Scrollbar handle hover"},
3063 "Scrollbar handle active"},
3065 "Window resize grip"},
3067 "Resize grip hover"},
3069 "Resize grip active"}};
3071 for (
auto& [label, color_ptr, description] : border_control_colors) {
3072 ImGui::TableNextRow();
3073 ImGui::TableNextColumn();
3074 ImGui::AlignTextToFramePadding();
3075 ImGui::Text(
"%s:", label);
3077 ImGui::TableNextColumn();
3079 std::string
id = absl::StrFormat(
"##border_%s", label);
3080 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
3081 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
3082 apply_live_preview();
3085 ImGui::TableNextColumn();
3086 ImGui::TextWrapped(
"%s", description);
3092 ImGui::EndTabItem();
3096 if (ImGui::BeginTabItem(
3099 tr(
"Enhanced semantic colors and editor-specific customization"));
3103 if (ImGui::CollapsingHeader(tr(
"Enhanced Semantic Colors"),
3104 ImGuiTreeNodeFlags_DefaultOpen)) {
3105 if (ImGui::BeginTable(
"EnhancedSemanticTable", 3,
3106 ImGuiTableFlags_SizingStretchProp)) {
3107 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3109 ImGui::TableSetupColumn(
"Picker",
3110 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3111 ImGui::TableSetupColumn(
"Description",
3112 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3113 ImGui::TableHeadersRow();
3115 auto enhanced_colors =
3116 std::vector<std::tuple<const char*, Color*, const char*>>{
3118 "Code blocks background"},
3120 "Light success variant"},
3122 "Light warning variant"},
3124 "Light error variant"},
3126 "Light info variant"}};
3128 for (
auto& [label, color_ptr, description] : enhanced_colors) {
3129 ImGui::TableNextRow();
3130 ImGui::TableNextColumn();
3131 ImGui::AlignTextToFramePadding();
3132 ImGui::Text(
"%s:", label);
3134 ImGui::TableNextColumn();
3136 std::string
id = absl::StrFormat(
"##enhanced_%s", label);
3137 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
3138 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
3140 apply_live_preview();
3143 ImGui::TableNextColumn();
3144 ImGui::TextWrapped(
"%s", description);
3152 if (ImGui::CollapsingHeader(tr(
"UI State Colors"))) {
3153 if (ImGui::BeginTable(
"UIStateTable", 3,
3154 ImGuiTableFlags_SizingStretchProp)) {
3155 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3157 ImGui::TableSetupColumn(
"Picker",
3158 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3159 ImGui::TableSetupColumn(
"Description",
3160 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3161 ImGui::TableHeadersRow();
3164 ImGui::TableNextRow();
3165 ImGui::TableNextColumn();
3166 ImGui::AlignTextToFramePadding();
3167 ImGui::Text(tr(
"Active Selection:"));
3168 ImGui::TableNextColumn();
3169 ImVec4 active_selection =
3171 if (ImGui::ColorEdit4(
"##active_selection", &active_selection.x)) {
3173 active_selection.x, active_selection.y, active_selection.z,
3174 active_selection.w};
3175 apply_live_preview();
3177 ImGui::TableNextColumn();
3178 ImGui::TextWrapped(tr(
"Active/selected UI elements"));
3180 ImGui::TableNextRow();
3181 ImGui::TableNextColumn();
3182 ImGui::AlignTextToFramePadding();
3183 ImGui::Text(tr(
"Hover Highlight:"));
3184 ImGui::TableNextColumn();
3185 ImVec4 hover_highlight =
3187 if (ImGui::ColorEdit4(
"##hover_highlight", &hover_highlight.x)) {
3189 hover_highlight.x, hover_highlight.y, hover_highlight.z,
3191 apply_live_preview();
3193 ImGui::TableNextColumn();
3194 ImGui::TextWrapped(tr(
"General hover state highlighting"));
3196 ImGui::TableNextRow();
3197 ImGui::TableNextColumn();
3198 ImGui::AlignTextToFramePadding();
3199 ImGui::Text(tr(
"Focus Border:"));
3200 ImGui::TableNextColumn();
3202 if (ImGui::ColorEdit3(
"##focus_border", &focus_border.x)) {
3203 edit_theme.
focus_border = {focus_border.x, focus_border.y,
3204 focus_border.z, focus_border.w};
3205 apply_live_preview();
3207 ImGui::TableNextColumn();
3208 ImGui::TextWrapped(tr(
"Border for focused input elements"));
3210 ImGui::TableNextRow();
3211 ImGui::TableNextColumn();
3212 ImGui::AlignTextToFramePadding();
3213 ImGui::Text(tr(
"Disabled Overlay:"));
3214 ImGui::TableNextColumn();
3215 ImVec4 disabled_overlay =
3217 if (ImGui::ColorEdit4(
"##disabled_overlay", &disabled_overlay.x)) {
3219 disabled_overlay.x, disabled_overlay.y, disabled_overlay.z,
3220 disabled_overlay.w};
3221 apply_live_preview();
3223 ImGui::TableNextColumn();
3225 tr(
"Semi-transparent overlay for disabled elements"));
3232 if (ImGui::CollapsingHeader(tr(
"Editor-Specific Colors"))) {
3233 if (ImGui::BeginTable(
"EditorColorsTable", 3,
3234 ImGuiTableFlags_SizingStretchProp)) {
3235 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3237 ImGui::TableSetupColumn(
"Picker",
3238 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3239 ImGui::TableSetupColumn(
"Description",
3240 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3241 ImGui::TableHeadersRow();
3243 auto editor_colors =
3244 std::vector<std::tuple<const char*, Color*, const char*, bool>>{
3246 "Main editor canvas background",
false},
3248 "Grid lines in map/graphics editors",
true},
3250 "Cursor color in editors",
false},
3252 "Selection highlight in editors",
true}};
3254 for (
auto& [label, color_ptr, description, use_alpha] :
3256 ImGui::TableNextRow();
3257 ImGui::TableNextColumn();
3258 ImGui::AlignTextToFramePadding();
3259 ImGui::Text(
"%s:", label);
3261 ImGui::TableNextColumn();
3263 std::string
id = absl::StrFormat(
"##editor_%s", label);
3264 if (use_alpha ? ImGui::ColorEdit4(
id.c_str(), &color_vec.x)
3265 : ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
3266 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
3268 apply_live_preview();
3271 ImGui::TableNextColumn();
3272 ImGui::TextWrapped(
"%s", description);
3279 ImGui::EndTabItem();
3283 if (ImGui::BeginTabItem(
3285 ImGui::Text(tr(
"Control UI density, spacing, and typography scaling"));
3289 ImGui::TextColored(ImVec4(0.7f, 0.8f, 1.0f, 1.0f),
3294 int current_preset =
static_cast<int>(edit_theme.
density_preset);
3296 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 12));
3297 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 0));
3300 bool is_compact = (current_preset == 0);
3302 ImGui::PushStyleColor(
3311 apply_live_preview();
3314 ImGui::PopStyleColor();
3316 if (ImGui::IsItemHovered()) {
3318 tr(
"Dense UI with smaller widgets and tighter spacing\n"
3319 "Best for: Information-dense workflows"));
3325 bool is_normal = (current_preset == 1);
3327 ImGui::PushStyleColor(
3332 if (ImGui::Button(absl::StrFormat(
"%s Normal",
ICON_MD_CHECK).c_str(),
3335 apply_live_preview();
3338 ImGui::PopStyleColor();
3340 if (ImGui::IsItemHovered()) {
3342 tr(
"Balanced spacing and widget sizes\n"
3343 "Best for: General use"));
3349 bool is_comfortable = (current_preset == 2);
3350 if (is_comfortable) {
3351 ImGui::PushStyleColor(
3360 apply_live_preview();
3362 if (is_comfortable) {
3363 ImGui::PopStyleColor();
3365 if (ImGui::IsItemHovered()) {
3367 tr(
"Spacious layout with larger click targets\n"
3368 "Best for: Touch screens, accessibility"));
3371 ImGui::PopStyleVar(2);
3378 if (ImGui::CollapsingHeader(tr(
"Advanced Density Controls"))) {
3381 ImGui::Text(tr(
"Fine-tune individual spacing multipliers:"));
3385 if (ImGui::SliderFloat(tr(
"Compact Factor"),
3388 apply_live_preview();
3390 if (ImGui::IsItemHovered()) {
3392 tr(
"Global density multiplier (0.5 = very compact, "
3393 "1.5 = very spacious)"));
3399 if (ImGui::SliderFloat(tr(
"Widget Height"),
3402 apply_live_preview();
3406 if (ImGui::SliderFloat(tr(
"Item Spacing"),
3409 apply_live_preview();
3413 if (ImGui::SliderFloat(tr(
"Toolbar Height"),
3416 apply_live_preview();
3420 if (ImGui::SliderFloat(tr(
"Panel Padding"),
3423 apply_live_preview();
3427 if (ImGui::SliderFloat(tr(
"Button Padding"),
3430 apply_live_preview();
3434 if (ImGui::SliderFloat(tr(
"Table Row Height"),
3437 apply_live_preview();
3444 if (ImGui::CollapsingHeader(tr(
"Corner Rounding"))) {
3447 if (ImGui::SliderFloat(tr(
"Window Rounding"),
3450 apply_live_preview();
3453 if (ImGui::SliderFloat(tr(
"Frame Rounding"),
3456 apply_live_preview();
3459 if (ImGui::SliderFloat(tr(
"Tab Rounding"), &edit_theme.
tab_rounding,
3460 0.0f, 12.0f,
"%.1f")) {
3461 apply_live_preview();
3464 if (ImGui::SliderFloat(tr(
"Scrollbar Rounding"),
3467 apply_live_preview();
3470 if (ImGui::SliderFloat(tr(
"Grab Rounding"), &edit_theme.
grab_rounding,
3471 0.0f, 12.0f,
"%.1f")) {
3472 apply_live_preview();
3479 if (ImGui::CollapsingHeader(tr(
"Animation Settings"))) {
3482 if (ImGui::Checkbox(tr(
"Enable Animations"),
3484 apply_live_preview();
3488 if (ImGui::SliderFloat(tr(
"Animation Speed"),
3491 apply_live_preview();
3495 if (ImGui::Checkbox(tr(
"Enable Glow Effects"),
3497 apply_live_preview();
3503 ImGui::EndTabItem();
3511 if (ImGui::Button(tr(
"Preview Theme"))) {
3516 if (ImGui::Button(tr(
"Reset to Current"))) {
3522 theme_name[name_len] =
'\0';
3525 sizeof(theme_description) - 1);
3528 theme_description[desc_len] =
'\0';
3533 theme_author[author_len] =
'\0';
3536 if (theme_backup_made) {
3537 theme_backup_made =
false;
3544 if (ImGui::Button(tr(
"Save Theme"))) {
3545 edit_theme.
name = std::string(theme_name);
3546 edit_theme.
description = std::string(theme_description);
3547 edit_theme.
author = std::string(theme_author);
3554 theme_backup_made =
false;
3561 bool can_save_over = !current_file_path.empty();
3563 if (!can_save_over) {
3564 ImGui::BeginDisabled();
3567 if (ImGui::Button(tr(
"Save Over Current"))) {
3568 edit_theme.
name = std::string(theme_name);
3569 edit_theme.
description = std::string(theme_description);
3570 edit_theme.
author = std::string(theme_author);
3580 LOG_ERROR(
"Theme Manager",
"Failed to save over current theme");
3584 if (!can_save_over) {
3585 ImGui::EndDisabled();
3588 if (ImGui::IsItemHovered() && can_save_over) {
3589 ImGui::BeginTooltip();
3590 ImGui::Text(tr(
"Save over current theme file:"));
3591 ImGui::Text(
"%s", current_file_path.c_str());
3592 ImGui::EndTooltip();
3593 }
else if (ImGui::IsItemHovered()) {
3594 ImGui::BeginTooltip();
3595 ImGui::Text(tr(
"No current theme file to overwrite"));
3596 ImGui::Text(tr(
"Use 'Save to File...' to create a new theme file"));
3597 ImGui::EndTooltip();
3601 if (ImGui::Button(tr(
"Save to File..."))) {
3602 edit_theme.
name = std::string(theme_name);
3603 edit_theme.
description = std::string(theme_description);
3604 edit_theme.
author = std::string(theme_author);
3607 std::string safe_name =
3608 edit_theme.
name.empty() ?
"custom_theme" : edit_theme.
name;
3612 if (!file_path.empty()) {
3614 if (file_path.find(
".theme") == std::string::npos) {
3615 file_path +=
".theme";
3624 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
3629 if (ImGui::IsItemHovered()) {
3630 ImGui::BeginTooltip();
3631 ImGui::Text(tr(
"Save theme to a .theme file"));
3632 ImGui::Text(tr(
"Saved themes can be shared and loaded later"));
3633 ImGui::EndTooltip();