Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIListbox.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIListbox.cpp
00003         created:        13/4/2004
00004         author:         Paul D Turner
00005         
00006         purpose:        Implementation of Listbox widget base class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "CEGUIExceptions.h"
00027 #include "CEGUIWindowManager.h"
00028 #include "elements/CEGUIListbox.h"
00029 #include "elements/CEGUIListboxItem.h"
00030 #include "elements/CEGUIScrollbar.h"
00031 #include "elements/CEGUITooltip.h"
00032 
00033 #include <algorithm>
00034 
00035 // Start of CEGUI namespace section
00036 namespace CEGUI
00037 {
00038 const String Listbox::EventNamespace("Listbox");
00039 
00040 /*************************************************************************
00041         Definition of Properties for this class
00042 *************************************************************************/
00043 ListboxProperties::Sort                                 Listbox::d_sortProperty;
00044 ListboxProperties::MultiSelect                  Listbox::d_multiSelectProperty;
00045 ListboxProperties::ForceVertScrollbar   Listbox::d_forceVertProperty;
00046 ListboxProperties::ForceHorzScrollbar   Listbox::d_forceHorzProperty;
00047 ListboxProperties::ItemTooltips                 Listbox::d_itemTooltipsProperty;
00048 
00049 
00050 /*************************************************************************
00051         Constants
00052 *************************************************************************/
00053 // event names
00054 const String Listbox::EventListContentsChanged( (utf8*)"ListItemsChanged" );
00055 const String Listbox::EventSelectionChanged( (utf8*)"ItemSelectionChanged" );
00056 const String Listbox::EventSortModeChanged( (utf8*)"SortModeChanged" );
00057 const String Listbox::EventMultiselectModeChanged( (utf8*)"MuliselectModeChanged" );
00058 const String Listbox::EventVertScrollbarModeChanged( (utf8*)"VertScrollModeChanged" );
00059 const String Listbox::EventHorzScrollbarModeChanged( (utf8*)"HorzScrollModeChanged" );
00060 
00061         
00062 /*************************************************************************
00063         Constructor for Listbox base class.
00064 *************************************************************************/
00065 Listbox::Listbox(const String& type, const String& name)
00066         : Window(type, name),
00067         d_sorted(false),
00068         d_multiselect(false),
00069         d_forceVertScroll(false),
00070         d_forceHorzScroll(false),
00071         d_itemTooltips(false),
00072         d_lastSelected(NULL)
00073 {
00074         // add new events specific to list box.
00075         addListboxEvents();
00076 
00077         addListboxProperties();
00078 }
00079 
00080 
00081 /*************************************************************************
00082         Destructor for Listbox base class.
00083 *************************************************************************/
00084 Listbox::~Listbox(void)
00085 {
00086         resetList_impl();
00087 }
00088 
00089 
00090 /*************************************************************************
00091         Initialise the Window based object ready for use.
00092 *************************************************************************/
00093 void Listbox::initialise(void)
00094 {
00095         // create the component sub-widgets
00096         d_vertScrollbar = createVertScrollbar(getName() + "__auto_vscrollbar__");
00097         d_horzScrollbar = createHorzScrollbar(getName() + "__auto_hscrollbar__");
00098 
00099         addChildWindow(d_vertScrollbar);
00100         addChildWindow(d_horzScrollbar);
00101 
00102     d_vertScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&Listbox::handle_scrollChange, this));
00103     d_horzScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&Listbox::handle_scrollChange, this));
00104 
00105         configureScrollbars();
00106         performChildWindowLayout();
00107 }
00108 
00109 
00110 /*************************************************************************
00111         Return the number of selected items in the list box.    
00112 *************************************************************************/
00113 size_t Listbox::getSelectedCount(void) const
00114 {
00115         size_t count = 0;
00116 
00117         for (size_t index = 0; index < d_listItems.size(); ++index)
00118         {
00119                 if (d_listItems[index]->isSelected())
00120                 {
00121                         count++;
00122                 }
00123 
00124         }
00125 
00126         return count;
00127 }
00128 
00129 
00130 /*************************************************************************
00131         Return a pointer to the first selected item.
00132 *************************************************************************/
00133 ListboxItem* Listbox::getFirstSelectedItem(void) const
00134 {
00135         return getNextSelected(NULL);
00136 }
00137 
00138 
00139 /*************************************************************************
00140         Return a pointer to the next selected item after item 'start_item'
00141 *************************************************************************/
00142 ListboxItem* Listbox::getNextSelected(const ListboxItem* start_item) const
00143 {
00144         // if start_item is NULL begin search at begining, else start at item after start_item
00145         size_t index = (start_item == NULL) ? 0 : (getItemIndex(start_item) + 1);
00146 
00147         while (index < d_listItems.size())
00148         {
00149                 // return pointer to this item if it's selected.
00150                 if (d_listItems[index]->isSelected())
00151                 {
00152                         return d_listItems[index];
00153                 }
00154                 // not selected, advance to next
00155                 else
00156                 {
00157                         index++;
00158                 }
00159 
00160         }
00161 
00162         // no more selected items.
00163         return NULL;
00164 }
00165 
00166 
00167 /*************************************************************************
00168         Return the item at index position 'index'.
00169 *************************************************************************/
00170 ListboxItem* Listbox::getListboxItemFromIndex(size_t index) const
00171 {
00172         if (index < d_listItems.size())
00173         {
00174                 return d_listItems[index];
00175         }
00176         else
00177         {
00178                 throw InvalidRequestException((utf8*)"Listbox::getListboxItemFromIndex - the specified index is out of range for this Listbox.");
00179         }
00180 }
00181 
00182 
00183 /*************************************************************************
00184         Return the index of ListboxItem \a item
00185 *************************************************************************/
00186 size_t Listbox::getItemIndex(const ListboxItem* item) const
00187 {
00188         LBItemList::const_iterator pos = std::find(d_listItems.begin(), d_listItems.end(), item);
00189 
00190         if (pos != d_listItems.end())
00191         {
00192                 return std::distance(d_listItems.begin(), pos);
00193         }
00194         else
00195         {
00196                 throw InvalidRequestException((utf8*)"Listbox::getItemIndex - the specified ListboxItem is not attached to this Listbox.");
00197         }
00198 
00199 }
00200 
00201 
00202 /*************************************************************************
00203         return whether the string at index position \a index is selected
00204 *************************************************************************/
00205 bool Listbox::isItemSelected(size_t index) const
00206 {
00207         if (index < d_listItems.size())
00208         {
00209                 return d_listItems[index]->isSelected();
00210         }
00211         else
00212         {
00213                 throw InvalidRequestException((utf8*)"Listbox::isItemSelected - the specified index is out of range for this Listbox.");
00214         }
00215 
00216 }
00217 
00218 
00219 /*************************************************************************
00220         Search the list for an item with the specified text
00221 *************************************************************************/
00222 ListboxItem* Listbox::findItemWithText(const String& text, const ListboxItem* start_item)
00223 {
00224         // if start_item is NULL begin search at begining, else start at item after start_item
00225         size_t index = (start_item == NULL) ? 0 : (getItemIndex(start_item) + 1);
00226 
00227         while (index < d_listItems.size())
00228         {
00229                 // return pointer to this item if it's text matches
00230                 if (d_listItems[index]->getText() == text)
00231                 {
00232                         return d_listItems[index];
00233                 }
00234                 // no matching text, advance to next item
00235                 else
00236                 {
00237                         index++;
00238                 }
00239 
00240         }
00241 
00242         // no items matched.
00243         return NULL;
00244 }
00245 
00246 
00247 /*************************************************************************
00248         Return whether the specified ListboxItem is in the List
00249 *************************************************************************/
00250 bool Listbox::isListboxItemInList(const ListboxItem* item) const
00251 {
00252         return std::find(d_listItems.begin(), d_listItems.end(), item) != d_listItems.end();
00253 }
00254 
00255 
00256 
00257 /*************************************************************************
00258         Remove all items from the list.
00259 *************************************************************************/
00260 void Listbox::resetList(void)
00261 {
00262         if (resetList_impl())
00263         {
00264                 WindowEventArgs args(this);
00265                 onListContentsChanged(args);
00266         }
00267 
00268 }
00269 
00270 
00271 /*************************************************************************
00272         Add the given ListboxItem to the list.
00273 *************************************************************************/
00274 void Listbox::addItem(ListboxItem* item)
00275 {
00276         if (item != NULL)
00277         {
00278                 // establish ownership
00279                 item->setOwnerWindow(this);
00280 
00281                 // if sorting is enabled, re-sort the list
00282                 if (isSortEnabled())
00283                 {
00284                         d_listItems.insert(std::upper_bound(d_listItems.begin(), d_listItems.end(), item, &lbi_less), item);
00285                 
00286                 }
00287                 // not sorted, just stick it on the end.
00288                 else
00289                 {
00290                         d_listItems.push_back(item);
00291                 }
00292 
00293                 WindowEventArgs args(this);
00294                 onListContentsChanged(args);
00295         }
00296 
00297 }
00298 
00299 
00300 /*************************************************************************
00301         Insert an item into the list box after a specified item already in
00302         the list.
00303 *************************************************************************/
00304 void Listbox::insertItem(ListboxItem* item, const ListboxItem* position)
00305 {
00306         // if the list is sorted, it's the same as a normal add operation
00307         if (isSortEnabled())
00308         {
00309                 addItem(item);
00310         }
00311         else if (item != NULL)
00312         {
00313                 // establish ownership
00314                 item->setOwnerWindow(this);
00315 
00316                 // if position is NULL begin insert at begining, else insert after item 'position'
00317                 LBItemList::iterator ins_pos;
00318 
00319                 if (position == NULL)
00320                 {
00321                         ins_pos = d_listItems.begin();
00322                 }
00323                 else
00324                 {
00325                         ins_pos = std::find(d_listItems.begin(), d_listItems.end(), position);
00326 
00327                         // throw if item 'position' is not in the list
00328                         if (ins_pos == d_listItems.end())
00329                         {
00330                                 throw InvalidRequestException((utf8*)"Listbox::insertItem - the specified ListboxItem for parameter 'position' is not attached to this Listbox.");
00331                         }
00332 
00333                 }
00334                 
00335                 d_listItems.insert(ins_pos, item);
00336 
00337                 WindowEventArgs args(this);
00338                 onListContentsChanged(args);
00339         }
00340 
00341 }
00342 
00343 
00344 /*************************************************************************
00345         Removes the given item from the list box.
00346 *************************************************************************/
00347 void Listbox::removeItem(const ListboxItem* item)
00348 {
00349         if (item != NULL)
00350         {
00351                 LBItemList::iterator pos = std::find(d_listItems.begin(), d_listItems.end(), item);
00352 
00353                 // if item is in the list
00354                 if (pos != d_listItems.end())
00355                 {
00356                         // disown item
00357                         (*pos)->setOwnerWindow(NULL);
00358 
00359                         // remove item
00360                         d_listItems.erase(pos);
00361 
00362                         // if item was the last selected item, reset that to NULL
00363                         if (item == d_lastSelected)
00364                         {
00365                                 d_lastSelected = NULL;
00366                         }
00367 
00368                         // if item is supposed to be deleted by us
00369                         if (item->isAutoDeleted())
00370                         {
00371                                 // clean up this item.
00372                                 delete item;
00373                         }
00374 
00375                         WindowEventArgs args(this);
00376                         onListContentsChanged(args);
00377                 }
00378 
00379         }
00380         
00381 }
00382 
00383 
00384 /*************************************************************************
00385         Clear the selected state for all items.
00386 *************************************************************************/
00387 void Listbox::clearAllSelections(void)
00388 {
00389         // only fire events and update if we actually made any changes
00390         if (clearAllSelections_impl())
00391         {
00392                 WindowEventArgs args(this);
00393                 onSelectionChanged(args);
00394         }
00395 
00396 }
00397 
00398 
00399 /*************************************************************************
00400         Set whether the list should be sorted.
00401 *************************************************************************/
00402 void Listbox::setSortingEnabled(bool setting)
00403 {
00404         // only react if the setting will change
00405         if (d_sorted != setting)
00406         {
00407                 d_sorted = setting;
00408 
00409                 // if we are enabling sorting, we need to sort the list
00410                 if (d_sorted)
00411                 {
00412                         std::sort(d_listItems.begin(), d_listItems.end(), &lbi_greater);
00413                 }
00414 
00415         WindowEventArgs args(this);
00416                 onSortModeChanged(args);
00417         }
00418 
00419 }
00420 
00421 
00422 /*************************************************************************
00423         Set whether the list should allow multiple selections or just a
00424         single selection
00425 *************************************************************************/
00426 void Listbox::setMultiselectEnabled(bool setting)
00427 {
00428         // only react if the setting is changed
00429         if (d_multiselect != setting)
00430         {
00431                 d_multiselect = setting;
00432 
00433                 // if we change to single-select, deselect all except the first selected item.
00434         WindowEventArgs args(this);
00435                 if ((!d_multiselect) && (getSelectedCount() > 1))
00436                 {
00437                         ListboxItem* itm = getFirstSelectedItem();
00438 
00439                         while ((itm = getNextSelected(itm)))
00440                         {
00441                                 itm->setSelected(false);
00442                         }
00443 
00444                         onSelectionChanged(args);
00445 
00446                 }
00447 
00448                 onMultiselectModeChanged(args);
00449         }
00450 
00451 }
00452 
00453 void Listbox::setItemTooltipsEnabled(bool setting)
00454 {
00455         d_itemTooltips = setting;
00456 }
00457 
00458 
00459 
00460 /*************************************************************************
00461         Set whether the vertical scroll bar should always be shown.
00462 *************************************************************************/
00463 void Listbox::setShowVertScrollbar(bool setting)
00464 {
00465         if (d_forceVertScroll != setting)
00466         {
00467                 d_forceVertScroll = setting;
00468 
00469                 configureScrollbars();
00470                 WindowEventArgs args(this);
00471                 onVertScrollbarModeChanged(args);
00472         }
00473 
00474 }
00475 
00476 
00477 /*************************************************************************
00478         Set whether the horizontal scroll bar should always be shown.
00479 *************************************************************************/
00480 void Listbox::setShowHorzScrollbar(bool setting)
00481 {
00482         if (d_forceHorzScroll != setting)
00483         {
00484                 d_forceHorzScroll = setting;
00485 
00486                 configureScrollbars();
00487                 WindowEventArgs args(this);
00488                 onHorzScrollbarModeChanged(args);
00489         }
00490 
00491 }
00492 
00493 
00494 /*************************************************************************
00495         Set the select state of an attached ListboxItem.
00496 *************************************************************************/
00497 void Listbox::setItemSelectState(ListboxItem* item, bool state)
00498 {
00499         LBItemList::iterator pos = std::find(d_listItems.begin(), d_listItems.end(), item);
00500 
00501         if (pos != d_listItems.end())
00502         {
00503                 setItemSelectState(std::distance(d_listItems.begin(), pos), state);
00504         }
00505         else
00506         {
00507                 throw InvalidRequestException((utf8*)"Listbox::setItemSelectState - the specified ListboxItem is not attached to this Listbox.");
00508         }
00509 }
00510 
00511 
00512 /*************************************************************************
00513         Set the select state of an attached ListboxItem.        
00514 *************************************************************************/
00515 void Listbox::setItemSelectState(size_t item_index, bool state)
00516 {
00517         if (item_index < getItemCount())
00518         {
00519                 // only do this if the setting is changing
00520                 if (d_listItems[item_index]->isSelected() != state)
00521                 {
00522                         // conditions apply for single-select mode
00523                         if (state && !d_multiselect)
00524                         {
00525                                 clearAllSelections_impl();
00526                         }
00527 
00528                         d_listItems[item_index]->setSelected(state);
00529             WindowEventArgs args(this);
00530                         onSelectionChanged(args);
00531                 }
00532 
00533         }
00534         else
00535         {
00536                 throw InvalidRequestException((utf8*)"Listbox::setItemSelectState - the value passed in the 'item_index' parameter is out of range for this Listbox.");
00537         }
00538 
00539 }
00540 
00541 
00542 /*************************************************************************
00543         Causes the list box to update it's internal state after changes have
00544         been made to one or more attached ListboxItem objects.  
00545 *************************************************************************/
00546 void Listbox::handleUpdatedItemData(void)
00547 {
00548         configureScrollbars();
00549         requestRedraw();
00550 }
00551 
00552 
00553 /*************************************************************************
00554         Perform the actual rendering for this Window.
00555 *************************************************************************/
00556 void Listbox::populateRenderCache()
00557 {
00558     // get the derived class to render general stuff before we handle the items
00559     cacheListboxBaseImagery();
00560 
00561     //
00562     // Render list items
00563     //
00564     Vector3     itemPos;
00565     Size        itemSize;
00566     Rect        itemClipper, itemRect;
00567     float       widest = getWidestItemWidth();
00568 
00569     // calculate position of area we have to render into
00570     Rect itemsArea(getListRenderArea());
00571 
00572     // set up some initial positional details for items
00573     itemPos.d_x = itemsArea.d_left - d_horzScrollbar->getScrollPosition();
00574     itemPos.d_y = itemsArea.d_top - d_vertScrollbar->getScrollPosition();
00575     itemPos.d_z = System::getSingleton().getRenderer()->getZLayer(3) - System::getSingleton().getRenderer()->getCurrentZ();
00576 
00577     float alpha = getEffectiveAlpha();
00578 
00579     // loop through the items
00580     size_t itemCount = getItemCount();
00581 
00582     for (size_t i = 0; i < itemCount; ++i)
00583     {
00584         itemSize.d_height = d_listItems[i]->getPixelSize().d_height;
00585 
00586         // allow item to have full width of box if this is wider than items
00587         itemSize.d_width = ceguimax(itemsArea.getWidth(), widest);
00588 
00589         // calculate destination area for this item.
00590         itemRect.d_left = itemPos.d_x;
00591         itemRect.d_top  = itemPos.d_y;
00592         itemRect.setSize(itemSize);
00593         itemClipper = itemRect.getIntersection(itemsArea);
00594 
00595         // skip this item if totally clipped
00596         if (itemClipper.getWidth() == 0)
00597         {
00598             itemPos.d_y += itemSize.d_height;
00599             continue;
00600         }
00601 
00602         // draw this item
00603         d_listItems[i]->draw(d_renderCache, itemRect, itemPos.d_z, alpha, &itemClipper);
00604 
00605         // update position ready for next item
00606         itemPos.d_y += itemSize.d_height;
00607     }
00608 
00609 }
00610 
00611 
00612 /*************************************************************************
00613         display required integrated scroll bars according to current state
00614         of the list box and update their values.
00615 *************************************************************************/
00616 void Listbox::configureScrollbars(void)
00617 {
00618     Scrollbar* vertScrollbar;
00619     Scrollbar* horzScrollbar;
00620 
00621     try
00622     {
00623         vertScrollbar = static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_vscrollbar__"));
00624         horzScrollbar = static_cast<Scrollbar*>(WindowManager::getSingleton().getWindow(getName() + "__auto_hscrollbar__"));
00625     }
00626     catch (UnknownObjectException)
00627     {
00628         // no scrollbars?  Can't configure then!
00629         return;
00630     }
00631 
00632         float totalHeight       = getTotalItemsHeight();
00633         float widestItem        = getWidestItemWidth();
00634 
00635         //
00636         // First show or hide the scroll bars as needed (or requested)
00637         //
00638         // show or hide vertical scroll bar as required (or as specified by option)
00639         if ((totalHeight > getListRenderArea().getHeight()) || d_forceVertScroll)
00640         {
00641                 vertScrollbar->show();
00642 
00643                 // show or hide horizontal scroll bar as required (or as specified by option)
00644                 if ((widestItem > getListRenderArea().getWidth()) || d_forceHorzScroll)
00645                 {
00646                         horzScrollbar->show();
00647                 }
00648                 else
00649                 {
00650                         horzScrollbar->hide();
00651                 }
00652 
00653         }
00654         else
00655         {
00656                 // show or hide horizontal scroll bar as required (or as specified by option)
00657                 if ((widestItem > getListRenderArea().getWidth()) || d_forceHorzScroll)
00658                 {
00659                         horzScrollbar->show();
00660 
00661                         // show or hide vertical scroll bar as required (or as specified by option)
00662                         if ((totalHeight > getListRenderArea().getHeight()) || d_forceVertScroll)
00663                         {
00664                                 vertScrollbar->show();
00665                         }
00666                         else
00667                         {
00668                                 vertScrollbar->hide();
00669                         }
00670 
00671                 }
00672                 else
00673                 {
00674                         vertScrollbar->hide();
00675                         horzScrollbar->hide();
00676                 }
00677 
00678         }
00679 
00680         //
00681         // Set up scroll bar values
00682         //
00683         Rect renderArea(getListRenderArea());
00684 
00685         vertScrollbar->setDocumentSize(totalHeight);
00686         vertScrollbar->setPageSize(renderArea.getHeight());
00687         vertScrollbar->setStepSize(ceguimax(1.0f, renderArea.getHeight() / 10.0f));
00688         vertScrollbar->setScrollPosition(vertScrollbar->getScrollPosition());
00689 
00690         horzScrollbar->setDocumentSize(widestItem);
00691         horzScrollbar->setPageSize(renderArea.getWidth());
00692         horzScrollbar->setStepSize(ceguimax(1.0f, renderArea.getWidth() / 10.0f));
00693         horzScrollbar->setScrollPosition(horzScrollbar->getScrollPosition());
00694 }
00695 
00696 
00697 /*************************************************************************
00698         select all strings between positions 'start' and 'end' (inclusive)
00699 *************************************************************************/
00700 void Listbox::selectRange(size_t start, size_t end)
00701 {
00702         // only continue if list has some items
00703         if (d_listItems.size() > 0)
00704         {
00705                 // if start is out of range, start at begining.
00706                 if (start > d_listItems.size())
00707                 {
00708                         start = 0;
00709                 }
00710 
00711                 // if end is out of range end at the last item.
00712                 if (end >= d_listItems.size())
00713                 {
00714                         end = d_listItems.size() - 1;
00715                 }
00716 
00717                 // ensure start becomes before the end.
00718                 if (start > end)
00719                 {
00720                         size_t tmp;
00721                         tmp = start;
00722                         start = end;
00723                         end = tmp;
00724                 }
00725 
00726                 // perform selections
00727                 for( ; start <= end; ++start)
00728                 {
00729                         d_listItems[start]->setSelected(true);
00730                 }
00731 
00732         }
00733 
00734 }
00735 
00736 
00737 /*************************************************************************
00738         Return the sum of all item heights      
00739 *************************************************************************/
00740 float Listbox::getTotalItemsHeight(void) const
00741 {
00742         float height = 0;
00743 
00744         for (size_t i = 0; i < getItemCount(); ++i)
00745         {
00746                 height += d_listItems[i]->getPixelSize().d_height;
00747         }
00748 
00749         return height;
00750 }
00751 
00752 
00753 /*************************************************************************
00754         Return the width of the widest item
00755 *************************************************************************/
00756 float Listbox::getWidestItemWidth(void) const
00757 {
00758         float widest = 0;
00759 
00760         for (size_t i = 0; i < getItemCount(); ++i)
00761         {
00762                 float thisWidth = d_listItems[i]->getPixelSize().d_width;
00763 
00764                 if (thisWidth > widest)
00765                 {
00766                         widest = thisWidth;
00767                 }
00768 
00769         }
00770 
00771         return widest;
00772 }
00773 
00774 
00775 /*************************************************************************
00776         Clear the selected state for all items (implementation)
00777 *************************************************************************/
00778 bool Listbox::clearAllSelections_impl(void)
00779 {
00780         // flag used so we can track if we did anything.
00781         bool modified = false;
00782 
00783         for (size_t index = 0; index < d_listItems.size(); ++index)
00784         {
00785                 if (d_listItems[index]->isSelected())
00786                 {
00787                         d_listItems[index]->setSelected(false);
00788                         modified = true;
00789                 }
00790 
00791         }
00792 
00793         return modified;
00794 }
00795 
00796 
00797 /*************************************************************************
00798         Return the ListboxItem under the given window local pixel co-ordinate.
00799 *************************************************************************/
00800 ListboxItem* Listbox::getItemAtPoint(const Point& pt) const
00801 {
00802         Rect renderArea(getListRenderArea());
00803 
00804         // point must be within the rendering area of the Listbox.
00805         if (renderArea.isPointInRect(pt))
00806         {
00807                 float y = renderArea.d_top - d_vertScrollbar->getScrollPosition();
00808 
00809                 // test if point is above first item
00810                 if (pt.d_y >= y)
00811                 {
00812                         for (size_t i = 0; i < getItemCount(); ++i)
00813                         {
00814                                 y += d_listItems[i]->getPixelSize().d_height;
00815 
00816                                 if (pt.d_y < y)
00817                                 {
00818                                         return d_listItems[i];
00819                                 }
00820 
00821                         }
00822                 }
00823         }
00824 
00825         return NULL;
00826 }
00827 
00828 
00829 /*************************************************************************
00830         Add list box specific events
00831 *************************************************************************/
00832 void Listbox::addListboxEvents(void)
00833 {
00834         addEvent(EventListContentsChanged);
00835         addEvent(EventSelectionChanged);
00836         addEvent(EventSortModeChanged);
00837         addEvent(EventMultiselectModeChanged);
00838         addEvent(EventVertScrollbarModeChanged);
00839         addEvent(EventHorzScrollbarModeChanged);
00840 }
00841 
00842 
00843 /*************************************************************************
00844         Handler called internally when the list contents are changed    
00845 *************************************************************************/
00846 void Listbox::onListContentsChanged(WindowEventArgs& e)
00847 {
00848         configureScrollbars();
00849         requestRedraw();
00850         fireEvent(EventListContentsChanged, e, EventNamespace);
00851 }
00852 
00853 
00854 /*************************************************************************
00855         Handler called internally when the currently selected item or items
00856         changes.
00857 *************************************************************************/
00858 void Listbox::onSelectionChanged(WindowEventArgs& e)
00859 {
00860         requestRedraw();
00861         fireEvent(EventSelectionChanged, e, EventNamespace);
00862 }
00863 
00864 
00865 /*************************************************************************
00866         Handler called internally when the sort mode setting changes.
00867 *************************************************************************/
00868 void Listbox::onSortModeChanged(WindowEventArgs& e)
00869 {
00870         requestRedraw();
00871         fireEvent(EventSortModeChanged, e, EventNamespace);
00872 }
00873 
00874 
00875 /*************************************************************************
00876         Handler called internally when the multi-select mode setting changes.
00877 *************************************************************************/
00878 void Listbox::onMultiselectModeChanged(WindowEventArgs& e)
00879 {
00880         fireEvent(EventMultiselectModeChanged, e, EventNamespace);
00881 }
00882 
00883 
00884 /*************************************************************************
00885         Handler called internally when the forced display of the vertical
00886         scroll bar setting changes.
00887 *************************************************************************/
00888 void Listbox::onVertScrollbarModeChanged(WindowEventArgs& e)
00889 {
00890         requestRedraw();
00891         fireEvent(EventVertScrollbarModeChanged, e, EventNamespace);
00892 }
00893 
00894 
00895 /*************************************************************************
00896         Handler called internally when the forced display of the horizontal
00897         scroll bar setting changes.
00898 *************************************************************************/
00899 void Listbox::onHorzScrollbarModeChanged(WindowEventArgs& e)
00900 {
00901         requestRedraw();
00902         fireEvent(EventHorzScrollbarModeChanged, e, EventNamespace);
00903 }
00904 
00905 
00906 /*************************************************************************
00907         Handler for when we are sized
00908 *************************************************************************/
00909 void Listbox::onSized(WindowEventArgs& e)
00910 {
00911         // base class handling
00912         Window::onSized(e);
00913 
00914         configureScrollbars();
00915 
00916         e.handled = true;
00917 }
00918 
00919 
00920 /*************************************************************************
00921         Handler for when mouse button is pressed
00922 *************************************************************************/
00923 void Listbox::onMouseButtonDown(MouseEventArgs& e)
00924 {
00925         // base class processing
00926         Window::onMouseButtonDown(e);
00927 
00928         if (e.button == LeftButton)
00929         {
00930                 bool modified = false;
00931 
00932                 // clear old selections if no control key is pressed or if multi-select is off
00933                 if (!(e.sysKeys & Control) || !d_multiselect)
00934                 {
00935                         modified = clearAllSelections_impl();
00936                 }
00937 
00938                 Point localPos(screenToWindow(e.position));
00939 
00940                 if (getMetricsMode() == Relative)
00941                 {
00942                         localPos = relativeToAbsolute(localPos);
00943                 }
00944 
00945                 ListboxItem* item = getItemAtPoint(localPos);
00946 
00947                 if (item != NULL)
00948                 {
00949                         modified = true;
00950 
00951                         // select range or item, depending upon keys and last selected item
00952                         if (((e.sysKeys & Shift) && (d_lastSelected != NULL)) && d_multiselect)
00953                         {
00954                                 selectRange(getItemIndex(item), getItemIndex(d_lastSelected));
00955                         }
00956                         else
00957                         {
00958                                 item->setSelected(item->isSelected() ^ true);
00959                         }
00960 
00961                         // update last selected item
00962                         d_lastSelected = item->isSelected() ? item : NULL;
00963                 }
00964 
00965                 // fire event if needed
00966                 if (modified)
00967                 {
00968                         WindowEventArgs args(this);
00969                         onSelectionChanged(args);
00970                 }
00971                 
00972                 e.handled = true;
00973         }
00974 
00975 }
00976 
00977 
00978 /*************************************************************************
00979         Handler for mouse wheel changes
00980 *************************************************************************/
00981 void Listbox::onMouseWheel(MouseEventArgs& e)
00982 {
00983         // base class processing.
00984         Window::onMouseWheel(e);
00985 
00986         if (d_vertScrollbar->isVisible() && (d_vertScrollbar->getDocumentSize() > d_vertScrollbar->getPageSize()))
00987         {
00988                 d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + d_vertScrollbar->getStepSize() * -e.wheelChange);
00989         }
00990         else if (d_horzScrollbar->isVisible() && (d_horzScrollbar->getDocumentSize() > d_horzScrollbar->getPageSize()))
00991         {
00992                 d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + d_horzScrollbar->getStepSize() * -e.wheelChange);
00993         }
00994 
00995         e.handled = true;
00996 }
00997 
00998 /*************************************************************************
00999     Handler for mouse movement
01000 *************************************************************************/
01001 void Listbox::onMouseMove(MouseEventArgs& e)
01002 {
01003     if (d_itemTooltips)
01004     {
01005         static ListboxItem* lastItem = NULL;
01006 
01007         Point posi = relativeToAbsolute(screenToWindow(e.position));
01008         ListboxItem* item = getItemAtPoint(posi);
01009         if (item != lastItem)
01010         {
01011             if (item != NULL)
01012             {
01013                 setTooltipText(item->getTooltipText());
01014             }
01015             else
01016             {
01017                 setTooltipText("");
01018             }
01019             lastItem = item;
01020         }
01021 
01022         // must check the result from getTooltip(), as the tooltip object could
01023         // be 0 at any time for various reasons.
01024         Tooltip* tooltip = getTooltip();
01025 
01026         if (tooltip)
01027         {
01028             if (tooltip->getTargetWindow() != this)
01029                 tooltip->setTargetWindow(this);
01030             else
01031                 tooltip->positionSelf();
01032         }
01033     }
01034 
01035     Window::onMouseMove(e);
01036 }
01037 
01038 
01039 /*************************************************************************
01040         Ensure the item at the specified index is visible within the list box.  
01041 *************************************************************************/
01042 void Listbox::ensureItemIsVisible(size_t item_index)
01043 {
01044         // handle simple "scroll to the bottom" case
01045         if (item_index >= getItemCount())
01046         {
01047                 d_vertScrollbar->setScrollPosition(d_vertScrollbar->getDocumentSize() - d_vertScrollbar->getPageSize());
01048         }
01049         else
01050         {
01051                 float bottom;
01052                 float listHeight = getListRenderArea().getHeight();
01053                 float top = 0;
01054 
01055                 // get height to top of item
01056                 size_t i;
01057                 for (i = 0; i < item_index; ++i)
01058                 {
01059                         top += d_listItems[i]->getPixelSize().d_height;
01060                 }
01061 
01062                 // calculate height to bottom of item
01063                 bottom = top + d_listItems[i]->getPixelSize().d_height;
01064 
01065                 // account for current scrollbar value
01066                 float currPos = d_vertScrollbar->getScrollPosition();
01067                 top             -= currPos;
01068                 bottom  -= currPos;
01069 
01070                 // if top is above the view area, or if item is too big to fit
01071                 if ((top < 0.0f) || ((bottom - top) > listHeight))
01072                 {
01073                         // scroll top of item to top of box.
01074                         d_vertScrollbar->setScrollPosition(currPos + top);
01075                 }
01076                 // if bottom is below the view area
01077                 else if (bottom >= listHeight)
01078                 {
01079                         // position bottom of item at the bottom of the list
01080                         d_vertScrollbar->setScrollPosition(currPos + bottom - listHeight);              
01081                 }
01082                 
01083                 // Item is already fully visible - nothing more to do.
01084         }
01085 
01086 }
01087 
01088 
01089 /*************************************************************************
01090         Ensure the item at the specified index is visible within the list box.
01091 *************************************************************************/
01092 void Listbox::ensureItemIsVisible(const ListboxItem* item)
01093 {
01094         ensureItemIsVisible(getItemIndex(item));
01095 }
01096 
01097 
01098 /*************************************************************************
01099         Return whether the vertical scroll bar is always shown. 
01100 *************************************************************************/
01101 bool Listbox::isVertScrollbarAlwaysShown(void) const
01102 {
01103         return d_forceVertScroll;
01104 }
01105 
01106 
01107 /*************************************************************************
01108         Return whether the horizontal scroll bar is always shown.       
01109 *************************************************************************/
01110 bool Listbox::isHorzScrollbarAlwaysShown(void) const
01111 {
01112         return d_forceHorzScroll;
01113 }
01114 
01115 /*************************************************************************
01116         Add properties for this class
01117 *************************************************************************/
01118 void Listbox::addListboxProperties(void)
01119 {
01120         addProperty(&d_sortProperty);
01121         addProperty(&d_multiSelectProperty);
01122         addProperty(&d_forceHorzProperty);
01123         addProperty(&d_forceVertProperty);
01124         addProperty(&d_itemTooltipsProperty);
01125 }
01126 
01127 
01128 /*************************************************************************
01129         Remove all items from the list.
01130 *************************************************************************/
01131 bool Listbox::resetList_impl(void)
01132 {
01133         // just return false if the list is already empty
01134         if (getItemCount() == 0)
01135         {
01136                 return false;
01137         }
01138         // we have items to be removed and possible deleted
01139         else
01140         {
01141                 // delete any items we are supposed to
01142                 for (size_t i = 0; i < getItemCount(); ++i)
01143                 {
01144                         // if item is supposed to be deleted by us
01145                         if (d_listItems[i]->isAutoDeleted())
01146                         {
01147                                 // clean up this item.
01148                                 delete d_listItems[i];
01149                         }
01150 
01151                 }
01152 
01153                 // clear out the list.
01154                 d_listItems.clear();
01155 
01156                 d_lastSelected = NULL;
01157 
01158                 return true;
01159         }
01160 
01161 }
01162 
01163 /*************************************************************************
01164     Handler for scroll position changes.
01165 *************************************************************************/
01166 bool Listbox::handle_scrollChange(const EventArgs& args)
01167 {
01168     // simply trigger a redraw of the Listbox.
01169     requestRedraw();
01170     return true;
01171 }
01172 
01173 
01175 /*************************************************************************
01176         Functions used for predicates in std algorithms
01177 *************************************************************************/
01179 /*************************************************************************
01180         used for < comparisons between ListboxItem pointers
01181 *************************************************************************/
01182 bool lbi_less(const ListboxItem* a, const ListboxItem* b)
01183 {
01184         return *a < *b;
01185 }
01186 
01187 /*************************************************************************
01188         used for > comparisons between ListboxItem pointers
01189 *************************************************************************/
01190 bool lbi_greater(const ListboxItem* a, const ListboxItem* b)
01191 {
01192         return *a > *b;
01193 }
01194 
01195 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:32 2005 for Crazy Eddies GUI System by  doxygen 1.4.3