2196 if (!p_open || !*p_open)
2199 ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
2201 if (ImGui::Begin(absl::StrFormat(
"%s Theme Editor",
ICON_MD_PALETTE).c_str(),
2202 p_open, ImGuiWindowFlags_MenuBar)) {
2204 static float editor_animation_time = 0.0f;
2205 editor_animation_time += ImGui::GetIO().DeltaTime;
2207 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2208 ImVec2 window_pos = ImGui::GetWindowPos();
2209 ImVec2 window_size = ImGui::GetWindowSize();
2213 std::vector<gui::Color> theme_colors = {
2214 current_theme.primary, current_theme.secondary, current_theme.accent,
2215 current_theme.success, current_theme.warning, current_theme.error};
2217 for (
size_t i = 0; i < theme_colors.size(); ++i) {
2218 float time_offset = i * 1.0f;
2219 float orbit_radius = 60.0f + i * 8.0f;
2220 float x = window_pos.x + window_size.x * 0.8f +
2221 cosf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
2222 float y = window_pos.y + window_size.y * 0.3f +
2223 sinf(editor_animation_time * 0.3f + time_offset) * orbit_radius;
2226 0.15f + 0.1f * sinf(editor_animation_time * 1.5f + time_offset);
2227 ImU32 orb_color = ImGui::ColorConvertFloat4ToU32(
2228 ImVec4(theme_colors[i].red, theme_colors[i].green,
2229 theme_colors[i].blue, alpha));
2232 4.0f + sinf(editor_animation_time * 2.0f + time_offset) * 1.0f;
2233 draw_list->AddCircleFilled(ImVec2(x, y), radius, orb_color);
2237 if (ImGui::BeginMenuBar()) {
2238 if (ImGui::BeginMenu(
"File")) {
2239 if (ImGui::MenuItem(
2240 absl::StrFormat(
"%s New Theme",
ICON_MD_ADD).c_str())) {
2244 if (ImGui::MenuItem(
2248 if (!file_path.empty()) {
2253 if (ImGui::MenuItem(
2254 absl::StrFormat(
"%s Save Theme",
ICON_MD_SAVE).c_str())) {
2257 if (!current_file_path.empty()) {
2260 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2266 if (!file_path.empty()) {
2269 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2274 if (ImGui::MenuItem(
2279 if (!file_path.empty()) {
2282 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
2287 if (ImGui::MenuItem(
2296 for (
char& c : safe_name) {
2297 if (c ==
' ' || c ==
'/' || c ==
'\\' || c ==
':' || c ==
'*' ||
2298 c ==
'?' || c ==
'"' || c ==
'<' || c ==
'>' || c ==
'|') {
2302 std::string file_path = user_themes_dir + safe_name +
".theme";
2306 LOG_INFO(
"Theme Manager",
"Exported theme to: %s",
2309 LOG_ERROR(
"Theme Manager",
"Failed to export theme to user themes");
2315 if (ImGui::BeginMenu(
"Presets")) {
2316 if (ImGui::MenuItem(
"YAZE Classic")) {
2321 if (!available_themes.empty()) {
2323 for (
const auto& theme_name : available_themes) {
2324 if (ImGui::MenuItem(theme_name.c_str())) {
2332 ImGui::EndMenuBar();
2336 static char theme_name[128];
2337 static char theme_description[256];
2338 static char theme_author[128];
2339 static bool live_preview =
true;
2340 static Theme original_theme;
2341 static bool theme_backup_made =
false;
2344 auto apply_live_preview = [&]() {
2346 if (!theme_backup_made) {
2348 theme_backup_made =
true;
2357 ImGui::Checkbox(
"Live Preview", &live_preview);
2359 ImGui::Text(
"| Changes apply immediately when enabled");
2362 static bool prev_live_preview = live_preview;
2363 if (prev_live_preview && !live_preview && theme_backup_made) {
2365 theme_backup_made =
false;
2367 prev_live_preview = live_preview;
2372 if (ImGui::BeginTable(
"ThemeMetadata", 2,
2373 ImGuiTableFlags_SizingStretchProp)) {
2374 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed,
2376 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthStretch);
2378 ImGui::TableNextRow();
2379 ImGui::TableNextColumn();
2380 ImGui::AlignTextToFramePadding();
2381 ImGui::Text(
"Name:");
2382 ImGui::TableNextColumn();
2383 if (ImGui::InputText(
"##theme_name", theme_name,
sizeof(theme_name))) {
2384 edit_theme.
name = std::string(theme_name);
2387 ImGui::TableNextRow();
2388 ImGui::TableNextColumn();
2389 ImGui::AlignTextToFramePadding();
2390 ImGui::Text(
"Description:");
2391 ImGui::TableNextColumn();
2392 if (ImGui::InputText(
"##theme_description", theme_description,
2393 sizeof(theme_description))) {
2394 edit_theme.
description = std::string(theme_description);
2397 ImGui::TableNextRow();
2398 ImGui::TableNextColumn();
2399 ImGui::AlignTextToFramePadding();
2400 ImGui::Text(
"Author:");
2401 ImGui::TableNextColumn();
2402 if (ImGui::InputText(
"##theme_author", theme_author,
2403 sizeof(theme_author))) {
2404 edit_theme.
author = std::string(theme_author);
2413 if (ImGui::BeginTabBar(
"ThemeEditorTabs", ImGuiTabBarFlags_None)) {
2415 static bool first_frame =
true;
2416 if (first_frame && live_preview) {
2417 apply_live_preview();
2418 first_frame =
false;
2422 if (ImGui::BeginTabItem(
2426 ImGui::PushStyleColor(ImGuiCol_ChildBg,
2427 ImVec4(0.1f, 0.1f, 0.12f, 0.5f));
2428 ImGui::BeginChild(
"AccentGenerator", ImVec2(0, 120),
true);
2430 ImGui::TextColored(ImVec4(0.7f, 0.8f, 1.0f, 1.0f),
2431 "%s Generate Theme from Accent Color",
2435 static Color accent_picker_color = {0.4f, 0.6f, 0.9f, 1.0f};
2436 static bool dark_mode_generate =
true;
2438 ImGui::Text(
"Accent Color:");
2441 if (ImGui::ColorEdit3(
"##AccentPicker", &accent_vec.x,
2442 ImGuiColorEditFlags_NoInputs)) {
2443 accent_picker_color = {accent_vec.x, accent_vec.y, accent_vec.z,
2448 ImGui::Checkbox(
"Dark Mode", &dark_mode_generate);
2451 if (ImGui::Button(absl::StrFormat(
"%s Generate",
ICON_MD_BOLT).c_str(),
2456 edit_theme = generated;
2457 apply_live_preview();
2461 ImGui::Text(
"Preview: ");
2465 Theme preview_theme =
2472 ImGui::ColorButton(
"##prev_primary", prev_primary, 0, ImVec2(24, 24));
2473 ImGui::SameLine(0, 2);
2474 ImGui::ColorButton(
"##prev_secondary", prev_secondary, 0,
2476 ImGui::SameLine(0, 2);
2477 ImGui::ColorButton(
"##prev_bg", prev_bg, 0, ImVec2(24, 24));
2478 ImGui::SameLine(0, 2);
2479 ImGui::ColorButton(
"##prev_surface", prev_surface, 0, ImVec2(24, 24));
2482 ImGui::PopStyleColor();
2486 if (ImGui::BeginTable(
"PrimaryColorsTable", 3,
2487 ImGuiTableFlags_SizingStretchProp)) {
2488 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
2490 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2492 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2494 ImGui::TableHeadersRow();
2497 ImGui::TableNextRow();
2498 ImGui::TableNextColumn();
2499 ImGui::AlignTextToFramePadding();
2500 ImGui::Text(
"Primary:");
2501 ImGui::TableNextColumn();
2503 if (ImGui::ColorEdit3(
"##primary", &primary.x)) {
2504 edit_theme.
primary = {primary.x, primary.y, primary.z, primary.w};
2505 apply_live_preview();
2507 ImGui::TableNextColumn();
2508 ImGui::Button(
"Primary Preview", ImVec2(-1, 30));
2511 ImGui::TableNextRow();
2512 ImGui::TableNextColumn();
2513 ImGui::AlignTextToFramePadding();
2514 ImGui::Text(
"Secondary:");
2515 ImGui::TableNextColumn();
2517 if (ImGui::ColorEdit3(
"##secondary", &secondary.x)) {
2518 edit_theme.
secondary = {secondary.x, secondary.y, secondary.z,
2520 apply_live_preview();
2522 ImGui::TableNextColumn();
2523 ImGui::PushStyleColor(ImGuiCol_Button, secondary);
2524 ImGui::Button(
"Secondary Preview", ImVec2(-1, 30));
2525 ImGui::PopStyleColor();
2528 ImGui::TableNextRow();
2529 ImGui::TableNextColumn();
2530 ImGui::AlignTextToFramePadding();
2531 ImGui::Text(
"Accent:");
2532 ImGui::TableNextColumn();
2534 if (ImGui::ColorEdit3(
"##accent", &accent.x)) {
2535 edit_theme.
accent = {accent.x, accent.y, accent.z, accent.w};
2536 apply_live_preview();
2538 ImGui::TableNextColumn();
2539 ImGui::PushStyleColor(ImGuiCol_Button, accent);
2540 ImGui::Button(
"Accent Preview", ImVec2(-1, 30));
2541 ImGui::PopStyleColor();
2544 ImGui::TableNextRow();
2545 ImGui::TableNextColumn();
2546 ImGui::AlignTextToFramePadding();
2547 ImGui::Text(
"Background:");
2548 ImGui::TableNextColumn();
2550 if (ImGui::ColorEdit4(
"##background", &background.x)) {
2551 edit_theme.
background = {background.x, background.y, background.z,
2553 apply_live_preview();
2555 ImGui::TableNextColumn();
2556 ImGui::Text(
"Background preview shown in window");
2560 ImGui::EndTabItem();
2564 if (ImGui::BeginTabItem(
2566 if (ImGui::BeginTable(
"TextColorsTable", 3,
2567 ImGuiTableFlags_SizingStretchProp)) {
2568 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
2570 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2572 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2574 ImGui::TableHeadersRow();
2577 auto text_colors = std::vector<std::pair<const char*, Color*>>{
2587 for (
auto& [label, color_ptr] : text_colors) {
2588 ImGui::TableNextRow();
2589 ImGui::TableNextColumn();
2590 ImGui::AlignTextToFramePadding();
2591 ImGui::Text(
"%s:", label);
2593 ImGui::TableNextColumn();
2595 std::string
id = absl::StrFormat(
"##%s", label);
2596 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2597 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2598 apply_live_preview();
2601 ImGui::TableNextColumn();
2602 ImGui::PushStyleColor(ImGuiCol_Text, color_vec);
2603 ImGui::Text(
"Sample %s", label);
2604 ImGui::PopStyleColor();
2609 ImGui::EndTabItem();
2613 if (ImGui::BeginTabItem(
2615 if (ImGui::BeginTable(
"InteractiveColorsTable", 3,
2616 ImGuiTableFlags_SizingStretchProp)) {
2617 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2619 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2621 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2623 ImGui::TableHeadersRow();
2626 auto interactive_colors =
2627 std::vector<std::tuple<const char*, Color*, ImGuiCol>>{
2628 {
"Button", &edit_theme.
button, ImGuiCol_Button},
2630 ImGuiCol_ButtonHovered},
2632 ImGuiCol_ButtonActive},
2633 {
"Frame Background", &edit_theme.
frame_bg, ImGuiCol_FrameBg},
2635 ImGuiCol_FrameBgHovered},
2637 ImGuiCol_FrameBgActive},
2638 {
"Check Mark", &edit_theme.
check_mark, ImGuiCol_CheckMark},
2639 {
"Slider Grab", &edit_theme.
slider_grab, ImGuiCol_SliderGrab},
2641 ImGuiCol_SliderGrabActive}};
2643 for (
auto& [label, color_ptr, imgui_col] : interactive_colors) {
2644 ImGui::TableNextRow();
2645 ImGui::TableNextColumn();
2646 ImGui::AlignTextToFramePadding();
2647 ImGui::Text(
"%s:", label);
2649 ImGui::TableNextColumn();
2651 std::string
id = absl::StrFormat(
"##%s", label);
2652 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2653 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2654 apply_live_preview();
2657 ImGui::TableNextColumn();
2658 ImGui::PushStyleColor(imgui_col, color_vec);
2659 ImGui::Button(absl::StrFormat(
"Preview %s", label).c_str(),
2661 ImGui::PopStyleColor();
2666 ImGui::EndTabItem();
2670 if (ImGui::BeginTabItem(
2672 ImGui::Text(
"Rounding and Border Settings:");
2674 if (ImGui::SliderFloat(
"Window Rounding", &edit_theme.
window_rounding,
2679 if (ImGui::SliderFloat(
"Frame Rounding", &edit_theme.
frame_rounding,
2684 if (ImGui::SliderFloat(
"Scrollbar Rounding",
2689 if (ImGui::SliderFloat(
"Tab Rounding", &edit_theme.
tab_rounding, 0.0f,
2694 if (ImGui::SliderFloat(
"Grab Rounding", &edit_theme.
grab_rounding, 0.0f,
2701 ImGui::Text(
"Border Sizes:");
2703 if (ImGui::SliderFloat(
"Window Border Size",
2708 if (ImGui::SliderFloat(
"Frame Border Size",
2715 ImGui::Text(
"Animation & Effects:");
2717 if (ImGui::Checkbox(
"Enable Animations",
2723 if (ImGui::SliderFloat(
"Animation Speed", &edit_theme.
animation_speed,
2725 apply_live_preview();
2728 if (ImGui::Checkbox(
"Enable Glow Effects",
2734 ImGui::EndTabItem();
2738 if (ImGui::BeginTabItem(
2740 if (ImGui::BeginTable(
"NavigationTable", 3,
2741 ImGuiTableFlags_SizingStretchProp)) {
2742 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2744 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2746 ImGui::TableSetupColumn(
"Preview", ImGuiTableColumnFlags_WidthStretch,
2748 ImGui::TableHeadersRow();
2751 auto window_colors =
2752 std::vector<std::tuple<const char*, Color*, const char*>>{
2753 {
"Window Background", &edit_theme.
window_bg,
2754 "Main window background"},
2755 {
"Child Background", &edit_theme.
child_bg,
2756 "Child window background"},
2757 {
"Popup Background", &edit_theme.
popup_bg,
2758 "Popup window background"},
2759 {
"Modal Background", &edit_theme.
modal_bg,
2760 "Modal window background"},
2762 "Menu bar background"}};
2764 for (
auto& [label, color_ptr, description] : window_colors) {
2765 ImGui::TableNextRow();
2766 ImGui::TableNextColumn();
2767 ImGui::AlignTextToFramePadding();
2768 ImGui::Text(
"%s:", label);
2770 ImGui::TableNextColumn();
2772 std::string
id = absl::StrFormat(
"##window_%s", label);
2773 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2774 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2775 apply_live_preview();
2778 ImGui::TableNextColumn();
2779 ImGui::TextWrapped(
"%s", description);
2788 if (ImGui::CollapsingHeader(
"Headers & Tabs",
2789 ImGuiTreeNodeFlags_DefaultOpen)) {
2790 if (ImGui::BeginTable(
"HeaderTabTable", 3,
2791 ImGuiTableFlags_SizingStretchProp)) {
2792 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2794 ImGui::TableSetupColumn(
"Picker",
2795 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2796 ImGui::TableSetupColumn(
"Preview",
2797 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2798 ImGui::TableHeadersRow();
2800 auto header_tab_colors =
2801 std::vector<std::pair<const char*, Color*>>{
2802 {
"Header", &edit_theme.
header},
2805 {
"Tab", &edit_theme.
tab},
2812 {
"Title Background", &edit_theme.
title_bg},
2816 for (
auto& [label, color_ptr] : header_tab_colors) {
2817 ImGui::TableNextRow();
2818 ImGui::TableNextColumn();
2819 ImGui::AlignTextToFramePadding();
2820 ImGui::Text(
"%s:", label);
2822 ImGui::TableNextColumn();
2824 std::string
id = absl::StrFormat(
"##header_%s", label);
2825 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2826 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
2828 apply_live_preview();
2831 ImGui::TableNextColumn();
2832 ImGui::PushStyleColor(ImGuiCol_Button, color_vec);
2833 ImGui::Button(absl::StrFormat(
"Preview %s", label).c_str(),
2835 ImGui::PopStyleColor();
2843 if (ImGui::CollapsingHeader(
"Navigation & Special")) {
2844 if (ImGui::BeginTable(
"NavSpecialTable", 3,
2845 ImGuiTableFlags_SizingStretchProp)) {
2846 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2848 ImGui::TableSetupColumn(
"Picker",
2849 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2850 ImGui::TableSetupColumn(
"Description",
2851 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2852 ImGui::TableHeadersRow();
2854 auto nav_special_colors =
2855 std::vector<std::tuple<const char*, Color*, const char*>>{
2857 "Navigation cursor color"},
2859 "Window selection highlight"},
2861 "Background dimming for navigation"},
2863 "Background dimming for modals"},
2865 "Drag and drop target highlight"},
2867 "Docking area preview"},
2869 "Empty docking space background"}};
2871 for (
auto& [label, color_ptr, description] : nav_special_colors) {
2872 ImGui::TableNextRow();
2873 ImGui::TableNextColumn();
2874 ImGui::AlignTextToFramePadding();
2875 ImGui::Text(
"%s:", label);
2877 ImGui::TableNextColumn();
2879 std::string
id = absl::StrFormat(
"##nav_%s", label);
2880 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2881 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
2883 apply_live_preview();
2886 ImGui::TableNextColumn();
2887 ImGui::TextWrapped(
"%s", description);
2894 ImGui::EndTabItem();
2898 if (ImGui::BeginTabItem(
2900 if (ImGui::BeginTable(
"TablesDataTable", 3,
2901 ImGuiTableFlags_SizingStretchProp)) {
2902 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2904 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
2906 ImGui::TableSetupColumn(
"Description",
2907 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2908 ImGui::TableHeadersRow();
2911 std::vector<std::tuple<const char*, Color*, const char*>>{
2913 "Table column headers"},
2915 "Outer table borders"},
2917 "Inner table borders"},
2919 "Normal table rows"},
2921 "Alternating table rows"},
2923 "Tree view connection lines"}};
2925 for (
auto& [label, color_ptr, description] : table_colors) {
2926 ImGui::TableNextRow();
2927 ImGui::TableNextColumn();
2928 ImGui::AlignTextToFramePadding();
2929 ImGui::Text(
"%s:", label);
2931 ImGui::TableNextColumn();
2933 std::string
id = absl::StrFormat(
"##table_%s", label);
2934 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
2935 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
2936 apply_live_preview();
2939 ImGui::TableNextColumn();
2940 ImGui::TextWrapped(
"%s", description);
2949 if (ImGui::CollapsingHeader(
"Plots & Graphs")) {
2950 if (ImGui::BeginTable(
"PlotsTable", 3,
2951 ImGuiTableFlags_SizingStretchProp)) {
2952 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
2954 ImGui::TableSetupColumn(
"Picker",
2955 ImGuiTableColumnFlags_WidthStretch, 0.6f);
2956 ImGui::TableSetupColumn(
"Description",
2957 ImGuiTableColumnFlags_WidthStretch, 0.4f);
2958 ImGui::TableHeadersRow();
2961 std::vector<std::tuple<const char*, Color*, const char*>>{
2962 {
"Plot Lines", &edit_theme.
plot_lines,
"Line plot color"},
2964 "Line plot hover color"},
2966 "Histogram fill color"},
2967 {
"Plot Histogram Hovered",
2969 "Histogram hover color"}};
2971 for (
auto& [label, color_ptr, description] : plot_colors) {
2972 ImGui::TableNextRow();
2973 ImGui::TableNextColumn();
2974 ImGui::AlignTextToFramePadding();
2975 ImGui::Text(
"%s:", label);
2977 ImGui::TableNextColumn();
2979 std::string
id = absl::StrFormat(
"##plot_%s", label);
2980 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
2981 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
2983 apply_live_preview();
2986 ImGui::TableNextColumn();
2987 ImGui::TextWrapped(
"%s", description);
2994 ImGui::EndTabItem();
2998 if (ImGui::BeginTabItem(
3000 if (ImGui::BeginTable(
"BordersControlsTable", 3,
3001 ImGuiTableFlags_SizingStretchProp)) {
3002 ImGui::TableSetupColumn(
"Element", ImGuiTableColumnFlags_WidthFixed,
3004 ImGui::TableSetupColumn(
"Picker", ImGuiTableColumnFlags_WidthStretch,
3006 ImGui::TableSetupColumn(
"Description",
3007 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3008 ImGui::TableHeadersRow();
3010 auto border_control_colors =
3011 std::vector<std::tuple<const char*, Color*, const char*>>{
3012 {
"Border", &edit_theme.
border,
"General border color"},
3014 "Border shadow/depth"},
3016 "Horizontal/vertical separators"},
3018 "Separator hover state"},
3020 "Separator active/dragged state"},
3022 "Scrollbar track background"},
3024 "Scrollbar handle"},
3026 "Scrollbar handle hover"},
3028 "Scrollbar handle active"},
3030 "Window resize grip"},
3032 "Resize grip hover"},
3034 "Resize grip active"}};
3036 for (
auto& [label, color_ptr, description] : border_control_colors) {
3037 ImGui::TableNextRow();
3038 ImGui::TableNextColumn();
3039 ImGui::AlignTextToFramePadding();
3040 ImGui::Text(
"%s:", label);
3042 ImGui::TableNextColumn();
3044 std::string
id = absl::StrFormat(
"##border_%s", label);
3045 if (ImGui::ColorEdit4(
id.c_str(), &color_vec.x)) {
3046 *color_ptr = {color_vec.x, color_vec.y, color_vec.z, color_vec.w};
3047 apply_live_preview();
3050 ImGui::TableNextColumn();
3051 ImGui::TextWrapped(
"%s", description);
3057 ImGui::EndTabItem();
3061 if (ImGui::BeginTabItem(
3064 "Enhanced semantic colors and editor-specific customization");
3068 if (ImGui::CollapsingHeader(
"Enhanced Semantic Colors",
3069 ImGuiTreeNodeFlags_DefaultOpen)) {
3070 if (ImGui::BeginTable(
"EnhancedSemanticTable", 3,
3071 ImGuiTableFlags_SizingStretchProp)) {
3072 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3074 ImGui::TableSetupColumn(
"Picker",
3075 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3076 ImGui::TableSetupColumn(
"Description",
3077 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3078 ImGui::TableHeadersRow();
3080 auto enhanced_colors =
3081 std::vector<std::tuple<const char*, Color*, const char*>>{
3083 "Code blocks background"},
3085 "Light success variant"},
3087 "Light warning variant"},
3089 "Light error variant"},
3091 "Light info variant"}};
3093 for (
auto& [label, color_ptr, description] : enhanced_colors) {
3094 ImGui::TableNextRow();
3095 ImGui::TableNextColumn();
3096 ImGui::AlignTextToFramePadding();
3097 ImGui::Text(
"%s:", label);
3099 ImGui::TableNextColumn();
3101 std::string
id = absl::StrFormat(
"##enhanced_%s", label);
3102 if (ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
3103 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
3105 apply_live_preview();
3108 ImGui::TableNextColumn();
3109 ImGui::TextWrapped(
"%s", description);
3117 if (ImGui::CollapsingHeader(
"UI State Colors")) {
3118 if (ImGui::BeginTable(
"UIStateTable", 3,
3119 ImGuiTableFlags_SizingStretchProp)) {
3120 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3122 ImGui::TableSetupColumn(
"Picker",
3123 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3124 ImGui::TableSetupColumn(
"Description",
3125 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3126 ImGui::TableHeadersRow();
3129 ImGui::TableNextRow();
3130 ImGui::TableNextColumn();
3131 ImGui::AlignTextToFramePadding();
3132 ImGui::Text(
"Active Selection:");
3133 ImGui::TableNextColumn();
3134 ImVec4 active_selection =
3136 if (ImGui::ColorEdit4(
"##active_selection", &active_selection.x)) {
3138 active_selection.x, active_selection.y, active_selection.z,
3139 active_selection.w};
3140 apply_live_preview();
3142 ImGui::TableNextColumn();
3143 ImGui::TextWrapped(
"Active/selected UI elements");
3145 ImGui::TableNextRow();
3146 ImGui::TableNextColumn();
3147 ImGui::AlignTextToFramePadding();
3148 ImGui::Text(
"Hover Highlight:");
3149 ImGui::TableNextColumn();
3150 ImVec4 hover_highlight =
3152 if (ImGui::ColorEdit4(
"##hover_highlight", &hover_highlight.x)) {
3154 hover_highlight.x, hover_highlight.y, hover_highlight.z,
3156 apply_live_preview();
3158 ImGui::TableNextColumn();
3159 ImGui::TextWrapped(
"General hover state highlighting");
3161 ImGui::TableNextRow();
3162 ImGui::TableNextColumn();
3163 ImGui::AlignTextToFramePadding();
3164 ImGui::Text(
"Focus Border:");
3165 ImGui::TableNextColumn();
3167 if (ImGui::ColorEdit3(
"##focus_border", &focus_border.x)) {
3168 edit_theme.
focus_border = {focus_border.x, focus_border.y,
3169 focus_border.z, focus_border.w};
3170 apply_live_preview();
3172 ImGui::TableNextColumn();
3173 ImGui::TextWrapped(
"Border for focused input elements");
3175 ImGui::TableNextRow();
3176 ImGui::TableNextColumn();
3177 ImGui::AlignTextToFramePadding();
3178 ImGui::Text(
"Disabled Overlay:");
3179 ImGui::TableNextColumn();
3180 ImVec4 disabled_overlay =
3182 if (ImGui::ColorEdit4(
"##disabled_overlay", &disabled_overlay.x)) {
3184 disabled_overlay.x, disabled_overlay.y, disabled_overlay.z,
3185 disabled_overlay.w};
3186 apply_live_preview();
3188 ImGui::TableNextColumn();
3190 "Semi-transparent overlay for disabled elements");
3197 if (ImGui::CollapsingHeader(
"Editor-Specific Colors")) {
3198 if (ImGui::BeginTable(
"EditorColorsTable", 3,
3199 ImGuiTableFlags_SizingStretchProp)) {
3200 ImGui::TableSetupColumn(
"Color", ImGuiTableColumnFlags_WidthFixed,
3202 ImGui::TableSetupColumn(
"Picker",
3203 ImGuiTableColumnFlags_WidthStretch, 0.6f);
3204 ImGui::TableSetupColumn(
"Description",
3205 ImGuiTableColumnFlags_WidthStretch, 0.4f);
3206 ImGui::TableHeadersRow();
3208 auto editor_colors =
3209 std::vector<std::tuple<const char*, Color*, const char*, bool>>{
3211 "Main editor canvas background",
false},
3213 "Grid lines in map/graphics editors",
true},
3215 "Cursor color in editors",
false},
3217 "Selection highlight in editors",
true}};
3219 for (
auto& [label, color_ptr, description, use_alpha] :
3221 ImGui::TableNextRow();
3222 ImGui::TableNextColumn();
3223 ImGui::AlignTextToFramePadding();
3224 ImGui::Text(
"%s:", label);
3226 ImGui::TableNextColumn();
3228 std::string
id = absl::StrFormat(
"##editor_%s", label);
3229 if (use_alpha ? ImGui::ColorEdit4(
id.c_str(), &color_vec.x)
3230 : ImGui::ColorEdit3(
id.c_str(), &color_vec.x)) {
3231 *color_ptr = {color_vec.x, color_vec.y, color_vec.z,
3233 apply_live_preview();
3236 ImGui::TableNextColumn();
3237 ImGui::TextWrapped(
"%s", description);
3244 ImGui::EndTabItem();
3248 if (ImGui::BeginTabItem(
3250 ImGui::Text(
"Control UI density, spacing, and typography scaling");
3254 ImGui::TextColored(ImVec4(0.7f, 0.8f, 1.0f, 1.0f),
"%s Quick Presets",
3259 int current_preset =
static_cast<int>(edit_theme.
density_preset);
3261 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 12));
3262 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 0));
3265 bool is_compact = (current_preset == 0);
3267 ImGui::PushStyleColor(
3276 apply_live_preview();
3279 ImGui::PopStyleColor();
3281 if (ImGui::IsItemHovered()) {
3283 "Dense UI with smaller widgets and tighter spacing\n"
3284 "Best for: Information-dense workflows");
3290 bool is_normal = (current_preset == 1);
3292 ImGui::PushStyleColor(
3297 if (ImGui::Button(absl::StrFormat(
"%s Normal",
ICON_MD_CHECK).c_str(),
3300 apply_live_preview();
3303 ImGui::PopStyleColor();
3305 if (ImGui::IsItemHovered()) {
3307 "Balanced spacing and widget sizes\n"
3308 "Best for: General use");
3314 bool is_comfortable = (current_preset == 2);
3315 if (is_comfortable) {
3316 ImGui::PushStyleColor(
3325 apply_live_preview();
3327 if (is_comfortable) {
3328 ImGui::PopStyleColor();
3330 if (ImGui::IsItemHovered()) {
3332 "Spacious layout with larger click targets\n"
3333 "Best for: Touch screens, accessibility");
3336 ImGui::PopStyleVar(2);
3343 if (ImGui::CollapsingHeader(
"Advanced Density Controls")) {
3346 ImGui::Text(
"Fine-tune individual spacing multipliers:");
3350 if (ImGui::SliderFloat(
"Compact Factor", &edit_theme.
compact_factor,
3351 0.5f, 1.5f,
"%.2f")) {
3352 apply_live_preview();
3354 if (ImGui::IsItemHovered()) {
3356 "Global density multiplier (0.5 = very compact, "
3357 "1.5 = very spacious)");
3363 if (ImGui::SliderFloat(
"Widget Height",
3366 apply_live_preview();
3371 0.5f, 1.5f,
"%.2f")) {
3372 apply_live_preview();
3376 if (ImGui::SliderFloat(
"Toolbar Height",
3379 apply_live_preview();
3383 if (ImGui::SliderFloat(
"Panel Padding",
3386 apply_live_preview();
3390 if (ImGui::SliderFloat(
"Button Padding",
3393 apply_live_preview();
3397 if (ImGui::SliderFloat(
"Table Row Height",
3400 apply_live_preview();
3407 if (ImGui::CollapsingHeader(
"Corner Rounding")) {
3410 if (ImGui::SliderFloat(
"Window Rounding", &edit_theme.
window_rounding,
3411 0.0f, 20.0f,
"%.1f")) {
3412 apply_live_preview();
3415 if (ImGui::SliderFloat(
"Frame Rounding", &edit_theme.
frame_rounding,
3416 0.0f, 12.0f,
"%.1f")) {
3417 apply_live_preview();
3420 if (ImGui::SliderFloat(
"Tab Rounding", &edit_theme.
tab_rounding, 0.0f,
3422 apply_live_preview();
3425 if (ImGui::SliderFloat(
"Scrollbar Rounding",
3428 apply_live_preview();
3431 if (ImGui::SliderFloat(
"Grab Rounding", &edit_theme.
grab_rounding,
3432 0.0f, 12.0f,
"%.1f")) {
3433 apply_live_preview();
3440 if (ImGui::CollapsingHeader(
"Animation Settings")) {
3443 if (ImGui::Checkbox(
"Enable Animations",
3445 apply_live_preview();
3449 if (ImGui::SliderFloat(
"Animation Speed",
3452 apply_live_preview();
3456 if (ImGui::Checkbox(
"Enable Glow Effects",
3458 apply_live_preview();
3464 ImGui::EndTabItem();
3472 if (ImGui::Button(
"Preview Theme")) {
3477 if (ImGui::Button(
"Reset to Current")) {
3483 theme_name[name_len] =
'\0';
3486 sizeof(theme_description) - 1);
3489 theme_description[desc_len] =
'\0';
3494 theme_author[author_len] =
'\0';
3497 if (theme_backup_made) {
3498 theme_backup_made =
false;
3505 if (ImGui::Button(
"Save Theme")) {
3506 edit_theme.
name = std::string(theme_name);
3507 edit_theme.
description = std::string(theme_description);
3508 edit_theme.
author = std::string(theme_author);
3515 theme_backup_made =
false;
3522 bool can_save_over = !current_file_path.empty();
3524 if (!can_save_over) {
3525 ImGui::BeginDisabled();
3528 if (ImGui::Button(
"Save Over Current")) {
3529 edit_theme.
name = std::string(theme_name);
3530 edit_theme.
description = std::string(theme_description);
3531 edit_theme.
author = std::string(theme_author);
3541 LOG_ERROR(
"Theme Manager",
"Failed to save over current theme");
3545 if (!can_save_over) {
3546 ImGui::EndDisabled();
3549 if (ImGui::IsItemHovered() && can_save_over) {
3550 ImGui::BeginTooltip();
3551 ImGui::Text(
"Save over current theme file:");
3552 ImGui::Text(
"%s", current_file_path.c_str());
3553 ImGui::EndTooltip();
3554 }
else if (ImGui::IsItemHovered()) {
3555 ImGui::BeginTooltip();
3556 ImGui::Text(
"No current theme file to overwrite");
3557 ImGui::Text(
"Use 'Save to File...' to create a new theme file");
3558 ImGui::EndTooltip();
3562 if (ImGui::Button(
"Save to File...")) {
3563 edit_theme.
name = std::string(theme_name);
3564 edit_theme.
description = std::string(theme_description);
3565 edit_theme.
author = std::string(theme_author);
3568 std::string safe_name =
3569 edit_theme.
name.empty() ?
"custom_theme" : edit_theme.
name;
3573 if (!file_path.empty()) {
3575 if (file_path.find(
".theme") == std::string::npos) {
3576 file_path +=
".theme";
3585 LOG_ERROR(
"Theme Manager",
"Failed to save theme");
3590 if (ImGui::IsItemHovered()) {
3591 ImGui::BeginTooltip();
3592 ImGui::Text(
"Save theme to a .theme file");
3593 ImGui::Text(
"Saved themes can be shared and loaded later");
3594 ImGui::EndTooltip();