9120e874 Andy McCall 25 days ago
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
#if defined (_MSC_VER) && !defined (_CRT_SECURE_NO_WARNINGS)
36
#define _CRT_SECURE_NO_WARNINGS
37
#endif
38
39
#ifndef IMGUI_DEFINE_MATH_OPERATORS
40
#define IMGUI_DEFINE_MATH_OPERATORS
41
#endif
42
43
#include " imgui.h"
44
#ifndef IMGUI_DISABLE
45
#include " imgui_internal.h"
46
47
48
#include < stdint.h>
49
50
51
52
53
54
55
#ifdef _MSC_VER
56
#pragma warning (disable: 4127)
57
#pragma warning (disable: 4996)
58
#if defined (_MSC_VER) && _MSC_VER >= 1922
59
#pragma warning (disable: 5054)
60
#endif
61
#pragma warning (disable: 26451)
62
#pragma warning (disable: 26812)
63
#endif
64
65
66
#if defined (__clang__)
67
#if __has_warning("-Wunknown-warning-option")
68
#pragma clang diagnostic ignored "-Wunknown-warning-option"
69
#endif
70
#pragma clang diagnostic ignored "-Wunknown-pragmas"
71
#pragma clang diagnostic ignored "-Wold-style-cast"
72
#pragma clang diagnostic ignored "-Wfloat-equal"
73
#pragma clang diagnostic ignored "-Wformat-nonliteral"
74
#pragma clang diagnostic ignored "-Wsign-conversion"
75
#pragma clang diagnostic ignored "-Wunused-macros"
76
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
77
#pragma clang diagnostic ignored "-Wdouble-promotion"
78
#pragma clang diagnostic ignored "-Wenum-enum-conversion"
79
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
80
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
81
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
82
#pragma clang diagnostic ignored "-Wnontrivial-memaccess"
83
#elif defined (__GNUC__)
84
#pragma GCC diagnostic ignored "-Wpragmas"
85
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
86
#pragma GCC diagnostic ignored "-Wclass-memaccess"
87
#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
88
#endif
89
90
91
92
93
94
95
static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f ;
96
static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f ;
97
98
99
static const signed char IM_S8_MIN = - 128 ;
100
static const signed char IM_S8_MAX = 127 ;
101
static const unsigned char IM_U8_MIN = 0 ;
102
static const unsigned char IM_U8_MAX = 0xFF ;
103
static const signed short IM_S16_MIN = - 32768 ;
104
static const signed short IM_S16_MAX = 32767 ;
105
static const unsigned short IM_U16_MIN = 0 ;
106
static const unsigned short IM_U16_MAX = 0xFFFF ;
107
static const ImS32 IM_S32_MIN = INT_MIN;
108
static const ImS32 IM_S32_MAX = INT_MAX;
109
static const ImU32 IM_U32_MIN = 0 ;
110
static const ImU32 IM_U32_MAX = UINT_MAX;
111
#ifdef LLONG_MIN
112
static const ImS64 IM_S64_MIN = LLONG_MIN;
113
static const ImS64 IM_S64_MAX = LLONG_MAX;
114
#else
115
static const ImS64 IM_S64_MIN = - 9223372036854775807LL - 1 ;
116
static const ImS64 IM_S64_MAX = 9223372036854775807LL ;
117
#endif
118
static const ImU64 IM_U64_MIN = 0 ;
119
#ifdef ULLONG_MAX
120
static const ImU64 IM_U64_MAX = ULLONG_MAX;
121
#else
122
static const ImU64 IM_U64_MAX = ( 2ULL * 9223372036854775807LL + 1 ) ;
123
#endif
124
125
126
127
128
129
130
static bool InputTextFilterCharacter ( ImGuiContext* ctx , unsigned int * p_char , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * user_data , bool input_source_is_clipboard = false ) ;
131
static int InputTextCalcTextLenAndLineCount ( const char * text_begin , const char * * out_text_end ) ;
132
static ImVec2 InputTextCalcTextSize ( ImGuiContext* ctx , const char * text_begin , const char * text_end , const char * * remaining = NULL , ImVec2* out_offset = NULL , bool stop_on_new_line = false ) ;
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
void ImGui:: TextEx ( const char * text , const char * text_end , ImGuiTextFlags flags )
154
{
155
ImGuiWindow* window = GetCurrentWindow ( ) ;
156
if ( window-> SkipItems )
157
return ;
158
ImGuiContext& g = * GImGui;
159
160
161
if ( text == text_end)
162
text = text_end = " " ;
163
164
165
const char * text_begin = text;
166
if ( text_end == NULL )
167
text_end = text + strlen ( text ) ;
168
169
const ImVec2 text_pos ( window-> DC . CursorPos . x , window-> DC . CursorPos . y + window-> DC . CurrLineTextBaseOffset ) ;
170
const float wrap_pos_x = window-> DC . TextWrapPos ;
171
const bool wrap_enabled = ( wrap_pos_x >= 0.0f ) ;
172
if ( text_end - text <= 2000 || wrap_enabled)
173
{
174
175
const float wrap_width = wrap_enabled ? CalcWrapWidthForPos ( window-> DC . CursorPos , wrap_pos_x ) : 0.0f ;
176
const ImVec2 text_size = CalcTextSize ( text_begin, text_end, false , wrap_width ) ;
177
178
ImRect bb ( text_pos, text_pos + text_size ) ;
179
ItemSize ( text_size, 0.0f ) ;
180
if ( ! ItemAdd ( bb, 0 ) )
181
return ;
182
183
184
RenderTextWrapped ( bb. Min , text_begin, text_end, wrap_width ) ;
185
}
186
else
187
{
188
189
190
191
192
193
const char * line = text;
194
const float line_height = GetTextLineHeight ( ) ;
195
ImVec2 text_size ( 0 , 0 ) ;
196
197
198
ImVec2 pos = text_pos;
199
if ( ! g. LogEnabled )
200
{
201
int lines_skippable = ( int ) ( ( window-> ClipRect . Min . y - text_pos. y ) / line_height) ;
202
if ( lines_skippable > 0 )
203
{
204
int lines_skipped = 0 ;
205
while ( line < text_end && lines_skipped < lines_skippable)
206
{
207
const char * line_end = ( const char * ) memchr ( line, ' \n ' , text_end - line ) ;
208
if ( ! line_end)
209
line_end = text_end;
210
if ( ( flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0 )
211
text_size. x = ImMax ( text_size. x , CalcTextSize ( line, line_end ) . x ) ;
212
line = line_end + 1 ;
213
lines_skipped+ + ;
214
}
215
pos. y += lines_skipped * line_height;
216
}
217
}
218
219
220
if ( line < text_end)
221
{
222
ImRect line_rect ( pos, pos + ImVec2 ( FLT_MAX, line_height ) ) ;
223
while ( line < text_end)
224
{
225
if ( IsClippedEx ( line_rect, 0 ) )
226
break ;
227
228
const char * line_end = ( const char * ) memchr ( line, ' \n ' , text_end - line ) ;
229
if ( ! line_end)
230
line_end = text_end;
231
text_size. x = ImMax ( text_size. x , CalcTextSize ( line, line_end ) . x ) ;
232
RenderText ( pos, line, line_end, false ) ;
233
line = line_end + 1 ;
234
line_rect. Min . y += line_height;
235
line_rect. Max . y += line_height;
236
pos. y += line_height;
237
}
238
239
240
int lines_skipped = 0 ;
241
while ( line < text_end)
242
{
243
const char * line_end = ( const char * ) memchr ( line, ' \n ' , text_end - line ) ;
244
if ( ! line_end)
245
line_end = text_end;
246
if ( ( flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0 )
247
text_size. x = ImMax ( text_size. x , CalcTextSize ( line, line_end ) . x ) ;
248
line = line_end + 1 ;
249
lines_skipped+ + ;
250
}
251
pos. y += lines_skipped * line_height;
252
}
253
text_size. y = ( pos - text_pos) . y ;
254
255
ImRect bb ( text_pos, text_pos + text_size ) ;
256
ItemSize ( text_size, 0.0f ) ;
257
ItemAdd ( bb, 0 ) ;
258
}
259
}
260
261
void ImGui:: TextUnformatted ( const char * text , const char * text_end )
262
{
263
TextEx ( text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText ) ;
264
}
265
266
void ImGui:: Text ( const char * fmt , ... )
267
{
268
va_list args;
269
va_start ( args, fmt ) ;
270
TextV ( fmt, args ) ;
271
va_end ( args ) ;
272
}
273
274
void ImGui:: TextV ( const char * fmt , va_list args )
275
{
276
ImGuiWindow* window = GetCurrentWindow ( ) ;
277
if ( window-> SkipItems )
278
return ;
279
280
const char * text, * text_end;
281
ImFormatStringToTempBufferV ( & text, & text_end, fmt, args) ;
282
TextEx ( text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText ) ;
283
}
284
285
void ImGui:: TextColored ( const ImVec4& col , const char * fmt , ... )
286
{
287
va_list args;
288
va_start ( args, fmt ) ;
289
TextColoredV ( col, fmt, args ) ;
290
va_end ( args ) ;
291
}
292
293
void ImGui:: TextColoredV ( const ImVec4& col , const char * fmt , va_list args )
294
{
295
PushStyleColor ( ImGuiCol_Text, col ) ;
296
TextV ( fmt, args ) ;
297
PopStyleColor ( ) ;
298
}
299
300
void ImGui:: TextDisabled ( const char * fmt , ... )
301
{
302
va_list args;
303
va_start ( args, fmt ) ;
304
TextDisabledV ( fmt, args ) ;
305
va_end ( args ) ;
306
}
307
308
void ImGui:: TextDisabledV ( const char * fmt , va_list args )
309
{
310
ImGuiContext& g = * GImGui;
311
PushStyleColor ( ImGuiCol_Text, g. Style . Colors [ ImGuiCol_TextDisabled] ) ;
312
TextV ( fmt, args ) ;
313
PopStyleColor ( ) ;
314
}
315
316
void ImGui:: TextWrapped ( const char * fmt , ... )
317
{
318
va_list args;
319
va_start ( args, fmt ) ;
320
TextWrappedV ( fmt, args ) ;
321
va_end ( args ) ;
322
}
323
324
void ImGui:: TextWrappedV ( const char * fmt , va_list args )
325
{
326
ImGuiContext& g = * GImGui;
327
const bool need_backup = ( g. CurrentWindow -> DC . TextWrapPos < 0.0f ) ;
328
if ( need_backup)
329
PushTextWrapPos ( 0.0f ) ;
330
TextV ( fmt, args ) ;
331
if ( need_backup)
332
PopTextWrapPos ( ) ;
333
}
334
335
void ImGui:: LabelText ( const char * label , const char * fmt , ... )
336
{
337
va_list args;
338
va_start ( args, fmt ) ;
339
LabelTextV ( label, fmt, args ) ;
340
va_end ( args ) ;
341
}
342
343
344
void ImGui:: LabelTextV ( const char * label , const char * fmt , va_list args )
345
{
346
ImGuiWindow* window = GetCurrentWindow ( ) ;
347
if ( window-> SkipItems )
348
return ;
349
350
ImGuiContext& g = * GImGui;
351
const ImGuiStyle& style = g. Style ;
352
const float w = CalcItemWidth ( ) ;
353
354
const char * value_text_begin, * value_text_end;
355
ImFormatStringToTempBufferV ( & value_text_begin, & value_text_end, fmt, args) ;
356
const ImVec2 value_size = CalcTextSize ( value_text_begin, value_text_end, false ) ;
357
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
358
359
const ImVec2 pos = window-> DC . CursorPos ;
360
const ImRect value_bb ( pos, pos + ImVec2 ( w, value_size. y + style. FramePadding . y * 2 ) ) ;
361
const ImRect total_bb ( pos, pos + ImVec2 ( w + ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f ) , ImMax ( value_size. y , label_size. y ) + style. FramePadding . y * 2 ) ) ;
362
ItemSize ( total_bb, style. FramePadding . y ) ;
363
if ( ! ItemAdd ( total_bb, 0 ) )
364
return ;
365
366
367
RenderTextClipped ( value_bb. Min + style. FramePadding , value_bb. Max , value_text_begin, value_text_end, & value_size, ImVec2 ( 0.0f , 0.0f ) ) ;
368
if ( label_size. x > 0.0f )
369
RenderText ( ImVec2 ( value_bb. Max . x + style. ItemInnerSpacing . x , value_bb. Min . y + style. FramePadding . y ) , label) ;
370
}
371
372
void ImGui:: BulletText ( const char * fmt , ... )
373
{
374
va_list args;
375
va_start ( args, fmt ) ;
376
BulletTextV ( fmt, args ) ;
377
va_end ( args ) ;
378
}
379
380
381
void ImGui:: BulletTextV ( const char * fmt , va_list args )
382
{
383
ImGuiWindow* window = GetCurrentWindow ( ) ;
384
if ( window-> SkipItems )
385
return ;
386
387
ImGuiContext& g = * GImGui;
388
const ImGuiStyle& style = g. Style ;
389
390
const char * text_begin, * text_end;
391
ImFormatStringToTempBufferV ( & text_begin, & text_end, fmt, args) ;
392
const ImVec2 label_size = CalcTextSize ( text_begin, text_end, false ) ;
393
const ImVec2 total_size = ImVec2 ( g. FontSize + ( label_size. x > 0.0f ? ( label_size. x + style. FramePadding . x * 2 ) : 0.0f ) , label_size. y ) ;
394
ImVec2 pos = window-> DC . CursorPos ;
395
pos. y += window-> DC . CurrLineTextBaseOffset ;
396
ItemSize ( total_size, 0.0f ) ;
397
const ImRect bb ( pos, pos + total_size ) ;
398
if ( ! ItemAdd ( bb, 0 ) )
399
return ;
400
401
402
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
403
RenderBullet ( window-> DrawList , bb. Min + ImVec2 ( style. FramePadding . x + g. FontSize * 0.5f , g. FontSize * 0.5f ) , text_col ) ;
404
RenderText ( bb. Min + ImVec2 ( g. FontSize + style. FramePadding . x * 2 , 0.0f ) , text_begin, text_end, false ) ;
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
bool ImGui:: ButtonBehavior ( const ImRect& bb , ImGuiID id , bool * out_hovered , bool * out_held , ImGuiButtonFlags flags )
495
{
496
ImGuiContext& g = * GImGui;
497
ImGuiWindow* window = GetCurrentWindow ( ) ;
498
499
500
501
ImGuiItemFlags item_flags = ( g. LastItemData . ID == id ? g. LastItemData . ItemFlags : g. CurrentItemFlags ) ;
502
if ( flags & ImGuiButtonFlags_AllowOverlap)
503
item_flags |= ImGuiItemFlags_AllowOverlap;
504
505
506
if ( ( flags & ImGuiButtonFlags_MouseButtonMask_) == 0 )
507
flags |= ImGuiButtonFlags_MouseButtonLeft;
508
509
510
if ( ( flags & ImGuiButtonFlags_PressedOnMask_) == 0 )
511
flags |= ( item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_;
512
513
ImGuiWindow* backup_hovered_window = g. HoveredWindow ;
514
const bool flatten_hovered_children = ( flags & ImGuiButtonFlags_FlattenChildren) && g. HoveredWindow && g. HoveredWindow -> RootWindowDockTree == window-> RootWindowDockTree ;
515
if ( flatten_hovered_children)
516
g. HoveredWindow = window;
517
518
#ifdef IMGUI_ENABLE_TEST_ENGINE
519
520
if ( g. LastItemData . ID != id)
521
IMGUI_TEST_ENGINE_ITEM_ADD ( id, bb, NULL ) ;
522
#endif
523
524
bool pressed = false ;
525
bool hovered = ItemHoverable ( bb, id, item_flags ) ;
526
527
528
if ( g. DragDropActive && ( flags & ImGuiButtonFlags_PressedOnDragDropHold) && ! ( g. DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers) )
529
if ( IsItemHovered ( ImGuiHoveredFlags_AllowWhenBlockedByActiveItem ) )
530
{
531
hovered = true ;
532
SetHoveredID ( id ) ;
533
if ( g. HoveredIdTimer - g. IO . DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g. HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER)
534
{
535
pressed = true ;
536
g. DragDropHoldJustPressedId = id;
537
FocusWindow ( window ) ;
538
}
539
}
540
541
if ( flatten_hovered_children)
542
g. HoveredWindow = backup_hovered_window;
543
544
545
const ImGuiID test_owner_id = ( flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id;
546
if ( hovered)
547
{
548
IM_ASSERT ( id != 0 ) ;
549
550
551
552
553
int mouse_button_clicked = - 1 ;
554
int mouse_button_released = - 1 ;
555
for ( int button = 0 ; button < 3 ; button+ + )
556
if ( flags & ( ImGuiButtonFlags_MouseButtonLeft << button) )
557
{
558
if ( IsMouseClicked ( button, ImGuiInputFlags_None, test_owner_id ) && mouse_button_clicked == - 1 ) { mouse_button_clicked = button; }
559
if ( IsMouseReleased ( button, test_owner_id ) && mouse_button_released == - 1 ) { mouse_button_released = button; }
560
}
561
562
563
const bool mods_ok = ! ( flags & ImGuiButtonFlags_NoKeyModsAllowed) || ( ! g. IO . KeyCtrl && ! g. IO . KeyShift && ! g. IO . KeyAlt ) ;
564
if ( mods_ok)
565
{
566
if ( mouse_button_clicked != - 1 && g. ActiveId != id)
567
{
568
if ( ! ( flags & ImGuiButtonFlags_NoSetKeyOwner) )
569
SetKeyOwner ( MouseButtonToKey ( mouse_button_clicked ) , id) ;
570
if ( flags & ( ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere) )
571
{
572
SetActiveID ( id, window ) ;
573
g. ActiveIdMouseButton = mouse_button_clicked;
574
if ( ! ( flags & ImGuiButtonFlags_NoNavFocus) )
575
{
576
SetFocusID ( id, window ) ;
577
FocusWindow ( window ) ;
578
}
579
else
580
{
581
FocusWindow ( window, ImGuiFocusRequestFlags_RestoreFocusedChild ) ;
582
}
583
}
584
if ( ( flags & ImGuiButtonFlags_PressedOnClick) || ( ( flags & ImGuiButtonFlags_PressedOnDoubleClick) && g. IO . MouseClickedCount [ mouse_button_clicked] == 2 ) )
585
{
586
pressed = true ;
587
if ( flags & ImGuiButtonFlags_NoHoldingActiveId)
588
ClearActiveID ( ) ;
589
else
590
SetActiveID ( id, window ) ;
591
g. ActiveIdMouseButton = mouse_button_clicked;
592
if ( ! ( flags & ImGuiButtonFlags_NoNavFocus) )
593
{
594
SetFocusID ( id, window ) ;
595
FocusWindow ( window ) ;
596
}
597
else
598
{
599
FocusWindow ( window, ImGuiFocusRequestFlags_RestoreFocusedChild ) ;
600
}
601
}
602
}
603
if ( flags & ImGuiButtonFlags_PressedOnRelease)
604
{
605
if ( mouse_button_released != - 1 )
606
{
607
const bool has_repeated_at_least_once = ( item_flags & ImGuiItemFlags_ButtonRepeat) && g. IO . MouseDownDurationPrev [ mouse_button_released] >= g. IO . KeyRepeatDelay ;
608
if ( ! has_repeated_at_least_once)
609
pressed = true ;
610
if ( ! ( flags & ImGuiButtonFlags_NoNavFocus) )
611
SetFocusID ( id, window ) ;
612
ClearActiveID ( ) ;
613
}
614
}
615
616
617
618
if ( g. ActiveId == id && ( item_flags & ImGuiItemFlags_ButtonRepeat) )
619
if ( g. IO . MouseDownDuration [ g. ActiveIdMouseButton ] > 0.0f && IsMouseClicked ( g. ActiveIdMouseButton , ImGuiInputFlags_Repeat, test_owner_id ) )
620
pressed = true ;
621
}
622
623
if ( pressed && g. IO . ConfigNavCursorVisibleAuto )
624
g. NavCursorVisible = false ;
625
}
626
627
628
629
if ( g. NavId == id && g. NavCursorVisible && g. NavHighlightItemUnderNav )
630
if ( ! ( flags & ImGuiButtonFlags_NoHoveredOnFocus) )
631
hovered = true ;
632
if ( g. NavActivateDownId == id)
633
{
634
bool nav_activated_by_code = ( g. NavActivateId == id) ;
635
bool nav_activated_by_inputs = ( g. NavActivatePressedId == id) ;
636
if ( ! nav_activated_by_inputs && ( item_flags & ImGuiItemFlags_ButtonRepeat) )
637
{
638
639
const ImGuiKeyData* key1 = GetKeyData ( ImGuiKey_Space ) ;
640
const ImGuiKeyData* key2 = GetKeyData ( ImGuiKey_Enter ) ;
641
const ImGuiKeyData* key3 = GetKeyData ( ImGuiKey_NavGamepadActivate ) ;
642
const float t1 = ImMax ( ImMax ( key1-> DownDuration , key2-> DownDuration ) , key3-> DownDuration ) ;
643
nav_activated_by_inputs = CalcTypematicRepeatAmount ( t1 - g. IO . DeltaTime , t1, g. IO . KeyRepeatDelay , g. IO . KeyRepeatRate ) > 0 ;
644
}
645
if ( nav_activated_by_code || nav_activated_by_inputs)
646
{
647
648
pressed = true ;
649
SetActiveID ( id, window ) ;
650
g. ActiveIdSource = g. NavInputSource ;
651
if ( ! ( flags & ImGuiButtonFlags_NoNavFocus) && ! ( g. NavActivateFlags & ImGuiActivateFlags_FromShortcut) )
652
SetFocusID ( id, window ) ;
653
if ( g. NavActivateFlags & ImGuiActivateFlags_FromShortcut)
654
g. ActiveIdFromShortcut = true ;
655
}
656
}
657
658
659
bool held = false ;
660
if ( g. ActiveId == id)
661
{
662
if ( g. ActiveIdSource == ImGuiInputSource_Mouse)
663
{
664
if ( g. ActiveIdIsJustActivated )
665
g. ActiveIdClickOffset = g. IO . MousePos - bb. Min ;
666
667
const int mouse_button = g. ActiveIdMouseButton ;
668
if ( mouse_button == - 1 )
669
{
670
671
ClearActiveID ( ) ;
672
}
673
else if ( IsMouseDown ( mouse_button, test_owner_id ) )
674
{
675
held = true ;
676
}
677
else
678
{
679
bool release_in = hovered && ( flags & ImGuiButtonFlags_PressedOnClickRelease) != 0 ;
680
bool release_anywhere = ( flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0 ;
681
if ( ( release_in || release_anywhere) && ! g. DragDropActive )
682
{
683
684
bool is_double_click_release = ( flags & ImGuiButtonFlags_PressedOnDoubleClick) && g. IO . MouseReleased [ mouse_button] && g. IO . MouseClickedLastCount [ mouse_button] == 2 ;
685
bool is_repeating_already = ( item_flags & ImGuiItemFlags_ButtonRepeat) && g. IO . MouseDownDurationPrev [ mouse_button] >= g. IO . KeyRepeatDelay ;
686
bool is_button_avail_or_owned = TestKeyOwner ( MouseButtonToKey ( mouse_button ) , test_owner_id) ;
687
if ( ! is_double_click_release && ! is_repeating_already && is_button_avail_or_owned)
688
pressed = true ;
689
}
690
ClearActiveID ( ) ;
691
}
692
if ( ! ( flags & ImGuiButtonFlags_NoNavFocus) && g. IO . ConfigNavCursorVisibleAuto )
693
g. NavCursorVisible = false ;
694
}
695
else if ( g. ActiveIdSource == ImGuiInputSource_Keyboard || g. ActiveIdSource == ImGuiInputSource_Gamepad)
696
{
697
698
if ( g. NavActivateDownId == id)
699
held = true ;
700
else
701
ClearActiveID ( ) ;
702
}
703
if ( pressed)
704
g. ActiveIdHasBeenPressedBefore = true ;
705
}
706
707
708
if ( g. NavHighlightActivatedId == id)
709
hovered = true ;
710
711
if ( out_hovered) * out_hovered = hovered;
712
if ( out_held) * out_held = held;
713
714
return pressed;
715
}
716
717
bool ImGui:: ButtonEx ( const char * label , const ImVec2& size_arg , ImGuiButtonFlags flags )
718
{
719
ImGuiWindow* window = GetCurrentWindow ( ) ;
720
if ( window-> SkipItems )
721
return false ;
722
723
ImGuiContext& g = * GImGui;
724
const ImGuiStyle& style = g. Style ;
725
const ImGuiID id = window-> GetID ( label ) ;
726
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
727
728
ImVec2 pos = window-> DC . CursorPos ;
729
if ( ( flags & ImGuiButtonFlags_AlignTextBaseLine) && style. FramePadding . y < window-> DC . CurrLineTextBaseOffset )
730
pos. y += window-> DC . CurrLineTextBaseOffset - style. FramePadding . y ;
731
ImVec2 size = CalcItemSize ( size_arg, label_size. x + style. FramePadding . x * 2.0f , label_size. y + style. FramePadding . y * 2.0f ) ;
732
733
const ImRect bb ( pos, pos + size ) ;
734
ItemSize ( size, style. FramePadding . y ) ;
735
if ( ! ItemAdd ( bb, id ) )
736
return false ;
737
738
bool hovered, held;
739
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, flags ) ;
740
741
742
const ImU32 col = GetColorU32 ( ( held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button) ;
743
RenderNavCursor ( bb, id ) ;
744
RenderFrame ( bb. Min , bb. Max , col, true , style. FrameRounding ) ;
745
746
if ( g. LogEnabled )
747
LogSetNextTextDecoration ( " [" , " ]" ) ;
748
RenderTextClipped ( bb. Min + style. FramePadding , bb. Max - style. FramePadding , label, NULL , & label_size, style. ButtonTextAlign , & bb ) ;
749
750
751
752
753
754
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags ) ;
755
return pressed;
756
}
757
758
bool ImGui:: Button ( const char * label , const ImVec2& size_arg )
759
{
760
return ButtonEx ( label, size_arg, ImGuiButtonFlags_None ) ;
761
}
762
763
764
bool ImGui:: SmallButton ( const char * label )
765
{
766
ImGuiContext& g = * GImGui;
767
float backup_padding_y = g. Style . FramePadding . y ;
768
g. Style . FramePadding . y = 0.0f ;
769
bool pressed = ButtonEx ( label, ImVec2 ( 0 , 0 ) , ImGuiButtonFlags_AlignTextBaseLine ) ;
770
g. Style . FramePadding . y = backup_padding_y;
771
return pressed;
772
}
773
774
775
776
bool ImGui:: InvisibleButton ( const char * str_id , const ImVec2& size_arg , ImGuiButtonFlags flags )
777
{
778
ImGuiContext& g = * GImGui;
779
ImGuiWindow* window = GetCurrentWindow ( ) ;
780
if ( window-> SkipItems )
781
return false ;
782
783
784
IM_ASSERT ( size_arg. x != 0.0f && size_arg. y != 0.0f ) ;
785
786
const ImGuiID id = window-> GetID ( str_id ) ;
787
ImVec2 size = CalcItemSize ( size_arg, 0.0f , 0.0f ) ;
788
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + size ) ;
789
ItemSize ( size ) ;
790
if ( ! ItemAdd ( bb, id, NULL , ( flags & ImGuiButtonFlags_EnableNav) ? ImGuiItemFlags_None : ImGuiItemFlags_NoNav ) )
791
return false ;
792
793
bool hovered, held;
794
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, flags ) ;
795
RenderNavCursor ( bb, id ) ;
796
797
IMGUI_TEST_ENGINE_ITEM_INFO ( id, str_id, g. LastItemData . StatusFlags ) ;
798
return pressed;
799
}
800
801
bool ImGui:: ArrowButtonEx ( const char * str_id , ImGuiDir dir , ImVec2 size , ImGuiButtonFlags flags )
802
{
803
ImGuiContext& g = * GImGui;
804
ImGuiWindow* window = GetCurrentWindow ( ) ;
805
if ( window-> SkipItems )
806
return false ;
807
808
const ImGuiID id = window-> GetID ( str_id ) ;
809
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + size ) ;
810
const float default_size = GetFrameHeight ( ) ;
811
ItemSize ( size, ( size. y >= default_size) ? g. Style . FramePadding . y : - 1.0f ) ;
812
if ( ! ItemAdd ( bb, id ) )
813
return false ;
814
815
bool hovered, held;
816
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, flags ) ;
817
818
819
const ImU32 bg_col = GetColorU32 ( ( held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button) ;
820
const ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
821
RenderNavCursor ( bb, id ) ;
822
RenderFrame ( bb. Min , bb. Max , bg_col, true , g. Style . FrameRounding ) ;
823
RenderArrow ( window-> DrawList , bb. Min + ImVec2 ( ImMax ( 0.0f , ( size. x - g. FontSize ) * 0.5f ) , ImMax ( 0.0f , ( size. y - g. FontSize ) * 0.5f ) ) , text_col, dir ) ;
824
825
IMGUI_TEST_ENGINE_ITEM_INFO ( id, str_id, g. LastItemData . StatusFlags ) ;
826
return pressed;
827
}
828
829
bool ImGui:: ArrowButton ( const char * str_id , ImGuiDir dir )
830
{
831
float sz = GetFrameHeight ( ) ;
832
return ArrowButtonEx ( str_id, dir, ImVec2 ( sz, sz ) , ImGuiButtonFlags_None ) ;
833
}
834
835
836
bool ImGui:: CloseButton ( ImGuiID id , const ImVec2& pos )
837
{
838
ImGuiContext& g = * GImGui;
839
ImGuiWindow* window = g. CurrentWindow ;
840
841
842
843
const ImRect bb ( pos, pos + ImVec2 ( g. FontSize , g. FontSize ) ) ;
844
ImRect bb_interact = bb;
845
const float area_to_visible_ratio = window-> OuterRectClipped . GetArea ( ) / bb. GetArea ( ) ;
846
if ( area_to_visible_ratio < 1.5f )
847
bb_interact. Expand ( ImTrunc ( bb_interact. GetSize ( ) * - 0.25f ) ) ;
848
849
850
851
bool is_clipped = ! ItemAdd ( bb_interact, id ) ;
852
853
bool hovered, held;
854
bool pressed = ButtonBehavior ( bb_interact, id, & hovered, & held ) ;
855
if ( is_clipped)
856
return pressed;
857
858
859
ImU32 bg_col = GetColorU32 ( held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered ) ;
860
if ( hovered)
861
window-> DrawList -> AddRectFilled ( bb. Min , bb. Max , bg_col ) ;
862
RenderNavCursor ( bb, id, ImGuiNavRenderCursorFlags_Compact ) ;
863
ImU32 cross_col = GetColorU32 ( ImGuiCol_Text ) ;
864
ImVec2 cross_center = bb. GetCenter ( ) - ImVec2 ( 0.5f , 0.5f ) ;
865
float cross_extent = g. FontSize * 0.5f * 0.7071f - 1.0f ;
866
window-> DrawList -> AddLine ( cross_center + ImVec2 ( + cross_extent, + cross_extent) , cross_center + ImVec2 ( - cross_extent, - cross_extent) , cross_col, 1.0f ) ;
867
window-> DrawList -> AddLine ( cross_center + ImVec2 ( + cross_extent, - cross_extent) , cross_center + ImVec2 ( - cross_extent, + cross_extent) , cross_col, 1.0f ) ;
868
869
return pressed;
870
}
871
872
873
bool ImGui:: CollapseButton ( ImGuiID id , const ImVec2& pos , ImGuiDockNode* dock_node )
874
{
875
ImGuiContext& g = * GImGui;
876
ImGuiWindow* window = g. CurrentWindow ;
877
878
ImRect bb ( pos, pos + ImVec2 ( g. FontSize , g. FontSize ) ) ;
879
bool is_clipped = ! ItemAdd ( bb, id ) ;
880
bool hovered, held;
881
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, ImGuiButtonFlags_None ) ;
882
if ( is_clipped)
883
return pressed;
884
885
886
887
ImU32 bg_col = GetColorU32 ( ( held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button) ;
888
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
889
if ( hovered || held)
890
window-> DrawList -> AddRectFilled ( bb. Min , bb. Max , bg_col ) ;
891
RenderNavCursor ( bb, id, ImGuiNavRenderCursorFlags_Compact ) ;
892
893
if ( dock_node)
894
RenderArrowDockMenu ( window-> DrawList , bb. Min , g. FontSize , text_col ) ;
895
else
896
RenderArrow ( window-> DrawList , bb. Min , text_col, window-> Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f ) ;
897
898
899
if ( IsItemActive ( ) && IsMouseDragging ( 0 ) )
900
StartMouseMovingWindowOrNode ( window, dock_node, true ) ;
901
902
return pressed;
903
}
904
905
ImGuiID ImGui:: GetWindowScrollbarID ( ImGuiWindow* window , ImGuiAxis axis )
906
{
907
return window-> GetID ( axis == ImGuiAxis_X ? " #SCROLLX" : " #SCROLLY" ) ;
908
}
909
910
911
ImRect ImGui:: GetWindowScrollbarRect ( ImGuiWindow* window , ImGuiAxis axis )
912
{
913
const ImRect outer_rect = window-> Rect ( ) ;
914
const ImRect inner_rect = window-> InnerRect ;
915
const float border_size = window-> WindowBorderSize ;
916
const float scrollbar_size = window-> ScrollbarSizes [ axis ^ 1 ] ;
917
IM_ASSERT ( scrollbar_size > 0.0f ) ;
918
if ( axis == ImGuiAxis_X)
919
return ImRect ( inner_rect. Min . x , ImMax ( outer_rect. Min . y , outer_rect. Max . y - border_size - scrollbar_size ) , inner_rect. Max . x - border_size, outer_rect. Max . y - border_size ) ;
920
else
921
return ImRect ( ImMax ( outer_rect. Min . x , outer_rect. Max . x - border_size - scrollbar_size ) , inner_rect. Min . y , outer_rect. Max . x - border_size, inner_rect. Max . y - border_size) ;
922
}
923
924
void ImGui:: Scrollbar ( ImGuiAxis axis )
925
{
926
ImGuiContext& g = * GImGui;
927
ImGuiWindow* window = g. CurrentWindow ;
928
const ImGuiID id = GetWindowScrollbarID ( window, axis ) ;
929
930
931
ImRect bb = GetWindowScrollbarRect ( window, axis ) ;
932
ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone;
933
if ( axis == ImGuiAxis_X)
934
{
935
rounding_corners |= ImDrawFlags_RoundCornersBottomLeft;
936
if ( ! window-> ScrollbarY )
937
rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
938
}
939
else
940
{
941
if ( ( window-> Flags & ImGuiWindowFlags_NoTitleBar) && ! ( window-> Flags & ImGuiWindowFlags_MenuBar) )
942
rounding_corners |= ImDrawFlags_RoundCornersTopRight;
943
if ( ! window-> ScrollbarX )
944
rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
945
}
946
float size_visible = window-> InnerRect . Max [ axis] - window-> InnerRect . Min [ axis] ;
947
float size_contents = window-> ContentSize [ axis] + window-> WindowPadding [ axis] * 2.0f ;
948
ImS64 scroll = ( ImS64) window-> Scroll [ axis] ;
949
ScrollbarEx ( bb, id, axis, & scroll, ( ImS64) size_visible, ( ImS64) size_contents, rounding_corners ) ;
950
window-> Scroll [ axis] = ( float ) scroll;
951
}
952
953
954
955
956
957
958
959
bool ImGui:: ScrollbarEx ( const ImRect& bb_frame , ImGuiID id , ImGuiAxis axis , ImS64* p_scroll_v , ImS64 size_visible_v , ImS64 size_contents_v , ImDrawFlags flags )
960
{
961
ImGuiContext& g = * GImGui;
962
ImGuiWindow* window = g. CurrentWindow ;
963
if ( window-> SkipItems )
964
return false ;
965
966
const float bb_frame_width = bb_frame. GetWidth ( ) ;
967
const float bb_frame_height = bb_frame. GetHeight ( ) ;
968
if ( bb_frame_width <= 0.0f || bb_frame_height <= 0.0f )
969
return false ;
970
971
972
float alpha = 1.0f ;
973
if ( ( axis == ImGuiAxis_Y) && bb_frame_height < g. FontSize + g. Style . FramePadding . y * 2.0f )
974
alpha = ImSaturate ( ( bb_frame_height - g. FontSize ) / ( g. Style . FramePadding . y * 2.0f ) ) ;
975
if ( alpha <= 0.0f )
976
return false ;
977
978
const ImGuiStyle& style = g. Style ;
979
const bool allow_interaction = ( alpha >= 1.0f ) ;
980
981
ImRect bb = bb_frame;
982
bb. Expand ( ImVec2 ( - ImClamp ( IM_TRUNC ( ( bb_frame_width - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) , - ImClamp ( IM_TRUNC ( ( bb_frame_height - 2.0f ) * 0.5f ) , 0.0f , 3.0f ) ) ) ;
983
984
985
const float scrollbar_size_v = ( axis == ImGuiAxis_X) ? bb. GetWidth ( ) : bb. GetHeight ( ) ;
986
987
988
989
IM_ASSERT ( ImMax ( size_contents_v, size_visible_v ) > 0.0f ) ;
990
const ImS64 win_size_v = ImMax ( ImMax ( size_contents_v, size_visible_v ) , ( ImS64) 1 ) ;
991
const float grab_h_pixels = ImClamp ( scrollbar_size_v * ( ( float ) size_visible_v / ( float ) win_size_v) , style. GrabMinSize , scrollbar_size_v ) ;
992
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
993
994
995
bool held = false ;
996
bool hovered = false ;
997
ItemAdd ( bb_frame, id, NULL , ImGuiItemFlags_NoNav ) ;
998
ButtonBehavior ( bb, id, & hovered, & held, ImGuiButtonFlags_NoNavFocus ) ;
999
1000
const ImS64 scroll_max = ImMax ( ( ImS64) 1 , size_contents_v - size_visible_v) ;
1001
float scroll_ratio = ImSaturate ( ( float ) * p_scroll_v / ( float ) scroll_max) ;
1002
float grab_v_norm = scroll_ratio * ( scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
1003
if ( held && allow_interaction && grab_h_norm < 1.0f )
1004
{
1005
const float scrollbar_pos_v = bb. Min [ axis] ;
1006
const float mouse_pos_v = g. IO . MousePos [ axis] ;
1007
1008
1009
const float clicked_v_norm = ImSaturate ( ( mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v) ;
1010
1011
const int held_dir = ( clicked_v_norm < grab_v_norm) ? - 1 : ( clicked_v_norm > grab_v_norm + grab_h_norm) ? + 1 : 0 ;
1012
if ( g. ActiveIdIsJustActivated )
1013
{
1014
1015
const bool scroll_to_clicked_location = ( g. IO . ConfigScrollbarScrollByPage == false || g. IO . KeyShift || held_dir == 0 ) ;
1016
g. ScrollbarSeekMode = scroll_to_clicked_location ? 0 : ( short ) held_dir;
1017
g. ScrollbarClickDeltaToGrabCenter = ( held_dir == 0 && ! g. IO . KeyShift ) ? clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f : 0.0f ;
1018
}
1019
1020
1021
1022
if ( g. ScrollbarSeekMode == 0 )
1023
{
1024
1025
const float scroll_v_norm = ImSaturate ( ( clicked_v_norm - g. ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f ) / ( 1.0f - grab_h_norm) ) ;
1026
* p_scroll_v = ( ImS64) ( scroll_v_norm * scroll_max) ;
1027
}
1028
else
1029
{
1030
1031
if ( IsMouseClicked ( ImGuiMouseButton_Left, ImGuiInputFlags_Repeat ) && held_dir == g. ScrollbarSeekMode )
1032
{
1033
float page_dir = ( g. ScrollbarSeekMode > 0.0f ) ? + 1.0f : - 1.0f ;
1034
* p_scroll_v = ImClamp ( * p_scroll_v + ( ImS64) ( page_dir * size_visible_v) , ( ImS64) 0 , scroll_max) ;
1035
}
1036
}
1037
1038
1039
scroll_ratio = ImSaturate ( ( float ) * p_scroll_v / ( float ) scroll_max) ;
1040
grab_v_norm = scroll_ratio * ( scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
1041
1042
1043
1044
1045
}
1046
1047
1048
const ImU32 bg_col = GetColorU32 ( ImGuiCol_ScrollbarBg ) ;
1049
const ImU32 grab_col = GetColorU32 ( held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha ) ;
1050
window-> DrawList -> AddRectFilled ( bb_frame. Min , bb_frame. Max , bg_col, window-> WindowRounding , flags ) ;
1051
ImRect grab_rect;
1052
if ( axis == ImGuiAxis_X)
1053
grab_rect = ImRect ( ImLerp ( bb. Min . x , bb. Max . x , grab_v_norm ) , bb. Min . y , ImLerp ( bb. Min . x , bb. Max . x , grab_v_norm ) + grab_h_pixels, bb. Max . y ) ;
1054
else
1055
grab_rect = ImRect ( bb. Min . x , ImLerp ( bb. Min . y , bb. Max . y , grab_v_norm ) , bb. Max . x , ImLerp ( bb. Min . y , bb. Max . y , grab_v_norm ) + grab_h_pixels ) ;
1056
window-> DrawList -> AddRectFilled ( grab_rect. Min , grab_rect. Max , grab_col, style. ScrollbarRounding ) ;
1057
1058
return held;
1059
}
1060
1061
1062
1063
void ImGui:: Image ( ImTextureID user_texture_id , const ImVec2& image_size , const ImVec2& uv0 , const ImVec2& uv1 , const ImVec4& tint_col , const ImVec4& border_col )
1064
{
1065
ImGuiWindow* window = GetCurrentWindow ( ) ;
1066
if ( window-> SkipItems )
1067
return ;
1068
1069
const float border_size = ( border_col. w > 0.0f ) ? 1.0f : 0.0f ;
1070
const ImVec2 padding ( border_size, border_size ) ;
1071
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + image_size + padding * 2.0f ) ;
1072
ItemSize ( bb ) ;
1073
if ( ! ItemAdd ( bb, 0 ) )
1074
return ;
1075
1076
1077
if ( border_size > 0.0f )
1078
window-> DrawList -> AddRect ( bb. Min , bb. Max , GetColorU32 ( border_col ) , 0.0f , ImDrawFlags_None, border_size ) ;
1079
window-> DrawList -> AddImage ( user_texture_id, bb. Min + padding, bb. Max - padding, uv0, uv1, GetColorU32 ( tint_col ) ) ;
1080
}
1081
1082
1083
1084
bool ImGui:: ImageButtonEx ( ImGuiID id , ImTextureID texture_id , const ImVec2& image_size , const ImVec2& uv0 , const ImVec2& uv1 , const ImVec4& bg_col , const ImVec4& tint_col , ImGuiButtonFlags flags )
1085
{
1086
ImGuiContext& g = * GImGui;
1087
ImGuiWindow* window = GetCurrentWindow ( ) ;
1088
if ( window-> SkipItems )
1089
return false ;
1090
1091
const ImVec2 padding = g. Style . FramePadding ;
1092
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + image_size + padding * 2.0f ) ;
1093
ItemSize ( bb ) ;
1094
if ( ! ItemAdd ( bb, id ) )
1095
return false ;
1096
1097
bool hovered, held;
1098
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, flags ) ;
1099
1100
1101
const ImU32 col = GetColorU32 ( ( held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button) ;
1102
RenderNavCursor ( bb, id ) ;
1103
RenderFrame ( bb. Min , bb. Max , col, true , ImClamp ( ( float ) ImMin ( padding. x , padding. y ) , 0.0f , g. Style . FrameRounding ) ) ;
1104
if ( bg_col. w > 0.0f )
1105
window-> DrawList -> AddRectFilled ( bb. Min + padding, bb. Max - padding, GetColorU32 ( bg_col ) ) ;
1106
window-> DrawList -> AddImage ( texture_id, bb. Min + padding, bb. Max - padding, uv0, uv1, GetColorU32 ( tint_col ) ) ;
1107
1108
return pressed;
1109
}
1110
1111
1112
bool ImGui:: ImageButton ( const char * str_id , ImTextureID user_texture_id , const ImVec2& image_size , const ImVec2& uv0 , const ImVec2& uv1 , const ImVec4& bg_col , const ImVec4& tint_col )
1113
{
1114
ImGuiContext& g = * GImGui;
1115
ImGuiWindow* window = g. CurrentWindow ;
1116
if ( window-> SkipItems )
1117
return false ;
1118
1119
return ImageButtonEx ( window-> GetID ( str_id ) , user_texture_id, image_size, uv0, uv1, bg_col, tint_col ) ;
1120
}
1121
1122
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
#endif
1143
1144
bool ImGui:: Checkbox ( const char * label , bool * v )
1145
{
1146
ImGuiWindow* window = GetCurrentWindow ( ) ;
1147
if ( window-> SkipItems )
1148
return false ;
1149
1150
ImGuiContext& g = * GImGui;
1151
const ImGuiStyle& style = g. Style ;
1152
const ImGuiID id = window-> GetID ( label ) ;
1153
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
1154
1155
const float square_sz = GetFrameHeight ( ) ;
1156
const ImVec2 pos = window-> DC . CursorPos ;
1157
const ImRect total_bb ( pos, pos + ImVec2 ( square_sz + ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f ) , label_size. y + style. FramePadding . y * 2.0f ) ) ;
1158
ItemSize ( total_bb, style. FramePadding . y ) ;
1159
const bool is_visible = ItemAdd ( total_bb, id ) ;
1160
const bool is_multi_select = ( g. LastItemData . ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0 ;
1161
if ( ! is_visible)
1162
if ( ! is_multi_select || ! g. BoxSelectState . UnclipMode || ! g. BoxSelectState . UnclipRect . Overlaps ( total_bb ) )
1163
{
1164
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Checkable | ( * v ? ImGuiItemStatusFlags_Checked : 0 ) ) ;
1165
return false ;
1166
}
1167
1168
1169
bool checked = * v;
1170
if ( is_multi_select)
1171
MultiSelectItemHeader ( id, & checked, NULL ) ;
1172
1173
bool hovered, held;
1174
bool pressed = ButtonBehavior ( total_bb, id, & hovered, & held ) ;
1175
1176
1177
if ( is_multi_select)
1178
MultiSelectItemFooter ( id, & checked, & pressed ) ;
1179
else if ( pressed)
1180
checked = ! checked;
1181
1182
if ( * v != checked)
1183
{
1184
* v = checked;
1185
pressed = true ;
1186
MarkItemEdited ( id ) ;
1187
}
1188
1189
const ImRect check_bb ( pos, pos + ImVec2 ( square_sz, square_sz ) ) ;
1190
const bool mixed_value = ( g. LastItemData . ItemFlags & ImGuiItemFlags_MixedValue) != 0 ;
1191
if ( is_visible)
1192
{
1193
RenderNavCursor ( total_bb, id ) ;
1194
RenderFrame ( check_bb. Min , check_bb. Max , GetColorU32 ( ( held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg) , true , style. FrameRounding ) ;
1195
ImU32 check_col = GetColorU32 ( ImGuiCol_CheckMark ) ;
1196
if ( mixed_value)
1197
{
1198
1199
1200
ImVec2 pad ( ImMax ( 1.0f , IM_TRUNC ( square_sz / 3.6f ) ) , ImMax ( 1.0f , IM_TRUNC ( square_sz / 3.6f ) ) ) ;
1201
window-> DrawList -> AddRectFilled ( check_bb. Min + pad, check_bb. Max - pad, check_col, style. FrameRounding ) ;
1202
}
1203
else if ( * v)
1204
{
1205
const float pad = ImMax ( 1.0f , IM_TRUNC ( square_sz / 6.0f ) ) ;
1206
RenderCheckMark ( window-> DrawList , check_bb. Min + ImVec2 ( pad, pad ) , check_col, square_sz - pad * 2.0f ) ;
1207
}
1208
}
1209
const ImVec2 label_pos = ImVec2 ( check_bb. Max . x + style. ItemInnerSpacing . x , check_bb. Min . y + style. FramePadding . y ) ;
1210
if ( g. LogEnabled )
1211
LogRenderedText ( & label_pos, mixed_value ? " [~]" : * v ? " [x]" : " [ ]" ) ;
1212
if ( is_visible && label_size. x > 0.0f )
1213
RenderText ( label_pos, label ) ;
1214
1215
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Checkable | ( * v ? ImGuiItemStatusFlags_Checked : 0 ) ) ;
1216
return pressed;
1217
}
1218
1219
template < typename T>
1220
bool ImGui:: CheckboxFlagsT ( const char * label , T* flags , T flags_value )
1221
{
1222
bool all_on = ( * flags & flags_value) == flags_value;
1223
bool any_on = ( * flags & flags_value) != 0 ;
1224
bool pressed;
1225
if ( ! all_on && any_on)
1226
{
1227
ImGuiContext& g = * GImGui;
1228
g. NextItemData . ItemFlags |= ImGuiItemFlags_MixedValue;
1229
pressed = Checkbox ( label, & all_on ) ;
1230
}
1231
else
1232
{
1233
pressed = Checkbox ( label, & all_on ) ;
1234
1235
}
1236
if ( pressed)
1237
{
1238
if ( all_on)
1239
* flags |= flags_value;
1240
else
1241
* flags &= ~ flags_value;
1242
}
1243
return pressed;
1244
}
1245
1246
bool ImGui:: CheckboxFlags ( const char * label , int * flags , int flags_value )
1247
{
1248
return CheckboxFlagsT ( label, flags, flags_value ) ;
1249
}
1250
1251
bool ImGui:: CheckboxFlags ( const char * label , unsigned int * flags , unsigned int flags_value )
1252
{
1253
return CheckboxFlagsT ( label, flags, flags_value ) ;
1254
}
1255
1256
bool ImGui:: CheckboxFlags ( const char * label , ImS64* flags , ImS64 flags_value )
1257
{
1258
return CheckboxFlagsT ( label, flags, flags_value ) ;
1259
}
1260
1261
bool ImGui:: CheckboxFlags ( const char * label , ImU64* flags , ImU64 flags_value )
1262
{
1263
return CheckboxFlagsT ( label, flags, flags_value ) ;
1264
}
1265
1266
bool ImGui:: RadioButton ( const char * label , bool active )
1267
{
1268
ImGuiWindow* window = GetCurrentWindow ( ) ;
1269
if ( window-> SkipItems )
1270
return false ;
1271
1272
ImGuiContext& g = * GImGui;
1273
const ImGuiStyle& style = g. Style ;
1274
const ImGuiID id = window-> GetID ( label ) ;
1275
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
1276
1277
const float square_sz = GetFrameHeight ( ) ;
1278
const ImVec2 pos = window-> DC . CursorPos ;
1279
const ImRect check_bb ( pos, pos + ImVec2 ( square_sz, square_sz ) ) ;
1280
const ImRect total_bb ( pos, pos + ImVec2 ( square_sz + ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f ) , label_size. y + style. FramePadding . y * 2.0f ) ) ;
1281
ItemSize ( total_bb, style. FramePadding . y ) ;
1282
if ( ! ItemAdd ( total_bb, id ) )
1283
return false ;
1284
1285
ImVec2 center = check_bb. GetCenter ( ) ;
1286
center. x = IM_ROUND ( center. x ) ;
1287
center. y = IM_ROUND ( center. y ) ;
1288
const float radius = ( square_sz - 1.0f ) * 0.5f ;
1289
1290
bool hovered, held;
1291
bool pressed = ButtonBehavior ( total_bb, id, & hovered, & held ) ;
1292
if ( pressed)
1293
MarkItemEdited ( id ) ;
1294
1295
RenderNavCursor ( total_bb, id ) ;
1296
const int num_segment = window-> DrawList -> _CalcCircleAutoSegmentCount ( radius ) ;
1297
window-> DrawList -> AddCircleFilled ( center, radius, GetColorU32 ( ( held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg) , num_segment ) ;
1298
if ( active)
1299
{
1300
const float pad = ImMax ( 1.0f , IM_TRUNC ( square_sz / 6.0f ) ) ;
1301
window-> DrawList -> AddCircleFilled ( center, radius - pad, GetColorU32 ( ImGuiCol_CheckMark ) ) ;
1302
}
1303
1304
if ( style. FrameBorderSize > 0.0f )
1305
{
1306
window-> DrawList -> AddCircle ( center + ImVec2 ( 1 , 1 ) , radius, GetColorU32 ( ImGuiCol_BorderShadow ) , num_segment, style. FrameBorderSize ) ;
1307
window-> DrawList -> AddCircle ( center, radius, GetColorU32 ( ImGuiCol_Border ) , num_segment, style. FrameBorderSize ) ;
1308
}
1309
1310
ImVec2 label_pos = ImVec2 ( check_bb. Max . x + style. ItemInnerSpacing . x , check_bb. Min . y + style. FramePadding . y ) ;
1311
if ( g. LogEnabled )
1312
LogRenderedText ( & label_pos, active ? " (x)" : " ( )" ) ;
1313
if ( label_size. x > 0.0f )
1314
RenderText ( label_pos, label ) ;
1315
1316
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags ) ;
1317
return pressed;
1318
}
1319
1320
1321
bool ImGui:: RadioButton ( const char * label , int * v , int v_button )
1322
{
1323
const bool pressed = RadioButton ( label, * v == v_button ) ;
1324
if ( pressed)
1325
* v = v_button;
1326
return pressed;
1327
}
1328
1329
1330
void ImGui:: ProgressBar ( float fraction , const ImVec2& size_arg , const char * overlay )
1331
{
1332
ImGuiWindow* window = GetCurrentWindow ( ) ;
1333
if ( window-> SkipItems )
1334
return ;
1335
1336
ImGuiContext& g = * GImGui;
1337
const ImGuiStyle& style = g. Style ;
1338
1339
ImVec2 pos = window-> DC . CursorPos ;
1340
ImVec2 size = CalcItemSize ( size_arg, CalcItemWidth ( ) , g. FontSize + style. FramePadding . y * 2.0f ) ;
1341
ImRect bb ( pos, pos + size ) ;
1342
ItemSize ( size, style. FramePadding . y ) ;
1343
if ( ! ItemAdd ( bb, 0 ) )
1344
return ;
1345
1346
1347
1348
const bool is_indeterminate = ( fraction < 0.0f ) ;
1349
if ( ! is_indeterminate)
1350
fraction = ImSaturate ( fraction ) ;
1351
1352
1353
float fill_n0 = 0.0f ;
1354
float fill_n1 = ( fraction == fraction) ? fraction : 0.0f ;
1355
1356
if ( is_indeterminate)
1357
{
1358
const float fill_width_n = 0.2f ;
1359
fill_n0 = ImFmod ( - fraction, 1.0f ) * ( 1.0f + fill_width_n) - fill_width_n;
1360
fill_n1 = ImSaturate ( fill_n0 + fill_width_n ) ;
1361
fill_n0 = ImSaturate ( fill_n0 ) ;
1362
}
1363
1364
1365
RenderFrame ( bb. Min , bb. Max , GetColorU32 ( ImGuiCol_FrameBg ) , true , style. FrameRounding ) ;
1366
bb. Expand ( ImVec2 ( - style. FrameBorderSize , - style. FrameBorderSize ) ) ;
1367
RenderRectFilledRangeH ( window-> DrawList , bb, GetColorU32 ( ImGuiCol_PlotHistogram ) , fill_n0, fill_n1, style. FrameRounding ) ;
1368
1369
1370
1371
char overlay_buf[ 32 ] ;
1372
if ( ! is_indeterminate || overlay != NULL )
1373
{
1374
if ( ! overlay)
1375
{
1376
ImFormatString ( overlay_buf, IM_ARRAYSIZE ( overlay_buf ) , " %.0f %% " , fraction * 100 + 0.01f ) ;
1377
overlay = overlay_buf;
1378
}
1379
1380
ImVec2 overlay_size = CalcTextSize ( overlay, NULL ) ;
1381
if ( overlay_size. x > 0.0f )
1382
{
1383
float text_x = is_indeterminate ? ( bb. Min . x + bb. Max . x - overlay_size. x ) * 0.5f : ImLerp ( bb. Min . x , bb. Max . x , fill_n1 ) + style. ItemSpacing . x ;
1384
RenderTextClipped ( ImVec2 ( ImClamp ( text_x, bb. Min . x , bb. Max . x - overlay_size. x - style. ItemInnerSpacing . x ) , bb. Min . y ) , bb. Max , overlay, NULL , & overlay_size, ImVec2 ( 0.0f , 0.5f ) , & bb) ;
1385
}
1386
}
1387
}
1388
1389
void ImGui:: Bullet ( )
1390
{
1391
ImGuiWindow* window = GetCurrentWindow ( ) ;
1392
if ( window-> SkipItems )
1393
return ;
1394
1395
ImGuiContext& g = * GImGui;
1396
const ImGuiStyle& style = g. Style ;
1397
const float line_height = ImMax ( ImMin ( window-> DC . CurrLineSize . y , g. FontSize + style. FramePadding . y * 2 ) , g. FontSize ) ;
1398
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + ImVec2 ( g. FontSize , line_height ) ) ;
1399
ItemSize ( bb ) ;
1400
if ( ! ItemAdd ( bb, 0 ) )
1401
{
1402
SameLine ( 0 , style. FramePadding . x * 2 ) ;
1403
return ;
1404
}
1405
1406
1407
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
1408
RenderBullet ( window-> DrawList , bb. Min + ImVec2 ( style. FramePadding . x + g. FontSize * 0.5f , line_height * 0.5f ) , text_col ) ;
1409
SameLine ( 0 , style. FramePadding . x * 2.0f ) ;
1410
}
1411
1412
1413
1414
1415
1416
bool ImGui:: TextLink ( const char * label )
1417
{
1418
ImGuiWindow* window = GetCurrentWindow ( ) ;
1419
if ( window-> SkipItems )
1420
return false ;
1421
1422
ImGuiContext& g = * GImGui;
1423
const ImGuiID id = window-> GetID ( label ) ;
1424
const char * label_end = FindRenderedTextEnd ( label ) ;
1425
1426
ImVec2 pos = window-> DC . CursorPos ;
1427
ImVec2 size = CalcTextSize ( label, label_end, true ) ;
1428
ImRect bb ( pos, pos + size ) ;
1429
ItemSize ( size, 0.0f ) ;
1430
if ( ! ItemAdd ( bb, id ) )
1431
return false ;
1432
1433
bool hovered, held;
1434
bool pressed = ButtonBehavior ( bb, id, & hovered, & held ) ;
1435
RenderNavCursor ( bb, id ) ;
1436
1437
if ( hovered)
1438
SetMouseCursor ( ImGuiMouseCursor_Hand ) ;
1439
1440
ImVec4 text_colf = g. Style . Colors [ ImGuiCol_TextLink] ;
1441
ImVec4 line_colf = text_colf;
1442
{
1443
1444
1445
float h, s, v;
1446
ColorConvertRGBtoHSV ( text_colf. x , text_colf. y , text_colf. z , h, s, v ) ;
1447
if ( held || hovered)
1448
{
1449
v = ImSaturate ( v + ( held ? 0.4f : 0.3f ) ) ;
1450
h = ImFmod ( h + 0.02f , 1.0f ) ;
1451
}
1452
ColorConvertHSVtoRGB ( h, s, v, text_colf. x , text_colf. y , text_colf. z ) ;
1453
v = ImSaturate ( v - 0.20f ) ;
1454
ColorConvertHSVtoRGB ( h, s, v, line_colf. x , line_colf. y , line_colf. z ) ;
1455
}
1456
1457
float line_y = bb. Max . y + ImFloor ( g. Font -> Descent * g. FontScale * 0.20f ) ;
1458
window-> DrawList -> AddLine ( ImVec2 ( bb. Min . x , line_y ) , ImVec2 ( bb. Max . x , line_y ) , GetColorU32 ( line_colf ) ) ;
1459
1460
PushStyleColor ( ImGuiCol_Text, GetColorU32 ( text_colf ) ) ;
1461
RenderText ( bb. Min , label, label_end ) ;
1462
PopStyleColor ( ) ;
1463
1464
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags ) ;
1465
return pressed;
1466
}
1467
1468
void ImGui:: TextLinkOpenURL ( const char * label , const char * url )
1469
{
1470
ImGuiContext& g = * GImGui;
1471
if ( url == NULL )
1472
url = label;
1473
if ( TextLink ( label ) )
1474
if ( g. PlatformIO . Platform_OpenInShellFn != NULL )
1475
g. PlatformIO . Platform_OpenInShellFn ( & g, url) ;
1476
SetItemTooltip ( LocalizeGetMsg ( ImGuiLocKey_OpenLink_s ) , url) ;
1477
if ( BeginPopupContextItem ( ) )
1478
{
1479
if ( MenuItem ( LocalizeGetMsg ( ImGuiLocKey_CopyLink ) ) )
1480
SetClipboardText ( url ) ;
1481
EndPopup ( ) ;
1482
}
1483
}
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
void ImGui:: Spacing ( )
1499
{
1500
ImGuiWindow* window = GetCurrentWindow ( ) ;
1501
if ( window-> SkipItems )
1502
return ;
1503
ItemSize ( ImVec2 ( 0 , 0 ) ) ;
1504
}
1505
1506
void ImGui:: Dummy ( const ImVec2& size )
1507
{
1508
ImGuiWindow* window = GetCurrentWindow ( ) ;
1509
if ( window-> SkipItems )
1510
return ;
1511
1512
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + size ) ;
1513
ItemSize ( size ) ;
1514
ItemAdd ( bb, 0 ) ;
1515
}
1516
1517
void ImGui:: NewLine ( )
1518
{
1519
ImGuiWindow* window = GetCurrentWindow ( ) ;
1520
if ( window-> SkipItems )
1521
return ;
1522
1523
ImGuiContext& g = * GImGui;
1524
const ImGuiLayoutType backup_layout_type = window-> DC . LayoutType ;
1525
window-> DC . LayoutType = ImGuiLayoutType_Vertical;
1526
window-> DC . IsSameLine = false ;
1527
if ( window-> DC . CurrLineSize . y > 0.0f )
1528
ItemSize ( ImVec2 ( 0 , 0 ) ) ;
1529
else
1530
ItemSize ( ImVec2 ( 0.0f , g. FontSize ) ) ;
1531
window-> DC . LayoutType = backup_layout_type;
1532
}
1533
1534
void ImGui:: AlignTextToFramePadding ( )
1535
{
1536
ImGuiWindow* window = GetCurrentWindow ( ) ;
1537
if ( window-> SkipItems )
1538
return ;
1539
1540
ImGuiContext& g = * GImGui;
1541
window-> DC . CurrLineSize . y = ImMax ( window-> DC . CurrLineSize . y , g. FontSize + g. Style . FramePadding . y * 2 ) ;
1542
window-> DC . CurrLineTextBaseOffset = ImMax ( window-> DC . CurrLineTextBaseOffset , g. Style . FramePadding . y ) ;
1543
}
1544
1545
1546
1547
1548
void ImGui:: SeparatorEx ( ImGuiSeparatorFlags flags , float thickness )
1549
{
1550
ImGuiWindow* window = GetCurrentWindow ( ) ;
1551
if ( window-> SkipItems )
1552
return ;
1553
1554
ImGuiContext& g = * GImGui;
1555
IM_ASSERT ( ImIsPowerOfTwo ( flags & ( ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical) ) ) ;
1556
IM_ASSERT ( thickness > 0.0f ) ;
1557
1558
if ( flags & ImGuiSeparatorFlags_Vertical)
1559
{
1560
1561
float y1 = window-> DC . CursorPos . y ;
1562
float y2 = window-> DC . CursorPos . y + window-> DC . CurrLineSize . y ;
1563
const ImRect bb ( ImVec2 ( window-> DC . CursorPos . x , y1 ) , ImVec2 ( window-> DC . CursorPos . x + thickness, y2 ) ) ;
1564
ItemSize ( ImVec2 ( thickness, 0.0f ) ) ;
1565
if ( ! ItemAdd ( bb, 0 ) )
1566
return ;
1567
1568
1569
window-> DrawList -> AddRectFilled ( bb. Min , bb. Max , GetColorU32 ( ImGuiCol_Separator ) ) ;
1570
if ( g. LogEnabled )
1571
LogText ( " |" ) ;
1572
}
1573
else if ( flags & ImGuiSeparatorFlags_Horizontal)
1574
{
1575
1576
float x1 = window-> DC . CursorPos . x ;
1577
float x2 = window-> WorkRect . Max . x ;
1578
1579
1580
1581
1582
ImGuiOldColumns* columns = ( flags & ImGuiSeparatorFlags_SpanAllColumns) ? window-> DC . CurrentColumns : NULL ;
1583
if ( columns)
1584
{
1585
x1 = window-> Pos . x + window-> DC . Indent . x ;
1586
x2 = window-> Pos . x + window-> Size . x ;
1587
PushColumnsBackground ( ) ;
1588
}
1589
1590
1591
1592
const float thickness_for_layout = ( thickness == 1.0f ) ? 0.0f : thickness;
1593
const ImRect bb ( ImVec2 ( x1, window-> DC . CursorPos . y ) , ImVec2 ( x2, window-> DC . CursorPos . y + thickness ) ) ;
1594
ItemSize ( ImVec2 ( 0.0f , thickness_for_layout) ) ;
1595
1596
if ( ItemAdd ( bb, 0 ) )
1597
{
1598
1599
window-> DrawList -> AddRectFilled ( bb. Min , bb. Max , GetColorU32 ( ImGuiCol_Separator ) ) ;
1600
if ( g. LogEnabled )
1601
LogRenderedText ( & bb. Min , " --------------------------------\n " ) ;
1602
1603
}
1604
if ( columns)
1605
{
1606
PopColumnsBackground ( ) ;
1607
columns-> LineMinY = window-> DC . CursorPos . y ;
1608
}
1609
}
1610
}
1611
1612
void ImGui:: Separator ( )
1613
{
1614
ImGuiContext& g = * GImGui;
1615
ImGuiWindow* window = g. CurrentWindow ;
1616
if ( window-> SkipItems )
1617
return ;
1618
1619
1620
1621
ImGuiSeparatorFlags flags = ( window-> DC . LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
1622
1623
1624
if ( window-> DC . CurrentColumns )
1625
flags |= ImGuiSeparatorFlags_SpanAllColumns;
1626
1627
SeparatorEx ( flags, 1.0f ) ;
1628
}
1629
1630
void ImGui:: SeparatorTextEx ( ImGuiID id , const char * label , const char * label_end , float extra_w )
1631
{
1632
ImGuiContext& g = * GImGui;
1633
ImGuiWindow* window = g. CurrentWindow ;
1634
ImGuiStyle& style = g. Style ;
1635
1636
const ImVec2 label_size = CalcTextSize ( label, label_end, false ) ;
1637
const ImVec2 pos = window-> DC . CursorPos ;
1638
const ImVec2 padding = style. SeparatorTextPadding ;
1639
1640
const float separator_thickness = style. SeparatorTextBorderSize ;
1641
const ImVec2 min_size ( label_size. x + extra_w + padding. x * 2.0f , ImMax ( label_size. y + padding. y * 2.0f , separator_thickness ) ) ;
1642
const ImRect bb ( pos, ImVec2 ( window-> WorkRect . Max . x , pos. y + min_size. y ) ) ;
1643
const float text_baseline_y = ImTrunc ( ( bb. GetHeight ( ) - label_size. y ) * style. SeparatorTextAlign . y + 0.99999f ) ;
1644
ItemSize ( min_size, text_baseline_y ) ;
1645
if ( ! ItemAdd ( bb, id ) )
1646
return ;
1647
1648
const float sep1_x1 = pos. x ;
1649
const float sep2_x2 = bb. Max . x ;
1650
const float seps_y = ImTrunc ( ( bb. Min . y + bb. Max . y ) * 0.5f + 0.99999f ) ;
1651
1652
const float label_avail_w = ImMax ( 0.0f , sep2_x2 - sep1_x1 - padding. x * 2.0f ) ;
1653
const ImVec2 label_pos ( pos. x + padding. x + ImMax ( 0.0f , ( label_avail_w - label_size. x - extra_w) * style. SeparatorTextAlign . x ) , pos. y + text_baseline_y ) ;
1654
1655
1656
window-> DC . CursorPosPrevLine . x = label_pos. x + label_size. x ;
1657
1658
const ImU32 separator_col = GetColorU32 ( ImGuiCol_Separator ) ;
1659
if ( label_size. x > 0.0f )
1660
{
1661
const float sep1_x2 = label_pos. x - style. ItemSpacing . x ;
1662
const float sep2_x1 = label_pos. x + label_size. x + extra_w + style. ItemSpacing . x ;
1663
if ( sep1_x2 > sep1_x1 && separator_thickness > 0.0f )
1664
window-> DrawList -> AddLine ( ImVec2 ( sep1_x1, seps_y ) , ImVec2 ( sep1_x2, seps_y ) , separator_col, separator_thickness) ;
1665
if ( sep2_x2 > sep2_x1 && separator_thickness > 0.0f )
1666
window-> DrawList -> AddLine ( ImVec2 ( sep2_x1, seps_y ) , ImVec2 ( sep2_x2, seps_y ) , separator_col, separator_thickness) ;
1667
if ( g. LogEnabled )
1668
LogSetNextTextDecoration ( " ---" , NULL ) ;
1669
RenderTextEllipsis ( window-> DrawList , label_pos, ImVec2 ( bb. Max . x , bb. Max . y + style. ItemSpacing . y ) , bb. Max . x , bb. Max . x , label, label_end, & label_size ) ;
1670
}
1671
else
1672
{
1673
if ( g. LogEnabled )
1674
LogText ( " ---" ) ;
1675
if ( separator_thickness > 0.0f )
1676
window-> DrawList -> AddLine ( ImVec2 ( sep1_x1, seps_y ) , ImVec2 ( sep2_x2, seps_y ) , separator_col, separator_thickness) ;
1677
}
1678
}
1679
1680
void ImGui:: SeparatorText ( const char * label )
1681
{
1682
ImGuiWindow* window = GetCurrentWindow ( ) ;
1683
if ( window-> SkipItems )
1684
return ;
1685
1686
1687
1688
1689
1690
1691
1692
SeparatorTextEx ( 0 , label, FindRenderedTextEnd ( label ) , 0.0f ) ;
1693
}
1694
1695
1696
bool ImGui:: SplitterBehavior ( const ImRect& bb , ImGuiID id , ImGuiAxis axis , float * size1 , float * size2 , float min_size1 , float min_size2 , float hover_extend , float hover_visibility_delay , ImU32 bg_col )
1697
{
1698
ImGuiContext& g = * GImGui;
1699
ImGuiWindow* window = g. CurrentWindow ;
1700
1701
if ( ! ItemAdd ( bb, id, NULL , ImGuiItemFlags_NoNav ) )
1702
return false ;
1703
1704
1705
1706
1707
ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren;
1708
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1709
button_flags |= ImGuiButtonFlags_AllowOverlap;
1710
#endif
1711
1712
bool hovered, held;
1713
ImRect bb_interact = bb;
1714
bb_interact. Expand ( axis == ImGuiAxis_Y ? ImVec2 ( 0.0f , hover_extend) : ImVec2 ( hover_extend, 0.0f ) ) ;
1715
ButtonBehavior ( bb_interact, id, & hovered, & held, button_flags ) ;
1716
if ( hovered)
1717
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
1718
1719
if ( held || ( hovered && g. HoveredIdPreviousFrame == id && g. HoveredIdTimer >= hover_visibility_delay) )
1720
SetMouseCursor ( axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW ) ;
1721
1722
ImRect bb_render = bb;
1723
if ( held)
1724
{
1725
float mouse_delta = ( g. IO . MousePos - g. ActiveIdClickOffset - bb_interact. Min ) [ axis] ;
1726
1727
1728
float size_1_maximum_delta = ImMax ( 0.0f , * size1 - min_size1) ;
1729
float size_2_maximum_delta = ImMax ( 0.0f , * size2 - min_size2) ;
1730
if ( mouse_delta < - size_1_maximum_delta)
1731
mouse_delta = - size_1_maximum_delta;
1732
if ( mouse_delta > size_2_maximum_delta)
1733
mouse_delta = size_2_maximum_delta;
1734
1735
1736
if ( mouse_delta != 0.0f )
1737
{
1738
* size1 = ImMax ( * size1 + mouse_delta, min_size1) ;
1739
* size2 = ImMax ( * size2 - mouse_delta, min_size2) ;
1740
bb_render. Translate ( ( axis == ImGuiAxis_X) ? ImVec2 ( mouse_delta, 0.0f ) : ImVec2 ( 0.0f , mouse_delta) ) ;
1741
MarkItemEdited ( id ) ;
1742
}
1743
}
1744
1745
1746
if ( bg_col & IM_COL32_A_MASK)
1747
window-> DrawList -> AddRectFilled ( bb_render. Min , bb_render. Max , bg_col, 0.0f ) ;
1748
const ImU32 col = GetColorU32 ( held ? ImGuiCol_SeparatorActive : ( hovered && g. HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator ) ;
1749
window-> DrawList -> AddRectFilled ( bb_render. Min , bb_render. Max , col, 0.0f ) ;
1750
1751
return held;
1752
}
1753
1754
static int IMGUI_CDECL ShrinkWidthItemComparer ( const void * lhs , const void * rhs )
1755
{
1756
const ImGuiShrinkWidthItem* a = ( const ImGuiShrinkWidthItem* ) lhs;
1757
const ImGuiShrinkWidthItem* b = ( const ImGuiShrinkWidthItem* ) rhs;
1758
if ( int d = ( int ) ( b-> Width - a-> Width ) )
1759
return d;
1760
return ( b-> Index - a-> Index ) ;
1761
}
1762
1763
1764
1765
void ImGui:: ShrinkWidths ( ImGuiShrinkWidthItem* items , int count , float width_excess )
1766
{
1767
if ( count == 1 )
1768
{
1769
if ( items[ 0 ] . Width >= 0.0f )
1770
items[ 0 ] . Width = ImMax ( items[ 0 ] . Width - width_excess, 1.0f ) ;
1771
return ;
1772
}
1773
ImQsort ( items, ( size_t ) count, sizeof ( ImGuiShrinkWidthItem ) , ShrinkWidthItemComparer ) ;
1774
int count_same_width = 1 ;
1775
while ( width_excess > 0.0f && count_same_width < count)
1776
{
1777
while ( count_same_width < count && items[ 0 ] . Width <= items[ count_same_width] . Width )
1778
count_same_width+ + ;
1779
float max_width_to_remove_per_item = ( count_same_width < count && items[ count_same_width] . Width >= 0.0f ) ? ( items[ 0 ] . Width - items[ count_same_width] . Width ) : ( items[ 0 ] . Width - 1.0f ) ;
1780
if ( max_width_to_remove_per_item <= 0.0f )
1781
break ;
1782
float width_to_remove_per_item = ImMin ( width_excess / count_same_width, max_width_to_remove_per_item ) ;
1783
for ( int item_n = 0 ; item_n < count_same_width; item_n+ + )
1784
items[ item_n] . Width -= width_to_remove_per_item;
1785
width_excess -= width_to_remove_per_item * count_same_width;
1786
}
1787
1788
1789
1790
width_excess = 0.0f ;
1791
for ( int n = 0 ; n < count; n+ + )
1792
{
1793
float width_rounded = ImTrunc ( items[ n] . Width ) ;
1794
width_excess += items[ n] . Width - width_rounded;
1795
items[ n] . Width = width_rounded;
1796
}
1797
while ( width_excess > 0.0f )
1798
for ( int n = 0 ; n < count && width_excess > 0.0f ; n+ + )
1799
{
1800
float width_to_add = ImMin ( items[ n] . InitialWidth - items[ n] . Width , 1.0f ) ;
1801
items[ n] . Width += width_to_add;
1802
width_excess -= width_to_add;
1803
}
1804
}
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
static float CalcMaxPopupHeightFromItemCount ( int items_count )
1819
{
1820
ImGuiContext& g = * GImGui;
1821
if ( items_count <= 0 )
1822
return FLT_MAX;
1823
return ( g. FontSize + g. Style . ItemSpacing . y ) * items_count - g. Style . ItemSpacing . y + ( g. Style . WindowPadding . y * 2 ) ;
1824
}
1825
1826
bool ImGui:: BeginCombo ( const char * label , const char * preview_value , ImGuiComboFlags flags )
1827
{
1828
ImGuiContext& g = * GImGui;
1829
ImGuiWindow* window = GetCurrentWindow ( ) ;
1830
1831
ImGuiNextWindowDataFlags backup_next_window_data_flags = g. NextWindowData . Flags ;
1832
g. NextWindowData . ClearFlags ( ) ;
1833
if ( window-> SkipItems )
1834
return false ;
1835
1836
const ImGuiStyle& style = g. Style ;
1837
const ImGuiID id = window-> GetID ( label ) ;
1838
IM_ASSERT ( ( flags & ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview) ) != ( ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview) ) ;
1839
if ( flags & ImGuiComboFlags_WidthFitPreview)
1840
IM_ASSERT ( ( flags & ( ImGuiComboFlags_NoPreview | ( ImGuiComboFlags) ImGuiComboFlags_CustomPreview) ) == 0 ) ;
1841
1842
const float arrow_size = ( flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight ( ) ;
1843
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
1844
const float preview_width = ( ( flags & ImGuiComboFlags_WidthFitPreview) && ( preview_value != NULL ) ) ? CalcTextSize ( preview_value, NULL , true ) . x : 0.0f ;
1845
const float w = ( flags & ImGuiComboFlags_NoPreview) ? arrow_size : ( ( flags & ImGuiComboFlags_WidthFitPreview) ? ( arrow_size + preview_width + style. FramePadding . x * 2.0f ) : CalcItemWidth ( ) ) ;
1846
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + ImVec2 ( w, label_size. y + style. FramePadding . y * 2.0f ) ) ;
1847
const ImRect total_bb ( bb. Min , bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0.0f ) ) ;
1848
ItemSize ( total_bb, style. FramePadding . y ) ;
1849
if ( ! ItemAdd ( total_bb, id, & bb ) )
1850
return false ;
1851
1852
1853
bool hovered, held;
1854
bool pressed = ButtonBehavior ( bb, id, & hovered, & held ) ;
1855
const ImGuiID popup_id = ImHashStr ( " ##ComboPopup" , 0 , id) ;
1856
bool popup_open = IsPopupOpen ( popup_id, ImGuiPopupFlags_None ) ;
1857
if ( pressed && ! popup_open)
1858
{
1859
OpenPopupEx ( popup_id, ImGuiPopupFlags_None ) ;
1860
popup_open = true ;
1861
}
1862
1863
1864
const ImU32 frame_col = GetColorU32 ( hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
1865
const float value_x2 = ImMax ( bb. Min . x , bb. Max . x - arrow_size ) ;
1866
RenderNavCursor ( bb, id ) ;
1867
if ( ! ( flags & ImGuiComboFlags_NoPreview) )
1868
window-> DrawList -> AddRectFilled ( bb. Min , ImVec2 ( value_x2, bb. Max . y ) , frame_col, style. FrameRounding , ( flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft ) ;
1869
if ( ! ( flags & ImGuiComboFlags_NoArrowButton) )
1870
{
1871
ImU32 bg_col = GetColorU32 ( ( popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button) ;
1872
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
1873
window-> DrawList -> AddRectFilled ( ImVec2 ( value_x2, bb. Min . y ) , bb. Max , bg_col, style. FrameRounding , ( w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight) ;
1874
if ( value_x2 + arrow_size - style. FramePadding . x <= bb. Max . x )
1875
RenderArrow ( window-> DrawList , ImVec2 ( value_x2 + style. FramePadding . y , bb. Min . y + style. FramePadding . y ) , text_col, ImGuiDir_Down, 1.0f ) ;
1876
}
1877
RenderFrameBorder ( bb. Min , bb. Max , style. FrameRounding ) ;
1878
1879
1880
if ( flags & ImGuiComboFlags_CustomPreview)
1881
{
1882
g. ComboPreviewData . PreviewRect = ImRect ( bb. Min . x , bb. Min . y , value_x2, bb. Max . y ) ;
1883
IM_ASSERT ( preview_value == NULL || preview_value[ 0 ] == 0 ) ;
1884
preview_value = NULL ;
1885
}
1886
1887
1888
if ( preview_value != NULL && ! ( flags & ImGuiComboFlags_NoPreview) )
1889
{
1890
if ( g. LogEnabled )
1891
LogSetNextTextDecoration ( " {" , " }" ) ;
1892
RenderTextClipped ( bb. Min + style. FramePadding , ImVec2 ( value_x2, bb. Max . y ) , preview_value, NULL , NULL ) ;
1893
}
1894
if ( label_size. x > 0 )
1895
RenderText ( ImVec2 ( bb. Max . x + style. ItemInnerSpacing . x , bb. Min . y + style. FramePadding . y ) , label) ;
1896
1897
if ( ! popup_open)
1898
return false ;
1899
1900
g. NextWindowData . Flags = backup_next_window_data_flags;
1901
return BeginComboPopup ( popup_id, bb, flags ) ;
1902
}
1903
1904
bool ImGui:: BeginComboPopup ( ImGuiID popup_id , const ImRect& bb , ImGuiComboFlags flags )
1905
{
1906
ImGuiContext& g = * GImGui;
1907
if ( ! IsPopupOpen ( popup_id, ImGuiPopupFlags_None ) )
1908
{
1909
g. NextWindowData . ClearFlags ( ) ;
1910
return false ;
1911
}
1912
1913
1914
float w = bb. GetWidth ( ) ;
1915
if ( g. NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
1916
{
1917
g. NextWindowData . SizeConstraintRect . Min . x = ImMax ( g. NextWindowData . SizeConstraintRect . Min . x , w ) ;
1918
}
1919
else
1920
{
1921
if ( ( flags & ImGuiComboFlags_HeightMask_) == 0 )
1922
flags |= ImGuiComboFlags_HeightRegular;
1923
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiComboFlags_HeightMask_ ) ) ;
1924
int popup_max_height_in_items = - 1 ;
1925
if ( flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8 ;
1926
else if ( flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4 ;
1927
else if ( flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20 ;
1928
ImVec2 constraint_min ( 0.0f , 0.0f ) , constraint_max ( FLT_MAX, FLT_MAX ) ;
1929
if ( ( g. NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g. NextWindowData . SizeVal . x <= 0.0f )
1930
constraint_min. x = w;
1931
if ( ( g. NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g. NextWindowData . SizeVal . y <= 0.0f )
1932
constraint_max. y = CalcMaxPopupHeightFromItemCount ( popup_max_height_in_items ) ;
1933
SetNextWindowSizeConstraints ( constraint_min, constraint_max ) ;
1934
}
1935
1936
1937
char name[ 16 ] ;
1938
ImFormatString ( name, IM_ARRAYSIZE ( name ) , " ##Combo_%02d " , g. BeginComboDepth ) ;
1939
1940
1941
1942
1943
if ( ImGuiWindow* popup_window = FindWindowByName ( name ) )
1944
if ( popup_window-> WasActive )
1945
{
1946
1947
ImVec2 size_expected = CalcWindowNextAutoFitSize ( popup_window ) ;
1948
popup_window-> AutoPosLastDirection = ( flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down;
1949
ImRect r_outer = GetPopupAllowedExtentRect ( popup_window ) ;
1950
ImVec2 pos = FindBestWindowPosForPopupEx ( bb. GetBL ( ) , size_expected, & popup_window-> AutoPosLastDirection , r_outer, bb, ImGuiPopupPositionPolicy_ComboBox ) ;
1951
SetNextWindowPos ( pos ) ;
1952
}
1953
1954
1955
ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove;
1956
PushStyleVarX ( ImGuiStyleVar_WindowPadding, g. Style . FramePadding . x ) ;
1957
bool ret = Begin ( name, NULL , window_flags ) ;
1958
PopStyleVar ( ) ;
1959
if ( ! ret)
1960
{
1961
EndPopup ( ) ;
1962
IM_ASSERT ( 0 ) ;
1963
return false ;
1964
}
1965
g. BeginComboDepth + + ;
1966
return true ;
1967
}
1968
1969
void ImGui:: EndCombo ( )
1970
{
1971
ImGuiContext& g = * GImGui;
1972
EndPopup ( ) ;
1973
g. BeginComboDepth - - ;
1974
}
1975
1976
1977
1978
bool ImGui:: BeginComboPreview ( )
1979
{
1980
ImGuiContext& g = * GImGui;
1981
ImGuiWindow* window = g. CurrentWindow ;
1982
ImGuiComboPreviewData* preview_data = & g. ComboPreviewData ;
1983
1984
if ( window-> SkipItems || ! ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_Visible) )
1985
return false ;
1986
IM_ASSERT ( g. LastItemData . Rect . Min . x == preview_data-> PreviewRect . Min . x && g. LastItemData . Rect . Min . y == preview_data-> PreviewRect . Min . y ) ;
1987
if ( ! window-> ClipRect . Overlaps ( preview_data-> PreviewRect ) )
1988
return false ;
1989
1990
1991
preview_data-> BackupCursorPos = window-> DC . CursorPos ;
1992
preview_data-> BackupCursorMaxPos = window-> DC . CursorMaxPos ;
1993
preview_data-> BackupCursorPosPrevLine = window-> DC . CursorPosPrevLine ;
1994
preview_data-> BackupPrevLineTextBaseOffset = window-> DC . PrevLineTextBaseOffset ;
1995
preview_data-> BackupLayout = window-> DC . LayoutType ;
1996
window-> DC . CursorPos = preview_data-> PreviewRect . Min + g. Style . FramePadding ;
1997
window-> DC . CursorMaxPos = window-> DC . CursorPos ;
1998
window-> DC . LayoutType = ImGuiLayoutType_Horizontal;
1999
window-> DC . IsSameLine = false ;
2000
PushClipRect ( preview_data-> PreviewRect . Min , preview_data-> PreviewRect . Max , true ) ;
2001
2002
return true ;
2003
}
2004
2005
void ImGui:: EndComboPreview ( )
2006
{
2007
ImGuiContext& g = * GImGui;
2008
ImGuiWindow* window = g. CurrentWindow ;
2009
ImGuiComboPreviewData* preview_data = & g. ComboPreviewData ;
2010
2011
2012
ImDrawList* draw_list = window-> DrawList ;
2013
if ( window-> DC . CursorMaxPos . x < preview_data-> PreviewRect . Max . x && window-> DC . CursorMaxPos . y < preview_data-> PreviewRect . Max . y )
2014
if ( draw_list-> CmdBuffer . Size > 1 )
2015
{
2016
draw_list-> _CmdHeader . ClipRect = draw_list-> CmdBuffer [ draw_list-> CmdBuffer . Size - 1 ] . ClipRect = draw_list-> CmdBuffer [ draw_list-> CmdBuffer . Size - 2 ] . ClipRect ;
2017
draw_list-> _TryMergeDrawCmds ( ) ;
2018
}
2019
PopClipRect ( ) ;
2020
window-> DC . CursorPos = preview_data-> BackupCursorPos ;
2021
window-> DC . CursorMaxPos = ImMax ( window-> DC . CursorMaxPos , preview_data-> BackupCursorMaxPos ) ;
2022
window-> DC . CursorPosPrevLine = preview_data-> BackupCursorPosPrevLine ;
2023
window-> DC . PrevLineTextBaseOffset = preview_data-> BackupPrevLineTextBaseOffset ;
2024
window-> DC . LayoutType = preview_data-> BackupLayout ;
2025
window-> DC . IsSameLine = false ;
2026
preview_data-> PreviewRect = ImRect ( ) ;
2027
}
2028
2029
2030
static const char * Items_ArrayGetter ( void * data , int idx )
2031
{
2032
const char * const * items = ( const char * const * ) data;
2033
return items[ idx] ;
2034
}
2035
2036
2037
static const char * Items_SingleStringGetter ( void * data , int idx )
2038
{
2039
const char * items_separated_by_zeros = ( const char * ) data;
2040
int items_count = 0 ;
2041
const char * p = items_separated_by_zeros;
2042
while ( * p)
2043
{
2044
if ( idx == items_count)
2045
break ;
2046
p += strlen ( p ) + 1 ;
2047
items_count+ + ;
2048
}
2049
return * p ? p : NULL ;
2050
}
2051
2052
2053
bool ImGui:: Combo ( const char * label , int * current_item , const char * ( * getter) ( void * user_data, int idx) , void * user_data , int items_count , int popup_max_height_in_items )
2054
{
2055
ImGuiContext& g = * GImGui;
2056
2057
2058
const char * preview_value = NULL ;
2059
if ( * current_item >= 0 && * current_item < items_count)
2060
preview_value = getter ( user_data, * current_item ) ;
2061
2062
2063
if ( popup_max_height_in_items != - 1 && ! ( g. NextWindowData . Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) )
2064
SetNextWindowSizeConstraints ( ImVec2 ( 0 , 0 ) , ImVec2 ( FLT_MAX, CalcMaxPopupHeightFromItemCount ( popup_max_height_in_items ) ) ) ;
2065
2066
if ( ! BeginCombo ( label, preview_value, ImGuiComboFlags_None ) )
2067
return false ;
2068
2069
2070
bool value_changed = false ;
2071
ImGuiListClipper clipper;
2072
clipper. Begin ( items_count ) ;
2073
clipper. IncludeItemByIndex ( * current_item) ;
2074
while ( clipper. Step ( ) )
2075
for ( int i = clipper. DisplayStart ; i < clipper. DisplayEnd ; i+ + )
2076
{
2077
const char * item_text = getter ( user_data, i ) ;
2078
if ( item_text == NULL )
2079
item_text = " *Unknown item*" ;
2080
2081
PushID ( i ) ;
2082
const bool item_selected = ( i == * current_item) ;
2083
if ( Selectable ( item_text, item_selected ) && * current_item != i)
2084
{
2085
value_changed = true ;
2086
* current_item = i;
2087
}
2088
if ( item_selected)
2089
SetItemDefaultFocus ( ) ;
2090
PopID ( ) ;
2091
}
2092
2093
EndCombo ( ) ;
2094
if ( value_changed)
2095
MarkItemEdited ( g. LastItemData . ID ) ;
2096
2097
return value_changed;
2098
}
2099
2100
2101
bool ImGui:: Combo ( const char * label , int * current_item , const char * const items [ ] , int items_count , int height_in_items )
2102
{
2103
const bool value_changed = Combo ( label, current_item, Items_ArrayGetter, ( void * ) items, items_count, height_in_items ) ;
2104
return value_changed;
2105
}
2106
2107
2108
bool ImGui:: Combo ( const char * label , int * current_item , const char * items_separated_by_zeros , int height_in_items )
2109
{
2110
int items_count = 0 ;
2111
const char * p = items_separated_by_zeros;
2112
while ( * p)
2113
{
2114
p += strlen ( p ) + 1 ;
2115
items_count+ + ;
2116
}
2117
bool value_changed = Combo ( label, current_item, Items_SingleStringGetter, ( void * ) items_separated_by_zeros, items_count, height_in_items ) ;
2118
return value_changed;
2119
}
2120
2121
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
2122
2123
struct ImGuiGetNameFromIndexOldToNewCallbackData { void * UserData; bool ( * OldCallback) ( void * , int , const char * * ) ; } ;
2124
static const char * ImGuiGetNameFromIndexOldToNewCallback ( void * user_data , int idx )
2125
{
2126
ImGuiGetNameFromIndexOldToNewCallbackData* data = ( ImGuiGetNameFromIndexOldToNewCallbackData* ) user_data;
2127
const char * s = NULL ;
2128
data-> OldCallback ( data-> UserData , idx, & s ) ;
2129
return s;
2130
}
2131
2132
bool ImGui:: ListBox ( const char * label , int * current_item , bool ( * old_getter) ( void * , int , const char * * ) , void * user_data , int items_count , int height_in_items )
2133
{
2134
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter } ;
2135
return ListBox ( label, current_item, ImGuiGetNameFromIndexOldToNewCallback, & old_to_new_data, items_count, height_in_items ) ;
2136
}
2137
bool ImGui:: Combo ( const char * label , int * current_item , bool ( * old_getter) ( void * , int , const char * * ) , void * user_data , int items_count , int popup_max_height_in_items )
2138
{
2139
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter } ;
2140
return Combo ( label, current_item, ImGuiGetNameFromIndexOldToNewCallback, & old_to_new_data, items_count, popup_max_height_in_items ) ;
2141
}
2142
2143
#endif
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
static const ImGuiDataTypeInfo GDataTypeInfo[ ] =
2159
{
2160
{ sizeof ( char ) , " S8" , " %d " , " %d " } ,
2161
{ sizeof ( unsigned char ) , " U8" , " %u " , " %u " } ,
2162
{ sizeof ( short ) , " S16" , " %d " , " %d " } ,
2163
{ sizeof ( unsigned short ) , " U16" , " %u " , " %u " } ,
2164
{ sizeof ( int ) , " S32" , " %d " , " %d " } ,
2165
{ sizeof ( unsigned int ) , " U32" , " %u " , " %u " } ,
2166
#ifdef _MSC_VER
2167
{ sizeof ( ImS64 ) , " S64" , " %I64d" , " %I64d" } ,
2168
{ sizeof ( ImU64 ) , " U64" , " %I64u" , " %I64u" } ,
2169
#else
2170
{ sizeof ( ImS64 ) , " S64" , " %lld " , " %lld " } ,
2171
{ sizeof ( ImU64 ) , " U64" , " %llu " , " %llu " } ,
2172
#endif
2173
{ sizeof ( float ) , " float" , " %.3f " , " %f " } ,
2174
{ sizeof ( double ) , " double" , " %f " , " %lf " } ,
2175
{ sizeof ( bool ) , " bool" , " %d " , " %d " } ,
2176
} ;
2177
IM_STATIC_ASSERT ( IM_ARRAYSIZE ( GDataTypeInfo ) == ImGuiDataType_COUNT) ;
2178
2179
const ImGuiDataTypeInfo* ImGui:: DataTypeGetInfo ( ImGuiDataType data_type )
2180
{
2181
IM_ASSERT ( data_type >= 0 && data_type < ImGuiDataType_COUNT ) ;
2182
return & GDataTypeInfo[ data_type] ;
2183
}
2184
2185
int ImGui:: DataTypeFormatString ( char * buf , int buf_size , ImGuiDataType data_type , const void * p_data , const char * format )
2186
{
2187
2188
if ( data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32)
2189
return ImFormatString ( buf, buf_size, format, * ( const ImU32* ) p_data ) ;
2190
if ( data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
2191
return ImFormatString ( buf, buf_size, format, * ( const ImU64* ) p_data ) ;
2192
if ( data_type == ImGuiDataType_Float)
2193
return ImFormatString ( buf, buf_size, format, * ( const float * ) p_data ) ;
2194
if ( data_type == ImGuiDataType_Double)
2195
return ImFormatString ( buf, buf_size, format, * ( const double * ) p_data ) ;
2196
if ( data_type == ImGuiDataType_S8)
2197
return ImFormatString ( buf, buf_size, format, * ( const ImS8* ) p_data ) ;
2198
if ( data_type == ImGuiDataType_U8)
2199
return ImFormatString ( buf, buf_size, format, * ( const ImU8* ) p_data ) ;
2200
if ( data_type == ImGuiDataType_S16)
2201
return ImFormatString ( buf, buf_size, format, * ( const ImS16* ) p_data ) ;
2202
if ( data_type == ImGuiDataType_U16)
2203
return ImFormatString ( buf, buf_size, format, * ( const ImU16* ) p_data ) ;
2204
IM_ASSERT ( 0 ) ;
2205
return 0 ;
2206
}
2207
2208
void ImGui:: DataTypeApplyOp ( ImGuiDataType data_type , int op , void * output , const void * arg1 , const void * arg2 )
2209
{
2210
IM_ASSERT ( op == ' +' || op == ' -' ) ;
2211
switch ( data_type)
2212
{
2213
case ImGuiDataType_S8:
2214
if ( op == ' +' ) { * ( ImS8* ) output = ImAddClampOverflow ( * ( const ImS8* ) arg1, * ( const ImS8* ) arg2, IM_S8_MIN, IM_S8_MAX) ; }
2215
if ( op == ' -' ) { * ( ImS8* ) output = ImSubClampOverflow ( * ( const ImS8* ) arg1, * ( const ImS8* ) arg2, IM_S8_MIN, IM_S8_MAX) ; }
2216
return ;
2217
case ImGuiDataType_U8:
2218
if ( op == ' +' ) { * ( ImU8* ) output = ImAddClampOverflow ( * ( const ImU8* ) arg1, * ( const ImU8* ) arg2, IM_U8_MIN, IM_U8_MAX) ; }
2219
if ( op == ' -' ) { * ( ImU8* ) output = ImSubClampOverflow ( * ( const ImU8* ) arg1, * ( const ImU8* ) arg2, IM_U8_MIN, IM_U8_MAX) ; }
2220
return ;
2221
case ImGuiDataType_S16:
2222
if ( op == ' +' ) { * ( ImS16* ) output = ImAddClampOverflow ( * ( const ImS16* ) arg1, * ( const ImS16* ) arg2, IM_S16_MIN, IM_S16_MAX) ; }
2223
if ( op == ' -' ) { * ( ImS16* ) output = ImSubClampOverflow ( * ( const ImS16* ) arg1, * ( const ImS16* ) arg2, IM_S16_MIN, IM_S16_MAX) ; }
2224
return ;
2225
case ImGuiDataType_U16:
2226
if ( op == ' +' ) { * ( ImU16* ) output = ImAddClampOverflow ( * ( const ImU16* ) arg1, * ( const ImU16* ) arg2, IM_U16_MIN, IM_U16_MAX) ; }
2227
if ( op == ' -' ) { * ( ImU16* ) output = ImSubClampOverflow ( * ( const ImU16* ) arg1, * ( const ImU16* ) arg2, IM_U16_MIN, IM_U16_MAX) ; }
2228
return ;
2229
case ImGuiDataType_S32:
2230
if ( op == ' +' ) { * ( ImS32* ) output = ImAddClampOverflow ( * ( const ImS32* ) arg1, * ( const ImS32* ) arg2, IM_S32_MIN, IM_S32_MAX) ; }
2231
if ( op == ' -' ) { * ( ImS32* ) output = ImSubClampOverflow ( * ( const ImS32* ) arg1, * ( const ImS32* ) arg2, IM_S32_MIN, IM_S32_MAX) ; }
2232
return ;
2233
case ImGuiDataType_U32:
2234
if ( op == ' +' ) { * ( ImU32* ) output = ImAddClampOverflow ( * ( const ImU32* ) arg1, * ( const ImU32* ) arg2, IM_U32_MIN, IM_U32_MAX) ; }
2235
if ( op == ' -' ) { * ( ImU32* ) output = ImSubClampOverflow ( * ( const ImU32* ) arg1, * ( const ImU32* ) arg2, IM_U32_MIN, IM_U32_MAX) ; }
2236
return ;
2237
case ImGuiDataType_S64:
2238
if ( op == ' +' ) { * ( ImS64* ) output = ImAddClampOverflow ( * ( const ImS64* ) arg1, * ( const ImS64* ) arg2, IM_S64_MIN, IM_S64_MAX) ; }
2239
if ( op == ' -' ) { * ( ImS64* ) output = ImSubClampOverflow ( * ( const ImS64* ) arg1, * ( const ImS64* ) arg2, IM_S64_MIN, IM_S64_MAX) ; }
2240
return ;
2241
case ImGuiDataType_U64:
2242
if ( op == ' +' ) { * ( ImU64* ) output = ImAddClampOverflow ( * ( const ImU64* ) arg1, * ( const ImU64* ) arg2, IM_U64_MIN, IM_U64_MAX) ; }
2243
if ( op == ' -' ) { * ( ImU64* ) output = ImSubClampOverflow ( * ( const ImU64* ) arg1, * ( const ImU64* ) arg2, IM_U64_MIN, IM_U64_MAX) ; }
2244
return ;
2245
case ImGuiDataType_Float:
2246
if ( op == ' +' ) { * ( float * ) output = * ( const float * ) arg1 + * ( const float * ) arg2; }
2247
if ( op == ' -' ) { * ( float * ) output = * ( const float * ) arg1 - * ( const float * ) arg2; }
2248
return ;
2249
case ImGuiDataType_Double:
2250
if ( op == ' +' ) { * ( double * ) output = * ( const double * ) arg1 + * ( const double * ) arg2; }
2251
if ( op == ' -' ) { * ( double * ) output = * ( const double * ) arg1 - * ( const double * ) arg2; }
2252
return ;
2253
case ImGuiDataType_COUNT: break ;
2254
}
2255
IM_ASSERT ( 0 ) ;
2256
}
2257
2258
2259
2260
bool ImGui:: DataTypeApplyFromText ( const char * buf , ImGuiDataType data_type , void * p_data , const char * format , void * p_data_when_empty )
2261
{
2262
2263
const ImGuiDataTypeInfo* type_info = DataTypeGetInfo ( data_type ) ;
2264
ImGuiDataTypeStorage data_backup;
2265
memcpy ( & data_backup, p_data, type_info-> Size ) ;
2266
2267
while ( ImCharIsBlankA ( * buf) )
2268
buf+ + ;
2269
if ( ! buf[ 0 ] )
2270
{
2271
if ( p_data_when_empty != NULL )
2272
{
2273
memcpy ( p_data, p_data_when_empty, type_info-> Size ) ;
2274
return memcmp ( & data_backup, p_data, type_info-> Size ) != 0 ;
2275
}
2276
return false ;
2277
}
2278
2279
2280
2281
2282
char format_sanitized[ 32 ] ;
2283
if ( data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
2284
format = type_info-> ScanFmt ;
2285
else
2286
format = ImParseFormatSanitizeForScanning ( format, format_sanitized, IM_ARRAYSIZE ( format_sanitized ) ) ;
2287
2288
2289
int v32 = 0 ;
2290
if ( sscanf ( buf, format, type_info-> Size >= 4 ? p_data : & v32 ) < 1 )
2291
return false ;
2292
if ( type_info-> Size < 4 )
2293
{
2294
if ( data_type == ImGuiDataType_S8)
2295
* ( ImS8* ) p_data = ( ImS8) ImClamp ( v32, ( int ) IM_S8_MIN, ( int ) IM_S8_MAX ) ;
2296
else if ( data_type == ImGuiDataType_U8)
2297
* ( ImU8* ) p_data = ( ImU8) ImClamp ( v32, ( int ) IM_U8_MIN, ( int ) IM_U8_MAX ) ;
2298
else if ( data_type == ImGuiDataType_S16)
2299
* ( ImS16* ) p_data = ( ImS16) ImClamp ( v32, ( int ) IM_S16_MIN, ( int ) IM_S16_MAX ) ;
2300
else if ( data_type == ImGuiDataType_U16)
2301
* ( ImU16* ) p_data = ( ImU16) ImClamp ( v32, ( int ) IM_U16_MIN, ( int ) IM_U16_MAX ) ;
2302
else
2303
IM_ASSERT ( 0 ) ;
2304
}
2305
2306
return memcmp ( & data_backup, p_data, type_info-> Size ) != 0 ;
2307
}
2308
2309
template < typename T>
2310
static int DataTypeCompareT ( const T* lhs , const T* rhs )
2311
{
2312
if ( * lhs < * rhs) return - 1 ;
2313
if ( * lhs > * rhs) return + 1 ;
2314
return 0 ;
2315
}
2316
2317
int ImGui:: DataTypeCompare ( ImGuiDataType data_type , const void * arg_1 , const void * arg_2 )
2318
{
2319
switch ( data_type)
2320
{
2321
case ImGuiDataType_S8: return DataTypeCompareT < ImS8 > ( ( const ImS8* ) arg_1, ( const ImS8* ) arg_2) ;
2322
case ImGuiDataType_U8: return DataTypeCompareT < ImU8 > ( ( const ImU8* ) arg_1, ( const ImU8* ) arg_2) ;
2323
case ImGuiDataType_S16: return DataTypeCompareT < ImS16 > ( ( const ImS16* ) arg_1, ( const ImS16* ) arg_2) ;
2324
case ImGuiDataType_U16: return DataTypeCompareT < ImU16 > ( ( const ImU16* ) arg_1, ( const ImU16* ) arg_2) ;
2325
case ImGuiDataType_S32: return DataTypeCompareT < ImS32 > ( ( const ImS32* ) arg_1, ( const ImS32* ) arg_2) ;
2326
case ImGuiDataType_U32: return DataTypeCompareT < ImU32 > ( ( const ImU32* ) arg_1, ( const ImU32* ) arg_2) ;
2327
case ImGuiDataType_S64: return DataTypeCompareT < ImS64 > ( ( const ImS64* ) arg_1, ( const ImS64* ) arg_2) ;
2328
case ImGuiDataType_U64: return DataTypeCompareT < ImU64 > ( ( const ImU64* ) arg_1, ( const ImU64* ) arg_2) ;
2329
case ImGuiDataType_Float: return DataTypeCompareT < float > ( ( const float * ) arg_1, ( const float * ) arg_2) ;
2330
case ImGuiDataType_Double: return DataTypeCompareT < double > ( ( const double * ) arg_1, ( const double * ) arg_2) ;
2331
case ImGuiDataType_COUNT: break ;
2332
}
2333
IM_ASSERT ( 0 ) ;
2334
return 0 ;
2335
}
2336
2337
template < typename T>
2338
static bool DataTypeClampT ( T* v , const T* v_min , const T* v_max )
2339
{
2340
2341
if ( v_min && * v < * v_min) { * v = * v_min; return true ; }
2342
if ( v_max && * v > * v_max) { * v = * v_max; return true ; }
2343
return false ;
2344
}
2345
2346
bool ImGui:: DataTypeClamp ( ImGuiDataType data_type , void * p_data , const void * p_min , const void * p_max )
2347
{
2348
switch ( data_type)
2349
{
2350
case ImGuiDataType_S8: return DataTypeClampT < ImS8 > ( ( ImS8* ) p_data, ( const ImS8* ) p_min, ( const ImS8* ) p_max) ;
2351
case ImGuiDataType_U8: return DataTypeClampT < ImU8 > ( ( ImU8* ) p_data, ( const ImU8* ) p_min, ( const ImU8* ) p_max) ;
2352
case ImGuiDataType_S16: return DataTypeClampT < ImS16 > ( ( ImS16* ) p_data, ( const ImS16* ) p_min, ( const ImS16* ) p_max) ;
2353
case ImGuiDataType_U16: return DataTypeClampT < ImU16 > ( ( ImU16* ) p_data, ( const ImU16* ) p_min, ( const ImU16* ) p_max) ;
2354
case ImGuiDataType_S32: return DataTypeClampT < ImS32 > ( ( ImS32* ) p_data, ( const ImS32* ) p_min, ( const ImS32* ) p_max) ;
2355
case ImGuiDataType_U32: return DataTypeClampT < ImU32 > ( ( ImU32* ) p_data, ( const ImU32* ) p_min, ( const ImU32* ) p_max) ;
2356
case ImGuiDataType_S64: return DataTypeClampT < ImS64 > ( ( ImS64* ) p_data, ( const ImS64* ) p_min, ( const ImS64* ) p_max) ;
2357
case ImGuiDataType_U64: return DataTypeClampT < ImU64 > ( ( ImU64* ) p_data, ( const ImU64* ) p_min, ( const ImU64* ) p_max) ;
2358
case ImGuiDataType_Float: return DataTypeClampT < float > ( ( float * ) p_data, ( const float * ) p_min, ( const float * ) p_max) ;
2359
case ImGuiDataType_Double: return DataTypeClampT < double > ( ( double * ) p_data, ( const double * ) p_min, ( const double * ) p_max) ;
2360
case ImGuiDataType_COUNT: break ;
2361
}
2362
IM_ASSERT ( 0 ) ;
2363
return false ;
2364
}
2365
2366
bool ImGui:: DataTypeIsZero ( ImGuiDataType data_type , const void * p_data )
2367
{
2368
ImGuiContext& g = * GImGui;
2369
return DataTypeCompare ( data_type, p_data, & g. DataTypeZeroValue ) == 0 ;
2370
}
2371
2372
static float GetMinimumStepAtDecimalPrecision ( int decimal_precision )
2373
{
2374
static const float min_steps[ 10 ] = { 1.0f , 0.1f , 0.01f , 0.001f , 0.0001f , 0.00001f , 0.000001f , 0.0000001f , 0.00000001f , 0.000000001f } ;
2375
if ( decimal_precision < 0 )
2376
return FLT_MIN;
2377
return ( decimal_precision < IM_ARRAYSIZE ( min_steps ) ) ? min_steps[ decimal_precision] : ImPow ( 10.0f , ( float ) - decimal_precision) ;
2378
}
2379
2380
template < typename TYPE>
2381
TYPE ImGui:: RoundScalarWithFormatT ( const char * format , ImGuiDataType data_type , TYPE v )
2382
{
2383
IM_UNUSED ( data_type ) ;
2384
IM_ASSERT ( data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double ) ;
2385
const char * fmt_start = ImParseFormatFindStart ( format ) ;
2386
if ( fmt_start[ 0 ] != ' %' || fmt_start[ 1 ] == ' %' )
2387
return v;
2388
2389
2390
char fmt_sanitized[ 32 ] ;
2391
ImParseFormatSanitizeForPrinting ( fmt_start, fmt_sanitized, IM_ARRAYSIZE ( fmt_sanitized ) ) ;
2392
fmt_start = fmt_sanitized;
2393
2394
2395
char v_str[ 64 ] ;
2396
ImFormatString ( v_str, IM_ARRAYSIZE ( v_str ) , fmt_start, v ) ;
2397
const char * p = v_str;
2398
while ( * p == ' ' )
2399
p+ + ;
2400
v = ( TYPE) ImAtof ( p ) ;
2401
2402
return v;
2403
}
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
template < typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
2426
bool ImGui:: DragBehaviorT ( ImGuiDataType data_type , TYPE* v , float v_speed , const TYPE v_min , const TYPE v_max , const char * format , ImGuiSliderFlags flags )
2427
{
2428
ImGuiContext& g = * GImGui;
2429
const ImGuiAxis axis = ( flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
2430
const bool is_bounded = ( v_min < v_max) || ( ( v_min == v_max) && ( v_min != 0.0f || ( flags & ImGuiSliderFlags_ClampZeroRange) ) ) ;
2431
const bool is_wrapped = is_bounded && ( flags & ImGuiSliderFlags_WrapAround) ;
2432
const bool is_logarithmic = ( flags & ImGuiSliderFlags_Logarithmic) != 0 ;
2433
const bool is_floating_point = ( data_type == ImGuiDataType_Float) || ( data_type == ImGuiDataType_Double) ;
2434
2435
2436
if ( v_speed == 0.0f && is_bounded && ( v_max - v_min < FLT_MAX) )
2437
v_speed = ( float ) ( ( v_max - v_min) * g. DragSpeedDefaultRatio ) ;
2438
2439
2440
float adjust_delta = 0.0f ;
2441
if ( g. ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid ( ) && IsMouseDragPastThreshold ( 0 , g. IO . MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR) )
2442
{
2443
adjust_delta = g. IO . MouseDelta [ axis] ;
2444
if ( g. IO . KeyAlt )
2445
adjust_delta *= 1.0f / 100.0f ;
2446
if ( g. IO . KeyShift )
2447
adjust_delta *= 10.0f ;
2448
}
2449
else if ( g. ActiveIdSource == ImGuiInputSource_Keyboard || g. ActiveIdSource == ImGuiInputSource_Gamepad)
2450
{
2451
const int decimal_precision = is_floating_point ? ImParseFormatPrecision ( format, 3 ) : 0 ;
2452
const bool tweak_slow = IsKeyDown ( ( g. NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow) ;
2453
const bool tweak_fast = IsKeyDown ( ( g. NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast) ;
2454
const float tweak_factor = tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f ;
2455
adjust_delta = GetNavTweakPressedAmount ( axis ) * tweak_factor;
2456
v_speed = ImMax ( v_speed, GetMinimumStepAtDecimalPrecision ( decimal_precision ) ) ;
2457
}
2458
adjust_delta *= v_speed;
2459
2460
2461
if ( axis == ImGuiAxis_Y)
2462
adjust_delta = - adjust_delta;
2463
2464
2465
if ( is_logarithmic && ( v_max - v_min < FLT_MAX) && ( ( v_max - v_min) > 0.000001f ) )
2466
adjust_delta /= ( float ) ( v_max - v_min) ;
2467
2468
2469
2470
const bool is_just_activated = g. ActiveIdIsJustActivated ;
2471
const bool is_already_past_limits_and_pushing_outward = is_bounded && ! is_wrapped && ( ( * v >= v_max && adjust_delta > 0.0f ) || ( * v <= v_min && adjust_delta < 0.0f ) ) ;
2472
if ( is_just_activated || is_already_past_limits_and_pushing_outward)
2473
{
2474
g. DragCurrentAccum = 0.0f ;
2475
g. DragCurrentAccumDirty = false ;
2476
}
2477
else if ( adjust_delta != 0.0f )
2478
{
2479
g. DragCurrentAccum += adjust_delta;
2480
g. DragCurrentAccumDirty = true ;
2481
}
2482
2483
if ( ! g. DragCurrentAccumDirty )
2484
return false ;
2485
2486
TYPE v_cur = * v;
2487
FLOATTYPE v_old_ref_for_accum_remainder = ( FLOATTYPE) 0.0f ;
2488
2489
float logarithmic_zero_epsilon = 0.0f ;
2490
const float zero_deadzone_halfsize = 0.0f ;
2491
if ( is_logarithmic)
2492
{
2493
2494
const int decimal_precision = is_floating_point ? ImParseFormatPrecision ( format, 3 ) : 1 ;
2495
logarithmic_zero_epsilon = ImPow ( 0.1f , ( float ) decimal_precision) ;
2496
2497
2498
float v_old_parametric = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
2499
float v_new_parametric = v_old_parametric + g. DragCurrentAccum ;
2500
v_cur = ScaleValueFromRatioT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
2501
v_old_ref_for_accum_remainder = v_old_parametric;
2502
}
2503
else
2504
{
2505
v_cur += ( SIGNEDTYPE) g. DragCurrentAccum ;
2506
}
2507
2508
2509
if ( is_floating_point && ! ( flags & ImGuiSliderFlags_NoRoundToFormat) )
2510
v_cur = RoundScalarWithFormatT < TYPE> ( format, data_type, v_cur ) ;
2511
2512
2513
g. DragCurrentAccumDirty = false ;
2514
if ( is_logarithmic)
2515
{
2516
2517
float v_new_parametric = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
2518
g. DragCurrentAccum -= ( float ) ( v_new_parametric - v_old_ref_for_accum_remainder) ;
2519
}
2520
else
2521
{
2522
g. DragCurrentAccum -= ( float ) ( ( SIGNEDTYPE) v_cur - ( SIGNEDTYPE) * v) ;
2523
}
2524
2525
2526
if ( v_cur == ( TYPE) - 0 )
2527
v_cur = ( TYPE) 0 ;
2528
2529
if ( * v != v_cur && is_bounded)
2530
{
2531
if ( is_wrapped)
2532
{
2533
2534
if ( v_cur < v_min)
2535
v_cur += v_max - v_min + ( is_floating_point ? 0 : 1 ) ;
2536
if ( v_cur > v_max)
2537
v_cur -= v_max - v_min + ( is_floating_point ? 0 : 1 ) ;
2538
}
2539
else
2540
{
2541
2542
if ( v_cur < v_min || ( v_cur > * v && adjust_delta < 0.0f && ! is_floating_point) )
2543
v_cur = v_min;
2544
if ( v_cur > v_max || ( v_cur < * v && adjust_delta > 0.0f && ! is_floating_point) )
2545
v_cur = v_max;
2546
}
2547
}
2548
2549
2550
if ( * v == v_cur)
2551
return false ;
2552
* v = v_cur;
2553
return true ;
2554
}
2555
2556
bool ImGui:: DragBehavior ( ImGuiID id , ImGuiDataType data_type , void * p_v , float v_speed , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags )
2557
{
2558
2559
IM_ASSERT ( ( flags == 1 || ( flags & ImGuiSliderFlags_InvalidMask_) == 0 ) && " Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead." ) ;
2560
2561
ImGuiContext& g = * GImGui;
2562
if ( g. ActiveId == id)
2563
{
2564
2565
if ( g. ActiveIdSource == ImGuiInputSource_Mouse && ! g. IO . MouseDown [ 0 ] )
2566
ClearActiveID ( ) ;
2567
else if ( ( g. ActiveIdSource == ImGuiInputSource_Keyboard || g. ActiveIdSource == ImGuiInputSource_Gamepad) && g. NavActivatePressedId == id && ! g. ActiveIdIsJustActivated )
2568
ClearActiveID ( ) ;
2569
}
2570
if ( g. ActiveId != id)
2571
return false ;
2572
if ( ( g. LastItemData . ItemFlags & ImGuiItemFlags_ReadOnly) || ( flags & ImGuiSliderFlags_ReadOnly) )
2573
return false ;
2574
2575
switch ( data_type)
2576
{
2577
case ImGuiDataType_S8: { ImS32 v32 = ( ImS32) * ( ImS8* ) p_v; bool r = DragBehaviorT < ImS32, ImS32, float > ( ImGuiDataType_S32, & v32, v_speed, p_min ? * ( const ImS8* ) p_min : IM_S8_MIN, p_max ? * ( const ImS8* ) p_max : IM_S8_MAX, format, flags ) ; if ( r) * ( ImS8* ) p_v = ( ImS8) v32; return r; }
2578
case ImGuiDataType_U8: { ImU32 v32 = ( ImU32) * ( ImU8* ) p_v; bool r = DragBehaviorT < ImU32, ImS32, float > ( ImGuiDataType_U32, & v32, v_speed, p_min ? * ( const ImU8* ) p_min : IM_U8_MIN, p_max ? * ( const ImU8* ) p_max : IM_U8_MAX, format, flags ) ; if ( r) * ( ImU8* ) p_v = ( ImU8) v32; return r; }
2579
case ImGuiDataType_S16: { ImS32 v32 = ( ImS32) * ( ImS16* ) p_v; bool r = DragBehaviorT < ImS32, ImS32, float > ( ImGuiDataType_S32, & v32, v_speed, p_min ? * ( const ImS16* ) p_min : IM_S16_MIN, p_max ? * ( const ImS16* ) p_max : IM_S16_MAX, format, flags ) ; if ( r) * ( ImS16* ) p_v = ( ImS16) v32; return r; }
2580
case ImGuiDataType_U16: { ImU32 v32 = ( ImU32) * ( ImU16* ) p_v; bool r = DragBehaviorT < ImU32, ImS32, float > ( ImGuiDataType_U32, & v32, v_speed, p_min ? * ( const ImU16* ) p_min : IM_U16_MIN, p_max ? * ( const ImU16* ) p_max : IM_U16_MAX, format, flags ) ; if ( r) * ( ImU16* ) p_v = ( ImU16) v32; return r; }
2581
case ImGuiDataType_S32: return DragBehaviorT < ImS32, ImS32, float > ( data_type, ( ImS32* ) p_v, v_speed, p_min ? * ( const ImS32* ) p_min : IM_S32_MIN, p_max ? * ( const ImS32* ) p_max : IM_S32_MAX, format, flags ) ;
2582
case ImGuiDataType_U32: return DragBehaviorT < ImU32, ImS32, float > ( data_type, ( ImU32* ) p_v, v_speed, p_min ? * ( const ImU32* ) p_min : IM_U32_MIN, p_max ? * ( const ImU32* ) p_max : IM_U32_MAX, format, flags ) ;
2583
case ImGuiDataType_S64: return DragBehaviorT < ImS64, ImS64, double > ( data_type, ( ImS64* ) p_v, v_speed, p_min ? * ( const ImS64* ) p_min : IM_S64_MIN, p_max ? * ( const ImS64* ) p_max : IM_S64_MAX, format, flags ) ;
2584
case ImGuiDataType_U64: return DragBehaviorT < ImU64, ImS64, double > ( data_type, ( ImU64* ) p_v, v_speed, p_min ? * ( const ImU64* ) p_min : IM_U64_MIN, p_max ? * ( const ImU64* ) p_max : IM_U64_MAX, format, flags ) ;
2585
case ImGuiDataType_Float: return DragBehaviorT < float , float , float > ( data_type, ( float * ) p_v, v_speed, p_min ? * ( const float * ) p_min : - FLT_MAX, p_max ? * ( const float * ) p_max : FLT_MAX, format, flags ) ;
2586
case ImGuiDataType_Double: return DragBehaviorT < double , double , double > ( data_type, ( double * ) p_v, v_speed, p_min ? * ( const double * ) p_min : - DBL_MAX, p_max ? * ( const double * ) p_max : DBL_MAX, format, flags ) ;
2587
case ImGuiDataType_COUNT: break ;
2588
}
2589
IM_ASSERT ( 0 ) ;
2590
return false ;
2591
}
2592
2593
2594
2595
bool ImGui:: DragScalar ( const char * label , ImGuiDataType data_type , void * p_data , float v_speed , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags )
2596
{
2597
ImGuiWindow* window = GetCurrentWindow ( ) ;
2598
if ( window-> SkipItems )
2599
return false ;
2600
2601
ImGuiContext& g = * GImGui;
2602
const ImGuiStyle& style = g. Style ;
2603
const ImGuiID id = window-> GetID ( label ) ;
2604
const float w = CalcItemWidth ( ) ;
2605
2606
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
2607
const ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + ImVec2 ( w, label_size. y + style. FramePadding . y * 2.0f ) ) ;
2608
const ImRect total_bb ( frame_bb. Min , frame_bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0.0f ) ) ;
2609
2610
const bool temp_input_allowed = ( flags & ImGuiSliderFlags_NoInput) == 0 ;
2611
ItemSize ( total_bb, style. FramePadding . y ) ;
2612
if ( ! ItemAdd ( total_bb, id, & frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0 ) )
2613
return false ;
2614
2615
2616
if ( format == NULL )
2617
format = DataTypeGetInfo ( data_type ) -> PrintFmt ;
2618
2619
const bool hovered = ItemHoverable ( frame_bb, id, g. LastItemData . ItemFlags ) ;
2620
bool temp_input_is_active = temp_input_allowed && TempInputIsActive ( id ) ;
2621
if ( ! temp_input_is_active)
2622
{
2623
2624
const bool clicked = hovered && IsMouseClicked ( 0 , ImGuiInputFlags_None, id) ;
2625
const bool double_clicked = ( hovered && g. IO . MouseClickedCount [ 0 ] == 2 && TestKeyOwner ( ImGuiKey_MouseLeft, id ) ) ;
2626
const bool make_active = ( clicked || double_clicked || g. NavActivateId == id) ;
2627
if ( make_active && ( clicked || double_clicked) )
2628
SetKeyOwner ( ImGuiKey_MouseLeft, id ) ;
2629
if ( make_active && temp_input_allowed)
2630
if ( ( clicked && g. IO . KeyCtrl ) || double_clicked || ( g. NavActivateId == id && ( g. NavActivateFlags & ImGuiActivateFlags_PreferInput) ) )
2631
temp_input_is_active = true ;
2632
2633
2634
if ( g. IO . ConfigDragClickToInputText && temp_input_allowed && ! temp_input_is_active)
2635
if ( g. ActiveId == id && hovered && g. IO . MouseReleased [ 0 ] && ! IsMouseDragPastThreshold ( 0 , g. IO . MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR) )
2636
{
2637
g. NavActivateId = id;
2638
g. NavActivateFlags = ImGuiActivateFlags_PreferInput;
2639
temp_input_is_active = true ;
2640
}
2641
2642
if ( make_active && ! temp_input_is_active)
2643
{
2644
SetActiveID ( id, window ) ;
2645
SetFocusID ( id, window ) ;
2646
FocusWindow ( window ) ;
2647
g. ActiveIdUsingNavDirMask = ( 1 << ImGuiDir_Left) | ( 1 << ImGuiDir_Right) ;
2648
}
2649
}
2650
2651
if ( temp_input_is_active)
2652
{
2653
2654
bool clamp_enabled = false ;
2655
if ( ( flags & ImGuiSliderFlags_ClampOnInput) && ( p_min != NULL || p_max != NULL ) )
2656
{
2657
const int clamp_range_dir = ( p_min != NULL && p_max != NULL ) ? DataTypeCompare ( data_type, p_min, p_max ) : 0 ;
2658
if ( p_min == NULL || p_max == NULL || clamp_range_dir < 0 )
2659
clamp_enabled = true ;
2660
else if ( clamp_range_dir == 0 )
2661
clamp_enabled = DataTypeIsZero ( data_type, p_min ) ? ( ( flags & ImGuiSliderFlags_ClampZeroRange) != 0 ) : true ;
2662
}
2663
return TempInputScalar ( frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL , clamp_enabled ? p_max : NULL ) ;
2664
}
2665
2666
2667
const ImU32 frame_col = GetColorU32 ( g. ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
2668
RenderNavCursor ( frame_bb, id ) ;
2669
RenderFrame ( frame_bb. Min , frame_bb. Max , frame_col, true , style. FrameRounding ) ;
2670
2671
2672
const bool value_changed = DragBehavior ( id, data_type, p_data, v_speed, p_min, p_max, format, flags ) ;
2673
if ( value_changed)
2674
MarkItemEdited ( id ) ;
2675
2676
2677
char value_buf[ 64 ] ;
2678
const char * value_buf_end = value_buf + DataTypeFormatString ( value_buf, IM_ARRAYSIZE ( value_buf ) , data_type, p_data, format ) ;
2679
if ( g. LogEnabled )
2680
LogSetNextTextDecoration ( " {" , " }" ) ;
2681
RenderTextClipped ( frame_bb. Min , frame_bb. Max , value_buf, value_buf_end, NULL , ImVec2 ( 0.5f , 0.5f ) ) ;
2682
2683
if ( label_size. x > 0.0f )
2684
RenderText ( ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , frame_bb. Min . y + style. FramePadding . y ) , label) ;
2685
2686
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ( temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0 ) ) ;
2687
return value_changed;
2688
}
2689
2690
bool ImGui:: DragScalarN ( const char * label , ImGuiDataType data_type , void * p_data , int components , float v_speed , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags )
2691
{
2692
ImGuiWindow* window = GetCurrentWindow ( ) ;
2693
if ( window-> SkipItems )
2694
return false ;
2695
2696
ImGuiContext& g = * GImGui;
2697
bool value_changed = false ;
2698
BeginGroup ( ) ;
2699
PushID ( label ) ;
2700
PushMultiItemsWidths ( components, CalcItemWidth ( ) ) ;
2701
size_t type_size = GDataTypeInfo[ data_type] . Size ;
2702
for ( int i = 0 ; i < components; i+ + )
2703
{
2704
PushID ( i ) ;
2705
if ( i > 0 )
2706
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2707
value_changed |= DragScalar ( " " , data_type, p_data, v_speed, p_min, p_max, format, flags) ;
2708
PopID ( ) ;
2709
PopItemWidth ( ) ;
2710
p_data = ( void * ) ( ( char * ) p_data + type_size) ;
2711
}
2712
PopID ( ) ;
2713
2714
const char * label_end = FindRenderedTextEnd ( label ) ;
2715
if ( label != label_end)
2716
{
2717
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2718
TextEx ( label, label_end ) ;
2719
}
2720
2721
EndGroup ( ) ;
2722
return value_changed;
2723
}
2724
2725
bool ImGui:: DragFloat ( const char * label , float * v , float v_speed , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
2726
{
2727
return DragScalar ( label, ImGuiDataType_Float, v, v_speed, & v_min, & v_max, format, flags ) ;
2728
}
2729
2730
bool ImGui:: DragFloat2 ( const char * label , float v [ 2 ] , float v_speed , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
2731
{
2732
return DragScalarN ( label, ImGuiDataType_Float, v, 2 , v_speed, & v_min, & v_max, format, flags ) ;
2733
}
2734
2735
bool ImGui:: DragFloat3 ( const char * label , float v [ 3 ] , float v_speed , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
2736
{
2737
return DragScalarN ( label, ImGuiDataType_Float, v, 3 , v_speed, & v_min, & v_max, format, flags ) ;
2738
}
2739
2740
bool ImGui:: DragFloat4 ( const char * label , float v [ 4 ] , float v_speed , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
2741
{
2742
return DragScalarN ( label, ImGuiDataType_Float, v, 4 , v_speed, & v_min, & v_max, format, flags ) ;
2743
}
2744
2745
2746
bool ImGui:: DragFloatRange2 ( const char * label , float * v_current_min , float * v_current_max , float v_speed , float v_min , float v_max , const char * format , const char * format_max , ImGuiSliderFlags flags )
2747
{
2748
ImGuiWindow* window = GetCurrentWindow ( ) ;
2749
if ( window-> SkipItems )
2750
return false ;
2751
2752
ImGuiContext& g = * GImGui;
2753
PushID ( label ) ;
2754
BeginGroup ( ) ;
2755
PushMultiItemsWidths ( 2 , CalcItemWidth ( ) ) ;
2756
2757
float min_min = ( v_min >= v_max) ? - FLT_MAX : v_min;
2758
float min_max = ( v_min >= v_max) ? * v_current_max : ImMin ( v_max, * v_current_max ) ;
2759
ImGuiSliderFlags min_flags = flags | ( ( min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0 ) ;
2760
bool value_changed = DragScalar ( " ##min" , ImGuiDataType_Float, v_current_min, v_speed, & min_min, & min_max, format, min_flags) ;
2761
PopItemWidth ( ) ;
2762
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2763
2764
float max_min = ( v_min >= v_max) ? * v_current_min : ImMax ( v_min, * v_current_min ) ;
2765
float max_max = ( v_min >= v_max) ? FLT_MAX : v_max;
2766
ImGuiSliderFlags max_flags = flags | ( ( max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0 ) ;
2767
value_changed |= DragScalar ( " ##max" , ImGuiDataType_Float, v_current_max, v_speed, & max_min, & max_max, format_max ? format_max : format, max_flags) ;
2768
PopItemWidth ( ) ;
2769
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2770
2771
TextEx ( label, FindRenderedTextEnd ( label ) ) ;
2772
EndGroup ( ) ;
2773
PopID ( ) ;
2774
2775
return value_changed;
2776
}
2777
2778
2779
bool ImGui:: DragInt ( const char * label , int * v , float v_speed , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
2780
{
2781
return DragScalar ( label, ImGuiDataType_S32, v, v_speed, & v_min, & v_max, format, flags ) ;
2782
}
2783
2784
bool ImGui:: DragInt2 ( const char * label , int v [ 2 ] , float v_speed , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
2785
{
2786
return DragScalarN ( label, ImGuiDataType_S32, v, 2 , v_speed, & v_min, & v_max, format, flags ) ;
2787
}
2788
2789
bool ImGui:: DragInt3 ( const char * label , int v [ 3 ] , float v_speed , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
2790
{
2791
return DragScalarN ( label, ImGuiDataType_S32, v, 3 , v_speed, & v_min, & v_max, format, flags ) ;
2792
}
2793
2794
bool ImGui:: DragInt4 ( const char * label , int v [ 4 ] , float v_speed , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
2795
{
2796
return DragScalarN ( label, ImGuiDataType_S32, v, 4 , v_speed, & v_min, & v_max, format, flags ) ;
2797
}
2798
2799
2800
bool ImGui:: DragIntRange2 ( const char * label , int * v_current_min , int * v_current_max , float v_speed , int v_min , int v_max , const char * format , const char * format_max , ImGuiSliderFlags flags )
2801
{
2802
ImGuiWindow* window = GetCurrentWindow ( ) ;
2803
if ( window-> SkipItems )
2804
return false ;
2805
2806
ImGuiContext& g = * GImGui;
2807
PushID ( label ) ;
2808
BeginGroup ( ) ;
2809
PushMultiItemsWidths ( 2 , CalcItemWidth ( ) ) ;
2810
2811
int min_min = ( v_min >= v_max) ? INT_MIN : v_min;
2812
int min_max = ( v_min >= v_max) ? * v_current_max : ImMin ( v_max, * v_current_max ) ;
2813
ImGuiSliderFlags min_flags = flags | ( ( min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0 ) ;
2814
bool value_changed = DragInt ( " ##min" , v_current_min, v_speed, min_min, min_max, format, min_flags) ;
2815
PopItemWidth ( ) ;
2816
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2817
2818
int max_min = ( v_min >= v_max) ? * v_current_min : ImMax ( v_min, * v_current_min ) ;
2819
int max_max = ( v_min >= v_max) ? INT_MAX : v_max;
2820
ImGuiSliderFlags max_flags = flags | ( ( max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0 ) ;
2821
value_changed |= DragInt ( " ##max" , v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags) ;
2822
PopItemWidth ( ) ;
2823
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
2824
2825
TextEx ( label, FindRenderedTextEnd ( label ) ) ;
2826
EndGroup ( ) ;
2827
PopID ( ) ;
2828
2829
return value_changed;
2830
}
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
template < typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
2857
float ImGui:: ScaleRatioFromValueT ( ImGuiDataType data_type , TYPE v , TYPE v_min , TYPE v_max , bool is_logarithmic , float logarithmic_zero_epsilon , float zero_deadzone_halfsize )
2858
{
2859
if ( v_min == v_max)
2860
return 0.0f ;
2861
IM_UNUSED ( data_type ) ;
2862
2863
const TYPE v_clamped = ( v_min < v_max) ? ImClamp ( v, v_min, v_max ) : ImClamp ( v, v_max, v_min ) ;
2864
if ( is_logarithmic)
2865
{
2866
bool flipped = v_max < v_min;
2867
2868
if ( flipped)
2869
ImSwap ( v_min, v_max ) ;
2870
2871
2872
FLOATTYPE v_min_fudged = ( ImAbs ( ( FLOATTYPE) v_min) < logarithmic_zero_epsilon) ? ( ( v_min < 0.0f ) ? - logarithmic_zero_epsilon : logarithmic_zero_epsilon) : ( FLOATTYPE) v_min;
2873
FLOATTYPE v_max_fudged = ( ImAbs ( ( FLOATTYPE) v_max) < logarithmic_zero_epsilon) ? ( ( v_max < 0.0f ) ? - logarithmic_zero_epsilon : logarithmic_zero_epsilon) : ( FLOATTYPE) v_max;
2874
2875
2876
if ( ( v_min == 0.0f ) && ( v_max < 0.0f ) )
2877
v_min_fudged = - logarithmic_zero_epsilon;
2878
else if ( ( v_max == 0.0f ) && ( v_min < 0.0f ) )
2879
v_max_fudged = - logarithmic_zero_epsilon;
2880
2881
float result;
2882
if ( v_clamped <= v_min_fudged)
2883
result = 0.0f ;
2884
else if ( v_clamped >= v_max_fudged)
2885
result = 1.0f ;
2886
else if ( ( v_min * v_max) < 0.0f )
2887
{
2888
float zero_point_center = ( - ( float ) v_min) / ( ( float ) v_max - ( float ) v_min) ;
2889
float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
2890
float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
2891
if ( v == 0.0f )
2892
result = zero_point_center;
2893
else if ( v < 0.0f )
2894
result = ( 1.0f - ( float ) ( ImLog ( - ( FLOATTYPE) v_clamped / logarithmic_zero_epsilon) / ImLog ( - v_min_fudged / logarithmic_zero_epsilon) ) ) * zero_point_snap_L;
2895
else
2896
result = zero_point_snap_R + ( ( float ) ( ImLog ( ( FLOATTYPE) v_clamped / logarithmic_zero_epsilon) / ImLog ( v_max_fudged / logarithmic_zero_epsilon ) ) * ( 1.0f - zero_point_snap_R) ) ;
2897
}
2898
else if ( ( v_min < 0.0f ) || ( v_max < 0.0f ) )
2899
result = 1.0f - ( float ) ( ImLog ( - ( FLOATTYPE) v_clamped / - v_max_fudged) / ImLog ( - v_min_fudged / - v_max_fudged) ) ;
2900
else
2901
result = ( float ) ( ImLog ( ( FLOATTYPE) v_clamped / v_min_fudged) / ImLog ( v_max_fudged / v_min_fudged ) ) ;
2902
2903
return flipped ? ( 1.0f - result) : result;
2904
}
2905
else
2906
{
2907
2908
return ( float ) ( ( FLOATTYPE) ( SIGNEDTYPE) ( v_clamped - v_min) / ( FLOATTYPE) ( SIGNEDTYPE) ( v_max - v_min) ) ;
2909
}
2910
}
2911
2912
2913
template < typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
2914
TYPE ImGui:: ScaleValueFromRatioT ( ImGuiDataType data_type , float t , TYPE v_min , TYPE v_max , bool is_logarithmic , float logarithmic_zero_epsilon , float zero_deadzone_halfsize )
2915
{
2916
2917
2918
if ( t <= 0.0f || v_min == v_max)
2919
return v_min;
2920
if ( t >= 1.0f )
2921
return v_max;
2922
2923
TYPE result = ( TYPE) 0 ;
2924
if ( is_logarithmic)
2925
{
2926
2927
FLOATTYPE v_min_fudged = ( ImAbs ( ( FLOATTYPE) v_min) < logarithmic_zero_epsilon) ? ( ( v_min < 0.0f ) ? - logarithmic_zero_epsilon : logarithmic_zero_epsilon) : ( FLOATTYPE) v_min;
2928
FLOATTYPE v_max_fudged = ( ImAbs ( ( FLOATTYPE) v_max) < logarithmic_zero_epsilon) ? ( ( v_max < 0.0f ) ? - logarithmic_zero_epsilon : logarithmic_zero_epsilon) : ( FLOATTYPE) v_max;
2929
2930
const bool flipped = v_max < v_min;
2931
if ( flipped)
2932
ImSwap ( v_min_fudged, v_max_fudged ) ;
2933
2934
2935
if ( ( v_max == 0.0f ) && ( v_min < 0.0f ) )
2936
v_max_fudged = - logarithmic_zero_epsilon;
2937
2938
float t_with_flip = flipped ? ( 1.0f - t) : t;
2939
2940
if ( ( v_min * v_max) < 0.0f )
2941
{
2942
float zero_point_center = ( - ( float ) ImMin ( v_min, v_max ) ) / ImAbs ( ( float ) v_max - ( float ) v_min) ;
2943
float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
2944
float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
2945
if ( t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R)
2946
result = ( TYPE) 0.0f ;
2947
else if ( t_with_flip < zero_point_center)
2948
result = ( TYPE) - ( logarithmic_zero_epsilon * ImPow ( - v_min_fudged / logarithmic_zero_epsilon, ( FLOATTYPE) ( 1.0f - ( t_with_flip / zero_point_snap_L) ) ) ) ;
2949
else
2950
result = ( TYPE) ( logarithmic_zero_epsilon * ImPow ( v_max_fudged / logarithmic_zero_epsilon, ( FLOATTYPE) ( ( t_with_flip - zero_point_snap_R) / ( 1.0f - zero_point_snap_R) ) ) ) ;
2951
}
2952
else if ( ( v_min < 0.0f ) || ( v_max < 0.0f ) )
2953
result = ( TYPE) - ( - v_max_fudged * ImPow ( - v_min_fudged / - v_max_fudged, ( FLOATTYPE) ( 1.0f - t_with_flip) ) ) ;
2954
else
2955
result = ( TYPE) ( v_min_fudged * ImPow ( v_max_fudged / v_min_fudged, ( FLOATTYPE) t_with_flip ) ) ;
2956
}
2957
else
2958
{
2959
2960
const bool is_floating_point = ( data_type == ImGuiDataType_Float) || ( data_type == ImGuiDataType_Double) ;
2961
if ( is_floating_point)
2962
{
2963
result = ImLerp ( v_min, v_max, t ) ;
2964
}
2965
else if ( t < 1.0 )
2966
{
2967
2968
2969
2970
2971
FLOATTYPE v_new_off_f = ( SIGNEDTYPE) ( v_max - v_min) * t;
2972
result = ( TYPE) ( ( SIGNEDTYPE) v_min + ( SIGNEDTYPE) ( v_new_off_f + ( FLOATTYPE) ( v_min > v_max ? - 0.5 : 0.5 ) ) ) ;
2973
}
2974
}
2975
2976
return result;
2977
}
2978
2979
2980
template < typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
2981
bool ImGui:: SliderBehaviorT ( const ImRect& bb , ImGuiID id , ImGuiDataType data_type , TYPE* v , const TYPE v_min , const TYPE v_max , const char * format , ImGuiSliderFlags flags , ImRect* out_grab_bb )
2982
{
2983
ImGuiContext& g = * GImGui;
2984
const ImGuiStyle& style = g. Style ;
2985
2986
const ImGuiAxis axis = ( flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
2987
const bool is_logarithmic = ( flags & ImGuiSliderFlags_Logarithmic) != 0 ;
2988
const bool is_floating_point = ( data_type == ImGuiDataType_Float) || ( data_type == ImGuiDataType_Double) ;
2989
const float v_range_f = ( float ) ( v_min < v_max ? v_max - v_min : v_min - v_max) ;
2990
2991
2992
const float grab_padding = 2.0f ;
2993
const float slider_sz = ( bb. Max [ axis] - bb. Min [ axis] ) - grab_padding * 2.0f ;
2994
float grab_sz = style. GrabMinSize ;
2995
if ( ! is_floating_point && v_range_f >= 0.0f )
2996
grab_sz = ImMax ( slider_sz / ( v_range_f + 1 ) , style. GrabMinSize ) ;
2997
grab_sz = ImMin ( grab_sz, slider_sz ) ;
2998
const float slider_usable_sz = slider_sz - grab_sz;
2999
const float slider_usable_pos_min = bb. Min [ axis] + grab_padding + grab_sz * 0.5f ;
3000
const float slider_usable_pos_max = bb. Max [ axis] - grab_padding - grab_sz * 0.5f ;
3001
3002
float logarithmic_zero_epsilon = 0.0f ;
3003
float zero_deadzone_halfsize = 0.0f ;
3004
if ( is_logarithmic)
3005
{
3006
3007
const int decimal_precision = is_floating_point ? ImParseFormatPrecision ( format, 3 ) : 1 ;
3008
logarithmic_zero_epsilon = ImPow ( 0.1f , ( float ) decimal_precision) ;
3009
zero_deadzone_halfsize = ( style. LogSliderDeadzone * 0.5f ) / ImMax ( slider_usable_sz, 1.0f ) ;
3010
}
3011
3012
3013
bool value_changed = false ;
3014
if ( g. ActiveId == id)
3015
{
3016
bool set_new_value = false ;
3017
float clicked_t = 0.0f ;
3018
if ( g. ActiveIdSource == ImGuiInputSource_Mouse)
3019
{
3020
if ( ! g. IO . MouseDown [ 0 ] )
3021
{
3022
ClearActiveID ( ) ;
3023
}
3024
else
3025
{
3026
const float mouse_abs_pos = g. IO . MousePos [ axis] ;
3027
if ( g. ActiveIdIsJustActivated )
3028
{
3029
float grab_t = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, * v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3030
if ( axis == ImGuiAxis_Y)
3031
grab_t = 1.0f - grab_t;
3032
const float grab_pos = ImLerp ( slider_usable_pos_min, slider_usable_pos_max, grab_t ) ;
3033
const bool clicked_around_grab = ( mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f ) && ( mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f ) ;
3034
g. SliderGrabClickOffset = ( clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f ;
3035
}
3036
if ( slider_usable_sz > 0.0f )
3037
clicked_t = ImSaturate ( ( mouse_abs_pos - g. SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz) ;
3038
if ( axis == ImGuiAxis_Y)
3039
clicked_t = 1.0f - clicked_t;
3040
set_new_value = true ;
3041
}
3042
}
3043
else if ( g. ActiveIdSource == ImGuiInputSource_Keyboard || g. ActiveIdSource == ImGuiInputSource_Gamepad)
3044
{
3045
if ( g. ActiveIdIsJustActivated )
3046
{
3047
g. SliderCurrentAccum = 0.0f ;
3048
g. SliderCurrentAccumDirty = false ;
3049
}
3050
3051
float input_delta = ( axis == ImGuiAxis_X) ? GetNavTweakPressedAmount ( axis ) : - GetNavTweakPressedAmount ( axis ) ;
3052
if ( input_delta != 0.0f )
3053
{
3054
const bool tweak_slow = IsKeyDown ( ( g. NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow) ;
3055
const bool tweak_fast = IsKeyDown ( ( g. NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast) ;
3056
const int decimal_precision = is_floating_point ? ImParseFormatPrecision ( format, 3 ) : 0 ;
3057
if ( decimal_precision > 0 )
3058
{
3059
input_delta /= 100.0f ;
3060
if ( tweak_slow)
3061
input_delta /= 10.0f ;
3062
}
3063
else
3064
{
3065
if ( ( v_range_f >= - 100.0f && v_range_f <= 100.0f && v_range_f != 0.0f ) || tweak_slow)
3066
input_delta = ( ( input_delta < 0.0f ) ? - 1.0f : + 1.0f ) / v_range_f;
3067
else
3068
input_delta /= 100.0f ;
3069
}
3070
if ( tweak_fast)
3071
input_delta *= 10.0f ;
3072
3073
g. SliderCurrentAccum += input_delta;
3074
g. SliderCurrentAccumDirty = true ;
3075
}
3076
3077
float delta = g. SliderCurrentAccum ;
3078
if ( g. NavActivatePressedId == id && ! g. ActiveIdIsJustActivated )
3079
{
3080
ClearActiveID ( ) ;
3081
}
3082
else if ( g. SliderCurrentAccumDirty )
3083
{
3084
clicked_t = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, * v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3085
3086
if ( ( clicked_t >= 1.0f && delta > 0.0f ) || ( clicked_t <= 0.0f && delta < 0.0f ) )
3087
{
3088
set_new_value = false ;
3089
g. SliderCurrentAccum = 0.0f ;
3090
}
3091
else
3092
{
3093
set_new_value = true ;
3094
float old_clicked_t = clicked_t;
3095
clicked_t = ImSaturate ( clicked_t + delta ) ;
3096
3097
3098
TYPE v_new = ScaleValueFromRatioT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3099
if ( is_floating_point && ! ( flags & ImGuiSliderFlags_NoRoundToFormat) )
3100
v_new = RoundScalarWithFormatT < TYPE> ( format, data_type, v_new ) ;
3101
float new_clicked_t = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3102
3103
if ( delta > 0 )
3104
g. SliderCurrentAccum -= ImMin ( new_clicked_t - old_clicked_t, delta ) ;
3105
else
3106
g. SliderCurrentAccum -= ImMax ( new_clicked_t - old_clicked_t, delta ) ;
3107
}
3108
3109
g. SliderCurrentAccumDirty = false ;
3110
}
3111
}
3112
3113
if ( set_new_value)
3114
if ( ( g. LastItemData . ItemFlags & ImGuiItemFlags_ReadOnly) || ( flags & ImGuiSliderFlags_ReadOnly) )
3115
set_new_value = false ;
3116
3117
if ( set_new_value)
3118
{
3119
TYPE v_new = ScaleValueFromRatioT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3120
3121
3122
if ( is_floating_point && ! ( flags & ImGuiSliderFlags_NoRoundToFormat) )
3123
v_new = RoundScalarWithFormatT < TYPE> ( format, data_type, v_new ) ;
3124
3125
3126
if ( * v != v_new)
3127
{
3128
* v = v_new;
3129
value_changed = true ;
3130
}
3131
}
3132
}
3133
3134
if ( slider_sz < 1.0f )
3135
{
3136
* out_grab_bb = ImRect ( bb. Min , bb. Min ) ;
3137
}
3138
else
3139
{
3140
3141
float grab_t = ScaleRatioFromValueT < TYPE, SIGNEDTYPE, FLOATTYPE> ( data_type, * v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize ) ;
3142
if ( axis == ImGuiAxis_Y)
3143
grab_t = 1.0f - grab_t;
3144
const float grab_pos = ImLerp ( slider_usable_pos_min, slider_usable_pos_max, grab_t ) ;
3145
if ( axis == ImGuiAxis_X)
3146
* out_grab_bb = ImRect ( grab_pos - grab_sz * 0.5f , bb. Min . y + grab_padding, grab_pos + grab_sz * 0.5f , bb. Max . y - grab_padding ) ;
3147
else
3148
* out_grab_bb = ImRect ( bb. Min . x + grab_padding, grab_pos - grab_sz * 0.5f , bb. Max . x - grab_padding, grab_pos + grab_sz * 0.5f ) ;
3149
}
3150
3151
return value_changed;
3152
}
3153
3154
3155
3156
3157
bool ImGui:: SliderBehavior ( const ImRect& bb , ImGuiID id , ImGuiDataType data_type , void * p_v , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags , ImRect* out_grab_bb )
3158
{
3159
3160
IM_ASSERT ( ( flags == 1 || ( flags & ImGuiSliderFlags_InvalidMask_) == 0 ) && " Invalid ImGuiSliderFlags flags! Has the legacy 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead." ) ;
3161
IM_ASSERT ( ( flags & ImGuiSliderFlags_WrapAround) == 0 ) ;
3162
3163
switch ( data_type)
3164
{
3165
case ImGuiDataType_S8: { ImS32 v32 = ( ImS32) * ( ImS8* ) p_v; bool r = SliderBehaviorT < ImS32, ImS32, float > ( bb, id, ImGuiDataType_S32, & v32, * ( const ImS8* ) p_min, * ( const ImS8* ) p_max, format, flags, out_grab_bb ) ; if ( r) * ( ImS8* ) p_v = ( ImS8) v32; return r; }
3166
case ImGuiDataType_U8: { ImU32 v32 = ( ImU32) * ( ImU8* ) p_v; bool r = SliderBehaviorT < ImU32, ImS32, float > ( bb, id, ImGuiDataType_U32, & v32, * ( const ImU8* ) p_min, * ( const ImU8* ) p_max, format, flags, out_grab_bb ) ; if ( r) * ( ImU8* ) p_v = ( ImU8) v32; return r; }
3167
case ImGuiDataType_S16: { ImS32 v32 = ( ImS32) * ( ImS16* ) p_v; bool r = SliderBehaviorT < ImS32, ImS32, float > ( bb, id, ImGuiDataType_S32, & v32, * ( const ImS16* ) p_min, * ( const ImS16* ) p_max, format, flags, out_grab_bb ) ; if ( r) * ( ImS16* ) p_v = ( ImS16) v32; return r; }
3168
case ImGuiDataType_U16: { ImU32 v32 = ( ImU32) * ( ImU16* ) p_v; bool r = SliderBehaviorT < ImU32, ImS32, float > ( bb, id, ImGuiDataType_U32, & v32, * ( const ImU16* ) p_min, * ( const ImU16* ) p_max, format, flags, out_grab_bb ) ; if ( r) * ( ImU16* ) p_v = ( ImU16) v32; return r; }
3169
case ImGuiDataType_S32:
3170
IM_ASSERT ( * ( const ImS32* ) p_min >= IM_S32_MIN / 2 && * ( const ImS32* ) p_max <= IM_S32_MAX / 2 ) ;
3171
return SliderBehaviorT < ImS32, ImS32, float > ( bb, id, data_type, ( ImS32* ) p_v, * ( const ImS32* ) p_min, * ( const ImS32* ) p_max, format, flags, out_grab_bb ) ;
3172
case ImGuiDataType_U32:
3173
IM_ASSERT ( * ( const ImU32* ) p_max <= IM_U32_MAX / 2 ) ;
3174
return SliderBehaviorT < ImU32, ImS32, float > ( bb, id, data_type, ( ImU32* ) p_v, * ( const ImU32* ) p_min, * ( const ImU32* ) p_max, format, flags, out_grab_bb ) ;
3175
case ImGuiDataType_S64:
3176
IM_ASSERT ( * ( const ImS64* ) p_min >= IM_S64_MIN / 2 && * ( const ImS64* ) p_max <= IM_S64_MAX / 2 ) ;
3177
return SliderBehaviorT < ImS64, ImS64, double > ( bb, id, data_type, ( ImS64* ) p_v, * ( const ImS64* ) p_min, * ( const ImS64* ) p_max, format, flags, out_grab_bb ) ;
3178
case ImGuiDataType_U64:
3179
IM_ASSERT ( * ( const ImU64* ) p_max <= IM_U64_MAX / 2 ) ;
3180
return SliderBehaviorT < ImU64, ImS64, double > ( bb, id, data_type, ( ImU64* ) p_v, * ( const ImU64* ) p_min, * ( const ImU64* ) p_max, format, flags, out_grab_bb ) ;
3181
case ImGuiDataType_Float:
3182
IM_ASSERT ( * ( const float * ) p_min >= - FLT_MAX / 2.0f && * ( const float * ) p_max <= FLT_MAX / 2.0f ) ;
3183
return SliderBehaviorT < float , float , float > ( bb, id, data_type, ( float * ) p_v, * ( const float * ) p_min, * ( const float * ) p_max, format, flags, out_grab_bb ) ;
3184
case ImGuiDataType_Double:
3185
IM_ASSERT ( * ( const double * ) p_min >= - DBL_MAX / 2.0f && * ( const double * ) p_max <= DBL_MAX / 2.0f ) ;
3186
return SliderBehaviorT < double , double , double > ( bb, id, data_type, ( double * ) p_v, * ( const double * ) p_min, * ( const double * ) p_max, format, flags, out_grab_bb ) ;
3187
case ImGuiDataType_COUNT: break ;
3188
}
3189
IM_ASSERT ( 0 ) ;
3190
return false ;
3191
}
3192
3193
3194
3195
bool ImGui:: SliderScalar ( const char * label , ImGuiDataType data_type , void * p_data , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags )
3196
{
3197
ImGuiWindow* window = GetCurrentWindow ( ) ;
3198
if ( window-> SkipItems )
3199
return false ;
3200
3201
ImGuiContext& g = * GImGui;
3202
const ImGuiStyle& style = g. Style ;
3203
const ImGuiID id = window-> GetID ( label ) ;
3204
const float w = CalcItemWidth ( ) ;
3205
3206
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
3207
const ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + ImVec2 ( w, label_size. y + style. FramePadding . y * 2.0f ) ) ;
3208
const ImRect total_bb ( frame_bb. Min , frame_bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0.0f ) ) ;
3209
3210
const bool temp_input_allowed = ( flags & ImGuiSliderFlags_NoInput) == 0 ;
3211
ItemSize ( total_bb, style. FramePadding . y ) ;
3212
if ( ! ItemAdd ( total_bb, id, & frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0 ) )
3213
return false ;
3214
3215
3216
if ( format == NULL )
3217
format = DataTypeGetInfo ( data_type ) -> PrintFmt ;
3218
3219
const bool hovered = ItemHoverable ( frame_bb, id, g. LastItemData . ItemFlags ) ;
3220
bool temp_input_is_active = temp_input_allowed && TempInputIsActive ( id ) ;
3221
if ( ! temp_input_is_active)
3222
{
3223
3224
const bool clicked = hovered && IsMouseClicked ( 0 , ImGuiInputFlags_None, id) ;
3225
const bool make_active = ( clicked || g. NavActivateId == id) ;
3226
if ( make_active && clicked)
3227
SetKeyOwner ( ImGuiKey_MouseLeft, id ) ;
3228
if ( make_active && temp_input_allowed)
3229
if ( ( clicked && g. IO . KeyCtrl ) || ( g. NavActivateId == id && ( g. NavActivateFlags & ImGuiActivateFlags_PreferInput) ) )
3230
temp_input_is_active = true ;
3231
3232
if ( make_active && ! temp_input_is_active)
3233
{
3234
SetActiveID ( id, window ) ;
3235
SetFocusID ( id, window ) ;
3236
FocusWindow ( window ) ;
3237
g. ActiveIdUsingNavDirMask |= ( 1 << ImGuiDir_Left) | ( 1 << ImGuiDir_Right) ;
3238
}
3239
}
3240
3241
if ( temp_input_is_active)
3242
{
3243
3244
const bool clamp_enabled = ( flags & ImGuiSliderFlags_ClampOnInput) != 0 ;
3245
return TempInputScalar ( frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL , clamp_enabled ? p_max : NULL ) ;
3246
}
3247
3248
3249
const ImU32 frame_col = GetColorU32 ( g. ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
3250
RenderNavCursor ( frame_bb, id ) ;
3251
RenderFrame ( frame_bb. Min , frame_bb. Max , frame_col, true , g. Style . FrameRounding ) ;
3252
3253
3254
ImRect grab_bb;
3255
const bool value_changed = SliderBehavior ( frame_bb, id, data_type, p_data, p_min, p_max, format, flags, & grab_bb ) ;
3256
if ( value_changed)
3257
MarkItemEdited ( id ) ;
3258
3259
3260
if ( grab_bb. Max . x > grab_bb. Min . x )
3261
window-> DrawList -> AddRectFilled ( grab_bb. Min , grab_bb. Max , GetColorU32 ( g. ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab ) , style. GrabRounding ) ;
3262
3263
3264
char value_buf[ 64 ] ;
3265
const char * value_buf_end = value_buf + DataTypeFormatString ( value_buf, IM_ARRAYSIZE ( value_buf ) , data_type, p_data, format ) ;
3266
if ( g. LogEnabled )
3267
LogSetNextTextDecoration ( " {" , " }" ) ;
3268
RenderTextClipped ( frame_bb. Min , frame_bb. Max , value_buf, value_buf_end, NULL , ImVec2 ( 0.5f , 0.5f ) ) ;
3269
3270
if ( label_size. x > 0.0f )
3271
RenderText ( ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , frame_bb. Min . y + style. FramePadding . y ) , label) ;
3272
3273
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ( temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0 ) ) ;
3274
return value_changed;
3275
}
3276
3277
3278
bool ImGui:: SliderScalarN ( const char * label , ImGuiDataType data_type , void * v , int components , const void * v_min , const void * v_max , const char * format , ImGuiSliderFlags flags )
3279
{
3280
ImGuiWindow* window = GetCurrentWindow ( ) ;
3281
if ( window-> SkipItems )
3282
return false ;
3283
3284
ImGuiContext& g = * GImGui;
3285
bool value_changed = false ;
3286
BeginGroup ( ) ;
3287
PushID ( label ) ;
3288
PushMultiItemsWidths ( components, CalcItemWidth ( ) ) ;
3289
size_t type_size = GDataTypeInfo[ data_type] . Size ;
3290
for ( int i = 0 ; i < components; i+ + )
3291
{
3292
PushID ( i ) ;
3293
if ( i > 0 )
3294
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
3295
value_changed |= SliderScalar ( " " , data_type, v, v_min, v_max, format, flags) ;
3296
PopID ( ) ;
3297
PopItemWidth ( ) ;
3298
v = ( void * ) ( ( char * ) v + type_size) ;
3299
}
3300
PopID ( ) ;
3301
3302
const char * label_end = FindRenderedTextEnd ( label ) ;
3303
if ( label != label_end)
3304
{
3305
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
3306
TextEx ( label, label_end ) ;
3307
}
3308
3309
EndGroup ( ) ;
3310
return value_changed;
3311
}
3312
3313
bool ImGui:: SliderFloat ( const char * label , float * v , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
3314
{
3315
return SliderScalar ( label, ImGuiDataType_Float, v, & v_min, & v_max, format, flags ) ;
3316
}
3317
3318
bool ImGui:: SliderFloat2 ( const char * label , float v [ 2 ] , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
3319
{
3320
return SliderScalarN ( label, ImGuiDataType_Float, v, 2 , & v_min, & v_max, format, flags ) ;
3321
}
3322
3323
bool ImGui:: SliderFloat3 ( const char * label , float v [ 3 ] , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
3324
{
3325
return SliderScalarN ( label, ImGuiDataType_Float, v, 3 , & v_min, & v_max, format, flags ) ;
3326
}
3327
3328
bool ImGui:: SliderFloat4 ( const char * label , float v [ 4 ] , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
3329
{
3330
return SliderScalarN ( label, ImGuiDataType_Float, v, 4 , & v_min, & v_max, format, flags ) ;
3331
}
3332
3333
bool ImGui:: SliderAngle ( const char * label , float * v_rad , float v_degrees_min , float v_degrees_max , const char * format , ImGuiSliderFlags flags )
3334
{
3335
if ( format == NULL )
3336
format = " %.0f deg" ;
3337
float v_deg = ( * v_rad) * 360.0f / ( 2 * IM_PI) ;
3338
bool value_changed = SliderFloat ( label, & v_deg, v_degrees_min, v_degrees_max, format, flags ) ;
3339
* v_rad = v_deg * ( 2 * IM_PI) / 360.0f ;
3340
return value_changed;
3341
}
3342
3343
bool ImGui:: SliderInt ( const char * label , int * v , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
3344
{
3345
return SliderScalar ( label, ImGuiDataType_S32, v, & v_min, & v_max, format, flags ) ;
3346
}
3347
3348
bool ImGui:: SliderInt2 ( const char * label , int v [ 2 ] , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
3349
{
3350
return SliderScalarN ( label, ImGuiDataType_S32, v, 2 , & v_min, & v_max, format, flags ) ;
3351
}
3352
3353
bool ImGui:: SliderInt3 ( const char * label , int v [ 3 ] , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
3354
{
3355
return SliderScalarN ( label, ImGuiDataType_S32, v, 3 , & v_min, & v_max, format, flags ) ;
3356
}
3357
3358
bool ImGui:: SliderInt4 ( const char * label , int v [ 4 ] , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
3359
{
3360
return SliderScalarN ( label, ImGuiDataType_S32, v, 4 , & v_min, & v_max, format, flags ) ;
3361
}
3362
3363
bool ImGui:: VSliderScalar ( const char * label , const ImVec2& size , ImGuiDataType data_type , void * p_data , const void * p_min , const void * p_max , const char * format , ImGuiSliderFlags flags )
3364
{
3365
ImGuiWindow* window = GetCurrentWindow ( ) ;
3366
if ( window-> SkipItems )
3367
return false ;
3368
3369
ImGuiContext& g = * GImGui;
3370
const ImGuiStyle& style = g. Style ;
3371
const ImGuiID id = window-> GetID ( label ) ;
3372
3373
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
3374
const ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + size ) ;
3375
const ImRect bb ( frame_bb. Min , frame_bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0.0f ) ) ;
3376
3377
ItemSize ( bb, style. FramePadding . y ) ;
3378
if ( ! ItemAdd ( frame_bb, id ) )
3379
return false ;
3380
3381
3382
if ( format == NULL )
3383
format = DataTypeGetInfo ( data_type ) -> PrintFmt ;
3384
3385
const bool hovered = ItemHoverable ( frame_bb, id, g. LastItemData . ItemFlags ) ;
3386
const bool clicked = hovered && IsMouseClicked ( 0 , ImGuiInputFlags_None, id) ;
3387
if ( clicked || g. NavActivateId == id)
3388
{
3389
if ( clicked)
3390
SetKeyOwner ( ImGuiKey_MouseLeft, id ) ;
3391
SetActiveID ( id, window ) ;
3392
SetFocusID ( id, window ) ;
3393
FocusWindow ( window ) ;
3394
g. ActiveIdUsingNavDirMask |= ( 1 << ImGuiDir_Up) | ( 1 << ImGuiDir_Down) ;
3395
}
3396
3397
3398
const ImU32 frame_col = GetColorU32 ( g. ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg ) ;
3399
RenderNavCursor ( frame_bb, id ) ;
3400
RenderFrame ( frame_bb. Min , frame_bb. Max , frame_col, true , g. Style . FrameRounding ) ;
3401
3402
3403
ImRect grab_bb;
3404
const bool value_changed = SliderBehavior ( frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, & grab_bb ) ;
3405
if ( value_changed)
3406
MarkItemEdited ( id ) ;
3407
3408
3409
if ( grab_bb. Max . y > grab_bb. Min . y )
3410
window-> DrawList -> AddRectFilled ( grab_bb. Min , grab_bb. Max , GetColorU32 ( g. ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab ) , style. GrabRounding ) ;
3411
3412
3413
3414
char value_buf[ 64 ] ;
3415
const char * value_buf_end = value_buf + DataTypeFormatString ( value_buf, IM_ARRAYSIZE ( value_buf ) , data_type, p_data, format ) ;
3416
RenderTextClipped ( ImVec2 ( frame_bb. Min . x , frame_bb. Min . y + style. FramePadding . y ) , frame_bb. Max , value_buf, value_buf_end, NULL , ImVec2 ( 0.5f , 0.0f ) ) ;
3417
if ( label_size. x > 0.0f )
3418
RenderText ( ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , frame_bb. Min . y + style. FramePadding . y ) , label) ;
3419
3420
return value_changed;
3421
}
3422
3423
bool ImGui:: VSliderFloat ( const char * label , const ImVec2& size , float * v , float v_min , float v_max , const char * format , ImGuiSliderFlags flags )
3424
{
3425
return VSliderScalar ( label, size, ImGuiDataType_Float, v, & v_min, & v_max, format, flags ) ;
3426
}
3427
3428
bool ImGui:: VSliderInt ( const char * label , const ImVec2& size , int * v , int v_min , int v_max , const char * format , ImGuiSliderFlags flags )
3429
{
3430
return VSliderScalar ( label, size, ImGuiDataType_S32, v, & v_min, & v_max, format, flags ) ;
3431
}
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
const char * ImParseFormatFindStart ( const char * fmt )
3458
{
3459
while ( char c = fmt[ 0 ] )
3460
{
3461
if ( c == ' %' && fmt[ 1 ] != ' %' )
3462
return fmt;
3463
else if ( c == ' %' )
3464
fmt+ + ;
3465
fmt+ + ;
3466
}
3467
return fmt;
3468
}
3469
3470
const char * ImParseFormatFindEnd ( const char * fmt )
3471
{
3472
3473
if ( fmt[ 0 ] != ' %' )
3474
return fmt;
3475
const unsigned int ignored_uppercase_mask = ( 1 << ( ' I' - ' A' ) ) | ( 1 << ( ' L' - ' A' ) ) ;
3476
const unsigned int ignored_lowercase_mask = ( 1 << ( ' h' - ' a' ) ) | ( 1 << ( ' j' - ' a' ) ) | ( 1 << ( ' l' - ' a' ) ) | ( 1 << ( ' t' - ' a' ) ) | ( 1 << ( ' w' - ' a' ) ) | ( 1 << ( ' z' - ' a' ) ) ;
3477
for ( char c; ( c = * fmt) != 0 ; fmt+ + )
3478
{
3479
if ( c >= ' A' && c <= ' Z' && ( ( 1 << ( c - ' A' ) ) & ignored_uppercase_mask) == 0 )
3480
return fmt + 1 ;
3481
if ( c >= ' a' && c <= ' z' && ( ( 1 << ( c - ' a' ) ) & ignored_lowercase_mask) == 0 )
3482
return fmt + 1 ;
3483
}
3484
return fmt;
3485
}
3486
3487
3488
3489
3490
3491
3492
const char * ImParseFormatTrimDecorations ( const char * fmt , char * buf , size_t buf_size )
3493
{
3494
const char * fmt_start = ImParseFormatFindStart ( fmt ) ;
3495
if ( fmt_start[ 0 ] != ' %' )
3496
return " " ;
3497
const char * fmt_end = ImParseFormatFindEnd ( fmt_start ) ;
3498
if ( fmt_end[ 0 ] == 0 )
3499
return fmt_start;
3500
ImStrncpy ( buf, fmt_start, ImMin ( ( size_t ) ( fmt_end - fmt_start) + 1 , buf_size) ) ;
3501
return buf;
3502
}
3503
3504
3505
3506
3507
void ImParseFormatSanitizeForPrinting ( const char * fmt_in , char * fmt_out , size_t fmt_out_size )
3508
{
3509
const char * fmt_end = ImParseFormatFindEnd ( fmt_in ) ;
3510
IM_UNUSED ( fmt_out_size ) ;
3511
IM_ASSERT ( ( size_t ) ( fmt_end - fmt_in + 1 ) < fmt_out_size) ;
3512
while ( fmt_in < fmt_end)
3513
{
3514
char c = * fmt_in+ + ;
3515
if ( c != ' \' ' && c != ' $' && c != ' _' )
3516
* ( fmt_out+ + ) = c;
3517
}
3518
* fmt_out = 0 ;
3519
}
3520
3521
3522
const char * ImParseFormatSanitizeForScanning ( const char * fmt_in , char * fmt_out , size_t fmt_out_size )
3523
{
3524
const char * fmt_end = ImParseFormatFindEnd ( fmt_in ) ;
3525
const char * fmt_out_begin = fmt_out;
3526
IM_UNUSED ( fmt_out_size ) ;
3527
IM_ASSERT ( ( size_t ) ( fmt_end - fmt_in + 1 ) < fmt_out_size) ;
3528
bool has_type = false ;
3529
while ( fmt_in < fmt_end)
3530
{
3531
char c = * fmt_in+ + ;
3532
if ( ! has_type && ( ( c >= ' 0' && c <= ' 9' ) || c == ' .' || c == ' +' || c == ' #' ) )
3533
continue ;
3534
has_type |= ( ( c >= ' a' && c <= ' z' ) || ( c >= ' A' && c <= ' Z' ) ) ;
3535
if ( c != ' \' ' && c != ' $' && c != ' _' )
3536
* ( fmt_out+ + ) = c;
3537
}
3538
* fmt_out = 0 ;
3539
return fmt_out_begin;
3540
}
3541
3542
template < typename TYPE>
3543
static const char * ImAtoi ( const char * src , TYPE* output )
3544
{
3545
int negative = 0 ;
3546
if ( * src == ' -' ) { negative = 1 ; src+ + ; }
3547
if ( * src == ' +' ) { src+ + ; }
3548
TYPE v = 0 ;
3549
while ( * src >= ' 0' && * src <= ' 9' )
3550
v = ( v * 10 ) + ( * src+ + - ' 0' ) ;
3551
* output = negative ? - v : v;
3552
return src;
3553
}
3554
3555
3556
3557
int ImParseFormatPrecision ( const char * fmt , int default_precision )
3558
{
3559
fmt = ImParseFormatFindStart ( fmt ) ;
3560
if ( fmt[ 0 ] != ' %' )
3561
return default_precision;
3562
fmt+ + ;
3563
while ( * fmt >= ' 0' && * fmt <= ' 9' )
3564
fmt+ + ;
3565
int precision = INT_MAX;
3566
if ( * fmt == ' .' )
3567
{
3568
fmt = ImAtoi < int > ( fmt + 1 , & precision ) ;
3569
if ( precision < 0 || precision > 99 )
3570
precision = default_precision;
3571
}
3572
if ( * fmt == ' e' || * fmt == ' E' )
3573
precision = - 1 ;
3574
if ( ( * fmt == ' g' || * fmt == ' G' ) && precision == INT_MAX)
3575
precision = - 1 ;
3576
return ( precision == INT_MAX) ? default_precision : precision;
3577
}
3578
3579
3580
3581
3582
3583
bool ImGui:: TempInputText ( const ImRect& bb , ImGuiID id , const char * label , char * buf , int buf_size , ImGuiInputTextFlags flags )
3584
{
3585
3586
3587
ImGuiContext& g = * GImGui;
3588
const bool init = ( g. TempInputId != id) ;
3589
if ( init)
3590
ClearActiveID ( ) ;
3591
3592
g. CurrentWindow -> DC . CursorPos = bb. Min ;
3593
g. LastItemData . ItemFlags |= ImGuiItemFlags_AllowDuplicateId;
3594
bool value_changed = InputTextEx ( label, NULL , buf, buf_size, bb. GetSize ( ) , flags | ImGuiInputTextFlags_MergedItem ) ;
3595
if ( init)
3596
{
3597
3598
IM_ASSERT ( g. ActiveId == id ) ;
3599
g. TempInputId = g. ActiveId ;
3600
}
3601
return value_changed;
3602
}
3603
3604
3605
3606
3607
bool ImGui:: TempInputScalar ( const ImRect& bb , ImGuiID id , const char * label , ImGuiDataType data_type , void * p_data , const char * format , const void * p_clamp_min , const void * p_clamp_max )
3608
{
3609
3610
3611
ImGuiContext& g = * GImGui;
3612
const ImGuiDataTypeInfo* type_info = DataTypeGetInfo ( data_type ) ;
3613
char fmt_buf[ 32 ] ;
3614
char data_buf[ 32 ] ;
3615
format = ImParseFormatTrimDecorations ( format, fmt_buf, IM_ARRAYSIZE ( fmt_buf ) ) ;
3616
if ( format[ 0 ] == 0 )
3617
format = type_info-> PrintFmt ;
3618
DataTypeFormatString ( data_buf, IM_ARRAYSIZE ( data_buf ) , data_type, p_data, format ) ;
3619
ImStrTrimBlanks ( data_buf ) ;
3620
3621
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ( ImGuiInputTextFlags) ImGuiInputTextFlags_LocalizeDecimalPoint;
3622
g. LastItemData . ItemFlags |= ImGuiItemFlags_NoMarkEdited;
3623
bool value_changed = false ;
3624
if ( TempInputText ( bb, id, label, data_buf, IM_ARRAYSIZE ( data_buf ) , flags ) )
3625
{
3626
3627
size_t data_type_size = type_info-> Size ;
3628
ImGuiDataTypeStorage data_backup;
3629
memcpy ( & data_backup, p_data, data_type_size) ;
3630
3631
3632
DataTypeApplyFromText ( data_buf, data_type, p_data, format, NULL ) ;
3633
if ( p_clamp_min || p_clamp_max)
3634
{
3635
if ( p_clamp_min && p_clamp_max && DataTypeCompare ( data_type, p_clamp_min, p_clamp_max ) > 0 )
3636
ImSwap ( p_clamp_min, p_clamp_max ) ;
3637
DataTypeClamp ( data_type, p_data, p_clamp_min, p_clamp_max ) ;
3638
}
3639
3640
3641
g. LastItemData . ItemFlags &= ~ ImGuiItemFlags_NoMarkEdited;
3642
value_changed = memcmp ( & data_backup, p_data, data_type_size) != 0 ;
3643
if ( value_changed)
3644
MarkItemEdited ( id ) ;
3645
}
3646
return value_changed;
3647
}
3648
3649
void ImGui:: SetNextItemRefVal ( ImGuiDataType data_type , void * p_data )
3650
{
3651
ImGuiContext& g = * GImGui;
3652
g. NextItemData . HasFlags |= ImGuiNextItemDataFlags_HasRefVal;
3653
memcpy ( & g. NextItemData . RefVal , p_data, DataTypeGetInfo ( data_type ) -> Size ) ;
3654
}
3655
3656
3657
3658
bool ImGui:: InputScalar ( const char * label , ImGuiDataType data_type , void * p_data , const void * p_step , const void * p_step_fast , const char * format , ImGuiInputTextFlags flags )
3659
{
3660
ImGuiWindow* window = GetCurrentWindow ( ) ;
3661
if ( window-> SkipItems )
3662
return false ;
3663
3664
ImGuiContext& g = * GImGui;
3665
ImGuiStyle& style = g. Style ;
3666
IM_ASSERT ( ( flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0 ) ;
3667
3668
if ( format == NULL )
3669
format = DataTypeGetInfo ( data_type ) -> PrintFmt ;
3670
3671
void * p_data_default = ( g. NextItemData . HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? & g. NextItemData . RefVal : & g. DataTypeZeroValue ;
3672
3673
char buf[ 64 ] ;
3674
if ( ( flags & ImGuiInputTextFlags_DisplayEmptyRefVal) && DataTypeCompare ( data_type, p_data, p_data_default ) == 0 )
3675
buf[ 0 ] = 0 ;
3676
else
3677
DataTypeFormatString ( buf, IM_ARRAYSIZE ( buf ) , data_type, p_data, format ) ;
3678
3679
3680
3681
g. NextItemData . ItemFlags |= ImGuiItemFlags_NoMarkEdited;
3682
flags |= ImGuiInputTextFlags_AutoSelectAll | ( ImGuiInputTextFlags) ImGuiInputTextFlags_LocalizeDecimalPoint;
3683
3684
bool value_changed = false ;
3685
if ( p_step == NULL )
3686
{
3687
if ( InputText ( label, buf, IM_ARRAYSIZE ( buf ) , flags ) )
3688
value_changed = DataTypeApplyFromText ( buf, data_type, p_data, format, ( flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL ) ;
3689
}
3690
else
3691
{
3692
const float button_size = GetFrameHeight ( ) ;
3693
3694
BeginGroup ( ) ;
3695
PushID ( label ) ;
3696
SetNextItemWidth ( ImMax ( 1.0f , CalcItemWidth ( ) - ( button_size + style. ItemInnerSpacing . x ) * 2 ) ) ;
3697
if ( InputText ( " " , buf, IM_ARRAYSIZE ( buf ) , flags) )
3698
value_changed = DataTypeApplyFromText ( buf, data_type, p_data, format, ( flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL ) ;
3699
IMGUI_TEST_ENGINE_ITEM_INFO ( g. LastItemData . ID , label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Inputable ) ;
3700
3701
3702
const ImVec2 backup_frame_padding = style. FramePadding ;
3703
style. FramePadding . x = style. FramePadding . y ;
3704
if ( flags & ImGuiInputTextFlags_ReadOnly)
3705
BeginDisabled ( ) ;
3706
PushItemFlag ( ImGuiItemFlags_ButtonRepeat, true ) ;
3707
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
3708
if ( ButtonEx ( " -" , ImVec2 ( button_size, button_size ) ) )
3709
{
3710
DataTypeApplyOp ( data_type, ' -' , p_data, p_data, g. IO . KeyCtrl && p_step_fast ? p_step_fast : p_step ) ;
3711
value_changed = true ;
3712
}
3713
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
3714
if ( ButtonEx ( " +" , ImVec2 ( button_size, button_size ) ) )
3715
{
3716
DataTypeApplyOp ( data_type, ' +' , p_data, p_data, g. IO . KeyCtrl && p_step_fast ? p_step_fast : p_step ) ;
3717
value_changed = true ;
3718
}
3719
PopItemFlag ( ) ;
3720
if ( flags & ImGuiInputTextFlags_ReadOnly)
3721
EndDisabled ( ) ;
3722
3723
const char * label_end = FindRenderedTextEnd ( label ) ;
3724
if ( label != label_end)
3725
{
3726
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
3727
TextEx ( label, label_end ) ;
3728
}
3729
style. FramePadding = backup_frame_padding;
3730
3731
PopID ( ) ;
3732
EndGroup ( ) ;
3733
}
3734
3735
g. LastItemData . ItemFlags &= ~ ImGuiItemFlags_NoMarkEdited;
3736
if ( value_changed)
3737
MarkItemEdited ( g. LastItemData . ID ) ;
3738
3739
return value_changed;
3740
}
3741
3742
bool ImGui:: InputScalarN ( const char * label , ImGuiDataType data_type , void * p_data , int components , const void * p_step , const void * p_step_fast , const char * format , ImGuiInputTextFlags flags )
3743
{
3744
ImGuiWindow* window = GetCurrentWindow ( ) ;
3745
if ( window-> SkipItems )
3746
return false ;
3747
3748
ImGuiContext& g = * GImGui;
3749
bool value_changed = false ;
3750
BeginGroup ( ) ;
3751
PushID ( label ) ;
3752
PushMultiItemsWidths ( components, CalcItemWidth ( ) ) ;
3753
size_t type_size = GDataTypeInfo[ data_type] . Size ;
3754
for ( int i = 0 ; i < components; i+ + )
3755
{
3756
PushID ( i ) ;
3757
if ( i > 0 )
3758
SameLine ( 0 , g. Style . ItemInnerSpacing . x ) ;
3759
value_changed |= InputScalar ( " " , data_type, p_data, p_step, p_step_fast, format, flags) ;
3760
PopID ( ) ;
3761
PopItemWidth ( ) ;
3762
p_data = ( void * ) ( ( char * ) p_data + type_size) ;
3763
}
3764
PopID ( ) ;
3765
3766
const char * label_end = FindRenderedTextEnd ( label ) ;
3767
if ( label != label_end)
3768
{
3769
SameLine ( 0.0f , g. Style . ItemInnerSpacing . x ) ;
3770
TextEx ( label, label_end ) ;
3771
}
3772
3773
EndGroup ( ) ;
3774
return value_changed;
3775
}
3776
3777
bool ImGui:: InputFloat ( const char * label , float * v , float step , float step_fast , const char * format , ImGuiInputTextFlags flags )
3778
{
3779
return InputScalar ( label, ImGuiDataType_Float, ( void * ) v, ( void * ) ( step > 0.0f ? & step : NULL ) , ( void * ) ( step_fast > 0.0f ? & step_fast : NULL ) , format, flags ) ;
3780
}
3781
3782
bool ImGui:: InputFloat2 ( const char * label , float v [ 2 ] , const char * format , ImGuiInputTextFlags flags )
3783
{
3784
return InputScalarN ( label, ImGuiDataType_Float, v, 2 , NULL , NULL , format, flags ) ;
3785
}
3786
3787
bool ImGui:: InputFloat3 ( const char * label , float v [ 3 ] , const char * format , ImGuiInputTextFlags flags )
3788
{
3789
return InputScalarN ( label, ImGuiDataType_Float, v, 3 , NULL , NULL , format, flags ) ;
3790
}
3791
3792
bool ImGui:: InputFloat4 ( const char * label , float v [ 4 ] , const char * format , ImGuiInputTextFlags flags )
3793
{
3794
return InputScalarN ( label, ImGuiDataType_Float, v, 4 , NULL , NULL , format, flags ) ;
3795
}
3796
3797
bool ImGui:: InputInt ( const char * label , int * v , int step , int step_fast , ImGuiInputTextFlags flags )
3798
{
3799
3800
const char * format = ( flags & ImGuiInputTextFlags_CharsHexadecimal) ? " %08X " : " %d " ;
3801
return InputScalar ( label, ImGuiDataType_S32, ( void * ) v, ( void * ) ( step > 0 ? & step : NULL ) , ( void * ) ( step_fast > 0 ? & step_fast : NULL ) , format, flags ) ;
3802
}
3803
3804
bool ImGui:: InputInt2 ( const char * label , int v [ 2 ] , ImGuiInputTextFlags flags )
3805
{
3806
return InputScalarN ( label, ImGuiDataType_S32, v, 2 , NULL , NULL , " %d " , flags ) ;
3807
}
3808
3809
bool ImGui:: InputInt3 ( const char * label , int v [ 3 ] , ImGuiInputTextFlags flags )
3810
{
3811
return InputScalarN ( label, ImGuiDataType_S32, v, 3 , NULL , NULL , " %d " , flags ) ;
3812
}
3813
3814
bool ImGui:: InputInt4 ( const char * label , int v [ 4 ] , ImGuiInputTextFlags flags )
3815
{
3816
return InputScalarN ( label, ImGuiDataType_S32, v, 4 , NULL , NULL , " %d " , flags ) ;
3817
}
3818
3819
bool ImGui:: InputDouble ( const char * label , double * v , double step , double step_fast , const char * format , ImGuiInputTextFlags flags )
3820
{
3821
return InputScalar ( label, ImGuiDataType_Double, ( void * ) v, ( void * ) ( step > 0.0 ? & step : NULL ) , ( void * ) ( step_fast > 0.0 ? & step_fast : NULL ) , format, flags ) ;
3822
}
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
namespace ImStb
3839
{
3840
#include " imstb_textedit.h"
3841
}
3842
3843
bool ImGui:: InputText ( const char * label , char * buf , size_t buf_size , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * user_data )
3844
{
3845
IM_ASSERT ( ! ( flags & ImGuiInputTextFlags_Multiline) ) ;
3846
return InputTextEx ( label, NULL , buf, ( int ) buf_size, ImVec2 ( 0 , 0 ) , flags, callback, user_data ) ;
3847
}
3848
3849
bool ImGui:: InputTextMultiline ( const char * label , char * buf , size_t buf_size , const ImVec2& size , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * user_data )
3850
{
3851
return InputTextEx ( label, NULL , buf, ( int ) buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data ) ;
3852
}
3853
3854
bool ImGui:: InputTextWithHint ( const char * label , const char * hint , char * buf , size_t buf_size , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * user_data )
3855
{
3856
IM_ASSERT ( ! ( flags & ImGuiInputTextFlags_Multiline) ) ;
3857
return InputTextEx ( label, hint, buf, ( int ) buf_size, ImVec2 ( 0 , 0 ) , flags, callback, user_data ) ;
3858
}
3859
3860
3861
static int InputTextCalcTextLenAndLineCount ( const char * text_begin , const char * * out_text_end )
3862
{
3863
int line_count = 0 ;
3864
const char * s = text_begin;
3865
while ( true )
3866
{
3867
const char * s_eol = strchr ( s, ' \n ' ) ;
3868
line_count+ + ;
3869
if ( s_eol == NULL )
3870
{
3871
s = s + strlen ( s ) ;
3872
break ;
3873
}
3874
s = s_eol + 1 ;
3875
}
3876
* out_text_end = s;
3877
return line_count;
3878
}
3879
3880
3881
static ImVec2 InputTextCalcTextSize ( ImGuiContext* ctx , const char * text_begin , const char * text_end , const char * * remaining , ImVec2* out_offset , bool stop_on_new_line )
3882
{
3883
ImGuiContext& g = * ctx;
3884
ImFont* font = g. Font ;
3885
const float line_height = g. FontSize ;
3886
const float scale = line_height / font-> FontSize ;
3887
3888
ImVec2 text_size = ImVec2 ( 0 , 0 ) ;
3889
float line_width = 0.0f ;
3890
3891
const char * s = text_begin;
3892
while ( s < text_end)
3893
{
3894
unsigned int c = ( unsigned int ) * s;
3895
if ( c < 0x80 )
3896
s += 1 ;
3897
else
3898
s += ImTextCharFromUtf8 ( & c, s, text_end) ;
3899
3900
if ( c == ' \n ' )
3901
{
3902
text_size. x = ImMax ( text_size. x , line_width ) ;
3903
text_size. y += line_height;
3904
line_width = 0.0f ;
3905
if ( stop_on_new_line)
3906
break ;
3907
continue ;
3908
}
3909
if ( c == ' \r ' )
3910
continue ;
3911
3912
const float char_width = ( ( int ) c < font-> IndexAdvanceX . Size ? font-> IndexAdvanceX . Data [ c] : font-> FallbackAdvanceX ) * scale;
3913
line_width += char_width;
3914
}
3915
3916
if ( text_size. x < line_width)
3917
text_size. x = line_width;
3918
3919
if ( out_offset)
3920
* out_offset = ImVec2 ( line_width, text_size. y + line_height ) ;
3921
3922
if ( line_width > 0 || text_size. y == 0.0f )
3923
text_size. y += line_height;
3924
3925
if ( remaining)
3926
* remaining = s;
3927
3928
return text_size;
3929
}
3930
3931
3932
3933
3934
3935
3936
namespace ImStb
3937
{
3938
static int STB_TEXTEDIT_STRINGLEN ( const ImGuiInputTextState* obj ) { return obj-> TextLen ; }
3939
static char STB_TEXTEDIT_GETCHAR ( const ImGuiInputTextState* obj , int idx ) { IM_ASSERT ( idx <= obj-> TextLen ) ; return obj-> TextA [ idx] ; }
3940
static float STB_TEXTEDIT_GETWIDTH ( ImGuiInputTextState* obj , int line_start_idx , int char_idx ) { unsigned int c; ImTextCharFromUtf8 ( & c, obj-> TextA . Data + line_start_idx + char_idx, obj-> TextA . Data + obj-> TextLen ) ; if ( ( ImWchar) c == ' \n ' ) return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = * obj-> Ctx ; return g. Font -> GetCharAdvance ( ( ImWchar) c) * g. FontScale ; }
3941
static char STB_TEXTEDIT_NEWLINE = ' \n ' ;
3942
static void STB_TEXTEDIT_LAYOUTROW ( StbTexteditRow* r , ImGuiInputTextState* obj , int line_start_idx )
3943
{
3944
const char * text = obj-> TextA . Data ;
3945
const char * text_remaining = NULL ;
3946
const ImVec2 size = InputTextCalcTextSize ( obj-> Ctx , text + line_start_idx, text + obj-> TextLen , & text_remaining, NULL , true ) ;
3947
r-> x0 = 0.0f ;
3948
r-> x1 = size. x ;
3949
r-> baseline_y_delta = size. y ;
3950
r-> ymin = 0.0f ;
3951
r-> ymax = size. y ;
3952
r-> num_chars = ( int ) ( text_remaining - ( text + line_start_idx) ) ;
3953
}
3954
3955
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL
3956
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL
3957
3958
static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL ( ImGuiInputTextState* obj , int idx )
3959
{
3960
if ( idx >= obj-> TextLen )
3961
return obj-> TextLen + 1 ;
3962
unsigned int c;
3963
return idx + ImTextCharFromUtf8 ( & c, obj-> TextA . Data + idx, obj-> TextA . Data + obj-> TextLen ) ;
3964
}
3965
3966
static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL ( ImGuiInputTextState* obj , int idx )
3967
{
3968
if ( idx <= 0 )
3969
return - 1 ;
3970
const char * p = ImTextFindPreviousUtf8Codepoint ( obj-> TextA . Data , obj-> TextA . Data + idx ) ;
3971
return ( int ) ( p - obj-> TextA . Data ) ;
3972
}
3973
3974
static bool ImCharIsSeparatorW ( unsigned int c )
3975
{
3976
static const unsigned int separator_list[ ] =
3977
{
3978
' ,' , 0x3001 , ' .' , 0x3002 , ' ;' , 0xFF1B , ' (' , 0xFF08 , ' )' , 0xFF09 , ' {' , 0xFF5B , ' }' , 0xFF5D ,
3979
' [' , 0x300C , ' ]' , 0x300D , ' |' , 0xFF5C , ' !' , 0xFF01 , ' \\ ' , 0xFFE5 , ' /' , 0x30FB , 0xFF0F ,
3980
' \n ' , ' \r ' ,
3981
} ;
3982
for ( unsigned int separator : separator_list)
3983
if ( c == separator)
3984
return true ;
3985
return false ;
3986
}
3987
3988
static int is_word_boundary_from_right ( ImGuiInputTextState* obj , int idx )
3989
{
3990
3991
if ( ( obj-> Flags & ImGuiInputTextFlags_Password) || idx <= 0 )
3992
return 0 ;
3993
3994
const char * curr_p = obj-> TextA . Data + idx;
3995
const char * prev_p = ImTextFindPreviousUtf8Codepoint ( obj-> TextA . Data , curr_p ) ;
3996
unsigned int curr_c; ImTextCharFromUtf8 ( & curr_c, curr_p, obj-> TextA . Data + obj-> TextLen ) ;
3997
unsigned int prev_c; ImTextCharFromUtf8 ( & prev_c, prev_p, obj-> TextA . Data + obj-> TextLen ) ;
3998
3999
bool prev_white = ImCharIsBlankW ( prev_c ) ;
4000
bool prev_separ = ImCharIsSeparatorW ( prev_c ) ;
4001
bool curr_white = ImCharIsBlankW ( curr_c ) ;
4002
bool curr_separ = ImCharIsSeparatorW ( curr_c ) ;
4003
return ( ( prev_white || prev_separ) && ! ( curr_separ || curr_white) ) || ( curr_separ && ! prev_separ) ;
4004
}
4005
static int is_word_boundary_from_left ( ImGuiInputTextState* obj , int idx )
4006
{
4007
if ( ( obj-> Flags & ImGuiInputTextFlags_Password) || idx <= 0 )
4008
return 0 ;
4009
4010
const char * curr_p = obj-> TextA . Data + idx;
4011
const char * prev_p = ImTextFindPreviousUtf8Codepoint ( obj-> TextA . Data , curr_p ) ;
4012
unsigned int prev_c; ImTextCharFromUtf8 ( & prev_c, curr_p, obj-> TextA . Data + obj-> TextLen ) ;
4013
unsigned int curr_c; ImTextCharFromUtf8 ( & curr_c, prev_p, obj-> TextA . Data + obj-> TextLen ) ;
4014
4015
bool prev_white = ImCharIsBlankW ( prev_c ) ;
4016
bool prev_separ = ImCharIsSeparatorW ( prev_c ) ;
4017
bool curr_white = ImCharIsBlankW ( curr_c ) ;
4018
bool curr_separ = ImCharIsSeparatorW ( curr_c ) ;
4019
return ( ( prev_white) && ! ( curr_separ || curr_white) ) || ( curr_separ && ! prev_separ) ;
4020
}
4021
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL ( ImGuiInputTextState* obj , int idx )
4022
{
4023
idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX ( obj, idx ) ;
4024
while ( idx >= 0 && ! is_word_boundary_from_right ( obj, idx ) )
4025
idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX ( obj, idx ) ;
4026
return idx < 0 ? 0 : idx;
4027
}
4028
static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC ( ImGuiInputTextState* obj , int idx )
4029
{
4030
int len = obj-> TextLen ;
4031
idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX ( obj, idx ) ;
4032
while ( idx < len && ! is_word_boundary_from_left ( obj, idx ) )
4033
idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX ( obj, idx ) ;
4034
return idx > len ? len : idx;
4035
}
4036
static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN ( ImGuiInputTextState* obj , int idx )
4037
{
4038
idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX ( obj, idx ) ;
4039
int len = obj-> TextLen ;
4040
while ( idx < len && ! is_word_boundary_from_right ( obj, idx ) )
4041
idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX ( obj, idx ) ;
4042
return idx > len ? len : idx;
4043
}
4044
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL ( ImGuiInputTextState* obj , int idx ) { ImGuiContext& g = * obj-> Ctx ; if ( g. IO . ConfigMacOSXBehaviors ) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC ( obj, idx ) ; else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN ( obj, idx ) ; }
4045
#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL
4046
#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
4047
4048
static void STB_TEXTEDIT_DELETECHARS ( ImGuiInputTextState* obj , int pos , int n )
4049
{
4050
char * dst = obj-> TextA . Data + pos;
4051
4052
obj-> Edited = true ;
4053
obj-> TextLen -= n;
4054
4055
4056
const char * src = obj-> TextA . Data + pos + n;
4057
while ( char c = * src+ + )
4058
* dst+ + = c;
4059
* dst = ' \0 ' ;
4060
}
4061
4062
static bool STB_TEXTEDIT_INSERTCHARS ( ImGuiInputTextState* obj , int pos , const char * new_text , int new_text_len )
4063
{
4064
const bool is_resizable = ( obj-> Flags & ImGuiInputTextFlags_CallbackResize) != 0 ;
4065
const int text_len = obj-> TextLen ;
4066
IM_ASSERT ( pos <= text_len ) ;
4067
4068
if ( ! is_resizable && ( new_text_len + obj-> TextLen + 1 > obj-> BufCapacity ) )
4069
return false ;
4070
4071
4072
if ( new_text_len + text_len + 1 > obj-> TextA . Size )
4073
{
4074
if ( ! is_resizable)
4075
return false ;
4076
obj-> TextA . resize ( text_len + ImClamp ( new_text_len, 32 , ImMax ( 256 , new_text_len) ) + 1 ) ;
4077
}
4078
4079
char * text = obj-> TextA . Data ;
4080
if ( pos != text_len)
4081
memmove ( text + pos + new_text_len, text + pos, ( size_t ) ( text_len - pos) ) ;
4082
memcpy ( text + pos, new_text, ( size_t ) new_text_len ) ;
4083
4084
obj-> Edited = true ;
4085
obj-> TextLen += new_text_len;
4086
obj-> TextA [ obj-> TextLen ] = ' \0 ' ;
4087
4088
return true ;
4089
}
4090
4091
4092
#define STB_TEXTEDIT_K_LEFT 0x200000
4093
#define STB_TEXTEDIT_K_RIGHT 0x200001
4094
#define STB_TEXTEDIT_K_UP 0x200002
4095
#define STB_TEXTEDIT_K_DOWN 0x200003
4096
#define STB_TEXTEDIT_K_LINESTART 0x200004
4097
#define STB_TEXTEDIT_K_LINEEND 0x200005
4098
#define STB_TEXTEDIT_K_TEXTSTART 0x200006
4099
#define STB_TEXTEDIT_K_TEXTEND 0x200007
4100
#define STB_TEXTEDIT_K_DELETE 0x200008
4101
#define STB_TEXTEDIT_K_BACKSPACE 0x200009
4102
#define STB_TEXTEDIT_K_UNDO 0x20000A
4103
#define STB_TEXTEDIT_K_REDO 0x20000B
4104
#define STB_TEXTEDIT_K_WORDLEFT 0x20000C
4105
#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D
4106
#define STB_TEXTEDIT_K_PGUP 0x20000E
4107
#define STB_TEXTEDIT_K_PGDOWN 0x20000F
4108
#define STB_TEXTEDIT_K_SHIFT 0x400000
4109
4110
#define IMSTB_TEXTEDIT_IMPLEMENTATION
4111
#define IMSTB_TEXTEDIT_memmove memmove
4112
#include " imstb_textedit.h"
4113
4114
4115
4116
static void stb_textedit_replace ( ImGuiInputTextState* str , STB_TexteditState* state , const IMSTB_TEXTEDIT_CHARTYPE* text , int text_len )
4117
{
4118
stb_text_makeundo_replace ( str, state, 0 , str-> TextLen , text_len ) ;
4119
ImStb:: STB_TEXTEDIT_DELETECHARS ( str, 0 , str-> TextLen ) ;
4120
state-> cursor = state-> select_start = state-> select_end = 0 ;
4121
if ( text_len <= 0 )
4122
return ;
4123
if ( ImStb:: STB_TEXTEDIT_INSERTCHARS ( str, 0 , text, text_len ) )
4124
{
4125
state-> cursor = state-> select_start = state-> select_end = text_len;
4126
state-> has_preferred_x = 0 ;
4127
return ;
4128
}
4129
IM_ASSERT ( 0 ) ;
4130
}
4131
4132
}
4133
4134
4135
ImGuiInputTextState:: ImGuiInputTextState ( )
4136
{
4137
memset ( this , 0 , sizeof ( * this ) ) ;
4138
Stb = IM_NEW ( ImStbTexteditState ) ;
4139
memset ( Stb, 0 , sizeof ( * Stb) ) ;
4140
}
4141
4142
ImGuiInputTextState:: ~ImGuiInputTextState ( )
4143
{
4144
IM_DELETE ( Stb ) ;
4145
}
4146
4147
void ImGuiInputTextState:: OnKeyPressed ( int key )
4148
{
4149
stb_textedit_key ( this , Stb, key) ;
4150
CursorFollow = true ;
4151
CursorAnimReset ( ) ;
4152
}
4153
4154
void ImGuiInputTextState:: OnCharPressed ( unsigned int c )
4155
{
4156
4157
4158
char utf8[ 5 ] ;
4159
ImTextCharToUtf8 ( utf8, c ) ;
4160
stb_textedit_text ( this , Stb, utf8, ( int ) strlen ( utf8 ) ) ;
4161
CursorFollow = true ;
4162
CursorAnimReset ( ) ;
4163
}
4164
4165
4166
void ImGuiInputTextState:: CursorAnimReset ( ) { CursorAnim = - 0.30f ; }
4167
void ImGuiInputTextState:: CursorClamp ( ) { Stb-> cursor = ImMin ( Stb-> cursor , TextLen ) ; Stb-> select_start = ImMin ( Stb-> select_start , TextLen ) ; Stb-> select_end = ImMin ( Stb-> select_end , TextLen ) ; }
4168
bool ImGuiInputTextState:: HasSelection ( ) const { return Stb-> select_start != Stb-> select_end ; }
4169
void ImGuiInputTextState:: ClearSelection ( ) { Stb-> select_start = Stb-> select_end = Stb-> cursor ; }
4170
int ImGuiInputTextState:: GetCursorPos ( ) const { return Stb-> cursor ; }
4171
int ImGuiInputTextState:: GetSelectionStart ( ) const { return Stb-> select_start ; }
4172
int ImGuiInputTextState:: GetSelectionEnd ( ) const { return Stb-> select_end ; }
4173
void ImGuiInputTextState:: SelectAll ( ) { Stb-> select_start = 0 ; Stb-> cursor = Stb-> select_end = TextLen; Stb-> has_preferred_x = 0 ; }
4174
void ImGuiInputTextState:: ReloadUserBufAndSelectAll ( ) { ReloadUserBuf = true ; ReloadSelectionStart = 0 ; ReloadSelectionEnd = INT_MAX; }
4175
void ImGuiInputTextState:: ReloadUserBufAndKeepSelection ( ) { ReloadUserBuf = true ; ReloadSelectionStart = Stb-> select_start ; ReloadSelectionEnd = Stb-> select_end ; }
4176
void ImGuiInputTextState:: ReloadUserBufAndMoveToEnd ( ) { ReloadUserBuf = true ; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; }
4177
4178
ImGuiInputTextCallbackData:: ImGuiInputTextCallbackData ( )
4179
{
4180
memset ( this , 0 , sizeof ( * this ) ) ;
4181
}
4182
4183
4184
4185
4186
void ImGuiInputTextCallbackData:: DeleteChars ( int pos , int bytes_count )
4187
{
4188
IM_ASSERT ( pos + bytes_count <= BufTextLen ) ;
4189
char * dst = Buf + pos;
4190
const char * src = Buf + pos + bytes_count;
4191
while ( char c = * src+ + )
4192
* dst+ + = c;
4193
* dst = ' \0 ' ;
4194
4195
if ( CursorPos >= pos + bytes_count)
4196
CursorPos -= bytes_count;
4197
else if ( CursorPos >= pos)
4198
CursorPos = pos;
4199
SelectionStart = SelectionEnd = CursorPos;
4200
BufDirty = true ;
4201
BufTextLen -= bytes_count;
4202
}
4203
4204
void ImGuiInputTextCallbackData:: InsertChars ( int pos , const char * new_text , const char * new_text_end )
4205
{
4206
4207
if ( new_text == new_text_end)
4208
return ;
4209
4210
4211
const bool is_resizable = ( Flags & ImGuiInputTextFlags_CallbackResize) != 0 ;
4212
const int new_text_len = new_text_end ? ( int ) ( new_text_end - new_text) : ( int ) strlen ( new_text ) ;
4213
if ( new_text_len + BufTextLen >= BufSize)
4214
{
4215
if ( ! is_resizable)
4216
return ;
4217
4218
4219
ImGuiContext& g = * Ctx;
4220
ImGuiInputTextState* edit_state = & g. InputTextState ;
4221
IM_ASSERT ( edit_state-> ID != 0 && g. ActiveId == edit_state-> ID ) ;
4222
IM_ASSERT ( Buf == edit_state-> TextA . Data ) ;
4223
int new_buf_size = BufTextLen + ImClamp ( new_text_len * 4 , 32 , ImMax ( 256 , new_text_len) ) + 1 ;
4224
edit_state-> TextA . resize ( new_buf_size + 1 ) ;
4225
Buf = edit_state-> TextA . Data ;
4226
BufSize = edit_state-> BufCapacity = new_buf_size;
4227
}
4228
4229
if ( BufTextLen != pos)
4230
memmove ( Buf + pos + new_text_len, Buf + pos, ( size_t ) ( BufTextLen - pos) ) ;
4231
memcpy ( Buf + pos, new_text, ( size_t ) new_text_len * sizeof ( char ) ) ;
4232
Buf[ BufTextLen + new_text_len] = ' \0 ' ;
4233
4234
if ( CursorPos >= pos)
4235
CursorPos += new_text_len;
4236
SelectionStart = SelectionEnd = CursorPos;
4237
BufDirty = true ;
4238
BufTextLen += new_text_len;
4239
}
4240
4241
4242
static bool InputTextFilterCharacter ( ImGuiContext* ctx , unsigned int * p_char , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * user_data , bool input_source_is_clipboard )
4243
{
4244
unsigned int c = * p_char;
4245
4246
4247
bool apply_named_filters = true ;
4248
if ( c < 0x20 )
4249
{
4250
bool pass = false ;
4251
pass |= ( c == ' \n ' ) && ( flags & ImGuiInputTextFlags_Multiline) != 0 ;
4252
pass |= ( c == ' \t ' ) && ( flags & ImGuiInputTextFlags_AllowTabInput) != 0 ;
4253
if ( ! pass)
4254
return false ;
4255
apply_named_filters = false ;
4256
}
4257
4258
if ( input_source_is_clipboard == false )
4259
{
4260
4261
if ( c == 127 )
4262
return false ;
4263
4264
4265
if ( c >= 0xE000 && c <= 0xF8FF )
4266
return false ;
4267
}
4268
4269
4270
if ( c > IM_UNICODE_CODEPOINT_MAX)
4271
return false ;
4272
4273
4274
if ( apply_named_filters && ( flags & ( ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific | ( ImGuiInputTextFlags) ImGuiInputTextFlags_LocalizeDecimalPoint) ) )
4275
{
4276
4277
4278
4279
4280
4281
4282
ImGuiContext& g = * ctx;
4283
const unsigned c_decimal_point = ( unsigned int ) g. PlatformIO . Platform_LocaleDecimalPoint ;
4284
if ( flags & ( ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ( ImGuiInputTextFlags) ImGuiInputTextFlags_LocalizeDecimalPoint) )
4285
if ( c == ' .' || c == ' ,' )
4286
c = c_decimal_point;
4287
4288
4289
4290
4291
if ( flags & ( ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal) )
4292
if ( c >= 0xFF01 && c <= 0xFF5E )
4293
c = c - 0xFF01 + 0x21 ;
4294
4295
4296
if ( flags & ImGuiInputTextFlags_CharsDecimal)
4297
if ( ! ( c >= ' 0' && c <= ' 9' ) && ( c != c_decimal_point) && ( c != ' -' ) && ( c != ' +' ) && ( c != ' *' ) && ( c != ' /' ) )
4298
return false ;
4299
4300
4301
if ( flags & ImGuiInputTextFlags_CharsScientific)
4302
if ( ! ( c >= ' 0' && c <= ' 9' ) && ( c != c_decimal_point) && ( c != ' -' ) && ( c != ' +' ) && ( c != ' *' ) && ( c != ' /' ) && ( c != ' e' ) && ( c != ' E' ) )
4303
return false ;
4304
4305
4306
if ( flags & ImGuiInputTextFlags_CharsHexadecimal)
4307
if ( ! ( c >= ' 0' && c <= ' 9' ) && ! ( c >= ' a' && c <= ' f' ) && ! ( c >= ' A' && c <= ' F' ) )
4308
return false ;
4309
4310
4311
if ( flags & ImGuiInputTextFlags_CharsUppercase)
4312
if ( c >= ' a' && c <= ' z' )
4313
c += ( unsigned int ) ( ' A' - ' a' ) ;
4314
4315
if ( flags & ImGuiInputTextFlags_CharsNoBlank)
4316
if ( ImCharIsBlankW ( c ) )
4317
return false ;
4318
4319
* p_char = c;
4320
}
4321
4322
4323
if ( flags & ImGuiInputTextFlags_CallbackCharFilter)
4324
{
4325
ImGuiContext& g = * GImGui;
4326
ImGuiInputTextCallbackData callback_data;
4327
callback_data. Ctx = & g;
4328
callback_data. EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
4329
callback_data. EventChar = ( ImWchar) c;
4330
callback_data. Flags = flags;
4331
callback_data. UserData = user_data;
4332
if ( callback ( & callback_data) != 0 )
4333
return false ;
4334
* p_char = callback_data. EventChar ;
4335
if ( ! callback_data. EventChar )
4336
return false ;
4337
}
4338
4339
return true ;
4340
}
4341
4342
4343
4344
4345
static void InputTextReconcileUndoStateAfterUserCallback ( ImGuiInputTextState* state , const char * new_buf_a , int new_length_a )
4346
{
4347
const char * old_buf = state-> CallbackTextBackup . Data ;
4348
const int old_length = state-> CallbackTextBackup . Size - 1 ;
4349
4350
const int shorter_length = ImMin ( old_length, new_length_a ) ;
4351
int first_diff;
4352
for ( first_diff = 0 ; first_diff < shorter_length; first_diff+ + )
4353
if ( old_buf[ first_diff] != new_buf_a[ first_diff] )
4354
break ;
4355
if ( first_diff == old_length && first_diff == new_length_a)
4356
return ;
4357
4358
int old_last_diff = old_length - 1 ;
4359
int new_last_diff = new_length_a - 1 ;
4360
for ( ; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff- - , new_last_diff- - )
4361
if ( old_buf[ old_last_diff] != new_buf_a[ new_last_diff] )
4362
break ;
4363
4364
const int insert_len = new_last_diff - first_diff + 1 ;
4365
const int delete_len = old_last_diff - first_diff + 1 ;
4366
if ( insert_len > 0 || delete_len > 0 )
4367
if ( IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo ( & state-> Stb -> undostate , first_diff, delete_len, insert_len) )
4368
for ( int i = 0 ; i < delete_len; i+ + )
4369
p[ i] = old_buf[ first_diff + i] ;
4370
}
4371
4372
4373
4374
4375
4376
void ImGui:: InputTextDeactivateHook ( ImGuiID id )
4377
{
4378
ImGuiContext& g = * GImGui;
4379
ImGuiInputTextState* state = & g. InputTextState ;
4380
if ( id == 0 || state-> ID != id)
4381
return ;
4382
g. InputTextDeactivatedState . ID = state-> ID ;
4383
if ( state-> Flags & ImGuiInputTextFlags_ReadOnly)
4384
{
4385
g. InputTextDeactivatedState . TextA . resize ( 0 ) ;
4386
}
4387
else
4388
{
4389
IM_ASSERT ( state-> TextA . Data != 0 ) ;
4390
g. InputTextDeactivatedState . TextA . resize ( state-> TextLen + 1 ) ;
4391
memcpy ( g. InputTextDeactivatedState . TextA . Data , state-> TextA . Data , state-> TextLen + 1 ) ;
4392
}
4393
}
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
bool ImGui:: InputTextEx ( const char * label , const char * hint , char * buf , int buf_size , const ImVec2& size_arg , ImGuiInputTextFlags flags , ImGuiInputTextCallback callback , void * callback_user_data )
4404
{
4405
ImGuiWindow* window = GetCurrentWindow ( ) ;
4406
if ( window-> SkipItems )
4407
return false ;
4408
4409
IM_ASSERT ( buf != NULL && buf_size >= 0 ) ;
4410
IM_ASSERT ( ! ( ( flags & ImGuiInputTextFlags_CallbackHistory) && ( flags & ImGuiInputTextFlags_Multiline) ) ) ;
4411
IM_ASSERT ( ! ( ( flags & ImGuiInputTextFlags_CallbackCompletion) && ( flags & ImGuiInputTextFlags_AllowTabInput) ) ) ;
4412
4413
ImGuiContext& g = * GImGui;
4414
ImGuiIO& io = g. IO ;
4415
const ImGuiStyle& style = g. Style ;
4416
4417
const bool RENDER_SELECTION_WHEN_INACTIVE = false ;
4418
const bool is_multiline = ( flags & ImGuiInputTextFlags_Multiline) != 0 ;
4419
4420
if ( is_multiline)
4421
BeginGroup ( ) ;
4422
const ImGuiID id = window-> GetID ( label ) ;
4423
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
4424
const ImVec2 frame_size = CalcItemSize ( size_arg, CalcItemWidth ( ) , ( is_multiline ? g. FontSize * 8.0f : label_size. y ) + style. FramePadding . y * 2.0f ) ;
4425
const ImVec2 total_size = ImVec2 ( frame_size. x + ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f ) , frame_size. y ) ;
4426
4427
const ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + frame_size ) ;
4428
const ImRect total_bb ( frame_bb. Min , frame_bb. Min + total_size ) ;
4429
4430
ImGuiWindow* draw_window = window;
4431
ImVec2 inner_size = frame_size;
4432
ImGuiLastItemData item_data_backup;
4433
if ( is_multiline)
4434
{
4435
ImVec2 backup_pos = window-> DC . CursorPos ;
4436
ItemSize ( total_bb, style. FramePadding . y ) ;
4437
if ( ! ItemAdd ( total_bb, id, & frame_bb, ImGuiItemFlags_Inputable ) )
4438
{
4439
EndGroup ( ) ;
4440
return false ;
4441
}
4442
item_data_backup = g. LastItemData ;
4443
window-> DC . CursorPos = backup_pos;
4444
4445
4446
if ( g. NavActivateId == id && ( g. NavActivateFlags & ImGuiActivateFlags_FromTabbing) && ( flags & ImGuiInputTextFlags_AllowTabInput) )
4447
g. NavActivateId = 0 ;
4448
4449
4450
const ImGuiID backup_activate_id = g. NavActivateId ;
4451
if ( g. ActiveId == id)
4452
g. NavActivateId = 0 ;
4453
4454
4455
PushStyleColor ( ImGuiCol_ChildBg, style. Colors [ ImGuiCol_FrameBg] ) ;
4456
PushStyleVar ( ImGuiStyleVar_ChildRounding, style. FrameRounding ) ;
4457
PushStyleVar ( ImGuiStyleVar_ChildBorderSize, style. FrameBorderSize ) ;
4458
PushStyleVar ( ImGuiStyleVar_WindowPadding, ImVec2 ( 0 , 0 ) ) ;
4459
bool child_visible = BeginChildEx ( label, id, frame_bb. GetSize ( ) , ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove ) ;
4460
g. NavActivateId = backup_activate_id;
4461
PopStyleVar ( 3 ) ;
4462
PopStyleColor ( ) ;
4463
if ( ! child_visible)
4464
{
4465
EndChild ( ) ;
4466
EndGroup ( ) ;
4467
return false ;
4468
}
4469
draw_window = g. CurrentWindow ;
4470
draw_window-> DC . NavLayersActiveMaskNext |= ( 1 << draw_window-> DC . NavLayerCurrent ) ;
4471
draw_window-> DC . CursorPos += style. FramePadding ;
4472
inner_size. x -= draw_window-> ScrollbarSizes . x ;
4473
}
4474
else
4475
{
4476
4477
ItemSize ( total_bb, style. FramePadding . y ) ;
4478
if ( ! ( flags & ImGuiInputTextFlags_MergedItem) )
4479
if ( ! ItemAdd ( total_bb, id, & frame_bb, ImGuiItemFlags_Inputable ) )
4480
return false ;
4481
}
4482
4483
4484
bool hovered = ItemHoverable ( frame_bb, id, g. LastItemData . ItemFlags | ImGuiItemFlags_NoNavDisableMouseHover ) ;
4485
if ( hovered)
4486
SetMouseCursor ( ImGuiMouseCursor_TextInput ) ;
4487
if ( hovered && g. NavHighlightItemUnderNav )
4488
hovered = false ;
4489
4490
4491
ImGuiInputTextState* state = GetInputTextState ( id ) ;
4492
4493
if ( g. LastItemData . ItemFlags & ImGuiItemFlags_ReadOnly)
4494
flags |= ImGuiInputTextFlags_ReadOnly;
4495
const bool is_readonly = ( flags & ImGuiInputTextFlags_ReadOnly) != 0 ;
4496
const bool is_password = ( flags & ImGuiInputTextFlags_Password) != 0 ;
4497
const bool is_undoable = ( flags & ImGuiInputTextFlags_NoUndoRedo) == 0 ;
4498
const bool is_resizable = ( flags & ImGuiInputTextFlags_CallbackResize) != 0 ;
4499
if ( is_resizable)
4500
IM_ASSERT ( callback != NULL ) ;
4501
4502
const bool input_requested_by_nav = ( g. ActiveId != id) && ( ( g. NavActivateId == id) && ( ( g. NavActivateFlags & ImGuiActivateFlags_PreferInput) || ( g. NavInputSource == ImGuiInputSource_Keyboard) ) ) ;
4503
4504
const bool user_clicked = hovered && io. MouseClicked [ 0 ] ;
4505
const bool user_scroll_finish = is_multiline && state != NULL && g. ActiveId == 0 && g. ActiveIdPreviousFrame == GetWindowScrollbarID ( draw_window, ImGuiAxis_Y ) ;
4506
const bool user_scroll_active = is_multiline && state != NULL && g. ActiveId == GetWindowScrollbarID ( draw_window, ImGuiAxis_Y ) ;
4507
bool clear_active_id = false ;
4508
bool select_all = false ;
4509
4510
float scroll_y = is_multiline ? draw_window-> Scroll . y : FLT_MAX;
4511
4512
const bool init_reload_from_user_buf = ( state != NULL && state-> ReloadUserBuf ) ;
4513
const bool init_changed_specs = ( state != NULL && state-> Stb -> single_line != ! is_multiline) ;
4514
const bool init_make_active = ( user_clicked || user_scroll_finish || input_requested_by_nav) ;
4515
const bool init_state = ( init_make_active || user_scroll_active) ;
4516
if ( ( init_state && g. ActiveId != id) || init_changed_specs || init_reload_from_user_buf)
4517
{
4518
4519
state = & g. InputTextState ;
4520
state-> CursorAnimReset ( ) ;
4521
state-> ReloadUserBuf = false ;
4522
4523
4524
InputTextDeactivateHook ( state-> ID ) ;
4525
4526
4527
const int buf_len = ( int ) strlen ( buf ) ;
4528
if ( ! init_reload_from_user_buf)
4529
{
4530
4531
state-> TextToRevertTo . resize ( buf_len + 1 ) ;
4532
memcpy ( state-> TextToRevertTo . Data , buf, buf_len + 1 ) ;
4533
}
4534
4535
4536
4537
bool recycle_state = ( state-> ID == id && ! init_changed_specs && ! init_reload_from_user_buf) ;
4538
if ( recycle_state && ( state-> TextLen != buf_len || ( strncmp ( state-> TextA . Data , buf, buf_len ) != 0 ) ) )
4539
recycle_state = false ;
4540
4541
4542
state-> ID = id;
4543
state-> TextA . resize ( buf_size + 1 ) ;
4544
state-> TextLen = ( int ) strlen ( buf ) ;
4545
memcpy ( state-> TextA . Data , buf, state-> TextLen + 1 ) ;
4546
4547
if ( recycle_state)
4548
{
4549
4550
4551
state-> CursorClamp ( ) ;
4552
}
4553
else
4554
{
4555
state-> Scroll = ImVec2 ( 0.0f , 0.0f ) ;
4556
stb_textedit_initialize_state ( state-> Stb , ! is_multiline ) ;
4557
}
4558
4559
if ( init_reload_from_user_buf)
4560
{
4561
state-> Stb -> select_start = state-> ReloadSelectionStart ;
4562
state-> Stb -> cursor = state-> Stb -> select_end = state-> ReloadSelectionEnd ;
4563
state-> CursorClamp ( ) ;
4564
}
4565
else if ( ! is_multiline)
4566
{
4567
if ( flags & ImGuiInputTextFlags_AutoSelectAll)
4568
select_all = true ;
4569
if ( input_requested_by_nav && ( ! recycle_state || ! ( g. NavActivateFlags & ImGuiActivateFlags_TryToPreserveState) ) )
4570
select_all = true ;
4571
if ( user_clicked && io. KeyCtrl )
4572
select_all = true ;
4573
}
4574
4575
if ( flags & ImGuiInputTextFlags_AlwaysOverwrite)
4576
state-> Stb -> insert_mode = 1 ;
4577
}
4578
4579
const bool is_osx = io. ConfigMacOSXBehaviors ;
4580
if ( g. ActiveId != id && init_make_active)
4581
{
4582
IM_ASSERT ( state && state-> ID == id ) ;
4583
SetActiveID ( id, window ) ;
4584
SetFocusID ( id, window ) ;
4585
FocusWindow ( window ) ;
4586
}
4587
if ( g. ActiveId == id)
4588
{
4589
4590
4591
const ImGuiKey always_owned_keys[ ] = { ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_Enter, ImGuiKey_KeypadEnter, ImGuiKey_Delete, ImGuiKey_Backspace, ImGuiKey_Home, ImGuiKey_End } ;
4592
for ( ImGuiKey key : always_owned_keys)
4593
SetKeyOwner ( key, id ) ;
4594
if ( user_clicked)
4595
SetKeyOwner ( ImGuiKey_MouseLeft, id ) ;
4596
g. ActiveIdUsingNavDirMask |= ( 1 << ImGuiDir_Left) | ( 1 << ImGuiDir_Right) ;
4597
if ( is_multiline || ( flags & ImGuiInputTextFlags_CallbackHistory) )
4598
{
4599
g. ActiveIdUsingNavDirMask |= ( 1 << ImGuiDir_Up) | ( 1 << ImGuiDir_Down) ;
4600
SetKeyOwner ( ImGuiKey_UpArrow, id ) ;
4601
SetKeyOwner ( ImGuiKey_DownArrow, id ) ;
4602
}
4603
if ( is_multiline)
4604
{
4605
SetKeyOwner ( ImGuiKey_PageUp, id ) ;
4606
SetKeyOwner ( ImGuiKey_PageDown, id ) ;
4607
}
4608
4609
if ( is_osx)
4610
SetKeyOwner ( ImGuiMod_Alt, id ) ;
4611
4612
4613
if ( is_multiline && state != NULL )
4614
state-> Scroll . y = draw_window-> Scroll . y ;
4615
}
4616
4617
4618
if ( g. ActiveId == id && state == NULL )
4619
ClearActiveID ( ) ;
4620
4621
4622
if ( g. ActiveId == id && io. MouseClicked [ 0 ] && ! init_state && ! init_make_active)
4623
clear_active_id = true ;
4624
4625
4626
bool render_cursor = ( g. ActiveId == id) || ( state && user_scroll_active) ;
4627
bool render_selection = state && ( state-> HasSelection ( ) || select_all) && ( RENDER_SELECTION_WHEN_INACTIVE || render_cursor) ;
4628
bool value_changed = false ;
4629
bool validated = false ;
4630
4631
4632
const bool buf_display_from_state = ( render_cursor || render_selection || g. ActiveId == id) && ! is_readonly && state;
4633
const bool is_displaying_hint = ( hint != NULL && ( buf_display_from_state ? state-> TextA . Data : buf) [ 0 ] == 0 ) ;
4634
4635
4636
if ( is_password && ! is_displaying_hint)
4637
{
4638
const ImFontGlyph* glyph = g. Font -> FindGlyph ( ' *' ) ;
4639
ImFont* password_font = & g. InputTextPasswordFont ;
4640
password_font-> FontSize = g. Font -> FontSize ;
4641
password_font-> Scale = g. Font -> Scale ;
4642
password_font-> Ascent = g. Font -> Ascent ;
4643
password_font-> Descent = g. Font -> Descent ;
4644
password_font-> ContainerAtlas = g. Font -> ContainerAtlas ;
4645
password_font-> FallbackGlyph = glyph;
4646
password_font-> FallbackAdvanceX = glyph-> AdvanceX ;
4647
IM_ASSERT ( password_font-> Glyphs . empty ( ) && password_font-> IndexAdvanceX . empty ( ) && password_font-> IndexLookup . empty ( ) ) ;
4648
PushFont ( password_font ) ;
4649
}
4650
4651
4652
if ( g. ActiveId == id)
4653
{
4654
IM_ASSERT ( state != NULL ) ;
4655
state-> Edited = false ;
4656
state-> BufCapacity = buf_size;
4657
state-> Flags = flags;
4658
4659
4660
4661
g. ActiveIdAllowOverlap = ! io. MouseDown [ 0 ] ;
4662
4663
4664
const float mouse_x = ( io. MousePos . x - frame_bb. Min . x - style. FramePadding . x ) + state-> Scroll . x ;
4665
const float mouse_y = ( is_multiline ? ( io. MousePos . y - draw_window-> DC . CursorPos . y ) : ( g. FontSize * 0.5f ) ) ;
4666
4667
if ( select_all)
4668
{
4669
state-> SelectAll ( ) ;
4670
state-> SelectedAllMouseLock = true ;
4671
}
4672
else if ( hovered && io. MouseClickedCount [ 0 ] >= 2 && ! io. KeyShift )
4673
{
4674
stb_textedit_click ( state, state-> Stb , mouse_x, mouse_y ) ;
4675
const int multiclick_count = ( io. MouseClickedCount [ 0 ] - 2 ) ;
4676
if ( ( multiclick_count % 2 ) == 0 )
4677
{
4678
4679
4680
4681
const bool is_bol = ( state-> Stb -> cursor == 0 ) || ImStb:: STB_TEXTEDIT_GETCHAR ( state, state-> Stb -> cursor - 1 ) == ' \n ' ;
4682
if ( STB_TEXT_HAS_SELECTION ( state-> Stb ) || ! is_bol)
4683
state-> OnKeyPressed ( STB_TEXTEDIT_K_WORDLEFT ) ;
4684
4685
if ( ! STB_TEXT_HAS_SELECTION ( state-> Stb ) )
4686
ImStb:: stb_textedit_prep_selection_at_cursor ( state-> Stb ) ;
4687
state-> Stb -> cursor = ImStb:: STB_TEXTEDIT_MOVEWORDRIGHT_MAC ( state, state-> Stb -> cursor ) ;
4688
state-> Stb -> select_end = state-> Stb -> cursor ;
4689
ImStb:: stb_textedit_clamp ( state, state-> Stb ) ;
4690
}
4691
else
4692
{
4693
4694
const bool is_eol = ImStb:: STB_TEXTEDIT_GETCHAR ( state, state-> Stb -> cursor ) == ' \n ' ;
4695
state-> OnKeyPressed ( STB_TEXTEDIT_K_LINESTART ) ;
4696
state-> OnKeyPressed ( STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT ) ;
4697
state-> OnKeyPressed ( STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT ) ;
4698
if ( ! is_eol && is_multiline)
4699
{
4700
ImSwap ( state-> Stb -> select_start , state-> Stb -> select_end ) ;
4701
state-> Stb -> cursor = state-> Stb -> select_end ;
4702
}
4703
state-> CursorFollow = false ;
4704
}
4705
state-> CursorAnimReset ( ) ;
4706
}
4707
else if ( io. MouseClicked [ 0 ] && ! state-> SelectedAllMouseLock )
4708
{
4709
if ( hovered)
4710
{
4711
if ( io. KeyShift )
4712
stb_textedit_drag ( state, state-> Stb , mouse_x, mouse_y ) ;
4713
else
4714
stb_textedit_click ( state, state-> Stb , mouse_x, mouse_y ) ;
4715
state-> CursorAnimReset ( ) ;
4716
}
4717
}
4718
else if ( io. MouseDown [ 0 ] && ! state-> SelectedAllMouseLock && ( io. MouseDelta . x != 0.0f || io. MouseDelta . y != 0.0f ) )
4719
{
4720
stb_textedit_drag ( state, state-> Stb , mouse_x, mouse_y ) ;
4721
state-> CursorAnimReset ( ) ;
4722
state-> CursorFollow = true ;
4723
}
4724
if ( state-> SelectedAllMouseLock && ! io. MouseDown [ 0 ] )
4725
state-> SelectedAllMouseLock = false ;
4726
4727
4728
4729
if ( ( flags & ImGuiInputTextFlags_AllowTabInput) && ! is_readonly)
4730
{
4731
if ( Shortcut ( ImGuiKey_Tab, ImGuiInputFlags_Repeat, id ) )
4732
{
4733
unsigned int c = ' \t ' ;
4734
if ( InputTextFilterCharacter ( & g, & c, flags, callback, callback_user_data) )
4735
state-> OnCharPressed ( c ) ;
4736
}
4737
4738
4739
4740
4741
4742
4743
}
4744
4745
4746
4747
const bool ignore_char_inputs = ( io. KeyCtrl && ! io. KeyAlt ) || ( is_osx && io. KeyCtrl ) ;
4748
if ( io. InputQueueCharacters . Size > 0 )
4749
{
4750
if ( ! ignore_char_inputs && ! is_readonly && ! input_requested_by_nav)
4751
for ( int n = 0 ; n < io. InputQueueCharacters . Size ; n+ + )
4752
{
4753
4754
unsigned int c = ( unsigned int ) io. InputQueueCharacters [ n] ;
4755
if ( c == ' \t ' )
4756
continue ;
4757
if ( InputTextFilterCharacter ( & g, & c, flags, callback, callback_user_data) )
4758
state-> OnCharPressed ( c ) ;
4759
}
4760
4761
4762
io. InputQueueCharacters . resize ( 0 ) ;
4763
}
4764
}
4765
4766
4767
bool revert_edit = false ;
4768
if ( g. ActiveId == id && ! g. ActiveIdIsJustActivated && ! clear_active_id)
4769
{
4770
IM_ASSERT ( state != NULL ) ;
4771
4772
const int row_count_per_page = ImMax ( ( int ) ( ( inner_size. y - style. FramePadding . y ) / g. FontSize ) , 1 ) ;
4773
state-> Stb -> row_count_per_page = row_count_per_page;
4774
4775
const int k_mask = ( io. KeyShift ? STB_TEXTEDIT_K_SHIFT : 0 ) ;
4776
const bool is_wordmove_key_down = is_osx ? io. KeyAlt : io. KeyCtrl ;
4777
const bool is_startend_key_down = is_osx && io. KeyCtrl && ! io. KeySuper && ! io. KeyAlt ;
4778
4779
4780
4781
const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;
4782
const bool is_cut = ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id ) || Shortcut ( ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id ) ) && ! is_readonly && ! is_password && ( ! is_multiline || state-> HasSelection ( ) ) ;
4783
const bool is_copy = ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_C, 0 , id ) || Shortcut ( ImGuiMod_Ctrl | ImGuiKey_Insert, 0 , id ) ) && ! is_password && ( ! is_multiline || state-> HasSelection ( ) ) ;
4784
const bool is_paste = ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id ) || Shortcut ( ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id ) ) && ! is_readonly;
4785
const bool is_undo = ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id ) ) && ! is_readonly && is_undoable;
4786
const bool is_redo = ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id ) || ( is_osx && Shortcut ( ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id ) ) ) && ! is_readonly && is_undoable;
4787
const bool is_select_all = Shortcut ( ImGuiMod_Ctrl | ImGuiKey_A, 0 , id ) ;
4788
4789
4790
const bool nav_gamepad_active = ( io. ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && ( io. BackendFlags & ImGuiBackendFlags_HasGamepad) != 0 ;
4791
const bool is_enter_pressed = IsKeyPressed ( ImGuiKey_Enter, true ) || IsKeyPressed ( ImGuiKey_KeypadEnter, true ) ;
4792
const bool is_gamepad_validate = nav_gamepad_active && ( IsKeyPressed ( ImGuiKey_NavGamepadActivate, false ) || IsKeyPressed ( ImGuiKey_NavGamepadInput, false ) ) ;
4793
const bool is_cancel = Shortcut ( ImGuiKey_Escape, f_repeat, id ) || ( nav_gamepad_active && Shortcut ( ImGuiKey_NavGamepadCancel, f_repeat, id ) ) ;
4794
4795
4796
4797
if ( IsKeyPressed ( ImGuiKey_LeftArrow ) ) { state-> OnKeyPressed ( ( is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask) ; }
4798
else if ( IsKeyPressed ( ImGuiKey_RightArrow ) ) { state-> OnKeyPressed ( ( is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask) ; }
4799
else if ( IsKeyPressed ( ImGuiKey_UpArrow ) && is_multiline) { if ( io. KeyCtrl ) SetScrollY ( draw_window, ImMax ( draw_window-> Scroll . y - g. FontSize , 0.0f ) ) ; else state-> OnKeyPressed ( ( is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask) ; }
4800
else if ( IsKeyPressed ( ImGuiKey_DownArrow ) && is_multiline) { if ( io. KeyCtrl ) SetScrollY ( draw_window, ImMin ( draw_window-> Scroll . y + g. FontSize , GetScrollMaxY ( ) ) ) ; else state-> OnKeyPressed ( ( is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask) ; }
4801
else if ( IsKeyPressed ( ImGuiKey_PageUp ) && is_multiline) { state-> OnKeyPressed ( STB_TEXTEDIT_K_PGUP | k_mask ) ; scroll_y -= row_count_per_page * g. FontSize ; }
4802
else if ( IsKeyPressed ( ImGuiKey_PageDown ) && is_multiline) { state-> OnKeyPressed ( STB_TEXTEDIT_K_PGDOWN | k_mask ) ; scroll_y += row_count_per_page * g. FontSize ; }
4803
else if ( IsKeyPressed ( ImGuiKey_Home ) ) { state-> OnKeyPressed ( io. KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask ) ; }
4804
else if ( IsKeyPressed ( ImGuiKey_End ) ) { state-> OnKeyPressed ( io. KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask ) ; }
4805
else if ( IsKeyPressed ( ImGuiKey_Delete ) && ! is_readonly && ! is_cut)
4806
{
4807
if ( ! state-> HasSelection ( ) )
4808
{
4809
4810
if ( is_wordmove_key_down)
4811
state-> OnKeyPressed ( STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT ) ;
4812
}
4813
state-> OnKeyPressed ( STB_TEXTEDIT_K_DELETE | k_mask ) ;
4814
}
4815
else if ( IsKeyPressed ( ImGuiKey_Backspace ) && ! is_readonly)
4816
{
4817
if ( ! state-> HasSelection ( ) )
4818
{
4819
if ( is_wordmove_key_down)
4820
state-> OnKeyPressed ( STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT ) ;
4821
else if ( is_osx && io. KeyCtrl && ! io. KeyAlt && ! io. KeySuper )
4822
state-> OnKeyPressed ( STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT ) ;
4823
}
4824
state-> OnKeyPressed ( STB_TEXTEDIT_K_BACKSPACE | k_mask ) ;
4825
}
4826
else if ( is_enter_pressed || is_gamepad_validate)
4827
{
4828
4829
bool ctrl_enter_for_new_line = ( flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0 ;
4830
if ( ! is_multiline || is_gamepad_validate || ( ctrl_enter_for_new_line && ! io. KeyCtrl ) || ( ! ctrl_enter_for_new_line && io. KeyCtrl ) )
4831
{
4832
validated = true ;
4833
if ( io. ConfigInputTextEnterKeepActive && ! is_multiline)
4834
state-> SelectAll ( ) ;
4835
else
4836
clear_active_id = true ;
4837
}
4838
else if ( ! is_readonly)
4839
{
4840
unsigned int c = ' \n ' ;
4841
if ( InputTextFilterCharacter ( & g, & c, flags, callback, callback_user_data) )
4842
state-> OnCharPressed ( c ) ;
4843
}
4844
}
4845
else if ( is_cancel)
4846
{
4847
if ( flags & ImGuiInputTextFlags_EscapeClearsAll)
4848
{
4849
if ( buf[ 0 ] != 0 )
4850
{
4851
revert_edit = true ;
4852
}
4853
else
4854
{
4855
render_cursor = render_selection = false ;
4856
clear_active_id = true ;
4857
}
4858
}
4859
else
4860
{
4861
clear_active_id = revert_edit = true ;
4862
render_cursor = render_selection = false ;
4863
}
4864
}
4865
else if ( is_undo || is_redo)
4866
{
4867
state-> OnKeyPressed ( is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO ) ;
4868
state-> ClearSelection ( ) ;
4869
}
4870
else if ( is_select_all)
4871
{
4872
state-> SelectAll ( ) ;
4873
state-> CursorFollow = true ;
4874
}
4875
else if ( is_cut || is_copy)
4876
{
4877
4878
if ( g. PlatformIO . Platform_SetClipboardTextFn != NULL )
4879
{
4880
const int ib = state-> HasSelection ( ) ? ImMin ( state-> Stb -> select_start , state-> Stb -> select_end ) : 0 ;
4881
const int ie = state-> HasSelection ( ) ? ImMax ( state-> Stb -> select_start , state-> Stb -> select_end ) : state-> TextLen ;
4882
4883
char backup = state-> TextA . Data [ ie] ;
4884
state-> TextA . Data [ ie] = 0 ;
4885
SetClipboardText ( state-> TextA . Data + ib ) ;
4886
state-> TextA . Data [ ie] = backup;
4887
}
4888
if ( is_cut)
4889
{
4890
if ( ! state-> HasSelection ( ) )
4891
state-> SelectAll ( ) ;
4892
state-> CursorFollow = true ;
4893
stb_textedit_cut ( state, state-> Stb ) ;
4894
}
4895
}
4896
else if ( is_paste)
4897
{
4898
if ( const char * clipboard = GetClipboardText ( ) )
4899
{
4900
4901
const int clipboard_len = ( int ) strlen ( clipboard ) ;
4902
char * clipboard_filtered = ( char * ) IM_ALLOC ( clipboard_len + 1 ) ;
4903
int clipboard_filtered_len = 0 ;
4904
for ( const char * s = clipboard; * s != 0 ; )
4905
{
4906
unsigned int c;
4907
int len = ImTextCharFromUtf8 ( & c, s, NULL ) ;
4908
s += len;
4909
if ( ! InputTextFilterCharacter ( & g, & c, flags, callback, callback_user_data, true ) )
4910
continue ;
4911
memcpy ( clipboard_filtered + clipboard_filtered_len, s - len, len ) ;
4912
clipboard_filtered_len += len;
4913
}
4914
clipboard_filtered[ clipboard_filtered_len] = 0 ;
4915
if ( clipboard_filtered_len > 0 )
4916
{
4917
stb_textedit_paste ( state, state-> Stb , clipboard_filtered, clipboard_filtered_len ) ;
4918
state-> CursorFollow = true ;
4919
}
4920
MemFree ( clipboard_filtered ) ;
4921
}
4922
}
4923
4924
4925
render_selection |= state-> HasSelection ( ) && ( RENDER_SELECTION_WHEN_INACTIVE || render_cursor) ;
4926
}
4927
4928
4929
const char * apply_new_text = NULL ;
4930
int apply_new_text_length = 0 ;
4931
if ( g. ActiveId == id)
4932
{
4933
IM_ASSERT ( state != NULL ) ;
4934
if ( revert_edit && ! is_readonly)
4935
{
4936
if ( flags & ImGuiInputTextFlags_EscapeClearsAll)
4937
{
4938
4939
IM_ASSERT ( buf[ 0 ] != 0 ) ;
4940
apply_new_text = " " ;
4941
apply_new_text_length = 0 ;
4942
value_changed = true ;
4943
IMSTB_TEXTEDIT_CHARTYPE empty_string;
4944
stb_textedit_replace ( state, state-> Stb , & empty_string, 0 ) ;
4945
}
4946
else if ( strcmp ( buf, state-> TextToRevertTo . Data ) != 0 )
4947
{
4948
apply_new_text = state-> TextToRevertTo . Data ;
4949
apply_new_text_length = state-> TextToRevertTo . Size - 1 ;
4950
4951
4952
4953
value_changed = true ;
4954
stb_textedit_replace ( state, state-> Stb , state-> TextToRevertTo . Data , state-> TextToRevertTo . Size - 1 ) ;
4955
}
4956
}
4957
4958
4959
4960
4961
4962
4963
4964
const bool apply_edit_back_to_user_buffer = ! revert_edit || ( validated && ( flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0 ) ;
4965
if ( apply_edit_back_to_user_buffer)
4966
{
4967
4968
4969
4970
4971
4972
4973
if ( ( flags & ( ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways) ) != 0 )
4974
{
4975
IM_ASSERT ( callback != NULL ) ;
4976
4977
4978
ImGuiInputTextFlags event_flag = 0 ;
4979
ImGuiKey event_key = ImGuiKey_None;
4980
if ( ( flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut ( ImGuiKey_Tab, 0 , id ) )
4981
{
4982
event_flag = ImGuiInputTextFlags_CallbackCompletion;
4983
event_key = ImGuiKey_Tab;
4984
}
4985
else if ( ( flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed ( ImGuiKey_UpArrow ) )
4986
{
4987
event_flag = ImGuiInputTextFlags_CallbackHistory;
4988
event_key = ImGuiKey_UpArrow;
4989
}
4990
else if ( ( flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed ( ImGuiKey_DownArrow ) )
4991
{
4992
event_flag = ImGuiInputTextFlags_CallbackHistory;
4993
event_key = ImGuiKey_DownArrow;
4994
}
4995
else if ( ( flags & ImGuiInputTextFlags_CallbackEdit) && state-> Edited )
4996
{
4997
event_flag = ImGuiInputTextFlags_CallbackEdit;
4998
}
4999
else if ( flags & ImGuiInputTextFlags_CallbackAlways)
5000
{
5001
event_flag = ImGuiInputTextFlags_CallbackAlways;
5002
}
5003
5004
if ( event_flag)
5005
{
5006
ImGuiInputTextCallbackData callback_data;
5007
callback_data. Ctx = & g;
5008
callback_data. EventFlag = event_flag;
5009
callback_data. Flags = flags;
5010
callback_data. UserData = callback_user_data;
5011
5012
5013
state-> CallbackTextBackup . resize ( state-> TextLen + 1 ) ;
5014
memcpy ( state-> CallbackTextBackup . Data , state-> TextA . Data , state-> TextLen + 1 ) ;
5015
5016
char * callback_buf = is_readonly ? buf : state-> TextA . Data ;
5017
callback_data. EventKey = event_key;
5018
callback_data. Buf = callback_buf;
5019
callback_data. BufTextLen = state-> TextLen ;
5020
callback_data. BufSize = state-> BufCapacity ;
5021
callback_data. BufDirty = false ;
5022
5023
const int utf8_cursor_pos = callback_data. CursorPos = state-> Stb -> cursor ;
5024
const int utf8_selection_start = callback_data. SelectionStart = state-> Stb -> select_start ;
5025
const int utf8_selection_end = callback_data. SelectionEnd = state-> Stb -> select_end ;
5026
5027
5028
callback ( & callback_data) ;
5029
5030
5031
callback_buf = is_readonly ? buf : state-> TextA . Data ;
5032
IM_ASSERT ( callback_data. Buf == callback_buf ) ;
5033
IM_ASSERT ( callback_data. BufSize == state-> BufCapacity ) ;
5034
IM_ASSERT ( callback_data. Flags == flags ) ;
5035
const bool buf_dirty = callback_data. BufDirty ;
5036
if ( callback_data. CursorPos != utf8_cursor_pos || buf_dirty) { state-> Stb -> cursor = callback_data. CursorPos ; state-> CursorFollow = true ; }
5037
if ( callback_data. SelectionStart != utf8_selection_start || buf_dirty) { state-> Stb -> select_start = ( callback_data. SelectionStart == callback_data. CursorPos ) ? state-> Stb -> cursor : callback_data. SelectionStart ; }
5038
if ( callback_data. SelectionEnd != utf8_selection_end || buf_dirty) { state-> Stb -> select_end = ( callback_data. SelectionEnd == callback_data. SelectionStart ) ? state-> Stb -> select_start : callback_data. SelectionEnd ; }
5039
if ( buf_dirty)
5040
{
5041
5042
IM_ASSERT ( callback_data. BufTextLen == ( int ) strlen ( callback_data. Buf ) ) ;
5043
InputTextReconcileUndoStateAfterUserCallback ( state, callback_data. Buf , callback_data. BufTextLen ) ;
5044
state-> TextLen = callback_data. BufTextLen ;
5045
state-> CursorAnimReset ( ) ;
5046
}
5047
}
5048
}
5049
5050
5051
if ( ! is_readonly && strcmp ( state-> TextA . Data , buf ) != 0 )
5052
{
5053
apply_new_text = state-> TextA . Data ;
5054
apply_new_text_length = state-> TextLen ;
5055
value_changed = true ;
5056
}
5057
}
5058
}
5059
5060
5061
if ( g. InputTextDeactivatedState . ID == id)
5062
{
5063
if ( g. ActiveId != id && IsItemDeactivatedAfterEdit ( ) && ! is_readonly && strcmp ( g. InputTextDeactivatedState . TextA . Data , buf ) != 0 )
5064
{
5065
apply_new_text = g. InputTextDeactivatedState . TextA . Data ;
5066
apply_new_text_length = g. InputTextDeactivatedState . TextA . Size - 1 ;
5067
value_changed = true ;
5068
5069
}
5070
g. InputTextDeactivatedState . ID = 0 ;
5071
}
5072
5073
5074
if ( apply_new_text != NULL )
5075
{
5076
5077
5078
5079
IM_ASSERT ( apply_new_text_length >= 0 ) ;
5080
if ( is_resizable)
5081
{
5082
ImGuiInputTextCallbackData callback_data;
5083
callback_data. Ctx = & g;
5084
callback_data. EventFlag = ImGuiInputTextFlags_CallbackResize;
5085
callback_data. Flags = flags;
5086
callback_data. Buf = buf;
5087
callback_data. BufTextLen = apply_new_text_length;
5088
callback_data. BufSize = ImMax ( buf_size, apply_new_text_length + 1 ) ;
5089
callback_data. UserData = callback_user_data;
5090
callback ( & callback_data) ;
5091
buf = callback_data. Buf ;
5092
buf_size = callback_data. BufSize ;
5093
apply_new_text_length = ImMin ( callback_data. BufTextLen , buf_size - 1 ) ;
5094
IM_ASSERT ( apply_new_text_length <= buf_size ) ;
5095
}
5096
5097
5098
5099
ImStrncpy ( buf, apply_new_text, ImMin ( apply_new_text_length + 1 , buf_size ) ) ;
5100
}
5101
5102
5103
5104
if ( g. ActiveId == id && clear_active_id)
5105
ClearActiveID ( ) ;
5106
else if ( g. ActiveId == id)
5107
g. WantTextInputNextFrame = 1 ;
5108
5109
5110
if ( ! is_multiline)
5111
{
5112
RenderNavCursor ( frame_bb, id ) ;
5113
RenderFrame ( frame_bb. Min , frame_bb. Max , GetColorU32 ( ImGuiCol_FrameBg ) , true , style. FrameRounding ) ;
5114
}
5115
5116
const ImVec4 clip_rect ( frame_bb. Min . x , frame_bb. Min . y , frame_bb. Min . x + inner_size. x , frame_bb. Min . y + inner_size. y ) ;
5117
ImVec2 draw_pos = is_multiline ? draw_window-> DC . CursorPos : frame_bb. Min + style. FramePadding ;
5118
ImVec2 text_size ( 0.0f , 0.0f ) ;
5119
5120
5121
5122
5123
const int buf_display_max_length = 2 * 1024 * 1024 ;
5124
const char * buf_display = buf_display_from_state ? state-> TextA . Data : buf;
5125
const char * buf_display_end = NULL ;
5126
if ( is_displaying_hint)
5127
{
5128
buf_display = hint;
5129
buf_display_end = hint + strlen ( hint ) ;
5130
}
5131
5132
5133
5134
if ( render_cursor || render_selection)
5135
{
5136
IM_ASSERT ( state != NULL ) ;
5137
if ( ! is_displaying_hint)
5138
buf_display_end = buf_display + state-> TextLen ;
5139
5140
5141
5142
5143
5144
5145
5146
5147
const char * text_begin = state-> TextA . Data ;
5148
const char * text_end = text_begin + state-> TextLen ;
5149
ImVec2 cursor_offset, select_start_offset;
5150
5151
{
5152
5153
int cursor_line_no = render_cursor ? - 1 : - 1000 ;
5154
int selmin_line_no = render_selection ? - 1 : - 1000 ;
5155
const char * cursor_ptr = render_cursor ? text_begin + state-> Stb -> cursor : NULL ;
5156
const char * selmin_ptr = render_selection ? text_begin + ImMin ( state-> Stb -> select_start , state-> Stb -> select_end ) : NULL ;
5157
5158
5159
int line_count = 1 ;
5160
if ( is_multiline)
5161
{
5162
for ( const char * s = text_begin; ( s = ( const char * ) memchr ( s, ' \n ' , ( size_t ) ( text_end - s) ) ) != NULL ; s+ + )
5163
{
5164
if ( cursor_line_no == - 1 && s >= cursor_ptr) { cursor_line_no = line_count; }
5165
if ( selmin_line_no == - 1 && s >= selmin_ptr) { selmin_line_no = line_count; }
5166
line_count+ + ;
5167
}
5168
}
5169
if ( cursor_line_no == - 1 )
5170
cursor_line_no = line_count;
5171
if ( selmin_line_no == - 1 )
5172
selmin_line_no = line_count;
5173
5174
5175
cursor_offset. x = InputTextCalcTextSize ( & g, ImStrbol ( cursor_ptr, text_begin ) , cursor_ptr) . x ;
5176
cursor_offset. y = cursor_line_no * g. FontSize ;
5177
if ( selmin_line_no >= 0 )
5178
{
5179
select_start_offset. x = InputTextCalcTextSize ( & g, ImStrbol ( selmin_ptr, text_begin ) , selmin_ptr) . x ;
5180
select_start_offset. y = selmin_line_no * g. FontSize ;
5181
}
5182
5183
5184
if ( is_multiline)
5185
text_size = ImVec2 ( inner_size. x , line_count * g. FontSize ) ;
5186
}
5187
5188
5189
if ( render_cursor && state-> CursorFollow )
5190
{
5191
5192
if ( ! ( flags & ImGuiInputTextFlags_NoHorizontalScroll) )
5193
{
5194
const float scroll_increment_x = inner_size. x * 0.25f ;
5195
const float visible_width = inner_size. x - style. FramePadding . x ;
5196
if ( cursor_offset. x < state-> Scroll . x )
5197
state-> Scroll . x = IM_TRUNC ( ImMax ( 0.0f , cursor_offset. x - scroll_increment_x) ) ;
5198
else if ( cursor_offset. x - visible_width >= state-> Scroll . x )
5199
state-> Scroll . x = IM_TRUNC ( cursor_offset. x - visible_width + scroll_increment_x ) ;
5200
}
5201
else
5202
{
5203
state-> Scroll . y = 0.0f ;
5204
}
5205
5206
5207
if ( is_multiline)
5208
{
5209
5210
if ( cursor_offset. y - g. FontSize < scroll_y)
5211
scroll_y = ImMax ( 0.0f , cursor_offset. y - g. FontSize ) ;
5212
else if ( cursor_offset. y - ( inner_size. y - style. FramePadding . y * 2.0f ) >= scroll_y)
5213
scroll_y = cursor_offset. y - inner_size. y + style. FramePadding . y * 2.0f ;
5214
const float scroll_max_y = ImMax ( ( text_size. y + style. FramePadding . y * 2.0f ) - inner_size. y , 0.0f ) ;
5215
scroll_y = ImClamp ( scroll_y, 0.0f , scroll_max_y ) ;
5216
draw_pos. y += ( draw_window-> Scroll . y - scroll_y) ;
5217
draw_window-> Scroll . y = scroll_y;
5218
}
5219
5220
state-> CursorFollow = false ;
5221
}
5222
5223
5224
const ImVec2 draw_scroll = ImVec2 ( state-> Scroll . x , 0.0f ) ;
5225
if ( render_selection)
5226
{
5227
const char * text_selected_begin = text_begin + ImMin ( state-> Stb -> select_start , state-> Stb -> select_end ) ;
5228
const char * text_selected_end = text_begin + ImMax ( state-> Stb -> select_start , state-> Stb -> select_end ) ;
5229
5230
ImU32 bg_color = GetColorU32 ( ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f ) ;
5231
float bg_offy_up = is_multiline ? 0.0f : - 1.0f ;
5232
float bg_offy_dn = is_multiline ? 0.0f : 2.0f ;
5233
ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
5234
for ( const char * p = text_selected_begin; p < text_selected_end; )
5235
{
5236
if ( rect_pos. y > clip_rect. w + g. FontSize )
5237
break ;
5238
if ( rect_pos. y < clip_rect. y )
5239
{
5240
p = ( const char * ) memchr ( ( void * ) p, ' \n ' , text_selected_end - p) ;
5241
p = p ? p + 1 : text_selected_end;
5242
}
5243
else
5244
{
5245
ImVec2 rect_size = InputTextCalcTextSize ( & g, p, text_selected_end, & p, NULL , true ) ;
5246
if ( rect_size. x <= 0.0f ) rect_size. x = IM_TRUNC ( g. Font -> GetCharAdvance ( ( ImWchar) ' ' ) * 0.50f ) ;
5247
ImRect rect ( rect_pos + ImVec2 ( 0.0f , bg_offy_up - g. FontSize ) , rect_pos + ImVec2 ( rect_size. x , bg_offy_dn ) ) ;
5248
rect. ClipWith ( clip_rect ) ;
5249
if ( rect. Overlaps ( clip_rect ) )
5250
draw_window-> DrawList -> AddRectFilled ( rect. Min , rect. Max , bg_color ) ;
5251
rect_pos. x = draw_pos. x - draw_scroll. x ;
5252
}
5253
rect_pos. y += g. FontSize ;
5254
}
5255
}
5256
5257
5258
5259
if ( is_multiline || ( buf_display_end - buf_display) < buf_display_max_length)
5260
{
5261
ImU32 col = GetColorU32 ( is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text ) ;
5262
draw_window-> DrawList -> AddText ( g. Font , g. FontSize , draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f , is_multiline ? NULL : & clip_rect ) ;
5263
}
5264
5265
5266
if ( render_cursor)
5267
{
5268
state-> CursorAnim += io. DeltaTime ;
5269
bool cursor_is_visible = ( ! g. IO . ConfigInputTextCursorBlink ) || ( state-> CursorAnim <= 0.0f ) || ImFmod ( state-> CursorAnim , 1.20f ) <= 0.80f ;
5270
ImVec2 cursor_screen_pos = ImTrunc ( draw_pos + cursor_offset - draw_scroll ) ;
5271
ImRect cursor_screen_rect ( cursor_screen_pos. x , cursor_screen_pos. y - g. FontSize + 0.5f , cursor_screen_pos. x + 1.0f , cursor_screen_pos. y - 1.5f ) ;
5272
if ( cursor_is_visible && cursor_screen_rect. Overlaps ( clip_rect ) )
5273
draw_window-> DrawList -> AddLine ( cursor_screen_rect. Min , cursor_screen_rect. GetBL ( ) , GetColorU32 ( ImGuiCol_Text ) ) ;
5274
5275
5276
if ( ! is_readonly)
5277
{
5278
g. PlatformImeData . WantVisible = true ;
5279
g. PlatformImeData . InputPos = ImVec2 ( cursor_screen_pos. x - 1.0f , cursor_screen_pos. y - g. FontSize ) ;
5280
g. PlatformImeData . InputLineHeight = g. FontSize ;
5281
g. PlatformImeViewport = window-> Viewport -> ID ;
5282
}
5283
}
5284
}
5285
else
5286
{
5287
5288
if ( is_multiline)
5289
text_size = ImVec2 ( inner_size. x , InputTextCalcTextLenAndLineCount ( buf_display, & buf_display_end ) * g. FontSize ) ;
5290
else if ( ! is_displaying_hint && g. ActiveId == id)
5291
buf_display_end = buf_display + state-> TextLen ;
5292
else if ( ! is_displaying_hint)
5293
buf_display_end = buf_display + strlen ( buf_display ) ;
5294
5295
if ( is_multiline || ( buf_display_end - buf_display) < buf_display_max_length)
5296
{
5297
ImU32 col = GetColorU32 ( is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text ) ;
5298
draw_window-> DrawList -> AddText ( g. Font , g. FontSize , draw_pos, col, buf_display, buf_display_end, 0.0f , is_multiline ? NULL : & clip_rect ) ;
5299
}
5300
}
5301
5302
if ( is_password && ! is_displaying_hint)
5303
PopFont ( ) ;
5304
5305
if ( is_multiline)
5306
{
5307
5308
Dummy ( ImVec2 ( text_size. x , text_size. y + style. FramePadding . y ) ) ;
5309
g. NextItemData . ItemFlags |= ( ImGuiItemFlags) ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;
5310
EndChild ( ) ;
5311
item_data_backup. StatusFlags |= ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_HoveredWindow) ;
5312
5313
5314
5315
EndGroup ( ) ;
5316
if ( g. LastItemData . ID == 0 || g. LastItemData . ID != GetWindowScrollbarID ( draw_window, ImGuiAxis_Y ) )
5317
{
5318
g. LastItemData . ID = id;
5319
g. LastItemData . ItemFlags = item_data_backup. ItemFlags ;
5320
g. LastItemData . StatusFlags = item_data_backup. StatusFlags ;
5321
}
5322
}
5323
5324
5325
if ( g. LogEnabled && ( ! is_password || is_displaying_hint) )
5326
{
5327
LogSetNextTextDecoration ( " {" , " }" ) ;
5328
LogRenderedText ( & draw_pos, buf_display, buf_display_end) ;
5329
}
5330
5331
if ( label_size. x > 0 )
5332
RenderText ( ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , frame_bb. Min . y + style. FramePadding . y ) , label) ;
5333
5334
if ( value_changed)
5335
MarkItemEdited ( id ) ;
5336
5337
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Inputable ) ;
5338
if ( ( flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0 )
5339
return validated;
5340
else
5341
return value_changed;
5342
}
5343
5344
void ImGui:: DebugNodeInputTextState ( ImGuiInputTextState* state )
5345
{
5346
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5347
ImGuiContext& g = * GImGui;
5348
ImStb:: STB_TexteditState* stb_state = state-> Stb ;
5349
ImStb:: StbUndoState* undo_state = & stb_state-> undostate ;
5350
Text ( " ID: 0x%08X , ActiveID: 0x%08X " , state-> ID , g. ActiveId ) ;
5351
DebugLocateItemOnHover ( state-> ID ) ;
5352
Text ( " CurLenA: %d , Cursor: %d , Selection: %d ..%d " , state-> TextLen , stb_state-> cursor , stb_state-> select_start , stb_state-> select_end ) ;
5353
Text ( " BufCapacityA: %d " , state-> BufCapacity ) ;
5354
Text ( " (Internal Buffer: TextA Size: %d , Capacity: %d )" , state-> TextA . Size , state-> TextA . Capacity ) ;
5355
Text ( " has_preferred_x: %d (%.2f )" , stb_state-> has_preferred_x , stb_state-> preferred_x ) ;
5356
Text ( " undo_point: %d , redo_point: %d , undo_char_point: %d , redo_char_point: %d " , undo_state-> undo_point , undo_state-> redo_point , undo_state-> undo_char_point , undo_state-> redo_char_point ) ;
5357
if ( BeginChild ( " undopoints" , ImVec2 ( 0.0f , GetTextLineHeight ( ) * 10 ) , ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY) )
5358
{
5359
PushStyleVar ( ImGuiStyleVar_ItemSpacing, ImVec2 ( 0 , 0 ) ) ;
5360
for ( int n = 0 ; n < IMSTB_TEXTEDIT_UNDOSTATECOUNT; n+ + )
5361
{
5362
ImStb:: StbUndoRecord* undo_rec = & undo_state-> undo_rec [ n] ;
5363
const char undo_rec_type = ( n < undo_state-> undo_point ) ? ' u' : ( n >= undo_state-> redo_point ) ? ' r' : ' ' ;
5364
if ( undo_rec_type == ' ' )
5365
BeginDisabled ( ) ;
5366
const int buf_preview_len = ( undo_rec_type != ' ' && undo_rec-> char_storage != - 1 ) ? undo_rec-> insert_length : 0 ;
5367
const char * buf_preview_str = undo_state-> undo_char + undo_rec-> char_storage ;
5368
Text ( " %c [%02d ] where %03d , insert %03d , delete %03d , char_storage %03d \" %.*s \" " ,
5369
undo_rec_type, n, undo_rec-> where , undo_rec-> insert_length , undo_rec-> delete_length , undo_rec-> char_storage , buf_preview_len, buf_preview_str ) ;
5370
if ( undo_rec_type == ' ' )
5371
EndDisabled ( ) ;
5372
}
5373
PopStyleVar ( ) ;
5374
}
5375
EndChild ( ) ;
5376
#else
5377
IM_UNUSED ( state ) ;
5378
#endif
5379
}
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
bool ImGui:: ColorEdit3 ( const char * label , float col [ 3 ] , ImGuiColorEditFlags flags )
5397
{
5398
return ColorEdit4 ( label, col, flags | ImGuiColorEditFlags_NoAlpha ) ;
5399
}
5400
5401
static void ColorEditRestoreH ( const float * col , float * H )
5402
{
5403
ImGuiContext& g = * GImGui;
5404
IM_ASSERT ( g. ColorEditCurrentID != 0 ) ;
5405
if ( g. ColorEditSavedID != g. ColorEditCurrentID || g. ColorEditSavedColor != ImGui:: ColorConvertFloat4ToU32 ( ImVec4 ( col[ 0 ] , col[ 1 ] , col[ 2 ] , 0 ) ) )
5406
return ;
5407
* H = g. ColorEditSavedHue ;
5408
}
5409
5410
5411
5412
static void ColorEditRestoreHS ( const float * col , float * H , float * S , float * V )
5413
{
5414
ImGuiContext& g = * GImGui;
5415
IM_ASSERT ( g. ColorEditCurrentID != 0 ) ;
5416
if ( g. ColorEditSavedID != g. ColorEditCurrentID || g. ColorEditSavedColor != ImGui:: ColorConvertFloat4ToU32 ( ImVec4 ( col[ 0 ] , col[ 1 ] , col[ 2 ] , 0 ) ) )
5417
return ;
5418
5419
5420
5421
if ( * S == 0.0f || ( * H == 0.0f && g. ColorEditSavedHue == 1 ) )
5422
* H = g. ColorEditSavedHue ;
5423
5424
5425
if ( * V == 0.0f )
5426
* S = g. ColorEditSavedSat ;
5427
}
5428
5429
5430
5431
5432
bool ImGui:: ColorEdit4 ( const char * label , float col [ 4 ] , ImGuiColorEditFlags flags )
5433
{
5434
ImGuiWindow* window = GetCurrentWindow ( ) ;
5435
if ( window-> SkipItems )
5436
return false ;
5437
5438
ImGuiContext& g = * GImGui;
5439
const ImGuiStyle& style = g. Style ;
5440
const float square_sz = GetFrameHeight ( ) ;
5441
const char * label_display_end = FindRenderedTextEnd ( label ) ;
5442
float w_full = CalcItemWidth ( ) ;
5443
g. NextItemData . ClearFlags ( ) ;
5444
5445
BeginGroup ( ) ;
5446
PushID ( label ) ;
5447
const bool set_current_color_edit_id = ( g. ColorEditCurrentID == 0 ) ;
5448
if ( set_current_color_edit_id)
5449
g. ColorEditCurrentID = window-> IDStack . back ( ) ;
5450
5451
5452
const ImGuiColorEditFlags flags_untouched = flags;
5453
if ( flags & ImGuiColorEditFlags_NoInputs)
5454
flags = ( flags & ( ~ ImGuiColorEditFlags_DisplayMask_) ) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions;
5455
5456
5457
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5458
ColorEditOptionsPopup ( col, flags ) ;
5459
5460
5461
if ( ! ( flags & ImGuiColorEditFlags_DisplayMask_) )
5462
flags |= ( g. ColorEditOptions & ImGuiColorEditFlags_DisplayMask_) ;
5463
if ( ! ( flags & ImGuiColorEditFlags_DataTypeMask_) )
5464
flags |= ( g. ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_) ;
5465
if ( ! ( flags & ImGuiColorEditFlags_PickerMask_) )
5466
flags |= ( g. ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ;
5467
if ( ! ( flags & ImGuiColorEditFlags_InputMask_) )
5468
flags |= ( g. ColorEditOptions & ImGuiColorEditFlags_InputMask_) ;
5469
flags |= ( g. ColorEditOptions & ~ ( ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_) ) ;
5470
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_DisplayMask_ ) ) ;
5471
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_InputMask_ ) ) ;
5472
5473
const bool alpha = ( flags & ImGuiColorEditFlags_NoAlpha) == 0 ;
5474
const bool hdr = ( flags & ImGuiColorEditFlags_HDR) != 0 ;
5475
const int components = alpha ? 4 : 3 ;
5476
const float w_button = ( flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : ( square_sz + style. ItemInnerSpacing . x ) ;
5477
const float w_inputs = ImMax ( w_full - w_button, 1.0f ) ;
5478
w_full = w_inputs + w_button;
5479
5480
5481
float f[ 4 ] = { col[ 0 ] , col[ 1 ] , col[ 2 ] , alpha ? col[ 3 ] : 1.0f } ;
5482
if ( ( flags & ImGuiColorEditFlags_InputHSV) && ( flags & ImGuiColorEditFlags_DisplayRGB) )
5483
ColorConvertHSVtoRGB ( f[ 0 ] , f[ 1 ] , f[ 2 ] , f[ 0 ] , f[ 1 ] , f[ 2 ] ) ;
5484
else if ( ( flags & ImGuiColorEditFlags_InputRGB) && ( flags & ImGuiColorEditFlags_DisplayHSV) )
5485
{
5486
5487
ColorConvertRGBtoHSV ( f[ 0 ] , f[ 1 ] , f[ 2 ] , f[ 0 ] , f[ 1 ] , f[ 2 ] ) ;
5488
ColorEditRestoreHS ( col, & f[ 0 ] , & f[ 1 ] , & f[ 2 ] ) ;
5489
}
5490
int i[ 4 ] = { IM_F32_TO_INT8_UNBOUND ( f[ 0 ] ) , IM_F32_TO_INT8_UNBOUND ( f[ 1 ] ) , IM_F32_TO_INT8_UNBOUND ( f[ 2 ] ) , IM_F32_TO_INT8_UNBOUND ( f[ 3 ] ) } ;
5491
5492
bool value_changed = false ;
5493
bool value_changed_as_float = false ;
5494
5495
const ImVec2 pos = window-> DC . CursorPos ;
5496
const float inputs_offset_x = ( style. ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f ;
5497
window-> DC . CursorPos . x = pos. x + inputs_offset_x;
5498
5499
if ( ( flags & ( ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV) ) != 0 && ( flags & ImGuiColorEditFlags_NoInputs) == 0 )
5500
{
5501
5502
const float w_items = w_inputs - style. ItemInnerSpacing . x * ( components - 1 ) ;
5503
5504
const bool hide_prefix = ( IM_TRUNC ( w_items / components ) <= CalcTextSize ( ( flags & ImGuiColorEditFlags_Float) ? " M:0.000" : " M:000" ) . x ) ;
5505
static const char * ids[ 4 ] = { " ##X" , " ##Y" , " ##Z" , " ##W" } ;
5506
static const char * fmt_table_int[ 3 ] [ 4 ] =
5507
{
5508
{ " %3d " , " %3d " , " %3d " , " %3d " } ,
5509
{ " R:%3d " , " G:%3d " , " B:%3d " , " A:%3d " } ,
5510
{ " H:%3d " , " S:%3d " , " V:%3d " , " A:%3d " }
5511
} ;
5512
static const char * fmt_table_float[ 3 ] [ 4 ] =
5513
{
5514
{ " %0.3f " , " %0.3f " , " %0.3f " , " %0.3f " } ,
5515
{ " R:%0.3f " , " G:%0.3f " , " B:%0.3f " , " A:%0.3f " } ,
5516
{ " H:%0.3f " , " S:%0.3f " , " V:%0.3f " , " A:%0.3f " }
5517
} ;
5518
const int fmt_idx = hide_prefix ? 0 : ( flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1 ;
5519
5520
float prev_split = 0.0f ;
5521
for ( int n = 0 ; n < components; n+ + )
5522
{
5523
if ( n > 0 )
5524
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
5525
float next_split = IM_TRUNC ( w_items * ( n + 1 ) / components ) ;
5526
SetNextItemWidth ( ImMax ( next_split - prev_split, 1.0f ) ) ;
5527
prev_split = next_split;
5528
5529
5530
if ( flags & ImGuiColorEditFlags_Float)
5531
{
5532
value_changed |= DragFloat ( ids[ n] , & f[ n] , 1.0f / 255.0f , 0.0f , hdr ? 0.0f : 1.0f , fmt_table_float[ fmt_idx] [ n] ) ;
5533
value_changed_as_float |= value_changed;
5534
}
5535
else
5536
{
5537
value_changed |= DragInt ( ids[ n] , & i[ n] , 1.0f , 0 , hdr ? 0 : 255 , fmt_table_int[ fmt_idx] [ n] ) ;
5538
}
5539
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5540
OpenPopupOnItemClick ( " context" , ImGuiPopupFlags_MouseButtonRight) ;
5541
}
5542
}
5543
else if ( ( flags & ImGuiColorEditFlags_DisplayHex) != 0 && ( flags & ImGuiColorEditFlags_NoInputs) == 0 )
5544
{
5545
5546
char buf[ 64 ] ;
5547
if ( alpha)
5548
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " #%02X %02X %02X %02X " , ImClamp ( i[ 0 ] , 0 , 255 ) , ImClamp ( i[ 1 ] , 0 , 255 ) , ImClamp ( i[ 2 ] , 0 , 255 ) , ImClamp ( i[ 3 ] , 0 , 255 ) ) ;
5549
else
5550
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " #%02X %02X %02X " , ImClamp ( i[ 0 ] , 0 , 255 ) , ImClamp ( i[ 1 ] , 0 , 255 ) , ImClamp ( i[ 2 ] , 0 , 255 ) ) ;
5551
SetNextItemWidth ( w_inputs ) ;
5552
if ( InputText ( " ##Text" , buf, IM_ARRAYSIZE ( buf ) , ImGuiInputTextFlags_CharsUppercase) )
5553
{
5554
value_changed = true ;
5555
char * p = buf;
5556
while ( * p == ' #' || ImCharIsBlankA ( * p) )
5557
p+ + ;
5558
i[ 0 ] = i[ 1 ] = i[ 2 ] = 0 ;
5559
i[ 3 ] = 0xFF ;
5560
int r;
5561
if ( alpha)
5562
r = sscanf ( p, " %02X %02X %02X %02X " , ( unsigned int * ) & i[ 0 ] , ( unsigned int * ) & i[ 1 ] , ( unsigned int * ) & i[ 2 ] , ( unsigned int * ) & i[ 3 ] ) ;
5563
else
5564
r = sscanf ( p, " %02X %02X %02X " , ( unsigned int * ) & i[ 0 ] , ( unsigned int * ) & i[ 1 ] , ( unsigned int * ) & i[ 2 ] ) ;
5565
IM_UNUSED ( r ) ;
5566
}
5567
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5568
OpenPopupOnItemClick ( " context" , ImGuiPopupFlags_MouseButtonRight) ;
5569
}
5570
5571
ImGuiWindow* picker_active_window = NULL ;
5572
if ( ! ( flags & ImGuiColorEditFlags_NoSmallPreview) )
5573
{
5574
const float button_offset_x = ( ( flags & ImGuiColorEditFlags_NoInputs) || ( style. ColorButtonPosition == ImGuiDir_Left) ) ? 0.0f : w_inputs + style. ItemInnerSpacing . x ;
5575
window-> DC . CursorPos = ImVec2 ( pos. x + button_offset_x, pos. y ) ;
5576
5577
const ImVec4 col_v4 ( col[ 0 ] , col[ 1 ] , col[ 2 ] , alpha ? col[ 3 ] : 1.0f ) ;
5578
if ( ColorButton ( " ##ColorButton" , col_v4, flags) )
5579
{
5580
if ( ! ( flags & ImGuiColorEditFlags_NoPicker) )
5581
{
5582
5583
g. ColorPickerRef = col_v4;
5584
OpenPopup ( " picker" ) ;
5585
SetNextWindowPos ( g. LastItemData . Rect . GetBL ( ) + ImVec2 ( 0.0f , style. ItemSpacing . y ) ) ;
5586
}
5587
}
5588
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5589
OpenPopupOnItemClick ( " context" , ImGuiPopupFlags_MouseButtonRight) ;
5590
5591
if ( BeginPopup ( " picker" ) )
5592
{
5593
if ( g. CurrentWindow -> BeginCount == 1 )
5594
{
5595
picker_active_window = g. CurrentWindow ;
5596
if ( label != label_display_end)
5597
{
5598
TextEx ( label, label_display_end ) ;
5599
Spacing ( ) ;
5600
}
5601
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
5602
ImGuiColorEditFlags picker_flags = ( flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
5603
SetNextItemWidth ( square_sz * 12.0f ) ;
5604
value_changed |= ColorPicker4 ( " ##picker" , col, picker_flags, & g. ColorPickerRef . x ) ;
5605
}
5606
EndPopup ( ) ;
5607
}
5608
}
5609
5610
if ( label != label_display_end && ! ( flags & ImGuiColorEditFlags_NoLabel) )
5611
{
5612
5613
5614
SameLine ( 0.0f , style. ItemInnerSpacing . x ) ;
5615
window-> DC . CursorPos . x = pos. x + ( ( flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style. ItemInnerSpacing . x ) ;
5616
TextEx ( label, label_display_end ) ;
5617
}
5618
5619
5620
if ( value_changed && picker_active_window == NULL )
5621
{
5622
if ( ! value_changed_as_float)
5623
for ( int n = 0 ; n < 4 ; n+ + )
5624
f[ n] = i[ n] / 255.0f ;
5625
if ( ( flags & ImGuiColorEditFlags_DisplayHSV) && ( flags & ImGuiColorEditFlags_InputRGB) )
5626
{
5627
g. ColorEditSavedHue = f[ 0 ] ;
5628
g. ColorEditSavedSat = f[ 1 ] ;
5629
ColorConvertHSVtoRGB ( f[ 0 ] , f[ 1 ] , f[ 2 ] , f[ 0 ] , f[ 1 ] , f[ 2 ] ) ;
5630
g. ColorEditSavedID = g. ColorEditCurrentID ;
5631
g. ColorEditSavedColor = ColorConvertFloat4ToU32 ( ImVec4 ( f[ 0 ] , f[ 1 ] , f[ 2 ] , 0 ) ) ;
5632
}
5633
if ( ( flags & ImGuiColorEditFlags_DisplayRGB) && ( flags & ImGuiColorEditFlags_InputHSV) )
5634
ColorConvertRGBtoHSV ( f[ 0 ] , f[ 1 ] , f[ 2 ] , f[ 0 ] , f[ 1 ] , f[ 2 ] ) ;
5635
5636
col[ 0 ] = f[ 0 ] ;
5637
col[ 1 ] = f[ 1 ] ;
5638
col[ 2 ] = f[ 2 ] ;
5639
if ( alpha)
5640
col[ 3 ] = f[ 3 ] ;
5641
}
5642
5643
if ( set_current_color_edit_id)
5644
g. ColorEditCurrentID = 0 ;
5645
PopID ( ) ;
5646
EndGroup ( ) ;
5647
5648
5649
5650
if ( ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_HoveredRect) && ! ( g. LastItemData . ItemFlags & ImGuiItemFlags_ReadOnly) && ! ( flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget ( ) )
5651
{
5652
bool accepted_drag_drop = false ;
5653
if ( const ImGuiPayload* payload = AcceptDragDropPayload ( IMGUI_PAYLOAD_TYPE_COLOR_3F ) )
5654
{
5655
memcpy ( ( float * ) col, payload-> Data , sizeof ( float ) * 3 ) ;
5656
value_changed = accepted_drag_drop = true ;
5657
}
5658
if ( const ImGuiPayload* payload = AcceptDragDropPayload ( IMGUI_PAYLOAD_TYPE_COLOR_4F ) )
5659
{
5660
memcpy ( ( float * ) col, payload-> Data , sizeof ( float ) * components) ;
5661
value_changed = accepted_drag_drop = true ;
5662
}
5663
5664
5665
if ( accepted_drag_drop && ( flags & ImGuiColorEditFlags_InputHSV) )
5666
ColorConvertRGBtoHSV ( col[ 0 ] , col[ 1 ] , col[ 2 ] , col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
5667
EndDragDropTarget ( ) ;
5668
}
5669
5670
5671
if ( picker_active_window && g. ActiveId != 0 && g. ActiveIdWindow == picker_active_window)
5672
g. LastItemData . ID = g. ActiveId ;
5673
5674
if ( value_changed && g. LastItemData . ID != 0 )
5675
MarkItemEdited ( g. LastItemData . ID ) ;
5676
5677
return value_changed;
5678
}
5679
5680
bool ImGui:: ColorPicker3 ( const char * label , float col [ 3 ] , ImGuiColorEditFlags flags )
5681
{
5682
float col4[ 4 ] = { col[ 0 ] , col[ 1 ] , col[ 2 ] , 1.0f } ;
5683
if ( ! ColorPicker4 ( label, col4, flags | ImGuiColorEditFlags_NoAlpha ) )
5684
return false ;
5685
col[ 0 ] = col4[ 0 ] ; col[ 1 ] = col4[ 1 ] ; col[ 2 ] = col4[ 2 ] ;
5686
return true ;
5687
}
5688
5689
5690
static void RenderArrowsForVerticalBar ( ImDrawList* draw_list , ImVec2 pos , ImVec2 half_sz , float bar_w , float alpha )
5691
{
5692
ImU32 alpha8 = IM_F32_TO_INT8_SAT ( alpha ) ;
5693
ImGui:: RenderArrowPointingAt ( draw_list, ImVec2 ( pos. x + half_sz. x + 1 , pos. y ) , ImVec2 ( half_sz. x + 2 , half_sz. y + 1 ) , ImGuiDir_Right, IM_COL32 ( 0 , 0 , 0 , alpha8) ) ;
5694
ImGui:: RenderArrowPointingAt ( draw_list, ImVec2 ( pos. x + half_sz. x , pos. y ) , half_sz, ImGuiDir_Right, IM_COL32 ( 255 , 255 , 255 , alpha8) ) ;
5695
ImGui:: RenderArrowPointingAt ( draw_list, ImVec2 ( pos. x + bar_w - half_sz. x - 1 , pos. y ) , ImVec2 ( half_sz. x + 2 , half_sz. y + 1 ) , ImGuiDir_Left, IM_COL32 ( 0 , 0 , 0 , alpha8) ) ;
5696
ImGui:: RenderArrowPointingAt ( draw_list, ImVec2 ( pos. x + bar_w - half_sz. x , pos. y ) , half_sz, ImGuiDir_Left, IM_COL32 ( 255 , 255 , 255 , alpha8) ) ;
5697
}
5698
5699
5700
5701
5702
5703
bool ImGui:: ColorPicker4 ( const char * label , float col [ 4 ] , ImGuiColorEditFlags flags , const float * ref_col )
5704
{
5705
ImGuiContext& g = * GImGui;
5706
ImGuiWindow* window = GetCurrentWindow ( ) ;
5707
if ( window-> SkipItems )
5708
return false ;
5709
5710
ImDrawList* draw_list = window-> DrawList ;
5711
ImGuiStyle& style = g. Style ;
5712
ImGuiIO& io = g. IO ;
5713
5714
const float width = CalcItemWidth ( ) ;
5715
const bool is_readonly = ( ( g. NextItemData . ItemFlags | g. CurrentItemFlags ) & ImGuiItemFlags_ReadOnly) != 0 ;
5716
g. NextItemData . ClearFlags ( ) ;
5717
5718
PushID ( label ) ;
5719
const bool set_current_color_edit_id = ( g. ColorEditCurrentID == 0 ) ;
5720
if ( set_current_color_edit_id)
5721
g. ColorEditCurrentID = window-> IDStack . back ( ) ;
5722
BeginGroup ( ) ;
5723
5724
if ( ! ( flags & ImGuiColorEditFlags_NoSidePreview) )
5725
flags |= ImGuiColorEditFlags_NoSmallPreview;
5726
5727
5728
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5729
ColorPickerOptionsPopup ( col, flags ) ;
5730
5731
5732
if ( ! ( flags & ImGuiColorEditFlags_PickerMask_) )
5733
flags |= ( ( g. ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g. ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_;
5734
if ( ! ( flags & ImGuiColorEditFlags_InputMask_) )
5735
flags |= ( ( g. ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g. ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_;
5736
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_PickerMask_ ) ) ;
5737
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_InputMask_ ) ) ;
5738
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5739
flags |= ( g. ColorEditOptions & ImGuiColorEditFlags_AlphaBar) ;
5740
5741
5742
int components = ( flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4 ;
5743
bool alpha_bar = ( flags & ImGuiColorEditFlags_AlphaBar) && ! ( flags & ImGuiColorEditFlags_NoAlpha) ;
5744
ImVec2 picker_pos = window-> DC . CursorPos ;
5745
float square_sz = GetFrameHeight ( ) ;
5746
float bars_width = square_sz;
5747
float sv_picker_size = ImMax ( bars_width * 1 , width - ( alpha_bar ? 2 : 1 ) * ( bars_width + style. ItemInnerSpacing . x ) ) ;
5748
float bar0_pos_x = picker_pos. x + sv_picker_size + style. ItemInnerSpacing . x ;
5749
float bar1_pos_x = bar0_pos_x + bars_width + style. ItemInnerSpacing . x ;
5750
float bars_triangles_half_sz = IM_TRUNC ( bars_width * 0.20f ) ;
5751
5752
float backup_initial_col[ 4 ] ;
5753
memcpy ( backup_initial_col, col, components * sizeof ( float ) ) ;
5754
5755
float wheel_thickness = sv_picker_size * 0.08f ;
5756
float wheel_r_outer = sv_picker_size * 0.50f ;
5757
float wheel_r_inner = wheel_r_outer - wheel_thickness;
5758
ImVec2 wheel_center ( picker_pos. x + ( sv_picker_size + bars_width) * 0.5f , picker_pos. y + sv_picker_size * 0.5f ) ;
5759
5760
5761
float triangle_r = wheel_r_inner - ( int ) ( sv_picker_size * 0.027f ) ;
5762
ImVec2 triangle_pa = ImVec2 ( triangle_r, 0.0f ) ;
5763
ImVec2 triangle_pb = ImVec2 ( triangle_r * - 0.5f , triangle_r * - 0.866025f ) ;
5764
ImVec2 triangle_pc = ImVec2 ( triangle_r * - 0.5f , triangle_r * + 0.866025f ) ;
5765
5766
float H = col[ 0 ] , S = col[ 1 ] , V = col[ 2 ] ;
5767
float R = col[ 0 ] , G = col[ 1 ] , B = col[ 2 ] ;
5768
if ( flags & ImGuiColorEditFlags_InputRGB)
5769
{
5770
5771
ColorConvertRGBtoHSV ( R, G, B, H, S, V ) ;
5772
ColorEditRestoreHS ( col, & H, & S, & V ) ;
5773
}
5774
else if ( flags & ImGuiColorEditFlags_InputHSV)
5775
{
5776
ColorConvertHSVtoRGB ( H, S, V, R, G, B ) ;
5777
}
5778
5779
bool value_changed = false , value_changed_h = false , value_changed_sv = false ;
5780
5781
PushItemFlag ( ImGuiItemFlags_NoNav, true ) ;
5782
if ( flags & ImGuiColorEditFlags_PickerHueWheel)
5783
{
5784
5785
InvisibleButton ( " hsv" , ImVec2 ( sv_picker_size + style. ItemInnerSpacing . x + bars_width, sv_picker_size ) ) ;
5786
if ( IsItemActive ( ) && ! is_readonly)
5787
{
5788
ImVec2 initial_off = g. IO . MouseClickedPos [ 0 ] - wheel_center;
5789
ImVec2 current_off = g. IO . MousePos - wheel_center;
5790
float initial_dist2 = ImLengthSqr ( initial_off ) ;
5791
if ( initial_dist2 >= ( wheel_r_inner - 1 ) * ( wheel_r_inner - 1 ) && initial_dist2 <= ( wheel_r_outer + 1 ) * ( wheel_r_outer + 1 ) )
5792
{
5793
5794
H = ImAtan2 ( current_off. y , current_off. x ) / IM_PI * 0.5f ;
5795
if ( H < 0.0f )
5796
H += 1.0f ;
5797
value_changed = value_changed_h = true ;
5798
}
5799
float cos_hue_angle = ImCos ( - H * 2.0f * IM_PI) ;
5800
float sin_hue_angle = ImSin ( - H * 2.0f * IM_PI) ;
5801
if ( ImTriangleContainsPoint ( triangle_pa, triangle_pb, triangle_pc, ImRotate ( initial_off, cos_hue_angle, sin_hue_angle ) ) )
5802
{
5803
5804
ImVec2 current_off_unrotated = ImRotate ( current_off, cos_hue_angle, sin_hue_angle ) ;
5805
if ( ! ImTriangleContainsPoint ( triangle_pa, triangle_pb, triangle_pc, current_off_unrotated ) )
5806
current_off_unrotated = ImTriangleClosestPoint ( triangle_pa, triangle_pb, triangle_pc, current_off_unrotated ) ;
5807
float uu, vv, ww;
5808
ImTriangleBarycentricCoords ( triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww ) ;
5809
V = ImClamp ( 1.0f - vv, 0.0001f , 1.0f ) ;
5810
S = ImClamp ( uu / V, 0.0001f , 1.0f ) ;
5811
value_changed = value_changed_sv = true ;
5812
}
5813
}
5814
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5815
OpenPopupOnItemClick ( " context" , ImGuiPopupFlags_MouseButtonRight) ;
5816
}
5817
else if ( flags & ImGuiColorEditFlags_PickerHueBar)
5818
{
5819
5820
InvisibleButton ( " sv" , ImVec2 ( sv_picker_size, sv_picker_size ) ) ;
5821
if ( IsItemActive ( ) && ! is_readonly)
5822
{
5823
S = ImSaturate ( ( io. MousePos . x - picker_pos. x ) / ( sv_picker_size - 1 ) ) ;
5824
V = 1.0f - ImSaturate ( ( io. MousePos . y - picker_pos. y ) / ( sv_picker_size - 1 ) ) ;
5825
ColorEditRestoreH ( col, & H ) ;
5826
value_changed = value_changed_sv = true ;
5827
}
5828
if ( ! ( flags & ImGuiColorEditFlags_NoOptions) )
5829
OpenPopupOnItemClick ( " context" , ImGuiPopupFlags_MouseButtonRight) ;
5830
5831
5832
SetCursorScreenPos ( ImVec2 ( bar0_pos_x, picker_pos. y ) ) ;
5833
InvisibleButton ( " hue" , ImVec2 ( bars_width, sv_picker_size ) ) ;
5834
if ( IsItemActive ( ) && ! is_readonly)
5835
{
5836
H = ImSaturate ( ( io. MousePos . y - picker_pos. y ) / ( sv_picker_size - 1 ) ) ;
5837
value_changed = value_changed_h = true ;
5838
}
5839
}
5840
5841
5842
if ( alpha_bar)
5843
{
5844
SetCursorScreenPos ( ImVec2 ( bar1_pos_x, picker_pos. y ) ) ;
5845
InvisibleButton ( " alpha" , ImVec2 ( bars_width, sv_picker_size ) ) ;
5846
if ( IsItemActive ( ) )
5847
{
5848
col[ 3 ] = 1.0f - ImSaturate ( ( io. MousePos . y - picker_pos. y ) / ( sv_picker_size - 1 ) ) ;
5849
value_changed = true ;
5850
}
5851
}
5852
PopItemFlag ( ) ;
5853
5854
if ( ! ( flags & ImGuiColorEditFlags_NoSidePreview) )
5855
{
5856
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
5857
BeginGroup ( ) ;
5858
}
5859
5860
if ( ! ( flags & ImGuiColorEditFlags_NoLabel) )
5861
{
5862
const char * label_display_end = FindRenderedTextEnd ( label ) ;
5863
if ( label != label_display_end)
5864
{
5865
if ( ( flags & ImGuiColorEditFlags_NoSidePreview) )
5866
SameLine ( 0 , style. ItemInnerSpacing . x ) ;
5867
TextEx ( label, label_display_end ) ;
5868
}
5869
}
5870
5871
if ( ! ( flags & ImGuiColorEditFlags_NoSidePreview) )
5872
{
5873
PushItemFlag ( ImGuiItemFlags_NoNavDefaultFocus, true ) ;
5874
ImVec4 col_v4 ( col[ 0 ] , col[ 1 ] , col[ 2 ] , ( flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[ 3 ] ) ;
5875
if ( ( flags & ImGuiColorEditFlags_NoLabel) )
5876
Text ( " Current" ) ;
5877
5878
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip;
5879
ColorButton ( " ##current" , col_v4, ( flags & sub_flags_to_forward) , ImVec2 ( square_sz * 3 , square_sz * 2 ) ) ;
5880
if ( ref_col != NULL )
5881
{
5882
Text ( " Original" ) ;
5883
ImVec4 ref_col_v4 ( ref_col[ 0 ] , ref_col[ 1 ] , ref_col[ 2 ] , ( flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[ 3 ] ) ;
5884
if ( ColorButton ( " ##original" , ref_col_v4, ( flags & sub_flags_to_forward) , ImVec2 ( square_sz * 3 , square_sz * 2 ) ) )
5885
{
5886
memcpy ( col, ref_col, components * sizeof ( float ) ) ;
5887
value_changed = true ;
5888
}
5889
}
5890
PopItemFlag ( ) ;
5891
EndGroup ( ) ;
5892
}
5893
5894
5895
if ( value_changed_h || value_changed_sv)
5896
{
5897
if ( flags & ImGuiColorEditFlags_InputRGB)
5898
{
5899
ColorConvertHSVtoRGB ( H, S, V, col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
5900
g. ColorEditSavedHue = H;
5901
g. ColorEditSavedSat = S;
5902
g. ColorEditSavedID = g. ColorEditCurrentID ;
5903
g. ColorEditSavedColor = ColorConvertFloat4ToU32 ( ImVec4 ( col[ 0 ] , col[ 1 ] , col[ 2 ] , 0 ) ) ;
5904
}
5905
else if ( flags & ImGuiColorEditFlags_InputHSV)
5906
{
5907
col[ 0 ] = H;
5908
col[ 1 ] = S;
5909
col[ 2 ] = V;
5910
}
5911
}
5912
5913
5914
bool value_changed_fix_hue_wrap = false ;
5915
if ( ( flags & ImGuiColorEditFlags_NoInputs) == 0 )
5916
{
5917
PushItemWidth ( ( alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos. x ) ;
5918
ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf;
5919
ImGuiColorEditFlags sub_flags = ( flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
5920
if ( flags & ImGuiColorEditFlags_DisplayRGB || ( flags & ImGuiColorEditFlags_DisplayMask_) == 0 )
5921
if ( ColorEdit4 ( " ##rgb" , col, sub_flags | ImGuiColorEditFlags_DisplayRGB) )
5922
{
5923
5924
5925
value_changed_fix_hue_wrap = ( g. ActiveId != 0 && ! g. ActiveIdAllowOverlap ) ;
5926
value_changed = true ;
5927
}
5928
if ( flags & ImGuiColorEditFlags_DisplayHSV || ( flags & ImGuiColorEditFlags_DisplayMask_) == 0 )
5929
value_changed |= ColorEdit4 ( " ##hsv" , col, sub_flags | ImGuiColorEditFlags_DisplayHSV) ;
5930
if ( flags & ImGuiColorEditFlags_DisplayHex || ( flags & ImGuiColorEditFlags_DisplayMask_) == 0 )
5931
value_changed |= ColorEdit4 ( " ##hex" , col, sub_flags | ImGuiColorEditFlags_DisplayHex) ;
5932
PopItemWidth ( ) ;
5933
}
5934
5935
5936
if ( value_changed_fix_hue_wrap && ( flags & ImGuiColorEditFlags_InputRGB) )
5937
{
5938
float new_H, new_S, new_V;
5939
ColorConvertRGBtoHSV ( col[ 0 ] , col[ 1 ] , col[ 2 ] , new_H, new_S, new_V ) ;
5940
if ( new_H <= 0 && H > 0 )
5941
{
5942
if ( new_V <= 0 && V != new_V)
5943
ColorConvertHSVtoRGB ( H, S, new_V <= 0 ? V * 0.5f : new_V, col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
5944
else if ( new_S <= 0 )
5945
ColorConvertHSVtoRGB ( H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
5946
}
5947
}
5948
5949
if ( value_changed)
5950
{
5951
if ( flags & ImGuiColorEditFlags_InputRGB)
5952
{
5953
R = col[ 0 ] ;
5954
G = col[ 1 ] ;
5955
B = col[ 2 ] ;
5956
ColorConvertRGBtoHSV ( R, G, B, H, S, V ) ;
5957
ColorEditRestoreHS ( col, & H, & S, & V ) ;
5958
}
5959
else if ( flags & ImGuiColorEditFlags_InputHSV)
5960
{
5961
H = col[ 0 ] ;
5962
S = col[ 1 ] ;
5963
V = col[ 2 ] ;
5964
ColorConvertHSVtoRGB ( H, S, V, R, G, B ) ;
5965
}
5966
}
5967
5968
const int style_alpha8 = IM_F32_TO_INT8_SAT ( style. Alpha ) ;
5969
const ImU32 col_black = IM_COL32 ( 0 , 0 , 0 , style_alpha8) ;
5970
const ImU32 col_white = IM_COL32 ( 255 , 255 , 255 , style_alpha8) ;
5971
const ImU32 col_midgrey = IM_COL32 ( 128 , 128 , 128 , style_alpha8) ;
5972
const ImU32 col_hues[ 6 + 1 ] = { IM_COL32 ( 255 , 0 , 0 , style_alpha8) , IM_COL32 ( 255 , 255 , 0 , style_alpha8) , IM_COL32 ( 0 , 255 , 0 , style_alpha8) , IM_COL32 ( 0 , 255 , 255 , style_alpha8) , IM_COL32 ( 0 , 0 , 255 , style_alpha8) , IM_COL32 ( 255 , 0 , 255 , style_alpha8) , IM_COL32 ( 255 , 0 , 0 , style_alpha8) } ;
5973
5974
ImVec4 hue_color_f ( 1 , 1 , 1 , style. Alpha ) ; ColorConvertHSVtoRGB ( H, 1 , 1 , hue_color_f. x , hue_color_f. y , hue_color_f. z ) ;
5975
ImU32 hue_color32 = ColorConvertFloat4ToU32 ( hue_color_f ) ;
5976
ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32 ( ImVec4 ( R, G, B, style. Alpha ) ) ;
5977
5978
ImVec2 sv_cursor_pos;
5979
5980
if ( flags & ImGuiColorEditFlags_PickerHueWheel)
5981
{
5982
5983
const float aeps = 0.5f / wheel_r_outer;
5984
const int segment_per_arc = ImMax ( 4 , ( int ) wheel_r_outer / 12 ) ;
5985
for ( int n = 0 ; n < 6 ; n+ + )
5986
{
5987
const float a0 = ( n) / 6.0f * 2.0f * IM_PI - aeps;
5988
const float a1 = ( n+ 1.0f ) / 6.0f * 2.0f * IM_PI + aeps;
5989
const int vert_start_idx = draw_list-> VtxBuffer . Size ;
5990
draw_list-> PathArcTo ( wheel_center, ( wheel_r_inner + wheel_r_outer) * 0.5f , a0, a1, segment_per_arc ) ;
5991
draw_list-> PathStroke ( col_white, 0 , wheel_thickness ) ;
5992
const int vert_end_idx = draw_list-> VtxBuffer . Size ;
5993
5994
5995
ImVec2 gradient_p0 ( wheel_center. x + ImCos ( a0 ) * wheel_r_inner, wheel_center. y + ImSin ( a0 ) * wheel_r_inner ) ;
5996
ImVec2 gradient_p1 ( wheel_center. x + ImCos ( a1 ) * wheel_r_inner, wheel_center. y + ImSin ( a1 ) * wheel_r_inner ) ;
5997
ShadeVertsLinearColorGradientKeepAlpha ( draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[ n] , col_hues[ n + 1 ] ) ;
5998
}
5999
6000
6001
float cos_hue_angle = ImCos ( H * 2.0f * IM_PI ) ;
6002
float sin_hue_angle = ImSin ( H * 2.0f * IM_PI ) ;
6003
ImVec2 hue_cursor_pos ( wheel_center. x + cos_hue_angle * ( wheel_r_inner + wheel_r_outer) * 0.5f , wheel_center. y + sin_hue_angle * ( wheel_r_inner + wheel_r_outer) * 0.5f ) ;
6004
float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f ;
6005
int hue_cursor_segments = draw_list-> _CalcCircleAutoSegmentCount ( hue_cursor_rad ) ;
6006
draw_list-> AddCircleFilled ( hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments ) ;
6007
draw_list-> AddCircle ( hue_cursor_pos, hue_cursor_rad + 1 , col_midgrey, hue_cursor_segments ) ;
6008
draw_list-> AddCircle ( hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments ) ;
6009
6010
6011
ImVec2 tra = wheel_center + ImRotate ( triangle_pa, cos_hue_angle, sin_hue_angle ) ;
6012
ImVec2 trb = wheel_center + ImRotate ( triangle_pb, cos_hue_angle, sin_hue_angle ) ;
6013
ImVec2 trc = wheel_center + ImRotate ( triangle_pc, cos_hue_angle, sin_hue_angle ) ;
6014
ImVec2 uv_white = GetFontTexUvWhitePixel ( ) ;
6015
draw_list-> PrimReserve ( 3 , 3 ) ;
6016
draw_list-> PrimVtx ( tra, uv_white, hue_color32 ) ;
6017
draw_list-> PrimVtx ( trb, uv_white, col_black ) ;
6018
draw_list-> PrimVtx ( trc, uv_white, col_white ) ;
6019
draw_list-> AddTriangle ( tra, trb, trc, col_midgrey, 1.5f ) ;
6020
sv_cursor_pos = ImLerp ( ImLerp ( trc, tra, ImSaturate ( S ) ) , trb, ImSaturate ( 1 - V) ) ;
6021
}
6022
else if ( flags & ImGuiColorEditFlags_PickerHueBar)
6023
{
6024
6025
draw_list-> AddRectFilledMultiColor ( picker_pos, picker_pos + ImVec2 ( sv_picker_size, sv_picker_size ) , col_white, hue_color32, hue_color32, col_white ) ;
6026
draw_list-> AddRectFilledMultiColor ( picker_pos, picker_pos + ImVec2 ( sv_picker_size, sv_picker_size ) , 0 , 0 , col_black, col_black ) ;
6027
RenderFrameBorder ( picker_pos, picker_pos + ImVec2 ( sv_picker_size, sv_picker_size ) , 0.0f ) ;
6028
sv_cursor_pos. x = ImClamp ( IM_ROUND ( picker_pos. x + ImSaturate ( S ) * sv_picker_size ) , picker_pos. x + 2 , picker_pos. x + sv_picker_size - 2 ) ;
6029
sv_cursor_pos. y = ImClamp ( IM_ROUND ( picker_pos. y + ImSaturate ( 1 - V) * sv_picker_size ) , picker_pos. y + 2 , picker_pos. y + sv_picker_size - 2 ) ;
6030
6031
6032
for ( int i = 0 ; i < 6 ; + + i)
6033
draw_list-> AddRectFilledMultiColor ( ImVec2 ( bar0_pos_x, picker_pos. y + i * ( sv_picker_size / 6 ) ) , ImVec2 ( bar0_pos_x + bars_width, picker_pos. y + ( i + 1 ) * ( sv_picker_size / 6 ) ) , col_hues[ i] , col_hues[ i] , col_hues[ i + 1 ] , col_hues[ i + 1 ] ) ;
6034
float bar0_line_y = IM_ROUND ( picker_pos. y + H * sv_picker_size ) ;
6035
RenderFrameBorder ( ImVec2 ( bar0_pos_x, picker_pos. y ) , ImVec2 ( bar0_pos_x + bars_width, picker_pos. y + sv_picker_size ) , 0.0f ) ;
6036
RenderArrowsForVerticalBar ( draw_list, ImVec2 ( bar0_pos_x - 1 , bar0_line_y ) , ImVec2 ( bars_triangles_half_sz + 1 , bars_triangles_half_sz ) , bars_width + 2.0f , style. Alpha ) ;
6037
}
6038
6039
6040
float sv_cursor_rad = value_changed_sv ? wheel_thickness * 0.55f : wheel_thickness * 0.40f ;
6041
int sv_cursor_segments = draw_list-> _CalcCircleAutoSegmentCount ( sv_cursor_rad ) ;
6042
draw_list-> AddCircleFilled ( sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments ) ;
6043
draw_list-> AddCircle ( sv_cursor_pos, sv_cursor_rad + 1 , col_midgrey, sv_cursor_segments ) ;
6044
draw_list-> AddCircle ( sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments ) ;
6045
6046
6047
if ( alpha_bar)
6048
{
6049
float alpha = ImSaturate ( col[ 3 ] ) ;
6050
ImRect bar1_bb ( bar1_pos_x, picker_pos. y , bar1_pos_x + bars_width, picker_pos. y + sv_picker_size ) ;
6051
RenderColorRectWithAlphaCheckerboard ( draw_list, bar1_bb. Min , bar1_bb. Max , 0 , bar1_bb. GetWidth ( ) / 2.0f , ImVec2 ( 0.0f , 0.0f ) ) ;
6052
draw_list-> AddRectFilledMultiColor ( bar1_bb. Min , bar1_bb. Max , user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~ IM_COL32_A_MASK, user_col32_striped_of_alpha & ~ IM_COL32_A_MASK ) ;
6053
float bar1_line_y = IM_ROUND ( picker_pos. y + ( 1.0f - alpha) * sv_picker_size ) ;
6054
RenderFrameBorder ( bar1_bb. Min , bar1_bb. Max , 0.0f ) ;
6055
RenderArrowsForVerticalBar ( draw_list, ImVec2 ( bar1_pos_x - 1 , bar1_line_y ) , ImVec2 ( bars_triangles_half_sz + 1 , bars_triangles_half_sz ) , bars_width + 2.0f , style. Alpha ) ;
6056
}
6057
6058
EndGroup ( ) ;
6059
6060
if ( value_changed && memcmp ( backup_initial_col, col, components * sizeof ( float ) ) == 0 )
6061
value_changed = false ;
6062
if ( value_changed && g. LastItemData . ID != 0 )
6063
MarkItemEdited ( g. LastItemData . ID ) ;
6064
6065
if ( set_current_color_edit_id)
6066
g. ColorEditCurrentID = 0 ;
6067
PopID ( ) ;
6068
6069
return value_changed;
6070
}
6071
6072
6073
6074
6075
6076
bool ImGui:: ColorButton ( const char * desc_id , const ImVec4& col , ImGuiColorEditFlags flags , const ImVec2& size_arg )
6077
{
6078
ImGuiWindow* window = GetCurrentWindow ( ) ;
6079
if ( window-> SkipItems )
6080
return false ;
6081
6082
ImGuiContext& g = * GImGui;
6083
const ImGuiID id = window-> GetID ( desc_id ) ;
6084
const float default_size = GetFrameHeight ( ) ;
6085
const ImVec2 size ( size_arg. x == 0.0f ? default_size : size_arg. x , size_arg. y == 0.0f ? default_size : size_arg. y ) ;
6086
const ImRect bb ( window-> DC . CursorPos , window-> DC . CursorPos + size ) ;
6087
ItemSize ( bb, ( size. y >= default_size) ? g. Style . FramePadding . y : 0.0f ) ;
6088
if ( ! ItemAdd ( bb, id ) )
6089
return false ;
6090
6091
bool hovered, held;
6092
bool pressed = ButtonBehavior ( bb, id, & hovered, & held ) ;
6093
6094
if ( flags & ImGuiColorEditFlags_NoAlpha)
6095
flags &= ~ ( ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf) ;
6096
6097
ImVec4 col_rgb = col;
6098
if ( flags & ImGuiColorEditFlags_InputHSV)
6099
ColorConvertHSVtoRGB ( col_rgb. x , col_rgb. y , col_rgb. z , col_rgb. x , col_rgb. y , col_rgb. z ) ;
6100
6101
ImVec4 col_rgb_without_alpha ( col_rgb. x , col_rgb. y , col_rgb. z , 1.0f ) ;
6102
float grid_step = ImMin ( size. x , size. y ) / 2.99f ;
6103
float rounding = ImMin ( g. Style . FrameRounding , grid_step * 0.5f ) ;
6104
ImRect bb_inner = bb;
6105
float off = 0.0f ;
6106
if ( ( flags & ImGuiColorEditFlags_NoBorder) == 0 )
6107
{
6108
off = - 0.75f ;
6109
bb_inner. Expand ( off ) ;
6110
}
6111
if ( ( flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb. w < 1.0f )
6112
{
6113
float mid_x = IM_ROUND ( ( bb_inner. Min . x + bb_inner. Max . x ) * 0.5f ) ;
6114
RenderColorRectWithAlphaCheckerboard ( window-> DrawList , ImVec2 ( bb_inner. Min . x + grid_step, bb_inner. Min . y ) , bb_inner. Max , GetColorU32 ( col_rgb ) , grid_step, ImVec2 ( - grid_step + off, off) , rounding, ImDrawFlags_RoundCornersRight ) ;
6115
window-> DrawList -> AddRectFilled ( bb_inner. Min , ImVec2 ( mid_x, bb_inner. Max . y ) , GetColorU32 ( col_rgb_without_alpha ) , rounding, ImDrawFlags_RoundCornersLeft ) ;
6116
}
6117
else
6118
{
6119
6120
ImVec4 col_source = ( flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha;
6121
if ( col_source. w < 1.0f )
6122
RenderColorRectWithAlphaCheckerboard ( window-> DrawList , bb_inner. Min , bb_inner. Max , GetColorU32 ( col_source ) , grid_step, ImVec2 ( off, off ) , rounding ) ;
6123
else
6124
window-> DrawList -> AddRectFilled ( bb_inner. Min , bb_inner. Max , GetColorU32 ( col_source ) , rounding ) ;
6125
}
6126
RenderNavCursor ( bb, id ) ;
6127
if ( ( flags & ImGuiColorEditFlags_NoBorder) == 0 )
6128
{
6129
if ( g. Style . FrameBorderSize > 0.0f )
6130
RenderFrameBorder ( bb. Min , bb. Max , rounding ) ;
6131
else
6132
window-> DrawList -> AddRect ( bb. Min , bb. Max , GetColorU32 ( ImGuiCol_FrameBg ) , rounding ) ;
6133
}
6134
6135
6136
6137
if ( g. ActiveId == id && ! ( flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource ( ) )
6138
{
6139
if ( flags & ImGuiColorEditFlags_NoAlpha)
6140
SetDragDropPayload ( IMGUI_PAYLOAD_TYPE_COLOR_3F, & col_rgb, sizeof ( float ) * 3 , ImGuiCond_Once ) ;
6141
else
6142
SetDragDropPayload ( IMGUI_PAYLOAD_TYPE_COLOR_4F, & col_rgb, sizeof ( float ) * 4 , ImGuiCond_Once ) ;
6143
ColorButton ( desc_id, col, flags ) ;
6144
SameLine ( ) ;
6145
TextEx ( " Color" ) ;
6146
EndDragDropSource ( ) ;
6147
}
6148
6149
6150
if ( ! ( flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered ( ImGuiHoveredFlags_ForTooltip ) )
6151
ColorTooltip ( desc_id, & col. x , flags & ( ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf) ) ;
6152
6153
return pressed;
6154
}
6155
6156
6157
void ImGui:: SetColorEditOptions ( ImGuiColorEditFlags flags )
6158
{
6159
ImGuiContext& g = * GImGui;
6160
if ( ( flags & ImGuiColorEditFlags_DisplayMask_) == 0 )
6161
flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_;
6162
if ( ( flags & ImGuiColorEditFlags_DataTypeMask_) == 0 )
6163
flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_;
6164
if ( ( flags & ImGuiColorEditFlags_PickerMask_) == 0 )
6165
flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_;
6166
if ( ( flags & ImGuiColorEditFlags_InputMask_) == 0 )
6167
flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_;
6168
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_DisplayMask_ ) ) ;
6169
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_DataTypeMask_ ) ) ;
6170
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_PickerMask_ ) ) ;
6171
IM_ASSERT ( ImIsPowerOfTwo ( flags & ImGuiColorEditFlags_InputMask_ ) ) ;
6172
g. ColorEditOptions = flags;
6173
}
6174
6175
6176
void ImGui:: ColorTooltip ( const char * text , const float * col , ImGuiColorEditFlags flags )
6177
{
6178
ImGuiContext& g = * GImGui;
6179
6180
if ( ! BeginTooltipEx ( ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None ) )
6181
return ;
6182
const char * text_end = text ? FindRenderedTextEnd ( text, NULL ) : text;
6183
if ( text_end > text)
6184
{
6185
TextEx ( text, text_end ) ;
6186
Separator ( ) ;
6187
}
6188
6189
ImVec2 sz ( g. FontSize * 3 + g. Style . FramePadding . y * 2 , g. FontSize * 3 + g. Style . FramePadding . y * 2 ) ;
6190
ImVec4 cf ( col[ 0 ] , col[ 1 ] , col[ 2 ] , ( flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[ 3 ] ) ;
6191
int cr = IM_F32_TO_INT8_SAT ( col[ 0 ] ) , cg = IM_F32_TO_INT8_SAT ( col[ 1 ] ) , cb = IM_F32_TO_INT8_SAT ( col[ 2 ] ) , ca = ( flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT ( col[ 3 ] ) ;
6192
ColorButton ( " ##preview" , cf, ( flags & ( ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf) ) | ImGuiColorEditFlags_NoTooltip, sz) ;
6193
SameLine ( ) ;
6194
if ( ( flags & ImGuiColorEditFlags_InputRGB) || ! ( flags & ImGuiColorEditFlags_InputMask_) )
6195
{
6196
if ( flags & ImGuiColorEditFlags_NoAlpha)
6197
Text ( " #%02X %02X %02X \n R: %d , G: %d , B: %d \n (%.3f , %.3f , %.3f )" , cr, cg, cb, cr, cg, cb, col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
6198
else
6199
Text ( " #%02X %02X %02X %02X \n R:%d , G:%d , B:%d , A:%d \n (%.3f , %.3f , %.3f , %.3f )" , cr, cg, cb, ca, cr, cg, cb, ca, col[ 0 ] , col[ 1 ] , col[ 2 ] , col[ 3 ] ) ;
6200
}
6201
else if ( flags & ImGuiColorEditFlags_InputHSV)
6202
{
6203
if ( flags & ImGuiColorEditFlags_NoAlpha)
6204
Text ( " H: %.3f , S: %.3f , V: %.3f " , col[ 0 ] , col[ 1 ] , col[ 2 ] ) ;
6205
else
6206
Text ( " H: %.3f , S: %.3f , V: %.3f , A: %.3f " , col[ 0 ] , col[ 1 ] , col[ 2 ] , col[ 3 ] ) ;
6207
}
6208
EndTooltip ( ) ;
6209
}
6210
6211
void ImGui:: ColorEditOptionsPopup ( const float * col , ImGuiColorEditFlags flags )
6212
{
6213
bool allow_opt_inputs = ! ( flags & ImGuiColorEditFlags_DisplayMask_) ;
6214
bool allow_opt_datatype = ! ( flags & ImGuiColorEditFlags_DataTypeMask_) ;
6215
if ( ( ! allow_opt_inputs && ! allow_opt_datatype) || ! BeginPopup ( " context" ) )
6216
return ;
6217
6218
ImGuiContext& g = * GImGui;
6219
PushItemFlag ( ImGuiItemFlags_NoMarkEdited, true ) ;
6220
ImGuiColorEditFlags opts = g. ColorEditOptions ;
6221
if ( allow_opt_inputs)
6222
{
6223
if ( RadioButton ( " RGB" , ( opts & ImGuiColorEditFlags_DisplayRGB) != 0 ) ) opts = ( opts & ~ ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB;
6224
if ( RadioButton ( " HSV" , ( opts & ImGuiColorEditFlags_DisplayHSV) != 0 ) ) opts = ( opts & ~ ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV;
6225
if ( RadioButton ( " Hex" , ( opts & ImGuiColorEditFlags_DisplayHex) != 0 ) ) opts = ( opts & ~ ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex;
6226
}
6227
if ( allow_opt_datatype)
6228
{
6229
if ( allow_opt_inputs) Separator ( ) ;
6230
if ( RadioButton ( " 0..255" , ( opts & ImGuiColorEditFlags_Uint8) != 0 ) ) opts = ( opts & ~ ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8;
6231
if ( RadioButton ( " 0.00..1.00" , ( opts & ImGuiColorEditFlags_Float) != 0 ) ) opts = ( opts & ~ ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float;
6232
}
6233
6234
if ( allow_opt_inputs || allow_opt_datatype)
6235
Separator ( ) ;
6236
if ( Button ( " Copy as.." , ImVec2 ( - 1 , 0 ) ) )
6237
OpenPopup ( " Copy" ) ;
6238
if ( BeginPopup ( " Copy" ) )
6239
{
6240
int cr = IM_F32_TO_INT8_SAT ( col[ 0 ] ) , cg = IM_F32_TO_INT8_SAT ( col[ 1 ] ) , cb = IM_F32_TO_INT8_SAT ( col[ 2 ] ) , ca = ( flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT ( col[ 3 ] ) ;
6241
char buf[ 64 ] ;
6242
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " (%.3f f, %.3f f, %.3f f, %.3f f)" , col[ 0 ] , col[ 1 ] , col[ 2 ] , ( flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[ 3 ] ) ;
6243
if ( Selectable ( buf ) )
6244
SetClipboardText ( buf ) ;
6245
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " (%d ,%d ,%d ,%d )" , cr, cg, cb, ca ) ;
6246
if ( Selectable ( buf ) )
6247
SetClipboardText ( buf ) ;
6248
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " #%02X %02X %02X " , cr, cg, cb ) ;
6249
if ( Selectable ( buf ) )
6250
SetClipboardText ( buf ) ;
6251
if ( ! ( flags & ImGuiColorEditFlags_NoAlpha) )
6252
{
6253
ImFormatString ( buf, IM_ARRAYSIZE ( buf ) , " #%02X %02X %02X %02X " , cr, cg, cb, ca ) ;
6254
if ( Selectable ( buf ) )
6255
SetClipboardText ( buf ) ;
6256
}
6257
EndPopup ( ) ;
6258
}
6259
6260
g. ColorEditOptions = opts;
6261
PopItemFlag ( ) ;
6262
EndPopup ( ) ;
6263
}
6264
6265
void ImGui:: ColorPickerOptionsPopup ( const float * ref_col , ImGuiColorEditFlags flags )
6266
{
6267
bool allow_opt_picker = ! ( flags & ImGuiColorEditFlags_PickerMask_) ;
6268
bool allow_opt_alpha_bar = ! ( flags & ImGuiColorEditFlags_NoAlpha) && ! ( flags & ImGuiColorEditFlags_AlphaBar) ;
6269
if ( ( ! allow_opt_picker && ! allow_opt_alpha_bar) || ! BeginPopup ( " context" ) )
6270
return ;
6271
6272
ImGuiContext& g = * GImGui;
6273
PushItemFlag ( ImGuiItemFlags_NoMarkEdited, true ) ;
6274
if ( allow_opt_picker)
6275
{
6276
ImVec2 picker_size ( g. FontSize * 8 , ImMax ( g. FontSize * 8 - ( GetFrameHeight ( ) + g. Style . ItemInnerSpacing . x ) , 1.0f ) ) ;
6277
PushItemWidth ( picker_size. x ) ;
6278
for ( int picker_type = 0 ; picker_type < 2 ; picker_type+ + )
6279
{
6280
6281
if ( picker_type > 0 ) Separator ( ) ;
6282
PushID ( picker_type ) ;
6283
ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | ( flags & ImGuiColorEditFlags_NoAlpha) ;
6284
if ( picker_type == 0 ) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
6285
if ( picker_type == 1 ) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
6286
ImVec2 backup_pos = GetCursorScreenPos ( ) ;
6287
if ( Selectable ( " ##selectable" , false , 0 , picker_size) )
6288
g. ColorEditOptions = ( g. ColorEditOptions & ~ ImGuiColorEditFlags_PickerMask_) | ( picker_flags & ImGuiColorEditFlags_PickerMask_) ;
6289
SetCursorScreenPos ( backup_pos ) ;
6290
ImVec4 previewing_ref_col;
6291
memcpy ( & previewing_ref_col, ref_col, sizeof ( float ) * ( ( picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4 ) ) ;
6292
ColorPicker4 ( " ##previewing_picker" , & previewing_ref_col. x , picker_flags) ;
6293
PopID ( ) ;
6294
}
6295
PopItemWidth ( ) ;
6296
}
6297
if ( allow_opt_alpha_bar)
6298
{
6299
if ( allow_opt_picker) Separator ( ) ;
6300
CheckboxFlags ( " Alpha Bar" , & g. ColorEditOptions , ImGuiColorEditFlags_AlphaBar) ;
6301
}
6302
PopItemFlag ( ) ;
6303
EndPopup ( ) ;
6304
}
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
bool ImGui:: TreeNode ( const char * str_id , const char * fmt , ... )
6322
{
6323
va_list args;
6324
va_start ( args, fmt ) ;
6325
bool is_open = TreeNodeExV ( str_id, 0 , fmt, args ) ;
6326
va_end ( args ) ;
6327
return is_open;
6328
}
6329
6330
bool ImGui:: TreeNode ( const void * ptr_id , const char * fmt , ... )
6331
{
6332
va_list args;
6333
va_start ( args, fmt ) ;
6334
bool is_open = TreeNodeExV ( ptr_id, 0 , fmt, args ) ;
6335
va_end ( args ) ;
6336
return is_open;
6337
}
6338
6339
bool ImGui:: TreeNode ( const char * label )
6340
{
6341
ImGuiWindow* window = GetCurrentWindow ( ) ;
6342
if ( window-> SkipItems )
6343
return false ;
6344
ImGuiID id = window-> GetID ( label ) ;
6345
return TreeNodeBehavior ( id, ImGuiTreeNodeFlags_None, label, NULL ) ;
6346
}
6347
6348
bool ImGui:: TreeNodeV ( const char * str_id , const char * fmt , va_list args )
6349
{
6350
return TreeNodeExV ( str_id, 0 , fmt, args ) ;
6351
}
6352
6353
bool ImGui:: TreeNodeV ( const void * ptr_id , const char * fmt , va_list args )
6354
{
6355
return TreeNodeExV ( ptr_id, 0 , fmt, args ) ;
6356
}
6357
6358
bool ImGui:: TreeNodeEx ( const char * label , ImGuiTreeNodeFlags flags )
6359
{
6360
ImGuiWindow* window = GetCurrentWindow ( ) ;
6361
if ( window-> SkipItems )
6362
return false ;
6363
ImGuiID id = window-> GetID ( label ) ;
6364
return TreeNodeBehavior ( id, flags, label, NULL ) ;
6365
}
6366
6367
bool ImGui:: TreeNodeEx ( const char * str_id , ImGuiTreeNodeFlags flags , const char * fmt , ... )
6368
{
6369
va_list args;
6370
va_start ( args, fmt ) ;
6371
bool is_open = TreeNodeExV ( str_id, flags, fmt, args ) ;
6372
va_end ( args ) ;
6373
return is_open;
6374
}
6375
6376
bool ImGui:: TreeNodeEx ( const void * ptr_id , ImGuiTreeNodeFlags flags , const char * fmt , ... )
6377
{
6378
va_list args;
6379
va_start ( args, fmt ) ;
6380
bool is_open = TreeNodeExV ( ptr_id, flags, fmt, args ) ;
6381
va_end ( args ) ;
6382
return is_open;
6383
}
6384
6385
bool ImGui:: TreeNodeExV ( const char * str_id , ImGuiTreeNodeFlags flags , const char * fmt , va_list args )
6386
{
6387
ImGuiWindow* window = GetCurrentWindow ( ) ;
6388
if ( window-> SkipItems )
6389
return false ;
6390
6391
ImGuiID id = window-> GetID ( str_id ) ;
6392
const char * label, * label_end;
6393
ImFormatStringToTempBufferV ( & label, & label_end, fmt, args) ;
6394
return TreeNodeBehavior ( id, flags, label, label_end ) ;
6395
}
6396
6397
bool ImGui:: TreeNodeExV ( const void * ptr_id , ImGuiTreeNodeFlags flags , const char * fmt , va_list args )
6398
{
6399
ImGuiWindow* window = GetCurrentWindow ( ) ;
6400
if ( window-> SkipItems )
6401
return false ;
6402
6403
ImGuiID id = window-> GetID ( ptr_id ) ;
6404
const char * label, * label_end;
6405
ImFormatStringToTempBufferV ( & label, & label_end, fmt, args) ;
6406
return TreeNodeBehavior ( id, flags, label, label_end ) ;
6407
}
6408
6409
bool ImGui:: TreeNodeGetOpen ( ImGuiID storage_id )
6410
{
6411
ImGuiContext& g = * GImGui;
6412
ImGuiStorage* storage = g. CurrentWindow -> DC . StateStorage ;
6413
return storage-> GetInt ( storage_id, 0 ) != 0 ;
6414
}
6415
6416
void ImGui:: TreeNodeSetOpen ( ImGuiID storage_id , bool open )
6417
{
6418
ImGuiContext& g = * GImGui;
6419
ImGuiStorage* storage = g. CurrentWindow -> DC . StateStorage ;
6420
storage-> SetInt ( storage_id, open ? 1 : 0 ) ;
6421
}
6422
6423
bool ImGui:: TreeNodeUpdateNextOpen ( ImGuiID storage_id , ImGuiTreeNodeFlags flags )
6424
{
6425
if ( flags & ImGuiTreeNodeFlags_Leaf)
6426
return true ;
6427
6428
6429
ImGuiContext& g = * GImGui;
6430
ImGuiWindow* window = g. CurrentWindow ;
6431
ImGuiStorage* storage = window-> DC . StateStorage ;
6432
6433
bool is_open;
6434
if ( g. NextItemData . HasFlags & ImGuiNextItemDataFlags_HasOpen)
6435
{
6436
if ( g. NextItemData . OpenCond & ImGuiCond_Always)
6437
{
6438
is_open = g. NextItemData . OpenVal ;
6439
TreeNodeSetOpen ( storage_id, is_open ) ;
6440
}
6441
else
6442
{
6443
6444
const int stored_value = storage-> GetInt ( storage_id, - 1 ) ;
6445
if ( stored_value == - 1 )
6446
{
6447
is_open = g. NextItemData . OpenVal ;
6448
TreeNodeSetOpen ( storage_id, is_open ) ;
6449
}
6450
else
6451
{
6452
is_open = stored_value != 0 ;
6453
}
6454
}
6455
}
6456
else
6457
{
6458
is_open = storage-> GetInt ( storage_id, ( flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0 ) != 0 ;
6459
}
6460
6461
6462
6463
if ( g. LogEnabled && ! ( flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && ( window-> DC . TreeDepth - g. LogDepthRef ) < g. LogDepthToExpand )
6464
is_open = true ;
6465
6466
return is_open;
6467
}
6468
6469
6470
6471
static void TreeNodeStoreStackData ( ImGuiTreeNodeFlags flags )
6472
{
6473
ImGuiContext& g = * GImGui;
6474
ImGuiWindow* window = g. CurrentWindow ;
6475
6476
g. TreeNodeStack . resize ( g. TreeNodeStack . Size + 1 ) ;
6477
ImGuiTreeNodeStackData* tree_node_data = & g. TreeNodeStack . back ( ) ;
6478
tree_node_data-> ID = g. LastItemData . ID ;
6479
tree_node_data-> TreeFlags = flags;
6480
tree_node_data-> ItemFlags = g. LastItemData . ItemFlags ;
6481
tree_node_data-> NavRect = g. LastItemData . NavRect ;
6482
window-> DC . TreeHasStackDataDepthMask |= ( 1 << window-> DC . TreeDepth ) ;
6483
}
6484
6485
6486
bool ImGui:: TreeNodeBehavior ( ImGuiID id , ImGuiTreeNodeFlags flags , const char * label , const char * label_end )
6487
{
6488
ImGuiWindow* window = GetCurrentWindow ( ) ;
6489
if ( window-> SkipItems )
6490
return false ;
6491
6492
ImGuiContext& g = * GImGui;
6493
const ImGuiStyle& style = g. Style ;
6494
const bool display_frame = ( flags & ImGuiTreeNodeFlags_Framed) != 0 ;
6495
const ImVec2 padding = ( display_frame || ( flags & ImGuiTreeNodeFlags_FramePadding) ) ? style. FramePadding : ImVec2 ( style. FramePadding . x , ImMin ( window-> DC . CurrLineTextBaseOffset , style. FramePadding . y ) ) ;
6496
6497
if ( ! label_end)
6498
label_end = FindRenderedTextEnd ( label ) ;
6499
const ImVec2 label_size = CalcTextSize ( label, label_end, false ) ;
6500
6501
const float text_offset_x = g. FontSize + ( display_frame ? padding. x * 3 : padding. x * 2 ) ;
6502
const float text_offset_y = ImMax ( padding. y , window-> DC . CurrLineTextBaseOffset ) ;
6503
const float text_width = g. FontSize + label_size. x + padding. x * 2 ;
6504
6505
6506
const float frame_height = ImMax ( ImMin ( window-> DC . CurrLineSize . y , g. FontSize + style. FramePadding . y * 2 ) , label_size. y + padding. y * 2 ) ;
6507
const bool span_all_columns = ( flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && ( g. CurrentTable != NULL ) ;
6508
ImRect frame_bb;
6509
frame_bb. Min . x = span_all_columns ? window-> ParentWorkRect . Min . x : ( flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window-> WorkRect . Min . x : window-> DC . CursorPos . x ;
6510
frame_bb. Min . y = window-> DC . CursorPos . y ;
6511
frame_bb. Max . x = span_all_columns ? window-> ParentWorkRect . Max . x : ( flags & ImGuiTreeNodeFlags_SpanTextWidth) ? window-> DC . CursorPos . x + text_width + padding. x : window-> WorkRect . Max . x ;
6512
frame_bb. Max . y = window-> DC . CursorPos . y + frame_height;
6513
if ( display_frame)
6514
{
6515
const float outer_extend = IM_TRUNC ( window-> WindowPadding . x * 0.5f ) ;
6516
frame_bb. Min . x -= outer_extend;
6517
frame_bb. Max . x += outer_extend;
6518
}
6519
6520
ImVec2 text_pos ( window-> DC . CursorPos . x + text_offset_x, window-> DC . CursorPos . y + text_offset_y ) ;
6521
ItemSize ( ImVec2 ( text_width, frame_height ) , padding. y ) ;
6522
6523
6524
ImRect interact_bb = frame_bb;
6525
if ( ( flags & ( ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanTextWidth | ImGuiTreeNodeFlags_SpanAllColumns) ) == 0 )
6526
interact_bb. Max . x = frame_bb. Min . x + text_width + ( label_size. x > 0.0f ? style. ItemSpacing . x * 2.0f : 0.0f ) ;
6527
6528
6529
ImGuiID storage_id = ( g. NextItemData . HasFlags & ImGuiNextItemDataFlags_HasStorageID) ? g. NextItemData . StorageId : id;
6530
bool is_open = TreeNodeUpdateNextOpen ( storage_id, flags ) ;
6531
6532
bool is_visible;
6533
if ( span_all_columns)
6534
{
6535
6536
const float backup_clip_rect_min_x = window-> ClipRect . Min . x ;
6537
const float backup_clip_rect_max_x = window-> ClipRect . Max . x ;
6538
window-> ClipRect . Min . x = window-> ParentWorkRect . Min . x ;
6539
window-> ClipRect . Max . x = window-> ParentWorkRect . Max . x ;
6540
is_visible = ItemAdd ( interact_bb, id ) ;
6541
window-> ClipRect . Min . x = backup_clip_rect_min_x;
6542
window-> ClipRect . Max . x = backup_clip_rect_max_x;
6543
}
6544
else
6545
{
6546
is_visible = ItemAdd ( interact_bb, id ) ;
6547
}
6548
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
6549
g. LastItemData . DisplayRect = frame_bb;
6550
6551
6552
6553
6554
6555
bool store_tree_node_stack_data = false ;
6556
if ( ! ( flags & ImGuiTreeNodeFlags_NoTreePushOnOpen) )
6557
{
6558
if ( ( flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && is_open && ! g. NavIdIsAlive )
6559
if ( g. NavMoveDir == ImGuiDir_Left && g. NavWindow == window && NavMoveRequestButNoResultYet ( ) )
6560
store_tree_node_stack_data = true ;
6561
}
6562
6563
const bool is_leaf = ( flags & ImGuiTreeNodeFlags_Leaf) != 0 ;
6564
if ( ! is_visible)
6565
{
6566
if ( store_tree_node_stack_data && is_open)
6567
TreeNodeStoreStackData ( flags ) ;
6568
if ( is_open && ! ( flags & ImGuiTreeNodeFlags_NoTreePushOnOpen) )
6569
TreePushOverrideID ( id ) ;
6570
IMGUI_TEST_ENGINE_ITEM_INFO ( g. LastItemData . ID , label, g. LastItemData . StatusFlags | ( is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | ( is_open ? ImGuiItemStatusFlags_Opened : 0 ) ) ;
6571
return is_open;
6572
}
6573
6574
if ( span_all_columns)
6575
{
6576
TablePushBackgroundChannel ( ) ;
6577
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HasClipRect;
6578
g. LastItemData . ClipRect = window-> ClipRect ;
6579
}
6580
6581
ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;
6582
if ( ( flags & ImGuiTreeNodeFlags_AllowOverlap) || ( g. LastItemData . ItemFlags & ImGuiItemFlags_AllowOverlap) )
6583
button_flags |= ImGuiButtonFlags_AllowOverlap;
6584
if ( ! is_leaf)
6585
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
6586
6587
6588
6589
6590
const float arrow_hit_x1 = ( text_pos. x - text_offset_x) - style. TouchExtraPadding . x ;
6591
const float arrow_hit_x2 = ( text_pos. x - text_offset_x) + ( g. FontSize + padding. x * 2.0f ) + style. TouchExtraPadding . x ;
6592
const bool is_mouse_x_over_arrow = ( g. IO . MousePos . x >= arrow_hit_x1 && g. IO . MousePos . x < arrow_hit_x2) ;
6593
6594
const bool is_multi_select = ( g. LastItemData . ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0 ;
6595
if ( is_multi_select)
6596
flags |= ( flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick : ImGuiTreeNodeFlags_OpenOnArrow;
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
if ( is_mouse_x_over_arrow)
6608
button_flags |= ImGuiButtonFlags_PressedOnClick;
6609
else if ( flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
6610
button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
6611
else
6612
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
6613
6614
bool selected = ( flags & ImGuiTreeNodeFlags_Selected) != 0 ;
6615
const bool was_selected = selected;
6616
6617
6618
if ( is_multi_select)
6619
{
6620
6621
MultiSelectItemHeader ( id, & selected, & button_flags ) ;
6622
if ( is_mouse_x_over_arrow)
6623
button_flags = ( button_flags | ImGuiButtonFlags_PressedOnClick) & ~ ImGuiButtonFlags_PressedOnClickRelease;
6624
}
6625
else
6626
{
6627
if ( window != g. HoveredWindow || ! is_mouse_x_over_arrow)
6628
button_flags |= ImGuiButtonFlags_NoKeyModsAllowed;
6629
}
6630
6631
bool hovered, held;
6632
bool pressed = ButtonBehavior ( interact_bb, id, & hovered, & held, button_flags ) ;
6633
bool toggled = false ;
6634
if ( ! is_leaf)
6635
{
6636
if ( pressed && g. DragDropHoldJustPressedId != id)
6637
{
6638
if ( ( flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 || ( g. NavActivateId == id && ! is_multi_select) )
6639
toggled = true ;
6640
if ( flags & ImGuiTreeNodeFlags_OpenOnArrow)
6641
toggled |= is_mouse_x_over_arrow && ! g. NavHighlightItemUnderNav ;
6642
if ( ( flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g. IO . MouseClickedCount [ 0 ] == 2 )
6643
toggled = true ;
6644
}
6645
else if ( pressed && g. DragDropHoldJustPressedId == id)
6646
{
6647
IM_ASSERT ( button_flags & ImGuiButtonFlags_PressedOnDragDropHold ) ;
6648
if ( ! is_open)
6649
toggled = true ;
6650
else
6651
pressed = false ;
6652
}
6653
6654
if ( g. NavId == id && g. NavMoveDir == ImGuiDir_Left && is_open)
6655
{
6656
toggled = true ;
6657
NavClearPreferredPosForAxis ( ImGuiAxis_X ) ;
6658
NavMoveRequestCancel ( ) ;
6659
}
6660
if ( g. NavId == id && g. NavMoveDir == ImGuiDir_Right && ! is_open)
6661
{
6662
toggled = true ;
6663
NavClearPreferredPosForAxis ( ImGuiAxis_X ) ;
6664
NavMoveRequestCancel ( ) ;
6665
}
6666
6667
if ( toggled)
6668
{
6669
is_open = ! is_open;
6670
window-> DC . StateStorage -> SetInt ( storage_id, is_open ) ;
6671
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
6672
}
6673
}
6674
6675
6676
if ( is_multi_select)
6677
{
6678
bool pressed_copy = pressed && ! toggled;
6679
MultiSelectItemFooter ( id, & selected, & pressed_copy ) ;
6680
if ( pressed)
6681
SetNavID ( id, window-> DC . NavLayerCurrent , g. CurrentFocusScopeId , interact_bb ) ;
6682
}
6683
6684
if ( selected != was_selected)
6685
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
6686
6687
6688
{
6689
const ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
6690
ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact;
6691
if ( is_multi_select)
6692
nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw;
6693
if ( display_frame)
6694
{
6695
6696
const ImU32 bg_col = GetColorU32 ( ( held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header) ;
6697
RenderFrame ( frame_bb. Min , frame_bb. Max , bg_col, true , style. FrameRounding ) ;
6698
RenderNavCursor ( frame_bb, id, nav_render_cursor_flags ) ;
6699
if ( flags & ImGuiTreeNodeFlags_Bullet)
6700
RenderBullet ( window-> DrawList , ImVec2 ( text_pos. x - text_offset_x * 0.60f , text_pos. y + g. FontSize * 0.5f ) , text_col ) ;
6701
else if ( ! is_leaf)
6702
RenderArrow ( window-> DrawList , ImVec2 ( text_pos. x - text_offset_x + padding. x , text_pos. y ) , text_col, is_open ? ( ( flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f ) ;
6703
else
6704
text_pos. x -= text_offset_x - padding. x ;
6705
if ( flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)
6706
frame_bb. Max . x -= g. FontSize + style. FramePadding . x ;
6707
if ( g. LogEnabled )
6708
LogSetNextTextDecoration ( " ###" , " ###" ) ;
6709
}
6710
else
6711
{
6712
6713
if ( hovered || selected)
6714
{
6715
const ImU32 bg_col = GetColorU32 ( ( held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header) ;
6716
RenderFrame ( frame_bb. Min , frame_bb. Max , bg_col, false ) ;
6717
}
6718
RenderNavCursor ( frame_bb, id, nav_render_cursor_flags ) ;
6719
if ( flags & ImGuiTreeNodeFlags_Bullet)
6720
RenderBullet ( window-> DrawList , ImVec2 ( text_pos. x - text_offset_x * 0.5f , text_pos. y + g. FontSize * 0.5f ) , text_col ) ;
6721
else if ( ! is_leaf)
6722
RenderArrow ( window-> DrawList , ImVec2 ( text_pos. x - text_offset_x + padding. x , text_pos. y + g. FontSize * 0.15f ) , text_col, is_open ? ( ( flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f ) ;
6723
if ( g. LogEnabled )
6724
LogSetNextTextDecoration ( " >" , NULL ) ;
6725
}
6726
6727
if ( span_all_columns)
6728
TablePopBackgroundChannel ( ) ;
6729
6730
6731
if ( display_frame)
6732
RenderTextClipped ( text_pos, frame_bb. Max , label, label_end, & label_size ) ;
6733
else
6734
RenderText ( text_pos, label, label_end, false ) ;
6735
}
6736
6737
if ( store_tree_node_stack_data && is_open)
6738
TreeNodeStoreStackData ( flags ) ;
6739
if ( is_open && ! ( flags & ImGuiTreeNodeFlags_NoTreePushOnOpen) )
6740
TreePushOverrideID ( id ) ;
6741
6742
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ( is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | ( is_open ? ImGuiItemStatusFlags_Opened : 0 ) ) ;
6743
return is_open;
6744
}
6745
6746
void ImGui:: TreePush ( const char * str_id )
6747
{
6748
ImGuiWindow* window = GetCurrentWindow ( ) ;
6749
Indent ( ) ;
6750
window-> DC . TreeDepth + + ;
6751
PushID ( str_id ) ;
6752
}
6753
6754
void ImGui:: TreePush ( const void * ptr_id )
6755
{
6756
ImGuiWindow* window = GetCurrentWindow ( ) ;
6757
Indent ( ) ;
6758
window-> DC . TreeDepth + + ;
6759
PushID ( ptr_id ) ;
6760
}
6761
6762
void ImGui:: TreePushOverrideID ( ImGuiID id )
6763
{
6764
ImGuiContext& g = * GImGui;
6765
ImGuiWindow* window = g. CurrentWindow ;
6766
Indent ( ) ;
6767
window-> DC . TreeDepth + + ;
6768
PushOverrideID ( id ) ;
6769
}
6770
6771
void ImGui:: TreePop ( )
6772
{
6773
ImGuiContext& g = * GImGui;
6774
ImGuiWindow* window = g. CurrentWindow ;
6775
Unindent ( ) ;
6776
6777
window-> DC . TreeDepth - - ;
6778
ImU32 tree_depth_mask = ( 1 << window-> DC . TreeDepth ) ;
6779
6780
if ( window-> DC . TreeHasStackDataDepthMask & tree_depth_mask)
6781
{
6782
ImGuiTreeNodeStackData* data = & g. TreeNodeStack . back ( ) ;
6783
IM_ASSERT ( data-> ID == window-> IDStack . back ( ) ) ;
6784
if ( data-> TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere)
6785
{
6786
6787
if ( g. NavIdIsAlive && g. NavMoveDir == ImGuiDir_Left && g. NavWindow == window && NavMoveRequestButNoResultYet ( ) )
6788
NavMoveRequestResolveWithPastTreeNode ( & g. NavMoveResultLocal , data) ;
6789
}
6790
g. TreeNodeStack . pop_back ( ) ;
6791
window-> DC . TreeHasStackDataDepthMask &= ~ tree_depth_mask;
6792
}
6793
6794
IM_ASSERT ( window-> IDStack . Size > 1 ) ;
6795
PopID ( ) ;
6796
}
6797
6798
6799
float ImGui:: GetTreeNodeToLabelSpacing ( )
6800
{
6801
ImGuiContext& g = * GImGui;
6802
return g. FontSize + ( g. Style . FramePadding . x * 2.0f ) ;
6803
}
6804
6805
6806
void ImGui:: SetNextItemOpen ( bool is_open , ImGuiCond cond )
6807
{
6808
ImGuiContext& g = * GImGui;
6809
if ( g. CurrentWindow -> SkipItems )
6810
return ;
6811
g. NextItemData . HasFlags |= ImGuiNextItemDataFlags_HasOpen;
6812
g. NextItemData . OpenVal = is_open;
6813
g. NextItemData . OpenCond = ( ImU8) ( cond ? cond : ImGuiCond_Always) ;
6814
}
6815
6816
6817
void ImGui:: SetNextItemStorageID ( ImGuiID storage_id )
6818
{
6819
ImGuiContext& g = * GImGui;
6820
if ( g. CurrentWindow -> SkipItems )
6821
return ;
6822
g. NextItemData . HasFlags |= ImGuiNextItemDataFlags_HasStorageID;
6823
g. NextItemData . StorageId = storage_id;
6824
}
6825
6826
6827
6828
bool ImGui:: CollapsingHeader ( const char * label , ImGuiTreeNodeFlags flags )
6829
{
6830
ImGuiWindow* window = GetCurrentWindow ( ) ;
6831
if ( window-> SkipItems )
6832
return false ;
6833
ImGuiID id = window-> GetID ( label ) ;
6834
return TreeNodeBehavior ( id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label ) ;
6835
}
6836
6837
6838
6839
6840
6841
bool ImGui:: CollapsingHeader ( const char * label , bool * p_visible , ImGuiTreeNodeFlags flags )
6842
{
6843
ImGuiWindow* window = GetCurrentWindow ( ) ;
6844
if ( window-> SkipItems )
6845
return false ;
6846
6847
if ( p_visible && ! * p_visible)
6848
return false ;
6849
6850
ImGuiID id = window-> GetID ( label ) ;
6851
flags |= ImGuiTreeNodeFlags_CollapsingHeader;
6852
if ( p_visible)
6853
flags |= ImGuiTreeNodeFlags_AllowOverlap | ( ImGuiTreeNodeFlags) ImGuiTreeNodeFlags_ClipLabelForTrailingButton;
6854
bool is_open = TreeNodeBehavior ( id, flags, label ) ;
6855
if ( p_visible != NULL )
6856
{
6857
6858
6859
6860
ImGuiContext& g = * GImGui;
6861
ImGuiLastItemData last_item_backup = g. LastItemData ;
6862
float button_size = g. FontSize ;
6863
float button_x = ImMax ( g. LastItemData . Rect . Min . x , g. LastItemData . Rect . Max . x - g. Style . FramePadding . x - button_size ) ;
6864
float button_y = g. LastItemData . Rect . Min . y + g. Style . FramePadding . y ;
6865
ImGuiID close_button_id = GetIDWithSeed ( " #CLOSE" , NULL , id) ;
6866
if ( CloseButton ( close_button_id, ImVec2 ( button_x, button_y ) ) )
6867
* p_visible = false ;
6868
g. LastItemData = last_item_backup;
6869
}
6870
6871
return is_open;
6872
}
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
6884
bool ImGui:: Selectable ( const char * label , bool selected , ImGuiSelectableFlags flags , const ImVec2& size_arg )
6885
{
6886
ImGuiWindow* window = GetCurrentWindow ( ) ;
6887
if ( window-> SkipItems )
6888
return false ;
6889
6890
ImGuiContext& g = * GImGui;
6891
const ImGuiStyle& style = g. Style ;
6892
6893
6894
ImGuiID id = window-> GetID ( label ) ;
6895
ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
6896
ImVec2 size ( size_arg. x != 0.0f ? size_arg. x : label_size. x , size_arg. y != 0.0f ? size_arg. y : label_size. y ) ;
6897
ImVec2 pos = window-> DC . CursorPos ;
6898
pos. y += window-> DC . CurrLineTextBaseOffset ;
6899
ItemSize ( size, 0.0f ) ;
6900
6901
6902
6903
const bool span_all_columns = ( flags & ImGuiSelectableFlags_SpanAllColumns) != 0 ;
6904
const float min_x = span_all_columns ? window-> ParentWorkRect . Min . x : pos. x ;
6905
const float max_x = span_all_columns ? window-> ParentWorkRect . Max . x : window-> WorkRect . Max . x ;
6906
if ( size_arg. x == 0.0f || ( flags & ImGuiSelectableFlags_SpanAvailWidth) )
6907
size. x = ImMax ( label_size. x , max_x - min_x ) ;
6908
6909
6910
const ImVec2 text_min = pos;
6911
const ImVec2 text_max ( min_x + size. x , pos. y + size. y ) ;
6912
6913
6914
6915
ImRect bb ( min_x, pos. y , text_max. x , text_max. y ) ;
6916
if ( ( flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0 )
6917
{
6918
const float spacing_x = span_all_columns ? 0.0f : style. ItemSpacing . x ;
6919
const float spacing_y = style. ItemSpacing . y ;
6920
const float spacing_L = IM_TRUNC ( spacing_x * 0.50f ) ;
6921
const float spacing_U = IM_TRUNC ( spacing_y * 0.50f ) ;
6922
bb. Min . x -= spacing_L;
6923
bb. Min . y -= spacing_U;
6924
bb. Max . x += ( spacing_x - spacing_L) ;
6925
bb. Max . y += ( spacing_y - spacing_U) ;
6926
}
6927
6928
6929
const bool disabled_item = ( flags & ImGuiSelectableFlags_Disabled) != 0 ;
6930
const ImGuiItemFlags extra_item_flags = disabled_item ? ( ImGuiItemFlags) ImGuiItemFlags_Disabled : ImGuiItemFlags_None;
6931
bool is_visible;
6932
if ( span_all_columns)
6933
{
6934
6935
const float backup_clip_rect_min_x = window-> ClipRect . Min . x ;
6936
const float backup_clip_rect_max_x = window-> ClipRect . Max . x ;
6937
window-> ClipRect . Min . x = window-> ParentWorkRect . Min . x ;
6938
window-> ClipRect . Max . x = window-> ParentWorkRect . Max . x ;
6939
is_visible = ItemAdd ( bb, id, NULL , extra_item_flags ) ;
6940
window-> ClipRect . Min . x = backup_clip_rect_min_x;
6941
window-> ClipRect . Max . x = backup_clip_rect_max_x;
6942
}
6943
else
6944
{
6945
is_visible = ItemAdd ( bb, id, NULL , extra_item_flags ) ;
6946
}
6947
6948
const bool is_multi_select = ( g. LastItemData . ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0 ;
6949
if ( ! is_visible)
6950
if ( ! is_multi_select || ! g. BoxSelectState . UnclipMode || ! g. BoxSelectState . UnclipRect . Overlaps ( bb ) )
6951
return false ;
6952
6953
const bool disabled_global = ( g. CurrentItemFlags & ImGuiItemFlags_Disabled) != 0 ;
6954
if ( disabled_item && ! disabled_global)
6955
BeginDisabled ( ) ;
6956
6957
6958
6959
if ( span_all_columns)
6960
{
6961
if ( g. CurrentTable )
6962
TablePushBackgroundChannel ( ) ;
6963
else if ( window-> DC . CurrentColumns )
6964
PushColumnsBackground ( ) ;
6965
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HasClipRect;
6966
g. LastItemData . ClipRect = window-> ClipRect ;
6967
}
6968
6969
6970
ImGuiButtonFlags button_flags = 0 ;
6971
if ( flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; }
6972
if ( flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; }
6973
if ( flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }
6974
if ( flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
6975
if ( flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }
6976
if ( ( flags & ImGuiSelectableFlags_AllowOverlap) || ( g. LastItemData . ItemFlags & ImGuiItemFlags_AllowOverlap) ) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
6977
6978
6979
const bool was_selected = selected;
6980
if ( is_multi_select)
6981
{
6982
6983
MultiSelectItemHeader ( id, & selected, & button_flags ) ;
6984
}
6985
6986
bool hovered, held;
6987
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, button_flags ) ;
6988
6989
6990
if ( is_multi_select)
6991
{
6992
MultiSelectItemFooter ( id, & selected, & pressed ) ;
6993
}
6994
else
6995
{
6996
6997
6998
6999
7000
7001
7002
7003
if ( ( flags & ImGuiSelectableFlags_SelectOnNav) && g. NavJustMovedToId != 0 && g. NavJustMovedToFocusScopeId == g. CurrentFocusScopeId )
7004
if ( g. NavJustMovedToId == id)
7005
selected = pressed = true ;
7006
}
7007
7008
7009
if ( pressed || ( hovered && ( flags & ImGuiSelectableFlags_SetNavIdOnHover) ) )
7010
{
7011
if ( ! g. NavHighlightItemUnderNav && g. NavWindow == window && g. NavLayer == window-> DC . NavLayerCurrent )
7012
{
7013
SetNavID ( id, window-> DC . NavLayerCurrent , g. CurrentFocusScopeId , WindowRectAbsToRel ( window, bb ) ) ;
7014
if ( g. IO . ConfigNavCursorVisibleAuto )
7015
g. NavCursorVisible = false ;
7016
}
7017
}
7018
if ( pressed)
7019
MarkItemEdited ( id ) ;
7020
7021
if ( selected != was_selected)
7022
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
7023
7024
7025
if ( is_visible)
7026
{
7027
const bool highlighted = hovered || ( flags & ImGuiSelectableFlags_Highlight) ;
7028
if ( highlighted || selected)
7029
{
7030
7031
ImU32 col = GetColorU32 ( ( held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header) ;
7032
RenderFrame ( bb. Min , bb. Max , col, false , 0.0f ) ;
7033
}
7034
if ( g. NavId == id)
7035
{
7036
ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding;
7037
if ( is_multi_select)
7038
nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw;
7039
RenderNavCursor ( bb, id, nav_render_cursor_flags ) ;
7040
}
7041
}
7042
7043
if ( span_all_columns)
7044
{
7045
if ( g. CurrentTable )
7046
TablePopBackgroundChannel ( ) ;
7047
else if ( window-> DC . CurrentColumns )
7048
PopColumnsBackground ( ) ;
7049
}
7050
7051
if ( is_visible)
7052
RenderTextClipped ( text_min, text_max, label, NULL , & label_size, style. SelectableTextAlign , & bb ) ;
7053
7054
7055
if ( pressed && ( window-> Flags & ImGuiWindowFlags_Popup) && ! ( flags & ImGuiSelectableFlags_NoAutoClosePopups) && ( g. LastItemData . ItemFlags & ImGuiItemFlags_AutoClosePopups) )
7056
CloseCurrentPopup ( ) ;
7057
7058
if ( disabled_item && ! disabled_global)
7059
EndDisabled ( ) ;
7060
7061
7062
7063
7064
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags ) ;
7065
return pressed;
7066
}
7067
7068
bool ImGui:: Selectable ( const char * label , bool * p_selected , ImGuiSelectableFlags flags , const ImVec2& size_arg )
7069
{
7070
if ( Selectable ( label, * p_selected, flags, size_arg ) )
7071
{
7072
* p_selected = ! * p_selected;
7073
return true ;
7074
}
7075
return false ;
7076
}
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
ImGuiTypingSelectRequest* ImGui:: GetTypingSelectRequest ( ImGuiTypingSelectFlags flags )
7091
{
7092
ImGuiContext& g = * GImGui;
7093
ImGuiTypingSelectState* data = & g. TypingSelectState ;
7094
ImGuiTypingSelectRequest* out_request = & data-> Request ;
7095
7096
7097
const float TYPING_SELECT_RESET_TIMER = 1.80f ;
7098
const int TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK = 4 ;
7099
if ( data-> SearchBuffer [ 0 ] != 0 )
7100
{
7101
bool clear_buffer = false ;
7102
clear_buffer |= ( g. NavFocusScopeId != data-> FocusScope ) ;
7103
clear_buffer |= ( data-> LastRequestTime + TYPING_SELECT_RESET_TIMER < g. Time ) ;
7104
clear_buffer |= g. NavAnyRequest ;
7105
clear_buffer |= g. ActiveId != 0 && g. NavActivateId == 0 ;
7106
clear_buffer |= IsKeyPressed ( ImGuiKey_Escape ) || IsKeyPressed ( ImGuiKey_Enter ) ;
7107
clear_buffer |= IsKeyPressed ( ImGuiKey_Backspace ) && ( flags & ImGuiTypingSelectFlags_AllowBackspace) == 0 ;
7108
7109
if ( clear_buffer)
7110
data-> Clear ( ) ;
7111
}
7112
7113
7114
const int buffer_max_len = IM_ARRAYSIZE ( data-> SearchBuffer ) - 1 ;
7115
int buffer_len = ( int ) strlen ( data-> SearchBuffer ) ;
7116
bool select_request = false ;
7117
for ( ImWchar w : g. IO . InputQueueCharacters )
7118
{
7119
const int w_len = ImTextCountUtf8BytesFromStr ( & w, & w + 1 ) ;
7120
if ( w < 32 || ( buffer_len == 0 && ImCharIsBlankW ( w ) ) || ( buffer_len + w_len > buffer_max_len) )
7121
continue ;
7122
char w_buf[ 5 ] ;
7123
ImTextCharToUtf8 ( w_buf, ( unsigned int ) w ) ;
7124
if ( data-> SingleCharModeLock && w_len == out_request-> SingleCharSize && memcmp ( w_buf, data-> SearchBuffer , w_len ) == 0 )
7125
{
7126
select_request = true ;
7127
continue ;
7128
}
7129
if ( data-> SingleCharModeLock )
7130
{
7131
data-> Clear ( ) ;
7132
buffer_len = 0 ;
7133
}
7134
memcpy ( data-> SearchBuffer + buffer_len, w_buf, w_len + 1 ) ;
7135
buffer_len += w_len;
7136
select_request = true ;
7137
}
7138
g. IO . InputQueueCharacters . resize ( 0 ) ;
7139
7140
7141
if ( ( flags & ImGuiTypingSelectFlags_AllowBackspace) && IsKeyPressed ( ImGuiKey_Backspace, ImGuiInputFlags_Repeat ) )
7142
{
7143
char * p = ( char * ) ( void * ) ImTextFindPreviousUtf8Codepoint ( data-> SearchBuffer , data-> SearchBuffer + buffer_len ) ;
7144
* p = 0 ;
7145
buffer_len = ( int ) ( p - data-> SearchBuffer ) ;
7146
}
7147
7148
7149
if ( buffer_len == 0 )
7150
return NULL ;
7151
if ( select_request)
7152
{
7153
data-> FocusScope = g. NavFocusScopeId ;
7154
data-> LastRequestFrame = g. FrameCount ;
7155
data-> LastRequestTime = ( float ) g. Time ;
7156
}
7157
out_request-> Flags = flags;
7158
out_request-> SearchBufferLen = buffer_len;
7159
out_request-> SearchBuffer = data-> SearchBuffer ;
7160
out_request-> SelectRequest = ( data-> LastRequestFrame == g. FrameCount ) ;
7161
out_request-> SingleCharMode = false ;
7162
out_request-> SingleCharSize = 0 ;
7163
7164
7165
7166
7167
7168
if ( flags & ImGuiTypingSelectFlags_AllowSingleCharMode)
7169
{
7170
const char * buf_begin = out_request-> SearchBuffer ;
7171
const char * buf_end = out_request-> SearchBuffer + out_request-> SearchBufferLen ;
7172
const int c0_len = ImTextCountUtf8BytesFromChar ( buf_begin, buf_end ) ;
7173
const char * p = buf_begin + c0_len;
7174
for ( ; p < buf_end; p += c0_len)
7175
if ( memcmp ( buf_begin, p, ( size_t ) c0_len ) != 0 )
7176
break ;
7177
const int single_char_count = ( p == buf_end) ? ( out_request-> SearchBufferLen / c0_len) : 0 ;
7178
out_request-> SingleCharMode = ( single_char_count > 0 || data-> SingleCharModeLock ) ;
7179
out_request-> SingleCharSize = ( ImS8) c0_len;
7180
data-> SingleCharModeLock |= ( single_char_count >= TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK) ;
7181
}
7182
7183
return out_request;
7184
}
7185
7186
static int ImStrimatchlen ( const char * s1 , const char * s1_end , const char * s2 )
7187
{
7188
int match_len = 0 ;
7189
while ( s1 < s1_end && ImToUpper ( * s1+ + ) == ImToUpper ( * s2+ + ) )
7190
match_len+ + ;
7191
return match_len;
7192
}
7193
7194
7195
7196
7197
7198
7199
7200
int ImGui:: TypingSelectFindMatch ( ImGuiTypingSelectRequest* req , int items_count , const char * ( * get_item_name_func) ( void * , int ) , void * user_data , int nav_item_idx )
7201
{
7202
if ( req == NULL || req-> SelectRequest == false )
7203
return - 1 ;
7204
int idx = - 1 ;
7205
if ( req-> SingleCharMode && ( req-> Flags & ImGuiTypingSelectFlags_AllowSingleCharMode) )
7206
idx = TypingSelectFindNextSingleCharMatch ( req, items_count, get_item_name_func, user_data, nav_item_idx ) ;
7207
else
7208
idx = TypingSelectFindBestLeadingMatch ( req, items_count, get_item_name_func, user_data ) ;
7209
if ( idx != - 1 )
7210
SetNavCursorVisibleAfterMove ( ) ;
7211
return idx;
7212
}
7213
7214
7215
int ImGui:: TypingSelectFindNextSingleCharMatch ( ImGuiTypingSelectRequest* req , int items_count , const char * ( * get_item_name_func) ( void * , int ) , void * user_data , int nav_item_idx )
7216
{
7217
7218
7219
7220
7221
int first_match_idx = - 1 ;
7222
bool return_next_match = false ;
7223
for ( int idx = 0 ; idx < items_count; idx+ + )
7224
{
7225
const char * item_name = get_item_name_func ( user_data, idx ) ;
7226
if ( ImStrimatchlen ( req-> SearchBuffer , req-> SearchBuffer + req-> SingleCharSize , item_name ) < req-> SingleCharSize )
7227
continue ;
7228
if ( return_next_match)
7229
return idx;
7230
if ( first_match_idx == - 1 && nav_item_idx == - 1 )
7231
return idx;
7232
if ( first_match_idx == - 1 )
7233
first_match_idx = idx;
7234
if ( nav_item_idx == idx)
7235
return_next_match = true ;
7236
}
7237
return first_match_idx;
7238
}
7239
7240
int ImGui:: TypingSelectFindBestLeadingMatch ( ImGuiTypingSelectRequest* req , int items_count , const char * ( * get_item_name_func) ( void * , int ) , void * user_data )
7241
{
7242
int longest_match_idx = - 1 ;
7243
int longest_match_len = 0 ;
7244
for ( int idx = 0 ; idx < items_count; idx+ + )
7245
{
7246
const char * item_name = get_item_name_func ( user_data, idx ) ;
7247
const int match_len = ImStrimatchlen ( req-> SearchBuffer , req-> SearchBuffer + req-> SearchBufferLen , item_name ) ;
7248
if ( match_len <= longest_match_len)
7249
continue ;
7250
longest_match_idx = idx;
7251
longest_match_len = match_len;
7252
if ( match_len == req-> SearchBufferLen )
7253
break ;
7254
}
7255
return longest_match_idx;
7256
}
7257
7258
void ImGui:: DebugNodeTypingSelectState ( ImGuiTypingSelectState* data )
7259
{
7260
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
7261
Text ( " SearchBuffer = \" %s \" " , data-> SearchBuffer ) ;
7262
Text ( " SingleCharMode = %d , Size = %d , Lock = %d " , data-> Request . SingleCharMode , data-> Request . SingleCharSize , data-> SingleCharModeLock ) ;
7263
Text ( " LastRequest = time: %.2f , frame: %d " , data-> LastRequestTime , data-> LastRequestFrame ) ;
7264
#else
7265
IM_UNUSED ( data ) ;
7266
#endif
7267
}
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
static void BoxSelectPreStartDrag ( ImGuiID id , ImGuiSelectionUserData clicked_item )
7285
{
7286
ImGuiContext& g = * GImGui;
7287
ImGuiBoxSelectState* bs = & g. BoxSelectState ;
7288
bs-> ID = id;
7289
bs-> IsStarting = true ;
7290
bs-> IsStartedFromVoid = ( clicked_item == ImGuiSelectionUserData_Invalid) ;
7291
bs-> IsStartedSetNavIdOnce = bs-> IsStartedFromVoid ;
7292
bs-> KeyMods = g. IO . KeyMods ;
7293
bs-> StartPosRel = bs-> EndPosRel = ImGui:: WindowPosAbsToRel ( g. CurrentWindow , g. IO . MousePos ) ;
7294
bs-> ScrollAccum = ImVec2 ( 0.0f , 0.0f ) ;
7295
}
7296
7297
static void BoxSelectActivateDrag ( ImGuiBoxSelectState* bs , ImGuiWindow* window )
7298
{
7299
ImGuiContext& g = * GImGui;
7300
IMGUI_DEBUG_LOG_SELECTION ( " [selection] BeginBoxSelect() 0X%08X : Activate\n " , bs-> ID ) ;
7301
bs-> IsActive = true ;
7302
bs-> Window = window;
7303
bs-> IsStarting = false ;
7304
ImGui:: SetActiveID ( bs-> ID , window ) ;
7305
ImGui:: SetActiveIdUsingAllKeyboardKeys ( ) ;
7306
if ( bs-> IsStartedFromVoid && ( bs-> KeyMods & ( ImGuiMod_Ctrl | ImGuiMod_Shift) ) == 0 )
7307
bs-> RequestClear = true ;
7308
}
7309
7310
static void BoxSelectDeactivateDrag ( ImGuiBoxSelectState* bs )
7311
{
7312
ImGuiContext& g = * GImGui;
7313
bs-> IsActive = bs-> IsStarting = false ;
7314
if ( g. ActiveId == bs-> ID )
7315
{
7316
IMGUI_DEBUG_LOG_SELECTION ( " [selection] BeginBoxSelect() 0X%08X : Deactivate\n " , bs-> ID ) ;
7317
ImGui:: ClearActiveID ( ) ;
7318
}
7319
bs-> ID = 0 ;
7320
}
7321
7322
static void BoxSelectScrollWithMouseDrag ( ImGuiBoxSelectState* bs , ImGuiWindow* window , const ImRect& inner_r )
7323
{
7324
ImGuiContext& g = * GImGui;
7325
IM_ASSERT ( bs-> Window == window ) ;
7326
for ( int n = 0 ; n < 2 ; n+ + )
7327
{
7328
const float mouse_pos = g. IO . MousePos [ n] ;
7329
const float dist = ( mouse_pos > inner_r. Max [ n] ) ? mouse_pos - inner_r. Max [ n] : ( mouse_pos < inner_r. Min [ n] ) ? mouse_pos - inner_r. Min [ n] : 0.0f ;
7330
const float scroll_curr = window-> Scroll [ n] ;
7331
if ( dist == 0.0f || ( dist < 0.0f && scroll_curr < 0.0f ) || ( dist > 0.0f && scroll_curr >= window-> ScrollMax [ n] ) )
7332
continue ;
7333
7334
const float speed_multiplier = ImLinearRemapClamp ( g. FontSize , g. FontSize * 5.0f , 1.0f , 4.0f , ImAbs ( dist ) ) ;
7335
const float scroll_step = g. FontSize * 35.0f * speed_multiplier * ImSign ( dist ) * g. IO . DeltaTime ;
7336
bs-> ScrollAccum [ n] += scroll_step;
7337
7338
7339
const float scroll_step_i = ImFloor ( bs-> ScrollAccum [ n] ) ;
7340
if ( scroll_step_i == 0.0f )
7341
continue ;
7342
if ( n == 0 )
7343
ImGui:: SetScrollX ( window, scroll_curr + scroll_step_i ) ;
7344
else
7345
ImGui:: SetScrollY ( window, scroll_curr + scroll_step_i ) ;
7346
bs-> ScrollAccum [ n] -= scroll_step_i;
7347
}
7348
}
7349
7350
bool ImGui:: BeginBoxSelect ( const ImRect& scope_rect , ImGuiWindow* window , ImGuiID box_select_id , ImGuiMultiSelectFlags ms_flags )
7351
{
7352
ImGuiContext& g = * GImGui;
7353
ImGuiBoxSelectState* bs = & g. BoxSelectState ;
7354
KeepAliveID ( box_select_id ) ;
7355
if ( bs-> ID != box_select_id)
7356
return false ;
7357
7358
7359
bs-> UnclipMode = false ;
7360
bs-> RequestClear = false ;
7361
if ( bs-> IsStarting && IsMouseDragPastThreshold ( 0 ) )
7362
BoxSelectActivateDrag ( bs, window ) ;
7363
else if ( ( bs-> IsStarting || bs-> IsActive ) && g. IO . MouseDown [ 0 ] == false )
7364
BoxSelectDeactivateDrag ( bs ) ;
7365
if ( ! bs-> IsActive )
7366
return false ;
7367
7368
7369
7370
ImVec2 start_pos_abs = WindowPosRelToAbs ( window, bs-> StartPosRel ) ;
7371
ImVec2 prev_end_pos_abs = WindowPosRelToAbs ( window, bs-> EndPosRel ) ;
7372
ImVec2 curr_end_pos_abs = g. IO . MousePos ;
7373
if ( ms_flags & ImGuiMultiSelectFlags_ScopeWindow)
7374
curr_end_pos_abs = ImClamp ( curr_end_pos_abs, scope_rect. Min , scope_rect. Max ) ;
7375
bs-> BoxSelectRectPrev . Min = ImMin ( start_pos_abs, prev_end_pos_abs ) ;
7376
bs-> BoxSelectRectPrev . Max = ImMax ( start_pos_abs, prev_end_pos_abs ) ;
7377
bs-> BoxSelectRectCurr . Min = ImMin ( start_pos_abs, curr_end_pos_abs ) ;
7378
bs-> BoxSelectRectCurr . Max = ImMax ( start_pos_abs, curr_end_pos_abs ) ;
7379
7380
7381
7382
if ( ms_flags & ImGuiMultiSelectFlags_BoxSelect2d)
7383
if ( bs-> BoxSelectRectPrev . Min . x != bs-> BoxSelectRectCurr . Min . x || bs-> BoxSelectRectPrev . Max . x != bs-> BoxSelectRectCurr . Max . x )
7384
{
7385
bs-> UnclipMode = true ;
7386
bs-> UnclipRect = bs-> BoxSelectRectPrev ;
7387
bs-> UnclipRect . Add ( bs-> BoxSelectRectCurr ) ;
7388
}
7389
7390
7391
7392
7393
return true ;
7394
}
7395
7396
void ImGui:: EndBoxSelect ( const ImRect& scope_rect , ImGuiMultiSelectFlags ms_flags )
7397
{
7398
ImGuiContext& g = * GImGui;
7399
ImGuiWindow* window = g. CurrentWindow ;
7400
ImGuiBoxSelectState* bs = & g. BoxSelectState ;
7401
IM_ASSERT ( bs-> IsActive ) ;
7402
bs-> UnclipMode = false ;
7403
7404
7405
bs-> EndPosRel = WindowPosAbsToRel ( window, ImClamp ( g. IO . MousePos , scope_rect. Min , scope_rect. Max ) ) ;
7406
ImRect box_select_r = bs-> BoxSelectRectCurr ;
7407
box_select_r. ClipWith ( scope_rect ) ;
7408
window-> DrawList -> AddRectFilled ( box_select_r. Min , box_select_r. Max , GetColorU32 ( ImGuiCol_SeparatorHovered, 0.30f ) ) ;
7409
window-> DrawList -> AddRect ( box_select_r. Min , box_select_r. Max , GetColorU32 ( ImGuiCol_NavCursor ) ) ;
7410
7411
7412
const bool enable_scroll = ( ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && ( ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0 ;
7413
if ( enable_scroll)
7414
{
7415
ImRect scroll_r = scope_rect;
7416
scroll_r. Expand ( - g. FontSize ) ;
7417
7418
if ( ! scroll_r. Contains ( g. IO . MousePos ) )
7419
BoxSelectScrollWithMouseDrag ( bs, window, scroll_r ) ;
7420
}
7421
}
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
static void DebugLogMultiSelectRequests ( const char * function , const ImGuiMultiSelectIO* io )
7437
{
7438
ImGuiContext& g = * GImGui;
7439
IM_UNUSED ( function ) ;
7440
for ( const ImGuiSelectionRequest& req : io-> Requests )
7441
{
7442
if ( req. Type == ImGuiSelectionRequestType_SetAll) IMGUI_DEBUG_LOG_SELECTION ( " [selection] %s : Request: SetAll %d (= %s )\n " , function, req. Selected , req. Selected ? " SelectAll" : " Clear" ) ;
7443
if ( req. Type == ImGuiSelectionRequestType_SetRange) IMGUI_DEBUG_LOG_SELECTION ( " [selection] %s : Request: SetRange %" IM_PRId64 " ..%" IM_PRId64 " (0x%" IM_PRIX64 " ..0x%" IM_PRIX64 " ) = %d (dir %d )\n " , function, req. RangeFirstItem , req. RangeLastItem , req. RangeFirstItem , req. RangeLastItem , req. Selected , req. RangeDirection ) ;
7444
}
7445
}
7446
7447
static ImRect CalcScopeRect ( ImGuiMultiSelectTempData* ms , ImGuiWindow* window )
7448
{
7449
ImGuiContext& g = * GImGui;
7450
if ( ms-> Flags & ImGuiMultiSelectFlags_ScopeRect)
7451
{
7452
7453
return ImRect ( ms-> ScopeRectMin , ImMax ( window-> DC . CursorMaxPos , ms-> ScopeRectMin ) ) ;
7454
}
7455
else
7456
{
7457
7458
ImRect scope_rect = window-> InnerClipRect ;
7459
if ( g. CurrentTable != NULL )
7460
scope_rect = g. CurrentTable -> HostClipRect ;
7461
7462
7463
scope_rect. Min = ImMin ( scope_rect. Min + ImVec2 ( window-> DecoInnerSizeX1 , window-> DecoInnerSizeY1 ) , scope_rect. Max ) ;
7464
return scope_rect;
7465
}
7466
}
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
ImGuiMultiSelectIO* ImGui:: BeginMultiSelect ( ImGuiMultiSelectFlags flags , int selection_size , int items_count )
7477
{
7478
ImGuiContext& g = * GImGui;
7479
ImGuiWindow* window = g. CurrentWindow ;
7480
7481
if ( + + g. MultiSelectTempDataStacked > g. MultiSelectTempData . Size )
7482
g. MultiSelectTempData . resize ( g. MultiSelectTempDataStacked , ImGuiMultiSelectTempData ( ) ) ;
7483
ImGuiMultiSelectTempData* ms = & g. MultiSelectTempData [ g. MultiSelectTempDataStacked - 1 ] ;
7484
IM_STATIC_ASSERT ( offsetof ( ImGuiMultiSelectTempData, IO ) == 0 ) ;
7485
g. CurrentMultiSelect = ms;
7486
if ( ( flags & ( ImGuiMultiSelectFlags_ScopeWindow | ImGuiMultiSelectFlags_ScopeRect) ) == 0 )
7487
flags |= ImGuiMultiSelectFlags_ScopeWindow;
7488
if ( flags & ImGuiMultiSelectFlags_SingleSelect)
7489
flags &= ~ ( ImGuiMultiSelectFlags_BoxSelect2d | ImGuiMultiSelectFlags_BoxSelect1d) ;
7490
if ( flags & ImGuiMultiSelectFlags_BoxSelect2d)
7491
flags &= ~ ImGuiMultiSelectFlags_BoxSelect1d;
7492
7493
7494
const ImGuiID id = window-> IDStack . back ( ) ;
7495
ms-> Clear ( ) ;
7496
ms-> FocusScopeId = id;
7497
ms-> Flags = flags;
7498
ms-> IsFocused = ( ms-> FocusScopeId == g. NavFocusScopeId ) ;
7499
ms-> BackupCursorMaxPos = window-> DC . CursorMaxPos ;
7500
ms-> ScopeRectMin = window-> DC . CursorMaxPos = window-> DC . CursorPos ;
7501
PushFocusScope ( ms-> FocusScopeId ) ;
7502
if ( flags & ImGuiMultiSelectFlags_ScopeWindow)
7503
window-> DC . NavLayersActiveMask |= 1 << ImGuiNavLayer_Main;
7504
7505
7506
ms-> KeyMods = g. NavJustMovedToId ? ( g. NavJustMovedToIsTabbing ? 0 : g. NavJustMovedToKeyMods ) : g. IO . KeyMods ;
7507
if ( flags & ImGuiMultiSelectFlags_NoRangeSelect)
7508
ms-> KeyMods &= ~ ImGuiMod_Shift;
7509
7510
7511
ImGuiMultiSelectState* storage = g. MultiSelectStorage . GetOrAddByKey ( id ) ;
7512
storage-> ID = id;
7513
storage-> LastFrameActive = g. FrameCount ;
7514
storage-> LastSelectionSize = selection_size;
7515
storage-> Window = window;
7516
ms-> Storage = storage;
7517
7518
7519
ms-> IO . Requests . resize ( 0 ) ;
7520
ms-> IO . RangeSrcItem = storage-> RangeSrcItem ;
7521
ms-> IO . NavIdItem = storage-> NavIdItem ;
7522
ms-> IO . NavIdSelected = ( storage-> NavIdSelected == 1 ) ? true : false ;
7523
ms-> IO . ItemsCount = items_count;
7524
7525
7526
7527
bool request_clear = false ;
7528
bool request_select_all = false ;
7529
if ( g. NavJustMovedToId != 0 && g. NavJustMovedToFocusScopeId == ms-> FocusScopeId && g. NavJustMovedToHasSelectionData )
7530
{
7531
if ( ms-> KeyMods & ImGuiMod_Shift)
7532
ms-> IsKeyboardSetRange = true ;
7533
if ( ms-> IsKeyboardSetRange )
7534
IM_ASSERT ( storage-> RangeSrcItem != ImGuiSelectionUserData_Invalid ) ;
7535
if ( ( ms-> KeyMods & ( ImGuiMod_Ctrl | ImGuiMod_Shift) ) == 0 && ( flags & ( ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect) ) == 0 )
7536
request_clear = true ;
7537
}
7538
else if ( g. NavJustMovedFromFocusScopeId == ms-> FocusScopeId )
7539
{
7540
7541
if ( ( ms-> KeyMods & ( ImGuiMod_Ctrl | ImGuiMod_Shift) ) == 0 && ( flags & ( ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect) ) == 0 )
7542
request_clear = true ;
7543
}
7544
7545
7546
ImGuiBoxSelectState* bs = & g. BoxSelectState ;
7547
if ( flags & ( ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d) )
7548
{
7549
ms-> BoxSelectId = GetID ( " ##BoxSelect" ) ;
7550
if ( BeginBoxSelect ( CalcScopeRect ( ms, window ) , window, ms-> BoxSelectId , flags) )
7551
request_clear |= bs-> RequestClear ;
7552
}
7553
7554
if ( ms-> IsFocused )
7555
{
7556
7557
7558
7559
if ( flags & ImGuiMultiSelectFlags_ClearOnEscape)
7560
{
7561
if ( selection_size != 0 || bs-> IsActive )
7562
if ( Shortcut ( ImGuiKey_Escape, ImGuiInputFlags_None, bs-> IsActive ? bs-> ID : 0 ) )
7563
{
7564
request_clear = true ;
7565
if ( bs-> IsActive )
7566
BoxSelectDeactivateDrag ( bs ) ;
7567
}
7568
}
7569
7570
7571
if ( ! ( flags & ImGuiMultiSelectFlags_SingleSelect) && ! ( flags & ImGuiMultiSelectFlags_NoSelectAll) )
7572
if ( Shortcut ( ImGuiMod_Ctrl | ImGuiKey_A ) )
7573
request_select_all = true ;
7574
}
7575
7576
if ( request_clear || request_select_all)
7577
{
7578
MultiSelectAddSetAll ( ms, request_select_all ) ;
7579
if ( ! request_select_all)
7580
storage-> LastSelectionSize = 0 ;
7581
}
7582
ms-> LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : - 1 ;
7583
ms-> LastSubmittedItem = ImGuiSelectionUserData_Invalid;
7584
7585
if ( g. DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
7586
DebugLogMultiSelectRequests ( " BeginMultiSelect" , & ms-> IO ) ;
7587
7588
return & ms-> IO ;
7589
}
7590
7591
7592
7593
ImGuiMultiSelectIO* ImGui:: EndMultiSelect ( )
7594
{
7595
ImGuiContext& g = * GImGui;
7596
ImGuiMultiSelectTempData* ms = g. CurrentMultiSelect ;
7597
ImGuiMultiSelectState* storage = ms-> Storage ;
7598
ImGuiWindow* window = g. CurrentWindow ;
7599
IM_ASSERT_USER_ERROR ( ms-> FocusScopeId == g. CurrentFocusScopeId , " EndMultiSelect() FocusScope mismatch!" ) ;
7600
IM_ASSERT ( g. CurrentMultiSelect != NULL && storage-> Window == g. CurrentWindow ) ;
7601
IM_ASSERT ( g. MultiSelectTempDataStacked > 0 && & g. MultiSelectTempData [ g. MultiSelectTempDataStacked - 1 ] == g. CurrentMultiSelect ) ;
7602
7603
ImRect scope_rect = CalcScopeRect ( ms, window ) ;
7604
if ( ms-> IsFocused )
7605
{
7606
7607
if ( ms-> IO . RangeSrcReset || ( ms-> RangeSrcPassedBy == false && ms-> IO . RangeSrcItem != ImGuiSelectionUserData_Invalid) )
7608
{
7609
IMGUI_DEBUG_LOG_SELECTION ( " [selection] EndMultiSelect: Reset RangeSrcItem.\n " ) ;
7610
storage-> RangeSrcItem = ImGuiSelectionUserData_Invalid;
7611
}
7612
if ( ms-> NavIdPassedBy == false && storage-> NavIdItem != ImGuiSelectionUserData_Invalid)
7613
{
7614
IMGUI_DEBUG_LOG_SELECTION ( " [selection] EndMultiSelect: Reset NavIdItem.\n " ) ;
7615
storage-> NavIdItem = ImGuiSelectionUserData_Invalid;
7616
storage-> NavIdSelected = - 1 ;
7617
}
7618
7619
if ( ( ms-> Flags & ( ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d) ) && GetBoxSelectState ( ms-> BoxSelectId ) )
7620
EndBoxSelect ( scope_rect, ms-> Flags ) ;
7621
}
7622
7623
if ( ms-> IsEndIO == false )
7624
ms-> IO . Requests . resize ( 0 ) ;
7625
7626
7627
7628
7629
bool scope_hovered = IsWindowHovered ( ) && window-> InnerRect . Contains ( g. IO . MousePos ) ;
7630
if ( scope_hovered && ( ms-> Flags & ImGuiMultiSelectFlags_ScopeRect) )
7631
scope_hovered &= scope_rect. Contains ( g. IO . MousePos ) ;
7632
if ( scope_hovered && g. HoveredId == 0 && g. ActiveId == 0 )
7633
{
7634
if ( ms-> Flags & ( ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d) )
7635
{
7636
if ( ! g. BoxSelectState . IsActive && ! g. BoxSelectState . IsStarting && g. IO . MouseClickedCount [ 0 ] == 1 )
7637
{
7638
BoxSelectPreStartDrag ( ms-> BoxSelectId , ImGuiSelectionUserData_Invalid ) ;
7639
FocusWindow ( window, ImGuiFocusRequestFlags_UnlessBelowModal ) ;
7640
SetHoveredID ( ms-> BoxSelectId ) ;
7641
if ( ms-> Flags & ImGuiMultiSelectFlags_ScopeRect)
7642
SetNavID ( 0 , ImGuiNavLayer_Main, ms-> FocusScopeId , ImRect ( g. IO . MousePos , g. IO . MousePos ) ) ;
7643
}
7644
}
7645
7646
if ( ms-> Flags & ImGuiMultiSelectFlags_ClearOnClickVoid)
7647
if ( IsMouseReleased ( 0 ) && IsMouseDragPastThreshold ( 0 ) == false && g. IO . KeyMods == ImGuiMod_None)
7648
MultiSelectAddSetAll ( ms, false ) ;
7649
}
7650
7651
7652
if ( ms-> Flags & ImGuiMultiSelectFlags_NavWrapX)
7653
{
7654
IM_ASSERT ( ms-> Flags & ImGuiMultiSelectFlags_ScopeWindow ) ;
7655
ImGui:: NavMoveRequestTryWrapping ( ImGui:: GetCurrentWindow ( ) , ImGuiNavMoveFlags_WrapX) ;
7656
}
7657
7658
7659
window-> DC . CursorMaxPos = ImMax ( ms-> BackupCursorMaxPos , window-> DC . CursorMaxPos ) ;
7660
PopFocusScope ( ) ;
7661
7662
if ( g. DebugLogFlags & ImGuiDebugLogFlags_EventSelection)
7663
DebugLogMultiSelectRequests ( " EndMultiSelect" , & ms-> IO ) ;
7664
7665
ms-> FocusScopeId = 0 ;
7666
ms-> Flags = ImGuiMultiSelectFlags_None;
7667
g. CurrentMultiSelect = ( - - g. MultiSelectTempDataStacked > 0 ) ? & g. MultiSelectTempData [ g. MultiSelectTempDataStacked - 1 ] : NULL ;
7668
7669
return & ms-> IO ;
7670
}
7671
7672
void ImGui:: SetNextItemSelectionUserData ( ImGuiSelectionUserData selection_user_data )
7673
{
7674
7675
7676
ImGuiContext& g = * GImGui;
7677
g. NextItemData . SelectionUserData = selection_user_data;
7678
g. NextItemData . FocusScopeId = g. CurrentFocusScopeId ;
7679
7680
if ( ImGuiMultiSelectTempData* ms = g. CurrentMultiSelect )
7681
{
7682
7683
g. NextItemData . ItemFlags |= ImGuiItemFlags_HasSelectionUserData | ImGuiItemFlags_IsMultiSelect;
7684
if ( ms-> IO . RangeSrcItem == selection_user_data)
7685
ms-> RangeSrcPassedBy = true ;
7686
}
7687
else
7688
{
7689
g. NextItemData . ItemFlags |= ImGuiItemFlags_HasSelectionUserData;
7690
}
7691
}
7692
7693
7694
7695
7696
7697
void ImGui:: MultiSelectItemHeader ( ImGuiID id , bool * p_selected , ImGuiButtonFlags* p_button_flags )
7698
{
7699
ImGuiContext& g = * GImGui;
7700
ImGuiMultiSelectTempData* ms = g. CurrentMultiSelect ;
7701
7702
bool selected = * p_selected;
7703
if ( ms-> IsFocused )
7704
{
7705
ImGuiMultiSelectState* storage = ms-> Storage ;
7706
ImGuiSelectionUserData item_data = g. NextItemData . SelectionUserData ;
7707
IM_ASSERT ( g. NextItemData . FocusScopeId == g. CurrentFocusScopeId && " Forgot to call SetNextItemSelectionUserData() prior to item, required in BeginMultiSelect()/EndMultiSelect() scope" ) ;
7708
7709
7710
7711
7712
if ( ms-> LoopRequestSetAll != - 1 )
7713
selected = ( ms-> LoopRequestSetAll == 1 ) ;
7714
7715
7716
7717
if ( ms-> IsKeyboardSetRange )
7718
{
7719
IM_ASSERT ( id != 0 && ( ms-> KeyMods & ImGuiMod_Shift) != 0 ) ;
7720
const bool is_range_dst = ( ms-> RangeDstPassedBy == false ) && g. NavJustMovedToId == id;
7721
if ( is_range_dst)
7722
ms-> RangeDstPassedBy = true ;
7723
if ( is_range_dst && storage-> RangeSrcItem == ImGuiSelectionUserData_Invalid)
7724
{
7725
storage-> RangeSrcItem = item_data;
7726
storage-> RangeSelected = selected ? 1 : 0 ;
7727
}
7728
const bool is_range_src = storage-> RangeSrcItem == item_data;
7729
if ( is_range_src || is_range_dst || ms-> RangeSrcPassedBy != ms-> RangeDstPassedBy )
7730
{
7731
7732
IM_ASSERT ( storage-> RangeSrcItem != ImGuiSelectionUserData_Invalid && storage-> RangeSelected != - 1 ) ;
7733
selected = ( storage-> RangeSelected != 0 ) ;
7734
}
7735
else if ( ( ms-> KeyMods & ImGuiMod_Ctrl) == 0 && ( ms-> Flags & ImGuiMultiSelectFlags_NoAutoClear) == 0 )
7736
{
7737
7738
selected = false ;
7739
}
7740
}
7741
* p_selected = selected;
7742
}
7743
7744
7745
7746
7747
if ( p_button_flags != NULL )
7748
{
7749
ImGuiButtonFlags button_flags = * p_button_flags;
7750
button_flags |= ImGuiButtonFlags_NoHoveredOnFocus;
7751
if ( ( ! selected || ( g. ActiveId == id && g. ActiveIdHasBeenPressedBefore ) ) && ! ( ms-> Flags & ImGuiMultiSelectFlags_SelectOnClickRelease) )
7752
button_flags = ( button_flags | ImGuiButtonFlags_PressedOnClick) & ~ ImGuiButtonFlags_PressedOnClickRelease;
7753
else
7754
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
7755
* p_button_flags = button_flags;
7756
}
7757
}
7758
7759
7760
7761
7762
7763
7764
7765
7766
void ImGui:: MultiSelectItemFooter ( ImGuiID id , bool * p_selected , bool * p_pressed )
7767
{
7768
ImGuiContext& g = * GImGui;
7769
ImGuiWindow* window = g. CurrentWindow ;
7770
7771
bool selected = * p_selected;
7772
bool pressed = * p_pressed;
7773
ImGuiMultiSelectTempData* ms = g. CurrentMultiSelect ;
7774
ImGuiMultiSelectState* storage = ms-> Storage ;
7775
if ( pressed)
7776
ms-> IsFocused = true ;
7777
7778
bool hovered = false ;
7779
if ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_HoveredRect)
7780
hovered = IsItemHovered ( ImGuiHoveredFlags_AllowWhenBlockedByPopup ) ;
7781
if ( ! ms-> IsFocused && ! hovered)
7782
return ;
7783
7784
ImGuiSelectionUserData item_data = g. NextItemData . SelectionUserData ;
7785
7786
ImGuiMultiSelectFlags flags = ms-> Flags ;
7787
const bool is_singleselect = ( flags & ImGuiMultiSelectFlags_SingleSelect) != 0 ;
7788
bool is_ctrl = ( ms-> KeyMods & ImGuiMod_Ctrl) != 0 ;
7789
bool is_shift = ( ms-> KeyMods & ImGuiMod_Shift) != 0 ;
7790
7791
bool apply_to_range_src = false ;
7792
7793
if ( g. NavId == id && storage-> RangeSrcItem == ImGuiSelectionUserData_Invalid)
7794
apply_to_range_src = true ;
7795
if ( ms-> IsEndIO == false )
7796
{
7797
ms-> IO . Requests . resize ( 0 ) ;
7798
ms-> IsEndIO = true ;
7799
}
7800
7801
7802
if ( g. NavJustMovedToId == id)
7803
{
7804
if ( ( flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0 )
7805
{
7806
if ( is_ctrl && is_shift)
7807
pressed = true ;
7808
else if ( ! is_ctrl)
7809
selected = pressed = true ;
7810
}
7811
else
7812
{
7813
7814
if ( is_shift)
7815
pressed = true ;
7816
else if ( ! is_ctrl)
7817
apply_to_range_src = true ;
7818
}
7819
}
7820
7821
if ( apply_to_range_src)
7822
{
7823
storage-> RangeSrcItem = item_data;
7824
storage-> RangeSelected = selected;
7825
}
7826
7827
7828
if ( ms-> BoxSelectId != 0 )
7829
if ( ImGuiBoxSelectState* bs = GetBoxSelectState ( ms-> BoxSelectId ) )
7830
{
7831
const bool rect_overlap_curr = bs-> BoxSelectRectCurr . Overlaps ( g. LastItemData . Rect ) ;
7832
const bool rect_overlap_prev = bs-> BoxSelectRectPrev . Overlaps ( g. LastItemData . Rect ) ;
7833
if ( ( rect_overlap_curr && ! rect_overlap_prev && ! selected) || ( rect_overlap_prev && ! rect_overlap_curr) )
7834
{
7835
if ( storage-> LastSelectionSize <= 0 && bs-> IsStartedSetNavIdOnce )
7836
{
7837
pressed = true ;
7838
bs-> IsStartedSetNavIdOnce = false ;
7839
}
7840
else
7841
{
7842
selected = ! selected;
7843
MultiSelectAddSetRange ( ms, selected, + 1 , item_data, item_data ) ;
7844
}
7845
storage-> LastSelectionSize = ImMax ( storage-> LastSelectionSize + 1 , 1 ) ;
7846
}
7847
}
7848
7849
7850
7851
if ( hovered && IsMouseClicked ( 1 ) && ( flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0 )
7852
{
7853
if ( g. ActiveId != 0 && g. ActiveId != id)
7854
ClearActiveID ( ) ;
7855
SetFocusID ( id, window ) ;
7856
if ( ! pressed && ! selected)
7857
{
7858
pressed = true ;
7859
is_ctrl = is_shift = false ;
7860
}
7861
}
7862
7863
7864
7865
7866
const bool enter_pressed = pressed && ( g. NavActivateId == id) && ( g. NavActivateFlags & ImGuiActivateFlags_PreferInput) ;
7867
7868
7869
if ( pressed && ( ! enter_pressed || ! selected) )
7870
{
7871
7872
ImGuiInputSource input_source = ( g. NavJustMovedToId == id || g. NavActivateId == id) ? g. NavInputSource : ImGuiInputSource_Mouse;
7873
if ( flags & ( ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d) )
7874
if ( selected == false && ! g. BoxSelectState . IsActive && ! g. BoxSelectState . IsStarting && input_source == ImGuiInputSource_Mouse && g. IO . MouseClickedCount [ 0 ] == 1 )
7875
BoxSelectPreStartDrag ( ms-> BoxSelectId , item_data ) ;
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
if ( ( flags & ImGuiMultiSelectFlags_NoAutoClear) == 0 )
7895
{
7896
bool request_clear = false ;
7897
if ( is_singleselect)
7898
request_clear = true ;
7899
else if ( ( input_source == ImGuiInputSource_Mouse || g. NavActivateId == id) && ! is_ctrl)
7900
request_clear = ( flags & ImGuiMultiSelectFlags_NoAutoClearOnReselect) ? ! selected : true ;
7901
else if ( ( input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Gamepad) && is_shift && ! is_ctrl)
7902
request_clear = true ;
7903
if ( request_clear)
7904
MultiSelectAddSetAll ( ms, false ) ;
7905
}
7906
7907
int range_direction;
7908
bool range_selected;
7909
if ( is_shift && ! is_singleselect)
7910
{
7911
7912
if ( storage-> RangeSrcItem == ImGuiSelectionUserData_Invalid)
7913
storage-> RangeSrcItem = item_data;
7914
if ( ( flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0 )
7915
{
7916
7917
7918
range_selected = ( is_ctrl && storage-> RangeSelected != - 1 ) ? ( storage-> RangeSelected != 0 ) : true ;
7919
}
7920
else
7921
{
7922
7923
7924
if ( ms-> IsKeyboardSetRange )
7925
range_selected = ( storage-> RangeSelected != - 1 ) ? ( storage-> RangeSelected != 0 ) : true ;
7926
else
7927
range_selected = ! selected;
7928
}
7929
range_direction = ms-> RangeSrcPassedBy ? + 1 : - 1 ;
7930
}
7931
else
7932
{
7933
7934
if ( ( flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0 )
7935
selected = is_ctrl ? ! selected : true ;
7936
else
7937
selected = ! selected;
7938
storage-> RangeSrcItem = item_data;
7939
range_selected = selected;
7940
range_direction = + 1 ;
7941
}
7942
MultiSelectAddSetRange ( ms, range_selected, range_direction, storage-> RangeSrcItem , item_data ) ;
7943
}
7944
7945
7946
if ( storage-> RangeSrcItem == item_data)
7947
storage-> RangeSelected = selected ? 1 : 0 ;
7948
7949
7950
if ( g. NavId == id)
7951
{
7952
storage-> NavIdItem = item_data;
7953
storage-> NavIdSelected = selected ? 1 : 0 ;
7954
}
7955
if ( storage-> NavIdItem == item_data)
7956
ms-> NavIdPassedBy = true ;
7957
ms-> LastSubmittedItem = item_data;
7958
7959
* p_selected = selected;
7960
* p_pressed = pressed;
7961
}
7962
7963
void ImGui:: MultiSelectAddSetAll ( ImGuiMultiSelectTempData* ms , bool selected )
7964
{
7965
ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, selected, 0 , ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid } ;
7966
ms-> IO . Requests . resize ( 0 ) ;
7967
ms-> IO . Requests . push_back ( req ) ;
7968
}
7969
7970
void ImGui:: MultiSelectAddSetRange ( ImGuiMultiSelectTempData* ms , bool selected , int range_dir , ImGuiSelectionUserData first_item , ImGuiSelectionUserData last_item )
7971
{
7972
7973
if ( ms-> IO . Requests . Size > 0 && first_item == last_item && ( ms-> Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0 )
7974
{
7975
ImGuiSelectionRequest* prev = & ms-> IO . Requests . Data [ ms-> IO . Requests . Size - 1 ] ;
7976
if ( prev-> Type == ImGuiSelectionRequestType_SetRange && prev-> RangeLastItem == ms-> LastSubmittedItem && prev-> Selected == selected)
7977
{
7978
prev-> RangeLastItem = last_item;
7979
return ;
7980
}
7981
}
7982
7983
ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, ( ImS8) range_dir, ( range_dir > 0 ) ? first_item : last_item, ( range_dir > 0 ) ? last_item : first_item } ;
7984
ms-> IO . Requests . push_back ( req ) ;
7985
}
7986
7987
void ImGui:: DebugNodeMultiSelectState ( ImGuiMultiSelectState* storage )
7988
{
7989
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
7990
const bool is_active = ( storage-> LastFrameActive >= GetFrameCount ( ) - 2 ) ;
7991
if ( ! is_active) { PushStyleColor ( ImGuiCol_Text, GetStyleColorVec4 ( ImGuiCol_TextDisabled ) ) ; }
7992
bool open = TreeNode ( ( void * ) ( intptr_t ) storage-> ID , " MultiSelect 0x%08X in '%s '%s " , storage-> ID , storage-> Window ? storage-> Window -> Name : " N/A" , is_active ? " " : " *Inactive*" ) ;
7993
if ( ! is_active) { PopStyleColor ( ) ; }
7994
if ( ! open)
7995
return ;
7996
Text ( " RangeSrcItem = %" IM_PRId64 " (0x%" IM_PRIX64 " ), RangeSelected = %d " , storage-> RangeSrcItem , storage-> RangeSrcItem , storage-> RangeSelected ) ;
7997
Text ( " NavIdItem = %" IM_PRId64 " (0x%" IM_PRIX64 " ), NavIdSelected = %d " , storage-> NavIdItem , storage-> NavIdItem , storage-> NavIdSelected ) ;
7998
Text ( " LastSelectionSize = %d " , storage-> LastSelectionSize ) ;
7999
TreePop ( ) ;
8000
#else
8001
IM_UNUSED ( storage ) ;
8002
#endif
8003
}
8004
8005
8006
8007
8008
8009
8010
8011
8012
ImGuiSelectionBasicStorage:: ImGuiSelectionBasicStorage ( )
8013
{
8014
Size = 0 ;
8015
PreserveOrder = false ;
8016
UserData = NULL ;
8017
AdapterIndexToStorageId = [ ] ( ImGuiSelectionBasicStorage* , int idx) { return ( ImGuiID) idx; } ;
8018
_SelectionOrder = 1 ;
8019
}
8020
8021
void ImGuiSelectionBasicStorage:: Clear ( )
8022
{
8023
Size = 0 ;
8024
_SelectionOrder = 1 ;
8025
_Storage. Data . resize ( 0 ) ;
8026
}
8027
8028
void ImGuiSelectionBasicStorage:: Swap ( ImGuiSelectionBasicStorage& r )
8029
{
8030
ImSwap ( Size , r. Size ) ;
8031
ImSwap ( _SelectionOrder, r. _SelectionOrder ) ;
8032
_Storage. Data . swap ( r. _Storage . Data ) ;
8033
}
8034
8035
bool ImGuiSelectionBasicStorage:: Contains ( ImGuiID id ) const
8036
{
8037
return _Storage. GetInt ( id, 0 ) != 0 ;
8038
}
8039
8040
static int IMGUI_CDECL PairComparerByValueInt ( const void * lhs , const void * rhs )
8041
{
8042
int lhs_v = ( ( const ImGuiStoragePair* ) lhs) -> val_i ;
8043
int rhs_v = ( ( const ImGuiStoragePair* ) rhs) -> val_i ;
8044
return ( lhs_v > rhs_v ? + 1 : lhs_v < rhs_v ? - 1 : 0 ) ;
8045
}
8046
8047
8048
8049
bool ImGuiSelectionBasicStorage:: GetNextSelectedItem ( void * * opaque_it , ImGuiID* out_id )
8050
{
8051
ImGuiStoragePair* it = ( ImGuiStoragePair* ) * opaque_it;
8052
ImGuiStoragePair* it_end = _Storage. Data . Data + _Storage. Data . Size ;
8053
if ( PreserveOrder && it == NULL && it_end != NULL )
8054
ImQsort ( _Storage. Data . Data , ( size_t ) _Storage. Data . Size , sizeof ( ImGuiStoragePair ) , PairComparerByValueInt ) ;
8055
if ( it == NULL )
8056
it = _Storage. Data . Data ;
8057
IM_ASSERT ( it >= _Storage. Data . Data && it <= it_end ) ;
8058
if ( it != it_end)
8059
while ( it-> val_i == 0 && it < it_end)
8060
it+ + ;
8061
const bool has_more = ( it != it_end) ;
8062
* opaque_it = has_more ? ( void * * ) ( it + 1 ) : ( void * * ) ( it) ;
8063
* out_id = has_more ? it-> key : 0 ;
8064
if ( PreserveOrder && ! has_more)
8065
_Storage. BuildSortByKey ( ) ;
8066
return has_more;
8067
}
8068
8069
void ImGuiSelectionBasicStorage:: SetItemSelected ( ImGuiID id , bool selected )
8070
{
8071
int * p_int = _Storage. GetIntRef ( id, 0 ) ;
8072
if ( selected && * p_int == 0 ) { * p_int = _SelectionOrder+ + ; Size + + ; }
8073
else if ( ! selected && * p_int != 0 ) { * p_int = 0 ; Size - - ; }
8074
}
8075
8076
8077
static void ImGuiSelectionBasicStorage_BatchSetItemSelected ( ImGuiSelectionBasicStorage* selection , ImGuiID id , bool selected , int size_before_amends , int selection_order )
8078
{
8079
ImGuiStorage* storage = & selection-> _Storage ;
8080
ImGuiStoragePair* it = ImLowerBound ( storage-> Data . Data , storage-> Data . Data + size_before_amends, id ) ;
8081
const bool is_contained = ( it != storage-> Data . Data + size_before_amends) && ( it-> key == id) ;
8082
if ( selected == ( is_contained && it-> val_i != 0 ) )
8083
return ;
8084
if ( selected && ! is_contained)
8085
storage-> Data . push_back ( ImGuiStoragePair ( id, selection_order ) ) ;
8086
else if ( is_contained)
8087
it-> val_i = selected ? selection_order : 0 ;
8088
selection-> Size += selected ? + 1 : - 1 ;
8089
}
8090
8091
static void ImGuiSelectionBasicStorage_BatchFinish ( ImGuiSelectionBasicStorage* selection , bool selected , int size_before_amends )
8092
{
8093
ImGuiStorage* storage = & selection-> _Storage ;
8094
if ( selected && selection-> Size != size_before_amends)
8095
storage-> BuildSortByKey ( ) ;
8096
}
8097
8098
8099
8100
8101
8102
8103
8104
8105
8106
8107
8108
8109
8110
8111
8112
8113
8114
void ImGuiSelectionBasicStorage:: ApplyRequests ( ImGuiMultiSelectIO* ms_io )
8115
{
8116
8117
8118
8119
IM_ASSERT ( ms_io-> ItemsCount != - 1 && " Missing value for items_count in BeginMultiSelect() call!" ) ;
8120
IM_ASSERT ( AdapterIndexToStorageId != NULL ) ;
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
8131
for ( ImGuiSelectionRequest& req : ms_io-> Requests )
8132
{
8133
if ( req. Type == ImGuiSelectionRequestType_SetAll)
8134
{
8135
Clear ( ) ;
8136
if ( req. Selected )
8137
{
8138
_Storage. Data . reserve ( ms_io-> ItemsCount ) ;
8139
const int size_before_amends = _Storage. Data . Size ;
8140
for ( int idx = 0 ; idx < ms_io-> ItemsCount ; idx+ + , _SelectionOrder+ + )
8141
ImGuiSelectionBasicStorage_BatchSetItemSelected ( this , GetStorageIdFromIndex ( idx ) , req. Selected , size_before_amends, _SelectionOrder) ;
8142
ImGuiSelectionBasicStorage_BatchFinish ( this , req. Selected , size_before_amends) ;
8143
}
8144
}
8145
else if ( req. Type == ImGuiSelectionRequestType_SetRange)
8146
{
8147
const int selection_changes = ( int ) req. RangeLastItem - ( int ) req. RangeFirstItem + 1 ;
8148
8149
if ( selection_changes == 1 || ( selection_changes < Size / 100 ) )
8150
{
8151
8152
8153
for ( int idx = ( int ) req. RangeFirstItem ; idx <= ( int ) req. RangeLastItem ; idx+ + )
8154
SetItemSelected ( GetStorageIdFromIndex ( idx ) , req. Selected ) ;
8155
}
8156
else
8157
{
8158
8159
8160
const int size_before_amends = _Storage. Data . Size ;
8161
int selection_order = _SelectionOrder + ( ( req. RangeDirection < 0 ) ? selection_changes - 1 : 0 ) ;
8162
for ( int idx = ( int ) req. RangeFirstItem ; idx <= ( int ) req. RangeLastItem ; idx+ + , selection_order += req. RangeDirection )
8163
ImGuiSelectionBasicStorage_BatchSetItemSelected ( this , GetStorageIdFromIndex ( idx ) , req. Selected , size_before_amends, selection_order) ;
8164
if ( req. Selected )
8165
_SelectionOrder += selection_changes;
8166
ImGuiSelectionBasicStorage_BatchFinish ( this , req. Selected , size_before_amends) ;
8167
}
8168
}
8169
}
8170
}
8171
8172
8173
8174
ImGuiSelectionExternalStorage:: ImGuiSelectionExternalStorage ( )
8175
{
8176
UserData = NULL ;
8177
AdapterSetItemSelected = NULL ;
8178
}
8179
8180
8181
8182
8183
void ImGuiSelectionExternalStorage:: ApplyRequests ( ImGuiMultiSelectIO* ms_io )
8184
{
8185
IM_ASSERT ( AdapterSetItemSelected ) ;
8186
for ( ImGuiSelectionRequest& req : ms_io-> Requests )
8187
{
8188
if ( req. Type == ImGuiSelectionRequestType_SetAll)
8189
for ( int idx = 0 ; idx < ms_io-> ItemsCount ; idx+ + )
8190
AdapterSetItemSelected ( this , idx, req. Selected ) ;
8191
if ( req. Type == ImGuiSelectionRequestType_SetRange)
8192
for ( int idx = ( int ) req. RangeFirstItem ; idx <= ( int ) req. RangeLastItem ; idx+ + )
8193
AdapterSetItemSelected ( this , idx, req. Selected ) ;
8194
}
8195
}
8196
8197
8198
8199
8200
8201
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
bool ImGui:: BeginListBox ( const char * label , const ImVec2& size_arg )
8216
{
8217
ImGuiContext& g = * GImGui;
8218
ImGuiWindow* window = GetCurrentWindow ( ) ;
8219
if ( window-> SkipItems )
8220
return false ;
8221
8222
const ImGuiStyle& style = g. Style ;
8223
const ImGuiID id = GetID ( label ) ;
8224
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
8225
8226
8227
8228
ImVec2 size = ImTrunc ( CalcItemSize ( size_arg, CalcItemWidth ( ) , GetTextLineHeightWithSpacing ( ) * 7.25f + style. FramePadding . y * 2.0f ) ) ;
8229
ImVec2 frame_size = ImVec2 ( size. x , ImMax ( size. y , label_size. y ) ) ;
8230
ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + frame_size ) ;
8231
ImRect bb ( frame_bb. Min , frame_bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0.0f ) ) ;
8232
g. NextItemData . ClearFlags ( ) ;
8233
8234
if ( ! IsRectVisible ( bb. Min , bb. Max ) )
8235
{
8236
ItemSize ( bb. GetSize ( ) , style. FramePadding . y ) ;
8237
ItemAdd ( bb, 0 , & frame_bb ) ;
8238
g. NextWindowData . ClearFlags ( ) ;
8239
return false ;
8240
}
8241
8242
8243
BeginGroup ( ) ;
8244
if ( label_size. x > 0.0f )
8245
{
8246
ImVec2 label_pos = ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , frame_bb. Min . y + style. FramePadding . y ) ;
8247
RenderText ( label_pos, label ) ;
8248
window-> DC . CursorMaxPos = ImMax ( window-> DC . CursorMaxPos , label_pos + label_size ) ;
8249
AlignTextToFramePadding ( ) ;
8250
}
8251
8252
BeginChild ( id, frame_bb. GetSize ( ) , ImGuiChildFlags_FrameStyle ) ;
8253
return true ;
8254
}
8255
8256
void ImGui:: EndListBox ( )
8257
{
8258
ImGuiContext& g = * GImGui;
8259
ImGuiWindow* window = g. CurrentWindow ;
8260
IM_ASSERT ( ( window-> Flags & ImGuiWindowFlags_ChildWindow) && " Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?" ) ;
8261
IM_UNUSED ( window ) ;
8262
8263
EndChild ( ) ;
8264
EndGroup ( ) ;
8265
}
8266
8267
bool ImGui:: ListBox ( const char * label , int * current_item , const char * const items [ ] , int items_count , int height_items )
8268
{
8269
const bool value_changed = ListBox ( label, current_item, Items_ArrayGetter, ( void * ) items, items_count, height_items ) ;
8270
return value_changed;
8271
}
8272
8273
8274
8275
bool ImGui:: ListBox ( const char * label , int * current_item , const char * ( * getter) ( void * user_data, int idx) , void * user_data , int items_count , int height_in_items )
8276
{
8277
ImGuiContext& g = * GImGui;
8278
8279
8280
if ( height_in_items < 0 )
8281
height_in_items = ImMin ( items_count, 7 ) ;
8282
float height_in_items_f = height_in_items + 0.25f ;
8283
ImVec2 size ( 0.0f , ImTrunc ( GetTextLineHeightWithSpacing ( ) * height_in_items_f + g. Style . FramePadding . y * 2.0f ) ) ;
8284
8285
if ( ! BeginListBox ( label, size ) )
8286
return false ;
8287
8288
8289
8290
bool value_changed = false ;
8291
ImGuiListClipper clipper;
8292
clipper. Begin ( items_count, GetTextLineHeightWithSpacing ( ) ) ;
8293
clipper. IncludeItemByIndex ( * current_item) ;
8294
while ( clipper. Step ( ) )
8295
for ( int i = clipper. DisplayStart ; i < clipper. DisplayEnd ; i+ + )
8296
{
8297
const char * item_text = getter ( user_data, i ) ;
8298
if ( item_text == NULL )
8299
item_text = " *Unknown item*" ;
8300
8301
PushID ( i ) ;
8302
const bool item_selected = ( i == * current_item) ;
8303
if ( Selectable ( item_text, item_selected ) )
8304
{
8305
* current_item = i;
8306
value_changed = true ;
8307
}
8308
if ( item_selected)
8309
SetItemDefaultFocus ( ) ;
8310
PopID ( ) ;
8311
}
8312
EndListBox ( ) ;
8313
8314
if ( value_changed)
8315
MarkItemEdited ( g. LastItemData . ID ) ;
8316
8317
return value_changed;
8318
}
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
int ImGui:: PlotEx ( ImGuiPlotType plot_type , const char * label , float ( * values_getter) ( void * data, int idx) , void * data , int values_count , int values_offset , const char * overlay_text , float scale_min , float scale_max , const ImVec2& size_arg )
8334
{
8335
ImGuiContext& g = * GImGui;
8336
ImGuiWindow* window = GetCurrentWindow ( ) ;
8337
if ( window-> SkipItems )
8338
return - 1 ;
8339
8340
const ImGuiStyle& style = g. Style ;
8341
const ImGuiID id = window-> GetID ( label ) ;
8342
8343
const ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
8344
const ImVec2 frame_size = CalcItemSize ( size_arg, CalcItemWidth ( ) , label_size. y + style. FramePadding . y * 2.0f ) ;
8345
8346
const ImRect frame_bb ( window-> DC . CursorPos , window-> DC . CursorPos + frame_size ) ;
8347
const ImRect inner_bb ( frame_bb. Min + style. FramePadding , frame_bb. Max - style. FramePadding ) ;
8348
const ImRect total_bb ( frame_bb. Min , frame_bb. Max + ImVec2 ( label_size. x > 0.0f ? style. ItemInnerSpacing . x + label_size. x : 0.0f , 0 ) ) ;
8349
ItemSize ( total_bb, style. FramePadding . y ) ;
8350
if ( ! ItemAdd ( total_bb, id, & frame_bb, ImGuiItemFlags_NoNav ) )
8351
return - 1 ;
8352
bool hovered;
8353
ButtonBehavior ( frame_bb, id, & hovered, NULL ) ;
8354
8355
8356
if ( scale_min == FLT_MAX || scale_max == FLT_MAX)
8357
{
8358
float v_min = FLT_MAX;
8359
float v_max = - FLT_MAX;
8360
for ( int i = 0 ; i < values_count; i+ + )
8361
{
8362
const float v = values_getter ( data, i ) ;
8363
if ( v != v)
8364
continue ;
8365
v_min = ImMin ( v_min, v ) ;
8366
v_max = ImMax ( v_max, v ) ;
8367
}
8368
if ( scale_min == FLT_MAX)
8369
scale_min = v_min;
8370
if ( scale_max == FLT_MAX)
8371
scale_max = v_max;
8372
}
8373
8374
RenderFrame ( frame_bb. Min , frame_bb. Max , GetColorU32 ( ImGuiCol_FrameBg ) , true , style. FrameRounding ) ;
8375
8376
const int values_count_min = ( plot_type == ImGuiPlotType_Lines) ? 2 : 1 ;
8377
int idx_hovered = - 1 ;
8378
if ( values_count >= values_count_min)
8379
{
8380
int res_w = ImMin ( ( int ) frame_size. x , values_count) + ( ( plot_type == ImGuiPlotType_Lines) ? - 1 : 0 ) ;
8381
int item_count = values_count + ( ( plot_type == ImGuiPlotType_Lines) ? - 1 : 0 ) ;
8382
8383
8384
if ( hovered && inner_bb. Contains ( g. IO . MousePos ) )
8385
{
8386
const float t = ImClamp ( ( g. IO . MousePos . x - inner_bb. Min . x ) / ( inner_bb. Max . x - inner_bb. Min . x ) , 0.0f , 0.9999f ) ;
8387
const int v_idx = ( int ) ( t * item_count) ;
8388
IM_ASSERT ( v_idx >= 0 && v_idx < values_count ) ;
8389
8390
const float v0 = values_getter ( data, ( v_idx + values_offset) % values_count ) ;
8391
const float v1 = values_getter ( data, ( v_idx + 1 + values_offset) % values_count ) ;
8392
if ( plot_type == ImGuiPlotType_Lines)
8393
SetTooltip ( " %d : %8.4g \n %d : %8.4g " , v_idx, v0, v_idx + 1 , v1) ;
8394
else if ( plot_type == ImGuiPlotType_Histogram)
8395
SetTooltip ( " %d : %8.4g " , v_idx, v0) ;
8396
idx_hovered = v_idx;
8397
}
8398
8399
const float t_step = 1.0f / ( float ) res_w;
8400
const float inv_scale = ( scale_min == scale_max) ? 0.0f : ( 1.0f / ( scale_max - scale_min) ) ;
8401
8402
float v0 = values_getter ( data, ( 0 + values_offset) % values_count ) ;
8403
float t0 = 0.0f ;
8404
ImVec2 tp0 = ImVec2 ( t0, 1.0f - ImSaturate ( ( v0 - scale_min) * inv_scale) ) ;
8405
float histogram_zero_line_t = ( scale_min * scale_max < 0.0f ) ? ( 1 + scale_min * inv_scale) : ( scale_min < 0.0f ? 0.0f : 1.0f ) ;
8406
8407
const ImU32 col_base = GetColorU32 ( ( plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram) ;
8408
const ImU32 col_hovered = GetColorU32 ( ( plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered) ;
8409
8410
for ( int n = 0 ; n < res_w; n+ + )
8411
{
8412
const float t1 = t0 + t_step;
8413
const int v1_idx = ( int ) ( t0 * item_count + 0.5f ) ;
8414
IM_ASSERT ( v1_idx >= 0 && v1_idx < values_count ) ;
8415
const float v1 = values_getter ( data, ( v1_idx + values_offset + 1 ) % values_count ) ;
8416
const ImVec2 tp1 = ImVec2 ( t1, 1.0f - ImSaturate ( ( v1 - scale_min) * inv_scale) ) ;
8417
8418
8419
ImVec2 pos0 = ImLerp ( inner_bb. Min , inner_bb. Max , tp0 ) ;
8420
ImVec2 pos1 = ImLerp ( inner_bb. Min , inner_bb. Max , ( plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2 ( tp1. x , histogram_zero_line_t ) ) ;
8421
if ( plot_type == ImGuiPlotType_Lines)
8422
{
8423
window-> DrawList -> AddLine ( pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base ) ;
8424
}
8425
else if ( plot_type == ImGuiPlotType_Histogram)
8426
{
8427
if ( pos1. x >= pos0. x + 2.0f )
8428
pos1. x -= 1.0f ;
8429
window-> DrawList -> AddRectFilled ( pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base ) ;
8430
}
8431
8432
t0 = t1;
8433
tp0 = tp1;
8434
}
8435
}
8436
8437
8438
if ( overlay_text)
8439
RenderTextClipped ( ImVec2 ( frame_bb. Min . x , frame_bb. Min . y + style. FramePadding . y ) , frame_bb. Max , overlay_text, NULL , NULL , ImVec2 ( 0.5f , 0.0f ) ) ;
8440
8441
if ( label_size. x > 0.0f )
8442
RenderText ( ImVec2 ( frame_bb. Max . x + style. ItemInnerSpacing . x , inner_bb. Min . y ) , label) ;
8443
8444
8445
8446
return idx_hovered;
8447
}
8448
8449
struct ImGuiPlotArrayGetterData
8450
{
8451
const float * Values;
8452
int Stride;
8453
8454
ImGuiPlotArrayGetterData ( const float * values , int stride ) { Values = values; Stride = stride; }
8455
} ;
8456
8457
static float Plot_ArrayGetter ( void * data , int idx )
8458
{
8459
ImGuiPlotArrayGetterData* plot_data = ( ImGuiPlotArrayGetterData* ) data;
8460
const float v = * ( const float * ) ( const void * ) ( ( const unsigned char * ) plot_data-> Values + ( size_t ) idx * plot_data-> Stride ) ;
8461
return v;
8462
}
8463
8464
void ImGui:: PlotLines ( const char * label , const float * values , int values_count , int values_offset , const char * overlay_text , float scale_min , float scale_max , ImVec2 graph_size , int stride )
8465
{
8466
ImGuiPlotArrayGetterData data ( values, stride ) ;
8467
PlotEx ( ImGuiPlotType_Lines, label, & Plot_ArrayGetter, ( void * ) & data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size ) ;
8468
}
8469
8470
void ImGui:: PlotLines ( const char * label , float ( * values_getter) ( void * data, int idx) , void * data , int values_count , int values_offset , const char * overlay_text , float scale_min , float scale_max , ImVec2 graph_size )
8471
{
8472
PlotEx ( ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size ) ;
8473
}
8474
8475
void ImGui:: PlotHistogram ( const char * label , const float * values , int values_count , int values_offset , const char * overlay_text , float scale_min , float scale_max , ImVec2 graph_size , int stride )
8476
{
8477
ImGuiPlotArrayGetterData data ( values, stride ) ;
8478
PlotEx ( ImGuiPlotType_Histogram, label, & Plot_ArrayGetter, ( void * ) & data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size ) ;
8479
}
8480
8481
void ImGui:: PlotHistogram ( const char * label , float ( * values_getter) ( void * data, int idx) , void * data , int values_count , int values_offset , const char * overlay_text , float scale_min , float scale_max , ImVec2 graph_size )
8482
{
8483
PlotEx ( ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size ) ;
8484
}
8485
8486
8487
8488
8489
8490
8491
8492
8493
void ImGui:: Value ( const char * prefix , bool b )
8494
{
8495
Text ( " %s : %s " , prefix, ( b ? " true" : " false" ) ) ;
8496
}
8497
8498
void ImGui:: Value ( const char * prefix , int v )
8499
{
8500
Text ( " %s : %d " , prefix, v) ;
8501
}
8502
8503
void ImGui:: Value ( const char * prefix , unsigned int v )
8504
{
8505
Text ( " %s : %d " , prefix, v) ;
8506
}
8507
8508
void ImGui:: Value ( const char * prefix , float v , const char * float_format )
8509
{
8510
if ( float_format)
8511
{
8512
char fmt[ 64 ] ;
8513
ImFormatString ( fmt, IM_ARRAYSIZE ( fmt ) , " %% s: %s " , float_format ) ;
8514
Text ( fmt, prefix, v ) ;
8515
}
8516
else
8517
{
8518
Text ( " %s : %.3f " , prefix, v) ;
8519
}
8520
}
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536
8537
void ImGuiMenuColumns:: Update ( float spacing , bool window_reappearing )
8538
{
8539
if ( window_reappearing)
8540
memset ( Widths, 0 , sizeof ( Widths ) ) ;
8541
Spacing = ( ImU16) spacing;
8542
CalcNextTotalWidth ( true ) ;
8543
memset ( Widths, 0 , sizeof ( Widths ) ) ;
8544
TotalWidth = NextTotalWidth;
8545
NextTotalWidth = 0 ;
8546
}
8547
8548
void ImGuiMenuColumns:: CalcNextTotalWidth ( bool update_offsets )
8549
{
8550
ImU16 offset = 0 ;
8551
bool want_spacing = false ;
8552
for ( int i = 0 ; i < IM_ARRAYSIZE ( Widths ) ; i+ + )
8553
{
8554
ImU16 width = Widths[ i] ;
8555
if ( want_spacing && width > 0 )
8556
offset += Spacing;
8557
want_spacing |= ( width > 0 ) ;
8558
if ( update_offsets)
8559
{
8560
if ( i == 1 ) { OffsetLabel = offset; }
8561
if ( i == 2 ) { OffsetShortcut = offset; }
8562
if ( i == 3 ) { OffsetMark = offset; }
8563
}
8564
offset += width;
8565
}
8566
NextTotalWidth = offset;
8567
}
8568
8569
float ImGuiMenuColumns:: DeclColumns ( float w_icon , float w_label , float w_shortcut , float w_mark )
8570
{
8571
Widths[ 0 ] = ImMax ( Widths[ 0 ] , ( ImU16) w_icon ) ;
8572
Widths[ 1 ] = ImMax ( Widths[ 1 ] , ( ImU16) w_label ) ;
8573
Widths[ 2 ] = ImMax ( Widths[ 2 ] , ( ImU16) w_shortcut ) ;
8574
Widths[ 3 ] = ImMax ( Widths[ 3 ] , ( ImU16) w_mark ) ;
8575
CalcNextTotalWidth ( false ) ;
8576
return ( float ) ImMax ( TotalWidth, NextTotalWidth ) ;
8577
}
8578
8579
8580
8581
8582
8583
bool ImGui:: BeginMenuBar ( )
8584
{
8585
ImGuiWindow* window = GetCurrentWindow ( ) ;
8586
if ( window-> SkipItems )
8587
return false ;
8588
if ( ! ( window-> Flags & ImGuiWindowFlags_MenuBar) )
8589
return false ;
8590
8591
IM_ASSERT ( ! window-> DC . MenuBarAppending ) ;
8592
BeginGroup ( ) ;
8593
PushID ( " ##menubar" ) ;
8594
8595
8596
8597
ImRect bar_rect = window-> MenuBarRect ( ) ;
8598
ImRect clip_rect ( ImFloor ( bar_rect. Min . x + window-> WindowBorderSize ) , ImFloor ( bar_rect. Min . y + window-> WindowBorderSize ) , ImFloor ( ImMax ( bar_rect. Min . x , bar_rect. Max . x - ImMax ( window-> WindowRounding , window-> WindowBorderSize ) ) ) , ImFloor ( bar_rect. Max . y ) ) ;
8599
clip_rect. ClipWith ( window-> OuterRectClipped ) ;
8600
PushClipRect ( clip_rect. Min , clip_rect. Max , false ) ;
8601
8602
8603
window-> DC . CursorPos = window-> DC . CursorMaxPos = ImVec2 ( bar_rect. Min . x + window-> DC . MenuBarOffset . x , bar_rect. Min . y + window-> DC . MenuBarOffset . y ) ;
8604
window-> DC . LayoutType = ImGuiLayoutType_Horizontal;
8605
window-> DC . IsSameLine = false ;
8606
window-> DC . NavLayerCurrent = ImGuiNavLayer_Menu;
8607
window-> DC . MenuBarAppending = true ;
8608
AlignTextToFramePadding ( ) ;
8609
return true ;
8610
}
8611
8612
void ImGui:: EndMenuBar ( )
8613
{
8614
ImGuiWindow* window = GetCurrentWindow ( ) ;
8615
if ( window-> SkipItems )
8616
return ;
8617
ImGuiContext& g = * GImGui;
8618
8619
8620
if ( NavMoveRequestButNoResultYet ( ) && ( g. NavMoveDir == ImGuiDir_Left || g. NavMoveDir == ImGuiDir_Right) && ( g. NavWindow -> Flags & ImGuiWindowFlags_ChildMenu) )
8621
{
8622
8623
ImGuiWindow* nav_earliest_child = g. NavWindow ;
8624
while ( nav_earliest_child-> ParentWindow && ( nav_earliest_child-> ParentWindow -> Flags & ImGuiWindowFlags_ChildMenu) )
8625
nav_earliest_child = nav_earliest_child-> ParentWindow ;
8626
if ( nav_earliest_child-> ParentWindow == window && nav_earliest_child-> DC . ParentLayoutType == ImGuiLayoutType_Horizontal && ( g. NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0 )
8627
{
8628
8629
8630
const ImGuiNavLayer layer = ImGuiNavLayer_Menu;
8631
IM_ASSERT ( window-> DC . NavLayersActiveMaskNext & ( 1 << layer) ) ;
8632
FocusWindow ( window ) ;
8633
SetNavID ( window-> NavLastIds [ layer] , layer, 0 , window-> NavRectRel [ layer] ) ;
8634
8635
if ( g. NavCursorVisible )
8636
{
8637
g. NavCursorVisible = false ;
8638
g. NavCursorHideFrames = 2 ;
8639
}
8640
g. NavHighlightItemUnderNav = g. NavMousePosDirty = true ;
8641
NavMoveRequestForward ( g. NavMoveDir , g. NavMoveClipDir , g. NavMoveFlags , g. NavMoveScrollFlags ) ;
8642
}
8643
}
8644
8645
IM_MSVC_WARNING_SUPPRESS ( 6011 ) ;
8646
IM_ASSERT ( window-> Flags & ImGuiWindowFlags_MenuBar ) ;
8647
IM_ASSERT ( window-> DC . MenuBarAppending ) ;
8648
PopClipRect ( ) ;
8649
PopID ( ) ;
8650
window-> DC . MenuBarOffset . x = window-> DC . CursorPos . x - window-> Pos . x ;
8651
8652
8653
ImGuiGroupData& group_data = g. GroupStack . back ( ) ;
8654
group_data. EmitItem = false ;
8655
ImVec2 restore_cursor_max_pos = group_data. BackupCursorMaxPos ;
8656
window-> DC . IdealMaxPos . x = ImMax ( window-> DC . IdealMaxPos . x , window-> DC . CursorMaxPos . x - window-> Scroll . x ) ;
8657
EndGroup ( ) ;
8658
window-> DC . LayoutType = ImGuiLayoutType_Vertical;
8659
window-> DC . IsSameLine = false ;
8660
window-> DC . NavLayerCurrent = ImGuiNavLayer_Main;
8661
window-> DC . MenuBarAppending = false ;
8662
window-> DC . CursorMaxPos = restore_cursor_max_pos;
8663
}
8664
8665
8666
8667
8668
bool ImGui:: BeginViewportSideBar ( const char * name , ImGuiViewport* viewport_p , ImGuiDir dir , float axis_size , ImGuiWindowFlags window_flags )
8669
{
8670
IM_ASSERT ( dir != ImGuiDir_None ) ;
8671
8672
ImGuiWindow* bar_window = FindWindowByName ( name ) ;
8673
ImGuiViewportP* viewport = ( ImGuiViewportP* ) ( void * ) ( viewport_p ? viewport_p : GetMainViewport ( ) ) ;
8674
if ( bar_window == NULL || bar_window-> BeginCount == 0 )
8675
{
8676
8677
ImRect avail_rect = viewport-> GetBuildWorkRect ( ) ;
8678
ImGuiAxis axis = ( dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
8679
ImVec2 pos = avail_rect. Min ;
8680
if ( dir == ImGuiDir_Right || dir == ImGuiDir_Down)
8681
pos[ axis] = avail_rect. Max [ axis] - axis_size;
8682
ImVec2 size = avail_rect. GetSize ( ) ;
8683
size[ axis] = axis_size;
8684
SetNextWindowPos ( pos ) ;
8685
SetNextWindowSize ( size ) ;
8686
8687
8688
if ( dir == ImGuiDir_Up || dir == ImGuiDir_Left)
8689
viewport-> BuildWorkInsetMin [ axis] += axis_size;
8690
else if ( dir == ImGuiDir_Down || dir == ImGuiDir_Right)
8691
viewport-> BuildWorkInsetMax [ axis] += axis_size;
8692
}
8693
8694
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
8695
SetNextWindowViewport ( viewport-> ID ) ;
8696
PushStyleVar ( ImGuiStyleVar_WindowRounding, 0.0f ) ;
8697
PushStyleVar ( ImGuiStyleVar_WindowMinSize, ImVec2 ( 0 , 0 ) ) ;
8698
bool is_open = Begin ( name, NULL , window_flags ) ;
8699
PopStyleVar ( 2 ) ;
8700
8701
return is_open;
8702
}
8703
8704
bool ImGui:: BeginMainMenuBar ( )
8705
{
8706
ImGuiContext& g = * GImGui;
8707
ImGuiViewportP* viewport = ( ImGuiViewportP* ) ( void * ) GetMainViewport ( ) ;
8708
8709
8710
SetCurrentViewport ( NULL , viewport) ;
8711
8712
8713
8714
8715
g. NextWindowData . MenuBarOffsetMinVal = ImVec2 ( g. Style . DisplaySafeAreaPadding . x , ImMax ( g. Style . DisplaySafeAreaPadding . y - g. Style . FramePadding . y , 0.0f ) ) ;
8716
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
8717
float height = GetFrameHeight ( ) ;
8718
bool is_open = BeginViewportSideBar ( " ##MainMenuBar" , viewport, ImGuiDir_Up, height, window_flags) ;
8719
g. NextWindowData . MenuBarOffsetMinVal = ImVec2 ( 0.0f , 0.0f ) ;
8720
8721
if ( is_open)
8722
BeginMenuBar ( ) ;
8723
else
8724
End ( ) ;
8725
return is_open;
8726
}
8727
8728
void ImGui:: EndMainMenuBar ( )
8729
{
8730
EndMenuBar ( ) ;
8731
8732
8733
8734
ImGuiContext& g = * GImGui;
8735
if ( g. CurrentWindow == g. NavWindow && g. NavLayer == ImGuiNavLayer_Main && ! g. NavAnyRequest )
8736
FocusTopMostWindowUnderOne ( g. NavWindow , NULL , NULL , ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild ) ;
8737
8738
End ( ) ;
8739
}
8740
8741
static bool IsRootOfOpenMenuSet ( )
8742
{
8743
ImGuiContext& g = * GImGui;
8744
ImGuiWindow* window = g. CurrentWindow ;
8745
if ( ( g. OpenPopupStack . Size <= g. BeginPopupStack . Size ) || ( window-> Flags & ImGuiWindowFlags_ChildMenu) )
8746
return false ;
8747
8748
8749
8750
8751
8752
8753
8754
8755
8756
8757
8758
8759
const ImGuiPopupData* upper_popup = & g. OpenPopupStack [ g. BeginPopupStack . Size ] ;
8760
if ( window-> DC . NavLayerCurrent != upper_popup-> ParentNavLayer )
8761
return false ;
8762
return upper_popup-> Window && ( upper_popup-> Window -> Flags & ImGuiWindowFlags_ChildMenu) && ImGui:: IsWindowChildOf ( upper_popup-> Window , window, true , false ) ;
8763
}
8764
8765
bool ImGui:: BeginMenuEx ( const char * label , const char * icon , bool enabled )
8766
{
8767
ImGuiWindow* window = GetCurrentWindow ( ) ;
8768
if ( window-> SkipItems )
8769
return false ;
8770
8771
ImGuiContext& g = * GImGui;
8772
const ImGuiStyle& style = g. Style ;
8773
const ImGuiID id = window-> GetID ( label ) ;
8774
bool menu_is_open = IsPopupOpen ( id, ImGuiPopupFlags_None ) ;
8775
8776
8777
8778
ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
8779
if ( window-> Flags & ImGuiWindowFlags_ChildMenu)
8780
window_flags |= ImGuiWindowFlags_ChildWindow;
8781
8782
8783
8784
8785
if ( g. MenusIdSubmittedThisFrame . contains ( id ) )
8786
{
8787
if ( menu_is_open)
8788
menu_is_open = BeginPopupEx ( id, window_flags ) ;
8789
else
8790
g. NextWindowData . ClearFlags ( ) ;
8791
return menu_is_open;
8792
}
8793
8794
8795
g. MenusIdSubmittedThisFrame . push_back ( id ) ;
8796
8797
ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
8798
8799
8800
8801
const bool menuset_is_open = IsRootOfOpenMenuSet ( ) ;
8802
if ( menuset_is_open)
8803
PushItemFlag ( ImGuiItemFlags_NoWindowHoverableCheck, true ) ;
8804
8805
8806
8807
8808
ImVec2 popup_pos, pos = window-> DC . CursorPos ;
8809
PushID ( label ) ;
8810
if ( ! enabled)
8811
BeginDisabled ( ) ;
8812
const ImGuiMenuColumns* offsets = & window-> DC . MenuColumns ;
8813
bool pressed;
8814
8815
8816
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
8817
if ( window-> DC . LayoutType == ImGuiLayoutType_Horizontal)
8818
{
8819
8820
8821
8822
popup_pos = ImVec2 ( pos. x - 1.0f - IM_TRUNC ( style. ItemSpacing . x * 0.5f ) , pos. y - style. FramePadding . y + window-> MenuBarHeight ) ;
8823
window-> DC . CursorPos . x += IM_TRUNC ( style. ItemSpacing . x * 0.5f ) ;
8824
PushStyleVarX ( ImGuiStyleVar_ItemSpacing, style. ItemSpacing . x * 2.0f ) ;
8825
float w = label_size. x ;
8826
ImVec2 text_pos ( window-> DC . CursorPos . x + offsets-> OffsetLabel , window-> DC . CursorPos . y + window-> DC . CurrLineTextBaseOffset ) ;
8827
pressed = Selectable ( " " , menu_is_open, selectable_flags, ImVec2 ( w, label_size. y ) ) ;
8828
LogSetNextTextDecoration ( " [" , " ]" ) ;
8829
RenderText ( text_pos, label ) ;
8830
PopStyleVar ( ) ;
8831
window-> DC . CursorPos . x += IM_TRUNC ( style. ItemSpacing . x * ( - 1.0f + 0.5f ) ) ;
8832
}
8833
else
8834
{
8835
8836
8837
8838
popup_pos = ImVec2 ( pos. x , pos. y - style. WindowPadding . y ) ;
8839
float icon_w = ( icon && icon[ 0 ] ) ? CalcTextSize ( icon, NULL ) . x : 0.0f ;
8840
float checkmark_w = IM_TRUNC ( g. FontSize * 1.20f ) ;
8841
float min_w = window-> DC . MenuColumns . DeclColumns ( icon_w, label_size. x , 0.0f , checkmark_w ) ;
8842
float extra_w = ImMax ( 0.0f , GetContentRegionAvail ( ) . x - min_w) ;
8843
ImVec2 text_pos ( window-> DC . CursorPos . x + offsets-> OffsetLabel , window-> DC . CursorPos . y + window-> DC . CurrLineTextBaseOffset ) ;
8844
pressed = Selectable ( " " , menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2 ( min_w, label_size. y ) ) ;
8845
LogSetNextTextDecoration ( " " , " >" ) ;
8846
RenderText ( text_pos, label ) ;
8847
if ( icon_w > 0.0f )
8848
RenderText ( pos + ImVec2 ( offsets-> OffsetIcon , 0.0f ) , icon ) ;
8849
RenderArrow ( window-> DrawList , pos + ImVec2 ( offsets-> OffsetMark + extra_w + g. FontSize * 0.30f , 0.0f ) , GetColorU32 ( ImGuiCol_Text ) , ImGuiDir_Right ) ;
8850
}
8851
if ( ! enabled)
8852
EndDisabled ( ) ;
8853
8854
const bool hovered = ( g. HoveredId == id) && enabled && ! g. NavHighlightItemUnderNav ;
8855
if ( menuset_is_open)
8856
PopItemFlag ( ) ;
8857
8858
bool want_open = false ;
8859
bool want_open_nav_init = false ;
8860
bool want_close = false ;
8861
if ( window-> DC . LayoutType == ImGuiLayoutType_Vertical)
8862
{
8863
8864
8865
bool moving_toward_child_menu = false ;
8866
ImGuiPopupData* child_popup = ( g. BeginPopupStack . Size < g. OpenPopupStack . Size ) ? & g. OpenPopupStack [ g. BeginPopupStack . Size ] : NULL ;
8867
ImGuiWindow* child_menu_window = ( child_popup && child_popup-> Window && child_popup-> Window -> ParentWindow == window) ? child_popup-> Window : NULL ;
8868
if ( g. HoveredWindow == window && child_menu_window != NULL )
8869
{
8870
const float ref_unit = g. FontSize ;
8871
const float child_dir = ( window-> Pos . x < child_menu_window-> Pos . x ) ? 1.0f : - 1.0f ;
8872
const ImRect next_window_rect = child_menu_window-> Rect ( ) ;
8873
ImVec2 ta = ( g. IO . MousePos - g. IO . MouseDelta ) ;
8874
ImVec2 tb = ( child_dir > 0.0f ) ? next_window_rect. GetTL ( ) : next_window_rect. GetTR ( ) ;
8875
ImVec2 tc = ( child_dir > 0.0f ) ? next_window_rect. GetBL ( ) : next_window_rect. GetBR ( ) ;
8876
const float pad_farmost_h = ImClamp ( ImFabs ( ta. x - tb. x ) * 0.30f , ref_unit * 0.5f , ref_unit * 2.5f ) ;
8877
ta. x += child_dir * - 0.5f ;
8878
tb. x += child_dir * ref_unit;
8879
tc. x += child_dir * ref_unit;
8880
tb. y = ta. y + ImMax ( ( tb. y - pad_farmost_h) - ta. y , - ref_unit * 8.0f ) ;
8881
tc. y = ta. y + ImMin ( ( tc. y + pad_farmost_h) - ta. y , + ref_unit * 8.0f ) ;
8882
moving_toward_child_menu = ImTriangleContainsPoint ( ta, tb, tc, g. IO . MousePos ) ;
8883
8884
}
8885
8886
8887
8888
8889
if ( menu_is_open && ! hovered && g. HoveredWindow == window && ! moving_toward_child_menu && ! g. NavHighlightItemUnderNav && g. ActiveId == 0 )
8890
want_close = true ;
8891
8892
8893
8894
if ( ! menu_is_open && pressed)
8895
want_open = true ;
8896
else if ( ! menu_is_open && hovered && ! moving_toward_child_menu)
8897
want_open = true ;
8898
else if ( ! menu_is_open && hovered && g. HoveredIdTimer >= 0.30f && g. MouseStationaryTimer >= 0.30f )
8899
want_open = true ;
8900
if ( g. NavId == id && g. NavMoveDir == ImGuiDir_Right)
8901
{
8902
want_open = want_open_nav_init = true ;
8903
NavMoveRequestCancel ( ) ;
8904
SetNavCursorVisibleAfterMove ( ) ;
8905
}
8906
}
8907
else
8908
{
8909
8910
if ( menu_is_open && pressed && menuset_is_open)
8911
{
8912
want_close = true ;
8913
want_open = menu_is_open = false ;
8914
}
8915
else if ( pressed || ( hovered && menuset_is_open && ! menu_is_open) )
8916
{
8917
want_open = true ;
8918
}
8919
else if ( g. NavId == id && g. NavMoveDir == ImGuiDir_Down)
8920
{
8921
want_open = true ;
8922
NavMoveRequestCancel ( ) ;
8923
}
8924
}
8925
8926
if ( ! enabled)
8927
want_close = true ;
8928
if ( want_close && IsPopupOpen ( id, ImGuiPopupFlags_None ) )
8929
ClosePopupToLevel ( g. BeginPopupStack . Size , true ) ;
8930
8931
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Openable | ( menu_is_open ? ImGuiItemStatusFlags_Opened : 0 ) ) ;
8932
PopID ( ) ;
8933
8934
if ( want_open && ! menu_is_open && g. OpenPopupStack . Size > g. BeginPopupStack . Size )
8935
{
8936
8937
OpenPopup ( label ) ;
8938
}
8939
else if ( want_open)
8940
{
8941
menu_is_open = true ;
8942
OpenPopup ( label, ImGuiPopupFlags_NoReopen ) ;
8943
}
8944
8945
if ( menu_is_open)
8946
{
8947
ImGuiLastItemData last_item_in_parent = g. LastItemData ;
8948
SetNextWindowPos ( popup_pos, ImGuiCond_Always ) ;
8949
PushStyleVar ( ImGuiStyleVar_ChildRounding, style. PopupRounding ) ;
8950
menu_is_open = BeginPopupEx ( id, window_flags ) ;
8951
PopStyleVar ( ) ;
8952
if ( menu_is_open)
8953
{
8954
8955
8956
if ( want_open && want_open_nav_init && ! g. NavInitRequest )
8957
{
8958
FocusWindow ( g. CurrentWindow , ImGuiFocusRequestFlags_UnlessBelowModal ) ;
8959
NavInitWindow ( g. CurrentWindow , false ) ;
8960
}
8961
8962
8963
8964
g. LastItemData = last_item_in_parent;
8965
if ( g. HoveredWindow == window)
8966
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
8967
}
8968
}
8969
else
8970
{
8971
g. NextWindowData . ClearFlags ( ) ;
8972
}
8973
8974
return menu_is_open;
8975
}
8976
8977
bool ImGui:: BeginMenu ( const char * label , bool enabled )
8978
{
8979
return BeginMenuEx ( label, NULL , enabled ) ;
8980
}
8981
8982
void ImGui:: EndMenu ( )
8983
{
8984
8985
ImGuiContext& g = * GImGui;
8986
ImGuiWindow* window = g. CurrentWindow ;
8987
IM_ASSERT ( window-> Flags & ImGuiWindowFlags_Popup ) ;
8988
ImGuiWindow* parent_window = window-> ParentWindow ;
8989
if ( window-> BeginCount == window-> BeginCountPreviousFrame )
8990
if ( g. NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet ( ) )
8991
if ( g. NavWindow && ( g. NavWindow -> RootWindowForNav == window) && parent_window-> DC . LayoutType == ImGuiLayoutType_Vertical)
8992
{
8993
ClosePopupToLevel ( g. BeginPopupStack . Size - 1 , true ) ;
8994
NavMoveRequestCancel ( ) ;
8995
}
8996
8997
EndPopup ( ) ;
8998
}
8999
9000
bool ImGui:: MenuItemEx ( const char * label , const char * icon , const char * shortcut , bool selected , bool enabled )
9001
{
9002
ImGuiWindow* window = GetCurrentWindow ( ) ;
9003
if ( window-> SkipItems )
9004
return false ;
9005
9006
ImGuiContext& g = * GImGui;
9007
ImGuiStyle& style = g. Style ;
9008
ImVec2 pos = window-> DC . CursorPos ;
9009
ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
9010
9011
9012
const bool menuset_is_open = IsRootOfOpenMenuSet ( ) ;
9013
if ( menuset_is_open)
9014
PushItemFlag ( ImGuiItemFlags_NoWindowHoverableCheck, true ) ;
9015
9016
9017
9018
bool pressed;
9019
PushID ( label ) ;
9020
if ( ! enabled)
9021
BeginDisabled ( ) ;
9022
9023
9024
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
9025
const ImGuiMenuColumns* offsets = & window-> DC . MenuColumns ;
9026
if ( window-> DC . LayoutType == ImGuiLayoutType_Horizontal)
9027
{
9028
9029
9030
float w = label_size. x ;
9031
window-> DC . CursorPos . x += IM_TRUNC ( style. ItemSpacing . x * 0.5f ) ;
9032
ImVec2 text_pos ( window-> DC . CursorPos . x + offsets-> OffsetLabel , window-> DC . CursorPos . y + window-> DC . CurrLineTextBaseOffset ) ;
9033
PushStyleVarX ( ImGuiStyleVar_ItemSpacing, style. ItemSpacing . x * 2.0f ) ;
9034
pressed = Selectable ( " " , selected, selectable_flags, ImVec2 ( w, 0.0f ) ) ;
9035
PopStyleVar ( ) ;
9036
if ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_Visible)
9037
RenderText ( text_pos, label ) ;
9038
window-> DC . CursorPos . x += IM_TRUNC ( style. ItemSpacing . x * ( - 1.0f + 0.5f ) ) ;
9039
}
9040
else
9041
{
9042
9043
9044
9045
float icon_w = ( icon && icon[ 0 ] ) ? CalcTextSize ( icon, NULL ) . x : 0.0f ;
9046
float shortcut_w = ( shortcut && shortcut[ 0 ] ) ? CalcTextSize ( shortcut, NULL ) . x : 0.0f ;
9047
float checkmark_w = IM_TRUNC ( g. FontSize * 1.20f ) ;
9048
float min_w = window-> DC . MenuColumns . DeclColumns ( icon_w, label_size. x , shortcut_w, checkmark_w ) ;
9049
float stretch_w = ImMax ( 0.0f , GetContentRegionAvail ( ) . x - min_w) ;
9050
pressed = Selectable ( " " , false , selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2 ( min_w, label_size. y ) ) ;
9051
if ( g. LastItemData . StatusFlags & ImGuiItemStatusFlags_Visible)
9052
{
9053
RenderText ( pos + ImVec2 ( offsets-> OffsetLabel , 0.0f ) , label ) ;
9054
if ( icon_w > 0.0f )
9055
RenderText ( pos + ImVec2 ( offsets-> OffsetIcon , 0.0f ) , icon ) ;
9056
if ( shortcut_w > 0.0f )
9057
{
9058
PushStyleColor ( ImGuiCol_Text, style. Colors [ ImGuiCol_TextDisabled] ) ;
9059
LogSetNextTextDecoration ( " (" , " )" ) ;
9060
RenderText ( pos + ImVec2 ( offsets-> OffsetShortcut + stretch_w, 0.0f ) , shortcut, NULL , false ) ;
9061
PopStyleColor ( ) ;
9062
}
9063
if ( selected)
9064
RenderCheckMark ( window-> DrawList , pos + ImVec2 ( offsets-> OffsetMark + stretch_w + g. FontSize * 0.40f , g. FontSize * 0.134f * 0.5f ) , GetColorU32 ( ImGuiCol_Text ) , g. FontSize * 0.866f ) ;
9065
}
9066
}
9067
IMGUI_TEST_ENGINE_ITEM_INFO ( g. LastItemData . ID , label, g. LastItemData . StatusFlags | ImGuiItemStatusFlags_Checkable | ( selected ? ImGuiItemStatusFlags_Checked : 0 ) ) ;
9068
if ( ! enabled)
9069
EndDisabled ( ) ;
9070
PopID ( ) ;
9071
if ( menuset_is_open)
9072
PopItemFlag ( ) ;
9073
9074
return pressed;
9075
}
9076
9077
bool ImGui:: MenuItem ( const char * label , const char * shortcut , bool selected , bool enabled )
9078
{
9079
return MenuItemEx ( label, NULL , shortcut, selected, enabled ) ;
9080
}
9081
9082
bool ImGui:: MenuItem ( const char * label , const char * shortcut , bool * p_selected , bool enabled )
9083
{
9084
if ( MenuItemEx ( label, NULL , shortcut, p_selected ? * p_selected : false , enabled ) )
9085
{
9086
if ( p_selected)
9087
* p_selected = ! * p_selected;
9088
return true ;
9089
}
9090
return false ;
9091
}
9092
9093
9094
9095
9096
9097
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107
9108
9109
9110
9111
9112
9113
9114
9115
9116
9117
9118
9119
9120
struct ImGuiTabBarSection
9121
{
9122
int TabCount;
9123
float Width;
9124
float Spacing;
9125
9126
ImGuiTabBarSection ( ) { memset ( this , 0 , sizeof ( * this ) ) ; }
9127
} ;
9128
9129
namespace ImGui
9130
{
9131
static void TabBarLayout ( ImGuiTabBar* tab_bar ) ;
9132
static ImU32 TabBarCalcTabID ( ImGuiTabBar* tab_bar , const char * label , ImGuiWindow* docked_window ) ;
9133
static float TabBarCalcMaxTabWidth ( ) ;
9134
static float TabBarScrollClamp ( ImGuiTabBar* tab_bar , float scrolling ) ;
9135
static void TabBarScrollToTab ( ImGuiTabBar* tab_bar , ImGuiID tab_id , ImGuiTabBarSection* sections ) ;
9136
static ImGuiTabItem* TabBarScrollingButtons ( ImGuiTabBar* tab_bar ) ;
9137
static ImGuiTabItem* TabBarTabListPopupButton ( ImGuiTabBar* tab_bar ) ;
9138
}
9139
9140
ImGuiTabBar:: ImGuiTabBar ( )
9141
{
9142
memset ( this , 0 , sizeof ( * this ) ) ;
9143
CurrFrameVisible = PrevFrameVisible = - 1 ;
9144
LastTabItemIdx = - 1 ;
9145
}
9146
9147
static inline int TabItemGetSectionIdx ( const ImGuiTabItem* tab )
9148
{
9149
return ( tab-> Flags & ImGuiTabItemFlags_Leading) ? 0 : ( tab-> Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1 ;
9150
}
9151
9152
static int IMGUI_CDECL TabItemComparerBySection ( const void * lhs , const void * rhs )
9153
{
9154
const ImGuiTabItem* a = ( const ImGuiTabItem* ) lhs;
9155
const ImGuiTabItem* b = ( const ImGuiTabItem* ) rhs;
9156
const int a_section = TabItemGetSectionIdx ( a ) ;
9157
const int b_section = TabItemGetSectionIdx ( b ) ;
9158
if ( a_section != b_section)
9159
return a_section - b_section;
9160
return ( int ) ( a-> IndexDuringLayout - b-> IndexDuringLayout ) ;
9161
}
9162
9163
static int IMGUI_CDECL TabItemComparerByBeginOrder ( const void * lhs , const void * rhs )
9164
{
9165
const ImGuiTabItem* a = ( const ImGuiTabItem* ) lhs;
9166
const ImGuiTabItem* b = ( const ImGuiTabItem* ) rhs;
9167
return ( int ) ( a-> BeginOrder - b-> BeginOrder ) ;
9168
}
9169
9170
static ImGuiTabBar* GetTabBarFromTabBarRef ( const ImGuiPtrOrIndex& ref )
9171
{
9172
ImGuiContext& g = * GImGui;
9173
return ref. Ptr ? ( ImGuiTabBar* ) ref. Ptr : g. TabBars . GetByIndex ( ref. Index ) ;
9174
}
9175
9176
static ImGuiPtrOrIndex GetTabBarRefFromTabBar ( ImGuiTabBar* tab_bar )
9177
{
9178
ImGuiContext& g = * GImGui;
9179
if ( g. TabBars . Contains ( tab_bar ) )
9180
return ImGuiPtrOrIndex ( g. TabBars . GetIndex ( tab_bar ) ) ;
9181
return ImGuiPtrOrIndex ( tab_bar ) ;
9182
}
9183
9184
bool ImGui:: BeginTabBar ( const char * str_id , ImGuiTabBarFlags flags )
9185
{
9186
ImGuiContext& g = * GImGui;
9187
ImGuiWindow* window = g. CurrentWindow ;
9188
if ( window-> SkipItems )
9189
return false ;
9190
9191
ImGuiID id = window-> GetID ( str_id ) ;
9192
ImGuiTabBar* tab_bar = g. TabBars . GetOrAddByKey ( id ) ;
9193
ImRect tab_bar_bb = ImRect ( window-> DC . CursorPos . x , window-> DC . CursorPos . y , window-> WorkRect . Max . x , window-> DC . CursorPos . y + g. FontSize + g. Style . FramePadding . y * 2 ) ;
9194
tab_bar-> ID = id;
9195
tab_bar-> SeparatorMinX = tab_bar-> BarRect . Min . x - IM_TRUNC ( window-> WindowPadding . x * 0.5f ) ;
9196
tab_bar-> SeparatorMaxX = tab_bar-> BarRect . Max . x + IM_TRUNC ( window-> WindowPadding . x * 0.5f ) ;
9197
9198
flags |= ImGuiTabBarFlags_IsFocused;
9199
return BeginTabBarEx ( tab_bar, tab_bar_bb, flags ) ;
9200
}
9201
9202
bool ImGui:: BeginTabBarEx ( ImGuiTabBar* tab_bar , const ImRect& tab_bar_bb , ImGuiTabBarFlags flags )
9203
{
9204
ImGuiContext& g = * GImGui;
9205
ImGuiWindow* window = g. CurrentWindow ;
9206
if ( window-> SkipItems )
9207
return false ;
9208
9209
IM_ASSERT ( tab_bar-> ID != 0 ) ;
9210
if ( ( flags & ImGuiTabBarFlags_DockNode) == 0 )
9211
PushOverrideID ( tab_bar-> ID ) ;
9212
9213
9214
g. CurrentTabBarStack . push_back ( GetTabBarRefFromTabBar ( tab_bar ) ) ;
9215
g. CurrentTabBar = tab_bar;
9216
tab_bar-> Window = window;
9217
9218
9219
tab_bar-> BackupCursorPos = window-> DC . CursorPos ;
9220
if ( tab_bar-> CurrFrameVisible == g. FrameCount )
9221
{
9222
window-> DC . CursorPos = ImVec2 ( tab_bar-> BarRect . Min . x , tab_bar-> BarRect . Max . y + tab_bar-> ItemSpacingY ) ;
9223
tab_bar-> BeginCount + + ;
9224
return true ;
9225
}
9226
9227
9228
if ( ( flags & ImGuiTabBarFlags_Reorderable) != ( tab_bar-> Flags & ImGuiTabBarFlags_Reorderable) || ( tab_bar-> TabsAddedNew && ! ( flags & ImGuiTabBarFlags_Reorderable) ) )
9229
if ( ( flags & ImGuiTabBarFlags_DockNode) == 0 )
9230
ImQsort ( tab_bar-> Tabs . Data , tab_bar-> Tabs . Size , sizeof ( ImGuiTabItem ) , TabItemComparerByBeginOrder ) ;
9231
tab_bar-> TabsAddedNew = false ;
9232
9233
9234
if ( ( flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0 )
9235
flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
9236
9237
tab_bar-> Flags = flags;
9238
tab_bar-> BarRect = tab_bar_bb;
9239
tab_bar-> WantLayout = true ;
9240
tab_bar-> PrevFrameVisible = tab_bar-> CurrFrameVisible ;
9241
tab_bar-> CurrFrameVisible = g. FrameCount ;
9242
tab_bar-> PrevTabsContentsHeight = tab_bar-> CurrTabsContentsHeight ;
9243
tab_bar-> CurrTabsContentsHeight = 0.0f ;
9244
tab_bar-> ItemSpacingY = g. Style . ItemSpacing . y ;
9245
tab_bar-> FramePadding = g. Style . FramePadding ;
9246
tab_bar-> TabsActiveCount = 0 ;
9247
tab_bar-> LastTabItemIdx = - 1 ;
9248
tab_bar-> BeginCount = 1 ;
9249
9250
9251
window-> DC . CursorPos = ImVec2 ( tab_bar-> BarRect . Min . x , tab_bar-> BarRect . Max . y + tab_bar-> ItemSpacingY ) ;
9252
9253
9254
9255
const ImU32 col = GetColorU32 ( ( flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) ;
9256
if ( g. Style . TabBarBorderSize > 0.0f )
9257
{
9258
const float y = tab_bar-> BarRect . Max . y ;
9259
window-> DrawList -> AddRectFilled ( ImVec2 ( tab_bar-> SeparatorMinX , y - g. Style . TabBarBorderSize ) , ImVec2 ( tab_bar-> SeparatorMaxX , y ) , col) ;
9260
}
9261
return true ;
9262
}
9263
9264
void ImGui:: EndTabBar ( )
9265
{
9266
ImGuiContext& g = * GImGui;
9267
ImGuiWindow* window = g. CurrentWindow ;
9268
if ( window-> SkipItems )
9269
return ;
9270
9271
ImGuiTabBar* tab_bar = g. CurrentTabBar ;
9272
if ( tab_bar == NULL )
9273
{
9274
IM_ASSERT_USER_ERROR ( tab_bar != NULL , " Mismatched BeginTabBar()/EndTabBar()!" ) ;
9275
return ;
9276
}
9277
9278
9279
if ( tab_bar-> WantLayout )
9280
TabBarLayout ( tab_bar ) ;
9281
9282
9283
const bool tab_bar_appearing = ( tab_bar-> PrevFrameVisible + 1 < g. FrameCount ) ;
9284
if ( tab_bar-> VisibleTabWasSubmitted || tab_bar-> VisibleTabId == 0 || tab_bar_appearing)
9285
{
9286
tab_bar-> CurrTabsContentsHeight = ImMax ( window-> DC . CursorPos . y - tab_bar-> BarRect . Max . y , tab_bar-> CurrTabsContentsHeight ) ;
9287
window-> DC . CursorPos . y = tab_bar-> BarRect . Max . y + tab_bar-> CurrTabsContentsHeight ;
9288
}
9289
else
9290
{
9291
window-> DC . CursorPos . y = tab_bar-> BarRect . Max . y + tab_bar-> PrevTabsContentsHeight ;
9292
}
9293
if ( tab_bar-> BeginCount > 1 )
9294
window-> DC . CursorPos = tab_bar-> BackupCursorPos ;
9295
9296
tab_bar-> LastTabItemIdx = - 1 ;
9297
if ( ( tab_bar-> Flags & ImGuiTabBarFlags_DockNode) == 0 )
9298
PopID ( ) ;
9299
9300
g. CurrentTabBarStack . pop_back ( ) ;
9301
g. CurrentTabBar = g. CurrentTabBarStack . empty ( ) ? NULL : GetTabBarFromTabBarRef ( g. CurrentTabBarStack . back ( ) ) ;
9302
}
9303
9304
9305
static float TabBarCalcScrollableWidth ( ImGuiTabBar* tab_bar , ImGuiTabBarSection* sections )
9306
{
9307
return tab_bar-> BarRect . GetWidth ( ) - sections[ 0 ] . Width - sections[ 2 ] . Width - sections[ 1 ] . Spacing ;
9308
}
9309
9310
9311
9312
static void ImGui:: TabBarLayout ( ImGuiTabBar* tab_bar )
9313
{
9314
ImGuiContext& g = * GImGui;
9315
tab_bar-> WantLayout = false ;
9316
9317
9318
9319
int tab_dst_n = 0 ;
9320
bool need_sort_by_section = false ;
9321
ImGuiTabBarSection sections[ 3 ] ;
9322
for ( int tab_src_n = 0 ; tab_src_n < tab_bar-> Tabs . Size ; tab_src_n+ + )
9323
{
9324
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_src_n] ;
9325
if ( tab-> LastFrameVisible < tab_bar-> PrevFrameVisible || tab-> WantClose )
9326
{
9327
9328
if ( tab_bar-> VisibleTabId == tab-> ID ) { tab_bar-> VisibleTabId = 0 ; }
9329
if ( tab_bar-> SelectedTabId == tab-> ID ) { tab_bar-> SelectedTabId = 0 ; }
9330
if ( tab_bar-> NextSelectedTabId == tab-> ID ) { tab_bar-> NextSelectedTabId = 0 ; }
9331
continue ;
9332
}
9333
if ( tab_dst_n != tab_src_n)
9334
tab_bar-> Tabs [ tab_dst_n] = tab_bar-> Tabs [ tab_src_n] ;
9335
9336
tab = & tab_bar-> Tabs [ tab_dst_n] ;
9337
tab-> IndexDuringLayout = ( ImS16) tab_dst_n;
9338
9339
9340
int curr_tab_section_n = TabItemGetSectionIdx ( tab ) ;
9341
if ( tab_dst_n > 0 )
9342
{
9343
ImGuiTabItem* prev_tab = & tab_bar-> Tabs [ tab_dst_n - 1 ] ;
9344
int prev_tab_section_n = TabItemGetSectionIdx ( prev_tab ) ;
9345
if ( curr_tab_section_n == 0 && prev_tab_section_n != 0 )
9346
need_sort_by_section = true ;
9347
if ( prev_tab_section_n == 2 && curr_tab_section_n != 2 )
9348
need_sort_by_section = true ;
9349
}
9350
9351
sections[ curr_tab_section_n] . TabCount + + ;
9352
tab_dst_n+ + ;
9353
}
9354
if ( tab_bar-> Tabs . Size != tab_dst_n)
9355
tab_bar-> Tabs . resize ( tab_dst_n ) ;
9356
9357
if ( need_sort_by_section)
9358
ImQsort ( tab_bar-> Tabs . Data , tab_bar-> Tabs . Size , sizeof ( ImGuiTabItem ) , TabItemComparerBySection ) ;
9359
9360
9361
sections[ 0 ] . Spacing = sections[ 0 ] . TabCount > 0 && ( sections[ 1 ] . TabCount + sections[ 2 ] . TabCount ) > 0 ? g. Style . ItemInnerSpacing . x : 0.0f ;
9362
sections[ 1 ] . Spacing = sections[ 1 ] . TabCount > 0 && sections[ 2 ] . TabCount > 0 ? g. Style . ItemInnerSpacing . x : 0.0f ;
9363
9364
9365
ImGuiID scroll_to_tab_id = 0 ;
9366
if ( tab_bar-> NextSelectedTabId )
9367
{
9368
tab_bar-> SelectedTabId = tab_bar-> NextSelectedTabId ;
9369
tab_bar-> NextSelectedTabId = 0 ;
9370
scroll_to_tab_id = tab_bar-> SelectedTabId ;
9371
}
9372
9373
9374
if ( tab_bar-> ReorderRequestTabId != 0 )
9375
{
9376
if ( TabBarProcessReorder ( tab_bar ) )
9377
if ( tab_bar-> ReorderRequestTabId == tab_bar-> SelectedTabId )
9378
scroll_to_tab_id = tab_bar-> ReorderRequestTabId ;
9379
tab_bar-> ReorderRequestTabId = 0 ;
9380
}
9381
9382
9383
const bool tab_list_popup_button = ( tab_bar-> Flags & ImGuiTabBarFlags_TabListPopupButton) != 0 ;
9384
if ( tab_list_popup_button)
9385
if ( ImGuiTabItem* tab_to_select = TabBarTabListPopupButton ( tab_bar ) )
9386
scroll_to_tab_id = tab_bar-> SelectedTabId = tab_to_select-> ID ;
9387
9388
9389
9390
int shrink_buffer_indexes[ 3 ] = { 0 , sections[ 0 ] . TabCount + sections[ 2 ] . TabCount , sections[ 0 ] . TabCount } ;
9391
g. ShrinkWidthBuffer . resize ( tab_bar-> Tabs . Size ) ;
9392
9393
9394
ImGuiTabItem* most_recently_selected_tab = NULL ;
9395
int curr_section_n = - 1 ;
9396
bool found_selected_tab_id = false ;
9397
for ( int tab_n = 0 ; tab_n < tab_bar-> Tabs . Size ; tab_n+ + )
9398
{
9399
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_n] ;
9400
IM_ASSERT ( tab-> LastFrameVisible >= tab_bar-> PrevFrameVisible ) ;
9401
9402
if ( ( most_recently_selected_tab == NULL || most_recently_selected_tab-> LastFrameSelected < tab-> LastFrameSelected ) && ! ( tab-> Flags & ImGuiTabItemFlags_Button) )
9403
most_recently_selected_tab = tab;
9404
if ( tab-> ID == tab_bar-> SelectedTabId )
9405
found_selected_tab_id = true ;
9406
if ( scroll_to_tab_id == 0 && g. NavJustMovedToId == tab-> ID )
9407
scroll_to_tab_id = tab-> ID ;
9408
9409
9410
9411
9412
const char * tab_name = TabBarGetTabName ( tab_bar, tab ) ;
9413
const bool has_close_button_or_unsaved_marker = ( tab-> Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || ( tab-> Flags & ImGuiTabItemFlags_UnsavedDocument) ;
9414
tab-> ContentWidth = ( tab-> RequestedWidth >= 0.0f ) ? tab-> RequestedWidth : TabItemCalcSize ( tab_name, has_close_button_or_unsaved_marker ) . x ;
9415
9416
int section_n = TabItemGetSectionIdx ( tab ) ;
9417
ImGuiTabBarSection* section = & sections[ section_n] ;
9418
section-> Width += tab-> ContentWidth + ( section_n == curr_section_n ? g. Style . ItemInnerSpacing . x : 0.0f ) ;
9419
curr_section_n = section_n;
9420
9421
9422
IM_MSVC_WARNING_SUPPRESS ( 6385 ) ;
9423
ImGuiShrinkWidthItem* shrink_width_item = & g. ShrinkWidthBuffer [ shrink_buffer_indexes[ section_n] + + ] ;
9424
shrink_width_item-> Index = tab_n;
9425
shrink_width_item-> Width = shrink_width_item-> InitialWidth = tab-> ContentWidth ;
9426
tab-> Width = ImMax ( tab-> ContentWidth , 1.0f ) ;
9427
}
9428
9429
9430
tab_bar-> WidthAllTabsIdeal = 0.0f ;
9431
for ( int section_n = 0 ; section_n < 3 ; section_n+ + )
9432
tab_bar-> WidthAllTabsIdeal += sections[ section_n] . Width + sections[ section_n] . Spacing ;
9433
9434
9435
9436
if ( ( tab_bar-> WidthAllTabsIdeal > tab_bar-> BarRect . GetWidth ( ) && tab_bar-> Tabs . Size > 1 ) && ! ( tab_bar-> Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && ( tab_bar-> Flags & ImGuiTabBarFlags_FittingPolicyScroll) )
9437
if ( ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons ( tab_bar ) )
9438
{
9439
scroll_to_tab_id = scroll_and_select_tab-> ID ;
9440
if ( ( scroll_and_select_tab-> Flags & ImGuiTabItemFlags_Button) == 0 )
9441
tab_bar-> SelectedTabId = scroll_to_tab_id;
9442
}
9443
9444
9445
float section_0_w = sections[ 0 ] . Width + sections[ 0 ] . Spacing ;
9446
float section_1_w = sections[ 1 ] . Width + sections[ 1 ] . Spacing ;
9447
float section_2_w = sections[ 2 ] . Width + sections[ 2 ] . Spacing ;
9448
bool central_section_is_visible = ( section_0_w + section_2_w) < tab_bar-> BarRect . GetWidth ( ) ;
9449
float width_excess;
9450
if ( central_section_is_visible)
9451
width_excess = ImMax ( section_1_w - ( tab_bar-> BarRect . GetWidth ( ) - section_0_w - section_2_w) , 0.0f ) ;
9452
else
9453
width_excess = ( section_0_w + section_2_w) - tab_bar-> BarRect . GetWidth ( ) ;
9454
9455
9456
if ( width_excess >= 1.0f && ( ( tab_bar-> Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || ! central_section_is_visible) )
9457
{
9458
int shrink_data_count = ( central_section_is_visible ? sections[ 1 ] . TabCount : sections[ 0 ] . TabCount + sections[ 2 ] . TabCount ) ;
9459
int shrink_data_offset = ( central_section_is_visible ? sections[ 0 ] . TabCount + sections[ 2 ] . TabCount : 0 ) ;
9460
ShrinkWidths ( g. ShrinkWidthBuffer . Data + shrink_data_offset, shrink_data_count, width_excess ) ;
9461
9462
9463
for ( int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n+ + )
9464
{
9465
ImGuiTabItem* tab = & tab_bar-> Tabs [ g. ShrinkWidthBuffer [ tab_n] . Index ] ;
9466
float shrinked_width = IM_TRUNC ( g. ShrinkWidthBuffer [ tab_n] . Width ) ;
9467
if ( shrinked_width < 0.0f )
9468
continue ;
9469
9470
shrinked_width = ImMax ( 1.0f , shrinked_width) ;
9471
int section_n = TabItemGetSectionIdx ( tab ) ;
9472
sections[ section_n] . Width -= ( tab-> Width - shrinked_width) ;
9473
tab-> Width = shrinked_width;
9474
}
9475
}
9476
9477
9478
int section_tab_index = 0 ;
9479
float tab_offset = 0.0f ;
9480
tab_bar-> WidthAllTabs = 0.0f ;
9481
for ( int section_n = 0 ; section_n < 3 ; section_n+ + )
9482
{
9483
ImGuiTabBarSection* section = & sections[ section_n] ;
9484
if ( section_n == 2 )
9485
tab_offset = ImMin ( ImMax ( 0.0f , tab_bar-> BarRect . GetWidth ( ) - section-> Width ) , tab_offset) ;
9486
9487
for ( int tab_n = 0 ; tab_n < section-> TabCount ; tab_n+ + )
9488
{
9489
ImGuiTabItem* tab = & tab_bar-> Tabs [ section_tab_index + tab_n] ;
9490
tab-> Offset = tab_offset;
9491
tab-> NameOffset = - 1 ;
9492
tab_offset += tab-> Width + ( tab_n < section-> TabCount - 1 ? g. Style . ItemInnerSpacing . x : 0.0f ) ;
9493
}
9494
tab_bar-> WidthAllTabs += ImMax ( section-> Width + section-> Spacing , 0.0f ) ;
9495
tab_offset += section-> Spacing ;
9496
section_tab_index += section-> TabCount ;
9497
}
9498
9499
9500
tab_bar-> TabsNames . Buf . resize ( 0 ) ;
9501
9502
9503
if ( found_selected_tab_id == false )
9504
tab_bar-> SelectedTabId = 0 ;
9505
if ( tab_bar-> SelectedTabId == 0 && tab_bar-> NextSelectedTabId == 0 && most_recently_selected_tab != NULL )
9506
scroll_to_tab_id = tab_bar-> SelectedTabId = most_recently_selected_tab-> ID ;
9507
9508
9509
tab_bar-> VisibleTabId = tab_bar-> SelectedTabId ;
9510
tab_bar-> VisibleTabWasSubmitted = false ;
9511
9512
9513
if ( g. NavWindowingTarget != NULL && g. NavWindowingTarget -> DockNode && g. NavWindowingTarget -> DockNode -> TabBar == tab_bar)
9514
tab_bar-> VisibleTabId = scroll_to_tab_id = g. NavWindowingTarget -> TabId ;
9515
9516
9517
if ( scroll_to_tab_id != 0 )
9518
TabBarScrollToTab ( tab_bar, scroll_to_tab_id, sections ) ;
9519
else if ( ( tab_bar-> Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect ( tab_bar-> BarRect . Min , tab_bar-> BarRect . Max , true ) && IsWindowContentHoverable ( g. CurrentWindow ) )
9520
{
9521
const float wheel = g. IO . MouseWheelRequestAxisSwap ? g. IO . MouseWheel : g. IO . MouseWheelH ;
9522
const ImGuiKey wheel_key = g. IO . MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX;
9523
if ( TestKeyOwner ( wheel_key, tab_bar-> ID ) && wheel != 0.0f )
9524
{
9525
const float scroll_step = wheel * TabBarCalcScrollableWidth ( tab_bar, sections ) / 3.0f ;
9526
tab_bar-> ScrollingTargetDistToVisibility = 0.0f ;
9527
tab_bar-> ScrollingTarget = TabBarScrollClamp ( tab_bar, tab_bar-> ScrollingTarget - scroll_step ) ;
9528
}
9529
SetKeyOwner ( wheel_key, tab_bar-> ID ) ;
9530
}
9531
9532
9533
tab_bar-> ScrollingAnim = TabBarScrollClamp ( tab_bar, tab_bar-> ScrollingAnim ) ;
9534
tab_bar-> ScrollingTarget = TabBarScrollClamp ( tab_bar, tab_bar-> ScrollingTarget ) ;
9535
if ( tab_bar-> ScrollingAnim != tab_bar-> ScrollingTarget )
9536
{
9537
9538
9539
tab_bar-> ScrollingSpeed = ImMax ( tab_bar-> ScrollingSpeed , 70.0f * g. FontSize ) ;
9540
tab_bar-> ScrollingSpeed = ImMax ( tab_bar-> ScrollingSpeed , ImFabs ( tab_bar-> ScrollingTarget - tab_bar-> ScrollingAnim ) / 0.3f ) ;
9541
const bool teleport = ( tab_bar-> PrevFrameVisible + 1 < g. FrameCount ) || ( tab_bar-> ScrollingTargetDistToVisibility > 10.0f * g. FontSize ) ;
9542
tab_bar-> ScrollingAnim = teleport ? tab_bar-> ScrollingTarget : ImLinearSweep ( tab_bar-> ScrollingAnim , tab_bar-> ScrollingTarget , g. IO . DeltaTime * tab_bar-> ScrollingSpeed ) ;
9543
}
9544
else
9545
{
9546
tab_bar-> ScrollingSpeed = 0.0f ;
9547
}
9548
tab_bar-> ScrollingRectMinX = tab_bar-> BarRect . Min . x + sections[ 0 ] . Width + sections[ 0 ] . Spacing ;
9549
tab_bar-> ScrollingRectMaxX = tab_bar-> BarRect . Max . x - sections[ 2 ] . Width - sections[ 1 ] . Spacing ;
9550
9551
9552
ImGuiWindow* window = g. CurrentWindow ;
9553
window-> DC . CursorPos = tab_bar-> BarRect . Min ;
9554
ItemSize ( ImVec2 ( tab_bar-> WidthAllTabs , tab_bar-> BarRect . GetHeight ( ) ) , tab_bar-> FramePadding . y ) ;
9555
window-> DC . IdealMaxPos . x = ImMax ( window-> DC . IdealMaxPos . x , tab_bar-> BarRect . Min . x + tab_bar-> WidthAllTabsIdeal ) ;
9556
}
9557
9558
9559
static ImU32 ImGui:: TabBarCalcTabID ( ImGuiTabBar* tab_bar , const char * label , ImGuiWindow* docked_window )
9560
{
9561
if ( docked_window != NULL )
9562
{
9563
IM_UNUSED ( tab_bar ) ;
9564
IM_ASSERT ( tab_bar-> Flags & ImGuiTabBarFlags_DockNode ) ;
9565
ImGuiID id = docked_window-> TabId ;
9566
KeepAliveID ( id ) ;
9567
return id;
9568
}
9569
else
9570
{
9571
ImGuiWindow* window = GImGui-> CurrentWindow ;
9572
return window-> GetID ( label ) ;
9573
}
9574
}
9575
9576
static float ImGui:: TabBarCalcMaxTabWidth ( )
9577
{
9578
ImGuiContext& g = * GImGui;
9579
return g. FontSize * 20.0f ;
9580
}
9581
9582
ImGuiTabItem* ImGui:: TabBarFindTabByID ( ImGuiTabBar* tab_bar , ImGuiID tab_id )
9583
{
9584
if ( tab_id != 0 )
9585
for ( int n = 0 ; n < tab_bar-> Tabs . Size ; n+ + )
9586
if ( tab_bar-> Tabs [ n] . ID == tab_id)
9587
return & tab_bar-> Tabs [ n] ;
9588
return NULL ;
9589
}
9590
9591
9592
ImGuiTabItem* ImGui:: TabBarFindTabByOrder ( ImGuiTabBar* tab_bar , int order )
9593
{
9594
if ( order < 0 || order >= tab_bar-> Tabs . Size )
9595
return NULL ;
9596
return & tab_bar-> Tabs [ order] ;
9597
}
9598
9599
9600
ImGuiTabItem* ImGui:: TabBarFindMostRecentlySelectedTabForActiveWindow ( ImGuiTabBar* tab_bar )
9601
{
9602
ImGuiTabItem* most_recently_selected_tab = NULL ;
9603
for ( int tab_n = 0 ; tab_n < tab_bar-> Tabs . Size ; tab_n+ + )
9604
{
9605
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_n] ;
9606
if ( most_recently_selected_tab == NULL || most_recently_selected_tab-> LastFrameSelected < tab-> LastFrameSelected )
9607
if ( tab-> Window && tab-> Window -> WasActive )
9608
most_recently_selected_tab = tab;
9609
}
9610
return most_recently_selected_tab;
9611
}
9612
9613
ImGuiTabItem* ImGui:: TabBarGetCurrentTab ( ImGuiTabBar* tab_bar )
9614
{
9615
if ( tab_bar-> LastTabItemIdx < 0 || tab_bar-> LastTabItemIdx >= tab_bar-> Tabs . Size )
9616
return NULL ;
9617
return & tab_bar-> Tabs [ tab_bar-> LastTabItemIdx ] ;
9618
}
9619
9620
const char * ImGui:: TabBarGetTabName ( ImGuiTabBar* tab_bar , ImGuiTabItem* tab )
9621
{
9622
if ( tab-> Window )
9623
return tab-> Window -> Name ;
9624
if ( tab-> NameOffset == - 1 )
9625
return " N/A" ;
9626
IM_ASSERT ( tab-> NameOffset < tab_bar-> TabsNames . Buf . Size ) ;
9627
return tab_bar-> TabsNames . Buf . Data + tab-> NameOffset ;
9628
}
9629
9630
9631
9632
void ImGui:: TabBarAddTab ( ImGuiTabBar* tab_bar , ImGuiTabItemFlags tab_flags , ImGuiWindow* window )
9633
{
9634
ImGuiContext& g = * GImGui;
9635
IM_ASSERT ( TabBarFindTabByID ( tab_bar, window-> TabId ) == NULL ) ;
9636
IM_ASSERT ( g. CurrentTabBar != tab_bar ) ;
9637
9638
if ( ! window-> HasCloseButton )
9639
tab_flags |= ImGuiTabItemFlags_NoCloseButton;
9640
9641
ImGuiTabItem new_tab;
9642
new_tab. ID = window-> TabId ;
9643
new_tab. Flags = tab_flags;
9644
new_tab. LastFrameVisible = tab_bar-> CurrFrameVisible ;
9645
if ( new_tab. LastFrameVisible == - 1 )
9646
new_tab. LastFrameVisible = g. FrameCount - 1 ;
9647
new_tab. Window = window;
9648
tab_bar-> Tabs . push_back ( new_tab ) ;
9649
}
9650
9651
9652
void ImGui:: TabBarRemoveTab ( ImGuiTabBar* tab_bar , ImGuiID tab_id )
9653
{
9654
if ( ImGuiTabItem* tab = TabBarFindTabByID ( tab_bar, tab_id ) )
9655
tab_bar-> Tabs . erase ( tab ) ;
9656
if ( tab_bar-> VisibleTabId == tab_id) { tab_bar-> VisibleTabId = 0 ; }
9657
if ( tab_bar-> SelectedTabId == tab_id) { tab_bar-> SelectedTabId = 0 ; }
9658
if ( tab_bar-> NextSelectedTabId == tab_id) { tab_bar-> NextSelectedTabId = 0 ; }
9659
}
9660
9661
9662
void ImGui:: TabBarCloseTab ( ImGuiTabBar* tab_bar , ImGuiTabItem* tab )
9663
{
9664
if ( tab-> Flags & ImGuiTabItemFlags_Button)
9665
return ;
9666
9667
if ( ( tab-> Flags & ( ImGuiTabItemFlags_UnsavedDocument | ImGuiTabItemFlags_NoAssumedClosure) ) == 0 )
9668
{
9669
9670
9671
tab-> WantClose = true ;
9672
if ( tab_bar-> VisibleTabId == tab-> ID )
9673
{
9674
tab-> LastFrameVisible = - 1 ;
9675
tab_bar-> SelectedTabId = tab_bar-> NextSelectedTabId = 0 ;
9676
}
9677
}
9678
else
9679
{
9680
9681
if ( tab_bar-> VisibleTabId != tab-> ID )
9682
TabBarQueueFocus ( tab_bar, tab ) ;
9683
}
9684
}
9685
9686
static float ImGui:: TabBarScrollClamp ( ImGuiTabBar* tab_bar , float scrolling )
9687
{
9688
scrolling = ImMin ( scrolling, tab_bar-> WidthAllTabs - tab_bar-> BarRect . GetWidth ( ) ) ;
9689
return ImMax ( scrolling, 0.0f ) ;
9690
}
9691
9692
9693
static void ImGui:: TabBarScrollToTab ( ImGuiTabBar* tab_bar , ImGuiID tab_id , ImGuiTabBarSection* sections )
9694
{
9695
ImGuiTabItem* tab = TabBarFindTabByID ( tab_bar, tab_id ) ;
9696
if ( tab == NULL )
9697
return ;
9698
if ( tab-> Flags & ImGuiTabItemFlags_SectionMask_)
9699
return ;
9700
9701
ImGuiContext& g = * GImGui;
9702
float margin = g. FontSize * 1.0f ;
9703
int order = TabBarGetTabOrder ( tab_bar, tab ) ;
9704
9705
9706
float scrollable_width = TabBarCalcScrollableWidth ( tab_bar, sections ) ;
9707
9708
9709
float tab_x1 = tab-> Offset - sections[ 0 ] . Width + ( order > sections[ 0 ] . TabCount - 1 ? - margin : 0.0f ) ;
9710
float tab_x2 = tab-> Offset - sections[ 0 ] . Width + tab-> Width + ( order + 1 < tab_bar-> Tabs . Size - sections[ 2 ] . TabCount ? margin : 1.0f ) ;
9711
tab_bar-> ScrollingTargetDistToVisibility = 0.0f ;
9712
if ( tab_bar-> ScrollingTarget > tab_x1 || ( tab_x2 - tab_x1 >= scrollable_width) )
9713
{
9714
9715
tab_bar-> ScrollingTargetDistToVisibility = ImMax ( tab_bar-> ScrollingAnim - tab_x2, 0.0f ) ;
9716
tab_bar-> ScrollingTarget = tab_x1;
9717
}
9718
else if ( tab_bar-> ScrollingTarget < tab_x2 - scrollable_width)
9719
{
9720
9721
tab_bar-> ScrollingTargetDistToVisibility = ImMax ( ( tab_x1 - scrollable_width) - tab_bar-> ScrollingAnim , 0.0f ) ;
9722
tab_bar-> ScrollingTarget = tab_x2 - scrollable_width;
9723
}
9724
}
9725
9726
void ImGui:: TabBarQueueFocus ( ImGuiTabBar* tab_bar , ImGuiTabItem* tab )
9727
{
9728
tab_bar-> NextSelectedTabId = tab-> ID ;
9729
}
9730
9731
void ImGui:: TabBarQueueFocus ( ImGuiTabBar* tab_bar , const char * tab_name )
9732
{
9733
IM_ASSERT ( ( tab_bar-> Flags & ImGuiTabBarFlags_DockNode) == 0 ) ;
9734
ImGuiID tab_id = TabBarCalcTabID ( tab_bar, tab_name, NULL ) ;
9735
tab_bar-> NextSelectedTabId = tab_id;
9736
}
9737
9738
void ImGui:: TabBarQueueReorder ( ImGuiTabBar* tab_bar , ImGuiTabItem* tab , int offset )
9739
{
9740
IM_ASSERT ( offset != 0 ) ;
9741
IM_ASSERT ( tab_bar-> ReorderRequestTabId == 0 ) ;
9742
tab_bar-> ReorderRequestTabId = tab-> ID ;
9743
tab_bar-> ReorderRequestOffset = ( ImS16) offset;
9744
}
9745
9746
void ImGui:: TabBarQueueReorderFromMousePos ( ImGuiTabBar* tab_bar , ImGuiTabItem* src_tab , ImVec2 mouse_pos )
9747
{
9748
ImGuiContext& g = * GImGui;
9749
IM_ASSERT ( tab_bar-> ReorderRequestTabId == 0 ) ;
9750
if ( ( tab_bar-> Flags & ImGuiTabBarFlags_Reorderable) == 0 )
9751
return ;
9752
9753
const bool is_central_section = ( src_tab-> Flags & ImGuiTabItemFlags_SectionMask_) == 0 ;
9754
const float bar_offset = tab_bar-> BarRect . Min . x - ( is_central_section ? tab_bar-> ScrollingTarget : 0 ) ;
9755
9756
9757
const int dir = ( bar_offset + src_tab-> Offset ) > mouse_pos. x ? - 1 : + 1 ;
9758
const int src_idx = tab_bar-> Tabs . index_from_ptr ( src_tab ) ;
9759
int dst_idx = src_idx;
9760
for ( int i = src_idx; i >= 0 && i < tab_bar-> Tabs . Size ; i += dir)
9761
{
9762
9763
const ImGuiTabItem* dst_tab = & tab_bar-> Tabs [ i] ;
9764
if ( dst_tab-> Flags & ImGuiTabItemFlags_NoReorder)
9765
break ;
9766
if ( ( dst_tab-> Flags & ImGuiTabItemFlags_SectionMask_) != ( src_tab-> Flags & ImGuiTabItemFlags_SectionMask_) )
9767
break ;
9768
dst_idx = i;
9769
9770
9771
const float x1 = bar_offset + dst_tab-> Offset - g. Style . ItemInnerSpacing . x ;
9772
const float x2 = bar_offset + dst_tab-> Offset + dst_tab-> Width + g. Style . ItemInnerSpacing . x ;
9773
9774
if ( ( dir < 0 && mouse_pos. x > x1) || ( dir > 0 && mouse_pos. x < x2) )
9775
break ;
9776
}
9777
9778
if ( dst_idx != src_idx)
9779
TabBarQueueReorder ( tab_bar, src_tab, dst_idx - src_idx ) ;
9780
}
9781
9782
bool ImGui:: TabBarProcessReorder ( ImGuiTabBar* tab_bar )
9783
{
9784
ImGuiTabItem* tab1 = TabBarFindTabByID ( tab_bar, tab_bar-> ReorderRequestTabId ) ;
9785
if ( tab1 == NULL || ( tab1-> Flags & ImGuiTabItemFlags_NoReorder) )
9786
return false ;
9787
9788
9789
int tab2_order = TabBarGetTabOrder ( tab_bar, tab1 ) + tab_bar-> ReorderRequestOffset ;
9790
if ( tab2_order < 0 || tab2_order >= tab_bar-> Tabs . Size )
9791
return false ;
9792
9793
9794
9795
ImGuiTabItem* tab2 = & tab_bar-> Tabs [ tab2_order] ;
9796
if ( tab2-> Flags & ImGuiTabItemFlags_NoReorder)
9797
return false ;
9798
if ( ( tab1-> Flags & ImGuiTabItemFlags_SectionMask_) != ( tab2-> Flags & ImGuiTabItemFlags_SectionMask_) )
9799
return false ;
9800
9801
ImGuiTabItem item_tmp = * tab1;
9802
ImGuiTabItem* src_tab = ( tab_bar-> ReorderRequestOffset > 0 ) ? tab1 + 1 : tab2;
9803
ImGuiTabItem* dst_tab = ( tab_bar-> ReorderRequestOffset > 0 ) ? tab1 : tab2 + 1 ;
9804
const int move_count = ( tab_bar-> ReorderRequestOffset > 0 ) ? tab_bar-> ReorderRequestOffset : - tab_bar-> ReorderRequestOffset ;
9805
memmove ( dst_tab, src_tab, move_count * sizeof ( ImGuiTabItem ) ) ;
9806
* tab2 = item_tmp;
9807
9808
if ( tab_bar-> Flags & ImGuiTabBarFlags_SaveSettings)
9809
MarkIniSettingsDirty ( ) ;
9810
return true ;
9811
}
9812
9813
static ImGuiTabItem* ImGui:: TabBarScrollingButtons ( ImGuiTabBar* tab_bar )
9814
{
9815
ImGuiContext& g = * GImGui;
9816
ImGuiWindow* window = g. CurrentWindow ;
9817
9818
const ImVec2 arrow_button_size ( g. FontSize - 2.0f , g. FontSize + g. Style . FramePadding . y * 2.0f ) ;
9819
const float scrolling_buttons_width = arrow_button_size. x * 2.0f ;
9820
9821
const ImVec2 backup_cursor_pos = window-> DC . CursorPos ;
9822
9823
9824
int select_dir = 0 ;
9825
ImVec4 arrow_col = g. Style . Colors [ ImGuiCol_Text] ;
9826
arrow_col. w *= 0.5f ;
9827
9828
PushStyleColor ( ImGuiCol_Text, arrow_col ) ;
9829
PushStyleColor ( ImGuiCol_Button, ImVec4 ( 0 , 0 , 0 , 0 ) ) ;
9830
PushItemFlag ( ImGuiItemFlags_ButtonRepeat, true ) ;
9831
const float backup_repeat_delay = g. IO . KeyRepeatDelay ;
9832
const float backup_repeat_rate = g. IO . KeyRepeatRate ;
9833
g. IO . KeyRepeatDelay = 0.250f ;
9834
g. IO . KeyRepeatRate = 0.200f ;
9835
float x = ImMax ( tab_bar-> BarRect . Min . x , tab_bar-> BarRect . Max . x - scrolling_buttons_width ) ;
9836
window-> DC . CursorPos = ImVec2 ( x, tab_bar-> BarRect . Min . y ) ;
9837
if ( ArrowButtonEx ( " ##<" , ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick) )
9838
select_dir = - 1 ;
9839
window-> DC . CursorPos = ImVec2 ( x + arrow_button_size. x , tab_bar-> BarRect . Min . y ) ;
9840
if ( ArrowButtonEx ( " ##>" , ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick) )
9841
select_dir = + 1 ;
9842
PopItemFlag ( ) ;
9843
PopStyleColor ( 2 ) ;
9844
g. IO . KeyRepeatRate = backup_repeat_rate;
9845
g. IO . KeyRepeatDelay = backup_repeat_delay;
9846
9847
ImGuiTabItem* tab_to_scroll_to = NULL ;
9848
if ( select_dir != 0 )
9849
if ( ImGuiTabItem* tab_item = TabBarFindTabByID ( tab_bar, tab_bar-> SelectedTabId ) )
9850
{
9851
int selected_order = TabBarGetTabOrder ( tab_bar, tab_item ) ;
9852
int target_order = selected_order + select_dir;
9853
9854
9855
while ( tab_to_scroll_to == NULL )
9856
{
9857
9858
tab_to_scroll_to = & tab_bar-> Tabs [ ( target_order >= 0 && target_order < tab_bar-> Tabs . Size ) ? target_order : selected_order] ;
9859
9860
9861
9862
if ( tab_to_scroll_to-> Flags & ImGuiTabItemFlags_Button)
9863
{
9864
target_order += select_dir;
9865
selected_order += select_dir;
9866
tab_to_scroll_to = ( target_order < 0 || target_order >= tab_bar-> Tabs . Size ) ? tab_to_scroll_to : NULL ;
9867
}
9868
}
9869
}
9870
window-> DC . CursorPos = backup_cursor_pos;
9871
tab_bar-> BarRect . Max . x -= scrolling_buttons_width + 1.0f ;
9872
9873
return tab_to_scroll_to;
9874
}
9875
9876
static ImGuiTabItem* ImGui:: TabBarTabListPopupButton ( ImGuiTabBar* tab_bar )
9877
{
9878
ImGuiContext& g = * GImGui;
9879
ImGuiWindow* window = g. CurrentWindow ;
9880
9881
9882
const float tab_list_popup_button_width = g. FontSize + g. Style . FramePadding . y ;
9883
const ImVec2 backup_cursor_pos = window-> DC . CursorPos ;
9884
window-> DC . CursorPos = ImVec2 ( tab_bar-> BarRect . Min . x - g. Style . FramePadding . y , tab_bar-> BarRect . Min . y ) ;
9885
tab_bar-> BarRect . Min . x += tab_list_popup_button_width;
9886
9887
ImVec4 arrow_col = g. Style . Colors [ ImGuiCol_Text] ;
9888
arrow_col. w *= 0.5f ;
9889
PushStyleColor ( ImGuiCol_Text, arrow_col ) ;
9890
PushStyleColor ( ImGuiCol_Button, ImVec4 ( 0 , 0 , 0 , 0 ) ) ;
9891
bool open = BeginCombo ( " ##v" , NULL , ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest) ;
9892
PopStyleColor ( 2 ) ;
9893
9894
ImGuiTabItem* tab_to_select = NULL ;
9895
if ( open)
9896
{
9897
for ( int tab_n = 0 ; tab_n < tab_bar-> Tabs . Size ; tab_n+ + )
9898
{
9899
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_n] ;
9900
if ( tab-> Flags & ImGuiTabItemFlags_Button)
9901
continue ;
9902
9903
const char * tab_name = TabBarGetTabName ( tab_bar, tab ) ;
9904
if ( Selectable ( tab_name, tab_bar-> SelectedTabId == tab-> ID ) )
9905
tab_to_select = tab;
9906
}
9907
EndCombo ( ) ;
9908
}
9909
9910
window-> DC . CursorPos = backup_cursor_pos;
9911
return tab_to_select;
9912
}
9913
9914
9915
9916
9917
9918
9919
9920
9921
9922
9923
9924
9925
9926
9927
bool ImGui:: BeginTabItem ( const char * label , bool * p_open , ImGuiTabItemFlags flags )
9928
{
9929
ImGuiContext& g = * GImGui;
9930
ImGuiWindow* window = g. CurrentWindow ;
9931
if ( window-> SkipItems )
9932
return false ;
9933
9934
ImGuiTabBar* tab_bar = g. CurrentTabBar ;
9935
if ( tab_bar == NULL )
9936
{
9937
IM_ASSERT_USER_ERROR ( tab_bar, " Needs to be called between BeginTabBar() and EndTabBar()!" ) ;
9938
return false ;
9939
}
9940
IM_ASSERT ( ( flags & ImGuiTabItemFlags_Button) == 0 ) ;
9941
9942
bool ret = TabItemEx ( tab_bar, label, p_open, flags, NULL ) ;
9943
if ( ret && ! ( flags & ImGuiTabItemFlags_NoPushId) )
9944
{
9945
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_bar-> LastTabItemIdx ] ;
9946
PushOverrideID ( tab-> ID ) ;
9947
}
9948
return ret;
9949
}
9950
9951
void ImGui:: EndTabItem ( )
9952
{
9953
ImGuiContext& g = * GImGui;
9954
ImGuiWindow* window = g. CurrentWindow ;
9955
if ( window-> SkipItems )
9956
return ;
9957
9958
ImGuiTabBar* tab_bar = g. CurrentTabBar ;
9959
if ( tab_bar == NULL )
9960
{
9961
IM_ASSERT_USER_ERROR ( tab_bar != NULL , " Needs to be called between BeginTabBar() and EndTabBar()!" ) ;
9962
return ;
9963
}
9964
IM_ASSERT ( tab_bar-> LastTabItemIdx >= 0 ) ;
9965
ImGuiTabItem* tab = & tab_bar-> Tabs [ tab_bar-> LastTabItemIdx ] ;
9966
if ( ! ( tab-> Flags & ImGuiTabItemFlags_NoPushId) )
9967
PopID ( ) ;
9968
}
9969
9970
bool ImGui:: TabItemButton ( const char * label , ImGuiTabItemFlags flags )
9971
{
9972
ImGuiContext& g = * GImGui;
9973
ImGuiWindow* window = g. CurrentWindow ;
9974
if ( window-> SkipItems )
9975
return false ;
9976
9977
ImGuiTabBar* tab_bar = g. CurrentTabBar ;
9978
if ( tab_bar == NULL )
9979
{
9980
IM_ASSERT_USER_ERROR ( tab_bar != NULL , " Needs to be called between BeginTabBar() and EndTabBar()!" ) ;
9981
return false ;
9982
}
9983
return TabItemEx ( tab_bar, label, NULL , flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL ) ;
9984
}
9985
9986
bool ImGui:: TabItemEx ( ImGuiTabBar* tab_bar , const char * label , bool * p_open , ImGuiTabItemFlags flags , ImGuiWindow* docked_window )
9987
{
9988
9989
ImGuiContext& g = * GImGui;
9990
if ( tab_bar-> WantLayout )
9991
{
9992
ImGuiNextItemData backup_next_item_data = g. NextItemData ;
9993
TabBarLayout ( tab_bar ) ;
9994
g. NextItemData = backup_next_item_data;
9995
}
9996
ImGuiWindow* window = g. CurrentWindow ;
9997
if ( window-> SkipItems )
9998
return false ;
9999
10000
const ImGuiStyle& style = g. Style ;
10001
const ImGuiID id = TabBarCalcTabID ( tab_bar, label, docked_window ) ;
10002
10003
10004
10005
IMGUI_TEST_ENGINE_ITEM_INFO ( id, label, g. LastItemData . StatusFlags ) ;
10006
if ( p_open && ! * p_open)
10007
{
10008
ItemAdd ( ImRect ( ) , id, NULL , ImGuiItemFlags_NoNav) ;
10009
return false ;
10010
}
10011
10012
IM_ASSERT ( ! p_open || ! ( flags & ImGuiTabItemFlags_Button) ) ;
10013
IM_ASSERT ( ( flags & ( ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing) ) != ( ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing) ) ;
10014
10015
10016
if ( flags & ImGuiTabItemFlags_NoCloseButton)
10017
p_open = NULL ;
10018
else if ( p_open == NULL )
10019
flags |= ImGuiTabItemFlags_NoCloseButton;
10020
10021
10022
ImGuiTabItem* tab = TabBarFindTabByID ( tab_bar, id ) ;
10023
bool tab_is_new = false ;
10024
if ( tab == NULL )
10025
{
10026
tab_bar-> Tabs . push_back ( ImGuiTabItem ( ) ) ;
10027
tab = & tab_bar-> Tabs . back ( ) ;
10028
tab-> ID = id;
10029
tab_bar-> TabsAddedNew = tab_is_new = true ;
10030
}
10031
tab_bar-> LastTabItemIdx = ( ImS16) tab_bar-> Tabs . index_from_ptr ( tab ) ;
10032
10033
10034
ImVec2 size = TabItemCalcSize ( label, ( p_open != NULL ) || ( flags & ImGuiTabItemFlags_UnsavedDocument) ) ;
10035
tab-> RequestedWidth = - 1.0f ;
10036
if ( g. NextItemData . HasFlags & ImGuiNextItemDataFlags_HasWidth)
10037
size. x = tab-> RequestedWidth = g. NextItemData . Width ;
10038
if ( tab_is_new)
10039
tab-> Width = ImMax ( 1.0f , size. x ) ;
10040
tab-> ContentWidth = size. x ;
10041
tab-> BeginOrder = tab_bar-> TabsActiveCount + + ;
10042
10043
const bool tab_bar_appearing = ( tab_bar-> PrevFrameVisible + 1 < g. FrameCount ) ;
10044
const bool tab_bar_focused = ( tab_bar-> Flags & ImGuiTabBarFlags_IsFocused) != 0 ;
10045
const bool tab_appearing = ( tab-> LastFrameVisible + 1 < g. FrameCount ) ;
10046
const bool tab_just_unsaved = ( flags & ImGuiTabItemFlags_UnsavedDocument) && ! ( tab-> Flags & ImGuiTabItemFlags_UnsavedDocument) ;
10047
const bool is_tab_button = ( flags & ImGuiTabItemFlags_Button) != 0 ;
10048
tab-> LastFrameVisible = g. FrameCount ;
10049
tab-> Flags = flags;
10050
tab-> Window = docked_window;
10051
10052
10053
10054
if ( docked_window != NULL )
10055
{
10056
IM_ASSERT ( tab_bar-> Flags & ImGuiTabBarFlags_DockNode ) ;
10057
tab-> NameOffset = - 1 ;
10058
}
10059
else
10060
{
10061
tab-> NameOffset = ( ImS32) tab_bar-> TabsNames . size ( ) ;
10062
tab_bar-> TabsNames . append ( label, label + strlen ( label ) + 1 ) ;
10063
}
10064
10065
10066
if ( ! is_tab_button)
10067
{
10068
if ( tab_appearing && ( tab_bar-> Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar-> NextSelectedTabId == 0 )
10069
if ( ! tab_bar_appearing || tab_bar-> SelectedTabId == 0 )
10070
TabBarQueueFocus ( tab_bar, tab ) ;
10071
if ( ( flags & ImGuiTabItemFlags_SetSelected) && ( tab_bar-> SelectedTabId != id) )
10072
TabBarQueueFocus ( tab_bar, tab ) ;
10073
}
10074
10075
10076
10077
bool tab_contents_visible = ( tab_bar-> VisibleTabId == id) ;
10078
if ( tab_contents_visible)
10079
tab_bar-> VisibleTabWasSubmitted = true ;
10080
10081
10082
if ( ! tab_contents_visible && tab_bar-> SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL )
10083
if ( tab_bar-> Tabs . Size == 1 && ! ( tab_bar-> Flags & ImGuiTabBarFlags_AutoSelectNewTabs) )
10084
tab_contents_visible = true ;
10085
10086
10087
10088
if ( tab_appearing && ( ! tab_bar_appearing || tab_is_new) )
10089
{
10090
ItemAdd ( ImRect ( ) , id, NULL , ImGuiItemFlags_NoNav) ;
10091
if ( is_tab_button)
10092
return false ;
10093
return tab_contents_visible;
10094
}
10095
10096
if ( tab_bar-> SelectedTabId == id)
10097
tab-> LastFrameSelected = g. FrameCount ;
10098
10099
10100
const ImVec2 backup_main_cursor_pos = window-> DC . CursorPos ;
10101
10102
10103
const bool is_central_section = ( tab-> Flags & ImGuiTabItemFlags_SectionMask_) == 0 ;
10104
size. x = tab-> Width ;
10105
if ( is_central_section)
10106
window-> DC . CursorPos = tab_bar-> BarRect . Min + ImVec2 ( IM_TRUNC ( tab-> Offset - tab_bar-> ScrollingAnim ) , 0.0f ) ;
10107
else
10108
window-> DC . CursorPos = tab_bar-> BarRect . Min + ImVec2 ( tab-> Offset , 0.0f ) ;
10109
ImVec2 pos = window-> DC . CursorPos ;
10110
ImRect bb ( pos, pos + size ) ;
10111
10112
10113
const bool want_clip_rect = is_central_section && ( bb. Min . x < tab_bar-> ScrollingRectMinX || bb. Max . x > tab_bar-> ScrollingRectMaxX ) ;
10114
if ( want_clip_rect)
10115
PushClipRect ( ImVec2 ( ImMax ( bb. Min . x , tab_bar-> ScrollingRectMinX ) , bb. Min . y - 1 ) , ImVec2 ( tab_bar-> ScrollingRectMaxX , bb. Max . y ) , true ) ;
10116
10117
ImVec2 backup_cursor_max_pos = window-> DC . CursorMaxPos ;
10118
ItemSize ( bb. GetSize ( ) , style. FramePadding . y ) ;
10119
window-> DC . CursorMaxPos = backup_cursor_max_pos;
10120
10121
if ( ! ItemAdd ( bb, id ) )
10122
{
10123
if ( want_clip_rect)
10124
PopClipRect ( ) ;
10125
window-> DC . CursorPos = backup_main_cursor_pos;
10126
return tab_contents_visible;
10127
}
10128
10129
10130
ImGuiButtonFlags button_flags = ( ( is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap) ;
10131
if ( g. DragDropActive && ! g. DragDropPayload . IsDataType ( IMGUI_PAYLOAD_TYPE_WINDOW ) )
10132
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
10133
bool hovered, held;
10134
bool pressed = ButtonBehavior ( bb, id, & hovered, & held, button_flags ) ;
10135
if ( pressed && ! is_tab_button)
10136
TabBarQueueFocus ( tab_bar, tab ) ;
10137
10138
10139
10140
if ( held && docked_window && g. ActiveId == id && g. ActiveIdIsJustActivated )
10141
g. ActiveIdWindow = docked_window;
10142
10143
10144
ImGuiDockNode* node = docked_window ? docked_window-> DockNode : NULL ;
10145
const bool single_floating_window_node = node && node-> IsFloatingNode ( ) && ( node-> Windows . Size == 1 ) ;
10146
if ( held && single_floating_window_node && IsMouseDragging ( 0 , 0.0f ) )
10147
{
10148
10149
StartMouseMovingWindow ( docked_window ) ;
10150
}
10151
else if ( held && ! tab_appearing && IsMouseDragging ( 0 ) )
10152
{
10153
10154
int drag_dir = 0 ;
10155
float drag_distance_from_edge_x = 0.0f ;
10156
if ( ! g. DragDropActive && ( ( tab_bar-> Flags & ImGuiTabBarFlags_Reorderable) || ( docked_window != NULL ) ) )
10157
{
10158
10159
if ( g. IO . MouseDelta . x < 0.0f && g. IO . MousePos . x < bb. Min . x )
10160
{
10161
drag_dir = - 1 ;
10162
drag_distance_from_edge_x = bb. Min . x - g. IO . MousePos . x ;
10163
TabBarQueueReorderFromMousePos ( tab_bar, tab, g. IO . MousePos ) ;
10164
}
10165
else if ( g. IO . MouseDelta . x > 0.0f && g. IO . MousePos . x > bb. Max . x )
10166
{
10167
drag_dir = + 1 ;
10168
drag_distance_from_edge_x = g. IO . MousePos . x - bb. Max . x ;
10169
TabBarQueueReorderFromMousePos ( tab_bar, tab, g. IO . MousePos ) ;
10170
}
10171
}
10172
10173
10174
const bool can_undock = docked_window != NULL && ! ( docked_window-> Flags & ImGuiWindowFlags_NoMove) && ! ( node-> MergedFlags & ImGuiDockNodeFlags_NoUndocking) ;
10175
if ( can_undock)
10176
{
10177
10178
bool undocking_tab = ( g. DragDropActive && g. DragDropPayload . SourceId == id) ;
10179
if ( ! undocking_tab)
10180
{
10181
float threshold_base = g. FontSize ;
10182
float threshold_x = ( threshold_base * 2.2f ) ;
10183
float threshold_y = ( threshold_base * 1.5f ) + ImClamp ( ( ImFabs ( g. IO . MouseDragMaxDistanceAbs [ 0 ] . x ) - threshold_base * 2.0f ) * 0.20f , 0.0f , threshold_base * 4.0f ) ;
10184
10185
10186
float distance_from_edge_y = ImMax ( bb. Min . y - g. IO . MousePos . y , g. IO . MousePos . y - bb. Max . y ) ;
10187
if ( distance_from_edge_y >= threshold_y)
10188
undocking_tab = true ;
10189
if ( drag_distance_from_edge_x > threshold_x)
10190
if ( ( drag_dir < 0 && TabBarGetTabOrder ( tab_bar, tab ) == 0 ) || ( drag_dir > 0 && TabBarGetTabOrder ( tab_bar, tab ) == tab_bar-> Tabs . Size - 1 ) )
10191
undocking_tab = true ;
10192
}
10193
10194
if ( undocking_tab)
10195
{
10196
10197
10198
DockContextQueueUndockWindow ( & g, docked_window) ;
10199
g. MovingWindow = docked_window;
10200
SetActiveID ( g. MovingWindow -> MoveId , g. MovingWindow ) ;
10201
g. ActiveIdClickOffset -= g. MovingWindow -> Pos - bb. Min ;
10202
g. ActiveIdNoClearOnFocusLoss = true ;
10203
SetActiveIdUsingAllKeyboardKeys ( ) ;
10204
}
10205
}
10206
}
10207
10208
#if 0
10209
10210
10211
10212
10213
10214
10215
10216
#endif
10217
10218
10219
ImDrawList* display_draw_list = window-> DrawList ;
10220
const ImU32 tab_col = GetColorU32 ( ( held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? ( tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : ( tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed) ) ;
10221
TabItemBackground ( display_draw_list, bb, flags, tab_col ) ;
10222
if ( tab_contents_visible && ( tab_bar-> Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style. TabBarOverlineSize > 0.0f )
10223
{
10224
float x_offset = IM_TRUNC ( 0.4f * style. TabRounding ) ;
10225
if ( x_offset < 2.0f * g. CurrentDpiScale )
10226
x_offset = 0.0f ;
10227
float y_offset = 1.0f * g. CurrentDpiScale ;
10228
display_draw_list-> AddLine ( bb. GetTL ( ) + ImVec2 ( x_offset, y_offset ) , bb. GetTR ( ) + ImVec2 ( - x_offset, y_offset) , GetColorU32 ( tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline ) , style. TabBarOverlineSize ) ;
10229
}
10230
RenderNavCursor ( bb, id ) ;
10231
10232
10233
const bool hovered_unblocked = IsItemHovered ( ImGuiHoveredFlags_AllowWhenBlockedByPopup ) ;
10234
if ( tab_bar-> SelectedTabId != tab-> ID && hovered_unblocked && ( IsMouseClicked ( 1 ) || IsMouseReleased ( 1 ) ) && ! is_tab_button)
10235
TabBarQueueFocus ( tab_bar, tab ) ;
10236
10237
if ( tab_bar-> Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
10238
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
10239
10240
10241
const ImGuiID close_button_id = p_open ? GetIDWithSeed ( " #CLOSE" , NULL , docked_window ? docked_window-> ID : id) : 0 ;
10242
bool just_closed;
10243
bool text_clipped;
10244
TabItemLabelAndCloseButton ( display_draw_list, bb, tab_just_unsaved ? ( flags & ~ ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar-> FramePadding , label, id, close_button_id, tab_contents_visible, & just_closed, & text_clipped ) ;
10245
if ( just_closed && p_open != NULL )
10246
{
10247
* p_open = false ;
10248
TabBarCloseTab ( tab_bar, tab ) ;
10249
}
10250
10251
10252
10253
if ( docked_window && ( hovered || g. HoveredId == close_button_id) )
10254
g. LastItemData . StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
10255
10256
10257
if ( want_clip_rect)
10258
PopClipRect ( ) ;
10259
window-> DC . CursorPos = backup_main_cursor_pos;
10260
10261
10262
10263
10264
10265
10266
if ( text_clipped && g. HoveredId == id && ! held)
10267
if ( ! ( tab_bar-> Flags & ImGuiTabBarFlags_NoTooltip) && ! ( tab-> Flags & ImGuiTabItemFlags_NoTooltip) )
10268
SetItemTooltip ( " %.*s " , ( int ) ( FindRenderedTextEnd ( label ) - label) , label) ;
10269
10270
IM_ASSERT ( ! is_tab_button || ! ( tab_bar-> SelectedTabId == tab-> ID && is_tab_button) ) ;
10271
if ( is_tab_button)
10272
return pressed;
10273
return tab_contents_visible;
10274
}
10275
10276
10277
10278
10279
void ImGui:: SetTabItemClosed ( const char * label )
10280
{
10281
ImGuiContext& g = * GImGui;
10282
bool is_within_manual_tab_bar = g. CurrentTabBar && ! ( g. CurrentTabBar -> Flags & ImGuiTabBarFlags_DockNode) ;
10283
if ( is_within_manual_tab_bar)
10284
{
10285
ImGuiTabBar* tab_bar = g. CurrentTabBar ;
10286
ImGuiID tab_id = TabBarCalcTabID ( tab_bar, label, NULL ) ;
10287
if ( ImGuiTabItem* tab = TabBarFindTabByID ( tab_bar, tab_id ) )
10288
tab-> WantClose = true ;
10289
}
10290
else if ( ImGuiWindow* window = FindWindowByName ( label ) )
10291
{
10292
if ( window-> DockIsActive )
10293
if ( ImGuiDockNode* node = window-> DockNode )
10294
{
10295
ImGuiID tab_id = TabBarCalcTabID ( node-> TabBar , label, window ) ;
10296
TabBarRemoveTab ( node-> TabBar , tab_id ) ;
10297
window-> DockTabWantClose = true ;
10298
}
10299
}
10300
}
10301
10302
ImVec2 ImGui:: TabItemCalcSize ( const char * label , bool has_close_button_or_unsaved_marker )
10303
{
10304
ImGuiContext& g = * GImGui;
10305
ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
10306
ImVec2 size = ImVec2 ( label_size. x + g. Style . FramePadding . x , label_size. y + g. Style . FramePadding . y * 2.0f ) ;
10307
if ( has_close_button_or_unsaved_marker)
10308
size. x += g. Style . FramePadding . x + ( g. Style . ItemInnerSpacing . x + g. FontSize ) ;
10309
else
10310
size. x += g. Style . FramePadding . x + 1.0f ;
10311
return ImVec2 ( ImMin ( size. x , TabBarCalcMaxTabWidth ( ) ) , size. y ) ;
10312
}
10313
10314
ImVec2 ImGui:: TabItemCalcSize ( ImGuiWindow* window )
10315
{
10316
return TabItemCalcSize ( window-> Name , window-> HasCloseButton || ( window-> Flags & ImGuiWindowFlags_UnsavedDocument) ) ;
10317
}
10318
10319
void ImGui:: TabItemBackground ( ImDrawList* draw_list , const ImRect& bb , ImGuiTabItemFlags flags , ImU32 col )
10320
{
10321
10322
ImGuiContext& g = * GImGui;
10323
const float width = bb. GetWidth ( ) ;
10324
IM_UNUSED ( flags ) ;
10325
IM_ASSERT ( width > 0.0f ) ;
10326
const float rounding = ImMax ( 0.0f , ImMin ( ( flags & ImGuiTabItemFlags_Button) ? g. Style . FrameRounding : g. Style . TabRounding , width * 0.5f - 1.0f ) ) ;
10327
const float y1 = bb. Min . y + 1.0f ;
10328
const float y2 = bb. Max . y - g. Style . TabBarBorderSize ;
10329
draw_list-> PathLineTo ( ImVec2 ( bb. Min . x , y2 ) ) ;
10330
draw_list-> PathArcToFast ( ImVec2 ( bb. Min . x + rounding, y1 + rounding ) , rounding, 6 , 9 ) ;
10331
draw_list-> PathArcToFast ( ImVec2 ( bb. Max . x - rounding, y1 + rounding ) , rounding, 9 , 12 ) ;
10332
draw_list-> PathLineTo ( ImVec2 ( bb. Max . x , y2 ) ) ;
10333
draw_list-> PathFillConvex ( col ) ;
10334
if ( g. Style . TabBorderSize > 0.0f )
10335
{
10336
draw_list-> PathLineTo ( ImVec2 ( bb. Min . x + 0.5f , y2 ) ) ;
10337
draw_list-> PathArcToFast ( ImVec2 ( bb. Min . x + rounding + 0.5f , y1 + rounding + 0.5f ) , rounding, 6 , 9 ) ;
10338
draw_list-> PathArcToFast ( ImVec2 ( bb. Max . x - rounding - 0.5f , y1 + rounding + 0.5f ) , rounding, 9 , 12 ) ;
10339
draw_list-> PathLineTo ( ImVec2 ( bb. Max . x - 0.5f , y2 ) ) ;
10340
draw_list-> PathStroke ( GetColorU32 ( ImGuiCol_Border ) , 0 , g. Style . TabBorderSize ) ;
10341
}
10342
}
10343
10344
10345
10346
void ImGui:: TabItemLabelAndCloseButton ( ImDrawList* draw_list , const ImRect& bb , ImGuiTabItemFlags flags , ImVec2 frame_padding , const char * label , ImGuiID tab_id , ImGuiID close_button_id , bool is_contents_visible , bool * out_just_closed , bool * out_text_clipped )
10347
{
10348
ImGuiContext& g = * GImGui;
10349
ImVec2 label_size = CalcTextSize ( label, NULL , true ) ;
10350
10351
if ( out_just_closed)
10352
* out_just_closed = false ;
10353
if ( out_text_clipped)
10354
* out_text_clipped = false ;
10355
10356
if ( bb. GetWidth ( ) <= 1.0f )
10357
return ;
10358
10359
10360
10361
#if 0
10362
10363
10364
10365
#endif
10366
10367
10368
ImRect text_pixel_clip_bb ( bb. Min . x + frame_padding. x , bb. Min . y + frame_padding. y , bb. Max . x - frame_padding. x , bb. Max . y ) ;
10369
ImRect text_ellipsis_clip_bb = text_pixel_clip_bb;
10370
10371
10372
if ( out_text_clipped)
10373
{
10374
* out_text_clipped = ( text_ellipsis_clip_bb. Min . x + label_size. x ) > text_pixel_clip_bb. Max . x ;
10375
10376
}
10377
10378
const float button_sz = g. FontSize ;
10379
const ImVec2 button_pos ( ImMax ( bb. Min . x , bb. Max . x - frame_padding. x - button_sz ) , bb. Min . y + frame_padding. y ) ;
10380
10381
10382
10383
10384
10385
10386
bool close_button_pressed = false ;
10387
bool close_button_visible = false ;
10388
if ( close_button_id != 0 )
10389
if ( is_contents_visible || bb. GetWidth ( ) >= ImMax ( button_sz, g. Style . TabMinWidthForCloseButton ) )
10390
if ( g. HoveredId == tab_id || g. HoveredId == close_button_id || g. ActiveId == tab_id || g. ActiveId == close_button_id)
10391
close_button_visible = true ;
10392
bool unsaved_marker_visible = ( flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && ( button_pos. x + button_sz <= bb. Max . x ) ;
10393
10394
if ( close_button_visible)
10395
{
10396
ImGuiLastItemData last_item_backup = g. LastItemData ;
10397
if ( CloseButton ( close_button_id, button_pos ) )
10398
close_button_pressed = true ;
10399
g. LastItemData = last_item_backup;
10400
10401
10402
if ( ! ( flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked ( 2 ) )
10403
close_button_pressed = true ;
10404
}
10405
else if ( unsaved_marker_visible)
10406
{
10407
const ImRect bullet_bb ( button_pos, button_pos + ImVec2 ( button_sz, button_sz ) ) ;
10408
RenderBullet ( draw_list, bullet_bb. GetCenter ( ) , GetColorU32 ( ImGuiCol_Text ) ) ;
10409
}
10410
10411
10412
10413
10414
float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb. Max . x : bb. Max . x - 1.0f ;
10415
if ( close_button_visible || unsaved_marker_visible)
10416
{
10417
text_pixel_clip_bb. Max . x -= close_button_visible ? ( button_sz) : ( button_sz * 0.80f ) ;
10418
text_ellipsis_clip_bb. Max . x -= unsaved_marker_visible ? ( button_sz * 0.80f ) : 0.0f ;
10419
ellipsis_max_x = text_pixel_clip_bb. Max . x ;
10420
}
10421
LogSetNextTextDecoration ( " /" , " \\ " ) ;
10422
RenderTextEllipsis ( draw_list, text_ellipsis_clip_bb. Min , text_ellipsis_clip_bb. Max , text_pixel_clip_bb. Max . x , ellipsis_max_x, label, NULL , & label_size ) ;
10423
10424
#if 0
10425
10426
10427
#endif
10428
10429
if ( out_just_closed)
10430
* out_just_closed = close_button_pressed;
10431
}
10432
10433
10434
#endif