00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qlayout.h"
00025 #include "private/qlayoutengine_p.h"
00026
00027 #include "qvector.h"
00028 #include "qwidget.h"
00029
00030 #include <qlist.h>
00031 #include <qalgorithms.h>
00032
00033 #include <qdebug.h>
00034
00035
00036 typedef qint64 Fixed;
00037 static inline Fixed toFixed(int i) { return (Fixed)i * 256; }
00038 static inline int fRound(Fixed i) {
00039 return (i % 256 < 128) ? i / 256 : 1 + i / 256;
00040 }
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count,
00058 int pos, int space, int spacer)
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;
00067
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--;
00086
00087 if (space < cMin + spacerCount * spacer) {
00088
00089
00090
00091
00092 int minSize = cMin + spacerCount * spacer;
00093
00094
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
00130
00131
00132
00133
00134 int n = count;
00135 int space_left = space - spacerCount*spacer;
00136 int overdraft = cHint - space_left;
00137
00138
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
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
00159 fp_w += fp_over / n;
00160
00161
00162 int w = fRound(fp_w);
00163 chain[i].size = chain[i].smartSizeHint() - w;
00164 fp_w -= toFixed(w);
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
00172 n--;
00173 break;
00174 }
00175 }
00176 }
00177 } else {
00178 int n = count;
00179 int space_left = space - spacerCount*spacer;
00180
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
00198
00199
00200
00201
00202
00203
00204
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);
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
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
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
00261
00262
00263
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 }
00284
00285 Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i)
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 }
00317
00318 Q_GUI_EXPORT QSize qSmartMinSize(const QWidget *w)
00319 {
00320 QWidgetItem item(const_cast<QWidget *>(w));
00321 return qSmartMinSize(&item);
00322 }
00323
00324 Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align)
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 }
00346
00347 Q_GUI_EXPORT QSize qSmartMaxSize(const QWidget *w, Qt::Alignment align)
00348 {
00349 QWidgetItem item(const_cast<QWidget *>(w));
00350 return qSmartMaxSize(&item, align);
00351 }
00352