summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-10-20 11:29:18 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-10-20 11:29:18 +0000
commit59472ef68fdef3f7e8858a81a46e28c127119c58 (patch)
tree75b5f5e658fa1b05487463f0449440524ed76256
parent41cf359468d6379bc0e033bee9ac148d1b9255dd (diff)
downloadmana-59472ef68fdef3f7e8858a81a46e28c127119c58.tar.gz
mana-59472ef68fdef3f7e8858a81a46e28c127119c58.tar.bz2
mana-59472ef68fdef3f7e8858a81a46e28c127119c58.tar.xz
mana-59472ef68fdef3f7e8858a81a46e28c127119c58.zip
Added a layout handler for automatically positioning widgets in a window. Fixed layout of login dialog box when native language is not English.
-rw-r--r--ChangeLog10
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gui/login.cpp44
-rw-r--r--src/gui/widgets/layout.cpp159
-rw-r--r--src/gui/widgets/layout.h116
-rw-r--r--src/gui/window.cpp65
-rw-r--r--src/gui/window.h39
7 files changed, 365 insertions, 70 deletions
diff --git a/ChangeLog b/ChangeLog
index 88dfff79..7d93294f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-10-20 Guillaume Melquiond <guillaume.melquiond@gmail.com>
+
+ * src/gui/widgets/layout.h, src/gui/widgets/layout.cpp,
+ src/Makefile.am: Added a layout handler for automatically positioning
+ widgets in a window.
+ * src/gui/window.h, src/gui/window.cpp: Removed garbage-collected
+ container. Fixed dangling resize widget. Added layout handler.
+ * src/gui/login.cpp: Fixed layout of login dialog box when native
+ language is not English.
+
2007-10-19 Guillaume Melquiond <guillaume.melquiond@gmail.com>
* data/equipment.xml: Removed obsolete file.
diff --git a/src/Makefile.am b/src/Makefile.am
index e0a5a41b..6e6cdfa4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,6 +3,8 @@ AUTOMAKE_OPTIONS = subdir-objects
bin_PROGRAMS = tmw
tmw_SOURCES = gui/widgets/dropdown.cpp \
gui/widgets/dropdown.h \
+ gui/widgets/layout.cpp \
+ gui/widgets/layout.h \
gui/widgets/resizegrip.cpp \
gui/widgets/resizegrip.h \
gui/box.h \
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index fccfc05a..9a7d1e5b 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -36,6 +36,8 @@
#include "passwordfield.h"
#include "textfield.h"
+#include "widgets/layout.h"
+
#include "../utils/gettext.h"
LoginDialog::LoginDialog(LoginData *loginData):
@@ -50,28 +52,6 @@ LoginDialog::LoginDialog(LoginData *loginData):
mCancelButton = new Button(_("Cancel"), "cancel", this);
mRegisterButton = new Button(_("Register"), "register", this);
- const int width = 220;
- const int height = 100;
-
- setContentSize(width, height);
-
- userLabel->setPosition(5, 5);
- passLabel->setPosition(5, 14 + userLabel->getHeight());
- mUserField->setPosition(65, 5);
- mPassField->setPosition(65, 14 + userLabel->getHeight());
- mUserField->setWidth(width - 70);
- mPassField->setWidth(width - 70);
- mKeepCheck->setPosition(4, 68);
- 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");
@@ -81,14 +61,18 @@ LoginDialog::LoginDialog(LoginData *loginData):
mPassField->addActionListener(this);
mKeepCheck->addActionListener(this);
- add(userLabel);
- add(passLabel);
- add(mUserField);
- add(mPassField);
- add(mKeepCheck);
- add(mOkButton);
- add(mCancelButton);
- add(mRegisterButton);
+ setPadding(8);
+ place(0, 0, userLabel);
+ place(0, 1, passLabel);
+ place(1, 0, mUserField, 3).setPadding(2);
+ place(1, 1, mPassField, 3).setPadding(2);
+ place(0, 2, mKeepCheck, 4);
+ place(0, 3, mRegisterButton).setHAlign(Cell::LEFT);
+ place(2, 3, mOkButton);
+ place(3, 3, mCancelButton);
+ getLayout().setColWidth(1, 20);
+ reflowLayout();
+ forgetLayout();
setLocationRelativeTo(getParent());
setVisible(true);
diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp
new file mode 100644
index 00000000..8a64acc0
--- /dev/null
+++ b/src/gui/widgets/layout.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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
+ *
+ * $Id$
+ */
+
+#include "layout.h"
+
+void Layout::resizeGrid(int w, int h)
+{
+ bool extW = w && w > (int)mColWidths.size(),
+ extH = h && h > (int)mRowHeights.size();
+ if (!extW && !extH) return;
+
+ if (extH)
+ {
+ mRowHeights.resize(h, -1);
+ mCells.resize(h);
+ if (!extW) w = (int)mColWidths.size();
+ }
+
+ mColWidths.resize(w, -1);
+ for (std::vector< std::vector< Cell > >::iterator
+ i = mCells.begin(), i_end = mCells.end(); i != i_end; ++i)
+ {
+ i->resize(w);
+ }
+}
+
+void Layout::setColWidth(int n, int w)
+{
+ resizeGrid(n + 1, 0);
+ mColWidths[n] = w;
+}
+
+void Layout::setRowHeight(int n, int h)
+{
+ resizeGrid(0, n + 1);
+ mRowHeights[n] = h;
+}
+
+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.mPadding = 0;
+ cell.mHAlign = Cell::FILL;
+ cell.mVAlign = Cell::FILL;
+ return cell;
+}
+
+static void align(int &pos, int &cur, int upp, Cell::Alignment a)
+{
+ cur = std::min(cur, upp);
+ switch (a)
+ {
+ case Cell::LEFT:
+ return;
+ case Cell::RIGHT:
+ pos += upp - cur;
+ return;
+ case Cell::CENTER:
+ pos += (upp - cur) / 2;
+ return;
+ case Cell::FILL:
+ cur = upp;
+ return;
+ }
+}
+
+void Layout::reflow()
+{
+ int gridW = mColWidths.size(), gridH = mRowHeights.size();
+
+ std::vector< int > widths(gridW, 0);
+ std::vector< int > heights(gridH, 0);
+
+ for (int gridY = 0; gridY < gridH; ++gridY)
+ {
+ for (int gridX = 0; gridX < gridW; ++gridX)
+ {
+ 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)
+ {
+ int h = cell.mWidget->getHeight() + cell.mPadding * 2;
+ if (h > heights[gridY]) heights[gridY] = h;
+ }
+ }
+ }
+
+ for (int gridX = 0; gridX < gridW; ++gridX)
+ {
+ int w = mColWidths[gridX];
+ if (w != -1) widths[gridX] = w;
+ }
+
+ for (int gridY = 0; gridY < gridH; ++gridY)
+ {
+ int h = mRowHeights[gridY];
+ if (h != -1) heights[gridY] = h;
+ }
+
+ int y = 0;
+ for (int gridY = 0; gridY < gridH; ++gridY)
+ {
+ int h = heights[gridY];
+ int x = 0;
+ 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);
+ cell.mWidget->setDimension(gcn::Rectangle(dx, dy, dw, dh));
+ }
+ x += w + mPadding;
+ }
+ y += h + mPadding;
+ }
+}
diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h
new file mode 100644
index 00000000..1c4df490
--- /dev/null
+++ b/src/gui/widgets/layout.h
@@ -0,0 +1,116 @@
+/*
+ * 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
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_WIDGET_LAYOUT_H__
+#define _TMW_WIDGET_LAYOUT_H__
+
+#include <vector>
+
+#include <guichan/widget.hpp>
+
+class Cell
+{
+ friend class Layout;
+
+ public:
+
+ enum Alignment
+ {
+ LEFT, RIGHT, CENTER, FILL
+ };
+
+ Cell(): mWidget(0) {}
+
+ /**
+ * Sets padding.
+ */
+ Cell &setPadding(int p)
+ { mPadding = p; return *this; }
+
+ /**
+ * Sets horizontal alignment of cell content.
+ */
+ Cell &setHAlign(Alignment a)
+ { mHAlign = a; return *this; }
+
+ /**
+ * Sets vertical alignment of cell content.
+ */
+ Cell &setVAlign(Alignment a)
+ { mVAlign = a; return *this; }
+
+ private:
+
+ gcn::Widget *mWidget;
+ int mColExtent, mRowExtent;
+ int mPadding;
+ Alignment mHAlign, mVAlign;
+};
+
+class Layout
+{
+ public:
+
+ Layout(): mPadding(4) {}
+
+ /**
+ * Sets the width of a column.
+ */
+ void setColWidth(int n, int w);
+
+ /**
+ * Sets the height of a row.
+ */
+ void setRowHeight(int n, int h);
+
+ /**
+ * Sets padding between cells.
+ */
+ void setPadding(int p)
+ { mPadding = p; }
+
+ /**
+ * Places a widget in given cell.
+ */
+ Cell &place(gcn::Widget *, int x, int y, int w, int h);
+
+ /**
+ * Computes position of all the widgets.
+ */
+ void reflow();
+
+ private:
+
+ /**
+ * Ensures the private vectors are large enough.
+ */
+ void resizeGrid(int w, int h);
+
+ std::vector< int > mColWidths;
+ std::vector< int > mRowHeights;
+ std::vector< std::vector < Cell > > mCells;
+
+ int mPadding;
+};
+
+#endif
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 17447009..b5ac79b5 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -30,6 +30,7 @@
#include "gccontainer.h"
#include "windowcontainer.h"
+#include "widgets/layout.h"
#include "widgets/resizegrip.h"
#include "../configlistener.h"
@@ -61,6 +62,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
gcn::Window(caption),
mGrip(0),
mParent(parent),
+ mLayout(NULL),
mModal(modal),
mResizable(false),
mCloseButton(false),
@@ -105,11 +107,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);
@@ -141,6 +138,15 @@ Window::~Window()
}
}
+ delete mLayout;
+
+ while (!mWidgets.empty())
+ {
+ gcn::Widget *w = mWidgets.front();
+ remove(w);
+ delete(w);
+ }
+
instances--;
if (instances == 0)
@@ -161,9 +167,6 @@ Window::~Window()
delete border.grid[8];
closeImage->decRef();
}
-
- delete mChrome;
- delete mGrip;
}
void Window::setWindowContainer(WindowContainer *wc)
@@ -198,13 +201,11 @@ void Window::draw(gcn::Graphics *graphics)
void Window::setContentWidth(int width)
{
- mChrome->setWidth(width);
setWidth(width + 2 * getPadding());
}
void Window::setContentHeight(int height)
{
- mChrome->setHeight(height);
setHeight(height + getPadding() + getTitleBarHeight());
}
@@ -304,6 +305,7 @@ void Window::setMaxHeight(unsigned int height)
void Window::setResizable(bool r)
{
+ if (mResizable == r) return;
mResizable = r;
if (mResizable)
@@ -311,10 +313,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;
}
@@ -357,16 +360,6 @@ void Window::scheduleDelete()
windowContainer->scheduleDelete(this);
}
-void Window::add(gcn::Widget *w, bool delChild)
-{
- mChrome->add(w, delChild);
-}
-
-void Window::add(gcn::Widget *w, int x, int y, bool delChild)
-{
- mChrome->add(w, x, y, delChild);
-}
-
void Window::mousePressed(gcn::MouseEvent &event)
{
// Let Guichan move window to top and figure out title bar drag
@@ -519,8 +512,6 @@ void Window::mouseDragged(gcn::MouseEvent &event)
// Set the new window and content dimensions
setDimension(newDim);
- const gcn::Rectangle area = getChildrenArea();
- mChrome->setSize(area.width, area.height);
updateContentSize();
}
}
@@ -536,9 +527,6 @@ void Window::loadWindowState(std::string const &name)
{
setSize((int) config.getValue(name + "WinWidth", getWidth()),
(int) config.getValue(name + "WinHeight", getHeight()));
-
- const gcn::Rectangle area = getChildrenArea();
- mChrome->setSize(area.width, area.height);
}
}
@@ -607,3 +595,28 @@ void Window::fireWindowEvent(const WindowEvent &event)
break;
}
}
+
+Layout &Window::getLayout()
+{
+ if (!mLayout) mLayout = new Layout;
+ return *mLayout;
+}
+
+void Window::forgetLayout()
+{
+ delete mLayout;
+ mLayout = 0;
+}
+
+Cell &Window::place(int x, int y, gcn::Widget *wg, int w, int h)
+{
+ add(wg);
+ return getLayout().place(wg, x, y, w, h);
+}
+
+void Window::reflowLayout()
+{
+ if (!mLayout) return;
+ mLayout->reflow();
+ resizeToContent();
+}
diff --git a/src/gui/window.h b/src/gui/window.h
index ab266422..034c99da 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -30,12 +30,13 @@
#include "windowlistener.h"
+class Cell;
class ConfigListener;
-class GCContainer;
+class Image;
class ImageRect;
+class Layout;
class ResizeGrip;
class WindowContainer;
-class Image;
/**
* A window. This window can be dragged around and has a title bar. Windows are
@@ -62,7 +63,7 @@ class Window : public gcn::Window
Window *parent = NULL);
/**
- * Destructor.
+ * Destructor. Deletes all the added widgets.
*/
~Window();
@@ -77,16 +78,6 @@ class Window : public gcn::Window
void draw(gcn::Graphics *graphics);
/**
- * Adds a widget to the window.
- */
- void add(gcn::Widget *wi, bool delChild = true);
-
- /**
- * Adds a widget to the window and also specifices its position.
- */
- void add(gcn::Widget *w, int x, int y, bool delChild = true);
-
- /**
* Sets the width of the window contents.
*/
void setContentWidth(int width);
@@ -291,6 +282,26 @@ class Window : public gcn::Window
/** The window container windows add themselves to. */
static WindowContainer *windowContainer;
+ /**
+ * Gets the layout handler for this window.
+ */
+ Layout &getLayout();
+
+ /**
+ * Deletes the layout handler.
+ */
+ void forgetLayout();
+
+ /**
+ * Resizes the window after computing the position of the widgets.
+ */
+ void reflowLayout();
+
+ /**
+ * Adds a widget to the window and sets it at given cell.
+ */
+ Cell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1);
+
private:
/**
* Determines if the mouse is in a resize area and returns appropriate
@@ -301,9 +312,9 @@ class Window : public gcn::Window
*/
int getResizeHandles(gcn::MouseEvent &event);
- GCContainer *mChrome; /**< Contained container */
ResizeGrip *mGrip; /**< Resize grip */
Window *mParent; /**< The parent window */
+ Layout *mLayout; /**< Layout handler */
std::string mConfigName; /**< Name used for saving window-related data */
bool mShowTitle; /**< Window has a title bar */
bool mModal; /**< Window is modal */