]> git.tdb.fi Git - libs/gltk.git/blob - source/list.h
Use size_t to represent counts and indices
[libs/gltk.git] / source / list.h
1 #ifndef MSP_GLTK_LIST_H_
2 #define MSP_GLTK_LIST_H_
3
4 #include <stdexcept>
5 #include <typeinfo>
6 #include <sigc++/signal.h>
7 #include "container.h"
8 #include "label.h"
9 #include "listdata.h"
10 #include "mspgltk_api.h"
11 #include "slider.h"
12
13 namespace Msp {
14 namespace GLtk {
15
16 /**
17 Thrown if a list's item type is incompatible with its data.
18 */
19 class MSPGLTK_API incompatible_data: public std::logic_error
20 {
21 public:
22         incompatible_data(const std::type_info &);
23 };
24
25
26 /**
27 Shows a list of items, allowing the user to select one.  A slider is included
28 to allow scrolling through a long list.
29 */
30 class MSPGLTK_API List: virtual public Widget, private Container
31 {
32 public:
33         enum ViewMode
34         {
35                 LIST,
36                 GRID
37         };
38
39         static constexpr size_t INVALID_INDEX = std::numeric_limits<size_t>::max();
40
41         class Loader: public DataFile::DerivedObjectLoader<List, Widget::Loader>
42         {
43         public:
44                 Loader(List &);
45         private:
46                 void item(const std::string &);
47         };
48
49 private:
50         /// This exists to make disconnecting signals easier
51         class DataObserver: public sigc::trackable
52         {
53         private:
54                 List &list;
55
56         public:
57                 DataObserver(List &);
58
59                 void item_added(std::size_t);
60                 void item_removed(std::size_t);
61                 void cleared();
62                 void refresh_item(std::size_t);
63         };
64
65 public:
66         class Item: virtual public Widget, protected Container
67         {
68         protected:
69                 Item();
70
71         public:
72                 const char *get_class() const override { return "listitem"; }
73
74         protected:
75                 void autosize_special(const Part &, Geometry &) const override;
76         public:
77                 void set_active(bool);
78
79                 void render_special(const Part &, GL::Renderer &) const override;
80         };
81
82         class SimpleItem: public Item
83         {
84         protected:
85                 SimpleItem() = default;
86
87                 void on_style_change() override;
88         };
89
90         class MultiColumnItem: public Item
91         {
92         protected:
93                 MultiColumnItem() = default;
94
95                 virtual void check_widths(std::vector<unsigned> &) const;
96                 virtual void set_widths(const std::vector<unsigned> &);
97
98                 void on_style_change() override;
99         };
100
101 private:
102         class BasicItem: public SimpleItem
103         {
104         private:
105                 Label label;
106
107         public:
108                 BasicItem(const std::string &);
109         };
110
111         class ItemFactory
112         {
113         protected:
114                 ItemFactory() = default;
115         public:
116                 virtual ~ItemFactory() = default;
117
118                 virtual void set_data(const ListData &) = 0;
119                 virtual Item *create_item(std::size_t) const = 0;
120         };
121
122         template<typename I>
123         class TypedItemFactory: public ItemFactory
124         {
125         private:
126                 typedef typename I::ValueType ValueType;
127
128                 const ListDataStore<ValueType> *data;
129
130         public:
131                 TypedItemFactory(const ListData &d)
132                 { set_data(d); }
133
134                 void set_data(const ListData &d) override
135                 {
136                         if(const ListDataStore<ValueType> *ds = dynamic_cast<const ListDataStore<ValueType> *>(&d))
137                                 data = ds;
138                         else
139                                 throw incompatible_data(typeid(ValueType));
140                 }
141
142                 Item *create_item(std::size_t i) const override
143                 {
144                         return new I(data->get(i));
145                 }
146         };
147
148         struct Row
149         {
150                 std::size_t first;
151                 unsigned height;
152
153                 Row(std::size_t f): first(f), height(0) { }
154         };
155
156 public:
157         sigc::signal<void, std::size_t> signal_item_selected;
158         sigc::signal<void> signal_selection_cleared;
159
160 private:
161         ListData *data = nullptr;
162         bool own_data = false;
163         DataObserver *observer = nullptr;
164         ItemFactory *item_factory = nullptr;
165         ViewMode view_mode = LIST;
166         std::size_t sel_index = INVALID_INDEX;
167         std::size_t focus_index = INVALID_INDEX;
168         std::size_t first_row = 0;
169         std::size_t max_scroll = 0;
170         unsigned view_rows = 5;
171         unsigned view_columns = 5;
172         const Part *items_part = nullptr;
173         bool ignore_slider_change = false;
174         bool dragging = false;
175         int drag_start_x = 0;
176         int drag_start_y = 0;
177
178         VSlider slider;
179         std::vector<Item *> items;
180         std::vector<Row> rows;
181
182 public:
183         List();
184         List(ListData &);
185         virtual ~List();
186
187         const char *get_class() const override { return "list"; }
188
189 private:
190         void autosize_special(const Part &, Geometry &) const override;
191
192 public:
193         void set_data(ListData &);
194         ListData &get_data() { return *data; }
195         const ListData &get_data() const { return *data; }
196 private:
197         void items_changed();
198
199 public:
200         template<typename I>
201         void set_item_type()
202         {
203                 ItemFactory *f = new TypedItemFactory<I>(*data);
204                 delete item_factory;
205                 item_factory = f;
206         }
207 private:
208         Item *create_item(std::size_t);
209
210 public:
211         void set_view_mode(ViewMode);
212         void set_view_size(unsigned);
213         void set_view_size(unsigned, unsigned);
214         void set_view_all();
215
216         void set_selected_index(std::size_t);
217         int get_selected_index() const { return sel_index; }
218 private:
219         void set_selected_item(Widget *);
220
221         void rebuild_special(const Part &) override;
222         void render_special(const Part &, GL::Renderer &) const override;
223
224 public:
225         bool key_press(unsigned, unsigned) override;
226         void button_press(int, int, unsigned) override;
227         void touch_press(int, int, unsigned) override;
228         void touch_release(int, int, unsigned) override;
229         void touch_motion(int, int, unsigned) override;
230         void focus_in() override;
231         bool navigate(Navigation) override;
232 private:
233         void on_style_change() override;
234
235         void move_focus(Navigation, bool);
236         void set_focus_index(std::size_t);
237
238         void item_autosize_changed(Item *);
239         void reposition_items(bool);
240         std::size_t last_to_first_row(std::size_t) const;
241         std::size_t item_index_to_row(std::size_t) const;
242         void check_view_range();
243         void scroll_to_focus();
244         void slider_value_changed(double);
245         static void adjust_index(std::size_t &, std::size_t, std::ptrdiff_t);
246 };
247
248 MSPGLTK_API void operator>>(const LexicalConverter &, List::ViewMode &);
249
250 } // namespace GLtk
251 } // namespace Msp
252
253 #endif