diff options
Diffstat (limited to 'src/gui')
146 files changed, 6029 insertions, 2073 deletions
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp index 2d805b9c..a06b9a6e 100644 --- a/src/gui/browserbox.cpp +++ b/src/gui/browserbox.cpp @@ -21,15 +21,17 @@ #include <algorithm> -#include "browserbox.h" +#include <guichan/graphics.hpp> +#include "browserbox.h" +#include "color.h" #include "linkhandler.h" #include "truetypefont.h" -BrowserBox::BrowserBox(unsigned int mode): +BrowserBox::BrowserBox(unsigned int mode, bool opaque): gcn::Widget(), mMode(mode), mHighMode(UNDERLINE | BACKGROUND), - mOpaque(true), + mOpaque(opaque), mUseLinksAndUserColors(true), mSelectedLink(-1), mMaxRows(0) @@ -98,12 +100,12 @@ void BrowserBox::addRow(const std::string &row) mLinks.push_back(bLink); - newRow += "##L" + bLink.caption; + newRow += "##<" + bLink.caption; tmp.erase(0, idx3 + 2); - if(tmp != "") + if (!tmp.empty()) { - newRow += "##P"; + newRow += "##>"; } idx1 = tmp.find("@@"); } @@ -122,7 +124,18 @@ void BrowserBox::addRow(const std::string &row) //discard older rows when a row limit has been set if (mMaxRows > 0) { - while (mTextRows.size() > mMaxRows) mTextRows.pop_front(); + 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 @@ -210,8 +223,7 @@ struct MouseOverLink int mX, mY; }; -void -BrowserBox::mousePressed(gcn::MouseEvent &event) +void BrowserBox::mousePressed(gcn::MouseEvent &event) { LinkIterator i = find_if(mLinks.begin(), mLinks.end(), MouseOverLink(event.getX(), event.getY())); @@ -221,8 +233,7 @@ BrowserBox::mousePressed(gcn::MouseEvent &event) } } -void -BrowserBox::mouseMoved(gcn::MouseEvent &event) +void BrowserBox::mouseMoved(gcn::MouseEvent &event) { LinkIterator i = find_if(mLinks.begin(), mLinks.end(), MouseOverLink(event.getX(), event.getY())); @@ -230,8 +241,7 @@ BrowserBox::mouseMoved(gcn::MouseEvent &event) mSelectedLink = (i != mLinks.end()) ? (i - mLinks.begin()) : -1; } -void -BrowserBox::draw(gcn::Graphics *graphics) +void BrowserBox::draw(gcn::Graphics *graphics) { if (mOpaque) { @@ -241,9 +251,10 @@ BrowserBox::draw(gcn::Graphics *graphics) if (mSelectedLink >= 0) { + bool valid; if ((mHighMode & BACKGROUND)) { - graphics->setColor(gcn::Color(HIGHLIGHT)); + graphics->setColor(gcn::Color(textColor->getColor('H', valid))); graphics->fillRectangle(gcn::Rectangle( mLinks[mSelectedLink].x1, mLinks[mSelectedLink].y1, @@ -254,7 +265,7 @@ BrowserBox::draw(gcn::Graphics *graphics) if ((mHighMode & UNDERLINE)) { - graphics->setColor(gcn::Color(LINK)); + graphics->setColor(gcn::Color(textColor->getColor('<', valid))); graphics->drawLine( mLinks[mSelectedLink].x1, mLinks[mSelectedLink].y2, @@ -265,6 +276,7 @@ BrowserBox::draw(gcn::Graphics *graphics) int x = 0, y = 0; int wrappedLines = 0; + int link = 0; TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont()); graphics->setColor(BLACK); @@ -311,57 +323,36 @@ BrowserBox::draw(gcn::Graphics *graphics) // Check for color change in format "##x", x = [L,P,0..9] if (row.find("##", start) == start && row.size() > start + 2) { - switch (row.at(start + 2)) + char c = row.at(start + 2); + if (c == '>') { - 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: + selColor = prevColor; + } + else + { + bool valid; + int rgb = textColor->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; - selColor = BLACK; + } + if (valid) + { + selColor = rgb; + } } start += 3; + + if (start == row.size()) + { + break; + } } graphics->setColor(gcn::Color(selColor)); } @@ -424,3 +415,4 @@ BrowserBox::draw(gcn::Graphics *graphics) setHeight((mTextRows.size() + wrappedLines) * font->getHeight()); } } + diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h index 4dc41e3d..5dde402e 100644 --- a/src/gui/browserbox.h +++ b/src/gui/browserbox.h @@ -22,15 +22,12 @@ #ifndef BROWSERBOX_H #define BROWSERBOX_H -#include <iosfwd> +#include <list> #include <vector> #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> -#include "../guichanfwd.h" -#include "../main.h" - class LinkHandler; struct BROWSER_LINK { @@ -49,7 +46,7 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener /** * Constructor. */ - BrowserBox(unsigned int mode = AUTO_SIZE); + BrowserBox(unsigned int mode = AUTO_SIZE, bool opaque = true); /** * Destructor. @@ -165,3 +162,4 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener }; #endif + diff --git a/src/gui/buddywindow.cpp b/src/gui/buddywindow.cpp deleted file mode 100644 index 0927ddf8..00000000 --- a/src/gui/buddywindow.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 "buddywindow.h" - -#include <guichan/widgets/listbox.hpp> - -#include "button.h" -#include "chat.h" -#include "scrollarea.h" - -#include "../resources/buddylist.h" - -extern ChatWindow *chatWindow; - -BuddyWindow::BuddyWindow(): - Window("Buddy") -{ - setContentSize(124, 202); - - mBuddyList = new BuddyList(); - - mListbox = new gcn::ListBox(); - mListbox->setListModel(mBuddyList); - - ScrollArea *scrollArea = new ScrollArea(mListbox); - scrollArea->setDimension(gcn::Rectangle( - 7, 5, 110, 170)); - add(scrollArea); - - Button *talk = new Button("Talk", "Talk", this); - Button *remove = new Button("Remove", "Remove", this); - Button *cancel = new Button("Cancel", "Cancel", this); - - talk->setPosition(2,180); - remove->setPosition(talk->getWidth()+2,180); - cancel->setPosition(talk->getWidth()+remove->getWidth()+2,180); - - add(talk); - add(remove); - add(cancel); -} - -void BuddyWindow::action(const gcn::ActionEvent &event) -{ - if (event.getId() == "Talk") { - int selected = mListbox->getSelected(); - if ( selected > -1 ) - { - std::string who = mBuddyList->getElementAt(selected); - chatWindow->setInputText(who +": "); - } - } - else if (event.getId() == "Remove") { - int selected = mListbox->getSelected(); - if ( selected > -1 ) - { - std::string who = mBuddyList->getElementAt(selected); - mBuddyList->removeBuddy(who); - } - } - else if (event.getId() == "Cancel") { - setVisible(false); - } -} diff --git a/src/gui/button.cpp b/src/gui/button.cpp index caf93b94..1d3a04e4 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -19,8 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/exception.hpp> +#include <guichan/font.hpp> + #include "button.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -28,13 +32,8 @@ #include "../utils/dtor.h" -#include <guichan/exception.hpp> -#include <guichan/graphics.hpp> -#include <guichan/font.hpp> - -#include <algorithm> - int Button::mInstances = 0; +float Button::mAlpha = config.getValue("guialpha", 0.8); enum{ BUTTON_STANDARD, // 0 @@ -100,6 +99,7 @@ void Button::init() 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++; } } @@ -122,22 +122,29 @@ Button::~Button() } } -void -Button::draw(gcn::Graphics *graphics) +void Button::draw(gcn::Graphics *graphics) { int mode; - if (!isEnabled()) { + if (!isEnabled()) mode = BUTTON_DISABLED; - } - else if (isPressed() || mIsLogged) { + else if (isPressed() || mIsLogged) mode = BUTTON_PRESSED; - } - else if (mHasMouse || isFocused()) { + else if (mHasMouse || isFocused()) mode = BUTTON_HIGHLIGHTED; - } - else { + 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)-> @@ -148,7 +155,8 @@ Button::draw(gcn::Graphics *graphics) int textX; int textY = getHeight() / 2 - getFont()->getHeight() / 2; - switch (getAlignment()) { + switch (getAlignment()) + { case gcn::Graphics::LEFT: textX = 4; break; @@ -164,10 +172,8 @@ Button::draw(gcn::Graphics *graphics) graphics->setFont(getFont()); - if (isPressed()) { + if (isPressed()) graphics->drawText(getCaption(), textX + 1, textY + 1, getAlignment()); - } - else { + else graphics->drawText(getCaption(), textX, textY, getAlignment()); - } } diff --git a/src/gui/button.h b/src/gui/button.h index 0ec99245..abaf5c43 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -22,8 +22,6 @@ #ifndef BUTTON_H #define BUTTON_H -#include <iosfwd> - #include <guichan/widgets/button.hpp> class ImageRect; @@ -69,6 +67,7 @@ class Button : public gcn::Button static ImageRect button[4]; /**< Button state graphics */ static int mInstances; /**< Number of button instances */ + static float mAlpha; bool mIsLogged; /**< Makes the button appear pressed all the time */ }; diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index 49dd52af..0c8c4d9d 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -19,11 +19,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "buy.h" - #include <guichan/widgets/label.hpp> #include "button.h" +#include "buy.h" #include "scrollarea.h" #include "shop.h" #include "shoplistbox.h" @@ -43,7 +42,7 @@ BuyDialog::BuyDialog(Network *network): Window(_("Buy")), mNetwork(network), mMoney(0), mAmountItems(0), mMaxItems(0) { - setWindowName("Buy"); + setWindowName(_("Buy")); setResizable(true); setMinWidth(260); setMinHeight(230); diff --git a/src/gui/buy.h b/src/gui/buy.h index 37a39890..0f1cfede 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -25,9 +25,9 @@ #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> -#include "window.h" +#include <SDL_types.h> -#include "../guichanfwd.h" +#include "window.h" class Network; class ShopItems; @@ -40,7 +40,7 @@ class ListBox; * \ingroup Interface */ class BuyDialog : public Window, public gcn::ActionListener, - gcn::SelectionListener + public gcn::SelectionListener { public: /** @@ -111,9 +111,9 @@ class BuyDialog : public Window, public gcn::ActionListener, ShopItems *mShopItems; - int mMoney; - int mAmountItems; - int mMaxItems; + Uint32 mMoney; + Uint32 mAmountItems; + Uint32 mMaxItems; }; #endif diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index cdab0855..d060db85 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -19,9 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "buysell.h" - #include "button.h" +#include "buysell.h" #include "../npc.h" diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index df57f969..8de4f5a7 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -19,13 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "char_select.h" - #include <string> +#include <guichan/font.hpp> + #include <guichan/widgets/label.hpp> #include "button.h" +#include "char_select.h" #include "confirm_dialog.h" #include "ok_dialog.h" #include "playerbox.h" @@ -40,6 +41,8 @@ #include "../net/charserverhandler.h" #include "../net/messageout.h" +#include "../resources/colordb.h" + #include "../utils/gettext.h" #include "../utils/strprintf.h" #include "../utils/trim.h" @@ -69,7 +72,8 @@ CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m): void CharDeleteConfirm::action(const gcn::ActionEvent &event) { //ConfirmDialog::action(event); - if (event.getId() == "yes") { + if (event.getId() == "yes") + { master->attemptCharDelete(); } ConfirmDialog::action(event); @@ -81,38 +85,42 @@ CharSelectDialog::CharSelectDialog(Network *network, Window(_("Select Character")), mNetwork(network), mCharInfo(charInfo), mGender(gender), mCharSelected(false) { - mSelectButton = new Button(_("Ok"), "ok", this); - mCancelButton = new Button(_("Cancel"), "cancel", this); - mNewCharButton = new Button(_("New"), "new", this); - mDelCharButton = new Button(_("Delete"), "delete", this); - mPreviousButton = new Button(_("Previous"), "previous", this); - mNextButton = new Button(_("Next"), "next", this); + // Control that shows the Player + mPlayerBox = new PlayerBox; + mPlayerBox->setWidth(74); mNameLabel = new gcn::Label(strprintf(_("Name: %s"), "")); mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0)); mJobLevelLabel = new gcn::Label(strprintf(_("Job Level: %d"), 0)); mMoneyLabel = new gcn::Label(strprintf(_("Money: %d"), 0)); - // Control that shows the Player - mPlayerBox = new PlayerBox; - mPlayerBox->setWidth(74); + const std::string tempString = getFont()->getWidth(_("New")) < + getFont()->getWidth(_("Delete")) ? + _("Delete") : _("New"); + + mPreviousButton = new Button(_("Previous"), "previous", this); + mNextButton = new Button(_("Next"), "next", this); + mNewDelCharButton = new Button(tempString, "newdel", this); + mSelectButton = new Button(_("Ok"), "ok", this); + mCancelButton = new Button(_("Cancel"), "cancel", this); ContainerPlacer place; place = getPlacer(0, 0); + place(0, 0, mPlayerBox, 1, 6).setPadding(3); - place(1, 0, mNameLabel, 3); - place(1, 1, mLevelLabel, 3); - place(1, 2, mJobLevelLabel, 3); - place(1, 3, mMoneyLabel, 3); - place(1, 4, mPreviousButton); - place(2, 4, mNextButton); - place(1, 5, mNewCharButton); - place(2, 5, mDelCharButton); - place.getCell().matchColWidth(1, 2); + place(1, 0, mNewDelCharButton); + place(1, 1, mNameLabel, 5); + place(1, 2, mLevelLabel, 5); + place(1, 3, mJobLevelLabel, 5); + place(1, 4, mMoneyLabel, 5); + place.getCell().matchColWidth(1, 4); place = getPlacer(0, 2); - place(0, 0, mSelectButton); - place(1, 0, mCancelButton); - reflowLayout(265, 0); + place(0, 0, mPreviousButton); + place(1, 0, mNextButton); + place(4, 0, mCancelButton); + place(5, 0, mSelectButton); + + reflowLayout(250, 0); setLocationRelativeTo(getParent()); setVisible(true); @@ -125,8 +133,7 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) if (event.getId() == "ok" && n_character > 0) { // Start game - mNewCharButton->setEnabled(false); - mDelCharButton->setEnabled(false); + mNewDelCharButton->setEnabled(false); mSelectButton->setEnabled(false); mPreviousButton->setEnabled(false); mNextButton->setEnabled(false); @@ -137,20 +144,21 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) { state = EXIT_STATE; } - else if (event.getId() == "new" && n_character <= MAX_SLOT) + else if (event.getId() == "newdel") { - // Start new character dialog - CharCreateDialog *charCreateDialog = - new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mGender); - charServerHandler.setCharCreateDialog(charCreateDialog); - } - else if (event.getId() == "delete") - { - // Delete character - if (mCharInfo->getEntry()) + // Check for a character + if (mCharInfo->getEntry() && n_character <= MAX_SLOT ) { new CharDeleteConfirm(this); } + else + { + // Start new character dialog + CharCreateDialog *charCreateDialog = + new CharCreateDialog(this, mCharInfo->getPos(), + mNetwork, mGender); + charServerHandler.setCharCreateDialog(charCreateDialog); + } } else if (event.getId() == "previous") { @@ -174,18 +182,17 @@ void CharSelectDialog::updatePlayerInfo() mMoneyLabel->setCaption(strprintf(_("Gold: %d"), pi->mGp)); if (!mCharSelected) { - mNewCharButton->setEnabled(false); - mDelCharButton->setEnabled(true); + mNewDelCharButton->setCaption(_("Delete")); mSelectButton->setEnabled(true); } } - else { + else + { mNameLabel->setCaption(strprintf(_("Name: %s"), "")); mLevelLabel->setCaption(strprintf(_("Level: %d"), 0)); mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0)); mMoneyLabel->setCaption(strprintf(_("Money: %d"), 0)); - mNewCharButton->setEnabled(true); - mDelCharButton->setEnabled(false); + mNewDelCharButton->setCaption(_("New")); mSelectButton->setEnabled(false); } @@ -224,7 +231,8 @@ bool CharSelectDialog::selectByName(const std::string &name) unsigned int oldPos = mCharInfo->getPos(); mCharInfo->select(0); - do { + do + { LocalPlayer *player = mCharInfo->getEntry(); if (player && player->getName() == name) @@ -244,7 +252,10 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, { mPlayer = new Player(0, 0, NULL); mPlayer->setGender(gender); - mPlayer->setHairStyle(rand() % Being::getHairStylesNr(), rand() % Being::getHairColorsNr()); + + int numberOfHairColors = ColorDB::size(); + + mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), rand() % numberOfHairColors); mNameField = new TextField(""); mNameLabel = new gcn::Label(_("Name:")); @@ -258,41 +269,29 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, mCancelButton = new Button(_("Cancel"), "cancel", this); mPlayerBox = new PlayerBox(mPlayer); + mPlayerBox->setWidth(74); + mNameField->setActionEventId("create"); + mNameField->addActionListener(this); - int w = 200; - int h = 150; - setContentSize(w, h); - mPlayerBox->setDimension(gcn::Rectangle(80, 30, 110, 85)); - mNameLabel->setPosition(5, 5); - mNameField->setDimension( - gcn::Rectangle(45, 5, w - 45 - 7, mNameField->getHeight())); - mPrevHairColorButton->setPosition(90, 35); - mNextHairColorButton->setPosition(165, 35); - mHairColorLabel->setPosition(5, 40); - mPrevHairStyleButton->setPosition(90, 64); - mNextHairStyleButton->setPosition(165, 64); - mHairStyleLabel->setPosition(5, 70); - mCancelButton->setPosition( - w - 5 - mCancelButton->getWidth(), - h - 5 - mCancelButton->getHeight()); - mCreateButton->setPosition( - mCancelButton->getX() - 5 - mCreateButton->getWidth(), - h - 5 - mCancelButton->getHeight()); + ContainerPlacer place; + place = getPlacer(0, 0); - mNameField->addActionListener(this); + place(0, 0, mNameLabel, 1); + place(1, 0, mNameField, 6); + place(0, 1, mHairStyleLabel, 1); + place(1, 1, mPrevHairStyleButton); + place(2, 1, mPlayerBox, 1, 8).setPadding(3); + place(3, 1, mNextHairStyleButton); + place(0, 2, mHairColorLabel, 1); + place(1, 2, mPrevHairColorButton); + place(3, 2, mNextHairColorButton); + place.getCell().matchColWidth(0, 2); + place = getPlacer(0, 2); + place(4, 0, mCancelButton); + place(5, 0, mCreateButton); - add(mPlayerBox); - add(mNameField); - add(mNameLabel); - add(mNextHairColorButton); - add(mPrevHairColorButton); - add(mHairColorLabel); - add(mNextHairStyleButton); - add(mPrevHairStyleButton); - add(mHairStyleLabel); - add(mCreateButton); - add(mCancelButton); + reflowLayout(225, 0); setLocationRelativeTo(getParent()); setVisible(true); @@ -307,53 +306,54 @@ CharCreateDialog::~CharCreateDialog() charServerHandler.setCharCreateDialog(0); } -void -CharCreateDialog::action(const gcn::ActionEvent &event) +void CharCreateDialog::action(const gcn::ActionEvent &event) { - if (event.getId() == "create") { - if (getName().length() >= 4) { + int numberOfColors = ColorDB::size(); + if (event.getId() == "create") + { + if (getName().length() >= 4) + { // Attempt to create the character mCreateButton->setEnabled(false); attemptCharCreate(); } - else { + else + { new OkDialog("Error", "Your name needs to be at least 4 characters.", this); } } - else if (event.getId() == "cancel") { + else if (event.getId() == "cancel") scheduleDelete(); - } - else if (event.getId() == "nextcolor") { - mPlayer->setHairStyle(-1, mPlayer->getHairColor() + 1); - } - else if (event.getId() == "prevcolor") { - mPlayer->setHairStyle(-1, mPlayer->getHairColor() + Being::getHairColorsNr() - 1); - } - else if (event.getId() == "nextstyle") { - mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, -1); - } - else if (event.getId() == "prevstyle") { - mPlayer->setHairStyle(mPlayer->getHairStyle() + Being::getHairStylesNr() - 1, -1); - } + else if (event.getId() == "nextcolor") + mPlayer->setHairStyle(mPlayer->getHairStyle(), + (mPlayer->getHairColor() + 1) % numberOfColors); + else if (event.getId() == "prevcolor") + mPlayer->setHairStyle(mPlayer->getHairStyle(), + (mPlayer->getHairColor() + numberOfColors - 1) % + numberOfColors); + else if (event.getId() == "nextstyle") + mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, + mPlayer->getHairColor()); + else if (event.getId() == "prevstyle") + mPlayer->setHairStyle(mPlayer->getHairStyle() + + mPlayer->getNumOfHairstyles() - 1, + mPlayer->getHairColor()); } -std::string -CharCreateDialog::getName() +std::string CharCreateDialog::getName() { std::string name = mNameField->getText(); trim(name); return name; } -void -CharCreateDialog::unlock() +void CharCreateDialog::unlock() { mCreateButton->setEnabled(true); } -void -CharCreateDialog::attemptCharCreate() +void CharCreateDialog::attemptCharCreate() { // Send character infos MessageOut outMsg(mNetwork); diff --git a/src/gui/char_select.h b/src/gui/char_select.h index 74745788..23de061d 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -22,17 +22,16 @@ #ifndef _CHAR_SELECT_H #define _CHAR_SELECT_H +#include <guichan/actionlistener.hpp> + #include "window.h" -#include "../guichanfwd.h" -#include "../lockedarray.h" #include "../being.h" +#include "../lockedarray.h" -#include <guichan/actionlistener.hpp> - -class Player; class LocalPlayer; class Network; +class Player; class PlayerBox; /** @@ -65,8 +64,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener gcn::Button *mSelectButton; gcn::Button *mCancelButton; - gcn::Button *mNewCharButton; - gcn::Button *mDelCharButton; + gcn::Button *mNewDelCharButton; gcn::Button *mPreviousButton; gcn::Button *mNextButton; @@ -110,14 +108,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ ~CharCreateDialog(); - void - action(const gcn::ActionEvent &event); + void action(const gcn::ActionEvent &event); /** * Unlocks the dialog, enabling the create character button again. */ - void - unlock(); + void unlock(); private: /** diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp index 7be2441d..bc096379 100644 --- a/src/gui/char_server.cpp +++ b/src/gui/char_server.cpp @@ -19,9 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "char_server.h" - #include "button.h" +#include "char_server.h" #include "listbox.h" #include "scrollarea.h" @@ -29,10 +28,7 @@ #include "../main.h" #include "../serverinfo.h" -#include "../net/network.h" // TODO this is just for iptostring, move that? - #include "../utils/gettext.h" -#include "../utils/strprintf.h" #include "../utils/tostring.h" extern SERVER_INFO **server_info; @@ -40,7 +36,8 @@ extern SERVER_INFO **server_info; /** * The list model for the server list. */ -class ServerListModel : public gcn::ListModel { +class ServerListModel : public gcn::ListModel +{ public: virtual ~ServerListModel() {}; @@ -81,13 +78,12 @@ ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState): add(mOkButton); add(mCancelButton); - if (n_server == 0) { + if (n_server == 0) // Disable Ok button mOkButton->setEnabled(false); - } else { + else // Select first server mServerList->setSelected(1); - } setLocationRelativeTo(getParent()); setVisible(true); @@ -99,31 +95,27 @@ ServerSelectDialog::~ServerSelectDialog() delete mServerListModel; } -void -ServerSelectDialog::action(const gcn::ActionEvent &event) +void ServerSelectDialog::action(const gcn::ActionEvent &event) { - if (event.getId() == "ok") { + if (event.getId() == "ok") + { mOkButton->setEnabled(false); const SERVER_INFO *si = server_info[mServerList->getSelected()]; mLoginData->hostname = iptostring(si->address); mLoginData->port = si->port; mLoginData->updateHost = si->updateHost; - state = mNextState; } - else if (event.getId() == "cancel") { + else if (event.getId() == "cancel") state = LOGIN_STATE; - } } -int -ServerListModel::getNumberOfElements() +int ServerListModel::getNumberOfElements() { return n_server; } -std::string -ServerListModel::getElementAt(int i) +std::string ServerListModel::getElementAt(int i) { const SERVER_INFO *si = server_info[i]; return si->name + " (" + toString(si->online_users) + ")"; diff --git a/src/gui/char_server.h b/src/gui/char_server.h index 9419c92d..49a5b47b 100644 --- a/src/gui/char_server.h +++ b/src/gui/char_server.h @@ -27,8 +27,6 @@ #include "window.h" -#include "../guichanfwd.h" - class LoginData; class ServerListModel; diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index 87d843a0..2845691a 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -19,57 +19,61 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> -#include <sstream> - #include <guichan/focushandler.hpp> -#include "chat.h" - #include "browserbox.h" +#include "chat.h" #include "chatinput.h" +#include "itemlinkhandler.h" +#include "recorder.h" #include "scrollarea.h" #include "sdlinput.h" #include "windowcontainer.h" #include "widgets/layout.h" +#include "../beingmanager.h" #include "../configuration.h" #include "../game.h" #include "../localplayer.h" +#include "../party.h" #include "../net/messageout.h" #include "../net/protocol.h" +#include "../resources/iteminfo.h" +#include "../resources/itemdb.h" + #include "../utils/gettext.h" #include "../utils/strprintf.h" +#include "../utils/tostring.h" #include "../utils/trim.h" -ChatWindow::ChatWindow(Network *network): - Window(""), - mNetwork(network), - mTmpVisible(false) +ChatWindow::ChatWindow(Network * network): +Window(""), mNetwork(network), mTmpVisible(false) { - setWindowName("Chat"); + setWindowName(_("Chat")); setResizable(true); setDefaultSize(0, windowContainer->getHeight() - 123, 600, 123); setMinWidth(150); setMinHeight(90); + mItemLinkHandler = new ItemLinkHandler(); + mChatInput = new ChatInput; mChatInput->setActionEventId("chatinput"); mChatInput->addActionListener(this); mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP); mTextOutput->setOpaque(false); - mTextOutput->disableLinksAndUserColors(); mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0)); + mTextOutput->setLinkHandler(mItemLinkHandler); + mScrollArea = new ScrollArea(mTextOutput); - mScrollArea->setPosition( - mScrollArea->getFrameSize(), mScrollArea->getFrameSize()); - mScrollArea->setScrollPolicy( - gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS); + mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_ALWAYS); + mScrollArea->setScrollAmount(0, 1); mScrollArea->setOpaque(false); place(0, 0, mScrollArea, 5, 5).setPadding(0); @@ -84,23 +88,48 @@ ChatWindow::ChatWindow(Network *network): // Add key listener to chat input to be able to respond to up/down mChatInput->addKeyListener(this); mCurHist = mHistory.end(); + + // Read the party prefix + std::string partyPrefix = config.getValue("PartyPrefix", "$"); + mPartyPrefix = (partyPrefix.empty() ? '$' : partyPrefix.at(0)); + mReturnToggles = config.getValue("ReturnToggles", "0") == "1"; + mRecorder = new Recorder(this); + mParty = new Party(this, mNetwork); + + // If the player had @assert on in the last session, ask the server to + // run the @assert command for the player again. Convenience for GMs. + if (config.getValue(player_node->getName() + "GMassert", 0)) + chatSend(player_node->getName(), "@assert"); +} + +ChatWindow::~ChatWindow() +{ + char partyPrefix[2] = "."; + *partyPrefix = mPartyPrefix; + config.setValue("PartyPrefix", partyPrefix); + config.setValue("ReturnToggles", mReturnToggles ? "1" : "0"); + delete mRecorder; } -void ChatWindow::chatLog(std::string line, int own) +void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord) { // Trim whitespace trim(line); CHATLOG tmp; - tmp.own = own; + tmp.own = own; tmp.nick = ""; tmp.text = line; + std::string::size_type pos = line.find(" : "); - if (pos != std::string::npos) { + if (pos != std::string::npos) + { tmp.nick = line.substr(0, pos); tmp.text = line.substr(pos + 3); - } else { + } + else + { // Fix the owner of welcome message. if (line.substr(0, 7) == "Welcome") { @@ -108,77 +137,99 @@ void ChatWindow::chatLog(std::string line, int own) } } - std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK - switch (own) { + std::string lineColor = "##C"; + switch (own) + { case BY_GM: - if (tmp.nick.empty()) { - tmp.nick = _("Global announcement:"); + if (tmp.nick.empty()) + { + tmp.nick = std::string(_("Global announcement:")); tmp.nick += " "; - } else { + lineColor = "##G"; + } + else + { tmp.nick = strprintf(_("Global announcement from %s:"), tmp.nick.c_str()); tmp.nick += " "; + lineColor = "##1"; // Equiv. to BrowserBox::RED } - lineColor = "##1"; // Equiv. to BrowserBox::RED break; case BY_PLAYER: tmp.nick += CAT_NORMAL; - lineColor = "##2"; // Equiv. to BrowserBox::GREEN + lineColor = "##Y"; break; case BY_OTHER: tmp.nick += CAT_NORMAL; - lineColor = "##0"; // Equiv. to BrowserBox::BLACK + lineColor = "##C"; break; case BY_SERVER: tmp.nick = _("Server:"); tmp.nick += " "; tmp.text = line; - lineColor = "##7"; // Equiv. to BrowserBox::PINK + lineColor = "##S"; + break; + case BY_PARTY: + tmp.nick += CAT_NORMAL; + lineColor = "##P"; break; case ACT_WHISPER: tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str()); tmp.nick += " "; - lineColor = "##3"; // Equiv. to BrowserBox::BLUE + lineColor = "##W"; break; case ACT_IS: tmp.nick += CAT_IS; - lineColor = "##5"; // Equiv. to BrowserBox::YELLOW + lineColor = "##I"; break; case BY_LOGGER: tmp.nick = ""; tmp.text = line; - lineColor = "##8"; // Equiv. to BrowserBox::GREY + lineColor = "##L"; break; } + if (tmp.nick == ": ") + { + tmp.nick = ""; + lineColor = "##S"; + } + + if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") + { + player_node->setGM(); + } + // Get the current system time time_t t; time(&t); // Format the time string properly std::stringstream timeStr; - timeStr << "[" - << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int)(((t / 60) / 60) % 24) - << ":" - << (((t / 60) % 60 < 10) ? "0" : "") - << (int)((t / 60) % 60) - << "] "; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; line = lineColor + timeStr.str() + tmp.nick + tmp.text; // We look if the Vertical Scroll Bar is set at the max before // adding a row, otherwise the max will always be a row higher // at comparison. - if (mScrollArea->getVerticalScrollAmount() == mScrollArea->getVerticalMaxScroll()) + if (mScrollArea->getVerticalScrollAmount() == + mScrollArea->getVerticalMaxScroll()) { mTextOutput->addRow(line); - mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); + mScrollArea->setVerticalScrollAmount(mScrollArea-> + getVerticalMaxScroll()); } else { mTextOutput->addRow(line); } + + mRecorder->record(line.substr(3)); } void ChatWindow::chatLog(CHATSKILL act) @@ -192,12 +243,13 @@ void ChatWindow::action(const gcn::ActionEvent &event) { std::string message = mChatInput->getText(); - if (!message.empty()) { + if (!message.empty()) + { // If message different from previous, put it in the history - if (mHistory.empty() || message != mHistory.back()) { + if (mHistory.empty() || message != mHistory.back()) + { mHistory.push_back(message); } - // Reset history iterator mCurHist = mHistory.end(); @@ -208,13 +260,15 @@ void ChatWindow::action(const gcn::ActionEvent &event) mChatInput->setText(""); } - // Remove focus and hide input - mFocusHandler->focusNone(); + if (message.empty() || !mReturnToggles) + { + // Remove focus and hide input + mFocusHandler->focusNone(); - // If the chatWindow is shown up because you want to send a message - // It should hide now - if (mTmpVisible) { - setVisible(false); + // If the chatWindow is shown up because you want to send a message + // It should hide now + if (mTmpVisible) + setVisible(false); } } } @@ -244,16 +298,15 @@ bool ChatWindow::isInputFocused() return mChatInput->isFocused(); } -void ChatWindow::whisper(const std::string &nick, std::string msg, - int prefixlen) +void ChatWindow::whisper(const std::string &nick, std::string msg) { std::string recvnick = ""; - msg.erase(0, prefixlen + 1); if (msg.substr(0, 1) == "\"") { const std::string::size_type pos = msg.find('"', 1); - if (pos != std::string::npos) { + if (pos != std::string::npos) + { recvnick = msg.substr(1, pos - 1); msg.erase(0, pos + 2); } @@ -261,7 +314,8 @@ void ChatWindow::whisper(const std::string &nick, std::string msg, else { const std::string::size_type pos = msg.find(" "); - if (pos != std::string::npos) { + if (pos != std::string::npos) + { recvnick = msg.substr(0, pos); msg.erase(0, pos + 1); } @@ -274,8 +328,8 @@ void ChatWindow::whisper(const std::string &nick, std::string msg, outMsg.writeString(msg, msg.length()); chatLog(strprintf(_("Whispering to %s: %s"), - recvnick.c_str(), msg.c_str()), - BY_PLAYER); + recvnick.c_str(), msg.c_str()), + BY_PLAYER); } void ChatWindow::chatSend(const std::string &nick, std::string msg) @@ -284,8 +338,68 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg) * require server handling by proper packet. Probably * those if elses should be replaced by protocol calls */ + trim(msg); + + if (msg.compare("") == 0) + return; + + // Send party message + if (msg.at(0) == mPartyPrefix) + { + msg.erase(0, 1); + std::size_t length = msg.length() + 1; + + if (length == 0) + { + chatLog(_("Trying to send a blank party message."), BY_SERVER); + return; + } + MessageOut outMsg(mNetwork); + + outMsg.writeInt16(CMSG_PARTY_MESSAGE); + outMsg.writeInt16(length + 4); + outMsg.writeString(msg, length); + return; + } + + // check for item link + std::string::size_type start = msg.find('['); + while (start != std::string::npos && msg[start+1] != '@') + { + std::string::size_type end = msg.find(']', start); + if (end != std::string::npos) + { + // Catch multiple embeds and ignore them so it doesn't crash the client. + while ((msg.find('[', start + 1) != std::string::npos) && + (msg.find('[', start + 1) < end)) + { + start = msg.find('[', start + 1); + } + + std::string temp = msg.substr(start+1, end - start - 1); + + trim(temp); + + for (unsigned int i = 0; i < temp.size(); i++) + { + temp[i] = (char) tolower(temp[i]); + } + + const ItemInfo itemInfo = ItemDB::get(temp); + if (itemInfo.getName() != _("Unknown item")) + { + msg.insert(end, "@@"); + msg.insert(start+1, "|"); + msg.insert(start+1, toString(itemInfo.getId())); + msg.insert(start+1, "@@"); + } + } + start = msg.find('[', start + 1); + } + // Prepare ordinary message - if (msg.substr(0, 1) != "/") { + if (msg.substr(0, 1) != "/") + { msg = nick + " : " + msg; MessageOut outMsg(mNetwork); @@ -293,21 +407,38 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg) // Added + 1 in order to let eAthena parse admin commands correctly outMsg.writeInt16(msg.length() + 4 + 1); outMsg.writeString(msg, msg.length() + 1); + return; + } + + msg.erase(0, 1); + trim(msg); + + std::size_t space = msg.find(" "); + std::string command = msg.substr(0, space); + + if (space == std::string::npos) + { + msg = ""; } - else if (msg.substr(0, IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE) + else + { + msg = msg.substr(space); + trim(msg); + } + + if (command == "announce") { - msg.erase(0, IS_ANNOUNCE_LENGTH); MessageOut outMsg(mNetwork); outMsg.writeInt16(0x0099); outMsg.writeInt16(msg.length() + 4); outMsg.writeString(msg, msg.length()); } - else if (msg.substr(0, IS_HELP_LENGTH) == IS_HELP) + else if (command == "help") { - msg.erase(0, IS_HELP_LENGTH + 1); trim(msg); std::size_t space = msg.find(" "); std::string msg1; + if (space == std::string::npos) { msg1 = ""; @@ -317,33 +448,155 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg) msg1 = msg.substr(space + 1, msg.length()); msg = msg.substr(0, space); } - if (msg != "" && msg.at(0) == '/') + + if (!msg.empty() && msg.at(0) == '/') { msg.erase(0, 1); } + trim(msg1); help(msg, msg1); } - else if (msg.substr(0, IS_WHERE_LENGTH) == IS_WHERE) + else if (command == "where") { // Display the current map, X, and Y std::ostringstream where; where << map_path << " " << player_node->mX << "," << player_node->mY; chatLog(where.str(), BY_SERVER); } - else if (msg.substr(0, IS_WHO_LENGTH) == IS_WHO) + else if (command == "who") { MessageOut outMsg(mNetwork); outMsg.writeInt16(0x00c1); } - else if (msg.substr(0, IS_CLEAR_LENGTH) == IS_CLEAR) - { + else if (command == "clear") mTextOutput->clearRows(); + else if (command == "whisper" || command == "msg" || command == "w") + whisper(nick, msg); + else if (command == "record") + mRecorder->changeRecordingStatus(msg); + else if (command == "toggle") + { + if (msg.empty()) + { + chatLog(mReturnToggles ? _("Return toggles chat.") + : _("Message closes chat."), BY_SERVER); + return; + } + + msg = msg.substr(0, 1); + + if (msg == "1" || + msg == "y" || msg == "Y" || + msg == "t" || msg == "T") + { + chatLog(_("Return now toggles chat."), BY_SERVER); + mReturnToggles = true; + return; + } + else if (msg == "0" || + msg == "n" || msg == "N" || + msg == "f" || msg == "F") + { + chatLog(_("Message now closes chat."), BY_SERVER); + mReturnToggles = false; + return; + } + else + chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", " + "\"false\", \"1\", \"0\"."), BY_SERVER); + } + else if (command == "party") + { + if (msg.empty()) + { + chatLog(_("Unknown party command... Type \"/help\" party for more " + "information."), BY_SERVER); + return; + } + + const std::string::size_type space = msg.find(" "); + std::string rest = (space == std::string::npos ? "" + : msg.substr(space + 1, msg.length())); + + if (!rest.empty()) + { + msg = msg.substr(0, space); + trim(msg); + } + + party(msg, rest); + return; + } + else if (command == "cast") + { + /* + * This will eventually be replaced by a GUI, so + * we don't need to get too sophisticated + */ + MessageOut outMsg(mNetwork); + if (msg == "heal") + { + outMsg.writeInt16(0x03f3); + outMsg.writeInt16(0x01); + outMsg.writeInt32(0); + outMsg.writeInt8(0); + outMsg.writeInt8(0); + outMsg.writeString("", 24); + } + else if (msg == "gather") + { + outMsg.writeInt16(0x03f3); + outMsg.writeInt16(0x02); + outMsg.writeInt32(0); + outMsg.writeInt8(0); + outMsg.writeInt8(0); + outMsg.writeString("", 24); + } + else + chatLog(_("No such spell!"), BY_SERVER); + } + else if (command == "present") + { + Beings & beings = beingManager->getAll(); + std::string response = ""; + + for (BeingIterator bi = beings.begin(), be = beings.end(); + bi != be; ++bi) + { + if ((*bi)->getType() == Being::PLAYER) + { + if (!response.empty()) + { + response += ", "; + } + response += (*bi)->getName(); + } + } + + if (mRecorder->isRecording()) + { + // Get the current system time + time_t t; + time(&t); + + // Format the time string properly + std::stringstream timeStr; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; + + + mRecorder->record(timeStr.str() + _("Present: ") + response + "."); + chatLog(_("Attendance written to record log."), BY_SERVER, true); + } + else + { + chatLog(_("Present: ") + response, BY_SERVER); + } } - else if (msg.substr(0, IS_WHISPER_LENGTH) == IS_WHISPER) - whisper(nick, msg, IS_WHISPER_LENGTH); - else if (msg.substr(0, IS_SHORT_WHISPER_LENGTH) == IS_SHORT_WHISPER) - whisper(nick, msg, IS_SHORT_WHISPER_LENGTH); else { chatLog(_("Unknown command"), BY_SERVER); @@ -353,8 +606,10 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg) std::string ChatWindow::const_msg(CHATSKILL act) { std::string msg; - if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC) { - switch (act.bskill) { + if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC) + { + switch (act.bskill) + { case BSKILL_TRADE: msg = _("Trade failed!"); break; @@ -377,7 +632,8 @@ std::string ChatWindow::const_msg(CHATSKILL act) msg += " "; - switch (act.reason) { + switch (act.reason) + { case RFAIL_SKILLDEP: msg += _("You have not yet reached a high enough lvl!"); break; @@ -412,8 +668,11 @@ std::string ChatWindow::const_msg(CHATSKILL act) msg += _("Huh? What's that?"); break; } - } else { - switch (act.skill) { + } + else + { + switch (act.skill) + { case SKILL_WARP : msg = _("Warp failed..."); break; @@ -448,11 +707,14 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event) { // Move forward through the history HistoryIterator prevHist = mCurHist++; - if (mCurHist != mHistory.end()) { + + if (mCurHist != mHistory.end()) + { mChatInput->setText(*mCurHist); mChatInput->setCaretPosition(mChatInput->getText().length()); } - else { + else + { mCurHist = prevHist; } } @@ -468,10 +730,18 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event) void ChatWindow::setInputText(std::string input_str) { - mChatInput->setText(input_str + " "); + mChatInput->setText(mChatInput->getText() + input_str + " "); requestChatFocus(); } +void ChatWindow::addItemText(const std::string &item) +{ + std::ostringstream text; + text << "[" << item << "] "; + mChatInput->setText(mChatInput->getText() + text.str()); + requestChatFocus(); +} + void ChatWindow::setVisible(bool isVisible) { Window::setVisible(isVisible); @@ -484,70 +754,137 @@ void ChatWindow::setVisible(bool isVisible) mTmpVisible = false; } -void ChatWindow::help(const std::string &msg1, const std::string &msg2) +void ChatWindow::party(const std::string & command, const std::string & rest) +{ + if (command == "prefix") + { + if (rest.empty()) + { + char temp[2] = "."; + *temp = mPartyPrefix; + chatLog(_("The current party prefix is ") + std::string(temp), + BY_SERVER); + } + else if (rest.length() != 1) + { + chatLog(_("Party prefix must be one character long."), BY_SERVER); + } + else + { + if (rest == "/") + { + chatLog(_("Cannot use a '/' as the prefix."), BY_SERVER); + } + else + { + mPartyPrefix = rest.at(0); + chatLog(_("Changing prefix to ") + rest, BY_SERVER); + } + } + } + else + mParty->respond(command, rest); +} + +void ChatWindow::help(const std::string & msg1, const std::string & msg2) { chatLog(_("-- Help --"), BY_SERVER); - if (msg1 == "") + if (msg1.empty()) { chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER); chatLog(_("/clear: Clears this window"), BY_SERVER); chatLog(_("/help: Display this help"), BY_SERVER); + chatLog(_("/party <command> <params>: Party commands."), BY_SERVER); + chatLog(_("/msg <nick> <message>: Alternate form for /whisper"), BY_SERVER); + chatLog(_("/present: Get list of players present"), BY_SERVER); + chatLog(_("/record <filename>: Start recording the chat to an" + " external file."), BY_SERVER); + chatLog(_("/toggle: Determine whether <return> toggles the chat log."), + BY_SERVER); chatLog(_("/where: Display map name"), BY_SERVER); + chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER); chatLog(_("/whisper <nick> <message>: Sends a private <message>" " to <nick>"), BY_SERVER); - chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER); chatLog(_("/who: Display number of online users"), BY_SERVER); chatLog(_("For more information, type /help <command>"), BY_SERVER); - return; } - if (msg1 == "announce") + else if (msg1 == "announce") { chatLog(_("Command: /announce <msg>"), BY_SERVER); chatLog(_("*** only available to a GM ***"), BY_SERVER); chatLog(_("This command sends the message <msg> to " "all players currently online."), BY_SERVER); - return; } - if (msg1 == "clear") + else if (msg1 == "clear") { chatLog(_("Command: /clear"), BY_SERVER); chatLog(_("This command clears the chat log of previous chat."), BY_SERVER); - return; } - if (msg1 == "help") + else if (msg1 == "help") { chatLog(_("Command: /help"), BY_SERVER); chatLog(_("This command displays a list of all commands available."), BY_SERVER); chatLog(_("Command: /help <command>"), BY_SERVER); chatLog(_("This command displays help on <command>."), BY_SERVER); - return; } - if (msg1 == "where") + else if (msg1 == "party") + { + mParty->help(msg2); + } + else if (msg1 == "present") + { + chatLog(_("Command: /present"), BY_SERVER); + chatLog(_("This command gets a list of players within hearing and " + "sends it to either the record log if recording, or the chat " + "log otherwise."), BY_SERVER); + } + else if (msg1 == "record") + { + chatLog(_("Command: /record <filename>"), BY_SERVER); + chatLog(_("This command starts recording the chat log to the file " + "<filename>."), BY_SERVER); + chatLog(_("Command: /record"), BY_SERVER); + chatLog(_("This command finishes a recording session."), BY_SERVER); + } + else if (msg1 == "toggle") + { + chatLog(_("Command: /toggle <state>"), BY_SERVER); + chatLog(_("This command sets whether the return key should toggle the" + "chat log, or whether the chat log turns off automatically."), + BY_SERVER); + chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to " + "turn the toggle on, or \"0\", \"no\", \"false\" to turn the " + "toggle off."), BY_SERVER); + chatLog(_("Command: /toggle"), BY_SERVER); + chatLog(_("This command displays the return toggle status."), BY_SERVER); + } + else if (msg1 == "where") { chatLog(_("Command: /where"), BY_SERVER); chatLog(_("This command displays the name of the current map."), BY_SERVER); - return; } - if (msg1 == "whisper" || msg1 == "w") + else if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w") { + chatLog(_("Command: /msg <nick> <msg>"), BY_SERVER); chatLog(_("Command: /whisper <nick> <msg>"), BY_SERVER); chatLog(_("Command: /w <nick> <msg>"), BY_SERVER); chatLog(_("This command sends the message <msg> to <nick>."), BY_SERVER); chatLog(_("If the <nick> has spaces in it, enclose it in " - "double quotes (\")."), BY_SERVER); - return; + "double quotes (\")."), BY_SERVER); } - if (msg1 == "who") + else if (msg1 == "who") { chatLog(_("Command: /who"), BY_SERVER); chatLog(_("This command displays the number of players currently " - "online."), BY_SERVER); - return; + "online."), BY_SERVER); + } + else + { + chatLog(_("Unknown command."), BY_SERVER); + chatLog(_("Type /help for a list of commands."), BY_SERVER); } - chatLog(_("Unknown command."), BY_SERVER); - chatLog(_("Type /help for a list of commands."), BY_SERVER); } diff --git a/src/gui/chat.h b/src/gui/chat.h index ad89c8dc..2fadb014 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -30,36 +30,23 @@ #include "window.h" -#include "../guichanfwd.h" - class BrowserBox; class Network; +class Recorder; +class Party; class ScrollArea; +class ItemLinkHandler; #define BY_GM 0 // those should be self-explanatory =) #define BY_PLAYER 1 #define BY_OTHER 2 #define BY_SERVER 3 +#define BY_PARTY 4 + +#define ACT_WHISPER 5 // getting whispered at +#define ACT_IS 6 // equivalent to "/me" on IRC -#define ACT_WHISPER 4 // getting whispered at -#define ACT_IS 5 // equivalent to "/me" on IRC - -#define BY_LOGGER 6 - -#define IS_ANNOUNCE "/announce " -#define IS_ANNOUNCE_LENGTH 10 -#define IS_HELP "/help" -#define IS_HELP_LENGTH 5 -#define IS_WHERE "/where" -#define IS_WHERE_LENGTH 6 -#define IS_WHO "/who" -#define IS_WHO_LENGTH 4 -#define IS_CLEAR "/clear" -#define IS_CLEAR_LENGTH 6 -#define IS_WHISPER "/whisper" -#define IS_WHISPER_LENGTH 8 -#define IS_SHORT_WHISPER "/w" -#define IS_SHORT_WHISPER_LENGTH 2 +#define BY_LOGGER 7 /** * gets in between usernick and message text depending on @@ -127,14 +114,19 @@ class ChatWindow : public Window, public gcn::ActionListener, ChatWindow(Network *network); /** + * Destructor: used to write back values to the config file + */ + ~ChatWindow(); + + /** * Adds a line of text to our message list. Parameters: * * @param line Text message. * @parem own Type of message (usually the owner-type). */ - void chatLog(std::string line, int own); + void chatLog(std::string line, int own, bool ignoreRecord = false); - /* + /** * Calls original chat_log() after processing the packet. */ void chatLog(CHATSKILL); @@ -186,6 +178,9 @@ class ChatWindow : public Window, public gcn::ActionListener, /** Called to set current text */ void setInputText(std::string input_str); + /** Called to add item to chat */ + void addItemText(const std::string &item); + /** Override to reset mTmpVisible */ void setVisible(bool visible); @@ -199,6 +194,14 @@ class ChatWindow : public Window, public gcn::ActionListener, void scroll(int amount); /** + * party implements the partying chat commands + * + * @param command is the party command to perform + * @param msg is the remainder of the message + */ + void party(const std::string &command, const std::string &msg); + + /** * help implements the /help command * * @param msg1 is the command that the player needs help on @@ -207,10 +210,11 @@ class ChatWindow : public Window, public gcn::ActionListener, void help(const std::string &msg1, const std::string &msg2); private: + Network *mNetwork; bool mTmpVisible; - void whisper(const std::string &nick, std::string msg, int prefixlen); + void whisper(const std::string &nick, std::string msg); /** One item in the chat log */ struct CHATLOG @@ -226,13 +230,19 @@ class ChatWindow : public Window, public gcn::ActionListener, gcn::TextField *mChatInput; /**< Input box for typing chat messages */ BrowserBox *mTextOutput; /**< Text box for displaying chat history */ ScrollArea *mScrollArea; /**< Scroll area around text output */ - + ItemLinkHandler *mItemLinkHandler; /** Used for showing item popup on + clicking links **/ typedef std::list<std::string> History; typedef History::iterator HistoryIterator; History mHistory; /**< Command history */ HistoryIterator mCurHist; /**< History iterator */ + Recorder *mRecorder; /**< Recording class */ + char mPartyPrefix; /**< Messages beginning with the prefix are sent to + the party */ + bool mReturnToggles; /**< Marks whether <Return> toggles the chat log + or not */ + Party *mParty; }; - extern ChatWindow *chatWindow; #endif diff --git a/src/gui/chatinput.h b/src/gui/chatinput.h index 07144c5b..a4a50502 100644 --- a/src/gui/chatinput.h +++ b/src/gui/chatinput.h @@ -22,10 +22,10 @@ #ifndef CHATINPUT_H #define CHATINPUT_H -#include "textfield.h" - #include <guichan/focuslistener.hpp> +#include "textfield.h" + /** * The chat input hides when it loses focus. It is also invisible by default. */ diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp index b8fca2b8..511ed34c 100644 --- a/src/gui/checkbox.cpp +++ b/src/gui/checkbox.cpp @@ -21,12 +21,14 @@ #include "checkbox.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" int CheckBox::instances = 0; +float CheckBox::mAlpha = config.getValue("guialpha", 0.8); Image *CheckBox::checkBoxNormal; Image *CheckBox::checkBoxChecked; Image *CheckBox::checkBoxDisabled; @@ -43,6 +45,13 @@ CheckBox::CheckBox(const std::string& caption, bool selected): checkBoxChecked = checkBox->getSubImage(9, 0, 9, 10); checkBoxDisabled = checkBox->getSubImage(18, 0, 9, 10); checkBoxDisabledChecked = checkBox->getSubImage(27, 0, 9, 10); + if (config.getValue("opengl", 0)) + { + checkBoxNormal->setAlpha(mAlpha); + checkBoxChecked->setAlpha(mAlpha); + checkBoxDisabled->setAlpha(mAlpha); + checkBoxDisabledChecked->setAlpha(mAlpha); + } checkBox->decRef(); } @@ -66,16 +75,26 @@ void CheckBox::drawBox(gcn::Graphics* graphics) { Image *box; - if (isSelected()) { - if (isEnabled()) { + if (isSelected()) + { + if (isEnabled()) box = checkBoxChecked; - } else { + else box = checkBoxDisabledChecked; - } - } else if (isEnabled()) { + } + else if (isEnabled()) box = checkBoxNormal; - } else { + else box = checkBoxDisabled; + + if (config.getValue("guialpha", 0.8) != mAlpha && + config.getValue("opengl", 0)) + { + 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/checkbox.h b/src/gui/checkbox.h index 4b312d22..20adb43c 100644 --- a/src/gui/checkbox.h +++ b/src/gui/checkbox.h @@ -22,8 +22,6 @@ #ifndef CHECKBOX_H #define CHECKBOX_H -#include <iosfwd> - #include <guichan/widgets/checkbox.hpp> class Image; @@ -33,7 +31,8 @@ class Image; * * \ingroup GUI */ -class CheckBox : public gcn::CheckBox { +class CheckBox : public gcn::CheckBox +{ public: /** * Constructor. @@ -52,6 +51,7 @@ class CheckBox : public gcn::CheckBox { private: static int instances; + static float mAlpha; static Image *checkBoxNormal; static Image *checkBoxChecked; static Image *checkBoxDisabled; diff --git a/src/gui/color.cpp b/src/gui/color.cpp new file mode 100644 index 00000000..e37affda --- /dev/null +++ b/src/gui/color.cpp @@ -0,0 +1,146 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * 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 "color.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +Color::Color() +{ + addColor('C', 0x000000, _("Chat")); + addColor('G', 0xff0000, _("GM")); + addColor('H', 0xebc873, _("Highlight")); + addColor('Y', 0x1fa052, _("Player")); + addColor('W', 0x0000ff, _("Whisper")); + addColor('I', 0xf1dc27, _("Is")); + addColor('P', 0xff00d8, _("Party")); + addColor('S', 0x8415e2, _("Server")); + addColor('L', 0x919191, _("Logger")); + addColor('<', 0xe50d0d, _("Hyperlink")); + commit(); +} + +Color::~Color() +{ + for (ColVector::iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + config.setValue("color" + col->text, toString(col->rgb)); + } +} + +void Color::setColor(const char c, const int rgb) +{ + for (ColVector::iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + if (col->ch == c) + { + col->rgb = rgb; + return; + } + } +} + +int Color::getColor(const char c, bool &valid) const +{ + for (ColVector::const_iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + if (col->ch == c) + { + valid = true; + return col->rgb; + } + } + valid = false; + return 0x000000; +} + +std::string Color::getElementAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mColVector[i].text; +} + +char Color::getColorCharAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return 'C'; + } + return mColVector[i].ch; +} + +void Color::addColor(const char c, const int rgb, const std::string &text) +{ + int trueRgb = config.getValue("color" + text, rgb); + mColVector.push_back(colorElem(c, trueRgb, text)); +} + +int Color::getColorAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return 0; + } + return mColVector[i].rgb; +} + +void Color::setColorAt(int i, int rgb) +{ + if (i >= 0 && i < getNumberOfElements()) + { + mColVector[i].rgb = rgb; + } +} + +void Color::commit() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->committedRgb = i->rgb; + } +} + +void Color::rollback() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->rgb = i->committedRgb; + } +} diff --git a/src/gui/color.h b/src/gui/color.h new file mode 100644 index 00000000..509448e7 --- /dev/null +++ b/src/gui/color.h @@ -0,0 +1,136 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * 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 COLOUR_H +#define COLOUR_H + +#include <string> +#include <vector> + +#include <guichan/listmodel.hpp> + +class Color : public gcn::ListModel +{ + public: + /** + * Constructor + */ + Color(); + + /** + * Destructor + */ + ~Color(); + + /** + * Define the color replacement for a character + * + * @param c charater to be replaced + * @param rgb color to replace character + */ + void setColor(const char c, const int rgb); + + /** + * Define the color replacement for a character + * + * @param c character to be replaced + * @param r red component + * @param g green component + * @param b blue component + */ + void setColor(const char c, const int r, const int g, const int b) + { + setColor(c, (r << 16) | (g << 8) | b); + } + + /** + * Return the color associated with a character, if exists + * + * @param c character requested + * @param valid indicate whether character is known + */ + int getColor(const char c, bool &valid) const; + + /** + * Return the number of colors known + */ + int getNumberOfElements() {return mColVector.size(); } + + /** + * Return the name of the ith color + * + * @param i index of color interested in + */ + std::string getElementAt(int i); + + /** + * Get the color for the element at index i in the current color + * model + */ + int getColorAt(int i); + + /** + * Get the character used by the color for the element at index i in + * the current color model + */ + char getColorCharAt(int i); + + /** + * Set the color for the element at index i + */ + void setColorAt(int i, int rgb); + + /** + * Commit the colors + */ + void commit(); + + /** + * Rollback the colors + */ + void rollback(); + + private: + struct colorElem + { + colorElem(const char c, const int rgb, const std::string &text) : + ch(c), rgb(rgb), text(text) {} + char ch; + int rgb; + int committedRgb; + std::string text; + }; + typedef std::vector<colorElem> ColVector; + ColVector mColVector; + + /** + * Initialise color + * + * @param c character that needs initialising + * @param rgb default color if not found in config + * @param text identifier of color + */ + void addColor(const char c, const int rgb, const std::string &text); +}; + +extern Color *textColor; + +#endif diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index 46b7c971..38697f3a 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -19,11 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "confirm_dialog.h" - -#include <guichan/widgets/label.hpp> +#include <guichan/font.hpp> #include "button.h" +#include "confirm_dialog.h" +#include "scrollarea.h" +#include "textbox.h" #include "../utils/gettext.h" @@ -31,32 +32,55 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, Window *parent): Window(title, true, parent) { - gcn::Label *textLabel = new gcn::Label(msg); + mTextBox = new TextBox(); + mTextBox->setEditable(false); + mTextBox->setOpaque(false); + + mTextArea = new ScrollArea(mTextBox); gcn::Button *yesButton = new Button(_("Yes"), "yes", this); gcn::Button *noButton = new Button(_("No"), "no", this); - int w = textLabel->getWidth() + 20; + mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setOpaque(false); + + mTextBox->setTextWrapped(msg, 260); + + int numRows = mTextBox->getNumberOfRows(); + int width = getFont()->getWidth(title); int inWidth = yesButton->getWidth() + noButton->getWidth() + 5; - int h = textLabel->getHeight() + 25 + yesButton->getHeight(); - if (w < inWidth + 10) { - w = inWidth + 10; + if (numRows > 1) + { + // 15 == height of each line of text (based on font heights) + // 14 == row top + bottom graphic pixel heights + setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + noButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5, + 3 + (numRows * 14))); + } + else + { + if (width < getFont()->getWidth(msg)) + width = getFont()->getWidth(msg); + if (width < inWidth) + width = inWidth; + setContentSize(width + 15, 30 + noButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17)); } - setContentSize(w, h); - textLabel->setPosition(10, 10); yesButton->setPosition( - (w - inWidth) / 2, - h - 5 - noButton->getHeight()); + (mTextBox->getMinWidth() - inWidth) / 2, + (numRows * 14) + noButton->getHeight() - 8); noButton->setPosition( yesButton->getX() + yesButton->getWidth() + 5, - h - 5 - noButton->getHeight()); + (numRows * 14) + noButton->getHeight() - 8); - add(textLabel); + add(mTextArea); add(yesButton); add(noButton); - if (getParent()) { + if (getParent()) + { setLocationRelativeTo(getParent()); getParent()->moveToTop(this); } @@ -64,6 +88,11 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, yesButton->requestFocus(); } +unsigned int ConfirmDialog::getNumRows() +{ + return mTextBox->getNumberOfRows(); +} + void ConfirmDialog::action(const gcn::ActionEvent &event) { // Proxy button events to our listeners diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h index 69b3e9e4..3fa2b90d 100644 --- a/src/gui/confirm_dialog.h +++ b/src/gui/confirm_dialog.h @@ -26,13 +26,16 @@ #include "window.h" +class ScrollArea; +class TextBox; /** * An option dialog. * * \ingroup GUI */ -class ConfirmDialog : public Window, public gcn::ActionListener { +class ConfirmDialog : public Window, public gcn::ActionListener +{ public: /** * Constructor. @@ -42,10 +45,17 @@ class ConfirmDialog : public Window, public gcn::ActionListener { ConfirmDialog(const std::string &title, const std::string &msg, Window *parent = NULL); + unsigned int getNumRows(); + /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); + + private: + TextBox *mTextBox; + ScrollArea *mTextArea; + gcn::Button *okButton; }; #endif diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp index f73bb74d..a69698e9 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connection.cpp @@ -19,20 +19,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "connection.h" - #include <guichan/actionlistener.hpp> #include <guichan/widgets/label.hpp> #include "button.h" +#include "connection.h" #include "progressbar.h" #include "../main.h" #include "../utils/gettext.h" -namespace { +namespace +{ struct ConnectionActionListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) { state = EXIT_STATE; } @@ -63,10 +63,10 @@ ConnectionDialog::ConnectionDialog(): void ConnectionDialog::logic() { mProgress += 0.005f; + if (mProgress > 1.0f) - { mProgress = 0.0f; - } + mProgressBar->setProgress(mProgress); Window::logic(); } diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 669aabd2..5a5acfad 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -19,14 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "debugwindow.h" - #include <SDL_mouse.h> #include <guichan/widgets/label.hpp> -#include "button.h" -#include "gui.h" +#include "debugwindow.h" #include "viewport.h" #include "widgets/layout.h" diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index 00119d15..e089de27 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -22,14 +22,10 @@ #ifndef DEBUGWINDOW_H #define DEBUGWINDOW_H -#include <iosfwd> - #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - /** * The debug window. * diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp new file mode 100644 index 00000000..94ce9736 --- /dev/null +++ b/src/gui/emotecontainer.cpp @@ -0,0 +1,172 @@ +/* + * Extended support for activating emotes + * 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 <guichan/mouseinput.hpp> +#include <guichan/selectionlistener.hpp> + +#include "emotecontainer.h" + +#include "../animatedsprite.h" +#include "../configuration.h" +#include "../emoteshortcut.h" +#include "../graphics.h" +#include "../localplayer.h" +#include "../log.h" + +#include "../resources/emotedb.h" +#include "../resources/image.h" +#include "../resources/iteminfo.h" +#include "../resources/resourcemanager.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +const int EmoteContainer::gridWidth = 34; // emote icon width + 4 +const int EmoteContainer::gridHeight = 36; // emote icon height + 4 + +static const int NO_EMOTE = -1; + +EmoteContainer::EmoteContainer(): + mSelectedEmoteIndex(NO_EMOTE) +{ + ResourceManager *resman = ResourceManager::getInstance(); + + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + mEmoteImg.push_back(player_node->getEmote(i)); + } + + mSelImg = resman->getImage("graphics/gui/selection.png"); + if (!mSelImg) logger->error(_("Unable to load selection.png")); + + mSelImg->setAlpha(config.getValue("guialpha", 0.8)); + + mMaxEmote = EmoteDB::getLast() + 1; + + addMouseListener(this); + addWidgetListener(this); +} + +EmoteContainer::~EmoteContainer() +{ + if (!mSelImg) + { + mSelImg->decRef(); + mSelImg = NULL; + } +} + +void EmoteContainer::draw(gcn::Graphics *graphics) +{ + int columns = getWidth() / gridWidth; + + // Have at least 1 column + if (columns < 1) + { + columns = 1; + } + + for (int i = 0; i < mMaxEmote ; i++) + { + int emoteX = ((i) % columns) * gridWidth; + int emoteY = ((i) / columns) * gridHeight; + + // Draw emote icon + mEmoteImg[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY); + + // Draw selection image below selected item + if (mSelectedEmoteIndex == i) + { + static_cast<Graphics*>(graphics)->drawImage( + mSelImg, emoteX, emoteY); + } + } +} + +void EmoteContainer::widgetResized(const gcn::Event &event) +{ + recalculateHeight(); +} + +void EmoteContainer::recalculateHeight() +{ + int cols = getWidth() / gridWidth; + + if (cols < 1) + cols = 1; + + const int rows = (mMaxEmote / cols) + (mMaxEmote % cols > 0 ? 1 : 0); + const int height = rows * gridHeight + 8; + if (height != getHeight()) + setHeight(height); +} + +int EmoteContainer::getSelectedEmote() +{ + if (mSelectedEmoteIndex == NO_EMOTE) + return 0; + + return 1 + mSelectedEmoteIndex; +} + +void EmoteContainer::selectNone() +{ + setSelectedEmoteIndex(NO_EMOTE); +} + +void EmoteContainer::setSelectedEmoteIndex(int index) +{ + if (index < 0 || index >= mMaxEmote ) + mSelectedEmoteIndex = NO_EMOTE; + else + mSelectedEmoteIndex = index; +} + +void EmoteContainer::distributeValueChangedEvent() +{ + gcn::SelectionEvent event(this); + std::list<gcn::SelectionListener*>::iterator i_end = mListeners.end(); + std::list<gcn::SelectionListener*>::iterator i; + + for (i = mListeners.begin(); i != i_end; ++i) + { + (*i)->valueChanged(event); + } +} + +void EmoteContainer::mousePressed(gcn::MouseEvent &event) +{ + int button = event.getButton(); + if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT) + { + int columns = getWidth() / gridWidth; + int mx = event.getX(); + int my = event.getY(); + int index = mx / gridWidth + ((my / gridHeight) * columns); + if (index < mMaxEmote) + { + setSelectedEmoteIndex(index); + emoteShortcut->setEmoteSelected(index + 1); + } + } +} diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h new file mode 100644 index 00000000..fefce793 --- /dev/null +++ b/src/gui/emotecontainer.h @@ -0,0 +1,136 @@ +/* + * Extended support for activating emotes + * 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 EMOTECONTAINER_H +#define EMOTECONTAINER_H + +#include <list> +#include <vector> + +#include <guichan/mouselistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +class AnimatedSprite; +class Image; + +namespace gcn { + class SelectionListener; +} + +/** + * An emote container. Used to show emotes in inventory and trade dialog. + * + * \ingroup GUI + */ +class EmoteContainer : public gcn::Widget, + public gcn::MouseListener, + public gcn::WidgetListener +{ + public: + /** + * Constructor. Initializes the graphic. + */ + EmoteContainer(); + + /** + * Destructor. + */ + virtual ~EmoteContainer(); + + /** + * Draws the emotes. + */ + void draw(gcn::Graphics *graphics); + + /** + * Called whenever the widget changes size. + */ + void widgetResized(const gcn::Event &event); + + /** + * Handles mouse click. + */ + void mousePressed(gcn::MouseEvent &event); + + /** + * Returns the selected emote. + */ + int getSelectedEmote(); + + /** + * Sets selected emote to NULL. + */ + void selectNone(); + + /** + * Adds a listener to the list that's notified each time a change to + * the selection occurs. + */ + void addSelectionListener(gcn::SelectionListener *listener) + { + mListeners.push_back(listener); + } + + /** + * Removes a listener from the list that's notified each time a change + * to the selection occurs. + */ + void removeSelectionListener(gcn::SelectionListener *listener) + { + mListeners.remove(listener); + } + + private: + /** + * Sets the currently selected emote. Invalid (e.g., negative) indices + * set `no emotr'. + */ + void setSelectedEmoteIndex(int index); + + /** + * Find the current emote index by the most recently used emote ID + */ + void refindSelectedEmote(void); + + /** + * Determine and set the height of the container. + */ + void recalculateHeight(void); + + /** + * Sends out selection events to the list of selection listeners. + */ + void distributeValueChangedEvent(void); + + std::vector<AnimatedSprite*> mEmoteImg; + Image *mSelImg; + int mSelectedEmoteIndex; + + int mMaxEmote; + + std::list<gcn::SelectionListener*> mListeners; + + static const int gridWidth; + static const int gridHeight; +}; + +#endif diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp new file mode 100644 index 00000000..b66592c1 --- /dev/null +++ b/src/gui/emoteshortcutcontainer.cpp @@ -0,0 +1,204 @@ +/* + * Extended support for activating emotes + * 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 "emoteshortcutcontainer.h" + +#include "../animatedsprite.h" +#include "../configuration.h" +#include "../emoteshortcut.h" +#include "../graphics.h" +#include "../inventory.h" +#include "../item.h" +#include "../itemshortcut.h" +#include "../keyboardconfig.h" +#include "../localplayer.h" +#include "../log.h" + +#include "../resources/emotedb.h" +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +static const int MAX_ITEMS = 12; + +EmoteShortcutContainer::EmoteShortcutContainer(): + ShortcutContainer(), + mEmoteClicked(false), + mEmoteMoved(0) +{ + addMouseListener(this); + addWidgetListener(this); + + ResourceManager *resman = ResourceManager::getInstance(); + + mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); + + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + mEmoteImg.push_back(player_node->getEmote(i)); + } + + mMaxItems = EmoteDB::getLast() < MAX_ITEMS ? EmoteDB::getLast() : MAX_ITEMS; + + mBoxHeight = mBackgroundImg->getHeight(); + mBoxWidth = mBackgroundImg->getWidth(); +} + +EmoteShortcutContainer::~EmoteShortcutContainer() +{ + mBackgroundImg->decRef(); +} + +void EmoteShortcutContainer::draw(gcn::Graphics *graphics) +{ + Graphics *g = static_cast<Graphics*>(graphics); + + graphics->setFont(getFont()); + + for (int i = 0; i < mMaxItems; i++) + { + const int emoteX = (i % mGridWidth) * mBoxWidth; + const int emoteY = (i / mGridWidth) * mBoxHeight; + + g->drawImage(mBackgroundImg, emoteX, emoteY); + + // Draw emote keyboard shortcut. + const char *key = SDL_GetKeyName( + (SDLKey) keyboard.getKeyValue(keyboard.KEY_EMOTE_1 + i)); + graphics->setColor(0x000000); + g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT); + + if (emoteShortcut->getEmote(i)) + { + mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2, emoteY + 10); + } + + } + + if (mEmoteMoved) + { + // Draw the emote image being dragged by the cursor. + AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1]; + if (sprite) + { + const int tPosX = mCursorPosX - (sprite->getWidth() / 2); + const int tPosY = mCursorPosY - (sprite->getHeight() / 2); + + sprite->draw(g, tPosX, tPosY); + } + } + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + mBackgroundImg->setAlpha(mAlpha); + } +} + +void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (!mEmoteMoved && mEmoteClicked) + { + const int index = getIndexFromGrid(event.getX(), event.getY()); + const int emoteId = emoteShortcut->getEmote(index); + + if (index == -1) + { + return; + } + + if (emoteId) + { + mEmoteMoved = emoteId; + emoteShortcut->removeEmote(index); + } + } + if (mEmoteMoved) + { + mCursorPosX = event.getX(); + mCursorPosY = event.getY(); + } + } +} + +void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event) +{ + const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (index == -1) + { + return; + } + + // Stores the selected emote if there is one. + if (emoteShortcut->isEmoteSelected()) + { + emoteShortcut->setEmote(index); + emoteShortcut->setEmoteSelected(0); + } + else if (emoteShortcut->getEmote(index)) + { + mEmoteClicked = true; + } +} + +void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (emoteShortcut->isEmoteSelected()) + { + emoteShortcut->setEmoteSelected(0); + } + + if (index == -1) + { + mEmoteMoved = 0; + return; + } + + if (mEmoteMoved) + { + emoteShortcut->setEmotes(index, mEmoteMoved); + mEmoteMoved = 0; + } + else if (emoteShortcut->getEmote(index) && mEmoteClicked) + { + emoteShortcut->useEmote(index + 1); + } + + if (mEmoteClicked) + { + mEmoteClicked = false; + } + } +} + diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h new file mode 100644 index 00000000..d32a9f79 --- /dev/null +++ b/src/gui/emoteshortcutcontainer.h @@ -0,0 +1,77 @@ +/* + * Extended support for activating emotes + * 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 EMOTESHORTCUTCONTAINER_H +#define EMOTESHORTCUTCONTAINER_H + +#include <vector> + +#include "shortcutcontainer.h" + +class AnimatedSprite; +class Image; + +/** + * An emote shortcut container. Used to quickly use emoticons. + * + * \ingroup GUI + */ +class EmoteShortcutContainer : public ShortcutContainer +{ + public: + /** + * Constructor. Initializes the graphic. + */ + EmoteShortcutContainer(); + + /** + * Destructor. + */ + virtual ~EmoteShortcutContainer(); + + /** + * Draws the items. + */ + void draw(gcn::Graphics *graphics); + + /** + * Handles mouse when dragged. + */ + void mouseDragged(gcn::MouseEvent &event); + + /** + * Handles mouse when pressed. + */ + void mousePressed(gcn::MouseEvent &event); + + /** + * Handles mouse release. + */ + void mouseReleased(gcn::MouseEvent &event); + + private: + std::vector<AnimatedSprite*> mEmoteImg; + + bool mEmoteClicked; + int mEmoteMoved; +}; + +#endif diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp new file mode 100644 index 00000000..f4a8999a --- /dev/null +++ b/src/gui/emotewindow.cpp @@ -0,0 +1,77 @@ +/* + * Extended support for activating emotes + * 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 "button.h" +#include "gui.h" +#include "emotewindow.h" +#include "emotecontainer.h" +#include "scrollarea.h" + +#include "widgets/layout.h" + +#include "../localplayer.h" + +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +EmoteWindow::EmoteWindow(): + Window(_("Emote")) +{ + setWindowName(_("Emote")); + setResizable(true); + setCloseButton(true); + setMinWidth(80); + setMinHeight(130); + setDefaultSize(115, 25, 322, 200); + + mUseButton = new Button(_("Use"), "use", this); + + mEmotes = new EmoteContainer(); + mEmotes->addSelectionListener(this); + + mEmoteScroll = new ScrollArea(mEmotes); + mEmoteScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + place(0, 0, mEmoteScroll, 5, 4); + place(4, 4, mUseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + mUseButton->setSize(60, mUseButton->getHeight()); + + loadWindowState(); +} + +void EmoteWindow::action(const gcn::ActionEvent &event) +{ + int emote = mEmotes->getSelectedEmote(); + + if (!emote) + return; + + player_node->emote(emote); +} + +int EmoteWindow::getSelectedEmote() const +{ + return mEmotes->getSelectedEmote(); +} diff --git a/src/gui/buddywindow.h b/src/gui/emotewindow.h index 4eed3a2c..8af24a7b 100644 --- a/src/gui/buddywindow.h +++ b/src/gui/emotewindow.h @@ -1,6 +1,6 @@ /* - * The Mana World - * Copyright (C) 2004 The Mana World Development Team + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team * * This file is part of The Mana World. * @@ -19,38 +19,48 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef BUDDYWINDOW_H -#define BUDDYWINDOW_H +#ifndef EMOTEWINDOW_H +#define EMOTEWINDOW_H #include <guichan/actionlistener.hpp> +#include <guichan/selectionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - -class BuddyList; +class EmoteContainer; +class TextBox; /** - * Window showing buddy list. + * Emote dialog. * * \ingroup Interface */ -class BuddyWindow : public Window, public gcn::ActionListener +class EmoteWindow : public Window, gcn::ActionListener, + gcn::SelectionListener { public: /** * Constructor. */ - BuddyWindow(); + EmoteWindow(); /** - * Performs action. + * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); + /** + * Returns the selected item. + */ + int getSelectedEmote() const; + private: - BuddyList *mBuddyList; - gcn::ListBox *mListbox; + EmoteContainer *mEmotes; + + gcn::Button *mUseButton; + gcn::ScrollArea *mEmoteScroll; }; -#endif /* BUDDYWINDOW_H */ +extern EmoteWindow *emoteWindow; + +#endif diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index aa6825f2..a2be6b00 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -19,14 +19,22 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define BOX_WIDTH 36 +#define BOX_HEIGHT 36 + +#include <guichan/font.hpp> + +#include "button.h" #include "equipmentwindow.h" +#include "itempopup.h" +#include "playerbox.h" +#include "viewport.h" #include "../equipment.h" -#include "../inventory.h" -#include "../localplayer.h" #include "../graphics.h" +#include "../inventory.h" #include "../item.h" -#include "../log.h" +#include "../localplayer.h" #include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" @@ -34,19 +42,60 @@ #include "../utils/gettext.h" #include "../utils/tostring.h" -EquipmentWindow::EquipmentWindow(Equipment *equipment): +// Positions of the boxes, 2nd dimension is X and Y respectively. +static const int boxPosition[][2] = { + {50, 208}, // EQUIP_LEGS_SLOT + {8, 123}, // EQUIP_FIGHT1_SLOT + {8, 78}, // EQUIP_GLOVES_SLOT + {129, 168}, // EQUIP_RING2_SLOT + {8, 168}, // EQUIP_RING1_SLOT + {129, 123}, // EQUIP_FIGHT2_SLOT + {90, 208}, // EQUIP_FEET_SLOT + {50, 40}, // EQUIP_CAPE_SLOT + {70, 0}, // EQUIP_HEAD_SLOT + {90, 40}, // EQUIP_TORSO_SLOT + {129, 78} // EQUIP_AMMO_SLOT +}; + +EquipmentWindow::EquipmentWindow(): Window(_("Equipment")), - mEquipment(equipment) + mSelected(-1) { + mItemPopup = new ItemPopup(); + + // Control that shows the Player + mPlayerBox = new PlayerBox; + mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 123)); + mPlayerBox->setPlayer(player_node); + setWindowName("Equipment"); setCloseButton(true); - setDefaultSize(5, 230, 200, 140); + setDefaultSize(5, 195, 180, 300); loadWindowState(); + + mUnequip = new Button(_("Unequip"), "unequip", this); + gcn::Rectangle const &area = getChildrenArea(); + mUnequip->setPosition(area.width - mUnequip->getWidth() - 5, + area.height - mUnequip->getHeight() - 5); + + add(mPlayerBox); + add(mUnequip); + + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) + { + mEquipBox[i].posX = boxPosition[i][0] + getPadding(); + mEquipBox[i].posY = boxPosition[i][1] + getTitleBarHeight(); + } + + mEquipment = player_node->mEquipment.get(); mInventory = player_node->getInventory(); } EquipmentWindow::~EquipmentWindow() { + delete mUnequip; + delete mItemPopup; + delete mPlayerBox; } void EquipmentWindow::draw(gcn::Graphics *graphics) @@ -54,37 +103,148 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) // Draw window graphics Window::draw(graphics); - Item *item; - Image *image; + Item* item; - // Rectangles around items are black - graphics->setColor(gcn::Color(0, 0, 0)); + Graphics *g = static_cast<Graphics*>(graphics); - for (int i = 0; i < EQUIPMENT_SIZE; i++) { - graphics->drawRectangle(gcn::Rectangle(10 + 36 * (i % 4), - 36 * (i / 4) + 25, 32, 32)); + Window::drawChildren(graphics); - if (!(item = mInventory->getItem(mEquipment->getEquipment(i)))) - continue; + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) + { + item = (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); + if (item) + { + // Draw Item. + Image* image = item->getImage(); + g->drawImage(image, mEquipBox[i].posX, mEquipBox[i].posY); + if (i == EQUIP_AMMO_SLOT) + { + g->setColor(gcn::Color(0, 0, 0)); + graphics->drawText(toString(item->getQuantity()), + mEquipBox[i].posX + (BOX_WIDTH / 2), + mEquipBox[i].posY - getFont()->getHeight(), + gcn::Graphics::CENTER); + } + } - image = item->getImage(); - if (image) + if (i == mSelected) { - static_cast<Graphics*>(graphics)->drawImage( - image, 36 * (i % 4) + 10, 36 * (i / 4) + 25); + // Set color red. + g->setColor(gcn::Color(255, 0, 0)); } + else + { + // Set color black. + g->setColor(gcn::Color(0, 0, 0)); + } + + // Draw box border. + g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY, + BOX_WIDTH, BOX_HEIGHT)); } +} - graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32)); +void EquipmentWindow::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "unequip" && mSelected > -1) + { + Item* item = (mSelected != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(mSelected)) : + mInventory->getItem(mEquipment->getArrows()); + player_node->unequipItem(item); + mSelected = -1; + } +} - if (!(item = mInventory->getItem(mEquipment->getArrows()))) - return; +Item* EquipmentWindow::getItem(const int &x, const int &y) +{ + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) + { + gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, + BOX_WIDTH, BOX_HEIGHT); - image = item->getImage(); - if (image) + if (tRect.isPointInRect(x, y)) + { + return (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); + } + } + return NULL; +} + +void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) +{ + Window::mousePressed(mouseEvent); + + const int x = mouseEvent.getX(); + const int y = mouseEvent.getY(); + + Item* item; + + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + // Checks if any of the presses were in the equip boxes. + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) + { + item = (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); + gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, + BOX_WIDTH, BOX_HEIGHT); + + if (tRect.isPointInRect(x, y)) + { + if (item) + { + mSelected = i; + } + } + } + } + else if (mouseEvent.getButton() == gcn::MouseEvent::RIGHT) + { + item = getItem(x, y); + + if (!item) + return; + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + const int mx = x + getX(); + const int my = y + getY(); + viewport->showPopup(mx, my, item); + } +} + +// Show ItemTooltip +void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) +{ + const int x = event.getX(); + const int y = event.getY(); + + Item* item = getItem(x, y); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item->getInfo()); + mItemPopup->setOpaque(false); + mItemPopup->view(x + getX(), y + getY()); + } + else { - static_cast<Graphics*>(graphics)->drawImage(image, 160, 25); + mItemPopup->setVisible(false); } - graphics->drawText(toString(item->getQuantity()), 170, 62, - gcn::Graphics::CENTER); +} + +// Hide ItemTooltip +void EquipmentWindow::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); } diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index e2420134..c491062a 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -22,23 +22,37 @@ #ifndef EQUIPMENTWINDOW_H #define EQUIPMENTWINDOW_H +#include <guichan/actionlistener.hpp> + #include "window.h" -#include "../inventory.h" class Equipment; +class Inventory; +class Item; +class ItemPopup; +class PlayerBox; + +/** + * Equipment box. + */ +struct EquipBox +{ + int posX; + int posY; +}; /** * Equipment dialog. * * \ingroup Interface */ -class EquipmentWindow : public Window +class EquipmentWindow : public Window, public gcn::ActionListener { public: /** * Constructor. */ - EquipmentWindow(Equipment *equipment); + EquipmentWindow(); /** * Destructor. @@ -50,9 +64,43 @@ class EquipmentWindow : public Window */ void draw(gcn::Graphics *graphics); + void action(const gcn::ActionEvent &event); + + void mousePressed(gcn::MouseEvent& mouseEvent); + + enum { + // Equipment rules: + EQUIP_LEGS_SLOT = 0, + EQUIP_FIGHT1_SLOT, + EQUIP_GLOVES_SLOT, + EQUIP_RING2_SLOT, + EQUIP_RING1_SLOT, + EQUIP_FIGHT2_SLOT, + EQUIP_FEET_SLOT, + EQUIP_CAPE_SLOT, + EQUIP_HEAD_SLOT, + EQUIP_TORSO_SLOT, + EQUIP_AMMO_SLOT, + EQUIP_VECTOREND + }; + + private: + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); + + Item* getItem(const int &x, const int &y); + Equipment *mEquipment; Inventory *mInventory; + gcn::Button *mUnequip; /**< Button for unequipping. */ + EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */ + + ItemPopup *mItemPopup; + + PlayerBox *mPlayerBox; + + int mSelected; /**< Index of selected item. */ }; extern EquipmentWindow *equipmentWindow; diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp index 3ceed595..b9cfd789 100644 --- a/src/gui/focushandler.cpp +++ b/src/gui/focushandler.cpp @@ -21,13 +21,12 @@ #include "focushandler.h" - void FocusHandler::requestModalFocus(gcn::Widget *widget) { /* If there is another widget with modal focus, remove its modal focus * and put it on the modal widget stack. */ - if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget) + if (mModalFocusedWidget && mModalFocusedWidget != widget) { mModalStack.push_front(mModalFocusedWidget); mModalFocusedWidget = NULL; diff --git a/src/gui/focushandler.h b/src/gui/focushandler.h index 124b5472..b0639bd8 100644 --- a/src/gui/focushandler.h +++ b/src/gui/focushandler.h @@ -26,8 +26,6 @@ #include <guichan/focushandler.hpp> -#include "../guichanfwd.h" - /** * The focus handler. This focus handler does exactly the same as the Guichan * focus handler, but keeps a stack of modal widgets to be able to handle diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2da451a3..87304bd1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -19,13 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "gui.h" - #include <guichan/exception.hpp> #include <guichan/image.hpp> #include <guichan/imagefont.hpp> #include "focushandler.h" +#include "gui.h" #include "sdlinput.h" #include "truetypefont.h" #include "viewport.h" @@ -39,12 +38,12 @@ #include "../resources/image.h" #include "../resources/imageset.h" -#include "../resources/resourcemanager.h" #include "../resources/imageloader.h" +#include "../resources/resourcemanager.h" // Guichan stuff Gui *gui = 0; -Viewport *viewport = 0; /**< Viewport on the map. */ +Viewport *viewport = 0; /**< Viewport on the map. */ SDLInput *guiInput = 0; // Fonts used in showing hits @@ -52,6 +51,9 @@ gcn::Font *hitRedFont = 0; gcn::Font *hitBlueFont = 0; gcn::Font *hitYellowFont = 0; +// Bolded font +gcn::Font *boldFont = 0; + class GuiConfigListener : public ConfigListener { public: @@ -61,7 +63,8 @@ class GuiConfigListener : public ConfigListener void optionChanged(const std::string &name) { - if (name == "customcursor") { + if (name == "customcursor") + { bool bCustomCursor = config.getValue("customcursor", 1) == 1; mGui->setUseCustomCursor(bCustomCursor); } @@ -105,7 +108,8 @@ Gui::Gui(Graphics *graphics): // Set global font std::string path = resman->getPath("fonts/dejavusans.ttf"); - try { + try + { const int fontSize = config.getValue("fontSize", 11); mGuiFont = new TrueTypeFont(path, fontSize); } @@ -115,14 +119,28 @@ Gui::Gui(Graphics *graphics): + e.getMessage()); } + // Set bold font + path = resman->getPath("fonts/dejavusans-bold.ttf"); + try + { + const int fontSize = config.getValue("fontSize", 11); + boldFont = new TrueTypeFont(path, fontSize); + } + catch (gcn::Exception e) + { + logger->error(std::string("Unable to load dejavusans-bold.ttf: ") + + e.getMessage()); + } + gcn::Widget::setGlobalFont(mGuiFont); - // Load hits' colourful fonts - try { + // Load hits' colorful fonts + try + { hitRedFont = new gcn::ImageFont("graphics/gui/hits_red.png", - "0123456789"); + "0123456789crit! "); hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png", - "0123456789"); + "0123456789crit! "); hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png", "0123456789misxp "); } @@ -158,6 +176,7 @@ Gui::~Gui() mMouseCursors->decRef(); delete mGuiFont; + delete boldFont; delete viewport; delete getTop(); @@ -167,12 +186,13 @@ Gui::~Gui() void Gui::logic() { // Fade out mouse cursor after extended inactivity - if (mMouseInactivityTimer < 100 * 15) { + if (mMouseInactivityTimer < 100 * 15) + { ++mMouseInactivityTimer; mMouseCursorAlpha = std::min(1.0f, mMouseCursorAlpha + 0.05f); - } else { - mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f); } + else + mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f); gcn::Gui::logic(); } @@ -217,9 +237,8 @@ void Gui::setUseCustomCursor(bool customCursor) mMouseCursors = resman->getImageSet("graphics/gui/mouse.png", 40, 40); - if (!mMouseCursors) { + if (!mMouseCursors) logger->error("Unable to load mouse cursors."); - } } else { @@ -227,7 +246,8 @@ void Gui::setUseCustomCursor(bool customCursor) SDL_ShowCursor(SDL_ENABLE); // Unload the mouse cursor - if (mMouseCursors) { + if (mMouseCursors) + { mMouseCursors->decRef(); mMouseCursors = NULL; } diff --git a/src/gui/gui.h b/src/gui/gui.h index 95cd5815..5c0c24f7 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -26,8 +26,8 @@ #include "../guichanfwd.h" -class GuiConfigListener; class Graphics; +class GuiConfigListener; class ImageSet; class SDLInput; class Viewport; @@ -115,7 +115,6 @@ class Gui : public gcn::Gui }; extern Gui *gui; /**< The GUI system */ -extern Viewport *viewport; /**< The viewport */ extern SDLInput *guiInput; /**< GUI input */ /** @@ -125,4 +124,9 @@ extern gcn::Font *hitRedFont; extern gcn::Font *hitBlueFont; extern gcn::Font *hitYellowFont; +/** + * Bolded text font + */ +extern gcn::Font *boldFont; + #endif diff --git a/src/gui/help.cpp b/src/gui/help.cpp index 390cb44e..ece2dce4 100644 --- a/src/gui/help.cpp +++ b/src/gui/help.cpp @@ -19,12 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "help.h" - #include "button.h" #include "browserbox.h" +#include "help.h" #include "scrollarea.h" +#include "widgets/layout.h" + #include "../resources/resourcemanager.h" #include "../utils/gettext.h" @@ -32,8 +33,11 @@ HelpWindow::HelpWindow(): Window(_("Help")) { + setMinWidth(300); + setMinHeight(250); setContentSize(455, 350); - setWindowName("Help"); + setWindowName(_("Help")); + setResizable(true); mBrowserBox = new BrowserBox(); mBrowserBox->setOpaque(false); @@ -48,8 +52,11 @@ HelpWindow::HelpWindow(): mBrowserBox->setLinkHandler(this); - add(mScrollArea); - add(okButton); + place(0, 0, mScrollArea, 5, 3).setPadding(3); + place(4, 3, okButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); } diff --git a/src/gui/help.h b/src/gui/help.h index e3d9246d..98e3aa67 100644 --- a/src/gui/help.h +++ b/src/gui/help.h @@ -24,10 +24,8 @@ #include <guichan/actionlistener.hpp> -#include "window.h" #include "linkhandler.h" - -#include "../guichanfwd.h" +#include "window.h" class BrowserBox; diff --git a/src/gui/inttextfield.cpp b/src/gui/inttextfield.cpp index eb61c4d7..fcbe938d 100644 --- a/src/gui/inttextfield.cpp +++ b/src/gui/inttextfield.cpp @@ -20,7 +20,6 @@ */ #include "inttextfield.h" - #include "sdlinput.h" #include "../utils/tostring.h" diff --git a/src/gui/inttextfield.h b/src/gui/inttextfield.h index 4dfef8e1..add78084 100644 --- a/src/gui/inttextfield.h +++ b/src/gui/inttextfield.h @@ -58,8 +58,7 @@ class IntTextField : public TextField /** * Responds to key presses. */ - void - keyPressed(gcn::KeyEvent &event); + void keyPressed(gcn::KeyEvent &event); private: int mMin; /**< Minimum value */ diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index 31ebb86e..af3b29a2 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -19,72 +19,101 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "inventorywindow.h" - #include <string> +#include <guichan/font.hpp> #include <guichan/mouseinput.hpp> + #include <guichan/widgets/label.hpp> #include "button.h" -#include "gui.h" +#include "inventorywindow.h" #include "item_amount.h" #include "itemcontainer.h" +#include "progressbar.h" #include "scrollarea.h" #include "viewport.h" +#include "widgets/layout.h" + #include "../inventory.h" #include "../item.h" -#include "../localplayer.h" #include "../resources/iteminfo.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" +#include "../utils/tostring.h" -InventoryWindow::InventoryWindow(): - Window(_("Inventory")) +InventoryWindow::InventoryWindow(int invSize): + Window(_("Inventory")), + mMaxSlots(invSize), + mItemDesc(false) { - setWindowName("Inventory"); + setWindowName(_("Inventory")); setResizable(true); setCloseButton(true); - setMinWidth(240); - setMinHeight(172); + // If you adjust these defaults, don't forget to adjust the trade window's. - setDefaultSize(115, 25, 322, 200); + setDefaultSize(115, 25, 375, 300); - mUseButton = new Button(_("Use"), "use", this); + std::string longestUseString = getFont()->getWidth(_("Equip")) > + getFont()->getWidth(_("Use")) ? + _("Equip") : _("Use"); + + if (getFont()->getWidth(longestUseString) < + getFont()->getWidth(_("Unequip"))) + { + longestUseString = _("Unequip"); + } + + mUseButton = new Button(longestUseString, "use", this); mDropButton = new Button(_("Drop"), "drop", this); - mItems = new ItemContainer(player_node->getInventory()); + mItems = new ItemContainer(player_node->getInventory(), 2); mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mItemNameLabel = new gcn::Label("Name:"); - mItemDescriptionLabel = new gcn::Label("Description:"); - mItemEffectLabel = new gcn::Label("Effect:"); - mWeightLabel = new gcn::Label("Weight:"); - mWeightLabel->setPosition(8, 8); - mInvenScroll->setPosition(8, - mWeightLabel->getY() + mWeightLabel->getHeight() + 5); - mInvenSlotLabel = new gcn::Label("Slots used:"); - mInvenSlotLabel->setPosition(mWeightLabel->getX() - + mWeightLabel->getWidth() + 100, 8); - - add(mUseButton); - add(mDropButton); - add(mInvenScroll); - add(mItemNameLabel); - add(mItemDescriptionLabel); - add(mItemEffectLabel); - add(mWeightLabel); - add(mInvenSlotLabel); - - mUseButton->setSize(60, mUseButton->getHeight()); + mTotalWeight = toString(player_node->mTotalWeight); + mMaxWeight = toString(player_node->mMaxWeight); + mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed()); + + mSlotsLabel = new gcn::Label(_("Slots: ")); + mWeightLabel = new gcn::Label(_("Weight: ")); + + mSlotsBar = new ProgressBar(1.0f, 100, 20, 225, 200, 25); + mWeightBar = new ProgressBar(1.0f, 100, 20, 0, 0, 255); + + setMinHeight(130); + setMinWidth(mWeightLabel->getWidth() + mSlotsLabel->getWidth() + 280); + + place(0, 0, mWeightLabel).setPadding(3); + place(1, 0, mWeightBar, 3); + place(4, 0, mSlotsLabel).setPadding(3); + place(5, 0, mSlotsBar, 2); + place(0, 1, mInvenScroll, 7, 4); + place(5, 5, mDropButton); + place(6, 5, mUseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, mDropButton->getHeight()); loadWindowState(); + setLocationRelativeTo(getParent()); +} + +InventoryWindow::~InventoryWindow() +{ + delete mWeightBar; + delete mSlotsBar; + delete mUseButton; + delete mDropButton; + delete mItems; + delete mWeightLabel; + delete mSlotsLabel; + delete mInvenScroll; } void InventoryWindow::logic() @@ -95,15 +124,39 @@ void InventoryWindow::logic() // redesign of InventoryWindow and ItemContainer probably. updateButtons(); - // Update weight information - mWeightLabel->setCaption(strprintf(_("Weight: %d / %d"), - player_node->mTotalWeight, - player_node->mMaxWeight)); + if ((mMaxWeight != toString(player_node->mMaxWeight)) || + mTotalWeight != toString(player_node->mTotalWeight) || + mUsedSlots != toString(player_node->getInventory()->getNumberOfSlotsUsed())) + { + mTotalWeight = toString(player_node->mTotalWeight); + mMaxWeight = toString(player_node->mMaxWeight); + mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed()); + + // Weight Bar coloration + if (int(player_node->mTotalWeight) < int(player_node->mMaxWeight / 3)) + { + mWeightBar->setColor(0, 0, 255); // Blue + } + else if (int(player_node->mTotalWeight) < + int((player_node->mMaxWeight / 3) * 2)) + { + mWeightBar->setColor(255, 255, 0); // Yellow + } + else + { + mWeightBar->setColor(255, 0, 0); // Red + } + + // Adjust progress bars + mSlotsBar->setProgress((float) + player_node->getInventory()->getNumberOfSlotsUsed() / mMaxSlots); + mWeightBar->setProgress((float) player_node->mTotalWeight / + player_node->mMaxWeight); - // Update number of items in inventory - mInvenSlotLabel->setCaption(strprintf(_("Slots used: %d / %d"), - player_node->getInventory()->getNumberOfSlotsUsed(), - player_node->getInventory()->getInventorySize())); + mSlotsBar->setText(strprintf("%s/%d", mUsedSlots.c_str(), mMaxSlots)); + mWeightBar->setText(strprintf("%sg/%sg", mTotalWeight.c_str(), + mMaxWeight.c_str())); + } } void InventoryWindow::action(const gcn::ActionEvent &event) @@ -113,55 +166,30 @@ void InventoryWindow::action(const gcn::ActionEvent &event) if (!item) return; - if (event.getId() == "use") { - if (item->isEquipment()) { - if (item->isEquipped()) { + if (event.getId() == "use") + { + if (item->isEquipment()) + { + if (item->isEquipped()) player_node->unequipItem(item); - } - else { + else player_node->equipItem(item); - } } - else { + else player_node->useItem(item); - } } else if (event.getId() == "drop") { - if (item->getQuantity() == 1) { + if (item->getQuantity() == 1) player_node->dropItem(item, 1); - } - else { + else + { // Choose amount of items to drop new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item); } } } -void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) -{ - const Item *item = mItems->getSelectedItem(); - - // Update name, effect and description - if (!item) - { - mItemNameLabel->setCaption(strprintf(_("Name: %s"), "")); - mItemEffectLabel->setCaption(strprintf(_("Effect: %s"), "")); - mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"), "")); - } - else - { - const ItemInfo& itemInfo = item->getInfo(); - mItemNameLabel->setCaption( - strprintf(_("Name: %s"), itemInfo.getName().c_str())); - mItemEffectLabel->setCaption( - strprintf(_("Effect: %s"), itemInfo.getEffect().c_str())); - mItemDescriptionLabel->setCaption( - strprintf(_("Description: %s"), - itemInfo.getDescription().c_str())); - } -} - void InventoryWindow::mouseClicked(gcn::MouseEvent &event) { Window::mouseClicked(event); @@ -182,55 +210,19 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) } } -void InventoryWindow::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - // Adjust widgets - mUseButton->setPosition(8, height - 8 - mUseButton->getHeight()); - mDropButton->setPosition(8 + mUseButton->getWidth() + 5, - mUseButton->getY()); - - mItemNameLabel->setDimension(gcn::Rectangle(8, - mUseButton->getY() - 5 - mItemNameLabel->getHeight(), - width - 16, - mItemNameLabel->getHeight())); - mItemEffectLabel->setDimension(gcn::Rectangle(8, - mItemNameLabel->getY() - 5 - mItemEffectLabel->getHeight(), - width - 16, - mItemEffectLabel->getHeight())); - mItemDescriptionLabel->setDimension(gcn::Rectangle(8, - mItemEffectLabel->getY() - 5 - mItemDescriptionLabel->getHeight(), - width - 16, - mItemDescriptionLabel->getHeight())); - - mInvenScroll->setSize(width - 16, - mItemDescriptionLabel->getY() - mWeightLabel->getHeight() - 18); - - mWeightLabel->setWidth(width - 16); - mInvenSlotLabel->setWidth(width - 16); -} - void InventoryWindow::updateButtons() { const Item *selectedItem = mItems->getSelectedItem(); if (selectedItem && selectedItem->isEquipment()) { - if (selectedItem->isEquipped()) { + if (selectedItem->isEquipped()) mUseButton->setCaption(_("Unequip")); - } - else { + else mUseButton->setCaption(_("Equip")); - } } - else { + else mUseButton->setCaption(_("Use")); - } mUseButton->setEnabled(selectedItem != 0); mDropButton->setEnabled(selectedItem != 0); diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 402ab0d2..78d30461 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -27,10 +27,12 @@ #include "window.h" -#include "../guichanfwd.h" +#include "../localplayer.h" class Item; class ItemContainer; +class ProgressBar; +class TextBox; /** * Inventory dialog. @@ -38,13 +40,18 @@ class ItemContainer; * \ingroup Interface */ class InventoryWindow : public Window, gcn::ActionListener, - gcn::SelectionListener + gcn::SelectionListener { public: /** * Constructor. */ - InventoryWindow(); + InventoryWindow(int invSize = (INVENTORY_SIZE - 2)); + + /** + * Destructor. + */ + ~InventoryWindow(); /** * Logic (updates buttons and weight information). @@ -61,30 +68,30 @@ class InventoryWindow : public Window, gcn::ActionListener, */ Item* getSelectedItem() const; - /** - * Updates labels to currently selected item. - */ - void valueChanged(const gcn::SelectionEvent &event); - void mouseClicked(gcn::MouseEvent &event); - /** - * Called whenever the widget changes size. - */ - void widgetResized(const gcn::Event &event); - private: void updateButtons(); /**< Updates button states. */ ItemContainer *mItems; + std::string mWeight; + std::string mSlots; + std::string mUsedSlots; + std::string mTotalWeight; + std::string mMaxWeight; gcn::Button *mUseButton, *mDropButton; gcn::ScrollArea *mInvenScroll; - gcn::Label *mItemNameLabel; - gcn::Label *mItemDescriptionLabel; - gcn::Label *mItemEffectLabel; + gcn::Label *mWeightLabel; - gcn::Label *mInvenSlotLabel; + gcn::Label *mSlotsLabel; + + ProgressBar *mWeightBar; + ProgressBar *mSlotsBar; + + int mMaxSlots; + + bool mItemDesc; }; extern InventoryWindow *inventoryWindow; diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp index 7ef3d71b..92be3d6e 100644 --- a/src/gui/item_amount.cpp +++ b/src/gui/item_amount.cpp @@ -19,10 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "item_amount.h" - #include "button.h" #include "inttextfield.h" +#include "item_amount.h" #include "slider.h" #include "trade.h" @@ -71,7 +70,8 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item): resetAmount(); - switch (usage) { + switch (usage) + { case AMOUNT_TRADE_ADD: setCaption(_("Select amount of items to trade.")); okButton->setActionEventId("AddTrade"); diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h index d8eedadb..618d7d51 100644 --- a/src/gui/item_amount.h +++ b/src/gui/item_amount.h @@ -22,14 +22,10 @@ #ifndef ITEM_AMOUNT_WINDOW_H #define ITEM_AMOUNT_WINDOW_H -#include <iosfwd> - #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - class IntTextField; class Item; diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index a0885279..0beb5cfb 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -21,17 +21,21 @@ #include "itemcontainer.h" +#include "itempopup.h" + #include <guichan/mouseinput.hpp> #include <guichan/selectionlistener.hpp> +#include <SDL_mouse.h> + #include "../graphics.h" #include "../inventory.h" #include "../item.h" #include "../itemshortcut.h" +#include "../localplayer.h" #include "../log.h" #include "../resources/image.h" -#include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" #include "../utils/tostring.h" @@ -41,11 +45,14 @@ const int ItemContainer::gridHeight = 42; // item icon height + 10 static const int NO_ITEM = -1; -ItemContainer::ItemContainer(Inventory *inventory): +ItemContainer::ItemContainer(Inventory *inventory, int offset): mInventory(inventory), mSelectedItemIndex(NO_ITEM), - mLastSelectedItemId(NO_ITEM) + mLastSelectedItemId(NO_ITEM), + mOffset(offset) { + mItemPopup = new ItemPopup(); + ResourceManager *resman = ResourceManager::getInstance(); mSelImg = resman->getImage("graphics/gui/selection.png"); @@ -60,6 +67,7 @@ ItemContainer::ItemContainer(Inventory *inventory): ItemContainer::~ItemContainer() { mSelImg->decRef(); + delete mItemPopup; } void ItemContainer::logic() @@ -86,10 +94,11 @@ void ItemContainer::draw(gcn::Graphics *graphics) } /* - * eAthena seems to start inventory from the 3rd slot. Still a mystery to - * us why, make sure not to copy this oddity to our own server. + * mOffset is used to compensate for some weirdness that eAthena inherited from + * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index, + * while storage slots are +1. */ - for (int i = 2; i < INVENTORY_SIZE; i++) + for (int i = mOffset; i < mInventory->getSize(); i++) { Item *item = mInventory->getItem(i); @@ -115,6 +124,7 @@ void ItemContainer::draw(gcn::Graphics *graphics) } // Draw item caption + graphics->setFont(getFont()); graphics->setColor(gcn::Color(0, 0, 0)); graphics->drawText( (item->isEquipped() ? "Eq." : toString(item->getQuantity())), @@ -138,6 +148,7 @@ void ItemContainer::recalculateHeight() const int rows = (mMaxItems / cols) + (mMaxItems % cols > 0 ? 1 : 0); const int height = rows * gridHeight + 8; + if (height != getHeight()) setHeight(height); } @@ -159,8 +170,8 @@ void ItemContainer::selectNone() void ItemContainer::refindSelectedItem() { - if (mSelectedItemIndex != NO_ITEM) { - + if (mSelectedItemIndex != NO_ITEM) + { if (mInventory->getItem(mSelectedItemIndex) && mInventory->getItem(mSelectedItemIndex)->getId() == mLastSelectedItemId) return; // we're already fine @@ -170,7 +181,8 @@ void ItemContainer::refindSelectedItem() for (int i = 0; i <= mMaxItems + 1; i++) if (mInventory->getItem(i) && - mInventory->getItem(i)->getId() == mLastSelectedItemId) { + mInventory->getItem(i)->getId() == mLastSelectedItemId) + { mSelectedItemIndex = i; return; } @@ -179,14 +191,16 @@ void ItemContainer::refindSelectedItem() mLastSelectedItemId = mSelectedItemIndex = NO_ITEM; } - void ItemContainer::setSelectedItemIndex(int index) { int newSelectedItemIndex; - // mMaxItems is broken because of eAthena's odd inventory layout and the client's refusal - // to handle it properly, so we work around the issue right here. - if (index < 0 || index > mMaxItems + 1 || mInventory->getItem(index) == NULL) + /* + * mOffset is used to compensate for some weirdness that eAthena inherited from + * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index, + * while storage slots are +1. + */ + if (index < 0 || index > mMaxItems + mOffset || mInventory->getItem(index) == NULL) newSelectedItemIndex = NO_ITEM; else newSelectedItemIndex = index; @@ -218,14 +232,14 @@ void ItemContainer::distributeValueChangedEvent() void ItemContainer::mousePressed(gcn::MouseEvent &event) { - int button = event.getButton(); + const int button = event.getButton(); if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT) { int columns = getWidth() / gridWidth; int mx = event.getX(); int my = event.getY(); - int index = mx / gridWidth + ((my / gridHeight) * columns) + 2; + int index = mx / gridWidth + ((my / gridHeight) * columns) + mOffset; itemShortcut->setItemSelected(-1); setSelectedItemIndex(index); @@ -236,3 +250,38 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event) itemShortcut->setItemSelected(item->getId()); } } + +// Show ItemTooltip +void ItemContainer::mouseMoved(gcn::MouseEvent &event) +{ + Item *item = mInventory->getItem(getSlotIndex(event.getX(), event.getY())); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item->getInfo()); + mItemPopup->setOpaque(false); + mItemPopup->view(mouseX, mouseY); + } + else + { + mItemPopup->setVisible(false); + } +} + +// Hide ItemTooltip +void ItemContainer::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); +} + +int ItemContainer::getSlotIndex(const int posX, const int posY) const +{ + int columns = getWidth() / gridWidth; + int index = posX / gridWidth + ((posY / gridHeight) * columns) + mOffset; + + return (index); +} + diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h index a40237af..71fcc5d0 100644 --- a/src/gui/itemcontainer.h +++ b/src/gui/itemcontainer.h @@ -22,15 +22,16 @@ #ifndef ITEMCONTAINER_H #define ITEMCONTAINER_H +#include <list> + #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> #include <guichan/widgetlistener.hpp> -#include <list> - class Image; class Inventory; class Item; +class ItemPopup; namespace gcn { class SelectionListener; @@ -41,14 +42,15 @@ namespace gcn { * * \ingroup GUI */ -class ItemContainer : public gcn::Widget, public gcn::MouseListener, - public gcn::WidgetListener +class ItemContainer : public gcn::Widget, + public gcn::MouseListener, + public gcn::WidgetListener { public: /** * Constructor. Initializes the graphic. */ - ItemContainer(Inventory *inventory); + ItemContainer(Inventory *inventory, int offset); /** * Destructor. @@ -104,7 +106,11 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener, } private: + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); + /** + * Sets the currently selected item. Invalid (e.g., negative) indices set `no item'. */ void setSelectedItemIndex(int index); @@ -124,12 +130,24 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener, */ void distributeValueChangedEvent(); + /** + * Gets the slot index based on the cursor position. + * + * @param posX The X Coordinate position. + * @param posY The Y Coordinate position. + * @return The slot index on success, -1 on failure. + */ + int getSlotIndex(const int posX, const int posY) const; + Inventory *mInventory; Image *mSelImg; - int mSelectedItemIndex; - int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID. + int mSelectedItemIndex; + int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID. int mMaxItems; + int mOffset; + + ItemPopup *mItemPopup; std::list<gcn::SelectionListener*> mListeners; diff --git a/src/gui/itemlinkhandler.cpp b/src/gui/itemlinkhandler.cpp new file mode 100644 index 00000000..97c0b94f --- /dev/null +++ b/src/gui/itemlinkhandler.cpp @@ -0,0 +1,63 @@ +/* + * The Mana World + * Copyright 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sstream> +#include <string> + +#include <SDL_mouse.h> + +#include "itemlinkhandler.h" +#include "itempopup.h" + +#include "../resources/iteminfo.h" +#include "../resources/itemdb.h" + +ItemLinkHandler::ItemLinkHandler() +{ + mItemPopup = new ItemPopup; +} + +ItemLinkHandler::~ItemLinkHandler() +{ + delete mItemPopup; +} + +void ItemLinkHandler::handleLink(const std::string &link) +{ + int id = 0; + std::stringstream stream; + stream << link; + stream >> id; + if (id > 0) + { + const ItemInfo &iteminfo = ItemDB::get(id); + int mouseX, mouseY; + + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(iteminfo); + + if (mItemPopup->isVisible()) + mItemPopup->setVisible(false); + else + mItemPopup->view(mouseX, mouseY); + } +} diff --git a/src/gui/itemlinkhandler.h b/src/gui/itemlinkhandler.h new file mode 100644 index 00000000..cd6fd900 --- /dev/null +++ b/src/gui/itemlinkhandler.h @@ -0,0 +1,40 @@ +/* + * The Mana World + * Copyright 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ITEM_LINK_HANDLER_H_ +#define ITEM_LINK_HANDLER_H_ + +#include "linkhandler.h" + +class ItemPopup; + +class ItemLinkHandler : public LinkHandler +{ + public: + ItemLinkHandler(); + ~ItemLinkHandler(); + void handleLink(const std::string &link); + + private: + ItemPopup *mItemPopup; +}; + +#endif diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp new file mode 100644 index 00000000..4c117f0a --- /dev/null +++ b/src/gui/itempopup.cpp @@ -0,0 +1,216 @@ +/* + * The Mana World + * Copyright (C) 2008 The Legend of Mazzeroth Development Team + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/font.hpp> + +#include <guichan/widgets/label.hpp> + +#include "gui.h" +#include "itempopup.h" +#include "scrollarea.h" +#include "textbox.h" +#include "windowcontainer.h" + +#include "widgets/layout.h" + +#include "../resources/iteminfo.h" + +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +ItemPopup::ItemPopup(): + Window() +{ + setResizable(false); + setShowTitle(false); + setTitleBarHeight(0); + + // Item Name + mItemName = new gcn::Label("Label"); + mItemName->setFont(boldFont); + mItemName->setPosition(2, 2); + + // Item Description + mItemDesc = new TextBox(); + mItemDesc->setEditable(false); + mItemDescScroll = new ScrollArea(mItemDesc); + + mItemDescScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemDescScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemDescScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); + mItemDescScroll->setOpaque(false); + mItemDescScroll->setPosition(2, getFont()->getHeight()); + + // Item Effect + mItemEffect = new TextBox(); + mItemEffect->setEditable(false); + mItemEffectScroll = new ScrollArea(mItemEffect); + + mItemEffectScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemEffectScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemEffectScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); + mItemEffectScroll->setOpaque(false); + mItemEffectScroll->setPosition(2, (2 * getFont()->getHeight()) + 5); + + // Item Weight + mItemWeight = new TextBox(); + mItemWeight->setEditable(false); + mItemWeightScroll = new ScrollArea(mItemWeight); + + mItemWeightScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemWeightScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemWeightScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); + mItemWeightScroll->setOpaque(false); + mItemWeightScroll->setPosition(2, (3 * getFont()->getHeight()) + 10); + + add(mItemName); + add(mItemDescScroll); + add(mItemEffectScroll); + add(mItemWeightScroll); + + setLocationRelativeTo(getParent()); +} + +ItemPopup::~ItemPopup() +{ + delete mItemName; + delete mItemDesc; + delete mItemDescScroll; + delete mItemEffect; + delete mItemEffectScroll; + delete mItemWeight; + delete mItemWeightScroll; +} + +void ItemPopup::setItem(const ItemInfo &item) +{ + mItemName->setCaption(item.getName()); + mItemName->setForegroundColor(getColor(item.getType())); + mItemName->setWidth(boldFont->getWidth(item.getName())); + mItemDesc->setTextWrapped(item.getDescription(), 196); + mItemEffect->setTextWrapped(item.getEffect(), 196); + mItemWeight->setTextWrapped(_("Weight: ") + toString(item.getWeight()) + + _(" grams"), 196); + + int minWidth = mItemName->getWidth(); + + if (mItemDesc->getMinWidth() > minWidth) + minWidth = mItemDesc->getMinWidth(); + if (mItemEffect->getMinWidth() > minWidth) + minWidth = mItemEffect->getMinWidth(); + if (mItemWeight->getMinWidth() > minWidth) + minWidth = mItemWeight->getMinWidth(); + + minWidth += 8; + setWidth(minWidth); + + int numRowsDesc = mItemDesc->getNumberOfRows(); + int numRowsEffect = mItemEffect->getNumberOfRows(); + int numRowsWeight = mItemWeight->getNumberOfRows(); + + mItemDescScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsDesc * getFont()->getHeight())); + + mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsEffect * getFont()->getHeight())); + + mItemWeightScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsWeight * getFont()->getHeight())); + + if (item.getEffect().empty()) + { + setContentSize(minWidth, (numRowsDesc * getFont()->getHeight() + + (3 * getFont()->getHeight()))); + + mItemWeightScroll->setPosition(2, + (numRowsDesc * getFont()->getHeight()) + + (2 * getFont()->getHeight())); + } + else + { + setContentSize(minWidth, (numRowsDesc * getFont()->getHeight()) + + (numRowsEffect * getFont()->getHeight()) + + (3 * getFont()->getHeight())); + + mItemWeightScroll->setPosition(2, + (numRowsDesc * getFont()->getHeight()) + + (numRowsEffect * getFont()->getHeight()) + + (2 * getFont()->getHeight())); + } + + mItemDescScroll->setPosition(2, 20); + mItemEffectScroll->setPosition(2, (numRowsDesc * getFont()->getHeight()) + + (2 * getFont()->getHeight())); +} + +gcn::Color ItemPopup::getColor(const std::string& type) +{ + gcn::Color color; + + if (type.compare("generic") == 0) + color = 0x21a5b1; + else if (type.compare("equip-head") == 0) + color = 0x527fa4; + else if (type.compare("usable") == 0) + color = 0x268d24; + else if (type.compare("equip-torso") == 0) + color = 0xd12aa4; + else if (type.compare("equip-1hand") == 0) + color = 0xf42a2a; + else if (type.compare("equip-legs") == 0) + color = 0x699900; + else if (type.compare("equip-feet") == 0) + color = 0xaa1d48; + else if (type.compare("equip-2hand") == 0) + color = 0xf46d0e; + else if (type.compare("equip-shield") == 0) + color = 0x9c2424; + else if (type.compare("equip-ring") == 0) + color = 0x0000ff; + else if (type.compare("equip-arms") == 0) + color = 0x9c24e8; + else if (type.compare("equip-ammo") == 0) + color = 0x8b6311; + else + color = 0x000000; + + return color; +} + +unsigned int ItemPopup::getNumRows() +{ + return mItemDesc->getNumberOfRows() + mItemEffect->getNumberOfRows() + + mItemWeight->getNumberOfRows(); +} + +void ItemPopup::view(int x, int y) +{ + if (windowContainer->getWidth() < (x + getWidth() + 5)) + x = windowContainer->getWidth() - getWidth(); + if ((y - getHeight() - 10) < 0) + y = 0; + else + y = y - getHeight() - 10; + setPosition(x, y); + setVisible(true); + requestMoveToTop(); +} diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h new file mode 100644 index 00000000..c820e3a0 --- /dev/null +++ b/src/gui/itempopup.h @@ -0,0 +1,54 @@ +/* + * The Mana World + * Copyright (C) 2008 The Legend of Mazzeroth Development Team + * 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 ITEMPOPUP_H +#define ITEMPOPUP_H + +#include "window.h" + +class ItemInfo; +class ScrollArea; +class TextBox; + +class ItemPopup : public Window +{ + public: + ItemPopup(); + ~ItemPopup(); + + void setItem(const ItemInfo &item); + unsigned int getNumRows(); + void view(int x, int y); + + private: + gcn::Label *mItemName; + TextBox *mItemDesc; + TextBox *mItemEffect; + TextBox *mItemWeight; + ScrollArea *mItemDescScroll; + ScrollArea *mItemEffectScroll; + ScrollArea *mItemWeightScroll; + + gcn::Color getColor(const std::string& type); +}; + +#endif // ITEMPOPUP_H diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index b2f70348..42e3b853 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -18,15 +18,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <SDL_mouse.h> #include "itemshortcutcontainer.h" +#include "itempopup.h" +#include "viewport.h" -#include "../localplayer.h" +#include "../configuration.h" #include "../graphics.h" #include "../inventory.h" #include "../item.h" #include "../itemshortcut.h" #include "../keyboardconfig.h" +#include "../localplayer.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" @@ -34,30 +38,33 @@ #include "../utils/tostring.h" ItemShortcutContainer::ItemShortcutContainer(): - mGridWidth(1), - mGridHeight(1), + ShortcutContainer(), mItemClicked(false), mItemMoved(NULL) { addMouseListener(this); addWidgetListener(this); + mItemPopup = new ItemPopup(); + ResourceManager *resman = ResourceManager::getInstance(); mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); mMaxItems = itemShortcut->getItemCount(); - mBoxHeight = 42; - mBoxWidth = 36; + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + + mBoxHeight = mBackgroundImg->getHeight(); + mBoxWidth = mBackgroundImg->getWidth(); } ItemShortcutContainer::~ItemShortcutContainer() { mBackgroundImg->decRef(); + delete mItemPopup; } -void -ItemShortcutContainer::logic() +void ItemShortcutContainer::logic() { gcn::Widget::logic(); @@ -70,8 +77,7 @@ ItemShortcutContainer::logic() } } -void -ItemShortcutContainer::draw(gcn::Graphics *graphics) +void ItemShortcutContainer::draw(gcn::Graphics *graphics) { Graphics *g = static_cast<Graphics*>(graphics); @@ -87,7 +93,8 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) // Draw item keyboard shortcut. const char *key = SDL_GetKeyName( - (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_0 + i)); + (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_1 + i)); + graphics->setColor(0x000000); g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT); if (itemShortcut->getItem(i) < 0) @@ -97,6 +104,8 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) player_node->getInventory()->findItem(itemShortcut->getItem(i)); if (item) { // Draw item icon. + const std::string label = + item->isEquipped() ? "Eq." : toString(item->getQuantity()); Image* image = item->getImage(); if (image) { const std::string label = @@ -127,37 +136,30 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) gcn::Graphics::CENTER); } } -} -void ItemShortcutContainer::widgetResized(const gcn::Event &event) -{ - mGridWidth = getWidth() / mBoxWidth; - if (mGridWidth < 1) { - mGridWidth = 1; - } - - setHeight((mMaxItems / mGridWidth + - (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight); - - mGridHeight = getHeight() / mBoxHeight; - if (mGridHeight < 1) { - mGridHeight = 1; + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); } } -void -ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) +void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) { - if (event.getButton() == gcn::MouseEvent::LEFT) { - if (!mItemMoved && mItemClicked) { + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (!mItemMoved && mItemClicked) + { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { - return; - } const int itemId = itemShortcut->getItem(index); + + if (index == -1) + return; + if (itemId < 0) return; + Item *item = player_node->getInventory()->findItem(itemId); + if (item) { mItemMoved = item; @@ -171,39 +173,56 @@ ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) } } -void -ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) +void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { + if (index == -1) return; - } - // Stores the selected item if theirs one. - if (itemShortcut->isItemSelected()) { - itemShortcut->setItem(index); - itemShortcut->setItemSelected(-1); + if (event.getButton() == gcn::MouseEvent::LEFT) + { + + // Stores the selected item if theirs one. + if (itemShortcut->isItemSelected()) + { + itemShortcut->setItem(index); + itemShortcut->setItemSelected(-1); + } + else if (itemShortcut->getItem(index)) + mItemClicked = true; } - else if (itemShortcut->getItem(index)) { - mItemClicked = true; + else if (event.getButton() == gcn::MouseEvent::RIGHT) + { + Item *item = player_node->getInventory()-> + findItem(itemShortcut->getItem(index)); + + if (!item) + return; + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + int mx, my; + SDL_GetMouseState(&mx, &my); + viewport->showPopup(mx, my, item); } } -void -ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) +void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) { if (event.getButton() == gcn::MouseEvent::LEFT) { if (itemShortcut->isItemSelected()) - { itemShortcut->setItemSelected(-1); - } + const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { + if (index == -1) + { mItemMoved = NULL; return; } - if (mItemMoved) { + if (mItemMoved) + { itemShortcut->setItems(index, mItemMoved->getId()); mItemMoved = NULL; } @@ -211,25 +230,43 @@ ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) { itemShortcut->useItem(index); } - if (mItemClicked) { + if (mItemClicked) mItemClicked = false; - } } } -int -ItemShortcutContainer::getIndexFromGrid(int pointX, int pointY) const +// Show ItemTooltip +void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) { - const gcn::Rectangle tRect = gcn::Rectangle( - 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); - if (!tRect.isPointInRect(pointX, pointY)) { - return -1; + const int index = getIndexFromGrid(event.getX(), event.getY()); + const int itemId = itemShortcut->getItem(index); + + if (index == -1) + return; + + if (itemId < 0) + return; + + Item *item = player_node->getInventory()->findItem(itemId); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item->getInfo()); + mItemPopup->setOpaque(false); + mItemPopup->view(mouseX, mouseY); } - const int index = ((pointY / mBoxHeight) * mGridWidth) + - pointX / mBoxWidth; - if (index >= mMaxItems) + else { - return -1; + mItemPopup->setVisible(false); } - return index; } + +// Hide ItemTooltip +void ItemShortcutContainer::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); +} + diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h index cdaf6713..22d94ec2 100644 --- a/src/gui/itemshortcutcontainer.h +++ b/src/gui/itemshortcutcontainer.h @@ -23,20 +23,19 @@ #define ITEMSHORTCUTCONTAINER_H #include <guichan/mouselistener.hpp> -#include <guichan/widget.hpp> -#include <guichan/widgetlistener.hpp> + +#include "shortcutcontainer.h" class Image; class Item; +class ItemPopup; /** * An item shortcut container. Used to quickly use items. * * \ingroup GUI */ -class ItemShortcutContainer : public gcn::Widget, - public gcn::WidgetListener, - public gcn::MouseListener +class ItemShortcutContainer : public ShortcutContainer { public: /** @@ -60,12 +59,6 @@ class ItemShortcutContainer : public gcn::Widget, void draw(gcn::Graphics *graphics); /** - * Invoked when a widget changes its size. This is used to determine - * the new height of the container. - */ - void widgetResized(const gcn::Event &event); - - /** * Handles mouse when dragged. */ void mouseDragged(gcn::MouseEvent &event); @@ -80,34 +73,14 @@ class ItemShortcutContainer : public gcn::Widget, */ void mouseReleased(gcn::MouseEvent &event); - int getMaxItems() - { return mMaxItems; } - - int getBoxWidth() - { return mBoxWidth; } - - int getBoxHeight() - { return mBoxHeight; } - private: - /** - * Gets the index from the grid provided the point is in an item box. - * - * @param pointX X coordinate of the point. - * @param pointY Y coordinate of the point. - * @return index on success, -1 on failure. - */ - int getIndexFromGrid(int pointX, int pointY) const; + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); - Image *mBackgroundImg; - - int mMaxItems; - int mBoxWidth; - int mBoxHeight; - int mCursorPosX, mCursorPosY; - int mGridWidth, mGridHeight; bool mItemClicked; Item *mItemMoved; + + ItemPopup *mItemPopup; }; #endif diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp index b72c64cf..63e55e24 100644 --- a/src/gui/listbox.cpp +++ b/src/gui/listbox.cpp @@ -19,12 +19,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "listbox.h" - #include <guichan/font.hpp> #include <guichan/graphics.hpp> #include <guichan/listmodel.hpp> -#include <guichan/mouseinput.hpp> + +#include "color.h" +#include "listbox.h" + +#include "../configuration.h" + +float ListBox::mAlpha = config.getValue("guialpha", 0.8); ListBox::ListBox(gcn::ListModel *listModel): gcn::ListBox(listModel) @@ -36,29 +40,35 @@ void ListBox::draw(gcn::Graphics *graphics) if (!mListModel) return; - graphics->setColor(gcn::Color(110, 160, 255)); + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + bool valid; + const int red = (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = mAlpha * 255; + + graphics->setColor(gcn::Color(red, green, blue, alpha)); graphics->setFont(getFont()); - int fontHeight = getFont()->getHeight(); + const int fontHeight = getFont()->getHeight(); // Draw rectangle below the selected list element - if (mSelected >= 0) { + if (mSelected >= 0) graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected, getWidth(), fontHeight)); - } // Draw the list elements - graphics->setColor(gcn::Color(0, 0, 0)); - for (int i = 0, y = 0; - i < mListModel->getNumberOfElements(); + graphics->setColor(gcn::Color(0, 0, 0, 255)); + for (int i = 0, y = 0; i < mListModel->getNumberOfElements(); ++i, y += fontHeight) { graphics->drawText(mListModel->getElementAt(i), 1, y); } } -void -ListBox::mouseDragged(gcn::MouseEvent &event) +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. diff --git a/src/gui/listbox.h b/src/gui/listbox.h index 934ea82e..12fcb955 100644 --- a/src/gui/listbox.h +++ b/src/gui/listbox.h @@ -47,6 +47,9 @@ class ListBox : public gcn::ListBox void draw(gcn::Graphics *graphics); void mouseDragged(gcn::MouseEvent &event); + + private: + static float mAlpha; }; #endif diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 2b87f6df..90ceab1a 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -19,24 +19,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "login.h" - -#include <string> - #include <guichan/widgets/label.hpp> -#include "../main.h" -#include "../logindata.h" - #include "button.h" #include "checkbox.h" +#include "listbox.h" +#include "login.h" #include "ok_dialog.h" #include "passwordfield.h" +#include "scrollarea.h" #include "textfield.h" +#include "widgets/dropdown.h" #include "widgets/layout.h" +#include "../main.h" +#include "../logindata.h" +#include "../configuration.h" + #include "../utils/gettext.h" +#include "../utils/tostring.h" + +static const int MAX_SERVER_LIST_SIZE = 5; +static const int LOGIN_DIALOG_WIDTH = 220; +static const int LOGIN_DIALOG_HEIGHT = 140; +static const int FIELD_WIDTH = LOGIN_DIALOG_WIDTH - 70; LoginDialog::LoginDialog(LoginData *loginData): Window(_("Login")), mLoginData(loginData) @@ -44,36 +51,62 @@ LoginDialog::LoginDialog(LoginData *loginData): gcn::Label *userLabel = new gcn::Label(_("Name:")); gcn::Label *passLabel = new gcn::Label(_("Password:")); gcn::Label *serverLabel = new gcn::Label(_("Server:")); + gcn::Label *portLabel = new gcn::Label(_("Port:")); + gcn::Label *dropdownLabel = new gcn::Label(_("Recent:")); + std::vector<std::string> dfltServer; + dfltServer.push_back("server.themanaworld.org"); + std::vector<std::string> dfltPort; + dfltPort.push_back("6901"); + mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort, + MAX_SERVER_LIST_SIZE); + mServerListBox = new ListBox(mServerList); + mServerScrollArea = new ScrollArea(); + mUserField = new TextField(mLoginData->username); mPassField = new PasswordField(mLoginData->password); - mServerField = new TextField(mLoginData->hostname); + mServerField = new TextField(mServerList->getServerAt(0)); + mPortField = new TextField(mServerList->getPortAt(0)); + mServerDropDown = new DropDown(mServerList, + mServerScrollArea, + mServerListBox); + mServerDropDown->setOpaque(false); + mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember); - mOkButton = new Button(_("Ok"), "ok", this); + mOkButton = new Button(_("OK"), "ok", this); mCancelButton = new Button(_("Cancel"), "cancel", this); mRegisterButton = new Button(_("Register"), "register", this); mUserField->setActionEventId("ok"); mPassField->setActionEventId("ok"); mServerField->setActionEventId("ok"); + mServerDropDown->setActionEventId("changeSelection"); mUserField->addKeyListener(this); mPassField->addKeyListener(this); mServerField->addKeyListener(this); + mPortField->addKeyListener(this); + mServerDropDown->addKeyListener(this); mUserField->addActionListener(this); mPassField->addActionListener(this); mServerField->addActionListener(this); + mPortField->addActionListener(this); + mServerDropDown->addActionListener(this); mKeepCheck->addActionListener(this); place(0, 0, userLabel); place(0, 1, passLabel); place(0, 2, serverLabel); - place(1, 0, mUserField, 3).setPadding(2); - place(1, 1, mPassField, 3).setPadding(2); - place(1, 2, mServerField, 3).setPadding(2); - place(0, 3, mKeepCheck, 4); - place(0, 4, mRegisterButton).setHAlign(LayoutCell::LEFT); - place(2, 4, mOkButton); - place(3, 4, mCancelButton); + place(0, 3, portLabel); + place(0, 4, dropdownLabel); + place(1, 0, mUserField, 3).setPadding(1); + place(1, 1, mPassField, 3).setPadding(1); + place(1, 2, mServerField, 3).setPadding(1); + place(1, 3, mPortField, 3).setPadding(1); + place(1, 4, mServerDropDown, 3).setPadding(1); + place(0, 5, mKeepCheck, 4); + place(0, 6, mRegisterButton).setHAlign(LayoutCell::LEFT); + place(2, 6, mCancelButton); + place(3, 6, mOkButton); reflowLayout(250, 0); setLocationRelativeTo(getParent()); @@ -90,6 +123,9 @@ LoginDialog::LoginDialog(LoginData *loginData): LoginDialog::~LoginDialog() { + delete mServerList; + delete mServerListBox; + delete mServerScrollArea; } void LoginDialog::action(const gcn::ActionEvent &event) @@ -97,6 +133,7 @@ void LoginDialog::action(const gcn::ActionEvent &event) if (event.getId() == "ok" && canSubmit()) { mLoginData->hostname = mServerField->getText(); + mLoginData->port = getUShort(mPortField->getText()); mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); mLoginData->remember = mKeepCheck->isSelected(); @@ -104,9 +141,15 @@ void LoginDialog::action(const gcn::ActionEvent &event) mOkButton->setEnabled(false); mRegisterButton->setEnabled(false); - + mServerList->save(mServerField->getText(), mPortField->getText()); state = ACCOUNT_STATE; } + else if (event.getId() == "changeSelection") + { + int selected = mServerListBox->getSelected(); + mServerField->setText(mServerList->getServerAt(selected)); + mPortField->setText(mServerList->getPortAt(selected)); + } else if (event.getId() == "cancel") { state = EXIT_STATE; @@ -115,6 +158,14 @@ void LoginDialog::action(const gcn::ActionEvent &event) { // Transfer these fields on to the register dialog mLoginData->hostname = mServerField->getText(); + if (isUShort(mPortField->getText())) + { + mLoginData->port = getUShort(mPortField->getText()); + } + else + { + mLoginData->port = 6901; + } mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); @@ -132,5 +183,138 @@ bool LoginDialog::canSubmit() return !mUserField->getText().empty() && !mPassField->getText().empty() && !mServerField->getText().empty() && + isUShort(mPortField->getText()) && state == LOGIN_STATE; } + +bool LoginDialog::isUShort(const std::string &str) +{ + if (str.empty()) + { + return false; + } + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + if (*strPtr < '0' || *strPtr > '9') + { + return false; + } + l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative + if (l > 65535) + { + return false; + } + } + return true; +} + +unsigned short LoginDialog::getUShort(const std::string &str) +{ + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + l = l * 10 + (*strPtr - '0'); + } + return static_cast<unsigned short>(l); +} + +/** + * LoginDialog::DropDownList + */ + +void LoginDialog::DropDownList::saveEntry(const std::string &server, + const std::string &port, int &saved) +{ + if (saved < MAX_SERVER_LIST_SIZE && !server.empty()) + { + config.setValue(mConfigPrefix + "Server" + toString(saved), server); + config.setValue(mConfigPrefix + "Port" + toString(saved), port); + ++saved; + } +} + +LoginDialog::DropDownList::DropDownList(std::string prefix, + std::vector<std::string> dflt, + std::vector<std::string> dfltPort, + int maxEntries) : + mConfigPrefix(prefix), + mMaxEntries(maxEntries) +{ + for (int i = 0; i < maxEntries; ++i) + { + std::string server = config.getValue(mConfigPrefix + "Server" + + toString(i), ""); + if (server.empty()) // Just in case had original config entries + { + server = config.getValue(mConfigPrefix + "ServerList" + + toString(i), ""); + } + std::string port = config.getValue(mConfigPrefix + "Port" + + toString(i), dfltPort.front()); + + if (!server.empty()) + { + mServers.push_back(server); + mPorts.push_back(port); + } + } + if (mServers.empty()) + { + mServers.assign(dflt.begin(), dflt.end()); + mPorts.assign(dfltPort.begin(), dfltPort.end()); + } +} + +void LoginDialog::DropDownList::save(const std::string &server, + const std::string &port) +{ + int position = 0; + saveEntry(server, port, position); + for (std::vector<std::string>::const_iterator sPtr = mServers.begin(), + sEnd = mServers.end(), + pPtr = mPorts.begin(), + pEnd = mPorts.end(); + sPtr != sEnd && pPtr != pEnd; + ++sPtr, ++pPtr) + { + if (*sPtr != server || *pPtr != port) + { + saveEntry(*sPtr, *pPtr, position); + } + } +} + +int LoginDialog::DropDownList::getNumberOfElements() +{ + return mServers.size(); +} + +std::string LoginDialog::DropDownList::getElementAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return getServerAt(i) + ":" + getPortAt(i); +} + +std::string LoginDialog::DropDownList::getServerAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mServers.at(i); +} + +std::string LoginDialog::DropDownList::getPortAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mPorts.at(i); +} diff --git a/src/gui/login.h b/src/gui/login.h index 7dd59a96..c0d6e755 100644 --- a/src/gui/login.h +++ b/src/gui/login.h @@ -22,14 +22,18 @@ #ifndef LOGIN_H #define LOGIN_H -#include <iosfwd> +#include <string> +#include <vector> + #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#include <guichan/listmodel.hpp> #include "window.h" -#include "../guichanfwd.h" +class DropDown; class LoginData; +class ScrollArea; /** * The login dialog. @@ -67,18 +71,65 @@ class LoginDialog : public Window, public gcn::ActionListener, * Returns whether submit can be enabled. This is true in the login * state, when all necessary fields have some text. */ - bool - canSubmit(); + bool canSubmit(); + + /** + * Function to decide whether string is an unsigned short or not + * + * @param str the string to parse + * + * @return true is str is an unsigned short, false otherwise + */ + static bool isUShort(const std::string &str); + + /** + * Converts string to an unsigned short (undefined if invalid) + * + * @param str the string to parse + * + * @return the value str represents + */ + static unsigned short getUShort(const std::string &str); + DropDown *mServerDropDown; gcn::TextField *mUserField; gcn::TextField *mPassField; gcn::TextField *mServerField; + gcn::TextField *mPortField; gcn::CheckBox *mKeepCheck; gcn::Button *mOkButton; gcn::Button *mCancelButton; gcn::Button *mRegisterButton; LoginData *mLoginData; + + /** + * Helper class to keep a list of all the recent entries for the + * dropdown + */ + class DropDownList : public gcn::ListModel + { + private: + std::vector<std::string> mServers; + std::vector<std::string> mPorts; + std::string mConfigPrefix; + int mMaxEntries; + void saveEntry(const std::string &server, + const std::string &port, int &saved); + public: + DropDownList(std::string prefix, + std::vector<std::string> dfltServer, + std::vector<std::string> dfltPort, + int maxEntries); + void save(const std::string &server, const std::string &port); + int getNumberOfElements(); + std::string getElementAt(int i); + std::string getServerAt(int i); + std::string getPortAt(int i); + }; + DropDownList *mServerList; + gcn::ListBox *mServerListBox; + gcn::ScrollArea *mServerScrollArea; }; #endif diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index e19cc3e8..0dcc999f 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -19,23 +19,24 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "menuwindow.h" - #include <string> #include <guichan/actionlistener.hpp> #include "button.h" +#include "menuwindow.h" #include "windowcontainer.h" #include "../utils/gettext.h" -extern Window *setupWindow; -extern Window *inventoryWindow; +extern Window *chatWindow; extern Window *equipmentWindow; +extern Window *inventoryWindow; +extern Window *itemShortcutWindow; +extern Window *emoteWindow; +extern Window *setupWindow; extern Window *skillDialog; extern Window *statusWindow; -extern Window *itemShortcutWindow; namespace { struct MenuWindowListener : public gcn::ActionListener @@ -58,12 +59,14 @@ MenuWindow::MenuWindow(): // Buttons static const char *buttonNames[] = { - N_("Status"), - N_("Equipment"), - N_("Inventory"), - N_("Skills"), - N_("Shortcut"), - N_("Setup"), + _("Chat"), + _("Status"), + _("Equipment"), + _("Inventory"), + _("Skills"), + _("Shortcut"), + _("Emote"), + _("Setup"), 0 }; int x = 0, h = 0; @@ -91,27 +94,35 @@ void MenuWindowListener::action(const gcn::ActionEvent &event) { Window *window = NULL; - if (event.getId() == "Status") + if (event.getId() == _("Chat")) + { + window = chatWindow; + } + else if (event.getId() == _("Status")) { window = statusWindow; } - else if (event.getId() == "Equipment") + else if (event.getId() == _("Equipment")) { window = equipmentWindow; } - else if (event.getId() == "Inventory") + else if (event.getId() == _("Inventory")) { window = inventoryWindow; } - else if (event.getId() == "Skills") + else if (event.getId() == _("Skills")) { window = skillDialog; } - else if (event.getId() == "Shortcut") + else if (event.getId() == _("Shortcut")) { window = itemShortcutWindow; } - else if (event.getId() == "Setup") + else if (event.getId() == _("Emote")) + { + window = emoteWindow; + } + else if (event.getId() == _("Setup")) { window = setupWindow; } diff --git a/src/gui/menuwindow.h b/src/gui/menuwindow.h index 9b784c35..9bb54e29 100644 --- a/src/gui/menuwindow.h +++ b/src/gui/menuwindow.h @@ -24,8 +24,6 @@ #include "window.h" -#include "../guichanfwd.h" - /** * The Button Menu. * diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index f5c0c1e6..ccadf3e1 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -19,10 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/font.hpp> + #include "minimap.h" #include "../being.h" #include "../beingmanager.h" +#include "../configuration.h" #include "../graphics.h" #include "../localplayer.h" @@ -30,12 +33,18 @@ #include "../utils/gettext.h" +bool Minimap::mShow = true; + Minimap::Minimap(): Window(_("MiniMap")), - mMapImage(NULL) + mMapImage(NULL), + mProportion(0.5) { - setWindowName("MiniMap"); + setWindowName(_("MiniMap")); + mShow = config.getValue(getWindowName() + "Show", true); setDefaultSize(5, 25, 100, 100); + setResizable(true); + loadWindowState(); } @@ -43,6 +52,8 @@ Minimap::~Minimap() { if (mMapImage) mMapImage->decRef(); + + config.setValue(getWindowName() + "Show", mShow); } void Minimap::setMapImage(Image *img) @@ -53,13 +64,59 @@ void Minimap::setMapImage(Image *img) mMapImage = img; if (mMapImage) - mMapImage->setAlpha(0.7); + { + const int offsetX = 2 * getPadding(); + const int offsetY = getTitleBarHeight() + getPadding(); + const int titleWidth = getFont()->getWidth(getCaption()) + 15; + const int mapWidth = mMapImage->getWidth() < 100 ? + mMapImage->getWidth() + offsetX : 100; + const int mapHeight = mMapImage->getHeight() < 100 ? + mMapImage->getHeight() + offsetY : 100; + + setMinWidth(mapWidth > titleWidth ? mapWidth : titleWidth); + setMinHeight(mapHeight); + setMaxWidth(mMapImage->getWidth() > titleWidth ? + mMapImage->getWidth() + offsetX : titleWidth); + setMaxHeight(mMapImage->getHeight() + offsetY); + + // Make sure the window is within the minimum and maximum boundaries + // TODO: Shouldn't this be happening automatically within the Window + // class? + if (getMinWidth() > getWidth()) + setWidth(getMinWidth()); + else if (getMaxWidth() < getWidth()) + setWidth(getMaxWidth()); + if (getMinHeight() > getHeight()) + setHeight(getMinHeight()); + else if (getMaxHeight() < getHeight()) + setHeight(getMaxHeight()); + + setContentSize(getWidth() - offsetX, getHeight() - offsetY); + setDefaultSize(getX(), getY(), getWidth(), getHeight()); + resetToDefaultSize(); + + setVisible(mShow); + } + else + { + setVisible(false); + } +} + +void Minimap::toggle() +{ + mShow = !mShow; } void Minimap::draw(gcn::Graphics *graphics) { + setVisible(mShow); + Window::draw(graphics); + if (!mShow) + return; + const gcn::Rectangle a = getChildrenArea(); graphics->pushClipArea(a); @@ -72,8 +129,8 @@ void Minimap::draw(gcn::Graphics *graphics) if (mMapImage->getWidth() > a.width || mMapImage->getHeight() > a.height) { - mapOriginX = (a.width - player_node->mX) / 2; - mapOriginY = (a.height - player_node->mY) / 2; + mapOriginX = (int) (((a.width) / 2) - (player_node->mX * mProportion)); + mapOriginY = (int) (((a.height) / 2) - (player_node->mY * mProportion)); const int minOriginX = a.width - mMapImage->getWidth(); const int minOriginY = a.height - mMapImage->getHeight(); @@ -87,6 +144,7 @@ void Minimap::draw(gcn::Graphics *graphics) if (mapOriginY > 0) mapOriginY = 0; } + static_cast<Graphics*>(graphics)-> drawImage(mMapImage, mapOriginX, mapOriginY); } @@ -122,10 +180,11 @@ void Minimap::draw(gcn::Graphics *graphics) continue; } - const int offset = (dotSize - 1) / 2; + const int offset = (int) ((dotSize - 1) * mProportion); + graphics->fillRectangle(gcn::Rectangle( - being->mX / 2 + mapOriginX - offset, - being->mY / 2 + mapOriginY - offset, + (int) (being->mX * mProportion) + mapOriginX - offset, + (int) (being->mY * mProportion) + mapOriginY - offset, dotSize, dotSize)); } diff --git a/src/gui/minimap.h b/src/gui/minimap.h index 67f5eb18..3ce0aacd 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -50,12 +50,24 @@ class Minimap : public Window void setMapImage(Image *img); /** + * Sets the map proportion (1 means 1 tile to one pixel, .5 means 2 tiles to 1 pixel, etc.) + */ + void setProportion(float proportion) { mProportion = proportion; } + + /** + * Toggles the displaying of the minimap. + */ + void toggle(); + + /** * Draws the minimap. */ void draw(gcn::Graphics *graphics); private: Image *mMapImage; + float mProportion; + static bool mShow; }; extern Minimap *minimap; diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp index e613a745..7058d572 100644 --- a/src/gui/ministatus.cpp +++ b/src/gui/ministatus.cpp @@ -19,14 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ministatus.h" - #include "gui.h" +#include "ministatus.h" #include "progressbar.h" -#include "../localplayer.h" +#include "../animatedsprite.h" #include "../configuration.h" #include "../graphics.h" +#include "../localplayer.h" #include "../utils/tostring.h" @@ -90,29 +90,27 @@ void MiniStatusWindow::update() mHpBar->setColor(0, 171, 34); // Green } + float xp = (float) player_node->getXp() / player_node->mXpForNextLevel; + + if (xp != xp) xp = 0.0f; // check for NaN + if (xp < 0.0f) xp = 0.0f; // make sure the experience isn't negative (uninitialized pointer most likely) + if (xp > 1.0f) xp = 1.0f; + mHpBar->setProgress((float) player_node->mHp / player_node->mMaxHp); mMpBar->setProgress((float) player_node->mMp / player_node->mMaxMp); - if (player_node->MATK <= 0) - mMpBar->setColor(100, 100, 100); // grey, to indicate that we lack magic - else - mMpBar->setColor(26, 102, 230); // blue, to indicate that we have magic - - mXpBar->setProgress( - (float) player_node->getXp() / player_node->mXpForNextLevel); + mXpBar->setProgress(xp); // Update labels mHpBar->setText(toString(player_node->mHp)); mMpBar->setText(toString(player_node->mMp)); std::stringstream updatedText; - updatedText << (int) ( - (float) player_node->getXp() / - player_node->mXpForNextLevel * 100) << "%"; + updatedText << (float) ((int) (xp * 10000.0f)) / 100.0f << "%"; // Displays the number of monsters to next lvl // (disabled for now but interesting idea) /* - if(config.getValue("xpBarMonsterCounterExp", 0)!=0) + if (config.getValue("xpBarMonsterCounterExp", 0)!=0) { updatedText << " | " << (int)(((float)player_node->mXpForNextLevel - (float)player_node->mXp) diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h index c6a36a98..f262a2a0 100644 --- a/src/gui/ministatus.h +++ b/src/gui/ministatus.h @@ -22,14 +22,11 @@ #ifndef MINISTATUS_H #define MINISTATUS_H -#include <iosfwd> -#include <vector> - #include "window.h" -#include "../guichanfwd.h" -#include "../animatedsprite.h" +#include <vector> +class AnimatedSprite; class ProgressBar; /** diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp index 6ad698bc..b4313b70 100644 --- a/src/gui/npc_text.cpp +++ b/src/gui/npc_text.cpp @@ -19,13 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npc_text.h" - -#include <string> - -#include "browserbox.h" #include "button.h" +#include "npc_text.h" #include "scrollarea.h" +#include "textbox.h" + +#include "widgets/layout.h" #include "../npc.h" @@ -39,66 +38,55 @@ NpcTextDialog::NpcTextDialog(): setMinWidth(200); setMinHeight(150); - mBrowserBox = new BrowserBox(BrowserBox::AUTO_WRAP); - mBrowserBox->setOpaque(true); + setDefaultSize(0, 0, 260, 200); + + mTextBox = new TextBox; + mTextBox->setEditable(false); + mTextBox->setOpaque(false); - scrollArea = new ScrollArea(mBrowserBox); + scrollArea = new ScrollArea(mTextBox); okButton = new Button(_("OK"), "ok", this); - setContentSize(260, 175); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - scrollArea->setDimension(gcn::Rectangle( - 5, 5, 250, 160 - okButton->getHeight())); - okButton->setPosition( - 260 - 5 - okButton->getWidth(), - 175 - 5 - okButton->getHeight()); - add(scrollArea); - add(okButton); + place(0, 0, scrollArea, 5).setPadding(3); + place(4, 1, okButton); - setLocationRelativeTo(getParent()); -} + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); -void NpcTextDialog::clearText() -{ - mBrowserBox->clearRows(); + loadWindowState(); + setLocationRelativeTo(getParent()); } void NpcTextDialog::setText(const std::string &text) { - mBrowserBox->clearRows(); - mBrowserBox->addRow(text); + mText = text; + mTextBox->setTextWrapped(mText, scrollArea->getWidth() - 15); } void NpcTextDialog::addText(const std::string &text) { - mBrowserBox->addRow(text); -} - -void NpcTextDialog::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - scrollArea->setDimension(gcn::Rectangle( - 5, 5, width - 10, height - 15 - okButton->getHeight())); - okButton->setPosition( - width - 5 - okButton->getWidth(), - height - 5 - okButton->getHeight()); + setText(mText + text + "\n"); } void NpcTextDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") { - clearText(); + setText(""); setVisible(false); if (current_npc) current_npc->nextDialog(); current_npc = 0; } } + +void NpcTextDialog::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + setText(mText); +} + diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h index c881467a..a07aa04f 100644 --- a/src/gui/npc_text.h +++ b/src/gui/npc_text.h @@ -22,12 +22,13 @@ #ifndef NPC_TEXT_H #define NPC_TEXT_H -#include <iosfwd> +#include <string> + #include <guichan/actionlistener.hpp> #include "window.h" -class BrowserBox; +class TextBox; /** * The npc text dialog. @@ -45,13 +46,6 @@ class NpcTextDialog : public Window, public gcn::ActionListener NpcTextDialog(); /** - * Called when resizing the window. - * - * @param event The calling event - */ - void widgetResized(const gcn::Event &event); - - /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); @@ -76,10 +70,19 @@ class NpcTextDialog : public Window, public gcn::ActionListener */ void addText(const std::string &string); + /** + * Called when resizing the window. + * + * @param event The calling event + */ + void widgetResized(const gcn::Event &event); + private: gcn::Button *okButton; gcn::ScrollArea *scrollArea; - BrowserBox *mBrowserBox; + TextBox *mTextBox; + + std::string mText; }; #endif // NPC_TEXT_H diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp index ec91d736..c58fc460 100644 --- a/src/gui/npcintegerdialog.cpp +++ b/src/gui/npcintegerdialog.cpp @@ -19,27 +19,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npcintegerdialog.h" - -#include <limits> -#include <sstream> - #include "button.h" #include "inttextfield.h" +#include "npcintegerdialog.h" + +#include "widgets/layout.h" #include "../npc.h" #include "../utils/gettext.h" -#include "../utils/tostring.h" - -#include "widgets/layout.h" NpcIntegerDialog::NpcIntegerDialog(): Window(_("NPC Number Request")) { + mValueField = new IntTextField(); + mDecButton = new Button("-", "decvalue", this); mIncButton = new Button("+", "incvalue", this); - mValueField = new IntTextField(); okButton = new Button(_("OK"), "ok", this); cancelButton = new Button(_("Cancel"), "cancel", this); resetButton = new Button(_("Reset"), "reset", this); @@ -61,9 +57,6 @@ NpcIntegerDialog::NpcIntegerDialog(): reflowLayout(175, 0); setLocationRelativeTo(getParent()); - - mValueField->setActionEventId("valuefield"); - mValueField->addKeyListener(this); } void NpcIntegerDialog::setRange(const int min, const int max) @@ -107,5 +100,16 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event) setVisible(false); current_npc->integerInput(mValueField->getValue()); current_npc = 0; + mValueField->reset(); } } + +bool NpcIntegerDialog::isInputFocused() +{ + return mValueField->isFocused(); +} + +void NpcIntegerDialog::requestFocus() +{ + mValueField->requestFocus(); +} diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h index 983c46fe..10ec60b9 100644 --- a/src/gui/npcintegerdialog.h +++ b/src/gui/npcintegerdialog.h @@ -22,16 +22,10 @@ #ifndef GUI_NPCINTEGERDIALOG_H #define GUI_NPCINTEGERDIALOG_H -#include <iosfwd> -#include <vector> - #include <guichan/actionlistener.hpp> -#include <guichan/keylistener.hpp> #include "window.h" -#include "../guichanfwd.h" - class IntTextField; /** @@ -39,8 +33,7 @@ class IntTextField; * * \ingroup Interface */ -class NpcIntegerDialog : public Window, public gcn::ActionListener, - public gcn::KeyListener +class NpcIntegerDialog : public Window, public gcn::ActionListener { public: /** @@ -68,6 +61,16 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener, */ void setRange(const int min, const int max); + /** + * Checks whether NpcStringDialog is Focused or not. + */ + bool isInputFocused(); + + /** + * Requests the textfield to take focus for input. + */ + void requestFocus(); + private: gcn::Button *mDecButton; gcn::Button *mIncButton; diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp index 4b05df5a..7d8a362a 100644 --- a/src/gui/npclistdialog.cpp +++ b/src/gui/npclistdialog.cpp @@ -19,13 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npclistdialog.h" - #include <sstream> #include "button.h" -#include "scrollarea.h" #include "listbox.h" +#include "npclistdialog.h" +#include "scrollarea.h" + +#include "widgets/layout.h" #include "../npc.h" @@ -39,30 +40,25 @@ NpcListDialog::NpcListDialog(): setMinWidth(200); setMinHeight(150); + setDefaultSize(0, 0, 260, 200); + mItemList = new ListBox(this); + mItemList->setWrappingEnabled(true); scrollArea = new ScrollArea(mItemList); okButton = new Button(_("OK"), "ok", this); cancelButton = new Button(_("Cancel"), "cancel", this); setContentSize(260, 175); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setDimension(gcn::Rectangle( - 5, 5, 250, 160 - okButton->getHeight())); - cancelButton->setPosition( - 260 - 5 - cancelButton->getWidth(), - 175 - 5 - cancelButton->getHeight()); - okButton->setPosition( - cancelButton->getX() - 5 - okButton->getWidth(), - cancelButton->getY()); - - mItemList->setActionEventId("item"); - mItemList->addActionListener(this); + place(0, 0, scrollArea, 5).setPadding(3); + place(3, 1, okButton); + place(4, 1, cancelButton); - add(scrollArea); - add(okButton); - add(cancelButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + loadWindowState(); setLocationRelativeTo(getParent()); } @@ -90,24 +86,6 @@ void NpcListDialog::reset() mItems.clear(); } -void NpcListDialog::widgetResized(const gcn::Event &event) -{ - Window::widgetResized(event); - - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - scrollArea->setDimension(gcn::Rectangle( - 5, 5, width - 10, height - 15 - okButton->getHeight())); - cancelButton->setPosition( - width - 5 - cancelButton->getWidth(), - height - 5 - cancelButton->getHeight()); - okButton->setPosition( - cancelButton->getX() - 5 - okButton->getWidth(), - cancelButton->getY()); -} - void NpcListDialog::action(const gcn::ActionEvent &event) { int choice = 0; diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h index 2ae4aae3..30167a5e 100644 --- a/src/gui/npclistdialog.h +++ b/src/gui/npclistdialog.h @@ -22,7 +22,6 @@ #ifndef GUI_NPCLISTDIALOG_H #define GUI_NPCLISTDIALOG_H -#include <iosfwd> #include <vector> #include <guichan/actionlistener.hpp> @@ -30,8 +29,6 @@ #include "window.h" -#include "../guichanfwd.h" - /** * The npc list dialog. * @@ -49,13 +46,6 @@ class NpcListDialog : public Window, public gcn::ActionListener, NpcListDialog(); /** - * Called when resizing the window - * - * @param event The calling event - */ - void widgetResized(const gcn::Event &event); - - /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp index 1c92d620..718c416f 100644 --- a/src/gui/npcstringdialog.cpp +++ b/src/gui/npcstringdialog.cpp @@ -19,18 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npcstringdialog.h" - -#include <limits> -#include <sstream> - #include "button.h" +#include "npcstringdialog.h" #include "textfield.h" #include "../npc.h" #include "../utils/gettext.h" -#include "../utils/tostring.h" #include "widgets/layout.h" @@ -38,12 +33,13 @@ NpcStringDialog::NpcStringDialog(): Window(_("NPC Text Request")) { mValueField = new TextField(""); + okButton = new Button(_("OK"), "ok", this); cancelButton = new Button(_("Cancel"), "cancel", this); place(0, 0, mValueField, 3); - place(1, 1, okButton); - place(2, 1, cancelButton); + place(1, 1, cancelButton); + place(2, 1, okButton); reflowLayout(175, 0); setLocationRelativeTo(getParent()); @@ -69,9 +65,15 @@ void NpcStringDialog::action(const gcn::ActionEvent &event) setVisible(false); current_npc->stringInput(mValueField->getText()); current_npc = 0; + mValueField->setText(""); } bool NpcStringDialog::isInputFocused() { return mValueField->isFocused(); } + +void NpcStringDialog::requestFocus() +{ + mValueField->requestFocus(); +} diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h index 5aea2de0..1933e0f1 100644 --- a/src/gui/npcstringdialog.h +++ b/src/gui/npcstringdialog.h @@ -22,16 +22,10 @@ #ifndef GUI_NPCSTRINGDIALOG_H #define GUI_NPCSTRINGDIALOG_H -#include <iosfwd> -#include <vector> - #include <guichan/actionlistener.hpp> -#include <guichan/keylistener.hpp> #include "window.h" -#include "../guichanfwd.h" - /** * The npc integer input dialog. * @@ -69,6 +63,11 @@ class NpcStringDialog : public Window, public gcn::ActionListener */ bool isInputFocused(); + /** + * Requests the textfield to take focus for input. + */ + void requestFocus(); + private: gcn::TextField *mValueField; gcn::Button *okButton; diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index a2134d5d..2c67e71f 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -19,10 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ok_dialog.h" -#include "textbox.h" +#include <guichan/font.hpp> + #include "button.h" +#include "ok_dialog.h" #include "scrollarea.h" +#include "textbox.h" #include "../utils/gettext.h" @@ -30,25 +32,44 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, Window *parent): Window(title, true, parent) { - TextBox *textBox = new TextBox(); - textBox->setEditable(false); + mTextBox = new TextBox(); + mTextBox->setEditable(false); + mTextBox->setOpaque(false); + + mTextArea = new ScrollArea(mTextBox); + okButton = new Button(_("Ok"), "ok", this); + + mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setOpaque(false); - gcn::ScrollArea *scrollArea = new ScrollArea(textBox); - gcn::Button *okButton = new Button(_("Ok"), "ok", this); + mTextBox->setTextWrapped(msg, 260); - setContentSize(260, 175); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - scrollArea->setDimension(gcn::Rectangle( - 5, 5, 250, 160 - okButton->getHeight())); + int numRows = mTextBox->getNumberOfRows(); - textBox->setTextWrapped(msg); + if (numRows > 1) + { + // 15 == height of each line of text (based on font heights) + // 14 == row top + bottom graphic pixel heights + setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + okButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5, + 3 + (numRows * 14))); + } + else + { + int width = getFont()->getWidth(title); + if (width < getFont()->getWidth(msg)) + width = getFont()->getWidth(msg); + if (width < okButton->getWidth()) + width = okButton->getWidth(); + setContentSize(width + 15, 30 + okButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17)); + } - okButton->setPosition( - 260 - 5 - okButton->getWidth(), - 175 - 5 - okButton->getHeight()); + okButton->setPosition((mTextBox->getMinWidth() - okButton->getWidth()) / 2, + (numRows * 14) + okButton->getHeight() - 8); - add(scrollArea); + add(mTextArea); add(okButton); setLocationRelativeTo(getParent()); @@ -56,6 +77,11 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, okButton->requestFocus(); } +unsigned int OkDialog::getNumRows() +{ + return mTextBox->getNumberOfRows(); +} + void OkDialog::action(const gcn::ActionEvent &event) { // Proxy button events to our listeners diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h index 44dc6bb9..3a438513 100644 --- a/src/gui/ok_dialog.h +++ b/src/gui/ok_dialog.h @@ -26,6 +26,9 @@ #include "window.h" +class ScrollArea; +class TextBox; + /** * An 'Ok' button dialog. * @@ -41,10 +44,17 @@ class OkDialog : public Window, public gcn::ActionListener { OkDialog(const std::string &title, const std::string &msg, Window *parent = NULL); + unsigned int getNumRows(); + /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); + + private: + TextBox *mTextBox; + ScrollArea *mTextArea; + gcn::Button *okButton; }; #endif diff --git a/src/gui/passwordfield.cpp b/src/gui/passwordfield.cpp index 09b6abda..345ee1c3 100644 --- a/src/gui/passwordfield.cpp +++ b/src/gui/passwordfield.cpp @@ -21,8 +21,6 @@ #include "passwordfield.h" -#include <string> - PasswordField::PasswordField(const std::string& text): TextField(text) { diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h index d6082e3f..42f8d187 100644 --- a/src/gui/passwordfield.h +++ b/src/gui/passwordfield.h @@ -22,6 +22,8 @@ #ifndef PASSWORDFIELD_H #define PASSWORDFIELD_H +#include <string> + #include "textfield.h" /** @@ -29,7 +31,8 @@ * * \ingroup GUI */ -class PasswordField : public TextField { +class PasswordField : public TextField +{ public: /** * Constructor, initializes the password field with the given string. diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 8f698df5..f99ce6ef 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -19,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include "playerbox.h" -#include "../player.h" +#include "../animatedsprite.h" +#include "../configuration.h" #include "../graphics.h" +#include "../player.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" @@ -32,6 +32,7 @@ #include "../utils/dtor.h" int PlayerBox::instances = 0; +float PlayerBox::mAlpha = config.getValue("guialpha", 0.8); ImageRect PlayerBox::background; PlayerBox::PlayerBox(const Player *player): @@ -54,6 +55,7 @@ PlayerBox::PlayerBox(const Player *player): 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++; } } @@ -83,7 +85,21 @@ void PlayerBox::draw(gcn::Graphics *graphics) bs = getFrameSize(); x = getWidth() / 2 - 16 + bs; y = getHeight() / 2 + bs; - mPlayer->draw(static_cast<Graphics*>(graphics), x, y); + for (int i = 0; i < Being::VECTOREND_SPRITE; i++) + { + if (mPlayer->getSprite(i)) + { + mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y); + } + } + } + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + for (int a = 0; a < 9; a++) + { + background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + } } } diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index d66db4d4..7c08defd 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -51,8 +51,7 @@ class PlayerBox : public gcn::ScrollArea * player to <code>NULL</code> causes the box not to draw any * character. */ - void - setPlayer(const Player *player) { mPlayer = player; } + void setPlayer(const Player *player) { mPlayer = player; } /** * Draws the scroll area. @@ -67,6 +66,7 @@ class PlayerBox : public gcn::ScrollArea private: const Player *mPlayer; /**< The character used for display */ + static float mAlpha; static int instances; static ImageRect background; }; diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 06a2ad87..3503d0ea 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -19,16 +19,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "popupmenu.h" - #include <cassert> -#include <iostream> - -#include <guichan/focushandler.hpp> #include "browserbox.h" +#include "chat.h" #include "inventorywindow.h" #include "item_amount.h" +#include "popupmenu.h" #include "windowcontainer.h" #include "../being.h" @@ -39,7 +36,9 @@ #include "../npc.h" #include "../player_relations.h" -#include "../resources/iteminfo.h" +#include "../net/messageout.h" +#include "../net/protocol.h" + #include "../resources/itemdb.h" #include "../utils/gettext.h" @@ -77,34 +76,35 @@ void PopupMenu::showPopup(int x, int y, Being *being) // Players can be traded with. Later also attack, follow and // add as buddy will be options in this menu. const std::string &name = being->getName(); - mBrowserBox->addRow( - strprintf(_("@@trade|Trade With %s@@"), name.c_str())); - mBrowserBox->addRow( - strprintf(_("@@attack|Attack %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@trade|Trade With %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@attack|Attack %s@@"), name.c_str())); mBrowserBox->addRow("##3---"); switch (player_relations.getRelation(name)) { - case PlayerRelation::NEUTRAL: - mBrowserBox->addRow("@@friend|Befriend " + name + "@@"); - - case PlayerRelation::FRIEND: - mBrowserBox->addRow("@@disregard|Disregard " + name + "@@"); - mBrowserBox->addRow("@@ignore|Ignore " + name + "@@"); - break; - - case PlayerRelation::DISREGARDED: - mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@"); - mBrowserBox->addRow("@@ignore|Completely ignore " + name + "@@"); - break; - - case PlayerRelation::IGNORED: - mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@"); - break; + case PlayerRelation::NEUTRAL: + mBrowserBox->addRow(strprintf(_("@@friend|Befriend %s@@"), name.c_str())); + + case PlayerRelation::FRIEND: + mBrowserBox->addRow(strprintf(_("@@disregard|Disregard %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::DISREGARDED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Completely ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::IGNORED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + break; } - //mBrowserBox->addRow("@@follow|Follow " + name + "@@"); - //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@"); + //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@"); + //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@"); + + mBrowserBox->addRow("##3---"); + mBrowserBox->addRow(strprintf(_("@@party-invite|Invite %s to party@@"), name.c_str())); } break; @@ -148,7 +148,7 @@ void PopupMenu::handleLink(const std::string& link) // Talk To action if (link == "talk" && - being != NULL && + being && being->getType() == Being::NPC && current_npc == 0) { @@ -157,7 +157,7 @@ void PopupMenu::handleLink(const std::string& link) // Trade action else if (link == "trade" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_node->trade(being); @@ -166,35 +166,35 @@ void PopupMenu::handleLink(const std::string& link) // Attack action else if (link == "attack" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_node->attack(being, true); } else if (link == "unignore" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::NEUTRAL); } else if (link == "ignore" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::IGNORED); } else if (link == "disregard" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::DISREGARDED); } else if (link == "friend" && - being != NULL && + being && being->getType() == Being::PLAYER) { player_relations.setRelation(being->getName(), PlayerRelation::FRIEND); @@ -208,7 +208,7 @@ void PopupMenu::handleLink(const std::string& link) /* // Add Buddy action - else if ((link == "buddy") && being != NULL && being->isPlayer()) + else if ((link == "buddy") && being && being->isPlayer()) { if (!buddyWindow->isVisible()) buddyWindow->setVisible(true); @@ -217,7 +217,7 @@ void PopupMenu::handleLink(const std::string& link) }*/ // Pick Up Floor Item action - else if ((link == "pickup") && mFloorItem != NULL) + else if ((link == "pickup") && mFloorItem) { player_node->pickUp(mFloorItem); } @@ -247,15 +247,22 @@ void PopupMenu::handleLink(const std::string& link) } } + else if (link == "chat") + { + chatWindow->addItemText(mItem->getInfo().getName()); + } + else if (link == "drop") { new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem); } - - else if (link == "description") + else if (link == "party-invite" && + being && + being->getType() == Being::PLAYER) { - // do nothing for now, I need to write - // a window for the description first + MessageOut outMsg(player_node->getNetwork()); + outMsg.writeInt16(CMSG_PARTY_INVITE); + outMsg.writeInt32(being->getId()); } // Unknown actions @@ -288,7 +295,7 @@ void PopupMenu::showPopup(int x, int y, Item *item) mBrowserBox->addRow(_("@@use|Use@@")); mBrowserBox->addRow(_("@@drop|Drop@@")); - mBrowserBox->addRow(_("@@description|Description@@")); + mBrowserBox->addRow(_("@@chat|Add to Chat@@")); mBrowserBox->addRow("##3---"); mBrowserBox->addRow(_("@@cancel|Cancel@@")); diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h index 1165bcb2..2694abd8 100644 --- a/src/gui/popupmenu.h +++ b/src/gui/popupmenu.h @@ -24,15 +24,14 @@ #include <SDL.h> // for Uint32 -#include "window.h" #include "linkhandler.h" +#include "window.h" class Being; class BrowserBox; class FloorItem; class Item; - /** * Window showing popup menu. */ diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp index d877bfbc..867477e0 100644 --- a/src/gui/progressbar.cpp +++ b/src/gui/progressbar.cpp @@ -19,17 +19,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/font.hpp> + +#include "gui.h" #include "progressbar.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 = config.getValue("guialpha", 0.8); ProgressBar::ProgressBar(float progress, unsigned int width, unsigned int height, @@ -55,6 +58,12 @@ ProgressBar::ProgressBar(float progress, 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(); } @@ -92,12 +101,27 @@ void ProgressBar::logic() void ProgressBar::draw(gcn::Graphics *graphics) { + if (config.getValue("guialpha", 0.8) != mAlpha) + { + if (config.getValue("opengl", 0)) + mAlpha = config.getValue("guialpha", 0.8); + else + mAlpha = 1.0f; + 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 = mAlpha * 255; + // The bar if (mProgress > 0) { - graphics->setColor(gcn::Color(mRed, mGreen, mBlue, 200)); + + graphics->setColor(gcn::Color(mRed, mGreen, mBlue, alpha)); graphics->fillRectangle(gcn::Rectangle(4, 4, (int) (mProgress * (getWidth() - 8)), getHeight() - 8)); @@ -105,20 +129,22 @@ void ProgressBar::draw(gcn::Graphics *graphics) // The label if (!mText.empty()) { - gcn::Font *f = getFont(); + gcn::Font *f = boldFont; const int textX = getWidth() / 2; const int textY = (getHeight() - f->getHeight()) / 2; graphics->setFont(f); - graphics->setColor(gcn::Color(0, 0, 0)); + graphics->setColor(gcn::Color(0, 0, 0, alpha)); graphics->drawText(mText, textX + 1, textY, gcn::Graphics::CENTER); graphics->drawText(mText, textX, textY - 1, gcn::Graphics::CENTER); graphics->drawText(mText, textX, textY + 1, gcn::Graphics::CENTER); graphics->drawText(mText, textX - 1, textY, gcn::Graphics::CENTER); - graphics->setColor(gcn::Color(255, 255, 255)); + graphics->setColor(gcn::Color(255, 255, 255, alpha)); graphics->drawText(mText, textX, textY, gcn::Graphics::CENTER); + + graphics->setColor(gcn::Color(0, 0, 0)); } } diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h index a4b30b04..2c1b22da 100644 --- a/src/gui/progressbar.h +++ b/src/gui/progressbar.h @@ -22,12 +22,12 @@ #ifndef PROGRESSBAR_H #define PROGRESSBAR_H +#include <string> + #include <guichan/widget.hpp> #include <SDL_types.h> -#include <string> - class ImageRect; /** @@ -81,12 +81,12 @@ class ProgressBar : public gcn::Widget Uint8 getRed() const { return mRed; } /** - * Returns the red value of color. + * Returns the green value of color. */ Uint8 getGreen() const { return mGreen; } /** - * Returns the red value of color. + * Returns the blue value of color. */ Uint8 getBlue() const { return mBlue; } @@ -110,6 +110,7 @@ class ProgressBar : public gcn::Widget static ImageRect mBorder; static int mInstances; + static float mAlpha; }; #endif diff --git a/src/gui/radiobutton.cpp b/src/gui/radiobutton.cpp index 245112a7..c8ae2fad 100644 --- a/src/gui/radiobutton.cpp +++ b/src/gui/radiobutton.cpp @@ -21,12 +21,14 @@ #include "radiobutton.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" int RadioButton::instances = 0; +float RadioButton::mAlpha = config.getValue("guialpha", 0.8); Image *RadioButton::radioNormal; Image *RadioButton::radioChecked; Image *RadioButton::radioDisabled; @@ -43,6 +45,10 @@ RadioButton::RadioButton(const std::string& caption, const std::string& group, 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++; @@ -63,32 +69,37 @@ RadioButton::~RadioButton() 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()) { + if (isSelected()) + { + if (isEnabled()) box = radioChecked; - } else { + else box = radioDisabledChecked; - } - } else if (isEnabled()) { + } + else if (isEnabled()) box = radioNormal; - } else { + else box = radioDisabled; - } - if (box != NULL) { + 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)); + graphics->pushClipArea(gcn::Rectangle(1, 1, getWidth() - 1, + getHeight() - 1)); drawBox(graphics); diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h index 2d2bdbb7..3d952b3f 100644 --- a/src/gui/radiobutton.h +++ b/src/gui/radiobutton.h @@ -26,11 +26,11 @@ class Image; - /* * Guichan based RadioButton with custom look */ -class RadioButton : public gcn::RadioButton { +class RadioButton : public gcn::RadioButton +{ public: /* * Constructor. @@ -56,6 +56,7 @@ class RadioButton : public gcn::RadioButton { private: static int instances; + static float mAlpha; static Image *radioNormal; static Image *radioChecked; static Image *radioDisabled; diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp new file mode 100644 index 00000000..40ef974b --- /dev/null +++ b/src/gui/recorder.cpp @@ -0,0 +1,116 @@ +/* + * A chat recorder + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * 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 <physfs.h> + +#include "button.h" +#include "chat.h" +#include "recorder.h" +#include "windowcontainer.h" + +#include "widgets/layout.h" + +#include "../utils/trim.h" + +Recorder::Recorder(ChatWindow *chat, const std::string &title, + const std::string &buttonTxt) : + Window(title) +{ + setWindowName(_("Recorder")); + const int offsetX = 2 * getPadding() + 10; + const int offsetY = getTitleBarHeight() + getPadding() + 10; + + mChat = chat; + Button *button = new Button(buttonTxt, "activate", this); + setDefaultSize(0, windowContainer->getHeight() - 123 - button->getHeight() - + offsetY, button->getWidth() + offsetX, button->getHeight() + + offsetY); + + place(0, 0, button); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); +} + +Recorder::~Recorder() +{ +} + +void Recorder::record(const std::string &msg) +{ + if (mStream.is_open()) + { + mStream << msg << std::endl; + } +} + +void Recorder::changeRecordingStatus(const std::string &msg) +{ + std::string msgCopy = msg; + trim(msgCopy); + + if (msgCopy.empty()) + { + if (mStream.is_open()) + { + mStream.close(); + setVisible(false); + + /* + * Message should go after mStream is closed so that it isn't + * recorded. + */ + mChat->chatLog(_("Finishing recording."), BY_SERVER); + } + else + { + mChat->chatLog(_("Not currently recording."), BY_SERVER); + } + } + else if (mStream.is_open()) + { + mChat->chatLog(_("Already recording."), BY_SERVER); + } + else + { + /* + * Message should go before mStream is opened so that it isn't + * recorded. + */ + mChat->chatLog(_("Starting to record..."), BY_SERVER); + const std::string file = + std::string(PHYSFS_getUserDir()) + "/.tmw/" + msgCopy; + + mStream.open(file.c_str(), std::ios_base::trunc); + + if (mStream.is_open()) + setVisible(true); + else + mChat->chatLog(_("Failed to start recording."), BY_SERVER); + } +} + +void Recorder::action(const gcn::ActionEvent &event) +{ + changeRecordingStatus(""); +} diff --git a/src/gui/recorder.h b/src/gui/recorder.h new file mode 100644 index 00000000..0bbab012 --- /dev/null +++ b/src/gui/recorder.h @@ -0,0 +1,76 @@ +/* + * A chat recorder + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * 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 RECORD_H +#define RECORD_H + +#include <fstream> +#include <string> + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +#include "../utils/gettext.h" + +class ChatWindow; + +class Recorder : public Window, public gcn::ActionListener +{ + public: + Recorder(ChatWindow *chat, const std::string &title = _("Recording..."), + const std::string &buttonTxt = _("Stop recording")); + + virtual ~Recorder(); + + /* + * Outputs the message to the recorder file + * + * @param msg the line to write to the recorded file. + */ + void record(const std::string &msg); + + /* + * Outputs the message to the recorder file + * + * @param msg The file to write out to. If null, then stop recording. + */ + void changeRecordingStatus(const std::string &msg); + + /* + * Whether or not the recorder is in use. + */ + bool isRecording() {return (bool) mStream.is_open();} + + /* + * called when the button is pressed + * + * @param event is the event that is generated + */ + void action(const gcn::ActionEvent &event); + + private: + ChatWindow *mChat; + + std::ofstream mStream; +}; + +#endif diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 5605ef96..e17f5902 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -19,30 +19,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "register.h" - -#include <string> -#include <sstream> - #include <guichan/widgets/label.hpp> -#include "../main.h" #include "../configuration.h" #include "../log.h" #include "../logindata.h" +#include "../main.h" #include "button.h" #include "checkbox.h" #include "login.h" +#include "ok_dialog.h" #include "passwordfield.h" #include "radiobutton.h" +#include "register.h" #include "textfield.h" -#include "ok_dialog.h" #include "widgets/layout.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" +#include "../utils/tostring.h" /** * Listener used while dealing with wrong data. It is used to direct the focus @@ -80,10 +77,12 @@ RegisterDialog::RegisterDialog(LoginData *loginData): gcn::Label *passwordLabel = new gcn::Label(_("Password:")); gcn::Label *confirmLabel = new gcn::Label(_("Confirm:")); gcn::Label *serverLabel = new gcn::Label(_("Server:")); + gcn::Label *portLabel = new gcn::Label(_("Port:")); mUserField = new TextField(loginData->username); mPasswordField = new PasswordField(loginData->password); mConfirmField = new PasswordField; mServerField = new TextField(loginData->hostname); + mPortField = new TextField(toString(loginData->port)); mMaleButton = new RadioButton(_("Male"), "sex", true); mFemaleButton = new RadioButton(_("Female"), "sex", false); mRegisterButton = new Button(_("Register"), "register", this); @@ -97,10 +96,12 @@ RegisterDialog::RegisterDialog(LoginData *loginData): place(1, 3, mMaleButton); place(2, 3, mFemaleButton); place(0, 4, serverLabel); + place(0, 5, portLabel); place(1, 0, mUserField, 3).setPadding(2); place(1, 1, mPasswordField, 3).setPadding(2); place(1, 2, mConfirmField, 3).setPadding(2); place(1, 4, mServerField, 3).setPadding(2); + place(1, 5, mPortField, 3).setPadding(2); place = getPlacer(0, 2); place(1, 0, mRegisterButton); place(2, 0, mCancelButton); @@ -110,6 +111,7 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mPasswordField->addKeyListener(this); mConfirmField->addKeyListener(this); mServerField->addKeyListener(this); + mPortField->addKeyListener(this); /* TODO: * This is a quick and dirty way to respond to the ENTER key, regardless of @@ -120,10 +122,13 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mPasswordField->setActionEventId("register"); mConfirmField->setActionEventId("register"); mServerField->setActionEventId("register"); + mPortField->setActionEventId("register"); + mUserField->addActionListener(this); mPasswordField->addActionListener(this); mConfirmField->addActionListener(this); mServerField->addActionListener(this); + mPortField->addActionListener(this); setLocationRelativeTo(getParent()); setVisible(true); @@ -216,7 +221,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event) mRegisterButton->setEnabled(false); mLoginData->hostname = mServerField->getText(); - mLoginData->port = (short) config.getValue("port", 0); + mLoginData->port = getUShort(mPortField->getText()); mLoginData->username = mUserField->getText(); mLoginData->password = mPasswordField->getText(); mLoginData->username += mFemaleButton->isSelected() ? "_F" : "_M"; @@ -238,5 +243,40 @@ bool RegisterDialog::canSubmit() const !mPasswordField->getText().empty() && !mConfirmField->getText().empty() && !mServerField->getText().empty() && + isUShort(mPortField->getText()) && state == REGISTER_STATE; } + +bool RegisterDialog::isUShort(const std::string &str) +{ + if (str.empty()) + { + return false; + } + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + if (*strPtr < '0' || *strPtr > '9') + { + return false; + } + l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative + if (l > 65535) + { + return false; + } + } + return true; +} + +unsigned short RegisterDialog::getUShort(const std::string &str) +{ + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + l = l * 10 + (*strPtr - '0'); + } + return static_cast<unsigned short>(l); +} diff --git a/src/gui/register.h b/src/gui/register.h index 3dddae0f..9588e07e 100644 --- a/src/gui/register.h +++ b/src/gui/register.h @@ -22,12 +22,12 @@ #ifndef REGISTER_H #define REGISTER_H -#include <iosfwd> +#include <string> + #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> #include "window.h" -#include "../guichanfwd.h" class LoginData; class OkDialog; @@ -72,10 +72,29 @@ class RegisterDialog : public Window, public gcn::ActionListener, */ bool canSubmit() const; + /** + * Function to decide whether string is an unsigned short or not + * + * @param str the string to parse + * + * @return true if str is an unsigned short, false otherwise + */ + static bool isUShort(const std::string &str); + + /** + * Converts string to an unsigned short (undefined if invalid) + * + * @param str the string to parse + * + * @return the value str represents + */ + static unsigned short getUShort(const std::string &str); + gcn::TextField *mUserField; gcn::TextField *mPasswordField; gcn::TextField *mConfirmField; gcn::TextField *mServerField; + gcn::TextField *mPortField; gcn::Button *mRegisterButton; gcn::Button *mCancelButton; diff --git a/src/gui/scrollarea.cpp b/src/gui/scrollarea.cpp index 8a74cd72..bc3a62dc 100644 --- a/src/gui/scrollarea.cpp +++ b/src/gui/scrollarea.cpp @@ -19,10 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include "scrollarea.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -31,19 +30,22 @@ #include "../utils/dtor.h" int ScrollArea::instances = 0; +float ScrollArea::mAlpha = config.getValue("guialpha", 0.8); ImageRect ScrollArea::background; ImageRect ScrollArea::vMarker; Image *ScrollArea::buttons[4][2]; -ScrollArea::ScrollArea(bool gc): +ScrollArea::ScrollArea(bool gc, bool opaque): gcn::ScrollArea(), + mOpaque(opaque), mGC(gc) { init(); } -ScrollArea::ScrollArea(gcn::Widget *widget, bool gc): +ScrollArea::ScrollArea(gcn::Widget *widget, bool gc, bool opaque): gcn::ScrollArea(widget), + mOpaque(opaque), mGC(gc) { init(); @@ -52,9 +54,8 @@ ScrollArea::ScrollArea(gcn::Widget *widget, bool gc): ScrollArea::~ScrollArea() { // Garbage collection - if (mGC) { + if (mGC) delete getContent(); - } instances--; @@ -88,12 +89,15 @@ void ScrollArea::init() 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++) { + 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++; } } @@ -106,12 +110,15 @@ void ScrollArea::init() int vsgridy[4] = {0, 4, 15, 19}; a = 0; - for (y = 0; y < 3; y++) { - for (x = 0; x < 3; x++) { + 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++; } } @@ -146,7 +153,7 @@ void ScrollArea::logic() // When no scrollbar in a certain direction, adapt content size to match // the content dimension exactly. - if (content != NULL) + if (content) { if (getHorizontalScrollPolicy() == gcn::ScrollArea::SHOW_NEVER) { @@ -188,6 +195,16 @@ void ScrollArea::draw(gcn::Graphics *graphics) 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); } @@ -197,7 +214,8 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics) int w = getWidth() + bs * 2; int h = getHeight() + bs * 2; - if (mOpaque) { + if (mOpaque) + { static_cast<Graphics*>(graphics)-> drawImageRect(0, 0, w, h, background); } @@ -207,10 +225,12 @@ void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; - if (mOpaque) { + if (mOpaque) + { setFrameSize(2); } - else { + else + { setFrameSize(0); } } @@ -220,7 +240,8 @@ void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir) int state = 0; gcn::Rectangle dim; - switch(dir) { + switch (dir) + { case UP: state = mUpButtonPressed ? 1 : 0; dim = getUpButtonDimension(); diff --git a/src/gui/scrollarea.h b/src/gui/scrollarea.h index 1641f318..33ebc692 100644 --- a/src/gui/scrollarea.h +++ b/src/gui/scrollarea.h @@ -38,12 +38,12 @@ class ScrollArea : public gcn::ScrollArea /** * Constructor. */ - ScrollArea(bool gc = true); + ScrollArea(bool gc = true, bool opaque = true); /** * Constructor. */ - ScrollArea(gcn::Widget *content, bool gc = true); + ScrollArea(gcn::Widget *content, bool gc = true, bool opaque = true); /** * Destructor. @@ -100,6 +100,7 @@ class ScrollArea : public gcn::ScrollArea void drawHMarker(gcn::Graphics *graphics); static int instances; + static float mAlpha; static ImageRect background; static ImageRect vMarker; static Image *buttons[4][2]; diff --git a/src/gui/sdlinput.cpp b/src/gui/sdlinput.cpp index f68dc9c8..51442798 100644 --- a/src/gui/sdlinput.cpp +++ b/src/gui/sdlinput.cpp @@ -228,7 +228,7 @@ int SDLInput::convertMouseButton(int button) int SDLInput::convertKeyCharacter(SDL_Event event) { SDL_keysym keysym = event.key.keysym; - + int value = keysym.unicode; switch (keysym.sym) diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index cc6f02d5..e4be7921 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -19,25 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "sell.h" - -#include <cassert> - #include <guichan/widgets/label.hpp> #include "button.h" -#include "shoplistbox.h" #include "scrollarea.h" +#include "sell.h" #include "shop.h" +#include "shoplistbox.h" #include "slider.h" #include "widgets/layout.h" -#include "../item.h" #include "../npc.h" -#include "../resources/iteminfo.h" - #include "../net/messageout.h" #include "../net/protocol.h" diff --git a/src/gui/sell.h b/src/gui/sell.h index 8e639a3d..c11a7b7c 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -25,9 +25,9 @@ #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> -#include "window.h" +#include <SDL_types.h> -#include "../guichanfwd.h" +#include "window.h" class Item; class Network; diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index d38fb2e3..09eaeff0 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -19,31 +19,30 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup.h" - #include "button.h" +#include "setup.h" #include "setup_audio.h" +#include "setup_colors.h" #include "setup_joystick.h" -#include "setup_video.h" #include "setup_keyboard.h" #include "setup_players.h" +#include "setup_video.h" #include "widgets/tabbedarea.h" #include "../utils/dtor.h" #include "../utils/gettext.h" -#include <algorithm> -#include <iostream> - -extern Window *statusWindow; -extern Window *minimap; extern Window *chatWindow; -extern Window *inventoryWindow; extern Window *equipmentWindow; extern Window *helpWindow; +extern Window *inventoryWindow; +extern Window *minimap; extern Window *skillDialog; +extern Window *statusWindow; extern Window *itemShortcutWindow; +extern Window *emoteShortcutWindow; +extern Window *emoteWindow; extern Window *tradeWindow; Setup::Setup(): @@ -58,7 +57,8 @@ Setup::Setup(): N_("Apply"), N_("Cancel"), N_("Reset Windows"), 0 }; int x = width; - for (const char **curBtn = buttonNames; *curBtn; ++curBtn) { + for (const char **curBtn = buttonNames; *curBtn; ++curBtn) + { Button *btn = new Button(gettext(*curBtn), *curBtn, this); x -= btn->getWidth() + 5; btn->setPosition(x, height - btn->getHeight() - 5); @@ -90,6 +90,10 @@ Setup::Setup(): panel->addTab(_("Keyboard"), tab); mTabs.push_back(tab); + tab = new Setup_Colors(); + panel->addTab(_("Colors"), tab); + mTabs.push_back(tab); + tab = new Setup_Players(); panel->addTab(_("Players"), tab); mTabs.push_back(tab); @@ -131,6 +135,8 @@ void Setup::action(const gcn::ActionEvent &event) helpWindow->resetToDefaultSize(); skillDialog->resetToDefaultSize(); itemShortcutWindow->resetToDefaultSize(); + emoteShortcutWindow->resetToDefaultSize(); + emoteWindow->resetToDefaultSize(); tradeWindow->resetToDefaultSize(); } } diff --git a/src/gui/setup.h b/src/gui/setup.h index 881961f6..e4eb0902 100644 --- a/src/gui/setup.h +++ b/src/gui/setup.h @@ -28,6 +28,8 @@ #include "window.h" +#include "../guichanfwd.h" + class SetupTab; /** @@ -51,8 +53,7 @@ class Setup : public Window, public gcn::ActionListener /** * Event handling method. */ - void - action(const gcn::ActionEvent &event); + void action(const gcn::ActionEvent &event); private: std::list<SetupTab*> mTabs; diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index b9fc1d2d..5c189882 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -19,12 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_audio.h" - #include <guichan/widgets/label.hpp> #include "checkbox.h" #include "ok_dialog.h" +#include "setup_audio.h" #include "slider.h" #include "widgets/layouthelper.h" @@ -110,8 +109,8 @@ void Setup_Audio::cancel() sound.setMusicVolume(mMusicVolume); mMusicSlider->setValue(mMusicVolume); - config.setValue("sound", mSoundEnabled ? 1 : 0); - config.setValue("sfxVolume", mSfxVolume ? 1 : 0); + config.setValue("sound", mSoundEnabled ? true : false); + config.setValue("sfxVolume", mSfxVolume); config.setValue("musicVolume", mMusicVolume); } diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h index 5345d3cf..9e951895 100644 --- a/src/gui/setup_audio.h +++ b/src/gui/setup_audio.h @@ -22,11 +22,9 @@ #ifndef GUI_SETUP_AUDIO_H #define GUI_SETUP_AUDIO_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Audio : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp new file mode 100644 index 00000000..372dbd17 --- /dev/null +++ b/src/gui/setup_colors.cpp @@ -0,0 +1,249 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * 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 <string> +#include <cmath> + +#include <guichan/listmodel.hpp> +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/slider.hpp> + +#include "browserbox.h" +#include "color.h" +#include "itemlinkhandler.h" +#include "listbox.h" +#include "scrollarea.h" +#include "setup_colors.h" +#include "slider.h" +#include "textfield.h" + +#include "widgets/layouthelper.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" +#include "../utils/tostring.h" + +Setup_Colors::Setup_Colors() : + mSelected(-1) +{ + setOpaque(false); + + mColorBox = new ListBox(textColor); + mColorBox->setActionEventId("color_box"); + mColorBox->addActionListener(this); + + mScroll = new ScrollArea(mColorBox); + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mPreview = new BrowserBox(BrowserBox::AUTO_WRAP); + mPreview->setOpaque(false); + + // Replace this later with a more appropriate link handler. For now, this'll + // do, as it'll do nothing when clicked on. + mPreview->setLinkHandler(new ItemLinkHandler()); + + mPreviewBox = new ScrollArea(mPreview); + mPreviewBox->setHeight(20); + mPreviewBox->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_NEVER); + + mRedLabel = new gcn::Label(_("Red: ")); + + mRedText = new TextField(); + mRedText->setWidth(40); + mRedText->setRange(0, 255); + mRedText->setNumeric(true); + mRedText->addListener(this); + + mRedSlider = new Slider(0, 255); + mRedSlider->setWidth(160); + mRedSlider->setValue(mRedText->getValue()); + mRedSlider->setActionEventId("slider_red"); + mRedSlider->addActionListener(this); + + mGreenLabel = new gcn::Label(_("Green: ")); + + mGreenText = new TextField(); + mGreenText->setWidth(40); + mGreenText->setRange(0, 255); + mGreenText->setNumeric(true); + mGreenText->addListener(this); + + mGreenSlider = new Slider(0, 255); + mGreenSlider->setWidth(160); + mGreenSlider->setValue(mGreenText->getValue()); + mGreenSlider->setActionEventId("slider_green"); + mGreenSlider->addActionListener(this); + + mBlueLabel = new gcn::Label(_("Blue: ")); + + mBlueText = new TextField(); + mBlueText->setWidth(40); + mBlueText->setRange(0, 255); + mBlueText->setNumeric(true); + mBlueText->addListener(this); + + mBlueSlider = new Slider(0, 255); + mBlueSlider->setWidth(160); + mBlueSlider->setValue(mBlueText->getValue()); + mBlueSlider->setActionEventId("slider_blue"); + mBlueSlider->addActionListener(this); + + setOpaque(false); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mScroll, 4, 7).setPadding(2); + place(0, 7, mPreviewBox, 4).setPadding(2); + place(0, 8, mRedLabel, 2); + place(2, 8, mRedSlider); + place(3, 8, mRedText).setPadding(1); + place(0, 9, mGreenLabel, 2); + place(2, 9, mGreenSlider); + place(3, 9, mGreenText).setPadding(1); + place(0, 10, mBlueLabel, 2); + place(2, 10, mBlueSlider); + place(3, 10, mBlueText).setPadding(1); + + setDimension(gcn::Rectangle(0, 0, 290, 250)); +} + +Setup_Colors::~Setup_Colors() +{ + delete mRedLabel; + delete mRedSlider; + delete mRedText; + + delete mGreenLabel; + delete mGreenSlider; + delete mGreenText; + + delete mBlueLabel; + delete mBlueSlider; + delete mBlueText; + + delete mScroll; +} + +void Setup_Colors::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "color_box") + { + mSelected = mColorBox->getSelected(); + int col = textColor->getColorAt(mSelected); + char ch = textColor->getColorCharAt(mSelected); + std::string msg; + + if (ch == '<') + msg = toString("@@|") + + _("This is what the color looks like") + "@@"; + else + msg = "##" + toString(ch) + + _("This is what the color looks like"); + + mPreview->clearRows(); + mPreview->addRow(msg); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); + return; + } + + if (event.getId() == "slider_red") + { + mRedText->setText(toString(std::floor(mRedSlider->getValue()))); + updateColor(); + return; + } + + if (event.getId() == "slider_green") + { + mGreenText->setText(toString(std::floor(mGreenSlider->getValue()))); + updateColor(); + return; + } + + if (event.getId() == "slider_blue") + { + mBlueText->setText(toString(std::floor(mBlueSlider->getValue()))); + updateColor(); + return; + } +} + +void Setup_Colors::setEntry(gcn::Slider *s, TextField *t, int value) +{ + s->setValue(value); + char buffer[100]; + sprintf(buffer, "%d", value); + t->setText(buffer); +} + +void Setup_Colors::apply() +{ + textColor->commit(); +} + +void Setup_Colors::cancel() +{ + textColor->rollback(); + int col = textColor->getColorAt(mSelected); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); +} + +void Setup_Colors::listen(const TextField *tf) +{ + if (tf == mRedText) + { + mRedSlider->setValue(tf->getValue()); + updateColor(); + return; + } + if (tf == mGreenText) + { + mGreenSlider->setValue(tf->getValue()); + updateColor(); + return; + } + if (tf == mBlueText) + { + mBlueSlider->setValue(tf->getValue()); + updateColor(); + return; + } +} + +void Setup_Colors::updateColor() +{ + if (mSelected == -1) + { + return; + } + int rgb = static_cast<int>(mRedSlider->getValue()) << 16 | + static_cast<int>(mGreenSlider->getValue()) << 8 | + static_cast<int>(mBlueSlider->getValue()); + textColor->setColorAt(mSelected, rgb); +} diff --git a/src/gui/setup_colors.h b/src/gui/setup_colors.h new file mode 100644 index 00000000..8fd1ba59 --- /dev/null +++ b/src/gui/setup_colors.h @@ -0,0 +1,75 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * 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 SETUP_COLOURS_H +#define SETUP_COLOURS_H + +#include <string> + +#include <guichan/actionlistener.hpp> + +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/listbox.hpp> + +#include "setuptab.h" +#include "textfield.h" + +#include "../guichanfwd.h" + +class BrowserBox; + +class Setup_Colors : public SetupTab, public gcn::ActionListener, + public TextFieldListener +{ + public: + Setup_Colors(); + ~Setup_Colors(); + void apply(); + void cancel(); + void action(const gcn::ActionEvent &event); + + void listen(const TextField *tf); + private: + gcn::ListBox *mColorBox; + gcn::ScrollArea *mScroll; + BrowserBox *mPreview; + gcn::ScrollArea *mPreviewBox; + int mSelected; + + gcn::Label *mRedLabel; + gcn::Slider *mRedSlider; + TextField *mRedText; + int mRedValue; + + gcn::Label *mGreenLabel; + gcn::Slider *mGreenSlider; + TextField *mGreenText; + int mGreenValue; + + gcn::Label *mBlueLabel; + gcn::Slider *mBlueSlider; + TextField *mBlueText; + int mBlueValue; + + void setEntry(gcn::Slider *s, TextField *t, int value); + void updateColor(); +}; +#endif diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index f8fc194f..2ebcdbde 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -19,12 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_joystick.h" - #include <guichan/widgets/label.hpp> #include "button.h" #include "checkbox.h" +#include "setup_joystick.h" #include "widgets/layouthelper.h" @@ -42,7 +41,7 @@ Setup_Joystick::Setup_Joystick(): { setOpaque(false); - mOriginalJoystickEnabled = (int)config.getValue("joystickEnabled", 0) != 0; + mOriginalJoystickEnabled = !config.getValue("joystickEnabled", false); mJoystickEnabled->setSelected(mOriginalJoystickEnabled); mJoystickEnabled->addActionListener(this); @@ -62,7 +61,8 @@ Setup_Joystick::Setup_Joystick(): void Setup_Joystick::action(const gcn::ActionEvent &event) { - if (!joystick) { + if (!joystick) + { return; } @@ -72,12 +72,15 @@ void Setup_Joystick::action(const gcn::ActionEvent &event) } else { - if (joystick->isCalibrating()) { + if (joystick->isCalibrating()) + { mCalibrateButton->setCaption(_("Calibrate")); mCalibrateLabel->setCaption (_("Press the button to start calibration")); joystick->finishCalibration(); - } else { + } + else + { mCalibrateButton->setCaption(_("Stop")); mCalibrateLabel->setCaption(_("Rotate the stick")); joystick->startCalibration(); diff --git a/src/gui/setup_joystick.h b/src/gui/setup_joystick.h index dd8c331f..eba8a2cc 100644 --- a/src/gui/setup_joystick.h +++ b/src/gui/setup_joystick.h @@ -22,11 +22,9 @@ #ifndef GUI_SETUP_JOYSTICK_H #define GUI_SETUP_JOYSTICK_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Joystick : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp index cf44731c..5d7519ef 100644 --- a/src/gui/setup_keyboard.cpp +++ b/src/gui/setup_keyboard.cpp @@ -1,6 +1,7 @@ /* - * The Mana World - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> + * Copyright (C) 2009 The Mana World Development Team * * This file is part of The Mana World. * @@ -19,7 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_keyboard.h" +#include <SDL_keyboard.h> #include <guichan/widgets/label.hpp> #include <guichan/listmodel.hpp> @@ -28,17 +29,15 @@ #include "listbox.h" #include "ok_dialog.h" #include "scrollarea.h" +#include "setup_keyboard.h" #include "widgets/layouthelper.h" -#include "../configuration.h" #include "../keyboardconfig.h" #include "../utils/gettext.h" #include "../utils/tostring.h" -#include <SDL_keyboard.h> - /** * The list model for key function list. * @@ -79,11 +78,10 @@ Setup_Keyboard::Setup_Keyboard(): refreshKeys(); - mKeyList->setDimension(gcn::Rectangle(0, 0, 185, 140)); mKeyList->addActionListener(this); - mKeyList->setSelected(-1); ScrollArea *scrollArea = new ScrollArea(mKeyList); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mAssignKeyButton = new Button(_("Assign"), "assign", this); mAssignKeyButton->addActionListener(this); @@ -140,9 +138,8 @@ void Setup_Keyboard::action(const gcn::ActionEvent &event) { if (event.getSource() == mKeyList) { - if (!mKeySetting) { + if (!mKeySetting) mAssignKeyButton->setEnabled(true); - } } else if (event.getId() == "assign") { @@ -186,7 +183,8 @@ void Setup_Keyboard::refreshKeys() void Setup_Keyboard::keyUnresolved() { - if (mKeySetting) { + if (mKeySetting) + { newKeyCallback(keyboard.getNewKeyIndex()); keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); } diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h index f04be792..dee12135 100644 --- a/src/gui/setup_keyboard.h +++ b/src/gui/setup_keyboard.h @@ -1,6 +1,6 @@ /* - * The Mana World - * Copyright (C) 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * * This file is part of The Mana World. * @@ -22,14 +22,13 @@ #ifndef GUI_SETUP_KEYBOARD_H #define GUI_SETUP_KEYBOARD_H -#include "setuptab.h" -#include "button.h" -#include "../guichanfwd.h" +#include <string> #include <guichan/actionlistener.hpp> +#include "setuptab.h" -#include <string> +#include "../guichanfwd.h" class Setup_Keyboard : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp index 1d8649eb..d25117de 100644 --- a/src/gui/setup_players.cpp +++ b/src/gui/setup_players.cpp @@ -19,26 +19,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_players.h" +#include <string> +#include <vector> + +#include <guichan/widgets/label.hpp> #include "button.h" #include "checkbox.h" +#include "listbox.h" #include "ok_dialog.h" +#include "scrollarea.h" +#include "setup_players.h" +#include "table.h" +#include "widgets/dropdown.h" #include "widgets/layouthelper.h" #include "../configuration.h" #include "../log.h" -#include "../player_relations.h" -#include "../sound.h" #include "../utils/gettext.h" -#include <guichan/widgets/dropdown.hpp> -#include <guichan/widgets/label.hpp> - -#include <vector> - #define COLUMNS_NR 2 // name plus listbox #define NAME_COLUMN 0 #define RELATION_CHOICE_COLUMN 1 @@ -136,8 +137,12 @@ public: std::string name = (*player_names)[r]; gcn::Widget *widget = new gcn::Label(name); mWidgets.push_back(widget); + gcn::ListModel *playerRelation = new PlayerRelationListModel(); - gcn::DropDown *choicebox = new gcn::DropDown(new PlayerRelationListModel()); + gcn::DropDown *choicebox = new DropDown(playerRelation, + new ScrollArea(), + new ListBox(playerRelation), + false); choicebox->setSelected(player_relations.getRelation(name)); mWidgets.push_back(choicebox); } @@ -198,7 +203,7 @@ public: virtual std::string getElementAt(int i) { if (i >= getNumberOfElements()) { - return "???"; + return _("???"); } return (*player_relations.getPlayerIgnoreStrategies())[i]->mDescription; } @@ -220,18 +225,22 @@ Setup_Players::Setup_Players(): player_relations.getDefault() & PlayerRelation::TRADE)), mDefaultWhisper(new CheckBox(_("Allow whispers"), player_relations.getDefault() & PlayerRelation::WHISPER)), - mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)), - mIgnoreActionChoicesBox(new gcn::DropDown(new IgnoreChoicesListModel())) + mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)) { setOpaque(false); + mPlayerTable->setOpaque(false); int table_width = NAME_COLUMN_WIDTH + RELATION_CHOICE_COLUMN_WIDTH; mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH); mPlayerTableTitleModel->fixColumnWidth(RELATION_CHOICE_COLUMN, RELATION_CHOICE_COLUMN_WIDTH); - mPlayerTitleTable->setDimension(gcn::Rectangle(10, 10, table_width, 10)); + mPlayerTitleTable->setDimension(gcn::Rectangle(10, 10, table_width - 1, 10)); mPlayerTitleTable->setBackgroundColor(gcn::Color(0xbf, 0xbf, 0xbf)); + gcn::ListModel *ignoreChoices = new IgnoreChoicesListModel(); + mIgnoreActionChoicesBox = new DropDown(ignoreChoices, new ScrollArea(), + new ListBox(ignoreChoices), false); + for (int i = 0; i < COLUMNS_NR; i++) { mPlayerTableTitleModel->set(0, i, diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h index d380d9f6..74247b77 100644 --- a/src/gui/setup_players.h +++ b/src/gui/setup_players.h @@ -22,20 +22,19 @@ #ifndef GUI_SETUP_PLAYERS_H #define GUI_SETUP_PLAYERS_H -#include "setuptab.h" - -#include "scrollarea.h" -#include "button.h" -#include "table.h" #include <guichan/actionlistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" #include "../player_relations.h" +class GuiTable; class PlayerTableModel; +class StaticTableModel; -class Setup_Players : public SetupTab, public gcn::ActionListener, public PlayerRelationsListener +class Setup_Players : public SetupTab, + public gcn::ActionListener, + public PlayerRelationsListener { public: Setup_Players(); @@ -55,13 +54,13 @@ private: PlayerTableModel *mPlayerTableModel; GuiTable *mPlayerTable; GuiTable *mPlayerTitleTable; - ScrollArea *mPlayerScrollArea; + gcn::ScrollArea *mPlayerScrollArea; gcn::CheckBox *mPersistIgnores; gcn::CheckBox *mDefaultTrading; gcn::CheckBox *mDefaultWhisper; - Button *mDeleteButton; + gcn::Button *mDeleteButton; gcn::DropDown *mIgnoreActionChoicesBox; }; diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 53041a9c..c02025c8 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -19,11 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_video.h" - +#include <SDL.h> #include <string> #include <vector> -#include <SDL.h> #include <guichan/key.hpp> #include <guichan/listmodel.hpp> @@ -34,6 +32,7 @@ #include "listbox.h" #include "ok_dialog.h" #include "scrollarea.h" +#include "setup_video.h" #include "slider.h" #include "textfield.h" @@ -41,6 +40,7 @@ #include "../configuration.h" #include "../graphics.h" +#include "../localplayer.h" #include "../log.h" #include "../main.h" #include "../particle.h" @@ -104,9 +104,12 @@ ModeListModel::ModeListModel() } Setup_Video::Setup_Video(): - mFullScreenEnabled(config.getValue("screen", 0)), - mOpenGLEnabled(config.getValue("opengl", 0)), - mCustomCursorEnabled(config.getValue("customcursor", 1)), + mFullScreenEnabled(config.getValue("screen", false)), + mOpenGLEnabled(config.getValue("opengl", false)), + mCustomCursorEnabled(config.getValue("customcursor", true)), + mParticleEffectsEnabled(config.getValue("particleeffects", true)), + mSpeechBubbleEnabled(config.getValue("speechbubble", true)), + mNameEnabled(config.getValue("showownname", false)), mOpacity(config.getValue("guialpha", 0.8)), mFps((int) config.getValue("fpslimit", 0)), mModeListModel(new ModeListModel), @@ -114,6 +117,9 @@ Setup_Video::Setup_Video(): mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)), mOpenGLCheckBox(new CheckBox(_("OpenGL"), mOpenGLEnabled)), mCustomCursorCheckBox(new CheckBox(_("Custom cursor"), mCustomCursorEnabled)), + mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)), + mSpeechBubbleCheckBox(new CheckBox(_("Speech bubbles"), mSpeechBubbleEnabled)), + mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)), mAlphaSlider(new Slider(0.2, 1.0)), mFpsCheckBox(new CheckBox(_("FPS Limit:"))), mFpsSlider(new Slider(10, 200)), @@ -137,13 +143,12 @@ Setup_Video::Setup_Video(): scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); gcn::Label *alphaLabel = new gcn::Label(_("Gui opacity")); - gcn::Label *scrollRadiusLabel = new gcn::Label(_("Scroll radius")); gcn::Label *scrollLazinessLabel = new gcn::Label(_("Scroll laziness")); gcn::Label *overlayDetailLabel = new gcn::Label(_("Ambient FX")); gcn::Label *particleDetailLabel = new gcn::Label(_("Particle Detail")); - mModeList->setEnabled(false); + mModeList->setEnabled(true); #ifndef USE_OPENGL mOpenGLCheckBox->setEnabled(false); #endif @@ -159,7 +164,11 @@ Setup_Video::Setup_Video(): mFpsSlider->setEnabled(mFps > 0); mFpsCheckBox->setSelected(mFps > 0); + mModeList->setActionEventId("videomode"); mCustomCursorCheckBox->setActionEventId("customcursor"); + mParticleEffectsCheckBox->setActionEventId("particleeffects"); + mSpeechBubbleCheckBox->setActionEventId("speechbubble"); + mNameCheckBox->setActionEventId("showownname"); mAlphaSlider->setActionEventId("guialpha"); mFpsCheckBox->setActionEventId("fpslimitcheckbox"); mFpsSlider->setActionEventId("fpslimitslider"); @@ -172,7 +181,11 @@ Setup_Video::Setup_Video(): mParticleDetailSlider->setActionEventId("particledetailslider"); mParticleDetailField->setActionEventId("particledetailfield"); + mModeList->addActionListener(this); mCustomCursorCheckBox->addActionListener(this); + mParticleEffectsCheckBox->addActionListener(this); + mSpeechBubbleCheckBox->addActionListener(this); + mNameCheckBox->addActionListener(this); mAlphaSlider->addActionListener(this); mFpsCheckBox->addActionListener(this); mFpsSlider->addActionListener(this); @@ -227,30 +240,33 @@ Setup_Video::Setup_Video(): LayoutHelper h(this); ContainerPlacer place = h.getPlacer(0, 0); - place(0, 0, scrollArea, 1, 4).setPadding(2); + place(0, 0, scrollArea, 1, 6).setPadding(2); place(1, 0, mFsCheckBox, 3); place(1, 1, mOpenGLCheckBox, 3); place(1, 2, mCustomCursorCheckBox, 3); - - place(0, 4, mAlphaSlider); - place(0, 5, mFpsSlider); - place(0, 6, mScrollRadiusSlider); - place(0, 7, mScrollLazinessSlider); - place(0, 8, mOverlayDetailSlider); - place(0, 9, mParticleDetailSlider); - - place(1, 4, alphaLabel, 2); - place(1, 5, mFpsCheckBox).setPadding(3); - place(1, 6, scrollRadiusLabel); - place(1, 7, scrollLazinessLabel); - place(1, 8, overlayDetailLabel); - place(1, 9, particleDetailLabel); - - place(2, 5, mFpsField).setPadding(1); - place(2, 6, mScrollRadiusField).setPadding(1); - place(2, 7, mScrollLazinessField).setPadding(1); - place(2, 8, mOverlayDetailField, 2).setPadding(2); - place(2, 9, mParticleDetailField, 2).setPadding(2); + place(1, 3, mSpeechBubbleCheckBox, 3); + place(1, 4, mNameCheckBox, 3); + place(1, 5, mParticleEffectsCheckBox, 3); + + place(0, 7, mAlphaSlider); + place(0, 8, mFpsSlider); + place(0, 9, mScrollRadiusSlider); + place(0, 10, mScrollLazinessSlider); + place(0, 11, mOverlayDetailSlider); + place(0, 12, mParticleDetailSlider); + + place(1, 7, alphaLabel, 2); + place(1, 8, mFpsCheckBox).setPadding(3); + place(1, 9, scrollRadiusLabel); + place(1, 10, scrollLazinessLabel); + place(1, 11, overlayDetailLabel); + place(1, 12, particleDetailLabel); + + place(2, 8, mFpsField).setPadding(1); + place(2, 9, mScrollRadiusField).setPadding(1); + place(2, 10, mScrollLazinessField).setPadding(1); + place(2, 11, mOverlayDetailField, 2).setPadding(2); + place(2, 12, mParticleDetailField, 2).setPadding(2); setDimension(gcn::Rectangle(0, 0, 295, 250)); } @@ -264,7 +280,7 @@ void Setup_Video::apply() { // Full screen changes bool fullscreen = mFsCheckBox->isSelected(); - if (fullscreen != (config.getValue("screen", 0) == 1)) + if (fullscreen != (config.getValue("screen", false) == 1)) { /* The OpenGL test is only necessary on Windows, since switching * to/from full screen works fine on Linux. On Windows we'd have to @@ -275,7 +291,7 @@ void Setup_Video::apply() #if defined(WIN32) || defined(__APPLE__) // checks for opengl usage - if (!(config.getValue("opengl", 0) == 1)) + if (!(config.getValue("opengl", false) == 1)) { #endif if (!graphics->setFullscreen(fullscreen)) @@ -284,9 +300,9 @@ void Setup_Video::apply() if (!graphics->setFullscreen(fullscreen)) { std::stringstream error; - error << "Failed to switch to " << - (fullscreen ? "windowed" : "fullscreen") << - "mode and restoration of old mode also failed!" << + error << _("Failed to switch to ") << + (fullscreen ? _("windowed") : _("fullscreen")) << + _("mode and restoration of old mode also failed!") << std::endl; logger->error(error.str()); } @@ -297,13 +313,13 @@ void Setup_Video::apply() _("Restart needed for changes to take effect.")); } #endif - config.setValue("screen", fullscreen ? 1 : 0); + config.setValue("screen", fullscreen ? true : false); } // OpenGL change if (mOpenGLCheckBox->isSelected() != mOpenGLEnabled) { - config.setValue("opengl", mOpenGLCheckBox->isSelected() ? 1 : 0); + config.setValue("opengl", mOpenGLCheckBox->isSelected() ? true : false); // OpenGL can currently only be changed by restarting, notify user. new OkDialog(_("Changing OpenGL"), @@ -314,11 +330,14 @@ void Setup_Video::apply() config.setValue("fpslimit", mFps); // We sync old and new values at apply time - mFullScreenEnabled = config.getValue("screen", 0); - mCustomCursorEnabled = config.getValue("customcursor", 1); + mFullScreenEnabled = config.getValue("screen", false); + mCustomCursorEnabled = config.getValue("customcursor", true); + mParticleEffectsEnabled = config.getValue("particleeffects", true); + mSpeechBubbleEnabled = config.getValue("speechbubble", true); + mNameEnabled = config.getValue("showownname", false); mOpacity = config.getValue("guialpha", 0.8); - mOverlayDetail = (int)config.getValue("OverlayDetail", 2); - mOpenGLEnabled = config.getValue("opengl", 0); + mOverlayDetail = (int) config.getValue("OverlayDetail", 2); + mOpenGLEnabled = config.getValue("opengl", false); } int Setup_Video::updateSlider(gcn::Slider *slider, gcn::TextField *field, @@ -346,6 +365,9 @@ void Setup_Video::cancel() mFsCheckBox->setSelected(mFullScreenEnabled); mOpenGLCheckBox->setSelected(mOpenGLEnabled); mCustomCursorCheckBox->setSelected(mCustomCursorEnabled); + mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled); + mSpeechBubbleCheckBox->setSelected(mSpeechBubbleEnabled); + mNameCheckBox->setSelected(mNameEnabled); mAlphaSlider->setValue(mOpacity); mOverlayDetailSlider->setValue(mOverlayDetail); mParticleDetailSlider->setValue(mParticleDetail); @@ -355,22 +377,59 @@ void Setup_Video::cancel() updateSlider(mScrollRadiusSlider, mScrollRadiusField, "ScrollRadius"); updateSlider(mScrollLazinessSlider, mScrollLazinessField, "ScrollLaziness"); - config.setValue("screen", mFullScreenEnabled ? 1 : 0); - config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0); + config.setValue("screen", mFullScreenEnabled ? true : false); + config.setValue("customcursor", mCustomCursorEnabled ? true : false); + config.setValue("particleeffects", mParticleEffectsEnabled ? true : false); + config.setValue("speechbubble", mSpeechBubbleEnabled ? true : false); + config.setValue("showownname", mNameEnabled ? true : false); config.setValue("guialpha", mOpacity); - config.setValue("opengl", mOpenGLEnabled ? 1 : 0); + config.setValue("opengl", mOpenGLEnabled ? true : false); } void Setup_Video::action(const gcn::ActionEvent &event) { - if (event.getId() == "guialpha") + if (event.getId() == "videomode") + { + const std::string mode = mModeListModel->getElementAt(mModeList->getSelected()); + const int width = atoi(mode.substr(0, mode.find("x")).c_str()); + const int height = atoi(mode.substr(mode.find("x") + 1).c_str()); + + // TODO: Find out why the drawing area doesn't resize without a restart. + new OkDialog(_("Screen resolution changed"), + _("Restart your client for the change to take effect.")); + + config.setValue("screenwidth", width); + config.setValue("screenheight", height); + } + else if (event.getId() == "guialpha") { config.setValue("guialpha", mAlphaSlider->getValue()); } else if (event.getId() == "customcursor") { config.setValue("customcursor", - mCustomCursorCheckBox->isSelected() ? 1 : 0); + mCustomCursorCheckBox->isSelected() ? true : false); + } + else if (event.getId() == "particleeffects") + { + config.setValue("particleeffects", + mParticleEffectsCheckBox->isSelected() ? true : false); + new OkDialog(_("Particle effect settings changed"), + _("Restart your client or change maps for the change to take effect.")); + } + else if (event.getId() == "speechbubble") + { + config.setValue("speechbubble", + mSpeechBubbleCheckBox->isSelected() ? true : false); + } + else if (event.getId() == "showownname") + { + // Notify the local player that settings have changed for the name + // and requires an update + if (player_node) + player_node->mUpdateName = true; + config.setValue("showownname", + mNameCheckBox->isSelected() ? true : false); } else if (event.getId() == "fpslimitslider") { diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index b7011186..303b5bfc 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -22,12 +22,10 @@ #ifndef GUI_SETUP_VIDEO_H #define GUI_SETUP_VIDEO_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Video : public SetupTab, public gcn::ActionListener, public gcn::KeyListener @@ -53,6 +51,9 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, bool mFullScreenEnabled; bool mOpenGLEnabled; bool mCustomCursorEnabled; + bool mParticleEffectsEnabled; + bool mSpeechBubbleEnabled; + bool mNameEnabled; double mOpacity; int mFps; @@ -62,6 +63,9 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, gcn::CheckBox *mFsCheckBox; gcn::CheckBox *mOpenGLCheckBox; gcn::CheckBox *mCustomCursorCheckBox; + gcn::CheckBox *mParticleEffectsCheckBox; + gcn::CheckBox *mSpeechBubbleCheckBox; + gcn::CheckBox *mNameCheckBox; gcn::Slider *mAlphaSlider; gcn::CheckBox *mFpsCheckBox; diff --git a/src/gui/shop.h b/src/gui/shop.h index 4a03b2bc..e0db4c59 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -27,10 +27,10 @@ #include <guichan/listmodel.hpp> -#include "../resources/image.h" - #include "../shopitem.h" +class ShopItem; + class ShopItems : public gcn::ListModel { public: diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index 2517d749..94187818 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -19,19 +19,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "shoplistbox.h" - #include <guichan/font.hpp> -#include <guichan/graphics.hpp> #include <guichan/listmodel.hpp> -#include <guichan/mouseinput.hpp> -#include <guichan/imagefont.hpp> -#include <guichan/basiccontainer.hpp> +#include "color.h" +#include "shop.h" +#include "shoplistbox.h" + +#include "../configuration.h" #include "../graphics.h" const int ITEM_ICON_SIZE = 32; +float ShopListBox::mAlpha = config.getValue("guialpha", 0.8); + ShopListBox::ShopListBox(gcn::ListModel *listModel): ListBox(listModel), mPlayerMoney(0) @@ -59,6 +60,15 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (!mListModel) return; + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + bool valid; + const int red = (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = mAlpha * 255; + Graphics *graphics = static_cast<Graphics*>(gcnGraphics); graphics->setFont(getFont()); @@ -68,16 +78,16 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) i < mListModel->getNumberOfElements(); ++i, y += mRowHeight) { - gcn::Color backgroundColor = gcn::Color(0xffffff); + gcn::Color backgroundColor = gcn::Color(255, 255, 255, alpha); if (i == mSelected) { - backgroundColor = gcn::Color(110, 160, 255); + backgroundColor = gcn::Color(red, green, blue, alpha); } else if (mShopItems && mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck) { - backgroundColor = gcn::Color(0x919191); + backgroundColor = gcn::Color(145, 145, 145, alpha); } graphics->setColor(backgroundColor); diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h index bad848d6..cde4786e 100644 --- a/src/gui/shoplistbox.h +++ b/src/gui/shoplistbox.h @@ -23,7 +23,8 @@ #define SHOPLISTBOX_H #include "listbox.h" -#include "shop.h" + +class ShopItems; /** * A list box, meant to be used inside a scroll area. Same as the Guichan list @@ -84,6 +85,8 @@ class ShopListBox : public ListBox unsigned int mRowHeight; /**< Row Height */ + static float mAlpha; + bool mPriceCheck; }; diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp new file mode 100644 index 00000000..4472818e --- /dev/null +++ b/src/gui/shortcutcontainer.cpp @@ -0,0 +1,71 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "shortcutcontainer.h" + +#include "../configuration.h" + +#include "../resources/image.h" + +#include "../utils/tostring.h" + +float ShortcutContainer::mAlpha = config.getValue("guialpha", 0.8); + +ShortcutContainer::ShortcutContainer(): + mGridWidth(1), + mGridHeight(1) +{ +} + +void ShortcutContainer::widgetResized(const gcn::Event &event) +{ + mGridWidth = getWidth() / mBoxWidth; + if (mGridWidth < 1) + { + mGridWidth = 1; + } + + setHeight((mMaxItems / mGridWidth + + (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight); + + mGridHeight = getHeight() / mBoxHeight; + if (mGridHeight < 1) + { + mGridHeight = 1; + } +} + +int ShortcutContainer::getIndexFromGrid(int pointX, int pointY) const +{ + const gcn::Rectangle tRect = gcn::Rectangle( + 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); + if (!tRect.isPointInRect(pointX, pointY)) + { + return -1; + } + const int index = ((pointY / mBoxHeight) * mGridWidth) + + pointX / mBoxWidth; + if (index >= mMaxItems) + { + return -1; + } + return index; +} diff --git a/src/gui/shortcutcontainer.h b/src/gui/shortcutcontainer.h new file mode 100644 index 00000000..f5f06163 --- /dev/null +++ b/src/gui/shortcutcontainer.h @@ -0,0 +1,107 @@ +/* + * The Mana World + * Copyright 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SHORTCUTCONTAINER_H__ +#define SHORTCUTCONTAINER_H__ + +#include <guichan/mouselistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +class Image; + +/** + * A generic shortcut container. + * + * \ingroup GUI + */ +class ShortcutContainer : public gcn::Widget, + public gcn::WidgetListener, + public gcn::MouseListener +{ + public: + /** + * Constructor. Initializes the shortcut container. + */ + ShortcutContainer(); + + /** + * Destructor. + */ + ~ShortcutContainer(){} + + /** + * Draws the shortcuts + */ + virtual void draw(gcn::Graphics *graphics) = 0; + + /** + * Invoked when a widget changes its size. This is used to determine + * the new height of the container. + */ + virtual void widgetResized(const gcn::Event &event); + + /** + * Handles mouse when dragged. + */ + virtual void mouseDragged(gcn::MouseEvent &event) = 0; + + /** + * Handles mouse when pressed. + */ + virtual void mousePressed(gcn::MouseEvent &event) = 0; + + /** + * Handles mouse release. + */ + virtual void mouseReleased(gcn::MouseEvent &event) = 0; + + virtual int getMaxItems() + { return mMaxItems; } + + virtual int getBoxWidth() + { return mBoxWidth; } + + virtual int getBoxHeight() + { return mBoxHeight; } + + protected: + /** + * Gets the index from the grid provided the point is in an item box. + * + * @param pointX X coordinate of the point. + * @param pointY Y coordinate of the point. + * @return index on success, -1 on failure. + */ + int getIndexFromGrid(int pointX, int pointY) const; + + Image *mBackgroundImg; + + static float mAlpha; + + int mMaxItems; + int mBoxWidth; + int mBoxHeight; + int mCursorPosX, mCursorPosY; + int mGridWidth, mGridHeight; +}; + +#endif diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/shortcutwindow.cpp index 6fe1a10b..b6987b3e 100644 --- a/src/gui/itemshortcutwindow.cpp +++ b/src/gui/shortcutwindow.cpp @@ -19,23 +19,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "itemshortcutwindow.h" - -#include "itemshortcutcontainer.h" #include "scrollarea.h" +#include "shortcutcontainer.h" +#include "shortcutwindow.h" + +#include "../configuration.h" static const int SCROLL_PADDING = 0; -ItemShortcutWindow::ItemShortcutWindow() +int ShortcutWindow::mInstances = 0; + +ShortcutWindow::ShortcutWindow(const char *title, ShortcutContainer *content) { - setWindowName("ItemShortcut"); + setWindowName(title); // no title presented, title bar is padding so window can be moved. gcn::Window::setTitleBarHeight(gcn::Window::getPadding()); setShowTitle(false); setResizable(true); - setDefaultSize(758, 174, 42, 426); - mItems = new ItemShortcutContainer; + mItems = content; + + mInstances++; const int border = SCROLL_PADDING * 2 + getPadding() * 2; setMinWidth(mItems->getBoxWidth() + border); @@ -43,6 +47,15 @@ ItemShortcutWindow::ItemShortcutWindow() setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); + const int width = (int) config.getValue("screenwidth", 800); + const int height = (int) config.getValue("screenheight", 600); + + setDefaultSize(width - (mInstances * mItems->getBoxWidth()) - + (mInstances * border), height - (mItems->getBoxHeight() * + mItems->getMaxItems()) - border, mItems->getBoxWidth() + + border, (mItems->getBoxHeight() * mItems->getMaxItems()) + + border); + mScrollArea = new ScrollArea(mItems); mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING); mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); @@ -53,13 +66,13 @@ ItemShortcutWindow::ItemShortcutWindow() loadWindowState(); } -ItemShortcutWindow::~ItemShortcutWindow() +ShortcutWindow::~ShortcutWindow() { delete mItems; delete mScrollArea; } -void ItemShortcutWindow::widgetResized(const gcn::Event &event) +void ShortcutWindow::widgetResized(const gcn::Event &event) { Window::widgetResized(event); diff --git a/src/gui/itemshortcutwindow.h b/src/gui/shortcutwindow.h index baa34b13..64592328 100644 --- a/src/gui/itemshortcutwindow.h +++ b/src/gui/shortcutwindow.h @@ -19,31 +19,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef ITEMSHORTCUTWINDOW_H -#define ITEMSHORTCUTWINDOW_H +#ifndef SHORTCUTWINDOW_H +#define SHORTCUTWINDOW_H #include "window.h" -class ItemShortcutContainer; class ScrollArea; +class ShortcutContainer; /** * A window around the ItemShortcutContainer. * * \ingroup Interface */ -class ItemShortcutWindow : public Window +class ShortcutWindow : public Window { public: /** * Constructor. */ - ItemShortcutWindow(); + ShortcutWindow(const char *title, ShortcutContainer *content); /** * Destructor. */ - ~ItemShortcutWindow(); + ~ShortcutWindow(); /** * Called whenever the widget changes size. @@ -51,11 +51,15 @@ class ItemShortcutWindow : public Window void widgetResized(const gcn::Event &event); private: - ItemShortcutContainer *mItems; + ShortcutWindow(); + ShortcutContainer *mItems; ScrollArea *mScrollArea; + + static int mInstances; }; -extern ItemShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *emoteShortcutWindow; #endif diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index 4afd913d..03711a47 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -21,13 +21,15 @@ #include <guichan/widgets/label.hpp> -#include "skill.h" - #include "button.h" #include "listbox.h" #include "scrollarea.h" +#include "skill.h" +#include "table.h" #include "windowcontainer.h" +#include "widgets/layout.h" + #include "../localplayer.h" #include "../log.h" @@ -36,13 +38,18 @@ #include "../utils/strprintf.h" #include "../utils/xml.h" -static const char *SKILLS_FILE = "skills.xml"; +static const char *SKILLS_FILE = _("skills.xml"); struct SkillInfo { std::string name; bool modifiable; }; +static const SkillInfo fakeSkillInfo = { + _("Mystery Skill"), + false +}; + std::vector<SkillInfo> skill_db; static void initSkillinfo(); @@ -58,14 +65,17 @@ public: update(); } - virtual int getRows() { return mEntriesNr; } + virtual int getRows(void) + { + return mEntriesNr; + } virtual int getColumnWidth(int index) { - switch (index) { - case 0: return 160; - default: return 35; - } + if (index == 0) + return 160; + + return 35; } virtual int getRowHeight() @@ -75,15 +85,11 @@ public: virtual void update() { - static const SkillInfo fakeSkillInfo = { - _("Mystery Skill"), - false - }; - mEntriesNr = mDialog->getSkills().size(); resize(); - for (int i = 0; i < mEntriesNr; i++) { + for (int i = 0; i < mEntriesNr; i++) + { SKILL *skill = mDialog->getSkills()[i]; SkillInfo const *info; char tmp[128]; @@ -120,37 +126,35 @@ SkillDialog::SkillDialog(): { initSkillinfo(); mTableModel = new SkillGuiTableModel(this); - mTable.setModel(mTableModel); - mTable.setLinewiseSelection(true); - - setWindowName("Skills"); + mTable = new GuiTable(mTableModel); + mTable->setOpaque(false); + mTable->setLinewiseSelection(true); + mTable->setWrappingEnabled(true); + mTable->setActionEventId("skill"); + mTable->addActionListener(this); + + setWindowName(_("Skills")); setCloseButton(true); setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260); -// mSkillListBox = new ListBox(this); - ScrollArea *skillScrollArea = new ScrollArea(&mTable); + setMinHeight(50 + mTableModel->getHeight()); + setMinWidth(200); + + ScrollArea *skillScrollArea = new ScrollArea(mTable); mPointsLabel = new gcn::Label(strprintf(_("Skill points: %d"), 0)); - mIncButton = new Button(_("Up"), "inc", this); - mUseButton = new Button(_("Use"), "use", this); + mIncButton = new Button(_("Up"), _("inc"), this); + mUseButton = new Button(_("Use"), _("use"), this); mUseButton->setEnabled(false); -// mSkillListBox->setActionEventId("skill"); - mTable.setActionEventId("skill"); - skillScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - skillScrollArea->setDimension(gcn::Rectangle(5, 5, 230, 180)); - mPointsLabel->setDimension(gcn::Rectangle(8, 190, 200, 16)); - mIncButton->setPosition(skillScrollArea->getX(), 210); - mUseButton->setPosition(mIncButton->getX() + mIncButton->getWidth() + 5, - 210); - add(skillScrollArea); - add(mPointsLabel); - add(mIncButton); - add(mUseButton); + place(0, 0, skillScrollArea, 5).setPadding(3); + place(0, 1, mPointsLabel, 2); + place(3, 2, mIncButton); + place(4, 2, mUseButton); -// mSkillListBox->addActionListener(this); - mTable.addActionListener(this); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); loadWindowState(); @@ -158,6 +162,7 @@ SkillDialog::SkillDialog(): SkillDialog::~SkillDialog() { + delete mTable; } void SkillDialog::action(const gcn::ActionEvent &event) @@ -165,22 +170,25 @@ void SkillDialog::action(const gcn::ActionEvent &event) if (event.getId() == "inc") { // Increment skill - int selectedSkill = mTable.getSelectedRow();//mSkillListBox->getSelected(); + int selectedSkill = mTable->getSelectedRow(); if (selectedSkill >= 0) - { player_node->raiseSkill(mSkillList[selectedSkill]->id); - } } - else if (event.getId() == "skill") + else if (event.getId() == "skill" && mTable->getSelectedRow() > -1) { - mIncButton->setEnabled( - mTable.getSelectedRow() > -1 && - player_node->mSkillPoint > 0); + SKILL *skill = mSkillList[mTable->getSelectedRow()]; + SkillInfo const *info; + + if (skill->id >= 0 && (unsigned int) skill->id < skill_db.size()) + info = &skill_db[skill->id]; + else + info = &fakeSkillInfo; + + mIncButton->setEnabled(player_node->mSkillPoint > 0 && + info->modifiable); } else if (event.getId() == "close") - { setVisible(false); - } } void SkillDialog::update() @@ -188,9 +196,10 @@ void SkillDialog::update() mPointsLabel->setCaption(strprintf(_("Skill points: %d"), player_node->mSkillPoint)); - int selectedSkill = mTable.getSelectedRow(); + int selectedSkill = mTable->getSelectedRow(); - if (selectedSkill >= 0) { + if (selectedSkill >= 0) + { int skillId = mSkillList[selectedSkill]->id; bool modifiable; @@ -201,10 +210,12 @@ void SkillDialog::update() mIncButton->setEnabled(modifiable && player_node->mSkillPoint > 0); - } else + } + else mIncButton->setEnabled(false); mTableModel->update(); + setMinHeight(50 + mTableModel->getHeight()); } int SkillDialog::getNumberOfElements() @@ -214,10 +225,10 @@ int SkillDialog::getNumberOfElements() bool SkillDialog::hasSkill(int id) { - for (unsigned int i = 0; i < mSkillList.size(); i++) { - if (mSkillList[i]->id == id) { + for (unsigned int i = 0; i < mSkillList.size(); i++) + { + if (mSkillList[i]->id == id) return true; - } } return false; } @@ -233,8 +244,10 @@ void SkillDialog::addSkill(int id, int lvl, int mp) void SkillDialog::setSkill(int id, int lvl, int mp) { - for (unsigned int i = 0; i < mSkillList.size(); i++) { - if (mSkillList[i]->id == id) { + for (unsigned int i = 0; i < mSkillList.size(); i++) + { + if (mSkillList[i]->id == id) + { mSkillList[i]->lv = lvl; mSkillList[i]->sp = mp; } @@ -271,7 +284,8 @@ static void initSkillinfo() std::string name = XML::getProperty(node, "name", ""); bool modifiable = !atoi(XML::getProperty(node, "fixed", "0").c_str()); - if (index >= 0) { + if (index >= 0) + { skill_db.resize(index + 1, emptySkillInfo); skill_db[index].name = name; skill_db[index].modifiable = modifiable; diff --git a/src/gui/skill.h b/src/gui/skill.h index 893a61e7..0600d106 100644 --- a/src/gui/skill.h +++ b/src/gui/skill.h @@ -24,19 +24,16 @@ #include <vector> -#include <guichan/listmodel.hpp> #include <guichan/actionlistener.hpp> #include "window.h" -#include "table.h" - -#include "../guichanfwd.h" struct SKILL { short id; /**< Index into "skill_db" array */ short lv, sp; }; +class GuiTable; class SkillGuiTableModel; /** @@ -71,7 +68,8 @@ class SkillDialog : public Window, public gcn::ActionListener const std::vector<SKILL*>& getSkills() const { return mSkillList; } private: - GuiTable mTable;//gcn::ListBox *mSkillListBox; + GuiTable *mTable; + ScrollArea *skillScrollArea; SkillGuiTableModel *mTableModel; gcn::Label *mPointsLabel; gcn::Button *mIncButton; diff --git a/src/gui/slider.cpp b/src/gui/slider.cpp index 37136012..9bfa840f 100644 --- a/src/gui/slider.cpp +++ b/src/gui/slider.cpp @@ -21,6 +21,7 @@ #include "slider.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -28,6 +29,7 @@ Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip; Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip; +float Slider::mAlpha = config.getValue("guialpha", 0.8); int Slider::mInstances = 0; Slider::Slider(double scaleEnd): @@ -107,6 +109,20 @@ void Slider::draw(gcn::Graphics *graphics) 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(); diff --git a/src/gui/slider.h b/src/gui/slider.h index 1fe668c5..56ea334a 100644 --- a/src/gui/slider.h +++ b/src/gui/slider.h @@ -26,7 +26,6 @@ class Image; - /** * Slider widget. Same as the Guichan slider but with custom look. * @@ -67,6 +66,7 @@ class Slider : public gcn::Slider { static Image *hStart, *hMid, *hEnd, *hGrip; static Image *vStart, *vMid, *vEnd, *vGrip; + static float mAlpha; static int mInstances; }; diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp new file mode 100644 index 00000000..dd404a63 --- /dev/null +++ b/src/gui/speechbubble.cpp @@ -0,0 +1,95 @@ +/* + * Speech bubbles + * Copyright (C) 2008 The Legend of Mazzeroth 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 <guichan/font.hpp> + +#include <guichan/widgets/label.hpp> + +#include "gui.h" +#include "scrollarea.h" +#include "speechbubble.h" +#include "textbox.h" + +#include "../utils/gettext.h" + +SpeechBubble::SpeechBubble(): + Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml") +{ + setContentSize(140, 46); + setShowTitle(false); + setTitleBarHeight(0); + + mCaption = new gcn::Label(""); + mCaption->setFont(boldFont); + mCaption->setPosition(5, 3); + + mSpeechBox = new TextBox(); + mSpeechBox->setEditable(false); + mSpeechBox->setOpaque(false); + + mSpeechArea = new ScrollArea(mSpeechBox); + + mSpeechArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mSpeechArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mSpeechArea->setDimension(gcn::Rectangle(4, boldFont->getHeight() + 3, + 130, 28)); + mSpeechArea->setOpaque(false); + + add(mCaption); + add(mSpeechArea); + + setLocationRelativeTo(getParent()); +} + +SpeechBubble::~SpeechBubble() +{ + delete mCaption; + delete mSpeechBox; + delete mSpeechArea; +} + +void SpeechBubble::setCaption(const std::string &name, const gcn::Color &color) +{ + mCaption->setCaption(name); + mCaption->adjustSize(); + mCaption->setForegroundColor(color); +} + +void SpeechBubble::setText(std::string mText) +{ + int width = mCaption->getWidth() + 3; + mSpeechBox->setTextWrapped(mText, 130 > width ? 130 : width); + + const int fontHeight = getFont()->getHeight(); + const int numRows = mSpeechBox->getNumberOfRows() + 1; + + if (width < mSpeechBox->getMinWidth()) + width = mSpeechBox->getMinWidth(); + + setContentSize(width + fontHeight, (numRows * fontHeight) + 6); + mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3, width + 5, + (numRows * fontHeight))); +} + +unsigned int SpeechBubble::getNumRows() +{ + return mSpeechBox->getNumberOfRows(); +} diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h new file mode 100644 index 00000000..d2d81332 --- /dev/null +++ b/src/gui/speechbubble.h @@ -0,0 +1,48 @@ +/* + * Speech bubbles + * Copyright (C) 2008 The Legend of Mazzeroth 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 SPEECHBUBBLE_H +#define SPEECHBUBBLE_H + +#include "window.h" + +class ScrollArea; +class TextBox; + +class SpeechBubble : public Window +{ + public: + SpeechBubble(); + ~SpeechBubble(); + + void setCaption(const std::string &name, + const gcn::Color &color = 0x000000); + void setText(std::string mText); + void setLocation(int x, int y); + unsigned int getNumRows(); + + private: + gcn::Label *mCaption; + TextBox *mSpeechBox; + ScrollArea *mSpeechArea; +}; + +#endif diff --git a/src/gui/status.cpp b/src/gui/status.cpp index b95a1eb8..683a9a41 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -19,14 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "status.h" - #include <guichan/widgets/label.hpp> #include "button.h" #include "progressbar.h" +#include "status.h" #include "windowcontainer.h" +#include "widgets/layout.h" + #include "../localplayer.h" #include "../utils/gettext.h" @@ -37,87 +38,30 @@ StatusWindow::StatusWindow(LocalPlayer *player): Window(player->getName()), mPlayer(player) { - setWindowName("Status"); - setResizable(true); + setWindowName(_("Status")); setCloseButton(true); setDefaultSize((windowContainer->getWidth() - 365) / 2, - (windowContainer->getHeight() - 255) / 2, 365, 275); - loadWindowState(); + (windowContainer->getHeight() - 255) / 2, 400, 345); // ---------------------- // Status Part // ---------------------- mLvlLabel = new gcn::Label(strprintf(_("Level: %d"), 0)); - mGpLabel = new gcn::Label(strprintf(_("Job: %d"), 0)); - mJobLvlLabel = new gcn::Label(strprintf(_("Money: %d GP"), 0)); + mJobLvlLabel = new gcn::Label(strprintf(_("Job: %d"), 0)); + mGpLabel = new gcn::Label(strprintf(_("Money: %d GP"), 0)); - mHpLabel = new gcn::Label("HP:"); + mHpLabel = new gcn::Label(_("HP:")); mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); - mHpValueLabel = new gcn::Label; - mXpLabel = new gcn::Label("Exp:"); + mXpLabel = new gcn::Label(_("Exp:")); mXpBar = new ProgressBar(1.0f, 80, 15, 143, 192, 211); - mXpValueLabel = new gcn::Label; - mMpLabel = new gcn::Label("MP:"); + mMpLabel = new gcn::Label(_("MP:")); mMpBar = new ProgressBar(1.0f, 80, 15, 26, 102, 230); - mMpValueLabel = new gcn::Label; - - mJobXpLabel = new gcn::Label("Job:"); - mJobXpBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203); - mJobValueLabel = new gcn::Label; - - int y = 3; - int x = 5; - - mLvlLabel->setPosition(x, y); - x += mLvlLabel->getWidth() + 40; - mJobLvlLabel->setPosition(x, y); - x += mJobLvlLabel->getWidth() + 40; - mGpLabel->setPosition(x, y); - - y += mLvlLabel->getHeight() + 5; // Next Row - x = 5; - - mHpLabel->setPosition(x, y); - x += mHpLabel->getWidth() + 5; - mHpBar->setPosition(x, y); - x += mHpBar->getWidth() + 5; - mHpValueLabel->setPosition(x, y); - - mXpLabel->setPosition(175, y); - mXpBar->setPosition(205, y); - mXpValueLabel->setPosition(290, y); - - y += mHpLabel->getHeight() + 5; // Next Row - x = 5; - - mMpLabel->setPosition(x, y); - x += mMpLabel->getWidth() + 5; - mMpBar->setPosition(x, y); - x += mMpBar->getWidth() + 5; - mMpValueLabel->setPosition(x, y); - - mJobXpLabel->setPosition(175, y); - mJobXpBar->setPosition(205, y); - mJobValueLabel->setPosition(290, y); - - add(mLvlLabel); - add(mJobLvlLabel); - add(mGpLabel); - add(mHpLabel); - add(mHpValueLabel); - add(mMpLabel); - add(mMpValueLabel); - add(mXpLabel); - add(mXpValueLabel); - add(mJobXpLabel); - add(mJobValueLabel); - add(mHpBar); - add(mMpBar); - add(mXpBar); - add(mJobXpBar); + + mJobLabel = new gcn::Label(_("Job:")); + mJobBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203); // ---------------------- // Stats Part @@ -127,14 +71,18 @@ StatusWindow::StatusWindow(LocalPlayer *player): gcn::Label *mStatsTitleLabel = new gcn::Label(_("Stats")); gcn::Label *mStatsTotalLabel = new gcn::Label(_("Total")); gcn::Label *mStatsCostLabel = new gcn::Label(_("Cost")); + mStatsTotalLabel->setAlignment(gcn::Graphics::CENTER); // Derived Stats mStatsAttackLabel = new gcn::Label(_("Attack:")); mStatsDefenseLabel= new gcn::Label(_("Defense:")); mStatsMagicAttackLabel = new gcn::Label(_("M.Attack:")); mStatsMagicDefenseLabel = new gcn::Label(_("M.Defense:")); + // Gettext flag for next line: xgettext:no-c-format mStatsAccuracyLabel = new gcn::Label(_("% Accuracy:")); + // Gettext flag for next line: xgettext:no-c-format mStatsEvadeLabel = new gcn::Label(_("% Evade:")); + // Gettext flag for next line: xgettext:no-c-format mStatsReflexLabel = new gcn::Label(_("% Reflex:")); mStatsAttackPoints = new gcn::Label; @@ -146,10 +94,13 @@ StatusWindow::StatusWindow(LocalPlayer *player): mStatsReflexPoints = new gcn::Label; // New labels - for (int i = 0; i < 6; i++) { - mStatsLabel[i] = new gcn::Label; + for (int i = 0; i < 6; i++) + { + mStatsLabel[i] = new gcn::Label("0"); + mStatsLabel[i]->setAlignment(gcn::Graphics::CENTER); mStatsDisplayLabel[i] = new gcn::Label; mPointsLabel[i] = new gcn::Label("0"); + mPointsLabel[i]->setAlignment(gcn::Graphics::CENTER); } mRemainingStatsPointsLabel = new gcn::Label; @@ -161,68 +112,53 @@ StatusWindow::StatusWindow(LocalPlayer *player): mStatsButton[4] = new Button("+", "DEX", this); mStatsButton[5] = new Button("+", "LUK", this); - - // Set position - mStatsTitleLabel->setPosition(mMpLabel->getX(), mMpLabel->getY() + 23 ); - mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15); - int totalLabelY = mStatsTotalLabel->getY(); - mStatsCostLabel->setPosition(170, totalLabelY); - + // Assemble + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mLvlLabel, 3); + place(5, 0, mJobLvlLabel, 3); + place(8, 0, mGpLabel, 3); + place(1, 1, mHpLabel).setPadding(3); + place(2, 1, mHpBar, 3); + place(6, 1, mXpLabel).setPadding(3); + place(7, 1, mXpBar, 3); + place(1, 2, mMpLabel).setPadding(3); + place(2, 2, mMpBar, 3); + place(6, 2, mJobLabel).setPadding(3); + place(7, 2, mJobBar, 3); + place.getCell().matchColWidth(0, 1); + place = getPlacer(0, 3); + place(0, 0, mStatsTitleLabel, 5); + place(5, 1, mStatsTotalLabel, 5); + place(12, 1, mStatsCostLabel, 5); for (int i = 0; i < 6; i++) { - mStatsLabel[i]->setPosition(5, mStatsTotalLabel->getY() + (i * 23) + 15); - mStatsDisplayLabel[i]->setPosition(115, - totalLabelY + (i * 23) + 15); - mStatsButton[i]->setPosition(145, totalLabelY + (i * 23) + 10); - mPointsLabel[i]->setPosition(175, totalLabelY + (i * 23) + 15); + place(0, 2 + i, mStatsLabel[i], 7).setPadding(5); + place(7, 2 + i, mStatsDisplayLabel[i]).setPadding(5); + place(10, 2 + i, mStatsButton[i]); + place(12, 2 + i, mPointsLabel[i]).setPadding(5); } + place(14, 2, mStatsAttackLabel, 7).setPadding(5); + place(14, 3, mStatsDefenseLabel, 7).setPadding(5); + place(14, 4, mStatsMagicAttackLabel, 7).setPadding(5); + place(14, 5, mStatsMagicDefenseLabel, 7).setPadding(5); + place(14, 6, mStatsAccuracyLabel, 7).setPadding(5); + place(14, 7, mStatsEvadeLabel, 7).setPadding(5); + place(14, 8, mStatsReflexLabel, 7).setPadding(5); + place(21, 2, mStatsAttackPoints, 3).setPadding(5); + place(21, 3, mStatsDefensePoints, 3).setPadding(5); + place(21, 4, mStatsMagicAttackPoints, 3).setPadding(5); + place(21, 5, mStatsMagicDefensePoints, 3).setPadding(5); + place(21, 6, mStatsAccuracyPoints, 3).setPadding(5); + place(21, 7, mStatsEvadePoints, 3).setPadding(5); + place(21, 8, mStatsReflexPoints, 3).setPadding(5); + place(0, 8, mRemainingStatsPointsLabel, 3).setPadding(5); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); - mRemainingStatsPointsLabel->setPosition(5, mPointsLabel[5]->getY() + 25); - - mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY()); - mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY()); - mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY()); - mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY()); - mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY()); - mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY()); - mStatsReflexLabel->setPosition(220, mRemainingStatsPointsLabel->getY()); - - mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY()); - mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY()); - mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY()); - mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY()); - mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY()); - mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY()); - mStatsReflexPoints->setPosition(310, mRemainingStatsPointsLabel->getY()); - - // Assemble - add(mStatsTitleLabel); - add(mStatsTotalLabel); - add(mStatsCostLabel); - for(int i = 0; i < 6; i++) - { - add(mStatsLabel[i]); - add(mStatsDisplayLabel[i]); - add(mStatsButton[i]); - add(mPointsLabel[i]); - } - add(mStatsAttackLabel); - add(mStatsDefenseLabel); - add(mStatsMagicAttackLabel); - add(mStatsMagicDefenseLabel); - add(mStatsAccuracyLabel); - add(mStatsEvadeLabel); - add(mStatsReflexLabel); - - add(mStatsAttackPoints); - add(mStatsDefensePoints); - add(mStatsMagicAttackPoints); - add(mStatsMagicDefensePoints); - add(mStatsAccuracyPoints); - add(mStatsEvadePoints); - add(mStatsReflexPoints); - - add(mRemainingStatsPointsLabel); + loadWindowState(); } void StatusWindow::update() @@ -238,21 +174,17 @@ void StatusWindow::update() mGpLabel->setCaption(strprintf(_("Money: %d GP"), mPlayer->mGp)); mGpLabel->adjustSize(); - mHpValueLabel->setCaption(toString(mPlayer->mHp) + - "/" + toString(mPlayer->mMaxHp)); - mHpValueLabel->adjustSize(); + mHpBar->setText(toString(mPlayer->mHp) + + "/" + toString(mPlayer->mMaxHp)); - mMpValueLabel->setCaption(toString(mPlayer->mMp) + - "/" + toString(mPlayer->mMaxMp)); - mMpValueLabel->adjustSize(); + mMpBar->setText(toString(mPlayer->mMp) + + "/" + toString(mPlayer->mMaxMp)); - mXpValueLabel->setCaption(toString(mPlayer->getXp()) + - "/" + toString(mPlayer->mXpForNextLevel)); - mXpValueLabel->adjustSize(); + mXpBar->setText(toString(mPlayer->getXp()) + + "/" + toString(mPlayer->mXpForNextLevel)); - mJobValueLabel->setCaption(toString(mPlayer->mJobXp) + - "/" + toString(mPlayer->mJobXpForNextLevel)); - mJobValueLabel->adjustSize(); + mJobBar->setText(toString(mPlayer->mJobXp) + + "/" + toString(mPlayer->mJobXpForNextLevel)); // HP Bar coloration if (mPlayer->mHp < int(mPlayer->mMaxHp / 3)) @@ -273,7 +205,7 @@ void StatusWindow::update() mXpBar->setProgress( (float) mPlayer->getXp() / (float) mPlayer->mXpForNextLevel); - mJobXpBar->setProgress( + mJobBar->setProgress( (float) mPlayer->mJobXp / (float) mPlayer->mJobXpForNextLevel); // Stats Part @@ -338,30 +270,6 @@ void StatusWindow::update() // Reflex % mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter mStatsReflexPoints->adjustSize(); - - // Update Second column widgets position - mJobLvlLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, - mLvlLabel->getY()); - mGpLabel->setPosition(mJobLvlLabel->getX() + mJobLvlLabel->getWidth() + 20, - mJobLvlLabel->getY()); - - mXpLabel->setPosition( - mHpValueLabel->getX() + mHpValueLabel->getWidth() + 10, - mHpLabel->getY()); - mXpBar->setPosition( - mXpLabel->getX() + mXpLabel->getWidth() + 5, - mXpLabel->getY()); - mXpValueLabel->setPosition( - mXpBar->getX() + mXpBar->getWidth() + 5, - mXpLabel->getY()); - - mJobXpLabel->setPosition(mXpBar->getX() - mJobXpLabel->getWidth() - 5, - mMpLabel->getY()); - mJobXpBar->setPosition( - mJobXpLabel->getX() + mJobXpLabel->getWidth() + 5, - mJobXpLabel->getY()); - mJobValueLabel->setPosition(mJobXpBar->getX() + mJobXpBar->getWidth() + 5, - mJobXpLabel->getY()); } void StatusWindow::draw(gcn::Graphics *g) @@ -402,3 +310,4 @@ void StatusWindow::action(const gcn::ActionEvent &event) } } } + diff --git a/src/gui/status.h b/src/gui/status.h index 6d360caf..00a48f4e 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -22,18 +22,13 @@ #ifndef STATUS_H #define STATUS_H -#include <iosfwd> - #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - class LocalPlayer; class ProgressBar; - /** * The player status dialog. * @@ -70,11 +65,9 @@ class StatusWindow : public Window, public gcn::ActionListener */ gcn::Label *mLvlLabel, *mJobLvlLabel; gcn::Label *mGpLabel; - gcn::Label *mHpLabel, *mHpValueLabel; - gcn::Label *mMpLabel, *mMpValueLabel; - gcn::Label *mXpLabel, *mXpValueLabel, *mJobXpLabel, *mJobValueLabel; + gcn::Label *mHpLabel, *mMpLabel, *mXpLabel, *mJobLabel; ProgressBar *mHpBar, *mMpBar; - ProgressBar *mXpBar, *mJobXpBar; + ProgressBar *mXpBar, *mJobBar; /** * Derived Statistics captions diff --git a/src/gui/table.cpp b/src/gui/table.cpp index f6678737..8dd546d9 100644 --- a/src/gui/table.cpp +++ b/src/gui/table.cpp @@ -19,13 +19,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/actionlistener.hpp> +#include <guichan/graphics.hpp> +#include <guichan/key.hpp> + +#include "color.h" #include "table.h" -#include <guichan/graphics.hpp> -#include <guichan/actionlistener.hpp> +#include "../configuration.h" -#include <cassert> +#include "../utils/dtor.h" +float GuiTable::mAlpha = config.getValue("guialpha", 0.8); class GuiTableActionListener : public gcn::ActionListener { @@ -50,7 +55,8 @@ GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *wid mColumn(column), mWidget(widget) { - if (widget) { + if (widget) + { widget->addActionListener(this); widget->_setParent(table); } @@ -58,7 +64,8 @@ GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *wid GuiTableActionListener::~GuiTableActionListener() { - if (mWidget) { + if (mWidget) + { mWidget->removeActionListener(this); mWidget->_setParent(NULL); } @@ -71,14 +78,20 @@ void GuiTableActionListener::action(const gcn::ActionEvent& actionEvent) } -GuiTable::GuiTable(TableModel *initial_model) : +GuiTable::GuiTable(TableModel *initial_model, gcn::Color background, + bool opacity) : mLinewiseMode(false), + mWrappingEnabled(false), + mOpaque(opacity), + mBackgroundColor(background), mModel(NULL), mSelectedRow(0), mSelectedColumn(0), mTopWidget(NULL) { setModel(initial_model); + setFocusable(true); + addMouseListener(this); addKeyListener(this); } @@ -95,7 +108,8 @@ TableModel *GuiTable::getModel() const void GuiTable::setModel(TableModel *new_model) { - if (mModel) { + if (mModel) + { uninstallActionListeners(); mModel->removeListener(this); } @@ -103,13 +117,13 @@ void GuiTable::setModel(TableModel *new_model) mModel = new_model; installActionListeners(); - if (new_model) { + if (new_model) + { new_model->installListener(this); recomputeDimensions(); } } - void GuiTable::recomputeDimensions() { int rows_nr = mModel->getRows(); @@ -169,10 +183,62 @@ int GuiTable::getColumnWidth(int i) return 0; } -void GuiTable::uninstallActionListeners() +void GuiTable::setSelectedRow(int selected) { - for (std::vector<GuiTableActionListener *>::const_iterator it = action_listeners.begin(); it != action_listeners.end(); it++) - delete *it; + if (!mModel) + { + mSelectedRow = -1; + } + else + { + if (selected < 0 && !mWrappingEnabled) + { + mSelectedRow = -1; + } + else if (selected >= mModel->getRows() && mWrappingEnabled) + { + mSelectedRow = 0; + } + else if ((selected >= mModel->getRows() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedRow = mModel->getRows() - 1; + } + else + { + mSelectedRow = selected; + } + } +} + +void GuiTable::setSelectedColumn(int selected) +{ + if (!mModel) + { + mSelectedColumn = -1; + } + else + { + if ((selected >= mModel->getColumns() && mWrappingEnabled) || + (selected < 0 && !mWrappingEnabled)) + { + mSelectedColumn = 0; + } + else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedColumn = mModel->getColumns() - 1; + } + else + { + mSelectedColumn = selected; + } + } +} + +void GuiTable::uninstallActionListeners(void) +{ + delete_all(action_listeners); action_listeners.clear(); } @@ -185,10 +251,11 @@ void GuiTable::installActionListeners() int columns = mModel->getColumns(); for (int row = 0; row < rows; ++row) - for (int column = 0; column < columns; ++column) { + for (int column = 0; column < columns; ++column) + { gcn::Widget *widget = mModel->getElementAt(row, column); action_listeners.push_back(new GuiTableActionListener(this, widget, - row, column)); + row, column)); } _setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets @@ -197,12 +264,22 @@ void GuiTable::installActionListeners() // -- widget ops void GuiTable::draw(gcn::Graphics* graphics) { - graphics->setColor(getBackgroundColor()); - graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); - if (!mModel) return; + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + if (mOpaque) + { + const int red = getBackgroundColor().r; + const int green = getBackgroundColor().g; + const int blue = getBackgroundColor().b; + const int alpha = mAlpha * 255; + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); + } + // First, determine how many rows we need to draw, and where we should start. int first_row = -(getY() / getRowHeight()); @@ -224,44 +301,68 @@ void GuiTable::draw(gcn::Graphics* graphics) int height = getRowHeight(); int y_offset = first_row * height; - for (int r = first_row; r < first_row + rows_nr; ++r) { + for (int r = first_row; r < first_row + rows_nr; ++r) + { int x_offset = 0; - for (int c = first_column; c <= last_column; ++c) { + for (int c = first_column; c <= last_column; ++c) + { gcn::Widget *widget = mModel->getElementAt(r, c); int width = getColumnWidth(c); - if (widget) { + if (widget) + { gcn::Rectangle bounds(x_offset, y_offset, width, height); - if (widget == mTopWidget) { + if (widget == mTopWidget) + { bounds.height = widget->getHeight(); bounds.width = widget->getWidth(); } widget->setDimension(bounds); + if (!mLinewiseMode && c == mSelectedColumn && r == mSelectedRow) + { + bool valid; + const int red = + (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = + (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = mAlpha * 127; + + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(bounds); + } + graphics->pushClipArea(bounds); widget->draw(graphics); graphics->popClipArea(); - - if (!mLinewiseMode - && c == mSelectedColumn - && r == mSelectedRow) - graphics->drawRectangle(bounds); } x_offset += width; } - if (mLinewiseMode - && r == mSelectedRow) - graphics->drawRectangle(gcn::Rectangle(0, y_offset, + if (mLinewiseMode && r == mSelectedRow) + { + bool valid; + const int red = + (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = + (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = mAlpha * 127; + + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, y_offset, x_offset, height)); + } y_offset += height; } - if (mTopWidget) { + if (mTopWidget) + { gcn::Rectangle bounds = mTopWidget->getDimension(); graphics->pushClipArea(bounds); mTopWidget->draw(graphics); @@ -269,21 +370,17 @@ void GuiTable::draw(gcn::Graphics* graphics) } } -void GuiTable::logic() -{ -} - void GuiTable::moveToTop(gcn::Widget *widget) { gcn::Widget::moveToTop(widget); - this->mTopWidget = widget; + mTopWidget = widget; } void GuiTable::moveToBottom(gcn::Widget *widget) { gcn::Widget::moveToBottom(widget); - if (widget == this->mTopWidget) - this->mTopWidget = NULL; + if (widget == mTopWidget) + mTopWidget = NULL; } gcn::Rectangle GuiTable::getChildrenArea() @@ -294,17 +391,62 @@ gcn::Rectangle GuiTable::getChildrenArea() // -- KeyListener notifications void GuiTable::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) + { + setSelectedRow(mSelectedRow - 1); + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::DOWN) + { + setSelectedRow(mSelectedRow + 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::LEFT) + { + setSelectedColumn(mSelectedColumn - 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::RIGHT) + { + setSelectedColumn(mSelectedColumn + 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::HOME) + { + setSelectedRow(0); + setSelectedColumn(0); + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::END) + { + setSelectedRow(mModel->getRows() - 1); + setSelectedColumn(mModel->getColumns() - 1); + keyEvent.consume(); + } +} // -- MouseListener notifications void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) { - if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) { + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { int row = getRowForY(mouseEvent.getY()); int column = getColumnForX(mouseEvent.getX()); - if (row > -1 && column > -1) { + if (row > -1 && column > -1 && + row < mModel->getRows() && column < mModel->getColumns()) + { mSelectedColumn = column; mSelectedRow = row; } @@ -315,10 +457,25 @@ void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) { + if (isFocused()) + { + if (getSelectedRow() >= 0 ) + { + setSelectedRow(getSelectedRow() - 1); + } + + mouseEvent.consume(); + } } void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) { + if (isFocused()) + { + setSelectedRow(getSelectedRow() + 1); + + mouseEvent.consume(); + } } void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) @@ -328,10 +485,13 @@ void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) // -- TableModelListener notifications void GuiTable::modelUpdated(bool completed) { - if (completed) { + if (completed) + { recomputeDimensions(); installActionListeners(); - } else { // before the update? + } + else + { // before the update? mTopWidget = NULL; // No longer valid in general uninstallActionListeners(); } @@ -342,18 +502,18 @@ gcn::Widget *GuiTable::getWidgetAt(int x, int y) int row = getRowForY(y); int column = getColumnForX(x); - if (mTopWidget - && mTopWidget->getDimension().isPointInRect(x, y)) + if (mTopWidget && mTopWidget->getDimension().isPointInRect(x, y)) return mTopWidget; - if (row > -1 - && column > -1) { + if (row > -1 && column > -1) + { gcn::Widget *w = mModel->getElementAt(row, column); if (w && w->isFocusable()) return w; else return NULL; // Grab the event locally - } else + } + else return NULL; } @@ -361,8 +521,7 @@ int GuiTable::getRowForY(int y) { int row = y / getRowHeight(); - if (row < 0 - || row >= mModel->getRows()) + if (row < 0 || row >= mModel->getRows()) return -1; else return row; @@ -373,20 +532,19 @@ int GuiTable::getColumnForX(int x) int column; int delta = 0; - for (column = 0; column < mModel->getColumns(); column++) { + for (column = 0; column < mModel->getColumns(); column++) + { delta += getColumnWidth(column); if (x <= delta) break; } - if (column < 0 - || column >= mModel->getColumns()) + if (column < 0 || column >= mModel->getColumns()) return -1; else return column; } - void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler) { gcn::Widget::_setFocusHandler(focusHandler); diff --git a/src/gui/table.h b/src/gui/table.h index c7ede36c..841f6ef2 100644 --- a/src/gui/table.h +++ b/src/gui/table.h @@ -24,14 +24,11 @@ #include <vector> -#include <guichan/gui.hpp> #include <guichan/keylistener.hpp> #include <guichan/mouselistener.hpp> -#include <guichan/platform.hpp> #include <guichan/widget.hpp> #include "table_model.h" -#include "../guichanfwd.h" class GuiTableActionListener; @@ -53,7 +50,8 @@ class GuiTable : public gcn::Widget, friend class GuiTableActionListener; public: - GuiTable(TableModel * initial_model = NULL); + GuiTable(TableModel * initial_model = NULL, gcn::Color background = 0xffffff, + bool opacity = true); virtual ~GuiTable(); @@ -67,25 +65,36 @@ public: * * Note that actions issued by widgets returned from the model will update * the table selection, but only AFTER any event handlers installed within - * the widget have been triggered. To be notified after such an update, - * add an action listener to the table instead. + * the widget have been triggered. To be notified after such an update, add + * an action listener to the table instead. */ void setModel(TableModel *m); + const TableModel* getModel() {return mModel;} + void setSelected(int row, int column); int getSelectedRow(); int getSelectedColumn(); - gcn::Rectangle getChildrenArea(); + void setSelectedRow(int selected); + + void setSelectedColumn(int selected); + + bool isWrappingEnabled() const {return mWrappingEnabled;} + + void setWrappingEnabled(bool wrappingEnabled) + {mWrappingEnabled = wrappingEnabled;} + + gcn::Rectangle getChildrenArea(void); /** - * Toggle whether to use linewise selection mode, in which the table - * selects an entire line at a time, rather than a single cell. + * Toggle whether to use linewise selection mode, in which the table selects + * an entire line at a time, rather than a single cell. * - * Note that column information is tracked even in linewise selection - * mode; this mode therefore only affects visualisation. + * Note that column information is tracked even in linewise selection mode; + * this mode therefore only affects visualisation. * * Disabled by default. * @@ -96,8 +105,6 @@ public: // Inherited from Widget virtual void draw(gcn::Graphics* graphics); - virtual void logic(); - virtual gcn::Widget *getWidgetAt(int x, int y); virtual void moveToTop(gcn::Widget *child); @@ -109,6 +116,21 @@ public: // Inherited from KeyListener virtual void keyPressed(gcn::KeyEvent& keyEvent); + /** + * Sets the table to be opaque, that is sets the table + * to display its background. + * + * @param opaque True if the table should be opaque, false otherwise. + */ + virtual void setOpaque(bool opaque) {mOpaque = opaque;} + + /** + * Checks if the table is opaque, that is if the table area displays its + * background. + * + * @return True if the table is opaque, false otherwise. + */ + virtual bool isOpaque() const {return mOpaque;} // Inherited from MouseListener virtual void mousePressed(gcn::MouseEvent& mouseEvent); @@ -136,6 +158,15 @@ private: int getColumnForX(int x); // -1 on error void recomputeDimensions(); bool mLinewiseMode; + bool mWrappingEnabled; + bool mOpaque; + + static float mAlpha; + + /** + * Holds the background color of the table. + */ + gcn::Color mBackgroundColor; TableModel *mModel; diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp index 7bc29b47..4fa13bae 100644 --- a/src/gui/table_model.cpp +++ b/src/gui/table_model.cpp @@ -19,10 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "table_model.h" - #include <guichan/widget.hpp> -#include <cstdlib> + +#include "table_model.h" #include "../utils/dtor.h" @@ -49,7 +48,6 @@ void TableModel::signalAfterUpdate() } - #define WIDGET_AT(row, column) (((row) * mColumns) + (column)) #define DYN_SIZE(h) ((h) >= 0) // determines whether this size is tagged for auto-detection @@ -143,3 +141,21 @@ int StaticTableModel::getColumns() { return mColumns; } + +int StaticTableModel::getWidth(void) +{ + int width = 0; + + for (unsigned int i = 0; i < mWidths.size(); i++) + { + width += mWidths[i]; + } + + return width; +} + +int StaticTableModel::getHeight(void) +{ + return (mColumns * mHeight); +} + diff --git a/src/gui/table_model.h b/src/gui/table_model.h index d245d7bd..9ca36120 100644 --- a/src/gui/table_model.h +++ b/src/gui/table_model.h @@ -22,10 +22,6 @@ #ifndef TABLE_MODEL_H #define TABLE_MODEL_H -#include "../guichanfwd.h" - -#include <guichan/gui.hpp> - #include <set> #include <vector> @@ -133,6 +129,8 @@ public: virtual int getRows(); virtual int getColumns(); virtual int getRowHeight(); + virtual int getWidth(); + virtual int getHeight(); virtual int getColumnWidth(int index); virtual gcn::Widget *getElementAt(int row, int column); diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp index 75f0b5a1..2a86d549 100644 --- a/src/gui/textbox.cpp +++ b/src/gui/textbox.cpp @@ -19,21 +19,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "textbox.h" - #include <sstream> -#include <guichan/basiccontainer.hpp> #include <guichan/font.hpp> +#include "textbox.h" + TextBox::TextBox(): gcn::TextBox() { setOpaque(false); setFrameSize(0); + mMinWidth = getWidth(); } -void TextBox::setTextWrapped(const std::string &text) +void TextBox::setTextWrapped(const std::string &text, int minDimension) { // Make sure parent scroll area sets width of this widget if (getParent()) @@ -41,8 +41,13 @@ void TextBox::setTextWrapped(const std::string &text) 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 newlinePos, lastNewlinePos = 0; + int minWidth = 0; + int xpos; do { @@ -57,7 +62,18 @@ void TextBox::setTextWrapped(const std::string &text) std::string line = text.substr(lastNewlinePos, newlinePos - lastNewlinePos); std::string::size_type spacePos, lastSpacePos = 0; - int xpos = 0; + xpos = 0; + + 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 { @@ -73,7 +89,7 @@ void TextBox::setTextWrapped(const std::string &text) int width = getFont()->getWidth(word); - if (xpos != 0 && xpos + width < getWidth()) + if (xpos != 0 && xpos + width + getFont()->getWidth(" ") <= mMinWidth) { xpos += width + getFont()->getWidth(" "); wrappedStream << " " << word; @@ -85,22 +101,46 @@ void TextBox::setTextWrapped(const std::string &text) } 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; - wrappedStream << "\n" << word; } - 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/textbox.h b/src/gui/textbox.h index a42562ea..10a81fc0 100644 --- a/src/gui/textbox.h +++ b/src/gui/textbox.h @@ -31,7 +31,8 @@ * * \ingroup GUI */ -class TextBox : public gcn::TextBox { +class TextBox : public gcn::TextBox +{ public: /** * Constructor. @@ -41,7 +42,15 @@ class TextBox : public gcn::TextBox { /** * Sets the text after wrapping it to the current width of the widget. */ - void setTextWrapped(const std::string &text); + void setTextWrapped(const std::string &text, int minDimension); + + /** + * Get the minimum text width for the text box. + */ + int getMinWidth() { return mMinWidth; } + + private: + int mMinWidth; }; #endif diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp index f7b02cbf..99a95a2e 100644 --- a/src/gui/textfield.cpp +++ b/src/gui/textfield.cpp @@ -19,14 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "textfield.h" - -#include <algorithm> - #include <guichan/font.hpp> #include "sdlinput.h" +#include "textfield.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -37,10 +35,13 @@ #undef DELETE //Win32 compatibility hack int TextField::instances = 0; +float TextField::mAlpha = config.getValue("guialpha", 0.8); ImageRect TextField::skin; TextField::TextField(const std::string& text): - gcn::TextField(text) + gcn::TextField(text), + mNumeric(false), + mListener(0) { setFrameSize(2); @@ -51,9 +52,6 @@ TextField::TextField(const std::string& text): Image *textbox = resman->getImage("graphics/gui/deepbox.png"); int gridx[4] = {0, 3, 28, 31}; int gridy[4] = {0, 3, 28, 31}; - //Image *textbox = resman->getImage("graphics/gui/textbox.png"); - //int gridx[4] = {0, 5, 26, 31}; - //int gridy[4] = {0, 5, 26, 31}; int a = 0, x, y; for (y = 0; y < 3; y++) { @@ -62,6 +60,7 @@ TextField::TextField(const std::string& text): 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++; } } @@ -93,6 +92,15 @@ void TextField::draw(gcn::Graphics *graphics) graphics->setColor(getForegroundColor()); 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) @@ -105,6 +113,42 @@ void TextField::drawFrame(gcn::Graphics *graphics) 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(); diff --git a/src/gui/textfield.h b/src/gui/textfield.h index 3570f89d..73824615 100644 --- a/src/gui/textfield.h +++ b/src/gui/textfield.h @@ -25,6 +25,13 @@ #include <guichan/widgets/textfield.hpp> class ImageRect; +class TextField; + +class TextFieldListener +{ + public: + virtual void listen(const TextField *value) = 0; +}; /** * A text field. @@ -54,13 +61,48 @@ class TextField : public gcn::TextField { 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/trade.cpp b/src/gui/trade.cpp index 66df55b8..af30d1fe 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -19,8 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "trade.h" - #include <sstream> #include <guichan/widgets/label.hpp> @@ -32,26 +30,28 @@ #include "itemcontainer.h" #include "scrollarea.h" #include "textfield.h" +#include "trade.h" + +#include "widgets/layout.h" #include "../inventory.h" #include "../item.h" +#include "../localplayer.h" #include "../net/messageout.h" #include "../net/protocol.h" -#include "../resources/iteminfo.h" - #include "../utils/gettext.h" #include "../utils/strprintf.h" #include "../utils/tostring.h" TradeWindow::TradeWindow(Network *network): - Window("Trade: You"), + Window(_("Trade: You")), mNetwork(network), - mMyInventory(new Inventory), - mPartnerInventory(new Inventory) + mMyInventory(new Inventory(INVENTORY_SIZE)), + mPartnerInventory(new Inventory(INVENTORY_SIZE)) { - setWindowName("Trade"); + setWindowName(_("Trade")); setDefaultSize(115, 227, 342, 209); setResizable(true); @@ -63,47 +63,43 @@ TradeWindow::TradeWindow(Network *network): mCancelButton = new Button(_("Cancel"), "cancel", this); mTradeButton = new Button(_("Trade"), "trade", this); - mMyItemContainer = new ItemContainer(mMyInventory.get()); + mTradeButton->setEnabled(false); + + mMyItemContainer = new ItemContainer(mMyInventory.get(), 2); + mMyItemContainer->setWidth(160); mMyItemContainer->addSelectionListener(this); - mMyItemContainer->setPosition(2, 2); mMyScroll = new ScrollArea(mMyItemContainer); - mMyScroll->setPosition(8, 8); - mPartnerItemContainer = new ItemContainer(mPartnerInventory.get()); + mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 2); + mPartnerItemContainer->setWidth(160); mPartnerItemContainer->addSelectionListener(this); - mPartnerItemContainer->setPosition(2, 58); mPartnerScroll = new ScrollArea(mPartnerItemContainer); - mPartnerScroll->setPosition(8, 64); mMoneyLabel = new gcn::Label(strprintf(_("You get %d GP."), 0)); mMoneyLabel2 = new gcn::Label(_("You give:")); mMoneyField = new TextField; mMoneyField->setWidth(50); - mAddButton->adjustSize(); - mOkButton->adjustSize(); - mCancelButton->adjustSize(); - mTradeButton->adjustSize(); - - mTradeButton->setEnabled(false); - - mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), "")); - mItemDescriptionLabel = new gcn::Label( - strprintf(_("Description: %s"), "")); - - add(mMyScroll); - add(mPartnerScroll); - add(mAddButton); - add(mOkButton); - add(mCancelButton); - add(mTradeButton); - add(mItemNameLabel); - add(mItemDescriptionLabel); - add(mMoneyLabel2); - add(mMoneyField); - add(mMoneyLabel); + place(1, 0, mMoneyLabel); + place(0, 1, mMyScroll).setPadding(3); + place(1, 1, mPartnerScroll).setPadding(3); + ContainerPlacer place; + place = getPlacer(0, 0); + place(0, 0, mMoneyLabel2); + place(1, 0, mMoneyField); + place = getPlacer(0, 2); + place(0, 0, mAddButton); + place(1, 0, mOkButton); + place(2, 0, mTradeButton); + place(3, 0, mCancelButton); + Layout &layout = getLayout(); + layout.extend(0, 2, 2, 1); + layout.setRowHeight(1, Layout::AUTO_SET); + layout.setRowHeight(2, 0); + layout.setColWidth(0, Layout::AUTO_SET); + layout.setColWidth(1, Layout::AUTO_SET); loadWindowState(); } @@ -114,48 +110,13 @@ TradeWindow::~TradeWindow() void TradeWindow::widgetResized(const gcn::Event &event) { - Window::widgetResized(event); + mMyItemContainer->setWidth(mMyScroll->getWidth()); + mPartnerItemContainer->setWidth(mPartnerScroll->getWidth()); - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - mMoneyLabel2->setPosition(8, height - 8 - mMoneyLabel2->getHeight()); - mMoneyField->setPosition( - 8 + mMoneyLabel2->getWidth(), - height - 8 - mMoneyField->getHeight()); - mMoneyLabel->setPosition( - mMoneyField->getX() + mMoneyField->getWidth() + 6, - mMoneyLabel2->getY()); - - mCancelButton->setPosition(width - 8 - mCancelButton->getWidth(), - height - 8 - mCancelButton->getHeight()); - mTradeButton->setPosition( - mCancelButton->getX() - 4 - mTradeButton->getWidth(), - mCancelButton->getY()); - mOkButton->setPosition(mTradeButton->getX() - 4 - mOkButton->getWidth(), - mCancelButton->getY()); - mAddButton->setPosition(mOkButton->getX() - 4 - mAddButton->getWidth(), - mCancelButton->getY()); - - mItemDescriptionLabel->setPosition(8, - mOkButton->getY() - mItemDescriptionLabel->getHeight() - 4); - mItemNameLabel->setPosition(8, - mItemDescriptionLabel->getY() - mItemNameLabel->getHeight() - 4); - - const int remaining = mItemNameLabel->getY() - 4 - 8 - 8; - const int itemContainerHeight = remaining / 2; - - mMyItemContainer->setSize(width - 24 - 12 - 1, - (INVENTORY_SIZE * 24) / (width / 24) - 1); - mMyScroll->setSize(width - 16, itemContainerHeight); - - mPartnerItemContainer->setSize(width - 24 - 12 - 1, - (INVENTORY_SIZE * 24) / (width / 24) - 1); - mPartnerScroll->setSize(width - 16, itemContainerHeight); - mPartnerScroll->setPosition(8, 8 + itemContainerHeight + 8); + Window::widgetResized(event); } + void TradeWindow::addMoney(int amount) { mMoneyLabel->setCaption(strprintf(_("You get %d GP."), amount)); @@ -164,38 +125,40 @@ void TradeWindow::addMoney(int amount) void TradeWindow::addItem(int id, bool own, int quantity, bool equipment) { - if (own) { + if (own) + { + mMyItemContainer->setWidth(mMyScroll->getWidth()); mMyInventory->addItem(id, quantity, equipment); - } else { + } + else + { + mPartnerItemContainer->setWidth(mPartnerScroll->getWidth()); mPartnerInventory->addItem(id, quantity, equipment); } } void TradeWindow::removeItem(int id, bool own) { - if (own) { + if (own) mMyInventory->removeItem(id); - } else { + else mPartnerInventory->removeItem(id); - } } void TradeWindow::changeQuantity(int index, bool own, int quantity) { - if (own) { + if (own) mMyInventory->getItem(index)->setQuantity(quantity); - } else { + else mPartnerInventory->getItem(index)->setQuantity(quantity); - } } void TradeWindow::increaseQuantity(int index, bool own, int quantity) { - if (own) { + if (own) mMyInventory->getItem(index)->increaseQuantity(quantity); - } else { + else mPartnerInventory->getItem(index)->increaseQuantity(quantity); - } } void TradeWindow::reset() @@ -218,21 +181,30 @@ void TradeWindow::setTradeButton(bool enabled) void TradeWindow::receivedOk(bool own) { - if (own) { + if (own) + { mOkMe = true; - if (mOkOther) { + if (mOkOther) + { mTradeButton->setEnabled(true); mOkButton->setEnabled(false); - } else { + } + else + { mTradeButton->setEnabled(false); mOkButton->setEnabled(false); } - } else { + } + else + { mOkOther = true; - if (mOkMe) { + if (mOkMe) + { mTradeButton->setEnabled(true); mOkButton->setEnabled(false); - } else { + } + else + { mTradeButton->setEnabled(false); mOkButton->setEnabled(true); } @@ -256,22 +228,9 @@ void TradeWindow::valueChanged(const gcn::SelectionEvent &event) */ if (event.getSource() == mMyItemContainer && (item = mMyItemContainer->getSelectedItem())) - { mPartnerItemContainer->selectNone(); - } else if ((item = mPartnerItemContainer->getSelectedItem())) - { mMyItemContainer->selectNone(); - } - - // Update name and description - ItemInfo const *info = item ? &item->getInfo() : NULL; - mItemNameLabel->setCaption(strprintf(_("Name: %s"), - info ? info->getName().c_str() : "")); - mItemNameLabel->adjustSize(); - mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"), - info ? info->getDescription().c_str() : "")); - mItemDescriptionLabel->adjustSize(); } void TradeWindow::action(const gcn::ActionEvent &event) @@ -286,16 +245,19 @@ void TradeWindow::action(const gcn::ActionEvent &event) if (mMyInventory->getFreeSlot() < 1) return; - if (mMyInventory->contains(item)) { + if (mMyInventory->contains(item)) + { chatWindow->chatLog(_("Failed adding item. You can not " "overlap one kind of item on the window."), BY_SERVER); return; } - if (item->getQuantity() == 1) { + if (item->getQuantity() == 1) + { tradeItem(item, 1); } - else { + else + { // Choose amount of items to trade new ItemAmountWindow(AMOUNT_TRADE_ADD, this, item); } @@ -317,7 +279,9 @@ void TradeWindow::action(const gcn::ActionEvent &event) outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); outMsg.writeInt16(0); outMsg.writeInt32(tempInt); - } else { + } + else + { mMoneyField->setText(""); } mMoneyField->setEnabled(false); diff --git a/src/gui/trade.h b/src/gui/trade.h index 3129c4b9..df724038 100644 --- a/src/gui/trade.h +++ b/src/gui/trade.h @@ -128,8 +128,6 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener ItemContainer *mMyItemContainer; ItemContainer *mPartnerItemContainer; - gcn::Label *mItemNameLabel; - gcn::Label *mItemDescriptionLabel; gcn::Label *mMoneyLabel; gcn::Label *mMoneyLabel2; gcn::Button *mAddButton, *mOkButton, *mCancelButton, *mTradeButton; diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index f65b3446..8e6636df 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -19,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "truetypefont.h" - #include <list> #include <guichan/exception.hpp> +#include "truetypefont.h" + #include "../graphics.h" #include "../resources/image.h" @@ -74,7 +74,6 @@ class TextChunk gcn::Color color; }; - // Word surfaces cache static std::list<TextChunk> cache; typedef std::list<TextChunk>::iterator CacheIterator; @@ -92,7 +91,7 @@ TrueTypeFont::TrueTypeFont(const std::string &filename, int size) ++fontCounter; mFont = TTF_OpenFont(filename.c_str(), size); - if (mFont == NULL) + if (!mFont) { throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont: " + std::string(TTF_GetError())); diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h index 6f0671a2..cd68a94e 100644 --- a/src/gui/truetypefont.h +++ b/src/gui/truetypefont.h @@ -25,7 +25,6 @@ #include <string> #include <guichan/font.hpp> -#include <guichan/graphics.hpp> #ifndef __APPLE__ #include <SDL/SDL_ttf.h> #else diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 96c2e95c..b3861b27 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -19,8 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "updatewindow.h" - #include <iostream> #include <SDL.h> #include <SDL_thread.h> @@ -28,23 +26,26 @@ #include <guichan/widgets/label.hpp> +// Curl should be included after Guichan to avoid Windows redefinitions +#include <curl/curl.h> + #include "browserbox.h" #include "button.h" #include "progressbar.h" #include "scrollarea.h" +#include "updatewindow.h" -// Curl should be included after Guichan to avoid Windows redefinitions -#include <curl/curl.h> +#include "widgets/layout.h" #include "../configuration.h" #include "../log.h" #include "../main.h" +#include "../resources/resourcemanager.h" + #include "../utils/gettext.h" #include "../utils/tostring.h" -#include "../resources/resourcemanager.h" - /** * Calculates the Alder-32 checksum for the given file. */ @@ -68,8 +69,7 @@ static unsigned long fadler32(FILE *file) /** * Load the given file into a vector of strings. */ -std::vector<std::string> -loadTextFile(const std::string &fileName) +std::vector<std::string> loadTextFile(const std::string &fileName) { std::vector<std::string> lines; std::ifstream fin(fileName.c_str()); @@ -107,34 +107,29 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, { mCurlError[0] = 0; - const int h = 240; - const int w = 320; - setContentSize(w, h); - mBrowserBox = new BrowserBox(); mScrollArea = new ScrollArea(mBrowserBox); mLabel = new gcn::Label(_("Connecting...")); - mProgressBar = new ProgressBar(0.0, w - 10, 20, 37, 70, 200); + mProgressBar = new ProgressBar(0.0, 310, 20, 168, 116, 31); mCancelButton = new Button(_("Cancel"), "cancel", this); mPlayButton = new Button(_("Play"), "play", this); mBrowserBox->setOpaque(false); mPlayButton->setEnabled(false); - mCancelButton->setPosition(5, h - 5 - mCancelButton->getHeight()); - mPlayButton->setPosition( - mCancelButton->getX() + mCancelButton->getWidth() + 5, - h - 5 - mPlayButton->getHeight()); - mProgressBar->setPosition(5, mCancelButton->getY() - 20 - 5); - mLabel->setPosition(5, mProgressBar->getY() - mLabel->getHeight() - 5); + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mScrollArea, 5, 3).setPadding(3); + place(0, 3, mLabel, 5); + place(0, 4, mProgressBar, 5); + place(3, 5, mCancelButton); + place(4, 5, mPlayButton); - mScrollArea->setDimension(gcn::Rectangle(5, 5, 310, mLabel->getY() - 12)); + reflowLayout(320, 240); - add(mScrollArea); - add(mLabel); - add(mProgressBar); - add(mCancelButton); - add(mPlayButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); setVisible(true); @@ -210,7 +205,7 @@ void UpdaterWindow::loadNews() // Tokenize and add each line separately char *line = strtok(mMemoryBuffer, "\n"); - while (line != NULL) + while (line) { mBrowserBox->addRow(line); line = strtok(NULL, "\n"); @@ -246,8 +241,7 @@ int UpdaterWindow::updateProgress(void *ptr, return 0; } -size_t -UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) +size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) { UpdaterWindow *uw = reinterpret_cast<UpdaterWindow *>(stream); size_t totalMem = size * nmemb; @@ -330,8 +324,8 @@ int UpdaterWindow::downloadThread(void *ptr) { case CURLE_COULDNT_CONNECT: default: - std::cerr << "curl error " << res << ": " - << uw->mCurlError << " host: " << url.c_str() + std::cerr << _("curl error ") << res << ": " + << uw->mCurlError << _(" host: ") << url.c_str() << std::endl; break; } @@ -366,7 +360,7 @@ int UpdaterWindow::downloadThread(void *ptr) // Remove the corrupted file ::remove(outFilename.c_str()); logger->log( - "Checksum for file %s failed: (%lx/%lx)", + _("Checksum for file %s failed: (%lx/%lx)"), uw->mCurrentFile.c_str(), adler, uw->mCurrentChecksum); attempts++; @@ -414,7 +408,7 @@ void UpdaterWindow::download() mDownloadComplete = false; mThread = SDL_CreateThread(UpdaterWindow::downloadThread, this); - if (mThread == NULL) + if (!mThread) { logger->log("Unable to create mThread"); mDownloadStatus = UPDATE_ERROR; @@ -454,9 +448,9 @@ void UpdaterWindow::logic() mThread = NULL; } mBrowserBox->addRow(""); - mBrowserBox->addRow("##1 The update process is incomplete."); - mBrowserBox->addRow("##1 It is strongly recommended that"); - mBrowserBox->addRow("##1 you try again later"); + mBrowserBox->addRow(_("##1 The update process is incomplete.")); + mBrowserBox->addRow(_("##1 It is strongly recommended that")); + mBrowserBox->addRow(_("##1 you try again later")); mBrowserBox->addRow(mCurlError); mScrollArea->setVerticalScrollAmount( mScrollArea->getVerticalMaxScroll()); diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 3acbfb7e..4ada3c3a 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -23,13 +23,12 @@ #define _UPDATERWINDOW_H #include <guichan/actionlistener.hpp> + #include <string> #include <vector> #include "window.h" -#include "../guichanfwd.h" - #include "../utils/mutex.h" class BrowserBox; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index ff0883f7..f5a6edb4 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -19,33 +19,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "viewport.h" - -#include "gui.h" -#include "popupmenu.h" #include "ministatus.h" +#include "popupmenu.h" +#include "viewport.h" -#include "../simpleanimation.h" #include "../beingmanager.h" #include "../configuration.h" #include "../flooritemmanager.h" #include "../graphics.h" +#include "../keyboardconfig.h" #include "../localplayer.h" #include "../map.h" #include "../monster.h" #include "../npc.h" #include "../textmanager.h" -#include "../resources/animation.h" #include "../resources/monsterinfo.h" #include "../resources/resourcemanager.h" -#include "../resources/image.h" -#include "../resources/imageset.h" #include "../utils/tostring.h" -#include <cassert> - extern volatile int tick_time; Viewport::Viewport(): @@ -70,76 +63,21 @@ Viewport::Viewport(): config.addListener("ScrollRadius", this); mPopupMenu = new PopupMenu(); - - // Load target cursors - loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35, - false, Being::TC_SMALL); - loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35, - true, Being::TC_SMALL); - loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44, - false, Being::TC_MEDIUM); - loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44, - true, Being::TC_MEDIUM); - loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60, - false, Being::TC_LARGE); - loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60, - true, Being::TC_LARGE); -} - -void -Viewport::loadTargetCursor(std::string filename, int width, int height, - bool outRange, Being::TargetCursorSize size) -{ - assert(size > -1); - assert(size < 3); - - ImageSet* currentImageSet; - SimpleAnimation* currentCursor; - - ResourceManager *resman = ResourceManager::getInstance(); - - currentImageSet = resman->getImageSet(filename, width, height); - Animation *anim = new Animation(); - for (unsigned int i = 0; i < currentImageSet->size(); ++i) - { - anim->addFrame(currentImageSet->get(i), 75, 0, 0); - } - currentCursor = new SimpleAnimation(anim); - - if (outRange) - { - mOutRangeImages[size] = currentImageSet; - mTargetCursorOutRange[size] = currentCursor; - } - else { - mInRangeImages[size] = currentImageSet; - mTargetCursorInRange[size] = currentCursor; - } } Viewport::~Viewport() { delete mPopupMenu; - - for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) - { - delete mTargetCursorInRange[i]; - delete mTargetCursorOutRange[i]; - mInRangeImages[i]->decRef(); - mOutRangeImages[i]->decRef(); - } } -void -Viewport::setMap(Map *map) +void Viewport::setMap(Map *map) { mMap = map; } extern MiniStatusWindow *miniStatusWindow; -void -Viewport::draw(gcn::Graphics *gcnGraphics) +void Viewport::draw(gcn::Graphics *gcnGraphics) { static int lastTick = tick_time; @@ -148,6 +86,10 @@ Viewport::draw(gcn::Graphics *gcnGraphics) Graphics *graphics = static_cast<Graphics*>(gcnGraphics); + // Ensure the client doesn't freak out if a feature localplayer uses + // is dependent on a map. + player_node->mMapInitialized = true; + // Avoid freaking out when tick_time overflows if (tick_time < lastTick) { @@ -225,37 +167,39 @@ Viewport::draw(gcn::Graphics *gcnGraphics) if (mMap) { mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY); - drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite - } - // Find a path from the player to the mouse, and draw it. This is for debug - // purposes. - if (mShowDebugPath && mMap) - { - // Get the current mouse position - int mouseX, mouseY; - SDL_GetMouseState(&mouseX, &mouseY); + // Find a path from the player to the mouse, and draw it. This is for debug + // purposes. + if (mShowDebugPath) + { + // Get the current mouse position + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); - int mouseTileX = mouseX / 32 + mTileViewX; - int mouseTileY = mouseY / 32 + mTileViewY; + int mouseTileX = mouseX / 32 + mTileViewX; + int mouseTileY = mouseY / 32 + mTileViewY; - Path debugPath = mMap->findPath( - player_node->mX, player_node->mY, - mouseTileX, mouseTileY); + Path debugPath = mMap->findPath(player_node->mX, player_node->mY, mouseTileX, mouseTileY); - graphics->setColor(gcn::Color(255, 0, 0)); - for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) - { - int squareX = i->x * 32 - (int) mPixelViewX + 12; - int squareY = i->y * 32 - (int) mPixelViewY + 12; + graphics->setColor(gcn::Color(255, 0, 0)); + for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++) + { + int squareX = i->x * 32 - (int) mPixelViewX + 12; + int squareY = i->y * 32 - (int) mPixelViewY + 12; - graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); - graphics->drawText( - toString(mMap->getMetaTile(i->x, i->y)->Gcost), - squareX + 4, squareY + 12, gcn::Graphics::CENTER); + graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8)); + graphics->drawText(toString(mMap->getMetaTile(i->x, i->y)->Gcost), squareX + 4, squareY + 12, gcn::Graphics::CENTER); + } } } + if (player_node->mUpdateName) + { + player_node->mUpdateName = false; + player_node->setName(player_node->getName()); + } + + // Draw text if (textManager) { @@ -266,6 +210,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics) Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) { + (*i)->drawSpeech(-(int) mPixelViewX, -(int) mPixelViewY); (*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY); } @@ -276,8 +221,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics) WindowContainer::draw(gcnGraphics); } -void -Viewport::logic() +void Viewport::logic() { WindowContainer::logic(); @@ -294,49 +238,9 @@ Viewport::logic() mouseY / 32 + mTileViewY); mWalkTime = player_node->mWalkTime; } - - for (int i = 0; i < 3; i++) - { - mTargetCursorInRange[i]->update(10); - mTargetCursorOutRange[i]->update(10); - } -} - -void -Viewport::drawTargetCursor(Graphics *graphics) -{ - // Draw target marker if needed - Being *target = player_node->getTarget(); - if (target) - { - // Calculate target circle position - - // Find whether target is in range - int rangeX = abs(target->mX - player_node->mX); - int rangeY = abs(target->mY - player_node->mY); - int attackRange = player_node->getAttackRange(); - - // Get the correct target cursors graphic - Being::TargetCursorSize cursorSize = target->getTargetCursorSize(); - Image* targetCursor; - if (rangeX > attackRange || rangeY > attackRange) - { - targetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage(); - } - else { - targetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage(); - } - - // Draw the target cursor at the correct position - int posX = target->getPixelX() + 16 - targetCursor->getWidth() / 2 - (int) mPixelViewX; - int posY = target->getPixelY() + 16 - targetCursor->getHeight() / 2 - (int) mPixelViewY; - - graphics->drawImage(targetCursor, posX, posY); - } } -void -Viewport::mousePressed(gcn::MouseEvent &event) +void Viewport::mousePressed(gcn::MouseEvent &event) { // Check if we are alive and kickin' if (!mMap || !player_node || player_node->mAction == Being::DEAD) @@ -348,8 +252,10 @@ Viewport::mousePressed(gcn::MouseEvent &event) mPlayerFollowMouse = false; - int tilex = event.getX() / 32 + mTileViewX; - int tiley = event.getY() / 32 + mTileViewY; + const int tilex = event.getX() / 32 + mTileViewX; + const int tiley = event.getY() / 32 + mTileViewY; + const int x = (int)((float) event.getX() + mPixelViewX); + const int y = (int)((float) event.getY() + mPixelViewY); // Right click might open a popup if (event.getButton() == gcn::MouseEvent::RIGHT) @@ -357,13 +263,14 @@ Viewport::mousePressed(gcn::MouseEvent &event) Being *being; FloorItem *floorItem; - if ((being = beingManager->findBeing(tilex, tiley)) && - being != player_node) + if ((being = beingManager->findBeingByPixel(x, y)) && + being != player_node) { - mPopupMenu->showPopup(event.getX(), event.getY(), being); - return; + mPopupMenu->showPopup(event.getX(), event.getY(), being); + return; } - else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley))) + else if ((floorItem = floorItemManager->findByCoordinates(tilex, + tiley))) { mPopupMenu->showPopup(event.getX(), event.getY(), floorItem); return; @@ -384,9 +291,7 @@ Viewport::mousePressed(gcn::MouseEvent &event) FloorItem *item; // Interact with some being -// if ((being = beingManager->findBeing(tilex, tiley)) - int x = (int)((float) event.getX() + mPixelViewX); - int y = (int)((float) event.getY() + mPixelViewY); +// if ((being = beingManager->findBeing(tilex, tiley))) if ((being = beingManager->findBeingByPixel(x, y))) { switch (being->getType()) @@ -400,59 +305,47 @@ Viewport::mousePressed(gcn::MouseEvent &event) if (being->mAction == Being::DEAD) break; - if (player_node->withinAttackRange(being)) + if (player_node->withinAttackRange(being) || keyboard.isKeyActive(keyboard.KEY_ATTACK)) { - player_node->attack(being, true); + player_node->setGotoTarget(being); + player_node->attack(being, !keyboard.isKeyActive(keyboard.KEY_TARGET)); } else { - Uint8 *keys = SDL_GetKeyState(NULL); - if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) - { - player_node->stopAttack(); - player_node->setGotoTarget(being); - } + player_node->setDestination(tilex, tiley); } break; default: break; - } + } } // Pick up some item else if ((item = floorItemManager->findByCoordinates(tilex, tiley))) { - player_node->pickUp(item); + player_node->pickUp(item); } // Just walk around else { - // XXX XXX XXX REALLY UGLY! - Uint8 *keys = SDL_GetKeyState(NULL); - if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) - { - player_node->setDestination(tilex, tiley); - player_node->stopAttack(); - } + player_node->stopAttack(); + player_node->setDestination(tilex, tiley); mPlayerFollowMouse = true; } } else if (event.getButton() == gcn::MouseEvent::MIDDLE) { // Find the being nearest to the clicked position - Being *target = beingManager->findNearestLivingBeing( - tilex, tiley, - 20, Being::MONSTER); + Being *target = beingManager->findBeingByPixel(x, y); if (target) { - player_node->setTarget(target); + player_node->setTarget(target); } } } -void -Viewport::mouseDragged(gcn::MouseEvent &event) +void Viewport::mouseDragged(gcn::MouseEvent &event) { if (!mMap || !player_node) return; @@ -465,20 +358,17 @@ Viewport::mouseDragged(gcn::MouseEvent &event) } } -void -Viewport::mouseReleased(gcn::MouseEvent &event) +void Viewport::mouseReleased(gcn::MouseEvent &event) { mPlayerFollowMouse = false; } -void -Viewport::showPopup(int x, int y, Item *item) +void Viewport::showPopup(int x, int y, Item *item) { mPopupMenu->showPopup(x, y, item); } -void -Viewport::optionChanged(const std::string &name) +void Viewport::optionChanged(const std::string &name) { mScrollLaziness = (int) config.getValue("ScrollLaziness", 32); mScrollRadius = (int) config.getValue("ScrollRadius", 32); diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 8965ad95..522ea734 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -27,15 +27,14 @@ #include "windowcontainer.h" #include "../configlistener.h" -#include "../being.h" +#include "../position.h" -class Map; class FloorItem; +class Graphics; class ImageSet; class Item; +class Map; class PopupMenu; -class Graphics; -class SimpleAnimation; /** * The viewport on the map. Displays the current map and handles mouse input @@ -62,97 +61,65 @@ class Viewport : public WindowContainer, public gcn::MouseListener, /** * Sets the map displayed by the viewport. */ - void - setMap(Map *map); + void setMap(Map *map); /** * Draws the viewport. */ - void - draw(gcn::Graphics *graphics); + void draw(gcn::Graphics *graphics); /** * Implements player to keep following mouse. */ - void - logic(); + void logic(); /** * Toggles whether the path debug graphics are shown */ - void - toggleDebugPath() { mShowDebugPath = !mShowDebugPath; } + void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; } /** * Handles mouse press on map. */ - void - mousePressed(gcn::MouseEvent &event); + void mousePressed(gcn::MouseEvent &event); /** * Handles mouse move on map */ - void - mouseDragged(gcn::MouseEvent &event); + void mouseDragged(gcn::MouseEvent &event); /** * Handles mouse button release on map. */ - void - mouseReleased(gcn::MouseEvent &event); + void mouseReleased(gcn::MouseEvent &event); /** * Shows a popup for an item. * TODO Find some way to get rid of Item here */ - void - showPopup(int x, int y, Item *item); + void showPopup(int x, int y, Item *item); /** * A relevant config option changed. */ - void - optionChanged(const std::string &name); + void optionChanged(const std::string &name); /** - * Returns camera x offset in tiles. + * Returns camera x offset in pixels. */ - int - getCameraX() { return mTileViewX; } + int getCameraX() const { return (int) mPixelViewX; } /** - * Returns camera y offset in tiles. + * Returns camera y offset in pixels. */ - int - getCameraY() { return mTileViewY; } + int getCameraY() const { return (int) mPixelViewY; } /** * Changes viewpoint by relative pixel coordinates. */ - void - scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; } + void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; } private: - /** - * Helper function for loading target cursors - */ - void - loadTargetCursor(std::string filename, int width, int height, - bool outRange, Being::TargetCursorSize size); - - /** - * Draws range based target cursor - */ - void - drawTargetCursor(Graphics *graphics); - - /** - * Draws target name - */ - void - drawTargetName(Graphics *graphics); - - Map *mMap; /**< The current map. */ int mScrollRadius; @@ -165,22 +132,12 @@ class Viewport : public WindowContainer, public gcn::MouseListener, int mTileViewY; /**< Current viewpoint in tiles. */ bool mShowDebugPath; /**< Show a path from player to pointer. */ - /** Images of in range target cursor. */ - ImageSet *mInRangeImages[Being::NUM_TC]; - - /** Images of out of range target cursor. */ - ImageSet *mOutRangeImages[Being::NUM_TC]; - - /** Animated in range target cursor. */ - SimpleAnimation *mTargetCursorInRange[Being::NUM_TC]; - - /** Animated out of range target cursor. */ - SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC]; - bool mPlayerFollowMouse; int mWalkTime; PopupMenu *mPopupMenu; /**< Popup menu. */ }; +extern Viewport *viewport; /**< The viewport */ + #endif diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp new file mode 100644 index 00000000..29c6c69c --- /dev/null +++ b/src/gui/widgets/dropdown.cpp @@ -0,0 +1,203 @@ +/* + * 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 + */ + +#include <algorithm> + +#include "dropdown.h" + +#include "../color.h" +#include "../listbox.h" +#include "../scrollarea.h" + +#include "../../configuration.h" +#include "../../graphics.h" + +#include "../../resources/image.h" +#include "../../resources/resourcemanager.h" + +#include "../../utils/dtor.h" + +int DropDown::instances = 0; +Image *DropDown::buttons[2][2]; +ImageRect DropDown::skin; +float DropDown::mAlpha = config.getValue("guialpha", 0.8); + +DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea, + gcn::ListBox *listBox, bool opacity): + gcn::DropDown::DropDown(listModel, scrollArea, listBox), + mOpaque(opacity) +{ + setFrameSize(2); + + // Initialize graphics + if (instances == 0) + { + // Load the background skin + ResourceManager *resman = ResourceManager::getInstance(); + + // Get the button skin + buttons[1][0] = + resman->getImage("graphics/gui/vscroll_up_default.png"); + buttons[0][0] = + resman->getImage("graphics/gui/vscroll_down_default.png"); + buttons[1][1] = + resman->getImage("graphics/gui/vscroll_up_pressed.png"); + buttons[0][1] = + resman->getImage("graphics/gui/vscroll_down_pressed.png"); + + buttons[0][0]->setAlpha(mAlpha); + buttons[0][1]->setAlpha(mAlpha); + buttons[1][0]->setAlpha(mAlpha); + buttons[1][1]->setAlpha(mAlpha); + + // get the border skin + Image *boxBorder = 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] = boxBorder->getSubImage( + gridx[x], gridy[y], + gridx[x + 1] - gridx[x] + 1, + gridy[y + 1] - gridy[y] + 1); + skin.grid[a]->setAlpha(mAlpha); + a++; + } + } + + boxBorder->decRef(); + } + + instances++; +} + +DropDown::~DropDown() +{ + instances--; + // Free images memory + if (instances == 0) + { + buttons[0][0]->decRef(); + buttons[0][1]->decRef(); + buttons[1][0]->decRef(); + buttons[1][1]->decRef(); + + for_each(skin.grid, skin.grid + 9, dtor<Image*>()); + } +} + +void DropDown::draw(gcn::Graphics* graphics) +{ + int h; + + if (mDroppedDown) + { + h = mFoldedUpHeight; + } + else + { + h = getHeight(); + } + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + + buttons[0][0]->setAlpha(mAlpha); + buttons[0][1]->setAlpha(mAlpha); + buttons[1][0]->setAlpha(mAlpha); + buttons[1][1]->setAlpha(mAlpha); + + for (int a = 0; a < 9; a++) + { + skin.grid[a]->setAlpha(mAlpha); + } + } + + bool valid; + const int alpha = mAlpha * 255; + gcn::Color faceColor = getBaseColor(); + faceColor.a = alpha; + gcn::Color highlightColor = textColor->getColor('H', valid); + highlightColor.a = alpha; + gcn::Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + if (mOpaque) + { + int red = getBackgroundColor().r; + int green = getBackgroundColor().g; + int blue = getBackgroundColor().b; + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h)); + + red = getForegroundColor().r; + green = getForegroundColor().g; + blue = getForegroundColor().b; + graphics->setColor(gcn::Color(red, green, blue, alpha)); + } + + graphics->setFont(getFont()); + + if (mListBox->getListModel() && mListBox->getSelected() >= 0) + { + graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0); + } + + if (isFocused()) + { + graphics->setColor(highlightColor); + graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h)); + } + + drawButton(graphics); + + if (mDroppedDown) + { + drawChildren(graphics); + + // Draw two lines separating the ListBox with selected + // element view. + graphics->setColor(highlightColor); + graphics->drawLine(0, h, getWidth(), h); + graphics->setColor(shadowColor); + graphics->drawLine(0, h + 1, getWidth(), h + 1); + } +} + +void DropDown::drawFrame(gcn::Graphics *graphics) +{ + 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, skin); +} + +void DropDown::drawButton(gcn::Graphics *graphics) +{ + int height = mDroppedDown ? mFoldedUpHeight : getHeight(); + + static_cast<Graphics*>(graphics)-> + drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1); +} diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h new file mode 100644 index 00000000..e5919dc7 --- /dev/null +++ b/src/gui/widgets/dropdown.h @@ -0,0 +1,99 @@ +/* + * 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 + */ + +#ifndef DROPDOWN_H +#define DROPDOWN_H + +#include <guichan/widgets/dropdown.hpp> + +class Image; +class ImageRect; + + /** + * A drop down box from which you can select different values. It is one of + * the most complicated Widgets you will find in Guichan. For drawing the + * DroppedDown box it uses one ScrollArea and one ListBox. It also uses an + * internal FocusHandler to handle the focus of the internal ScollArea and + * ListBox. DropDown uses a ListModel to handle the list. To be able to use + * DropDown you must give DropDown an implemented ListModel which represents + * your list. + */ +class DropDown : public gcn::DropDown +{ + public: + /** + * Contructor. + * + * @param listModel the ListModel to use. + * @param scrollArea the ScrollArea to use. + * @param listBox the listBox to use. + * @see ListModel, ScrollArea, ListBox. + */ + DropDown(gcn::ListModel *listModel = NULL, + gcn::ScrollArea *scrollArea = NULL, + gcn::ListBox *listBox = NULL, + bool opacity = true); + + /** + * Destructor. + */ + ~DropDown(); + + void draw(gcn::Graphics* graphics); + + void drawFrame(gcn::Graphics* graphics); + + /** + * Sets the widget to be opaque, that is sets the widget to display its + * background. + * + * @param opaque True if the widget should be opaque, false otherwise. + */ + void setOpaque(bool opaque) {mOpaque = opaque;} + + /** + * Checks if the widget is opaque, that is if the widget area displays + * its background. + * + * @return True if the widget is opaque, false otherwise. + */ + bool isOpaque() const {return mOpaque;} + + + protected: + /** + * Draws the button with the little down arrow. + * + * @param graphics a Graphics object to draw with. + */ + void drawButton(gcn::Graphics *graphics); + + // Add own Images. + static int instances; + static Image *buttons[2][2]; + static ImageRect skin; + static float mAlpha; + + bool mOpaque; +}; + +#endif // end DROPDOWN_H + diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index 00689575..fa264e37 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -19,10 +19,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "resizegrip.h" - #include <guichan/graphics.hpp> +#include "resizegrip.h" + +#include "../../configuration.h" #include "../../graphics.h" #include "../../resources/image.h" @@ -30,14 +31,16 @@ Image *ResizeGrip::gripImage = 0; int ResizeGrip::mInstances = 0; +float ResizeGrip::mAlpha = config.getValue("guialpha", 0.8); -ResizeGrip::ResizeGrip() +ResizeGrip::ResizeGrip(std::string image) { if (mInstances == 0) { // Load the grip image ResourceManager *resman = ResourceManager::getInstance(); - gripImage = resman->getImage("graphics/gui/resize.png"); + gripImage = resman->getImage(image); + gripImage->setAlpha(mAlpha); } mInstances++; @@ -56,8 +59,13 @@ ResizeGrip::~ResizeGrip() } } -void -ResizeGrip::draw(gcn::Graphics *graphics) +void ResizeGrip::draw(gcn::Graphics *graphics) { + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + gripImage->setAlpha(mAlpha); + } + static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0); } diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h index 5c6ea4bd..620c133f 100644 --- a/src/gui/widgets/resizegrip.h +++ b/src/gui/widgets/resizegrip.h @@ -39,7 +39,7 @@ class ResizeGrip : public gcn::Widget /** * Constructor. */ - ResizeGrip(); + ResizeGrip(std::string image = "graphics/gui/resize.png"); /** * Destructor. @@ -54,6 +54,7 @@ class ResizeGrip : public gcn::Widget private: static Image *gripImage; /**< Resize grip image */ static int mInstances; /**< Number of resize grip instances */ + static float mAlpha; }; #endif diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index c54b2390..21402c89 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -19,12 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> +#include <guichan/widgets/label.hpp> #include "tab.h" - #include "tabbedarea.h" +#include "../../configuration.h" #include "../../graphics.h" #include "../../resources/image.h" @@ -33,6 +33,7 @@ #include "../../utils/dtor.h" int Tab::mInstances = 0; +float Tab::mAlpha = config.getValue("guialpha", 0.8); enum{ TAB_STANDARD, // 0 @@ -50,10 +51,10 @@ struct TabData }; static TabData const data[TAB_COUNT] = { - {"graphics/gui/tab.png", 0, 0}, - {"graphics/gui/tab.png", 9, 4}, - {"graphics/gui/tabselected.png", 16, 19}, - {"graphics/gui/tab.png", 25, 23} + { "graphics/gui/tab.png", 0, 0 }, + { "graphics/gui/tab.png", 9, 4 }, + { "graphics/gui/tabselected.png", 16, 19 }, + { "graphics/gui/tab.png", 25, 23 } }; ImageRect Tab::tabImg[TAB_COUNT]; @@ -79,6 +80,7 @@ Tab::~Tab() void Tab::init() { setFrameSize(0); + mHighlighted = false; if (mInstances == 0) { @@ -98,6 +100,7 @@ void Tab::init() data[x].gridX, data[y].gridY, data[x + 1].gridX - data[x].gridX + 1, data[y + 1].gridY - data[y].gridY + 1); + tabImg[mode].grid[a]->setAlpha(mAlpha); a++; } } @@ -109,16 +112,33 @@ void Tab::init() void Tab::draw(gcn::Graphics *graphics) { - int mode; + int mode = TAB_STANDARD; // check which type of tab to draw - if (mTabbedArea && mTabbedArea->isTabSelected(this)) + if (mTabbedArea) { - mode = TAB_SELECTED; + if (mTabbedArea->isTabSelected(this)) + { + mode = TAB_SELECTED; + // if tab is selected, it doesnt need to highlight activity + mLabel->setForegroundColor(gcn::Color(0, 0, 0)); + mHighlighted = false; + } + else if (mHighlighted) + { + mode = TAB_HIGHLIGHTED; + mLabel->setForegroundColor(gcn::Color(255, 0, 0)); + } } - else + + if (config.getValue("guialpha", 0.8) != mAlpha) { - mode = TAB_STANDARD; + mAlpha = config.getValue("guialpha", 0.8); + for (int a = 0; a < 9; a++) + { + tabImg[TAB_SELECTED].grid[a]->setAlpha(mAlpha); + tabImg[TAB_STANDARD].grid[a]->setAlpha(mAlpha); + } } // draw tab @@ -128,3 +148,8 @@ void Tab::draw(gcn::Graphics *graphics) // draw label drawChildren(graphics); } + +void Tab::setHighlighted(bool high) +{ + mHighlighted = high; +} diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h index 8382df83..3af4e2bf 100644 --- a/src/gui/widgets/tab.h +++ b/src/gui/widgets/tab.h @@ -47,12 +47,20 @@ class Tab : public gcn::Tab */ void draw(gcn::Graphics *graphics); + /** + * Set tab highlighted + */ + void setHighlighted(bool high); + private: /** Load images if no other instances exist yet */ void init(); static ImageRect tabImg[4]; /**< Tab state graphics */ static int mInstances; /**< Number of tab instances */ + static float mAlpha; + + bool mHighlighted; }; #endif diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index c4e22bff..5ff7c4bc 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -90,7 +90,7 @@ void TabbedArea::addTab(Tab *tab, gcn::Widget *widget) mTabContainer->add(tab); mTabs.push_back(std::pair<Tab*, gcn::Widget*>(tab, widget)); - if (mSelectedTab == NULL) + if (!mSelectedTab) { setSelectedTab(tab); } diff --git a/src/gui/window.cpp b/src/gui/window.cpp index ed5bb8fc..797b4be9 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -24,11 +24,9 @@ #include <climits> #include <guichan/exception.hpp> -#include <guichan/widgets/icon.hpp> - -#include "window.h" #include "gui.h" +#include "window.h" #include "windowcontainer.h" #include "widgets/layout.h" @@ -36,30 +34,30 @@ #include "../configlistener.h" #include "../configuration.h" -#include "../graphics.h" #include "../log.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" +#include "../utils/xml.h" + ConfigListener *Window::windowConfigListener = 0; WindowContainer *Window::windowContainer = 0; int Window::instances = 0; int Window::mouseResize = 0; -ImageRect Window::border; +//ImageRect Window::border; Image *Window::closeImage = NULL; +bool Window::mAlphaChanged = false; class WindowConfigListener : public ConfigListener { void optionChanged(const std::string &) { - for_each(Window::border.grid, Window::border.grid + 9, - std::bind2nd(std::mem_fun(&Image::setAlpha), - config.getValue("guialpha", 0.8))); + Window::mAlphaChanged = true; } }; -Window::Window(const std::string& caption, bool modal, Window *parent): +Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin): gcn::Window(caption), mGrip(0), mParent(parent), @@ -72,31 +70,23 @@ Window::Window(const std::string& caption, bool modal, Window *parent): mMinWinWidth(100), mMinWinHeight(40), mMaxWinWidth(INT_MAX), - mMaxWinHeight(INT_MAX) + mMaxWinHeight(INT_MAX), + mSkin(skin) { logger->log("Window::Window(\"%s\")", caption.c_str()); - if (!windowContainer) { + if (!windowContainer) + { throw GCN_EXCEPTION("Window::Window(): no windowContainer set"); } + // Loads the skin + loadSkin(mSkin); + + setGuiAlpha(); + if (instances == 0) { - // Load static resources - ResourceManager *resman = ResourceManager::getInstance(); - Image *dBorders = resman->getImage("graphics/gui/vscroll_grey.png"); - border.grid[0] = dBorders->getSubImage(0, 0, 4, 4); - border.grid[1] = dBorders->getSubImage(4, 0, 3, 4); - border.grid[2] = dBorders->getSubImage(7, 0, 4, 4); - border.grid[3] = dBorders->getSubImage(0, 4, 4, 10); - border.grid[4] = resman->getImage("graphics/gui/bg_quad_dis.png"); - border.grid[5] = dBorders->getSubImage(7, 4, 4, 10); - border.grid[6] = dBorders->getSubImage(0, 15, 4, 4); - border.grid[7] = dBorders->getSubImage(4, 15, 3, 4); - border.grid[8] = dBorders->getSubImage(7, 15, 4, 4); - dBorders->decRef(); - closeImage = resman->getImage("graphics/gui/close_button.png"); - windowConfigListener = new WindowConfigListener(); // Send GUI alpha changed for initialization windowConfigListener->optionChanged("guialpha"); @@ -130,12 +120,14 @@ Window::~Window() const std::string &name = mWindowName; // Saving X, Y and Width and Height for resizables in the config - if (!name.empty()) { + if (!name.empty()) + { config.setValue(name + "WinX", getX()); config.setValue(name + "WinY", getY()); config.setValue(name + "Visible", isVisible()); - if (mGrip) { + if (mGrip) + { config.setValue(name + "WinWidth", getWidth()); config.setValue(name + "WinHeight", getHeight()); } @@ -152,22 +144,19 @@ Window::~Window() instances--; + // Clean up static resources + for (int i = 0; i < 9; i++) + { + delete border.grid[i]; + border.grid[i] = NULL; + } + if (instances == 0) { config.removeListener("guialpha", windowConfigListener); delete windowConfigListener; windowConfigListener = NULL; - // Clean up static resources - delete border.grid[0]; - delete border.grid[1]; - delete border.grid[2]; - delete border.grid[3]; - border.grid[4]->decRef(); - delete border.grid[5]; - delete border.grid[6]; - delete border.grid[7]; - delete border.grid[8]; closeImage->decRef(); } } @@ -199,6 +188,15 @@ void Window::draw(gcn::Graphics *graphics) getPadding() ); } + + // Update window alpha values + if (mAlphaChanged) + { + for_each(border.grid, border.grid + 9, + std::bind2nd(std::mem_fun(&Image::setAlpha), + config.getValue("guialpha", 0.8))); + closeImage->setAlpha(config.getValue("guialpha", 0.8)); + } drawChildren(graphics); } @@ -524,6 +522,187 @@ int Window::getResizeHandles(gcn::MouseEvent &event) return resizeHandles; } +void Window::setGuiAlpha() +{ + //logger->log("Window::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8)); + for (int i = 0; i < 9; i++) + { + //logger->log("Window::setGuiAlpha: Border Image (%i)", i); + border.grid[i]->setAlpha(config.getValue("guialpha", 0.8)); + } + + mAlphaChanged = false; +} + +void Window::loadSkin(const std::string &filename) +{ + const std::string windowId = Window::getId(); + + ResourceManager *resman = ResourceManager::getInstance(); + + logger->log("Loading Window Skin '%s'.", filename.c_str()); + logger->log("Loading Window ID '%s'.", windowId.c_str()); + + + if (filename.empty()) + logger->error("Window::loadSkin(): Invalid File Name."); + + // TODO: + // If there is an error loading the specified file, we should try to revert + // to a 'default' skin file. Only if the 'default' skin file can't be loaded + // should we have a terminating error. + XML::Document doc(filename); + xmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset")) + { + logger->error("Widget Skinning error"); + } + + std::string skinSetImage; + skinSetImage = XML::getProperty(rootNode, "image", ""); + Image *dBorders = NULL; + if (!skinSetImage.empty()) + { + logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str()); + dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png"); + } + else + { + logger->error("Window::loadSkin(): Skinset does not define an image!"); + } + + //iterate <widget>'s + for_each_xml_child_node(widgetNode, rootNode) + { + if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget")) + continue; + + std::string widgetType; + widgetType = XML::getProperty(widgetNode, "type", "unknown"); + if (widgetType == "Window") + { + // Iterate through <part>'s + // LEEOR / TODO: + // We need to make provisions to load in a CloseButton image. For now it + // can just be hard-coded. + for_each_xml_child_node(partNode, widgetNode) + { + if (!xmlStrEqual(partNode->name, BAD_CAST "part")) + { + continue; + } + + std::string partType; + partType = XML::getProperty(partNode, "type", "unknown"); + // TOP ROW + if (partType == "top-left-corner") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "top-edge") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "top-right-corner") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height); + } + + // MIDDLE ROW + else if (partType == "left-edge") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "bg-quad") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "right-edge") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height); + } + + // BOTTOM ROW + else if (partType == "bottom-left-corner") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "bottom-edge") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height); + } + else if (partType == "bottom-right-corner") + { + const int xPos = XML::getProperty(partNode, "xpos", 0); + const int yPos = XML::getProperty(partNode, "ypos", 0); + const int width = XML::getProperty(partNode, "width", 1); + const int height = XML::getProperty(partNode, "height", 1); + + border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height); + } + + // Part is of an uknown type. + else + { + logger->log("Window::loadSkin(): Unknown Part Type '%s'", partType.c_str()); + } + } + } + // Widget is of an uknown type. + else + { + logger->log("Window::loadSkin(): Unknown Widget Type '%s'", widgetType.c_str()); + } + } + dBorders->decRef(); + + logger->log("Finished loading Window Skin."); + + // Hard-coded for now until we update the above code to look for window buttons. + closeImage = resman->getImage("graphics/gui/close_button.png"); +} + Layout &Window::getLayout() { if (!mLayout) mLayout = new Layout; diff --git a/src/gui/window.h b/src/gui/window.h index 19d59c26..518de6e9 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -22,9 +22,11 @@ #ifndef WINDOW_H #define WINDOW_H -#include <guichan/widgets/window.hpp> #include <guichan/widgetlistener.hpp> +#include <guichan/widgets/window.hpp> + +#include "../graphics.h" #include "../guichanfwd.h" class ConfigListener; @@ -56,9 +58,10 @@ class Window : public gcn::Window, gcn::WidgetListener * @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); + Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml"); /** * Destructor. Deletes all the added widgets. @@ -126,6 +129,26 @@ class Window : public gcn::Window, gcn::WidgetListener void setMaxHeight(unsigned int height); /** + * Gets the minimum width of the window. + */ + int getMinWidth() { return mMinWinWidth; } + + /** + * Gets the minimum height of the window. + */ + int getMinHeight() { return mMinWinHeight; } + + /** + * Gets the maximum width of the window. + */ + int getMaxWidth() { return mMaxWinWidth; } + + /** + * Gets the minimum height of the window. + */ + int getMaxHeight() { return mMaxWinHeight; } + + /** * Sets flag to show a title or not. */ void setShowTitle(bool flag) @@ -238,6 +261,11 @@ class Window : public gcn::Window, gcn::WidgetListener void reflowLayout(int w = 0, int h = 0); /** + * Loads a window skin + */ + void loadSkin(const std::string &filename); + + /** * 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); @@ -269,6 +297,8 @@ class Window : public gcn::Window, gcn::WidgetListener */ int getResizeHandles(gcn::MouseEvent &event); + void setGuiAlpha(); + ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ Layout *mLayout; /**< Layout handler */ @@ -277,6 +307,7 @@ class Window : public gcn::Window, gcn::WidgetListener bool mModal; /**< Window is modal */ bool mCloseButton; /**< Window has a close button */ bool mSticky; /**< Window resists minimization */ + static bool mAlphaChanged; /**< Whether the alpha percent was changed */ int mMinWinWidth; /**< Minimum window width */ int mMinWinHeight; /**< Minimum window height */ int mMaxWinWidth; /**< Maximum window width */ @@ -285,6 +316,7 @@ class Window : public gcn::Window, gcn::WidgetListener int mDefaultY; /**< Default window Y position */ int mDefaultWidth; /**< Default window width */ int mDefaultHeight; /**< Default window height */ + std::string mSkin; /**< Name of the skin to use */ /** * The config listener that listens to changes relevant to all windows. @@ -293,7 +325,7 @@ class Window : public gcn::Window, gcn::WidgetListener static int mouseResize; /**< Active resize handles */ static int instances; /**< Number of Window instances */ - static ImageRect border; /**< The window border and background */ + ImageRect border; /**< The window border and background */ static Image *closeImage; /**< Close Button Image */ /** diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h index a25f2037..62704d1b 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -30,7 +30,8 @@ * * \ingroup GUI */ -class WindowContainer : public gcn::Container { +class WindowContainer : public gcn::Container +{ public: /** * Do GUI logic. This functions adds automatic deletion of objects that |