src/gui/kernel/qlayoutengine.cpp File Reference

#include "qlayout.h"
#include "private/qlayoutengine_p.h"
#include "qvector.h"
#include "qwidget.h"
#include <qlist.h>
#include <qalgorithms.h>
#include <qdebug.h>

Include dependency graph for qlayoutengine.cpp:

Go to the source code of this file.

Typedefs

typedef qint64 Fixed

Functions

static Fixed toFixed (int i)
static int fRound (Fixed i)
void qGeomCalc (QVector< QLayoutStruct > &chain, int start, int count, int pos, int space, int spacer)
Q_GUI_EXPORT QSize qSmartMinSize (const QWidgetItem *i)
Q_GUI_EXPORT QSize qSmartMinSize (const QWidget *w)
Q_GUI_EXPORT QSize qSmartMaxSize (const QWidgetItem *i, Qt::Alignment align)
Q_GUI_EXPORT QSize qSmartMaxSize (const QWidget *w, Qt::Alignment align)


Typedef Documentation

typedef qint64 Fixed

Definition at line 36 of file qlayoutengine.cpp.


Function Documentation

static int fRound ( Fixed  i  )  [inline, static]

Definition at line 38 of file qlayoutengine.cpp.

Referenced by qGeomCalc().

00038                                   {
00039     return (i % 256 < 128) ? i / 256 : 1 + i / 256;
00040 }

void qGeomCalc ( QVector< QLayoutStruct > &  chain,
int  start,
int  count,
int  pos,
int  space,
int  spacer 
)

Definition at line 57 of file qlayoutengine.cpp.

References QVector< T >::empty(), fRound(), i, n, p, qDebug(), qMin(), qSort(), QVector< T >::size(), size, space_left(), toFixed(), and w.

Referenced by QBoxLayoutPrivate::calcHfw(), QGridLayoutPrivate::distribute(), distributeMultiBox(), QSplitterPrivate::doResize(), QDockAreaLayoutInfo::fitItems(), QDockWidgetLayout::fitLayout(), QGridLayoutPrivate::heightForWidth(), QTabBarPrivate::layoutTabs(), and QBoxLayout::setGeometry().

