1 /*
2    Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "widget.hpp"
18 
19 #include <boost/dynamic_bitset.hpp>
20 
21 #include <array>
22 
23 namespace gui2
24 {
25 
26 struct builder_grid;
27 typedef std::shared_ptr<const builder_grid> builder_grid_const_ptr;
28 
29 class grid;
30 
31 /**
32  * Abstract base class for the generator.
33  *
34  * A generator is a class which holds multiple grids and controls their
35  * placement on the screen. The final class is policy based, more info about
36  * the possible policies is documented in the build() function. This function
37  * is the factory to generate the classes as well.
38  */
39 class generator_base : public widget
40 {
41 	friend class debug_layout_graph;
42 
43 public:
~generator_base()44 	virtual ~generator_base()
45 	{
46 	}
47 
48 	/** Determines how the items are placed. */
49 	enum placement {
50 		horizontal_list,
51 		vertical_list,
52 		table,
53 		independent
54 	};
55 
56 	/**
57 	 * Create a new generator.
58 	 *
59 	 * @param has_minimum         Does one item need to be selected?
60 	 * @param has_maximum         Is one the maximum number of items that can
61 	 *                            be selected?
62 	 * @param placement           The placement of the grids, see tplacement
63 	 *                            for more info.
64 	 * @param select              If a grid is selected, what should happen?
65 	 *                            If true the grid is selected, if false the
66 	 *                            grid is shown.
67 	 *
68 	 * @returns                   A pointer to a new object. The caller gets
69 	 *                            ownership of the new object.
70 	 */
71 	static generator_base* build(const bool has_minimum,
72 							  const bool has_maximum,
73 							  const placement placement,
74 							  const bool select);
75 
76 	/**
77 	 * Deletes an item.
78 	 */
79 	virtual void delete_item(const unsigned index) = 0;
80 
81 	/** Deletes all items. */
82 	virtual void clear() = 0;
83 
84 	/**
85 	 * (De)selects an item.
86 	 *
87 	 * @param index               The item to (de)select.
88 	 * @param select              If true selects, if false deselects.
89 	 */
90 	virtual void select_item(const unsigned index, const bool select) = 0;
91 
92 	/**
93 	 * Toggles the selection state of an item.
94 	 *
95 	 * @param index               The item to toggle.
96 	 */
toggle_item(const unsigned index)97 	void toggle_item(const unsigned index)
98 	{
99 		select_item(index, !is_selected(index));
100 	}
101 
102 	/** Returns whether the item is selected. */
103 	virtual bool is_selected(const unsigned index) const = 0;
104 
105 	/**
106 	 * Shows or hides an item.
107 	 *
108 	 * The caller is responsible for reformatting the grid. If a selected item
109 	 * is hidden then it will be automatically deselected; if no items are
110 	 * shown then no items will be selected, even if has_minimum was requested.
111 	 *
112 	 * @param index               The item to show or hide.
113 	 * @param show                If true shows the item, else hides it.
114 	 */
115 	virtual void set_item_shown(const unsigned index, const bool show) = 0;
116 
117 	/** Returns whether the item is shown. */
118 	virtual bool get_item_shown(const unsigned index) const = 0;
119 
120 	/** Returns the visibility of all the items as a bit set. */
get_items_shown() const121 	boost::dynamic_bitset<> get_items_shown() const
122 	{
123 		boost::dynamic_bitset<> items_shown(get_item_count());
124 		for (unsigned int i = 0u; i < get_item_count(); ++i)
125 		{
126 			items_shown[i] = get_item_shown(i);
127 		}
128 		return items_shown;
129 	}
130 
131 	/** Returns the number of items. */
132 	virtual unsigned get_item_count() const = 0;
133 
134 	/** Returns the number of selected items. */
135 	virtual unsigned get_selected_item_count() const = 0;
136 
137 	/**
138 	 * Returns the selected item.
139 	 *
140 	 * If a list has multiple selected items it looks whether it knows the last
141 	 * item actually selected, if that item is selected that one is chosen.
142 	 * Else is goes through all selected items and returns the first one
143 	 * selected.
144 	 *
145 	 * @note stacked_widget depends on that behavior it always has all items
146 	 * selected and thus shown and by default the last selected item (the top
147 	 * one) is active.
148 	 *
149 	 * @returns                   The selected item, -1 if none selected.
150 	 */
151 	virtual int get_selected_item() const = 0;
152 
153 	/** Gets the grid of an item. */
154 	virtual grid& item(const unsigned index) = 0;
155 
156 	/** Gets the grid of an item. */
157 	virtual const grid& item(const unsigned index) const = 0;
158 
159 	/***** ***** ***** ***** Create items ***** ***** ***** *****/
160 
161 	/**
162 	 * Creates a new item.
163 	 *
164 	 * The item_data is used for the first widget found, this normally should
165 	 * be used when there's one widget in an item.
166 	 *
167 	 * @param index               The item before which to add the new item,
168 	 *                            0 == begin, -1 == end.
169 	 * @param list_builder        A grid builder that's will build the
170 	 *                            contents of the new item.
171 	 * @param item_data           The data to initialize the parameters of
172 	 *                            the new item.
173 	 * @param callback            The callback function to call when an item
174 	 *                            in the grid is (de)selected.
175 	 *
176 	 * @returns                   A reference to the newly created grid.
177 	 */
178 	virtual grid& create_item(const int index,
179 							   builder_grid_const_ptr list_builder,
180 							   const string_map& item_data,
181 							   const std::function<void(widget&)>& callback)
182 			= 0;
183 
184 	/**
185 	 * Creates a new item.
186 	 *
187 	 * The item_data is used by id, and is meant to set multiple widgets in
188 	 * an item.
189 	 *
190 	 * @param index               The item before which to add the new item,
191 	 *                            0 == begin, -1 == end.
192 	 * @param list_builder        A grid builder that's will build the
193 	 *                            contents of the new item.
194 	 * @param data                The data to initialize the parameters of
195 	 *                            the new item.
196 	 * @param callback            The callback function to call when an item
197 	 *                            in the grid is (de)selected.
198 	 *
199 	 * @returns                   A reference to the newly created grid.
200 	 */
201 	virtual grid&
202 	create_item(const int index,
203 				builder_grid_const_ptr list_builder,
204 				const std::map<std::string /* widget id */, string_map>& data,
205 				const std::function<void(widget&)>& callback) = 0;
206 
207 	/**
208 	 * Creates one or more new item(s).
209 	 *
210 	 * For every item in item_data a new item is generated. This version
211 	 * expects one widget per item.
212 	 *
213 	 * @param index               The item before which to add the new item,
214 	 *                            0 == begin, -1 == end.
215 	 * @param list_builder        A grid builder that's will build the
216 	 *                            contents of the new item.
217 	 * @param data                The data to initialize the parameters of
218 	 *                            the new item.
219 	 * @param callback            The callback function to call when an item
220 	 *                            in the grid is (de)selected.
221 	 */
222 	virtual void create_items(const int index,
223 							  builder_grid_const_ptr list_builder,
224 							  const std::vector<string_map>& data,
225 							  const std::function<void(widget&)>& callback)
226 			= 0;
227 
228 	/**
229 	 * Creates one or more new item(s).
230 	 *
231 	 * For every item in item_data a new item is generated. This version
232 	 * expects multiple widgets per item.
233 	 *
234 	 * @param index               The item before which to add the new item,
235 	 *                            0 == begin, -1 == end.
236 	 * @param list_builder        A grid builder that's will build the
237 	 *                            contents of the new item.
238 	 * @param data                The data to initialize the parameters of
239 	 *                            the new item.
240 	 * @param callback            The callback function to call when an item
241 	 *                            in the grid is (de)selected.
242 	 */
243 	virtual void create_items(
244 			const int index,
245 			builder_grid_const_ptr list_builder,
246 			const std::vector<std::map<std::string /*widget id*/, string_map>>&
247 					data,
248 			const std::function<void(widget&)>& callback) = 0;
249 
250 	typedef std::function<bool (unsigned, unsigned)> order_func;
251 	virtual void set_order(const order_func& order) = 0;
252 
253 	/***** ***** ***** ***** Inherited ***** ***** ***** *****/
254 
255 	/*
256 	 * These functions must be defined in our child classes so make sure they
257 	 * become pure virtuals.
258 	 */
259 
260 	/** See @ref widget::layout_initialize. */
261 	virtual void layout_initialize(const bool full_initialization) override = 0;
262 
263 	/** See @ref widget::request_reduce_width. */
264 	virtual void request_reduce_width(const unsigned maximum_width) override
265 			= 0;
266 
267 	/** See @ref widget::request_reduce_height. */
268 	virtual void request_reduce_height(const unsigned maximum_height) override
269 			= 0;
270 
271 	/** See @ref widget::calculate_best_size. */
272 	virtual point calculate_best_size() const override = 0;
273 
274 	/** See @ref widget::place. */
275 	virtual void place(const point& origin, const point& size) override = 0;
276 
277 	/** See @ref widget::set_origin. */
278 	virtual void set_origin(const point& origin) override = 0;
279 
280 	/** See @ref widget::set_visible_rectangle. */
281 	virtual void set_visible_rectangle(const SDL_Rect& rectangle) override = 0;
282 
283 	/** See @ref widget::impl_draw_children. */
284 	virtual void impl_draw_children(surface& frame_buffer,
285 									int x_offset,
286 									int y_offset) override = 0;
287 
288 protected:
289 	/** See @ref widget::child_populate_dirty_list. */
290 	virtual void
291 	child_populate_dirty_list(window& caller,
292 							  const std::vector<widget*>& call_stack) override
293 			= 0;
294 
295 public:
296 	/** See @ref widget::find_at. */
297 	virtual widget* find_at(const point& coordinate,
298 							 const bool must_be_active) override = 0;
299 
300 	/** See @ref widget::find_at. */
301 	virtual const widget* find_at(const point& coordinate,
302 								   const bool must_be_active) const override
303 			= 0;
304 
305 	/***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
306 
307 	/**
308 	 * Up arrow key pressed.
309 	 *
310 	 * @param modifier            The SDL keyboard modifier when the key was
311 	 *                            pressed.
312 	 * @param handled             If the function handles the key it should
313 	 *                            set handled to true else do not modify it.
314 	 *                            This is used in the keyboard event
315 	 *                            changing.
316 	 */
317 	virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) = 0;
318 
319 	/**
320 	 * Down arrow key pressed.
321 	 *
322 	 * @param modifier            The SDL keyboard modifier when the key was
323 	 *                            pressed.
324 	 * @param handled             If the function handles the key it should
325 	 *                            set handled to true else do not modify it.
326 	 *                            This is used in the keyboard event
327 	 *                            changing.
328 	 */
329 	virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) = 0;
330 
331 	/**
332 	 * Left arrow key pressed.
333 	 *
334 	 * @param modifier            The SDL keyboard modifier when the key was
335 	 *                            pressed.
336 	 * @param handled             If the function handles the key it should
337 	 *                            set handled to true else do not modify it.
338 	 *                            This is used in the keyboard event
339 	 *                            changing.
340 	 */
341 	virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) = 0;
342 
343 	/**
344 	 * Right arrow key pressed.
345 	 *
346 	 * @param modifier            The SDL keyboard modifier when the key was
347 	 *                            pressed.
348 	 * @param handled             If the function handles the key it should
349 	 *                            set handled to true else do not modify it.
350 	 *                            This is used in the keyboard event
351 	 *                            changing.
352 	 */
353 	virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) = 0;
354 
355 protected:
356 	/**
357 	 * Selects a not selected item.
358 	 *
359 	 * @param index               The index of a not selected item.
360 	 */
361 	virtual void do_select_item(const unsigned index) = 0;
362 
363 	/**
364 	 * Deselects a selected item.
365 	 *
366 	 * @param index               The index of a selected item.
367 	 */
368 	virtual void do_deselect_item(const unsigned index) = 0;
369 
370 	/** Gets the grid of an item. */
371 	virtual grid& item_ordered(const unsigned index) = 0;
372 
373 	/** Gets the grid of an item. */
374 	virtual const grid& item_ordered(const unsigned index) const = 0;
375 
376 public:
377 	/**
378 	 * If a sort-order is being applied, maps from unsorted to sorted indicies.
379 	 * This does not take account of whether each object is shown or not.
380 	 */
381 	virtual unsigned get_ordered_index(unsigned index) const = 0;
382 
383 	/**
384 	 * If a sort-order is being applied, maps from sorted to unsorted indicies.
385 	 * This does not take account of whether each object is shown or not.
386 	 */
387 	virtual unsigned get_item_at_ordered(unsigned index_ordered) const = 0;
388 
389 };
390 
391 using generator_sort_array = std::array<generator_base::order_func, 2>;
392 
393 } // namespace gui2
394