diff options
author | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-04-07 23:47:57 +0200 |
---|---|---|
committer | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2009-04-07 23:52:46 +0200 |
commit | d69d85f06fa6dc22ac4c7789e4140e32d119a7f1 (patch) | |
tree | 1d2311bfdba616136d0ac26f8cbe9ab73c88f0e4 /src/gui/widgets | |
parent | 303c1f69761e90b83d4809e911f7785ec66b46aa (diff) | |
download | mana-client-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.gz mana-client-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.bz2 mana-client-d69d85f06fa6dc22ac4c7789e4140e32d119a7f1.tar.xz mana-client-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')
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 |