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
5 #include "CGUIComboBox.h"
\r
6 #ifdef _IRR_COMPILE_WITH_GUI_
\r
8 #include "IGUIEnvironment.h"
\r
9 #include "IVideoDriver.h"
\r
10 #include "IGUISkin.h"
\r
11 #include "IGUIEnvironment.h"
\r
12 #include "IGUIFont.h"
\r
13 #include "IGUIButton.h"
\r
14 #include "CGUIListBox.h"
\r
23 CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
\r
24 s32 id, core::rect<s32> rectangle)
\r
25 : IGUIComboBox(environment, parent, id, rectangle),
\r
26 ListButton(0), SelectedText(0), ListBox(0), LastFocus(0),
\r
27 Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false),
\r
31 setDebugName("CGUIComboBox");
\r
34 IGUISkin* skin = Environment->getSkin();
\r
36 ListButton = Environment->addButton(core::recti(0,0,1,1), this, -1, L"");
\r
37 if (skin && skin->getSpriteBank())
\r
39 ListButton->setSpriteBank(skin->getSpriteBank());
\r
40 ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
\r
41 ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
\r
43 ListButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
\r
44 ListButton->setSubElement(true);
\r
45 ListButton->setTabStop(false);
\r
47 SelectedText = Environment->addStaticText(L"", core::recti(0,0,1,1), false, false, this, -1, false);
\r
48 SelectedText->setSubElement(true);
\r
49 SelectedText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
\r
50 SelectedText->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_CENTER);
\r
52 SelectedText->setOverrideColor(skin->getColor(EGDC_BUTTON_TEXT));
\r
53 SelectedText->enableOverrideColor(true);
\r
55 updateListButtonWidth(skin ? skin->getSize(EGDS_SCROLLBAR_SIZE) : 15);
\r
57 // this element can be tabbed to
\r
63 void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
\r
65 HAlign = horizontal;
\r
67 SelectedText->setTextAlignment(horizontal, vertical);
\r
71 //! Set the maximal number of rows for the selection listbox
\r
72 void CGUIComboBox::setMaxSelectionRows(u32 max)
\r
74 MaxSelectionRows = max;
\r
76 // force recalculation of open listbox
\r
84 //! Get the maximal number of rows for the selection listbox
\r
85 u32 CGUIComboBox::getMaxSelectionRows() const
\r
87 return MaxSelectionRows;
\r
91 //! Returns amount of items in box
\r
92 u32 CGUIComboBox::getItemCount() const
\r
94 return Items.size();
\r
98 //! returns string of an item. the idx may be a value from 0 to itemCount-1
\r
99 const wchar_t* CGUIComboBox::getItem(u32 idx) const
\r
101 if (idx >= Items.size())
\r
104 return Items[idx].Name.c_str();
\r
107 //! returns string of an item. the idx may be a value from 0 to itemCount-1
\r
108 u32 CGUIComboBox::getItemData(u32 idx) const
\r
110 if (idx >= Items.size())
\r
113 return Items[idx].Data;
\r
116 //! Returns index based on item data
\r
117 s32 CGUIComboBox::getIndexForItemData(u32 data ) const
\r
119 for ( u32 i = 0; i < Items.size (); ++i )
\r
121 if ( Items[i].Data == data )
\r
128 //! Removes an item from the combo box.
\r
129 void CGUIComboBox::removeItem(u32 idx)
\r
131 if (idx >= Items.size())
\r
134 if (Selected == (s32)idx)
\r
141 //! Returns caption of this element.
\r
142 const wchar_t* CGUIComboBox::getText() const
\r
144 return getItem(Selected);
\r
148 //! adds an item and returns the index of it
\r
149 u32 CGUIComboBox::addItem(const wchar_t* text, u32 data)
\r
151 Items.push_back( SComboData ( text, data ) );
\r
153 if (Selected == -1)
\r
156 return Items.size() - 1;
\r
160 //! deletes all items in the combo box
\r
161 void CGUIComboBox::clear()
\r
168 //! returns id of selected item. returns -1 if no item is selected.
\r
169 s32 CGUIComboBox::getSelected() const
\r
175 //! sets the selected item. Set this to -1 if no item should be selected
\r
176 void CGUIComboBox::setSelected(s32 idx)
\r
178 if (idx < -1 || idx >= (s32)Items.size())
\r
182 if (Selected == -1)
\r
183 SelectedText->setText(L"");
\r
185 SelectedText->setText(Items[Selected].Name.c_str());
\r
189 //! called if an event happened.
\r
190 bool CGUIComboBox::OnEvent(const SEvent& event)
\r
194 switch(event.EventType)
\r
197 case EET_KEY_INPUT_EVENT:
\r
198 if (ListBox && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
\r
205 if (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)
\r
207 if (!event.KeyInput.PressedDown)
\r
212 ListButton->setPressed(ListBox == 0);
\r
217 if (event.KeyInput.PressedDown)
\r
219 s32 oldSelected = Selected;
\r
220 bool absorb = true;
\r
221 switch (event.KeyInput.Key)
\r
224 setSelected(Selected+1);
\r
227 setSelected(Selected-1);
\r
235 setSelected((s32)Items.size()-1);
\r
244 if (Selected >= (s32)Items.size())
\r
245 setSelected((s32)Items.size() -1);
\r
247 if (Selected != oldSelected)
\r
249 sendSelectionChangedEvent();
\r
258 case EET_GUI_EVENT:
\r
260 switch(event.GUIEvent.EventType)
\r
262 case EGET_ELEMENT_FOCUS_LOST:
\r
264 (Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) &&
\r
265 event.GUIEvent.Element != this &&
\r
266 !isMyChild(event.GUIEvent.Element) &&
\r
267 !ListBox->isMyChild(event.GUIEvent.Element))
\r
272 case EGET_BUTTON_CLICKED:
\r
273 if (event.GUIEvent.Caller == ListButton)
\r
279 case EGET_LISTBOX_SELECTED_AGAIN:
\r
280 case EGET_LISTBOX_CHANGED:
\r
281 if (event.GUIEvent.Caller == ListBox)
\r
283 setSelected(ListBox->getSelected());
\r
284 if (Selected <0 || Selected >= (s32)Items.size())
\r
288 sendSelectionChangedEvent();
\r
295 case EET_MOUSE_INPUT_EVENT:
\r
297 switch(event.MouseInput.Event)
\r
299 case EMIE_LMOUSE_PRESSED_DOWN:
\r
301 core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
\r
303 // send to list box
\r
304 if (ListBox && ListBox->isPointInside(p) && ListBox->OnEvent(event))
\r
309 case EMIE_LMOUSE_LEFT_UP:
\r
311 core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
\r
313 // send to list box
\r
315 ListBox->getAbsolutePosition().isPointInside(p) &&
\r
316 ListBox->OnEvent(event)))
\r
322 case EMIE_MOUSE_WHEEL:
\r
324 s32 oldSelected = Selected;
\r
325 setSelected( Selected + ((event.MouseInput.Wheel < 0) ? 1 : -1));
\r
330 if (Selected >= (s32)Items.size())
\r
331 setSelected((s32)Items.size() -1);
\r
333 if (Selected != oldSelected)
\r
335 sendSelectionChangedEvent();
\r
348 return IGUIElement::OnEvent(event);
\r
352 void CGUIComboBox::sendSelectionChangedEvent()
\r
358 event.EventType = EET_GUI_EVENT;
\r
359 event.GUIEvent.Caller = this;
\r
360 event.GUIEvent.Element = 0;
\r
361 event.GUIEvent.EventType = EGET_COMBO_BOX_CHANGED;
\r
362 Parent->OnEvent(event);
\r
366 void CGUIComboBox::updateListButtonWidth(s32 width)
\r
368 if (ListButton->getRelativePosition().getWidth() != width)
\r
371 r.UpperLeftCorner.X = RelativeRect.getWidth() - width - 2;
\r
372 r.LowerRightCorner.X = RelativeRect.getWidth() - 2;
\r
373 r.UpperLeftCorner.Y = 2;
\r
374 r.LowerRightCorner.Y = RelativeRect.getHeight() - 2;
\r
375 ListButton->setRelativePosition(r);
\r
377 r.UpperLeftCorner.X = 2;
\r
378 r.UpperLeftCorner.Y = 2;
\r
379 r.LowerRightCorner.X = RelativeRect.getWidth() - (width + 2);
\r
380 r.LowerRightCorner.Y = RelativeRect.getHeight() - 2;
\r
381 SelectedText->setRelativePosition(r);
\r
385 //! draws the element and its children
\r
386 void CGUIComboBox::draw()
\r
391 IGUISkin* skin = Environment->getSkin();
\r
393 updateListButtonWidth(skin->getSize(EGDS_SCROLLBAR_SIZE));
\r
395 // font changed while the listbox is open?
\r
396 if ( ActiveFont != skin->getFont() && ListBox )
\r
398 // close and re-open to use new font-size
\r
404 IGUIElement *currentFocus = Environment->getFocus();
\r
405 if (currentFocus != LastFocus)
\r
407 HasFocus = currentFocus == this || isMyChild(currentFocus);
\r
408 LastFocus = currentFocus;
\r
411 // set colors each time as skin-colors can be changed
\r
412 SelectedText->setBackgroundColor(skin->getColor(EGDC_HIGH_LIGHT));
\r
415 SelectedText->setDrawBackground(HasFocus);
\r
416 SelectedText->setOverrideColor(skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT));
\r
420 SelectedText->setDrawBackground(false);
\r
421 SelectedText->setOverrideColor(skin->getColor(EGDC_GRAY_TEXT));
\r
423 ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
\r
424 ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
\r
427 core::rect<s32> frameRect(AbsoluteRect);
\r
431 skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT),
\r
432 true, true, frameRect, &AbsoluteClippingRect);
\r
435 IGUIElement::draw();
\r
439 void CGUIComboBox::openCloseMenu()
\r
444 Environment->setFocus(this);
\r
451 Parent->bringToFront(this);
\r
453 IGUISkin* skin = Environment->getSkin();
\r
454 u32 h = Items.size();
\r
456 if (h > getMaxSelectionRows())
\r
457 h = getMaxSelectionRows();
\r
461 ActiveFont = skin->getFont();
\r
463 h *= (ActiveFont->getDimension(L"A").Height + 4);
\r
466 core::rect<s32> r(0, AbsoluteRect.getHeight(),
\r
467 AbsoluteRect.getWidth(), AbsoluteRect.getHeight() + h);
\r
469 ListBox = new CGUIListBox(Environment, this, -1, r, false, true, true);
\r
470 ListBox->setSubElement(true);
\r
471 ListBox->setNotClipped(true);
\r
474 // ensure that list box is always completely visible
\r
475 if (ListBox->getAbsolutePosition().LowerRightCorner.Y > Environment->getRootGUIElement()->getAbsolutePosition().getHeight())
\r
476 ListBox->setRelativePosition( core::rect<s32>(0, -ListBox->getAbsolutePosition().getHeight(), AbsoluteRect.getWidth(), 0) );
\r
478 for (s32 i=0; i<(s32)Items.size(); ++i)
\r
479 ListBox->addItem(Items[i].Name.c_str());
\r
481 ListBox->setSelected(Selected);
\r
484 Environment->setFocus(ListBox);
\r
489 } // end namespace gui
\r
490 } // end namespace irr
\r
493 #endif // _IRR_COMPILE_WITH_GUI_
\r