forked from ocornut/imgui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
imgui.cpp
11341 lines (9893 loc) · 467 KB
/
imgui.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
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ImGui library v1.38 WIP
// See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui
// Developed by Omar Cornut and ImGui contributors.
/*
Index
- MISSION STATEMENT
- END-USER GUIDE
- PROGRAMMER GUIDE (read me!)
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
- Can I have multiple widgets with the same label? (Yes)
- Why is my text output blurry?
- How can I load a different font than the default?
- How can I load multiple fonts?
- How can I display and input Chinese, Japanese, Korean characters?
- ISSUES & TODO-LIST
- CODE
- SAMPLE CODE
- FONT DATA
MISSION STATEMENT
=================
- easy to use to create code-driven and data-driven tools
- easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
- easy to hack and improve
- minimize screen real-estate usage
- minimize setup and maintenance
- minimize state storage on user side
- portable, minimize dependencies, run on target (consoles, phones, etc.)
- efficient runtime (NB- we do allocate when "growing" content - creating a window / opening a tree node for the first time, etc. - but a typical frame won't allocate anything)
- read about immediate-mode gui principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html
Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
- doesn't look fancy, doesn't animate
- limited layout features, intricate layouts are typically crafted in code
- occasionally uses statically sized buffers for string manipulations - won't crash, but some very long pieces of text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction.
END-USER GUIDE
==============
- double-click title bar to collapse window
- click upper right corner to close a window, available when 'bool* p_opened' is passed to ImGui::Begin()
- click and drag on lower right corner to resize window
- click and drag on any empty space to move window
- double-click/double-tap on lower right corner grip to auto-fit to content
- TAB/SHIFT+TAB to cycle through keyboard editable fields
- use mouse wheel to scroll
- use CTRL+mouse wheel to zoom window contents (if IO.FontAllowScaling is true)
- CTRL+Click on a slider to input value as text
- text editor:
- Hold SHIFT or use mouse to select text.
- CTRL+Left/Right to word jump
- CTRL+Shift+Left/Right to select words
- CTRL+A our Double-Click to select all
- CTRL+X,CTRL+C,CTRL+V to use OS clipboard
- CTRL+Z,CTRL+Y to undo/redo
- ESCAPE to revert text to its original value
- You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
PROGRAMMER GUIDE
================
- read the FAQ below this section!
- your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs.
- call and read ImGui::ShowTestWindow() for sample code demonstrating most features.
- see examples/ folder for standalone sample applications. e.g. examples/opengl_example/
- customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme).
- getting started:
- initialisation: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the 'Settings' data.
- every frame:
1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the 'Input' data, then call ImGui::NewFrame().
2/ use any ImGui function you want between NewFrame() and Render()
3/ ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure.
- all rendering information are stored into command-lists until ImGui::Render() is called.
- ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you must provide.
- effectively it means you can create widgets at any time in your code, regardless of "update" vs "render" considerations.
- refer to the examples applications in the examples/ folder for instruction on how to setup your code.
- a typical application skeleton may be:
// Application init
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = 1920.0f;
io.DisplaySize.y = 1280.0f;
io.DeltaTime = 1.0f/60.0f;
io.IniFilename = "imgui.ini";
// TODO: Fill others settings of the io structure
// Load texture
unsigned char* pixels;
int width, height, bytes_per_pixels;
io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height, &bytes_per_pixels);
// TODO: copy texture to graphics memory.
// TODO: store your texture pointer/identifier in 'io.Fonts->TexID'
// Application main loop
while (true)
{
// 1) get low-level input
// e.g. on Win32, GetKeyboardState(), or poll your events, etc.
// 2) TODO: fill all fields of IO structure and call NewFrame
ImGuiIO& io = ImGui::GetIO();
io.MousePos = mouse_pos;
io.MouseDown[0] = mouse_button_0;
io.KeysDown[i] = ...
ImGui::NewFrame();
// 3) most of your application code here - you can use any of ImGui::* functions at any point in the frame
ImGui::Begin("My window");
ImGui::Text("Hello, world.");
ImGui::End();
GameUpdate();
GameRender();
// 4) render & swap video buffers
ImGui::Render();
// swap video buffer, etc.
}
- after calling ImGui::NewFrame() you can read back 'io.WantCaptureMouse' and 'io.WantCaptureKeyboard' to tell if ImGui
wants to use your inputs. if it does you can discard/hide the inputs from the rest of your application.
API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
- 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
- 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
- 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
- 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
- 2015/03/17 (1.36) - renamed GetItemRectMin()/GetItemRectMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete).
- 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
- 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete).
- 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth
- 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete).
- 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
- 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
- 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
- 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
- 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
- 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
- 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
(1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
this sequence:
const void* png_data;
unsigned int png_size;
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
// <Copy to GPU>
became:
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// <Copy to GPU>
io.Fonts->TexID = (your_texture_identifier);
you now have much more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
it is now recommended your sample the font texture with bilinear interpolation.
(1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
(1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
(1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
- 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
- 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
- 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
- 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
- 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
- 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
- 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
- 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
- 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
- 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
- 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
======================================
Q: Can I have multiple widgets with the same label?
A: Yes. A primer on the use of labels/IDs in ImGui..
- Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget).
to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
Button("OK"); // Label = "OK", ID = hash of "OK"
Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
- Elements that are not clickable, such as Text() items don't need an ID.
- ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows
or in two different locations of a tree.
- if you have a same ID twice in the same location, you'll have a conflict:
Button("OK");
Button("OK"); // ID collision! Both buttons will be treated as the same.
Fear not! this is easy to solve and there are many ways to solve it!
- when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
use "##" to pass a complement to the ID that won't be visible to the end-user:
Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
- occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels.
use "###" to pass a label that isn't part of ID:
Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
- use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
this is the most convenient way of distinguish ID if you are iterating and creating many UI elements.
you can push a pointer, a string or an integer value. remember that ID are formed from the addition of everything in the ID stack!
for (int i = 0; i < 100; i++)
{
PushID(i);
Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique)
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj);
Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique)
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj->Name);
Button("Click"); // Label = "Click", ID = hash of string + "label" (unique)
PopID();
}
- more example showing that you can stack multiple prefixes into the ID stack:
Button("Click"); // Label = "Click", ID = hash of "Click"
PushID("node");
Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
PushID(my_ptr);
Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click"
PopID();
PopID();
- tree nodes implicitly creates a scope for you by calling PushID().
Button("Click"); // Label = "Click", ID = hash of "Click"
if (TreeNode("node"))
{
Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
TreePop();
}
- when working with trees, ID are used to preserve the opened/closed state of each tree node.
depending on your use cases you may want to use strings, indices or pointers as ID.
e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
Q: Why is my text output blurry?
A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
A: Use the font atlas to load the TTF file you want:
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
Q: How can I load multiple fonts?
A: Use the font atlas to pack them into a single texture:
ImFont* font0 = io.Fonts->AddFontDefault();
ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
// the first loaded font gets used by default
// use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
Q: How can I render and input Chinese, Japanese, Korean characters?
A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. ImGui will support UTF-8 encoding across the board.
Character input depends on you passing the right character code to io.AddInputCharacter(). The example applications do that.
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
io.ImeWindowHandle = MY_HWND; // To input using Microsoft IME, give ImGui the hwnd of your application
- tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code.
- tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
- tip: you can call Render() multiple times (e.g for VR renders).
- tip: call and read the ShowTestWindow() code for more example of how to use ImGui!
ISSUES & TODO-LIST
==================
- misc: merge or clarify ImVec4 vs ImRect?
- window: add horizontal scroll
- window: fix resize grip rendering scaling along with Rounding style setting
- window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit?
- window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list.
- window: allow resizing of child windows (possibly given min/max for each axis?)
- window: background options for child windows, border option (disable rounding)
- window: resizing from any sides? + mouse cursor directives for app.
- widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc.
- widgets: clean up widgets internal toward exposing everything.
- main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them.
- main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
!- input number: large int not reliably supported because of int<>float conversions.
- input number: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
- input number: use mouse wheel to step up/down
- input number: non-decimal input.
- text: proper alignment options
- layout: horizontal layout helper (github issue #97)
- layout: more generic alignment state (left/right/centered) for single items?
- layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding.
- columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (github issue #125)
- columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) (github issue #125)
- columns: columns header to act as button (~sort op) and allow resize/reorder (github issue #125)
- columns: user specify columns size (github issue #125)
- popup: border options. richer api like BeginChild() perhaps? (github issue #197)
- combo: turn child handling code into pop up helper
- combo: contents should extends to fit label if combo widget is small
- listbox: multiple selection
- listbox: user may want to initial scroll to focus on the one selected value?
! menubar, menus (github issue #126)
- tabs
- gauge: various forms of gauge/loading bars widgets
- color: better color editor.
- plot: make it easier for user to draw extra stuff into the graph (e.g: draw basis, highlight certain points, 2d plots, multiple plots)
- plot: "smooth" automatic scale over time, user give an input 0.0(full user scale) 1.0(full derived from value)
- plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID)
- file selection widget -> build the tool in our codebase to improve model-dialog idioms
- slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt()
- slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar).
- slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate.
- text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now.
- text edit: centered text for slider as input text so it matches typical positioning.
- text edit: flag to disable live update of the user buffer.
- text edit: field resize behavior - field could stretch when being edited? hover tooltip shows more text?
- text edit: add multi-line text edit
- tree: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings
- settings: write more decent code to allow saving/loading new fields
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file
! style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost.
- style: checkbox: padding for "active" color should be a multiplier of the
- style: colorbox not always square?
- text: simple markup language for color change?
- log: LogButtons() options for specifying depth and/or hiding depth slider
- log: have more control over the log scope (e.g. stop logging when leaving current tree node scope)
- log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard)
- log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs.
- filters: set a current filter that tree node can automatically query to hide themselves
- filters: handle wildcards (with implicit leading/trailing *), regexps
- shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus)
! keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing
- keyboard: full keyboard navigation and focus.
- input: rework IO to be able to pass actual events to fix temporal aliasing issues.
- input: support track pad style scrolling & slider edit.
- tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen).
- portability: big-endian test/support (github issue #81)
- misc: mark printf compiler attributes on relevant functions
- misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL)
- misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon?
- style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space?
- style editor: color child window height expressed in multiple of line height.
- optimization/render: use indexed rendering to reduce vertex data cost (e.g. for remote/networked imgui)
- optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)?
- optimization: turn some the various stack vectors into statically-sized arrays
- optimization: better clipping for multi-component widgets
*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "imgui.h"
#include <ctype.h> // toupper, isprint
#include <math.h> // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf
#include <stdint.h> // intptr_t
#include <stdio.h> // vsnprintf, sscanf
#include <new> // new (ptr)
#ifdef _MSC_VER
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#endif
// Clang warnings with -Weverything
#ifdef __clang__
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning : function xx could be declared with attribute 'noreturn' warning // GetDefaultFontData() asserts which some implementation makes it never return.
#endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#endif
//-------------------------------------------------------------------------
// STB libraries implementation
//-------------------------------------------------------------------------
struct ImGuiTextEditState;
//#define IMGUI_STB_NAMESPACE ImStb
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
#ifdef IMGUI_STB_NAMESPACE
namespace IMGUI_STB_NAMESPACE
{
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#endif
#define STBRP_ASSERT(x) IM_ASSERT(x)
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
#define STBRP_STATIC
#define STB_RECT_PACK_IMPLEMENTATION
#endif
#include "stb_rect_pack.h"
#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
#define STBTT_assert(x) IM_ASSERT(x)
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
#define STBTT_STATIC
#define STB_TRUETYPE_IMPLEMENTATION
#endif
#include "stb_truetype.h"
#undef STB_TEXTEDIT_STRING
#undef STB_TEXTEDIT_CHARTYPE
#define STB_TEXTEDIT_STRING ImGuiTextEditState
#define STB_TEXTEDIT_CHARTYPE ImWchar
#include "stb_textedit.h"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef IMGUI_STB_NAMESPACE
} // namespace ImStb
using namespace IMGUI_STB_NAMESPACE;
#endif
//-------------------------------------------------------------------------
// Forward Declarations
//-------------------------------------------------------------------------
struct ImRect;
struct ImGuiColMod;
struct ImGuiStyleMod;
struct ImGuiDrawContext;
struct ImGuiTextEditState;
struct ImGuiIniData;
struct ImGuiState;
struct ImGuiWindow;
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false);
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
static void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
static void RenderTextClipped(ImVec2 pos, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& clip_max);
static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false);
static void SetFont(ImFont* font);
static bool ItemAdd(const ImRect& bb, const ImGuiID* id);
static void ItemSize(ImVec2 size, float text_offset_y = 0.0f);
static void ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
static void PushColumnClipRect(int column_index = -1);
static bool IsClippedEx(const ImRect& bb, bool clip_even_when_logged);
static bool IsMouseHoveringRect(const ImRect& bb);
static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
static void Scrollbar(ImGuiWindow* window);
static bool CloseWindowButton(bool* p_opened = NULL);
static void FocusWindow(ImGuiWindow* window);
static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
// Helpers: String
static int ImStricmp(const char* str1, const char* str2);
static int ImStrnicmp(const char* str1, const char* str2, int count);
static char* ImStrdup(const char *str);
static size_t ImStrlenW(const ImWchar* str);
static const char* ImStristr(const char* haystack, const char* needle, const char* needle_end);
static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt, ...);
static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args);
// Helpers: Misc
static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed);
static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes = 0);
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; }
// Helpers: UTF-8 <> wchar
static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count
static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
static ptrdiff_t ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
static int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
static int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
//-----------------------------------------------------------------------------
// Platform dependent default implementations
//-----------------------------------------------------------------------------
static const char* GetClipboardTextFn_DefaultImpl();
static void SetClipboardTextFn_DefaultImpl(const char* text);
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
//-----------------------------------------------------------------------------
// User facing structures
//-----------------------------------------------------------------------------
ImGuiStyle::ImGuiStyle()
{
Alpha = 1.0f; // Global alpha applies to everything in ImGui
WindowPadding = ImVec2(8,8); // Padding within a window
WindowMinSize = ImVec2(32,32); // Minimum window size
WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows
FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
AutoFitPadding = ImVec2(8,8); // Extra space after auto-fit (double-clicking on resize grip)
WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin()
IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
ScrollbarWidth = 16.0f; // Width of the vertical scrollbar
GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab
DisplaySafeAreaPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding
Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f);
Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input
Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f);
Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f);
Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f);
Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f);
Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f);
Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
Colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
Colors[ImGuiCol_Button] = ImVec4(0.67f, 0.40f, 0.40f, 0.60f);
Colors[ImGuiCol_ButtonHovered] = ImVec4(0.67f, 0.40f, 0.40f, 1.00f);
Colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
Colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
Colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
Colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
Colors[ImGuiCol_Column] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
Colors[ImGuiCol_ColumnHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f);
Colors[ImGuiCol_ColumnActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f);
Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
Colors[ImGuiCol_CloseButton] = ImVec4(0.50f, 0.50f, 0.90f, 0.50f);
Colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.70f, 0.70f, 0.90f, 0.60f);
Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
}
// Statically allocated font atlas. This is merely a maneuver to keep ImFontAtlas definition at the bottom of the .h file (otherwise it'd be inside ImGuiIO)
// Also we wouldn't be able to new() one at this point, before users may define IO.MemAllocFn.
static ImFontAtlas GDefaultFontAtlas;
ImGuiIO::ImGuiIO()
{
// Most fields are initialized with zero
memset(this, 0, sizeof(*this));
DisplaySize = ImVec2(-1.0f, -1.0f);
DeltaTime = 1.0f/60.0f;
IniSavingRate = 5.0f;
IniFilename = "imgui.ini";
LogFilename = "imgui_log.txt";
Fonts = &GDefaultFontAtlas;
FontGlobalScale = 1.0f;
MousePos = ImVec2(-1,-1);
MousePosPrev = ImVec2(-1,-1);
MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f;
MouseDragThreshold = 6.0f;
UserData = NULL;
// User functions
RenderDrawListsFn = NULL;
MemAllocFn = malloc;
MemFreeFn = free;
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
}
// Pass in translated ASCII characters for text input.
// - with glfw you can get those from the callback set in glfwSetCharCallback()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
void ImGuiIO::AddInputCharacter(ImWchar c)
{
const size_t n = ImStrlenW(InputCharacters);
if (n + 1 < sizeof(InputCharacters) / sizeof(InputCharacters[0]))
{
InputCharacters[n] = c;
InputCharacters[n+1] = 0;
}
}
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
#undef PI
const float PI = 3.14159265358979323846f;
#ifdef INT_MAX
#define IM_INT_MIN INT_MIN
#define IM_INT_MAX INT_MAX
#else
#define IM_INT_MIN (-2147483647-1)
#define IM_INT_MAX (2147483647)
#endif
// Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
#ifdef _MSC_VER
#define STR_NEWLINE "\r\n"
#else
#define STR_NEWLINE "\n"
#endif
// Math bits
// We are keeping those static in the .cpp file so as not to leak them outside, in the case the user has implicit cast operators between ImVec2 and its own types.
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); }
//static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); }
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); }
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); }
static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2 rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); }
static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2 rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); }
static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; }
static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
//static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; }
static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; }
static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; }
static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMin(lhs.x,rhs.x), ImMin(lhs.y,rhs.y)); }
static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMax(lhs.x,rhs.x), ImMax(lhs.y,rhs.y)); }
static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x,mn.x,mx.x), ImClamp(f.y,mn.y,mx.y)); }
static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
static int ImStricmp(const char* str1, const char* str2)
{
int d;
while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
return d;
}
static int ImStrnicmp(const char* str1, const char* str2, int count)
{
int d = 0;
while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
return d;
}
static char* ImStrdup(const char *str)
{
char *buff = (char*)ImGui::MemAlloc(strlen(str) + 1);
IM_ASSERT(buff);
strcpy(buff, str);
return buff;
}
static size_t ImStrlenW(const ImWchar* str)
{
size_t n = 0;
while (*str++) n++;
return n;
}
static const char* ImStristr(const char* haystack, const char* needle, const char* needle_end)
{
if (!needle_end)
needle_end = needle + strlen(needle);
const char un0 = (char)toupper(*needle);
while (*haystack)
{
if (toupper(*haystack) == un0)
{
const char* b = needle + 1;
for (const char* a = haystack + 1; b < needle_end; a++, b++)
if (toupper(*a) != toupper(*b))
break;
if (b == needle_end)
return haystack;
}
haystack++;
}
return NULL;
}
// Pass data_size==0 for zero-terminated string
// Try to replace with FNV1a hash?
static ImU32 ImHash(const void* data, size_t data_size, ImU32 seed = 0)
{
static ImU32 crc32_lut[256] = { 0 };
if (!crc32_lut[1])
{
const ImU32 polynomial = 0xEDB88320;
for (ImU32 i = 0; i < 256; i++)
{
ImU32 crc = i;
for (ImU32 j = 0; j < 8; j++)
crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
crc32_lut[i] = crc;
}
}
seed = ~seed;
ImU32 crc = seed;
const unsigned char* current = (const unsigned char*)data;
if (data_size > 0)
{
// Known size
while (data_size--)
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
}
else
{
// Zero-terminated string
while (unsigned char c = *current++)
{
// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
// Because this syntax is rarely used we are optimizing for the common case.
// - If we reach ### in the string we discard the hash so far and reset to the seed.
// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
if (c == '#' && current[0] == '#' && current[1] == '#')
crc = seed;
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
}
}
return ~crc;
}
static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int w = vsnprintf(buf, buf_size, fmt, args);
va_end(args);
buf[buf_size-1] = 0;
return (w == -1) ? buf_size : (size_t)w;
}
static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
{
int w = vsnprintf(buf, buf_size, fmt, args);
buf[buf_size-1] = 0;
return (w == -1) ? buf_size : (size_t)w;
}
ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
{
ImU32 out = ((ImU32)(ImSaturate(in.x)*255.f));
out |= ((ImU32)(ImSaturate(in.y)*255.f) << 8);
out |= ((ImU32)(ImSaturate(in.z)*255.f) << 16);
out |= ((ImU32)(ImSaturate(in.w)*255.f) << 24);
return out;
}
// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
{
float K = 0.f;
if (g < b)
{
const float tmp = g; g = b; b = tmp;
K = -1.f;
}
if (r < g)
{
const float tmp = r; r = g; g = tmp;
K = -2.f / 6.f - K;
}
const float chroma = r - (g < b ? g : b);
out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
out_s = chroma / (r + 1e-20f);
out_v = r;
}
// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
// also http://en.wikipedia.org/wiki/HSL_and_HSV
void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
{
if (s == 0.0f)
{
// gray
out_r = out_g = out_b = v;
return;
}
h = fmodf(h, 1.0f) / (60.0f/360.0f);
int i = (int)h;
float f = h - (float)i;
float p = v * (1.0f - s);
float q = v * (1.0f - s * f);
float t = v * (1.0f - s * (1.0f - f));
switch (i)
{
case 0: out_r = v; out_g = t; out_b = p; break;
case 1: out_r = q; out_g = v; out_b = p; break;
case 2: out_r = p; out_g = v; out_b = t; break;
case 3: out_r = p; out_g = q; out_b = v; break;
case 4: out_r = t; out_g = p; out_b = v; break;
case 5: default: out_r = v; out_g = p; out_b = q; break;
}
}
// Load file content into memory
// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes)
{
IM_ASSERT(filename && file_open_mode && out_file_data && out_file_size);
*out_file_data = NULL;
*out_file_size = 0;
FILE* f;
if ((f = fopen(filename, file_open_mode)) == NULL)
return false;
long file_size_signed;
if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
{
fclose(f);
return false;
}
size_t file_size = (size_t)file_size_signed;
void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
if (file_data == NULL)
{
fclose(f);
return false;
}
if (fread(file_data, 1, file_size, f) != file_size)
{
fclose(f);
ImGui::MemFree(file_data);
return false;
}
if (padding_bytes > 0)
memset((void *)(((char*)file_data) + file_size), 0, padding_bytes);
fclose(f);
*out_file_data = file_data;
*out_file_size = file_size;
return true;
}
//-----------------------------------------------------------------------------
struct ImGuiColMod // Color modifier, backup of modified data so we can restore it
{
ImGuiCol Col;
ImVec4 PreviousValue;
};
struct ImGuiStyleMod // Style modifier, backup of modified data so we can restore it
{
ImGuiStyleVar Var;
ImVec2 PreviousValue;
};
struct ImRect // 2D axis aligned bounding-box
{
ImVec2 Min;
ImVec2 Max;
ImRect() { Min = ImVec2(FLT_MAX,FLT_MAX); Max = ImVec2(-FLT_MAX,-FLT_MAX); }
ImRect(const ImVec2& min, const ImVec2& max) { Min = min; Max = max; }
ImRect(const ImVec4& v) { Min.x = v.x; Min.y = v.y; Max.x = v.z; Max.y = v.w; }
ImRect(float x1, float y1, float x2, float y2) { Min.x = x1; Min.y = y1; Max.x = x2; Max.y = y2; }
ImVec2 GetCenter() const { return Min + (Max-Min)*0.5f; }
ImVec2 GetSize() const { return Max-Min; }
float GetWidth() const { return (Max-Min).x; }
float GetHeight() const { return (Max-Min).y; }
ImVec2 GetTL() const { return Min; }
ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); }
ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); }
ImVec2 GetBR() const { return Max; }
bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; }
bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; }
bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; }
void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); }
void Add(const ImRect& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); }
void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; }
void Expand(const ImVec2& amount) { Min -= amount; Max += amount; }
void Clip(const ImRect& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); }
ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const
{
if (!on_edge && Contains(p))
return p;
if (p.x > Max.x) p.x = Max.x;
else if (p.x < Min.x) p.x = Min.x;
if (p.y > Max.y) p.y = Max.y;
else if (p.y < Min.y) p.y = Min.y;
return p;
}
};
typedef ImRect ImGuiAabb; // FIXME-OBSOLETE
struct ImGuiGroupData
{
ImVec2 BackupCursorPos;
ImVec2 BackupCursorMaxPos;
float BackupColumnsStartX;
float BackupCurrentLineHeight;
float BackupCurrentLineTextBaseOffset;
float BackupLogLinePosY;
};
// Temporary per-window data, reset at the beginning of the frame
struct ImGuiDrawContext
{
ImVec2 CursorPos;
ImVec2 CursorPosPrevLine;
ImVec2 CursorStartPos;
ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame
float CurrentLineHeight;
float CurrentLineTextBaseOffset;
float PrevLineHeight;
float PrevLineTextBaseOffset;
float LogLinePosY;
int TreeDepth;
ImGuiID LastItemID;
ImRect LastItemRect;
bool LastItemHoveredAndUsable;
bool LastItemHoveredRect;
ImVector<ImGuiWindow*> ChildWindows;
ImVector<bool> AllowKeyboardFocus;
ImVector<float> ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
ImVector<float> TextWrapPos;
ImVector<ImGuiGroupData> GroupStack;
ImGuiColorEditMode ColorEditMode;
ImGuiStorage* StateStorage;
float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)