GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/tabbedarea.cpp Lines: 262 387 67.7 %
Date: 2017-11-29 Branches: 140 328 42.7 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2008-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/*      _______   __   __   __   ______   __   __   _______   __   __
24
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
25
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
26
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
27
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
28
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
29
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
30
 *
31
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
32
 *
33
 *
34
 * Per Larsson a.k.a finalman
35
 * Olof Naessén a.k.a jansem/yakslem
36
 *
37
 * Visit: http://guichan.sourceforge.net
38
 *
39
 * License: (BSD)
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in
47
 *    the documentation and/or other materials provided with the
48
 *    distribution.
49
 * 3. Neither the name of Guichan nor the names of its contributors may
50
 *    be used to endorse or promote products derived from this software
51
 *    without specific prior written permission.
52
 *
53
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
59
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64
 */
65
66
#include "gui/widgets/tabbedarea.h"
67
68
#include "gui/gui.h"
69
70
#include "gui/widgets/button.h"
71
#include "gui/widgets/scrollarea.h"
72
#include "gui/widgets/tabs/tab.h"
73
74
#include "utils/delete2.h"
75
#include "utils/foreach.h"
76
77
#include "debug.h"
78
79
22
TabbedArea::TabbedArea(const Widget2 *const widget) :
80
    ActionListener(),
81
    BasicContainer(widget),
82
    KeyListener(),
83
    MouseListener(),
84
    WidgetListener(),
85
    mArrowButton(),
86
    mSelectedTab(nullptr),
87

22
    mTabContainer(new BasicContainer2(widget)),
88

22
    mWidgetContainer(new BasicContainer2(widget)),
89
    mTabsToDelete(),
90
    mTabs(),
91
    mTabsWidth(0),
92
    mVisibleTabsWidth(0),
93
    mTabScrollIndex(0),
94
    mRightMargin(0),
95
    mOpaque(Opaque_false),
96
    mEnableScrollButtons(false),
97
    mFollowDownScroll(false),
98
    mBlockSwitching(true),
99
220
    mResizeHeight(true)
100
{
101
22
    setFocusable(true);
102
22
    addKeyListener(this);
103
22
    addMouseListener(this);
104
22
}
105
106
22
void TabbedArea::postInit()
107
{
108
22
    mTabContainer->setOpaque(Opaque_false);
109
110
22
    add(mTabContainer);
111
22
    add(mWidgetContainer);
112
113
44
    mWidgetContainer->setOpaque(Opaque_false);
114
22
    addWidgetListener(this);
115
116


154
    mArrowButton[0] = new Button(this, "<", "shift_left", this);
117


154
    mArrowButton[1] = new Button(this, ">", "shift_right", this);
118
119
22
    widgetResized(Event(nullptr));
120
22
}
121
122
176
TabbedArea::~TabbedArea()
123
{
124
22
    if (gui != nullptr)
125
22
        gui->removeDragged(this);
126
127
    // +++ virtual method calls
128
22
    remove(mTabContainer);
129
22
    remove(mWidgetContainer);
130
131
22
    delete2(mTabContainer);
132
22
    delete2(mWidgetContainer);
133
134
110
    for (size_t i = 0, sz = mTabsToDelete.size(); i < sz; i++)
135
198
        delete2(mTabsToDelete[i])
136
137
22
    delete2(mArrowButton[0]);
138
22
    delete2(mArrowButton[1]);
139
44
}
140
141
8
void TabbedArea::enableScrollButtons(const bool enable)
142
{
143

8
    if (mEnableScrollButtons && !enable)
144
    {
145
        if (mArrowButton[0] != nullptr)
146
            remove(mArrowButton[0]);
147
        if (mArrowButton[1] != nullptr)
148
            remove(mArrowButton[1]);
149
    }
150

8
    else if (!mEnableScrollButtons && enable)
151
    {
152
8
        if (mArrowButton[0] != nullptr)
153
8
            add(mArrowButton[0]);
154
8
        if (mArrowButton[1] != nullptr)
155
8
            add(mArrowButton[1]);
156
    }
157
8
    mEnableScrollButtons = enable;
158
8
}
159
160
int TabbedArea::getNumberOfTabs() const
161
{
162
36
    return CAST_S32(mTabs.size());
163
}
164
165
Tab *TabbedArea::getTab(const std::string &name) const
166
{
167
    TabContainer::const_iterator itr = mTabs.begin();
168
    const TabContainer::const_iterator itr_end = mTabs.end();
169
    while (itr != itr_end)
170
    {
171
        if ((*itr).first->getCaption() == name)
172
            return static_cast<Tab*>((*itr).first);
173
174
        ++itr;
175
    }
176
    return nullptr;
177
}
178
179
2
void TabbedArea::draw(Graphics *const graphics)
180
{
181
    BLOCK_START("TabbedArea::draw")
182
4
    if (mTabs.empty())
183
    {
184
        BLOCK_END("TabbedArea::draw")
185
        return;
186
    }
187
188
    drawChildren(graphics);
189
    BLOCK_END("TabbedArea::draw")
190
}
191
192
void TabbedArea::safeDraw(Graphics *const graphics)
193
{
194
    BLOCK_START("TabbedArea::draw")
195
    if (mTabs.empty())
196
    {
197
        BLOCK_END("TabbedArea::draw")
198
        return;
199
    }
200
201
    safeDrawChildren(graphics);
202
    BLOCK_END("TabbedArea::draw")
203
}
204
205
332
Widget *TabbedArea::getWidget(const std::string &name) const
206
{
207
664
    TabContainer::const_iterator itr = mTabs.begin();
208
664
    const TabContainer::const_iterator itr_end = mTabs.end();
209
332
    while (itr != itr_end)
210
    {
211
664
        if ((*itr).first->getCaption() == name)
212
332
            return (*itr).second;
213
214
        ++itr;
215
    }
216
217
    return nullptr;
218
}
219
220
502
Widget *TabbedArea::getCurrentWidget() const
221
{
222
502
    const Tab *const tab = getSelectedTab();
223
224
502
    if (tab != nullptr)
225
332
        return getWidget(tab->getCaption());
226
    return nullptr;
227
}
228
229
86
void TabbedArea::addTab(Tab *const tab,
230
                        Widget *const widget)
