#include "theme.h" #include "imgui.h" #include "json/value.h" #include "translation.h" #include #include #include #include #include #include #include "IconsForkAwesome.h" using namespace std::filesystem; using namespace std::numbers; const char* Theme::prefPath = NULL; path Theme::themeDir = path(); std::set Theme::availableThemes = std::set(); ImVec4 change_accent_color(ImVec4 in, float hue) { if (in.x == in.y && in.y == in.z) { return in; } ImVec4 hsv = in; ImVec4 out = in; ImGui::ColorConvertRGBtoHSV(in.x, in.y, in.z, hsv.x, hsv.y, hsv.z); hsv.x = hue / 360.0f; ImGui::ColorConvertHSVtoRGB(hsv.x, hsv.y, hsv.z, out.x, out.y, out.z); return out; } bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_width, int window_height) { static FileBrowser importDialog(false, ImGuiFileBrowserFlags_NoTitleBar|ImGuiFileBrowserFlags_NoMove|ImGuiFileBrowserFlags_NoResize); static FileBrowser exportDialog(true, ImGuiFileBrowserFlags_NoTitleBar|ImGuiFileBrowserFlags_NoMove|ImGuiFileBrowserFlags_NoResize); static bool loadOpen = false; static bool saveAsOpen = false; ImGui::SetNextWindowDockID(dockid); ImGui::Begin(_TRI_CTX(ICON_FK_MAGIC, "Window title", "Theme Editor"), open); ImGuiStyle& style = theme->style; ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); ImVec2 buttonSize = ImVec2((ImGui::GetWindowWidth() * 0.50f) - (ImGui::GetStyle().WindowPadding.x) - (ImGui::GetStyle().ItemSpacing.x * 0.5f), 0); if (ImGui::Button(_TR_CTX("Theme Editor > preset button", "Create light"), buttonSize)) { delete theme; theme = new Theme(false); ImGui::PopItemWidth(); ImGui::End(); return true; } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > preset button", "Create dark"), buttonSize)) { delete theme; theme = new Theme(true); ImGui::PopItemWidth(); ImGui::End(); return true; } if (ImGui::Button(_TR_CTX("Theme Editor > import button. Opens the theme import file dialog", "Import..."), buttonSize)) { importDialog.SetTitle(_TR_CTX("Theme Editor file dialog title", "Import theme...")); importDialog.SetTypeFilters(_TR_CTX("Theme Editor file dialog filter name", "Theme JSON files"), { ".json"}); std::string userdir = std::getenv( #ifdef _WIN32 "UserProfile" #else "HOME" #endif ); importDialog.SetPwd(userdir); importDialog.Open(); } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > export button. Opens the theme export file dialog", "Export..."), buttonSize)) { exportDialog.SetTitle(_TR_CTX("Theme Editor file dialog title", "Export theme...")); exportDialog.SetTypeFilters(_TR_CTX("Theme Editor file dialog filter name", "Theme JSON files"), { ".json"}); std::string userdir = std::getenv( #ifdef _WIN32 "UserProfile" #else "HOME" #endif ); exportDialog.SetPwd(userdir); exportDialog.Open(); } if (importDialog.IsOpened()) { importDialog.SetWindowSize(window_width, window_height); importDialog.SetWindowPos(0, 0); } if (exportDialog.IsOpened()) { exportDialog.SetWindowSize(window_width, window_height); exportDialog.SetWindowPos(0, 0); } importDialog.Display(); exportDialog.Display(); if (!theme->file_path.empty()) { if (ImGui::Button(_TR_CTX("Theme Editor > button. Reverts to saved file.", "Revert"), buttonSize)) { string file_path_backup = theme->file_path; delete theme; theme = new Theme(file_path_backup); ImGui::PopItemWidth(); ImGui::End(); return true; } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > button. Saves the theme to it's current location. Not shown when it doesn't already have one.", "Save"), buttonSize)) { theme->Save(theme->file_path); } } if (ImGui::Button(_TR_CTX("Theme Editor > button. Opens the theme loading dialog for themes created or imported by the user.", "Load..."), buttonSize)) { loadOpen = true; } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > button. Opens the theme saving dialog for themes created or imported by the user.", "Save as..."), buttonSize)) { saveAsOpen = true; } // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) if (ImGui::SliderFloat(_TR_CTX("Theme Editor > slider. Simplified frame rounding.", "Frame Rounding"), &style.FrameRounding, 0.0f, 12.0f, "%.0f")) style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox(_TR_CTX("Theme Editor > checkbox", "Window Border"), &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } ImGui::SameLine(); { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox(_TR_CTX("Theme Editor > checkbox", "Frame Border"), &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } ImGui::SameLine(); { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox(_TR_CTX("Theme Editor > checkbox", "Popup Border"), &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } ImGui::Separator(); if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) { if (ImGui::BeginTabItem(_TR_CTX("Theme Editor > Tab label", "Sizes"))) { ImGui::SeparatorText(_TR_CTX("Theme Editor > Sizes > Section label", "Sizing")); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Window Padding"), (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Frame Padding"), (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Cell Padding"), (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Item Spacing"), (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Inner Item Spacing"), (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); //ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); //ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Sizing > slider label", "IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Sizing > slider label", "Scrollbar Size"), &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Sizing > slider label", "Minimum Grabber Size"), &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat2(_TR_CTX("Theme Editor > Sizes > Sizing > label of XY sliders", "Separator Text Padding"), (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); ImGui::SeparatorText(_TR_CTX("Theme Editor > Sizes > Section label", "Borders")); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Window Border Size"), &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Child Border Size"), &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Popup Border Size"), &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Frame Border Size"), &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Tab Border Size"), &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Borders > slider label", "Separator Text Border Size"), &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); ImGui::SeparatorText(_TR_CTX("Theme Editor > Sizes > Section label", "Rounding")); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Window Rounding"), &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Child Rounding"), &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Frame Rounding"), &style.FrameRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Popup Rounding"), &style.PopupRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Scrollbar Rounding"), &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Grabber Rounding"), &style.GrabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat(_TR_CTX("Theme Editor > Sizes > Rounding > slider label", "Tab Rounding"), &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::EndTabItem(); } if (ImGui::BeginTabItem(_TR_CTX("Theme Editor > Tab label", "Colors"))) { static ImGuiTextFilter filter; filter.Draw(_TR_CTX("Theme Editor > Colors > text filter", "Filter colors"), ImGui::GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; if (ImGui::RadioButton(_TR_CTX("Theme Editor > Colors > preview settings radio button", "Opaque"), alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); if (ImGui::RadioButton(_TR_CTX("Theme Editor > Colors > preview settings radio button", "Alpha"), alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); if (ImGui::RadioButton(_TR_CTX("Theme Editor > Colors > preview settings radio button", "Both"), alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); ImGui::PushItemWidth(-160); for (int i = 0; i < ImGuiCol_COUNT; i++) { const char* name = ImGui::GetStyleColorName(i); if (!filter.PassFilter(name)) continue; ImGui::PushID(i); bool hueEnabled = theme->HueEnabledColors.contains(i); if (ImGui::Checkbox(_TR_CTX("Theme Editor > Colors > (Any color) > recoloring checkbox", "Match hue preference"), &hueEnabled)) { if (hueEnabled) { theme->HueEnabledColors.insert(i); } else { theme->HueEnabledColors.erase(i); } } ImGui::SameLine(); ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV); ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); ImGui::TextUnformatted(name); ImGui::PopID(); } ImGui::PopItemWidth(); ImGui::EndChild(); ImGui::EndTabItem(); } ImGui::EndTabBar(); } ImGui::PopItemWidth(); ImGui::End(); if (importDialog.HasSelected()) { path selected_path = importDialog.GetSelected(); path filename = selected_path.filename(); copy_file(selected_path, theme->themeDir / filename); Theme::updateAvailableThemes(); importDialog.ClearSelected(); } if (exportDialog.HasSelected()) { path selected_path = exportDialog.GetSelected(); theme->Save(selected_path); exportDialog.ClearSelected(); } if (loadOpen) { ImGui::OpenPopup(_TR_CTX("Theme Editor > Custom modal dialog title", "Load...")); ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); if (ImGui::BeginPopupModal(_TR_CTX("Theme Editor > Custom modal dialog title", "Load..."), nullptr, ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize)) { static path selectedThemePath; static char filter[1024] = {0}; ImGui::Text(_TR_CTX("Theme Editor > Load dialog > Theme selector > filter label", "Filter:")); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x); ImGui::InputText("##FilterInput", filter, 1024); ImGui::Text(_TR_CTX("Theme Editor > Load dialog > Theme selector > label", "Available themes...")); if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) { for (auto themePath : Theme::availableThemes) { if (themePath.stem().string().starts_with(filter)) { const bool is_selected = themePath == selectedThemePath; if (ImGui::Selectable(themePath.stem().generic_string().c_str(), is_selected)) { selectedThemePath = themePath; } if (is_selected) { ImGui::SetItemDefaultFocus(); } } } ImGui::EndListBox(); } if (ImGui::Button(_TR_CTX("Theme Editor > Load dialog > Load button", "Load"))) { if (!selectedThemePath.empty()) { filter[0] = '\0'; loadOpen = false; delete theme; theme = new Theme(selectedThemePath); selectedThemePath = path(); ImGui::EndPopup(); return true; } } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > Load dialog > Cancel button", "Cancel"))) { selectedThemePath = path(); filter[0] = '\0'; loadOpen = false; } ImGui::EndPopup(); } } if (saveAsOpen) { ImGui::OpenPopup(_TR_CTX("Theme Editor > Custom modal dialog title", "Save as...")); ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); if (ImGui::BeginPopupModal(_TR_CTX("Theme Editor > Custom modal dialog title", "Save as..."), nullptr, ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize)) { static char selectedThemeName[1024] = {0}; static char filter[1024] = {0}; ImGui::Text(_TR_CTX("Theme Editor > Save as dialog > Theme selector > filter label", "Filter:")); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - ImGui::GetStyle().WindowPadding.x); ImGui::InputText("##FilterInput", filter, 1024); ImGui::Text(_TR_CTX("Theme Editor > Save as dialog > Theme selector > label", "Available themes...")); if (ImGui::BeginListBox("##Themes", ImVec2(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f), -ImGui::GetFrameHeightWithSpacing() - ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().WindowPadding.y))) { for (auto themePath : Theme::availableThemes) { if (themePath.stem().string().starts_with(filter)) { const bool is_selected = strcmp(themePath.stem().generic_string().c_str(), selectedThemeName) == 0; if (ImGui::Selectable(themePath.stem().generic_string().c_str(), is_selected)) { strncpy(selectedThemeName, themePath.stem().generic_string().c_str(), 1023); } if (is_selected) { ImGui::SetItemDefaultFocus(); } } } ImGui::EndListBox(); } ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - (ImGui::GetStyle().WindowPadding.x * 2.0f)); ImGui::InputText(_TR_CTX("Theme Editor > Save as dialog > Theme name input label", "Theme name: "), selectedThemeName, 1024); if (ImGui::Button(_TR_CTX("Theme Editor > Save as dialog > Save button", "Save"))) { path selectedThemePath(selectedThemeName); if (!selectedThemePath.empty() && !selectedThemePath.is_absolute()) { selectedThemeName[0] = '\0'; // This empties the string by taking advantage of C strings. filter[0] = '\0'; saveAsOpen = false; theme->Save(Theme::themeDir / selectedThemePath.replace_extension(".json")); theme->file_path = selectedThemePath.generic_string(); } } ImGui::SameLine(); if (ImGui::Button(_TR_CTX("Theme Editor > Save as dialog > Cancel button", "Cancel"))) { selectedThemeName[0] = '\0'; // Same as above filter[0] = '\0'; saveAsOpen = false; } ImGui::EndPopup(); } } return false; } void Theme::Apply(float hue) { ImGuiStyle& actual_style = ImGui::GetStyle(); actual_style = style; for (int i = 0; i < ImGuiCol_COUNT; i++) { if (HueEnabledColors.contains(i)) { actual_style.Colors[i] = change_accent_color(style.Colors[i], hue); } } ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { actual_style.WindowRounding = 0.0f; actual_style.Colors[ImGuiCol_WindowBg].w = 1.0f; } } void Theme::Save(string path) { printf("Saving theme to %s...\n", path.c_str()); { Json::Value config; std::ofstream stream; stream.open(path); { Json::Value metadata; metadata["SchemaVersion"] = 1; { Json::Value stringsList; for (auto kv : strings) { Json::Value stringsEntry; string language = kv.first; ThemeStrings strings = kv.second; stringsEntry["Name"] = strings.name; stringsEntry["Description"] = strings.description; stringsList[language] = stringsEntry; } metadata["Strings"] = stringsList; } config["meta"] = metadata; } { Json::Value rounding; rounding["Frame"] = style.FrameRounding; rounding["Window"] = style.WindowRounding; rounding["Child"] = style.ChildRounding; rounding["Popup"] = style.PopupRounding; rounding["Scrollbar"] = style.ScrollbarRounding; rounding["Grab"] = style.GrabRounding; rounding["Tab"] = style.TabRounding; config["rounding"] = rounding; } { Json::Value sizing; sizing["FrameX"] = style.FramePadding.x; sizing["FrameY"] = style.FramePadding.y; sizing["WindowX"] = style.WindowPadding.x; sizing["WindowY"] = style.WindowPadding.y; sizing["CellX"] = style.CellPadding.x; sizing["CellY"] = style.CellPadding.y; sizing["SeparatorTextX"] = style.SeparatorTextPadding.x; sizing["SeparatorTextY"] = style.SeparatorTextPadding.y; sizing["ItemSpacingX"] = style.ItemSpacing.x; sizing["ItemSpacingY"] = style.ItemSpacing.y; sizing["Scrollbar"] = style.ScrollbarSize; sizing["Grab"] = style.GrabMinSize; config["sizing"] = sizing; } { Json::Value borders; borders["Frame"] = style.FrameBorderSize; borders["Window"] = style.WindowBorderSize; borders["Child"] = style.ChildBorderSize; borders["Popup"] = style.PopupBorderSize; borders["Tab"] = style.TabBorderSize; borders["Tab"] = style.TabBorderSize; borders["SeparatorText"] = style.SeparatorTextBorderSize; config["borders"] = borders; } { Json::Value colors; for (int i = 0; i < ImGuiCol_COUNT; i++) { const char* name = ImGui::GetStyleColorName(i); ImVec4 color = style.Colors[i]; Json::Value colorValue; colorValue["r"] = color.x; colorValue["g"] = color.y; colorValue["b"] = color.z; colorValue["a"] = color.w; colorValue["ConvertToAccent"] = HueEnabledColors.contains(i); colors[name] = colorValue; } config["colors"] = colors; } stream << config; stream.close(); } updateAvailableThemes(); } void Theme::Save(path path) { Save((string)path.string()); } void Theme::updateAvailableThemes() { themeDir = path(prefPath) / path("themes"); create_directories(themeDir); availableThemes.clear(); for (auto const& dir_entry : directory_iterator(themeDir)) { if (dir_entry.is_regular_file()) { if (dir_entry.path().extension().string() == ".json") { availableThemes.insert(dir_entry.path()); } } } } Theme::Theme() { if (prefPath == NULL) { throw std::exception(); } updateAvailableThemes(); } Theme::Theme(bool dark) : Theme() { if (dark) { ImGui::StyleColorsDark(&style); } else { ImGui::StyleColorsLight(&style); style.FrameBorderSize = 1; } for (int i = 0; i < ImGuiCol_COUNT; i++) { ImVec4 color = style.Colors[i]; if (color.x != color.y || color.y != color.z) { HueEnabledColors.insert(i); } } style.FrameRounding = 12; style.GrabRounding = 12; style.WindowRounding = 12; } ThemeStrings::ThemeStrings() { name = _TRS_CTX("Theme default strings > name", "A theme"); description = _TRS_CTX("Theme default strings > description", "(No description)"); } Theme::Theme(string path) : Theme() { Json::Value config; std::ifstream stream; stream.open(path); if (stream.is_open()) { stream >> config; if (config.isMember("meta")) { Json::Value metadata = config["meta"]; //metadata["SchemaVersion"] = 1; if (metadata.isMember("Strings")) { Json::Value stringsList = metadata["Strings"]; for (string language : stringsList.getMemberNames()) { Json::Value stringsEntry = stringsList[language]; ThemeStrings strings; if (stringsEntry.isMember("Name")) { strings.name = stringsEntry["Name"].asString(); } if (stringsEntry.isMember("Description")) { strings.description = stringsEntry["Description"].asString(); } } } } if (config.isMember("rounding")) { Json::Value rounding = config["rounding"]; style.FrameRounding = rounding["Frame"].asFloat(); style.WindowRounding = rounding["Window"].asFloat(); style.ChildRounding = rounding["Child"].asFloat(); style.PopupRounding = rounding["Popup"].asFloat(); style.ScrollbarRounding = rounding["Scrollbar"].asFloat(); style.GrabRounding = rounding["Grab"].asFloat(); style.TabRounding = rounding["Tab"].asFloat(); } if (config.isMember("sizing")) { Json::Value sizing = config["sizing"]; style.FramePadding.x = sizing["FrameX"].asFloat(); style.FramePadding.y = sizing["FrameY"].asFloat(); style.WindowPadding.x = sizing["WindowX"].asFloat(); style.WindowPadding.y = sizing["WindowY"].asFloat(); style.CellPadding.x = sizing["CellX"].asFloat(); style.CellPadding.y = sizing["CellY"].asFloat(); style.SeparatorTextPadding.x = sizing["SeparatorTextX"].asFloat(); style.SeparatorTextPadding.y = sizing["SeparatorTextY"].asFloat(); style.ItemSpacing.x = sizing["ItemSpacingX"].asFloat(); style.ItemSpacing.y = sizing["ItemSpacingY"].asFloat(); style.ScrollbarSize = sizing["Scrollbar"].asFloat(); style.GrabMinSize = sizing["Grab"].asFloat(); } if (config.isMember("borders")) { Json::Value borders = config["borders"]; style.FrameBorderSize = borders["Frame"].asFloat(); style.WindowBorderSize = borders["Window"].asFloat(); style.ChildBorderSize = borders["Child"].asFloat(); style.PopupBorderSize = borders["Popup"].asFloat(); style.TabBorderSize = borders["Tab"].asFloat(); if (borders.isMember("SeparatorText")) { style.SeparatorTextBorderSize = borders["SeparatorText"].asFloat(); } } if (config.isMember("colors")) { Json::Value colors = config["colors"]; for (int i = 0; i < ImGuiCol_COUNT; i++) { const char* name = ImGui::GetStyleColorName(i); if (colors.isMember(name)) { Json::Value colorValue = colors[name]; ImVec4 color = ImVec4(colorValue["r"].asFloat(), colorValue["g"].asFloat(), colorValue["b"].asFloat(), colorValue["a"].asFloat()); bool hueShifted = colorValue["ConvertToAccent"].asBool(); style.Colors[i] = color; if (hueShifted) { HueEnabledColors.insert(i); } } } } stream.close(); } file_path = path; } Theme::Theme(path path) : Theme(path.string()) { }