GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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-2019 The ManaPlus Developers |
||
6 |
* Copyright (C) 2019-2021 Andrei Karas |
||
7 |
* |
||
8 |
* This file is part of The ManaPlus Client. |
||
9 |
* |
||
10 |
* This program is free software; you can redistribute it and/or modify |
||
11 |
* it under the terms of the GNU General Public License as published by |
||
12 |
* the Free Software Foundation; either version 2 of the License, or |
||
13 |
* any later version. |
||
14 |
* |
||
15 |
* This program is distributed in the hope that it will be useful, |
||
16 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 |
* GNU General Public License for more details. |
||
19 |
* |
||
20 |
* You should have received a copy of the GNU General Public License |
||
21 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
22 |
*/ |
||
23 |
|||
24 |
/* _______ __ __ __ ______ __ __ _______ __ __ |
||
25 |
* / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ |
||
26 |
* / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / |
||
27 |
* / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / |
||
28 |
* / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / |
||
29 |
* /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / |
||
30 |
* \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ |
||
31 |
* |
||
32 |
* Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson |
||
33 |
* |
||
34 |
* |
||
35 |
* Per Larsson a.k.a finalman |
||
36 |
* Olof Naessén a.k.a jansem/yakslem |
||
37 |
* |
||
38 |
* Visit: http://guichan.sourceforge.net |
||
39 |
* |
||
40 |
* License: (BSD) |
||
41 |
* Redistribution and use in source and binary forms, with or without |
||
42 |
* modification, are permitted provided that the following conditions |
||
43 |
* are met: |
||
44 |
* 1. Redistributions of source code must retain the above copyright |
||
45 |
* notice, this list of conditions and the following disclaimer. |
||
46 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
47 |
* notice, this list of conditions and the following disclaimer in |
||
48 |
* the documentation and/or other materials provided with the |
||
49 |
* distribution. |
||
50 |
* 3. Neither the name of Guichan nor the names of its contributors may |
||
51 |
* be used to endorse or promote products derived from this software |
||
52 |
* without specific prior written permission. |
||
53 |
* |
||
54 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
55 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
56 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
57 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
58 |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
59 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
||
60 |
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||
61 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||
62 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||
63 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
64 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
65 |
*/ |
||
66 |
|||
67 |
#include "gui/widgets/tabbedarea.h" |
||
68 |
|||
69 |
#include "gui/gui.h" |
||
70 |
|||
71 |
#include "gui/widgets/button.h" |
||
72 |
#include "gui/widgets/scrollarea.h" |
||
73 |
#include "gui/widgets/tabs/tab.h" |
||
74 |
|||
75 |
#include "utils/delete2.h" |
||
76 |
#include "utils/foreach.h" |
||
77 |
|||
78 |
#include "debug.h" |
||
79 |
|||
80 |
12 |
TabbedArea::TabbedArea(const Widget2 *const widget) : |
|
81 |
ActionListener(), |
||
82 |
BasicContainer(widget), |
||
83 |
KeyListener(), |
||
84 |
MouseListener(), |
||
85 |
WidgetListener(), |
||
86 |
mArrowButton(), |
||
87 |
mSelectedTab(nullptr), |
||
88 |
✓✗✓✗ |
12 |
mTabContainer(new BasicContainer2(widget)), |
89 |
✓✗✓✗ |
12 |
mWidgetContainer(new BasicContainer2(widget)), |
90 |
mTabsToDelete(), |
||
91 |
mTabs(), |
||
92 |
mTabsWidth(0), |
||
93 |
mVisibleTabsWidth(0), |
||
94 |
mTabScrollIndex(0), |
||
95 |
mRightMargin(0), |
||
96 |
mOpaque(Opaque_false), |
||
97 |
mEnableScrollButtons(false), |
||
98 |
mFollowDownScroll(false), |
||
99 |
mBlockSwitching(true), |
||
100 |
✓✓ | 120 |
mResizeHeight(true) |
101 |
{ |
||
102 |
✓✗ | 12 |
setFocusable(true); |
103 |
✓✗ | 12 |
addKeyListener(this); |
104 |
✓✗ | 12 |
addMouseListener(this); |
105 |
12 |
} |
|
106 |
|||
107 |
12 |
void TabbedArea::postInit() |
|
108 |
{ |
||
109 |
24 |
mTabContainer->setOpaque(Opaque_false); |
|
110 |
|||
111 |
12 |
add(mTabContainer); |
|
112 |
12 |
add(mWidgetContainer); |
|
113 |
|||
114 |
24 |
mWidgetContainer->setOpaque(Opaque_false); |
|
115 |
12 |
addWidgetListener(this); |
|
116 |
|||
117 |
12 |
mArrowButton[0] = new Button(this, |
|
118 |
"<", |
||
119 |
"shift_left", |
||
120 |
BUTTON_SKIN, |
||
121 |
✓✗✓✗ ✓✗ |
72 |
this); |
122 |
12 |
mArrowButton[1] = new Button(this, |
|
123 |
">", |
||
124 |
"shift_right", |
||
125 |
BUTTON_SKIN, |
||
126 |
✓✗✓✗ ✓✗ |
84 |
this); |
127 |
|||
128 |
12 |
widgetResized(Event(nullptr)); |
|
129 |
12 |
} |
|
130 |
|||
131 |
96 |
TabbedArea::~TabbedArea() |
|
132 |
{ |
||
133 |
✓✗ | 12 |
if (gui != nullptr) |
134 |
12 |
gui->removeDragged(this); |
|
135 |
|||
136 |
// +++ virtual method calls |
||
137 |
12 |
remove(mTabContainer); |
|
138 |
12 |
remove(mWidgetContainer); |
|
139 |
|||
140 |
✓✗ | 12 |
delete2(mTabContainer) |
141 |
✓✗ | 12 |
delete2(mWidgetContainer) |
142 |
|||
143 |
✓✓ | 63 |
for (size_t i = 0, sz = mTabsToDelete.size(); i < sz; i++) |
144 |
✓✗ | 117 |
delete2(mTabsToDelete[i]) |
145 |
|||
146 |
✓✗ | 12 |
delete2(mArrowButton[0]) |
147 |
✓✗ | 12 |
delete2(mArrowButton[1]) |
148 |
24 |
} |
|
149 |
|||
150 |
4 |
void TabbedArea::enableScrollButtons(const bool enable) |
|
151 |
{ |
||
152 |
✗✓✗✗ |
4 |
if (mEnableScrollButtons && !enable) |
153 |
{ |
||
154 |
if (mArrowButton[0] != nullptr) |
||
155 |
remove(mArrowButton[0]); |
||
156 |
if (mArrowButton[1] != nullptr) |
||
157 |
remove(mArrowButton[1]); |
||
158 |
} |
||
159 |
✓✗✓✗ |
4 |
else if (!mEnableScrollButtons && enable) |
160 |
{ |
||
161 |
✓✗ | 4 |
if (mArrowButton[0] != nullptr) |
162 |
4 |
add(mArrowButton[0]); |
|
163 |
✓✗ | 4 |
if (mArrowButton[1] != nullptr) |
164 |
4 |
add(mArrowButton[1]); |
|
165 |
} |
||
166 |
4 |
mEnableScrollButtons = enable; |
|
167 |
4 |
} |
|
168 |
|||
169 |
int TabbedArea::getNumberOfTabs() const |
||
170 |
{ |
||
171 |
18 |
return CAST_S32(mTabs.size()); |
|
172 |
} |
||
173 |
|||
174 |
Tab *TabbedArea::getTab(const std::string &name) const |
||
175 |
{ |
||
176 |
TabContainer::const_iterator itr = mTabs.begin(); |
||
177 |
const TabContainer::const_iterator itr_end = mTabs.end(); |
||
178 |
while (itr != itr_end) |
||
179 |
{ |
||
180 |
if ((*itr).first->getCaption() == name) |
||
181 |
return static_cast<Tab*>((*itr).first); |
||
182 |
|||
183 |
++itr; |
||
184 |
} |
||
185 |
return nullptr; |
||
186 |
} |
||
187 |
|||
188 |
1 |
void TabbedArea::draw(Graphics *const graphics) |
|
189 |
{ |
||
190 |
BLOCK_START("TabbedArea::draw") |
||
191 |
✗✓ | 2 |
if (mTabs.empty()) |
192 |
{ |
||
193 |
BLOCK_END("TabbedArea::draw") |
||
194 |
return; |
||
195 |
} |
||
196 |
|||
197 |
drawChildren(graphics); |
||
198 |
BLOCK_END("TabbedArea::draw") |
||
199 |
} |
||
200 |
|||
201 |
void TabbedArea::safeDraw(Graphics *const graphics) |
||
202 |
{ |
||
203 |
BLOCK_START("TabbedArea::draw") |
||
204 |
if (mTabs.empty()) |
||
205 |
{ |
||
206 |
BLOCK_END("TabbedArea::draw") |
||
207 |
return; |
||
208 |
} |
||
209 |
|||
210 |
safeDrawChildren(graphics); |
||
211 |
BLOCK_END("TabbedArea::draw") |
||
212 |
} |
||
213 |
|||
214 |
192 |
Widget *TabbedArea::getWidget(const std::string &name) const |
|
215 |
{ |
||
216 |
384 |
TabContainer::const_iterator itr = mTabs.begin(); |
|
217 |
384 |
const TabContainer::const_iterator itr_end = mTabs.end(); |
|
218 |
✓✗ | 192 |
while (itr != itr_end) |
219 |
{ |
||
220 |
✓✗ | 192 |
if ((*itr).first->getCaption() == name) |
221 |
192 |
return (*itr).second; |
|
222 |
|||
223 |
++itr; |
||
224 |
} |
||
225 |
|||
226 |
return nullptr; |
||
227 |
} |
||
228 |
|||
229 |
279 |
Widget *TabbedArea::getCurrentWidget() const |
|
230 |
{ |
||
231 |
279 |
const Tab *const tab = getSelectedTab(); |
|
232 |
|||
233 |
✓✓ | 279 |
if (tab != nullptr) |
234 |
192 |
return getWidget(tab->getCaption()); |
|
235 |
return nullptr; |
||
236 |
} |
||
237 |
|||
238 |
49 |
void TabbedArea::addTab(Tab *const tab, |
|
239 |
Widget *const widget) |
||
240 |
{ |
||
241 |
✓✗✓✗ |
49 |
if ((tab == nullptr) || (widget == nullptr)) |
242 |
return; |
||
243 |
|||
244 |
49 |
tab->setTabbedArea(this); |
|
245 |
49 |
tab->addActionListener(this); |
|
246 |
|||
247 |
49 |
mTabContainer->add(tab); |
|
248 |
98 |
mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget)); |
|
249 |
|||
250 |
✓✓✓✗ |
49 |
if ((mSelectedTab == nullptr) && tab->mVisible == Visible_true) |
251 |
9 |
setSelectedTab(tab); |
|
252 |
|||
253 |
49 |
adjustTabPositions(); |
|
254 |
49 |
adjustSize(); |
|
255 |
|||
256 |
49 |
const int frameSize = 2 * mFrameSize; |
|
257 |
98 |
widget->setSize(getWidth() - frameSize, |
|
258 |
196 |
getHeight() - frameSize - mTabContainer->getHeight()); |
|
259 |
|||
260 |
49 |
widgetResized(Event(nullptr)); |
|
261 |
49 |
updateTabsWidth(); |
|
262 |
49 |
updateArrowEnableState(); |
|
263 |
} |
||
264 |
|||
265 |
4 |
void TabbedArea::adjustWidget(Widget *const widget) const |
|
266 |
{ |
||
267 |
✓✗ | 4 |
if (widget == nullptr) |
268 |
return; |
||
269 |
4 |
const int frameSize = 2 * mFrameSize; |
|
270 |
8 |
widget->setSize(getWidth() - frameSize, |
|
271 |
16 |
getHeight() - frameSize - mTabContainer->getHeight()); |
|
272 |
} |
||
273 |
|||
274 |
43 |
void TabbedArea::addTab(const std::string &caption, Widget *const widget) |
|
275 |
{ |
||
276 |
✓✗ | 43 |
Tab *const tab = new Tab(this); |
277 |
43 |
tab->setCaption(caption); |
|
278 |
43 |
mTabsToDelete.push_back(tab); |
|
279 |
|||
280 |
43 |
addTab(tab, widget); |
|
281 |
43 |
} |
|
282 |
|||
283 |
void TabbedArea::addTab(Image *const image, Widget *const widget) |
||
284 |
{ |
||
285 |
Tab *const tab = new Tab(this); |
||
286 |
tab->setImage(image); |
||
287 |
mTabsToDelete.push_back(tab); |
||
288 |
|||
289 |
addTab(tab, widget); |
||
290 |
} |
||
291 |
|||
292 |
bool TabbedArea::isTabSelected(const size_t index) const |
||
293 |
{ |
||
294 |
if (index >= mTabs.size()) |
||
295 |
return false; |
||
296 |
|||
297 |
return mSelectedTab == mTabs[index].first; |
||
298 |
} |
||
299 |
|||
300 |
bool TabbedArea::isTabPresent(const Tab *const tab) const |
||
301 |
{ |
||
302 |
FOR_EACH (TabContainer::const_iterator, it, mTabs) |
||
303 |
{ |
||
304 |
if ((*it).first == tab || (*it).second == tab) |
||
305 |
return true; |
||
306 |
} |
||
307 |
return false; |
||
308 |
} |
||
309 |
|||
310 |
bool TabbedArea::isTabSelected(const Tab *const tab) const |
||
311 |
{ |
||
312 |
return mSelectedTab == tab; |
||
313 |
} |
||
314 |
|||
315 |
void TabbedArea::setSelectedTabByIndex(const size_t index) |
||
316 |
{ |
||
317 |
✓✗✗✗ |
1 |
if (index >= mTabs.size()) |
318 |
return; |
||
319 |
|||
320 |
1 |
setSelectedTab(mTabs[index].first); |
|
321 |
} |
||
322 |
|||
323 |
6 |
void TabbedArea::removeTab(Tab *const tab) |
|
324 |
{ |
||
325 |
6 |
int tabIndexToBeSelected = -1; |
|
326 |
|||
327 |
✓✓ | 6 |
if (tab == mSelectedTab) |
328 |
{ |
||
329 |
2 |
const int index = getSelectedTabIndex(); |
|
330 |
2 |
const size_t sz = mTabs.size(); |
|
331 |
✓✗✓✓ |
2 |
if (index == CAST_S32(sz) - 1 && sz == 1) |
332 |
tabIndexToBeSelected = -1; |
||
333 |
else |
||
334 |
1 |
tabIndexToBeSelected = index - 1; |
|
335 |
} |
||
336 |
|||
337 |
✓✓ | 24 |
for (TabContainer::iterator iter = mTabs.begin(); |
338 |
24 |
iter != mTabs.end(); ++iter) |
|
339 |
{ |
||
340 |
✓✓ | 11 |
if (iter->first == tab) |
341 |
{ |
||
342 |
5 |
mTabContainer->remove(tab); |
|
343 |
10 |
mTabs.erase(iter); |
|
344 |
5 |
break; |
|
345 |
} |
||
346 |
} |
||
347 |
|||
348 |
✓✓ | 24 |
for (STD_VECTOR<Tab*>::iterator iter2 = mTabsToDelete.begin(); |
349 |
24 |
iter2 != mTabsToDelete.end(); ++iter2) |
|
350 |
{ |
||
351 |
✓✓ | 10 |
if (*iter2 == tab) |
352 |
{ |
||
353 |
8 |
mTabsToDelete.erase(iter2); |
|
354 |
✓✗ | 4 |
delete tab; |
355 |
break; |
||
356 |
} |
||
357 |
} |
||
358 |
|||
359 |
12 |
const int tabsSize = CAST_S32(mTabs.size()); |
|
360 |
✗✓ | 6 |
if (tabIndexToBeSelected >= tabsSize) |
361 |
tabIndexToBeSelected = tabsSize - 1; |
||
362 |
✓✓ | 6 |
if (tabIndexToBeSelected < -1) |
363 |
1 |
tabIndexToBeSelected = -1; |
|
364 |
|||
365 |
✓✗ | 6 |
if (tabIndexToBeSelected == -1) |
366 |
{ |
||
367 |
6 |
mSelectedTab = nullptr; |
|
368 |
6 |
mWidgetContainer->clear(); |
|
369 |
} |
||
370 |
else |
||
371 |
{ |
||
372 |
setSelectedTabByIndex(tabIndexToBeSelected); |
||
373 |
} |
||
374 |
|||
375 |
6 |
adjustSize(); |
|
376 |
6 |
updateTabsWidth(); |
|
377 |
6 |
widgetResized(Event(nullptr)); |
|
378 |
6 |
} |
|
379 |
|||
380 |
1 |
void TabbedArea::logic() |
|
381 |
{ |
||
382 |
BLOCK_START("TabbedArea::logic") |
||
383 |
1 |
logicChildren(); |
|
384 |
BLOCK_END("TabbedArea::logic") |
||
385 |
1 |
} |
|
386 |
|||
387 |
void TabbedArea::mousePressed(MouseEvent &event) |
||
388 |
{ |
||
389 |
if (event.isConsumed()) |
||
390 |
return; |
||
391 |
|||
392 |
if (event.getButton() == MouseButton::LEFT) |
||
393 |
{ |
||
394 |
Widget *const widget = mTabContainer->getWidgetAt( |
||
395 |
event.getX(), event.getY()); |
||
396 |
Tab *const tab = dynamic_cast<Tab *>(widget); |
||
397 |
|||
398 |
if (tab != nullptr) |
||
399 |
{ |
||
400 |
event.consume(); |
||
401 |
setSelectedTab(tab); |
||
402 |
requestFocus(); |
||
403 |
} |
||
404 |
} |
||
405 |
} |
||
406 |
|||
407 |
10 |
void TabbedArea::setSelectedTab(Tab *const tab) |
|
408 |
{ |
||
409 |
✓✓ | 46 |
for (size_t i = 0; i < mTabs.size(); i++) |
410 |
{ |
||
411 |
✓✓ | 26 |
if (mTabs[i].first == mSelectedTab) |
412 |
1 |
mWidgetContainer->remove(mTabs[i].second); |
|
413 |
} |
||
414 |
|||
415 |
✓✓ | 59 |
for (size_t i = 0; i < mTabs.size(); i++) |
416 |
{ |
||
417 |
✓✓ | 26 |
if (mTabs[i].first == tab) |
418 |
{ |
||
419 |
10 |
mSelectedTab = tab; |
|
420 |
10 |
mWidgetContainer->add(mTabs[i].second); |
|
421 |
} |
||
422 |
} |
||
423 |
|||
424 |
10 |
Tab *const newTab = tab; |
|
425 |
|||
426 |
✓✗ | 10 |
if (newTab != nullptr) |
427 |
10 |
newTab->setCurrent(); |
|
428 |
|||
429 |
10 |
widgetResized(Event(nullptr)); |
|
430 |
10 |
} |
|
431 |
|||
432 |
void TabbedArea::setSelectedTabDefault() |
||
433 |
{ |
||
434 |
if (mSelectedTab == nullptr || |
||
435 |
mSelectedTab->mVisible == Visible_false) |
||
436 |
{ |
||
437 |
for (size_t i = 0; i < mTabs.size(); i++) |
||
438 |
{ |
||
439 |
Tab *const tab = mTabs[i].first; |
||
440 |
if ((tab != nullptr) && tab->mVisible == Visible_true) |
||
441 |
{ |
||
442 |
setSelectedTab(tab); |
||
443 |
return; |
||
444 |
} |
||
445 |
} |
||
446 |
} |
||
447 |
} |
||
448 |
|||
449 |
int TabbedArea::getSelectedTabIndex() const |
||
450 |
{ |
||
451 |
10 |
for (unsigned int i = 0, fsz = CAST_U32(mTabs.size()); |
|
452 |
✗✗✗✗ ✗✗✗✗ ✓✓✗✗ ✓✓ |
5 |
i < fsz; |
453 |
i++) |
||
454 |
{ |
||
455 |
✗✗✗✗ ✗✗✗✗ ✓✗✗✗ ✓✗ |
4 |
if (mTabs[i].first == mSelectedTab) |
456 |
2 |
return i; |
|
457 |
} |
||
458 |
|||
459 |
return -1; |
||
460 |
} |
||
461 |
|||
462 |
void TabbedArea::setSelectedTabByName(const std::string &name) |
||
463 |
{ |
||
464 |
FOR_EACH (TabContainer::const_iterator, itr, mTabs) |
||
465 |
{ |
||
466 |
if (((*itr).first != nullptr) && (*itr).first->getCaption() == name) |
||
467 |
{ |
||
468 |
setSelectedTab((*itr).first); |
||
469 |
return; |
||
470 |
} |
||
471 |
} |
||
472 |
} |
||
473 |
|||
474 |
99 |
void TabbedArea::widgetResized(const Event &event A_UNUSED) |
|
475 |
{ |
||
476 |
99 |
adjustSize(); |
|
477 |
|||
478 |
99 |
const int frameSize = 2 * mFrameSize; |
|
479 |
198 |
const int widgetFrameSize = 2 * mWidgetContainer->getFrameSize(); |
|
480 |
99 |
const int w1 = mDimension.width; |
|
481 |
99 |
const int h1 = mDimension.height; |
|
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 |
99 |
const int width = w1 - frameSize - widgetFrameSize; |
|
533 |
// Move the right arrow to fit the windows content. |
||
534 |
198 |
newWidth = width - mArrowButton[1]->getWidth() - mRightMargin; |
|
535 |
✓✓ | 99 |
if (newWidth < 0) |
536 |
28 |
newWidth = 0; |
|
537 |
99 |
mArrowButton[1]->setPosition(newWidth, 0); |
|
538 |
} |
||
539 |
} |
||
540 |
|||
541 |
99 |
updateArrowEnableState(); |
|
542 |
99 |
adjustTabPositions(); |
|
543 |
99 |
} |
|
544 |
|||
545 |
203 |
void TabbedArea::updateTabsWidth() |
|
546 |
{ |
||
547 |
203 |
mTabsWidth = 0; |
|
548 |
✓✓ | 2010 |
FOR_EACH (TabContainer::const_iterator, itr, mTabs) |
549 |
{ |
||
550 |
792 |
Tab *const tab = (*itr).first; |
|
551 |
✓✗✓✗ |
792 |
if ((tab != nullptr) && tab->mVisible == Visible_true) |
552 |
1584 |
mTabsWidth += tab->getWidth(); |
|
553 |
} |
||
554 |
203 |
updateVisibleTabsWidth(); |
|
555 |
203 |
} |
|
556 |
|||
557 |
203 |
void TabbedArea::updateVisibleTabsWidth() |
|
558 |
{ |
||
559 |
203 |
unsigned int visibleTabsWidth = 0; |
|
560 |
✓✓ | 1198 |
for (size_t i = mTabScrollIndex, sz = mTabs.size(); i < sz; ++i) |
561 |
{ |
||
562 |
1584 |
Tab *const tab = mTabs[i].first; |
|
563 |
✓✗✓✗ |
792 |
if (tab != nullptr && tab->mVisible == Visible_true) |
564 |
1584 |
visibleTabsWidth += CAST_S32(tab->getWidth()); |
|
565 |
} |
||
566 |
203 |
mVisibleTabsWidth = visibleTabsWidth; |
|
567 |
203 |
} |
|
568 |
|||
569 |
180 |
void TabbedArea::adjustSize() |
|
570 |
{ |
||
571 |
180 |
int maxTabHeight = 0; |
|
572 |
|||
573 |
180 |
const int width = mDimension.width; |
|
574 |
180 |
const int height = mDimension.height; |
|
575 |
|||
576 |
✓✓ | 964 |
for (size_t i = 0, sz = mTabs.size(); i < sz; i++) |
577 |
{ |
||
578 |
✓✓ | 1812 |
if (mTabs[i].first->getHeight() > maxTabHeight) |
579 |
131 |
maxTabHeight = mTabs[i].first->getHeight(); |
|
580 |
} |
||
581 |
|||
582 |
180 |
mTabContainer->setSize(width - mRightMargin, maxTabHeight); |
|
583 |
|||
584 |
180 |
mWidgetContainer->setPosition(0, maxTabHeight); |
|
585 |
180 |
mWidgetContainer->setSize(width, height - maxTabHeight); |
|
586 |
180 |
Widget *const w = getCurrentWidget(); |
|
587 |
✓✓ | 180 |
if (w != nullptr) |
588 |
{ |
||
589 |
125 |
const int wFrameSize = w->getFrameSize(); |
|
590 |
125 |
const int frame2 = 2 * wFrameSize; |
|
591 |
|||
592 |
125 |
w->setPosition(wFrameSize, wFrameSize); |
|
593 |
✓✓ | 125 |
if (mResizeHeight) |
594 |
{ |
||
595 |
244 |
w->setSize(mWidgetContainer->getWidth() - frame2, |
|
596 |
366 |
mWidgetContainer->getHeight() - frame2); |
|
597 |
} |
||
598 |
else |
||
599 |
{ |
||
600 |
6 |
w->setSize(mWidgetContainer->getWidth() - frame2, |
|
601 |
3 |
w->getHeight()); |
|
602 |
} |
||
603 |
} |
||
604 |
180 |
} |
|
605 |
|||
606 |
148 |
void TabbedArea::adjustTabPositions() |
|
607 |
{ |
||
608 |
148 |
int maxTabHeight = 0; |
|
609 |
296 |
const size_t sz = mTabs.size(); |
|
610 |
✓✓ | 695 |
for (size_t i = 0; i < sz; ++i) |
611 |
{ |
||
612 |
1094 |
const Tab *const tab = mTabs[i].first; |
|
613 |
✓✗✓✓ |
1094 |
if ((tab != nullptr) && |
614 |
✓✗✓✓ |
1094 |
tab->mVisible == Visible_true && |
615 |
1094 |
tab->getHeight() > maxTabHeight) |
|
616 |
{ |
||
617 |
238 |
maxTabHeight = tab->getHeight(); |
|
618 |
} |
||
619 |
} |
||
620 |
|||
621 |
✓✓ | 212 |
unsigned int x = (mEnableScrollButtons && |
622 |
✓✓ | 160 |
mArrowButton[0]->mVisible == Visible_true) ? |
623 |
172 |
mArrowButton[0]->getWidth() : 0U; |
|
624 |
✓✓ | 695 |
for (size_t i = mTabScrollIndex; i < sz; ++i) |
625 |
{ |
||
626 |
1094 |
Tab *const tab = mTabs[i].first; |
|
627 |
✓✗✓✗ |
547 |
if ((tab == nullptr) || tab->mVisible == Visible_false) |
628 |
continue; |
||
629 |
1094 |
tab->setPosition(x, maxTabHeight - tab->getHeight()); |
|
630 |
1094 |
x += tab->getWidth(); |
|
631 |
} |
||
632 |
|||
633 |
// If the tabs are scrolled, we hide them away. |
||
634 |
✗✓ | 148 |
if (mTabScrollIndex > 0) |
635 |
{ |
||
636 |
x = 0; |
||
637 |
for (unsigned i = 0; i < mTabScrollIndex; ++i) |
||
638 |
{ |
||
639 |
Tab *const tab = mTabs[i].first; |
||
640 |
if ((tab != nullptr) && tab->mVisible == Visible_true) |
||
641 |
{ |
||
642 |
x -= tab->getWidth(); |
||
643 |
tab->setPosition(x, maxTabHeight - tab->getHeight()); |
||
644 |
} |
||
645 |
} |
||
646 |
} |
||
647 |
148 |
} |
|
648 |
|||
649 |
void TabbedArea::action(const ActionEvent& actionEvent) |
||
650 |
{ |
||
651 |
Widget *const source = actionEvent.getSource(); |
||
652 |
Tab *const tab = dynamic_cast<Tab *>(source); |
||
653 |
|||
654 |
if (tab != nullptr) |
||
655 |
{ |
||
656 |
setSelectedTab(tab); |
||
657 |
} |
||
658 |
else |
||
659 |
{ |
||
660 |
const std::string &eventId = actionEvent.getId(); |
||
661 |
if (eventId == "shift_left") |
||
662 |
{ |
||
663 |
if (mTabScrollIndex != 0U) |
||
664 |
--mTabScrollIndex; |
||
665 |
} |
||
666 |
else if (eventId == "shift_right") |
||
667 |
{ |
||
668 |
if (CAST_SIZE(mTabScrollIndex) < mTabs.size() - 1) |
||
669 |
++mTabScrollIndex; |
||
670 |
} |
||
671 |
adjustTabPositions(); |
||
672 |
updateArrowEnableState(); |
||
673 |
} |
||
674 |
} |
||
675 |
|||
676 |
148 |
void TabbedArea::updateArrowEnableState() |
|
677 |
{ |
||
678 |
148 |
updateTabsWidth(); |
|
679 |
✓✗✓✗ |
148 |
if ((mArrowButton[0] == nullptr) || (mArrowButton[1] == nullptr)) |
680 |
return; |
||
681 |
|||
682 |
148 |
const int width = mDimension.width; |
|
683 |
✓✓ | 296 |
if (mTabsWidth > width - 4 |
684 |
296 |
- mArrowButton[0]->getWidth() |
|
685 |
296 |
- mArrowButton[1]->getWidth() - mRightMargin) |
|
686 |
{ |
||
687 |
64 |
mArrowButton[0]->setVisible(Visible_true); |
|
688 |
64 |
mArrowButton[1]->setVisible(Visible_true); |
|
689 |
} |
||
690 |
else |
||
691 |
{ |
||
692 |
84 |
mArrowButton[0]->setVisible(Visible_false); |
|
693 |
84 |
mArrowButton[1]->setVisible(Visible_false); |
|
694 |
84 |
mTabScrollIndex = 0; |
|
695 |
} |
||
696 |
|||
697 |
// Left arrow consistency check |
||
698 |
✓✗ | 148 |
if (mTabScrollIndex == 0U) |
699 |
148 |
mArrowButton[0]->setEnabled(false); |
|
700 |
else |
||
701 |
mArrowButton[0]->setEnabled(true); |
||
702 |
|||
703 |
// Right arrow consistency check |
||
704 |
✓✓ | 296 |
if (mVisibleTabsWidth < width - 4 |
705 |
296 |
- mArrowButton[0]->getWidth() |
|
706 |
296 |
- mArrowButton[1]->getWidth() - mRightMargin) |
|
707 |
{ |
||
708 |
84 |
mArrowButton[1]->setEnabled(false); |
|
709 |
} |
||
710 |
else |
||
711 |
{ |
||
712 |
64 |
mArrowButton[1]->setEnabled(true); |
|
713 |
} |
||
714 |
} |
||
715 |
|||
716 |
1 |
Tab *TabbedArea::getTabByIndex(const int index) const |
|
717 |
{ |
||
718 |
✓✗✓✗ ✗✓ |
2 |
if (index < 0 || index >= CAST_S32(mTabs.size())) |
719 |
return nullptr; |
||
720 |
return static_cast<Tab*>(mTabs[index].first); |
||
721 |
} |
||
722 |
|||
723 |
Widget *TabbedArea::getWidgetByIndex(const int index) const |
||
724 |
{ |
||
725 |
if (index < 0 || index >= CAST_S32(mTabs.size())) |
||
726 |
return nullptr; |
||
727 |
return mTabs[index].second; |
||
728 |
} |
||
729 |
|||
730 |
3 |
void TabbedArea::removeAll(const bool del) |
|
731 |
{ |
||
732 |
✓✓ | 3 |
if (getSelectedTabIndex() != -1) |
733 |
{ |
||
734 |
setSelectedTabByIndex(CAST_U32(0)); |
||
735 |
} |
||
736 |
✓✓ | 7 |
while (getNumberOfTabs() > 0) |
737 |
{ |
||
738 |
4 |
const int idx = getNumberOfTabs() - 1; |
|
739 |
8 |
Tab *tab = mTabs[idx].first; |
|
740 |
4 |
Widget *widget = mTabs[idx].second; |
|
741 |
4 |
removeTab(tab); |
|
742 |
✓✗ | 4 |
if (del) |
743 |
{ |
||
744 |
delete tab; |
||
745 |
delete widget; |
||
746 |
} |
||
747 |
} |
||
748 |
3 |
} |
|
749 |
|||
750 |
3 |
void TabbedArea::setWidth(int width) |
|
751 |
{ |
||
752 |
// +++ need use virtual |
||
753 |
3 |
Widget::setWidth(width); |
|
754 |
3 |
adjustSize(); |
|
755 |
3 |
} |
|
756 |
|||
757 |
3 |
void TabbedArea::setHeight(int height) |
|
758 |
{ |
||
759 |
// +++ need use virtual |
||
760 |
3 |
Widget::setHeight(height); |
|
761 |
3 |
adjustSize(); |
|
762 |
3 |
} |
|
763 |
|||
764 |
2 |
void TabbedArea::setSize(int width, int height) |
|
765 |
{ |
||
766 |
// +++ need use virtual |
||
767 |
2 |
Widget::setSize(width, height); |
|
768 |
2 |
adjustSize(); |
|
769 |
2 |
} |
|
770 |
|||
771 |
12 |
void TabbedArea::setDimension(const Rect &dimension) |
|
772 |
{ |
||
773 |
// +++ need use virtual |
||
774 |
12 |
Widget::setDimension(dimension); |
|
775 |
12 |
adjustSize(); |
|
776 |
12 |
} |
|
777 |
|||
778 |
void TabbedArea::keyPressed(KeyEvent& event) |
||
779 |
{ |
||
780 |
if (mBlockSwitching || event.isConsumed() || !isFocused()) |
||
781 |
return; |
||
782 |
|||
783 |
const InputActionT actionId = event.getActionId(); |
||
784 |
|||
785 |
if (actionId == InputAction::GUI_LEFT) |
||
786 |
{ |
||
787 |
int index = getSelectedTabIndex(); |
||
788 |
index--; |
||
789 |
|||
790 |
if (index < 0) |
||
791 |
return; |
||
792 |
|||
793 |
setSelectedTab(mTabs[index].first); |
||
794 |
event.consume(); |
||
795 |
} |
||
796 |
else if (actionId == InputAction::GUI_RIGHT) |
||
797 |
{ |
||
798 |
int index = getSelectedTabIndex(); |
||
799 |
index++; |
||
800 |
|||
801 |
if (index >= CAST_S32(mTabs.size())) |
||
802 |
return; |
||
803 |
|||
804 |
setSelectedTab(mTabs[index].first); |
||
805 |
event.consume(); |
||
806 |
} |
||
807 |
} |
||
808 |
|||
809 |
8 |
void TabbedArea::death(const Event &event) |
|
810 |
{ |
||
811 |
✓✗ | 8 |
Tab *const tab = dynamic_cast<Tab*>(event.getSource()); |
812 |
|||
813 |
✗✓ | 8 |
if (tab != nullptr) |
814 |
removeTab(tab); |
||
815 |
else |
||
816 |
8 |
BasicContainer::death(event); |
|
817 |
8 |
} |
|
818 |
|||
819 |
void TabbedArea::selectNextTab() |
||
820 |
{ |
||
821 |
int tab = getSelectedTabIndex(); |
||
822 |
tab++; |
||
823 |
if (tab == CAST_S32(mTabs.size())) |
||
824 |
tab = 0; |
||
825 |
setSelectedTab(mTabs[tab].first); |
||
826 |
} |
||
827 |
|||
828 |
void TabbedArea::selectPrevTab() |
||
829 |
{ |
||
830 |
int tab = getSelectedTabIndex(); |
||
831 |
|||
832 |
if (tab == 0) |
||
833 |
tab = CAST_S32(mTabs.size()); |
||
834 |
if (tab < 0) |
||
835 |
return; |
||
836 |
tab--; |
||
837 |
setSelectedTab(mTabs[tab].first); |
||
838 |
✓✗✓✗ |
3 |
} |
Generated by: GCOVR (Version 3.3) |