comparison ext/guichan-0.8.2/src/widgets/tabbedarea.cpp @ 378:64738befdf3b

bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author vtchill@33b003aa-7bff-0310-803a-e67f0ece8222
date Mon, 11 Jan 2010 23:34:52 +0000
parents
children
comparison
equal deleted inserted replaced
377:fe6fb0e0ed23 378:64738befdf3b
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 mOpaque(false)
65 {
66 setFocusable(true);
67 addKeyListener(this);
68 addMouseListener(this);
69
70 mTabContainer = new Container();
71 mTabContainer->setOpaque(false);
72 mWidgetContainer = new Container();
73
74 add(mTabContainer);
75 add(mWidgetContainer);
76 }
77
78 TabbedArea::~TabbedArea()
79 {
80 remove(mTabContainer);
81 remove(mWidgetContainer);
82
83 delete mTabContainer;
84 delete mWidgetContainer;
85
86 for (unsigned int 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::setOpaque(bool opaque)
254 {
255 mOpaque = opaque;
256 }
257
258 bool TabbedArea::isOpaque() const
259 {
260 return mOpaque;
261 }
262
263 void TabbedArea::draw(Graphics *graphics)
264 {
265 const Color &faceColor = getBaseColor();
266 const int alpha = getBaseColor().a;
267 Color highlightColor = faceColor + 0x303030;
268 highlightColor.a = alpha;
269 Color shadowColor = faceColor - 0x303030;
270 shadowColor.a = alpha;
271
272 // Draw a border.
273 graphics->setColor(highlightColor);
274 graphics->drawLine(0,
275 mTabContainer->getHeight(),
276 0,
277 getHeight() - 2);
278 graphics->setColor(shadowColor);
279 graphics->drawLine(getWidth() - 1,
280 mTabContainer->getHeight() + 1,
281 getWidth() - 1,
282 getHeight() - 1);
283 graphics->drawLine(1,
284 getHeight() - 1,
285 getWidth() - 1,
286 getHeight() - 1);
287
288 if (isOpaque())
289 {
290 graphics->setColor(getBaseColor());
291 graphics->fillRectangle(Rectangle(1, 1,
292 getWidth() - 2,
293 getHeight() - 2));
294 }
295
296 // Draw a line underneath the tabs.
297 graphics->setColor(highlightColor);
298 graphics->drawLine(1,
299 mTabContainer->getHeight(),
300 getWidth() - 1,
301 mTabContainer->getHeight());
302
303 // If a tab is selected, remove the line right underneath
304 // the selected tab.
305 if (mSelectedTab != NULL)
306 {
307 graphics->setColor(getBaseColor());
308 graphics->drawLine(mSelectedTab->getX() + 1,
309 mTabContainer->getHeight(),
310 mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
311 mTabContainer->getHeight());
312
313 }
314
315 drawChildren(graphics);
316 }
317
318 void TabbedArea::logic()
319 {
320 }
321
322 void TabbedArea::adjustSize()
323 {
324 int maxTabHeight = 0;
325
326 for (unsigned int i = 0; i < mTabs.size(); i++)
327 {
328 if (mTabs[i].first->getHeight() > maxTabHeight)
329 {
330 maxTabHeight = mTabs[i].first->getHeight();
331 }
332 }
333
334 mTabContainer->setSize(getWidth() - 2,
335 maxTabHeight);
336
337 mWidgetContainer->setPosition(1, maxTabHeight + 1);
338 mWidgetContainer->setSize(getWidth() - 2,
339 getHeight() - maxTabHeight - 2);
340 }
341
342 void TabbedArea::adjustTabPositions()
343 {
344 int maxTabHeight = 0;
345 unsigned int i;
346 for (i = 0; i < mTabs.size(); i++)
347 {
348 if (mTabs[i].first->getHeight() > maxTabHeight)
349 {
350 maxTabHeight = mTabs[i].first->getHeight();
351 }
352 }
353
354 int x = 0;
355 for (i = 0; i < mTabs.size(); i++)
356 {
357 Tab* tab = mTabs[i].first;
358 tab->setPosition(x, maxTabHeight - tab->getHeight());
359 x += tab->getWidth();
360 }
361 }
362
363 void TabbedArea::setWidth(int width)
364 {
365 Widget::setWidth(width);
366 adjustSize();
367 }
368
369 void TabbedArea::setHeight(int height)
370 {
371 Widget::setHeight(height);
372 adjustSize();
373 }
374
375 void TabbedArea::setSize(int width, int height)
376 {
377 Widget::setSize(width, height);
378 adjustSize();
379 }
380
381 void TabbedArea::setDimension(const Rectangle& dimension)
382 {
383 Widget::setDimension(dimension);
384 adjustSize();
385 }
386
387 void TabbedArea::keyPressed(KeyEvent& keyEvent)
388 {
389 if (keyEvent.isConsumed() || !isFocused())
390 {
391 return;
392 }
393
394 if (keyEvent.getKey().getValue() == Key::LEFT)
395 {
396 int index = getSelectedTabIndex();
397 index--;
398
399 if (index < 0)
400 {
401 return;
402 }
403 else
404 {
405 setSelectedTab(mTabs[index].first);
406 }
407
408 keyEvent.consume();
409 }
410 else if (keyEvent.getKey().getValue() == Key::RIGHT)
411 {
412 int index = getSelectedTabIndex();
413 index++;
414
415 if (index >= (int)mTabs.size())
416 {
417 return;
418 }
419 else
420 {
421 setSelectedTab(mTabs[index].first);
422 }
423
424 keyEvent.consume();
425 }
426 }
427
428
429 void TabbedArea::mousePressed(MouseEvent& mouseEvent)
430 {
431 if (mouseEvent.isConsumed())
432 {
433 return;
434 }
435
436 if (mouseEvent.getButton() == MouseEvent::LEFT)
437 {
438 Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
439 Tab* tab = dynamic_cast<Tab*>(widget);
440
441 if (tab != NULL)
442 {
443 setSelectedTab(tab);
444 }
445 }
446
447 // Request focus only if the source of the event
448 // is not focusble. If the source of the event
449 // is focused we don't want to steal the focus.
450 if (!mouseEvent.getSource()->isFocusable())
451 {
452 requestFocus();
453 }
454 }
455
456 void TabbedArea::death(const Event& event)
457 {
458 Tab* tab = dynamic_cast<Tab*>(event.getSource());
459
460 if (tab != NULL)
461 {
462 removeTab(tab);
463 }
464 else
465 {
466 BasicContainer::death(event);
467 }
468 }
469
470 void TabbedArea::action(const ActionEvent& actionEvent)
471 {
472 Widget* source = actionEvent.getSource();
473 Tab* tab = dynamic_cast<Tab*>(source);
474
475 if (tab == NULL)
476 {
477 throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
478 }
479
480 setSelectedTab(tab);
481 }
482 }