00059 {
00060     int cHint = 0;
00061     int cMin = 0;
00062     int cMax = 0;
00063     int sumStretch = 0;
00064     int spacerCount = 0;
00065 
00066     bool wannaGrow = false; // anyone who really wants to grow?
00067     //    bool canShrink = false; // anyone who could be persuaded to shrink?
00068 
00069     bool allEmptyNonstretch = true;
00070     int i;
00071     for (i = start; i < start + count; i++) {
00072         chain[i].done = false;
00073         cHint += chain[i].smartSizeHint();
00074         cMin += chain[i].minimumSize;
00075         cMax += chain[i].maximumSize;
00076         sumStretch += chain[i].stretch;
00077         if (!chain[i].empty)
00078             spacerCount++;
00079         wannaGrow = wannaGrow || chain[i].expansive || chain[i].stretch > 0;
00080         allEmptyNonstretch = allEmptyNonstretch && !wannaGrow && chain[i].empty;
00081     }
00082 
00083     int extraspace = 0;
00084     if (spacerCount)
00085         spacerCount--; // only spacers between things
00086 
00087     if (space < cMin + spacerCount * spacer) {
00088         /*
00089           Less space than minimumSize; take from the biggest first
00090         */
00091 
00092         int minSize =  cMin + spacerCount * spacer;
00093 
00094         //shrink the spacers proportionally
00095         spacer = minSize > 0 ? (spacer * space) / minSize : 0;
00096 
00097         QList<int> list;
00098 
00099         for (i = start; i < start+count; i++) {
00100             list << chain[i].minimumSize;
00101         }
00102 
00103         qSort(list);
00104 
00105         int space_left = space - spacerCount*spacer;
00106 
00107         int sum = 0;
00108         int idx = 0;
00109         int space_used=0;
00110         int current = 0;
00111         while (idx < count && space_used < space_left) {
00112             current = list.at(idx);
00113             space_used = sum + current * (count - idx);
00114             sum += current;
00115             ++idx;
00116         }
00117         --idx;
00118         int deficit = space_used - space_left;
00119 
00120         int items = count - idx;
00121         int maxval = current - deficit/items;
00122 
00123         for (i = start; i < start+count; i++) {
00124             chain[i].size = qMin(chain[i].minimumSize, maxval);
00125             chain[i].done = true;
00126         }
00127     } else if (space < cHint + spacerCount*spacer) {
00128         /*
00129           Less space than smartSizeHint(), but more than minimumSize.
00130           Currently take space equally from each, as in Qt 2.x.
00131           Commented-out lines will give more space to stretchier
00132           items.
00133         */
00134         int n = count;
00135         int space_left = space - spacerCount*spacer;
00136         int overdraft = cHint - space_left;
00137 
00138         // first give to the fixed ones:
00139         for (i = start; i < start + count; i++) {
00140             if (!chain[i].done
00141                  && chain[i].minimumSize >= chain[i].smartSizeHint()) {
00142                 chain[i].size = chain[i].smartSizeHint();
00143                 chain[i].done = true;
00144                 space_left -= chain[i].smartSizeHint();
00145                 // sumStretch -= chain[i].stretch;
00146                 n--;
00147             }
00148         }
00149         bool finished = n == 0;
00150         while (!finished) {
00151             finished = true;
00152             Fixed fp_over = toFixed(overdraft);
00153             Fixed fp_w = 0;
00154 
00155             for (i = start; i < start+count; i++) {
00156                 if (chain[i].done)
00157                     continue;
00158                 // if (sumStretch <= 0)
00159                 fp_w += fp_over / n;
00160                 // else
00161                 //    fp_w += (fp_over * chain[i].stretch) / sumStretch;
00162                 int w = fRound(fp_w);
00163                 chain[i].size = chain[i].smartSizeHint() - w;
00164                 fp_w -= toFixed(w); // give the difference to the next
00165                 if (chain[i].size < chain[i].minimumSize) {
00166                     chain[i].done = true;
00167                     chain[i].size = chain[i].minimumSize;
00168                     finished = false;
00169                     overdraft -= (chain[i].smartSizeHint()
00170                                    - chain[i].minimumSize);
00171                     // sumStretch -= chain[i].stretch;
00172                     n--;
00173                     break;
00174                 }
00175             }
00176         }
00177     } else { // extra space
00178         int n = count;
00179         int space_left = space - spacerCount*spacer;
00180         // first give to the fixed ones, and handle non-expansiveness
00181         for (i = start; i < start + count; i++) {
00182             if (!chain[i].done
00183                 && (chain[i].maximumSize <= chain[i].smartSizeHint()
00184                     || (wannaGrow && !chain[i].expansive && chain[i].stretch == 0)
00185                     || (!allEmptyNonstretch && chain[i].empty &&
00186                         !chain[i].expansive && chain[i].stretch == 0))) {
00187                 chain[i].size = chain[i].smartSizeHint();
00188                 chain[i].done = true;
00189                 space_left -= chain[i].size;
00190                 sumStretch -= chain[i].stretch;
00191                 n--;
00192             }
00193         }
00194         extraspace = space_left;
00195 
00196         /*
00197           Do a trial distribution and calculate how much it is off.
00198           If there are more deficit pixels than surplus pixels, give
00199           the minimum size items what they need, and repeat.
00200           Otherwise give to the maximum size items, and repeat.
00201 
00202           Paul Olav Tvete has a wonderful mathematical proof of the
00203           correctness of this principle, but unfortunately this
00204           comment is too small to contain it.
00205         */
00206         int surplus, deficit;
00207         do {
00208             surplus = deficit = 0;
00209             Fixed fp_space = toFixed(space_left);
00210             Fixed fp_w = 0;
00211             for (i = start; i < start+count; i++) {
00212                 if (chain[i].done)
00213                     continue;
00214                 extraspace = 0;
00215                 if (sumStretch <= 0)
00216                     fp_w += fp_space / n;
00217                 else
00218                     fp_w += (fp_space * chain[i].stretch) / sumStretch;
00219                 int w = fRound(fp_w);
00220                 chain[i].size = w;
00221                 fp_w -= toFixed(w); // give the difference to the next
00222                 if (w < chain[i].smartSizeHint()) {
00223                     deficit +=  chain[i].smartSizeHint() - w;
00224                 } else if (w > chain[i].maximumSize) {
00225                     surplus += w - chain[i].maximumSize;
00226                 }
00227             }
00228             if (deficit > 0 && surplus <= deficit) {
00229                 // give to the ones that have too little
00230                 for (i = start; i < start+count; i++) {
00231                     if (!chain[i].done &&
00232                          chain[i].size < chain[i].smartSizeHint()) {
00233                         chain[i].size = chain[i].smartSizeHint();
00234                         chain[i].done = true;
00235                         space_left -= chain[i].smartSizeHint();
00236                         sumStretch -= chain[i].stretch;
00237                         n--;
00238                     }
00239                 }
00240             }
00241             if (surplus > 0 && surplus >= deficit) {
00242                 // take from the ones that have too much
00243                 for (i = start; i < start+count; i++) {
00244                     if (!chain[i].done &&
00245                          chain[i].size > chain[i].maximumSize) {
00246                         chain[i].size = chain[i].maximumSize;
00247                         chain[i].done = true;
00248                         space_left -= chain[i].maximumSize;
00249                         sumStretch -= chain[i].stretch;
00250                         n--;
00251                     }
00252                 }
00253             }
00254         } while (n > 0 && surplus != deficit);
00255         if (n == 0)
00256             extraspace = space_left;
00257     }
00258 
00259     /*
00260       As a last resort, we distribute the unwanted space equally
00261       among the spacers (counting the start and end of the chain). We
00262       could, but don't, attempt a sub-pixel allocation of the extra
00263       space.
00264     */
00265     int extra = extraspace / (spacerCount + 2);
00266     int p = pos + extra;
00267     for (i = start; i < start+count; i++) {
00268         chain[i].pos = p;
00269         p = p + chain[i].size;
00270         if (!chain[i].empty)
00271             p += spacer+extra;
00272     }
00273 
00274 
00275 #ifdef QLAYOUT_EXTRA_DEBUG
00276     qDebug() << "qGeomCalc" << "start" << start <<  "count" << count <<  "pos" << pos <<  "space" << space <<  "spacer" << spacer;
00277     for (i = start; i < start + count; i++) {
00278         qDebug() << i << ":" << chain[i].minimumSize << chain[i].smartSizeHint() << chain[i].maximumSize
00279                  << "stretch" << chain[i].stretch << "empty" << chain[i].empty << "expansive" << chain[i].expansive;
00280         qDebug() << "result pos" << chain[i].pos << "size" << chain[i].size;
00281     }
00282 #endif
00283 }

