]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CGUITabControl.cpp
30a31c39bb67f4792b6647fda411748bb154d661
[irrlicht.git] / source / Irrlicht / CGUITabControl.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CGUITabControl.h"\r
6 #ifdef _IRR_COMPILE_WITH_GUI_\r
7 \r
8 #include "CGUIButton.h"\r
9 #include "IGUISkin.h"\r
10 #include "IGUIEnvironment.h"\r
11 #include "IGUIFont.h"\r
12 #include "IVideoDriver.h"\r
13 #include "rect.h"\r
14 #include "os.h"\r
15 \r
16 namespace irr\r
17 {\r
18 namespace gui\r
19 {\r
20 \r
21 // ------------------------------------------------------------------\r
22 // Tab\r
23 // ------------------------------------------------------------------\r
24 \r
25 //! constructor\r
26 CGUITab::CGUITab(IGUIEnvironment* environment,\r
27         IGUIElement* parent, const core::rect<s32>& rectangle,\r
28         s32 id)\r
29         : IGUITab(environment, parent, id, rectangle),\r
30                 BackColor(0,0,0,0), OverrideTextColorEnabled(false), TextColor(255,0,0,0),\r
31                 DrawBackground(false)\r
32 {\r
33         #ifdef _DEBUG\r
34         setDebugName("CGUITab");\r
35         #endif\r
36 \r
37         const IGUISkin* const skin = environment->getSkin();\r
38         if (skin)\r
39                 TextColor = skin->getColor(EGDC_BUTTON_TEXT);\r
40 }\r
41 \r
42 //! draws the element and its children\r
43 void CGUITab::draw()\r
44 {\r
45         if (!IsVisible)\r
46                 return;\r
47 \r
48         IGUISkin *skin = Environment->getSkin();\r
49 \r
50         if (skin && DrawBackground)\r
51                 skin->draw2DRectangle(this, BackColor, AbsoluteRect, &AbsoluteClippingRect);\r
52 \r
53         IGUIElement::draw();\r
54 }\r
55 \r
56 \r
57 //! sets if the tab should draw its background\r
58 void CGUITab::setDrawBackground(bool draw)\r
59 {\r
60         DrawBackground = draw;\r
61 }\r
62 \r
63 \r
64 //! sets the color of the background, if it should be drawn.\r
65 void CGUITab::setBackgroundColor(video::SColor c)\r
66 {\r
67         BackColor = c;\r
68 }\r
69 \r
70 \r
71 //! sets the color of the text\r
72 void CGUITab::setTextColor(video::SColor c)\r
73 {\r
74         OverrideTextColorEnabled = true;\r
75         TextColor = c;\r
76 }\r
77 \r
78 \r
79 video::SColor CGUITab::getTextColor() const\r
80 {\r
81         if ( OverrideTextColorEnabled )\r
82                 return TextColor;\r
83         else\r
84                 return Environment->getSkin()->getColor(EGDC_BUTTON_TEXT);\r
85 }\r
86 \r
87 //! returns true if the tab is drawing its background, false if not\r
88 bool CGUITab::isDrawingBackground() const\r
89 {\r
90         return DrawBackground;\r
91 }\r
92 \r
93 \r
94 //! returns the color of the background\r
95 video::SColor CGUITab::getBackgroundColor() const\r
96 {\r
97         return BackColor;\r
98 }\r
99 \r
100 \r
101 // ------------------------------------------------------------------\r
102 // Tabcontrol\r
103 // ------------------------------------------------------------------\r
104 \r
105 //! constructor\r
106 CGUITabControl::CGUITabControl(IGUIEnvironment* environment,\r
107         IGUIElement* parent, const core::rect<s32>& rectangle,\r
108         bool fillbackground, bool border, s32 id)\r
109         : IGUITabControl(environment, parent, id, rectangle), ActiveTabIndex(-1),\r
110         Border(border), FillBackground(fillbackground), ScrollControl(false), TabHeight(0), VerticalAlignment(EGUIA_UPPERLEFT),\r
111         UpButton(0), DownButton(0), TabMaxWidth(0), CurrentScrollTabIndex(0), TabExtraWidth(20)\r
112 {\r
113         #ifdef _DEBUG\r
114         setDebugName("CGUITabControl");\r
115         #endif\r
116 \r
117         IGUISkin* skin = Environment->getSkin();\r
118         IGUISpriteBank* sprites = 0;\r
119 \r
120         TabHeight = 32;\r
121 \r
122         if (skin)\r
123         {\r
124                 sprites = skin->getSpriteBank();\r
125                 TabHeight = skin->getSize(gui::EGDS_BUTTON_HEIGHT) + 2;\r
126         }\r
127 \r
128         UpButton = Environment->addButton(core::rect<s32>(0,0,10,10), this);\r
129 \r
130         if (UpButton)\r
131         {\r
132                 UpButton->setSpriteBank(sprites);\r
133                 UpButton->setVisible(false);\r
134                 UpButton->setSubElement(true);\r
135                 UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);\r
136                 UpButton->setOverrideFont(Environment->getBuiltInFont());\r
137                 UpButton->grab();\r
138         }\r
139 \r
140         DownButton = Environment->addButton(core::rect<s32>(0,0,10,10), this);\r
141 \r
142         if (DownButton)\r
143         {\r
144                 DownButton->setSpriteBank(sprites);\r
145                 DownButton->setVisible(false);\r
146                 DownButton->setSubElement(true);\r
147                 DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);\r
148                 DownButton->setOverrideFont(Environment->getBuiltInFont());\r
149                 DownButton->grab();\r
150         }\r
151 \r
152         setTabVerticalAlignment(EGUIA_UPPERLEFT);\r
153         refreshSprites();\r
154 }\r
155 \r
156 //! destructor\r
157 CGUITabControl::~CGUITabControl()\r
158 {\r
159         for (u32 i=0; i<Tabs.size(); ++i)\r
160         {\r
161                 if (Tabs[i])\r
162                         Tabs[i]->drop();\r
163         }\r
164 \r
165         if (UpButton)\r
166                 UpButton->drop();\r
167 \r
168         if (DownButton)\r
169                 DownButton->drop();\r
170 }\r
171 \r
172 void CGUITabControl::refreshSprites()\r
173 {\r
174         video::SColor color(255,255,255,255);\r
175         IGUISkin* skin = Environment->getSkin();\r
176         if (skin)\r
177         {\r
178                 color = skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL);\r
179 \r
180                 if (UpButton)\r
181                 {\r
182                         UpButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_LEFT), color);\r
183                         UpButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_LEFT), color);\r
184                 }\r
185 \r
186                 if (DownButton)\r
187                 {\r
188                         DownButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_RIGHT), color);\r
189                         DownButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_RIGHT), color);\r
190                 }\r
191         }\r
192 }\r
193 \r
194 //! Adds a tab\r
195 IGUITab* CGUITabControl::addTab(const wchar_t* caption, s32 id)\r
196 {\r
197         CGUITab* tab = new CGUITab(Environment, this, calcTabPos(), id);\r
198 \r
199         tab->setText(caption);\r
200         tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);\r
201         tab->setVisible(false);\r
202         Tabs.push_back(tab);    // no grab as new already creates a reference\r
203 \r
204         if (ActiveTabIndex == -1)\r
205         {\r
206                 ActiveTabIndex = Tabs.size()-1;\r
207                 tab->setVisible(true);\r
208         }\r
209 \r
210         recalculateScrollBar();\r
211 \r
212         return tab;\r
213 }\r
214 \r
215 \r
216 //! adds a tab which has been created elsewhere\r
217 s32 CGUITabControl::addTab(IGUITab* tab)\r
218 {\r
219         return insertTab( Tabs.size(), tab, false);\r
220 }\r
221 \r
222 //! Insert the tab at the given index\r
223 IGUITab* CGUITabControl::insertTab(s32 idx, const wchar_t* caption, s32 id)\r
224 {\r
225         if ( idx < 0 || idx > (s32)Tabs.size() )        // idx == Tabs.size() is indeed OK here as core::array can handle that\r
226                 return NULL;\r
227 \r
228         CGUITab* tab = new CGUITab(Environment, this, calcTabPos(), id);\r
229 \r
230         tab->setText(caption);\r
231         tab->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);\r
232         tab->setVisible(false);\r
233         Tabs.insert(tab, (u32)idx);\r
234 \r
235         if (ActiveTabIndex == -1)\r
236         {\r
237                 ActiveTabIndex = (u32)idx;\r
238                 tab->setVisible(true);\r
239         }\r
240         else if ( idx <= ActiveTabIndex )\r
241         {\r
242                 ++ActiveTabIndex;\r
243                 setVisibleTab(ActiveTabIndex);\r
244         }\r
245 \r
246         recalculateScrollBar();\r
247 \r
248         return tab;\r
249 }\r
250 \r
251 s32 CGUITabControl::insertTab(s32 idx, IGUITab* tab, bool serializationMode)\r
252 {\r
253         if (!tab)\r
254                 return -1;\r
255         if ( idx > (s32)Tabs.size() && !serializationMode )     // idx == Tabs.size() is indeed OK here as core::array can handle that\r
256                 return -1;\r
257         // Not allowing to add same tab twice as it would make things complicated (serialization or setting active visible)\r
258         if ( getTabIndex(tab) >= 0 )\r
259                 return -1;\r
260 \r
261         if ( idx < 0 )\r
262                 idx = (s32)Tabs.size();\r
263 \r
264         if ( tab->getParent() != this )\r
265                 this->addChildToEnd(tab);\r
266 \r
267         tab->setVisible(false);\r
268 \r
269         tab->grab();\r
270 \r
271         if ( serializationMode)\r
272         {\r
273                 while ( idx >= (s32)Tabs.size() )\r
274                 {\r
275                         Tabs.push_back(0);\r
276                 }\r
277                 Tabs[idx] = tab;\r
278 \r
279                 if ( idx == ActiveTabIndex)     // in serialization that can happen for any index\r
280                 {\r
281                         setVisibleTab(ActiveTabIndex);\r
282                         tab->setVisible(true);\r
283                 }\r
284         }\r
285         else\r
286         {\r
287                 Tabs.insert(tab, (u32)idx);\r
288 \r
289                 if (ActiveTabIndex == -1)\r
290                 {\r
291                         ActiveTabIndex = idx;\r
292                         setVisibleTab(ActiveTabIndex);\r
293                 }\r
294                 else if ( idx <= ActiveTabIndex)\r
295                 {\r
296                         ++ActiveTabIndex;\r
297                         setVisibleTab(ActiveTabIndex);\r
298                 }\r
299         }\r
300 \r
301         recalculateScrollBar();\r
302 \r
303         return idx;\r
304 }\r
305 \r
306 //! Removes a child.\r
307 void CGUITabControl::removeChild(IGUIElement* child)\r
308 {\r
309         s32 idx = getTabIndex(child);\r
310         if ( idx >= 0 )\r
311                 removeTabButNotChild(idx);\r
312 \r
313         // remove real element\r
314         IGUIElement::removeChild(child);\r
315 \r
316         recalculateScrollBar();\r
317 }\r
318 \r
319 \r
320 //! Removes a tab from the tabcontrol\r
321 void CGUITabControl::removeTab(s32 idx)\r
322 {\r
323         if ( idx < 0 || idx >= (s32)Tabs.size() )\r
324                 return;\r
325 \r
326         removeChild(Tabs[(u32)idx]);\r
327 }\r
328 \r
329 void CGUITabControl::removeTabButNotChild(s32 idx)\r
330 {\r
331         if ( idx < 0 || idx >= (s32)Tabs.size() )\r
332                 return;\r
333 \r
334         Tabs[(u32)idx]->drop();\r
335         Tabs.erase((u32)idx);\r
336 \r
337         if ( idx < ActiveTabIndex )\r
338         {\r
339                 --ActiveTabIndex;\r
340                 setVisibleTab(ActiveTabIndex);\r
341         }\r
342         else if ( idx == ActiveTabIndex )\r
343         {\r
344                 if ( (u32)idx == Tabs.size() )\r
345                         --ActiveTabIndex;\r
346                 setVisibleTab(ActiveTabIndex);\r
347         }\r
348 }\r
349 \r
350 //! Clears the tabcontrol removing all tabs\r
351 void CGUITabControl::clear()\r
352 {\r
353         for (u32 i=0; i<Tabs.size(); ++i)\r
354         {\r
355                 if (Tabs[i])\r
356                 {\r
357                         IGUIElement::removeChild(Tabs[i]);\r
358                         Tabs[i]->drop();\r
359                 }\r
360         }\r
361         Tabs.clear();\r
362 \r
363         recalculateScrollBar();\r
364 }\r
365 \r
366 //! Returns amount of tabs in the tabcontrol\r
367 s32 CGUITabControl::getTabCount() const\r
368 {\r
369         return Tabs.size();\r
370 }\r
371 \r
372 \r
373 //! Returns a tab based on zero based index\r
374 IGUITab* CGUITabControl::getTab(s32 idx) const\r
375 {\r
376         if (idx < 0 || (u32)idx >= Tabs.size())\r
377                 return 0;\r
378 \r
379         return Tabs[idx];\r
380 }\r
381 \r
382 \r
383 //! called if an event happened.\r
384 bool CGUITabControl::OnEvent(const SEvent& event)\r
385 {\r
386         if (isEnabled())\r
387         {\r
388                 switch(event.EventType)\r
389                 {\r
390                 case EET_GUI_EVENT:\r
391                         switch(event.GUIEvent.EventType)\r
392                         {\r
393                         case EGET_BUTTON_CLICKED:\r
394                                 if (event.GUIEvent.Caller == UpButton)\r
395                                 {\r
396                                         scrollLeft();\r
397                                         return true;\r
398                                 }\r
399                                 else if (event.GUIEvent.Caller == DownButton)\r
400                                 {\r
401                                         scrollRight();\r
402                                         return true;\r
403                                 }\r
404 \r
405                         break;\r
406                         default:\r
407                         break;\r
408                         }\r
409                         break;\r
410                 case EET_MOUSE_INPUT_EVENT:\r
411                         switch(event.MouseInput.Event)\r
412                         {\r
413                         //case EMIE_LMOUSE_PRESSED_DOWN:\r
414                         //      // todo: dragging tabs around\r
415                         //      return true;\r
416                         case EMIE_LMOUSE_LEFT_UP:\r
417                         {\r
418                                 s32 idx = getTabAt(event.MouseInput.X, event.MouseInput.Y);\r
419                                 if ( idx >= 0 )\r
420                                 {\r
421                                         setActiveTab(idx);\r
422                                         return true;\r
423                                 }\r
424                                 break;\r
425                         }\r
426                         default:\r
427                                 break;\r
428                         }\r
429                         break;\r
430                 default:\r
431                         break;\r
432                 }\r
433         }\r
434 \r
435         return IGUIElement::OnEvent(event);\r
436 }\r
437 \r
438 \r
439 void CGUITabControl::scrollLeft()\r
440 {\r
441         if ( CurrentScrollTabIndex > 0 )\r
442                 --CurrentScrollTabIndex;\r
443         recalculateScrollBar();\r
444 }\r
445 \r
446 \r
447 void CGUITabControl::scrollRight()\r
448 {\r
449         if ( CurrentScrollTabIndex < (s32)(Tabs.size()) - 1 )\r
450         {\r
451                 if ( needScrollControl(CurrentScrollTabIndex, true) )\r
452                         ++CurrentScrollTabIndex;\r
453         }\r
454         recalculateScrollBar();\r
455 }\r
456 \r
457 s32 CGUITabControl::calcTabWidth(IGUIFont* font, const wchar_t* text) const\r
458 {\r
459         if ( !font )\r
460                 return 0;\r
461 \r
462         s32 len = font->getDimension(text).Width + TabExtraWidth;\r
463         if ( TabMaxWidth > 0 && len > TabMaxWidth )\r
464                 len = TabMaxWidth;\r
465 \r
466         return len;\r
467 }\r
468 \r
469 bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl, s32 *pos_rightmost)\r
470 {\r
471         if ( startIndex < 0 )\r
472                 startIndex = 0;\r
473 \r
474         IGUISkin* skin = Environment->getSkin();\r
475         if (!skin)\r
476                 return false;\r
477 \r
478         IGUIFont* font = skin->getFont();\r
479 \r
480         if (Tabs.empty())\r
481                 return false;\r
482 \r
483         if (!font)\r
484                 return false;\r
485 \r
486         s32 pos = AbsoluteRect.UpperLeftCorner.X + 2;\r
487         const s32 pos_right = withScrollControl ?\r
488                 UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 :\r
489                 AbsoluteRect.LowerRightCorner.X;\r
490 \r
491         for (s32 i = startIndex; i < (s32)Tabs.size(); ++i)\r
492         {\r
493                 // get Text\r
494                 const wchar_t* text = 0;\r
495                 if (Tabs[i])\r
496                 {\r
497                         text = Tabs[i]->getText();\r
498 \r
499                         // get text length\r
500                         s32 len = calcTabWidth(font, text);     // always without withScrollControl here or len would be shortened\r
501                         pos += len;\r
502                 }\r
503 \r
504                 if (pos > pos_right)\r
505                         return true;\r
506         }\r
507 \r
508         if (pos_rightmost)\r
509                 *pos_rightmost = pos;\r
510         return false;\r
511 }\r
512 \r
513 \r
514 s32 CGUITabControl::calculateScrollIndexFromActive()\r
515 {\r
516         if (!ScrollControl || Tabs.empty())\r
517                 return 0;\r
518 \r
519         IGUISkin *skin = Environment->getSkin();\r
520         if (!skin)\r
521                 return false;\r
522 \r
523         IGUIFont *font = skin->getFont();\r
524         if (!font)\r
525                 return false;\r
526 \r
527         const s32 pos_left = AbsoluteRect.UpperLeftCorner.X + 2;\r
528         const s32 pos_right = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2;\r
529 \r
530         // Move from center to the left border left until it is reached\r
531         s32 pos_cl = (pos_left + pos_right) / 2;\r
532         s32 i = ActiveTabIndex;\r
533         for (; i > 0; --i) {\r
534                 if (!Tabs[i])\r
535                         continue;\r
536 \r
537                 s32 len = calcTabWidth(font, Tabs[i]->getText());\r
538                 if (i == ActiveTabIndex)\r
539                         len /= 2;\r
540                 if (pos_cl - len < pos_left)\r
541                         break;\r
542 \r
543                 pos_cl -= len;\r
544         }\r
545         if (i == 0)\r
546                 return i;\r
547 \r
548         // Is scrolling to right still possible?\r
549         s32 pos_rr = 0;\r
550         if (needScrollControl(i, true, &pos_rr))\r
551                 return i; // Yes? -> OK\r
552 \r
553         // No? -> Decrease "i" more. Append tabs until scrolling becomes necessary\r
554         for (--i; i > 0; --i) {\r
555                 if (!Tabs[i])\r
556                         continue;\r
557 \r
558                 pos_rr += calcTabWidth(font, Tabs[i]->getText());\r
559                 if (pos_rr > pos_right)\r
560                         break;\r
561         }\r
562         return i + 1;\r
563 }\r
564 \r
565 core::rect<s32> CGUITabControl::calcTabPos()\r
566 {\r
567         core::rect<s32> r;\r
568         r.UpperLeftCorner.X = 0;\r
569         r.LowerRightCorner.X = AbsoluteRect.getWidth();\r
570         if ( Border )\r
571         {\r
572                 ++r.UpperLeftCorner.X;\r
573                 --r.LowerRightCorner.X;\r
574         }\r
575 \r
576         if ( VerticalAlignment == EGUIA_UPPERLEFT )\r
577         {\r
578                 r.UpperLeftCorner.Y = TabHeight+2;\r
579                 r.LowerRightCorner.Y = AbsoluteRect.getHeight()-1;\r
580                 if ( Border )\r
581                 {\r
582                         --r.LowerRightCorner.Y;\r
583                 }\r
584         }\r
585         else\r
586         {\r
587                 r.UpperLeftCorner.Y = 0;\r
588                 r.LowerRightCorner.Y = AbsoluteRect.getHeight()-(TabHeight+2);\r
589                 if ( Border )\r
590                 {\r
591                         ++r.UpperLeftCorner.Y;\r
592                 }\r
593         }\r
594 \r
595         return r;\r
596 }\r
597 \r
598 \r
599 //! draws the element and its children\r
600 void CGUITabControl::draw()\r
601 {\r
602         if (!IsVisible)\r
603                 return;\r
604 \r
605         IGUISkin* skin = Environment->getSkin();\r
606         if (!skin)\r
607                 return;\r
608 \r
609         IGUIFont* font = skin->getFont();\r
610         video::IVideoDriver* driver = Environment->getVideoDriver();\r
611 \r
612         core::rect<s32> frameRect(AbsoluteRect);\r
613 \r
614         // some empty background as placeholder when there are no tabs\r
615         if (Tabs.empty())\r
616                 driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), frameRect, &AbsoluteClippingRect);\r
617 \r
618         if (!font)\r
619                 return;\r
620 \r
621         // tab button bar can be above or below the tabs\r
622         if ( VerticalAlignment == EGUIA_UPPERLEFT )\r
623         {\r
624                 frameRect.UpperLeftCorner.Y += 2;\r
625                 frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight;\r
626         }\r
627         else\r
628         {\r
629                 frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight - 1;\r
630                 frameRect.LowerRightCorner.Y -= 2;\r
631         }\r
632 \r
633         core::rect<s32> tr;\r
634         s32 pos = frameRect.UpperLeftCorner.X + 2;\r
635 \r
636         bool needLeftScroll = CurrentScrollTabIndex > 0;\r
637         bool needRightScroll = false;\r
638 \r
639         // left and right pos of the active tab\r
640         s32 left = 0;\r
641         s32 right = 0;\r
642 \r
643         //const wchar_t* activetext = 0;\r
644         IGUITab *activeTab = 0;\r
645 \r
646         // Draw all tab-buttons except the active one\r
647         for (u32 i = CurrentScrollTabIndex; i < Tabs.size() && !needRightScroll; ++i)\r
648         {\r
649                 // get Text\r
650                 const wchar_t* text = 0;\r
651                 if (Tabs[i])\r
652                         text = Tabs[i]->getText();\r
653 \r
654                 // get text length\r
655                 s32 len = calcTabWidth(font, text);\r
656                 if (ScrollControl) {\r
657                         s32 space = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos;\r
658                         if (space < len) {\r
659                                 needRightScroll = true;\r
660                                 len = space;\r
661                         }\r
662                 }\r
663 \r
664                 frameRect.LowerRightCorner.X += len;\r
665                 frameRect.UpperLeftCorner.X = pos;\r
666                 frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;\r
667 \r
668                 pos += len;\r
669 \r
670                 if ((s32)i == ActiveTabIndex)\r
671                 {\r
672                         // for active button just remember values\r
673                         left = frameRect.UpperLeftCorner.X;\r
674                         right = frameRect.LowerRightCorner.X;\r
675                         //activetext = text;\r
676                         activeTab = Tabs[i];\r
677                 }\r
678                 else\r
679                 {\r
680                         skin->draw3DTabButton(this, false, frameRect, &AbsoluteClippingRect, VerticalAlignment);\r
681 \r
682                         // draw text\r
683                         core::rect<s32> textClipRect(frameRect);        // TODO: exact size depends on borders in draw3DTabButton which we don't get with current interface\r
684                         textClipRect.clipAgainst(AbsoluteClippingRect);\r
685                         font->draw(text, frameRect, Tabs[i]->getTextColor(),\r
686                                 true, true, &textClipRect);\r
687                 }\r
688         }\r
689 \r
690         // Draw active tab button\r
691         // Drawn later than other buttons because it draw over the buttons before/after it.\r
692         if (left != 0 && right != 0 && activeTab != 0)\r
693         {\r
694                 // draw upper highlight frame\r
695                 if ( VerticalAlignment == EGUIA_UPPERLEFT )\r
696                 {\r
697                         frameRect.UpperLeftCorner.X = left-2;\r
698                         frameRect.LowerRightCorner.X = right+2;\r
699                         frameRect.UpperLeftCorner.Y -= 2;\r
700 \r
701                         skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment);\r
702 \r
703                         // draw text\r
704                         core::rect<s32> textClipRect(frameRect);        // TODO: exact size depends on borders in draw3DTabButton which we don't get with current interface\r
705                         textClipRect.clipAgainst(AbsoluteClippingRect);\r
706                         font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(),\r
707                                 true, true, &textClipRect);\r
708 \r
709                         tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X;\r
710                         tr.LowerRightCorner.X = left - 1;\r
711                         tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1;\r
712                         tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y;\r
713                         driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);\r
714 \r
715                         tr.UpperLeftCorner.X = right;\r
716                         tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;\r
717                         driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);\r
718                 }\r
719                 else\r
720                 {\r
721                         frameRect.UpperLeftCorner.X = left-2;\r
722                         frameRect.LowerRightCorner.X = right+2;\r
723                         frameRect.LowerRightCorner.Y += 2;\r
724 \r
725                         skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment);\r
726 \r
727                         // draw text\r
728                         font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(),\r
729                                 true, true, &frameRect);\r
730 \r
731                         tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X;\r
732                         tr.LowerRightCorner.X = left - 1;\r
733                         tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1;\r
734                         tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y;\r
735                         driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect);\r
736 \r
737                         tr.UpperLeftCorner.X = right;\r
738                         tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;\r
739                         driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect);\r
740                 }\r
741         }\r
742         else\r
743         {\r
744                 // No active tab\r
745                 // Draw a line separating button bar from tab area\r
746                 tr.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X;\r
747                 tr.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;\r
748                 tr.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - 1;\r
749                 tr.LowerRightCorner.Y = frameRect.LowerRightCorner.Y;\r
750 \r
751                 if ( VerticalAlignment == EGUIA_UPPERLEFT )\r
752                 {\r
753                         driver->draw2DRectangle(skin->getColor(EGDC_3D_HIGH_LIGHT), tr, &AbsoluteClippingRect);\r
754                 }\r
755                 else\r
756                 {\r
757                         tr.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - 1;\r
758                         tr.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y;\r
759                         driver->draw2DRectangle(skin->getColor(EGDC_3D_DARK_SHADOW), tr, &AbsoluteClippingRect);\r
760                 }\r
761         }\r
762 \r
763         // drawing some border and background for the tab-area.\r
764         skin->draw3DTabBody(this, Border, FillBackground, AbsoluteRect, &AbsoluteClippingRect, TabHeight, VerticalAlignment);\r
765 \r
766         // enable scrollcontrols on need\r
767         if ( UpButton )\r
768                 UpButton->setEnabled(needLeftScroll);\r
769         if ( DownButton )\r
770                 DownButton->setEnabled(needRightScroll);\r
771         refreshSprites();\r
772 \r
773         IGUIElement::draw();\r
774 }\r
775 \r
776 \r
777 //! Set the height of the tabs\r
778 void CGUITabControl::setTabHeight( s32 height )\r
779 {\r
780         if ( height < 0 )\r
781                 height = 0;\r
782 \r
783         TabHeight = height;\r
784 \r
785         recalculateScrollButtonPlacement();\r
786         recalculateScrollBar();\r
787 }\r
788 \r
789 \r
790 //! Get the height of the tabs\r
791 s32 CGUITabControl::getTabHeight() const\r
792 {\r
793         return TabHeight;\r
794 }\r
795 \r
796 //! set the maximal width of a tab. Per default width is 0 which means "no width restriction".\r
797 void CGUITabControl::setTabMaxWidth(s32 width )\r
798 {\r
799         TabMaxWidth = width;\r
800 }\r
801 \r
802 //! get the maximal width of a tab\r
803 s32 CGUITabControl::getTabMaxWidth() const\r
804 {\r
805         return TabMaxWidth;\r
806 }\r
807 \r
808 \r
809 //! Set the extra width added to tabs on each side of the text\r
810 void CGUITabControl::setTabExtraWidth( s32 extraWidth )\r
811 {\r
812         if ( extraWidth < 0 )\r
813                 extraWidth = 0;\r
814 \r
815         TabExtraWidth = extraWidth;\r
816 \r
817         recalculateScrollBar();\r
818 }\r
819 \r
820 \r
821 //! Get the extra width added to tabs on each side of the text\r
822 s32 CGUITabControl::getTabExtraWidth() const\r
823 {\r
824         return TabExtraWidth;\r
825 }\r
826 \r
827 \r
828 void CGUITabControl::recalculateScrollBar()\r
829 {\r
830         // Down: to right, Up: to left\r
831         if (!UpButton || !DownButton)\r
832                 return;\r
833 \r
834         ScrollControl = needScrollControl() || CurrentScrollTabIndex > 0;\r
835 \r
836         if (ScrollControl)\r
837         {\r
838                 UpButton->setVisible( true );\r
839                 DownButton->setVisible( true );\r
840         }\r
841         else\r
842         {\r
843                 UpButton->setVisible( false );\r
844                 DownButton->setVisible( false );\r
845         }\r
846 \r
847         bringToFront( UpButton );\r
848         bringToFront( DownButton );\r
849 }\r
850 \r
851 //! Set the alignment of the tabs\r
852 void CGUITabControl::setTabVerticalAlignment( EGUI_ALIGNMENT alignment )\r
853 {\r
854         VerticalAlignment = alignment;\r
855 \r
856         recalculateScrollButtonPlacement();\r
857         recalculateScrollBar();\r
858 \r
859         core::rect<s32> r(calcTabPos());\r
860         for ( u32 i=0; i<Tabs.size(); ++i )\r
861         {\r
862                 Tabs[i]->setRelativePosition(r);\r
863         }\r
864 }\r
865 \r
866 void CGUITabControl::recalculateScrollButtonPlacement()\r
867 {\r
868         IGUISkin* skin = Environment->getSkin();\r
869         s32 ButtonSize = 16;\r
870         s32 ButtonHeight = TabHeight - 2;\r
871         if ( ButtonHeight < 0 )\r
872                 ButtonHeight = TabHeight;\r
873         if (skin)\r
874         {\r
875                 ButtonSize = skin->getSize(EGDS_WINDOW_BUTTON_WIDTH);\r
876                 if (ButtonSize > TabHeight)\r
877                         ButtonSize = TabHeight;\r
878         }\r
879 \r
880         s32 ButtonX = RelativeRect.getWidth() - (s32)(2.5f*(f32)ButtonSize) - 1;\r
881         s32 ButtonY = 0;\r
882 \r
883         if (VerticalAlignment == EGUIA_UPPERLEFT)\r
884         {\r
885                 ButtonY = 2 + (TabHeight / 2) - (ButtonHeight / 2);\r
886                 UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);\r
887                 DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);\r
888         }\r
889         else\r
890         {\r
891                 ButtonY = RelativeRect.getHeight() - (TabHeight / 2) - (ButtonHeight / 2) - 2;\r
892                 UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);\r
893                 DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);\r
894         }\r
895 \r
896         UpButton->setRelativePosition(core::rect<s32>(ButtonX, ButtonY, ButtonX+ButtonSize, ButtonY+ButtonHeight));\r
897         ButtonX += ButtonSize + 1;\r
898         DownButton->setRelativePosition(core::rect<s32>(ButtonX, ButtonY, ButtonX+ButtonSize, ButtonY+ButtonHeight));\r
899 }\r
900 \r
901 //! Get the alignment of the tabs\r
902 EGUI_ALIGNMENT CGUITabControl::getTabVerticalAlignment() const\r
903 {\r
904         return VerticalAlignment;\r
905 }\r
906 \r
907 \r
908 s32 CGUITabControl::getTabAt(s32 xpos, s32 ypos) const\r
909 {\r
910         core::position2di p(xpos, ypos);\r
911         IGUISkin* skin = Environment->getSkin();\r
912         IGUIFont* font = skin->getFont();\r
913 \r
914         core::rect<s32> frameRect(AbsoluteRect);\r
915 \r
916         if ( VerticalAlignment == EGUIA_UPPERLEFT )\r
917         {\r
918                 frameRect.UpperLeftCorner.Y += 2;\r
919                 frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + TabHeight;\r
920         }\r
921         else\r
922         {\r
923                 frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - TabHeight;\r
924         }\r
925 \r
926         s32 pos = frameRect.UpperLeftCorner.X + 2;\r
927 \r
928         if (!frameRect.isPointInside(p))\r
929                 return -1;\r
930 \r
931         bool abort = false;\r
932         for (s32 i = CurrentScrollTabIndex; i < (s32)Tabs.size() && !abort; ++i)\r
933         {\r
934                 // get Text\r
935                 const wchar_t* text = 0;\r
936                 if (Tabs[i])\r
937                         text = Tabs[i]->getText();\r
938 \r
939                 // get text length\r
940                 s32 len = calcTabWidth(font, text);\r
941                 if (ScrollControl) {\r
942                         // TODO: merge this with draw() ?\r
943                         s32 space = UpButton->getAbsolutePosition().UpperLeftCorner.X - 2 - pos;\r
944                         if (space < len) {\r
945                                 abort = true;\r
946                                 len = space;\r
947                         }\r
948                 }\r
949 \r
950                 frameRect.UpperLeftCorner.X = pos;\r
951                 frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + len;\r
952 \r
953                 pos += len;\r
954 \r
955                 if (frameRect.isPointInside(p))\r
956                 {\r
957                         return i;\r
958                 }\r
959 \r
960         }\r
961         return -1;\r
962 }\r
963 \r
964 //! Returns which tab is currently active\r
965 s32 CGUITabControl::getActiveTab() const\r
966 {\r
967         return ActiveTabIndex;\r
968 }\r
969 \r
970 \r
971 //! Brings a tab to front.\r
972 bool CGUITabControl::setActiveTab(s32 idx)\r
973 {\r
974         if ((u32)idx >= Tabs.size())\r
975                 return false;\r
976 \r
977         bool changed = (ActiveTabIndex != idx);\r
978 \r
979         ActiveTabIndex = idx;\r
980 \r
981         setVisibleTab(ActiveTabIndex);\r
982 \r
983         if (changed && Parent)\r
984         {\r
985                 SEvent event;\r
986                 event.EventType = EET_GUI_EVENT;\r
987                 event.GUIEvent.Caller = this;\r
988                 event.GUIEvent.Element = 0;\r
989                 event.GUIEvent.EventType = EGET_TAB_CHANGED;\r
990                 Parent->OnEvent(event);\r
991         }\r
992 \r
993         if (ScrollControl) {\r
994                 CurrentScrollTabIndex = calculateScrollIndexFromActive();\r
995                 recalculateScrollBar();\r
996         }\r
997 \r
998         return true;\r
999 }\r
1000 \r
1001 void CGUITabControl::setVisibleTab(s32 idx)\r
1002 {\r
1003         for (u32 i=0; i<Tabs.size(); ++i)\r
1004                 if (Tabs[i])\r
1005                         Tabs[i]->setVisible( (s32)i == idx );\r
1006 }\r
1007 \r
1008 \r
1009 bool CGUITabControl::setActiveTab(IGUITab *tab)\r
1010 {\r
1011         return setActiveTab(getTabIndex(tab));\r
1012 }\r
1013 \r
1014 s32 CGUITabControl::getTabIndex(const IGUIElement *tab) const\r
1015 {\r
1016         for (u32 i=0; i<Tabs.size(); ++i)\r
1017                 if (Tabs[i] == tab)\r
1018                         return (s32)i;\r
1019 \r
1020         return -1;\r
1021 }\r
1022 \r
1023 //! Update the position of the element, decides scroll button status\r
1024 void CGUITabControl::updateAbsolutePosition()\r
1025 {\r
1026         IGUIElement::updateAbsolutePosition();\r
1027         recalculateScrollBar();\r
1028 }\r
1029 \r
1030 \r
1031 } // end namespace irr\r
1032 } // end namespace gui\r
1033 \r
1034 #endif // _IRR_COMPILE_WITH_GUI_\r
1035 \r