diff options
author | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-01-06 17:50:52 +0100 |
---|---|---|
committer | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-01-06 17:50:52 +0100 |
commit | 9219f1ffd4b05886b66c9074c918850fc97c430c (patch) | |
tree | cc6750b62b825636abb898297489d1372fc55848 /src | |
parent | 631a8a85e8be0ec472850ba672676fe31679e7c3 (diff) | |
download | mana-9219f1ffd4b05886b66c9074c918850fc97c430c.tar.gz mana-9219f1ffd4b05886b66c9074c918850fc97c430c.tar.bz2 mana-9219f1ffd4b05886b66c9074c918850fc97c430c.tar.xz mana-9219f1ffd4b05886b66c9074c918850fc97c430c.zip |
Merged layout handler from mainline
Also fixed login dialog layout. This is the layout handler by Guillaume
Melquiond, which he started in commit 59472ef68fdef3f7e8858a81a46e28c127119c58.
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/gui/login.cpp | 59 | ||||
-rw-r--r-- | src/gui/popupmenu.cpp | 2 | ||||
-rw-r--r-- | src/gui/widgets/layout.cpp | 327 | ||||
-rw-r--r-- | src/gui/widgets/layout.h | 320 | ||||
-rw-r--r-- | src/gui/window.cpp | 85 | ||||
-rw-r--r-- | src/gui/window.h | 64 |
8 files changed, 759 insertions, 104 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 666a675d..0a01f925 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,8 @@ MARK_AS_ADVANCED(SDL_LIBRARY) SET(SRCS gui/widgets/resizegrip.cpp gui/widgets/resizegrip.h + gui/widgets/layout.cpp + gui/widgets/layout.h gui/box.cpp gui/box.h gui/browserbox.cpp diff --git a/src/Makefile.am b/src/Makefile.am index c924760f..a366e9b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,9 @@ AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = tmw -tmw_SOURCES = gui/widgets/resizegrip.cpp \ +tmw_SOURCES = gui/widgets/layout.cpp \ + gui/widgets/layout.h \ + gui/widgets/resizegrip.cpp \ gui/widgets/resizegrip.h \ gui/box.h \ gui/box.cpp \ diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 5a748b52..db81c683 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -34,6 +34,8 @@ #include "passwordfield.h" #include "textfield.h" +#include "widgets/layout.h" + #include "../utils/gettext.h" LoginDialog::LoginDialog(LoginData *loginData): @@ -50,33 +52,6 @@ LoginDialog::LoginDialog(LoginData *loginData): mCancelButton = new Button(_("Cancel"), "cancel", this); mRegisterButton = new Button(_("Register"), "register", this); - const int width = 250; - const int height = 100; - - setContentSize(width, height); - - userLabel->setPosition(5, 5); - passLabel->setPosition(5, 14 + userLabel->getHeight()); - serverLabel->setPosition( - 5, 23 + userLabel->getHeight() + passLabel->getHeight()); - mUserField->setPosition(65, 5); - mPassField->setPosition(65, 14 + userLabel->getHeight()); - mServerField->setPosition( - 65, 23 + userLabel->getHeight() + passLabel->getHeight()); - mUserField->setWidth(width - 70); - mPassField->setWidth(width - 70); - mServerField->setWidth(width - 70); - mKeepCheck->setPosition(4, 77); - mCancelButton->setPosition( - width - mCancelButton->getWidth() - 5, - height - mCancelButton->getHeight() - 5); - mOkButton->setPosition( - mCancelButton->getX() - mOkButton->getWidth() - 5, - height - mOkButton->getHeight() - 5); - mRegisterButton->setPosition( - mKeepCheck->getX() + mKeepCheck->getWidth() + 10, - height - mRegisterButton->getHeight() - 5); - mUserField->setActionEventId("ok"); mPassField->setActionEventId("ok"); mServerField->setActionEventId("ok"); @@ -89,16 +64,17 @@ LoginDialog::LoginDialog(LoginData *loginData): mServerField->addActionListener(this); mKeepCheck->addActionListener(this); - add(userLabel); - add(passLabel); - add(serverLabel); - add(mUserField); - add(mPassField); - add(mServerField); - add(mKeepCheck); - add(mOkButton); - add(mCancelButton); - add(mRegisterButton); + place(0, 0, userLabel); + place(0, 1, passLabel); + place(0, 2, serverLabel); + place(1, 0, mUserField, 3).setPadding(2); + place(1, 1, mPassField, 3).setPadding(2); + place(1, 2, mServerField, 3).setPadding(2); + place(0, 3, mKeepCheck, 4); + place(0, 4, mRegisterButton).setHAlign(LayoutCell::LEFT); + place(2, 4, mOkButton); + place(3, 4, mCancelButton); + reflowLayout(250, 0); setLocationRelativeTo(getParent()); setVisible(true); @@ -116,8 +92,7 @@ LoginDialog::~LoginDialog() { } -void -LoginDialog::action(const gcn::ActionEvent &event) +void LoginDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok" && canSubmit()) { @@ -147,14 +122,12 @@ LoginDialog::action(const gcn::ActionEvent &event) } } -void -LoginDialog::keyPressed(gcn::KeyEvent &keyEvent) +void LoginDialog::keyPressed(gcn::KeyEvent &keyEvent) { mOkButton->setEnabled(canSubmit()); } -bool -LoginDialog::canSubmit() +bool LoginDialog::canSubmit() { return !mUserField->getText().empty() && !mPassField->getText().empty() && diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index bfa75ef9..1f5b3556 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -55,7 +55,7 @@ PopupMenu::PopupMenu(): { setResizable(false); setTitleBarHeight(0); - mShowTitle = false; + setShowTitle(false); mBrowserBox = new BrowserBox(); mBrowserBox->setPosition(4, 4); diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp new file mode 100644 index 00000000..bcc54cf7 --- /dev/null +++ b/src/gui/widgets/layout.cpp @@ -0,0 +1,327 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cassert> + +#include "layout.h" + +ContainerPlacer ContainerPlacer::at(int x, int y) +{ + return ContainerPlacer(mContainer, &mCell->at(x, y)); +} + +LayoutCell &ContainerPlacer::operator() + (int x, int y, gcn::Widget *wg, int w, int h) +{ + mContainer->add(wg); + return mCell->place(wg, x, y, w, h); +} + +LayoutCell::~LayoutCell() +{ + if (mType == ARRAY) delete mArray; +} + +LayoutArray &LayoutCell::getArray() +{ + assert(mType != WIDGET); + if (mType == ARRAY) return *mArray; + mArray = new LayoutArray; + mType = ARRAY; + mExtent[0] = 1; + mExtent[1] = 1; + mPadding = 0; + mAlign[0] = FILL; + mAlign[1] = FILL; + return *mArray; +} + +void LayoutCell::reflow(int nx, int ny, int nw, int nh) +{ + assert(mType != NONE); + nx += mPadding; + ny += mPadding; + nw -= 2 * mPadding; + nh -= 2 * mPadding; + if (mType == ARRAY) + mArray->reflow(nx, ny, nw, nh); + else + mWidget->setDimension(gcn::Rectangle(nx, ny, nw, nh)); +} + +void LayoutCell::computeSizes() +{ + assert(mType == ARRAY); + + for (std::vector< std::vector< LayoutCell * > >::iterator + i = mArray->mCells.begin(), i_end = mArray->mCells.end(); + i != i_end; ++i) + { + for (std::vector< LayoutCell * >::iterator + j = i->begin(), j_end = i->end(); j != j_end; ++j) + { + LayoutCell *cell = *j; + if (cell && cell->mType == ARRAY) cell->computeSizes(); + } + } + + mSize[0] = mArray->getSize(0); + mSize[1] = mArray->getSize(1); +} + +LayoutArray::LayoutArray(): mSpacing(4) +{ +} + +LayoutArray::~LayoutArray() +{ + for (std::vector< std::vector< LayoutCell * > >::iterator + i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i) + { + for (std::vector< LayoutCell * >::iterator + j = i->begin(), j_end = i->end(); j != j_end; ++j) + { + delete *j; + } + } +} + +LayoutCell &LayoutArray::at(int x, int y, int w, int h) +{ + resizeGrid(x + w, y + h); + LayoutCell *&cell = mCells[y][x]; + if (!cell) + { + cell = new LayoutCell; + } + return *cell; +} + +void LayoutArray::resizeGrid(int w, int h) +{ + bool extW = w && w > (int)mSizes[0].size(), + extH = h && h > (int)mSizes[1].size(); + if (!extW && !extH) return; + + if (extH) + { + mSizes[1].resize(h, Layout::AUTO_DEF); + mCells.resize(h); + if (!extW) w = mSizes[0].size(); + } + + if (extW) + { + mSizes[0].resize(w, Layout::AUTO_DEF); + } + + for (std::vector< std::vector< LayoutCell * > >::iterator + i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i) + { + i->resize(w, NULL); + } +} + +void LayoutArray::setColWidth(int n, int w) +{ + resizeGrid(n + 1, 0); + mSizes[0][n] = w; +} + +void LayoutArray::setRowHeight(int n, int h) +{ + resizeGrid(0, n + 1); + mSizes[1][n] = h; +} + +void LayoutArray::matchColWidth(int n1, int n2) +{ + resizeGrid(std::max(n1, n2) + 1, 0); + std::vector< short > widths = getSizes(0, Layout::AUTO_DEF); + int s = std::max(widths[n1], widths[n2]); + mSizes[0][n1] = s; + mSizes[0][n2] = s; +} + +void LayoutArray::extend(int x, int y, int w, int h) +{ + LayoutCell &cell = at(x, y, w, h); + cell.mExtent[0] = w; + cell.mExtent[1] = h; +} + +LayoutCell &LayoutArray::place(gcn::Widget *widget, int x, int y, int w, int h) +{ + LayoutCell &cell = at(x, y, w, h); + assert(cell.mType == LayoutCell::NONE); + cell.mType = LayoutCell::WIDGET; + cell.mWidget = widget; + cell.mSize[0] = w == 1 ? widget->getWidth() : 0; + cell.mSize[1] = h == 1 ? widget->getHeight() : 0; + cell.mExtent[0] = w; + cell.mExtent[1] = h; + cell.mPadding = 0; + cell.mAlign[0] = LayoutCell::FILL; + cell.mAlign[1] = LayoutCell::FILL; + short &cs = mSizes[0][x], &rs = mSizes[1][y]; + if (cs == Layout::AUTO_DEF && w == 1) cs = 0; + if (rs == Layout::AUTO_DEF && h == 1) rs = 0; + return cell; +} + +void LayoutArray::align(int &pos, int &size, int dim, + LayoutCell const &cell, short *sizes) const +{ + int size_max = sizes[0]; + for (int i = 1; i < cell.mExtent[dim]; ++i) + size_max += sizes[i] + mSpacing; + size = std::min<int>(cell.mSize[dim], size_max); + + switch (cell.mAlign[dim]) + { + case LayoutCell::LEFT: + return; + case LayoutCell::RIGHT: + pos += size_max - size; + return; + case LayoutCell::CENTER: + pos += (size_max - size) / 2; + return; + case LayoutCell::FILL: + size = size_max; + return; + } +} + +std::vector< short > LayoutArray::getSizes(int dim, int upp) const +{ + int gridW = mSizes[0].size(), gridH = mSizes[1].size(); + std::vector< short > sizes = mSizes[dim]; + + // Compute minimum sizes. + for (int gridY = 0; gridY < gridH; ++gridY) + { + for (int gridX = 0; gridX < gridW; ++gridX) + { + LayoutCell const *cell = mCells[gridY][gridX]; + if (!cell || cell->mType == LayoutCell::NONE) continue; + + if (cell->mExtent[dim] == 1) + { + int n = dim == 0 ? gridX : gridY; + int s = cell->mSize[dim] + cell->mPadding * 2; + if (s > sizes[n]) sizes[n] = s; + } + } + } + + if (upp == Layout::AUTO_DEF) return sizes; + + // Compute the FILL sizes. + int nb = sizes.size(); + int nbFill = 0; + for (int i = 0; i < nb; ++i) + { + if (mSizes[dim][i] <= Layout::AUTO_DEF) + { + ++nbFill; + if (mSizes[dim][i] == Layout::AUTO_SET || + sizes[i] <= Layout::AUTO_DEF) + { + sizes[i] = 0; + } + } + upp -= sizes[i] + mSpacing; + } + upp = upp + mSpacing; + + if (nbFill == 0) return sizes; + + for (int i = 0; i < nb; ++i) + { + if (mSizes[dim][i] > Layout::AUTO_DEF) continue; + int s = upp / nbFill; + sizes[i] += s; + upp -= s; + --nbFill; + } + + return sizes; +} + +int LayoutArray::getSize(int dim) const +{ + std::vector< short > sizes = getSizes(dim, Layout::AUTO_DEF); + int size = 0; + int nb = sizes.size(); + for (int i = 0; i < nb; ++i) + { + if (sizes[i] > Layout::AUTO_DEF) size += sizes[i]; + size += mSpacing; + } + return size - mSpacing; +} + +void LayoutArray::reflow(int nx, int ny, int nw, int nh) +{ + int gridW = mSizes[0].size(), gridH = mSizes[1].size(); + + std::vector< short > widths = getSizes(0, nw); + std::vector< short > heights = getSizes(1, nh); + + int y = ny; + for (int gridY = 0; gridY < gridH; ++gridY) + { + int x = nx; + for (int gridX = 0; gridX < gridW; ++gridX) + { + LayoutCell *cell = mCells[gridY][gridX]; + if (cell && cell->mType != LayoutCell::NONE) + { + int dx = x, dy = y, dw, dh; + align(dx, dw, 0, *cell, &widths[gridX]); + align(dy, dh, 1, *cell, &heights[gridY]); + cell->reflow(dx, dy, dw, dh); + } + x += widths[gridX] + mSpacing; + } + y += heights[gridY] + mSpacing; + } +} + +Layout::Layout(): mComputed(false) +{ + getArray(); + setPadding(6); +} + +void Layout::reflow(int &nw, int &nh) +{ + if (!mComputed) + { + computeSizes(); + mComputed = true; + } + + nw = nw == 0 ? mSize[0] + 2 * mPadding : nw; + nh = nh == 0 ? mSize[1] + 2 * mPadding : nh; + LayoutCell::reflow(0, 0, nw, nh); +} diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h new file mode 100644 index 00000000..d631c154 --- /dev/null +++ b/src/gui/widgets/layout.h @@ -0,0 +1,320 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _TMW_WIDGET_LAYOUT_H__ +#define _TMW_WIDGET_LAYOUT_H__ + +#include <vector> + +#include <guichan/widgets/container.hpp> + +class LayoutCell; + +/** + * This class is a helper for adding widgets to nested tables in a window. + */ +class ContainerPlacer +{ + public: + + ContainerPlacer(gcn::Container *c = NULL, LayoutCell *l = NULL): + mContainer(c), mCell(l) + {} + + /** + * Gets the pointed cell. + */ + LayoutCell &getCell() + { return *mCell; } + + /** + * Returns a placer for the same container but to an inner cell. + */ + ContainerPlacer at(int x, int y); + + /** + * Adds the given widget to the container and places it in the layout. + * @see LayoutArray::place + */ + LayoutCell &operator() + (int x, int y, gcn::Widget *, int w = 1, int h = 1); + + private: + + gcn::Container *mContainer; + LayoutCell *mCell; +}; + +/** + * This class contains a rectangular array of cells. + */ +class LayoutArray +{ + friend class LayoutCell; + + public: + + LayoutArray(); + + ~LayoutArray(); + + /** + * Returns a reference on the cell at given position. + */ + LayoutCell &at(int x, int y, int w = 1, int h = 1); + + /** + * Places a widget in a given cell. + * @param w number of columns the widget spawns. + * @param h number of rows the widget spawns. + * @note When @a w is 1, the width of column @a x is reset to zero if + * it was AUTO_DEF. Similarly for @a h. + */ + LayoutCell &place(gcn::Widget *, int x, int y, int w = 1, int h = 1); + + /** + * Sets the minimum width of a column. + */ + void setColWidth(int n, int w); + + /** + * Sets the minimum height of a row. + */ + void setRowHeight(int n, int h); + + /** + * Sets the widths of two columns to the maximum of their widths. + */ + void matchColWidth(int n1, int n2); + + /** + * Spawns a cell over several columns/rows. + */ + void extend(int x, int y, int w, int h); + + /** + * Computes and sets the positions of all the widgets. + * @param nW width of the array, used to resize the AUTO_ columns. + * @param nH height of the array, used to resize the AUTO_ rows. + */ + void reflow(int nX, int nY, int nW, int nH); + + private: + + // Copy not allowed, as the array owns all its cells. + LayoutArray(LayoutArray const &); + LayoutArray &operator=(LayoutArray const &); + + /** + * Gets the position and size of a widget along a given axis + */ + void align(int &pos, int &size, int dim, + LayoutCell const &cell, short *sizes) const; + + /** + * Ensures the private vectors are large enough. + */ + void resizeGrid(int w, int h); + + /** + * Gets the column/row sizes along a given axis. + * @param upp target size for the array. Ignored if AUTO_DEF. + */ + std::vector< short > getSizes(int dim, int upp) const; + + /** + * Gets the total size along a given axis. + */ + int getSize(int dim) const; + + std::vector< short > mSizes[2]; + std::vector< std::vector < LayoutCell * > > mCells; + + char mSpacing; +}; + +/** + * This class describes the formatting of a widget in the cell of a layout + * table. Horizontally, a widget can either fill the width of the cell (minus + * the cell padding), or it can retain its size and be flushed left, or flush + * right, or centered in the cell. The process is similar for the vertical + * alignment, except that top is represented by LEFT and bottom by RIGHT. + */ +class LayoutCell +{ + friend class Layout; + friend class LayoutArray; + + public: + + enum Alignment + { + LEFT, RIGHT, CENTER, FILL + }; + + LayoutCell(): mType(NONE) {} + + ~LayoutCell(); + + /** + * Sets the padding around the cell content. + */ + LayoutCell &setPadding(int p) + { mPadding = p; return *this; } + + /** + * Sets the horizontal alignment of the cell content. + */ + LayoutCell &setHAlign(Alignment a) + { mAlign[0] = a; return *this; } + + /** + * Sets the vertical alignment of the cell content. + */ + LayoutCell &setVAlign(Alignment a) + { mAlign[1] = a; return *this; } + + /** + * @see LayoutArray::at + */ + LayoutCell &at(int x, int y) + { return getArray().at(x, y); } + + /** + * @see LayoutArray::place + */ + LayoutCell &place(gcn::Widget *wg, int x, int y, int w = 1, int h = 1) + { return getArray().place(wg, x, y, w, h); } + + /** + * @see LayoutArray::matchColWidth + */ + void matchColWidth(int n1, int n2) + { getArray().matchColWidth(n1, n2); } + + /** + * @see LayoutArray::setColWidth + */ + void setColWidth(int n, int w) + { getArray().setColWidth(n, w); } + + /** + * @see LayoutArray::setRowHeight + */ + void setRowHeight(int n, int h) + { getArray().setRowHeight(n, h); } + + /** + * @see LayoutArray::extend. + */ + void extend(int x, int y, int w, int h) + { getArray().extend(x, y, w, h); } + + /** + * Sets the minimum widths and heights of this cell and of all the + * inner cells. + */ + void computeSizes(); + + private: + + // Copy not allowed, as the cell may own an array. + LayoutCell(LayoutCell const &); + LayoutCell &operator=(LayoutCell const &); + + union + { + gcn::Widget *mWidget; + LayoutArray *mArray; + }; + + enum + { + NONE, WIDGET, ARRAY + }; + + /** + * Returns the embedded array. Creates it if the cell does not contain + * anything yet. Aborts if it contains a widget. + */ + LayoutArray &getArray(); + + /** + * @see LayoutArray::reflow + */ + void reflow(int nx, int ny, int nw, int nh); + + short mSize[2]; + char mPadding; + char mExtent[2]; + char mAlign[2]; + char mNbFill[2]; + char mType; +}; + +/** + * This class is an helper for setting the position of widgets. They are + * positioned along the cells of some rectangular tables. The layout may either + * be a single table or a tree of nested tables. + * + * The size of a given table column can either be set manually or be chosen + * from the widest widget of the column. An empty column has a AUTO_DEF width, + * which means it will be extended so that the layout fits its minimum width. + * + * The process is similar for table rows. By default, there is a spacing of 4 + * pixels between rows and between columns, and a margin of 6 pixels around the + * whole layout. + */ +class Layout: public LayoutCell +{ + public: + + Layout(); + + /** + * Sets the margin around the layout. + */ + void setMargin(int m) + { setPadding(m); } + + /** + * Sets the positions of all the widgets. + * @see LayoutArray::reflow + */ + void reflow(int &nW, int &nH); + + /** + * When the minimum size of the layout is less than the available size, + * the remaining pixels are equally split amongst the FILL items. + */ + enum + { + AUTO_DEF = -42, /**< Default value, behaves like AUTO_ADD. */ + AUTO_SET = -43, /**< Uses the share as the new size. */ + AUTO_ADD = -44 /**< Adds the share to the current size. */ + }; + + private: + + bool mComputed; +}; + +#endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 630b4ddd..dfe7ac64 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -20,8 +20,8 @@ */ #include <algorithm> -#include <climits> #include <cassert> +#include <climits> #include <guichan/exception.hpp> #include <guichan/widgets/icon.hpp> @@ -29,9 +29,9 @@ #include "window.h" #include "gui.h" -#include "gccontainer.h" #include "windowcontainer.h" +#include "widgets/layout.h" #include "widgets/resizegrip.h" #include "../configlistener.h" @@ -63,6 +63,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent): gcn::Window(caption), mGrip(0), mParent(parent), + mLayout(NULL), mWindowName("window"), mShowTitle(true), mModal(modal), @@ -76,7 +77,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent): logger->log("Window::Window(\"%s\")", caption.c_str()); if (!windowContainer) { - throw GCN_EXCEPTION("Window::Window. no windowContainer set"); + throw GCN_EXCEPTION("Window::Window(): no windowContainer set"); } if (instances == 0) @@ -108,11 +109,6 @@ Window::Window(const std::string& caption, bool modal, Window *parent): setPadding(3); setTitleBarHeight(20); - // Add chrome - mChrome = new GCContainer(); - mChrome->setOpaque(false); - gcn::Window::add(mChrome); - // Add this window to the window container windowContainer->add(this); @@ -145,6 +141,15 @@ Window::~Window() } } + delete mLayout; + + while (!mWidgets.empty()) + { + gcn::Widget *w = mWidgets.front(); + remove(w); + delete(w); + } + instances--; if (instances == 0) @@ -165,9 +170,6 @@ Window::~Window() delete border.grid[8]; closeImage->decRef(); } - - delete mChrome; - delete mGrip; } void Window::setWindowContainer(WindowContainer *wc) @@ -202,7 +204,6 @@ void Window::draw(gcn::Graphics *graphics) void Window::setContentSize(int width, int height) { - mChrome->setSize(width, height); setSize(width + 2 * getPadding(), height + getPadding() + getTitleBarHeight()); } @@ -248,10 +249,11 @@ void Window::setResizable(bool r) mGrip = new ResizeGrip(); mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); - gcn::Window::add(mGrip); + add(mGrip); } else { + remove(mGrip); delete mGrip; mGrip = 0; } @@ -259,15 +261,19 @@ void Window::setResizable(bool r) void Window::widgetResized(const gcn::Event &event) { - const gcn::Rectangle area = getChildrenArea(); - - mChrome->setSize(area.width, area.height); - if (mGrip) { + const gcn::Rectangle area = getChildrenArea(); mGrip->setPosition(getWidth() - mGrip->getWidth() - area.x, getHeight() - mGrip->getHeight() - area.y); } + + if (mLayout) + { + int w = getWidth() - 2 * getPadding(); + int h = getHeight() - getPadding() - getTitleBarHeight(); + mLayout->reflow(w, h); + } } void Window::setCloseButton(bool flag) @@ -292,14 +298,7 @@ bool Window::isSticky() void Window::setVisible(bool visible) { - if (isSticky()) - { - gcn::Window::setVisible(true); - } - else - { - gcn::Window::setVisible(visible); - } + gcn::Window::setVisible(isSticky() || visible); } void Window::scheduleDelete() @@ -307,16 +306,6 @@ void Window::scheduleDelete() windowContainer->scheduleDelete(this); } -void Window::add(gcn::Widget *w) -{ - mChrome->add(w); -} - -void Window::add(gcn::Widget *w, int x, int y) -{ - mChrome->add(w, x, y); -} - void Window::mousePressed(gcn::MouseEvent &event) { // Let Guichan move window to top and figure out title bar drag @@ -535,3 +524,29 @@ int Window::getResizeHandles(gcn::MouseEvent &event) return resizeHandles; } + +Layout &Window::getLayout() +{ + if (!mLayout) mLayout = new Layout; + return *mLayout; +} + +LayoutCell &Window::place(int x, int y, gcn::Widget *wg, int w, int h) +{ + add(wg); + return getLayout().place(wg, x, y, w, h); +} + +ContainerPlacer Window::getPlacer(int x, int y) +{ + return ContainerPlacer(this, &getLayout().at(x, y)); +} + +void Window::reflowLayout(int w, int h) +{ + assert(mLayout); + mLayout->reflow(w, h); + delete mLayout; + mLayout = NULL; + setContentSize(w, h); +} diff --git a/src/gui/window.h b/src/gui/window.h index d40e8c91..a49788a5 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -28,11 +28,13 @@ #include "../guichanfwd.h" class ConfigListener; -class GCContainer; +class ContainerPlacer; +class Image; class ImageRect; +class Layout; +class LayoutCell; class ResizeGrip; class WindowContainer; -class Image; /** * A window. This window can be dragged around and has a title bar. Windows are @@ -59,7 +61,7 @@ class Window : public gcn::Window, gcn::WidgetListener Window *parent = NULL); /** - * Destructor. + * Destructor. Deletes all the added widgets. */ ~Window(); @@ -74,18 +76,6 @@ class Window : public gcn::Window, gcn::WidgetListener void draw(gcn::Graphics *graphics); /** - * Adds a widget to the window. The widget will be deleted by the - * window. - */ - void add(gcn::Widget *w); - - /** - * Adds a widget to the window and also specifices its position. The - * widget will be deleted by the window. - */ - void add(gcn::Widget *w, int x, int y); - - /** * Sets the size of this window. */ void setContentSize(int width, int height); @@ -217,21 +207,51 @@ class Window : public gcn::Window, gcn::WidgetListener * Don't forget to set these default values and resizable before * calling this function. */ - virtual void loadWindowState(); + void loadWindowState(); /** * Set the default win pos and size. * (which can be different of the actual ones.) */ - virtual void setDefaultSize(int defaultX, int defaultY, - int defaultWidth, int defaultHeight); + void setDefaultSize(int defaultX, int defaultY, + int defaultWidth, int defaultHeight); /** * Reset the win pos and size to default. Don't forget to set defaults * first. */ - virtual void resetToDefaultSize(); + void resetToDefaultSize(); + + /** + * Gets the layout handler for this window. + */ + Layout &getLayout(); + + /** + * Computes the position of the widgets according to the current + * layout. Resizes the window so that the layout fits. Deletes the + * layout. + * @param w if non-zero, force the window to this width. + * @param h if non-zero, force the window to this height. + * @note This function is meant to be called with fixed-size windows. + */ + void reflowLayout(int w = 0, int h = 0); + /** + * Adds a widget to the window and sets it at given cell. + */ + LayoutCell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1); + + /** + * Returns a proxy for adding widgets in an inner table of the layout. + */ + ContainerPlacer getPlacer(int x, int y); + + protected: + /** The window container windows add themselves to. */ + static WindowContainer *windowContainer; + + private: enum ResizeHandles { TOP = 0x01, @@ -240,7 +260,6 @@ class Window : public gcn::Window, gcn::WidgetListener LEFT = 0x08 }; - protected: /** * Determines if the mouse is in a resize area and returns appropriate * resize handles. Also initializes drag offset in case the resize @@ -250,9 +269,9 @@ class Window : public gcn::Window, gcn::WidgetListener */ int getResizeHandles(gcn::MouseEvent &event); - GCContainer *mChrome; /**< Contained container */ ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ + Layout *mLayout; /**< Layout handler */ std::string mWindowName; /**< Name of the window */ bool mShowTitle; /**< Window has a title bar */ bool mModal; /**< Window is modal */ @@ -267,9 +286,6 @@ class Window : public gcn::Window, gcn::WidgetListener int mDefaultWidth; /**< Default window width */ int mDefaultHeight; /**< Default window height */ - /** The window container windows add themselves to. */ - static WindowContainer *windowContainer; - /** * The config listener that listens to changes relevant to all windows. */ |