diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/include/IGUIListBox.h Irrlicht_starsonata/include/IGUIListBox.h --- irrlicht-svn-ss/trunk/include/IGUIListBox.h 2007-07-26 02:11:22.000000000 +0200 +++ Irrlicht_starsonata/include/IGUIListBox.h 2008-06-06 07:04:56.000000000 +0200 @@ -6,6 +6,9 @@ #define __I_GUI_LIST_BOX_BAR_H_INCLUDED__ #include "IGUIElement.h" +// -------------------------------------------------------- +#include "SColor.h" +// -------------------------------------------------------- namespace irr { @@ -13,12 +16,71 @@ namespace gui { class IGUIFont; class IGUISpriteBank; + class IGUIScrollBar; + + enum EGUI_LISTBOX_COLOR + { + EGUI_LBC_TEXT, + EGUI_LBC_TEXT_HIGHLIGHT, + EGUI_LBC_ICON, + EGUI_LBC_ICON_HIGHLIGHT, + + EGUI_LBC_SIZE + }; + + 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 + }; + + enum EGUI_LISTBOX_SCROLLING + { + //! don't scroll the listbox automatically + EGUI_LBSC_MANUAL, + //! always scroll so that the selected item is visible + EGUI_LBSC_TO_SELECTED, + //! scroll to the latest item which was added or inserted + EGUI_LBSC_TO_ADDED, + //! like EGUI_LBSC_TO_SELECTED + EGUI_LBSC_TO_ADDED + EGUI_LBSC_TO_ACTIVE, + //! Similar to EGUI_LBSC_TO_ACTIVE, + //! but don't scroll to the newest added item when the thumb is not + //! in the lowest position (avoid hindering users scrolling up while adding messages). + EGUI_LBSC_CHATLIKE + }; + + //! Names for EGUI_LISTBOX_SCROLLING + const c8* const GUIListBoxScrollingNames[] = + { + "manual", + "selected", + "added", + "active", + "chatlike", + 0 + }; + //! Default list box GUI element. class IGUIListBox : public IGUIElement { public: - //! constructor IGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) : IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle) {} @@ -63,14 +125,112 @@ namespace gui //! sets the selected item. Set this to -1 if no item should be selected virtual void setSelected(s32 id) = 0; - //! set whether the listbox should scroll to show a newly selected item - //! or a new item as it is added to the list. - virtual void setAutoScrollEnabled(bool scroll) = 0; + //! StarSonata, Micha: instead of setAutoScrollEnabled + //! Define when and how the listbox should scroll automaticaly + virtual void setScrollStyle( EGUI_LISTBOX_SCROLLING style=EGUI_LBSC_TO_SELECTED) = 0; - //! returns true if automatic scrolling is enabled, false if not. - virtual bool isAutoScrollEnabled() = 0; + //! StarSonata, Micha: instead of isAutoScrollEnabled + //! Get when and how the listbox will scroll automaticaly + virtual EGUI_LISTBOX_SCROLLING getScrollStyle() const = 0; - }; + //! StarSonata, Micha: replacing recalculateScrollPos + //! Scroll the listbox until the item with the given id is visible + virtual void scrollToItem(s32 id) = 0; + + // StarSonata, Micha: scrollbar visibility + //! Show scrollbar all the time. + //! By default it's only visible when so many items are in the listbox that + //! scrolling will be needed. + virtual void setScrollbarAlwaysVisible(bool always_) = 0; + + // MICHA, StarSonata, multicolor support + //! is the scrollbar set to be visible all the time? + virtual bool isScrollbarAlwaysVisible() const = 0; + + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar=true) = 0; + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(bool includeScrollbar=true) = 0; + + // MICHA, StarSonata, multicolor support + //! set all item colors at given index to color + virtual void setItemOverrideColor(s32 index, const video::SColor &color) = 0; + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color) = 0; + + //! clear all item colors at index + virtual void clearItemOverrideColor(s32 index) = 0; + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! has the item at index it's color overwritten? + virtual bool hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) = 0; + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) = 0; + + //! set the item at the given index + //! If icon is -1 no icon will be used + virtual void setItem(s32 index, const wchar_t* text, s32 icon) = 0; + + //! Insert the item at the given index + //! If icon is -1 no icon will be used + //! Return the index on success or -1 on failure. + virtual s32 insertItem(s32 index, const wchar_t* text, s32 icon) = 0; + + //! Swap the items at the given indices + virtual void swapItems(s32 index1, s32 index2) = 0; + + //! Enables or disables word wrap. Default is disabled. + /** \param enable: If set to true, words going over one line are + broken to the next line. */ + virtual void setWordWrap(bool enable) = 0; + + //! Checks if word wrap is enabled + //! \return true if word wrap is enabled, false otherwise + virtual bool isWordWrapEnabled() = 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 s32 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) = 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(s32 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(s32 id) const = 0; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections() = 0; + + //! Access the scrollbar + virtual IGUIScrollBar* getScrollBar() const = 0; +}; } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.cpp Irrlicht_starsonata/source/Irrlicht/CGUIListBox.cpp --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.cpp 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIListBox.cpp 2008-06-07 11:20:00.000000000 +0200 @@ -21,10 +21,12 @@ CGUIListBox::CGUIListBox(IGUIEnvironment s32 id, core::rect rectangle, bool clip, bool drawBack, bool moveOverSelect) : IGUIListBox(environment, parent, id, rectangle), Selected(-1), ItemHeight(0), - TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), + TotalItemHeight(0), ItemsIconWidth(0), Font(0), FontUsedToWrap(0), IconBank(0), ScrollBar(0), Selecting(false), DrawBack(drawBack), - MoveOverSelect(moveOverSelect), selectTime(0), AutoScroll(true), + MoveOverSelect(moveOverSelect), selectTime(0), ScrollStyle(EGUI_LBSC_TO_SELECTED), + ScrollbarAlwaysVisible(false), KeyBuffer(), LastKeyTime(0), HighlightWhenNotFocused(true) + ,WordWrap(false), SelectionMode(EGUI_LBS_SINGLE_SELECTION) { #ifdef _DEBUG setDebugName("CGUIListBox"); @@ -39,7 +41,7 @@ CGUIListBox::CGUIListBox(IGUIEnvironment ScrollBar->setSubElement(true); ScrollBar->setTabStop(false); ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); - ScrollBar->setVisible(false); + ScrollBar->setVisible(ScrollbarAlwaysVisible); ScrollBar->drop(); ScrollBar->setPos(0); @@ -64,6 +66,9 @@ CGUIListBox::~CGUIListBox() if (Font) Font->drop(); + if ( FontUsedToWrap ) + FontUsedToWrap->drop(); + if (IconBank) IconBank->drop(); } @@ -84,7 +89,7 @@ const wchar_t* CGUIListBox::getListItem( if (id<0 || id>((s32)Items.size())-1) return 0; - return Items[id].text.c_str(); + return Items[id].Text.c_str(); } //! Returns the icon of an item @@ -93,21 +98,14 @@ s32 CGUIListBox::getIcon(s32 id) const if (id<0 || id>((s32)Items.size())-1) return -1; - return Items[id].icon; + return Items[id].Icon; } //! adds an list item, returns id of item s32 CGUIListBox::addItem(const wchar_t* text) { - ListItem i; - i.text = text; - - Items.push_back(i); - recalculateItemHeight(); - recalculateScrollPos(); - - return Items.size() - 1; + return addItem(text, -1); } //! adds an list item, returns id of item @@ -149,8 +147,10 @@ void CGUIListBox::clear() -void CGUIListBox::recalculateItemHeight() +void CGUIListBox::recalculateItemHeight(bool onlyIfFontChanged_) { + // TODO: this does ignore icons so far + IGUISkin* skin = Environment->getSkin(); if (Font != skin->getFont()) @@ -167,11 +167,26 @@ void CGUIListBox::recalculateItemHeight( Font->grab(); } } + else if ( onlyIfFontChanged_ ) + return; + if ( WordWrap ) + { + TotalItemHeight = 0; + for ( s32 i=0; i < (s32)Items.size(); ++i ) + { + TotalItemHeight += Items[i].WrappedText.size() * ItemHeight; + } + } + else + { TotalItemHeight = ItemHeight * Items.size(); + } ScrollBar->setMax(TotalItemHeight - AbsoluteRect.getHeight()); + s32 pageSize = TotalItemHeight ? core::round32((f32)ScrollBar->getMax()*((f32)AbsoluteRect.getHeight() / (f32)TotalItemHeight)) : 1; + ScrollBar->setPageSize(pageSize); - if( TotalItemHeight <= AbsoluteRect.getHeight() ) + if( TotalItemHeight <= AbsoluteRect.getHeight() && !ScrollbarAlwaysVisible ) ScrollBar->setVisible(false); else ScrollBar->setVisible(true); @@ -191,14 +206,14 @@ s32 CGUIListBox::getSelected() //! sets the selected item. Set this to -1 if no item should be selected void CGUIListBox::setSelected(s32 id) { - if (id<0 || id>((s32)Items.size())-1) + if (id<0 || id>((s32)Items.size())-1 ) Selected = -1; else Selected = id; selectTime = os::Timer::getTime(); - recalculateScrollPos(); + scrollToItem(Selected); } @@ -206,10 +221,14 @@ void CGUIListBox::setSelected(s32 id) //! called if an event happened. bool CGUIListBox::OnEvent(SEvent event) { + if (!IsEnabled) + return IGUIElement::OnEvent(event); + 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 || @@ -247,7 +266,7 @@ bool CGUIListBox::OnEvent(SEvent event) if (Selected<0) Selected = 0; - recalculateScrollPos(); + scrollToItem(Selected); // post the news @@ -277,7 +296,8 @@ bool CGUIListBox::OnEvent(SEvent event) } 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(); @@ -304,16 +324,16 @@ bool CGUIListBox::OnEvent(SEvent event) // dont change selection if the key buffer matches the current item if (Selected > -1 && KeyBuffer.size() > 1) { - if (Items[Selected].text.size() >= KeyBuffer.size() && - KeyBuffer.equals_ignore_case(Items[Selected].text.subString(0,KeyBuffer.size()))) + if (Items[Selected].Text.size() >= KeyBuffer.size() && + KeyBuffer.equals_ignore_case(Items[Selected].Text.subString(0,KeyBuffer.size()))) return true; } while (current < (s32)Items.size()) { - if (Items[current].text.size() >= KeyBuffer.size()) + if (Items[current].Text.size() >= KeyBuffer.size()) { - if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) { if (Parent && Selected != current && !Selecting && !MoveOverSelect) { @@ -333,9 +353,9 @@ bool CGUIListBox::OnEvent(SEvent event) current = 0; while (current <= start) { - if (Items[current].text.size() >= KeyBuffer.size()) + if (Items[current].Text.size() >= KeyBuffer.size()) { - if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + if (KeyBuffer.equals_ignore_case(Items[current].Text.subString(0,KeyBuffer.size()))) { if (Parent && Selected != current && !Selecting && !MoveOverSelect) { @@ -399,15 +419,28 @@ bool CGUIListBox::OnEvent(SEvent event) } Selecting = false; - selectNew(event.MouseInput.Y); + selectNew(event.MouseInput.Y, false, event.MouseInput.Shift, event.MouseInput.Control ); return true; + case EMIE_LMOUSE_DOUBLE_CLICK: + { + if (Parent) + { + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.EventType = EGET_ELEMENT_DOUBLE_CLICKED; + Parent->OnEvent(event); + } + break; + } + 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; } } @@ -419,25 +452,74 @@ bool CGUIListBox::OnEvent(SEvent event) } - return Parent ? Parent->OnEvent(event) : false; + return IGUIElement::OnEvent(event); } -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; s32 oldSelected = Selected; // find new selected item. if (ItemHeight!=0) - Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + { + s32 selectedLine = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight; + + Selected = selectedLine; + if ( WordWrap ) + { + s32 lines = 0; + for ( u32 i=0; i < Items.size(); ++i) + { + lines += Items[i].WrappedText.size(); + if ( lines > selectedLine ) + { + Selected = i; + break; + } + } + } + } + + // 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 >= (s32)Items.size()) Selected = Items.size() - 1; - else - if (Selected<0) + else if (Selected<0) Selected = 0; - recalculateScrollPos(); + scrollToItem(Selected); // post the news if (Parent && !onlyHover) @@ -446,7 +528,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) ? EGET_LISTBOX_CHANGED : EGET_LISTBOX_SELECTED_AGAIN; + event.GUIEvent.EventType = (Selected != oldSelected) || (EGUI_LBS_MULTI_SELECTION == SelectionMode) ? EGET_LISTBOX_CHANGED : EGET_LISTBOX_SELECTED_AGAIN; Parent->OnEvent(event); } } @@ -457,6 +539,7 @@ void CGUIListBox::updateAbsolutePosition IGUIElement::updateAbsolutePosition(); recalculateItemHeight(); + wrapAllText(); } //! draws the element and its children @@ -465,7 +548,12 @@ void CGUIListBox::draw() if (!IsVisible) return; - recalculateItemHeight(); // if the font changed + if ( FontUsedToWrap != Font && WordWrap ) + { + wrapAllText(); + } + + recalculateItemHeight(true); IGUISkin* skin = Environment->getSkin(); @@ -474,8 +562,6 @@ void CGUIListBox::draw() // draw background core::rect frameRect(AbsoluteRect); - // draw items - core::rect clientClip(AbsoluteRect); clientClip.UpperLeftCorner.Y += 1; clientClip.UpperLeftCorner.X += 1; @@ -484,9 +570,13 @@ void CGUIListBox::draw() clientClip.LowerRightCorner.Y -= 1; clientClip.clipAgainst(AbsoluteClippingRect); - skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, + video::SColor backgroundCol = BackgroundOverrideColor.Use ? BackgroundOverrideColor.Color : skin->getColor(EGDC_3D_HIGH_LIGHT); + + skin->draw3DSunkenPane(this, backgroundCol, true, DrawBack, frameRect, &clientClip); + // draw items + if (clipRect) clientClip.clipAgainst(*clipRect); @@ -495,46 +585,84 @@ 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 ); + + if ( WordWrap ) + { + frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + ItemHeight * Items[i].WrappedText.size(); + } + else + { + 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 (Font) - { - if (IconBank && (Items[i].icon > -1)) + if (IconBank && (Items[i].Icon > -1)) { core::position2di iconPos = textRect.UpperLeftCorner; iconPos.Y += textRect.getHeight() / 2; iconPos.X += ItemsIconWidth/2; - IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, - skin->getColor((i==Selected && hl) ? EGDC_ICON_HIGH_LIGHT : EGDC_ICON), - (i==Selected && hl) ? selectTime : 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + + 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) + { textRect.UpperLeftCorner.X += ItemsIconWidth+3; - Font->draw(Items[i].text.c_str(), textRect, skin->getColor((i==Selected && hl) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT), 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 + textCol = hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT); + + if ( WordWrap ) + { + for ( u32 w=0; w < Items[i].WrappedText.size(); ++w ) + { + textRect.LowerRightCorner.Y = textRect.UpperLeftCorner.Y + ItemHeight; + Font->draw(Items[i].WrappedText[w].c_str(), textRect, textCol, false, true, &clientClip); + textRect.UpperLeftCorner.Y = textRect.LowerRightCorner.Y; + } + } + else + { + 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(); @@ -546,29 +674,29 @@ void CGUIListBox::draw() s32 CGUIListBox::addItem(const wchar_t* text, s32 icon) { ListItem i; - i.text = text; - i.icon = icon; + i.Text = text; + i.Icon = icon; + + if ( WordWrap ) + wrapText(i); + + bool scrollOnChat = ScrollStyle == EGUI_LBSC_CHATLIKE && ScrollBar->getPos() == ScrollBar->getMax(); Items.push_back(i); recalculateItemHeight(); + recalculateItemWidth(icon); - if (IconBank && icon > -1 && - IconBank->getSprites().size() > (u32)icon && - IconBank->getSprites()[(u32)icon].Frames.size()) - { - u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; - if (IconBank->getPositions().size() > rno) + if ( ScrollStyle == EGUI_LBSC_TO_ADDED + || ScrollStyle == EGUI_LBSC_TO_ACTIVE + || scrollOnChat + ) { - const s32 w = IconBank->getPositions()[rno].getWidth(); - if (w > ItemsIconWidth) - ItemsIconWidth = w; - } + ScrollBar->setPos(ScrollBar->getMax()); } return Items.size() - 1; } - void CGUIListBox::setSpriteBank(IGUISpriteBank* bank) { if (IconBank) @@ -578,33 +706,83 @@ void CGUIListBox::setSpriteBank(IGUISpri if (IconBank) IconBank->grab(); } -void CGUIListBox::recalculateScrollPos() + +void CGUIListBox::scrollToItem(s32 itemId) { - if (!AutoScroll) + if (ScrollStyle == EGUI_LBSC_MANUAL || ScrollStyle == EGUI_LBSC_TO_ADDED) return; - s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos(); + // height from top of list if the complete list would be visible + s32 selectedItemHeight = itemId < 0 ? 0 : itemId * ItemHeight; + if ( WordWrap && itemId >= 0 ) + { + selectedItemHeight = 0; + for ( s32 i=0; igetPos(); if (selPos < 0) { ScrollBar->setPos(ScrollBar->getPos() + selPos); } - else - if (selPos > AbsoluteRect.getHeight() - ItemHeight) + else if (selPos > AbsoluteRect.getHeight() - ItemHeight) { ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight); } } -void CGUIListBox::setAutoScrollEnabled(bool scroll) +void CGUIListBox::setScrollStyle( EGUI_LISTBOX_SCROLLING style) { - AutoScroll = scroll; + ScrollStyle = style; } -bool CGUIListBox::isAutoScrollEnabled() +EGUI_LISTBOX_SCROLLING CGUIListBox::getScrollStyle() const { - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return AutoScroll; + return ScrollStyle; +} + +void CGUIListBox::setScrollbarAlwaysVisible(bool always_) +{ + ScrollbarAlwaysVisible = always_; + if ( ScrollbarAlwaysVisible && ScrollBar ) + { + ScrollBar->setVisible(true); + } +} + +bool CGUIListBox::isScrollbarAlwaysVisible() const +{ + return ScrollbarAlwaysVisible; +} + +bool CGUIListBox::getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel) +{ + switch ( colorType ) + { + case EGUI_LBC_TEXT: + useColorLabel = "UseColText"; + colorLabel = "ColText"; + break; + case EGUI_LBC_TEXT_HIGHLIGHT: + useColorLabel = "UseColTextHl"; + colorLabel = "ColTextHl"; + break; + case EGUI_LBC_ICON: + useColorLabel = "UseColIcon"; + colorLabel = "ColIcon"; + break; + case EGUI_LBC_ICON_HIGHLIGHT: + useColorLabel = "UseColIconHl"; + colorLabel = "ColIconHl"; + break; + default: + return false; + } + return true; } //! Writes attributes of the element. @@ -615,16 +793,50 @@ void CGUIListBox::serializeAttributes(io // todo: out->addString ("IconBank", IconBank->getName?); out->addBool ("DrawBack", DrawBack); out->addBool ("MoveOverSelect", MoveOverSelect); - out->addBool ("AutoScroll", AutoScroll); + out->addEnum ("ScrollStyle", ScrollStyle, GUIListBoxScrollingNames ); + out->addBool ("ScrollbarAlwaysVisible", ScrollbarAlwaysVisible); + out->addBool ("WordWrap", WordWrap); + out->addEnum ("SelectionMode", SelectionMode, GUIListBoxSelectionNames ); - // todo: save list of items and icons. + // StarSonata, Micha: + // I also don't know yet how to handle icons, but added some text+color serialization now + // I did it the same way it's done for the context menus + out->addInt("ItemCount", Items.size()); + u32 i; + for (i=0;iaddString(label.c_str(), Items[i].Text.c_str() ); + + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + if ( Items[i].OverrideColors[c].Use ) + { + out->addBool(label.c_str(), true ); + label = colorLabel; label += i; + out->addColor(label.c_str(), Items[i].OverrideColors[c].Color); + } + else + { + out->addBool(label.c_str(), false ); + } + } + } + + // todo: icons. /*core::array tmpText; core::array tmpIcons; u32 i; for (i=0;iaddArray ("ItemText", tmpText); @@ -638,12 +850,51 @@ void CGUIListBox::serializeAttributes(io //! Reads attributes of the element void CGUIListBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { + clear(); + DrawBack = in->getAttributeAsBool("DrawBack"); MoveOverSelect = in->getAttributeAsBool("MoveOverSelect"); - AutoScroll = in->getAttributeAsBool("AutoScroll"); + ScrollStyle = (EGUI_LISTBOX_SCROLLING) in->getAttributeAsEnumeration("ScrollStyle", GUIListBoxScrollingNames); + ScrollbarAlwaysVisible = in->getAttributeAsBool("ScrollbarAlwaysVisible"); + WordWrap = in->getAttributeAsBool("WordWrap"); + SelectionMode = (EGUI_LISTBOX_SELECTION) in->getAttributeAsEnumeration("SelectionMode", GUIListBoxSelectionNames ); IGUIListBox::deserializeAttributes(in,options); + // StarSonata, Micha: + // I also don't know yet how to handle icons, but added some text+color serialization now + // I did it the same way it's done for the context menus + s32 count = in->getAttributeAsInt("ItemCount"); + for (s32 i=0; i<(s32)count; ++i) + { + core::stringc label; + ListItem item; + + label = "text"; label += i; + item.Text = in->getAttributeAsStringW(label.c_str()); + + addItem(item.Text.c_str(), item.Icon); + + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + core::stringc useColorLabel, colorLabel; + if ( !getSerializationLabels((EGUI_LISTBOX_COLOR)c, useColorLabel, colorLabel) ) + return; + label = useColorLabel; label += i; + Items[i].OverrideColors[c].Use = in->getAttributeAsBool(label.c_str()); + if ( Items[i].OverrideColors[c].Use ) + { + label = colorLabel; label += i; + Items[i].OverrideColors[c].Color = in->getAttributeAsColor(label.c_str()); + } + } + } + + if ( WordWrap ) + { + wrapAllText(); + } + // read arrays /* core::array tmpText; @@ -660,6 +911,392 @@ void CGUIListBox::deserializeAttributes( } +void CGUIListBox::recalculateItemWidth(s32 icon) +{ + if (IconBank && icon > -1 && + IconBank->getSprites().size() > (u32)icon && + IconBank->getSprites()[(u32)icon].Frames.size()) + { + u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber; + if (IconBank->getPositions().size() > rno) + { + const s32 w = IconBank->getPositions()[rno].getWidth(); + if (w > ItemsIconWidth) + ItemsIconWidth = w; + } + } +} + +void CGUIListBox::setItem(s32 index, const wchar_t* text, s32 icon) +{ + if ( index < 0 || index >= (s32)Items.size() ) + return; + + Items[index].Text = text; + Items[index].Icon = icon; + + if ( WordWrap ) + wrapText(Items[index]); + + recalculateItemHeight(); + recalculateItemWidth(icon); +} + +//! Insert the item at the given index +//! Return the index on success or -1 on failure. +s32 CGUIListBox::insertItem(s32 index, const wchar_t* text, s32 icon) +{ + if ( index < 0 ) + return -1; + ListItem i; + i.Text = text; + i.Icon = icon; + + if ( WordWrap ) + wrapText(i); + + Items.insert(i, index); + recalculateItemHeight(); + recalculateItemWidth(icon); + + if ( ScrollStyle == EGUI_LBSC_TO_ADDED + || ScrollStyle == EGUI_LBSC_TO_ACTIVE + || ScrollStyle == EGUI_LBSC_CHATLIKE + ) + { + scrollToItem(index); + } + + return index; +} + +void CGUIListBox::swapItems(s32 index1, s32 index2) +{ + if ( index1 < 0 || index2 < 0 || index1 >= (s32)Items.size() || index2 >= (s32)Items.size() ) + return; + + ListItem dummmy = Items[index1]; + Items[index1] = Items[index2]; + Items[index2] = dummmy; +} + +void CGUIListBox::setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar) +{ + BackgroundOverrideColor.Use = true; + BackgroundOverrideColor.Color = color; + + if ( includeScrollbar && ScrollBar ) + { + ScrollBar->setBackgroundOverrideColor(color); + } +} + +void CGUIListBox::clearBackgroundOverrideColor(bool includeScrollbar) +{ + BackgroundOverrideColor.Use = false; + if ( includeScrollbar && ScrollBar ) + { + ScrollBar->clearBackgroundOverrideColor(); + } +} + +void CGUIListBox::setItemOverrideColor(s32 index, const video::SColor &color) +{ + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + Items[index].OverrideColors[c].Use = true; + Items[index].OverrideColors[c].Color = color; + } +} + +void CGUIListBox::setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return; + + Items[index].OverrideColors[colorType].Use = true; + Items[index].OverrideColors[colorType].Color = color; +} + +void CGUIListBox::clearItemOverrideColor(s32 index) +{ + for ( int c=0; c < (int)EGUI_LBC_SIZE; ++c ) + { + Items[index].OverrideColors[c].Use = false; + } +} + +void CGUIListBox::clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return; + + Items[index].OverrideColors[colorType].Use = false; +} + +bool CGUIListBox::hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return false; + + return Items[index].OverrideColors[colorType].Use; +} + +video::SColor CGUIListBox::getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType) +{ + if ( index < 0 || index >= (s32)Items.size() || colorType < 0 || colorType >= EGUI_LBC_SIZE ) + return video::SColor(); + + return Items[index].OverrideColors[colorType].Color; +} + +video::SColor CGUIListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) +{ + IGUISkin* skin = Environment->getSkin(); + if ( !skin ) + return video::SColor(); + + switch ( colorType ) + { + case EGUI_LBC_TEXT: + return skin->getColor(EGDC_BUTTON_TEXT); + case EGUI_LBC_TEXT_HIGHLIGHT: + return skin->getColor(EGDC_HIGH_LIGHT_TEXT); + case EGUI_LBC_ICON: + return skin->getColor(EGDC_ICON); + case EGUI_LBC_ICON_HIGHLIGHT: + return skin->getColor(EGDC_ICON_HIGH_LIGHT); + default: + return video::SColor(); + } +} + +// TODO: This can't handle text without whitespaces. +// TODO: this is mostly copied from CGUIEditBox::breakText +// This part _should_ be an own class. For example CSplitTextLines. +// But that needs some more talk with the irrlicht guys and they are currently +// to busy getting 1.4 out which is already in beta, so this has to wait. +// So for now I put it in here (because I need it for the listbox) and made it at least a little more general so it can +// be moved to some other place without so much trouble later on. +void CGUIListBox::breakText( const core::stringw &origText, s32 maxWidth, gui::IGUIFont* font, bool wordWrap, bool multiLine, core::array &brokenText, core::array &brokenTextPositions) +{ + if ((!wordWrap && !multiLine) || !font || maxWidth <= 0) + { + brokenText.push_back(origText); + return; + } + + brokenText.clear(); // need to reallocate :/ + brokenTextPositions.set_used(0); + + core::stringw text(origText); // we need that currently because of windows break handling :( + core::stringw line; + core::stringw word; + core::stringw whitespace; + s32 lastLineStart = 0; + s32 size = origText.size(); + s32 length = 0; + wchar_t c; + + for (s32 i=0; igetDimension(whitespace.c_str()).Width; + s32 worldlgth = font->getDimension(word.c_str()).Width; + + if (wordWrap && length + worldlgth + whitelgth > maxWidth) + { + // break to next line + length = worldlgth; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); + lastLineStart = i - (s32)word.size(); + line = word; + } + else + { + // add word to line + line += whitespace; + line += word; + length += whitelgth + worldlgth; + } + + word = L""; + whitespace = L""; + } + + whitespace += c; + + // compute line break + if (lineBreak) + { + line += whitespace; + line += word; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); + lastLineStart = i+1; + line = L""; + word = L""; + whitespace = L""; + length = 0; + } + } + else + { + // yippee this is a word.. + word += c; + } + } + + line += whitespace; + line += word; + brokenText.push_back(line); + brokenTextPositions.push_back(lastLineStart); +} + +// create wrapped text for all lines +void CGUIListBox::wrapAllText() +{ + for ( s32 i = 0; i < (s32)Items.size(); ++i ) + { + wrapText(Items[i]); + } +} + +void CGUIListBox::wrapText( ListItem & item ) +{ + if ( FontUsedToWrap != Font ) + { + if ( FontUsedToWrap ) + FontUsedToWrap->drop(); + FontUsedToWrap = Font; + FontUsedToWrap->grab(); + } + + core::array brokenTextPositions; // we don't need it here + + // the reduction by 7 was calculated by adding the pixels by which the width is reduced in draw + s32 maxWidth = AbsoluteRect.getWidth()-(ItemsIconWidth+7); + if (ScrollBar->isVisible()) + maxWidth -= Environment->getSkin()->getSize(EGDS_SCROLLBAR_SIZE); + + breakText( item.Text, maxWidth, FontUsedToWrap, WordWrap, /*bool multiLine*/ true, item.WrappedText, brokenTextPositions); +} + +void CGUIListBox::setWordWrap(bool enable) +{ + if ( enable == WordWrap ) + return; + + WordWrap = enable; + if ( WordWrap ) + { + wrapAllText(); + } +} + +bool CGUIListBox::isWordWrapEnabled() +{ + return WordWrap; +} + +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 +s32 CGUIListBox::getMultiSelectedItemCount() const +{ + s32 count = 0; + for ( s32 i = 0; i < (s32)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) +{ + 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(s32 id, bool selected) +{ + if ( id < 0 || id >= (s32)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(s32 id) const +{ + if ( id < 0 || id >= (s32)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 ( s32 i = 0; i < (s32)Items.size(); ++i ) + Items[i].IsMultiSelected = false; +} + + +// -------------------------------------------------------- + } // end namespace gui diff -abBdpuNPr --exclude='*.svn' irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.h Irrlicht_starsonata/source/Irrlicht/CGUIListBox.h --- irrlicht-svn-ss/trunk/source/Irrlicht/CGUIListBox.h 2007-07-26 02:11:08.000000000 +0200 +++ Irrlicht_starsonata/source/Irrlicht/CGUIListBox.h 2008-06-06 07:03:10.000000000 +0200 @@ -71,11 +71,27 @@ namespace gui //! skin through getIcon virtual void setSpriteBank(IGUISpriteBank* bank); - //! sets if automatic scrolling is enabled or not. Default is true. - virtual void setAutoScrollEnabled(bool scroll); + //! StarSonata, Micha: instead of setAutoScrollEnabled + //! Define when and how the listbox should scroll automaticaly + virtual void setScrollStyle( EGUI_LISTBOX_SCROLLING style=EGUI_LBSC_TO_SELECTED); - //! returns true if automatic scrolling is enabled, false if not. - virtual bool isAutoScrollEnabled(); + //! StarSonata, Micha: instead of isAutoScrollEnabled + //! Get when and how the listbox will scroll automaticaly + virtual EGUI_LISTBOX_SCROLLING getScrollStyle() const; + + //! StarSonata, Micha: replacing recalculateScrollPos + //! Scroll the listbox until the item with the given id is visible + virtual void scrollToItem(s32 itemId); + + // StarSonata, Micha: scrollbar visibility + //! Show scrollbar all the time. + //! By default it's only visible when so many items are in the listbox that + //! scrolling will be needed. + virtual void setScrollbarAlwaysVisible(bool always_); + + // StarSonata, Micha: multicolor support + //! is the scrollbar set to be visible all the time? + virtual bool isScrollbarAlwaysVisible() const; //! Update the position and size of the listbox, and update the scrollbar virtual void updateAbsolutePosition(); @@ -86,19 +102,138 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); + // StarSonata, Micha + //! override the background color + virtual void setBackgroundOverrideColor(const video::SColor &color, bool includeScrollbar); + + // StarSonata, Micha + //! clear the background color override + virtual void clearBackgroundOverrideColor(bool includeScrollbar); + + // StarSonata, Micha: multicolor support + //! set all item colors at given index to color + virtual void setItemOverrideColor(s32 index, const video::SColor &color); + + //! set all item colors of specified type at given index to color + virtual void setItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType, const video::SColor &color); + + //! clear all item colors at index + virtual void clearItemOverrideColor(s32 index); + + //! clear item color at index for given colortype + virtual void clearItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! has the item at index it's color overwritten? + virtual bool hasItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! return the overwrite color at given item index. + virtual video::SColor getItemOverrideColor(s32 index, EGUI_LISTBOX_COLOR colorType); + + //! return the default color which is used for the given colorType + virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType); + + //! set the item at the given index + virtual void setItem(s32 index, const wchar_t* text, s32 icon); + + //! Insert the item at the given index + //! Return the index on success or -1 on failure. + virtual s32 insertItem(s32 index, const wchar_t* text, s32 icon); + + //! Swap the items at the given indices + virtual void swapItems(s32 index1, s32 index2); + + //! Enables or disables word wrap. Default is disabled. + /** \param enable: If set to true, words going over one line are + broken to the next line. */ + virtual void setWordWrap(bool enable); + + //! Checks if word wrap is enabled + //! \return true if word wrap is enabled, false otherwise + virtual bool isWordWrapEnabled(); + + //! 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 s32 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); + + //! 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(s32 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(s32 id) const; + + //! Clear the selection flags for all items + //! This works only in EGUI_LBS_MULTI_SELECTION mode + virtual void clearAllItemMultiSelections(); + + //! Access the scrollbar + virtual IGUIScrollBar* getScrollBar() const { return ScrollBar; } + private: + struct OverrideColor + { + OverrideColor() : Use(false) {} + bool Use; + video::SColor Color; + }; + struct ListItem { - ListItem() : icon(-1) {} + ListItem() : Icon(-1), IsMultiSelected(false) + {} - core::stringw text; - s32 icon; + core::stringw Text; + s32 Icon; + OverrideColor OverrideColors[EGUI_LBC_SIZE]; + + // StarSonata, Micha: + // flag used in multiselection + bool IsMultiSelected; + + // StarSonata, Micha: + // extension for wrapped text + core::array< core::stringw > WrappedText; }; - void recalculateItemHeight(); - void selectNew(s32 ypos, bool onlyHover=false); - void recalculateScrollPos(); + void recalculateItemHeight(bool onlyIfFontChanged_=false); + void selectNew(s32 ypos, bool onlyHover=false, bool shift=false, bool ctrl=false); + + // extracted that function to avoid copy&paste code + void recalculateItemWidth(s32 icon); + + // get labels used for serialization + bool getSerializationLabels(EGUI_LISTBOX_COLOR colorType, core::stringc & useColorLabel, core::stringc & colorLabel); + + // create wrapped text for all lines + void wrapAllText(); + void wrapText( ListItem & item); + + //! break Split text into several lines + // TODO: this should be a common function, for example in font, skin or iguielement + //! \param origText Text which should be split + //! \param maxWidth Width in pixels available for text. + //! \param font Font used to print the text + //! \param wordWrap Wrap into several lines if one line is too long. Prefer wrapping on whitespace. + //! \param multiLine Handle linebreaks like '\n' and '\r' + //! \param brokenText return the text split in several lines + //! \param brokenTextPosition return the positions at which the original text was splitted + void breakText( const core::stringw &origText, s32 maxWidth, gui::IGUIFont* font, bool wordWrap, bool multiLine, core::array &brokenText, core::array &brokenTextPosition); core::array< ListItem > Items; s32 Selected; @@ -106,16 +241,21 @@ namespace gui s32 TotalItemHeight; s32 ItemsIconWidth; gui::IGUIFont* Font; + gui::IGUIFont* FontUsedToWrap; gui::IGUISpriteBank* IconBank; gui::IGUIScrollBar* ScrollBar; bool Selecting; bool DrawBack; bool MoveOverSelect; u32 selectTime; - bool AutoScroll; + EGUI_LISTBOX_SCROLLING ScrollStyle; + bool ScrollbarAlwaysVisible; core::stringw KeyBuffer; u32 LastKeyTime; bool HighlightWhenNotFocused; + bool WordWrap; + EGUI_LISTBOX_SELECTION SelectionMode; + OverrideColor BackgroundOverrideColor; };