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