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 "CGUIListBox.h"
6 #ifdef _IRR_COMPILE_WITH_GUI_
7
8 #include "CGUIListBox.h"
9 #include "IGUISkin.h"
10 #include "IGUIEnvironment.h"
11 #include "IVideoDriver.h"
12 #include "IGUIFont.h"
13 #include "IGUISpriteBank.h"
14 #include "CGUIScrollBar.h"
15 #include "os.h"
16
17 namespace irr
18 {
19 namespace gui
20 {
21
22 //! constructor
CGUIListBox(IGUIEnvironment * environment,IGUIElement * parent,s32 id,core::rect<s32> rectangle,bool clip,bool drawBack,bool moveOverSelect)23 CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent,
24 s32 id, core::rect<s32> rectangle, bool clip,
25 bool drawBack, bool moveOverSelect)
26 : IGUIListBox(environment, parent, id, rectangle), Selected(-1),
27 ItemHeight(0),ItemHeightOverride(0),
28 TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0),
29 ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack),
30 MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true)
31 {
32 #ifdef _DEBUG
33 setDebugName("CGUIListBox");
34 #endif
35
36 IGUISkin* skin = Environment->getSkin();
37 const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE);
38
39 ScrollBar = new CGUIScrollBar(false, Environment, this, -1,
40 core::rect<s32>(RelativeRect.getWidth() - s, 0, RelativeRect.getWidth(), RelativeRect.getHeight()),
41 !clip);
42 ScrollBar->setSubElement(true);
43 ScrollBar->setTabStop(false);
44 ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
45 ScrollBar->setVisible(false);
46 ScrollBar->setPos(0);
47
48 setNotClipped(!clip);
49
50 // this element can be tabbed to
51 setTabStop(true);
52 setTabOrder(-1);
53
54 updateAbsolutePosition();
55 }
56
57
58 //! destructor
~CGUIListBox()59 CGUIListBox::~CGUIListBox()
60 {
61 if (ScrollBar)
62 ScrollBar->drop();
63
64 if (Font)
65 Font->drop();
66
67 if (IconBank)
68 IconBank->drop();
69 }
70
71
72 //! returns amount of list items
getItemCount() const73 u32 CGUIListBox::getItemCount() const
74 {
75 return Items.size();
76 }
77
78
79 //! returns string of a list item. the may be a value from 0 to itemCount-1
getListItem(u32 id) const80 const wchar_t* CGUIListBox::getListItem(u32 id) const
81 {
82 if (id>=Items.size())
83 return 0;
84
85 return Items[id].text.c_str();
86 }
87
88
89 //! Returns the icon of an item
getIcon(u32 id) const90 s32 CGUIListBox::getIcon(u32 id) const
91 {
92 if (id>=Items.size())
93 return -1;
94
95 return Items[id].icon;
96 }
97
98
99 //! adds a list item, returns id of item
addItem(const wchar_t * text)100 u32 CGUIListBox::addItem(const wchar_t* text)
101 {
102 return addItem(text, -1);
103 }
104
105
106 //! adds a list item, returns id of item
removeItem(u32 id)107 void CGUIListBox::removeItem(u32 id)
108 {
109 if (id >= Items.size())
110 return;
111
112 if ((u32)Selected==id)
113 {
114 Selected = -1;
115 }
116 else if ((u32)Selected > id)
117 {
118 Selected -= 1;
119 selectTime = os::Timer::getTime();
120 }
121
122 Items.erase(id);
123
124 recalculateItemHeight();
125 }
126
127
getItemAt(s32 xpos,s32 ypos) const128 s32 CGUIListBox::getItemAt(s32 xpos, s32 ypos) const
129 {
130 if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X
131 || ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y
132 )
133 return -1;
134
135 if ( ItemHeight == 0 )
136 return -1;
137
138 s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight;
139 if ( item < 0 || item >= (s32)Items.size())
140 return -1;
141
142 return item;
143 }
144
145 //! clears the list
clear()146 void CGUIListBox::clear()
147 {
148 Items.clear();
149 ItemsIconWidth = 0;
150 Selected = -1;
151
152 if (ScrollBar)
153 ScrollBar->setPos(0);
154
155 recalculateItemHeight();
156 }
157
158
recalculateItemHeight()159 void CGUIListBox::recalculateItemHeight()
160 {
161 IGUISkin* skin = Environment->getSkin();
162
163 if (Font != skin->getFont())
164 {
165 if (Font)
166 Font->drop();
167
168 Font = skin->getFont();
169 if ( 0 == ItemHeightOverride )
170 ItemHeight = 0;
171
172 if (Font)
173 {
174 if ( 0 == ItemHeightOverride )
175 ItemHeight = Font->getDimension(L"A").Height + 4;
176
177 Font->grab();
178 }
179 }
180
181 TotalItemHeight = ItemHeight * Items.size();
182 ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) );
183 s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1;
184 ScrollBar->setSmallStep ( minItemHeight );
185 ScrollBar->setLargeStep ( 2*minItemHeight );
186
187 if ( TotalItemHeight <= AbsoluteRect.getHeight() )
188 ScrollBar->setVisible(false);
189 else
190 ScrollBar->setVisible(true);
191 }
192
193
194 //! returns id of selected item. returns -1 if no item is selected.
getSelected() const195 s32 CGUIListBox::getSelected() const
196 {
197 return Selected;
198 }
199
200
201 //! sets the selected item. Set this to -1 if no item should be selected
setSelected(s32 id)202 void CGUIListBox::setSelected(s32 id)
203 {
204 if ((u32)id>=Items.size())
205 Selected = -1;
206 else
207 Selected = id;
208
209 selectTime = os::Timer::getTime();
210
211 recalculateScrollPos();
212 }
213
214 //! sets the selected item. Set this to -1 if no item should be selected
setSelected(const wchar_t * item)215 void CGUIListBox::setSelected(const wchar_t *item)
216 {
217 s32 index = -1;
218
219 if ( item )
220 {
221 for ( index = 0; index < (s32) Items.size(); ++index )
222 {
223 if ( Items[index].text == item )
224 break;
225 }
226 }
227 setSelected ( index );
228 }
229
230 //! called if an event happened.
OnEvent(const SEvent & event)231 bool CGUIListBox::OnEvent(const SEvent& event)
232 {
233 if (isEnabled())
234 {
235 switch(event.EventType)
236 {
237 case EET_KEY_INPUT_EVENT:
238 if (event.KeyInput.PressedDown &&
239 (event.KeyInput.Key == KEY_DOWN ||
240 event.KeyInput.Key == KEY_UP ||
241 event.KeyInput.Key == KEY_HOME ||
242 event.KeyInput.Key == KEY_END ||
243 event.KeyInput.Key == KEY_NEXT ||
244 event.KeyInput.Key == KEY_PRIOR ) )
245 {
246 s32 oldSelected = Selected;
247 switch (event.KeyInput.Key)
248 {
249 case KEY_DOWN:
250 Selected += 1;
251 break;
252 case KEY_UP:
253 Selected -= 1;
254 break;
255 case KEY_HOME:
256 Selected = 0;
257 break;
258 case KEY_END:
259 Selected = (s32)Items.size()-1;
260 break;
261 case KEY_NEXT:
262 Selected += AbsoluteRect.getHeight() / ItemHeight;
263 break;
264 case KEY_PRIOR:
265 Selected -= AbsoluteRect.getHeight() / ItemHeight;
266 break;
267 default:
268 break;
269 }
270 if (Selected<0)
271 Selected = 0;
272 if (Selected >= (s32)Items.size())
273 Selected = Items.size() - 1; // will set Selected to -1 for empty listboxes which is correct
274
275
276 recalculateScrollPos();
277
278 // post the news
279
280 if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect)
281 {
282 SEvent e;
283 e.EventType = EET_GUI_EVENT;
284 e.GUIEvent.Caller = this;
285 e.GUIEvent.Element = 0;
286 e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
287 Parent->OnEvent(e);
288 }
289
290 return true;
291 }
292 else
293 if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) )
294 {
295 if (Parent)
296 {
297 SEvent e;
298 e.EventType = EET_GUI_EVENT;
299 e.GUIEvent.Caller = this;
300 e.GUIEvent.Element = 0;
301 e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN;
302 Parent->OnEvent(e);
303 }
304 return true;
305 }
306 else if (event.KeyInput.PressedDown && event.KeyInput.Char)
307 {
308 // change selection based on text as it is typed.
309 u32 now = os::Timer::getTime();
310
311 if (now - LastKeyTime < 500)
312 {
313 // add to key buffer if it isn't a key repeat
314 if (!(KeyBuffer.size() == 1 && KeyBuffer[0] == event.KeyInput.Char))
315 {
316 KeyBuffer += L" ";
317 KeyBuffer[KeyBuffer.size()-1] = event.KeyInput.Char;
318 }
319 }
320 else
321 {
322 KeyBuffer = L" ";
323 KeyBuffer[0] = event.KeyInput.Char;
324 }
325 LastKeyTime = now;
326
327 // find the selected item, starting at the current selection
328 s32 start = Selected;
329 // dont change selection if the key buffer matches the current item
330 if (Selected > -1 && KeyBuffer.size() > 1)
331 {
332 if (Items[Selected].text.size() >= KeyBuffer.size() &&
333 KeyBuffer.equals_ignore_case(Items[Selected].text.subString(0,KeyBuffer.size())))
334 return true;
335 }
336
337 s32 current;
338 for (current = start+1; current < (s32)Items.size(); ++current)
339 {
340 if (Items[current].text.size() >= KeyBuffer.size())
341 {
342 if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size())))
343 {
344 if (Parent && Selected != current && !Selecting && !MoveOverSelect)
345 {
346 SEvent e;
347 e.EventType = EET_GUI_EVENT;
348 e.GUIEvent.Caller = this;
349 e.GUIEvent.Element = 0;
350 e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
351 Parent->OnEvent(e);
352 }
353 setSelected(current);
354 return true;
355 }
356 }
357 }
358 for (current = 0; current <= start; ++current)
359 {
360 if (Items[current].text.size() >= KeyBuffer.size())
361 {
362 if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size())))
363 {
364 if (Parent && Selected != current && !Selecting && !MoveOverSelect)
365 {
366 Selected = current;
367 SEvent e;
368 e.EventType = EET_GUI_EVENT;
369 e.GUIEvent.Caller = this;
370 e.GUIEvent.Element = 0;
371 e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
372 Parent->OnEvent(e);
373 }
374 setSelected(current);
375 return true;
376 }
377 }
378 }
379
380 return true;
381 }
382 break;
383
384 case EET_GUI_EVENT:
385 switch(event.GUIEvent.EventType)
386 {
387 case gui::EGET_SCROLL_BAR_CHANGED:
388 if (event.GUIEvent.Caller == ScrollBar)
389 return true;
390 break;
391 case gui::EGET_ELEMENT_FOCUS_LOST:
392 {
393 if (event.GUIEvent.Caller == this)
394 Selecting = false;
395 }
396 default:
397 break;
398 }
399 break;
400
401 case EET_MOUSE_INPUT_EVENT:
402 {
403 core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
404
405 switch(event.MouseInput.Event)
406 {
407 case EMIE_MOUSE_WHEEL:
408 ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2);
409 return true;
410
411 case EMIE_LMOUSE_PRESSED_DOWN:
412 {
413 Selecting = true;
414 return true;
415 }
416
417 case EMIE_LMOUSE_LEFT_UP:
418 {
419 Selecting = false;
420
421 if (isPointInside(p))
422 selectNew(event.MouseInput.Y);
423
424 return true;
425 }
426
427 case EMIE_MOUSE_MOVED:
428 if (Selecting || MoveOverSelect)
429 {
430 if (isPointInside(p))
431 {
432 selectNew(event.MouseInput.Y, true);
433 return true;
434 }
435 }
436 default:
437 break;
438 }
439 }
440 break;
441 case EET_LOG_TEXT_EVENT:
442 case EET_USER_EVENT:
443 case EET_JOYSTICK_INPUT_EVENT:
444 case EGUIET_FORCE_32_BIT:
445 break;
446 }
447 }
448
449 return IGUIElement::OnEvent(event);
450 }
451
452
selectNew(s32 ypos,bool onlyHover)453 void CGUIListBox::selectNew(s32 ypos, bool onlyHover)
454 {
455 u32 now = os::Timer::getTime();
456 s32 oldSelected = Selected;
457
458 Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos);
459 if (Selected<0 && !Items.empty())
460 Selected = 0;
461
462 recalculateScrollPos();
463
464 gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED;
465 selectTime = now;
466 // post the news
467 if (Parent && !onlyHover)
468 {
469 SEvent event;
470 event.EventType = EET_GUI_EVENT;
471 event.GUIEvent.Caller = this;
472 event.GUIEvent.Element = 0;
473 event.GUIEvent.EventType = eventType;
474 Parent->OnEvent(event);
475 }
476 }
477
478
479 //! Update the position and size of the listbox, and update the scrollbar
updateAbsolutePosition()480 void CGUIListBox::updateAbsolutePosition()
481 {
482 IGUIElement::updateAbsolutePosition();
483
484 recalculateItemHeight();
485 }
486
487
488 //! draws the element and its children
draw()489 void CGUIListBox::draw()
490 {
491 if (!IsVisible)
492 return;
493
494 recalculateItemHeight(); // if the font changed
495
496 IGUISkin* skin = Environment->getSkin();
497
498 core::rect<s32>* clipRect = 0;
499
500 // draw background
501 core::rect<s32> frameRect(AbsoluteRect);
502
503 // draw items
504
505 core::rect<s32> clientClip(AbsoluteRect);
506 clientClip.UpperLeftCorner.Y += 1;
507 clientClip.UpperLeftCorner.X += 1;
508 if (ScrollBar->isVisible())
509 clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
510 clientClip.LowerRightCorner.Y -= 1;
511 clientClip.clipAgainst(AbsoluteClippingRect);
512
513 skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true,
514 DrawBack, frameRect, &AbsoluteClippingRect);
515
516 if (clipRect)
517 clientClip.clipAgainst(*clipRect);
518
519 frameRect = AbsoluteRect;
520 frameRect.UpperLeftCorner.X += 1;
521 if (ScrollBar->isVisible())
522 frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
523
524 frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight;
525
526 frameRect.UpperLeftCorner.Y -= ScrollBar->getPos();
527 frameRect.LowerRightCorner.Y -= ScrollBar->getPos();
528
529 bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar));
530
531 for (s32 i=0; i<(s32)Items.size(); ++i)
532 {
533 if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y &&
534 frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
535 {
536 if (i == Selected && hl)
537 skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip);
538
539 core::rect<s32> textRect = frameRect;
540 textRect.UpperLeftCorner.X += 3;
541
542 if (Font)
543 {
544 if (IconBank && (Items[i].icon > -1))
545 {
546 core::position2di iconPos = textRect.UpperLeftCorner;
547 iconPos.Y += textRect.getHeight() / 2;
548 iconPos.X += ItemsIconWidth/2;
549
550 if ( i==Selected && hl )
551 {
552 IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip,
553 hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ?
554 getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT),
555 selectTime, os::Timer::getTime(), false, true);
556 }
557 else
558 {
559 IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip,
560 hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON),
561 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true);
562 }
563 }
564
565 textRect.UpperLeftCorner.X += ItemsIconWidth+3;
566
567 if ( i==Selected && hl )
568 {
569 Font->draw(Items[i].text.c_str(), textRect,
570 hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ?
571 getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT),
572 false, true, &clientClip);
573 }
574 else
575 {
576 Font->draw(Items[i].text.c_str(), textRect,
577 hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT),
578 false, true, &clientClip);
579 }
580
581 textRect.UpperLeftCorner.X -= ItemsIconWidth+3;
582 }
583 }
584
585 frameRect.UpperLeftCorner.Y += ItemHeight;
586 frameRect.LowerRightCorner.Y += ItemHeight;
587 }
588
589 IGUIElement::draw();
590 }
591
592
593 //! adds an list item with an icon
addItem(const wchar_t * text,s32 icon)594 u32 CGUIListBox::addItem(const wchar_t* text, s32 icon)
595 {
596 ListItem i;
597 i.text = text;
598 i.icon = icon;
599
600 Items.push_back(i);
601 recalculateItemHeight();
602 recalculateItemWidth(icon);
603
604 return Items.size() - 1;
605 }
606
607
setSpriteBank(IGUISpriteBank * bank)608 void CGUIListBox::setSpriteBank(IGUISpriteBank* bank)
609 {
610 if ( bank == IconBank )
611 return;
612 if (IconBank)
613 IconBank->drop();
614
615 IconBank = bank;
616 if (IconBank)
617 IconBank->grab();
618 }
619
620
recalculateScrollPos()621 void CGUIListBox::recalculateScrollPos()
622 {
623 if (!AutoScroll)
624 return;
625
626 const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos();
627
628 if (selPos < 0)
629 {
630 ScrollBar->setPos(ScrollBar->getPos() + selPos);
631 }
632 else
633 if (selPos > AbsoluteRect.getHeight() - ItemHeight)
634 {
635 ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight);
636 }
637 }
638
639
setAutoScrollEnabled(bool scroll)640 void CGUIListBox::setAutoScrollEnabled(bool scroll)
641 {
642 AutoScroll = scroll;
643 }
644
645
isAutoScrollEnabled() const646 bool CGUIListBox::isAutoScrollEnabled() const
647 {
648 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
649 return AutoScroll;
650 }
651
652
getSerializationLabels(EGUI_LISTBOX_COLOR colorType,core::stringc & useColorLabel,core::stringc & colorLabel) const653 bool CGUIListBox::getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) const
654 {
655 switch ( colorType )
656 {
657 case EGUI_LBC_TEXT:
658 useColorLabel = "UseColText";
659 colorLabel = "ColText";
660 break;
661 case EGUI_LBC_TEXT_HIGHLIGHT:
662 useColorLabel = "UseColTextHl";
663 colorLabel = "ColTextHl";
664 break;
665 case EGUI_LBC_ICON:
666 useColorLabel = "UseColIcon";
667 colorLabel = "ColIcon";
668 break;
669 case EGUI_LBC_ICON_HIGHLIGHT:
670 useColorLabel = "UseColIconHl";
671 colorLabel = "ColIconHl";
672 break;
673 default:
674 return false;
675 }
676 return true;
677 }
678
679
680 //! Writes attributes of the element.
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options=0) const681 void CGUIListBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
682 {
683 IGUIListBox::serializeAttributes(out,options);
684
685 // todo: out->addString ("IconBank", IconBank->getName?);
686 out->addBool ("DrawBack", DrawBack);
687 out->addBool ("MoveOverSelect", MoveOverSelect);
688 out->addBool ("AutoScroll", AutoScroll);
689
690 out->addInt("ItemCount", Items.size());
691 for (u32 i=0;i<Items.size(); ++i)
692 {
693 core::stringc label("text");
694 label += i;
695 out->addString(label.c_str(), Items[i].text.c_str() );
696
697 for ( s32 c=0; c < (s32)EGUI_LBC_COUNT; ++c )
698 {
699 core::stringc useColorLabel, colorLabel;
700 if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) )
701 return;
702 label = useColorLabel; label += i;
703 if ( Items[i].OverrideColors[c].Use )
704 {
705 out->addBool(label.c_str(), true );
706 label = colorLabel; label += i;
707 out->addColor(label.c_str(), Items[i].OverrideColors[c].Color);
708 }
709 else
710 {
711 out->addBool(label.c_str(), false );
712 }
713 }
714 }
715 }
716
717
718 //! Reads attributes of the element
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options=0)719 void CGUIListBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
720 {
721 clear();
722
723 DrawBack = in->getAttributeAsBool("DrawBack");
724 MoveOverSelect = in->getAttributeAsBool("MoveOverSelect");
725 AutoScroll = in->getAttributeAsBool("AutoScroll");
726
727 IGUIListBox::deserializeAttributes(in,options);
728
729 const s32 count = in->getAttributeAsInt("ItemCount");
730 for (s32 i=0; i<count; ++i)
731 {
732 core::stringc label("text");
733 ListItem item;
734
735 label += i;
736 item.text = in->getAttributeAsStringW(label.c_str());
737
738 addItem(item.text.c_str(), item.icon);
739
740 for ( u32 c=0; c < EGUI_LBC_COUNT; ++c )
741 {
742 core::stringc useColorLabel, colorLabel;
743 if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) )
744 return;
745 label = useColorLabel; label += i;
746 Items[i].OverrideColors[c].Use = in->getAttributeAsBool(label.c_str());
747 if ( Items[i].OverrideColors[c].Use )
748 {
749 label = colorLabel; label += i;
750 Items[i].OverrideColors[c].Color = in->getAttributeAsColor(label.c_str());
751 }
752 }
753 }
754 }
755
756
recalculateItemWidth(s32 icon)757 void CGUIListBox::recalculateItemWidth(s32 icon)
758 {
759 if (IconBank && icon > -1 &&
760 IconBank->getSprites().size() > (u32)icon &&
761 IconBank->getSprites()[(u32)icon].Frames.size())
762 {
763 u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber;
764 if (IconBank->getPositions().size() > rno)
765 {
766 const s32 w = IconBank->getPositions()[rno].getWidth();
767 if (w > ItemsIconWidth)
768 ItemsIconWidth = w;
769 }
770 }
771 }
772
773
setItem(u32 index,const wchar_t * text,s32 icon)774 void CGUIListBox::setItem(u32 index, const wchar_t* text, s32 icon)
775 {
776 if ( index >= Items.size() )
777 return;
778
779 Items[index].text = text;
780 Items[index].icon = icon;
781
782 recalculateItemHeight();
783 recalculateItemWidth(icon);
784 }
785
786
787 //! Insert the item at the given index
788 //! Return the index on success or -1 on failure.
insertItem(u32 index,const wchar_t * text,s32 icon)789 s32 CGUIListBox::insertItem(u32 index, const wchar_t* text, s32 icon)
790 {
791 ListItem i;
792 i.text = text;
793 i.icon = icon;
794
795 Items.insert(i, index);
796 recalculateItemHeight();
797 recalculateItemWidth(icon);
798
799 return index;
800 }
801
802
swapItems(u32 index1,u32 index2)803 void CGUIListBox::swapItems(u32 index1, u32 index2)
804 {
805 if ( index1 >= Items.size() || index2 >= Items.size() )
806 return;
807
808 ListItem dummmy = Items[index1];
809 Items[index1] = Items[index2];
810 Items[index2] = dummmy;
811 }
812
813
setItemOverrideColor(u32 index,video::SColor color)814 void CGUIListBox::setItemOverrideColor(u32 index, video::SColor color)
815 {
816 for ( u32 c=0; c < EGUI_LBC_COUNT; ++c )
817 {
818 Items[index].OverrideColors[c].Use = true;
819 Items[index].OverrideColors[c].Color = color;
820 }
821 }
822
823
setItemOverrideColor(u32 index,EGUI_LISTBOX_COLOR colorType,video::SColor color)824 void CGUIListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color)
825 {
826 if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
827 return;
828
829 Items[index].OverrideColors[colorType].Use = true;
830 Items[index].OverrideColors[colorType].Color = color;
831 }
832
833
clearItemOverrideColor(u32 index)834 void CGUIListBox::clearItemOverrideColor(u32 index)
835 {
836 for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c )
837 {
838 Items[index].OverrideColors[c].Use = false;
839 }
840 }
841
842
clearItemOverrideColor(u32 index,EGUI_LISTBOX_COLOR colorType)843 void CGUIListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType)
844 {
845 if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
846 return;
847
848 Items[index].OverrideColors[colorType].Use = false;
849 }
850
851
hasItemOverrideColor(u32 index,EGUI_LISTBOX_COLOR colorType) const852 bool CGUIListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
853 {
854 if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
855 return false;
856
857 return Items[index].OverrideColors[colorType].Use;
858 }
859
860
getItemOverrideColor(u32 index,EGUI_LISTBOX_COLOR colorType) const861 video::SColor CGUIListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
862 {
863 if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
864 return video::SColor();
865
866 return Items[index].OverrideColors[colorType].Color;
867 }
868
869
getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const870 video::SColor CGUIListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const
871 {
872 IGUISkin* skin = Environment->getSkin();
873 if ( !skin )
874 return video::SColor();
875
876 switch ( colorType )
877 {
878 case EGUI_LBC_TEXT:
879 return skin->getColor(EGDC_BUTTON_TEXT);
880 case EGUI_LBC_TEXT_HIGHLIGHT:
881 return skin->getColor(EGDC_HIGH_LIGHT_TEXT);
882 case EGUI_LBC_ICON:
883 return skin->getColor(EGDC_ICON);
884 case EGUI_LBC_ICON_HIGHLIGHT:
885 return skin->getColor(EGDC_ICON_HIGH_LIGHT);
886 default:
887 return video::SColor();
888 }
889 }
890
891 //! set global itemHeight
setItemHeight(s32 height)892 void CGUIListBox::setItemHeight( s32 height )
893 {
894 ItemHeight = height;
895 ItemHeightOverride = 1;
896 }
897
898
899 //! Sets whether to draw the background
setDrawBackground(bool draw)900 void CGUIListBox::setDrawBackground(bool draw)
901 {
902 DrawBack = draw;
903 }
904
905
906 } // end namespace gui
907 } // end namespace irr
908
909 #endif // _IRR_COMPILE_WITH_GUI_
910
911