231
{
232

86
    if ((tab == nullptr) || (widget == nullptr))
233
        return;
234
235
86
    tab->setTabbedArea(this);
236
86
    tab->addActionListener(this);
237
238
86
    mTabContainer->add(tab);
239
258
    mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));
240
241

86
    if ((mSelectedTab == nullptr) && tab->mVisible == Visible_true)
242
16
        setSelectedTab(tab);
243
244
86
    adjustTabPositions();
245
86
    adjustSize();
246
247
86
    const int frameSize = 2 * mFrameSize;
248
172
    widget->setSize(getWidth() - frameSize,
249
258
        getHeight() - frameSize - mTabContainer->getHeight());
250
251
86
    widgetResized(Event(nullptr));
252
86
    updateTabsWidth();
253
86
    updateArrowEnableState();
254
}
255
256
8
void TabbedArea::adjustWidget(Widget *const widget) const
257
{
258
8
    if (widget == nullptr)
259
        return;
260
8
    const int frameSize = 2 * mFrameSize;
261
16
    widget->setSize(getWidth() - frameSize,
262
24
        getHeight() - frameSize - mTabContainer->getHeight());
263
}
264
265
74
void TabbedArea::addTab(const std::string &caption, Widget *const widget)
266
{
267
74
    Tab *const tab = new Tab(this);
268
74
    tab->setCaption(caption);
269
74
    mTabsToDelete.push_back(tab);
270
271
74
    addTab(tab, widget);
272
74
}
273
274
void TabbedArea::addTab(Image *const image, Widget *const widget)
275
{
276
    Tab *const tab = new Tab(this);
277
    tab->setImage(image);
278
    mTabsToDelete.push_back(tab);
279
280
    addTab(tab, widget);
281
}
282
283
bool TabbedArea::isTabSelected(const size_t index) const
284
{
285
    if (index >= mTabs.size())
286
        return false;
287
288
    return mSelectedTab == mTabs[index].first;
289
}
290
291
bool TabbedArea::isTabPresent(const Tab *const tab) const
292
{
293
    FOR_EACH (TabContainer::const_iterator, it, mTabs)
294
    {
295
        if ((*it).first == tab || (*it).second == tab)
296
            return true;
297
    }
298
    return false;
299
}
300
301
bool TabbedArea::isTabSelected(const Tab *const tab) const
302
{
303
    return mSelectedTab == tab;
304
}
305
306
void TabbedArea::setSelectedTabByIndex(const size_t index)
307
{
308

2
    if (index >= mTabs.size())
309
        return;
310
311
2
    setSelectedTab(mTabs[index].first);
312
}
313
314
12
void TabbedArea::removeTab(Tab *const tab)
315
{
316
12
    int tabIndexToBeSelected = -1;
317
318
12
    if (tab == mSelectedTab)
319
    {
320
4
        const int index = getSelectedTabIndex();
321
4
        const size_t sz = mTabs.size();
322

4
        if (index == CAST_S32(sz) - 1 && sz == 1)
323
            tabIndexToBeSelected = -1;
324
        else
325
2
            tabIndexToBeSelected = index - 1;
326
    }
327
328
24
    for (TabContainer::iterator iter = mTabs.begin();
329
72
         iter != mTabs.end(); ++iter)
330
    {
331
22
        if (iter->first == tab)
332
        {
333
10
            mTabContainer->remove(tab);
334
30
            mTabs.erase(iter);
335
10
            break;
336
        }
337
    }
338
339
24
    for (STD_VECTOR<Tab*>::iterator iter2 = mTabsToDelete.begin();
340
72
         iter2 != mTabsToDelete.end(); ++iter2)
341
    {
342
20
        if (*iter2 == tab)
343
        {
344
24
            mTabsToDelete.erase(iter2);
345
8
            delete tab;
346
            break;
347
        }
348
    }
349
350
24
    const int tabsSize = CAST_S32(mTabs.size());
351
12
    if (tabIndexToBeSelected >= tabsSize)
352
        tabIndexToBeSelected = tabsSize - 1;
353
12
    if (tabIndexToBeSelected < -1)
354
        tabIndexToBeSelected = -1;
355
356
10
    if (tabIndexToBeSelected == -1)
357
    {
358
12
        mSelectedTab = nullptr;
359
12
        mWidgetContainer->clear();
360
    }
361
    else
362
    {
363
        setSelectedTabByIndex(tabIndexToBeSelected);
364
    }
365
366
12
    adjustSize();
367
12
    updateTabsWidth();
368
12
    widgetResized(Event(nullptr));
369
12
}
370
371
1
void TabbedArea::logic()
372
{
373
    BLOCK_START("TabbedArea::logic")
374
1
    logicChildren();
375
    BLOCK_END("TabbedArea::logic")
376
1
}
377
378
void TabbedArea::mousePressed(MouseEvent &event)
379
{
380
    if (event.isConsumed())
381
        return;
382
383
    if (event.getButton() == MouseButton::LEFT)
384
    {
385
        Widget *const widget = mTabContainer->getWidgetAt(
386
            event.getX(), event.getY());
387
        Tab *const tab = dynamic_cast<Tab *>(widget);
388
389
        if (tab != nullptr)
390
        {
391
            event.consume();
392
            setSelectedTab(tab);
393
            requestFocus();
394
        }
395
    }
396
}
397
398
18
void TabbedArea::setSelectedTab(Tab *const tab)
399
{
400
84
    for (size_t i = 0; i < mTabs.size(); i++)
401
    {
402
48
        if (mTabs[i].first == mSelectedTab)
403
2
            mWidgetContainer->remove(mTabs[i].second);
404
    }
405
406
108
    for (size_t i = 0; i < mTabs.size(); i++)
407
    {
408
48
        if (mTabs[i].first == tab)
409
        {
410
18
            mSelectedTab = tab;
411
18
            mWidgetContainer->add(mTabs[i].second);
412
        }
413
    }
414
415
18
    Tab *const newTab = tab;
416
417
18
    if (newTab != nullptr)
418
18
        newTab->setCurrent();
419
420
18
    widgetResized(Event(nullptr));
421
18
}
422
423
void TabbedArea::setSelectedTabDefault()
424
{
425
    if (mSelectedTab == nullptr ||
426
        mSelectedTab->mVisible == Visible_false)
427
    {
428
        for (size_t i = 0; i < mTabs.size(); i++)
429
        {
430
            Tab *const tab = mTabs[i].first;
431
            if ((tab != nullptr) && tab->mVisible == Visible_true)
432
            {
433
                setSelectedTab(tab);
434
                return;
435
            }
436
        }
437
    }
438
}
439
440
int TabbedArea::getSelectedTabIndex() const
441
{
442
20
    for (unsigned int i = 0, fsz = CAST_U32(mTabs.size());
443



10
         i < fsz;
444
         i++)
445
    {
446



8
        if (mTabs[i].first == mSelectedTab)
447
4
            return i;
448
    }
449
450
    return -1;
451
}
452
453
void TabbedArea::setSelectedTabByName(const std::string &name)
454
{
455
    FOR_EACH (TabContainer::const_iterator, itr, mTabs)
456
    {
457
        if (((*itr).first != nullptr) && (*itr).first->getCaption() == name)
458
        {
459
            setSelectedTab((*itr).first);
460
            return;
461
        }
462
    }
463
}
464
465
178
void TabbedArea::widgetResized(const Event &event A_UNUSED)
466
{
467
178
    adjustSize();
468
469
178
    const int frameSize = 2 * mFrameSize;
470
356
    const int widgetFrameSize = 2 * mWidgetContainer->getFrameSize();
471
178
    const int w1 = mDimension.width;
472
178
    const int h1 = mDimension.height;
473
178
    const int width = w1 - frameSize - widgetFrameSize;
474
178
    const int height = h1 - frameSize
475
356
        - mWidgetContainer->getY() - widgetFrameSize;
476
477
178
    Widget *const w = getCurrentWidget();
478
178
    ScrollArea *const scr = dynamic_cast<ScrollArea *>(w);
479
116
    if (scr != nullptr)
480
    {
481

16
        if (mFollowDownScroll && height != 0)
482
        {
483
4
            const Rect &rect = w->getDimension();
484

4
            if (rect.height != 0 && rect.height > height + 2)
485
            {
486
                if (scr->getVerticalScrollAmount()
487
                    >= scr->getVerticalMaxScroll() - 2
488
                    && scr->getVerticalScrollAmount()
489
                    <= scr->getVerticalMaxScroll() + 2)
490
                {
491
                    const int newScroll = scr->getVerticalScrollAmount()
492
                        + rect.height - height;
493
                    w->setSize(mWidgetContainer->getWidth() - frameSize,
494
                        mWidgetContainer->getHeight() - frameSize);
495
                    if (newScroll != 0)
496
                        scr->setVerticalScrollAmount(newScroll);
497
                }
498
            }
499
        }
500
    }
501
502
178
    if (mArrowButton[1] != nullptr)
503
    {
504
        // Check whether there is room to show more tabs now.
505
356
        int innerWidth = w1 - 4 - mArrowButton[0]->getWidth()
506
356
            - mArrowButton[1]->getWidth() - mRightMargin;
507
178
        if (innerWidth < 0)
508
40
            innerWidth = 0;
509
510
178
        int newWidth = mVisibleTabsWidth;
511

178
        while ((mTabScrollIndex != 0u) && newWidth < innerWidth)
512
        {
513
            Tab *const tab = mTabs[mTabScrollIndex - 1].first;
514
            if ((tab != nullptr) && tab->mVisible == Visible_true)
515
            {
516
                newWidth += tab->getWidth();
517
                if (newWidth < innerWidth)
518
                    --mTabScrollIndex;
519
            }
520
        }
521
522
        if (mArrowButton[1] != nullptr)
523
        {
524
            // Move the right arrow to fit the windows content.
525
356
            newWidth = width - mArrowButton[1]->getWidth() - mRightMargin;
526
178
            if (newWidth < 0)
527
40
                newWidth = 0;
528
178
            mArrowButton[1]->setPosition(newWidth, 0);
529
        }
530
    }
531
532
178
    updateArrowEnableState();
533
178
    adjustTabPositions();
534
178
}
535
536
362
void TabbedArea::updateTabsWidth()
537
{
538
362
    mTabsWidth = 0;
539
3622
    FOR_EACH (TabContainer::const_iterator, itr, mTabs)
540
    {
541
1450
        Tab *const tab = (*itr).first;
542

1450
        if ((tab != nullptr) && tab->mVisible == Visible_true)
543
2900
            mTabsWidth += tab->getWidth();
544
    }
545
362
    updateVisibleTabsWidth();
546
362
}
547
548
362
void TabbedArea::updateVisibleTabsWidth()
549
{
550
362
    mVisibleTabsWidth = 0;
551
2174
    for (size_t i = mTabScrollIndex, sz = mTabs.size(); i < sz; ++i)
552
    {
553
2900
        Tab *const tab = mTabs[i].first;
554

1450
        if ((tab != nullptr) && tab->mVisible == Visible_true)
555
2900
            mVisibleTabsWidth += CAST_S32(tab->getWidth());
556
    }
557
362
}
558
559
324
void TabbedArea::adjustSize()
560
{
561
324
    int maxTabHeight = 0;
562
563
324
    const int width = mDimension.width;
564
324
    const int height = mDimension.height;
565
566
1734
    for (size_t i = 0, sz = mTabs.size(); i < sz; i++)
567
    {
568
3258
        if (mTabs[i].first->getHeight() > maxTabHeight)
569
228
            maxTabHeight = mTabs[i].first->getHeight();
570
    }
571
572
324
    mTabContainer->setSize(width - mRightMargin, maxTabHeight);
573
574
324
    mWidgetContainer->setPosition(0, maxTabHeight);
575
324
    mWidgetContainer->setSize(width, height - maxTabHeight);
576
324
    Widget *const w = getCurrentWidget();
577
324
    if (w != nullptr)
578
    {
579
216
        const int wFrameSize = w->getFrameSize();
580
216
        const int frame2 = 2 * wFrameSize;
581
582
216
        w->setPosition(wFrameSize, wFrameSize);
583
216
        if (mResizeHeight)
584
        {
585
420
            w->setSize(mWidgetContainer->getWidth() - frame2,
586
420
                mWidgetContainer->getHeight() - frame2);
587
        }
588
        else
589
        {
590
12
            w->setSize(mWidgetContainer->getWidth() - frame2,
591
                w->getHeight());
592
        }
593
    }
594
324
}
595
596
264
void TabbedArea::adjustTabPositions()
597
{
598
264
    int maxTabHeight = 0;
599
528
    const size_t sz = mTabs.size();
600
1260
    for (size_t i = 0; i < sz; ++i)
601
    {
602
1992
        const Tab *const tab = mTabs[i].first;
603
996
        if ((tab != nullptr) &&
604

1992
            tab->mVisible == Visible_true &&
605
1992
            tab->getHeight() > maxTabHeight)
606
        {
607
            maxTabHeight = tab->getHeight();
608
        }
609
    }
610
611
392
    int x = (mEnableScrollButtons && mArrowButton[0]->mVisible == Visible_true)
612
328
        ? mArrowButton[0]->getWidth() : 0;
613
1260
    for (size_t i = mTabScrollIndex; i < sz; ++i)
614
    {
615
1992
        Tab *const tab = mTabs[i].first;
616

996
        if ((tab == nullptr) || tab->mVisible == Visible_false)
617
            continue;
618
1992
        tab->setPosition(x, maxTabHeight - tab->getHeight());
619
1992
        x += tab->getWidth();
620
    }
621
622
    // If the tabs are scrolled, we hide them away.
623
264
    if (mTabScrollIndex > 0)
624
    {
625
        x = 0;
626
        for (unsigned i = 0; i < mTabScrollIndex; ++i)
627
        {
628
            Tab *const tab = mTabs[i].first;
629
            if ((tab != nullptr) && tab->mVisible == Visible_true)
630
            {
631
                x -= tab->getWidth();
632
                tab->setPosition(x, maxTabHeight - tab->getHeight());
633
            }
634
        }
635
    }
636
264
}
637
638
void TabbedArea::action(const ActionEvent& actionEvent)
639
{
640
    Widget *const source = actionEvent.getSource();
641
    Tab *const tab = dynamic_cast<Tab *>(source);
642
643
    if (tab != nullptr)
644
    {
645
        setSelectedTab(tab);
646
    }
647
    else
648
    {
649
        const std::string &eventId = actionEvent.getId();
650
        if (eventId == "shift_left")
651
        {
652
            if (mTabScrollIndex != 0u)
653
                --mTabScrollIndex;
654
        }
655
        else if (eventId == "shift_right")
656
        {
657
            if (CAST_SIZE(mTabScrollIndex) < mTabs.size() - 1)
658
                ++mTabScrollIndex;
659
        }
660
        adjustTabPositions();
661
        updateArrowEnableState();
662
    }
663
}
664
665
264
void TabbedArea::updateArrowEnableState()
666
{
667
264
    updateTabsWidth();
668

264
    if ((mArrowButton[0] == nullptr) || (mArrowButton[1] == nullptr))
669
        return;
670
671
264
    const int width = mDimension.width;
672
528
    if (mTabsWidth > width - 4
673
528
        - mArrowButton[0]->getWidth()
674
528
        - mArrowButton[1]->getWidth() - mRightMargin)
675
    {
676
108
        mArrowButton[0]->setVisible(Visible_true);
677
108
        mArrowButton[1]->setVisible(Visible_true);
678
    }
679
    else
680
    {
681
156
        mArrowButton[0]->setVisible(Visible_false);
682
156
        mArrowButton[1]->setVisible(Visible_false);
683
156
        mTabScrollIndex = 0;
684
    }
685
686
    // Left arrow consistency check
687
264
    if (mTabScrollIndex == 0u)
688
264
        mArrowButton[0]->setEnabled(false);
689
    else
690
        mArrowButton[0]->setEnabled(true);
691
692
    // Right arrow consistency check
693
528
    if (mVisibleTabsWidth < width - 4
694
528
        - mArrowButton[0]->getWidth()
695
528
        - mArrowButton[1]->getWidth() - mRightMargin)
696
    {
697
156
        mArrowButton[1]->setEnabled(false);
698
    }
699
    else
700
    {
701
108
        mArrowButton[1]->setEnabled(true);
702
    }
703
}
704
705
2
Tab *TabbedArea::getTabByIndex(const int index) const
706
{
707

4
    if (index < 0 || index >= CAST_S32(mTabs.size()))
708
        return nullptr;
709
    return static_cast<Tab*>(mTabs[index].first);
710
}
711
712
Widget *TabbedArea::getWidgetByIndex(const int index) const
713
{
714
    if (index < 0 || index >= CAST_S32(mTabs.size()))
715
        return nullptr;
716
    return mTabs[index].second;
717
}
718
719
6
void TabbedArea::removeAll(const bool del)
720
{
721
6
    if (getSelectedTabIndex() != -1)
722
    {
723
        setSelectedTabByIndex(CAST_U32(0));
724
    }
725
14
    while (getNumberOfTabs() > 0)
726
    {
727
8
        const int idx = getNumberOfTabs() - 1;
728
16
        Tab *tab = mTabs[idx].first;
729
8
        Widget *widget = mTabs[idx].second;
730
8
        removeTab(tab);
731
8
        if (del)
732
        {
733
            delete tab;
734
            delete widget;
735
        }
736
    }
737
6
}
738
739
6
void TabbedArea::setWidth(int width)
740
{
741
    // +++ need use virtual
742
6
    Widget::setWidth(width);
743
6
    adjustSize();
744
6
}
745
746
6
void TabbedArea::setHeight(int height)
747
{
748
    // +++ need use virtual
749
6
    Widget::setHeight(height);
750
6
    adjustSize();
751
6
}
752
753
4
void TabbedArea::setSize(int width, int height)
754
{
755
    // +++ need use virtual
756
4
    Widget::setSize(width, height);
757
4
    adjustSize();
758
4
}
759
760
20
void TabbedArea::setDimension(const Rect &dimension)
761
{
762
    // +++ need use virtual
763
20
    Widget::setDimension(dimension);
764
20
    adjustSize();
765
20
}
766
767
void TabbedArea::keyPressed(KeyEvent& event)
768
{
769
    if (mBlockSwitching || event.isConsumed() || !isFocused())
770
        return;
771
772
    const InputActionT actionId = event.getActionId();
773
774
    if (actionId == InputAction::GUI_LEFT)
775
    {
776
        int index = getSelectedTabIndex();
777
        index--;
778
779
        if (index < 0)
780
            return;
781
782
        setSelectedTab(mTabs[index].first);
783
        event.consume();
784
    }
785
    else if (actionId == InputAction::GUI_RIGHT)
786
    {
787
        int index = getSelectedTabIndex();
788
        index++;
789
790
        if (index >= CAST_S32(mTabs.size()))
791
            return;
792
793
        setSelectedTab(mTabs[index].first);
794
        event.consume();
795
    }
796
}
797
798
16
void TabbedArea::death(const Event &event)
799
{
800
16
    Tab *const tab = dynamic_cast<Tab*>(event.getSource());
801
802
16
    if (tab != nullptr)
803
        removeTab(tab);
804
    else
805
16
        BasicContainer::death(event);
806
16
}
807
808
void TabbedArea::selectNextTab()
809
{
810
    int tab = getSelectedTabIndex();
811
    tab++;
812
    if (tab == CAST_S32(mTabs.size()))
813
        tab = 0;
814
    setSelectedTab(mTabs[tab].first);
815
}
816
817
void TabbedArea::selectPrevTab()
818
{
819
    int tab = getSelectedTabIndex();
820
821
    if (tab == 0)
822
        tab = CAST_S32(mTabs.size());
823
    if (tab < 0)
824
        return;
825
    tab--;
826
    setSelectedTab(mTabs[tab].first);
827

6
}