mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-29 15:42:28 +00:00
567 lines
21 KiB
C++
567 lines
21 KiB
C++
/*
|
|
* Functions to read/write a Dear ImGui style (ImGuiStyle) from/to a (ini-like)
|
|
* textfile, or generating C++ code for it.
|
|
*
|
|
* Hosted at https://github.com/DanielGibson/Snippets/
|
|
*
|
|
* Written for/tested with Dear ImGui v1.90.6
|
|
*
|
|
* 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
|
|
// style to a sane default before calling this function.
|
|
// returns true on success, false if opening the file failed
|
|
extern bool ReadImGuiStyle( ImGuiStyle& style, const char* filename );
|
|
|
|
// generate C++ code that replicates the given style into a text buffer
|
|
// (that you can write to a file or set the clipboard from or whatever)
|
|
// if refStyle is set, only differences in style compared to refStyle are written
|
|
extern ImGuiTextBuffer WriteImGuiStyleToCode( const ImGuiStyle& style, const ImGuiStyle* refStyle = nullptr );
|
|
} //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
|
|
//#define warnPrintf(...) fprintf( stderr, "Warning: " __VA_ARGS__ )
|
|
|
|
// DG: adjustment for dhewm3:
|
|
#include "framework/Common.h"
|
|
#undef strncmp // No, I don't want to use idStr::Cmpn() in this file.
|
|
#define warnPrintf(...) common->Warning( __VA_ARGS__ )
|
|
|
|
// 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 ) \
|
|
D3_IMATTR_INT( WindowMenuButtonPosition ) \
|
|
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 ) \
|
|
D3_IMATTR_FLOAT( TableAngledHeadersAngle ) \
|
|
D3_IMATTR_VEC2( TableAngledHeadersTextAlign ) \
|
|
D3_IMATTR_INT( ColorButtonPosition ) \
|
|
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 ) \
|
|
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( Tab ) \
|
|
D3_IMSTYLE_COLOR( TabHovered ) \
|
|
D3_IMSTYLE_COLOR( TabActive ) \
|
|
D3_IMSTYLE_COLOR( TabUnfocused ) \
|
|
D3_IMSTYLE_COLOR( TabUnfocusedActive ) \
|
|
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 ) \
|
|
D3_IMSTYLE_COLOR( TextSelectedBg ) \
|
|
D3_IMSTYLE_COLOR( DragDropTarget ) \
|
|
D3_IMSTYLE_COLOR( NavHighlight ) \
|
|
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; \
|
|
}
|
|
|
|
#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
|
|
#undef D3_IMATTR_BOOL
|
|
|
|
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
|
|
|
|
// NOTE: here backwards-compat is also possible, like
|
|
// if ( sscanf( line, "OldColorName = %f , %f , %f , %f", &c.x, &c.y, &c.z, &c.w) == 4 ) {
|
|
// s.Colors[ ImGuiCol_NewColorName = c;
|
|
// return;
|
|
// }
|
|
|
|
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 ) {
|
|
warnPrintf( "Couldn't open '%s' for reading\n", filename );
|
|
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 ) \
|
|
fprintf( f, "%s = %g\n", #NAME, s . NAME );
|
|
#define D3_IMATTR_VEC2( NAME ) \
|
|
fprintf( f, "%s = %g, %g\n", #NAME, s . NAME . x, s . NAME . y );
|
|
#define D3_IMATTR_INT( NAME ) \
|
|
fprintf( f, "%s = %d\n", #NAME, s . NAME );
|
|
#define D3_IMATTR_BOOL( NAME ) \
|
|
fprintf( f, "%s = %d\n", #NAME, (int)( s . NAME ) );
|
|
|
|
// 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
|
|
#undef D3_IMATTR_BOOL
|
|
|
|
fprintf( f, "\n[colors]\n" );
|
|
|
|
#define D3_IMSTYLE_COLOR( NAME ) { \
|
|
const ImVec4& c = s.Colors[ ImGuiCol_ ## NAME ]; \
|
|
fprintf( f, "%s = %g, %g, %g, %g\n", #NAME, c.x, c.y, c.z, c.w ); \
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
static inline int numSpaces( const char* name, int targetLen )
|
|
{
|
|
int ret = targetLen - strlen(name);
|
|
return ret > 0 ? ret : 0;
|
|
}
|
|
|
|
ImGuiTextBuffer WriteImGuiStyleToCode( const ImGuiStyle& s, const ImGuiStyle* refStyle )
|
|
{
|
|
ImGuiTextBuffer ret;
|
|
ret.reserve(6000);
|
|
ret.append( "ImGuiStyle& style = ImGui::GetStyle();\n" );
|
|
|
|
#define D3_IMATTR_FLOAT( NAME ) \
|
|
if ( refStyle == nullptr || s. NAME != refStyle-> NAME ) { \
|
|
ret.appendf( "style.%s %*s= %g;\n", #NAME, numSpaces( #NAME , 27 ), "", s. NAME ); \
|
|
}
|
|
#define D3_IMATTR_VEC2( NAME ) \
|
|
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 ); \
|
|
}
|
|
#define D3_IMATTR_INT( NAME ) \
|
|
if ( refStyle == nullptr || s. NAME != refStyle-> NAME ) { \
|
|
ret.appendf( "style.%s = %d; // TODO: flag\n", #NAME, s. NAME ); \
|
|
}
|
|
#define D3_IMATTR_BOOL( NAME ) \
|
|
if ( refStyle == nullptr || s. NAME != refStyle-> NAME ) { \
|
|
ret.appendf( "style.%s %*s= %s;\n", #NAME, numSpaces( #NAME , 27 ), "", s. NAME ? "true" : "false" ); \
|
|
}
|
|
|
|
D3_IMSTYLE_ATTRS
|
|
|
|
ret.append("\n");
|
|
|
|
D3_IMSTYLE_BEHAVIORS
|
|
|
|
#undef D3_IMATTR_FLOAT
|
|
#undef D3_IMATTR_VEC2
|
|
#undef D3_IMATTR_INT
|
|
#undef D3_IMATTR_BOOL
|
|
|
|
ret.append( "\nImVec4* colors = style.Colors;\n" );
|
|
|
|
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 );
|
|
}
|
|
|
|
ret.append("\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
} //namespace DG
|
|
|
|
// check correctness of the X macro tables above (detect when something is added/removed/renamed in struct ImGuiStyle or enum ImGuiCol_)
|
|
namespace {
|
|
|
|
#define D3_IMSTYLE_COLOR(C) + 1
|
|
// "0 D3_IMSTYLE_COLORS" is expanded to 0 + 1 + 1 ... for each D3_IMSTYLE_COLOR entry
|
|
// => it should have the same value as the ImGuiCol_COUNT constant
|
|
static_assert( ImGuiCol_COUNT == 0 D3_IMSTYLE_COLORS,
|
|
"something was added or removed in enum ImGuiCol_ => adjust D3_IMSTYLE_COLORS table above" );
|
|
#undef D3_IMSTYLE_COLOR
|
|
|
|
// 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 ;
|
|
#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
|
|
#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!" );
|
|
|
|
#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
|