From 50b0f0e7ea4508e1ee30f0a0ea8741af6d3212d4 Mon Sep 17 00:00:00 2001 From: José Ávila Date: Fri, 17 Jun 2005 07:14:23 +0000 Subject: new BrowserBox widget with colors/links support --- src/gui/browserbox.cpp | 318 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gui/browserbox.h | 147 +++++++++++++++++++++++ src/gui/linkhandler.h | 42 +++++++ src/gui/popupmenu.cpp | 213 +++++++++++++++++++++++++++++++++ src/gui/popupmenu.h | 78 ++++++++++++ 5 files changed, 798 insertions(+) create mode 100644 src/gui/browserbox.cpp create mode 100644 src/gui/browserbox.h create mode 100644 src/gui/linkhandler.h create mode 100644 src/gui/popupmenu.cpp create mode 100644 src/gui/popupmenu.h (limited to 'src/gui') diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp new file mode 100644 index 00000000..06094139 --- /dev/null +++ b/src/gui/browserbox.cpp @@ -0,0 +1,318 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "browserbox.h" + +int BrowserBox::instances = 0; +gcn::ImageFont* BrowserBox::browserFont; + +BrowserBox::BrowserBox(unsigned int mode): + gcn::Widget() +{ + mMode = mode; + setOpaque(true); + setHighlightMode(BOTH); + mSelectedLink = -1; + setFocusable(true); + addMouseListener(this); + + if (instances == 0) + { + browserFont = new gcn::ImageFont( + TMW_DATADIR "data/graphics/gui/browserfont.png", + " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567" + "89:@!\"$%&/=?^+*#[]{}()<>_;'.,\\|-~`"); + } + instances++; +} + +BrowserBox::~BrowserBox() +{ + instances--; + if (instances == 0) + { + // Clean up static resource font + delete browserFont; + } +} + +void BrowserBox::setLinkHandler(LinkHandler* linkHandler) +{ + mLinkHandler = linkHandler; +} + +void BrowserBox::setOpaque(bool opaque) +{ + mOpaque = opaque; +} + +void BrowserBox::setHighlightMode(unsigned int highMode) +{ + mHighMode = highMode; +} + +void BrowserBox::addRow(const std::string& row) +{ + std::string tmp = row; + std::string newRow; + BROWSER_LINK bLink; + int idx1, idx2, idx3; + + // 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() * browserFont->getHeight(); + bLink.y2 = bLink.y1 + browserFont->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 = browserFont->getWidth(tmp2) - 1; + bLink.x2 = bLink.x1 + browserFont->getWidth(bLink.caption) + 1; + + mLinks.push_back(bLink); + + newRow += "##L" + bLink.caption; + + tmp.erase(0, idx3 + 2); + if(tmp != "") + { + newRow += "##P"; + } + idx1 = tmp.find("@@"); + } + + newRow += tmp; + mTextRows.push_back(newRow); + + // 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 = browserFont->getWidth(plain); + if (w > getWidth()) + setWidth(w); + } + setHeight(browserFont->getHeight() * mTextRows.size()); +} + +void BrowserBox::clearRows() +{ + mTextRows.clear(); + mLinks.clear(); + setWidth(0); + mSelectedLink = -1; +} + +void BrowserBox::mousePress(int mx, int my, int button) +{ + if ((button == gcn::MouseInput::LEFT) && mLinkHandler) + { + for (unsigned int i = 0; i < mLinks.size(); i++) + { + if ((mx >= mLinks[i].x1) && (mx < mLinks[i].x2) && + (my > mLinks[i].y1) && (my < mLinks[i].y2)) + { + mLinkHandler->handleLink(mLinks[i].link); + return; + } + } + } +} + +void BrowserBox::mouseMotion(int mx, int my) +{ + for (unsigned int i = 0; i < mLinks.size(); i++) + { + if ((mx >= mLinks[i].x1) && (mx < mLinks[i].x2) && + (my > mLinks[i].y1) && (my < mLinks[i].y2)) + { + mSelectedLink = (int) i; + return; + } + else + { + mSelectedLink = -1; + } + } +} + +void BrowserBox::draw(gcn::Graphics* graphics) +{ + if (mOpaque) + { + graphics->setColor(gcn::Color(BGCOLOR)); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); + } + + if (mSelectedLink >= 0) + { + if ((mHighMode == BACKGROUND) || (mHighMode == BOTH)) + { + graphics->setColor(gcn::Color(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) || (mHighMode == BOTH)) + { + graphics->setColor(gcn::Color(LINK)); + graphics->drawLine( + mLinks[mSelectedLink].x1, + mLinks[mSelectedLink].y2, + mLinks[mSelectedLink].x2, + mLinks[mSelectedLink].y2); + } + } + + unsigned int i, j; + int x = 0, y = 0; + int wrappedLines = 0; + for (i = 0; i < mTextRows.size(); i++) + { + int selColor = BLACK; + int prevColor = selColor; + std::string row = mTextRows[i]; + x = 0; + + for (j = 0; j < row.size(); j++) + { + // Check for color change in format "##x", x = [L,P,0..9] + if ((row.at(j) == '#') && (row.at(j + 1) == '#')) + { + switch (row.at(j + 2)) + { + case 'L': // Link color + prevColor = selColor; + selColor = LINK; + break; + case 'P': // Previous color + selColor = prevColor; + break; + case '1': + prevColor = selColor; + selColor = RED; + break; + case '2': + prevColor = selColor; + selColor = GREEN; + break; + case '3': + prevColor = selColor; + selColor = BLUE; + break; + case '4': + prevColor = selColor; + selColor = ORANGE; + break; + case '5': + prevColor = selColor; + selColor = YELLOW; + break; + case '6': + prevColor = selColor; + selColor = PINK; + break; + case '7': + prevColor = selColor; + selColor = PURPLE; + break; + case '8': + prevColor = selColor; + selColor = GRAY; + break; + case '9': + prevColor = selColor; + selColor = BROWN; + break; + case '0': + default: + prevColor = selColor; + selColor = BLACK; + } + j += 3; + + if (j == row.size()) + { + break; + } + } + graphics->setColor(gcn::Color(selColor)); + + // Check for line separators in format "---" + if ((j <= 3) && (row.at(j) == '-') && (row.at(j + 1) == '-') && + (row.at(j + 2) == '-')) + { + for (x = 0; x < getWidth(); x++) + { + browserFont->drawGlyph(graphics, '-', x, y); + x += browserFont->getWidth('-') - 2; + } + break; + } + // Draw each char + else + { + browserFont->drawGlyph(graphics, row.at(j), x, y); + x += browserFont->getWidth(row.at(j)); + + // Auto wrap mode + if (mMode == AUTO_WRAP) + { + /** NOTE (by Javila): this is just a simple example and + * will force text wrap at widget width!!! + * Maybe it can need improvements. + */ + if ((x + 2 * browserFont->getWidth('~')) > getWidth()) + { + browserFont->drawGlyph(graphics, '~', + getWidth() - browserFont->getWidth('~'), y); + x = 15; // Ident in new line + y += browserFont->getHeight(); + wrappedLines++; + } + } + } + } + y += browserFont->getHeight(); + setHeight((mTextRows.size() + wrappedLines) * browserFont->getHeight()); + } +} diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h new file mode 100644 index 00000000..8ac5a54c --- /dev/null +++ b/src/gui/browserbox.h @@ -0,0 +1,147 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef __TMW_BROWSERBOX_H__ +#define __TMW_BROWSERBOX_H__ + +#include +#include "window.h" +#include "linkhandler.h" + +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); + + /** + * 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); + + /** + * Adds a text row to the browser. + */ + void addRow(const std::string& row); + + /** + * Remove all rows. + */ + void clearRows(); + + /** + * Handles mouse actions. + */ + void mousePress(int mx, int my, int button); + void mouseMotion(int mx, int my); + + /** + * 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 = 0x1fa052, /**< 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. + */ + enum { + UNDERLINE, + BACKGROUND, + BOTH + }; + + private: + std::vector mTextRows; + std::vector mLinks; + LinkHandler *mLinkHandler; + unsigned int mMode; + unsigned int mHighMode; + bool mOpaque; + int mSelectedLink; + + static int instances; /**< Number of Window instances */ + static gcn::ImageFont* browserFont; +}; + +#endif diff --git a/src/gui/linkhandler.h b/src/gui/linkhandler.h new file mode 100644 index 00000000..05a0a99b --- /dev/null +++ b/src/gui/linkhandler.h @@ -0,0 +1,42 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_LINK_HANDLER_H +#define _TMW_LINK_HANDLER_H + +/** + * A simple interface to windows that need to handle links from BrowserBox + * widget. + */ +class LinkHandler +{ + public: + virtual ~LinkHandler() { } + + virtual void handleLink(const std::string& link) { } + + protected: + LinkHandler() { } +}; + +#endif diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp new file mode 100644 index 00000000..c56bdfc8 --- /dev/null +++ b/src/gui/popupmenu.cpp @@ -0,0 +1,213 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "popupmenu.h" +#include "../graphics.h" +#include "../engine.h" +#include "../game.h" +#include + +PopupMenu::PopupMenu(): + Window() +{ + setResizable(false); + setTitleBarHeight(0); + + browserBox = new BrowserBox(); + browserBox->setPosition(4, 4); + browserBox->setHighlightMode(BrowserBox::BACKGROUND); + browserBox->setOpaque(false); + add(browserBox); + browserBox->setLinkHandler(this); + + being = NULL; + floorItem = NULL; + mX = -1; + mY = -1; +} + +PopupMenu::~PopupMenu() +{ + delete browserBox; + delete being; + delete floorItem; +} + +void PopupMenu::setVisible(bool visible) +{ + if (visible == false) + { + if (hasFocus()) + { + mFocusHandler->focusNone(); + } + setPosition(screen->w, screen->h); + } + + mVisible = visible; +} + +void PopupMenu::showPopup(int mx, int my) +{ + being = findNode(mx, my); + floorItem = find_floor_item_by_id(find_floor_item_by_cor(mx, my)); + mX = mx; + mY = mY; + browserBox->clearRows(); + + if (being) + { + if (being->isMonster()) + { + browserBox->addRow("@@attack|Attack Monster@@"); + } + else if (being->isNpc()) + { + browserBox->addRow("@@talk|Talk To NPC@@"); + } + else if (being->isPlayer()) + { + std::string name = being->name; + //browserBox->addRow("@@attack|Attack " + name + "@@"); + browserBox->addRow("@@trade|Trade With " + name + "@@"); + browserBox->addRow("@@follow|Follow " + name + "@@"); + browserBox->addRow("@@buddy|Add " + name + " to Buddy List@@"); + } + } + else if (floorItem) + { + std::string name = itemDb->getItemInfo(floorItem->id)->getName(); + browserBox->addRow("@@pickup|Pick Up " + name + "@@"); + } + else + { + browserBox->addRow("@@walk|Walk To@@"); + } + //browserBox->addRow("@@look|Look To@@"); + browserBox->addRow("##3---"); + browserBox->addRow("@@cancel|Cancel@@"); + + setContentSize(browserBox->getWidth() + 8, browserBox->getHeight() + 8); + mx = (mx - camera_x) * 32 + 25; + my = (my - camera_y) * 32 + 25; + if (screen->w < (mx + getWidth() + 5)) + mx -= (getWidth() + 50); + if (screen->h < (my + getHeight() + 5)) + my -= (getHeight() + 50); + setPosition(mx, my); + setVisible(true); +} + +void PopupMenu::draw(gcn::Graphics* graphics) +{ + int x, y; + getAbsolutePosition(x, y); + + ((Graphics*) graphics)->drawImageRect(x, y, getWidth(), getHeight(), + border); + + if (mContent != NULL) + { + graphics->pushClipArea(getContentDimension()); + graphics->pushClipArea(gcn::Rectangle( + 0, 0, mContent->getWidth(), mContent->getHeight())); + mContent->draw(graphics); + graphics->popClipArea(); + graphics->popClipArea(); + } +} + +void PopupMenu::handleLink(const std::string& link) +{ + // Attack action + if ((link == "attack") && being) + { + if (being->isMonster() && (being->action != MONSTER_DEAD)) + { + autoTarget = being; + attack(being); + } + } + + // Talk To action + else if ((link == "talk") && being && being->isNpc() && + (current_npc == 0)) + { + WFIFOW(0) = net_w_value(0x0090); + WFIFOL(2) = net_l_value(being->id); + WFIFOB(6) = 0; + WFIFOSET(7); + current_npc = being->id; + } + + // Trade action + else if ((link == "trade") && being && being->isPlayer()) + { + WFIFOW(0) = net_w_value(0x00e4); + WFIFOL(2) = net_l_value(being->id); + WFIFOSET(6); + } + + // Follow Player action + else if (link == "follow") + { + } + + // Add Buddy action + else if (link == "buddy") + { + } + + // Pick Up Floor Item action + else if ((link == "pickup") && floorItem) + { + WFIFOW(0) = net_w_value(0x009f); + WFIFOL(2) = net_l_value(floorItem->int_id); + WFIFOSET(6); + } + + // Walk To action + else if ((link == "walk") && (mX != -1) && (mY != -1)) + { + //walk(mX, mY, 0); + //player_node->setDestination(mX, mY); + } + + // Look To action + else if (link == "look") + { + } + + // Unknown actions + else + { + std::cout << link << std::endl; + } + + setVisible(false); + + being = NULL; + floorItem = NULL; + mX = -1; + mY = -1; +} diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h new file mode 100644 index 00000000..77c8931a --- /dev/null +++ b/src/gui/popupmenu.h @@ -0,0 +1,78 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_POPUP_MENU_H +#define _TMW_POPUP_MENU_H + +#include +#include "window.h" +#include "linkhandler.h" +#include "browserbox.h" +#include "../being.h" +#include "../floor_item.h" + +/** + * Window showing popup menu. + */ +class PopupMenu : public Window, public LinkHandler +{ + public: + /** + * Constructor. + */ + PopupMenu(); + + /** + * Destructor. + */ + ~PopupMenu(); + + /** + * Sets the visibility of popup + */ + void setVisible(bool visible); + + /** + * Shows the related popup menu specifies by the mouse click coords. + */ + void showPopup(int mx, int my); + + /** + * Draws updated popup menu + */ + void draw(gcn::Graphics* graphics); + + /** + * Handles link action. + */ + void handleLink(const std::string& link); + + private: + BrowserBox* browserBox; + int mX, mY; + + Being* being; + FloorItem* floorItem; +}; + +#endif -- cgit v1.2.3-70-g09d2