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