comparison ext/guichan-0.8.1/src/widgets/tabbedarea.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
1 /* _______ __ __ __ ______ __ __ _______ __ __
2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8 *
9 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
10 *
11 *
12 * Per Larsson a.k.a finalman
13 * Olof Naessén a.k.a jansem/yakslem
14 *
15 * Visit: http://guichan.sourceforge.net
16 *
17 * License: (BSD)
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in
25 * the documentation and/or other materials provided with the
26 * distribution.
27 * 3. Neither the name of Guichan nor the names of its contributors may
28 * be used to endorse or promote products derived from this software
29 * without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * For comments regarding functions please see the header file.
46 */
47
48 #include "guichan/widgets/tabbedarea.hpp"
49
50 #include "guichan/exception.hpp"
51 #include "guichan/focushandler.hpp"
52 #include "guichan/font.hpp"
53 #include "guichan/graphics.hpp"
54
55 #include "guichan/widgets/container.hpp"
56 #include "guichan/widgets/tab.hpp"
57
58 #include <algorithm>
59
60 namespace gcn
61 {
62 TabbedArea::TabbedArea()
63 :mSelectedTab(NULL)
64 {
65 setFocusable(true);
66 addKeyListener(this);
67 addMouseListener(this);
68
69 mTabContainer = new Container();
70 mTabContainer->setOpaque(false);
71 mWidgetContainer = new Container();
72
73 add(mTabContainer);
74 add(mWidgetContainer);
75 }
76
77 TabbedArea::~TabbedArea()
78 {
79 remove(mTabContainer);
80 remove(mWidgetContainer);
81
82 delete mTabContainer;
83 delete mWidgetContainer;
84
85 unsigned int i;
86 for (i = 0; i < mTabsToDelete.size(); i++)
87 {
88 delete mTabsToDelete[i];
89 }
90 }
91
92 void TabbedArea::addTab(const std::string& caption, Widget* widget)
93 {
94 Tab* tab = new Tab();
95 tab->setCaption(caption);
96 mTabsToDelete.push_back(tab);
97
98 addTab(tab, widget);
99 }
100
101 void TabbedArea::addTab(Tab* tab, Widget* widget)
102 {
103 tab->setTabbedArea(this);
104 tab->addActionListener(this);
105
106 mTabContainer->add(tab);
107 mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));
108
109 if (mSelectedTab == NULL)
110 {
111 setSelectedTab(tab);
112 }
113
114 adjustTabPositions();
115 adjustSize();
116 }
117
118 void TabbedArea::removeTabWithIndex(unsigned int index)
119 {
120 if (index >= mTabs.size())
121 {
122 throw GCN_EXCEPTION("No such tab index.");
123 }
124
125 removeTab(mTabs[index].first);
126 }
127
128 void TabbedArea::removeTab(Tab* tab)
129 {
130 int tabIndexToBeSelected = - 1;
131
132 if (tab == mSelectedTab)
133 {
134 int index = getSelectedTabIndex();
135
136 if (index == (int)mTabs.size() - 1
137 && mTabs.size() >= 2)
138 {
139 tabIndexToBeSelected = index--;
140 }
141 else if (index == (int)mTabs.size() - 1
142 && mTabs.size() == 1)
143 {
144 tabIndexToBeSelected = -1;
145 }
146 else
147 {
148 tabIndexToBeSelected = index;
149 }
150 }
151
152 std::vector<std::pair<Tab*, Widget*> >::iterator iter;
153 for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
154 {
155 if (iter->first == tab)
156 {
157 mTabContainer->remove(tab);
158 mTabs.erase(iter);
159 break;
160 }
161 }
162
163 std::vector<Tab*>::iterator iter2;
164 for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
165 {
166 if (*iter2 == tab)
167 {
168 mTabsToDelete.erase(iter2);
169 delete tab;
170 break;
171 }
172 }
173
174 if (tabIndexToBeSelected == -1)
175 {
176 mSelectedTab = NULL;
177 mWidgetContainer->clear();
178 }
179 else
180 {
181 setSelectedTab(tabIndexToBeSelected);
182 }
183
184 adjustSize();
185 adjustTabPositions();
186 }
187
188 bool TabbedArea::isTabSelected(unsigned int index) const
189 {
190 if (index >= mTabs.size())
191 {
192 throw GCN_EXCEPTION("No such tab index.");
193 }
194
195 return mSelectedTab == mTabs[index].first;
196 }
197
198 bool TabbedArea::isTabSelected(Tab* tab)
199 {
200 return mSelectedTab == tab;
201 }
202
203 void TabbedArea::setSelectedTab(unsigned int index)
204 {
205 if (index >= mTabs.size())
206 {
207 throw GCN_EXCEPTION("No such tab index.");
208 }
209
210 setSelectedTab(mTabs[index].first);
211 }
212
213 void TabbedArea::setSelectedTab(Tab* tab)
214 {
215 unsigned int i;
216 for (i = 0; i < mTabs.size(); i++)
217 {
218 if (mTabs[i].first == mSelectedTab)
219 {
220 mWidgetContainer->remove(mTabs[i].second);
221 }
222 }
223
224 for (i = 0; i < mTabs.size(); i++)
225 {
226 if (mTabs[i].first == tab)
227 {
228 mSelectedTab = tab;
229 mWidgetContainer->add(mTabs[i].second);
230 }
231 }
232 }
233
234 int TabbedArea::getSelectedTabIndex() const
235 {
236 unsigned int i;
237 for (i = 0; i < mTabs.size(); i++)
238 {
239 if (mTabs[i].first == mSelectedTab)
240 {
241 return i;
242 }
243 }
244
245 return -1;
246 }
247
248 Tab* TabbedArea::getSelectedTab()
249 {
250 return mSelectedTab;
251 }
252
253 void TabbedArea::draw(Graphics *graphics)
254 {
255 const Color &faceColor = getBaseColor();
256 const int alpha = getBaseColor().a;
257 Color highlightColor = faceColor + 0x303030;
258 highlightColor.a = alpha;
259 Color shadowColor = faceColor - 0x303030;
260 shadowColor.a = alpha;
261
262 // Draw a border.
263 graphics->setColor(highlightColor);
264 graphics->drawLine(0,
265 mTabContainer->getHeight(),
266 0,
267 getHeight() - 2);
268 graphics->setColor(shadowColor);
269 graphics->drawLine(getWidth() - 1,
270 mTabContainer->getHeight() + 1,
271 getWidth() - 1,
272 getHeight() - 1);
273 graphics->drawLine(1,
274 getHeight() - 1,
275 getWidth() - 1,
276 getHeight() - 1);
277
278 graphics->setColor(getBaseColor());
279 graphics->fillRectangle(Rectangle(1, 1, getWidth() - 2, getHeight() - 2));
280
281
282 // Draw a line underneath the tabs.
283 graphics->setColor(highlightColor);
284 graphics->drawLine(1,
285 mTabContainer->getHeight(),
286 getWidth() - 1,
287 mTabContainer->getHeight());
288
289 // If a tab is selected, remove the line right underneath
290 // the selected tab.
291 if (mSelectedTab != NULL)
292 {
293 graphics->setColor(getBaseColor());
294 graphics->drawLine(mSelectedTab->getX() + 1,
295 mTabContainer->getHeight(),
296 mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
297 mTabContainer->getHeight());
298
299 }
300
301 drawChildren(graphics);
302 }
303
304 void TabbedArea::logic()
305 {
306
307 }
308
309 void TabbedArea::adjustSize()
310 {
311 int maxTabHeight = 0;
312 unsigned int i;
313 for (i = 0; i < mTabs.size(); i++)
314 {
315 if (mTabs[i].first->getHeight() > maxTabHeight)
316 {
317 maxTabHeight = mTabs[i].first->getHeight();
318 }
319 }
320
321 mTabContainer->setSize(getWidth() - 2,
322 maxTabHeight);
323
324 mWidgetContainer->setPosition(1, maxTabHeight + 1);
325 mWidgetContainer->setSize(getWidth() - 2,
326 getHeight() - maxTabHeight - 2);
327 }
328
329 void TabbedArea::adjustTabPositions()
330 {
331 int maxTabHeight = 0;
332 unsigned int i;
333 for (i = 0; i < mTabs.size(); i++)
334 {
335 if (mTabs[i].first->getHeight() > maxTabHeight)
336 {
337 maxTabHeight = mTabs[i].first->getHeight();
338 }
339 }
340
341 int x = 0;
342 for (i = 0; i < mTabs.size(); i++)
343 {
344 Tab* tab = mTabs[i].first;
345 tab->setPosition(x, maxTabHeight - tab->getHeight());
346 x += tab->getWidth();
347 }
348 }
349
350 void TabbedArea::setWidth(int width)
351 {
352 Widget::setWidth(width);
353 adjustSize();
354 }
355
356
357 void TabbedArea::setHeight(int height)
358 {
359 Widget::setHeight(height);
360 adjustSize();
361 }
362
363 void TabbedArea::setSize(int width, int height)
364 {
365 setWidth(width);
366 setHeight(height);
367 }
368
369 void TabbedArea::setDimension(const Rectangle& dimension)
370 {
371 setX(dimension.x);
372 setY(dimension.y);
373 setWidth(dimension.width);
374 setHeight(dimension.height);
375 }
376
377 void TabbedArea::keyPressed(KeyEvent& keyEvent)
378 {
379 if (keyEvent.isConsumed() || !isFocused())
380 {
381 return;
382 }
383
384 if (keyEvent.getKey().getValue() == Key::LEFT)
385 {
386 int index = getSelectedTabIndex();
387 index--;
388
389 if (index < 0)
390 {
391 return;
392 }
393 else
394 {
395 setSelectedTab(mTabs[index].first);
396 }
397
398 keyEvent.consume();
399 }
400 else if (keyEvent.getKey().getValue() == Key::RIGHT)
401 {
402 int index = getSelectedTabIndex();
403 index++;
404
405 if (index >= (int)mTabs.size())
406 {
407 return;
408 }
409 else
410 {
411 setSelectedTab(mTabs[index].first);
412 }
413
414 keyEvent.consume();
415 }
416 }
417
418
419 void TabbedArea::mousePressed(MouseEvent& mouseEvent)
420 {
421 if (mouseEvent.isConsumed()
422 && mouseEvent.getSource()->isFocusable())
423 {
424 return;
425 }
426
427 if (mouseEvent.getButton() == MouseEvent::LEFT)
428 {
429 Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
430 Tab* tab = dynamic_cast<Tab*>(widget);
431
432 if (tab != NULL)
433 {
434 setSelectedTab(tab);
435 }
436 }
437
438 requestFocus();
439 }
440
441 void TabbedArea::death(const Event& event)
442 {
443 Widget* source = event.getSource();
444 Tab* tab = dynamic_cast<Tab*>(source);
445
446 if (tab != NULL)
447 {
448 removeTab(tab);
449 }
450 else
451 {
452 BasicContainer::death(event);
453 }
454 }
455
456 void TabbedArea::action(const ActionEvent& actionEvent)
457 {
458 Widget* source = actionEvent.getSource();
459 Tab* tab = dynamic_cast<Tab*>(source);
460
461 if (tab == NULL)
462 {
463 throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
464 }
465
466 setSelectedTab(tab);
467 }
468 }