GG
|
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_