1 // -*- C++ -*-
2 /* GG is a GUI for OpenGL.
3    Copyright (C) 2003-2008 T. Zachary Laine
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation; either version 2.1
8    of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA
19 
20    If you do not wish to comply with the terms of the LGPL please
21    contact the author as other terms are available for a fee.
22 
23    Zach Laine
24    whatwasthataddress@gmail.com */
25 
26 /** \file DropDownList.h \brief Contains the DropDownList class, a control
27     that displays a current selection, and allows the user to select one of
28     several options from a list that drops down when the control is
29     clicked. */
30 
31 #ifndef _GG_DropDownList_h_
32 #define _GG_DropDownList_h_
33 
34 #include <GG/ListBox.h>
35 #include <GG/GLClientAndServerBuffer.h>
36 
37 #include <memory>
38 
39 
40 class ModalListPicker;
41 
42 namespace GG {
43 
44 /** \brief Displays a single choice, and allows the user to select items from
45     a drop-down list.
46 
47     DropDownList is similar to GG::ListBox, but has significant restrictions
48     over the functionality of GG::ListBox.  Specifically, all list items must
49     have the same height, and there is no dragging or dropping.  Though any
50     Control-derived object may be placed in an item cell, the items are only
51     interactive in the drop-down list; the currently selected item is
52     displayed only.  Most of the ListBox interface is duplicated in
53     DropDownList.  Though you can still set the alignment, etc. of individual
54     rows, as in ListBox, the currently-selected row will have the same
55     alignment, etc. when displayed in the control in its unopened state.  Note
56     that this may look quite ugly.
57 
58     On selection DropDownList emits one of two signals, SelChangedSignal or
59     SelChangedWhileDroppedSignal.  SelChangedWhileDroppedSignal is emitted
60     when the selection changes while running a modal event loop to display the
61     drop down list and handle its events.
62 
63     SelChangedSignal will also be emitted when the drop down list closes if
64     the selected item changed.
65 */
66 class GG_API DropDownList : public Control
67 {
68 public:
69     /** This is a single item in a dropdown list. \see See GG::ListBox for details.*/
70     typedef ListBox::Row Row;
71 
72     typedef ListBox::iterator iterator;
73     typedef ListBox::const_iterator const_iterator;
74 
75     /** \name Signal Types */ ///@{
76     /** emitted when a new item is selected; will be end() when no item is
77       * selected */
78     typedef boost::signals2::signal<void (iterator)>   SelChangedSignalType;
79 
80     /** Signal \a true when drop down opens and false when it closes.*/
81     typedef boost::signals2::signal<void (bool)>       DropDownOpenedSignalType;
82     //@}
83 
84     /** \name Structors */ ///@{
85     /** basic ctor.  DropDownList retains ownership of \a lb, if it is non-null. */
86     DropDownList(size_t num_shown_elements, Clr color);
87     ~DropDownList();
88     //@}
89 
90     /** \name Accessors */ ///@{
91     iterator        CurrentItem() const;            ///< returns the currently selected list item (returns end() if none is selected)
92     std::size_t     CurrentItemIndex() const;       ///< returns the position of the currently selected list item within the list (returns -1 if none is selected)
93 
94     std::size_t     IteratorToIndex(iterator it) const;     ///< returns the position of \a it within the list (returns -1 if \a it == end())
95     iterator        IndexToIterator(std::size_t n) const;   ///< returns an iterator to the row in position \a n (returns end() if \a n is an invalid index)
96 
97     bool            Empty() const;                  ///< returns true when the list is empty
98 
99     const_iterator  begin() const;                  ///< returns an iterator to the first list row
100     const_iterator  end() const;                    ///< returns an iterator to the imaginary row one past the last
101 
102     const Row&      GetRow(std::size_t n) const;    ///< returns a const reference to the row at index \a n; not range-checked.  \note This function is O(n).
103     bool            Selected(iterator it) const;    ///< returns true if row \a it is selected
104     bool            Selected(std::size_t n) const;  ///< returns true if row at position \a n is selected
105     Clr             InteriorColor() const;          ///< returns the color painted into the client area of the control
106 
107     Y               DropHeight() const;             ///< returns the height of the drop-down list
108     bool            Dropped() const;                ///< Return true if the drop down list is open.
109 
110     /** Returns the style flags of the list \see GG::ListBoxStyle */
111     Flags<ListBoxStyle> Style() const;
112 
113     std::size_t     NumRows() const;          ///< returns the total number of items in the list
114     std::size_t     NumCols() const;          ///< returns the total number of columns in each list item
115 
116     /** Returns the index of the column used to sort items, when sorting is
117         enabled.  \note The sort column is not range checked when it is set by
118         the user; it may be >= NumCols(). */
119     std::size_t     SortCol() const;
120 
121     X               ColWidth(std::size_t n) const;     ///< returns the width of column \a n in pixels; not range-checked
122     Alignment       ColAlignment(std::size_t n) const; ///< returns the alignment of column \a n; must be LIST_LEFT, LIST_CENTER, or LIST_RIGHT; not range-checked
123     Alignment       RowAlignment(iterator it) const;   ///< returns the alignment of row \a n; must be LIST_TOP, LIST_VCENTER, or LIST_BOTTOM; not range-checked
124 
125     Pt ClientUpperLeft() const override;
126     Pt ClientLowerRight() const override;
127 
128     /** Return the width of the displayed row.  Override this function if the displayed row is a
129         different width than the client width.*/
130     virtual GG::X DisplayedRowWidth() const;
131 
132     /** Return the width of the dropped row.  Override this function if the dropped row is a
133         different width than the client width.*/
134     virtual GG::X DroppedRowWidth() const;
135 
136     /** The selection change signal while not running the modal drop down box.
137         This will also signal an event when the drop list closes if the selection changed.
138      */
139     mutable SelChangedSignalType SelChangedSignal;
140     /** The selection change signal while running the modal drop down box.*/
141     mutable SelChangedSignalType SelChangedWhileDroppedSignal;
142 
143     DropDownOpenedSignalType DropDownOpenedSignal;
144     //@}
145 
146     /** \name Mutators */ ///@{
147     void PreRender() override;
148     void Render() override;
149     /** Resizes the control, ensuring the proper height is maintained based on
150         the list's row height. */
151     void SizeMove(const Pt& ul, const Pt& lr) override;
152     void SetColor(Clr c) override;
153 
154     /** Insertion sorts \a row into a sorted list, or inserts into an unsorted
155         list before \a it; returns index of insertion point.  This Row becomes
156         the property of the DropDownList and should not be deleted or inserted
157         into any other DropDownLists */
158     iterator Insert(std::shared_ptr<Row> row, iterator it);
159 
160     /** Insertion sorts \a row into a sorted list, or inserts into an unsorted
161         list at the end of the list; returns index of insertion point.  This
162         Row becomes the property of the DropDownList and should not be deleted
163         or inserted into any other DropDownLists */
164     iterator Insert(std::shared_ptr<Row> row);
165 
166     /** Insertion sorts \a rows into a sorted list, or inserts into an unsorted
167         list before \a it. The Rows become the property of this DropDownList. */
168     void Insert(const std::vector<std::shared_ptr<Row>>& rows, iterator it);
169 
170     /** Insertion sorts \a rows into sorted list, or inserts into an unsorted
171         list at the end of the list. The Rows become the property of thiis
172         DropDownList. */
173     void Insert(const std::vector<std::shared_ptr<Row>>& rows);
174 
175     std::shared_ptr<Row> Erase(iterator it, bool signal = false); ///< removes and returns \a it from the list, or 0 if no such row exists
176     void Clear();                        ///< empties the list
177 
178     iterator begin();                    ///< returns an iterator to the first list row
179     iterator end();                      ///< returns an iterator to the imaginary row one past the last one
180 
181     Row& GetRow(std::size_t n);          ///< returns a reference to the Row at row index \a n; not range-checked.  \note This function is O(n).
182 
183     void Select(iterator it);            ///< selects row-item \a it in the list
184     void Select(std::size_t n);          ///< selects row-item \a it in the list
185 
186     void SetInteriorColor(Clr c);        ///< sets the color painted into the client area of the control
187 
188     /** sets the style flags for the list to \a s (invalidates currently
189         selected item). \see GG::ListBoxStyle */
190     void SetStyle(Flags<ListBoxStyle> s);
191 
192     void SetNumCols(std::size_t n);      ///< sets the number of columns in each list item to \a n; if no column widths exist before this call, proportional widths are calulated and set, otherwise no column widths are set
193     void SetSortCol(std::size_t n);      ///< sets the index of the column used to sort rows when sorting is enabled (invalidates currently selected item); not range-checked
194     void SetColWidth(std::size_t n, X w);///< sets the width of column \n to \a w; not range-checked
195 
196     /** Fixes the column widths; by default, an empty list will take on the
197         number of columns of its first added row. \note The number of columns
198         and their widths may still be set via SetNumCols() and SetColWidth()
199         after this function has been called. */
200     void LockColWidths();
201 
202     /** Allows the number of columns to be determined by the first row added
203         to an empty ListBox */
204     void UnLockColWidths();
205 
206     /** Set ListBox to stop managing column widths and alignment.  The number of columns must be
207         set with SetColWidth(), but widths of individual rows columns or the header will not be
208         managed by ListBox. */
209     void ManuallyManageColProps();
210 
211     void SetColAlignment(std::size_t n, Alignment align); ///< sets the alignment of column \a n to \a align; not range-checked
212     void SetRowAlignment(iterator it, Alignment align);   ///< sets the alignment of the Row at row index \a n to \a align; not range-checked
213 
214     /** Sets the stretch of column \a n to \a stretch; not range-checked */
215     void SetColStretch(std::size_t n, double stretch);
216 
217     /** Sets whether to normalize rows when inserted (true) or leave them as
218       * they are. */
219     void NormalizeRowsOnInsert(bool enable = true);
220 
221     /** Set the drop down list to only mouse scroll if it is dropped. */
222     void SetOnlyMouseScrollWhenDropped(bool enable);
223     //@}
224 
225 protected:
226     /** \name Mutators */ ///@{
227     void LButtonDown(const Pt& pt, Flags<ModKey> mod_keys) override;
228     void KeyPress(Key key, std::uint32_t key_code_point, Flags<ModKey> mod_keys) override;
229     void MouseWheel(const Pt& pt, int move, Flags<ModKey> mod_keys) override;
230 
231     ListBox*        LB();                ///< returns the ListBox used to render the selected row and the popup list
232 
233     virtual void InitBuffer();
234     virtual void RenderDisplayedRow();
235 
236     GL2DVertexBuffer    m_buffer;
237     //@}
238 
239 private:
240     const ListBox*  LB() const;
241 
242     const std::shared_ptr<ModalListPicker> m_modal_picker;
243 };
244 
245 } // namespace GG
246 
247 #endif
248