-
Notifications
You must be signed in to change notification settings - Fork 15
/
imgui_savestyle.cpp
640 lines (539 loc) · 23.2 KB
/
imgui_savestyle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
/*
* 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.92.2/3 (incl. Docking Branch)
*
* 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__ )
#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
// 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_DIR( 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( TabBarOverlineSize ) \
D3_IMATTR_FLOAT( TableAngledHeadersAngle ) \
D3_IMATTR_VEC2( TableAngledHeadersTextAlign ) \
D3_IMATTR_DIR( 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 ) \
DGIMST_ENABLE_IF_DOCKING( D3_IMATTR_FLOAT( DockingSeparatorSize ) ) \
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 ) \
D3_IMSTYLE_COLOR( Tab ) \
D3_IMSTYLE_COLOR( TabSelected ) \
D3_IMSTYLE_COLOR( TabSelectedOverline ) \
D3_IMSTYLE_COLOR( TabDimmed ) \
D3_IMSTYLE_COLOR( TabDimmedSelected ) \
D3_IMSTYLE_COLOR( TabDimmedSelectedOverline ) \
DGIMST_ENABLE_IF_DOCKING( D3_IMSTYLE_COLOR( DockingPreview ) ) \
DGIMST_ENABLE_IF_DOCKING( D3_IMSTYLE_COLOR( DockingEmptyBg ) ) \
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( TextLink ) \
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_DIR( NAME ) \
if ( sscanf( line, #NAME " = %d", &i ) == 1 ) { \
s . NAME = (ImGuiDir)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_DIR
#undef D3_IMATTR_BOOL
namespace {
// for renamed colors
struct ImGuiColorBackwardCompat {
const char* oldColorStr;
enum ImGuiCol_ newColorVal;
};
static struct ImGuiColorBackwardCompat backwardCompatColorMappings[] = {
{ "TabActive", ImGuiCol_TabSelected },
{ "TabUnfocused", ImGuiCol_TabDimmed },
{ "TabUnfocusedActive", ImGuiCol_TabDimmedSelected },
};
} //anon namespace
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;
// }
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;
}
}
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 ) {
// 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
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_DIR( 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_DIR
#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_DIR( NAME ) \
if ( refStyle == nullptr || s. NAME != refStyle-> NAME ) { \
ret.appendf( "style.%s = %d;\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_DIR
#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 {
// 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
#undef D3_IMSTYLE_COLOR
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" );
// 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_DIR( NAME ) ImGuiDir 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_DIR
#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_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!" );
#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