GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/widgets/tabbedarea.cpp Lines: 269 393 68.4 %
Date: 2018-11-12 Branches: 142 344 41.3 %

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
12
TabbedArea::TabbedArea(const Widget2 *const widget) :
80
    ActionListener(),
81
    BasicContainer(widget),
82
    KeyListener(),
83
    MouseListener(),
84
    WidgetListener(),
85
    mArrowButton(),
86
    mSelectedTab(nullptr),
87

12
    mTabContainer(new BasicContainer2(widget)),
88

12
    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
120
    mResizeHeight(true)
100
{
101
12
    setFocusable(true);
102
12
    addKeyListener(this);
103
12
    addMouseListener(this);
104
12
}
105
106
12
void TabbedArea::postInit()
107
{
108
24
    mTabContainer->setOpaque(Opaque_false);
109
110
12
    add(mTabContainer);
111
12
    add(mWidgetContainer);
112
113
24
    mWidgetContainer->setOpaque(Opaque_false);
114
12
    addWidgetListener(this);
115
116
12
    mArrowButton[0] = new Button(this,
117
        "<",
118
        "shift_left",
119
        BUTTON_SKIN,
120

72
        this);
121
12
    mArrowButton[1] = new Button(this,
122
        ">",
123
        "shift_right",
124
        BUTTON_SKIN,
125

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

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

4
    else if (!mEnableScrollButtons && enable)
159
    {
160
4
        if (mArrowButton[0] != nullptr)
161
4
            add(mArrowButton[0]);
162
4
        if (mArrowButton[1] != nullptr)
163
4
            add(mArrowButton[1]);
164
    }
165
4
    mEnableScrollButtons = enable;
166
4
}
167
168
int TabbedArea::getNumberOfTabs() const
169
{
170
18
    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
1
void TabbedArea::draw(Graphics *const graphics)
188
{
189
    BLOCK_START("TabbedArea::draw")
190
2
    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
192
Widget *TabbedArea::getWidget(const std::string &name) const
214
{
215
384
    TabContainer::const_iterator itr = mTabs.begin();
216
384
    const TabContainer::const_iterator itr_end = mTabs.end();
217
192
    while (itr != itr_end)
218
    {
219
192
        if ((*itr).first->getCaption() == name)
220
192
            return (*itr).second;
221
222
        ++itr;
223
    }
224
225
    return nullptr;
226
}
227
228
279
Widget *TabbedArea::getCurrentWidget() const
229
{
230
279
    const Tab *const tab = getSelectedTab();
231
232
279
    if (tab != nullptr)
233
192
        return getWidget(tab->getCaption());
234
    return nullptr;
235
}
236
237
49
void TabbedArea::addTab(Tab *const tab,
238
                        Widget *const widget)
239
{
240

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

49
    if ((mSelectedTab == nullptr) && tab->mVisible == Visible_true)
250
9
        setSelectedTab(tab);
251
252
49
    adjustTabPositions();
253
49
    adjustSize();
254
255
49
    const int frameSize = 2 * mFrameSize;
256
98
    widget->setSize(getWidth() - frameSize,
257
196
        getHeight() - frameSize - mTabContainer->getHeight());
258
259
49
    widgetResized(Event(nullptr));
260
49
    updateTabsWidth();
261
49
    updateArrowEnableState();
262
}
263
264
4
void TabbedArea::adjustWidget(Widget *const widget) const
265
{
266
4
    if (widget == nullptr)
267
        return;
268
4
    const int frameSize = 2 * mFrameSize;
269
8
    widget->setSize(getWidth() - frameSize,
270
16
        getHeight() - frameSize - mTabContainer->getHeight());
271
}
272
273
43
void TabbedArea::addTab(const std::string &caption, Widget *const widget)
274
{
275
43
    Tab *const tab = new Tab(this);
276
43
    tab->setCaption(caption);
277
43
    mTabsToDelete.push_back(tab);
278
279
43
    addTab(tab, widget);
280
43
}
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

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

2
        if (index == CAST_S32(sz) - 1 && sz == 1)
331
            tabIndexToBeSelected = -1;
332
        else
333
1
            tabIndexToBeSelected = index - 1;
334
    }
335
336
24
    for (TabContainer::iterator iter = mTabs.begin();
337
24
         iter != mTabs.end(); ++iter)
338
    {
339
11
        if (iter->first == tab)
340
        {
341
5
            mTabContainer->remove(tab);
342
10
            mTabs.erase(iter);
343
5
            break;
344
        }
345
    }
346
347
24
    for (STD_VECTOR<Tab*>::iterator iter2 = mTabsToDelete.begin();
348
24
         iter2 != mTabsToDelete.end(); ++iter2)
349
    {
350
10
        if (*iter2 == tab)
351
        {
352
8
            mTabsToDelete.erase(iter2);
353
4
            delete tab;
354
            break;
355
        }
356
    }
357
358
12
    const int tabsSize = CAST_S32(mTabs.size());
359
6
    if (tabIndexToBeSelected >= tabsSize)
360
        tabIndexToBeSelected = tabsSize - 1;
361
6
    if (tabIndexToBeSelected < -1)
362
1
        tabIndexToBeSelected = -1;
363
364
6
    if (tabIndexToBeSelected == -1)
365
    {
366
6
        mSelectedTab = nullptr;
367
6
        mWidgetContainer->clear();
368
    }
369
    else
370
    {
371
        setSelectedTabByIndex(tabIndexToBeSelected);
372
    }
373
374
6
    adjustSize();
375
6
    updateTabsWidth();
376
6
    widgetResized(Event(nullptr));
377
6
}
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
10
void TabbedArea::setSelectedTab(Tab *const tab)
407
{
408
46
    for (size_t i = 0; i < mTabs.size(); i++)
409
    {
410
26
        if (mTabs[i].first == mSelectedTab)
411
1
            mWidgetContainer->remove(mTabs[i].second);
412
    }
413
414
59
    for (size_t i = 0; i < mTabs.size(); i++)
415
    {
416
26
        if (mTabs[i].first == tab)
417
        {
418
10
            mSelectedTab = tab;
419
10
            mWidgetContainer->add(mTabs[i].second);
420
        }
421
    }
422
423
10
    Tab *const newTab = tab;
424
425
10
    if (newTab != nullptr)
426
10
        newTab->setCurrent();
427
428
10
    widgetResized(Event(nullptr));
429
10
}
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
10
    for (unsigned int i = 0, fsz = CAST_U32(mTabs.size());
451



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



4
        if (mTabs[i].first == mSelectedTab)
455
2
            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
99
void TabbedArea::widgetResized(const Event &event A_UNUSED)
474
{
475
99
    adjustSize();
476
477
99
    const int frameSize = 2 * mFrameSize;
478
198
    const int widgetFrameSize = 2 * mWidgetContainer->getFrameSize();
479
99
    const int w1 = mDimension.width;
480
99
    const int h1 = mDimension.height;
481
99
    const int width = w1 - frameSize - widgetFrameSize;
482
99
    const int height = h1 - frameSize
483
198
        - mWidgetContainer->getY() - widgetFrameSize;
484
485
99
    Widget *const w = getCurrentWidget();
486
99
    ScrollArea *const scr = dynamic_cast<ScrollArea *>(w);
487
99
    if (scr != nullptr)
488
    {
489

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

2
            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
99
    if (mArrowButton[1] != nullptr)
511
    {
512
        // Check whether there is room to show more tabs now.
513
198
        int innerWidth = w1 - 4 - mArrowButton[0]->getWidth()
514
198
            - mArrowButton[1]->getWidth() - mRightMargin;
515
99
        if (innerWidth < 0)
516
28
            innerWidth = 0;
517
518
99
        int newWidth = mVisibleTabsWidth;
519

99
        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
198
            newWidth = width - mArrowButton[1]->getWidth() - mRightMargin;
534
99
            if (newWidth < 0)
535
28
                newWidth = 0;
536
99
            mArrowButton[1]->setPosition(newWidth, 0);
537
        }
538
    }
539
540
99
    updateArrowEnableState();
541
99
    adjustTabPositions();
542
99
}
543
544
203
void TabbedArea::updateTabsWidth()
545
{
546
203
    mTabsWidth = 0;
547
2010
    FOR_EACH (TabContainer::const_iterator, itr, mTabs)
548
    {
549
792
        Tab *const tab = (*itr).first;
550

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

792
        if (tab != nullptr && tab->mVisible == Visible_true)
563
1584
            visibleTabsWidth += CAST_S32(tab->getWidth());
564
    }
565
203
    mVisibleTabsWidth = visibleTabsWidth;
566
203
}
567
568
180
void TabbedArea::adjustSize()
569
{
570
180
    int maxTabHeight = 0;
571
572
180
    const int width = mDimension.width;
573
180
    const int height = mDimension.height;
574
575
964
    for (size_t i = 0, sz = mTabs.size(); i < sz; i++)
576
    {
577
1812
        if (mTabs[i].first->getHeight() > maxTabHeight)
578
131
            maxTabHeight = mTabs[i].first->getHeight();
579
    }
580
581
180
    mTabContainer->setSize(width - mRightMargin, maxTabHeight);
582
583
180
    mWidgetContainer->setPosition(0, maxTabHeight);
584
180
    mWidgetContainer->setSize(width, height - maxTabHeight);
585
180
    Widget *const w = getCurrentWidget();
586
180
    if (w != nullptr)
587
    {
588
125
        const int wFrameSize = w->getFrameSize();
589
125
        const int frame2 = 2 * wFrameSize;
590
591
125
        w->setPosition(wFrameSize, wFrameSize);
592
125
        if (mResizeHeight)
593
        {
594
244
            w->setSize(mWidgetContainer->getWidth() - frame2,
595
366
                mWidgetContainer->getHeight() - frame2);
596
        }
597
        else
598
        {
599
6
            w->setSize(mWidgetContainer->getWidth() - frame2,
600
3
                w->getHeight());
601
        }
602
    }
603
180
}
604
605
148
void TabbedArea::adjustTabPositions()
606
{
607
148
    int maxTabHeight = 0;
608
296
    const size_t sz = mTabs.size();
609
695
    for (size_t i = 0; i < sz; ++i)
610
    {
611
1094
        const Tab *const tab = mTabs[i].first;
612

1094
        if ((tab != nullptr) &&
613

1094
            tab->mVisible == Visible_true &&
614
1094
            tab->getHeight() > maxTabHeight)
615
        {
616
238
            maxTabHeight = tab->getHeight();
617
        }
618
    }
619
620
212
    unsigned int x = (mEnableScrollButtons &&
621
160
        mArrowButton[0]->mVisible == Visible_true) ?
622
172
        mArrowButton[0]->getWidth() : 0U;
623
695
    for (size_t i = mTabScrollIndex; i < sz; ++i)
624
    {
625
1094
        Tab *const tab = mTabs[i].first;
626

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

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

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

3
}