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