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

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

Generated on Wed Feb 16 12:41:06 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1