Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/scene/test_tab_container.h
10277 views
1
/**************************************************************************/
2
/* test_tab_container.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "scene/gui/tab_container.h"
34
35
#include "tests/test_macros.h"
36
37
namespace TestTabContainer {
38
TEST_CASE("[SceneTree][TabContainer] tab operations") {
39
TabContainer *tab_container = memnew(TabContainer);
40
SceneTree::get_singleton()->get_root()->add_child(tab_container);
41
MessageQueue::get_singleton()->flush();
42
SIGNAL_WATCH(tab_container, "tab_selected");
43
SIGNAL_WATCH(tab_container, "tab_changed");
44
45
Control *tab0 = memnew(Control);
46
tab0->set_name("tab0");
47
Control *tab1 = memnew(Control);
48
tab1->set_name("tab1");
49
Control *tab2 = memnew(Control);
50
tab2->set_name("tab2");
51
52
SUBCASE("[TabContainer] add tabs by adding children") {
53
CHECK(tab_container->get_tab_count() == 0);
54
CHECK(tab_container->get_current_tab() == -1);
55
CHECK(tab_container->get_previous_tab() == -1);
56
57
// Add first tab child.
58
tab_container->add_child(tab0);
59
// MessageQueue::get_singleton()->flush();
60
CHECK(tab_container->get_tab_count() == 1);
61
CHECK(tab_container->get_current_tab() == 0);
62
CHECK(tab_container->get_previous_tab() == -1);
63
SIGNAL_CHECK("tab_selected", { { 0 } });
64
SIGNAL_CHECK("tab_changed", { { 0 } });
65
66
// Add second tab child.
67
tab_container->add_child(tab1);
68
CHECK(tab_container->get_tab_count() == 2);
69
CHECK(tab_container->get_current_tab() == 0);
70
CHECK(tab_container->get_previous_tab() == -1);
71
SIGNAL_CHECK_FALSE("tab_selected");
72
SIGNAL_CHECK_FALSE("tab_changed");
73
74
// Check default values, the title is the name of the child.
75
CHECK(tab_container->get_tab_control(0) == tab0);
76
CHECK(tab_container->get_tab_idx_from_control(tab0) == 0);
77
CHECK(tab_container->get_tab_title(0) == "tab0");
78
CHECK(tab_container->get_tab_tooltip(0) == "");
79
CHECK_FALSE(tab_container->is_tab_disabled(0));
80
CHECK_FALSE(tab_container->is_tab_hidden(0));
81
82
CHECK(tab_container->get_tab_control(1) == tab1);
83
CHECK(tab_container->get_tab_idx_from_control(tab1) == 1);
84
CHECK(tab_container->get_tab_title(1) == "tab1");
85
CHECK(tab_container->get_tab_tooltip(1) == "");
86
CHECK_FALSE(tab_container->is_tab_disabled(1));
87
CHECK_FALSE(tab_container->is_tab_hidden(1));
88
}
89
90
SUBCASE("[TabContainer] remove tabs by removing children") {
91
tab_container->add_child(tab0);
92
tab_container->add_child(tab1);
93
tab_container->add_child(tab2);
94
tab_container->set_current_tab(1);
95
CHECK(tab_container->get_tab_count() == 3);
96
CHECK(tab_container->get_current_tab() == 1);
97
CHECK(tab_container->get_previous_tab() == 0);
98
SIGNAL_DISCARD("tab_selected");
99
SIGNAL_DISCARD("tab_changed");
100
101
// Remove first tab.
102
tab_container->remove_child(tab0);
103
CHECK(tab_container->get_tab_count() == 2);
104
CHECK(tab_container->get_tab_title(0) == "tab1");
105
CHECK(tab_container->get_tab_title(1) == "tab2");
106
CHECK(tab_container->get_tab_idx_from_control(tab1) == 0);
107
CHECK(tab_container->get_tab_idx_from_control(tab2) == 1);
108
CHECK(tab_container->get_current_tab() == 0);
109
CHECK(tab_container->get_previous_tab() == 0);
110
SIGNAL_CHECK_FALSE("tab_selected");
111
SIGNAL_CHECK_FALSE("tab_changed");
112
113
// Remove last tab.
114
tab_container->remove_child(tab2);
115
CHECK(tab_container->get_tab_count() == 1);
116
CHECK(tab_container->get_tab_title(0) == "tab1");
117
CHECK(tab_container->get_tab_idx_from_control(tab1) == 0);
118
CHECK(tab_container->get_current_tab() == 0);
119
CHECK(tab_container->get_previous_tab() == 0);
120
SIGNAL_CHECK_FALSE("tab_selected");
121
SIGNAL_CHECK_FALSE("tab_changed");
122
123
// Remove only tab.
124
tab_container->remove_child(tab1);
125
CHECK(tab_container->get_tab_count() == 0);
126
CHECK(tab_container->get_current_tab() == -1);
127
CHECK(tab_container->get_previous_tab() == -1);
128
SIGNAL_CHECK_FALSE("tab_selected");
129
SIGNAL_CHECK("tab_changed", { { -1 } });
130
131
// Remove current tab when there are other tabs.
132
tab_container->add_child(tab0);
133
tab_container->add_child(tab1);
134
tab_container->add_child(tab2);
135
tab_container->set_current_tab(1);
136
tab_container->set_current_tab(2);
137
CHECK(tab_container->get_tab_count() == 3);
138
CHECK(tab_container->get_current_tab() == 2);
139
CHECK(tab_container->get_previous_tab() == 1);
140
SIGNAL_DISCARD("tab_selected");
141
SIGNAL_DISCARD("tab_changed");
142
143
tab_container->remove_child(tab2);
144
CHECK(tab_container->get_tab_count() == 2);
145
CHECK(tab_container->get_current_tab() == 1);
146
CHECK(tab_container->get_previous_tab() == 1);
147
SIGNAL_CHECK_FALSE("tab_selected");
148
SIGNAL_CHECK("tab_changed", { { 1 } });
149
}
150
151
SUBCASE("[TabContainer] move tabs by moving children") {
152
tab_container->add_child(tab0);
153
tab_container->add_child(tab1);
154
tab_container->add_child(tab2);
155
tab_container->set_current_tab(1);
156
CHECK(tab_container->get_current_tab() == 1);
157
CHECK(tab_container->get_previous_tab() == 0);
158
SIGNAL_DISCARD("tab_selected");
159
SIGNAL_DISCARD("tab_changed");
160
161
// Move the first tab to the end.
162
tab_container->move_child(tab0, 2);
163
CHECK(tab_container->get_tab_idx_from_control(tab0) == 2);
164
CHECK(tab_container->get_tab_idx_from_control(tab1) == 0);
165
CHECK(tab_container->get_tab_idx_from_control(tab2) == 1);
166
CHECK(tab_container->get_current_tab() == 0);
167
CHECK(tab_container->get_previous_tab() == 2);
168
SIGNAL_CHECK_FALSE("tab_selected");
169
SIGNAL_CHECK_FALSE("tab_changed");
170
171
// Move the second tab to the front.
172
tab_container->move_child(tab2, 0);
173
CHECK(tab_container->get_tab_idx_from_control(tab0) == 2);
174
CHECK(tab_container->get_tab_idx_from_control(tab1) == 1);
175
CHECK(tab_container->get_tab_idx_from_control(tab2) == 0);
176
CHECK(tab_container->get_current_tab() == 1);
177
CHECK(tab_container->get_previous_tab() == 2);
178
SIGNAL_CHECK_FALSE("tab_selected");
179
SIGNAL_CHECK_FALSE("tab_changed");
180
}
181
182
SUBCASE("[TabContainer] set current tab") {
183
tab_container->add_child(tab0);
184
tab_container->add_child(tab1);
185
tab_container->add_child(tab2);
186
CHECK(tab_container->get_current_tab() == 0);
187
CHECK(tab_container->get_previous_tab() == -1);
188
SIGNAL_CHECK("tab_selected", { { 0 } });
189
SIGNAL_CHECK("tab_changed", { { 0 } });
190
MessageQueue::get_singleton()->flush();
191
CHECK(tab0->is_visible());
192
CHECK_FALSE(tab1->is_visible());
193
CHECK_FALSE(tab2->is_visible());
194
195
// Set the current tab.
196
tab_container->set_current_tab(1);
197
CHECK(tab_container->get_current_tab() == 1);
198
CHECK(tab_container->get_previous_tab() == 0);
199
SIGNAL_CHECK("tab_selected", { { 1 } });
200
SIGNAL_CHECK("tab_changed", { { 1 } });
201
MessageQueue::get_singleton()->flush();
202
CHECK_FALSE(tab0->is_visible());
203
CHECK(tab1->is_visible());
204
CHECK_FALSE(tab2->is_visible());
205
206
// Set to same tab.
207
tab_container->set_current_tab(1);
208
CHECK(tab_container->get_current_tab() == 1);
209
CHECK(tab_container->get_previous_tab() == 1);
210
SIGNAL_CHECK("tab_selected", { { 1 } });
211
SIGNAL_CHECK_FALSE("tab_changed");
212
MessageQueue::get_singleton()->flush();
213
CHECK_FALSE(tab0->is_visible());
214
CHECK(tab1->is_visible());
215
CHECK_FALSE(tab2->is_visible());
216
217
// Out of bounds.
218
ERR_PRINT_OFF;
219
tab_container->set_current_tab(-5);
220
CHECK(tab_container->get_current_tab() == 1);
221
CHECK(tab_container->get_previous_tab() == 1);
222
SIGNAL_CHECK_FALSE("tab_selected");
223
SIGNAL_CHECK_FALSE("tab_changed");
224
MessageQueue::get_singleton()->flush();
225
CHECK_FALSE(tab0->is_visible());
226
CHECK(tab1->is_visible());
227
CHECK_FALSE(tab2->is_visible());
228
229
tab_container->set_current_tab(5);
230
CHECK(tab_container->get_current_tab() == 1);
231
CHECK(tab_container->get_previous_tab() == 1);
232
SIGNAL_CHECK_FALSE("tab_selected");
233
SIGNAL_CHECK_FALSE("tab_changed");
234
MessageQueue::get_singleton()->flush();
235
CHECK_FALSE(tab0->is_visible());
236
CHECK(tab1->is_visible());
237
CHECK_FALSE(tab2->is_visible());
238
ERR_PRINT_ON;
239
}
240
241
SUBCASE("[TabContainer] change current tab by changing visibility of children") {
242
tab_container->add_child(tab0);
243
tab_container->add_child(tab1);
244
tab_container->add_child(tab2);
245
SIGNAL_DISCARD("tab_selected");
246
SIGNAL_DISCARD("tab_changed");
247
MessageQueue::get_singleton()->flush();
248
CHECK(tab0->is_visible());
249
CHECK_FALSE(tab1->is_visible());
250
CHECK_FALSE(tab2->is_visible());
251
252
// Show a child to make it the current tab.
253
tab1->show();
254
CHECK(tab_container->get_current_tab() == 1);
255
CHECK(tab_container->get_previous_tab() == 0);
256
SIGNAL_CHECK("tab_selected", { { 1 } });
257
SIGNAL_CHECK("tab_changed", { { 1 } });
258
MessageQueue::get_singleton()->flush();
259
CHECK_FALSE(tab0->is_visible());
260
CHECK(tab1->is_visible());
261
CHECK_FALSE(tab2->is_visible());
262
263
// Hide the visible child to select the next tab.
264
tab1->hide();
265
CHECK(tab_container->get_current_tab() == 2);
266
CHECK(tab_container->get_previous_tab() == 1);
267
SIGNAL_CHECK("tab_selected", { { 2 } });
268
SIGNAL_CHECK("tab_changed", { { 2 } });
269
MessageQueue::get_singleton()->flush();
270
CHECK_FALSE(tab0->is_visible());
271
CHECK_FALSE(tab1->is_visible());
272
CHECK(tab2->is_visible());
273
274
// Hide the visible child to select the previous tab if there is no next.
275
tab2->hide();
276
CHECK(tab_container->get_current_tab() == 1);
277
CHECK(tab_container->get_previous_tab() == 2);
278
SIGNAL_CHECK("tab_selected", { { 1 } });
279
SIGNAL_CHECK("tab_changed", { { 1 } });
280
MessageQueue::get_singleton()->flush();
281
CHECK_FALSE(tab0->is_visible());
282
CHECK(tab1->is_visible());
283
CHECK_FALSE(tab2->is_visible());
284
285
// Cannot hide if there is only one valid child since deselection is not enabled.
286
tab_container->remove_child(tab1);
287
tab_container->remove_child(tab2);
288
CHECK(tab_container->get_current_tab() == 0);
289
CHECK(tab_container->get_previous_tab() == 0);
290
SIGNAL_DISCARD("tab_selected");
291
SIGNAL_DISCARD("tab_changed");
292
MessageQueue::get_singleton()->flush();
293
CHECK(tab0->is_visible());
294
295
tab0->hide();
296
CHECK(tab_container->get_current_tab() == 0);
297
CHECK(tab_container->get_previous_tab() == 0);
298
SIGNAL_CHECK_FALSE("tab_selected");
299
SIGNAL_CHECK_FALSE("tab_changed");
300
MessageQueue::get_singleton()->flush();
301
CHECK(tab0->is_visible());
302
303
// Can hide the last tab if deselection is enabled.
304
tab_container->set_deselect_enabled(true);
305
tab0->hide();
306
CHECK(tab_container->get_current_tab() == -1);
307
CHECK(tab_container->get_previous_tab() == 0);
308
SIGNAL_CHECK("tab_selected", { { -1 } });
309
SIGNAL_CHECK("tab_changed", { { -1 } });
310
MessageQueue::get_singleton()->flush();
311
CHECK_FALSE(tab0->is_visible());
312
}
313
314
SIGNAL_UNWATCH(tab_container, "tab_selected");
315
SIGNAL_UNWATCH(tab_container, "tab_changed");
316
317
memdelete(tab2);
318
memdelete(tab1);
319
memdelete(tab0);
320
memdelete(tab_container);
321
}
322
323
TEST_CASE("[SceneTree][TabContainer] initialization") {
324
TabContainer *tab_container = memnew(TabContainer);
325
326
Control *tab0 = memnew(Control);
327
tab0->set_name("tab0");
328
Control *tab1 = memnew(Control);
329
tab1->set_name("tab1 ");
330
Control *tab2 = memnew(Control);
331
tab2->set_name("tab2 ");
332
333
SIGNAL_WATCH(tab_container, "tab_selected");
334
SIGNAL_WATCH(tab_container, "tab_changed");
335
336
SUBCASE("[TabContainer] add children before entering tree") {
337
CHECK(tab_container->get_current_tab() == -1);
338
CHECK(tab_container->get_previous_tab() == -1);
339
340
tab_container->add_child(tab0);
341
CHECK(tab_container->get_tab_count() == 1);
342
CHECK(tab_container->get_current_tab() == 0);
343
CHECK(tab_container->get_previous_tab() == -1);
344
345
tab_container->add_child(tab1);
346
CHECK(tab_container->get_tab_count() == 2);
347
CHECK(tab_container->get_current_tab() == 0);
348
CHECK(tab_container->get_previous_tab() == -1);
349
350
SceneTree::get_singleton()->get_root()->add_child(tab_container);
351
MessageQueue::get_singleton()->flush();
352
CHECK(tab_container->get_tab_count() == 2);
353
CHECK(tab_container->get_current_tab() == 0);
354
CHECK(tab_container->get_previous_tab() == -1);
355
SIGNAL_CHECK_FALSE("tab_selected");
356
SIGNAL_CHECK_FALSE("tab_changed");
357
CHECK(tab0->is_visible());
358
CHECK_FALSE(tab1->is_visible());
359
}
360
361
SUBCASE("[TabContainer] current tab can be set before children are added") {
362
// Set the current tab before there are any tabs.
363
// This queues the current tab to update on entering the tree.
364
tab_container->set_current_tab(1);
365
CHECK(tab_container->get_current_tab() == -1);
366
CHECK(tab_container->get_previous_tab() == -1);
367
SIGNAL_CHECK_FALSE("tab_selected");
368
SIGNAL_CHECK_FALSE("tab_changed");
369
370
tab_container->add_child(tab0);
371
CHECK(tab_container->get_tab_count() == 1);
372
CHECK(tab_container->get_current_tab() == 0);
373
CHECK(tab_container->get_previous_tab() == -1);
374
375
tab_container->add_child(tab1);
376
CHECK(tab_container->get_tab_count() == 2);
377
CHECK(tab_container->get_current_tab() == 0);
378
CHECK(tab_container->get_previous_tab() == -1);
379
380
tab_container->add_child(tab2);
381
CHECK(tab_container->get_tab_count() == 3);
382
CHECK(tab_container->get_current_tab() == 0);
383
CHECK(tab_container->get_previous_tab() == -1);
384
SIGNAL_CHECK_FALSE("tab_selected");
385
SIGNAL_CHECK_FALSE("tab_changed");
386
387
// Current tab is set when entering the tree.
388
SceneTree::get_singleton()->get_root()->add_child(tab_container);
389
MessageQueue::get_singleton()->flush();
390
CHECK(tab_container->get_tab_count() == 3);
391
CHECK(tab_container->get_current_tab() == 1);
392
CHECK(tab_container->get_previous_tab() == 0);
393
SIGNAL_CHECK("tab_selected", { { 1 } });
394
SIGNAL_CHECK("tab_changed", { { 1 } });
395
CHECK_FALSE(tab0->is_visible());
396
CHECK(tab1->is_visible());
397
CHECK_FALSE(tab2->is_visible());
398
}
399
400
SUBCASE("[TabContainer] cannot set current tab to an invalid value before tabs are set") {
401
tab_container->set_current_tab(100);
402
CHECK(tab_container->get_current_tab() == -1);
403
CHECK(tab_container->get_previous_tab() == -1);
404
SIGNAL_CHECK_FALSE("tab_selected");
405
SIGNAL_CHECK_FALSE("tab_changed");
406
407
tab_container->add_child(tab0);
408
CHECK(tab_container->get_tab_count() == 1);
409
CHECK(tab_container->get_current_tab() == 0);
410
CHECK(tab_container->get_previous_tab() == -1);
411
SIGNAL_CHECK_FALSE("tab_selected");
412
SIGNAL_CHECK_FALSE("tab_changed");
413
414
tab_container->add_child(tab1);
415
CHECK(tab_container->get_tab_count() == 2);
416
CHECK(tab_container->get_current_tab() == 0);
417
CHECK(tab_container->get_previous_tab() == -1);
418
SIGNAL_CHECK_FALSE("tab_selected");
419
SIGNAL_CHECK_FALSE("tab_changed");
420
421
// This will print an error message as if `set_current_tab` was called after.
422
ERR_PRINT_OFF;
423
SceneTree::get_singleton()->get_root()->add_child(tab_container);
424
MessageQueue::get_singleton()->flush();
425
CHECK(tab_container->get_tab_count() == 2);
426
CHECK(tab_container->get_current_tab() == 0);
427
CHECK(tab_container->get_previous_tab() == -1);
428
SIGNAL_CHECK_FALSE("tab_selected");
429
SIGNAL_CHECK_FALSE("tab_changed");
430
ERR_PRINT_ON;
431
}
432
433
SUBCASE("[TabContainer] children visibility before entering tree") {
434
CHECK(tab_container->get_current_tab() == -1);
435
CHECK(tab_container->get_previous_tab() == -1);
436
437
// Adding a hidden child first will change visibility because it is the current tab.
438
tab0->hide();
439
tab_container->add_child(tab0);
440
CHECK(tab_container->get_tab_count() == 1);
441
CHECK(tab_container->get_current_tab() == 0);
442
CHECK(tab_container->get_previous_tab() == -1);
443
MessageQueue::get_singleton()->flush();
444
CHECK(tab0->is_visible());
445
446
// Adding a visible child after will hide it because it is not the current tab.
447
tab_container->add_child(tab1);
448
CHECK(tab_container->get_tab_count() == 2);
449
CHECK(tab_container->get_current_tab() == 0);
450
CHECK(tab_container->get_previous_tab() == -1);
451
MessageQueue::get_singleton()->flush();
452
CHECK(tab0->is_visible());
453
CHECK_FALSE(tab1->is_visible());
454
455
// Can change current by showing child now after children have been added.
456
// This queues the current tab to update on entering the tree.
457
tab1->show();
458
MessageQueue::get_singleton()->flush();
459
CHECK(tab_container->get_tab_count() == 2);
460
CHECK(tab_container->get_current_tab() == 0);
461
CHECK(tab_container->get_previous_tab() == -1);
462
SIGNAL_CHECK_FALSE("tab_selected");
463
SIGNAL_CHECK_FALSE("tab_changed");
464
CHECK(tab0->is_visible());
465
CHECK(tab1->is_visible());
466
467
SceneTree::get_singleton()->get_root()->add_child(tab_container);
468
MessageQueue::get_singleton()->flush();
469
CHECK(tab_container->get_tab_count() == 2);
470
CHECK(tab_container->get_current_tab() == 1);
471
CHECK(tab_container->get_previous_tab() == 0);
472
SIGNAL_CHECK("tab_selected", { { 1 } });
473
SIGNAL_CHECK("tab_changed", { { 1 } });
474
CHECK_FALSE(tab0->is_visible());
475
CHECK(tab1->is_visible());
476
}
477
478
SUBCASE("[TabContainer] setting current tab and changing child visibility after adding") {
479
tab_container->add_child(tab0);
480
tab_container->add_child(tab1);
481
tab_container->add_child(tab2);
482
MessageQueue::get_singleton()->flush();
483
CHECK(tab_container->get_current_tab() == 0);
484
CHECK(tab_container->get_previous_tab() == -1);
485
486
tab2->show();
487
MessageQueue::get_singleton()->flush();
488
CHECK(tab_container->get_tab_count() == 3);
489
CHECK(tab_container->get_current_tab() == 0);
490
CHECK(tab_container->get_previous_tab() == -1);
491
SIGNAL_CHECK_FALSE("tab_selected");
492
SIGNAL_CHECK_FALSE("tab_changed");
493
CHECK(tab0->is_visible());
494
CHECK_FALSE(tab1->is_visible());
495
CHECK(tab2->is_visible());
496
497
// Whichever happens last will have priority.
498
tab_container->set_current_tab(1);
499
CHECK(tab_container->get_current_tab() == 0);
500
CHECK(tab_container->get_previous_tab() == -1);
501
502
// Current tab is set when entering the tree.
503
SceneTree::get_singleton()->get_root()->add_child(tab_container);
504
MessageQueue::get_singleton()->flush();
505
CHECK(tab_container->get_tab_count() == 3);
506
CHECK(tab_container->get_current_tab() == 1);
507
CHECK(tab_container->get_previous_tab() == 0);
508
SIGNAL_CHECK("tab_selected", { { 1 } });
509
SIGNAL_CHECK("tab_changed", { { 1 } });
510
CHECK_FALSE(tab0->is_visible());
511
CHECK(tab1->is_visible());
512
CHECK_FALSE(tab2->is_visible());
513
}
514
515
SIGNAL_UNWATCH(tab_container, "tab_selected");
516
SIGNAL_UNWATCH(tab_container, "tab_changed");
517
518
memdelete(tab2);
519
memdelete(tab1);
520
memdelete(tab0);
521
memdelete(tab_container);
522
}
523
524
TEST_CASE("[SceneTree][TabContainer] layout and offset") {
525
TabContainer *tab_container = memnew(TabContainer);
526
SceneTree::get_singleton()->get_root()->add_child(tab_container);
527
tab_container->set_clip_tabs(false);
528
529
Control *tab0 = memnew(Control);
530
tab0->set_name("tab0");
531
Control *tab1 = memnew(Control);
532
tab1->set_name("tab1 ");
533
Control *tab2 = memnew(Control);
534
tab2->set_name("tab2 ");
535
536
tab_container->add_child(tab0);
537
tab_container->add_child(tab1);
538
tab_container->add_child(tab2);
539
540
MessageQueue::get_singleton()->flush();
541
542
Size2 all_tabs_size = tab_container->get_size();
543
const float side_margin = tab_container->get_theme_constant("side_margin");
544
545
TabBar *tab_bar = tab_container->get_tab_bar();
546
547
Vector<Rect2> tab_rects = {
548
tab_bar->get_tab_rect(0),
549
tab_bar->get_tab_rect(1),
550
tab_bar->get_tab_rect(2)
551
};
552
553
SUBCASE("[TabContainer] tabs are arranged next to each other") {
554
// Horizontal positions are next to each other.
555
CHECK(tab_rects[0].position.x == 0);
556
CHECK(tab_rects[1].position.x == tab_rects[0].size.x);
557
CHECK(tab_rects[2].position.x == tab_rects[1].position.x + tab_rects[1].size.x);
558
559
// Fills the entire width.
560
CHECK(tab_rects[2].position.x + tab_rects[2].size.x == all_tabs_size.x - side_margin);
561
562
// Horizontal sizes are positive.
563
CHECK(tab_rects[0].size.x > 0);
564
CHECK(tab_rects[1].size.x > 0);
565
CHECK(tab_rects[2].size.x > 0);
566
567
// Vertical positions are at 0.
568
CHECK(tab_rects[0].position.y == 0);
569
CHECK(tab_rects[1].position.y == 0);
570
CHECK(tab_rects[2].position.y == 0);
571
572
// Vertical sizes are the same.
573
CHECK(tab_rects[0].size.y == tab_rects[1].size.y);
574
CHECK(tab_rects[1].size.y == tab_rects[2].size.y);
575
}
576
577
SUBCASE("[TabContainer] tab position") {
578
float tab_height = tab_rects[0].size.y;
579
Ref<StyleBox> panel_style = tab_container->get_theme_stylebox("panel_style");
580
581
// Initial position, same as top position.
582
// Tab bar is at the top.
583
CHECK(tab_bar->get_anchor(SIDE_TOP) == 0);
584
CHECK(tab_bar->get_anchor(SIDE_BOTTOM) == 0);
585
CHECK(tab_bar->get_anchor(SIDE_LEFT) == 0);
586
CHECK(tab_bar->get_anchor(SIDE_RIGHT) == 1);
587
CHECK(tab_bar->get_offset(SIDE_TOP) == 0);
588
CHECK(tab_bar->get_offset(SIDE_BOTTOM) == tab_height);
589
CHECK(tab_bar->get_offset(SIDE_LEFT) == side_margin);
590
CHECK(tab_bar->get_offset(SIDE_RIGHT) == 0);
591
592
// Child is expanded and below the tab bar.
593
CHECK(tab0->get_anchor(SIDE_TOP) == 0);
594
CHECK(tab0->get_anchor(SIDE_BOTTOM) == 1);
595
CHECK(tab0->get_anchor(SIDE_LEFT) == 0);
596
CHECK(tab0->get_anchor(SIDE_RIGHT) == 1);
597
CHECK(tab0->get_offset(SIDE_TOP) == tab_height);
598
CHECK(tab0->get_offset(SIDE_BOTTOM) == 0);
599
CHECK(tab0->get_offset(SIDE_LEFT) == 0);
600
CHECK(tab0->get_offset(SIDE_RIGHT) == 0);
601
602
// Bottom position.
603
tab_container->set_tabs_position(TabContainer::POSITION_BOTTOM);
604
CHECK(tab_container->get_tabs_position() == TabContainer::POSITION_BOTTOM);
605
MessageQueue::get_singleton()->flush();
606
607
// Tab bar is at the bottom.
608
CHECK(tab_bar->get_anchor(SIDE_TOP) == 1);
609
CHECK(tab_bar->get_anchor(SIDE_BOTTOM) == 1);
610
CHECK(tab_bar->get_anchor(SIDE_LEFT) == 0);
611
CHECK(tab_bar->get_anchor(SIDE_RIGHT) == 1);
612
CHECK(tab_bar->get_offset(SIDE_TOP) == -tab_height);
613
CHECK(tab_bar->get_offset(SIDE_BOTTOM) == 0);
614
CHECK(tab_bar->get_offset(SIDE_LEFT) == side_margin);
615
CHECK(tab_bar->get_offset(SIDE_RIGHT) == 0);
616
617
// Child is expanded and above the tab bar.
618
CHECK(tab0->get_anchor(SIDE_TOP) == 0);
619
CHECK(tab0->get_anchor(SIDE_BOTTOM) == 1);
620
CHECK(tab0->get_anchor(SIDE_LEFT) == 0);
621
CHECK(tab0->get_anchor(SIDE_RIGHT) == 1);
622
CHECK(tab0->get_offset(SIDE_TOP) == 0);
623
CHECK(tab0->get_offset(SIDE_BOTTOM) == -tab_height);
624
CHECK(tab0->get_offset(SIDE_LEFT) == 0);
625
CHECK(tab0->get_offset(SIDE_RIGHT) == 0);
626
627
// Top position.
628
tab_container->set_tabs_position(TabContainer::POSITION_TOP);
629
CHECK(tab_container->get_tabs_position() == TabContainer::POSITION_TOP);
630
MessageQueue::get_singleton()->flush();
631
632
// Tab bar is at the top.
633
CHECK(tab_bar->get_anchor(SIDE_TOP) == 0);
634
CHECK(tab_bar->get_anchor(SIDE_BOTTOM) == 0);
635
CHECK(tab_bar->get_anchor(SIDE_LEFT) == 0);
636
CHECK(tab_bar->get_anchor(SIDE_RIGHT) == 1);
637
CHECK(tab_bar->get_offset(SIDE_TOP) == 0);
638
CHECK(tab_bar->get_offset(SIDE_BOTTOM) == tab_height);
639
CHECK(tab_bar->get_offset(SIDE_LEFT) == side_margin);
640
CHECK(tab_bar->get_offset(SIDE_RIGHT) == 0);
641
642
// Child is expanded and below the tab bar.
643
CHECK(tab0->get_anchor(SIDE_TOP) == 0);
644
CHECK(tab0->get_anchor(SIDE_BOTTOM) == 1);
645
CHECK(tab0->get_anchor(SIDE_LEFT) == 0);
646
CHECK(tab0->get_anchor(SIDE_RIGHT) == 1);
647
CHECK(tab0->get_offset(SIDE_TOP) == tab_height);
648
CHECK(tab0->get_offset(SIDE_BOTTOM) == 0);
649
CHECK(tab0->get_offset(SIDE_LEFT) == 0);
650
CHECK(tab0->get_offset(SIDE_RIGHT) == 0);
651
}
652
653
memdelete(tab_container);
654
}
655
656
TEST_CASE("[SceneTree][TabContainer] Mouse interaction") {
657
TabContainer *tab_container = memnew(TabContainer);
658
SceneTree::get_singleton()->get_root()->add_child(tab_container);
659
660
tab_container->set_clip_tabs(false);
661
Control *tab0 = memnew(Control);
662
tab0->set_name("tab0");
663
Control *tab1 = memnew(Control);
664
tab1->set_name("tab1 ");
665
Control *tab2 = memnew(Control);
666
tab2->set_name("tab2 ");
667
668
tab_container->add_child(tab0);
669
tab_container->add_child(tab1);
670
tab_container->add_child(tab2);
671
672
MessageQueue::get_singleton()->flush();
673
674
const float side_margin = tab_container->get_theme_constant("side_margin");
675
676
TabBar *tab_bar = tab_container->get_tab_bar();
677
Vector<Rect2> tab_rects = {
678
tab_bar->get_tab_rect(0),
679
tab_bar->get_tab_rect(1),
680
tab_bar->get_tab_rect(2)
681
};
682
683
SIGNAL_WATCH(tab_container, "active_tab_rearranged");
684
SIGNAL_WATCH(tab_container, "tab_changed");
685
SIGNAL_WATCH(tab_container, "tab_clicked");
686
SIGNAL_WATCH(tab_container, "tab_selected");
687
688
SUBCASE("[TabContainer] Click to change current") {
689
CHECK(tab_container->get_current_tab() == 0);
690
CHECK(tab_container->get_previous_tab() == -1);
691
SIGNAL_DISCARD("tab_selected");
692
SIGNAL_DISCARD("tab_changed");
693
694
// Click to set the current tab.
695
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
696
CHECK(tab_container->get_current_tab() == 1);
697
CHECK(tab_container->get_previous_tab() == 0);
698
SIGNAL_CHECK("tab_selected", { { 1 } });
699
SIGNAL_CHECK("tab_changed", { { 1 } });
700
SIGNAL_CHECK("tab_clicked", { { 1 } });
701
702
// Click on the same tab.
703
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
704
CHECK(tab_container->get_current_tab() == 1);
705
CHECK(tab_container->get_previous_tab() == 1);
706
SIGNAL_CHECK("tab_selected", { { 1 } });
707
SIGNAL_CHECK_FALSE("tab_changed");
708
SIGNAL_CHECK("tab_clicked", { { 1 } });
709
710
// Click outside of tabs.
711
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(0, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
712
CHECK(tab_container->get_current_tab() == 1);
713
CHECK(tab_container->get_previous_tab() == 1);
714
SIGNAL_CHECK_FALSE("tab_selected");
715
SIGNAL_CHECK_FALSE("tab_changed");
716
SIGNAL_CHECK_FALSE("tab_clicked");
717
}
718
719
SUBCASE("[TabContainer] Drag and drop internally") {
720
// Cannot drag if not enabled.
721
CHECK_FALSE(tab_container->get_drag_to_rearrange_enabled());
722
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
723
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButtonMask::LEFT, Key::NONE);
724
SIGNAL_CHECK("tab_selected", { { 0 } });
725
SIGNAL_CHECK_FALSE("tab_changed");
726
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
727
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
728
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
729
CHECK(tab_container->get_tab_idx_from_control(tab0) == 0);
730
CHECK(tab_container->get_tab_idx_from_control(tab1) == 1);
731
CHECK(tab_container->get_tab_idx_from_control(tab2) == 2);
732
SIGNAL_CHECK_FALSE("active_tab_rearranged");
733
SIGNAL_CHECK_FALSE("tab_selected");
734
SIGNAL_CHECK_FALSE("tab_changed");
735
736
tab_container->set_drag_to_rearrange_enabled(true);
737
CHECK(tab_container->get_drag_to_rearrange_enabled());
738
739
// Release over the same tab to not move.
740
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
741
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButtonMask::LEFT, Key::NONE);
742
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButtonMask::LEFT, Key::NONE);
743
SIGNAL_CHECK("tab_selected", { { 0 } });
744
SIGNAL_CHECK_FALSE("tab_changed");
745
CHECK(tab_container->get_viewport()->gui_is_dragging());
746
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
747
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
748
CHECK(tab_container->get_tab_idx_from_control(tab0) == 0);
749
CHECK(tab_container->get_tab_idx_from_control(tab1) == 1);
750
CHECK(tab_container->get_tab_idx_from_control(tab2) == 2);
751
SIGNAL_CHECK_FALSE("active_tab_rearranged");
752
SIGNAL_CHECK_FALSE("tab_selected");
753
SIGNAL_CHECK_FALSE("tab_changed");
754
755
// Move the first tab after the second.
756
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
757
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[1].position, MouseButtonMask::LEFT, Key::NONE);
758
SIGNAL_CHECK("tab_selected", { { 0 } });
759
SIGNAL_CHECK_FALSE("tab_changed");
760
CHECK(tab_container->get_viewport()->gui_is_dragging());
761
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2(side_margin, 0) + tab_rects[1].position + Point2(tab_rects[1].size.x / 2 + 1, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
762
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
763
CHECK(tab_container->get_tab_idx_from_control(tab1) == 0);
764
CHECK(tab_container->get_tab_idx_from_control(tab0) == 1);
765
CHECK(tab_container->get_tab_idx_from_control(tab2) == 2);
766
SIGNAL_CHECK("active_tab_rearranged", { { 1 } });
767
SIGNAL_CHECK("tab_selected", { { 1 } });
768
SIGNAL_CHECK_FALSE("tab_changed");
769
770
tab_rects = { tab_bar->get_tab_rect(0), tab_bar->get_tab_rect(1), tab_bar->get_tab_rect(2) };
771
772
// Move the last tab to be the first.
773
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[2].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
774
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButtonMask::LEFT, Key::NONE);
775
SIGNAL_CHECK("tab_selected", { { 2 } });
776
SIGNAL_CHECK("tab_changed", { { 2 } });
777
CHECK(tab_container->get_viewport()->gui_is_dragging());
778
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
779
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
780
CHECK(tab_container->get_tab_idx_from_control(tab2) == 0);
781
CHECK(tab_container->get_tab_idx_from_control(tab1) == 1);
782
CHECK(tab_container->get_tab_idx_from_control(tab0) == 2);
783
SIGNAL_CHECK("active_tab_rearranged", { { 0 } });
784
SIGNAL_CHECK("tab_selected", { { 0 } });
785
SIGNAL_CHECK_FALSE("tab_changed");
786
}
787
788
SUBCASE("[TabContainer] Drag and drop to different TabContainer") {
789
TabContainer *target_tab_container = memnew(TabContainer);
790
SceneTree::get_singleton()->get_root()->add_child(target_tab_container);
791
792
target_tab_container->set_clip_tabs(false);
793
Control *other_tab0 = memnew(Control);
794
other_tab0->set_name("other_tab0");
795
target_tab_container->add_child(other_tab0);
796
797
target_tab_container->set_position(tab_container->get_size());
798
MessageQueue::get_singleton()->flush();
799
800
Vector<Rect2> target_tab_rects = {
801
target_tab_container->get_tab_bar()->get_tab_rect(0)
802
};
803
tab_container->set_drag_to_rearrange_enabled(true);
804
tab_container->set_tabs_rearrange_group(1);
805
806
Point2 target_tab_after_first = Point2(side_margin, 0) + target_tab_container->get_position() + target_tab_rects[0].position + Point2(target_tab_rects[0].size.x / 2 + 1, 0);
807
808
// Cannot drag to another TabContainer that does not have drag to rearrange enabled.
809
CHECK_FALSE(target_tab_container->get_drag_to_rearrange_enabled());
810
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
811
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position + Point2(20, 0), MouseButtonMask::LEFT, Key::NONE);
812
SEND_GUI_MOUSE_MOTION_EVENT(target_tab_after_first, MouseButtonMask::LEFT, Key::NONE);
813
SIGNAL_CHECK("tab_selected", { { 0 } });
814
SIGNAL_CHECK_FALSE("tab_changed");
815
CHECK(tab_container->get_viewport()->gui_is_dragging());
816
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_tab_after_first, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
817
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
818
CHECK(tab_container->get_tab_count() == 3);
819
CHECK(target_tab_container->get_tab_count() == 1);
820
SIGNAL_CHECK_FALSE("active_tab_rearranged");
821
SIGNAL_CHECK_FALSE("tab_selected");
822
SIGNAL_CHECK_FALSE("tab_changed");
823
824
// Cannot drag to another TabContainer that has a tabs rearrange group of -1.
825
target_tab_container->set_drag_to_rearrange_enabled(true);
826
tab_container->set_tabs_rearrange_group(-1);
827
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
828
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position + Point2(20, 0), MouseButtonMask::LEFT, Key::NONE);
829
SEND_GUI_MOUSE_MOTION_EVENT(target_tab_after_first, MouseButtonMask::LEFT, Key::NONE);
830
SIGNAL_CHECK("tab_selected", { { 0 } });
831
SIGNAL_CHECK_FALSE("tab_changed");
832
CHECK(tab_container->get_viewport()->gui_is_dragging());
833
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_tab_after_first, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
834
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
835
CHECK(tab_container->get_tab_count() == 3);
836
CHECK(target_tab_container->get_tab_count() == 1);
837
SIGNAL_CHECK_FALSE("active_tab_rearranged");
838
SIGNAL_CHECK_FALSE("tab_selected");
839
SIGNAL_CHECK_FALSE("tab_changed");
840
841
// Cannot drag to another TabContainer that has a different tabs rearrange group.
842
tab_container->set_tabs_rearrange_group(1);
843
target_tab_container->set_tabs_rearrange_group(2);
844
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
845
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position + Point2(20, 0), MouseButtonMask::LEFT, Key::NONE);
846
SEND_GUI_MOUSE_MOTION_EVENT(target_tab_after_first, MouseButtonMask::LEFT, Key::NONE);
847
SIGNAL_CHECK("tab_selected", { { 0 } });
848
SIGNAL_CHECK_FALSE("tab_changed");
849
CHECK(tab_container->get_viewport()->gui_is_dragging());
850
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_tab_after_first, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
851
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
852
CHECK(tab_container->get_tab_count() == 3);
853
CHECK(target_tab_container->get_tab_count() == 1);
854
SIGNAL_CHECK_FALSE("active_tab_rearranged");
855
SIGNAL_CHECK_FALSE("tab_selected");
856
SIGNAL_CHECK_FALSE("tab_changed");
857
858
// Drag to target container.
859
target_tab_container->set_tabs_rearrange_group(1);
860
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
861
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position + Point2(20, 0), MouseButtonMask::LEFT, Key::NONE);
862
SEND_GUI_MOUSE_MOTION_EVENT(target_tab_after_first, MouseButtonMask::LEFT, Key::NONE);
863
SIGNAL_CHECK("tab_selected", { { 0 } });
864
SIGNAL_CHECK_FALSE("tab_changed");
865
CHECK(tab_container->get_viewport()->gui_is_dragging());
866
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_tab_after_first, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
867
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
868
CHECK(tab_container->get_tab_count() == 2);
869
CHECK(target_tab_container->get_tab_count() == 2);
870
CHECK(tab_container->get_child_count(false) == 2);
871
CHECK(target_tab_container->get_child_count(false) == 2);
872
CHECK(tab_container->get_tab_idx_from_control(tab1) == 0);
873
CHECK(tab_container->get_tab_idx_from_control(tab2) == 1);
874
CHECK(target_tab_container->get_tab_idx_from_control(other_tab0) == 0);
875
CHECK(target_tab_container->get_tab_idx_from_control(tab0) == 1);
876
CHECK(tab_container->get_current_tab() == 0);
877
CHECK(target_tab_container->get_current_tab() == 1);
878
SIGNAL_CHECK_FALSE("active_tab_rearranged");
879
SIGNAL_CHECK_FALSE("tab_selected"); // Does not send since tab was removed.
880
SIGNAL_CHECK("tab_changed", { { 0 } });
881
882
Point2 target_tab = Point2(side_margin, 0) + target_tab_container->get_position();
883
884
// Drag to target container at first index.
885
target_tab_container->set_tabs_rearrange_group(1);
886
SEND_GUI_MOUSE_BUTTON_EVENT(Point2(side_margin, 0) + tab_rects[0].position, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
887
SEND_GUI_MOUSE_MOTION_EVENT(Point2(side_margin, 0) + tab_rects[0].position + Point2(20, 0), MouseButtonMask::LEFT, Key::NONE);
888
SEND_GUI_MOUSE_MOTION_EVENT(target_tab, MouseButtonMask::LEFT, Key::NONE);
889
SIGNAL_CHECK("tab_selected", { { 0 } });
890
SIGNAL_CHECK_FALSE("tab_changed");
891
CHECK(tab_container->get_viewport()->gui_is_dragging());
892
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_tab, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
893
CHECK_FALSE(tab_container->get_viewport()->gui_is_dragging());
894
CHECK(tab_container->get_tab_count() == 1);
895
CHECK(target_tab_container->get_tab_count() == 3);
896
CHECK(tab_container->get_tab_idx_from_control(tab2) == 0);
897
CHECK(target_tab_container->get_tab_idx_from_control(tab1) == 0);
898
CHECK(target_tab_container->get_tab_idx_from_control(other_tab0) == 1);
899
CHECK(target_tab_container->get_tab_idx_from_control(tab0) == 2);
900
CHECK(tab_container->get_current_tab() == 0);
901
CHECK(target_tab_container->get_current_tab() == 0);
902
SIGNAL_CHECK_FALSE("active_tab_rearranged");
903
SIGNAL_CHECK_FALSE("tab_selected"); // Does not send since tab was removed.
904
SIGNAL_CHECK("tab_changed", { { 0 } });
905
906
memdelete(target_tab_container);
907
}
908
909
SIGNAL_UNWATCH(tab_container, "active_tab_rearranged");
910
SIGNAL_UNWATCH(tab_container, "tab_changed");
911
SIGNAL_UNWATCH(tab_container, "tab_clicked");
912
SIGNAL_UNWATCH(tab_container, "tab_selected");
913
914
memdelete(tab_container);
915
}
916
917
// FIXME: Add tests for keyboard navigation and other methods.
918
919
} // namespace TestTabContainer
920
921