diff options
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CGUIListBox.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CGUIListBox.cpp | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CGUIListBox.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CGUIListBox.cpp new file mode 100644 index 0000000..adbc28d --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CGUIListBox.cpp | |||
@@ -0,0 +1,910 @@ | |||
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 | ||
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 | ||
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 | ||
73 | 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 | ||
80 | 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 | ||
90 | 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 | ||
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 | ||
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 | |||
128 | 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 | ||
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 | |||
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. | ||
195 | 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 | ||
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 | ||
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. | ||
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 >= (s32)Items.size()) | ||
271 | Selected = Items.size() - 1; | ||
272 | else | ||
273 | if (Selected<0) | ||
274 | Selected = 0; | ||
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 | |||
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 | ||
480 | void CGUIListBox::updateAbsolutePosition() | ||
481 | { | ||
482 | IGUIElement::updateAbsolutePosition(); | ||
483 | |||
484 | recalculateItemHeight(); | ||
485 | } | ||
486 | |||
487 | |||
488 | //! draws the element and its children | ||
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, &clientClip); | ||
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 | ||
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 | |||
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 | |||
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 | |||
640 | void CGUIListBox::setAutoScrollEnabled(bool scroll) | ||
641 | { | ||
642 | AutoScroll = scroll; | ||
643 | } | ||
644 | |||
645 | |||
646 | bool CGUIListBox::isAutoScrollEnabled() const | ||
647 | { | ||
648 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
649 | return AutoScroll; | ||
650 | } | ||
651 | |||
652 | |||
653 | 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. | ||
681 | 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 | ||
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 | |||
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 | |||
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. | ||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
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 | |||
852 | 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 | |||
861 | 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 | |||
870 | 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 | ||
892 | void CGUIListBox::setItemHeight( s32 height ) | ||
893 | { | ||
894 | ItemHeight = height; | ||
895 | ItemHeightOverride = 1; | ||
896 | } | ||
897 | |||
898 | |||
899 | //! Sets whether to draw the background | ||
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 | |||