summaryrefslogtreecommitdiff
path: root/src/gui/widgets
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2009-04-07 23:47:57 +0200
committerBjørn Lindeijer <bjorn@lindeijer.nl>2009-04-07 23:52:46 +0200
commitd69d85f06fa6dc22ac4c7789e4140e32d119a7f1 (patch)
tree1d2311bfdba616136d0ac26f8cbe9ab73c88f0e4 /src/gui/widgets
parent303c1f69761e90b83d4809e911f7785ec66b46aa (diff)
downloadmana-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.gz
mana-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.bz2
mana-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.xz
mana-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.zip
Moved basic widgets into the gui/widgets directory
In an attempt to make the GUI code a little more structured, basic widgets are now put in gui/widgets. Many includes were also cleaned up.
Diffstat (limited to 'src/gui/widgets')
-rw-r--r--src/gui/widgets/avatar.cpp4
-rw-r--r--src/gui/widgets/avatar.h2
-rw-r--r--src/gui/widgets/browserbox.cpp418
-rw-r--r--src/gui/widgets/browserbox.h164
-rw-r--r--src/gui/widgets/button.cpp181
-rw-r--r--src/gui/widgets/button.h67
-rw-r--r--src/gui/widgets/chattab.cpp7
-rw-r--r--src/gui/widgets/checkbox.cpp111
-rw-r--r--src/gui/widgets/checkbox.h66
-rw-r--r--src/gui/widgets/dropdown.cpp5
-rw-r--r--src/gui/widgets/gccontainer.cpp54
-rw-r--r--src/gui/widgets/gccontainer.h50
-rw-r--r--src/gui/widgets/icon.cpp58
-rw-r--r--src/gui/widgets/icon.h66
-rw-r--r--src/gui/widgets/inttextfield.cpp105
-rw-r--r--src/gui/widgets/inttextfield.h75
-rw-r--r--src/gui/widgets/label.cpp40
-rw-r--r--src/gui/widgets/label.h53
-rw-r--r--src/gui/widgets/listbox.cpp158
-rw-r--r--src/gui/widgets/listbox.h74
-rw-r--r--src/gui/widgets/passwordfield.cpp36
-rw-r--r--src/gui/widgets/passwordfield.h46
-rw-r--r--src/gui/widgets/popup.cpp179
-rw-r--r--src/gui/widgets/popup.h165
-rw-r--r--src/gui/widgets/progressbar.cpp176
-rw-r--r--src/gui/widgets/progressbar.h136
-rw-r--r--src/gui/widgets/radiobutton.cpp113
-rw-r--r--src/gui/widgets/radiobutton.h66
-rw-r--r--src/gui/widgets/scrollarea.cpp309
-rw-r--r--src/gui/widgets/scrollarea.h115
-rw-r--r--src/gui/widgets/slider.cpp154
-rw-r--r--src/gui/widgets/slider.h73
-rw-r--r--src/gui/widgets/textbox.cpp142
-rw-r--r--src/gui/widgets/textbox.h71
-rw-r--r--src/gui/widgets/textfield.cpp243
-rw-r--r--src/gui/widgets/textfield.h109
-rw-r--r--src/gui/widgets/window.cpp725
-rw-r--r--src/gui/widgets/window.h363
-rw-r--r--src/gui/widgets/windowcontainer.cpp39
-rw-r--r--src/gui/widgets/windowcontainer.h64
40 files changed, 5074 insertions, 8 deletions
diff --git a/src/gui/widgets/avatar.cpp b/src/gui/widgets/avatar.cpp
index c9e8002e..55b1716a 100644
--- a/src/gui/widgets/avatar.cpp
+++ b/src/gui/widgets/avatar.cpp
@@ -21,8 +21,8 @@
#include "gui/widgets/avatar.h"
-#include "gui/icon.h"
-#include "gui/label.h"
+#include "gui/widgets/icon.h"
+#include "gui/widgets/label.h"
#include "resources/image.h"
#include "resources/resourcemanager.h"
diff --git a/src/gui/widgets/avatar.h b/src/gui/widgets/avatar.h
index 026a3581..d1380bfd 100644
--- a/src/gui/widgets/avatar.h
+++ b/src/gui/widgets/avatar.h
@@ -24,7 +24,7 @@
#include "guichanfwd.h"
-#include "gui/gccontainer.h"
+#include "gui/widgets/gccontainer.h"
#include <string>
diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp
new file mode 100644
index 00000000..6b1cb434
--- /dev/null
+++ b/src/gui/widgets/browserbox.cpp
@@ -0,0 +1,418 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/browserbox.h"
+
+#include "gui/linkhandler.h"
+#include "gui/palette.h"
+#include "gui/truetypefont.h"
+
+#include <guichan/graphics.hpp>
+
+#include <algorithm>
+
+BrowserBox::BrowserBox(unsigned int mode, bool opaque):
+ gcn::Widget(),
+ mMode(mode), mHighMode(UNDERLINE | BACKGROUND),
+ mOpaque(opaque),
+ mUseLinksAndUserColors(true),
+ mSelectedLink(-1),
+ mMaxRows(0)
+{
+ setFocusable(true);
+ addMouseListener(this);
+}
+
+BrowserBox::~BrowserBox()
+{
+}
+
+void BrowserBox::setLinkHandler(LinkHandler* linkHandler)
+{
+ mLinkHandler = linkHandler;
+}
+
+void BrowserBox::setOpaque(bool opaque)
+{
+ mOpaque = opaque;
+}
+
+void BrowserBox::setHighlightMode(unsigned int highMode)
+{
+ mHighMode = highMode;
+}
+
+void BrowserBox::disableLinksAndUserColors()
+{
+ mUseLinksAndUserColors = false;
+}
+
+void BrowserBox::addRow(const std::string &row)
+{
+ std::string tmp = row;
+ std::string newRow;
+ BROWSER_LINK bLink;
+ int idx1, idx2, idx3;
+ TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont());
+
+ // Use links and user defined colors
+ if (mUseLinksAndUserColors)
+ {
+ // Check for links in format "@@link|Caption@@"
+ idx1 = tmp.find("@@");
+ while (idx1 >= 0)
+ {
+ idx2 = tmp.find("|", idx1);
+ idx3 = tmp.find("@@", idx2);
+ bLink.link = tmp.substr(idx1 + 2, idx2 - (idx1 + 2));
+ bLink.caption = tmp.substr(idx2 + 1, idx3 - (idx2 + 1));
+ bLink.y1 = mTextRows.size() * font->getHeight();
+ bLink.y2 = bLink.y1 + font->getHeight();
+
+ newRow += tmp.substr(0, idx1);
+
+ std::string tmp2 = newRow;
+ idx1 = tmp2.find("##");
+ while (idx1 >= 0)
+ {
+ tmp2.erase(idx1, 3);
+ idx1 = tmp2.find("##");
+ }
+ bLink.x1 = font->getWidth(tmp2) - 1;
+ bLink.x2 = bLink.x1 + font->getWidth(bLink.caption) + 1;
+
+ mLinks.push_back(bLink);
+
+ newRow += "##<" + bLink.caption;
+
+ tmp.erase(0, idx3 + 2);
+ if (!tmp.empty())
+ {
+ newRow += "##>";
+ }
+ idx1 = tmp.find("@@");
+ }
+
+ newRow += tmp;
+ }
+
+ // Don't use links and user defined colors
+ else
+ {
+ newRow = row;
+ }
+
+ mTextRows.push_back(newRow);
+
+ //discard older rows when a row limit has been set
+ if (mMaxRows > 0)
+ {
+ while (mTextRows.size() > mMaxRows)
+ {
+ mTextRows.pop_front();
+ for (unsigned int i = 0; i < mLinks.size(); i++)
+ {
+ mLinks[i].y1 -= font->getHeight();
+ mLinks[i].y2 -= font->getHeight();
+
+ if (mLinks[i].y1 < 0)
+ mLinks.erase(mLinks.begin() + i);
+ }
+ }
+ }
+
+ // Auto size mode
+ if (mMode == AUTO_SIZE)
+ {
+ std::string plain = newRow;
+ for (idx1 = plain.find("##"); idx1 >= 0; idx1 = plain.find("##"))
+ plain.erase(idx1, 3);
+
+ // Adjust the BrowserBox size
+ int w = font->getWidth(plain);
+ if (w > getWidth())
+ setWidth(w);
+ }
+
+ if (mMode == AUTO_WRAP)
+ {
+ unsigned int y = 0;
+ unsigned int nextChar;
+ const char *hyphen = "~";
+ int hyphenWidth = font->getWidth(hyphen);
+ int x = 0;
+
+ for (TextRowIterator i = mTextRows.begin(); i != mTextRows.end(); i++)
+ {
+ std::string row = *i;
+ for (unsigned int j = 0; j < row.size(); j++)
+ {
+ std::string character = row.substr(j, 1);
+ x += font->getWidth(character);
+ nextChar = j + 1;
+
+ // Wraping between words (at blank spaces)
+ if ((nextChar < row.size()) && (row.at(nextChar) == ' '))
+ {
+ int nextSpacePos = row.find(" ", (nextChar + 1));
+ if (nextSpacePos <= 0)
+ {
+ nextSpacePos = row.size() - 1;
+ }
+ int nextWordWidth = font->getWidth(
+ row.substr(nextChar,
+ (nextSpacePos - nextChar)));
+
+ if ((x + nextWordWidth + 10) > getWidth())
+ {
+ x = 15; // Ident in new line
+ y += 1;
+ j++;
+ }
+ }
+ // Wrapping looong lines (brutal force)
+ else if ((x + 2 * hyphenWidth) > getWidth())
+ {
+ x = 15; // Ident in new line
+ y += 1;
+ }
+ }
+ }
+
+ setHeight(font->getHeight() * (mTextRows.size() + y));
+ }
+ else
+ {
+ setHeight(font->getHeight() * mTextRows.size());
+ }
+}
+
+void BrowserBox::clearRows()
+{
+ mTextRows.clear();
+ mLinks.clear();
+ setWidth(0);
+ mSelectedLink = -1;
+}
+
+struct MouseOverLink
+{
+ MouseOverLink(int x, int y) : mX(x),mY(y) { }
+ bool operator() (BROWSER_LINK &link)
+ {
+ return (mX >= link.x1 && mX < link.x2 &&
+ mY >= link.y1 && mY < link.y2);
+ }
+ int mX, mY;
+};
+
+void BrowserBox::mousePressed(gcn::MouseEvent &event)
+{
+ if (!mLinkHandler) return;
+ LinkIterator i = find_if(mLinks.begin(), mLinks.end(),
+ MouseOverLink(event.getX(), event.getY()));
+
+ if (i != mLinks.end()) {
+ mLinkHandler->handleLink(i->link);
+ }
+}
+
+void BrowserBox::mouseMoved(gcn::MouseEvent &event)
+{
+ LinkIterator i = find_if(mLinks.begin(), mLinks.end(),
+ MouseOverLink(event.getX(), event.getY()));
+
+ mSelectedLink = (i != mLinks.end()) ? (i - mLinks.begin()) : -1;
+}
+
+void BrowserBox::draw(gcn::Graphics *graphics)
+{
+ if (mOpaque)
+ {
+ graphics->setColor(guiPalette->getColor(Palette::BACKGROUND));
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
+ }
+
+ if (mSelectedLink >= 0)
+ {
+ if ((mHighMode & BACKGROUND))
+ {
+ graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT));
+ graphics->fillRectangle(gcn::Rectangle(
+ mLinks[mSelectedLink].x1,
+ mLinks[mSelectedLink].y1,
+ mLinks[mSelectedLink].x2 - mLinks[mSelectedLink].x1,
+ mLinks[mSelectedLink].y2 - mLinks[mSelectedLink].y1
+ ));
+ }
+
+ if ((mHighMode & UNDERLINE))
+ {
+ graphics->setColor(guiPalette->getColor(Palette::HYPERLINK));
+ graphics->drawLine(
+ mLinks[mSelectedLink].x1,
+ mLinks[mSelectedLink].y2,
+ mLinks[mSelectedLink].x2,
+ mLinks[mSelectedLink].y2);
+ }
+ }
+
+ int x = 0, y = 0;
+ int wrappedLines = 0;
+ int link = 0;
+ TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont());
+
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+ for (TextRowIterator i = mTextRows.begin(); i != mTextRows.end(); i++)
+ {
+ const gcn::Color *selColor = &guiPalette->getColor(Palette::TEXT);
+ const gcn::Color *prevColor = selColor;
+ std::string row = *(i);
+ bool wrapped = false;
+ x = 0;
+
+ // Check for separator lines
+ if (row.find("---", 0) == 0)
+ {
+ for (x = 0; x < getWidth(); x++)
+ {
+ font->drawString(graphics, "-", x, y);
+ x += font->getWidth("-") - 2;
+ }
+ y += font->getHeight();
+ continue;
+ }
+
+ // TODO: Check if we must take texture size limits into account here
+ // TODO: Check if some of the O(n) calls can be removed
+ for (std::string::size_type start = 0, end = std::string::npos;
+ start != std::string::npos;
+ start = end, end = std::string::npos)
+ {
+ // Wrapped line continuation shall be indented
+ if (wrapped)
+ {
+ y += font->getHeight();
+ x = 15;
+ }
+
+ // "Tokenize" the string at control sequences
+ if (mUseLinksAndUserColors)
+ end = row.find("##", start + 1);
+
+ if (mUseLinksAndUserColors ||
+ (!mUseLinksAndUserColors && (start == 0)))
+ {
+ // Check for color change in format "##x", x = [L,P,0..9]
+ if (row.find("##", start) == start && row.size() > start + 2)
+ {
+ char c = row.at(start + 2);
+ if (c == '>')
+ {
+ selColor = prevColor;
+ }
+ else
+ {
+ bool valid;
+ const gcn::Color *col = &guiPalette->getColor(c, valid);
+ if (c == '<')
+ {
+ const int size = mLinks[link].x2 - mLinks[link].x1;
+ mLinks[link].x1 = x;
+ mLinks[link].y1 = y;
+ mLinks[link].x2 = mLinks[link].x1 + size;
+ mLinks[link].y2 = y + font->getHeight();
+ link++;
+ prevColor = selColor;
+ }
+ if (valid)
+ {
+ selColor = col;
+ }
+ }
+ start += 3;
+
+ if (start == row.size())
+ {
+ break;
+ }
+ }
+ graphics->setColor(*selColor);
+ }
+
+ std::string::size_type len =
+ end == std::string::npos ? end : end - start;
+ std::string part = row.substr(start, len);
+
+ // Auto wrap mode
+ if (mMode == AUTO_WRAP &&
+ (x + font->getWidth(part.c_str()) + 10) > getWidth())
+ {
+ bool forced = false;
+ char const *hyphen = "~";
+ int hyphenWidth = font->getWidth(hyphen);
+
+ /* FIXME: This code layout makes it easy to crash remote
+ clients by talking garbage. Forged long utf-8 characters
+ will cause either a buffer underflow in substr or an
+ infinite loop in the main loop. */
+ do
+ {
+ if (!forced)
+ end = row.rfind(" ", end);
+
+ // Check if we have to (stupidly) force-wrap
+ if (end == std::string::npos || end <= start)
+ {
+ forced = true;
+ end = row.size();
+ x += hyphenWidth * 2; // Account for the wrap-notifier
+ continue;
+ }
+
+ // Skip to the start of the current character
+ while ((row[end] & 192) == 128)
+ end--;
+ end--; // And then to the last byte of the previous one
+
+ part = row.substr(start, end - start + 1);
+ } while ((x + font->getWidth(part.c_str()) + 10) > getWidth());
+
+ if (forced)
+ {
+ x -= hyphenWidth; // Remove the wrap-notifier accounting
+ font->drawString(graphics, hyphen,
+ getWidth() - hyphenWidth, y);
+ end++; // Skip to the next character
+ }
+ else
+ end += 2; // Skip to after the space
+
+ wrapped = true;
+ wrappedLines++;
+ }
+ font->drawString(graphics, part, x, y);
+ x += font->getWidth(part.c_str());
+ }
+ y += font->getHeight();
+ setHeight((mTextRows.size() + wrappedLines) * font->getHeight());
+ }
+}
diff --git a/src/gui/widgets/browserbox.h b/src/gui/widgets/browserbox.h
new file mode 100644
index 00000000..090c03e1
--- /dev/null
+++ b/src/gui/widgets/browserbox.h
@@ -0,0 +1,164 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef BROWSERBOX_H
+#define BROWSERBOX_H
+
+#include <list>
+#include <vector>
+
+#include <guichan/mouselistener.hpp>
+#include <guichan/widget.hpp>
+
+class LinkHandler;
+
+struct BROWSER_LINK {
+ int x1, x2, y1, y2; /**< Where link is placed */
+ std::string link;
+ std::string caption;
+};
+
+/**
+ * A simple browser box able to handle links and forward events to the
+ * parent conteiner.
+ */
+class BrowserBox : public gcn::Widget, public gcn::MouseListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ BrowserBox(unsigned int mode = AUTO_SIZE, bool opaque = true);
+
+ /**
+ * Destructor.
+ */
+ ~BrowserBox();
+
+ /**
+ * Sets the handler for links.
+ */
+ void setLinkHandler(LinkHandler *linkHandler);
+
+ /**
+ * Sets the BrowserBox opacity.
+ */
+ void setOpaque(bool opaque);
+
+ /**
+ * Sets the Highlight mode for links.
+ */
+ void setHighlightMode(unsigned int highMode);
+
+ /**
+ * Sets the maximum numbers of rows in the browser box. 0 = no limit.
+ */
+ void setMaxRow(int max) {mMaxRows = max; };
+
+ /**
+ * Disable links & user defined colors to be used in chat input.
+ */
+ void disableLinksAndUserColors();
+
+ /**
+ * Adds a text row to the browser.
+ */
+ void addRow(const std::string &row);
+
+ /**
+ * Remove all rows.
+ */
+ void clearRows();
+
+ /**
+ * Handles mouse actions.
+ */
+ void mousePressed(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
+
+ /**
+ * Draws the browser box.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * BrowserBox modes.
+ */
+ enum {
+ AUTO_SIZE,
+ AUTO_WRAP /**< Maybe it needs a fix or to be redone. */
+ };
+
+ /**
+ * BrowserBox colors.
+ *
+ * NOTES (by Javila):
+ * - color values is "0x" prefix followed by HTML color style.
+ * - we can add up to 10 different colors: [0..9].
+ * - we need a link and a highlighted link colors.
+ * - not all colors will be fine with all backgrounds due transparent
+ * windows and widgets. So, I think it's better keep BrowserBox
+ * opaque (white background) by default.
+ */
+ enum {
+ BLACK = 0x000000, /**< Color 0 */
+ RED = 0xff0000, /**< Color 1 */
+ GREEN = 0x009000, /**< Color 2 */
+ BLUE = 0x0000ff, /**< Color 3 */
+ ORANGE = 0xe0980e, /**< Color 4 */
+ YELLOW = 0xf1dc27, /**< Color 5 */
+ PINK = 0xff00d8, /**< Color 6 */
+ PURPLE = 0x8415e2, /**< Color 7 */
+ GRAY = 0x919191, /**< Color 8 */
+ BROWN = 0x8e4c17, /**< Color 9 */
+ BGCOLOR = 0xffffff, /**< Bg color for opacity */
+ LINK = 0xe50d0d, /**< Color L */
+ HIGHLIGHT = 0xcacaca /**< Bg color for highlighted link */
+ };
+
+ /**
+ * Highlight modes for links.
+ * This can be used for a bitmask.
+ */
+ enum {
+ UNDERLINE = 1,
+ BACKGROUND = 2
+ };
+
+ private:
+ typedef std::list<std::string> TextRows;
+ typedef TextRows::iterator TextRowIterator;
+ TextRows mTextRows;
+
+ typedef std::vector<BROWSER_LINK> Links;
+ typedef Links::iterator LinkIterator;
+ Links mLinks;
+
+ LinkHandler *mLinkHandler;
+ unsigned int mMode;
+ unsigned int mHighMode;
+ bool mOpaque;
+ bool mUseLinksAndUserColors;
+ int mSelectedLink;
+ unsigned int mMaxRows;
+};
+
+#endif
diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp
new file mode 100644
index 00000000..71579bd4
--- /dev/null
+++ b/src/gui/widgets/button.cpp
@@ -0,0 +1,181 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/button.h"
+
+#include "gui/palette.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#include "utils/dtor.h"
+
+#include <guichan/exception.hpp>
+#include <guichan/font.hpp>
+
+int Button::mInstances = 0;
+float Button::mAlpha = 1.0;
+
+enum{
+ BUTTON_STANDARD, // 0
+ BUTTON_HIGHLIGHTED, // 1
+ BUTTON_PRESSED, // 2
+ BUTTON_DISABLED, // 3
+ BUTTON_COUNT // 4 - Must be last.
+};
+
+struct ButtonData
+{
+ char const *file;
+ int gridX;
+ int gridY;
+};
+
+static ButtonData const data[BUTTON_COUNT] = {
+ { "graphics/gui/button.png", 0, 0 },
+ { "graphics/gui/buttonhi.png", 9, 4 },
+ { "graphics/gui/buttonpress.png", 16, 19 },
+ { "graphics/gui/button_disabled.png", 25, 23 }
+};
+
+ImageRect Button::button[BUTTON_COUNT];
+
+Button::Button()
+{
+ init();
+}
+
+Button::Button(const std::string &caption, const std::string &actionEventId,
+ gcn::ActionListener *listener):
+ gcn::Button(caption)
+{
+ init();
+ setActionEventId(actionEventId);
+
+ if (listener)
+ addActionListener(listener);
+}
+
+void Button::init()
+{
+ setFrameSize(0);
+
+ if (mInstances == 0)
+ {
+ // Load the skin
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *btn[BUTTON_COUNT];
+
+ int a, x, y, mode;
+
+ for (mode = 0; mode < BUTTON_COUNT; mode++)
+ {
+ btn[mode] = resman->getImage(data[mode].file);
+ a = 0;
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
+ button[mode].grid[a] = btn[mode]->getSubImage(
+ data[x].gridX, data[y].gridY,
+ data[x + 1].gridX - data[x].gridX + 1,
+ data[y + 1].gridY - data[y].gridY + 1);
+ button[mode].grid[a]->setAlpha(mAlpha);
+ a++;
+ }
+ }
+ btn[mode]->decRef();
+ }
+ }
+ mInstances++;
+}
+
+Button::~Button()
+{
+ mInstances--;
+
+ if (mInstances == 0)
+ {
+ for (int mode = 0; mode < BUTTON_COUNT; mode++)
+ {
+ for_each(button[mode].grid, button[mode].grid + 9, dtor<Image*>());
+ }
+ }
+}
+
+void Button::draw(gcn::Graphics *graphics)
+{
+ int mode;
+
+ if (!isEnabled())
+ mode = BUTTON_DISABLED;
+ else if (isPressed())
+ mode = BUTTON_PRESSED;
+ else if (mHasMouse || isFocused())
+ mode = BUTTON_HIGHLIGHTED;
+ else
+ mode = BUTTON_STANDARD;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ button[BUTTON_DISABLED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_PRESSED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_HIGHLIGHTED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_STANDARD].grid[a]->setAlpha(mAlpha);
+ }
+ }
+
+ static_cast<Graphics*>(graphics)->
+ drawImageRect(0, 0, getWidth(), getHeight(), button[mode]);
+
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+
+ int textX;
+ int textY = getHeight() / 2 - getFont()->getHeight() / 2;
+
+ switch (getAlignment())
+ {
+ case gcn::Graphics::LEFT:
+ textX = 4;
+ break;
+ case gcn::Graphics::CENTER:
+ textX = getWidth() / 2;
+ break;
+ case gcn::Graphics::RIGHT:
+ textX = getWidth() - 4;
+ break;
+ default:
+ throw GCN_EXCEPTION("Button::draw. Unknown alignment.");
+ }
+
+ graphics->setFont(getFont());
+
+ if (isPressed())
+ graphics->drawText(getCaption(), textX + 1, textY + 1, getAlignment());
+ else
+ graphics->drawText(getCaption(), textX, textY, getAlignment());
+}
diff --git a/src/gui/widgets/button.h b/src/gui/widgets/button.h
new file mode 100644
index 00000000..eebf7931
--- /dev/null
+++ b/src/gui/widgets/button.h
@@ -0,0 +1,67 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef BUTTON_H
+#define BUTTON_H
+
+#include <guichan/widgets/button.hpp>
+
+class ImageRect;
+
+/**
+ * Button widget. Same as the Guichan button but with custom look.
+ *
+ * \ingroup GUI
+ */
+class Button : public gcn::Button
+{
+ public:
+ /**
+ * Default constructor.
+ */
+ Button();
+
+ /**
+ * Constructor, sets the caption of the button to the given string and
+ * adds the given action listener.
+ */
+ Button(const std::string &caption, const std::string &actionEventId,
+ gcn::ActionListener *listener);
+
+ /**
+ * Destructor.
+ */
+ ~Button();
+
+ /**
+ * Draws the button.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ private:
+ void init();
+
+ static ImageRect button[4]; /**< Button state graphics */
+ static int mInstances; /**< Number of button instances */
+ static float mAlpha;
+};
+
+#endif
diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp
index 2211eb36..26bc121a 100644
--- a/src/gui/widgets/chattab.cpp
+++ b/src/gui/widgets/chattab.cpp
@@ -19,16 +19,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "chattab.h"
+#include "gui/widgets/chattab.h"
#include "commandhandler.h"
#include "configuration.h"
#include "localplayer.h"
-#include "gui/browserbox.h"
+#include "gui/widgets/browserbox.h"
+#include "gui/widgets/scrollarea.h"
+
#include "gui/itemlinkhandler.h"
#include "gui/recorder.h"
-#include "gui/scrollarea.h"
#include "net/chathandler.h"
#include "net/net.h"
diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp
new file mode 100644
index 00000000..2e9a234b
--- /dev/null
+++ b/src/gui/widgets/checkbox.cpp
@@ -0,0 +1,111 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/checkbox.h"
+
+#include "gui/palette.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+int CheckBox::instances = 0;
+float CheckBox::mAlpha = 1.0;
+Image *CheckBox::checkBoxNormal;
+Image *CheckBox::checkBoxChecked;
+Image *CheckBox::checkBoxDisabled;
+Image *CheckBox::checkBoxDisabledChecked;
+
+CheckBox::CheckBox(const std::string &caption, bool selected):
+ gcn::CheckBox(caption, selected)
+{
+ if (instances == 0)
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *checkBox = resman->getImage("graphics/gui/checkbox.png");
+ checkBoxNormal = checkBox->getSubImage(0, 0, 9, 10);
+ checkBoxChecked = checkBox->getSubImage(9, 0, 9, 10);
+ checkBoxDisabled = checkBox->getSubImage(18, 0, 9, 10);
+ checkBoxDisabledChecked = checkBox->getSubImage(27, 0, 9, 10);
+ checkBoxNormal->setAlpha(mAlpha);
+ checkBoxChecked->setAlpha(mAlpha);
+ checkBoxDisabled->setAlpha(mAlpha);
+ checkBoxDisabledChecked->setAlpha(mAlpha);
+ checkBox->decRef();
+ }
+
+ instances++;
+}
+
+CheckBox::~CheckBox()
+{
+ instances--;
+
+ if (instances == 0)
+ {
+ delete checkBoxNormal;
+ delete checkBoxChecked;
+ delete checkBoxDisabled;
+ delete checkBoxDisabledChecked;
+ }
+}
+
+void CheckBox::draw(gcn::Graphics* graphics)
+{
+ drawBox(graphics);
+
+ graphics->setFont(getFont());
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+
+ const int h = getHeight() + getHeight() / 2;
+
+ graphics->drawText(getCaption(), h - 2, 0);
+}
+
+void CheckBox::drawBox(gcn::Graphics* graphics)
+{
+ Image *box;
+
+ if (isSelected())
+ {
+ if (isEnabled())
+ box = checkBoxChecked;
+ else
+ box = checkBoxDisabledChecked;
+ }
+ else if (isEnabled())
+ box = checkBoxNormal;
+ else
+ box = checkBoxDisabled;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ checkBoxNormal->setAlpha(mAlpha);
+ checkBoxChecked->setAlpha(mAlpha);
+ checkBoxDisabled->setAlpha(mAlpha);
+ checkBoxDisabledChecked->setAlpha(mAlpha);
+ }
+
+ static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+}
diff --git a/src/gui/widgets/checkbox.h b/src/gui/widgets/checkbox.h
new file mode 100644
index 00000000..303782b0
--- /dev/null
+++ b/src/gui/widgets/checkbox.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef CHECKBOX_H
+#define CHECKBOX_H
+
+#include <guichan/widgets/checkbox.hpp>
+
+class Image;
+
+/**
+ * Check box widget. Same as the Guichan check box but with custom look.
+ *
+ * \ingroup GUI
+ */
+class CheckBox : public gcn::CheckBox
+{
+ public:
+ /**
+ * Constructor.
+ */
+ CheckBox(const std::string &caption, bool selected = false);
+
+ /**
+ * Destructor.
+ */
+ ~CheckBox();
+
+ /**
+ * Draws the caption, then calls drawBox to draw the check box.
+ */
+ void draw(gcn::Graphics* graphics);
+
+ /**
+ * Draws the check box, not the caption.
+ */
+ void drawBox(gcn::Graphics* graphics);
+
+ private:
+ static int instances;
+ static float mAlpha;
+ static Image *checkBoxNormal;
+ static Image *checkBoxChecked;
+ static Image *checkBoxDisabled;
+ static Image *checkBoxDisabledChecked;
+};
+
+#endif
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
index 68c7e093..8dabc3f9 100644
--- a/src/gui/widgets/dropdown.cpp
+++ b/src/gui/widgets/dropdown.cpp
@@ -21,9 +21,10 @@
#include "gui/widgets/dropdown.h"
-#include "gui/listbox.h"
+#include "gui/widgets/listbox.h"
+#include "gui/widgets/scrollarea.h"
+
#include "gui/palette.h"
-#include "gui/scrollarea.h"
#include "configuration.h"
#include "graphics.h"
diff --git a/src/gui/widgets/gccontainer.cpp b/src/gui/widgets/gccontainer.cpp
new file mode 100644
index 00000000..8325ccd4
--- /dev/null
+++ b/src/gui/widgets/gccontainer.cpp
@@ -0,0 +1,54 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gccontainer.h"
+
+GCContainer::~GCContainer()
+{
+ WidgetIterator i = mDeathList.begin();
+
+ while (i != mDeathList.end()) {
+ /* Take care _not_ to modify the list in our _announceDeath method */
+ gcn::Widget *w = (*i);
+ i = mDeathList.erase(i);
+ delete w;
+ }
+
+ mDeathList.clear();
+}
+
+void GCContainer::add(gcn::Widget *w)
+{
+ mDeathList.push_back(w);
+ Container::add(w);
+}
+
+void GCContainer::add(gcn::Widget *w, int x, int y)
+{
+ mDeathList.push_back(w);
+ Container::add(w, x, y);
+}
+
+void GCContainer::death(const gcn::Event &event)
+{
+ mDeathList.remove(event.getSource());
+ Container::death(event);
+}
diff --git a/src/gui/widgets/gccontainer.h b/src/gui/widgets/gccontainer.h
new file mode 100644
index 00000000..da584a42
--- /dev/null
+++ b/src/gui/widgets/gccontainer.h
@@ -0,0 +1,50 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GUI_GCCONTAINER_H
+#define GUI_GCCONTAINER_H
+
+#include <list>
+
+#include <guichan/widgets/container.hpp>
+
+/**
+ * A garbage collecting container. Childs added to this container are
+ * automatically deleted when the container is deleted.
+ */
+class GCContainer : public gcn::Container
+{
+ public:
+ virtual ~GCContainer();
+
+ virtual void add(gcn::Widget *w);
+
+ virtual void add(gcn::Widget *w, int x, int y);
+
+ virtual void death(const gcn::Event &event);
+
+ protected:
+ typedef std::list<gcn::Widget*> Widgets;
+ typedef Widgets::iterator WidgetIterator;
+ Widgets mDeathList;
+};
+
+#endif
diff --git a/src/gui/widgets/icon.cpp b/src/gui/widgets/icon.cpp
new file mode 100644
index 00000000..0e29f603
--- /dev/null
+++ b/src/gui/widgets/icon.cpp
@@ -0,0 +1,58 @@
+/*
+ * The Mana World
+ * Copyright (C) 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/icon.h"
+
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+Icon::Icon(const std::string &file)
+ : mImage(0)
+{
+ mImage = ResourceManager::getInstance()->getImage(file);
+ setSize(mImage->getWidth(), mImage->getHeight());
+
+}
+
+Icon::Icon(Image *image)
+ : mImage(image)
+{
+ setSize(mImage->getWidth(), mImage->getHeight());
+}
+
+void Icon::setImage(Image *image)
+{
+ mImage = image;
+ setSize(mImage->getWidth(), mImage->getHeight());
+}
+
+void Icon::draw(gcn::Graphics *g)
+{
+ if(mImage)
+ {
+ Graphics *graphics = static_cast<Graphics*>(g);
+ const int x = (getWidth() - mImage->getWidth()) / 2;
+ const int y = (getHeight() - mImage->getHeight()) / 2;
+ graphics->drawImage(mImage, x, y);
+ }
+}
diff --git a/src/gui/widgets/icon.h b/src/gui/widgets/icon.h
new file mode 100644
index 00000000..f8d77e0f
--- /dev/null
+++ b/src/gui/widgets/icon.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright (C) 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef ICON_H
+#define ICON_H
+
+#include <guichan/widget.hpp>
+
+class Image;
+
+/**
+ * An icon.
+ *
+ * \ingroup GUI
+ */
+class Icon : public gcn::Widget
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Icon(const std::string &filename);
+
+ /**
+ * Constructor, uses an existing Image.
+ */
+ Icon(Image *image);
+
+ /**
+ * Gets the current Image.
+ */
+ Image *getImage() const { return mImage; }
+
+ /**
+ * Sets the image to display.
+ */
+ void setImage(Image *image);
+
+ /**
+ * Draws the Icon.
+ */
+ void draw(gcn::Graphics *g);
+
+ private:
+ Image *mImage;
+};
+
+#endif // ICON_H
diff --git a/src/gui/widgets/inttextfield.cpp b/src/gui/widgets/inttextfield.cpp
new file mode 100644
index 00000000..dee27e8e
--- /dev/null
+++ b/src/gui/widgets/inttextfield.cpp
@@ -0,0 +1,105 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/inttextfield.h"
+
+#include "gui/sdlinput.h"
+
+#include "utils/stringutils.h"
+
+IntTextField::IntTextField(int def):
+ TextField(toString(def)),
+ mDefault(def),
+ mValue(def)
+{
+}
+
+void IntTextField::keyPressed(gcn::KeyEvent &event)
+{
+ const gcn::Key &key = event.getKey();
+
+ if (key.getValue() == Key::BACKSPACE ||
+ key.getValue() == Key::DELETE)
+ {
+ setText(std::string());
+ event.consume();
+ }
+
+ if (!key.isNumber())
+ return;
+
+ TextField::keyPressed(event);
+
+ std::istringstream s(getText());
+ int i;
+ s >> i;
+ setValue(i);
+}
+
+void IntTextField::setRange(int min, int max)
+{
+ mMin = min;
+ mMax = max;
+
+ if (mValue < mMin)
+ mValue = mMin;
+ else if (mValue > mMax)
+ mValue = mMax;
+
+ if (mDefault < mMin)
+ mDefault = mMin;
+ else if (mDefault > mMax)
+ mDefault = mMax;
+}
+
+int IntTextField::getValue()
+{
+ return getText().empty() ? mMin : mValue;
+}
+
+void IntTextField::setValue(int i)
+{
+ if (i < mMin)
+ mValue = mMin;
+ else if (i > mMax)
+ mValue = mMax;
+ else
+ mValue = i;
+
+ const std::string valStr = toString(mValue);
+ setText(valStr);
+ setCaretPosition(valStr.length() + 1);
+}
+
+void IntTextField::setDefaultValue(int value)
+{
+ if (value < mMin)
+ mDefault = mMin;
+ else if (value > mMax)
+ mDefault = mMax;
+ else
+ mDefault = value;
+}
+
+void IntTextField::reset()
+{
+ setValue(mDefault);
+}
diff --git a/src/gui/widgets/inttextfield.h b/src/gui/widgets/inttextfield.h
new file mode 100644
index 00000000..ec768bea
--- /dev/null
+++ b/src/gui/widgets/inttextfield.h
@@ -0,0 +1,75 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef INTTEXTFIELD_H
+#define INTTEXTFIELD_H
+
+#include "textfield.h"
+
+/**
+ * TextBox which only accepts numbers as input.
+ */
+class IntTextField : public TextField
+{
+ public:
+ /**
+ * Constructor, sets default value.
+ */
+ IntTextField(int def = 0);
+
+ /**
+ * Sets the minimum and maximum values of the text box.
+ */
+ void setRange(int minimum, int maximum);
+
+ /**
+ * Returns the value in the text box.
+ */
+ int getValue();
+
+ /**
+ * Reset the field to the default value.
+ */
+ void reset();
+
+ /**
+ * Set the value of the text box to the specified value.
+ */
+ void setValue(int value);
+
+ /**
+ * Set the default value of the text box to the specified value.
+ */
+ void setDefaultValue(int value);
+
+ /**
+ * Responds to key presses.
+ */
+ void keyPressed(gcn::KeyEvent &event);
+
+ private:
+ int mMin; /**< Minimum value */
+ int mMax; /**< Maximum value */
+ int mDefault; /**< Default value */
+ int mValue; /**< Current value */
+};
+
+#endif
diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp
new file mode 100644
index 00000000..39fbf220
--- /dev/null
+++ b/src/gui/widgets/label.cpp
@@ -0,0 +1,40 @@
+/*
+ * The Mana World
+ * Copyright (c) 2009 Aethyra Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/label.h"
+
+#include "gui/palette.h"
+
+Label::Label() :
+ gcn::Label()
+{
+}
+
+Label::Label(const std::string &caption) :
+ gcn::Label(caption)
+{
+}
+
+void Label::draw(gcn::Graphics *graphics)
+{
+ setForegroundColor(guiPalette->getColor(Palette::TEXT));
+ gcn::Label::draw(static_cast<gcn::Graphics*>(graphics));
+}
diff --git a/src/gui/widgets/label.h b/src/gui/widgets/label.h
new file mode 100644
index 00000000..dcda8e9d
--- /dev/null
+++ b/src/gui/widgets/label.h
@@ -0,0 +1,53 @@
+/*
+ * The Mana World
+ * Copyright (c) 2009 Aethyra Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LABEL_H
+#define LABEL_H
+
+#include <guichan/widgets/label.hpp>
+
+/**
+ * Label widget. Same as the Guichan label but modified to use the palette
+ * system.
+ *
+ * \ingroup GUI
+ */
+class Label : public gcn::Label
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Label();
+
+ /**
+ * Constructor. This version of the constructor sets the label with an
+ * inintialization string.
+ */
+ Label(const std::string &caption);
+
+ /**
+ * Draws the label.
+ */
+ void draw(gcn::Graphics *graphics);
+};
+
+#endif
diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp
new file mode 100644
index 00000000..1271bf77
--- /dev/null
+++ b/src/gui/widgets/listbox.cpp
@@ -0,0 +1,158 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/listbox.h"
+
+#include "gui/palette.h"
+
+#include "configuration.h"
+
+#include <guichan/font.hpp>
+#include <guichan/graphics.hpp>
+#include <guichan/key.hpp>
+#include <guichan/listmodel.hpp>
+
+float ListBox::mAlpha = 1.0;
+
+ListBox::ListBox(gcn::ListModel *listModel):
+ gcn::ListBox(listModel)
+{
+}
+
+void ListBox::draw(gcn::Graphics *graphics)
+{
+ if (!mListModel)
+ return;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT,
+ (int)(mAlpha * 255.0f)));
+ graphics->setFont(getFont());
+
+ const int fontHeight = getFont()->getHeight();
+
+ // Draw filled rectangle around the selected list element
+ if (mSelected >= 0)
+ graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
+ getWidth(), fontHeight));
+
+ // Draw the list elements
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+ for (int i = 0, y = 0; i < mListModel->getNumberOfElements();
+ ++i, y += fontHeight)
+ {
+ graphics->drawText(mListModel->getElementAt(i), 1, y);
+ }
+}
+
+void ListBox::setSelected(int selected)
+{
+ if (!mListModel)
+ {
+ mSelected = -1;
+ }
+ else
+ {
+ if (selected < 0 && !mWrappingEnabled)
+ {
+ mSelected = -1;
+ }
+ else if (selected >= mListModel->getNumberOfElements() &&
+ mWrappingEnabled)
+ {
+ mSelected = 0;
+ }
+ else if ((selected >= mListModel->getNumberOfElements() &&
+ !mWrappingEnabled) || (selected < 0 && mWrappingEnabled))
+ {
+ mSelected = mListModel->getNumberOfElements() - 1;
+ }
+ else
+ {
+ mSelected = selected;
+ }
+ }
+ gcn::ListBox::setSelected(mSelected);
+}
+
+// -- KeyListener notifications
+void ListBox::keyPressed(gcn::KeyEvent& keyEvent)
+{
+ gcn::Key key = keyEvent.getKey();
+
+ if (key.getValue() == gcn::Key::ENTER || key.getValue() == gcn::Key::SPACE)
+ {
+ distributeActionEvent();
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::UP)
+ {
+ setSelected(mSelected - 1);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::DOWN)
+ {
+ setSelected(mSelected + 1);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::HOME)
+ {
+ setSelected(0);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::END)
+ {
+ setSelected(getListModel()->getNumberOfElements() - 1);
+ keyEvent.consume();
+ }
+}
+
+void ListBox::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
+{
+ if (isFocused())
+ {
+ if (getSelected() > 0 || (getSelected() == 0 && mWrappingEnabled))
+ {
+ setSelected(getSelected() - 1);
+ }
+
+ mouseEvent.consume();
+ }
+}
+
+void ListBox::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
+{
+ if (isFocused())
+ {
+ setSelected(getSelected() + 1);
+
+ mouseEvent.consume();
+ }
+}
+
+void ListBox::mouseDragged(gcn::MouseEvent &event)
+{
+ // Pretend mouse is pressed continuously while dragged. Causes list
+ // selection to be updated as is default in many GUIs.
+ mousePressed(event);
+}
diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h
new file mode 100644
index 00000000..cfb58f15
--- /dev/null
+++ b/src/gui/widgets/listbox.h
@@ -0,0 +1,74 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LISTBOX_H
+#define LISTBOX_H
+
+#include <guichan/widgets/listbox.hpp>
+
+class SelectionListener;
+
+/**
+ * A list box, meant to be used inside a scroll area. Same as the Guichan list
+ * box except this one doesn't have a background, instead completely relying
+ * on the scroll area. It also adds selection listener functionality.
+ *
+ * \ingroup GUI
+ */
+class ListBox : public gcn::ListBox
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ListBox(gcn::ListModel *listModel);
+
+ /**
+ * Draws the list box.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ // Inherited from KeyListener
+
+ void keyPressed(gcn::KeyEvent& keyEvent);
+
+ // Inherited from MouseListener
+
+ void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent);
+
+ void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent);
+
+ void mouseDragged(gcn::MouseEvent &event);
+
+ /**
+ * Sets the selected item. The selected item is represented by
+ * an index from the list model.
+ *
+ * @param selected the selected item as an index from the list model.
+ * @see getSelected
+ */
+ void setSelected(int selected);
+
+ private:
+ static float mAlpha;
+};
+
+#endif
diff --git a/src/gui/widgets/passwordfield.cpp b/src/gui/widgets/passwordfield.cpp
new file mode 100644
index 00000000..fd8ebe22
--- /dev/null
+++ b/src/gui/widgets/passwordfield.cpp
@@ -0,0 +1,36 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "passwordfield.h"
+
+PasswordField::PasswordField(const std::string &text):
+ TextField(text)
+{
+}
+
+void PasswordField::draw(gcn::Graphics *graphics)
+{
+ // std::string uses cow, thus cheap copy
+ const std::string original = mText;
+ mText.assign(mText.length(), '*');
+ TextField::draw(graphics);
+ mText = original;
+}
diff --git a/src/gui/widgets/passwordfield.h b/src/gui/widgets/passwordfield.h
new file mode 100644
index 00000000..3b0b5dab
--- /dev/null
+++ b/src/gui/widgets/passwordfield.h
@@ -0,0 +1,46 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PASSWORDFIELD_H
+#define PASSWORDFIELD_H
+
+#include "textfield.h"
+
+/**
+ * A password field.
+ *
+ * \ingroup GUI
+ */
+class PasswordField : public TextField
+{
+ public:
+ /**
+ * Constructor, initializes the password field with the given string.
+ */
+ PasswordField(const std::string &text = "");
+
+ /**
+ * Draws the password field.
+ */
+ void draw(gcn::Graphics *graphics);
+};
+
+#endif
diff --git a/src/gui/widgets/popup.cpp b/src/gui/widgets/popup.cpp
new file mode 100644
index 00000000..9040d6b2
--- /dev/null
+++ b/src/gui/widgets/popup.cpp
@@ -0,0 +1,179 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/popup.h"
+
+#include "gui/widgets/windowcontainer.h"
+
+#include "gui/skin.h"
+
+#include "configuration.h"
+#include "graphics.h"
+#include "log.h"
+
+#include "resources/image.h"
+
+#include <guichan/exception.hpp>
+
+Popup::Popup(const std::string &name, const std::string &skin):
+ mPopupName(name),
+ mDefaultSkinPath(skin),
+ mMinWidth(100),
+ mMinHeight(40),
+ mMaxWidth(graphics->getWidth()),
+ mMaxHeight(graphics->getHeight())
+{
+ logger->log("Popup::Popup(\"%s\")", name.c_str());
+
+ if (!windowContainer)
+ throw GCN_EXCEPTION("Popup::Popup(): no windowContainer set");
+
+ setPadding(3);
+
+ // Loads the skin
+ mSkin = skinLoader->load(skin, mDefaultSkinPath);
+
+ // Add this window to the window container
+ windowContainer->add(this);
+
+ // Popups are invisible by default
+ setVisible(false);
+}
+
+Popup::~Popup()
+{
+ logger->log("Popup::~Popup(\"%s\")", mPopupName.c_str());
+
+ savePopupConfiguration();
+
+ while (!mWidgets.empty())
+ {
+ gcn::Widget *w = mWidgets.front();
+ remove(w);
+ delete(w);
+ }
+
+ mSkin->instances--;
+}
+
+void Popup::setWindowContainer(WindowContainer *wc)
+{
+ windowContainer = wc;
+}
+
+void Popup::loadPopupConfiguration()
+{
+ if (mPopupName.empty())
+ return;
+
+ const std::string &name = mPopupName;
+ const std::string &skinName = config.getValue(name + "Skin",
+ mSkin->getFilePath());
+
+ if (skinName.compare(mSkin->getFilePath()) != 0)
+ {
+ mSkin->instances--;
+ mSkin = skinLoader->load(skinName, mDefaultSkinPath);
+ }
+}
+
+void Popup::savePopupConfiguration()
+{
+ if (mPopupName.empty())
+ return;
+
+ const std::string &name = mPopupName;
+
+ // Saves the skin path in a config file (which allows for skins to be
+ // changed from the default path)
+ config.setValue(name + "Skin", mSkin->getFilePath());
+}
+
+void Popup::draw(gcn::Graphics *graphics)
+{
+ Graphics *g = static_cast<Graphics*>(graphics);
+
+ g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
+
+ drawChildren(graphics);
+}
+
+gcn::Rectangle Popup::getChildrenArea()
+{
+ return gcn::Rectangle(getPadding(), 0, getWidth() - getPadding() * 2,
+ getHeight() - getPadding() * 2);
+}
+
+void Popup::setContentSize(int width, int height)
+{
+ width += 2 * getPadding();
+ height += 2 * getPadding();
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
+}
+
+void Popup::setLocationRelativeTo(gcn::Widget *widget)
+{
+ int wx, wy;
+ int x, y;
+
+ widget->getAbsolutePosition(wx, wy);
+ getAbsolutePosition(x, y);
+
+ setPosition(getX() + (wx + (widget->getWidth() - getWidth()) / 2 - x),
+ getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y));
+}
+
+void Popup::setMinWidth(int width)
+{
+ mMinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
+}
+
+void Popup::setMinHeight(int height)
+{
+ mMinHeight = height > mSkin->getMinHeight() ? height : mSkin->getMinHeight();
+}
+
+void Popup::setMaxWidth(int width)
+{
+ mMaxWidth = width;
+}
+
+void Popup::setMaxHeight(int height)
+{
+ mMaxHeight = height;
+}
+
+void Popup::scheduleDelete()
+{
+ windowContainer->scheduleDelete(this);
+}
+
diff --git a/src/gui/widgets/popup.h b/src/gui/widgets/popup.h
new file mode 100644
index 00000000..71ce2d89
--- /dev/null
+++ b/src/gui/widgets/popup.h
@@ -0,0 +1,165 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef POPUP_H
+#define POPUP_H
+
+#include <guichan/widgets/container.hpp>
+
+#include "guichanfwd.h"
+
+class Skin;
+class SkinLoader;
+class WindowContainer;
+
+/**
+ * A rather reduced down version of the Window class that is particularly suited
+ * for popup type functionality that doesn't need to be resized or moved around
+ * by the mouse once created, but only needs to display some simple content,
+ * like a static message. Popups, in general, shouldn't also need to update
+ * their content once created, although this is not an explicit requirement to
+ * use the popup class.
+ *
+ * \ingroup GUI
+ */
+class Popup : public gcn::Container
+{
+ public:
+ /**
+ * Constructor. Initializes the title to the given text and hooks
+ * itself into the popup container.
+ *
+ * @param name A human readable name for the popup. Only useful for
+ * debugging purposes.
+ * @param skin The location where the Popup's skin XML can be found.
+ */
+ Popup(const std::string &name = "",
+ const std::string &skin = "graphics/gui/gui.xml");
+
+ /**
+ * Destructor. Deletes all the added widgets.
+ */
+ ~Popup();
+
+ /**
+ * Sets the window container to be used by new popups.
+ */
+ static void setWindowContainer(WindowContainer *windowContainer);
+
+ /**
+ * Changes the popup's skin to use the skin defined in the saved
+ * configuration file.
+ */
+ void loadPopupConfiguration();
+
+ /**
+ * Currently only saves the skin used by the popup so that when the
+ * client is reloaded, it can use the saved skin.
+ */
+ void savePopupConfiguration();
+
+ /**
+ * Draws the popup.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Sets the size of this popup.
+ */
+ void setContentSize(int width, int height);
+
+ /**
+ * Sets the location relative to the given widget.
+ */
+ void setLocationRelativeTo(gcn::Widget *widget);
+
+ /**
+ * Sets the minimum width of the popup.
+ */
+ void setMinWidth(int width);
+
+ int getMinWidth() const { return mMinWidth; }
+
+ /**
+ * Sets the minimum height of the popup.
+ */
+ void setMinHeight(int height);
+
+ int getMinHeight() const { return mMinHeight; }
+
+ /**
+ * Sets the maximum width of the popup.
+ */
+ void setMaxWidth(int width);
+
+ int getMaxWidth() const { return mMaxWidth; }
+
+ /**
+ * Sets the minimum height of the popup.
+ */
+ void setMaxHeight(int height);
+
+ int getMaxHeight() const { return mMaxHeight; }
+
+ /**
+ * Gets the padding of the popup. The padding is the distance between
+ * the popup border and the content.
+ *
+ * @return The padding of the popup.
+ * @see setPadding
+ */
+ int getPadding() const { return mPadding; }
+
+ void setPadding(int padding) { mPadding = padding; }
+
+ /**
+ * Sets the name of the popup. This is only useful for debug purposes.
+ */
+ void setPopupName(const std::string &name)
+ { mPopupName = name; }
+
+ const std::string &getPopupName() const
+ { return mPopupName; }
+
+ /**
+ * Schedule this popup for deletion. It will be deleted at the start
+ * of the next logic update.
+ */
+ void scheduleDelete();
+
+ // Inherited from BasicContainer
+
+ virtual gcn::Rectangle getChildrenArea();
+
+ private:
+ std::string mPopupName; /**< Name of the popup */
+ std::string mDefaultSkinPath; /**< Default skin path for this popup */
+ int mMinWidth; /**< Minimum popup width */
+ int mMinHeight; /**< Minimum popup height */
+ int mMaxWidth; /**< Maximum popup width */
+ int mMaxHeight; /**< Maximum popup height */
+ int mPadding; /**< Holds the padding of the popup. */
+
+ Skin *mSkin; /**< Skin in use by this popup */
+};
+
+#endif
diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp
new file mode 100644
index 00000000..0f278a67
--- /dev/null
+++ b/src/gui/widgets/progressbar.cpp
@@ -0,0 +1,176 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/progressbar.h"
+
+#include "gui/gui.h"
+#include "gui/palette.h"
+#include "gui/textrenderer.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#include <guichan/font.hpp>
+
+ImageRect ProgressBar::mBorder;
+int ProgressBar::mInstances = 0;
+float ProgressBar::mAlpha = 1.0;
+
+ProgressBar::ProgressBar(float progress,
+ unsigned int width, unsigned int height,
+ Uint8 red, Uint8 green, Uint8 blue):
+ gcn::Widget(),
+ mRed(red), mGreen(green), mBlue(blue),
+ mRedToGo(red), mGreenToGo(green), mBlueToGo(blue)
+{
+ mProgressToGo = mProgress = 0.0f;
+ mSmoothProgress = mSmoothColorChange = true;
+
+ setProgress(progress);
+ setWidth(width);
+ setHeight(height);
+
+ if (mInstances == 0)
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *dBorders = resman->getImage("graphics/gui/vscroll_grey.png");
+ mBorder.grid[0] = dBorders->getSubImage(0, 0, 4, 4);
+ mBorder.grid[1] = dBorders->getSubImage(4, 0, 3, 4);
+ mBorder.grid[2] = dBorders->getSubImage(7, 0, 4, 4);
+ mBorder.grid[3] = dBorders->getSubImage(0, 4, 4, 10);
+ mBorder.grid[4] = resman->getImage("graphics/gui/bg_quad_dis.png");
+ mBorder.grid[5] = dBorders->getSubImage(7, 4, 4, 10);
+ mBorder.grid[6] = dBorders->getSubImage(0, 15, 4, 4);
+ mBorder.grid[7] = dBorders->getSubImage(4, 15, 3, 4);
+ mBorder.grid[8] = dBorders->getSubImage(7, 15, 4, 4);
+
+ for (int i = 0; i < 9; i++)
+ {
+ mBorder.grid[i]->setAlpha(mAlpha);
+ }
+
+ dBorders->decRef();
+ }
+
+ mInstances++;
+}
+
+ProgressBar::~ProgressBar()
+{
+ mInstances--;
+
+ if (mInstances == 0)
+ {
+ delete mBorder.grid[0];
+ delete mBorder.grid[1];
+ delete mBorder.grid[2];
+ delete mBorder.grid[3];
+ mBorder.grid[4]->decRef();
+ delete mBorder.grid[5];
+ delete mBorder.grid[6];
+ delete mBorder.grid[7];
+ delete mBorder.grid[8];
+ }
+}
+
+void ProgressBar::logic()
+{
+ if (mSmoothColorChange)
+ {
+ // Smoothly changing the color for a nicer effect.
+ if (mRedToGo > mRed) mRed++;
+ if (mRedToGo < mRed) mRed--;
+ if (mGreenToGo > mGreen) mGreen++;
+ if (mGreenToGo < mGreen) mGreen--;
+ if (mBlueToGo > mBlue) mBlue++;
+ if (mBlueToGo < mBlue) mBlue--;
+ }
+ else
+ {
+ mRed = mRedToGo;
+ mGreen = mGreenToGo;
+ mBlue = mBlueToGo;
+ }
+
+ if (mSmoothProgress)
+ {
+ // Smoothly showing the progressbar changes.
+ if (mProgressToGo > mProgress) mProgress = mProgress + 0.005f;
+ if (mProgressToGo < mProgress) mProgress = mProgress - 0.005f;
+ }
+ else
+ mProgress = mProgressToGo;
+}
+
+void ProgressBar::draw(gcn::Graphics *graphics)
+{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int i = 0; i < 9; i++)
+ {
+ mBorder.grid[i]->setAlpha(mAlpha);
+ }
+ }
+
+ static_cast<Graphics*>(graphics)->
+ drawImageRect(0, 0, getWidth(), getHeight(), mBorder);
+
+ const int alpha = (int)(mAlpha * 255.0f);
+
+ // The bar
+ if (mProgress > 0)
+ {
+ graphics->setColor(gcn::Color(mRed, mGreen, mBlue, alpha));
+ graphics->fillRectangle(gcn::Rectangle(4, 4,
+ (int) (mProgress * (getWidth() - 8)),
+ getHeight() - 8));
+ }
+
+ // The label
+ if (!mText.empty())
+ {
+ const int textX = getWidth() / 2;
+ const int textY = (getHeight() - boldFont->getHeight()) / 2;
+
+ TextRenderer::renderText(graphics, mText, textX, textY,
+ gcn::Graphics::CENTER,
+ guiPalette->getColor(Palette::PROGRESS_BAR,
+ alpha), boldFont, true, false);
+ }
+}
+
+void ProgressBar::setProgress(float progress)
+{
+ if (progress < 0.0f) mProgressToGo = 0.0;
+ else if (progress > 1.0f) mProgressToGo = 1.0;
+ else mProgressToGo = progress;
+}
+
+void ProgressBar::setColor(Uint8 red, Uint8 green, Uint8 blue)
+{
+ mRedToGo = red;
+ mGreenToGo = green;
+ mBlueToGo = blue;
+}
diff --git a/src/gui/widgets/progressbar.h b/src/gui/widgets/progressbar.h
new file mode 100644
index 00000000..e75b1d44
--- /dev/null
+++ b/src/gui/widgets/progressbar.h
@@ -0,0 +1,136 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PROGRESSBAR_H
+#define PROGRESSBAR_H
+
+#include <string>
+
+#include <guichan/widget.hpp>
+
+#include <SDL_types.h>
+
+class ImageRect;
+
+/**
+ * A progress bar.
+ *
+ * \ingroup GUI
+ */
+class ProgressBar : public gcn::Widget
+{
+ public:
+ /**
+ * Constructor, initializes the progress with the given value.
+ */
+ ProgressBar(float progress = 0.0f,
+ unsigned int width = 40, unsigned int height = 7,
+ Uint8 red = 150, Uint8 green = 150, Uint8 blue = 150);
+
+ /**
+ * Destructor.
+ */
+ ~ProgressBar();
+
+ /**
+ * Performs progress bar logic (fading colors)
+ */
+ void logic();
+
+ /**
+ * Draws the progress bar.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Sets the current progress.
+ */
+ void setProgress(float progress);
+
+ /**
+ * Returns the current progress.
+ */
+ float getProgress() const { return mProgress; }
+
+ /**
+ * Change the filling of the progress bar.
+ */
+ void setColor(Uint8, Uint8 green, Uint8 blue);
+
+ /**
+ * Returns the red value of color.
+ */
+ Uint8 getRed() const { return mRed; }
+
+ /**
+ * Returns the green value of color.
+ */
+ Uint8 getGreen() const { return mGreen; }
+
+ /**
+ * Returns the blue value of color.
+ */
+ Uint8 getBlue() const { return mBlue; }
+
+ /**
+ * Sets the text shown on the progress bar.
+ */
+ void setText(const std::string &text)
+ { mText = text; }
+
+ /**
+ * Returns the text shown on the progress bar.
+ */
+ const std::string &text() const
+ { return mText; }
+
+ /**
+ * Set wether the progress is moved smoothly.
+ */
+ void setSmoothProgress(bool smoothProgress)
+ { mSmoothProgress = smoothProgress; }
+
+ /**
+ * Set wether the color changing is made smoothly.
+ */
+ void setSmoothColorChange(bool smoothColorChange)
+ { mSmoothColorChange = smoothColorChange; }
+
+
+ private:
+ float mProgress, mProgressToGo;
+ bool mSmoothProgress;
+
+ Uint8 mRed, mGreen, mBlue;
+ Uint8 mRedToGo, mGreenToGo, mBlueToGo;
+ bool mSmoothColorChange;
+
+ std::string mText;
+ bool mUpdated;
+
+ static ImageRect mBorder;
+ static int mInstances;
+ static float mAlpha;
+
+ static const gcn::Color TEXT_COLOR;
+};
+
+#endif
diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp
new file mode 100644
index 00000000..6f0ccdbd
--- /dev/null
+++ b/src/gui/widgets/radiobutton.cpp
@@ -0,0 +1,113 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/radiobutton.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+int RadioButton::instances = 0;
+float RadioButton::mAlpha = 1.0;
+Image *RadioButton::radioNormal;
+Image *RadioButton::radioChecked;
+Image *RadioButton::radioDisabled;
+Image *RadioButton::radioDisabledChecked;
+
+RadioButton::RadioButton(const std::string &caption, const std::string &group,
+ bool marked):
+ gcn::RadioButton(caption, group, marked)
+{
+ if (instances == 0)
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ radioNormal = resman->getImage("graphics/gui/radioout.png");
+ radioChecked = resman->getImage("graphics/gui/radioin.png");
+ radioDisabled = resman->getImage("graphics/gui/radioout.png");
+ radioDisabledChecked = resman->getImage("graphics/gui/radioin.png");
+ radioNormal->setAlpha(mAlpha);
+ radioChecked->setAlpha(mAlpha);
+ radioDisabled->setAlpha(mAlpha);
+ radioDisabledChecked->setAlpha(mAlpha);
+ }
+
+ instances++;
+}
+
+RadioButton::~RadioButton()
+{
+ instances--;
+
+ if (instances == 0)
+ {
+ radioNormal->decRef();
+ radioChecked->decRef();
+ radioDisabled->decRef();
+ radioDisabledChecked->decRef();
+ }
+}
+
+void RadioButton::drawBox(gcn::Graphics* graphics)
+{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ radioNormal->setAlpha(mAlpha);
+ radioChecked->setAlpha(mAlpha);
+ radioDisabled->setAlpha(mAlpha);
+ radioDisabledChecked->setAlpha(mAlpha);
+ }
+
+ Image *box = NULL;
+
+ if (isSelected())
+ {
+ if (isEnabled())
+ box = radioChecked;
+ else
+ box = radioDisabledChecked;
+ }
+ else if (isEnabled())
+ box = radioNormal;
+ else
+ box = radioDisabled;
+
+ if (box)
+ static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+}
+
+void RadioButton::draw(gcn::Graphics* graphics)
+{
+ graphics->pushClipArea(gcn::Rectangle(1, 1, getWidth() - 1,
+ getHeight() - 1));
+
+ drawBox(graphics);
+
+ graphics->popClipArea();
+
+ graphics->setFont(getFont());
+ graphics->setColor(getForegroundColor());
+
+ int h = getHeight() + getHeight() / 2;
+ graphics->drawText(getCaption(), h - 2, 0);
+}
diff --git a/src/gui/widgets/radiobutton.h b/src/gui/widgets/radiobutton.h
new file mode 100644
index 00000000..9aec3add
--- /dev/null
+++ b/src/gui/widgets/radiobutton.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef RADIOBUTTON_H
+#define RADIOBUTTON_H
+
+#include <guichan/widgets/radiobutton.hpp>
+
+class Image;
+
+/*
+ * Guichan based RadioButton with custom look
+ */
+class RadioButton : public gcn::RadioButton
+{
+ public:
+ /*
+ * Constructor.
+ */
+ RadioButton(const std::string &caption,const std::string &group,
+ bool marked = false);
+
+ /**
+ * Destructor.
+ */
+ ~RadioButton();
+
+ /**
+ * Draws the radiobutton, not the caption.
+ */
+ void drawBox(gcn::Graphics* graphics);
+
+ /**
+ * Implementation of the draw methods.
+ * Thus, avoiding the rhomb around the radio button.
+ */
+ void draw(gcn::Graphics* graphics);
+
+ private:
+ static int instances;
+ static float mAlpha;
+ static Image *radioNormal;
+ static Image *radioChecked;
+ static Image *radioDisabled;
+ static Image *radioDisabledChecked;
+};
+
+#endif /* RADIOBUTTON_H */
diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp
new file mode 100644
index 00000000..57995ba1
--- /dev/null
+++ b/src/gui/widgets/scrollarea.cpp
@@ -0,0 +1,309 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/scrollarea.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#include "utils/dtor.h"
+
+int ScrollArea::instances = 0;
+float ScrollArea::mAlpha = 1.0;
+ImageRect ScrollArea::background;
+ImageRect ScrollArea::vMarker;
+Image *ScrollArea::buttons[4][2];
+
+ScrollArea::ScrollArea():
+ gcn::ScrollArea(),
+ mOpaque(true)
+{
+ init();
+}
+
+ScrollArea::ScrollArea(gcn::Widget *widget):
+ gcn::ScrollArea(widget),
+ mOpaque(true)
+{
+ init();
+}
+
+ScrollArea::~ScrollArea()
+{
+ // Garbage collection
+ delete getContent();
+
+ instances--;
+
+ if (instances == 0)
+ {
+ for_each(background.grid, background.grid + 9, dtor<Image*>());
+ for_each(vMarker.grid, vMarker.grid + 9, dtor<Image*>());
+
+ buttons[UP][0]->decRef();
+ buttons[UP][1]->decRef();
+ buttons[DOWN][0]->decRef();
+ buttons[DOWN][1]->decRef();
+ buttons[LEFT][0]->decRef();
+ buttons[LEFT][1]->decRef();
+ buttons[RIGHT][0]->decRef();
+ buttons[RIGHT][1]->decRef();
+ }
+}
+
+void ScrollArea::init()
+{
+ // Draw background by default
+ setOpaque(true);
+
+ if (instances == 0)
+ {
+ // Load the background skin
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *textbox = resman->getImage("graphics/gui/deepbox.png");
+ const int bggridx[4] = {0, 3, 28, 31};
+ const int bggridy[4] = {0, 3, 28, 31};
+ int a = 0, x, y;
+
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
+ background.grid[a] = textbox->getSubImage(
+ bggridx[x], bggridy[y],
+ bggridx[x + 1] - bggridx[x] + 1,
+ bggridy[y + 1] - bggridy[y] + 1);
+ background.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
+ a++;
+ }
+ }
+
+ textbox->decRef();
+
+ // Load vertical scrollbar skin
+ Image *vscroll = resman->getImage("graphics/gui/vscroll_grey.png");
+ int vsgridx[4] = {0, 4, 7, 11};
+ int vsgridy[4] = {0, 4, 15, 19};
+ a = 0;
+
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
+ vMarker.grid[a] = vscroll->getSubImage(
+ vsgridx[x], vsgridy[y],
+ vsgridx[x + 1] - vsgridx[x],
+ vsgridy[y + 1] - vsgridy[y]);
+ vMarker.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
+ a++;
+ }
+ }
+
+ vscroll->decRef();
+
+ buttons[UP][0] =
+ resman->getImage("graphics/gui/vscroll_up_default.png");
+ buttons[DOWN][0] =
+ resman->getImage("graphics/gui/vscroll_down_default.png");
+ buttons[LEFT][0] =
+ resman->getImage("graphics/gui/hscroll_left_default.png");
+ buttons[RIGHT][0] =
+ resman->getImage("graphics/gui/hscroll_right_default.png");
+ buttons[UP][1] =
+ resman->getImage("graphics/gui/vscroll_up_pressed.png");
+ buttons[DOWN][1] =
+ resman->getImage("graphics/gui/vscroll_down_pressed.png");
+ buttons[LEFT][1] =
+ resman->getImage("graphics/gui/hscroll_left_pressed.png");
+ buttons[RIGHT][1] =
+ resman->getImage("graphics/gui/hscroll_right_pressed.png");
+ }
+
+ instances++;
+}
+
+void ScrollArea::logic()
+{
+ if (!isVisible())
+ return;
+
+ gcn::ScrollArea::logic();
+ gcn::Widget *content = getContent();
+
+ // When no scrollbar in a certain direction, adapt content size to match
+ // the content dimension exactly.
+ if (content)
+ {
+ if (getHorizontalScrollPolicy() == gcn::ScrollArea::SHOW_NEVER)
+ {
+ content->setWidth(getChildrenArea().width -
+ 2 * content->getFrameSize());
+ }
+ if (getVerticalScrollPolicy() == gcn::ScrollArea::SHOW_NEVER)
+ {
+ content->setHeight(getChildrenArea().height -
+ 2 * content->getFrameSize());
+ }
+ }
+}
+
+void ScrollArea::draw(gcn::Graphics *graphics)
+{
+ if (mVBarVisible)
+ {
+ drawUpButton(graphics);
+ drawDownButton(graphics);
+ drawVBar(graphics);
+ drawVMarker(graphics);
+ }
+
+ if (mHBarVisible)
+ {
+ drawLeftButton(graphics);
+ drawRightButton(graphics);
+ drawHBar(graphics);
+ drawHMarker(graphics);
+ }
+
+ if (mHBarVisible && mVBarVisible)
+ {
+ graphics->setColor(getBaseColor());
+ graphics->fillRectangle(gcn::Rectangle(getWidth() - mScrollbarWidth,
+ getHeight() - mScrollbarWidth,
+ mScrollbarWidth,
+ mScrollbarWidth));
+ }
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ background.grid[a]->setAlpha(mAlpha);
+ vMarker.grid[a]->setAlpha(mAlpha);
+ }
+ }
+
+ drawChildren(graphics);
+}
+
+void ScrollArea::drawFrame(gcn::Graphics *graphics)
+{
+ if (mOpaque)
+ {
+ const int bs = getFrameSize();
+ const int w = getWidth() + bs * 2;
+ const int h = getHeight() + bs * 2;
+
+ static_cast<Graphics*>(graphics)->
+ drawImageRect(0, 0, w, h, background);
+ }
+}
+
+void ScrollArea::setOpaque(bool opaque)
+{
+ mOpaque = opaque;
+ setFrameSize(mOpaque ? 2 : 0);
+}
+
+void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir)
+{
+ int state = 0;
+ gcn::Rectangle dim;
+
+ switch (dir)
+ {
+ case UP:
+ state = mUpButtonPressed ? 1 : 0;
+ dim = getUpButtonDimension();
+ break;
+ case DOWN:
+ state = mDownButtonPressed ? 1 : 0;
+ dim = getDownButtonDimension();
+ break;
+ case LEFT:
+ state = mLeftButtonPressed ? 1 : 0;
+ dim = getLeftButtonDimension();
+ break;
+ case RIGHT:
+ state = mRightButtonPressed ? 1 : 0;
+ dim = getRightButtonDimension();
+ break;
+ }
+
+ static_cast<Graphics*>(graphics)->
+ drawImage(buttons[dir][state], dim.x, dim.y);
+}
+
+void ScrollArea::drawUpButton(gcn::Graphics *graphics)
+{
+ drawButton(graphics, UP);
+}
+
+void ScrollArea::drawDownButton(gcn::Graphics *graphics)
+{
+ drawButton(graphics, DOWN);
+}
+
+void ScrollArea::drawLeftButton(gcn::Graphics *graphics)
+{
+ drawButton(graphics, LEFT);
+}
+
+void ScrollArea::drawRightButton(gcn::Graphics *graphics)
+{
+ drawButton(graphics, RIGHT);
+}
+
+void ScrollArea::drawVBar(gcn::Graphics *graphics)
+{
+ gcn::Rectangle dim = getVerticalBarDimension();
+ graphics->setColor(gcn::Color(0, 0, 0, 32));
+ graphics->fillRectangle(dim);
+ graphics->setColor(gcn::Color(255, 255, 255));
+}
+
+void ScrollArea::drawHBar(gcn::Graphics *graphics)
+{
+ gcn::Rectangle dim = getHorizontalBarDimension();
+ graphics->setColor(gcn::Color(0, 0, 0, 32));
+ graphics->fillRectangle(dim);
+ graphics->setColor(gcn::Color(255, 255, 255));
+}
+
+void ScrollArea::drawVMarker(gcn::Graphics *graphics)
+{
+ gcn::Rectangle dim = getVerticalMarkerDimension();
+
+ static_cast<Graphics*>(graphics)->
+ drawImageRect(dim.x, dim.y, dim.width, dim.height, vMarker);
+}
+
+void ScrollArea::drawHMarker(gcn::Graphics *graphics)
+{
+ gcn::Rectangle dim = getHorizontalMarkerDimension();
+
+ static_cast<Graphics*>(graphics)->
+ drawImageRect(dim.x, dim.y, dim.width, dim.height, vMarker);
+}
diff --git a/src/gui/widgets/scrollarea.h b/src/gui/widgets/scrollarea.h
new file mode 100644
index 00000000..e9aa5ed2
--- /dev/null
+++ b/src/gui/widgets/scrollarea.h
@@ -0,0 +1,115 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SCROLLAREA_H
+#define SCROLLAREA_H
+
+#include <guichan/widgets/scrollarea.hpp>
+
+class Image;
+class ImageRect;
+
+/**
+ * A scroll area.
+ *
+ * Contrary to Guichan's scroll area, this scroll area takes ownership over its
+ * content. However, it won't delete a previously set content widget when
+ * setContent is called!
+ *
+ * \ingroup GUI
+ */
+class ScrollArea : public gcn::ScrollArea
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ScrollArea();
+
+ /**
+ * Constructor.
+ */
+ ScrollArea(gcn::Widget *content);
+
+ /**
+ * Destructor.
+ */
+ ~ScrollArea();
+
+ /**
+ * Logic function optionally adapts width or height of contents. This
+ * depends on the scrollbar settings.
+ */
+ void logic();
+
+ /**
+ * Draws the scroll area.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Draws the background and border of the scroll area.
+ */
+ void drawFrame(gcn::Graphics *graphics);
+
+ /**
+ * Sets whether the widget should draw its background or not.
+ */
+ void setOpaque(bool opaque);
+
+ /**
+ * Returns whether the widget draws its background or not.
+ */
+ bool isOpaque() const { return mOpaque; }
+
+ protected:
+ enum BUTTON_DIR {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ };
+
+ /**
+ * Initializes the scroll area.
+ */
+ void init();
+
+ void drawButton(gcn::Graphics *graphics, BUTTON_DIR dir);
+ void drawUpButton(gcn::Graphics *graphics);
+ void drawDownButton(gcn::Graphics *graphics);
+ void drawLeftButton(gcn::Graphics *graphics);
+ void drawRightButton(gcn::Graphics *graphics);
+ void drawVBar(gcn::Graphics *graphics);
+ void drawHBar(gcn::Graphics *graphics);
+ void drawVMarker(gcn::Graphics *graphics);
+ void drawHMarker(gcn::Graphics *graphics);
+
+ static int instances;
+ static float mAlpha;
+ static ImageRect background;
+ static ImageRect vMarker;
+ static Image *buttons[4][2];
+
+ bool mOpaque;
+};
+
+#endif
diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp
new file mode 100644
index 00000000..7cd0e54a
--- /dev/null
+++ b/src/gui/widgets/slider.cpp
@@ -0,0 +1,154 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/slider.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip;
+Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip;
+float Slider::mAlpha = 1.0;
+int Slider::mInstances = 0;
+
+Slider::Slider(double scaleEnd):
+ gcn::Slider(scaleEnd)
+{
+ init();
+}
+
+Slider::Slider(double scaleStart, double scaleEnd):
+ gcn::Slider(scaleStart, scaleEnd)
+{
+ init();
+}
+
+Slider::~Slider()
+{
+ mInstances--;
+
+ if (mInstances == 0)
+ {
+ delete hStart;
+ delete hMid;
+ delete hEnd;
+ delete hGrip;
+ delete vStart;
+ delete vMid;
+ delete vEnd;
+ delete vGrip;
+ }
+}
+
+void Slider::init()
+{
+ int x, y, w, h,o1,o2;
+ setFrameSize(0);
+
+ // Load resources
+ if (mInstances == 0)
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *slider = resman->getImage("graphics/gui/slider.png");
+
+ x = 0; y = 0;
+ w = 15; h = 6;
+ o1 = 4; o2 = 11;
+ hStart = slider->getSubImage(x, y, o1 - x, h);
+ hMid = slider->getSubImage(o1, y, o2 - o1, h);
+ hEnd = slider->getSubImage(o2, y, w - o2 + x, h);
+
+ x = 6; y = 8;
+ w = 9; h = 10;
+ hGrip = slider->getSubImage(x, y, w, h);
+
+ x = 0; y = 6;
+ w = 6; h = 21;
+ o1 = 10; o2 = 18;
+ vStart = slider->getSubImage(x, y, w, o1 - y);
+ vMid = slider->getSubImage(x, o1, w, o2 - o1);
+ vEnd = slider->getSubImage(x, o2, w, h - o2 + y);
+
+ x = 6; y = 8;
+ w = 9; h = 10;
+ vGrip = slider->getSubImage(x, y, w, h);
+
+ slider->decRef();
+
+ hStart->setAlpha(mAlpha);
+ hMid->setAlpha(mAlpha);
+ hEnd->setAlpha(mAlpha);
+ hGrip->setAlpha(mAlpha);
+
+ vStart->setAlpha(mAlpha);
+ vMid->setAlpha(mAlpha);
+ vEnd->setAlpha(mAlpha);
+ vGrip->setAlpha(mAlpha);
+ }
+
+ mInstances++;
+
+ setMarkerLength(hGrip->getWidth());
+}
+
+void Slider::draw(gcn::Graphics *graphics)
+{
+ int w = getWidth();
+ int h = getHeight();
+ int x = 0;
+ int y = (h - hStart->getHeight()) / 2;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ hStart->setAlpha(mAlpha);
+ hMid->setAlpha(mAlpha);
+ hEnd->setAlpha(mAlpha);
+ hGrip->setAlpha(mAlpha);
+
+ vStart->setAlpha(mAlpha);
+ vMid->setAlpha(mAlpha);
+ vEnd->setAlpha(mAlpha);
+ vGrip->setAlpha(mAlpha);
+ }
+
+ static_cast<Graphics*>(graphics)->drawImage(hStart, x, y);
+
+ w -= hStart->getWidth() + hEnd->getWidth();
+ x += hStart->getWidth();
+
+ static_cast<Graphics*>(graphics)->
+ drawImagePattern(hMid, x, y, w, hMid->getHeight());
+
+ x += w;
+ static_cast<Graphics*>(graphics)->drawImage(hEnd, x, y);
+
+ drawMarker(graphics);
+}
+
+void Slider::drawMarker(gcn::Graphics *graphics)
+{
+ static_cast<Graphics*>(graphics)->
+ drawImage(hGrip, getMarkerPosition(), (getHeight() - hGrip->getHeight()) / 2);
+}
diff --git a/src/gui/widgets/slider.h b/src/gui/widgets/slider.h
new file mode 100644
index 00000000..56ea334a
--- /dev/null
+++ b/src/gui/widgets/slider.h
@@ -0,0 +1,73 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SLIDER_H
+#define SLIDER_H
+
+#include <guichan/widgets/slider.hpp>
+
+class Image;
+
+/**
+ * Slider widget. Same as the Guichan slider but with custom look.
+ *
+ * \ingroup GUI
+ */
+class Slider : public gcn::Slider {
+ public:
+ /**
+ * Constructor with scale start equal to 0.
+ */
+ Slider(double scaleEnd = 1.0);
+
+ /**
+ * Constructor.
+ */
+ Slider(double scaleStart, double scaleEnd);
+
+ /**
+ * Destructor.
+ */
+ ~Slider();
+
+ /**
+ * Draws the slider.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Draws the marker.
+ */
+ void drawMarker(gcn::Graphics *graphics);
+
+ private:
+ /**
+ * Used to initialize instances.
+ */
+ void init();
+
+ static Image *hStart, *hMid, *hEnd, *hGrip;
+ static Image *vStart, *vMid, *vEnd, *vGrip;
+ static float mAlpha;
+ static int mInstances;
+};
+
+#endif
diff --git a/src/gui/widgets/textbox.cpp b/src/gui/widgets/textbox.cpp
new file mode 100644
index 00000000..bf3692ec
--- /dev/null
+++ b/src/gui/widgets/textbox.cpp
@@ -0,0 +1,142 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/textbox.h"
+
+#include "gui/palette.h"
+
+#include <guichan/font.hpp>
+
+#include <sstream>
+
+TextBox::TextBox() :
+ gcn::TextBox(), mTextColor(&guiPalette->getColor(Palette::TEXT))
+{
+ setOpaque(false);
+ setFrameSize(0);
+ mMinWidth = getWidth();
+}
+
+void TextBox::setTextWrapped(const std::string &text, int minDimension)
+{
+ // Make sure parent scroll area sets width of this widget
+ if (getParent())
+ getParent()->logic();
+
+ // Take the supplied minimum dimension as a starting point and try to beat it
+ mMinWidth = minDimension;
+
+ std::stringstream wrappedStream;
+ std::string::size_type spacePos, newlinePos, lastNewlinePos = 0;
+ int minWidth = 0;
+ int xpos;
+
+ spacePos = text.rfind(" ", text.size());
+
+ if (spacePos != std::string::npos)
+ {
+ const std::string word = text.substr(spacePos + 1);
+ const int length = getFont()->getWidth(word);
+
+ if (length > mMinWidth)
+ mMinWidth = length;
+ }
+
+ do
+ {
+ // Determine next piece of string to wrap
+ newlinePos = text.find("\n", lastNewlinePos);
+
+ if (newlinePos == std::string::npos)
+ newlinePos = text.size();
+
+ std::string line =
+ text.substr(lastNewlinePos, newlinePos - lastNewlinePos);
+ std::string::size_type lastSpacePos = 0;
+ xpos = 0;
+
+ do
+ {
+ spacePos = line.find(" ", lastSpacePos);
+
+ if (spacePos == std::string::npos)
+ spacePos = line.size();
+
+ std::string word =
+ line.substr(lastSpacePos, spacePos - lastSpacePos);
+
+ int width = getFont()->getWidth(word);
+
+ if (xpos != 0 && xpos + width + getFont()->getWidth(" ") <= mMinWidth)
+ {
+ xpos += width + getFont()->getWidth(" ");
+ wrappedStream << " " << word;
+ }
+ else if (lastSpacePos == 0)
+ {
+ xpos += width;
+ wrappedStream << word;
+ }
+ else
+ {
+ if (xpos > minWidth)
+ minWidth = xpos;
+
+ // The window wasn't big enough. Resize it and try again.
+ if (minWidth > mMinWidth)
+ {
+ mMinWidth = minWidth;
+ wrappedStream.clear();
+ wrappedStream.str("");
+ spacePos = 0;
+ lastNewlinePos = 0;
+ newlinePos = text.find("\n", lastNewlinePos);
+ if (newlinePos == std::string::npos)
+ newlinePos = text.size();
+ line = text.substr(lastNewlinePos, newlinePos -
+ lastNewlinePos);
+ width = 0;
+ break;
+ }
+ else
+ {
+ wrappedStream << "\n" << word;
+ }
+ xpos = width;
+ }
+ lastSpacePos = spacePos + 1;
+ }
+ while (spacePos != line.size());
+
+ if (text.find("\n", lastNewlinePos) != std::string::npos)
+ wrappedStream << "\n";
+
+ lastNewlinePos = newlinePos + 1;
+ }
+ while (newlinePos != text.size());
+
+ if (xpos > minWidth)
+ minWidth = xpos;
+
+ mMinWidth = minWidth;
+
+ gcn::TextBox::setText(wrappedStream.str());
+}
diff --git a/src/gui/widgets/textbox.h b/src/gui/widgets/textbox.h
new file mode 100644
index 00000000..5884e11c
--- /dev/null
+++ b/src/gui/widgets/textbox.h
@@ -0,0 +1,71 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TEXTBOX_H
+#define TEXTBOX_H
+
+#include <guichan/widgets/textbox.hpp>
+
+/**
+ * A text box, meant to be used inside a scroll area. Same as the Guichan text
+ * box except this one doesn't have a background or border, instead completely
+ * relying on the scroll area.
+ *
+ * \ingroup GUI
+ */
+class TextBox : public gcn::TextBox
+{
+ public:
+ /**
+ * Constructor.
+ */
+ TextBox();
+
+ inline void setTextColor(const gcn::Color* color)
+ {
+ mTextColor = color;
+ }
+
+ /**
+ * Sets the text after wrapping it to the current width of the widget.
+ */
+ void setTextWrapped(const std::string &text, int minDimension);
+
+ /**
+ * Get the minimum text width for the text box.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ /**
+ * Draws the text.
+ */
+ inline void draw(gcn::Graphics *graphics)
+ {
+ setForegroundColor(*mTextColor);
+ gcn::TextBox::draw(graphics);
+ }
+
+ private:
+ int mMinWidth;
+ const gcn::Color* mTextColor;
+};
+
+#endif
diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp
new file mode 100644
index 00000000..d830f8d4
--- /dev/null
+++ b/src/gui/widgets/textfield.cpp
@@ -0,0 +1,243 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/textfield.h"
+
+#include "gui/palette.h"
+#include "gui/sdlinput.h"
+
+#include "configuration.h"
+#include "graphics.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#include "utils/dtor.h"
+
+#include <guichan/font.hpp>
+
+#undef DELETE //Win32 compatibility hack
+
+int TextField::instances = 0;
+float TextField::mAlpha = 1.0;
+ImageRect TextField::skin;
+
+TextField::TextField(const std::string &text):
+ gcn::TextField(text),
+ mNumeric(false),
+ mListener(0)
+{
+ setFrameSize(2);
+
+ if (instances == 0)
+ {
+ // Load the skin
+ ResourceManager *resman = ResourceManager::getInstance();
+ Image *textbox = resman->getImage("graphics/gui/deepbox.png");
+ int gridx[4] = {0, 3, 28, 31};
+ int gridy[4] = {0, 3, 28, 31};
+ int a = 0, x, y;
+
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
+ skin.grid[a] = textbox->getSubImage(
+ gridx[x], gridy[y],
+ gridx[x + 1] - gridx[x] + 1,
+ gridy[y + 1] - gridy[y] + 1);
+ skin.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
+ a++;
+ }
+ }
+
+ textbox->decRef();
+ }
+
+ instances++;
+}
+
+TextField::~TextField()
+{
+ instances--;
+
+ if (instances == 0)
+ for_each(skin.grid, skin.grid + 9, dtor<Image*>());
+}
+
+void TextField::draw(gcn::Graphics *graphics)
+{
+ if (isFocused())
+ {
+ drawCaret(graphics,
+ getFont()->getWidth(mText.substr(0, mCaretPosition)) -
+ mXScroll);
+ }
+
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+ graphics->setFont(getFont());
+ graphics->drawText(mText, 1 - mXScroll, 1);
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ skin.grid[a]->setAlpha(mAlpha);
+ }
+}
+
+void TextField::drawFrame(gcn::Graphics *graphics)
+{
+ int w, h, bs;
+ bs = getFrameSize();
+ w = getWidth() + bs * 2;
+ h = getHeight() + bs * 2;
+
+ static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+}
+
+void TextField::setNumeric(bool numeric)
+{
+ mNumeric = numeric;
+ if (!numeric)
+ return;
+
+ const char *text = mText.c_str();
+ for (const char *textPtr = text; *textPtr; ++textPtr)
+ {
+ if (*textPtr < '0' || *textPtr > '9')
+ {
+ setText(mText.substr(0, textPtr - text));
+ return;
+ }
+ }
+}
+
+int TextField::getValue() const
+{
+ if (!mNumeric)
+ return 0;
+
+ int value = atoi(mText.c_str());
+ if (value < mMinimum)
+ return mMinimum;
+
+ if (value > mMaximum)
+ return mMaximum;
+
+ return value;
+}
+
+void TextField::keyPressed(gcn::KeyEvent &keyEvent)
+{
+ int val = keyEvent.getKey().getValue();
+
+ if (val >= 32)
+ {
+ int l;
+ if (val < 128) l = 1; // 0xxxxxxx
+ else if (val < 0x800) l = 2; // 110xxxxx 10xxxxxx
+ else if (val < 0x10000) l = 3; // 1110xxxx 10xxxxxx 10xxxxxx
+ else l = 4; // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+ char buf[4];
+ for (int i = 0; i < l; ++i)
+ {
+ buf[i] = val >> (6 * (l - i - 1));
+ if (i > 0) buf[i] = (buf[i] & 63) | 128;
+ }
+
+ if (l > 1) buf[0] |= 255 << (8 - l);
+
+ mText.insert(mCaretPosition, std::string(buf, buf + l));
+ mCaretPosition += l;
+ }
+
+ /* In UTF-8, 10xxxxxx is only used for inner parts of characters. So skip
+ them when processing key presses. */
+
+ switch (val)
+ {
+ case Key::LEFT:
+ {
+ while (mCaretPosition > 0)
+ {
+ --mCaretPosition;
+ if ((mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::RIGHT:
+ {
+ unsigned sz = mText.size();
+ while (mCaretPosition < sz)
+ {
+ ++mCaretPosition;
+ if (mCaretPosition == sz ||
+ (mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::DELETE:
+ {
+ unsigned sz = mText.size();
+ while (mCaretPosition < sz)
+ {
+ --sz;
+ mText.erase(mCaretPosition, 1);
+ if (mCaretPosition == sz ||
+ (mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::BACKSPACE:
+ {
+ while (mCaretPosition > 0)
+ {
+ --mCaretPosition;
+ int v = mText[mCaretPosition];
+ mText.erase(mCaretPosition, 1);
+ if ((v & 192) != 128) break;
+ }
+ } break;
+
+ case Key::ENTER:
+ distributeActionEvent();
+ break;
+
+ case Key::HOME:
+ mCaretPosition = 0;
+ break;
+
+ case Key::END:
+ mCaretPosition = mText.size();
+ break;
+
+ case Key::TAB:
+ return;
+ }
+
+ keyEvent.consume();
+ fixScroll();
+}
diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h
new file mode 100644
index 00000000..070d86ae
--- /dev/null
+++ b/src/gui/widgets/textfield.h
@@ -0,0 +1,109 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TEXTFIELD_H
+#define TEXTFIELD_H
+
+#include <guichan/widgets/textfield.hpp>
+
+class ImageRect;
+class TextField;
+
+class TextFieldListener
+{
+ public:
+ virtual void listen(const TextField *value) = 0;
+};
+
+/**
+ * A text field.
+ *
+ * \ingroup GUI
+ */
+class TextField : public gcn::TextField
+{
+ public:
+ /**
+ * Constructor, initializes the text field with the given string.
+ */
+ TextField(const std::string &text = "");
+
+ /**
+ * Destructor.
+ */
+ ~TextField();
+
+ /**
+ * Draws the text field.
+ */
+ virtual void draw(gcn::Graphics *graphics);
+
+ /**
+ * Draws the background and border.
+ */
+ void drawFrame(gcn::Graphics *graphics);
+
+ /**
+ * Determine whether the field should be numeric or not
+ */
+ void setNumeric(bool numeric);
+
+ /**
+ * Set the range on the field if it is numeric
+ */
+ void setRange(int min, int max) {mMinimum = min; mMaximum = max; }
+
+ /**
+ * Processes one keypress.
+ */
+ void keyPressed(gcn::KeyEvent &keyEvent);
+
+ /**
+ * Set the minimum value for a range
+ */
+ void setMinimum(int min) {mMinimum = min; }
+
+ /**
+ * Set the maximum value for a range
+ */
+ void setMaximum(int max) {mMaximum = max; }
+
+ /**
+ * Return the value for a numeric field
+ */
+ int getValue() const;
+
+ /**
+ * Add a listener
+ */
+ void addListener(TextFieldListener *listener) {mListener = listener; }
+
+ private:
+ static int instances;
+ static float mAlpha;
+ static ImageRect skin;
+ bool mNumeric;
+ int mMinimum;
+ int mMaximum;
+ TextFieldListener *mListener;
+};
+
+#endif
diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp
new file mode 100644
index 00000000..0aadeb3e
--- /dev/null
+++ b/src/gui/widgets/window.cpp
@@ -0,0 +1,725 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/window.h"
+
+#include "gui/widgets/layout.h"
+#include "gui/widgets/resizegrip.h"
+#include "gui/widgets/windowcontainer.h"
+
+#include "gui/gui.h"
+#include "gui/palette.h"
+#include "gui/skin.h"
+
+#include "configuration.h"
+#include "log.h"
+
+#include "resources/image.h"
+
+#include <guichan/exception.hpp>
+
+int Window::instances = 0;
+int Window::mouseResize = 0;
+
+Window::Window(const std::string &caption, bool modal, Window *parent, const std::string &skin):
+ gcn::Window(caption),
+ mGrip(0),
+ mParent(parent),
+ mLayout(NULL),
+ mWindowName("window"),
+ mDefaultSkinPath(skin),
+ mShowTitle(true),
+ mModal(modal),
+ mCloseButton(false),
+ mStickyButton(false),
+ mSticky(false),
+ mMinWinWidth(100),
+ mMinWinHeight(40),
+ mMaxWinWidth(graphics->getWidth()),
+ mMaxWinHeight(graphics->getHeight())
+{
+ logger->log("Window::Window(\"%s\")", caption.c_str());
+
+ if (!windowContainer)
+ throw GCN_EXCEPTION("Window::Window(): no windowContainer set");
+
+ if (instances == 0)
+ skinLoader = new SkinLoader;
+
+ instances++;
+
+ setFrameSize(0);
+ setPadding(3);
+ setTitleBarHeight(20);
+
+ // Loads the skin
+ mSkin = skinLoader->load(skin, mDefaultSkinPath);
+
+ // Add this window to the window container
+ windowContainer->add(this);
+
+ if (mModal)
+ {
+ gui->setCursorType(Gui::CURSOR_POINTER);
+ requestModalFocus();
+ }
+
+ // Windows are invisible by default
+ setVisible(false);
+
+ addWidgetListener(this);
+}
+
+Window::~Window()
+{
+ logger->log("Window::~Window(\"%s\")", getCaption().c_str());
+
+ saveWindowState();
+
+ delete mLayout;
+
+ while (!mWidgets.empty())
+ {
+ gcn::Widget *w = mWidgets.front();
+ remove(w);
+ delete(w);
+ }
+
+ removeWidgetListener(this);
+
+ instances--;
+
+ mSkin->instances--;
+
+ if (instances == 0)
+ delete skinLoader;
+}
+
+void Window::setWindowContainer(WindowContainer *wc)
+{
+ windowContainer = wc;
+}
+
+void Window::draw(gcn::Graphics *graphics)
+{
+ Graphics *g = static_cast<Graphics*>(graphics);
+
+ g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
+
+ // Draw title
+ if (mShowTitle)
+ {
+ g->setColor(guiPalette->getColor(Palette::TEXT));
+ g->setFont(getFont());
+ g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT);
+ }
+
+ // Draw Close Button
+ if (mCloseButton)
+ {
+ g->drawImage(mSkin->getCloseImage(),
+ getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
+ getPadding());
+ }
+
+ // Draw Sticky Button
+ if (mStickyButton)
+ {
+ Image *button = mSkin->getStickyImage(mSticky);
+ int x = getWidth() - button->getWidth() - getPadding();
+ if (mCloseButton)
+ x -= mSkin->getCloseImage()->getWidth();
+
+ g->drawImage(button, x, getPadding());
+ }
+
+ drawChildren(graphics);
+}
+
+void Window::setContentSize(int width, int height)
+{
+ width = width + 2 * getPadding();
+ height = height + getPadding() + getTitleBarHeight();
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
+}
+
+void Window::setLocationRelativeTo(gcn::Widget *widget)
+{
+ int wx, wy;
+ int x, y;
+
+ widget->getAbsolutePosition(wx, wy);
+ getAbsolutePosition(x, y);
+
+ setPosition(getX() + (wx + (widget->getWidth() - getWidth()) / 2 - x),
+ getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y));
+}
+
+void Window::setLocationRelativeTo(ImageRect::ImagePosition position,
+ int offsetX, int offsetY)
+{
+ if (position == ImageRect::UPPER_LEFT)
+ {
+ }
+ else if (position == ImageRect::UPPER_CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ }
+ else if (position == ImageRect::UPPER_RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ }
+ else if (position == ImageRect::LEFT)
+ {
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::LOWER_LEFT)
+ {
+ offsetY += graphics->getHeight() - getHeight();
+ }
+ else if (position == ImageRect::LOWER_CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ offsetY += graphics->getHeight() - getHeight();
+ }
+ else if (position == ImageRect::LOWER_RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ offsetY += graphics->getHeight() - getHeight();
+ }
+
+ setPosition(offsetX, offsetY);
+}
+
+void Window::setMinWidth(int width)
+{
+ mMinWinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
+}
+
+void Window::setMinHeight(int height)
+{
+ mMinWinHeight = height > mSkin->getMinHeight() ?
+ height : mSkin->getMinHeight();
+}
+
+void Window::setMaxWidth(int width)
+{
+ mMaxWinWidth = width;
+}
+
+void Window::setMaxHeight(int height)
+{
+ mMaxWinHeight = height;
+}
+
+void Window::setResizable(bool r)
+{
+ if ((bool) mGrip == r) return;
+
+ if (r)
+ {
+ mGrip = new ResizeGrip;
+ mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x);
+ mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y);
+ add(mGrip);
+ }
+ else
+ {
+ remove(mGrip);
+ delete mGrip;
+ mGrip = 0;
+ }
+}
+
+void Window::widgetResized(const gcn::Event &event)
+{
+ const gcn::Rectangle area = getChildrenArea();
+
+ if (mGrip)
+ mGrip->setPosition(getWidth() - mGrip->getWidth() - area.x,
+ getHeight() - mGrip->getHeight() - area.y);
+
+ if (mLayout)
+ {
+ int w = area.width;
+ int h = area.height;
+ mLayout->reflow(w, h);
+ }
+}
+
+void Window::setCloseButton(bool flag)
+{
+ mCloseButton = flag;
+}
+
+bool Window::isResizable() const
+{
+ return mGrip;
+}
+
+void Window::setStickyButton(bool flag)
+{
+ mStickyButton = flag;
+}
+
+void Window::setSticky(bool sticky)
+{
+ mSticky = sticky;
+}
+
+void Window::setVisible(bool visible)
+{
+ setVisible(visible, false);
+}
+
+void Window::setVisible(bool visible, bool forceSticky)
+{
+ gcn::Window::setVisible((!forceSticky && isSticky()) || visible);
+}
+
+void Window::scheduleDelete()
+{
+ windowContainer->scheduleDelete(this);
+}
+
+void Window::mousePressed(gcn::MouseEvent &event)
+{
+ // Let Guichan move window to top and figure out title bar drag
+ gcn::Window::mousePressed(event);
+
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+ const int x = event.getX();
+ const int y = event.getY();
+
+ // Handle close button
+ if (mCloseButton)
+ {
+ gcn::Rectangle closeButtonRect(
+ getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
+ getPadding(),
+ mSkin->getCloseImage()->getWidth(),
+ mSkin->getCloseImage()->getHeight());
+
+ if (closeButtonRect.isPointInRect(x, y))
+ {
+ close();
+ }
+ }
+
+ // Handle sticky button
+ if (mStickyButton)
+ {
+ Image *button = mSkin->getStickyImage(mSticky);
+ int rx = getWidth() - button->getWidth() - getPadding();
+ if (mCloseButton)
+ rx -= mSkin->getCloseImage()->getWidth();
+ gcn::Rectangle stickyButtonRect(rx, getPadding(),
+ button->getWidth(), button->getHeight());
+
+ if (stickyButtonRect.isPointInRect(x, y))
+ {
+ setSticky(!isSticky());
+ }
+ }
+
+ // Handle window resizing
+ mouseResize = getResizeHandles(event);
+ }
+}
+
+void Window::close()
+{
+ setVisible(false);
+}
+
+void Window::mouseReleased(gcn::MouseEvent &event)
+{
+ if (mGrip && mouseResize)
+ {
+ mouseResize = 0;
+ gui->setCursorType(Gui::CURSOR_POINTER);
+ }
+
+ // This should be the responsibility of Guichan (and is from 0.8.0 on)
+ mMoved = false;
+}
+
+void Window::mouseExited(gcn::MouseEvent &event)
+{
+ if (mGrip && !mouseResize)
+ {
+ gui->setCursorType(Gui::CURSOR_POINTER);
+ }
+}
+
+void Window::mouseMoved(gcn::MouseEvent &event)
+{
+ int resizeHandles = getResizeHandles(event);
+
+ // Changes the custom mouse cursor based on it's current position.
+ switch (resizeHandles)
+ {
+ case BOTTOM | RIGHT:
+ gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_RIGHT);
+ break;
+ case BOTTOM | LEFT:
+ gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_LEFT);
+ break;
+ case BOTTOM:
+ gui->setCursorType(Gui::CURSOR_RESIZE_DOWN);
+ break;
+ case RIGHT:
+ case LEFT:
+ gui->setCursorType(Gui::CURSOR_RESIZE_ACROSS);
+ break;
+ default:
+ gui->setCursorType(Gui::CURSOR_POINTER);
+ }
+}
+
+void Window::mouseDragged(gcn::MouseEvent &event)
+{
+ // Let Guichan handle title bar drag
+ gcn::Window::mouseDragged(event);
+
+ // Keep guichan window inside screen when it may be moved
+ if (isMovable() && mMoved)
+ {
+ int newX = std::max(0, getX());
+ int newY = std::max(0, getY());
+ newX = std::min(graphics->getWidth() - getWidth(), newX);
+ newY = std::min(graphics->getHeight() - getHeight(), newY);
+ setPosition(newX, newY);
+ }
+
+ if (mouseResize && !mMoved)
+ {
+ const int dx = event.getX() - mDragOffsetX;
+ const int dy = event.getY() - mDragOffsetY;
+ gcn::Rectangle newDim = getDimension();
+
+ if (mouseResize & (TOP | BOTTOM))
+ {
+ int newHeight = newDim.height + ((mouseResize & TOP) ? -dy : dy);
+ newDim.height = std::min(mMaxWinHeight,
+ std::max(mMinWinHeight, newHeight));
+
+ if (mouseResize & TOP)
+ {
+ newDim.y -= newDim.height - getHeight();
+ }
+ }
+
+ if (mouseResize & (LEFT | RIGHT))
+ {
+ int newWidth = newDim.width + ((mouseResize & LEFT) ? -dx : dx);
+ newDim.width = std::min(mMaxWinWidth,
+ std::max(mMinWinWidth, newWidth));
+
+ if (mouseResize & LEFT)
+ {
+ newDim.x -= newDim.width - getWidth();
+ }
+ }
+
+ // Keep guichan window inside screen (supports resizing any side)
+ if (newDim.x < 0)
+ {
+ newDim.width += newDim.x;
+ newDim.x = 0;
+ }
+ if (newDim.y < 0)
+ {
+ newDim.height += newDim.y;
+ newDim.y = 0;
+ }
+ if (newDim.x + newDim.width > graphics->getWidth())
+ {
+ newDim.width = graphics->getWidth() - newDim.x;
+ }
+ if (newDim.y + newDim.height > graphics->getHeight())
+ {
+ newDim.height = graphics->getHeight() - newDim.y;
+ }
+
+ // Update mouse offset when dragging bottom or right border
+ if (mouseResize & BOTTOM)
+ {
+ mDragOffsetY += newDim.height - getHeight();
+ }
+ if (mouseResize & RIGHT)
+ {
+ mDragOffsetX += newDim.width - getWidth();
+ }
+
+ // Set the new window and content dimensions
+ setDimension(newDim);
+ }
+}
+
+void Window::loadWindowState()
+{
+ const std::string &name = mWindowName;
+ const std::string skinName = config.getValue(name + "Skin",
+ mSkin->getFilePath());
+ assert(!name.empty());
+
+ setPosition((int) config.getValue(name + "WinX", mDefaultX),
+ (int) config.getValue(name + "WinY", mDefaultY));
+
+ if (mCloseButton)
+ setVisible((bool) config.getValue(name + "Visible", false));
+
+ if (mStickyButton)
+ setSticky((bool) config.getValue(name + "Sticky", isSticky()));
+
+ if (skinName.compare(mSkin->getFilePath()) != 0)
+ {
+ mSkin->instances--;
+ mSkin = skinLoader->load(skinName, mDefaultSkinPath);
+ }
+
+ if (mGrip)
+ {
+ int width = (int) config.getValue(name + "WinWidth", mDefaultWidth);
+ int height = (int) config.getValue(name + "WinHeight", mDefaultHeight);
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
+ }
+ else
+ {
+ setSize(mDefaultWidth, mDefaultHeight);
+ }
+}
+
+void Window::saveWindowState()
+{
+ // Saving X, Y and Width and Height for resizables in the config
+ if (!mWindowName.empty() && mWindowName != "window")
+ {
+ config.setValue(mWindowName + "WinX", getX());
+ config.setValue(mWindowName + "WinY", getY());
+
+ if (mCloseButton)
+ config.setValue(mWindowName + "Visible", isVisible());
+
+ if (mStickyButton)
+ config.setValue(mWindowName + "Sticky", isSticky());
+
+ config.setValue(mWindowName + "Skin", mSkin->getFilePath());
+
+ if (mGrip)
+ {
+ if (getMinWidth() > getWidth())
+ setWidth(getMinWidth());
+ else if (getMaxWidth() < getWidth())
+ setWidth(getMaxWidth());
+ if (getMinHeight() > getHeight())
+ setHeight(getMinHeight());
+ else if (getMaxHeight() < getHeight())
+ setHeight(getMaxHeight());
+
+ config.setValue(mWindowName + "WinWidth", getWidth());
+ config.setValue(mWindowName + "WinHeight", getHeight());
+ }
+ }
+}
+
+void Window::setDefaultSize(int defaultX, int defaultY,
+ int defaultWidth, int defaultHeight)
+{
+ if (getMinWidth() > defaultWidth)
+ defaultWidth = getMinWidth();
+ else if (getMaxWidth() < defaultWidth)
+ defaultWidth = getMaxWidth();
+ if (getMinHeight() > defaultHeight)
+ defaultHeight = getMinHeight();
+ else if (getMaxHeight() < defaultHeight)
+ defaultHeight = getMaxHeight();
+
+ mDefaultX = defaultX;
+ mDefaultY = defaultY;
+ mDefaultWidth = defaultWidth;
+ mDefaultHeight = defaultHeight;
+}
+
+void Window::setDefaultSize()
+{
+ mDefaultX = getX();
+ mDefaultY = getY();
+ mDefaultWidth = getWidth();
+ mDefaultHeight = getHeight();
+}
+
+void Window::setDefaultSize(int defaultWidth, int defaultHeight,
+ ImageRect::ImagePosition position,
+ int offsetX, int offsetY)
+{
+ int x = 0, y = 0;
+
+ if (position == ImageRect::UPPER_LEFT)
+ {
+ }
+ else if (position == ImageRect::UPPER_CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ }
+ else if (position == ImageRect::UPPER_RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ }
+ else if (position == ImageRect::LEFT)
+ {
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::LOWER_LEFT)
+ {
+ y = graphics->getHeight() - defaultHeight;
+ }
+ else if (position == ImageRect::LOWER_CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ y = graphics->getHeight() - defaultHeight;
+ }
+ else if (position == ImageRect::LOWER_RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ y = graphics->getHeight() - defaultHeight;
+ }
+
+ mDefaultX = x - offsetX;
+ mDefaultY = y - offsetY;
+ mDefaultWidth = defaultWidth;
+ mDefaultHeight = defaultHeight;
+}
+
+void Window::resetToDefaultSize()
+{
+ setPosition(mDefaultX, mDefaultY);
+ setSize(mDefaultWidth, mDefaultHeight);
+ saveWindowState();
+}
+
+int Window::getResizeHandles(gcn::MouseEvent &event)
+{
+ int resizeHandles = 0;
+ const int y = event.getY();
+
+ if (mGrip && y > (int) mTitleBarHeight)
+ {
+ const int x = event.getX();
+
+ if (!getChildrenArea().isPointInRect(x, y) &&
+ event.getSource() == this)
+ {
+ resizeHandles |= (x > getWidth() - resizeBorderWidth) ? RIGHT :
+ (x < resizeBorderWidth) ? LEFT : 0;
+ resizeHandles |= (y > getHeight() - resizeBorderWidth) ? BOTTOM :
+ (y < resizeBorderWidth) ? TOP : 0;
+ }
+
+ if (event.getSource() == mGrip)
+ {
+ mDragOffsetX = x;
+ mDragOffsetY = y;
+ resizeHandles |= BOTTOM | RIGHT;
+ }
+ }
+
+ return resizeHandles;
+}
+
+int Window::getGuiAlpha()
+{
+ float alpha = config.getValue("guialpha", 0.8);
+ return (int) (alpha * 255.0f);
+}
+
+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);
+}
+
+void Window::center()
+{
+ setLocationRelativeTo(getParent());
+}
diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h
new file mode 100644
index 00000000..f53bc483
--- /dev/null
+++ b/src/gui/widgets/window.h
@@ -0,0 +1,363 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include "graphics.h"
+#include "guichanfwd.h"
+
+#include <guichan/widgetlistener.hpp>
+
+#include <guichan/widgets/window.hpp>
+
+class ContainerPlacer;
+class Layout;
+class LayoutCell;
+class ResizeGrip;
+class Skin;
+class SkinLoader;
+class WindowContainer;
+
+/**
+ * A window. This window can be dragged around and has a title bar. Windows are
+ * invisible by default.
+ *
+ * \ingroup GUI
+ */
+class Window : public gcn::Window, gcn::WidgetListener
+{
+ public:
+ /**
+ * Constructor. Initializes the title to the given text and hooks
+ * itself into the window container.
+ *
+ * @param caption The initial window title, "Window" by default.
+ * @param modal Block input to other windows.
+ * @param parent The parent window. This is the window standing above
+ * this one in the window hiearchy. When reordering,
+ * a window will never go below its parent window.
+ * @param skin The location where the window's skin XML can be found.
+ */
+ Window(const std::string &caption = "Window", bool modal = false,
+ Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml");
+
+ /**
+ * Destructor. Deletes all the added widgets.
+ */
+ ~Window();
+
+ /**
+ * Sets the window container to be used by new windows.
+ */
+ static void setWindowContainer(WindowContainer *windowContainer);
+
+ /**
+ * Draws the window.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Sets the size of this window.
+ */
+ void setContentSize(int width, int height);
+
+ /**
+ * Sets the location relative to the given widget.
+ */
+ void setLocationRelativeTo(gcn::Widget *widget);
+
+ /**
+ * Sets the location relative to the given enumerated position.
+ */
+ void setLocationRelativeTo(ImageRect::ImagePosition position,
+ int offsetX = 0, int offsetY = 0);
+
+ /**
+ * Sets whether or not the window can be resized.
+ */
+ void setResizable(bool resize);
+
+ /**
+ * Called whenever the widget changes size.
+ */
+ void widgetResized(const gcn::Event &event);
+
+ /**
+ * Sets whether or not the window has a close button.
+ */
+ void setCloseButton(bool flag);
+
+ /**
+ * Returns whether the window can be resized.
+ */
+ bool isResizable() const;
+
+ /**
+ * Sets the minimum width of the window.
+ */
+ void setMinWidth(int width);
+
+ int getMinWidth() const { return mMinWinWidth; }
+
+ /**
+ * Sets the minimum height of the window.
+ */
+ void setMinHeight(int height);
+
+ int getMinHeight() const { return mMinWinHeight; }
+
+ /**
+ * Sets the maximum width of the window.
+ */
+ void setMaxWidth(int width);
+
+ int getMaxWidth() const { return mMaxWinWidth; }
+
+ /**
+ * Sets the minimum height of the window.
+ */
+ void setMaxHeight(int height);
+
+ int getMaxHeight() const { return mMaxWinHeight; }
+
+ /**
+ * Sets flag to show a title or not.
+ */
+ void setShowTitle(bool flag) { mShowTitle = flag; }
+
+ /**
+ * Sets whether or not the window has a sticky button.
+ */
+ void setStickyButton(bool flag);
+
+ /**
+ * Sets whether the window is sticky. A sticky window will not have
+ * its visibility set to false on a general setVisible(false) call.
+ * Use this to set the default before you call loadWindowState().
+ */
+ void setSticky(bool sticky);
+
+ /**
+ * Returns whether the window is sticky.
+ */
+ bool isSticky() const { return mSticky; }
+
+ /**
+ * Overloads window setVisible by Guichan to allow sticky window
+ * handling.
+ */
+ void setVisible(bool visible);
+
+ /**
+ * Overloads window setVisible by Guichan to allow sticky window
+ * handling, or not, if you force the sticky state.
+ */
+ void setVisible(bool visible, bool forceSticky);
+
+ /**
+ * Returns the parent window.
+ *
+ * @return The parent window or <code>NULL</code> if there is none.
+ */
+ Window *getParentWindow() const { return mParent; }
+
+ /**
+ * Schedule this window for deletion. It will be deleted at the start
+ * of the next logic update.
+ */
+ void scheduleDelete();
+
+ /**
+ * Starts window resizing when appropriate.
+ */
+ void mousePressed(gcn::MouseEvent &event);
+
+ /**
+ * Implements window resizing and makes sure the window is not
+ * dragged/resized outside of the screen.
+ */
+ void mouseDragged(gcn::MouseEvent &event);
+
+ /**
+ * Implements custom cursor image changing context, based on mouse
+ * relative position.
+ */
+ void mouseMoved(gcn::MouseEvent &event);
+
+ /**
+ * When the mouse button has been let go, this ensures that the mouse
+ * custom cursor is restored back to it's standard image.
+ */
+ void mouseReleased(gcn::MouseEvent &event);
+
+ /**
+ * When the mouse leaves the window this ensures that the custom cursor
+ * is restored back to it's standard image.
+ */
+ void mouseExited(gcn::MouseEvent &event);
+
+ /**
+ * Sets the name of the window. This is not the window title.
+ */
+ void setWindowName(const std::string &name) { mWindowName = name; }
+
+ /**
+ * Returns the name of the window. This is not the window title.
+ */
+ const std::string &getWindowName() const { return mWindowName; }
+
+ /**
+ * Reads the position (and the size for resizable windows) in the
+ * configuration based on the given string.
+ * Uses the default values when config values are missing.
+ * Don't forget to set these default values and resizable before
+ * calling this function.
+ */
+ void loadWindowState();
+
+ /**
+ * Saves the window state so that when the window is reloaded, it'll
+ * maintain its previous state and location.
+ */
+ void saveWindowState();
+
+ /**
+ * Set the default win pos and size.
+ * (which can be different of the actual ones.)
+ */
+ void setDefaultSize(int defaultX, int defaultY,
+ int defaultWidth, int defaultHeight);
+
+ /**
+ * Set the default win pos and size tot he current ones.
+ */
+ void setDefaultSize();
+
+ /**
+ * Set the default win pos and size.
+ * (which can be different of the actual ones.)
+ * This version of setDefaultSize sets the window's position based
+ * on a relative enumerated position, rather than a coordinate position.
+ */
+ void setDefaultSize(int defaultWidth, int defaultHeight,
+ ImageRect::ImagePosition position,
+ int offsetx = 0, int offsetY = 0);
+
+ /**
+ * Reset the win pos and size to default. Don't forget to set defaults
+ * first.
+ */
+ virtual 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);
+
+ /**
+ * Positions the window in the center of it's parent.
+ */
+ void center();
+
+ /**
+ * Overrideable functionality for when the window is to close. This
+ * allows for class implementations to clean up or do certain actions
+ * on window close they couldn't do otherwise.
+ */
+ virtual void close();
+
+ /**
+ * Gets the alpha value used by the window, in a GUIChan usable format.
+ */
+ int getGuiAlpha();
+
+ private:
+ enum ResizeHandles
+ {
+ TOP = 0x01,
+ RIGHT = 0x02,
+ BOTTOM = 0x04,
+ LEFT = 0x08
+ };
+
+ /**
+ * Determines if the mouse is in a resize area and returns appropriate
+ * resize handles. Also initializes drag offset in case the resize
+ * grip is used.
+ *
+ * @see ResizeHandles
+ */
+ int getResizeHandles(gcn::MouseEvent &event);
+
+ ResizeGrip *mGrip; /**< Resize grip */
+ Window *mParent; /**< The parent window */
+ Layout *mLayout; /**< Layout handler */
+ std::string mWindowName; /**< Name of the window */
+ std::string mDefaultSkinPath; /**< Default skin path for this window */
+ bool mShowTitle; /**< Window has a title bar */
+ bool mModal; /**< Window is modal */
+ bool mCloseButton; /**< Window has a close button */
+ bool mStickyButton; /**< Window has a sticky button */
+ bool mSticky; /**< Window resists hiding*/
+ int mMinWinWidth; /**< Minimum window width */
+ int mMinWinHeight; /**< Minimum window height */
+ int mMaxWinWidth; /**< Maximum window width */
+ int mMaxWinHeight; /**< Maximum window height */
+ int mDefaultX; /**< Default window X position */
+ int mDefaultY; /**< Default window Y position */
+ int mDefaultWidth; /**< Default window width */
+ int mDefaultHeight; /**< Default window height */
+
+ static int mouseResize; /**< Active resize handles */
+ static int instances; /**< Number of Window instances */
+
+ Skin* mSkin; /**< Skin in use by this window */
+
+ /**
+ * The width of the resize border. Is independent of the actual window
+ * border width, and determines mostly the size of the corner area
+ * where two borders are moved at the same time.
+ */
+ static const int resizeBorderWidth = 10;
+};
+
+#endif
diff --git a/src/gui/widgets/windowcontainer.cpp b/src/gui/widgets/windowcontainer.cpp
new file mode 100644
index 00000000..d03e4fa4
--- /dev/null
+++ b/src/gui/widgets/windowcontainer.cpp
@@ -0,0 +1,39 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "gui/widgets/windowcontainer.h"
+
+#include "utils/dtor.h"
+
+WindowContainer *windowContainer = NULL;
+
+void WindowContainer::logic()
+{
+ delete_all(mDeathList);
+ mDeathList.clear();
+
+ gcn::Container::logic();
+}
+
+void WindowContainer::scheduleDelete(gcn::Widget *widget)
+{
+ mDeathList.push_back(widget);
+}
diff --git a/src/gui/widgets/windowcontainer.h b/src/gui/widgets/windowcontainer.h
new file mode 100644
index 00000000..bc918184
--- /dev/null
+++ b/src/gui/widgets/windowcontainer.h
@@ -0,0 +1,64 @@
+/*
+ * The Mana World
+ * Copyright (C) 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef WINDOWCONTAINER_H
+#define WINDOWCONTAINER_H
+
+#include <guichan/widgets/container.hpp>
+
+/**
+ * A window container. This container adds functionality for more convenient
+ * widget (windows in particular) destruction.
+ *
+ * \ingroup GUI
+ */
+class WindowContainer : public gcn::Container
+{
+ public:
+ /**
+ * Do GUI logic. This functions adds automatic deletion of objects that
+ * volunteered to be deleted.
+ */
+ void logic();
+
+ /**
+ * Schedule a widget for deletion. It will be deleted at the start of
+ * the next logic update.
+ */
+ void scheduleDelete(gcn::Widget *widget);
+
+ /**
+ * Get the number of widget instances
+ */
+ int getNumberOfInstances() { return mDeathList.size(); }
+
+ private:
+ /**
+ * List of widgets that are scheduled to be deleted.
+ */
+ typedef std::list<gcn::Widget*> Widgets;
+ typedef Widgets::iterator WidgetIterator;
+ Widgets mDeathList;
+};
+
+extern WindowContainer* windowContainer;
+
+#endif