2023-07-09 18:56:12 -07:00
# include "theme.h"
# include "imgui.h"
# include "json/value.h"
2023-12-22 14:13:48 -08:00
# include "thirdparty/toml.hpp"
2024-04-25 11:23:38 -07:00
# include <translation.hpp>
2023-07-09 18:56:12 -07:00
# include <cmath>
# include <exception>
# include <iostream>
# include <fstream>
# include <filesystem>
2023-07-25 07:56:56 -07:00
# include <functional>
2023-07-20 14:45:35 -07:00
# include "IconsForkAwesome.h"
2023-07-25 07:56:56 -07:00
# include "imgui_stdlib.h"
2024-03-23 18:41:26 -07:00
# include <log.hpp>
2024-05-01 09:07:08 -07:00
# include <util.hpp>
# include <web_functions.hpp>
2023-07-09 18:56:12 -07:00
using namespace std : : filesystem ;
const char * Theme : : prefPath = NULL ;
2023-07-10 19:27:55 -07:00
path Theme : : themeDir = path ( ) ;
std : : set < path > Theme : : availableThemes = std : : set < path > ( ) ;
2023-07-25 07:56:56 -07:00
std : : map < path , ThemeStrings > Theme : : themeStrings = std : : map < path , ThemeStrings > ( ) ;
2023-07-11 10:18:51 -07:00
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 ;
}
2023-07-17 15:45:43 -07:00
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 ) ;
2023-07-10 19:27:55 -07:00
static bool loadOpen = false ;
static bool saveAsOpen = false ;
2023-07-17 15:45:43 -07:00
ImGui : : SetNextWindowDockID ( dockid ) ;
2023-07-24 23:13:47 -07:00
ImGui : : Begin ( _TRI_CTX ( ICON_FK_MAGIC , " Window title " , " Theme Editor " ) , open ) ;
2023-07-10 19:27:55 -07:00
ImGuiStyle & style = theme - > style ;
2023-07-09 18:56:12 -07:00
ImGui : : PushItemWidth ( ImGui : : GetWindowWidth ( ) * 0.50f ) ;
2023-07-10 19:27:55 -07:00
ImVec2 buttonSize = ImVec2 ( ( ImGui : : GetWindowWidth ( ) * 0.50f ) - ( ImGui : : GetStyle ( ) . WindowPadding . x ) - ( ImGui : : GetStyle ( ) . ItemSpacing . x * 0.5f ) , 0 ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | preset button " , " Create light " ) , buttonSize ) ) {
2023-07-09 18:56:12 -07:00
delete theme ;
theme = new Theme ( false ) ;
ImGui : : PopItemWidth ( ) ;
ImGui : : End ( ) ;
return true ;
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | preset button " , " Create dark " ) , buttonSize ) ) {
2023-07-09 18:56:12 -07:00
delete theme ;
theme = new Theme ( true ) ;
ImGui : : PopItemWidth ( ) ;
ImGui : : End ( ) ;
return true ;
}
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | import button. Opens the theme import file dialog " , " Import... " ) , buttonSize ) ) {
2023-07-24 23:13:47 -07:00
importDialog . SetTitle ( _TR_CTX ( " Theme Editor file dialog title " , " Import theme... " ) ) ;
2024-01-21 15:21:18 -08:00
importDialog . SetTypeFilters ( _TR_CTX ( " Theme Editor file dialog filter name " , " Theme JSON files " ) , { " .toml " } ) ;
2023-07-09 18:56:12 -07:00
std : : string userdir = std : : getenv (
# ifdef _WIN32
" UserProfile "
# else
" HOME "
# endif
) ;
importDialog . SetPwd ( userdir ) ;
importDialog . Open ( ) ;
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | export button. Opens the theme export file dialog " , " Export... " ) , buttonSize ) ) {
2023-07-24 23:13:47 -07:00
exportDialog . SetTitle ( _TR_CTX ( " Theme Editor file dialog title " , " Export theme... " ) ) ;
2024-01-21 15:21:18 -08:00
exportDialog . SetTypeFilters ( _TR_CTX ( " Theme Editor file dialog filter name " , " Theme JSON files " ) , { " .toml " } ) ;
2023-07-09 18:56:12 -07:00
std : : string userdir = std : : getenv (
# ifdef _WIN32
" UserProfile "
# else
" HOME "
# endif
) ;
exportDialog . SetPwd ( userdir ) ;
exportDialog . Open ( ) ;
}
2023-07-17 15:45:43 -07:00
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 ) ;
}
2023-07-09 18:56:12 -07:00
importDialog . Display ( ) ;
exportDialog . Display ( ) ;
2023-07-10 19:27:55 -07:00
if ( ! theme - > file_path . empty ( ) ) {
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | button. Reverts to saved file. " , " Revert " ) , buttonSize ) ) {
2023-07-10 19:27:55 -07:00
string file_path_backup = theme - > file_path ;
2023-07-09 18:56:12 -07:00
delete theme ;
theme = new Theme ( file_path_backup ) ;
ImGui : : PopItemWidth ( ) ;
ImGui : : End ( ) ;
return true ;
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
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 ) ) {
2023-07-10 19:27:55 -07:00
theme - > Save ( theme - > file_path ) ;
2023-07-09 18:56:12 -07:00
}
}
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | button. Opens the theme loading dialog for themes created or imported by the user. " , " Load... " ) , buttonSize ) ) {
2023-07-09 18:56:12 -07:00
loadOpen = true ;
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | button. Opens the theme saving dialog for themes created or imported by the user. " , " Save as... " ) , buttonSize ) ) {
2023-07-09 18:56:12 -07:00
saveAsOpen = true ;
}
// Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
2023-07-25 14:33:29 -07:00
if ( ImGui : : SliderFloat ( _TR_CTX ( " Theme Editor | slider. Simplified frame rounding. " , " Frame Rounding " ) , & style . FrameRounding , 0.0f , 12.0f , " %.0f " ) )
2023-07-09 18:56:12 -07:00
style . GrabRounding = style . FrameRounding ; // Make GrabRounding always the same value as FrameRounding
2023-07-25 14:33:29 -07:00
{ bool border = ( style . WindowBorderSize > 0.0f ) ; if ( ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | checkbox " , " Window Border " ) , & border ) ) { style . WindowBorderSize = border ? 1.0f : 0.0f ; } }
2023-07-09 18:56:12 -07:00
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
{ bool border = ( style . FrameBorderSize > 0.0f ) ; if ( ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | checkbox " , " Frame Border " ) , & border ) ) { style . FrameBorderSize = border ? 1.0f : 0.0f ; } }
2023-07-09 18:56:12 -07:00
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
{ bool border = ( style . PopupBorderSize > 0.0f ) ; if ( ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | checkbox " , " Popup Border " ) , & border ) ) { style . PopupBorderSize = border ? 1.0f : 0.0f ; } }
2023-07-09 18:56:12 -07:00
ImGui : : Separator ( ) ;
if ( ImGui : : BeginTabBar ( " ##tabs " , ImGuiTabBarFlags_None ) )
{
2023-07-25 14:33:29 -07:00
if ( ImGui : : BeginTabItem ( _TR_CTX ( " Theme Editor | Tab label " , " Strings " ) ) )
2023-07-25 07:56:56 -07:00
{
2023-07-25 14:33:29 -07:00
ImGui : : InputText ( _TR_CTX ( " Theme Editor | Strings | Name input label " , " Name " ) , & theme - > strings [ " fallback " ] . name ) ;
ImGui : : InputText ( _TR_CTX ( " Theme Editor | Strings | Description input label " , " Description " ) , & theme - > strings [ " fallback " ] . description ) ;
2023-07-25 07:56:56 -07:00
ImGui : : EndTabItem ( ) ;
}
2023-07-25 14:33:29 -07:00
if ( ImGui : : BeginTabItem ( _TR_CTX ( " Theme Editor | Tab label " , " Sizes " ) ) )
2023-07-09 18:56:12 -07:00
{
2023-07-25 14:33:29 -07:00
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 " ) ;
2023-07-09 18:56:12 -07:00
2023-07-25 14:33:29 -07:00
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 " ) ;
2023-07-09 18:56:12 -07:00
2023-07-25 14:33:29 -07:00
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 " ) ;
2023-07-09 18:56:12 -07:00
ImGui : : EndTabItem ( ) ;
}
2023-07-25 14:33:29 -07:00
if ( ImGui : : BeginTabItem ( _TR_CTX ( " Theme Editor | Tab label " , " Colors " ) ) )
2023-07-09 18:56:12 -07:00
{
static ImGuiTextFilter filter ;
2023-07-25 14:33:29 -07:00
filter . Draw ( _TR_CTX ( " Theme Editor | Colors | text filter " , " Filter colors " ) , ImGui : : GetFontSize ( ) * 16 ) ;
2023-07-09 18:56:12 -07:00
static ImGuiColorEditFlags alpha_flags = 0 ;
2023-07-25 14:33:29 -07:00
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 ; }
2023-07-09 18:56:12 -07:00
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 ) ;
2023-10-16 10:44:25 -07:00
AccentColorizer & colorizer = theme - > AccentColorizers [ i ] ;
2024-04-10 13:27:07 -07:00
ImGui : : TextUnformatted ( _TR_CTX ( " Theme Editor | Colors | (Any color) | recoloring label " , " Match accent color preference: " ) ) ;
2023-10-16 10:44:25 -07:00
ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | Colors | (Any color) | recoloring checkbox | Hue " , " H: " ) , & colorizer . Hue ) ; ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | Colors | (Any color) | recoloring checkbox | Saturation " , " S: " ) , & colorizer . Saturation ) ; ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | Colors | (Any color) | recoloring checkbox | Value " , " V: " ) , & colorizer . Value ) ; ImGui : : SameLine ( ) ;
ImGui : : Checkbox ( _TR_CTX ( " Theme Editor | Colors | (Any color) | recoloring checkbox | Alpha (opacity) " , " A: " ) , & colorizer . Alpha ) ; ImGui : : SameLine ( ) ;
2023-07-11 10:18:51 -07:00
ImGui : : ColorEdit4 ( " ##color " , ( float * ) & style . Colors [ i ] , ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV ) ;
ImGui : : SameLine ( 0.0f , style . ItemInnerSpacing . x ) ;
ImGui : : TextUnformatted ( name ) ;
2023-07-09 18:56:12 -07:00
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 ( ) ;
2023-07-10 19:27:55 -07:00
copy_file ( selected_path , theme - > themeDir / filename ) ;
2023-07-17 13:23:02 -07:00
Theme : : updateAvailableThemes ( ) ;
2023-07-17 12:55:13 -07:00
importDialog . ClearSelected ( ) ;
2023-07-09 18:56:12 -07:00
}
if ( exportDialog . HasSelected ( ) ) {
2023-07-17 12:55:13 -07:00
path selected_path = exportDialog . GetSelected ( ) ;
2023-07-10 19:27:55 -07:00
theme - > Save ( selected_path ) ;
2023-07-17 12:55:13 -07:00
exportDialog . ClearSelected ( ) ;
2023-07-09 18:56:12 -07:00
}
if ( loadOpen ) {
2023-07-25 14:33:29 -07:00
ImGui : : OpenPopup ( _TR_CTX ( " Theme Editor | Custom modal dialog title " , " Load... " ) ) ;
2023-07-17 15:55:19 -07:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( window_width , window_height ) ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : BeginPopupModal ( _TR_CTX ( " Theme Editor | Custom modal dialog title " , " Load... " ) , nullptr , ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize ) ) {
2023-07-17 15:55:19 -07:00
static path selectedThemePath ;
2023-07-25 07:56:56 -07:00
static string filter = " " ;
2024-04-10 13:27:07 -07:00
ImGui : : TextUnformatted ( _TR_CTX ( " Theme Editor | Load dialog | Theme selector | filter label " , " Filter: " ) ) ; ImGui : : SameLine ( ) ;
2023-07-17 15:55:19 -07:00
ImGui : : SetNextItemWidth ( ImGui : : GetWindowWidth ( ) - ImGui : : GetCursorPosX ( ) - ImGui : : GetStyle ( ) . WindowPadding . x ) ;
2023-07-25 07:56:56 -07:00
ImGui : : InputText ( " ##FilterInput " , & filter ) ;
2024-04-10 13:27:07 -07:00
ImGui : : TextUnformatted ( _TR_CTX ( " Theme Editor | Load dialog | Theme selector | label " , " Available themes... " ) ) ;
2023-07-17 15:55:19 -07:00
if ( ImGui : : BeginListBox ( " ##Themes " , ImVec2 ( ImGui : : GetWindowWidth ( ) - ( ImGui : : GetStyle ( ) . WindowPadding . x * 2.0f ) , - ImGui : : GetTextLineHeightWithSpacing ( ) - ImGui : : GetStyle ( ) . WindowPadding . y ) ) ) {
for ( auto themePath : Theme : : availableThemes ) {
2023-07-25 07:56:56 -07:00
string themeStem = themePath . stem ( ) . string ( ) ;
if ( themeStem . starts_with ( filter ) ) {
2023-07-17 15:55:19 -07:00
const bool is_selected = themePath = = selectedThemePath ;
2023-07-25 07:56:56 -07:00
if ( ImGui : : Selectable ( ( theme - > themeStrings [ themePath ] . name + string ( " ( " ) + string ( themeStem ) + string ( " ) " ) ) . c_str ( ) , is_selected ) ) {
2023-07-17 15:55:19 -07:00
selectedThemePath = themePath ;
}
if ( is_selected ) {
ImGui : : SetItemDefaultFocus ( ) ;
}
2023-07-09 18:56:12 -07:00
}
}
2023-07-17 15:55:19 -07:00
ImGui : : EndListBox ( ) ;
2023-07-09 18:56:12 -07:00
}
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | Load dialog | Load button " , " Load " ) ) ) {
2023-07-17 15:55:19 -07:00
if ( ! selectedThemePath . empty ( ) ) {
2023-07-25 07:56:56 -07:00
filter = " " ;
2023-07-17 15:55:19 -07:00
loadOpen = false ;
delete theme ;
theme = new Theme ( selectedThemePath ) ;
selectedThemePath = path ( ) ;
ImGui : : EndPopup ( ) ;
return true ;
}
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | Load dialog | Cancel button " , " Cancel " ) ) ) {
2023-07-17 15:55:19 -07:00
selectedThemePath = path ( ) ;
2023-07-25 07:56:56 -07:00
filter = " " ;
2023-07-09 18:56:12 -07:00
loadOpen = false ;
}
2023-07-17 15:55:19 -07:00
ImGui : : EndPopup ( ) ;
2023-07-09 18:56:12 -07:00
}
}
if ( saveAsOpen ) {
2023-07-25 14:33:29 -07:00
ImGui : : OpenPopup ( _TR_CTX ( " Theme Editor | Custom modal dialog title " , " Save as... " ) ) ;
2023-07-17 15:55:19 -07:00
ImGui : : SetNextWindowPos ( ImVec2 ( 0 , 0 ) ) ;
ImGui : : SetNextWindowSize ( ImVec2 ( window_width , window_height ) ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : BeginPopupModal ( _TR_CTX ( " Theme Editor | Custom modal dialog title " , " Save as... " ) , nullptr , ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize ) ) {
2023-07-25 07:56:56 -07:00
static string selectedThemeName = " " ;
static string filter = " " ;
2024-04-10 13:27:07 -07:00
ImGui : : TextUnformatted ( _TR_CTX ( " Theme Editor | Save as dialog | Theme selector | filter label " , " Filter: " ) ) ; ImGui : : SameLine ( ) ;
2023-07-17 15:55:19 -07:00
ImGui : : SetNextItemWidth ( ImGui : : GetWindowWidth ( ) - ImGui : : GetCursorPosX ( ) - ImGui : : GetStyle ( ) . WindowPadding . x ) ;
2023-07-25 07:56:56 -07:00
ImGui : : InputText ( " ##FilterInput " , & filter , 1024 ) ;
2024-04-10 13:27:07 -07:00
ImGui : : TextUnformatted ( _TR_CTX ( " Theme Editor | Save as dialog | Theme selector | label " , " Available themes... " ) ) ;
2023-07-17 15:55:19 -07:00
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 ) {
2023-07-25 07:56:56 -07:00
string themeStem = themePath . stem ( ) . string ( ) ;
if ( themeStem . starts_with ( filter ) ) {
const bool is_selected = themeStem = = selectedThemeName ;
if ( ImGui : : Selectable ( ( theme - > themeStrings [ themePath ] . name + string ( " ( " ) + string ( themeStem ) + string ( " ) " ) ) . c_str ( ) , is_selected ) ) {
selectedThemeName = themeStem ;
2023-07-17 15:55:19 -07:00
}
if ( is_selected ) {
ImGui : : SetItemDefaultFocus ( ) ;
}
2023-07-09 18:56:12 -07:00
}
}
2023-07-17 15:55:19 -07:00
ImGui : : EndListBox ( ) ;
2023-07-09 18:56:12 -07:00
}
2023-07-17 15:55:19 -07:00
ImGui : : SetNextItemWidth ( ImGui : : GetWindowWidth ( ) - ( ImGui : : GetStyle ( ) . WindowPadding . x * 2.0f ) ) ;
2023-07-25 14:33:29 -07:00
ImGui : : InputText ( _TR_CTX ( " Theme Editor | Save as dialog | Theme name input label " , " Theme name: " ) , & selectedThemeName ) ;
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | Save as dialog | Save button " , " Save " ) ) ) {
2023-07-17 15:55:19 -07:00
path selectedThemePath ( selectedThemeName ) ;
if ( ! selectedThemePath . empty ( ) & & ! selectedThemePath . is_absolute ( ) ) {
2023-07-25 07:56:56 -07:00
selectedThemeName = " " ;
filter = " " ;
2023-07-17 15:55:19 -07:00
saveAsOpen = false ;
2023-12-22 14:13:48 -08:00
theme - > Save ( Theme : : themeDir / selectedThemePath . replace_extension ( " .toml " ) ) ;
2023-07-17 15:55:19 -07:00
theme - > file_path = selectedThemePath . generic_string ( ) ;
}
}
ImGui : : SameLine ( ) ;
2023-07-25 14:33:29 -07:00
if ( ImGui : : Button ( _TR_CTX ( " Theme Editor | Save as dialog | Cancel button " , " Cancel " ) ) ) {
2023-07-25 07:56:56 -07:00
selectedThemeName = " " ;
filter = " " ;
2023-07-09 18:56:12 -07:00
saveAsOpen = false ;
}
2023-07-17 15:55:19 -07:00
ImGui : : EndPopup ( ) ;
2023-07-09 18:56:12 -07:00
}
}
return false ;
}
2023-10-16 10:44:25 -07:00
AccentColorizer : : AccentColorizer ( ) {
Hue = false ;
Saturation = false ;
Value = false ;
Alpha = false ;
}
2023-12-22 14:13:48 -08:00
AccentColorizer : : AccentColorizer ( toml : : table table ) : AccentColorizer ( ) {
Hue = * * table [ " hue " ] . as_boolean ( ) ;
Saturation = * * table [ " saturation " ] . as_boolean ( ) ;
Value = * * table [ " value " ] . as_boolean ( ) ;
Alpha = * * table [ " alpha " ] . as_boolean ( ) ;
2023-10-16 10:44:25 -07:00
}
2023-12-22 14:13:48 -08:00
toml : : table AccentColorizer : : Serialize ( ) {
toml : : table output ;
output . insert ( " hue " , Hue ) ;
output . insert ( " saturation " , Saturation ) ;
output . insert ( " value " , Value ) ;
output . insert ( " alpha " , Alpha ) ;
2023-10-16 10:44:25 -07:00
return output ;
}
void AccentColorizer : : Colorize ( ImVec4 accent , ImVec4 & color ) {
ImVec4 hsv = color ;
ImGui : : ColorConvertRGBtoHSV ( color . x , color . y , color . z , hsv . x , hsv . y , hsv . z ) ;
if ( Saturation )
hsv . y = accent . y ;
if ( Value )
hsv . z = accent . z ;
if ( Hue )
hsv . x = accent . x ;
ImGui : : ColorConvertHSVtoRGB ( hsv . x , hsv . y , hsv . z , color . x , color . y , color . z ) ;
if ( Alpha )
color . w * = accent . w ;
}
2024-05-01 09:07:08 -07:00
void Theme : : Apply ( ImVec4 accent , float scale ) {
2023-07-09 18:56:12 -07:00
ImGuiStyle & actual_style = ImGui : : GetStyle ( ) ;
actual_style = style ;
for ( int i = 0 ; i < ImGuiCol_COUNT ; i + + )
{
2024-05-01 09:07:08 -07:00
if ( AccentColorizers . contains ( i ) ) {
AccentColorizers [ i ] . Colorize ( accent , actual_style . Colors [ i ] ) ;
}
2023-07-09 18:56:12 -07:00
}
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
{
actual_style . WindowRounding = 0.0f ;
actual_style . Colors [ ImGuiCol_WindowBg ] . w = 1.0f ;
}
2024-05-01 09:07:08 -07:00
actual_style . ScaleAllSizes ( scale ) ;
actual_style . WindowMinSize . x = MAX ( actual_style . WindowMinSize . x , 1.0 ) ;
actual_style . WindowMinSize . y = MAX ( actual_style . WindowMinSize . y , 1.0 ) ;
2024-05-02 14:52:11 -07:00
actual_style . CurveTessellationTol = MAX ( actual_style . CurveTessellationTol , 0.1 ) ;
actual_style . CircleTessellationMaxError = MAX ( actual_style . CircleTessellationMaxError , 0.1 ) ;
2023-07-09 18:56:12 -07:00
}
void Theme : : Save ( string path ) {
2024-03-23 18:41:26 -07:00
INFO . writefln ( " Saving theme to %s... " , path . c_str ( ) ) ;
2023-07-09 18:56:12 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table config ;
2024-05-01 09:07:08 -07:00
# ifdef __EMSCRIPTEN__
std : : ostringstream stream ;
# else
2023-07-09 18:56:12 -07:00
std : : ofstream stream ;
stream . open ( path ) ;
2024-05-01 09:07:08 -07:00
# endif
2023-07-24 23:13:47 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table metadata ;
metadata . insert ( " SchemaVersion " , 3 ) ;
2023-07-24 23:13:47 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table stringsList ;
2023-07-24 23:13:47 -07:00
for ( auto kv : strings ) {
2023-12-22 14:13:48 -08:00
toml : : table stringsEntryJson ;
2023-07-24 23:13:47 -07:00
string language = kv . first ;
2023-07-25 07:56:56 -07:00
ThemeStrings stringsEntry = kv . second ;
2023-12-22 14:13:48 -08:00
stringsEntryJson . insert ( " name " , stringsEntry . name ) ;
stringsEntryJson . insert ( " desc " , stringsEntry . description ) ;
stringsList . insert ( language , stringsEntryJson ) ;
2023-07-24 23:13:47 -07:00
}
2023-12-22 14:13:48 -08:00
metadata . insert ( " Strings " , stringsList ) ;
2023-07-24 23:13:47 -07:00
}
2023-12-22 14:13:48 -08:00
config . insert ( " meta " , metadata ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-09 18:56:12 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table rounding ;
rounding . insert ( " Frame " , style . FrameRounding ) ;
rounding . insert ( " Window " , style . WindowRounding ) ;
rounding . insert ( " Child " , style . ChildRounding ) ;
rounding . insert ( " Popup " , style . PopupRounding ) ;
rounding . insert ( " Scrollbar " , style . ScrollbarRounding ) ;
rounding . insert ( " Grab " , style . GrabRounding ) ;
rounding . insert ( " Tab " , style . TabRounding ) ;
config . insert ( " rounding " , rounding ) ;
2023-07-09 18:56:12 -07:00
}
2023-07-18 18:44:19 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table sizing ;
sizing . insert ( " FrameX " , style . FramePadding . x ) ;
sizing . insert ( " FrameY " , style . FramePadding . y ) ;
sizing . insert ( " WindowX " , style . WindowPadding . x ) ;
sizing . insert ( " WindowY " , style . WindowPadding . y ) ;
sizing . insert ( " CellX " , style . CellPadding . x ) ;
sizing . insert ( " CellY " , style . CellPadding . y ) ;
sizing . insert ( " SeparatorTextX " , style . SeparatorTextPadding . x ) ;
sizing . insert ( " SeparatorTextY " , style . SeparatorTextPadding . y ) ;
sizing . insert ( " ItemSpacingX " , style . ItemSpacing . x ) ;
sizing . insert ( " ItemSpacingY " , style . ItemSpacing . y ) ;
sizing . insert ( " Scrollbar " , style . ScrollbarSize ) ;
sizing . insert ( " Grab " , style . GrabMinSize ) ;
config . insert ( " sizing " , sizing ) ;
2023-07-18 18:44:19 -07:00
}
2023-07-09 18:56:12 -07:00
{
2023-12-22 14:13:48 -08:00
toml : : table borders ;
borders . insert ( " Frame " , style . FrameBorderSize ) ;
borders . insert ( " Window " , style . WindowBorderSize ) ;
borders . insert ( " Child " , style . ChildBorderSize ) ;
borders . insert ( " Popup " , style . PopupBorderSize ) ;
borders . insert ( " Tab " , style . TabBorderSize ) ;
borders . insert ( " SeparatorText " , style . SeparatorTextBorderSize ) ;
config . insert ( " borders " , borders ) ;
2023-07-09 18:56:12 -07:00
}
{
2023-12-22 14:13:48 -08:00
toml : : table colors ;
2023-07-09 18:56:12 -07:00
for ( int i = 0 ; i < ImGuiCol_COUNT ; i + + )
{
const char * name = ImGui : : GetStyleColorName ( i ) ;
ImVec4 color = style . Colors [ i ] ;
2023-12-22 14:13:48 -08:00
toml : : table colorValue ;
colorValue . insert ( " r " , color . x ) ;
colorValue . insert ( " g " , color . y ) ;
colorValue . insert ( " b " , color . z ) ;
colorValue . insert ( " a " , color . w ) ;
colorValue . insert ( " accent " , AccentColorizers [ i ] . Serialize ( ) ) ;
colors . insert ( name , colorValue ) ;
2023-07-09 18:56:12 -07:00
}
2023-12-22 14:13:48 -08:00
config . insert ( " colors " , colors ) ;
2023-07-09 18:56:12 -07:00
}
stream < < config ;
2024-05-01 09:07:08 -07:00
# ifdef __EMSCRIPTEN__
path = path ;
std : : string str = stream . str ( ) ;
write_storage ( path . c_str ( ) , str . c_str ( ) , str . length ( ) + 1 ) ;
# else
2023-07-09 18:56:12 -07:00
stream . close ( ) ;
2024-05-01 09:07:08 -07:00
# endif
2023-07-09 18:56:12 -07:00
}
updateAvailableThemes ( ) ;
}
2023-07-16 19:59:23 -07:00
void Theme : : Save ( path path ) {
2023-07-17 12:55:13 -07:00
Save ( ( string ) path . string ( ) ) ;
2023-07-16 19:59:23 -07:00
}
2023-07-09 18:56:12 -07:00
void Theme : : updateAvailableThemes ( ) {
2024-05-01 09:07:08 -07:00
# ifdef __EMSCRIPTEN__
themeDir = " theme " ;
# else
2023-07-10 19:27:55 -07:00
themeDir = path ( prefPath ) / path ( " themes " ) ;
create_directories ( themeDir ) ;
2024-05-01 09:07:08 -07:00
# endif
2023-07-09 18:56:12 -07:00
availableThemes . clear ( ) ;
2023-07-25 07:56:56 -07:00
themeStrings . clear ( ) ;
2024-05-01 09:07:08 -07:00
# ifdef __EMSCRIPTEN__
const char * * theme_files = nullptr ;
find_keys ( " theme/ " , & theme_files ) ;
if ( theme_files [ 0 ] ! = nullptr ) {
for ( size_t i = 0 ; theme_files [ i ] ! = nullptr ; i + + ) {
const char * dir_entry = theme_files [ i ] ;
if ( dir_entry = = nullptr ) {
break ;
}
string curpath = dir_entry ;
const char * theme_contents = nullptr ;
read_storage ( dir_entry , & theme_contents , nullptr ) ;
if ( theme_contents = = nullptr ) {
continue ;
}
availableThemes . insert ( curpath ) ;
toml : : table config = toml : : parse ( theme_contents ) ;
free ( ( void * ) theme_contents ) ;
themeStrings [ curpath ] = ThemeStrings ( config ) ;
free ( ( void * ) dir_entry ) ;
}
}
free ( ( void * ) theme_files ) ;
# else
2023-07-09 18:56:12 -07:00
for ( auto const & dir_entry : directory_iterator ( themeDir ) ) {
if ( dir_entry . is_regular_file ( ) ) {
if ( dir_entry . path ( ) . extension ( ) . string ( ) = = " .json " ) {
2023-12-22 14:13:48 -08:00
string curpath = Migrate ( dir_entry . path ( ) . string ( ) ) ;
std : : filesystem : : remove ( dir_entry . path ( ) ) ;
availableThemes . insert ( curpath ) ;
toml : : table config = toml : : parse_file ( curpath ) ;
themeStrings [ curpath ] = ThemeStrings ( config ) ;
} else if ( dir_entry . path ( ) . extension ( ) . string ( ) = = " .toml " ) {
2024-05-01 09:07:08 -07:00
2023-12-22 14:13:48 -08:00
string curpath = dir_entry . path ( ) . string ( ) ;
availableThemes . insert ( curpath ) ;
toml : : table config = toml : : parse_file ( curpath ) ;
themeStrings [ curpath ] = ThemeStrings ( config ) ;
2023-07-09 18:56:12 -07:00
}
2024-05-01 09:07:08 -07:00
}
2023-07-09 18:56:12 -07:00
}
2024-05-01 09:07:08 -07:00
# endif
2023-07-09 18:56:12 -07:00
}
Theme : : Theme ( ) {
if ( prefPath = = NULL ) {
throw std : : exception ( ) ;
}
updateAvailableThemes ( ) ;
2023-07-25 07:56:56 -07:00
strings [ " fallback " ] = ThemeStrings ( ) ;
2023-07-09 18:56:12 -07:00
}
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 + + )
{
2023-07-11 10:18:51 -07:00
ImVec4 color = style . Colors [ i ] ;
2023-10-16 10:44:25 -07:00
auto colorizer = AccentColorizer ( ) ;
2023-07-11 10:18:51 -07:00
if ( color . x ! = color . y | | color . y ! = color . z ) {
2023-10-16 10:44:25 -07:00
colorizer . Hue = true ;
colorizer . Saturation = true ;
colorizer . Alpha = true ;
2023-07-11 10:18:51 -07:00
}
2023-10-16 10:44:25 -07:00
AccentColorizers [ i ] = colorizer ;
2023-07-09 18:56:12 -07:00
}
style . FrameRounding = 12 ;
style . GrabRounding = 12 ;
style . WindowRounding = 12 ;
}
2023-07-24 23:13:47 -07:00
ThemeStrings : : ThemeStrings ( ) {
2023-07-25 14:33:29 -07:00
name = _TRS_CTX ( " Theme default strings | name " , " A theme " ) ;
description = _TRS_CTX ( " Theme default strings | description " , " (No description) " ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-25 07:56:56 -07:00
ThemeStrings Theme : : GetStrings ( ) {
char * language_c = CURRENT_LANGUAGE ;
string language = language_c ;
if ( strings . contains ( language ) ) {
return strings [ language ] ;
} else {
if ( ! strings . contains ( " fallback " ) ) {
strings [ " fallback " ] = ThemeStrings ( ) ;
}
return strings [ " fallback " ] ;
}
}
2023-12-22 14:13:48 -08:00
ThemeStrings : : ThemeStrings ( toml : : table config ) : ThemeStrings ( ) {
2023-07-25 07:56:56 -07:00
char * language_c = CURRENT_LANGUAGE ;
string language = language_c ;
2023-12-22 14:13:48 -08:00
if ( config . contains ( " meta " ) ) {
toml : : table metadata = * config [ " meta " ] . as_table ( ) ;
2023-07-25 07:56:56 -07:00
//metadata["SchemaVersion"] = 1;
2023-12-22 14:13:48 -08:00
if ( metadata . contains ( " Strings " ) ) {
toml : : table stringsList = * metadata [ " Strings " ] . as_table ( ) ;
if ( stringsList . contains ( language ) ) {
toml : : table stringsEntryJson = * stringsList [ language ] . as_table ( ) ;
if ( stringsEntryJson . contains ( " name " ) ) {
name = * * stringsEntryJson [ " name " ] . as_string ( ) ;
2023-07-25 07:56:56 -07:00
}
2023-12-22 14:13:48 -08:00
if ( stringsEntryJson . contains ( " desc " ) ) {
description = * * stringsEntryJson [ " desc " ] . as_string ( ) ;
2023-07-25 07:56:56 -07:00
}
2023-12-22 14:13:48 -08:00
} else if ( metadata . contains ( " fallback " ) ) {
toml : : table stringsEntryJson = * stringsList [ " fallback " ] . as_table ( ) ;
if ( stringsEntryJson . contains ( " name " ) ) {
name = * * stringsEntryJson [ " name " ] . as_string ( ) ;
2023-07-25 07:56:56 -07:00
}
2023-12-22 14:13:48 -08:00
if ( stringsEntryJson . contains ( " desc " ) ) {
description = * * stringsEntryJson [ " desc " ] . as_string ( ) ;
2023-07-25 07:56:56 -07:00
}
}
}
}
}
2023-12-22 14:13:48 -08:00
std : : string Theme : : Migrate ( std : : string path ) {
if ( path . ends_with ( " .json " ) ) {
2024-03-23 18:41:26 -07:00
INFO . writefln ( " Migrating theme file '%s'... " , path . c_str ( ) ) ;
2023-12-22 14:13:48 -08:00
std : : ifstream stream ( path ) ;
Json : : Value config ;
2023-07-09 18:56:12 -07:00
stream > > config ;
2023-12-22 14:13:48 -08:00
toml : : table newConfig ;
2023-07-24 23:13:47 -07:00
if ( config . isMember ( " meta " ) ) {
Json : : Value metadata = config [ " meta " ] ;
2023-12-22 14:13:48 -08:00
toml : : table newMeta ;
2023-07-24 23:13:47 -07:00
if ( metadata . isMember ( " Strings " ) ) {
Json : : Value stringsList = metadata [ " Strings " ] ;
2023-12-22 14:13:48 -08:00
toml : : table newStringsList ;
2023-07-24 23:13:47 -07:00
for ( string language : stringsList . getMemberNames ( ) ) {
2023-07-25 07:56:56 -07:00
Json : : Value stringsEntryJson = stringsList [ language ] ;
2023-12-22 14:13:48 -08:00
toml : : table newStringsEntry ;
2023-07-25 07:56:56 -07:00
if ( stringsEntryJson . isMember ( " Name " ) ) {
2023-12-22 14:13:48 -08:00
string value = stringsEntryJson [ " Name " ] . asString ( ) ;
newStringsEntry . insert ( " name " , value ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-25 07:56:56 -07:00
if ( stringsEntryJson . isMember ( " Description " ) ) {
2023-12-22 14:13:48 -08:00
string value = stringsEntryJson [ " Description " ] . asString ( ) ;
newStringsEntry . insert ( " desc " , value ) ;
2023-07-24 23:13:47 -07:00
}
2023-12-22 14:13:48 -08:00
newStringsList . insert ( language , newStringsEntry ) ;
2023-07-24 23:13:47 -07:00
}
2023-12-22 14:13:48 -08:00
newMeta . insert ( " Strings " , newStringsList ) ;
2023-07-24 23:13:47 -07:00
}
2023-12-22 14:13:48 -08:00
newConfig . insert ( " meta " , newMeta ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-09 18:56:12 -07:00
if ( config . isMember ( " rounding " ) ) {
Json : : Value rounding = config [ " rounding " ] ;
2023-12-22 14:13:48 -08:00
toml : : table newRounding ;
for ( string key : rounding . getMemberNames ( ) ) {
newRounding . insert ( key , rounding [ key ] . asFloat ( ) ) ;
}
newConfig . insert ( " rounding " , newRounding ) ;
2023-07-09 18:56:12 -07:00
}
2023-07-18 18:44:19 -07:00
if ( config . isMember ( " sizing " ) ) {
2023-12-22 14:13:48 -08:00
Json : : Value rounding = config [ " sizing " ] ;
toml : : table newRounding ;
for ( string key : rounding . getMemberNames ( ) ) {
newRounding . insert ( key , rounding [ key ] . asFloat ( ) ) ;
}
newConfig . insert ( " sizing " , newRounding ) ;
2023-07-18 18:44:19 -07:00
}
2023-07-09 18:56:12 -07:00
if ( config . isMember ( " borders " ) ) {
2023-12-22 14:13:48 -08:00
Json : : Value rounding = config [ " borders " ] ;
toml : : table newRounding ;
for ( string key : rounding . getMemberNames ( ) ) {
newRounding . insert ( key , rounding [ key ] . asFloat ( ) ) ;
2023-07-18 18:44:19 -07:00
}
2023-12-22 14:13:48 -08:00
newConfig . insert ( " borders " , newRounding ) ;
2023-07-09 18:56:12 -07:00
}
if ( config . isMember ( " colors " ) ) {
Json : : Value colors = config [ " colors " ] ;
2023-12-22 14:13:48 -08:00
toml : : table newColors ;
2023-07-09 18:56:12 -07:00
for ( int i = 0 ; i < ImGuiCol_COUNT ; i + + )
{
2023-12-22 14:13:48 -08:00
toml : : table newColor ;
2023-07-09 18:56:12 -07:00
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 ( ) ) ;
2023-12-22 14:13:48 -08:00
newColor . insert ( " r " , colorValue [ " r " ] . asFloat ( ) ) ;
newColor . insert ( " g " , colorValue [ " g " ] . asFloat ( ) ) ;
newColor . insert ( " b " , colorValue [ " b " ] . asFloat ( ) ) ;
newColor . insert ( " a " , colorValue [ " a " ] . asFloat ( ) ) ;
toml : : table newAccentOptions ;
if ( colorValue [ " ConvertToAccent " ] . isBool ( ) ) {
newAccentOptions . insert ( " hue " , colorValue [ " ConvertToAccent " ] . asBool ( ) ) ;
newAccentOptions . insert ( " saturation " , false ) ;
newAccentOptions . insert ( " value " , false ) ;
newAccentOptions . insert ( " alpha " , false ) ;
} else {
Json : : Value accentOptions = colorValue [ " ConvertToAccent " ] ;
newAccentOptions . insert ( " hue " , accentOptions [ " hue " ] . asBool ( ) ) ;
newAccentOptions . insert ( " saturation " , accentOptions [ " saturation " ] . asBool ( ) ) ;
newAccentOptions . insert ( " value " , accentOptions [ " value " ] . asBool ( ) ) ;
newAccentOptions . insert ( " alpha " , accentOptions [ " a lpha " ] . asBool ( ) ) ;
}
newColor . insert ( " accent " , newAccentOptions ) ;
newColors . insert ( name , newColor ) ;
2023-07-09 18:56:12 -07:00
}
}
}
stream . close ( ) ;
2023-12-22 14:13:48 -08:00
std : : string newPath = path . replace ( path . size ( ) - 4 , 4 , " toml " ) ;
std : : ofstream outStream ( newPath ) ;
outStream < < newConfig ;
outStream . close ( ) ;
return newPath ;
}
return path ;
}
Theme : : Theme ( string path ) : Theme ( ) {
path = Migrate ( path ) ;
2024-03-23 18:41:26 -07:00
INFO . writefln ( " Loading theme '%s'... " , path . c_str ( ) ) ;
2023-12-22 14:13:48 -08:00
toml : : table config ;
2024-05-01 09:07:08 -07:00
# ifdef __EMSCRIPTEN__
const char * contents = nullptr ;
read_storage ( path . c_str ( ) , & contents , nullptr ) ;
if ( contents = = nullptr ) {
throw std : : exception ( ) ;
}
config = toml : : parse ( contents ) ;
free ( ( void * ) contents ) ;
# else
2023-12-22 14:13:48 -08:00
config = toml : : parse_file ( path ) ;
2024-05-01 09:07:08 -07:00
# endif
2023-12-22 14:13:48 -08:00
if ( config . contains ( " meta " ) ) {
toml : : table metadata = * config [ " meta " ] . as_table ( ) ;
//metadata["SchemaVersion"] = 1;
if ( metadata . contains ( " Strings " ) ) {
toml : : table stringsList = * metadata [ " Strings " ] . as_table ( ) ;
for ( auto kv : stringsList ) {
string language = string ( kv . first . str ( ) ) ;
toml : : table stringEntryToml = * kv . second . as_table ( ) ;
ThemeStrings stringsEntry ;
if ( stringEntryToml . contains ( " name " ) ) {
stringsEntry . name = stringEntryToml [ " name " ] . as_string ( ) - > value_or ( " Unknown " ) ;
}
if ( stringEntryToml . contains ( " desc " ) ) {
stringsEntry . description = stringEntryToml [ " desc " ] . as_string ( ) - > value_or ( " No description. " ) ;
}
strings [ language ] = stringsEntry ;
}
}
}
if ( config . contains ( " rounding " ) ) {
toml : : table rounding = * config [ " rounding " ] . as_table ( ) ;
style . FrameRounding = ( float ) ( * * ( rounding [ " Frame " ] . as_floating_point ( ) ) ) ;
style . WindowRounding = ( float ) ( * * ( rounding [ " Window " ] . as_floating_point ( ) ) ) ;
style . ChildRounding = ( float ) ( * * ( rounding [ " Child " ] . as_floating_point ( ) ) ) ;
style . PopupRounding = ( float ) ( * * ( rounding [ " Popup " ] . as_floating_point ( ) ) ) ;
style . ScrollbarRounding = ( float ) ( * * ( rounding [ " Scrollbar " ] . as_floating_point ( ) ) ) ;
style . GrabRounding = ( float ) ( * * ( rounding [ " Grab " ] . as_floating_point ( ) ) ) ;
style . TabRounding = ( float ) ( * * ( rounding [ " Tab " ] . as_floating_point ( ) ) ) ;
}
if ( config . contains ( " sizing " ) ) {
toml : : table sizing = * config [ " sizing " ] . as_table ( ) ;
style . FramePadding . x = ( float ) ( * * sizing [ " FrameX " ] . as_floating_point ( ) ) ;
style . FramePadding . y = ( float ) ( * * sizing [ " FrameY " ] . as_floating_point ( ) ) ;
style . WindowPadding . x = ( float ) ( * * sizing [ " WindowX " ] . as_floating_point ( ) ) ;
style . WindowPadding . y = ( float ) ( * * sizing [ " WindowY " ] . as_floating_point ( ) ) ;
style . CellPadding . x = ( float ) ( * * sizing [ " CellX " ] . as_floating_point ( ) ) ;
style . CellPadding . y = ( float ) ( * * sizing [ " CellY " ] . as_floating_point ( ) ) ;
style . SeparatorTextPadding . x = ( float ) ( * * sizing [ " SeparatorTextX " ] . as_floating_point ( ) ) ;
style . SeparatorTextPadding . y = ( float ) ( * * sizing [ " SeparatorTextY " ] . as_floating_point ( ) ) ;
style . ItemSpacing . x = ( float ) ( * * sizing [ " ItemSpacingX " ] . as_floating_point ( ) ) ;
style . ItemSpacing . y = ( float ) ( * * sizing [ " ItemSpacingY " ] . as_floating_point ( ) ) ;
style . ScrollbarSize = ( float ) ( * * sizing [ " Scrollbar " ] . as_floating_point ( ) ) ;
style . GrabMinSize = ( float ) ( * * sizing [ " Grab " ] . as_floating_point ( ) ) ;
}
if ( config . contains ( " borders " ) ) {
toml : : table borders = * config [ " borders " ] . as_table ( ) ;
style . FrameBorderSize = ( float ) ( * * borders [ " Frame " ] . as_floating_point ( ) ) ;
style . WindowBorderSize = ( float ) ( * * borders [ " Window " ] . as_floating_point ( ) ) ;
style . ChildBorderSize = ( float ) ( * * borders [ " Child " ] . as_floating_point ( ) ) ;
style . PopupBorderSize = ( float ) ( * * borders [ " Popup " ] . as_floating_point ( ) ) ;
style . TabBorderSize = ( float ) ( * * borders [ " Tab " ] . as_floating_point ( ) ) ;
if ( borders . contains ( " SeparatorText " ) ) {
style . SeparatorTextBorderSize = ( float ) ( * * borders [ " SeparatorText " ] . as_floating_point ( ) ) ;
}
}
if ( config . contains ( " colors " ) ) {
toml : : table colors = * config [ " colors " ] . as_table ( ) ;
for ( int i = 0 ; i < ImGuiCol_COUNT ; i + + )
{
const char * name = ImGui : : GetStyleColorName ( i ) ;
if ( colors . contains ( name ) ) {
toml : : table colorValue = * colors [ name ] . as_table ( ) ;
ImVec4 color = ImVec4 ( ( float ) * * colorValue [ " r " ] . as_floating_point ( ) , ( float ) * * colorValue [ " g " ] . as_floating_point ( ) , ( float ) * * colorValue [ " b " ] . as_floating_point ( ) , ( float ) * * colorValue [ " a " ] . as_floating_point ( ) ) ;
AccentColorizers [ i ] = AccentColorizer ( * colorValue [ " accent " ] . as_table ( ) ) ;
style . Colors [ i ] = color ;
}
}
2023-07-09 18:56:12 -07:00
}
file_path = path ;
2023-07-16 19:59:23 -07:00
}
Theme : : Theme ( path path ) : Theme ( path . string ( ) ) {
2023-07-21 09:56:13 -07:00
}