Here is the call graph for this function:

Q_GUI_EXPORT QSize qSmartMaxSize ( const QWidget w,
Qt::Alignment  align 
)

Definition at line 347 of file qlayoutengine.cpp.

References qSmartMaxSize(), and w.

00348 {
00349     QWidgetItem item(const_cast<QWidget *>(w));
00350     return qSmartMaxSize(&item, align);
00351 }

Here is the call graph for this function:

Q_GUI_EXPORT QSize qSmartMaxSize ( const QWidgetItem i,
Qt::Alignment  align 
)

Definition at line 324 of file qlayoutengine.cpp.

Referenced by QLayout::closestAcceptableSize(), QWidgetItem::maximumSize(), QDockAreaLayoutItem::maximumSize(), qSmartMaxSize(), QWidgetItem::setGeometry(), and QScrollAreaPrivate::updateScrollBars().

00325 {
00326     QWidget *w = ((QWidgetItem*)i)->widget();
00327     if (align & Qt::AlignHorizontal_Mask && align & Qt::AlignVertical_Mask)
00328         return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
00329     QSize s = w->maximumSize();
00330     if (s.width() == QWIDGETSIZE_MAX && !(align & Qt::AlignHorizontal_Mask))
00331         if (!(w->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag))
00332             s.setWidth(w->sizeHint().width());
00333 
00334     if (s.height() == QWIDGETSIZE_MAX && !(align & Qt::AlignVertical_Mask))
00335         if (!(w->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag))
00336             s.setHeight(w->sizeHint().height());
00337 
00338     s = s.expandedTo(w->minimumSize());
00339 
00340     if (align & Qt::AlignHorizontal_Mask)
00341         s.setWidth(QLAYOUTSIZE_MAX);
00342     if (align & Qt::AlignVertical_Mask)
00343         s.setHeight(QLAYOUTSIZE_MAX);
00344     return s;
00345 }

