1 // -*- mode: c++ -*-
2 //
3 // This file is part of libyacurs.
4 // Copyright (C) 2013  Rafael Ostertag
5 //
6 // This program is free software: you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation, either version 3 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program.  If not, see
18 // <http://www.gnu.org/licenses/>.
19 //
20 //
21 // $Id$
22 
23 #ifndef PACK_H
24 #define PACK_H 1
25 
26 #include <list>
27 
28 #include "area.h"
29 #include "widgetbase.h"
30 
31 namespace YACURS {
32 /**
33  * A container widget for stacking widgets horizontally or vertically.
34  *
35  * A pack is a list of widgets, that are either horizontally, or
36  * vertically stacked and displayed.
37  *
38  * The pack will calculate the size needed for displaying the widgets
39  * horizontally, vertically. This should happen on realize() which is
40  * required to be implemented in derived classes.
41  *
42  * @warning If a Pack is destroyed before its associated Widgets, the
43  * Widgets will have a __parent pointer that is invalid.
44  *
45  * @see VPack
46  * @see HPack
47  */
48 class Pack : public WidgetBase {
49    private:
50     /**
51      * The Size of the Pack.
52      *
53      * This will be set by calling size_available().
54      *
55      * @internal
56      *
57      * the only reason for maintaining that field
58      * is, so that we can reset the size when reset_size() is
59      * called and return Size::zero() on subsequent calls to
60      * Pack::size(). Pack::size() may even choose to use a
61      * different size (@sa Pack::size()).
62      */
63     Size _size;
64 
65     /**
66      * When hinting is enabled (@c true) Pack::size_hint() queries
67      * associated Widgets for hints and returns a hint based on
68      * the result. When disabled (@c false) Pack::size_hint()
69      * always returns Size::zero().
70      *
71      * Default @c true.
72      */
73     bool _hinting;
74 
75     /**
76      * Indicates whether or not the Pack should behave as
77      * dynamically sized Widget.
78      *
79      * If @c true, a call to Pack::size() does NOT invoke call
80      * calc_size_non_dynamic(), which in turn returns Size !=
81      * Size::zero() if all associated Widgets are non-dynamic.
82      *
83      * If @c false Pack::size() calls calc_size_non_dynamic() and
84      * may return that result.
85      *
86      * Default @c false.
87      */
88     bool _always_dynamic;
89 
90     /**
91      * Call curses_window() on all associated Widgets.
92      */
93     void set_all_curses_window();
94 
95     /**
96      * Call focusgroup_id() on all associated Widgets.
97      */
98     void set_all_focusgroup_id();
99 
100     /**
101      * Refresh all associated Widgets.
102      *
103      * @param i immediate flag. @sa Realizeable::refresh().
104      */
105     void refresh_all_widgets(bool i);
106 
107     /**
108      * Calculate size required.
109      *
110      * Calculate the size required. Returns a Size not equal
111      * to Size::zero() only if there are no dynamically sized
112      * Widgets associated.
113      *
114      * @internal
115      *
116      * the idea is to use this function in size(), so it
117      * should return a Size != Size::zero() only if we can
118      * determine the size of all Widgets definitely, without
119      * calculating the size for dynamically sized Widgets. In
120      * other words, the Pack appears non-dynamically only if
121      * there are no dynamically sized Widgets associated.
122      */
123     virtual Size calc_size_non_dynamic() const = 0;
124 
125     void take_over(WidgetBase* w);
126 
127    protected:
128     /**
129      * List of all Widgets associated with the Pack.
130      */
131     std::list<WidgetBase*> widget_list;
132 
133     void unrealize();
134 
135    public:
136     Pack();
137 
138     Pack& operator=(const Pack&) = delete;
139     Pack(const Pack&) = delete;
140     Pack& operator=(Pack&&) = delete;
141     Pack(Pack&&) = delete;
142 
143     virtual ~Pack();
144 
145     std::list<WidgetBase*>::size_type widgets() const;
146 
147     /**
148      * Add a widget to the Pack. The widget will be added in front
149      * of any other widget.
150      *
151      * @important Widgets can only be added before the Pack is
152      * realized. It is not possible to add a Widget after the pack
153      * has been realized. Attempt to do so will raise
154      * AlreadyRealized exception
155      *
156      * @param w the widget to add. The pack does not create a
157      * copy, so the pointer has to remain valid for the lifetime
158      * of the pack.
159      */
160     void add_front(WidgetBase* w);
161 
162     /**
163      * Add a widget to the Pack. The widget will be added after
164      * all other widget.
165      *
166      * @important Widgets can only be added before the Pack is
167      * realized. It is not possible to add a Widget after the pack
168      * has been realized. Attempt to do so will raise
169      * AlreadyRealized exception
170      *
171      * @param w the widget to add. The pack does not create a
172      * copy, so the pointer has to remain valid for the lifetime
173      * of the pack.
174      */
175     void add_back(WidgetBase* w);
176 
177     /**
178      * Remove a previously added widget.
179      *
180      * @important Widgets can only be added before the Pack is
181      * realized. It is not possible to add a Widget after the pack
182      * has been realized. Attempt to do so will raise
183      * AlreadyRealized exception
184      *
185      * @param w widget to be removed. Pack compares the address
186      * of the widget.
187      */
188     void remove(WidgetBase* w);
189 
190     /**
191      * Set the curses window of the Pack and all associated
192      * Widgets.
193      *
194      * Pack has to maintain its curses window pointer as well as
195      * the pointer of the associated widgets.
196      *
197      * @param p pointer to curses window
198      */
199     void curses_window(YACURS::INTERNAL::CursWin* p);
200 
201     /**
202      * Set the Focus Group ID of the Pack and all associated
203      * Widgets.
204      *
205      * @param id Focus Group ID.
206      */
207     void focusgroup_id(FocusManager::fgid_t id);
208 
209     /**
210      * Set the available size.
211      *
212      * Since Pack is dynamically sizeable, we have to react on
213      * size_available(), unlike statically sized Widgets.
214      *
215      * @param s the size available to the Pack.
216      */
217     void size_available(const Size& s);
218 
219     Size size() const;
220 
221     /**
222      * Enable/disable hinting mode.
223      *
224      * When hinting is disabled, size_hint() will always return
225      * Size::zero(), else it uses size_hint() of associated
226      * Widgets.
227      *
228      * By default, hinting is enabled.
229      *
230      * @param h @c true enables hinting, @c false disables
231      * hinting.
232      */
233     void hinting(bool h);
234 
235     /**
236      * Query hinting mode.
237      *
238      * @return @c true if hinting is enabled, @c false otherwise.
239      *
240      * @sa hinting()
241      */
242     bool hinting() const;
243 
244     /**
245      * Enable/disable always dynamic mode.
246      *
247      * If always dynamic is disabled, the pack will behave like a
248      * non-dynamic Widget, if, and only if, it does not contain
249      * any dynamicially sized Widgets. Else it behaves like a
250      * dynamic Widget.
251      *
252      * If always dynmic is enabled, it behaves always like a
253      * dynamic widget.
254      *
255      * By default, always dynamic is disabled.
256      *
257      * @param d @c true to enable always dynamic mode, @c false
258      * to disable it.
259      */
260     void always_dynamic(bool d);
261 
262     /**
263      * Query always dynamic mode.
264      *
265      * @return @c true if always dynamic mode is enabled, @c false
266      * otherwise.
267      */
268     bool always_dynamic() const;
269 
270     void reset_size();
271 
272     /**
273      * Handle a size change in an associated Widget.
274      *
275      * If the pack has a parent, the notification is passed
276      * further up. Else it will handle the notification by calling
277      * Pack::resize().
278      *
279      * @return @c true if the notification can be handled, @c
280      * false otherwise.
281      */
282     bool size_change();
283 
284     bool can_focus() const;
285 
286     void focus(bool);
287 
288     bool focus() const;
289 
290     /**
291      * Refresh all Widgets in the Pack.
292      *
293      * @param immediate @see Realizeable
294      */
295     void refresh(bool immediate);
296 
297     /**
298      * Resize the pack.
299      *
300      * This function relies on the implementation of realize() of
301      * derived classes.
302      *
303      * @param a the new size available to the pack.
304      */
305     void resize(const Area& a);
306 
307     //
308     // Has to be implemented in derrived classes
309     // void realize();
310 };
311 }  // namespace YACURS
312 
313 #endif  // PACK_H
314