00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "gui/widgets/layout.h"
00023
00024 #include <cassert>
00025
00026 ContainerPlacer ContainerPlacer::at(int x, int y)
00027 {
00028 return ContainerPlacer(mContainer, &mCell->at(x, y));
00029 }
00030
00031 LayoutCell &ContainerPlacer::operator()
00032 (int x, int y, gcn::Widget *wg, int w, int h)
00033 {
00034 mContainer->add(wg);
00035 return mCell->place(wg, x, y, w, h);
00036 }
00037
00038 LayoutCell::~LayoutCell()
00039 {
00040 if (mType == ARRAY) delete mArray;
00041 }
00042
00043 LayoutArray &LayoutCell::getArray()
00044 {
00045 assert(mType != WIDGET);
00046 if (mType == ARRAY) return *mArray;
00047 mArray = new LayoutArray;
00048 mType = ARRAY;
00049 mExtent[0] = 1;
00050 mExtent[1] = 1;
00051 mPadding = 0;
00052 mAlign[0] = FILL;
00053 mAlign[1] = FILL;
00054 return *mArray;
00055 }
00056
00057 void LayoutCell::reflow(int nx, int ny, int nw, int nh)
00058 {
00059 assert(mType != NONE);
00060 nx += mPadding;
00061 ny += mPadding;
00062 nw -= 2 * mPadding;
00063 nh -= 2 * mPadding;
00064 if (mType == ARRAY)
00065 mArray->reflow(nx, ny, nw, nh);
00066 else
00067 mWidget->setDimension(gcn::Rectangle(nx, ny, nw, nh));
00068 }
00069
00070 void LayoutCell::computeSizes()
00071 {
00072 assert(mType == ARRAY);
00073
00074 for (std::vector< std::vector< LayoutCell * > >::iterator
00075 i = mArray->mCells.begin(), i_end = mArray->mCells.end();
00076 i != i_end; ++i)
00077 {
00078 for (std::vector< LayoutCell * >::iterator
00079 j = i->begin(), j_end = i->end(); j != j_end; ++j)
00080 {
00081 LayoutCell *cell = *j;
00082 if (cell && cell->mType == ARRAY) cell->computeSizes();
00083 }
00084 }
00085
00086 mSize[0] = mArray->getSize(0);
00087 mSize[1] = mArray->getSize(1);
00088 }
00089
00090 LayoutArray::LayoutArray(): mSpacing(4)
00091 {
00092 }
00093
00094 LayoutArray::~LayoutArray()
00095 {
00096 for (std::vector< std::vector< LayoutCell * > >::iterator
00097 i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i)
00098 {
00099 for (std::vector< LayoutCell * >::iterator
00100 j = i->begin(), j_end = i->end(); j != j_end; ++j)
00101 {
00102 delete *j;
00103 }
00104 }
00105 }
00106
00107 LayoutCell &LayoutArray::at(int x, int y, int w, int h)
00108 {
00109 resizeGrid(x + w, y + h);
00110 LayoutCell *&cell = mCells[y][x];
00111 if (!cell)
00112 {
00113 cell = new LayoutCell;
00114 }
00115 return *cell;
00116 }
00117
00118 void LayoutArray::resizeGrid(int w, int h)
00119 {
00120 bool extW = w && w > (int)mSizes[0].size(),
00121 extH = h && h > (int)mSizes[1].size();
00122 if (!extW && !extH) return;
00123
00124 if (extH)
00125 {
00126 mSizes[1].resize(h, Layout::AUTO_DEF);
00127 mCells.resize(h);
00128 if (!extW) w = mSizes[0].size();
00129 }
00130
00131 if (extW)
00132 {
00133 mSizes[0].resize(w, Layout::AUTO_DEF);
00134 }
00135
00136 for (std::vector< std::vector< LayoutCell * > >::iterator
00137 i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i)
00138 {
00139 i->resize(w, NULL);
00140 }
00141 }
00142
00143 void LayoutArray::setColWidth(int n, int w)
00144 {
00145 resizeGrid(n + 1, 0);
00146 mSizes[0][n] = w;
00147 }
00148
00149 void LayoutArray::setRowHeight(int n, int h)
00150 {
00151 resizeGrid(0, n + 1);
00152 mSizes[1][n] = h;
00153 }
00154
00155 void LayoutArray::matchColWidth(int n1, int n2)
00156 {
00157 resizeGrid(std::max(n1, n2) + 1, 0);
00158 std::vector< short > widths = getSizes(0, Layout::AUTO_DEF);
00159 int s = std::max(widths[n1], widths[n2]);
00160 mSizes[0][n1] = s;
00161 mSizes[0][n2] = s;
00162 }
00163
00164 void LayoutArray::extend(int x, int y, int w, int h)
00165 {
00166 LayoutCell &cell = at(x, y, w, h);
00167 cell.mExtent[0] = w;
00168 cell.mExtent[1] = h;
00169 }
00170
00171 LayoutCell &LayoutArray::place(gcn::Widget *widget, int x, int y, int w, int h)
00172 {
00173 LayoutCell &cell = at(x, y, w, h);
00174 assert(cell.mType == LayoutCell::NONE);
00175 cell.mType = LayoutCell::WIDGET;
00176 cell.mWidget = widget;
00177 cell.mSize[0] = w == 1 ? widget->getWidth() : 0;
00178 cell.mSize[1] = h == 1 ? widget->getHeight() : 0;
00179 cell.mExtent[0] = w;
00180 cell.mExtent[1] = h;
00181 cell.mPadding = 0;
00182 cell.mAlign[0] = LayoutCell::FILL;
00183 cell.mAlign[1] = LayoutCell::FILL;
00184 short &cs = mSizes[0][x], &rs = mSizes[1][y];
00185 if (cs == Layout::AUTO_DEF && w == 1) cs = 0;
00186 if (rs == Layout::AUTO_DEF && h == 1) rs = 0;
00187 return cell;
00188 }
00189
00190 void LayoutArray::align(int &pos, int &size, int dim,
00191 LayoutCell const &cell, short *sizes) const
00192 {
00193 int size_max = sizes[0];
00194 for (int i = 1; i < cell.mExtent[dim]; ++i)
00195 size_max += sizes[i] + mSpacing;
00196 size = std::min<int>(cell.mSize[dim], size_max);
00197
00198 switch (cell.mAlign[dim])
00199 {
00200 case LayoutCell::LEFT:
00201 return;
00202 case LayoutCell::RIGHT:
00203 pos += size_max - size;
00204 return;
00205 case LayoutCell::CENTER:
00206 pos += (size_max - size) / 2;
00207 return;
00208 case LayoutCell::FILL:
00209 size = size_max;
00210 return;
00211 }
00212 }
00213
00214 std::vector< short > LayoutArray::getSizes(int dim, int upp) const
00215 {
00216 int gridW = mSizes[0].size(), gridH = mSizes[1].size();
00217 std::vector< short > sizes = mSizes[dim];
00218
00219
00220 for (int gridY = 0; gridY < gridH; ++gridY)
00221 {
00222 for (int gridX = 0; gridX < gridW; ++gridX)
00223 {
00224 LayoutCell const *cell = mCells[gridY][gridX];
00225 if (!cell || cell->mType == LayoutCell::NONE) continue;
00226
00227 if (cell->mExtent[dim] == 1)
00228 {
00229 int n = dim == 0 ? gridX : gridY;
00230 int s = cell->mSize[dim] + cell->mPadding * 2;
00231 if (s > sizes[n]) sizes[n] = s;
00232 }
00233 }
00234 }
00235
00236 if (upp == Layout::AUTO_DEF) return sizes;
00237
00238
00239 int nb = sizes.size();
00240 int nbFill = 0;
00241 for (int i = 0; i < nb; ++i)
00242 {
00243 if (mSizes[dim][i] <= Layout::AUTO_DEF)
00244 {
00245 ++nbFill;
00246 if (mSizes[dim][i] == Layout::AUTO_SET ||
00247 sizes[i] <= Layout::AUTO_DEF)
00248 {
00249 sizes[i] = 0;
00250 }
00251 }
00252 upp -= sizes[i] + mSpacing;
00253 }
00254 upp = upp + mSpacing;
00255
00256 if (nbFill == 0) return sizes;
00257
00258 for (int i = 0; i < nb; ++i)
00259 {
00260 if (mSizes[dim][i] > Layout::AUTO_DEF) continue;
00261 int s = upp / nbFill;
00262 sizes[i] += s;
00263 upp -= s;
00264 --nbFill;
00265 }
00266
00267 return sizes;
00268 }
00269
00270 int LayoutArray::getSize(int dim) const
00271 {
00272 std::vector< short > sizes = getSizes(dim, Layout::AUTO_DEF);
00273 int size = 0;
00274 int nb = sizes.size();
00275 for (int i = 0; i < nb; ++i)
00276 {
00277 if (sizes[i] > Layout::AUTO_DEF) size += sizes[i];
00278 size += mSpacing;
00279 }
00280 return size - mSpacing;
00281 }
00282
00283 void LayoutArray::reflow(int nx, int ny, int nw, int nh)
00284 {
00285 int gridW = mSizes[0].size(), gridH = mSizes[1].size();
00286
00287 std::vector< short > widths = getSizes(0, nw);
00288 std::vector< short > heights = getSizes(1, nh);
00289
00290 int y = ny;
00291 for (int gridY = 0; gridY < gridH; ++gridY)
00292 {
00293 int x = nx;
00294 for (int gridX = 0; gridX < gridW; ++gridX)
00295 {
00296 LayoutCell *cell = mCells[gridY][gridX];
00297 if (cell && cell->mType != LayoutCell::NONE)
00298 {
00299 int dx = x, dy = y, dw, dh;
00300 align(dx, dw, 0, *cell, &widths[gridX]);
00301 align(dy, dh, 1, *cell, &heights[gridY]);
00302 cell->reflow(dx, dy, dw, dh);
00303 }
00304 x += widths[gridX] + mSpacing;
00305 }
00306 y += heights[gridY] + mSpacing;
00307 }
00308 }
00309
00310 Layout::Layout(): mComputed(false)
00311 {
00312 getArray();
00313 setPadding(6);
00314 }
00315
00316 void Layout::reflow(int &nw, int &nh)
00317 {
00318 if (!mComputed)
00319 {
00320 computeSizes();
00321 mComputed = true;
00322 }
00323
00324 nw = nw == 0 ? mSize[0] + 2 * mPadding : nw;
00325 nh = nh == 0 ? mSize[1] + 2 * mPadding : nh;
00326 LayoutCell::reflow(0, 0, nw, nh);
00327 }