libyui  3.3.2
YButtonBox.h
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YButtonBox.h
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 #ifndef YButtonBox_h
26 #define YButtonBox_h
27 
28 #include <vector>
29 
30 #include "YWidget.h"
31 #include "YPushButton.h"
32 
33 class YButtonBoxPrivate;
34 class YPushButton;
35 
36 
37 /**
38  * Helper class: Layout policy for YButtonBox widgets.
39  * This is used in the default YButtonBox::doLayout() method.
40  **/
42 {
44  : buttonOrder( YKDEButtonOrder )
45  , equalSizeButtons( false )
46  , addExcessSpaceToHelpButtonExtraMargin( false )
47  {
48  alignment[ YD_HORIZ ] = YAlignCenter;
49  alignment[ YD_VERT ] = YAlignBegin; // Align top
50  }
51 
52  YButtonOrder buttonOrder; // YKDEButtonOrder / YGnomeButtonOrder
53  bool equalSizeButtons; // Make all buttons the same size?
54  bool addExcessSpaceToHelpButtonExtraMargin;
55 
56  // Alignment for the YButtonBox itself
57  YAlignmentType alignment[ YUIAllDimensions ];
58 };
59 
60 
61 /**
62  * Helper class: Margins for YButtonBox widgets.
63  * All sizes are in UI-dependent units, i.e. in pixels.
64  **/
66 {
68  : left( 0 )
69  , right( 0 )
70  , top( 0 )
71  , bottom( 0 )
72  , spacing( 0 )
73  , helpButtonExtraSpacing( 0 )
74  {}
75 
76  int left; // Left of the leftmost button
77  int right; // Right of the rightmost button
78  int top; // Above the hightest button
79  int bottom; // Below the hightest button
80 
81  int spacing; // Between buttons
82  int helpButtonExtraSpacing; // Between [Help] and the next button
83 }; // (additionally to "spacing"!)
84 
85 
86 /**
87  * Container widget for dialog buttons that abstracts the button order
88  * depending on the desktop environment.
89  *
90  * KDE and Windows arrange dialog buttons like this:
91  *
92  * [OK] [Apply] [Cancel] [Custom1] [Custom2] ... [Help]
93  *
94  * [Continue] [Cancel]
95  *
96  * [Yes] [No]
97  *
98  *
99  * GNOME and MacOS arrange them like this:
100  *
101  * [Help] [Custom1] [Custom2] ... [Apply] [Cancel] [OK]
102  *
103  * [Cancel] [Continue]
104  *
105  * [No] [Yes]
106  *
107  *
108  * This class provides the abstraction to use whatever layout is more
109  * appropriate in the current environment. The application creates the buttons
110  * as child widgets of a YButtonBox (rather than a YHBox) and leaves the button
111  * order to the YButtonBox.
112  *
113  * Each of the standard buttons ([OK], [Apply], [Cancel], [Help]) needs to have
114  * a button role properly assigned.
115  *
116  * If set up properly (see YApplication::setDefaultFunctionKey()), known button
117  * labels will be assigned an appropriate role:
118  *
119  * [OK] F10
120  * [Continue] -> [OK] F10
121  * [Yes] -> [OK] F10
122  * [Accept] -> [OK] F10
123  * [Next] -> [OK] F10
124  *
125  * [Cancel] F9
126  * [No] -> [Cancel] F9
127  *
128  * [Help] F1
129  *
130  * Buttons with nonstandard labels that act in such a role need to be
131  * explicitly assigned that role:
132  *
133  * [Print ] [Cancel] [Help]
134  * [Delete] [Cancel] [Help]
135  *
136  * Those [Print] or [Delete] buttons act as [OK] buttons (the "yes, do it"
137  * action of that dialog). Call YPushButton::setButtonRole( YOkButton )
138  * explicitly for them.
139  *
140  *
141  * YButtonBox widgets only accept YPushButton child widgets. Otherwise an
142  * exception is thrown.
143  *
144  * If there is more than one button, one of the child buttons needs to have the
145  * [OK] role, and another needs to have the [Cancel] role. Otherwise an
146  * exception is thrown.
147  **/
148 class YButtonBox : public YWidget
149 {
150  friend class YButtonBoxPrivate;
151 
152 protected:
153  /**
154  * Constructor.
155  **/
156  YButtonBox( YWidget * parent );
157 
158 public:
159 
160  /**
161  * Destructor.
162  **/
163  virtual ~YButtonBox();
164 
165  /**
166  * Return a descriptive name of this widget class for logging,
167  * debugging etc.
168  **/
169  virtual const char * widgetClass() const { return "YButtonBox"; }
170 
171  /**
172  * Set the button policy for all future YButtonBox widgets:
173  * Button order, alignment if there is any excess space, whether or not to
174  * give all buttons the same size.
175  *
176  * You might want to use one of the predefined static methods:
177  * YButtonBox::kdeLayoutPolicy(), YButtonBox::gnomeLayoutPolicy().
178  *
179  * The default doLayout() method uses those values.
180  *
181  * Notice that there is intentionally no way to set this differently for
182  * each individual YButtonBox: This would defeat the purpose of consistency
183  * (with the desktop environment this application is running in), which is
184  * the reason for having this widget class.
185  **/
186  static void setLayoutPolicy( const YButtonBoxLayoutPolicy & layoutPolicy );
187 
188  /**
189  * Return the layout policy.
190  **/
191  static YButtonBoxLayoutPolicy layoutPolicy();
192 
193  /**
194  * Predefined layout policy for KDE-like behaviour.
195  **/
196  static YButtonBoxLayoutPolicy kdeLayoutPolicy();
197 
198  /**
199  * Predefined layout policy for GNOME-like behaviour.
200  **/
201  static YButtonBoxLayoutPolicy gnomeLayoutPolicy();
202 
203  /**
204  * Set the default margins for all future YButtonBox widgets.
205  **/
206  static void setDefaultMargins( const YButtonBoxMargins & margins );
207 
208  /**
209  * Return the default margins for all future YButtonBox widgets.
210  **/
211  static YButtonBoxMargins defaultMargins();
212 
213  /**
214  * Set the margins for this YButtonBox.
215  *
216  * Derived classes are free to reimplement this, but they should call this
217  * base class method in the new method.
218  **/
219  virtual void setMargins( const YButtonBoxMargins & margins );
220 
221  /**
222  * Return the margins of this YButtonBox.
223  *
224  * Notice that those are only the desired margins; if there is not enough
225  * space, margins and spacings will be reduced before buttons are cut off.
226  **/
227  YButtonBoxMargins margins() const;
228 
229  /**
230  * Lay out the button box and its children (its buttons). This is where the
231  * button order is implemented.
232  *
233  * This method is called by the default setSize() method. It uses
234  * YButtonBox::layoutPolicy() and the specified margins (defaultMargins
235  * unless changed with setMargins() ). It moves the buttons to their
236  * position with moveChild().
237  *
238  * This all should work reasonably in all cases (Qt-UI with KDE button
239  * order, Gtk-UI with Gnome button order, NCurses-UI with KDE button
240  * order).
241  *
242  * Still, derived classes can reimplement this. It does not make very much
243  * sense to call this default method in a new implementation.
244  **/
245  virtual void doLayout( int width, int height );
246 
247  /**
248  * Search the child widgets for the first button with the specified role.
249  * Return the button or 0 if there is no button with that role.
250  **/
251  YPushButton * findButton( YButtonRole role );
252 
253  /**
254  * Sanity check: Check if all child widgets have the correct widget class
255  * and if the button roles are assigned correctly.
256  *
257  * A YButtonBox with more than one button is required to have one YOKButton
258  * and ony YCancelButton. Neither button role may be assigned more than
259  * once.
260  *
261  * This method may throw exceptions:
262  * - YUIButtonRoleMismatchException
263  * - YUIInvalidChildException (wrong widget class)
264  *
265  * This cannot be done as child widgets are inserted since this is done
266  * from the child widgets' constructors, so virtual methods or dynamic_cast
267  * don't work at that point.
268  *
269  * This is called in the default setSize() method (just before doLayout()),
270  * so any of the above errors are caught only at that time. Applications
271  * are free to call this before that time to make error handling more
272  * transparent.
273  **/
274  void sanityCheck();
275 
276  /**
277  * Relax the sanity check done in sanityCheck(): Do not enforce that there
278  * has to be a YOKButton and a YCancelButton if there is more than one
279  * button.
280  *
281  * In very rare cases, it might be neccessary to have a less stringent
282  * sanity check: There are some very few legitimate cases for having a
283  * YButtonBox with multiple buttons, yet without a YCancelButton.
284  *
285  * Examples:
286  *
287  * ...message...
288  * <Countdown>
289  * [OK] [Stop]
290  *
291  * ...message...
292  * [OK] [Details]
293  *
294  * In those cases, it makes sense to relax the sanity check.
295  **/
296  void setSanityCheckRelaxed( bool relax = true );
297 
298  /**
299  * Return 'true' if sanity checks are currently relaxed, 'false' if not.
300  **/
301  bool sanityCheckRelaxed() const;
302 
303  /**
304  * Preferred width of the widget.
305  *
306  * Reimplemented from YWidget. This default method returns the sum of
307  * the the widths of all child widgets plus the left and right margins plus
308  * the spacings.
309  *
310  * Derived classes can reimplement this method. It does not make very much
311  * sense to call this base class method in a new implementation.
312  **/
313  virtual int preferredWidth();
314 
315  /**
316  * Preferred height of the widget.
317  *
318  * Reimplemented from YWidget. This default method returns the height of
319  * the highest child plus the top and bottom margins.
320  *
321  * Derived classes can reimplement this method. It does not make very much
322  * sense to call this base class method in a new implementation.
323  **/
324  virtual int preferredHeight();
325 
326  /**
327  * Sets the size of the YButtonBox.
328  *
329  * Derived classes can reimplement this, but this base class method should
330  * be called in the reimplemented function.
331  *
332  * Reimplemented from YWidget.
333  **/
334  virtual void setSize( int newWidth, int newHeight );
335 
336  /**
337  * Returns the stretchability of the YButtonBox. YButtonBox widgets are
338  * horizontally stretchable by default. How any excess space is used is
339  * specified in the layout policy.
340  *
341  * Reimplemented from YWidget.
342  **/
343  virtual bool stretchable( YUIDimension dimension ) const;
344 
345 
346 protected:
347 
348  /**
349  * Return the button children sorted (left to right) by the current button
350  * order (from the layout policy).
351  *
352  * This default implementation handles KDE and Gnome button orders. It is
353  * used in the default doLayout() method.
354  *
355  * This may throw exceptions if there are non-button children or if there
356  * are multiple buttons with any of the standard button roles (except
357  * YCustomButton, of course).
358  **/
359  virtual std::vector<YPushButton *> buttonsByButtonOrder();
360 
361  /**
362  * Return the (preferred) size of the biggest child widget in the specified
363  * dimension.
364  **/
365  int maxChildSize( YUIDimension dim ) const;
366 
367  /**
368  * Return the sum of the (preferred) widths of all child widgets.
369  **/
370  int totalChildrenWidth() const;
371 
372  /**
373  * Move a child to a new position. This is used in doLayout().
374  *
375  * Derived classes are required to implement this.
376  **/
377  virtual void moveChild( YWidget * child, int newX, int newY ) = 0;
378 
379  /**
380  * Calculate the preferred with with or without trying to enforce buttons
381  * of equal size.
382  **/
383  int preferredWidth( bool equalSizeButtons );
384 
385 
386 private:
387 
389 
390  static YButtonBoxLayoutPolicy _layoutPolicy;
391  static YButtonBoxMargins _defaultMargins;
392 };
393 
394 
395 #endif // YButtonBox_h
virtual const char * widgetClass() const
Return a descriptive name of this widget class for logging, debugging etc.
Definition: YButtonBox.h:169
Helper class: Layout policy for YButtonBox widgets.
Definition: YButtonBox.h:41
A push button; may have an icon, and a F-key shortcut.
Definition: YPushButton.h:37
Helper class: Margins for YButtonBox widgets.
Definition: YButtonBox.h:65
Container widget for dialog buttons that abstracts the button order depending on the desktop environm...
Definition: YButtonBox.h:148
Abstract base class of all UI widgets.
Definition: YWidget.h:54