libyui  3.9.3
YAlignment.cc
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: YAlignment.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 
26 #define YUILogComponent "ui"
27 #include "YUILog.h"
28 
29 #include "YAlignment.h"
30 #include "YBothDim.h"
31 #include "YPath.h"
32 #include "Libyui_config.h"
33 
34 using std::string;
35 
36 
38 {
39  /**
40  * Constructor.
41  **/
42  YAlignmentPrivate( YAlignmentType horAlign,
43  YAlignmentType vertAlign )
44  : leftMargin(0)
45  , rightMargin(0)
46  , topMargin(0)
47  , bottomMargin(0)
48  , minWidth(0)
49  , minHeight(0)
50  {
51  alignment.hor = horAlign;
52  alignment.vert = vertAlign;
53  }
54 
55  //
56  // Data Members
57  //
58 
59  int leftMargin;
60  int rightMargin;
61  int topMargin;
62  int bottomMargin;
63 
64  int minWidth;
65  int minHeight;
66 
67  string backgroundPixmap;
68 
69  YBothDim<YAlignmentType> alignment;
70 };
71 
72 
73 
74 
76  YAlignmentType horAlign,
77  YAlignmentType vertAlign )
78  : YSingleChildContainerWidget( parent )
79  , priv( new YAlignmentPrivate( horAlign, vertAlign ) )
80 {
81  YUI_CHECK_NEW( priv );
82 }
83 
84 
86 {
87  // NOP
88 }
89 
90 
91 YAlignmentType
92 YAlignment::alignment( YUIDimension dim ) const
93 {
94  return priv->alignment[ dim ];
95 }
96 
97 
99 {
100  return priv->leftMargin;
101 }
102 
103 
105 {
106  return priv->rightMargin;
107 }
108 
109 
111 {
112  return priv->topMargin;
113 }
114 
115 
117 {
118  return priv->bottomMargin;
119 }
120 
121 
122 void YAlignment::setLeftMargin( int margin )
123 {
124  priv->leftMargin = margin;
125 }
126 
127 
128 void YAlignment::setRightMargin( int margin )
129 {
130  priv->rightMargin = margin;
131 }
132 
133 
134 void YAlignment::setTopMargin( int margin )
135 {
136  priv->topMargin = margin;
137 }
138 
139 
140 void YAlignment::setBottomMargin( int margin )
141 {
142  priv->bottomMargin = margin;
143 }
144 
145 
147 {
148  return priv->minWidth;
149 }
150 
151 
153 {
154  return priv->minHeight;
155 }
156 
157 
158 void YAlignment::setMinWidth( int width )
159 {
160  priv->minWidth = width;
161 }
162 
163 
164 void YAlignment::setMinHeight( int height )
165 {
166  priv->minHeight = height;
167 }
168 
169 
171 {
172  return priv->backgroundPixmap;
173 }
174 
175 
177 {
179 
180  if ( minWidth() > 0 ) child->setStretchable( YD_HORIZ, true );
181  if ( minHeight() > 0 ) child->setStretchable( YD_VERT , true );
182 }
183 
184 
185 bool YAlignment::stretchable( YUIDimension dim ) const
186 {
187  if ( alignment( dim ) == YAlignUnchanged && hasChildren() )
188  return firstChild()->stretchable( dim );
189  else
190  return true;
191 }
192 
193 
195 {
196  if ( ! hasChildren() )
197  return minWidth();
198 
201 
202  return std::max( minWidth(), preferredWidth );
203 }
204 
205 
207 {
208  if ( ! hasChildren() )
209  return minHeight();
210 
213 
214  return std::max( minHeight(), preferredHeight );
215 }
216 
217 
218 void YAlignment::setSize( int newWidth, int newHeight )
219 {
220  if ( ! hasChildren() )
221  {
222  yuiError() << "No child in " << this << endl;
223  return;
224  }
225 
226 
227  YBothDim<int> newSize;
228  newSize.hor = newWidth;
229  newSize.vert = newHeight;
230 
231  YBothDim<int> offset;
232  offset.hor = leftMargin();
233  offset.vert = topMargin();
234 
235  YBothDim<int> totalMargin;
236  totalMargin.hor = leftMargin() + rightMargin();
237  totalMargin.vert = topMargin() + bottomMargin();
238 
239  YBothDim<int> newChildSize;
240  YBothDim<int> newChildPos;
241 
242  YUIDimension dim = YD_HORIZ;
243  while ( true ) // only toggle
244  {
245  int childPreferredSize = firstChild()->preferredSize( dim );
246  int preferredSize = childPreferredSize + totalMargin[ dim ];
247 
248  if ( newSize[ dim ] >= preferredSize )
249  // Optimum case: enough space for the child and all margins
250  {
251  if ( firstChild()->stretchable( dim ) &&
252  ( alignment( dim ) == YAlignUnchanged ||
253  stretchable( dim ) ) ) // special case: promote child stretchability if `opt(`?stretch) set
254  {
255  newChildSize[ dim ] = newSize[ dim ] - totalMargin[ dim ];
256  }
257  else
258  {
259  newChildSize[ dim ] = childPreferredSize;
260  }
261  }
262  else if ( newSize[ dim ] >= childPreferredSize )
263  // Still enough space for the child, but not for all margins
264  {
265  newChildSize[ dim ] = childPreferredSize; // Give the child as much space as it needs
266 
267  // Reduce the margins
268 
269  if ( totalMargin[ dim ] > 0 ) // Prevent division by zero
270  {
271  // Redistribute remaining space according to margin ratio
272  // (disregarding integer rounding errors - we don't care about one pixel)
273 
274  int remaining = newSize[ dim ] - childPreferredSize;
275  offset [ dim ] = remaining * offset[ dim ] / totalMargin[ dim ];
276  totalMargin[ dim ] = remaining;
277  }
278 
279  }
280  else // Not even enough space for the child - forget about the margins
281  {
282  newChildSize[ dim ] = newSize[ dim ];
283  offset [ dim ] = 0;
284  totalMargin [ dim ] = 0;
285  }
286 
287 
288  switch ( alignment( dim ) )
289  {
290  case YAlignCenter:
291  newChildPos[ dim ] = ( newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ] ) / 2;
292  break;
293 
294  case YAlignUnchanged:
295  case YAlignBegin:
296  newChildPos[ dim ] = 0;
297  break;
298 
299  case YAlignEnd:
300  newChildPos[ dim ] = newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ];
301  break;
302  }
303 
304  newChildPos[ dim ] += offset[ dim ];
305 
306  // we need to get out of this loop after the second run
307  if (dim == YD_HORIZ)
308  dim = YD_VERT;
309  else
310  break;
311  }
312 
313  firstChild()->setSize( newChildSize.hor, newChildSize.vert );
314  moveChild( firstChild(), newChildPos.hor, newChildPos.vert );
315 
316 #if 0
317  yuiDebug() << "setSize( alignment, " << newWidth << ", " << newHeight << ")" << endl;
318  yuiDebug() << "setSize( child, " << newChildSize.hor << ", " << newChildSize.vert << ")" << endl;
319  yuiDebug() << "moveChild( " << newChildPos.hor << ", " << newChildPos.vert << ")" << endl;
320 #endif
321 }
322 
323 
324 
325 int YAlignment::totalMargins( YUIDimension dim ) const
326 {
327  if ( dim == YD_HORIZ ) return leftMargin() + rightMargin();
328  else return topMargin() + bottomMargin();
329 }
330 
331 
332 
333 void YAlignment::setBackgroundPixmap( const string & pixmapFileName )
334 {
335  string pixmap = pixmapFileName;
336 
337  if ( pixmap.length() > 0 &&
338  pixmap[0] != '/' && // Absolute path?
339  pixmap[0] != '.' ) // Path relative to $CWD ?
340  {
341  // Prepend theme dir
342 
343  YPath pix( THEMEDIR, pixmap );
344 
345  pixmap = pix.path();
346  }
347 
348  priv->backgroundPixmap = pixmap;
349 }
350 
351 const char *
353 {
354  static const char *YAlignment_classes[3][5] =
355  {
356  {"YAlignment_Left", "YAlignment_HCenter", "YAlignment_Right", "YMarginBox", "YMinWidth"},
357  {"YAlignment_Top", "YAlignment_VCenter", "YAlignment_Bottom", "YMarginBox", "YMinHeight"},
358  {0, "YAlignment_HVCenter", 0, "YAlignment", "YMinSize"},
359  };
360 
361  int hIndex = 3;
362  int vIndex = 2;
363 
364  if ( priv->alignment.hor == YAlignBegin ) { vIndex = 0; hIndex = 0; }
365  else if ( priv->alignment.hor == YAlignEnd ) { vIndex = 0; hIndex = 2; }
366  else if ( priv->alignment.hor == YAlignCenter )
367  {
368  vIndex = 0; hIndex = 1;
369  if ( priv->alignment.vert == YAlignCenter )
370  vIndex = 2;
371  }
372  else if ( priv->alignment.vert == YAlignBegin ) { vIndex = 1; hIndex = 0; }
373  else if ( priv->alignment.vert == YAlignEnd ) { vIndex = 1; hIndex = 2; }
374  else if ( priv->alignment.vert == YAlignCenter ) { vIndex = 1; hIndex = 1; }
375 
376  if ( priv->alignment.hor == YAlignUnchanged &&
377  priv->alignment.vert == YAlignUnchanged )
378  {
379  if ( priv->leftMargin > 0 ||
380  priv->rightMargin > 0 ||
381  priv->topMargin > 0 ||
382  priv->bottomMargin > 0 )
383  {
384  vIndex = 0; hIndex = 3;
385  }
386 
387  if ( priv->minWidth > 0 || priv->minHeight > 0 )
388  {
389  if ( priv->minWidth == 0 ) { vIndex = 1; hIndex = 4; }
390  else if ( priv->minHeight == 0 ) { vIndex = 0; hIndex = 4; }
391  else { vIndex = 2; hIndex = 4; }
392  }
393  }
394  return YAlignment_classes[vIndex][hIndex];
395 }
std::string backgroundPixmap() const
Return the name of the background pixmap or an empty string, if there is none.
Definition: YAlignment.cc:170
std::string path()
Returns the full path of the file if found; if not found just the filename given in constructor...
Definition: YPath.cc:187
int minWidth() const
Return the minimum width of this alignment or 0 if none is set.
Definition: YAlignment.cc:146
YWidget * firstChild() const
Returns the first child or 0 if there is none.
Definition: YWidget.h:199
bool hasChildren() const
Returns &#39;true&#39; if this widget has any children.
Definition: YWidget.h:192
int minHeight() const
Return the minimum height of this alignment or 0 if none is set.
Definition: YAlignment.cc:152
virtual bool stretchable(YUIDimension dim) const
Return this widget&#39;s stretchability.
Definition: YAlignment.cc:185
virtual bool stretchable(YUIDimension dim) const
This is a boolean value that determines whether the widget is resizable beyond its preferred size in ...
Definition: YWidget.cc:572
virtual int preferredHeight()
Preferred height of the widget.
Definition: YAlignment.cc:206
virtual void moveChild(YWidget *child, int newx, int newy)=0
Move a child widget to a new position.
YAlignment(YWidget *parent, YAlignmentType horAlign, YAlignmentType vertAlign)
Constructor.
Definition: YAlignment.cc:75
virtual int preferredSize(YUIDimension dim)
Preferred size of the widget in the specified dimension.
Definition: YWidget.cc:546
virtual void addChild(YWidget *child)
Add a child widget.
Definition: YAlignment.cc:176
void setMinHeight(int height)
Set the minimum height to return for preferredHeight().
Definition: YAlignment.cc:164
virtual void setSize(int newWidth, int newHeight)
Set the current size and move the child widget according to its alignment.
Definition: YAlignment.cc:218
void setMinWidth(int width)
Set the minimum width to return for preferredWidth().
Definition: YAlignment.cc:158
YAlignmentType alignment(YUIDimension dim) const
Return the alignment in the specified dimension.
Definition: YAlignment.cc:92
Container widget class that manages one child.
virtual const char * widgetClass() const
Return a descriptive name of this widget class for logging, debugging etc.
Definition: YAlignment.cc:352
void setRightMargin(int margin)
Set the right margin in pixels.
Definition: YAlignment.cc:128
virtual void setSize(int newWidth, int newHeight)=0
Set the new size of the widget.
virtual int preferredWidth()
Preferred width of the widget.
Definition: YAlignment.cc:194
void setBottomMargin(int margin)
Set the bottom margin in pixels.
Definition: YAlignment.cc:140
int topMargin() const
Return the top margin in pixels, the distance between the top edge of this alignment and the top edge...
Definition: YAlignment.cc:110
virtual int preferredHeight()=0
Preferred height of the widget.
virtual void setBackgroundPixmap(const std::string &pixmapFileName)
Set a background pixmap.
Definition: YAlignment.cc:333
Finds files (e.g.
Definition: YPath.h:43
virtual int preferredWidth()=0
Preferred width of the widget.
int bottomMargin() const
Return the bottom margin in pixels, the distance between the bottom edge of this alignment and the bo...
Definition: YAlignment.cc:116
void setTopMargin(int margin)
Set the top margin in pixels.
Definition: YAlignment.cc:134
int totalMargins(YUIDimension dim) const
Return the sum of all margins in the specified dimension.
Definition: YAlignment.cc:325
virtual void addChild(YWidget *child)
Add a new child.
Definition: YWidget.cc:176
int leftMargin() const
Return the left margin in pixels, the distance between the left edge of this alignment and the left e...
Definition: YAlignment.cc:98
YAlignmentPrivate(YAlignmentType horAlign, YAlignmentType vertAlign)
Constructor.
Definition: YAlignment.cc:42
int rightMargin() const
Return the right margin in pixels, the distance between the right edge of this alignment and the righ...
Definition: YAlignment.cc:104
virtual ~YAlignment()
Destructor.
Definition: YAlignment.cc:85
void setStretchable(YUIDimension dim, bool newStretch)
Set the stretchable state to "newStretch" regardless of any hstretch or vstretch options.
Definition: YWidget.cc:560
Abstract base class of all UI widgets.
Definition: YWidget.h:54
void setLeftMargin(int margin)
Set the left margin in pixels.
Definition: YAlignment.cc:122