diff options
Diffstat (limited to 'src/gui')
130 files changed, 5116 insertions, 1589 deletions
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp index 2d805b9c..6fd0482a 100644 --- a/src/gui/browserbox.cpp +++ b/src/gui/browserbox.cpp @@ -22,7 +22,7 @@ #include <algorithm> #include "browserbox.h" - +#include "colour.h" #include "linkhandler.h" #include "truetypefont.h" @@ -98,12 +98,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 != "") { - newRow += "##P"; + newRow += "##>"; } idx1 = tmp.find("@@"); } @@ -210,8 +210,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 +220,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 +228,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) { @@ -254,7 +251,8 @@ BrowserBox::draw(gcn::Graphics *graphics) if ((mHighMode & UNDERLINE)) { - graphics->setColor(gcn::Color(LINK)); + bool valid; + graphics->setColor(gcn::Color(textColour->getColour('<', valid))); graphics->drawLine( mLinks[mSelectedLink].x1, mLinks[mSelectedLink].y2, @@ -311,57 +309,30 @@ 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 = textColour->getColour(c, valid); + if (c == '<') + { prevColor = selColor; - selColor = BLACK; + } + if (valid) + { + selColor = rgb; + } } start += 3; + + if (start == row.size()) + { + break; + } } graphics->setColor(gcn::Color(selColor)); } @@ -424,3 +395,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..4bdf224b 100644 --- a/src/gui/browserbox.h +++ b/src/gui/browserbox.h @@ -165,3 +165,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..9b624015 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -122,8 +122,7 @@ Button::~Button() } } -void -Button::draw(gcn::Graphics *graphics) +void Button::draw(gcn::Graphics *graphics) { int mode; diff --git a/src/gui/button.h b/src/gui/button.h index 0ec99245..d8ed9fa7 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -26,6 +26,8 @@ #include <guichan/widgets/button.hpp> +#include "../guichanfwd.h" + class ImageRect; /** diff --git a/src/gui/buttonbox.cpp b/src/gui/buttonbox.cpp new file mode 100644 index 00000000..d29f3c58 --- /dev/null +++ b/src/gui/buttonbox.cpp @@ -0,0 +1,43 @@ +/* + * 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 "button.h" +#include "buttonbox.h" + +ButtonBox::ButtonBox(const std::string &title, const std::string &buttonTxt, + ButtonBoxListener *listener) : + Window(title), + mListener(listener) +{ + Button *button = new Button(buttonTxt, "activate", this); + setContentSize(button->getWidth() + 10, + button->getHeight() + 10); + button->setPosition(5, 5); + add(button); +} + +void ButtonBox::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "activate") + { + mListener->buttonBoxRespond(); + } +} diff --git a/src/gui/buttonbox.h b/src/gui/buttonbox.h new file mode 100644 index 00000000..6d0e46b6 --- /dev/null +++ b/src/gui/buttonbox.h @@ -0,0 +1,69 @@ +/* + * 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 BUTTONBOX_H +#define BUTTONBOX_H + +#include <string> + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +#include "../guichanfwd.h" + +class ButtonBoxListener +{ + public: + + /* + * function that ButtonBox calls when the button has been pressed + */ + virtual void buttonBoxRespond() = 0; +}; + +class ButtonBox : public Window, public gcn::ActionListener +{ + public: + + /* + * Constructor + * + * @param title is the text that appears at the top of the box + * @param buttonTxt is the text that appears on the button + * @param listener points to the class that should respond to the + * button press + */ + ButtonBox(const std::string &title, const std::string &buttonTxt, + ButtonBoxListener *listener); + + /* + * called when the button is pressed + * + * @param event is the event that is generated + */ + void action(const gcn::ActionEvent &event); + + private: + + ButtonBoxListener *mListener; +}; +#endif 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..423918ce 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -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/buysell.h b/src/gui/buysell.h index e3cdc52a..60a6398d 100644 --- a/src/gui/buysell.h +++ b/src/gui/buysell.h @@ -26,6 +26,8 @@ #include "window.h" +#include "../guichanfwd.h" + /** * A dialog to choose between buying or selling at a shop. * diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index df57f969..e556dfa0 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -19,13 +19,13 @@ * 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" @@ -69,7 +69,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 +82,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 +130,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 +141,21 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) { state = EXIT_STATE; } - else if (event.getId() == "new" && n_character <= MAX_SLOT) - { - // Start new character dialog - CharCreateDialog *charCreateDialog = - new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mGender); - charServerHandler.setCharCreateDialog(charCreateDialog); - } - else if (event.getId() == "delete") + else if (event.getId() == "newdel") { - // 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 +179,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 +228,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 +249,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 +266,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 +303,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..5d4ecfa8 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -22,17 +22,17 @@ #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 <guichan/actionlistener.hpp> - -class Player; class LocalPlayer; class Network; +class Player; class PlayerBox; /** @@ -65,8 +65,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; diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp index 7be2441d..2e823b60 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" @@ -99,8 +98,7 @@ ServerSelectDialog::~ServerSelectDialog() delete mServerListModel; } -void -ServerSelectDialog::action(const gcn::ActionEvent &event) +void ServerSelectDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") { mOkButton->setEnabled(false); @@ -108,7 +106,6 @@ ServerSelectDialog::action(const gcn::ActionEvent &event) mLoginData->hostname = iptostring(si->address); mLoginData->port = si->port; mLoginData->updateHost = si->updateHost; - state = mNextState; } else if (event.getId() == "cancel") { @@ -116,14 +113,12 @@ ServerSelectDialog::action(const gcn::ActionEvent &event) } } -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/chat.cpp b/src/gui/chat.cpp index 87d843a0..c9c3e9bc 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -20,56 +20,66 @@ */ #include <algorithm> -#include <sstream> +#include <fstream> #include <guichan/focushandler.hpp> -#include "chat.h" - #include "browserbox.h" +#include "chat.h" #include "chatinput.h" +#include "itemlinkhandler.h" #include "scrollarea.h" #include "sdlinput.h" #include "windowcontainer.h" #include "widgets/layout.h" +#include "../beingmanager.h" #include "../configuration.h" +#include "../extensions.h" #include "../game.h" #include "../localplayer.h" +#include "../party.h" +#include "../recorder.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->setPosition(mScrollArea->getFrameSize(), + mScrollArea->getFrameSize()); + 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 +94,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 == "" ? '$' : 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"); } -void ChatWindow::chatLog(std::string line, int own) +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, 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 +143,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 == "" && 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 +249,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 +266,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 +304,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 +320,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 +334,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 +344,67 @@ 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 */ + // 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); + + while (temp[0] == ' ') + { + temp = temp.substr(1, temp.size()); + } + while (temp[temp.size()] == ' ') + { + temp = temp.substr(0, temp.size() - 1); + } + + for (unsigned int i = 0; i < temp.size(); i++) + { + temp[i] = (char) tolower(temp[i]); + } + + const ItemInfo itemInfo = ItemDB::get(temp); + 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 +412,39 @@ 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); + msg.erase(0, 6); trim(msg); std::size_t space = msg.find(" "); std::string msg1; + if (space == std::string::npos) { msg1 = ""; @@ -317,33 +454,160 @@ 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) == '/') { 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->respond(msg); + else if (command == "toggle") + { + if (msg == "") + { + 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 == "") + { + 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 != "") + { + 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 + */ + if (extensions.aethyra_spells) + { + 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 + chatLog(_("The current server doesn't support spells"), 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 != "") + { + 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 +617,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 +643,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 +679,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 +718,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 +741,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(int itemId, const std::string &item) +{ + std::ostringstream text; + text << "[@@" << itemId << "|" << item << "@@] "; + mChatInput->setText(mChatInput->getText() + text.str()); + requestChatFocus(); +} + void ChatWindow::setVisible(bool isVisible) { Window::setVisible(isVisible); @@ -484,70 +765,132 @@ 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 == "") + { + 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 == "") { chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER); chatLog(_("/clear: Clears this window"), BY_SERVER); chatLog(_("/help: Display this help"), BY_SERVER); + mParty->help(); + chatLog(_("/msg <nick> <message>: Alternate form for /whisper"), BY_SERVER); + chatLog(_("/present: Get list of players present"), BY_SERVER); + mRecorder->help(); + 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") + { + mRecorder->help(msg2); + } + 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..176fccb7 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -22,6 +22,7 @@ #ifndef CHAT_H #define CHAT_H +#include <fstream> #include <list> #include <string> @@ -34,32 +35,21 @@ 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 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 ACT_WHISPER 5 // getting whispered at +#define ACT_IS 6 // equivalent to "/me" on IRC + +#define BY_LOGGER 7 /** * gets in between usernick and message text depending on @@ -127,14 +117,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 +181,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(int itemid, const std::string &item); + /** Override to reset mTmpVisible */ void setVisible(bool visible); @@ -199,6 +197,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 +213,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 +233,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..d98e120b 100644 --- a/src/gui/chatinput.h +++ b/src/gui/chatinput.h @@ -22,9 +22,11 @@ #ifndef CHATINPUT_H #define CHATINPUT_H +#include <guichan/focuslistener.hpp> + #include "textfield.h" -#include <guichan/focuslistener.hpp> +#include "../guichanfwd.h" /** * The chat input hides when it loses focus. It is also invisible by default. diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h index 4b312d22..d92fc822 100644 --- a/src/gui/checkbox.h +++ b/src/gui/checkbox.h @@ -26,6 +26,8 @@ #include <guichan/widgets/checkbox.hpp> +#include "../guichanfwd.h" + class Image; /** diff --git a/src/gui/colour.cpp b/src/gui/colour.cpp new file mode 100644 index 00000000..816420ed --- /dev/null +++ b/src/gui/colour.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2008 by Douglas Boffey * + * * + * DougABoffey@netscape.net * + * 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 * + * (at your option) any later version. * + * * + * This program is distributed with The Mana Experiment * + * 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 <cstdio> + +#include "colour.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" + +Colour::Colour() +{ + addColour('C', 0x000000, _("Chat")); + addColour('G', 0xff0000, _("GM")); + addColour('Y', 0x1fa052, _("Player")); + addColour('W', 0x0000ff, _("Whisper")); + addColour('I', 0xf1dc27, _("Is")); + addColour('P', 0xff00d8, _("Party")); + addColour('S', 0x8415e2, _("Server")); + addColour('L', 0x919191, _("Logger")); + addColour('<', 0xe50d0d, _("Hyperlink")); + commit(); +} + +Colour::~Colour() +{ + for (ColVector::iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + char buffer[20]; + std::sprintf(buffer, "0x%06x", col->rgb); + config.setValue("Colour" + col->text, buffer); + } +} + +void Colour::setColour(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 Colour::getColour(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 Colour::getElementAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mColVector[i].text; +} + +void Colour::addColour(const char c, const int rgb, const std::string &text) +{ + int trueRgb = config.getValue("Colour" + text, rgb); + mColVector.push_back(ColourElem(c, trueRgb, text)); +} + +int Colour::getColourAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return 0; + } + return mColVector[i].rgb; +} + +void Colour::setColourAt(int i, int rgb) +{ + if (i >= 0 && i < getNumberOfElements()) + { + mColVector[i].rgb = rgb; + } +} + +void Colour::commit() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->committedRgb = i->rgb; + } +} + +void Colour::rollback() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->rgb = i->committedRgb; + } +} diff --git a/src/gui/colour.h b/src/gui/colour.h new file mode 100644 index 00000000..1e8ba3db --- /dev/null +++ b/src/gui/colour.h @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2008 by Douglas Boffey * + * * + * DougABoffey@netscape.net * + * 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 * + * (at your option) any later version. * + * * + * This program is distributed with The Mana Experiment * + * 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 <cstdio> +#include <string> +#include <vector> + +#include <guichan/listmodel.hpp> + +#include "../guichanfwd.h" + +class Colour : public gcn::ListModel +{ + public: + /** + * Constructor + */ + Colour(); + + /** + * Destructor + */ + ~Colour(); + + /** + * Define the colour replacement for a character + * + * @param c charater to be replaced + * @param rgb colour to replace character + */ + void setColour(const char c, const int rgb); + + /** + * Define the colour replacement for a character + * + * @param c character to be replaced + * @param r red component + * @param g green component + * @param b blue component + */ + void setColour(const char c, const int r, const int g, const int b) + { + setColour(c, (r << 16) | (g << 8) | b); + } + + /** + * Return the colour associated with a character, if exists + * + * @param c character requested + * @param valid indicate whether character is known + */ + int getColour(const char c, bool &valid) const; + + /** + * Return the number of colours known + */ + int getNumberOfElements() {return mColVector.size(); } + + /** + * Return the name of the ith colour + * + * @param i index of colour interested in + */ + std::string getElementAt(int i); + + /** + * Get the colour for the element at index i in the current colour + * model + */ + int getColourAt(int i); + + /** + * Set the colour for the element at index i + */ + void setColourAt(int i, int rgb); + + /** + * Commit the colours + */ + void commit(); + + /** + * Rollback the colours + */ + void rollback(); + + private: + struct ColourElem + { + ColourElem(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<ColourElem> ColVector; + ColVector mColVector; + + /** + * Initialise colour + * + * @param c character that needs initialising + * @param rgb default colour if not found in config + * @param text identifier of colour + */ + void addColour(const char c, const int rgb, const std::string &text); +}; + +extern Colour *textColour; + +#endif diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index 46b7c971..569fd93f 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -19,11 +19,9 @@ * 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 "../utils/gettext.h" @@ -31,28 +29,51 @@ 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->setMinWidth(260); + mTextBox->setTextWrapped(msg); + + 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); @@ -64,6 +85,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..fb8290c8 100644 --- a/src/gui/confirm_dialog.h +++ b/src/gui/confirm_dialog.h @@ -24,8 +24,12 @@ #include <guichan/actionlistener.hpp> +#include "button.h" +#include "scrollarea.h" +#include "textbox.h" #include "window.h" +#include "../guichanfwd.h" /** * An option dialog. @@ -42,10 +46,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..15d85bbc 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connection.cpp @@ -19,13 +19,12 @@ * 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" diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 669aabd2..223b7fbd 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -19,13 +19,12 @@ * 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 "debugwindow.h" #include "gui.h" #include "viewport.h" diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp new file mode 100644 index 00000000..fa63d4bb --- /dev/null +++ b/src/gui/emotecontainer.cpp @@ -0,0 +1,172 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; 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..8e52a206 --- /dev/null +++ b/src/gui/emotecontainer.h @@ -0,0 +1,138 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; 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> + +#include "../guichanfwd.h" + +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..f5ee9843 --- /dev/null +++ b/src/gui/emoteshortcutcontainer.cpp @@ -0,0 +1,195 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; 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 "../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(): + mEmoteClicked(false), + mEmoteMoved(0) +{ + mGridWidth = 1, + mGridHeight = 1, + addMouseListener(this); + addWidgetListener(this); + + ResourceManager *resman = ResourceManager::getInstance(); + + mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); + + // 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); + } + } +} + +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..cffaee6f --- /dev/null +++ b/src/gui/emoteshortcutcontainer.h @@ -0,0 +1,81 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; 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 <guichan/mouselistener.hpp> + +#include "shortcutcontainer.h" + +#include "../guichanfwd.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..b4e9c735 --- /dev/null +++ b/src/gui/emotewindow.cpp @@ -0,0 +1,82 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string> + +#include <guichan/mouseinput.hpp> + +#include "button.h" +#include "gui.h" +#include "emotewindow.h" +#include "emotecontainer.h" +#include "scrollarea.h" +#include "textbox.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/emotewindow.h b/src/gui/emotewindow.h new file mode 100644 index 00000000..8e36e5ce --- /dev/null +++ b/src/gui/emotewindow.h @@ -0,0 +1,68 @@ +/* + * Aethyra + * Copyright 2009 Aethyra Development Team + * + * This file is part of Aethyra. + * + * Aethyra 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. + * + * Aethyra 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 Aethyra; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTEWINDOW_H +#define EMOTEWINDOW_H + +#include <guichan/actionlistener.hpp> +#include <guichan/selectionlistener.hpp> + +#include "window.h" + +#include "../guichanfwd.h" + +class EmoteContainer; +class TextBox; + +/** + * Emote dialog. + * + * \ingroup Interface + */ +class EmoteWindow : public Window, gcn::ActionListener, + gcn::SelectionListener +{ + public: + /** + * Constructor. + */ + EmoteWindow(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Returns the selected item. + */ + int getSelectedEmote() const; + + private: + EmoteContainer *mEmotes; + + gcn::Button *mUseButton; + gcn::ScrollArea *mEmoteScroll; +}; + +extern EmoteWindow *emoteWindow; + +#endif diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index aa6825f2..1fb2b601 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -19,14 +19,20 @@ * 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 "playerbox.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 +40,57 @@ #include "../utils/gettext.h" #include "../utils/tostring.h" +// 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(Equipment *equipment): Window(_("Equipment")), - mEquipment(equipment) + mEquipment(equipment), + mSelected(-1) + { + // 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(); + } + mInventory = player_node->getInventory(); } EquipmentWindow::~EquipmentWindow() { + delete mUnequip; } void EquipmentWindow::draw(gcn::Graphics *graphics) @@ -54,37 +98,85 @@ 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) + { + // Set color red. + g->setColor(gcn::Color(255, 0, 0)); + } + else { - static_cast<Graphics*>(graphics)->drawImage( - image, 36 * (i % 4) + 10, 36 * (i / 4) + 25); + // 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)); + } +} + +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; } +} + +void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) +{ + Window::mousePressed(mouseEvent); - graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32)); + const int x = mouseEvent.getX(); + const int y = mouseEvent.getY(); - if (!(item = mInventory->getItem(mEquipment->getArrows()))) - return; + Item* item; - image = item->getImage(); - if (image) + // Checks if any of the presses were in the equip boxes. + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) { - static_cast<Graphics*>(graphics)->drawImage(image, 160, 25); + 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; + } + } } - graphics->drawText(toString(item->getQuantity()), 170, 62, - gcn::Graphics::CENTER); } + diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index e2420134..0b3aede0 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -22,17 +22,29 @@ #ifndef EQUIPMENTWINDOW_H #define EQUIPMENTWINDOW_H +#include <guichan/actionlistener.hpp> + #include "window.h" -#include "../inventory.h" class Equipment; +class Inventory; +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: /** @@ -50,9 +62,36 @@ 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: Equipment *mEquipment; Inventory *mInventory; + gcn::Button *mUnequip; /**< Button for unequipping. */ + EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */ + + 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..dd605be6 100644 --- a/src/gui/focushandler.cpp +++ b/src/gui/focushandler.cpp @@ -21,7 +21,6 @@ #include "focushandler.h" - void FocusHandler::requestModalFocus(gcn::Widget *widget) { /* If there is another widget with modal focus, remove its modal focus diff --git a/src/gui/gccontainer.h b/src/gui/gccontainer.h index da584a42..0a573645 100644 --- a/src/gui/gccontainer.h +++ b/src/gui/gccontainer.h @@ -26,6 +26,8 @@ #include <guichan/widgets/container.hpp> +#include "../guichanfwd.h" + /** * A garbage collecting container. Childs added to this container are * automatically deleted when the container is deleted. diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2da451a3..642e916b 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: @@ -115,14 +117,26 @@ 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 { 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 +172,7 @@ Gui::~Gui() mMouseCursors->decRef(); delete mGuiFont; + delete boldFont; delete viewport; delete getTop(); diff --git a/src/gui/gui.h b/src/gui/gui.h index 95cd5815..9681d44a 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; @@ -125,4 +125,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..6b14f6d8 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" @@ -33,7 +34,8 @@ HelpWindow::HelpWindow(): Window(_("Help")) { setContentSize(455, 350); - setWindowName("Help"); + setWindowName(_("Help")); + setResizable(true); mBrowserBox = new BrowserBox(); mBrowserBox->setOpaque(false); @@ -48,8 +50,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..2ba74c0a 100644 --- a/src/gui/help.h +++ b/src/gui/help.h @@ -24,8 +24,8 @@ #include <guichan/actionlistener.hpp> -#include "window.h" #include "linkhandler.h" +#include "window.h" #include "../guichanfwd.h" 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..2a913ef6 100644 --- a/src/gui/inttextfield.h +++ b/src/gui/inttextfield.h @@ -24,6 +24,8 @@ #include "textfield.h" +#include "../guichanfwd.h" + /** * TextBox which only accepts numbers as input. */ @@ -58,8 +60,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..58c13910 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -19,72 +19,91 @@ * 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 "textbox.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() + 310); + + place(0, 0, mInvenScroll, 7, 4); + place(0, 4, mWeightLabel).setPadding(3); + place(1, 4, mWeightBar, 2); + place(3, 4, mSlotsLabel).setPadding(3); + place(4, 4, mSlotsBar, 2); + place(5, 5, mDropButton); + place(6, 5, mUseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); loadWindowState(); + setLocationRelativeTo(getParent()); } void InventoryWindow::logic() @@ -95,15 +114,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 +156,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 +200,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..2c19ce26 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -28,9 +28,12 @@ #include "window.h" #include "../guichanfwd.h" +#include "../localplayer.h" class Item; class ItemContainer; +class ProgressBar; +class TextBox; /** * Inventory dialog. @@ -38,13 +41,13 @@ class ItemContainer; * \ingroup Interface */ class InventoryWindow : public Window, gcn::ActionListener, - gcn::SelectionListener + gcn::SelectionListener { public: /** * Constructor. */ - InventoryWindow(); + InventoryWindow(int invSize = (INVENTORY_SIZE - 2)); /** * Logic (updates buttons and weight information). @@ -61,30 +64,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..d8682c95 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" diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index a0885279..e3ecdd4e 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -21,13 +21,18 @@ #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" @@ -41,11 +46,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"); @@ -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); @@ -138,6 +147,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 +169,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 +180,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 +190,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 +231,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 +249,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..1fa76343 100644 --- a/src/gui/itemcontainer.h +++ b/src/gui/itemcontainer.h @@ -22,15 +22,18 @@ #ifndef ITEMCONTAINER_H #define ITEMCONTAINER_H +#include <list> + #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> #include <guichan/widgetlistener.hpp> -#include <list> +#include "../guichanfwd.h" class Image; class Inventory; class Item; +class ItemPopup; namespace gcn { class SelectionListener; @@ -41,14 +44,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 +108,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 +132,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..34c12a0c --- /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 <SDL_mouse.h> + +#include "itemlinkhandler.h" +#include "itempopup.h" + +#include "../resources/iteminfo.h" +#include "../resources/itemdb.h" + +#include <sstream> +#include <string> + +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..8235d640 --- /dev/null +++ b/src/gui/itempopup.cpp @@ -0,0 +1,176 @@ +/* + * 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 "windowcontainer.h" + +#include "widgets/layout.h" + +#include "../resources/image.h" +#include "../resources/iteminfo.h" +#include "../resources/resourcemanager.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" +#include "../utils/tostring.h" + +ItemPopup::ItemPopup(): + Window() +{ + setResizable(false); + setShowTitle(false); + setTitleBarHeight(0); + + // Item Name + mItemName = new gcn::Label("Label"); + mItemName->setFont(gui->getFont()); + mItemName->setPosition(2, 2); + mItemName->setWidth(getWidth() - 4); + mItemName->setFont(boldFont); + + // Item Description + mItemDesc = new TextBox(); + mItemDesc->setEditable(false); + mItemDesc->setMinWidth(186); + mItemDesc->setTextWrapped(""); + 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); + mItemEffect->setMinWidth(186); + mItemEffect->setTextWrapped(""); + 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); + mItemWeight->setMinWidth(186); + mItemWeight->setTextWrapped(""); + 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()); + + // LEEOR / TODO: This causes an exception error. + //moveToBottom(getParent()); +} + +void ItemPopup::setItem(const ItemInfo &item) +{ + const gcn::Rectangle &area = getChildrenArea(); + const int width = area.width; + + mItemDesc->setMinWidth(width - 10); + mItemEffect->setMinWidth(width - 10); + mItemWeight->setMinWidth(width - 10); + + mItemName->setCaption(item.getName()); + mItemDesc->setTextWrapped(item.getDescription()); + mItemEffect->setTextWrapped(item.getEffect()); + mItemWeight->setTextWrapped(_("Weight: ") + toString(item.getWeight()) + + _(" grams")); + + int numRowsDesc = mItemDesc->getNumberOfRows(); + int numRowsEffect = mItemEffect->getNumberOfRows(); + int numRowsWeight = mItemWeight->getNumberOfRows(); + + mItemDescScroll->setDimension(gcn::Rectangle(2, 0, 196, + numRowsDesc * getFont()->getHeight())); + + mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, 196, + numRowsEffect * getFont()->getHeight())); + + mItemWeightScroll->setDimension(gcn::Rectangle(2, 0, 196, + numRowsWeight * getFont()->getHeight())); + + if(item.getEffect() == "") + { + setContentSize(200, (numRowsDesc * getFont()->getHeight() + + (3 * getFont()->getHeight()))); + + mItemWeightScroll->setPosition(2, + (numRowsDesc * getFont()->getHeight()) + + (2 * getFont()->getHeight())); + } + else + { + setContentSize(200, (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())); +} + +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() - 5) < 0) + y = 0; + else + y = y - getHeight() - 5; + setPosition(x, y); + setVisible(true); + requestMoveToTop(); +} diff --git a/src/gui/buddywindow.h b/src/gui/itempopup.h index 4eed3a2c..b6120af8 100644 --- a/src/gui/buddywindow.h +++ b/src/gui/itempopup.h @@ -1,6 +1,7 @@ /* * The Mana World - * Copyright (C) 2004 The Mana World Development Team + * 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. * @@ -19,38 +20,32 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef BUDDYWINDOW_H -#define BUDDYWINDOW_H - -#include <guichan/actionlistener.hpp> +#ifndef ITEMPOPUP_H__ +#define ITEMPOPUP_H__ +#include "scrollarea.h" +#include "textbox.h" #include "window.h" -#include "../guichanfwd.h" - -class BuddyList; +#include "../item.h" -/** - * Window showing buddy list. - * - * \ingroup Interface - */ -class BuddyWindow : public Window, public gcn::ActionListener +class ItemPopup : public Window { public: - /** - * Constructor. - */ - BuddyWindow(); + ItemPopup(); - /** - * Performs action. - */ - void action(const gcn::ActionEvent &event); + void setItem(const ItemInfo &item); + unsigned int getNumRows(); + void view(int x, int y); private: - BuddyList *mBuddyList; - gcn::ListBox *mListbox; + gcn::Label *mItemName; + TextBox *mItemDesc; + TextBox *mItemEffect; + TextBox *mItemWeight; + ScrollArea *mItemDescScroll; + ScrollArea *mItemEffectScroll; + ScrollArea *mItemWeightScroll; }; -#endif /* BUDDYWINDOW_H */ +#endif // ITEMPOPUP_H__ diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index b2f70348..3735afe2 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -18,15 +18,20 @@ * 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 "gui.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,21 +39,25 @@ #include "../utils/tostring.h" ItemShortcutContainer::ItemShortcutContainer(): - mGridWidth(1), - mGridHeight(1), mItemClicked(false), mItemMoved(NULL) { + mGridWidth=1; + mGridHeight=1; 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() @@ -56,8 +65,7 @@ ItemShortcutContainer::~ItemShortcutContainer() mBackgroundImg->decRef(); } -void -ItemShortcutContainer::logic() +void ItemShortcutContainer::logic() { gcn::Widget::logic(); @@ -70,8 +78,7 @@ ItemShortcutContainer::logic() } } -void -ItemShortcutContainer::draw(gcn::Graphics *graphics) +void ItemShortcutContainer::draw(gcn::Graphics *graphics) { Graphics *g = static_cast<Graphics*>(graphics); @@ -87,7 +94,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 +105,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 = @@ -129,35 +139,23 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) } } -void ItemShortcutContainer::widgetResized(const gcn::Event &event) +void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &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; - } -} - -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 +169,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 +226,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..d6a04d7b 100644 --- a/src/gui/itemshortcutcontainer.h +++ b/src/gui/itemshortcutcontainer.h @@ -23,20 +23,21 @@ #define ITEMSHORTCUTCONTAINER_H #include <guichan/mouselistener.hpp> -#include <guichan/widget.hpp> -#include <guichan/widgetlistener.hpp> + +#include "shortcutcontainer.h" + +#include "../guichanfwd.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 +61,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 +75,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; - - Image *mBackgroundImg; + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); - 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..990a0ade 100644 --- a/src/gui/listbox.cpp +++ b/src/gui/listbox.cpp @@ -19,13 +19,13 @@ * 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 "listbox.h" + ListBox::ListBox(gcn::ListModel *listModel): gcn::ListBox(listModel) { @@ -36,7 +36,7 @@ void ListBox::draw(gcn::Graphics *graphics) if (!mListModel) return; - graphics->setColor(gcn::Color(110, 160, 255)); + graphics->setColor(gcn::Color(235, 200, 115)); graphics->setFont(getFont()); int fontHeight = getFont()->getHeight(); @@ -57,8 +57,7 @@ void ListBox::draw(gcn::Graphics *graphics) } } -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..3d0062bc 100644 --- a/src/gui/listbox.h +++ b/src/gui/listbox.h @@ -24,6 +24,8 @@ #include <guichan/widgets/listbox.hpp> +#include "../guichanfwd.h" + class SelectionListener; /** diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 2b87f6df..8de2867c 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 <vector> #include <guichan/widgets/label.hpp> -#include "../main.h" -#include "../logindata.h" - #include "button.h" #include "checkbox.h" +#include "login.h" #include "ok_dialog.h" #include "passwordfield.h" #include "textfield.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,64 @@ 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"); + dfltServer.push_back("server.themanaworld.org"); + std::vector<std::string> dfltPort; + dfltPort.push_back("21001"); + dfltPort.push_back("22001"); + dfltPort.push_back("21001"); + mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort, + MAX_SERVER_LIST_SIZE); + mServerListBox = new gcn::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); + 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 +125,9 @@ LoginDialog::LoginDialog(LoginData *loginData): LoginDialog::~LoginDialog() { + delete mServerList; + delete mServerListBox; + delete mServerScrollArea; } void LoginDialog::action(const gcn::ActionEvent &event) @@ -97,6 +135,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 +143,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 +160,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 +185,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 == "") + { + 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 != "") + { + 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 == "") // 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 != "") + { + mServers.push_back(server); + mPorts.push_back(port); + } + } + if (mServers.size() == 0) + { + 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..b85e5ae1 100644 --- a/src/gui/login.h +++ b/src/gui/login.h @@ -23,10 +23,17 @@ #define LOGIN_H #include <iosfwd> +#include <string> +#include <vector> + #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#include "scrollarea.h" #include "window.h" + +#include "widgets/dropdown.h" + #include "../guichanfwd.h" class LoginData; @@ -67,18 +74,66 @@ 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; + 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/minimap.cpp b/src/gui/minimap.cpp index f5c0c1e6..7802b583 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,13 +33,17 @@ #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() + "Visible", true); setDefaultSize(5, 25, 100, 100); - loadWindowState(); + setResizable(true); } Minimap::~Minimap() @@ -53,13 +60,57 @@ 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() + offsetX); + setMaxHeight(mMapImage->getHeight() + offsetY); + + mMapImage->setAlpha(config.getValue("guialpha", 0.8)); + + // Set content size to be within the minimum and maximum boundaries + setWidth(getMinWidth() < getWidth() ? getWidth() : getMinWidth()); + if (getMaxWidth() > getWidth()) + setWidth(getMaxWidth()); + setHeight(getMinHeight() < getHeight() ? getHeight() : getMinHeight()); + if (getMaxHeight() > getHeight()) + setHeight(getMaxHeight()); + + setDefaultSize(getX(), getY(), getWidth(), getHeight()); + resetToDefaultSize(); + + loadWindowState(); + setVisible(mShow); + } + else + { + setVisible(false); + } +} + +void Minimap::toggle() +{ + mShow = !mShow; + config.setValue(getWindowName() + "Visible", 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 +123,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 +138,7 @@ void Minimap::draw(gcn::Graphics *graphics) if (mapOriginY > 0) mapOriginY = 0; } + static_cast<Graphics*>(graphics)-> drawImage(mMapImage, mapOriginX, mapOriginY); } @@ -122,10 +174,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..b4574ad5 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -24,6 +24,8 @@ #include "window.h" +#include "../guichanfwd.h" + class Image; /** @@ -50,12 +52,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..915db961 100644 --- a/src/gui/ministatus.cpp +++ b/src/gui/ministatus.cpp @@ -19,14 +19,13 @@ * 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 "../configuration.h" #include "../graphics.h" +#include "../localplayer.h" #include "../utils/tostring.h" @@ -90,24 +89,22 @@ 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) diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp index 6ad698bc..a2e043d1 100644 --- a/src/gui/npc_text.cpp +++ b/src/gui/npc_text.cpp @@ -19,14 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npc_text.h" - #include <string> +#include "npc_text.h" #include "browserbox.h" #include "button.h" #include "scrollarea.h" +#include "widgets/layout.h" + #include "../npc.h" #include "../utils/gettext.h" @@ -39,24 +40,24 @@ NpcTextDialog::NpcTextDialog(): setMinWidth(200); setMinHeight(150); + setDefaultSize(0, 0, 260, 200); + mBrowserBox = new BrowserBox(BrowserBox::AUTO_WRAP); - mBrowserBox->setOpaque(true); + mBrowserBox->setOpaque(false); scrollArea = new ScrollArea(mBrowserBox); 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); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + loadWindowState(); setLocationRelativeTo(getParent()); } @@ -76,21 +77,6 @@ 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()); -} - void NpcTextDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h index c881467a..b4b6f1af 100644 --- a/src/gui/npc_text.h +++ b/src/gui/npc_text.h @@ -23,8 +23,10 @@ #define NPC_TEXT_H #include <iosfwd> + #include <guichan/actionlistener.hpp> +#include "scrollarea.h" #include "window.h" class BrowserBox; @@ -45,13 +47,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); diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp index ec91d736..65a1a7f1 100644 --- a/src/gui/npcintegerdialog.cpp +++ b/src/gui/npcintegerdialog.cpp @@ -107,5 +107,6 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event) setVisible(false); current_npc->integerInput(mValueField->getValue()); current_npc = 0; + mValueField->reset(); } } diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp index 4b05df5a..bb815680 100644 --- a/src/gui/npclistdialog.cpp +++ b/src/gui/npclistdialog.cpp @@ -19,13 +19,12 @@ * 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 "widgets/layout.h" #include "../npc.h" @@ -39,6 +38,8 @@ NpcListDialog::NpcListDialog(): setMinWidth(200); setMinHeight(150); + setDefaultSize(0, 0, 260, 200); + mItemList = new ListBox(this); scrollArea = new ScrollArea(mItemList); okButton = new Button(_("OK"), "ok", this); @@ -46,23 +47,15 @@ NpcListDialog::NpcListDialog(): 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"); + place(0, 0, scrollArea, 5).setPadding(3); + place(3, 1, okButton); + place(4, 1, cancelButton); - mItemList->addActionListener(this); - - add(scrollArea); - add(okButton); - add(cancelButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + loadWindowState(); setLocationRelativeTo(getParent()); } @@ -90,24 +83,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..ffeced3d 100644 --- a/src/gui/npclistdialog.h +++ b/src/gui/npclistdialog.h @@ -28,6 +28,8 @@ #include <guichan/actionlistener.hpp> #include <guichan/listmodel.hpp> +#include "button.h" +#include "scrollarea.h" #include "window.h" #include "../guichanfwd.h" @@ -49,13 +51,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..ccb3c411 100644 --- a/src/gui/npcstringdialog.cpp +++ b/src/gui/npcstringdialog.cpp @@ -42,8 +42,8 @@ NpcStringDialog::NpcStringDialog(): 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,6 +69,7 @@ void NpcStringDialog::action(const gcn::ActionEvent &event) setVisible(false); current_npc->stringInput(mValueField->getText()); current_npc = 0; + mValueField->setText(""); } bool NpcStringDialog::isInputFocused() diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index a2134d5d..dc66a900 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -20,9 +20,8 @@ */ #include "ok_dialog.h" -#include "textbox.h" -#include "button.h" -#include "scrollarea.h" + +#include <guichan/font.hpp> #include "../utils/gettext.h" @@ -30,25 +29,45 @@ 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->setMinWidth(260); + mTextBox->setTextWrapped(msg); - 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 +75,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..78b3d44f 100644 --- a/src/gui/ok_dialog.h +++ b/src/gui/ok_dialog.h @@ -24,8 +24,13 @@ #include <guichan/actionlistener.hpp> +#include "button.h" +#include "scrollarea.h" +#include "textbox.h" #include "window.h" +#include "../guichanfwd.h" + /** * An 'Ok' button dialog. * @@ -41,10 +46,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.h b/src/gui/passwordfield.h index d6082e3f..e01bedbd 100644 --- a/src/gui/passwordfield.h +++ b/src/gui/passwordfield.h @@ -24,12 +24,15 @@ #include "textfield.h" +#include "../guichanfwd.h" + /** * A password field. * * \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..c22d407c 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -23,8 +23,10 @@ #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" @@ -54,6 +56,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 +86,13 @@ 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) != NULL) + { + mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y); + } + } } } diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index d66db4d4..5aacd26f 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -24,6 +24,8 @@ #include <guichan/widgets/scrollarea.hpp> +#include "../guichanfwd.h" + class ImageRect; class Player; @@ -51,8 +53,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. diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 06a2ad87..9b0c2370 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -19,16 +19,16 @@ * 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,8 +39,11 @@ #include "../npc.h" #include "../player_relations.h" -#include "../resources/iteminfo.h" +#include "../net/messageout.h" +#include "../net/protocol.h" + #include "../resources/itemdb.h" +#include "../resources/iteminfo.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" @@ -72,51 +75,53 @@ void PopupMenu::showPopup(int x, int y, Being *being) switch (being->getType()) { - case Being::PLAYER: - { - // 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("##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; - } - - //mBrowserBox->addRow("@@follow|Follow " + name + "@@"); - //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@"); - } - break; - - case Being::NPC: - // NPCs can be talked to (single option, candidate for removal - // unless more options would be added) - mBrowserBox->addRow(_("@@talk|Talk To NPC@@")); - break; - - default: - /* Other beings aren't interesting... */ - break; + case Being::PLAYER: + { + // 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(_("@@trade|Trade With ") + name + "@@"); + mBrowserBox->addRow(_("@@attack|Attack ") + name + "@@"); + + 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; + } + + //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@"); + //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@"); + + mBrowserBox->addRow("##3---"); + mBrowserBox->addRow(_("@@party-invite|Invite ") + name + + " to party@@"); + } + break; + + case Being::NPC: + // NPCs can be talked to (single option, candidate for removal + // unless more options would be added) + mBrowserBox->addRow(_("@@talk|Talk To NPC@@")); + break; + + default: + /* Other beings aren't interesting... */ + break; } //browserBox->addRow("@@look|Look To@@"); @@ -148,28 +153,28 @@ void PopupMenu::handleLink(const std::string& link) // Talk To action if (link == "talk" && - being != NULL && - being->getType() == Being::NPC && - current_npc == 0) + being != NULL && + being->getType() == Being::NPC && + current_npc == 0) { - dynamic_cast<NPC*>(being)->talk(); + dynamic_cast<NPC*>(being)->talk(); } // Trade action else if (link == "trade" && - being != NULL && - being->getType() == Being::PLAYER) + being != NULL && + being->getType() == Being::PLAYER) { - player_node->trade(being); - tradePartnerName = being->getName(); + player_node->trade(being); + tradePartnerName = being->getName(); } // Attack action else if (link == "attack" && - being != NULL && - being->getType() == Being::PLAYER) + being != NULL && + being->getType() == Being::PLAYER) { - player_node->attack(being, true); + player_node->attack(being, true); } else if (link == "unignore" && @@ -194,10 +199,10 @@ void PopupMenu::handleLink(const std::string& link) } else if (link == "friend" && - being != NULL && - being->getType() == Being::PLAYER) + being != NULL && + being->getType() == Being::PLAYER) { - player_relations.setRelation(being->getName(), PlayerRelation::FRIEND); + player_relations.setRelation(being->getName(), PlayerRelation::FRIEND); } /* @@ -210,16 +215,16 @@ void PopupMenu::handleLink(const std::string& link) // Add Buddy action else if ((link == "buddy") && being != NULL && being->isPlayer()) { - if (!buddyWindow->isVisible()) - buddyWindow->setVisible(true); + if (!buddyWindow->isVisible()) + buddyWindow->setVisible(true); - buddyWindow->addBuddy(being->getName()); + buddyWindow->addBuddy(being->getName()); }*/ // Pick Up Floor Item action else if ((link == "pickup") && mFloorItem != NULL) { - player_node->pickUp(mFloorItem); + player_node->pickUp(mFloorItem); } // Look To action @@ -229,39 +234,46 @@ void PopupMenu::handleLink(const std::string& link) else if (link == "use") { - assert(mItem); - if (mItem->isEquipment()) - { - if (mItem->isEquipped()) - { - player_node->unequipItem(mItem); - } - else - { - player_node->equipItem(mItem); - } - } - else - { - player_node->useItem(mItem); - } + assert(mItem); + if (mItem->isEquipment()) + { + if (mItem->isEquipped()) + { + player_node->unequipItem(mItem); + } + else + { + player_node->equipItem(mItem); + } + } + else + { + player_node->useItem(mItem); + } } - else if (link == "drop") + else if (link == "chat") { - new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem); + chatWindow->addItemText(mItem->getId(), mItem->getInfo().getName()); } - else if (link == "description") + else if (link == "drop") + { + new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem); + } + else if (link == "party-invite" && + being != NULL && + 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 else { - std::cout << link << std::endl; + std::cout << link << std::endl; } setVisible(false); @@ -288,7 +300,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@@")); @@ -299,9 +311,9 @@ void PopupMenu::showPopup(int x, int y) { setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8); if (windowContainer->getWidth() < (x + getWidth() + 5)) - x = windowContainer->getWidth() - getWidth(); + x = windowContainer->getWidth() - getWidth(); if (windowContainer->getHeight() < (y + getHeight() + 5)) - y = windowContainer->getHeight() - getHeight(); + y = windowContainer->getHeight() - getHeight(); setPosition(x, y); setVisible(true); requestMoveToTop(); 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..ecc0017d 100644 --- a/src/gui/progressbar.cpp +++ b/src/gui/progressbar.cpp @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "gui.h" #include "progressbar.h" #include "../graphics.h" @@ -105,7 +106,7 @@ 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; diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h index a4b30b04..ee0a5f81 100644 --- a/src/gui/progressbar.h +++ b/src/gui/progressbar.h @@ -25,9 +25,10 @@ #include <guichan/widget.hpp> #include <SDL_types.h> - #include <string> +#include "../guichanfwd.h" + class ImageRect; /** @@ -81,12 +82,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; } diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h index 2d2bdbb7..dcd62802 100644 --- a/src/gui/radiobutton.h +++ b/src/gui/radiobutton.h @@ -24,8 +24,9 @@ #include <guichan/widgets/radiobutton.hpp> -class Image; +#include "../guichanfwd.h" +class Image; /* * Guichan based RadioButton with custom look diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 5605ef96..9c337d9e 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -19,8 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "register.h" - #include <string> #include <sstream> @@ -34,10 +32,13 @@ #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 "../utils/tostring.h" #include "widgets/layout.h" @@ -80,10 +81,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 +100,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 +115,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 +126,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); @@ -147,7 +156,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "register" && canSubmit()) { const std::string user = mUserField->getText(); - logger->log("RegisterDialog::register Username is %s", user.c_str()); + logger->log(_("RegisterDialog::register Username is %s"), user.c_str()); std::string errorMsg; int error = 0; @@ -216,7 +225,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 +247,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 == "") + { + 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..4b95a07b 100644 --- a/src/gui/register.h +++ b/src/gui/register.h @@ -23,10 +23,12 @@ #define REGISTER_H #include <iosfwd> + #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> #include "window.h" + #include "../guichanfwd.h" class LoginData; @@ -72,10 +74,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..1d7f8472 100644 --- a/src/gui/scrollarea.cpp +++ b/src/gui/scrollarea.cpp @@ -23,6 +23,7 @@ #include "scrollarea.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -94,6 +95,7 @@ void ScrollArea::init() 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 +108,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++; } } @@ -197,7 +202,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 +213,12 @@ void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; - if (mOpaque) { + if (mOpaque) + { setFrameSize(2); } - else { + else + { setFrameSize(0); } } @@ -220,7 +228,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..4fababfa 100644 --- a/src/gui/scrollarea.h +++ b/src/gui/scrollarea.h @@ -24,6 +24,8 @@ #include <guichan/widgets/scrollarea.hpp> +#include "../guichanfwd.h" + class Image; class ImageRect; diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index cc6f02d5..7976e32e 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -19,8 +19,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "sell.h" - #include <cassert> #include <guichan/widgets/label.hpp> @@ -28,6 +26,7 @@ #include "button.h" #include "shoplistbox.h" #include "scrollarea.h" +#include "sell.h" #include "shop.h" #include "slider.h" @@ -36,13 +35,14 @@ #include "../item.h" #include "../npc.h" -#include "../resources/iteminfo.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" SellDialog::SellDialog(Network *network): Window(_("Sell")), diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index d38fb2e3..d18f365c 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -19,31 +19,33 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup.h" +#include <algorithm> +#include <iostream> #include "button.h" +#include "setup.h" #include "setup_audio.h" +#include "setup_colours.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 +60,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 +93,10 @@ Setup::Setup(): panel->addTab(_("Keyboard"), tab); mTabs.push_back(tab); + tab = new Setup_Colours(); + panel->addTab(_("Colors"), tab); + mTabs.push_back(tab); + tab = new Setup_Players(); panel->addTab(_("Players"), tab); mTabs.push_back(tab); @@ -131,6 +138,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..7090136e 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" diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h index 5345d3cf..2f5cd736 100644 --- a/src/gui/setup_audio.h +++ b/src/gui/setup_audio.h @@ -22,10 +22,10 @@ #ifndef GUI_SETUP_AUDIO_H #define GUI_SETUP_AUDIO_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> +#include "setuptab.h" + #include "../guichanfwd.h" class Setup_Audio : public SetupTab, public gcn::ActionListener diff --git a/src/gui/setup_colours.cpp b/src/gui/setup_colours.cpp new file mode 100644 index 00000000..c08c94ef --- /dev/null +++ b/src/gui/setup_colours.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + * Copyright (C) 2008 by Douglas Boffey * + * * + * DougABoffey@netscape.net * + * 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 * + * (at your option) any later version. * + * * + * This program is distributed with The Mana Experiment * + * 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 <vector> + +#include <guichan/listmodel.hpp> +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/slider.hpp> + +#include "colour.h" +#include "scrollarea.h" +#include "setup_colours.h" +#include "slider.h" +#include "textfield.h" + +#include "widgets/layouthelper.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" + +Setup_Colours::Setup_Colours() : + mSelected(-1) +{ + setOpaque(false); + + mColourBox = new gcn::ListBox(textColour); + mColourBox->setActionEventId("colour_box"); + mColourBox->addActionListener(this); + + mScroll = new ScrollArea(mColourBox); + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScroll->setWidth(90); + + 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(90); + 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(90); + 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(90); + 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, 1, 3).setPadding(2); + place(1, 0, mRedLabel, 2); + place(3, 0, mRedSlider); + place(4, 0, mRedText).setPadding(1); + place(1, 1, mGreenLabel, 2); + place(3, 1, mGreenSlider); + place(4, 1, mGreenText).setPadding(1); + place(1, 2, mBlueLabel, 2); + place(3, 2, mBlueSlider); + place(4, 2, mBlueText).setPadding(1); + + setDimension(gcn::Rectangle(0, 0, 290, 150)); +} + +Setup_Colours::~Setup_Colours() +{ + delete mRedLabel; + delete mRedSlider; + delete mRedText; + + delete mGreenLabel; + delete mGreenSlider; + delete mGreenText; + + delete mBlueLabel; + delete mBlueSlider; + delete mBlueText; + + delete mScroll; +} + +void Setup_Colours::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "colour_box") + { + mSelected = mColourBox->getSelected(); + int col = textColour->getColourAt(mSelected); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); + return; + } + + if (event.getId() == "slider_red") + { + char buffer[30]; + std::sprintf(buffer, "%d", static_cast<int>(mRedSlider->getValue())); + mRedText->setText(buffer); + updateColour(); + return; + } + + if (event.getId() == "slider_green") + { + char buffer[30]; + std::sprintf(buffer, "%d", static_cast<int>(mGreenSlider->getValue())); + mGreenText->setText(buffer); + updateColour(); + return; + } + + if (event.getId() == "slider_blue") + { + char buffer[30]; + std::sprintf(buffer, "%d", static_cast<int>(mBlueSlider->getValue())); + mBlueText->setText(buffer); + updateColour(); + return; + } +} + +void Setup_Colours::setEntry(Slider *s, TextField *t, int value) +{ + s->setValue(value); + char buffer[100]; + sprintf(buffer, "%d", value); + t->setText(buffer); +} + +void Setup_Colours::apply() +{ + textColour->commit(); +} + +void Setup_Colours::cancel() +{ + textColour->rollback(); + int col = textColour->getColourAt(mSelected); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); +} + +void Setup_Colours::listen(const TextField *tf) +{ + if (tf == mRedText) + { + mRedSlider->setValue(tf->getValue()); + updateColour(); + return; + } + if (tf == mGreenText) + { + mGreenSlider->setValue(tf->getValue()); + updateColour(); + return; + } + if (tf == mBlueText) + { + mBlueSlider->setValue(tf->getValue()); + updateColour(); + return; + } +} + +void Setup_Colours::updateColour() +{ + if (mSelected == -1) + { + return; + } + int rgb = static_cast<int>(mRedSlider->getValue()) << 16 | + static_cast<int>(mGreenSlider->getValue()) << 8 | + static_cast<int>(mBlueSlider->getValue()); + textColour->setColourAt(mSelected, rgb); +} diff --git a/src/gui/setup_colours.h b/src/gui/setup_colours.h new file mode 100644 index 00000000..628efb43 --- /dev/null +++ b/src/gui/setup_colours.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2008 by Douglas Boffey * + * * + * DougABoffey@netscape.net * + * 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 * + * (at your option) any later version. * + * * + * This program is distributed with The Mana Experiment * + * 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 <vector> + +#include <guichan/actionlistener.hpp> +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/listbox.hpp> + +#include "scrollarea.h" +#include "setuptab.h" +#include "slider.h" +#include "textfield.h" + +#include "../guichanfwd.h" + +class Setup_Colours : public SetupTab, public gcn::ActionListener, + public TextFieldListener +{ + public: + Setup_Colours(); + ~Setup_Colours(); + void apply(); + void cancel(); + void action(const gcn::ActionEvent &event); + + void listen(const TextField *tf); + private: + gcn::ListBox *mColourBox; + ScrollArea *mScroll; + int mSelected; + + gcn::Label *mRedLabel; + Slider *mRedSlider; + TextField *mRedText; + int mRedValue; + + gcn::Label *mGreenLabel; + Slider *mGreenSlider; + TextField *mGreenText; + int mGreenValue; + + gcn::Label *mBlueLabel; + Slider *mBlueSlider; + TextField *mBlueText; + int mBlueValue; + + void setEntry(Slider *s, TextField *t, int value); + void updateColour(); +}; +#endif diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index f8fc194f..2c726b87 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" @@ -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..2dc56439 100644 --- a/src/gui/setup_joystick.h +++ b/src/gui/setup_joystick.h @@ -22,10 +22,10 @@ #ifndef GUI_SETUP_JOYSTICK_H #define GUI_SETUP_JOYSTICK_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> +#include "setuptab.h" + #include "../guichanfwd.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..c6b6869a 100644 --- a/src/gui/setup_keyboard.cpp +++ b/src/gui/setup_keyboard.cpp @@ -19,7 +19,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,6 +28,9 @@ #include "listbox.h" #include "ok_dialog.h" #include "scrollarea.h" +#include "setup_keyboard.h" + +#include "widgets/layouthelper.h" #include "widgets/layouthelper.h" @@ -37,8 +40,6 @@ #include "../utils/gettext.h" #include "../utils/tostring.h" -#include <SDL_keyboard.h> - /** * The list model for key function list. * diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h index f04be792..d4966053 100644 --- a/src/gui/setup_keyboard.h +++ b/src/gui/setup_keyboard.h @@ -22,14 +22,14 @@ #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 "button.h" +#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..9a7fb441 100644 --- a/src/gui/setup_players.cpp +++ b/src/gui/setup_players.cpp @@ -19,11 +19,15 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_players.h" +#include <vector> + +#include <guichan/widgets/dropdown.hpp> +#include <guichan/widgets/label.hpp> #include "button.h" #include "checkbox.h" #include "ok_dialog.h" +#include "setup_players.h" #include "widgets/layouthelper.h" @@ -34,11 +38,6 @@ #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 @@ -198,7 +197,7 @@ public: virtual std::string getElementAt(int i) { if (i >= getNumberOfElements()) { - return "???"; + return _("???"); } return (*player_relations.getPlayerIgnoreStrategies())[i]->mDescription; } diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h index d380d9f6..22c8a9b6 100644 --- a/src/gui/setup_players.h +++ b/src/gui/setup_players.h @@ -22,15 +22,14 @@ #ifndef GUI_SETUP_PLAYERS_H #define GUI_SETUP_PLAYERS_H -#include "setuptab.h" +#include <guichan/actionlistener.hpp> -#include "scrollarea.h" #include "button.h" +#include "scrollarea.h" +#include "setuptab.h" #include "table.h" -#include <guichan/actionlistener.hpp> #include "../guichanfwd.h" - #include "../player_relations.h" class PlayerTableModel; diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 53041a9c..2381ab41 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" @@ -89,9 +89,9 @@ ModeListModel::ModeListModel() /* Check which modes are available */ if (modes == (SDL_Rect **)0) { - logger->log("No modes available"); + logger->log(_("No modes available")); } else if (modes == (SDL_Rect **)-1) { - logger->log("All resolutions available"); + logger->log(_("All resolutions available")); } else { //logger->log("Available Modes"); for (int i = 0; modes[i]; ++i) { @@ -107,6 +107,9 @@ Setup_Video::Setup_Video(): mFullScreenEnabled(config.getValue("screen", 0)), mOpenGLEnabled(config.getValue("opengl", 0)), mCustomCursorEnabled(config.getValue("customcursor", 1)), + mParticleEffectsEnabled(config.getValue("particleeffects", 1)), + mSpeechBubbleEnabled(config.getValue("speechbubble", 1)), + mNameEnabled(config.getValue("showownname", 0)), 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)); } @@ -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()); } @@ -316,8 +332,11 @@ void Setup_Video::apply() // We sync old and new values at apply time mFullScreenEnabled = config.getValue("screen", 0); mCustomCursorEnabled = config.getValue("customcursor", 1); + mParticleEffectsEnabled = config.getValue("particleeffects", 1); + mSpeechBubbleEnabled = config.getValue("speechbubble", 1); + mNameEnabled = config.getValue("showownname", 0); mOpacity = config.getValue("guialpha", 0.8); - mOverlayDetail = (int)config.getValue("OverlayDetail", 2); + mOverlayDetail = (int) config.getValue("OverlayDetail", 2); mOpenGLEnabled = config.getValue("opengl", 0); } @@ -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); @@ -357,13 +379,46 @@ void Setup_Video::cancel() config.setValue("screen", mFullScreenEnabled ? 1 : 0); config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0); + config.setValue("particleeffects", mParticleEffectsEnabled ? 1 : 0); + config.setValue("speechbubble", mSpeechBubbleEnabled ? 1 : 0); + config.setValue("showownname", mNameEnabled ? 1 : 0); config.setValue("guialpha", mOpacity); config.setValue("opengl", mOpenGLEnabled ? 1 : 0); } 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()); + const int bpp = 0; + const bool fullscreen = ((int) config.getValue("screen", 0) == 1); + const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); + + // Try to set the desired video mode + if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel)) + { + std::cerr << _("Couldn't set ") + << width << "x" << height << "x" << bpp << _(" video mode: ") + << SDL_GetError() << std::endl; + exit(1); + } + + // Initialize for drawing + graphics->_endDraw(); + graphics->_beginDraw(); + graphics->updateScreen(); + + // 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()); } @@ -372,6 +427,27 @@ void Setup_Video::action(const gcn::ActionEvent &event) config.setValue("customcursor", mCustomCursorCheckBox->isSelected() ? 1 : 0); } + else if (event.getId() == "particleeffects") + { + config.setValue("particleeffects", + mParticleEffectsCheckBox->isSelected() ? 1 : 0); + 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() ? 1 : 0); + } + 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() ? 1 : 0); + } else if (event.getId() == "fpslimitslider") { mFps = (int) mFpsSlider->getValue(); diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index b7011186..d863fb64 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -22,11 +22,11 @@ #ifndef GUI_SETUP_VIDEO_H #define GUI_SETUP_VIDEO_H -#include "setuptab.h" - #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#include "setuptab.h" + #include "../guichanfwd.h" class Setup_Video : public SetupTab, public gcn::ActionListener, @@ -53,6 +53,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 +65,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..22b649d0 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -27,10 +27,11 @@ #include <guichan/listmodel.hpp> -#include "../resources/image.h" - +#include "../guichanfwd.h" #include "../shopitem.h" +#include "../resources/image.h" + class ShopItems : public gcn::ListModel { public: diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index 2517d749..765b9f08 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -19,14 +19,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "shoplistbox.h" - +#include <guichan/basiccontainer.hpp> #include <guichan/font.hpp> #include <guichan/graphics.hpp> +#include <guichan/imagefont.hpp> #include <guichan/listmodel.hpp> #include <guichan/mouseinput.hpp> -#include <guichan/imagefont.hpp> -#include <guichan/basiccontainer.hpp> + +#include "shoplistbox.h" #include "../graphics.h" @@ -72,7 +72,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (i == mSelected) { - backgroundColor = gcn::Color(110, 160, 255); + backgroundColor = gcn::Color(235, 200, 115); } else if (mShopItems && mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck) diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h index bad848d6..733af4eb 100644 --- a/src/gui/shoplistbox.h +++ b/src/gui/shoplistbox.h @@ -25,6 +25,8 @@ #include "listbox.h" #include "shop.h" +#include "../guichanfwd.h" + /** * A list box, meant to be used inside a scroll area. Same as the Guichan list * box except this one doesn't have a background, instead completely relying diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp new file mode 100644 index 00000000..d03bc809 --- /dev/null +++ b/src/gui/shortcutcontainer.cpp @@ -0,0 +1,76 @@ +/* + * 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 "../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" + +#include "../utils/tostring.h" + +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..66aca6c3 --- /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> + +#include "../guichanfwd.h" + +class Image; + +/** + * An item shortcut container. Used to quickly use items. + * + * \ingroup GUI + */ +class ShortcutContainer : public gcn::Widget, + public gcn::WidgetListener, + public gcn::MouseListener +{ + public: + /** + * Constructor. Initializes the graphic. + */ + ShortcutContainer(); + + /** + * Destructor. + */ + ~ShortcutContainer(){} + + /** + * Draws the items. + */ + 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; + + 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..3a7cf0e0 100644 --- a/src/gui/itemshortcutwindow.cpp +++ b/src/gui/shortcutwindow.cpp @@ -19,23 +19,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "itemshortcutwindow.h" - -#include "itemshortcutcontainer.h" +#include "shortcutcontainer.h" +#include "shortcutwindow.h" #include "scrollarea.h" +#include "../configuration.h" + static const int SCROLL_PADDING = 0; -ItemShortcutWindow::ItemShortcutWindow() +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; const int border = SCROLL_PADDING * 2 + getPadding() * 2; setMinWidth(mItems->getBoxWidth() + border); @@ -43,6 +43,14 @@ 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 - mItems->getBoxWidth() - 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 +61,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..0168669e 100644 --- a/src/gui/itemshortcutwindow.h +++ b/src/gui/shortcutwindow.h @@ -19,12 +19,14 @@ * 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; +#include "../guichanfwd.h" + +class ShortcutContainer; class ScrollArea; /** @@ -32,18 +34,18 @@ class ScrollArea; * * \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 +53,13 @@ class ItemShortcutWindow : public Window void widgetResized(const gcn::Event &event); private: - ItemShortcutContainer *mItems; + ShortcutWindow(); + ShortcutContainer *mItems; ScrollArea *mScrollArea; }; -extern ItemShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *emoteShortcutWindow; #endif diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index 4afd913d..304719b6 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -21,13 +21,13 @@ #include <guichan/widgets/label.hpp> -#include "skill.h" - #include "button.h" #include "listbox.h" -#include "scrollarea.h" +#include "skill.h" #include "windowcontainer.h" +#include "widgets/layout.h" + #include "../localplayer.h" #include "../log.h" @@ -36,7 +36,7 @@ #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; @@ -51,21 +51,24 @@ class SkillGuiTableModel : public StaticTableModel { public: SkillGuiTableModel(SkillDialog *dialog) : - StaticTableModel(0, 3) + StaticTableModel(0, 3, 0xbdb5aa) { mEntriesNr = 0; mDialog = dialog; 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() @@ -83,7 +86,8 @@ public: 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]; @@ -123,31 +127,33 @@ SkillDialog::SkillDialog(): mTable.setModel(mTableModel); mTable.setLinewiseSelection(true); - setWindowName("Skills"); + setWindowName(_("Skills")); setCloseButton(true); setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260); + setMinHeight(50 + mTableModel->getHeight()); + setMinWidth(200); + // mSkillListBox = new ListBox(this); 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); + skillScrollArea->setOpaque(false); + + place(0, 0, skillScrollArea, 5).setPadding(3); + place(0, 1, mPointsLabel, 2); + place(3, 2, mIncButton); + place(4, 2, mUseButton); - add(skillScrollArea); - add(mPointsLabel); - add(mIncButton); - add(mUseButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); // mSkillListBox->addActionListener(this); mTable.addActionListener(this); @@ -167,9 +173,7 @@ void SkillDialog::action(const gcn::ActionEvent &event) // Increment skill int selectedSkill = mTable.getSelectedRow();//mSkillListBox->getSelected(); if (selectedSkill >= 0) - { player_node->raiseSkill(mSkillList[selectedSkill]->id); - } } else if (event.getId() == "skill") { @@ -178,9 +182,7 @@ void SkillDialog::action(const gcn::ActionEvent &event) player_node->mSkillPoint > 0); } else if (event.getId() == "close") - { setVisible(false); - } } void SkillDialog::update() @@ -190,7 +192,8 @@ void SkillDialog::update() int selectedSkill = mTable.getSelectedRow(); - if (selectedSkill >= 0) { + if (selectedSkill >= 0) + { int skillId = mSkillList[selectedSkill]->id; bool modifiable; @@ -201,10 +204,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 +219,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 +238,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; } @@ -256,7 +263,7 @@ static void initSkillinfo() if (!root || !xmlStrEqual(root->name, BAD_CAST "skills")) { - logger->log("Error loading skills file: %s", SKILLS_FILE); + logger->log(_("Error loading skills file: %s"), SKILLS_FILE); skill_db.resize(2, emptySkillInfo); skill_db[1].name = "Basic"; skill_db[1].modifiable = true; diff --git a/src/gui/skill.h b/src/gui/skill.h index 893a61e7..582892f0 100644 --- a/src/gui/skill.h +++ b/src/gui/skill.h @@ -24,9 +24,11 @@ #include <vector> -#include <guichan/listmodel.hpp> #include <guichan/actionlistener.hpp> +#include <guichan/listmodel.hpp> +#include "scrollarea.h" +#include "table.h" #include "window.h" #include "table.h" @@ -72,6 +74,7 @@ class SkillDialog : public Window, public gcn::ActionListener private: GuiTable mTable;//gcn::ListBox *mSkillListBox; + ScrollArea *skillScrollArea; SkillGuiTableModel *mTableModel; gcn::Label *mPointsLabel; gcn::Button *mIncButton; diff --git a/src/gui/slider.h b/src/gui/slider.h index 1fe668c5..c14c5be9 100644 --- a/src/gui/slider.h +++ b/src/gui/slider.h @@ -24,8 +24,9 @@ #include <guichan/widgets/slider.hpp> -class Image; +#include "../guichanfwd.h" +class Image; /** * Slider widget. Same as the Guichan slider but with custom look. diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp new file mode 100644 index 00000000..a6bb5563 --- /dev/null +++ b/src/gui/speechbubble.cpp @@ -0,0 +1,111 @@ +/* + * The Legend of Mazzeroth + * Copyright (C) 2008, The Legend of Mazzeroth Development Team + * + * This file is part of The Legend of Mazzeroth based on original code + * from The Mana World. + * + * The Legend of Mazzeroth 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 Legend of Mazzeroth 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 Legend of Mazzeroth; 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 "speechbubble.h" + +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +#include "../utils/gettext.h" + +// TODO: Fix windows so that they can each load their own skins without the +// other windows overriding another window's skin. +SpeechBubble::SpeechBubble(): + Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml") +{ + // Height == Top Graphic (14px) + 1 Row of Text (15px) + Bottom Graphic (17px) + 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()); + + // LEEOR / TODO: This causes an exception error. + //moveToBottom(getParent()); + + mSpeechBox->setTextWrapped( "" ); +} + +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) +{ + mSpeechBox->setMinWidth(140); + mSpeechBox->setTextWrapped(mText); + + const int fontHeight = getFont()->getHeight(); + const int numRows = mSpeechBox->getNumberOfRows() + 1; + + if (numRows > 2) + { + // 15 == height of each line of text (based on font heights) + // 14 == speechbubble Top + Bottom graphic pixel heights + setContentSize(mSpeechBox->getMinWidth() + fontHeight, + (numRows * fontHeight) + 6); + mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3, + mSpeechBox->getMinWidth() + 5, + (numRows * fontHeight))); + } + else + { + int width = mCaption->getWidth() + 3; + if (width < getFont()->getWidth(mText)) + width = getFont()->getWidth(mText); + setContentSize(width + fontHeight, (fontHeight * 2) + 6); + mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3, + width, 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..23733813 --- /dev/null +++ b/src/gui/speechbubble.h @@ -0,0 +1,48 @@ +/* + * The Legend of Mazzeroth + * Copyright (C) 2008, The Legend of Mazzeroth Development Team + * + * This file is part of The Legend of Mazzeroth based on original code + * from The Mana World. + * + * The Legend of Mazzeroth 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 Legend of Mazzeroth 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 Legend of Mazzeroth; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LOM_SPEECHBUBBLE_H__ +#define _LOM_SPEECHBUBBLE_H__ + +#include "scrollarea.h" +#include "textbox.h" +#include "window.h" + +class SpeechBubble : public Window +{ + public: + + 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..bd6048f3 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -19,12 +19,11 @@ * 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 "../localplayer.h" @@ -37,11 +36,10 @@ 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); + (windowContainer->getHeight() - 255) / 2, 400, 275); loadWindowState(); // ---------------------- @@ -52,19 +50,19 @@ StatusWindow::StatusWindow(LocalPlayer *player): mGpLabel = new gcn::Label(strprintf(_("Job: %d"), 0)); mJobLvlLabel = 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:"); + mJobXpLabel = new gcn::Label(_("Job:")); mJobXpBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203); mJobValueLabel = new gcn::Label; diff --git a/src/gui/status.h b/src/gui/status.h index 6d360caf..14a7617e 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -33,7 +33,6 @@ class LocalPlayer; class ProgressBar; - /** * The player status dialog. * diff --git a/src/gui/table.cpp b/src/gui/table.cpp index f6678737..7e855523 100644 --- a/src/gui/table.cpp +++ b/src/gui/table.cpp @@ -19,13 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "table.h" +#include <cassert> #include <guichan/graphics.hpp> #include <guichan/actionlistener.hpp> -#include <cassert> - +#include "table.h" class GuiTableActionListener : public gcn::ActionListener { @@ -100,6 +99,7 @@ void GuiTable::setModel(TableModel *new_model) mModel->removeListener(this); } + mModel = new_model; installActionListeners(); @@ -109,7 +109,6 @@ void GuiTable::setModel(TableModel *new_model) } } - void GuiTable::recomputeDimensions() { int rows_nr = mModel->getRows(); @@ -296,7 +295,6 @@ void GuiTable::keyPressed(gcn::KeyEvent& keyEvent) { } - // -- MouseListener notifications void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) { @@ -386,7 +384,6 @@ int GuiTable::getColumnForX(int x) 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..9dde8900 100644 --- a/src/gui/table.h +++ b/src/gui/table.h @@ -31,6 +31,7 @@ #include <guichan/widget.hpp> #include "table_model.h" + #include "../guichanfwd.h" class GuiTableActionListener; diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp index 7bc29b47..e69ee808 100644 --- a/src/gui/table_model.cpp +++ b/src/gui/table_model.cpp @@ -19,10 +19,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "table_model.h" +#include <cstdlib> +#include <guichan/graphics.hpp> #include <guichan/widget.hpp> -#include <cstdlib> + +#include "table_model.h" #include "../utils/dtor.h" @@ -49,14 +51,16 @@ 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 -StaticTableModel::StaticTableModel(int row, int column) : +StaticTableModel::StaticTableModel(int row, int column, + gcn::Color backgroundColor, bool opacity) : mRows(row), mColumns(column), - mHeight(1) + mHeight(1), + mOpaque(opacity), + mBackgroundColor(backgroundColor) { mTableModel.resize(row * column, NULL); mWidths.resize(column, 1); @@ -143,3 +147,42 @@ 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); +} + +void StaticTableModel::drawBackground(gcn::Graphics *graphics) +{ + if (isOpaque()) + { + for (unsigned int i = 0; i < mTableModel.size(); i++) + { + mTableModel[i]->setBackgroundColor(mBackgroundColor); + } + } +} + +void StaticTableModel::setOpaque(bool opaque) +{ + mOpaque = opaque; +} + +bool StaticTableModel::isOpaque() const +{ + return mOpaque; +} + diff --git a/src/gui/table_model.h b/src/gui/table_model.h index d245d7bd..03b69dba 100644 --- a/src/gui/table_model.h +++ b/src/gui/table_model.h @@ -22,12 +22,13 @@ #ifndef TABLE_MODEL_H #define TABLE_MODEL_H -#include "../guichanfwd.h" +#include <set> +#include <vector> +#include <guichan/color.hpp> #include <guichan/gui.hpp> -#include <set> -#include <vector> +#include "../guichanfwd.h" class TableModelListener { @@ -100,7 +101,8 @@ private: class StaticTableModel : public TableModel { public: - StaticTableModel(int width, int height); + StaticTableModel(int width, int height, gcn::Color background = 0xffffff, + bool opacity = true); virtual ~StaticTableModel(); /** @@ -130,17 +132,49 @@ public: */ virtual void resize(); + /** + * 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); + + /** + * Checks if the scroll area is opaque, that is if the scroll area + * displays its background. + * + * @return True if the scroll area is opaque, false otherwise. + */ + virtual bool isOpaque() const; + 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); protected: int mRows, mColumns; int mHeight; + bool mOpaque; std::vector<gcn::Widget *> mTableModel; std::vector<int> mWidths; + + /** + * Holds the background color of the table. + */ + gcn::Color mBackgroundColor; + + /** + * Draws the background of the table, that is + * the area behind the content. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawBackground(gcn::Graphics *graphics); }; #endif /* !defined(TABLE_MODEL_H) */ diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp index 75f0b5a1..ee03c79d 100644 --- a/src/gui/textbox.cpp +++ b/src/gui/textbox.cpp @@ -19,13 +19,13 @@ * 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() { @@ -43,6 +43,8 @@ void TextBox::setTextWrapped(const std::string &text) std::stringstream wrappedStream; std::string::size_type newlinePos, lastNewlinePos = 0; + int minWidth = 0; + int xpos; do { @@ -57,7 +59,7 @@ 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; do { @@ -73,7 +75,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,10 +87,30 @@ 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); + 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()); @@ -97,10 +119,15 @@ void TextBox::setTextWrapped(const std::string &text) { 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..98b60402 100644 --- a/src/gui/textbox.h +++ b/src/gui/textbox.h @@ -24,6 +24,8 @@ #include <guichan/widgets/textbox.hpp> +#include "../guichanfwd.h" + /** * A text box, meant to be used inside a scroll area. Same as the Guichan text * box except this one doesn't have a background or border, instead completely @@ -42,6 +44,19 @@ class TextBox : public gcn::TextBox { * Sets the text after wrapping it to the current width of the widget. */ void setTextWrapped(const std::string &text); + + /** + * Get the minimum text width for the text box. + */ + int getMinWidth() { return mMinWidth; } + + /** + * Set the minimum text width for the text box. + */ + void setMinWidth(int width) { mMinWidth = width; } + + private: + int mMinWidth; }; #endif diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp index f7b02cbf..3369195d 100644 --- a/src/gui/textfield.cpp +++ b/src/gui/textfield.cpp @@ -19,14 +19,14 @@ * 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" @@ -40,7 +40,9 @@ int TextField::instances = 0; ImageRect TextField::skin; TextField::TextField(const std::string& text): - gcn::TextField(text) + gcn::TextField(text), + mNumeric(false), + mListener(0) { setFrameSize(2); @@ -62,6 +64,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++; } } @@ -105,6 +108,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..a2432175 100644 --- a/src/gui/textfield.h +++ b/src/gui/textfield.h @@ -24,7 +24,16 @@ #include <guichan/widgets/textfield.hpp> +#include "../guichanfwd.h" + class ImageRect; +class TextField; + +class TextFieldListener +{ + public: + virtual void listen(const TextField *value) = 0; +}; /** * A text field. @@ -54,13 +63,47 @@ 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 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..c89e55a2 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,9 +30,13 @@ #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" @@ -46,12 +48,12 @@ #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 +65,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 +112,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 +127,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 +183,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 +230,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 +247,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 +281,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..66855b77 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; diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 96c2e95c..67e05bbd 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> @@ -32,6 +30,9 @@ #include "button.h" #include "progressbar.h" #include "scrollarea.h" +#include "updatewindow.h" + +#include "widgets/layout.h" // Curl should be included after Guichan to avoid Windows redefinitions #include <curl/curl.h> @@ -40,11 +41,11 @@ #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,14 +69,13 @@ 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()); if (!fin) { - logger->log("Couldn't load text file: %s", fileName.c_str()); + logger->log(_("Couldn't load text file: %s"), fileName.c_str()); return lines; } @@ -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); @@ -198,7 +193,7 @@ void UpdaterWindow::loadNews() { if (!mMemoryBuffer) { - logger->log("Couldn't load news"); + logger->log(_("Couldn't load news")); return; } @@ -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++; @@ -416,7 +410,7 @@ void UpdaterWindow::download() if (mThread == NULL) { - logger->log("Unable to create 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()); @@ -510,7 +504,7 @@ void UpdaterWindow::logic() } else { - logger->log("%s already here", mCurrentFile.c_str()); + logger->log(_("%s already here"), mCurrentFile.c_str()); } mLineIndex++; } diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 3acbfb7e..6450ece2 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -23,6 +23,7 @@ #define _UPDATERWINDOW_H #include <guichan/actionlistener.hpp> + #include <string> #include <vector> diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index ff0883f7..326a7189 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -19,17 +19,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "viewport.h" +#include <cassert> #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" @@ -37,15 +38,13 @@ #include "../textmanager.h" #include "../resources/animation.h" -#include "../resources/monsterinfo.h" -#include "../resources/resourcemanager.h" #include "../resources/image.h" #include "../resources/imageset.h" +#include "../resources/monsterinfo.h" +#include "../resources/resourcemanager.h" #include "../utils/tostring.h" -#include <cassert> - extern volatile int tick_time; Viewport::Viewport(): @@ -70,76 +69,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 +92,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 +173,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 +216,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics) Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) { + (*i)->drawSpeech(graphics, -(int) mPixelViewX, -(int) mPixelViewY); (*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY); } @@ -276,8 +227,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics) WindowContainer::draw(gcnGraphics); } -void -Viewport::logic() +void Viewport::logic() { WindowContainer::logic(); @@ -294,49 +244,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 +258,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,11 +269,11 @@ 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))) { @@ -382,11 +294,9 @@ Viewport::mousePressed(gcn::MouseEvent &event) { Being *being; 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 +310,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 +363,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..5ed40166 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -26,8 +26,9 @@ #include "windowcontainer.h" -#include "../configlistener.h" #include "../being.h" +#include "../configlistener.h" +#include "../guichanfwd.h" class Map; class FloorItem; @@ -35,7 +36,6 @@ class ImageSet; class Item; class PopupMenu; class Graphics; -class SimpleAnimation; /** * The viewport on the map. Displays the current map and handles mouse input @@ -62,97 +62,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,18 +133,6 @@ 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; diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp new file mode 100644 index 00000000..88a12d68 --- /dev/null +++ b/src/gui/widgets/dropdown.cpp @@ -0,0 +1,167 @@ +/* + * 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 "../../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; + +DropDown::DropDown(gcn::ListModel *listModel, + gcn::ScrollArea *scrollArea, + gcn::ListBox *listBox): + gcn::DropDown::DropDown(listModel, + scrollArea, listBox) +{ + 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"); + + // 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); + 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(); + } + + int alpha = getBaseColor().a; + gcn::Color faceColor = getBaseColor(); + faceColor.a = alpha; + gcn::Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + gcn::Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h)); + + graphics->setColor(getForegroundColor()); + 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 se 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..25ae05f8 --- /dev/null +++ b/src/gui/widgets/dropdown.h @@ -0,0 +1,86 @@ +/* + * 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 <iosfwd> + +#include <guichan/widgets/dropdown.hpp> + +#include "../listbox.h" +#include "../scrollarea.h" + +#include "../../guichanfwd.h" + +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); + + /** + * Destructor. + */ + ~DropDown(); + + void draw(gcn::Graphics* graphics); + + void drawFrame(gcn::Graphics* graphics); + + + 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; +}; + +#endif // end DROPDOWN_H + diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index 00689575..4b8bb4da 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -19,10 +19,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "resizegrip.h" - #include <guichan/graphics.hpp> +#include "resizegrip.h" + #include "../../graphics.h" #include "../../resources/image.h" @@ -31,13 +31,13 @@ Image *ResizeGrip::gripImage = 0; int ResizeGrip::mInstances = 0; -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); } mInstances++; @@ -56,8 +56,7 @@ ResizeGrip::~ResizeGrip() } } -void -ResizeGrip::draw(gcn::Graphics *graphics) +void ResizeGrip::draw(gcn::Graphics *graphics) { static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0); } diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h index 5c6ea4bd..7f1329a2 100644 --- a/src/gui/widgets/resizegrip.h +++ b/src/gui/widgets/resizegrip.h @@ -24,6 +24,8 @@ #include <guichan/widget.hpp> +#include "../../guichanfwd.h" + class Image; /** @@ -39,7 +41,7 @@ class ResizeGrip : public gcn::Widget /** * Constructor. */ - ResizeGrip(); + ResizeGrip(std::string image = "graphics/gui/resize.png"); /** * Destructor. diff --git a/src/gui/window.cpp b/src/gui/window.cpp index ed5bb8fc..e0e88b31 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -24,11 +24,12 @@ #include <climits> #include <guichan/exception.hpp> -#include <guichan/widgets/icon.hpp> -#include "window.h" +#include <guichan/widgets/icon.hpp> #include "gui.h" +#include "gccontainer.h" +#include "window.h" #include "windowcontainer.h" #include "widgets/layout.h" @@ -42,24 +43,28 @@ #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; +// for_each(Window::border.grid, Window::border.grid + 9, +// std::bind2nd(std::mem_fun(&Image::setAlpha), +// config.getValue("guialpha", 0.8))); } }; -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 +77,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 +127,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 +151,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(); } } @@ -524,6 +520,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 == "") + 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 != "") + { + 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..deaf984c 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..a3e80223 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -24,6 +24,8 @@ #include <guichan/widgets/container.hpp> +#include "../guichanfwd.h" + /** * A window container. This container adds functionality for more convenient * widget (windows in particular) destruction. |