2023-07-09 18:56:12 -07:00
# include "theme.h"
# include "imgui.h"
# include "json/value.h"
2023-07-24 23:13:47 -07:00
# include "translation.h"
2023-07-09 18:56:12 -07:00
# include <cmath>
# include <exception>
# include <numbers>
# 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"
2023-07-09 18:56:12 -07:00
using namespace std : : filesystem ;
using namespace std : : numbers ;
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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -07:00
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 " } ) ;
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-24 23:13:47 -07:00
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 " } ) ;
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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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 07:56:56 -07:00
if ( ImGui : : BeginTabItem ( _TR_CTX ( " Theme Editor > Tab label " , " Strings " ) ) )
{
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 ) ;
ImGui : : EndTabItem ( ) ;
}
2023-07-24 23:13:47 -07:00
if ( ImGui : : BeginTabItem ( _TR_CTX ( " Theme Editor > Tab label " , " Sizes " ) ) )
2023-07-09 18:56:12 -07:00
{
2023-07-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-07-10 19:27:55 -07:00
bool hueEnabled = theme - > HueEnabledColors . contains ( i ) ;
2023-07-24 23:13:47 -07:00
if ( ImGui : : Checkbox ( _TR_CTX ( " Theme Editor > Colors > (Any color) > recoloring checkbox " , " Match hue preference " ) , & hueEnabled ) ) {
2023-07-09 18:56:12 -07:00
if ( hueEnabled ) {
2023-07-10 19:27:55 -07:00
theme - > HueEnabledColors . insert ( i ) ;
2023-07-09 18:56:12 -07:00
} else {
2023-07-10 19:27:55 -07:00
theme - > HueEnabledColors . erase ( i ) ;
2023-07-09 18:56:12 -07:00
}
}
2023-07-11 10:18:51 -07:00
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 ) ;
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-24 23:13:47 -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-24 23:13:47 -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 = " " ;
2023-07-24 23:13:47 -07:00
ImGui : : Text ( _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 ) ;
2023-07-24 23:13:47 -07:00
ImGui : : Text ( _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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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-24 23:13:47 -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 = " " ;
2023-07-24 23:13:47 -07:00
ImGui : : Text ( _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 ) ;
2023-07-24 23:13:47 -07:00
ImGui : : Text ( _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 07:56:56 -07:00
ImGui : : InputText ( _TR_CTX ( " Theme Editor > Save as dialog > Theme name input label " , " Theme name: " ) , & selectedThemeName ) ;
2023-07-24 23:13:47 -07:00
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 ;
theme - > Save ( Theme : : themeDir / selectedThemePath . replace_extension ( " .json " ) ) ;
theme - > file_path = selectedThemePath . generic_string ( ) ;
}
}
ImGui : : SameLine ( ) ;
2023-07-24 23:13:47 -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 ;
}
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 ) {
2023-07-17 12:55:13 -07:00
printf ( " Saving theme to %s... \n " , path . c_str ( ) ) ;
2023-07-09 18:56:12 -07:00
{
Json : : Value config ;
std : : ofstream stream ;
stream . open ( path ) ;
2023-07-24 23:13:47 -07:00
{
Json : : Value metadata ;
metadata [ " SchemaVersion " ] = 1 ;
{
Json : : Value stringsList ;
for ( auto kv : strings ) {
2023-07-25 07:56:56 -07:00
Json : : Value 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 ;
stringsEntryJson [ " Name " ] = stringsEntry . name ;
stringsEntryJson [ " Description " ] = stringsEntry . description ;
stringsList [ language ] = stringsEntryJson ;
2023-07-24 23:13:47 -07:00
}
metadata [ " Strings " ] = stringsList ;
}
config [ " meta " ] = metadata ;
}
2023-07-09 18:56:12 -07:00
{
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 ;
}
2023-07-18 18:44:19 -07:00
{
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 ;
}
2023-07-09 18:56:12 -07:00
{
Json : : Value borders ;
borders [ " Frame " ] = style . FrameBorderSize ;
borders [ " Window " ] = style . WindowBorderSize ;
borders [ " Child " ] = style . ChildBorderSize ;
borders [ " Popup " ] = style . PopupBorderSize ;
borders [ " Tab " ] = style . TabBorderSize ;
2023-07-18 18:44:19 -07:00
borders [ " Tab " ] = style . TabBorderSize ;
borders [ " SeparatorText " ] = style . SeparatorTextBorderSize ;
2023-07-09 18:56:12 -07:00
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 ( ) ;
}
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 ( ) {
2023-07-10 19:27:55 -07:00
themeDir = path ( prefPath ) / path ( " themes " ) ;
create_directories ( themeDir ) ;
2023-07-09 18:56:12 -07:00
availableThemes . clear ( ) ;
2023-07-25 07:56:56 -07:00
themeStrings . clear ( ) ;
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-07-25 07:56:56 -07:00
path path = dir_entry . path ( ) ;
availableThemes . insert ( path ) ;
Json : : Value config ;
std : : ifstream stream ;
stream . open ( path ) ;
if ( stream . is_open ( ) ) {
stream > > config ;
themeStrings [ path ] = ThemeStrings ( config ) ;
}
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 ] ;
if ( color . x ! = color . y | | color . y ! = color . z ) {
HueEnabledColors . insert ( i ) ;
}
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 ( ) {
name = _TRS_CTX ( " Theme default strings > name " , " A theme " ) ;
description = _TRS_CTX ( " Theme default strings > description " , " (No description) " ) ;
}
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 " ] ;
}
}
ThemeStrings : : ThemeStrings ( Json : : Value config ) : ThemeStrings ( ) {
char * language_c = CURRENT_LANGUAGE ;
string language = language_c ;
if ( config . isMember ( " meta " ) ) {
Json : : Value metadata = config [ " meta " ] ;
//metadata["SchemaVersion"] = 1;
if ( metadata . isMember ( " Strings " ) ) {
Json : : Value stringsList = metadata [ " Strings " ] ;
if ( stringsList . isMember ( language ) ) {
Json : : Value stringsEntryJson = stringsList [ language ] ;
if ( stringsEntryJson . isMember ( " Name " ) ) {
name = stringsEntryJson [ " Name " ] . asString ( ) ;
}
if ( stringsEntryJson . isMember ( " Description " ) ) {
description = stringsEntryJson [ " Description " ] . asString ( ) ;
}
} else if ( metadata . isMember ( " fallback " ) ) {
Json : : Value stringsEntryJson = stringsList [ " fallback " ] ;
if ( stringsEntryJson . isMember ( " Name " ) ) {
name = stringsEntryJson [ " Name " ] . asString ( ) ;
}
if ( stringsEntryJson . isMember ( " Description " ) ) {
description = stringsEntryJson [ " Description " ] . asString ( ) ;
}
}
}
}
}
2023-07-09 18:56:12 -07:00
Theme : : Theme ( string path ) : Theme ( ) {
Json : : Value config ;
std : : ifstream stream ;
stream . open ( path ) ;
if ( stream . is_open ( ) ) {
stream > > config ;
2023-07-24 23:13:47 -07:00
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 ( ) ) {
2023-07-25 07:56:56 -07:00
Json : : Value stringsEntryJson = stringsList [ language ] ;
ThemeStrings stringsEntry ;
if ( stringsEntryJson . isMember ( " Name " ) ) {
stringsEntry . name = stringsEntryJson [ " Name " ] . asString ( ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-25 07:56:56 -07:00
if ( stringsEntryJson . isMember ( " Description " ) ) {
stringsEntry . description = stringsEntryJson [ " Description " ] . asString ( ) ;
2023-07-24 23:13:47 -07:00
}
2023-07-25 07:56:56 -07:00
strings [ language ] = stringsEntry ;
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 " ] ;
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 ( ) ;
}
2023-07-18 18:44:19 -07:00
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 ( ) ;
}
2023-07-09 18:56:12 -07:00
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 ( ) ;
2023-07-18 18:44:19 -07:00
if ( borders . isMember ( " SeparatorText " ) ) {
style . SeparatorTextBorderSize = borders [ " SeparatorText " ] . asFloat ( ) ;
}
2023-07-09 18:56:12 -07:00
}
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 ;
2023-07-16 19:59:23 -07:00
}
Theme : : Theme ( path path ) : Theme ( path . string ( ) ) {
2023-07-21 09:56:13 -07:00
}