diff -r 9b90dec5e6a7 lib/irrlicht/include/IGUIListBox.h --- a/lib/irrlicht/include/IGUIListBox.h Wed Sep 23 01:31:00 2009 +0200 +++ b/lib/irrlicht/include/IGUIListBox.h Wed Sep 23 01:40:14 2009 +0200 @@ -29,6 +29,26 @@ namespace gui EGUI_LBC_COUNT }; + enum EGUI_LISTBOX_SELECTION + { + //! no lines can be selected + EGUI_LBS_NOT_SELECTABLE, + + //! only single lines can be selected (this is default) + EGUI_LBS_SINGLE_SELECTION, + + //! multiple lines can be selected + EGUI_LBS_MULTI_SELECTION + }; + + //! Names for selection modes + const c8* const GUIListBoxSelectionNames[] = + { + "notSelectable", + "singleSelection", + "multiSelection", + 0 + }; //! Default list box GUI element. class IGUIListBox : public IGUIElement @@ -120,6 +140,36 @@ namespace gui //! Sets whether to draw the background virtual void setDrawBackground(bool draw) = 0; + + //! Set the current selection mode for the listbox lines + virtual void setSelectionMode(EGUI_LISTBOX_SELECTION selection) = 0; + + //! Get the current selection mode for the listbox lines + virtual EGUI_LISTBOX_SELECTION getSelectionMode() const = 0; + + //! Get the number of items which are currently selected + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual u32 getMultiSelectedItemCount() const = 0; + + //! Get the id of the next item with set selection flag + //! returns the first item with selection flag when id=-1 + //! return -1 when no item was found + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getNextMultiSelectedItem(s32 id=-1) const = 0; + + //! Set the selection flag for the item with given id + //! Usually that will be done automatically when the users clicks. + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void setItemMultiSelection(u32 id, bool selected) = 0; + + //! Get the selection flag for the item with given id + //! return true when the item is selected, otherwise returns false + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual bool getItemMultiSelection(u32 id) const = 0; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections() = 0; }; diff -r 9b90dec5e6a7 lib/irrlicht/source/Irrlicht/CGUIListBox.cpp --- a/lib/irrlicht/source/Irrlicht/CGUIListBox.cpp Wed Sep 23 01:31:00 2009 +0200 +++ b/lib/irrlicht/source/Irrlicht/CGUIListBox.cpp Wed Sep 23 01:40:14 2009 +0200 @@ -28,6 +28,7 @@ CGUIListBox::CGUIListBox(IGUIEnvironment TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) + , SelectionMode(EGUI_LBS_SINGLE_SELECTION) { #ifdef _DEBUG setDebugName("CGUIListBox"); @@ -220,7 +221,8 @@ bool CGUIListBox::OnEvent(const SEvent& switch(event.EventType) { case EET_KEY_INPUT_EVENT: - if (event.KeyInput.PressedDown && + if (SelectionMode == EGUI_LBS_SINGLE_SELECTION && + event.KeyInput.PressedDown && (event.KeyInput.Key == KEY_DOWN || event.KeyInput.Key == KEY_UP || event.KeyInput.Key == KEY_HOME || @@ -288,7 +290,8 @@ bool CGUIListBox::OnEvent(const SEvent& } return true; } - else if (event.KeyInput.PressedDown && event.KeyInput.Char) + else if (SelectionMode == EGUI_LBS_SINGLE_SELECTION && + event.KeyInput.PressedDown && event.KeyInput.Char) { // change selection based on text as it is typed. u32 now = os::Timer::getTime(); @@ -404,17 +407,17 @@ bool CGUIListBox::OnEvent(const SEvent& Selecting = false; if (isPointInside(p)) - selectNew(event.MouseInput.Y); + selectNew(event.MouseInput.Y, false, event.MouseInput.Shift, event.MouseInput.Control ); return true; } case EMIE_MOUSE_MOVED: - if (Selecting || MoveOverSelect) + if ( Selecting || (MoveOverSelect && SelectionMode == EGUI_LBS_SINGLE_SELECTION) ) { if (isPointInside(p)) { - selectNew(event.MouseInput.Y, true); + selectNew(event.MouseInput.Y, true, event.MouseInput.Shift, event.MouseInput.Control ); return true; } } @@ -435,14 +438,48 @@ bool CGUIListBox::OnEvent(const SEvent& } -void CGUIListBox::selectNew(s32 ypos, bool onlyHover) +void CGUIListBox::selectNew(s32 ypos, bool onlyHover, bool shift, bool ctrl) { + if ( SelectionMode == EGUI_LBS_NOT_SELECTABLE ) + return; u32 now = os::Timer::getTime(); s32 oldSelected = Selected; // find new selected item. if (ItemHeight!=0) Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + + // set the multiselection flag. The other stuff like active selected can just be ignored. + if ( EGUI_LBS_MULTI_SELECTION == SelectionMode + && Selected < (s32)Items.size() + ) + { + if ( shift ) + { + clearAllItemMultiSelections(); + s32 start = core::min_(Selected, oldSelected); + if ( start < 0 ) + start = 0; + s32 end = core::max_(Selected, oldSelected); + if ( end >= (s32)Items.size() ) + end = Items.size()-1; + for ( s32 i=start; i <= end; ++i ) + { + Items[i].IsMultiSelected = true; + } + Selected = oldSelected; // Selection does not change when shift is pressed + } + else if ( ctrl ) + { + Items[Selected].IsMultiSelected = Items[Selected].IsMultiSelected ? false : true; + } + else + { + clearAllItemMultiSelections(); + Items[Selected].IsMultiSelected = true; + } + } + if (Selected<0) Selected = 0; @@ -459,7 +496,7 @@ void CGUIListBox::selectNew(s32 ypos, bo event.EventType = EET_GUI_EVENT; event.GUIEvent.Caller = this; event.GUIEvent.Element = 0; - event.GUIEvent.EventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED; + event.GUIEvent.EventType = (Selected != oldSelected) || (EGUI_LBS_MULTI_SELECTION == SelectionMode) ? EGET_LISTBOX_CHANGED : EGET_LISTBOX_SELECTED_AGAIN; Parent->OnEvent(event); } selectTime = now; @@ -511,69 +548,64 @@ void CGUIListBox::draw() if (ScrollBar->isVisible()) frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); - frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; - frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); - frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); for (s32 i=0; i<(s32)Items.size(); ++i) { + bool highlightSelected = (SelectionMode != EGUI_LBS_MULTI_SELECTION && i == Selected && hl) + || (SelectionMode == EGUI_LBS_MULTI_SELECTION && Items[i].IsMultiSelected ); + + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + ItemHeight; + if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) { - if (i == Selected && hl) + if ( highlightSelected ) skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); core::rect textRect = frameRect; textRect.UpperLeftCorner.X += 3; + if (IconBank && (Items[i].icon > -1)) + { + core::position2di iconPos = textRect.UpperLeftCorner; + iconPos.Y += textRect.getHeight() / 2; + iconPos.X += ItemsIconWidth/2; + + if ( highlightSelected ) + { + IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? + getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), + selectTime, os::Timer::getTime(), false, true); + } + else + { + IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, + hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), + 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + } + } + if (Font) { - if (IconBank && (Items[i].icon > -1)) - { - core::position2di iconPos = textRect.UpperLeftCorner; - iconPos.Y += textRect.getHeight() / 2; - iconPos.X += ItemsIconWidth/2; - - if ( i==Selected && hl ) - { - IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, - hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ? - getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT), - selectTime, os::Timer::getTime(), false, true); - } - else - { - IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, - hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON), - 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); - } - } - textRect.UpperLeftCorner.X += ItemsIconWidth+3; - if ( i==Selected && hl ) - { - Font->draw(Items[i].text.c_str(), textRect, - hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? - getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT), - false, true, &clientClip); - } + video::SColor textCol; + if ( highlightSelected ) + textCol = hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ? getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT); else - { - Font->draw(Items[i].text.c_str(), textRect, - hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT), - false, true, &clientClip); - } + textCol = hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT); + + Font->draw(Items[i].text.c_str(), textRect, textCol, false, true, &clientClip); textRect.UpperLeftCorner.X -= ItemsIconWidth+3; } } - frameRect.UpperLeftCorner.Y += ItemHeight; - frameRect.LowerRightCorner.Y += ItemHeight; + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y; } IGUIElement::draw(); @@ -676,6 +708,7 @@ void CGUIListBox::serializeAttributes(io out->addBool ("DrawBack", DrawBack); out->addBool ("MoveOverSelect", MoveOverSelect); out->addBool ("AutoScroll", AutoScroll); + out->addEnum ("SelectionMode", SelectionMode, GUIListBoxSelectionNames ); out->addInt("ItemCount", Items.size()); for (u32 i=0;igetAttributeAsBool("DrawBack"); MoveOverSelect = in->getAttributeAsBool("MoveOverSelect"); AutoScroll = in->getAttributeAsBool("AutoScroll"); + SelectionMode = (EGUI_LISTBOX_SELECTION) in->getAttributeAsEnumeration("SelectionMode", GUIListBoxSelectionNames ); IGUIListBox::deserializeAttributes(in,options); @@ -892,6 +926,71 @@ void CGUIListBox::setDrawBackground(bool DrawBack = draw; } +void CGUIListBox::setSelectionMode(EGUI_LISTBOX_SELECTION selection) +{ + SelectionMode = selection; + if ( SelectionMode != EGUI_LBS_SINGLE_SELECTION ) + setSelected(-1); +} + +EGUI_LISTBOX_SELECTION CGUIListBox::getSelectionMode() const +{ + return SelectionMode; +} + +//! Get the number of items which are currently selected +//! This works only in EGUI_LBS_MULTI_SELECTION mode +u32 CGUIListBox::getMultiSelectedItemCount() const +{ + u32 count = 0; + for ( u32 i = 0; i < Items.size(); ++i ) + if ( Items[i].IsMultiSelected ) + ++count; + + return count; +} + +//! Get the id of the next item with set selection flag +//! returns the first item with selection flag when id=-1 +//! return -1 when no item was found +//! This works only in EGUI_LBS_MULTI_SELECTION mode +s32 CGUIListBox::getNextMultiSelectedItem(s32 id) const +{ + for ( s32 i = id+1; i < (s32)Items.size(); ++i ) + if ( Items[i].IsMultiSelected ) + return i; + + return -1; +} + +//! Set the selection flag for the item with given id +//! Usually that will be done automatically when the users clicks. +//! This works only in EGUI_LBS_MULTI_SELECTION mode +void CGUIListBox::setItemMultiSelection(u32 id, bool selected) +{ + if ( id >= Items.size() ) + return; + + Items[id].IsMultiSelected = selected; +} + +//! Get the selection flag for the item with given id +//! This works only in EGUI_LBS_MULTI_SELECTION mode +bool CGUIListBox::getItemMultiSelection(u32 id) const +{ + if ( id >= Items.size() ) + return false; + + return Items[id].IsMultiSelected; +} + +//! Clear the selection flags for all items +//! This works only in EGUI_LBS_MULTI_SELECTION mode +void CGUIListBox::clearAllItemMultiSelections() +{ + for ( u32 i = 0; i < Items.size(); ++i ) + Items[i].IsMultiSelected = false; +} } // end namespace gui } // end namespace irr diff -r 9b90dec5e6a7 lib/irrlicht/source/Irrlicht/CGUIListBox.h --- a/lib/irrlicht/source/Irrlicht/CGUIListBox.h Wed Sep 23 01:31:00 2009 +0200 +++ b/lib/irrlicht/source/Irrlicht/CGUIListBox.h Wed Sep 23 01:40:14 2009 +0200 @@ -128,16 +128,46 @@ namespace gui //! Sets whether to draw the background virtual void setDrawBackground(bool draw); + //! Set the current selection mode for the listbox lines + virtual void setSelectionMode(EGUI_LISTBOX_SELECTION selection); + + //! Get the current selection mode for the listbox lines + virtual EGUI_LISTBOX_SELECTION getSelectionMode() const; + + //! Get the number of items which are currently selected + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual u32 getMultiSelectedItemCount() const; + + //! Get the id of the next item with set selection flag + //! returns the first item with selection flag when id=-1 + //! return -1 when no item was found + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual s32 getNextMultiSelectedItem(s32 id=-1) const; + + //! Set the selection flag for the item with given id + //! Usually that will be done automatically when the users clicks. + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void setItemMultiSelection(u32 id, bool selected); + + //! Get the selection flag for the item with given id + //! return true when the item is selected, otherwise returns false + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual bool getItemMultiSelection(u32 id) const; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections(); private: struct ListItem { - ListItem() : icon(-1) + ListItem() : icon(-1), IsMultiSelected(false) {} core::stringw text; s32 icon; + bool IsMultiSelected; // A multicolor extension struct ListItemOverrideColor @@ -150,7 +180,7 @@ namespace gui }; void recalculateItemHeight(); - void selectNew(s32 ypos, bool onlyHover=false); + void selectNew(s32 ypos, bool onlyHover=false, bool shift=false, bool ctrl=false); void recalculateScrollPos(); // extracted that function to avoid copy&paste code @@ -176,6 +206,7 @@ namespace gui bool MoveOverSelect; bool AutoScroll; bool HighlightWhenNotFocused; + EGUI_LISTBOX_SELECTION SelectionMode; };