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