GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/tabbedarea.cpp Lines: 264 389 67.9 %
Date: 2018-05-23 22:10:27 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-2018  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
24
TabbedArea::TabbedArea(const Widget2 *const widget) :
80
    ActionListener(),
81
    BasicContainer(widget),
82
    KeyListener(),
83
    MouseListener(),
84
    WidgetListener(),
85
    mArrowButton(),
86
    mSelectedTab(nullptr),
87

24
    mTabContainer(new BasicContainer2(widget)),
88

24
    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
240
    mResizeHeight(true)
100
{
101
24
    setFocusable(true);
102
24
    addKeyListener(this);
103
24
    addMouseListener(this);
104
24
}
105
106
24
void TabbedArea::postInit()
107
{
108
48
    mTabContainer->setOpaque(Opaque_false);
109
110
24
    add(mTabContainer);
111
24
    add(mWidgetContainer);
112
113
48
    mWidgetContainer->setOpaque(Opaque_false);
114
24
    addWidgetListener(this);
115
116

192
    mArrowButton[0] = new Button(this,
117
        "<",
118
        "shift_left",
119
        BUTTON_SKIN,
120

24
        this);
121

192
    mArrowButton[1] = new Button(this,
122
        ">",
123
        "shift_right",
124
        BUTTON_SKIN,
125

24
        this);
126
127
24
    widgetResized(Event(nullptr));
128
24
}
129
130
192
TabbedArea::~TabbedArea()
131
{
132
24
    if (gui != nullptr)
133
24
        gui->removeDragged(this);
134
135
    // +++ virtual method calls
136
24
    remove(mTabContainer);
137
24
    remove(mWidgetContainer);
138
139
24
    delete2(mTabContainer);
140
24
    delete2(mWidgetContainer);
141
142
122
    for (size_t i = 0, sz = mTabsToDelete.size(); i < sz; i++)
143
222
        delete2(mTabsToDelete[i])
144
145
24
    delete2(mArrowButton[0]);
146
24
    delete2(mArrowButton[1]);
147
48
}
148
149
8
void TabbedArea::enableScrollButtons(const bool enable)
150
{
151

8
    if (mEnableScrollButtons && !enable)
152
    {
153
        if (mArrowButton[0] != nullptr)
154
            remove(mArrowButton[0]);
155
        if (mArrowButton[1] != nullptr)
156
            remove(mArrowButton[1]);
157
    }
158

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

94
    if ((tab == nullptr) || (widget == nullptr))
241
        return;
242
243
94
    tab->setTabbedArea(this);
244
94
    tab->addActionListener(this);
245
246
94
    mTabContainer->add(tab);
247
282
    mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));
248
249

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

2
    if (index >= mTabs.size())
317
        return;
318
319
2
    setSelectedTab(mTabs[index].first);
