libyui  3.0.10
/usr/src/RPM/BUILD/libyui-3.0.10/src/YAlignment.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or 
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:         YAlignment.cc
00020 
00021   Author:       Stefan Hundhammer <sh@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "ui"
00027 #include "YUILog.h"
00028 
00029 #include "YAlignment.h"
00030 #include "YBothDim.h"
00031 #include "YPath.h"
00032 
00033 #include "Libyui_config.h"
00034 
00035 
00036 
00037 
00038 struct YAlignmentPrivate
00039 {
00040     /**
00041      * Constructor.
00042      **/
00043     YAlignmentPrivate( YAlignmentType horAlign,
00044                        YAlignmentType vertAlign )
00045         : leftMargin(0)
00046         , rightMargin(0)
00047         , topMargin(0)
00048         , bottomMargin(0)
00049         , minWidth(0)
00050         , minHeight(0)
00051         {
00052             alignment.hor  = horAlign;
00053             alignment.vert = vertAlign;
00054         }
00055 
00056     //
00057     // Data Members
00058     //
00059 
00060     int leftMargin;
00061     int rightMargin;
00062     int topMargin;
00063     int bottomMargin;
00064 
00065     int minWidth;
00066     int minHeight;
00067 
00068     std::string backgroundPixmap;
00069 
00070     YBothDim<YAlignmentType> alignment;
00071 };
00072 
00073 
00074 
00075 
00076 YAlignment::YAlignment( YWidget *       parent,
00077                         YAlignmentType  horAlign,
00078                         YAlignmentType  vertAlign )
00079     : YSingleChildContainerWidget( parent )
00080     , priv( new YAlignmentPrivate( horAlign, vertAlign ) )
00081 {
00082     YUI_CHECK_NEW( priv );
00083 }
00084 
00085 
00086 YAlignment::~YAlignment()
00087 {
00088     // NOP
00089 }
00090 
00091 
00092 YAlignmentType
00093 YAlignment::alignment( YUIDimension dim ) const
00094 {
00095     return priv->alignment[ dim ];
00096 }
00097 
00098 
00099 int YAlignment::leftMargin() const
00100 {
00101     return priv->leftMargin;
00102 }
00103 
00104 
00105 int YAlignment::rightMargin() const
00106 {
00107     return priv->rightMargin;
00108 }
00109 
00110 
00111 int YAlignment::topMargin() const
00112 {
00113     return priv->topMargin;
00114 }
00115 
00116 
00117 int YAlignment::bottomMargin() const
00118 {
00119     return priv->bottomMargin;
00120 }
00121 
00122 
00123 void YAlignment::setLeftMargin( int margin )
00124 {
00125     priv->leftMargin = margin;
00126 }
00127 
00128 
00129 void YAlignment::setRightMargin( int margin )
00130 {
00131     priv->rightMargin = margin;
00132 }
00133 
00134 
00135 void YAlignment::setTopMargin( int margin )
00136 {
00137     priv->topMargin = margin;
00138 }
00139 
00140 
00141 void YAlignment::setBottomMargin( int margin )
00142 {
00143     priv->bottomMargin = margin;
00144 }
00145 
00146 
00147 int YAlignment::minWidth() const
00148 {
00149     return priv->minWidth;
00150 }
00151 
00152 
00153 int YAlignment::minHeight() const
00154 {
00155     return priv->minHeight;
00156 }
00157 
00158 
00159 void YAlignment::setMinWidth( int width )
00160 {
00161     priv->minWidth = width;
00162 }
00163 
00164 
00165 void YAlignment::setMinHeight( int height )
00166 {
00167     priv->minHeight = height;
00168 }
00169 
00170 
00171 std::string YAlignment::backgroundPixmap() const
00172 {
00173     return priv->backgroundPixmap;
00174 }
00175 
00176 
00177 void YAlignment::addChild( YWidget * child )
00178 {
00179     YSingleChildContainerWidget::addChild( child );
00180 
00181     if ( minWidth()  > 0 )      child->setStretchable( YD_HORIZ, true );
00182     if ( minHeight() > 0 )      child->setStretchable( YD_VERT , true );
00183 }
00184 
00185 
00186 bool YAlignment::stretchable( YUIDimension dim ) const
00187 {
00188     if ( alignment( dim ) == YAlignUnchanged && hasChildren() )
00189         return firstChild()->stretchable( dim );
00190     else
00191         return true;
00192 }
00193 
00194 
00195 int YAlignment::preferredWidth()
00196 {
00197     if ( ! hasChildren() )
00198         return minWidth();
00199 
00200     int preferredWidth = firstChild()->preferredWidth();
00201     preferredWidth    += leftMargin() + rightMargin();
00202 
00203     return std::max( minWidth(), preferredWidth );
00204 }
00205 
00206 
00207 int YAlignment::preferredHeight()
00208 {
00209     if ( ! hasChildren() )
00210         return minHeight();
00211 
00212     int preferredHeight = firstChild()->preferredHeight();
00213     preferredHeight    += topMargin() + bottomMargin();
00214 
00215     return std::max( minHeight(), preferredHeight );
00216 }
00217 
00218 
00219 void YAlignment::setSize( int newWidth, int newHeight )
00220 {
00221     if ( ! hasChildren() )
00222     {
00223         yuiError() << "No child in " << this << std::endl;
00224         return;
00225     }
00226 
00227 
00228     YBothDim<int> newSize;
00229     newSize.hor  = newWidth;
00230     newSize.vert = newHeight;
00231 
00232     YBothDim<int> offset;
00233     offset.hor  = leftMargin();
00234     offset.vert = topMargin();
00235 
00236     YBothDim<int> totalMargin;
00237     totalMargin.hor  = leftMargin() + rightMargin();
00238     totalMargin.vert = topMargin()  + bottomMargin();
00239 
00240     YBothDim<int> newChildSize;
00241     YBothDim<int> newChildPos;
00242 
00243     YUIDimension dim = YD_HORIZ;
00244     while ( true ) // only toggle
00245     {
00246         int childPreferredSize = firstChild()->preferredSize( dim );
00247         int preferredSize      = childPreferredSize + totalMargin[ dim ];
00248 
00249         if ( newSize[ dim ] >= preferredSize )
00250             // Optimum case: enough space for the child and all margins
00251         {
00252             if ( firstChild()->stretchable( dim ) &&
00253                  ( alignment( dim ) == YAlignUnchanged ||
00254                    stretchable( dim ) ) )       // special case: promote child stretchability if `opt(`?stretch) set
00255             {
00256                 newChildSize[ dim ] = newSize[ dim ] - totalMargin[ dim ];
00257             }
00258             else
00259             {
00260                 newChildSize[ dim ] = childPreferredSize;
00261             }
00262         }
00263         else if ( newSize[ dim ] >= childPreferredSize )
00264             // Still enough space for the child, but not for all margins
00265         {
00266             newChildSize[ dim ] = childPreferredSize; // Give the child as much space as it needs
00267 
00268             // Reduce the margins
00269 
00270             if ( totalMargin[ dim ] > 0 ) // Prevent division by zero
00271             {
00272                 // Redistribute remaining space according to margin ratio
00273                 // (disregarding integer rounding errors - we don't care about one pixel)
00274 
00275                 int remaining = newSize[ dim ] - childPreferredSize;
00276                 offset     [ dim ] = remaining * offset[ dim ] / totalMargin[ dim ];
00277                 totalMargin[ dim ] = remaining;
00278             }
00279 
00280         }
00281         else // Not even enough space for the child - forget about the margins
00282         {
00283             newChildSize[ dim ] = newSize[ dim ];
00284             offset      [ dim ] = 0;
00285             totalMargin [ dim ] = 0;
00286         }
00287 
00288 
00289         switch ( alignment( dim ) )
00290         {
00291             case YAlignCenter:
00292                 newChildPos[ dim ] = ( newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ] ) / 2;
00293                 break;
00294 
00295             case YAlignUnchanged:
00296             case YAlignBegin:
00297                 newChildPos[ dim ] = 0;
00298                 break;
00299 
00300             case YAlignEnd:
00301                 newChildPos[ dim ] = newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ];
00302                 break;
00303         }
00304 
00305         newChildPos[ dim ] += offset[ dim ];
00306 
00307         // we need to get out of this loop after the second run
00308         if (dim == YD_HORIZ)
00309           dim = YD_VERT;
00310         else
00311           break;
00312     }
00313 
00314     firstChild()->setSize( newChildSize.hor, newChildSize.vert );
00315     moveChild( firstChild(), newChildPos.hor, newChildPos.vert );
00316 
00317 #if 0
00318     yuiDebug() << "setSize( alignment, " << newWidth         << ", " << newHeight         << ")" << std::endl;
00319     yuiDebug() << "setSize( child, "     << newChildSize.hor << ", " << newChildSize.vert << ")" << std::endl;
00320     yuiDebug() << "moveChild( "          << newChildPos.hor  << ", " << newChildPos.vert  << ")" << std::endl;
00321 #endif
00322 }
00323 
00324 
00325 
00326 int YAlignment::totalMargins( YUIDimension dim ) const
00327 {
00328     if ( dim == YD_HORIZ )      return leftMargin() + rightMargin();
00329     else                        return topMargin()  + bottomMargin();
00330 }
00331 
00332 
00333 
00334 void YAlignment::setBackgroundPixmap( const std::string & pixmapFileName )
00335 {
00336     std::string pixmap = pixmapFileName;
00337 
00338     if ( pixmap.length() > 0 &&
00339          pixmap[0] != '/'  &&   // Absolute path?
00340          pixmap[0] != '.'    )  // Path relative to $CWD ?
00341     {
00342         // Prepend theme dir
00343 
00344         YPath pix( THEMEDIR, pixmap );
00345 
00346         pixmap = pix.path();
00347     }
00348 
00349     priv->backgroundPixmap = pixmap;
00350 }
00351 
00352 const char *
00353 YAlignment::widgetClass() const
00354 {
00355     static const char *YAlignment_classes[3][5] =
00356     {
00357         {"YAlignment_Left", "YAlignment_HCenter", "YAlignment_Right",  "YMarginBox", "YMinWidth"},
00358         {"YAlignment_Top",  "YAlignment_VCenter", "YAlignment_Bottom", "YMarginBox", "YMinHeight"},
00359         {0,                 "YAlignment_HVCenter", 0,                  "YAlignment", "YMinSize"},
00360     };
00361 
00362     int hIndex = 3;
00363     int vIndex = 2;
00364 
00365     if      ( priv->alignment.hor == YAlignBegin    ) { vIndex = 0; hIndex = 0; }
00366     else if ( priv->alignment.hor == YAlignEnd      ) { vIndex = 0; hIndex = 2; }
00367     else if ( priv->alignment.hor == YAlignCenter   )
00368     {
00369         vIndex = 0; hIndex = 1;
00370         if  ( priv->alignment.vert == YAlignCenter  )
00371             vIndex = 2;
00372     }
00373     else if ( priv->alignment.vert == YAlignBegin   ) { vIndex = 1; hIndex = 0; }
00374     else if ( priv->alignment.vert == YAlignEnd     ) { vIndex = 1; hIndex = 2; }
00375     else if ( priv->alignment.vert == YAlignCenter  ) { vIndex = 1; hIndex = 1; }
00376 
00377     if ( priv->alignment.hor  == YAlignUnchanged &&
00378          priv->alignment.vert == YAlignUnchanged )
00379     {
00380         if ( priv->leftMargin   > 0 ||
00381              priv->rightMargin  > 0 ||
00382              priv->topMargin    > 0 ||
00383              priv->bottomMargin > 0 )
00384         {
00385             vIndex = 0; hIndex = 3;
00386         }
00387 
00388         if ( priv->minWidth > 0 || priv->minHeight > 0 )
00389         {
00390             if      ( priv->minWidth  == 0 ) { vIndex = 1; hIndex = 4; }
00391             else if ( priv->minHeight == 0 ) { vIndex = 0; hIndex = 4; }
00392             else                             { vIndex = 2; hIndex = 4; }
00393         }
00394     }
00395     return YAlignment_classes[vIndex][hIndex];
00396 }
 All Classes Functions Variables Enumerations Friends