2024-05-25 04:30:52 +00:00
/*
2024-05-25 23:23:30 +00:00
* Functions to read / write a Dear ImGui style ( ImGuiStyle ) from / to a ( ini - like )
* textfile , or generating C + + code for it .
2024-05-25 04:30:52 +00:00
*
* Hosted at https : //github.com/DanielGibson/Snippets/
*
2024-10-29 02:55:07 +00:00
* Written for / tested with Dear ImGui v1 .91 .4 ( incl . Docking Branch )
2024-05-25 04:30:52 +00:00
*
* If anything changes in struct ImGuiStyle or enum ImGuiCol_ , this code should detect it
* during compilation and give ( hopefully ) helpful errors with static_assert ( ) ( always check and
* fix the first error that occurs first , the remaining ones might be caused by the first ) .
*
* Released under the same license as Dear ImGui :
*
* The MIT License ( MIT )
*
* Copyright ( c ) 2024 Daniel Gibson
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include "imgui.h"
# include <stdio.h>
#if 0 // this is basically the header, just copy it to wherever you want to use these functions
namespace DG {
// writes the given ImGuiStyle to the given filename (opened with fopen())
// returns true on success, false if opening the file failed
extern bool WriteImGuiStyle ( const ImGuiStyle & style , const char * filename ) ;
// reads the the given filename (opened with fopen())
// and sets the given ImGuiStyle accordingly.
// if any attributes/colors/behaviors are missing the the file,
// they are not modified in style, so it probably makes sense to initialize
2024-05-25 23:23:30 +00:00
// style to a sane default before calling this function.
2024-05-25 04:30:52 +00:00
// returns true on success, false if opening the file failed
extern bool ReadImGuiStyle ( ImGuiStyle & style , const char * filename ) ;
2024-05-25 16:15:07 +00:00
// generate C++ code that replicates the given style into a text buffer
2024-05-25 23:23:30 +00:00
// (that you can write to a file or set the clipboard from or whatever)
2024-05-26 01:56:28 +00:00
// if refStyle is set, only differences in style compared to refStyle are written
extern ImGuiTextBuffer WriteImGuiStyleToCode ( const ImGuiStyle & style , const ImGuiStyle * refStyle = nullptr ) ;
2024-05-25 04:30:52 +00:00
} //namespace
# endif
// if you want to use another namespace than DG, modify this #define
// (either here or through a compiler argumenet like -DDG_IMSAVESTYLE_NAMESPACE=horst)
# ifndef DG_IMSAVESTYLE_NAMESPACE
# define DG_IMSAVESTYLE_NAMESPACE DG
# endif
// #define your own DG_IMSAVESTYLE_FOPEN if you want to use an alternative to
// standard fopen(), for example one that supports UTF-8 filenames on Windows
# ifndef DG_IMSAVESTYLE_FOPEN
# define DG_IMSAVESTYLE_FOPEN fopen
# endif
# undef warnPrintf
// TODO: maybe use your own logging system instead of fprintf() to stderr
2024-10-02 18:23:50 +00:00
# define warnPrintf(...) fprintf( stderr, "Warning: " __VA_ARGS__ )
# ifdef IMGUI_HAS_DOCK
// some members of struct ImGuiStyle and enum ImGuiCol_ only exist in the Docking branch..
# define DGIMST_ENABLE_IF_DOCKING(x) x
# else
// .. so disable them in the regular branch
# define DGIMST_ENABLE_IF_DOCKING(x)
# endif
2024-05-25 04:30:52 +00:00
// Note: The trick I'm using with these #defines below is called "X Macro"
// see https://en.wikipedia.org/wiki/X_macro (except I'm not calling the "entries" X,
// and have more then one kind of entry per table)
// If you're wondering about the D3_ prefix on the macros, I originally wrote this for dhewm3.
// this table contains all members of struct ImGuiStyle that come before the Colors array
// when updating Dear ImGui, this might have to be adjusted for members that have been added/removed/renamed
# define D3_IMSTYLE_ATTRS \
D3_IMATTR_FLOAT ( Alpha ) \
D3_IMATTR_FLOAT ( DisabledAlpha ) \
D3_IMATTR_VEC2 ( WindowPadding ) \
D3_IMATTR_FLOAT ( WindowRounding ) \
D3_IMATTR_FLOAT ( WindowBorderSize ) \
D3_IMATTR_VEC2 ( WindowMinSize ) \
D3_IMATTR_VEC2 ( WindowTitleAlign ) \
2024-06-06 18:07:30 +00:00
D3_IMATTR_DIR ( WindowMenuButtonPosition ) \
2024-05-25 04:30:52 +00:00
D3_IMATTR_FLOAT ( ChildRounding ) \
D3_IMATTR_FLOAT ( ChildBorderSize ) \
D3_IMATTR_FLOAT ( PopupRounding ) \
D3_IMATTR_FLOAT ( PopupBorderSize ) \
D3_IMATTR_VEC2 ( FramePadding ) \
D3_IMATTR_FLOAT ( FrameRounding ) \
D3_IMATTR_FLOAT ( FrameBorderSize ) \
D3_IMATTR_VEC2 ( ItemSpacing ) \
D3_IMATTR_VEC2 ( ItemInnerSpacing ) \
D3_IMATTR_VEC2 ( CellPadding ) \
D3_IMATTR_VEC2 ( TouchExtraPadding ) \
D3_IMATTR_FLOAT ( IndentSpacing ) \
D3_IMATTR_FLOAT ( ColumnsMinSpacing ) \
D3_IMATTR_FLOAT ( ScrollbarSize ) \
D3_IMATTR_FLOAT ( ScrollbarRounding ) \
D3_IMATTR_FLOAT ( GrabMinSize ) \
D3_IMATTR_FLOAT ( GrabRounding ) \
D3_IMATTR_FLOAT ( LogSliderDeadzone ) \
D3_IMATTR_FLOAT ( TabRounding ) \
D3_IMATTR_FLOAT ( TabBorderSize ) \
D3_IMATTR_FLOAT ( TabMinWidthForCloseButton ) \
D3_IMATTR_FLOAT ( TabBarBorderSize ) \
2024-10-02 20:17:41 +00:00
D3_IMATTR_FLOAT ( TabBarOverlineSize ) \
2024-05-25 04:30:52 +00:00
D3_IMATTR_FLOAT ( TableAngledHeadersAngle ) \
D3_IMATTR_VEC2 ( TableAngledHeadersTextAlign ) \
2024-06-06 18:07:30 +00:00
D3_IMATTR_DIR ( ColorButtonPosition ) \
2024-05-25 04:30:52 +00:00
D3_IMATTR_VEC2 ( ButtonTextAlign ) \
D3_IMATTR_VEC2 ( SelectableTextAlign ) \
D3_IMATTR_FLOAT ( SeparatorTextBorderSize ) \
D3_IMATTR_VEC2 ( SeparatorTextAlign ) \
D3_IMATTR_VEC2 ( SeparatorTextPadding ) \
D3_IMATTR_VEC2 ( DisplayWindowPadding ) \
D3_IMATTR_VEC2 ( DisplaySafeAreaPadding ) \
2024-10-02 18:23:50 +00:00
DGIMST_ENABLE_IF_DOCKING ( D3_IMATTR_FLOAT ( DockingSeparatorSize ) ) \
2024-05-25 04:30:52 +00:00
D3_IMATTR_FLOAT ( MouseCursorScale ) \
D3_IMATTR_BOOL ( AntiAliasedLines ) \
D3_IMATTR_BOOL ( AntiAliasedLinesUseTex ) \
D3_IMATTR_BOOL ( AntiAliasedFill ) \
D3_IMATTR_FLOAT ( CurveTessellationTol ) \
D3_IMATTR_FLOAT ( CircleTessellationMaxError )
// this table contains the members of struct ImGuiStyle that come after the Colors array
// when updating Dear ImGui, this might have to be adjusted for members that have been added/removed/renamed
# define D3_IMSTYLE_BEHAVIORS \
D3_IMATTR_FLOAT ( HoverStationaryDelay ) \
D3_IMATTR_FLOAT ( HoverDelayShort ) \
D3_IMATTR_FLOAT ( HoverDelayNormal ) \
D3_IMATTR_INT ( HoverFlagsForTooltipMouse ) \
D3_IMATTR_INT ( HoverFlagsForTooltipNav )
// this table contains one entry for every value of enum ImGuiCol_ (except for ImGuiCol_COUNT)
// as you can see, the "ImGuiCol_" prefix is left out in this table,
// it's added programatically when needed
// when updating Dear ImGui, this might have to be adjusted for enum members that have been added/removed/renamed
# define D3_IMSTYLE_COLORS \
D3_IMSTYLE_COLOR ( Text ) \
D3_IMSTYLE_COLOR ( TextDisabled ) \
D3_IMSTYLE_COLOR ( WindowBg ) \
D3_IMSTYLE_COLOR ( ChildBg ) \
D3_IMSTYLE_COLOR ( PopupBg ) \
D3_IMSTYLE_COLOR ( Border ) \
D3_IMSTYLE_COLOR ( BorderShadow ) \
D3_IMSTYLE_COLOR ( FrameBg ) \
D3_IMSTYLE_COLOR ( FrameBgHovered ) \
D3_IMSTYLE_COLOR ( FrameBgActive ) \
D3_IMSTYLE_COLOR ( TitleBg ) \
D3_IMSTYLE_COLOR ( TitleBgActive ) \
D3_IMSTYLE_COLOR ( TitleBgCollapsed ) \
D3_IMSTYLE_COLOR ( MenuBarBg ) \
D3_IMSTYLE_COLOR ( ScrollbarBg ) \
D3_IMSTYLE_COLOR ( ScrollbarGrab ) \
D3_IMSTYLE_COLOR ( ScrollbarGrabHovered ) \
D3_IMSTYLE_COLOR ( ScrollbarGrabActive ) \
D3_IMSTYLE_COLOR ( CheckMark ) \
D3_IMSTYLE_COLOR ( SliderGrab ) \
D3_IMSTYLE_COLOR ( SliderGrabActive ) \
D3_IMSTYLE_COLOR ( Button ) \
D3_IMSTYLE_COLOR ( ButtonHovered ) \
D3_IMSTYLE_COLOR ( ButtonActive ) \
D3_IMSTYLE_COLOR ( Header ) \
D3_IMSTYLE_COLOR ( HeaderHovered ) \
D3_IMSTYLE_COLOR ( HeaderActive ) \
D3_IMSTYLE_COLOR ( Separator ) \
D3_IMSTYLE_COLOR ( SeparatorHovered ) \
D3_IMSTYLE_COLOR ( SeparatorActive ) \
D3_IMSTYLE_COLOR ( ResizeGrip ) \
D3_IMSTYLE_COLOR ( ResizeGripHovered ) \
D3_IMSTYLE_COLOR ( ResizeGripActive ) \
D3_IMSTYLE_COLOR ( TabHovered ) \
2024-10-02 20:17:41 +00:00
D3_IMSTYLE_COLOR ( Tab ) \
D3_IMSTYLE_COLOR ( TabSelected ) \
D3_IMSTYLE_COLOR ( TabSelectedOverline ) \
D3_IMSTYLE_COLOR ( TabDimmed ) \
D3_IMSTYLE_COLOR ( TabDimmedSelected ) \
D3_IMSTYLE_COLOR ( TabDimmedSelectedOverline ) \
2024-10-02 18:23:50 +00:00
DGIMST_ENABLE_IF_DOCKING ( D3_IMSTYLE_COLOR ( DockingPreview ) ) \
DGIMST_ENABLE_IF_DOCKING ( D3_IMSTYLE_COLOR ( DockingEmptyBg ) ) \
2024-05-25 04:30:52 +00:00
D3_IMSTYLE_COLOR ( PlotLines ) \
D3_IMSTYLE_COLOR ( PlotLinesHovered ) \
D3_IMSTYLE_COLOR ( PlotHistogram ) \
D3_IMSTYLE_COLOR ( PlotHistogramHovered ) \
D3_IMSTYLE_COLOR ( TableHeaderBg ) \
D3_IMSTYLE_COLOR ( TableBorderStrong ) \
D3_IMSTYLE_COLOR ( TableBorderLight ) \
D3_IMSTYLE_COLOR ( TableRowBg ) \
D3_IMSTYLE_COLOR ( TableRowBgAlt ) \
2024-10-02 20:17:41 +00:00
D3_IMSTYLE_COLOR ( TextLink ) \
2024-05-25 04:30:52 +00:00
D3_IMSTYLE_COLOR ( TextSelectedBg ) \
D3_IMSTYLE_COLOR ( DragDropTarget ) \
2024-10-29 02:55:07 +00:00
D3_IMSTYLE_COLOR ( NavCursor ) \
2024-05-25 04:30:52 +00:00
D3_IMSTYLE_COLOR ( NavWindowingHighlight ) \
D3_IMSTYLE_COLOR ( NavWindowingDimBg ) \
D3_IMSTYLE_COLOR ( ModalWindowDimBg )
static inline char * skipWhitespace ( const char * s ) {
while ( * s = = ' ' | | * s = = ' \t ' )
+ + s ;
return ( char * ) s ;
}
# define D3_IMATTR_FLOAT( NAME ) \
if ( sscanf ( line , # NAME " = %f " , & f1 ) = = 1 ) { \
s . NAME = f1 ; \
return ; \
}
# define D3_IMATTR_VEC2( NAME ) \
if ( sscanf ( line , # NAME " = %f , %f " , & f1 , & f2 ) = = 2 ) { \
s . NAME . x = f1 ; s . NAME . y = f2 ; \
return ; \
}
# define D3_IMATTR_INT( NAME ) \
if ( sscanf ( line , # NAME " = %d " , & i ) = = 1 ) { \
s . NAME = i ; \
return ; \
}
2024-06-06 18:07:30 +00:00
# define D3_IMATTR_DIR( NAME ) \
if ( sscanf ( line , # NAME " = %d " , & i ) = = 1 ) { \
s . NAME = ( ImGuiDir ) i ; \
return ; \
}
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_BOOL( NAME ) \
if ( sscanf ( line , # NAME " = %d " , & i ) = = 1 ) { \
s . NAME = ( i ! = 0 ) ; \
return ; \
}
static void parseStyleLine ( ImGuiStyle & s , const char * line )
{
float f1 = 0 , f2 = 0 ;
int i = 0 ;
// with the D3_IMATTR_* #defines above, the following
// `D3_IMSTYLE_ATTRS` line turns into:
// if ( sscanf( line, "Alpha = %f", &f1 ) == 1 ) {
// s . Alpha = f1;
// return;
// }
// if ( sscanf( line, "DisabledAlpha = %f", &f1 ) == 1 ) {
// s . DisabledAlpha = f1;
// return;
// }
// if ( sscanf( line, "WindowPadding = %f , %f", &f1, &f2 ) == 2 ) {
// s . WindowPadding .x = f1; s . WindowPadding .y = f2;
// return;
// }
// etc
D3_IMSTYLE_ATTRS
// NOTE: if a member is renamed, for backwards-compatibility you could add code here like
// if ( sscanf( line, "OldName = %f", %f1 ) == 1 ) {
// s.NewName = f;
// return;
// }
warnPrintf ( " Invalid line in ImGui style under [style] section: '%s' \n " , line ) ;
}
static void parseBehaviorLine ( ImGuiStyle & s , const char * line )
{
float f1 = 0 , f2 = 0 ;
( void ) f2 ; // currently unused in behavior section
int i = 0 ;
D3_IMSTYLE_BEHAVIORS
// NOTE: same thing for backwards-compatbility as in parseStyleLine applies here
warnPrintf ( " Invalid line in ImGui style under [behaviors] section: '%s' \n " , line ) ;
}
# undef D3_IMATTR_FLOAT
# undef D3_IMATTR_VEC2
# undef D3_IMATTR_INT
2024-06-06 18:07:30 +00:00
# undef D3_IMATTR_DIR
2024-05-25 04:30:52 +00:00
# undef D3_IMATTR_BOOL
2024-10-02 20:17:41 +00:00
namespace {
// for renamed colors
struct ImGuiColorBackwardCompat {
const char * oldColorStr ;
enum ImGuiCol_ newColorVal ;
} ;
static struct ImGuiColorBackwardCompat backwardCompatColorMappings [ ] = {
2024-10-29 02:55:07 +00:00
{ " TabActive " , ImGuiCol_TabSelected } , // renamed in 1.90.9
{ " TabUnfocused " , ImGuiCol_TabDimmed } , // renamed in 1.90.9
{ " TabUnfocusedActive " , ImGuiCol_TabDimmedSelected } , // renamed in 1.90.9
{ " NavHighlight " , ImGuiCol_NavCursor } , // renamed in 1.91.4
2024-10-02 20:17:41 +00:00
} ;
} //anon namespace
2024-05-25 04:30:52 +00:00
static void parseColorLine ( ImGuiStyle & s , const char * line )
{
ImVec4 c ;
# define D3_IMSTYLE_COLOR( NAME ) \
if ( sscanf ( line , # NAME " = %f , %f , %f , %f " , & c . x , & c . y , & c . z , & c . w ) = = 4 ) { \
s . Colors [ ImGuiCol_ # # NAME ] = c ; \
return ; \
}
D3_IMSTYLE_COLORS
# undef D3_IMSTYLE_COLOR
2024-10-02 20:17:41 +00:00
for ( const ImGuiColorBackwardCompat & bc : backwardCompatColorMappings ) {
char matchString [ 64 ] ;
snprintf ( matchString , sizeof ( matchString ) , " %s = %%f , %%f , %%f , %%f " , bc . oldColorStr ) ;
if ( sscanf ( line , matchString , & c . x , & c . y , & c . z , & c . w ) = = 4 ) {
s . Colors [ bc . newColorVal ] = c ;
return ;
}
}
2024-05-25 04:30:52 +00:00
warnPrintf ( " Invalid line in ImGui style under [colors] section: '%s' \n " , line ) ;
}
namespace DG_IMSAVESTYLE_NAMESPACE {
bool ReadImGuiStyle ( ImGuiStyle & s , const char * filename )
{
FILE * f = DG_IMSAVESTYLE_FOPEN ( filename , " r " ) ; // TODO: "rt" on Windows?
if ( f = = nullptr ) {
2024-10-02 18:23:50 +00:00
// Note: Turns out that printing warning here is annoying, there's nothing wrong with the
// user not having saved a style yet.. just return false, the caller can log if appropriate
2024-05-25 04:30:52 +00:00
return false ;
}
char lineBuf [ 256 ] ;
int section = - 1 ; // 0: style, 1: behaviors, 2: colors
for ( char * line = fgets ( lineBuf , sizeof ( lineBuf ) , f ) ;
line ! = nullptr ;
line = fgets ( lineBuf , sizeof ( lineBuf ) , f ) )
{
// skip whitespace, if any
line = skipWhitespace ( line ) ;
if ( * line = = ' # ' ) // skip comment lines
continue ;
if ( * line = = ' [ ' ) { // start of a section
const char * secStr = line + 1 ; // skip '['
secStr = skipWhitespace ( secStr ) ;
// "[style]" "[behaviors]" "[colors]"
if ( strncmp ( secStr , " style " , 5 ) = = 0 ) {
section = 0 ;
} else if ( strncmp ( secStr , " behaviors " , 9 ) = = 0 ) {
section = 1 ;
} else if ( strncmp ( secStr , " colors " , 6 ) = = 0 ) {
section = 2 ;
} else {
warnPrintf ( " Invalid line that looks like a section in ImGui style: '%s' \n " , line ) ;
}
continue ;
}
if ( * line = = ' \r ' | | * line = = ' \n ' ) {
continue ; // empty line
}
if ( section = = 0 ) {
parseStyleLine ( s , line ) ;
} else if ( section = = 1 ) {
parseBehaviorLine ( s , line ) ;
} else if ( section = = 2 ) {
parseColorLine ( s , line ) ;
} else {
warnPrintf ( " Invalid line in ImGui before start of any section: '%s' \n " , line ) ;
}
}
return true ;
}
bool WriteImGuiStyle ( const ImGuiStyle & s , const char * filename ) {
FILE * f = DG_IMSAVESTYLE_FOPEN ( filename , " w " ) ; // TODO: "wt" on Windows?
if ( f = = nullptr ) {
warnPrintf ( " Couldn't open '%s' for writing \n " , filename ) ;
return false ;
}
fprintf ( f , " [style] \n " ) ;
# define D3_IMATTR_FLOAT( NAME ) \
2024-05-25 23:23:30 +00:00
fprintf ( f , " %s = %g \n " , # NAME , s . NAME ) ;
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_VEC2( NAME ) \
2024-05-25 23:23:30 +00:00
fprintf ( f , " %s = %g, %g \n " , # NAME , s . NAME . x , s . NAME . y ) ;
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_INT( NAME ) \
2024-05-25 23:23:30 +00:00
fprintf ( f , " %s = %d \n " , # NAME , s . NAME ) ;
2024-06-06 18:07:30 +00:00
# define D3_IMATTR_DIR( NAME ) \
fprintf ( f , " %s = %d \n " , # NAME , s . NAME ) ;
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_BOOL( NAME ) \
2024-05-25 23:23:30 +00:00
fprintf ( f , " %s = %d \n " , # NAME , ( int ) ( s . NAME ) ) ;
2024-05-25 04:30:52 +00:00
// this (together with the D3_IMATTR_* defines in the previous lines)
// expands the D3_IMSTYLE_ATTRS table to
// fprintf( f, "Alpha = %g\n", s . Alpha );
// fprintf( f, "DisabledAlpha = %g\n", s . DisabledAlpha );
// fprintf( f, "WindowPadding = %g %g\n", s . WindowPadding . x, s . WindowPadding . y );
// etc
D3_IMSTYLE_ATTRS
fprintf ( f , " \n [behaviors] \n " ) ;
// same for behaviors
D3_IMSTYLE_BEHAVIORS
# undef D3_IMATTR_FLOAT
# undef D3_IMATTR_VEC2
# undef D3_IMATTR_INT
2024-06-06 18:07:30 +00:00
# undef D3_IMATTR_DIR
2024-05-25 04:30:52 +00:00
# undef D3_IMATTR_BOOL
fprintf ( f , " \n [colors] \n " ) ;
# define D3_IMSTYLE_COLOR( NAME ) { \
const ImVec4 & c = s . Colors [ ImGuiCol_ # # NAME ] ; \
2024-05-25 23:23:30 +00:00
fprintf ( f , " %s = %g, %g, %g, %g \n " , # NAME , c . x , c . y , c . z , c . w ) ; \
2024-05-25 04:30:52 +00:00
}
// this turns into
// { const ImVec4& c = s.Colors[ ImGuiCol_Text ]; fprintf( f, "Text = %g %g %g %g\n", c.x, c.y, c.z, c.w ); }
// { const ImVec4& c = s.Colors[ ImGuiCol_TextDisabled ]; fprintf( f, "TextDisabled = %g %g %g %g\n", c.x, c.y, c.z, c.w ); }
// etc
D3_IMSTYLE_COLORS
# undef D3_IMSTYLE_COLOR
fprintf ( f , " \n " ) ;
fflush ( f ) ;
fclose ( f ) ;
return true ;
}
2024-05-25 23:23:30 +00:00
static inline int numSpaces ( const char * name , int targetLen )
{
int ret = targetLen - strlen ( name ) ;
return ret > 0 ? ret : 0 ;
}
2024-05-26 01:56:28 +00:00
ImGuiTextBuffer WriteImGuiStyleToCode ( const ImGuiStyle & s , const ImGuiStyle * refStyle )
2024-05-25 16:15:07 +00:00
{
ImGuiTextBuffer ret ;
ret . reserve ( 6000 ) ;
ret . append ( " ImGuiStyle& style = ImGui::GetStyle(); \n " ) ;
# define D3_IMATTR_FLOAT( NAME ) \
2024-05-26 01:56:28 +00:00
if ( refStyle = = nullptr | | s . NAME ! = refStyle - > NAME ) { \
ret . appendf ( " style.%s %*s= %g; \n " , # NAME , numSpaces ( # NAME , 27 ) , " " , s . NAME ) ; \
}
2024-05-25 16:15:07 +00:00
# define D3_IMATTR_VEC2( NAME ) \
2024-05-26 01:56:28 +00:00
if ( refStyle = = nullptr | | s . NAME . x ! = refStyle - > NAME . x | | s . NAME . y ! = refStyle - > NAME . y ) { \
ret . appendf ( " style.%s %*s= ImVec2( %g, %g ); \n " , # NAME , numSpaces ( # NAME , 27 ) , " " , s . NAME . x , s . NAME . y ) ; \
}
2024-05-25 16:15:07 +00:00
# define D3_IMATTR_INT( NAME ) \
2024-05-26 01:56:28 +00:00
if ( refStyle = = nullptr | | s . NAME ! = refStyle - > NAME ) { \
ret . appendf ( " style.%s = %d; // TODO: flag \n " , # NAME , s . NAME ) ; \
}
2024-06-06 18:07:30 +00:00
# define D3_IMATTR_DIR( NAME ) \
if ( refStyle = = nullptr | | s . NAME ! = refStyle - > NAME ) { \
ret . appendf ( " style.%s = %d; \n " , # NAME , s . NAME ) ; \
}
2024-05-25 16:15:07 +00:00
# define D3_IMATTR_BOOL( NAME ) \
2024-05-26 01:56:28 +00:00
if ( refStyle = = nullptr | | s . NAME ! = refStyle - > NAME ) { \
ret . appendf ( " style.%s %*s= %s; \n " , # NAME , numSpaces ( # NAME , 27 ) , " " , s . NAME ? " true " : " false " ) ; \
}
2024-05-25 16:15:07 +00:00
D3_IMSTYLE_ATTRS
ret . append ( " \n " ) ;
D3_IMSTYLE_BEHAVIORS
# undef D3_IMATTR_FLOAT
# undef D3_IMATTR_VEC2
# undef D3_IMATTR_INT
2024-06-06 18:07:30 +00:00
# undef D3_IMATTR_DIR
2024-05-25 16:15:07 +00:00
# undef D3_IMATTR_BOOL
ret . append ( " \n ImVec4* colors = style.Colors; \n " ) ;
2024-05-26 01:56:28 +00:00
for ( ImGuiCol cIdx = 0 ; cIdx < ImGuiCol_COUNT ; + + cIdx ) {
const ImVec4 & c = s . Colors [ cIdx ] ;
if ( refStyle ! = nullptr ) {
const ImVec4 & c2 = refStyle - > Colors [ cIdx ] ;
if ( c . x = = c2 . x & & c . y = = c2 . y & & c . z = = c2 . z & & c . w = = c2 . w ) {
// same colors, nothing to do
continue ;
}
}
const char * name = ImGui : : GetStyleColorName ( cIdx ) ;
ret . appendf ( " colors[ ImGuiCol_%s ]%*s = ImVec4( %g, %g, %g, %g ); \n " ,
name , numSpaces ( name , 21 ) , " " , c . x , c . y , c . z , c . w ) ;
2024-05-25 16:15:07 +00:00
}
ret . append ( " \n " ) ;
return ret ;
}
2024-05-25 04:30:52 +00:00
} //namespace DG
// check correctness of the X macro tables above (detect when something is added/removed/renamed in struct ImGuiStyle or enum ImGuiCol_)
namespace {
2024-10-02 18:23:50 +00:00
// recreate enum ImGuiCol_ from the D3_IMSTYLE_COLORS table to compare its members
// so we can easily detect when (and where) one is added
enum D3CHECK_ImguiCol_ {
# define D3_IMSTYLE_COLOR( NAME ) D3CHECK_ImGuiCol_ ## NAME ,
D3_IMSTYLE_COLORS
2024-05-25 04:30:52 +00:00
# undef D3_IMSTYLE_COLOR
2024-10-02 18:23:50 +00:00
D3CHECK_ImGuiCol_COUNT
} ;
# define D3_IMSTYLE_COLOR( NAME ) \
static_assert ( ( int ) D3CHECK_ImGuiCol_ # # NAME = = ( int ) ImGuiCol_ # # NAME , " Wrong value for ImGuiCol_ " # NAME " - probably something was added to enum ImGuiCol_ before it? => => adjust D3_IMSTYLE_COLORS table above " ) ;
D3_IMSTYLE_COLORS
# undef D3_IMSTYLE_COLOR
// if the following is the only failing static_assert, the new color was probably added to the end
static_assert ( ( int ) D3CHECK_ImGuiCol_COUNT = = ( int ) ImGuiCol_COUNT , " something was added or removed in enum ImGuiCol_ => adjust D3_IMSTYLE_COLORS table above " ) ;
2024-05-25 04:30:52 +00:00
// recreate struct ImGuiStyle from the tables above and see if they're identical
// (this struct is only used for the static assertions below)
struct D3_ImGuiStyle_Check {
# define D3_IMATTR_FLOAT( NAME ) float NAME ;
# define D3_IMATTR_VEC2( NAME ) ImVec2 NAME ;
# define D3_IMATTR_INT( NAME ) int NAME ;
2024-06-06 18:07:30 +00:00
# define D3_IMATTR_DIR( NAME ) ImGuiDir NAME ;
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_BOOL( NAME ) bool NAME ;
// this expands to all the ImGuiStyle members, up to (excluding) Colors
// exactly like in ImGuiStyle (except the pseudo-enums like ImGuiDir are plain ints here)
D3_IMSTYLE_ATTRS
ImVec4 Colors [ ImGuiCol_COUNT ] ;
// just like the other members/attributes, expand the behaviors
D3_IMSTYLE_BEHAVIORS
# undef D3_IMATTR_FLOAT
# undef D3_IMATTR_VEC2
# undef D3_IMATTR_INT
2024-06-06 18:07:30 +00:00
# undef D3_IMATTR_DIR
2024-05-25 04:30:52 +00:00
# undef D3_IMATTR_BOOL
} ;
template < class T , class U >
struct is_same {
static constexpr bool value = false ;
} ;
template < class T >
struct is_same < T , T > {
static constexpr bool value = true ;
} ;
# define D3_IMATTR_FLOAT( NAME ) \
static_assert ( offsetof ( ImGuiStyle , NAME ) = = offsetof ( D3_ImGuiStyle_Check , NAME ) , \
" member " # NAME " not at expected offset - is the member before it missing from the list, or moved to another position? " ) ; \
static_assert ( is_same < decltype ( ImGuiStyle : : NAME ) , float > : : value , " expected member " # NAME " to be a float - adjust the list! " ) ;
# define D3_IMATTR_VEC2( NAME ) \
static_assert ( offsetof ( ImGuiStyle , NAME ) = = offsetof ( D3_ImGuiStyle_Check , NAME ) , \
" member " # NAME " not at expected offset - is the member before it missing from the list, or moved to another position? " ) ; \
static_assert ( is_same < decltype ( ImGuiStyle : : NAME ) , ImVec2 > : : value , " expected member " # NAME " to be an ImVec2 - adjust the list! " ) ;
# define D3_IMATTR_INT( NAME ) \
static_assert ( offsetof ( ImGuiStyle , NAME ) = = offsetof ( D3_ImGuiStyle_Check , NAME ) , \
" member " # NAME " not at expected offset - is the member before it missing from the list, or moved to another position? " ) ; \
static_assert ( is_same < decltype ( ImGuiStyle : : NAME ) , int > : : value , " expected member " # NAME " to be an int - adjust the list! " ) ;
2024-06-06 18:07:30 +00:00
# define D3_IMATTR_DIR( NAME ) \
static_assert ( offsetof ( ImGuiStyle , NAME ) = = offsetof ( D3_ImGuiStyle_Check , NAME ) , \
" member " # NAME " not at expected offset - is the member before it missing from the list, or moved to another position? " ) ; \
static_assert ( is_same < decltype ( ImGuiStyle : : NAME ) , ImGuiDir > : : value , " expected member " # NAME " to be an ImGuiDir - adjust the list! " ) ;
2024-05-25 04:30:52 +00:00
# define D3_IMATTR_BOOL( NAME ) \
static_assert ( offsetof ( ImGuiStyle , NAME ) = = offsetof ( D3_ImGuiStyle_Check , NAME ) , \
" member " # NAME " not at expected offset - is the member before it missing from the list, or moved to another position? " ) ; \
static_assert ( is_same < decltype ( ImGuiStyle : : NAME ) , bool > : : value , " expected member " # NAME " to be a bool - adjust the list! " ) ;
// expanding those static assertions for offset and type for all attributes and behaviors
D3_IMSTYLE_ATTRS
D3_IMSTYLE_BEHAVIORS
# undef D3_IMATTR_FLOAT
# undef D3_IMATTR_VEC2
# undef D3_IMATTR_INT
# undef D3_IMATTR_BOOL
static_assert ( offsetof ( ImGuiStyle , Colors ) = = offsetof ( D3_ImGuiStyle_Check , Colors ) , " member Colors not at expected offset " ) ;
// if all other static assertions passed and the following failed, probably a member was added at the end of the ImGuiStyle struct
static_assert ( sizeof ( D3_ImGuiStyle_Check ) = = sizeof ( ImGuiStyle ) ,
" something seems to be missing or wrong type in D3_IMSTYLE_ATTRS or D3_IMSTYLE_BEHAVIORS " ) ;
} //anon namespace