320
}
321
322
12
void TabbedArea::removeTab(Tab *const tab)
323
{
324
12
    int tabIndexToBeSelected = -1;
325
326
12
    if (tab == mSelectedTab)
327
    {
328
4
        const int index = getSelectedTabIndex();
329
4
        const size_t sz = mTabs.size();
330

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



10
         i < fsz;
452
         i++)
453
    {
454



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

16
        if (mFollowDownScroll && height != 0)
490
        {
491
4
            const Rect &rect = w->getDimension();
492

4
            if (rect.height != 0 && rect.height > height + 2)
493
            {
494
                if (scr->getVerticalScrollAmount()
495
                    >= scr->getVerticalMaxScroll() - 2
496
                    && scr->getVerticalScrollAmount()
497
                    <= scr->getVerticalMaxScroll() + 2)
498
                {
499
                    const int newScroll = scr->getVerticalScrollAmount()
500
                        + rect.height - height;
501
                    w->setSize(mWidgetContainer->getWidth() - frameSize,
502
                        mWidgetContainer->getHeight() - frameSize);
503
                    if (newScroll != 0)
504
                        scr->setVerticalScrollAmount(newScroll);
505
                }
506
            }
507
        }
508
    }
509
510
194
    if (mArrowButton[1] != nullptr)
511
    {
512
        // Check whether there is room to show more tabs now.
513
388
        int innerWidth = w1 - 4 - mArrowButton[0]->getWidth()
514
388
            - mArrowButton[1]->getWidth() - mRightMargin;
515
194
        if (innerWidth < 0)
516
52
            innerWidth = 0;
517
518
194
        int newWidth = mVisibleTabsWidth;
519

194
        while ((mTabScrollIndex != 0u) && newWidth < innerWidth)
520
        {
521
            Tab *const tab = mTabs[mTabScrollIndex - 1].first;
522
            if ((tab != nullptr) && tab->mVisible == Visible_true)
523
            {
524
                newWidth += tab->getWidth();
525
                if (newWidth < innerWidth)
526
                    --mTabScrollIndex;
527
            }
528
        }
529
530
        if (mArrowButton[1] != nullptr)
531
        {
532
            // Move the right arrow to fit the windows content.
533
388
            newWidth = width - mArrowButton[1]->getWidth() - mRightMargin;
534
194
            if (newWidth < 0)
535
52
                newWidth = 0;
536
194
            mArrowButton[1]->setPosition(newWidth, 0);
537
        }
538
    }
539
540
194
    updateArrowEnableState();
541
194
    adjustTabPositions();
542
194
}
543
544
394
void TabbedArea::updateTabsWidth()
545
{
546
394
    mTabsWidth = 0;
547
3892
    FOR_EACH (TabContainer::const_iterator, itr, mTabs)
548
    {
549
1528
        Tab *const tab = (*itr).first;
550

1528
        if ((tab != nullptr) && tab->mVisible == Visible_true)
551
3056
            mTabsWidth += tab->getWidth();
552
    }
553
394
    updateVisibleTabsWidth();
554
394
}
555
556
394
void TabbedArea::updateVisibleTabsWidth()
557
{
558
394
    mVisibleTabsWidth = 0;
559
2316
    for (size_t i = mTabScrollIndex, sz = mTabs.size(); i < sz; ++i)
560
    {
561
3056
        Tab *const tab = mTabs[i].first;
562

1528
        if ((tab != nullptr) && tab->mVisible == Visible_true)
563
3056
            mVisibleTabsWidth += CAST_S32(tab->getWidth());
564
    }
565
394
}
566
567
352
void TabbedArea::adjustSize()
568
{
569
352
    int maxTabHeight = 0;
570
571
352
    const int width = mDimension.width;
572
352
    const int height = mDimension.height;
573
574
1864
    for (size_t i = 0, sz = mTabs.size(); i < sz; i++)
575
    {
576
3480
        if (mTabs[i].first->getHeight() > maxTabHeight)
577
254
            maxTabHeight = mTabs[i].first->getHeight();
578
    }
579
580
352
    mTabContainer->setSize(width - mRightMargin, maxTabHeight);
581
582
352
    mWidgetContainer->setPosition(0, maxTabHeight);
583
352
    mWidgetContainer->setSize(width, height - maxTabHeight);
584
352
    Widget *const w = getCurrentWidget();
585
352
    if (w != nullptr)
586
    {
587
242
        const int wFrameSize = w->getFrameSize();
588
242
        const int frame2 = 2 * wFrameSize;
589
590
242
        w->setPosition(wFrameSize, wFrameSize);
591
242
        if (mResizeHeight)
592
        {
593
472
            w->setSize(mWidgetContainer->getWidth() - frame2,
594
472
                mWidgetContainer->getHeight() - frame2);
595
        }
596
        else
597
        {
598
12
            w->setSize(mWidgetContainer->getWidth() - frame2,
599
                w->getHeight());
600
        }
601
    }
602
352
}
603
604
288
void TabbedArea::adjustTabPositions()
605
{
606
288
    int maxTabHeight = 0;
607
576
    const size_t sz = mTabs.size();
608
1342
    for (size_t i = 0; i < sz; ++i)
609
    {
610
2108
        const Tab *const tab = mTabs[i].first;
611
1054
        if ((tab != nullptr) &&
612

2108
            tab->mVisible == Visible_true &&
613
2108
            tab->getHeight() > maxTabHeight)
614
        {
615
            maxTabHeight = tab->getHeight();
616
        }
617
    }
618
619
416
    int x = (mEnableScrollButtons && mArrowButton[0]->mVisible == Visible_true)
620
352
        ? mArrowButton[0]->getWidth() : 0;
621
1342
    for (size_t i = mTabScrollIndex; i < sz; ++i)
622
    {
623
2108
        Tab *const tab = mTabs[i].first;
624

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

288
    if ((mArrowButton[0] == nullptr) || (mArrowButton[1] == nullptr))
677
        return;
678
679
288
    const int width = mDimension.width;
680
576
    if (mTabsWidth > width - 4
681
576
        - mArrowButton[0]->getWidth()
682
576
        - mArrowButton[1]->getWidth() - mRightMargin)
683
    {
684
128
        mArrowButton[0]->setVisible(Visible_true);
685
128
        mArrowButton[1]->setVisible(Visible_true);
686
    }
687
    else
688
    {
689
160
        mArrowButton[0]->setVisible(Visible_false);
690
160
        mArrowButton[1]->setVisible(Visible_false);
691
160
        mTabScrollIndex = 0;
692
    }
693
694
    // Left arrow consistency check
695
288
    if (mTabScrollIndex == 0u)
696
288
        mArrowButton[0]->setEnabled(false);
697
    else
698
        mArrowButton[0]->setEnabled(true);
699
700
    // Right arrow consistency check
701
576
    if (mVisibleTabsWidth < width - 4
702
576
        - mArrowButton[0]->getWidth()
703
576
        - mArrowButton[1]->getWidth() - mRightMargin)
704
    {
705
160
        mArrowButton[1]->setEnabled(false);
706
    }
707
    else
708
    {
709
128
        mArrowButton[1]->setEnabled(true);
710
    }
711
}
712
713
2
Tab *TabbedArea::getTabByIndex(const int index) const
714
{
715

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

6
}