Q_GUI_EXPORT QSize qSmartMinSize ( const QWidget w  ) 

Definition at line 318 of file qlayoutengine.cpp.

References qSmartMinSize(), and w.

00319 {
00320     QWidgetItem item(const_cast<QWidget *>(w));
00321     return qSmartMinSize(&item);
00322 }

Here is the call graph for this function:

Q_GUI_EXPORT QSize qSmartMinSize ( const QWidgetItem i  ) 

Definition at line 285 of file qlayoutengine.cpp.

Referenced by QSplitterPrivate::addContribution(), QWorkspace::addWindow(), QWorkspace::cascade(), QLayout::closestAcceptableSize(), QSplitterPrivate::doMove(), QSplitterPrivate::doResize(), QStatusBar::event(), QSplitterPrivate::findWidgetJustBeforeOrJustAfter(), QWidgetItem::minimumSize(), QStackedLayout::minimumSize(), QDockAreaLayoutItem::minimumSize(), QSplitter::minimumSizeHint(), QWidgetResizeHandler::mouseMoveEvent(), qSmartMinSize(), QSplitterPrivate::recalc(), QStatusBar::reformat(), QSplitterPrivate::setGeo(), QSplitter::setSizes(), Q3WidgetStack::sizeHint(), and QScrollAreaPrivate::updateScrollBars().

00286 {
00287     QWidget *w = ((QWidgetItem *)i)->widget();
00288 
00289     QSize s(0, 0);
00290     QSize msh(w->minimumSizeHint());
00291     QSize sh(w->sizeHint());
00292 
00293     if (w->sizePolicy().horizontalPolicy() != QSizePolicy::Ignored) {
00294         if (w->sizePolicy().horizontalPolicy() & QSizePolicy::ShrinkFlag)
00295             s.setWidth(msh.width());
00296         else
00297             s.setWidth(qMax(sh.width(), msh.width()));
00298     }
00299 
00300     if (w->sizePolicy().verticalPolicy() != QSizePolicy::Ignored) {
00301         if (w->sizePolicy().verticalPolicy() & QSizePolicy::ShrinkFlag) {
00302             s.setHeight(msh.height());
00303         } else {
00304             s.setHeight(qMax(sh.height(), msh.height()));
00305         }
00306     }
00307 
00308     s = s.boundedTo(w->maximumSize());
00309     QSize min = w->minimumSize();
00310     if (min.width() > 0)
00311         s.setWidth(min.width());
00312     if (min.height() > 0)
00313         s.setHeight(min.height());
00314 
00315     return s.expandedTo(QSize(0,0));
00316 }

static Fixed toFixed ( int  i  )  [inline, static]

Definition at line 37 of file qlayoutengine.cpp.

Referenced by qGeomCalc().

00037 { return (Fixed)i * 256; }


Generated on Thu Mar 15 13:27:53 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1