From aab0b1724897e186d2d4056da7f0cd34ccc12fcb Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sat, 20 Oct 2007 16:50:41 +0000 Subject: Improved layout manager. Reworked layout of character selection dialog box. --- src/gui/char_select.cpp | 58 ++++++++---------- src/gui/widgets/layout.cpp | 145 ++++++++++++++++++++++++++++----------------- src/gui/widgets/layout.h | 56 ++++++++++++++--- 3 files changed, 162 insertions(+), 97 deletions(-) (limited to 'src/gui') diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index e8381bef..ea04b6bc 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -36,6 +36,8 @@ #include "unregisterdialog.h" +#include "widgets/layout.h" + #include "../game.h" #include "../localplayer.h" #include "../main.h" @@ -100,40 +102,28 @@ CharSelectDialog::CharSelectDialog(LockedArray *charInfo, mMoneyLabel = new gcn::Label(strprintf(_("Money: %d"), 0)); mPlayerBox = new PlayerBox(); - int w = 195; - int h = 220; - setContentSize(w, h); - mPlayerBox->setDimension(gcn::Rectangle(5, 5, w - 10, 90)); - mNameLabel->setDimension(gcn::Rectangle(10, 100, 128, 16)); - mLevelLabel->setDimension(gcn::Rectangle(10, 116, 128, 16)); - mMoneyLabel->setDimension(gcn::Rectangle(10, 148, 128, 16)); - mPreviousButton->setPosition(5, 170); - mNextButton->setPosition(mPreviousButton->getWidth() + 10, 170); - mNewCharButton->setPosition(5, h - 5 - mNewCharButton->getHeight()); - mDelCharButton->setPosition( - 5 + mNewCharButton->getWidth() + 5, - mNewCharButton->getY()); - mCancelButton->setPosition( - w - 5 - mCancelButton->getWidth(), - mNewCharButton->getY()); - mSelectButton->setPosition( - mCancelButton->getX() - 5 - mSelectButton->getWidth(), - mNewCharButton->getY()); - mUnRegisterButton->setPosition( - w - 5 - mUnRegisterButton->getWidth(), - mCancelButton->getY() - 5 - mUnRegisterButton->getHeight()); - - add(mPlayerBox); - add(mSelectButton); - add(mCancelButton); - add(mUnRegisterButton); - add(mNewCharButton); - add(mDelCharButton); - add(mPreviousButton); - add(mNextButton); - add(mNameLabel); - add(mLevelLabel); - add(mMoneyLabel); + setPadding(8); + Layout &layout = getLayout(); + place(0, 0, mPlayerBox, 1, 5).setPadding(3); + place(1, 0, mNameLabel, 3); + place(1, 1, mLevelLabel, 3); + place(1, 2, mMoneyLabel, 3); + place(1, 3, mPreviousButton); + place(2, 3, mNextButton); + place(1, 4, mNewCharButton); + place(2, 4, mDelCharButton); + layout.setWidth(230); + layout.setColWidth(0, 80); + layout.setColWidth(3, Layout::FILL); + layout.matchColWidth(1, 2); + layout.setRowHeight(5, 5); + layout.flush(); + place(0, 0, mUnRegisterButton); + place(2, 0, mSelectButton); + place(3, 0, mCancelButton); + layout.setColWidth(1, Layout::FILL); + reflowLayout(); + forgetLayout(); setLocationRelativeTo(getParent()); setVisible(true); diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp index 8a64acc0..2133b077 100644 --- a/src/gui/widgets/layout.cpp +++ b/src/gui/widgets/layout.cpp @@ -25,18 +25,22 @@ void Layout::resizeGrid(int w, int h) { - bool extW = w && w > (int)mColWidths.size(), - extH = h && h > (int)mRowHeights.size(); + bool extW = w && w > (int)mSizes[0].size(), + extH = h && h > (int)mSizes[1].size(); if (!extW && !extH) return; if (extH) { - mRowHeights.resize(h, -1); + mSizes[1].resize(h, 0); mCells.resize(h); - if (!extW) w = (int)mColWidths.size(); + if (!extW) w = mSizes[0].size(); + } + + if (extW) + { + mSizes[0].resize(w, 0); } - mColWidths.resize(w, -1); for (std::vector< std::vector< Cell > >::iterator i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i) { @@ -47,13 +51,22 @@ void Layout::resizeGrid(int w, int h) void Layout::setColWidth(int n, int w) { resizeGrid(n + 1, 0); - mColWidths[n] = w; + mSizes[0][n] = w; } void Layout::setRowHeight(int n, int h) { resizeGrid(0, n + 1); - mRowHeights[n] = h; + mSizes[1][n] = h; +} + +void Layout::matchColWidth(int n1, int n2) +{ + resizeGrid(std::max(n1, n2) + 1, 0); + std::vector< int > widths = compute(0, mW); + int s = std::max(widths[n1], widths[n2]); + mSizes[0][n1] = s; + mSizes[0][n2] = s; } Cell &Layout::place(gcn::Widget *widget, int x, int y, int w, int h) @@ -61,40 +74,45 @@ Cell &Layout::place(gcn::Widget *widget, int x, int y, int w, int h) resizeGrid(x + w, y + h); Cell &cell = mCells[y][x]; cell.mWidget = widget; - cell.mColExtent = w; - cell.mRowExtent = h; + cell.mExtent[0] = w; + cell.mExtent[1] = h; cell.mPadding = 0; - cell.mHAlign = Cell::FILL; - cell.mVAlign = Cell::FILL; + cell.mAlign[0] = Cell::FILL; + cell.mAlign[1] = Cell::FILL; return cell; } -static void align(int &pos, int &cur, int upp, Cell::Alignment a) +void Layout::align(int &pos, int &size, int dim, Cell &cell, int *sizes) { - cur = std::min(cur, upp); - switch (a) + int size_max = sizes[0] - cell.mPadding * 2; + for (int i = 1; i < cell.mExtent[dim]; ++i) + size_max += sizes[i] + mPadding; + size = std::min(dim == 0 ? cell.mWidget->getWidth() + : cell.mWidget->getHeight(), size_max); + pos += cell.mPadding; + + switch (cell.mAlign[dim]) { case Cell::LEFT: return; case Cell::RIGHT: - pos += upp - cur; + pos += size_max - size; return; case Cell::CENTER: - pos += (upp - cur) / 2; + pos += (size_max - size) / 2; return; case Cell::FILL: - cur = upp; + size = size_max; return; } } -void Layout::reflow() +std::vector< int > Layout::compute(int dim, int upp) { - int gridW = mColWidths.size(), gridH = mRowHeights.size(); - - std::vector< int > widths(gridW, 0); - std::vector< int > heights(gridH, 0); + int gridW = mSizes[0].size(), gridH = mSizes[1].size(); + std::vector< int > sizes = mSizes[dim]; + // Compute minimum sizes. for (int gridY = 0; gridY < gridH; ++gridY) { for (int gridX = 0; gridX < gridW; ++gridX) @@ -102,58 +120,77 @@ void Layout::reflow() Cell &cell = mCells[gridY][gridX]; if (!cell.mWidget) continue; - if (cell.mColExtent == 1) - { - int w = cell.mWidget->getWidth() + cell.mPadding * 2; - if (w > widths[gridX]) widths[gridX] = w; - } - - if (cell.mRowExtent == 1) + if (cell.mExtent[dim] == 1) { - int h = cell.mWidget->getHeight() + cell.mPadding * 2; - if (h > heights[gridY]) heights[gridY] = h; + int s = dim == 0 ? cell.mWidget->getWidth() + : cell.mWidget->getHeight(); + int n = dim == 0 ? gridX : gridY; + s += cell.mPadding * 2; + if (s > sizes[n]) sizes[n] = s; } } } - for (int gridX = 0; gridX < gridW; ++gridX) + // Compute the FILL sizes. + int nb = sizes.size(); + int nbFill = 0; + for (int i = 0; i < nb; ++i) { - int w = mColWidths[gridX]; - if (w != -1) widths[gridX] = w; + if (mSizes[dim][i] == FILL) ++nbFill; + if (sizes[i] > 0) upp -= sizes[i]; + upp -= mPadding; } + upp += mPadding; - for (int gridY = 0; gridY < gridH; ++gridY) + if (upp <= 0 || nbFill == 0) return sizes; + + for (int i = 0; i < nb; ++i) { - int h = mRowHeights[gridY]; - if (h != -1) heights[gridY] = h; + if (mSizes[dim][i] != FILL) continue; + int s = (upp + nbFill / 2) / nbFill; + sizes[i] += s; + upp -= s; + --nbFill; } - int y = 0; + return sizes; +} + +void Layout::reflow() +{ + int gridW = mSizes[0].size(), gridH = mSizes[1].size(); + + std::vector< int > widths = compute(0, mW); + std::vector< int > heights = compute(1, mH); + + int y = mY; for (int gridY = 0; gridY < gridH; ++gridY) { - int h = heights[gridY]; - int x = 0; + int x = mX; for (int gridX = 0; gridX < gridW; ++gridX) { - int w = widths[gridX]; Cell &cell = mCells[gridY][gridX]; if (cell.mWidget) { - int ew = w - cell.mPadding * 2, - eh = h - cell.mPadding * 2; - for (int i = 1; i < cell.mColExtent; ++i) - ew += widths[gridX + i] + mPadding; - for (int i = 1; i < cell.mRowExtent; ++i) - eh += heights[gridY + i] + mPadding; - int dw = cell.mWidget->getWidth(), - dh = cell.mWidget->getHeight(); - int dx = x + cell.mPadding, dy = y + cell.mPadding; - align(dx, dw, ew, cell.mHAlign); - align(dy, dh, eh, cell.mVAlign); + int dx = x, dy = y, dw, dh; + align(dx, dw, 0, cell, &widths[gridX]); + align(dy, dh, 1, cell, &heights[gridY]); cell.mWidget->setDimension(gcn::Rectangle(dx, dy, dw, dh)); } - x += w + mPadding; + x += widths[gridX] + mPadding; + mNW = x - mX; } - y += h + mPadding; + y += heights[gridY] + mPadding; + mNH = y - mY; } } + +void Layout::flush() +{ + reflow(); + mY += mNH; + mW = mNW - mPadding; + mSizes[0].clear(); + mSizes[1].clear(); + mCells.clear(); +} diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h index 5be8e84c..09b511f6 100644 --- a/src/gui/widgets/layout.h +++ b/src/gui/widgets/layout.h @@ -58,20 +58,20 @@ class Cell * Sets the horizontal alignment of the cell content. */ Cell &setHAlign(Alignment a) - { mHAlign = a; return *this; } + { mAlign[0] = a; return *this; } /** * Sets the vertical alignment of the cell content. */ Cell &setVAlign(Alignment a) - { mVAlign = a; return *this; } + { mAlign[1] = a; return *this; } private: gcn::Widget *mWidget; - int mColExtent, mRowExtent; int mPadding; - Alignment mHAlign, mVAlign; + int mExtent[2]; + Alignment mAlign[2]; }; /** @@ -85,18 +85,35 @@ class Layout { public: - Layout(): mPadding(4) {} + Layout(): mPadding(4), mX(0), mY(0), mW(0), mH(0) {} /** - * Sets the width of a column. + * Sets the minimum width of a column. */ void setColWidth(int n, int w); /** - * Sets the height of a row. + * Sets the minimum height of a row. */ void setRowHeight(int n, int h); + /** + * Matchs widths of two columns. + */ + void matchColWidth(int n1, int n2); + + /** + * Sets the minimum width of the layout. + */ + void setWidth(int w) + { mW = w; } + + /** + * Sets the minimum height of the layout. + */ + void setHeight(int h) + { mH = h; } + /** * Sets the padding between cells. */ @@ -113,18 +130,39 @@ class Layout */ void reflow(); + /** + * Reflows the current layout. Then starts a new layout just below with + * the same width. + */ + void flush(); + + enum + { + FILL = -1, /**< Expand until the layout as the expected size. */ + }; + private: + /** + * Gets the position and size of a widget along a given axis + */ + void align(int &pos, int &size, int dim, Cell &cell, int *sizes); + /** * Ensures the private vectors are large enough. */ void resizeGrid(int w, int h); - std::vector< int > mColWidths; - std::vector< int > mRowHeights; + /** + * Gets the column/row sizes along a given axis. + */ + std::vector< int > compute(int dim, int upp); + + std::vector< int > mSizes[2]; std::vector< std::vector < Cell > > mCells; int mPadding; + int mX, mY, mW, mH, mNW, mNH; }; #endif -- cgit v1.2.3-70-g09d2