GG

ListBox.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /* GG is a GUI for SDL and OpenGL.
00003    Copyright (C) 2003-2008 T. Zachary Laine
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public License
00007    as published by the Free Software Foundation; either version 2.1
00008    of the License, or (at your option) any later version.
00009    
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014     
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA
00019 
00020    If you do not wish to comply with the terms of the LGPL please
00021    contact the author as other terms are available for a fee.
00022     
00023    Zach Laine
00024    whatwasthataddress@gmail.com */
00025 
00029 #ifndef _GG_ListBox_h_
00030 #define _GG_ListBox_h_
00031 
00032 #include <GG/AlignmentFlags.h>
00033 #include <GG/ClrConstants.h>
00034 #include <GG/Control.h>
00035 #include <GG/Timer.h>
00036 
00037 #include <set>
00038 
00039 #include <boost/serialization/version.hpp>
00040 
00041 
00042 namespace GG {
00043 
00044 class Font;
00045 class Scroll;
00046 class SubTexture;
00047 class WndEvent;
00048 
00050 GG_FLAG_TYPE(ListBoxStyle);
00051 extern GG_API const ListBoxStyle LIST_NONE;           
00052 extern GG_API const ListBoxStyle LIST_VCENTER;        
00053 extern GG_API const ListBoxStyle LIST_TOP;            
00054 extern GG_API const ListBoxStyle LIST_BOTTOM;         
00055 extern GG_API const ListBoxStyle LIST_CENTER;         
00056 extern GG_API const ListBoxStyle LIST_LEFT;           
00057 extern GG_API const ListBoxStyle LIST_RIGHT;          
00058 extern GG_API const ListBoxStyle LIST_NOSORT;         
00059 extern GG_API const ListBoxStyle LIST_SORTDESCENDING; 
00060 extern GG_API const ListBoxStyle LIST_NOSEL;          
00061 extern GG_API const ListBoxStyle LIST_SINGLESEL;      
00062 extern GG_API const ListBoxStyle LIST_QUICKSEL;       
00063 extern GG_API const ListBoxStyle LIST_USERDELETE;     
00064 extern GG_API const ListBoxStyle LIST_BROWSEUPDATES;  
00065 
00066 
00102 class GG_API ListBox : public Control
00103 {
00104 public:
00113     template <class Cont>
00114     struct RowPtrIteratorLess
00115     {
00116         typedef typename Cont::iterator Iter;
00117         RowPtrIteratorLess();
00118         RowPtrIteratorLess(Cont* c);
00119         bool operator()(Iter lhs, Iter rhs) const;
00120         static bool LessThan(Iter lhs, Iter rhs, Iter end);
00121     private:
00122         Cont* m_container;
00123     };
00124 
00149     struct GG_API Row : public Control
00150     {
00156         struct DeferAdjustLayout
00157         {
00158             DeferAdjustLayout(Row* row);
00159             ~DeferAdjustLayout();
00160             Row* const m_row;
00161         };
00162 
00164         typedef std::string SortKeyType;
00165  
00167         Row(); 
00168         Row(X w, Y h, const std::string& drag_drop_data_type, Alignment align = ALIGN_VCENTER, unsigned int margin = 2); 
00169         virtual ~Row();
00171  
00173         SortKeyType  SortKey(std::size_t column) const; 
00174         std::size_t  size() const;               
00175         bool         empty() const;              
00176 
00177         Control*     operator[](std::size_t n) const; 
00178         Control*     at(std::size_t n) const;    
00179 
00180         Alignment    RowAlignment() const;       
00181         Alignment    ColAlignment(std::size_t n) const; 
00182         X            ColWidth(std::size_t n) const; 
00183         unsigned int Margin() const;             
00184 
00185         Control*     CreateControl(const std::string& str, const boost::shared_ptr<Font>& font, Clr color) const; 
00186         Control*     CreateControl(const SubTexture& st) const; 
00187 
00188  
00190         virtual void Render();
00191 
00192         void         push_back(Control* c); 
00193         void         push_back(const std::string& str, const boost::shared_ptr<Font>& font, Clr color = CLR_BLACK); 
00194         void         push_back(const std::string& str, const std::string& font_filename, unsigned int pts, Clr color = CLR_BLACK); 
00195         void         push_back(const SubTexture& st); 
00196         void         clear(); 
00197         void         resize(std::size_t n); 
00198 
00199         void         SetCell(std::size_t n, Control* c); 
00200         Control*     RemoveCell(std::size_t n); 
00201         void         SetRowAlignment(Alignment align); 
00202         void         SetColAlignment(std::size_t n, Alignment align); 
00203         void         SetColWidth(std::size_t n, X width); 
00204         void         SetColAlignments(const std::vector<Alignment>& aligns); 
00205         void         SetColWidths(const std::vector<X>& widths); 
00206         void         SetMargin(unsigned int margin); 
00207 
00208 
00209     private:
00210         void AdjustLayout(bool adjust_for_push_back = false);
00211 
00212         std::vector<Control*>  m_cells;          
00213         Alignment              m_row_alignment;  
00214         std::vector<Alignment> m_col_alignments; 
00215         std::vector<X>         m_col_widths;     
00216         unsigned int           m_margin;         
00217 
00218         bool                   m_ignore_adjust_layout;
00219 
00220         friend class DeferAdjustLayout;
00221 
00222         friend class boost::serialization::access;
00223         template <class Archive>
00224         void serialize(Archive& ar, const unsigned int version);
00225     };
00226 
00227     typedef std::list<Row*>::iterator iterator;
00228     typedef std::list<Row*>::const_iterator const_iterator;
00229     typedef std::list<Row*>::reverse_iterator reverse_iterator;
00230     typedef std::list<Row*>::const_reverse_iterator const_reverse_iterator;
00231 
00232     typedef std::set<iterator, RowPtrIteratorLess<std::list<Row*> > > SelectionSet;
00233  
00235     typedef boost::signal<void ()>                    ClearedSignalType;    
00236     typedef boost::signal<void (const SelectionSet&)> SelChangedSignalType; 
00237     typedef boost::signal<void (iterator)>            RowSignalType;        
00238     typedef boost::signal<void (const_iterator)>      ConstRowSignalType;   
00239     typedef boost::signal<void (iterator, const Pt&)> RowClickSignalType;   
00240 
00241     typedef RowSignalType      InsertedSignalType;       
00242     typedef RowSignalType      DroppedSignalType;        
00243     typedef ConstRowSignalType DropAcceptableSignalType; 
00244     typedef RowClickSignalType LeftClickedSignalType;    
00245     typedef RowClickSignalType RightClickedSignalType;   
00246     typedef RowSignalType      DoubleClickedSignalType;  
00247     typedef RowSignalType      ErasedSignalType;         
00248     typedef RowSignalType      BrowsedSignalType;        
00249 
00250  
00252 
00253     ListBox(X x, Y y, X w, Y h, Clr color, Clr interior = CLR_ZERO, Flags<WndFlag> flags = INTERACTIVE);
00254 
00255     virtual ~ListBox(); 
00256 
00257  
00259     virtual void    DropsAcceptable(DropsAcceptableIter first,
00260                                     DropsAcceptableIter last,
00261                                     const Pt& pt) const;
00262 
00263     virtual Pt      MinUsableSize() const;
00264     virtual Pt      ClientUpperLeft() const;
00265     virtual Pt      ClientLowerRight() const;
00266 
00267     bool            Empty() const;          
00268     const_iterator  begin() const;          
00269     const_iterator  end() const;            
00270     const_reverse_iterator
00271                     rbegin() const;         
00272     const_reverse_iterator
00273                     rend() const;           
00274     const Row&      GetRow(std::size_t n) const; 
00275     iterator        Caret() const;          
00276     const SelectionSet&
00277                     Selections() const;     
00278     bool            Selected(iterator it) const; 
00279     Clr             InteriorColor() const;  
00280     Clr             HiliteColor() const;    
00281 
00283     Flags<ListBoxStyle> Style() const;
00284 
00285     const Row&      ColHeaders() const;     
00286     iterator        FirstRowShown() const;  
00287     std::size_t     FirstColShown() const;  
00288 
00289     iterator        LastVisibleRow() const; 
00290     std::size_t     LastVisibleCol() const; 
00291 
00292     std::size_t     NumRows() const;        
00293     std::size_t     NumCols() const;        
00294 
00296     bool            KeepColWidths() const;
00297 
00301     std::size_t     SortCol() const;
00302 
00303     X               ColWidth(std::size_t n) const;     
00304     Alignment       ColAlignment(std::size_t n) const; 
00305     Alignment       RowAlignment(iterator it) const;   
00306 
00310     const std::set<std::string>& AllowedDropTypes() const;
00311 
00314     bool            AutoScrollDuringDragDrops() const;
00315 
00318     unsigned int    AutoScrollMargin() const;
00319 
00322     unsigned int    AutoScrollInterval() const;
00323 
00328     mutable ClearedSignalType        ClearedSignal;
00329 
00334     mutable InsertedSignalType       InsertedSignal;
00335 
00336     mutable SelChangedSignalType     SelChangedSignal;     
00337     mutable DroppedSignalType        DroppedSignal;        
00338     mutable DropAcceptableSignalType DropAcceptableSignal; 
00339     mutable LeftClickedSignalType    LeftClickedSignal;    
00340     mutable RightClickedSignalType   RightClickedSignal;   
00341     mutable DoubleClickedSignalType  DoubleClickedSignal;  
00342     mutable ErasedSignalType         ErasedSignal;         
00343     mutable BrowsedSignalType        BrowsedSignal;        
00344 
00345  
00347     virtual void   StartingChildDragDrop(const Wnd* wnd, const GG::Pt& offset);
00348     virtual void   AcceptDrops(const std::vector<Wnd*>& wnds, const Pt& pt);
00349     virtual void   ChildrenDraggedAway(const std::vector<Wnd*>& wnds, const Wnd* destination);
00350     virtual void   Render();
00351 
00352     virtual void   SizeMove(const Pt& ul, const Pt& lr);  
00353 
00354     virtual void   Disable(bool b = true);
00355     virtual void   SetColor(Clr c);
00356 
00360     iterator       Insert(Row* row, iterator it);
00361 
00365     iterator       Insert(Row* row);
00366 
00367     Row*           Erase(iterator it);                    
00368     void           Clear();                               
00369     void           SelectRow(iterator it);                
00370     void           DeselectRow(iterator it);              
00371     void           SelectAll();                           
00372     void           DeselectAll();                         
00373     iterator       begin();                               
00374     iterator       end();                                 
00375     reverse_iterator
00376                    rbegin();                              
00377     reverse_iterator
00378                    rend();                                
00379     Row&           GetRow(std::size_t n);                 
00380 
00381     void           SetSelections(const SelectionSet& s);  
00382     void           SetCaret(iterator it);                 
00383     void           BringRowIntoView(iterator it);         
00384 
00385     void           SetInteriorColor(Clr c);               
00386     void           SetHiliteColor(Clr c);                 
00387 
00389     void           SetStyle(Flags<ListBoxStyle> s);
00390 
00391     void           SetColHeaders(Row* r);                 
00392     void           RemoveColHeaders();                    
00393 
00394     void           SetColWidth(std::size_t n, X w);  
00395     void           SetNumCols(std::size_t n);             
00396     void           SetSortCol(std::size_t n);             
00397 
00402     void           SetSortCmp(const boost::function<bool (const Row&, const Row&, std::size_t)>& sort_cmp);
00403 
00408     void           LockColWidths();
00409 
00412     void           UnLockColWidths();
00413 
00415     void           SetColAlignment(std::size_t n, Alignment align);
00416 
00418     void           SetRowAlignment(iterator it, Alignment align);
00419 
00422     void           AllowDropType(const std::string& str);
00423 
00428     void           DisallowDropType(const std::string& str);
00429 
00433     void           AutoScrollDuringDragDrops(bool auto_scroll);
00434 
00438     void           SetAutoScrollMargin(unsigned int margin);
00439 
00442     void           SetAutoScrollInterval(unsigned int interval);
00443 
00444     virtual void   DefineAttributes(WndEditor* editor);
00446 
00452     template <class RowType>
00453     struct DefaultRowCmp
00454     {
00456         bool operator()(const Row& lhs, const Row& rhs, std::size_t column) const;
00457     };
00458 
00459     static const unsigned int BORDER_THICK; 
00460  
00462 
00463     GG_ABSTRACT_EXCEPTION(Exception);
00464 
00468     GG_CONCRETE_EXCEPTION(DontAcceptDrop, GG::ListBox, Exception);
00470 
00471 protected: 
00473     ListBox(); 
00474 
00475  
00477     X               RightMargin() const;     
00478     Y               BottomMargin() const;    
00479     unsigned int    CellMargin() const;      
00480 
00481     iterator        RowUnderPt(const Pt& pt) const; 
00482 
00483     iterator        OldSelRow() const;   
00484     iterator        OldRDownRow() const; 
00485     iterator        LClickRow() const;   
00486     iterator        RClickRow() const;   
00487 
00488     bool            AutoScrollingUp() const;    
00489     bool            AutoScrollingDown() const;  
00490     bool            AutoScrollingLeft() const;  
00491     bool            AutoScrollingRight() const; 
00492 
00493  
00495     virtual void    KeyPress(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys);
00496     virtual void    MouseWheel(const Pt& pt, int move, Flags<ModKey> mod_keys);
00497     virtual void    DragDropEnter(const Pt& pt, const std::map<Wnd*, Pt>& drag_drop_wnds, Flags<ModKey> mod_keys);
00498     virtual void    DragDropHere(const Pt& pt, const std::map<Wnd*, Pt>& drag_drop_wnds, Flags<ModKey> mod_keys);
00499     virtual void    DragDropLeave();
00500     virtual void    TimerFiring(unsigned int ticks, Timer* timer);
00501 
00502     virtual bool    EventFilter(Wnd* w, const WndEvent& event);
00503 
00504     iterator        Insert(Row* row, iterator it, bool dropped);  
00505     Row*            Erase(iterator it, bool removing_duplicate, bool signal); 
00506     void            BringCaretIntoView();           
00507     void            RecreateScrolls();              
00508     void            ResetAutoScrollVars();          
00509     void            Resort();                       
00510 
00511 
00512 private:
00513     void            ConnectSignals();
00514     void            ValidateStyle(); 
00515     void            AdjustScrolls(bool adjust_for_resize); 
00516     void            VScrolled(int tab_low, int tab_high, int low, int high); 
00517     void            HScrolled(int tab_low, int tab_high, int low, int high); 
00518     void            ClickAtRow(iterator it, Flags<ModKey> mod_keys); 
00519     void            NormalizeRow(Row* row); 
00520     iterator        FirstRowShownWhenBottomIs(iterator bottom_row, Y client_height); 
00521     std::size_t     FirstColShownWhenRightIs(std::size_t right_col, X client_width); 
00522 
00523     std::list<Row*> m_rows;             
00524 
00525     Scroll*         m_vscroll;          
00526     Scroll*         m_hscroll;          
00527     iterator        m_caret;            
00528     SelectionSet    m_selections;       
00529     iterator        m_old_sel_row;      
00530     bool            m_old_sel_row_selected; 
00531     iterator        m_old_rdown_row;    
00532     iterator        m_lclick_row;       
00533     iterator        m_rclick_row;       
00534     iterator        m_last_row_browsed; 
00535 
00536     iterator        m_first_row_shown;  
00537     std::size_t     m_first_col_shown;  
00538     std::vector<X>  m_col_widths;       
00539     std::vector<Alignment> 
00540                     m_col_alignments;   
00541     unsigned int    m_cell_margin;      
00542 
00543     Clr             m_int_color;        
00544     Clr             m_hilite_color;     
00545     Flags<ListBoxStyle>
00546                     m_style;            
00547 
00548     Row*            m_header_row;       
00549     bool            m_keep_col_widths;  
00550     bool            m_clip_cells;       
00551     std::size_t     m_sort_col;         
00552     boost::function<bool (const Row&, const Row&, std::size_t)>
00553                     m_sort_cmp;         
00554     std::set<std::string>
00555                     m_allowed_drop_types;
00556 
00557     bool            m_auto_scroll_during_drag_drops;
00558     unsigned int    m_auto_scroll_margin;
00559     bool            m_auto_scrolling_up;
00560     bool            m_auto_scrolling_down;
00561     bool            m_auto_scrolling_left;
00562     bool            m_auto_scrolling_right;
00563     Timer           m_auto_scroll_timer;
00564 
00565     iterator*       m_iterator_being_erased;
00566 
00567     friend class DropDownList; 
00568 
00569     friend class boost::serialization::access;
00570     template <class Archive>
00571     void serialize(Archive& ar, const unsigned int version);
00572 };
00573 
00574 } // namespace GG
00575 
00576 
00577 // template implementations
00578 template <class Cont>
00579 GG::ListBox::RowPtrIteratorLess<Cont>::RowPtrIteratorLess() :
00580     m_container()
00581 { assert(m_container); }
00582 
00583 template <class Cont>
00584 GG::ListBox::RowPtrIteratorLess<Cont>::RowPtrIteratorLess(Cont* c) :
00585     m_container(c)
00586 { assert(m_container); }
00587 
00588 template <class Cont>
00589 bool GG::ListBox::RowPtrIteratorLess<Cont>::operator()(Iter lhs, Iter rhs) const
00590 {
00591     // If you've seen an error message that lead you here, it is because you
00592     // are attempting to use RowPtrIteratorLess to sort a type that is not
00593     // iterators-to-pointers-to-ListBox::Rows!
00594     BOOST_MPL_ASSERT((boost::is_same<typename Iter::value_type, ::GG::ListBox::Row*>));
00595     return LessThan(lhs, rhs, m_container->end());
00596 }
00597 
00598 template <class Cont>
00599 bool GG::ListBox::RowPtrIteratorLess<Cont>::LessThan(Iter lhs, Iter rhs, Iter end)
00600 {
00601     return lhs == end ?
00602         false :
00603         (rhs == end ?
00604          true : (*lhs)->UpperLeft().y < (*rhs)->UpperLeft().y);
00605 }
00606 
00607 template <class Archive>
00608 void GG::ListBox::Row::serialize(Archive& ar, const unsigned int version)
00609 {
00610     ar  & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Control)
00611         & BOOST_SERIALIZATION_NVP(m_cells)
00612         & BOOST_SERIALIZATION_NVP(m_row_alignment)
00613         & BOOST_SERIALIZATION_NVP(m_col_alignments)
00614         & BOOST_SERIALIZATION_NVP(m_col_widths)
00615         & BOOST_SERIALIZATION_NVP(m_margin);
00616 }
00617 
00618 template <class RowType>
00619 bool GG::ListBox::DefaultRowCmp<RowType>::operator()(const GG::ListBox::Row& lhs, const GG::ListBox::Row& rhs, std::size_t column) const
00620 {
00621     return static_cast<const RowType&>(lhs).SortKey(column) < static_cast<const RowType&>(rhs).SortKey(column);
00622 }
00623 
00624 template <class Archive>
00625 void GG::ListBox::serialize(Archive& ar, const unsigned int version)
00626 {
00627     std::size_t caret_index = std::distance(m_rows.begin(), m_caret);
00628     std::size_t old_sel_row_index = std::distance(m_rows.begin(), m_old_sel_row);
00629     std::size_t old_rdown_row_index = std::distance(m_rows.begin(), m_old_rdown_row);
00630     std::size_t lclick_row_index = std::distance(m_rows.begin(), m_lclick_row);
00631     std::size_t rclick_row_index = std::distance(m_rows.begin(), m_rclick_row);
00632     std::size_t last_row_browsed_index = std::distance(m_rows.begin(), m_last_row_browsed);
00633     std::size_t first_row_shown_index = std::distance(m_rows.begin(), m_first_row_shown);
00634     std::set<std::size_t> selection_indices;
00635 
00636     if (Archive::is_saving::value) {
00637         for (SelectionSet::iterator it = m_selections.begin(); it != m_selections.end(); ++it) {
00638             selection_indices.insert(std::distance(m_rows.begin(), *it));
00639         }
00640     }
00641 
00642     ar  & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Control)
00643         & BOOST_SERIALIZATION_NVP(m_rows)
00644         & BOOST_SERIALIZATION_NVP(m_vscroll)
00645         & BOOST_SERIALIZATION_NVP(m_hscroll)
00646         & BOOST_SERIALIZATION_NVP(caret_index)
00647         & BOOST_SERIALIZATION_NVP(selection_indices)
00648         & BOOST_SERIALIZATION_NVP(old_sel_row_index)
00649         & BOOST_SERIALIZATION_NVP(m_old_sel_row_selected)
00650         & BOOST_SERIALIZATION_NVP(old_rdown_row_index)
00651         & BOOST_SERIALIZATION_NVP(lclick_row_index)
00652         & BOOST_SERIALIZATION_NVP(rclick_row_index)
00653         & BOOST_SERIALIZATION_NVP(last_row_browsed_index)
00654         & BOOST_SERIALIZATION_NVP(first_row_shown_index)
00655         & BOOST_SERIALIZATION_NVP(m_first_col_shown)
00656         & BOOST_SERIALIZATION_NVP(m_col_widths)
00657         & BOOST_SERIALIZATION_NVP(m_col_alignments)
00658         & BOOST_SERIALIZATION_NVP(m_cell_margin)
00659         & BOOST_SERIALIZATION_NVP(m_int_color)
00660         & BOOST_SERIALIZATION_NVP(m_hilite_color)
00661         & BOOST_SERIALIZATION_NVP(m_style)
00662         & BOOST_SERIALIZATION_NVP(m_header_row)
00663         & BOOST_SERIALIZATION_NVP(m_keep_col_widths)
00664         & BOOST_SERIALIZATION_NVP(m_clip_cells)
00665         & BOOST_SERIALIZATION_NVP(m_sort_col)
00666         & BOOST_SERIALIZATION_NVP(m_allowed_drop_types)
00667         & BOOST_SERIALIZATION_NVP(m_auto_scroll_during_drag_drops)
00668         & BOOST_SERIALIZATION_NVP(m_auto_scroll_margin)
00669         & BOOST_SERIALIZATION_NVP(m_auto_scrolling_up)
00670         & BOOST_SERIALIZATION_NVP(m_auto_scrolling_down)
00671         & BOOST_SERIALIZATION_NVP(m_auto_scrolling_left)
00672         & BOOST_SERIALIZATION_NVP(m_auto_scrolling_right)
00673         & BOOST_SERIALIZATION_NVP(m_auto_scroll_timer);
00674 
00675     if (Archive::is_loading::value) {
00676         m_caret = boost::next(m_rows.begin(), caret_index);
00677         m_old_sel_row = boost::next(m_rows.begin(), old_sel_row_index);
00678         m_old_rdown_row = boost::next(m_rows.begin(), old_rdown_row_index);
00679         m_lclick_row = boost::next(m_rows.begin(), lclick_row_index);
00680         m_rclick_row = boost::next(m_rows.begin(), rclick_row_index);
00681         m_last_row_browsed = boost::next(m_rows.begin(), last_row_browsed_index);
00682         m_first_row_shown = boost::next(m_rows.begin(), first_row_shown_index);
00683 
00684         for (std::set<std::size_t>::iterator it = selection_indices.begin(); it != selection_indices.end(); ++it) {
00685             m_selections.insert(boost::next(m_rows.begin(), *it));
00686         }
00687 
00688         ValidateStyle();
00689         ConnectSignals();
00690     }
00691 }
00692 
00693 #endif // _GG_ListBox_h_