summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Sehmisch <tmw@crushnet.org>2008-07-01 14:51:23 +0000
committerPhilipp Sehmisch <tmw@crushnet.org>2008-07-01 14:51:23 +0000
commitd3ccf6a0b97ce4189eef4fde606cf5b5f93fac14 (patch)
treef4c4e5b1cc87b34d0a3946c3409882ba222e2ad7 /src
parent59c17d5f465ddcf1956e8cdf1aae1dbda0a1431f (diff)
downloadmana-client-d3ccf6a0b97ce4189eef4fde606cf5b5f93fac14.tar.gz
mana-client-d3ccf6a0b97ce4189eef4fde606cf5b5f93fac14.tar.bz2
mana-client-d3ccf6a0b97ce4189eef4fde606cf5b5f93fac14.tar.xz
mana-client-d3ccf6a0b97ce4189eef4fde606cf5b5f93fac14.zip
Ported some GUI improvements from Legend of Mazeroth (GUI skinning via XML files, item descriptions on mouse-over, map names in minimap window, speech bubbles)
Diffstat (limited to 'src')
-rw-r--r--src/being.cpp69
-rw-r--r--src/being.h15
-rw-r--r--src/engine.cpp11
-rw-r--r--src/gui/inventorywindow.cpp60
-rw-r--r--src/gui/inventorywindow.h9
-rw-r--r--src/gui/itemcontainer.cpp41
-rw-r--r--src/gui/itemcontainer.h8
-rw-r--r--src/gui/itempopup.cpp116
-rw-r--r--src/gui/itempopup.h53
-rw-r--r--src/gui/login.cpp21
-rw-r--r--src/gui/minimap.cpp19
-rw-r--r--src/gui/speechbubble.cpp73
-rw-r--r--src/gui/speechbubble.h47
-rw-r--r--src/gui/window.cpp257
-rw-r--r--src/gui/window.h10
15 files changed, 670 insertions, 139 deletions
diff --git a/src/being.cpp b/src/being.cpp
index b984708e..5fa18337 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -39,6 +39,7 @@
#include "resources/iteminfo.h"
#include "gui/gui.h"
+#include "gui/speechbubble.h"
#include "utils/dtor.h"
#include "utils/tostring.h"
@@ -67,12 +68,15 @@ Being::Being(int id, int job, Map *map):
{
setMap(map);
+ mSpeechBubble = new SpeechBubble();
+
if (instances == 0)
{
// Load the emotion set
ResourceManager *rm = ResourceManager::getInstance();
emotionSet = rm->getImageSet("graphics/sprites/emotions.png", 30, 32);
- if (!emotionSet) logger->error("Unable to load emotions!");
+ if (!emotionSet)
+ logger->error("Unable to load emotions!");
}
instances++;
@@ -253,20 +257,17 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY)
}
}
-void
-Being::setDestination(Uint16 destX, Uint16 destY)
+void Being::setDestination(Uint16 destX, Uint16 destY)
{
adjustCourse(mX, mY, destX, destY);
}
-void
-Being::clearPath()
+void Being::clearPath()
{
mPath.clear();
}
-void
-Being::setPath(const Path &path, int mod)
+void Being::setPath(const Path &path, int mod)
{
mPath = path;
mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds
@@ -296,23 +297,20 @@ Being::setPath(const Path &path, int mod)
}
}
-void
-Being::setSprite(int slot, int id, const std::string &color)
+void Being::setSprite(int slot, int id, const std::string &color)
{
assert(slot >= BASE_SPRITE && slot < VECTOREND_SPRITE);
mSpriteIDs[slot] = id;
mSpriteColors[slot] = color;
}
-void
-Being::setSpeech(const std::string &text, Uint32 time)
+void Being::setSpeech(const std::string &text, Uint32 time)
{
mSpeech = text;
mSpeechTime = 500;
}
-void
-Being::takeDamage(int amount)
+void Being::takeDamage(int amount)
{
gcn::Font *font;
std::string damage = amount ? toString(amount) : "miss";
@@ -343,14 +341,12 @@ Being::takeDamage(int amount)
mPx + 16, mPy + 16);
}
-void
-Being::handleAttack()
+void Being::handleAttack()
{
setAction(Being::ATTACK);
}
-void
-Being::setMap(Map *map)
+void Being::setMap(Map *map)
{
// Remove sprite from potential previous map
@@ -373,8 +369,7 @@ Being::setMap(Map *map)
mChildParticleEffects.clear();
}
-void
-Being::controlParticle(Particle *particle)
+void Being::controlParticle(Particle *particle)
{
if (particle)
{
@@ -384,8 +379,7 @@ Being::controlParticle(Particle *particle)
}
}
-void
-Being::setAction(Action action, int attackType)
+void Being::setAction(Action action, int attackType)
{
SpriteAction currentAction = ACTION_INVALID;
switch (action)
@@ -439,8 +433,7 @@ Being::setAction(Action action, int attackType)
}
-void
-Being::setDirection(Uint8 direction)
+void Being::setDirection(Uint8 direction)
{
if (mDirection == direction)
return;
@@ -477,8 +470,7 @@ Being::setDirection(Uint8 direction)
}
}
-void
-Being::nextStep()
+void Being::nextStep()
{
if (mPath.empty())
{
@@ -513,8 +505,7 @@ Being::nextStep()
mSpeedModifier / (32 * 1024);
}
-void
-Being::logic()
+void Being::logic()
{
// Determine whether the being should take another step
if (mAction == WALK && get_elapsed_time(mWalkTime) >= mStepTime)
@@ -563,8 +554,7 @@ Being::logic()
}
}
-void
-Being::draw(Graphics *graphics, int offsetX, int offsetY) const
+void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
{
int px = mPx + offsetX;
int py = mPy + offsetY;
@@ -578,8 +568,7 @@ Being::draw(Graphics *graphics, int offsetX, int offsetY) const
}
}
-void
-Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
+void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
{
if (!mEmotion)
return;
@@ -588,12 +577,11 @@ Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
const int py = mPy + offsetY - 60;
const int emotionIndex = mEmotion - 1;
- if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size())
+ if ( emotionIndex >= 0 && emotionIndex < (int) emotionSet->size() )
graphics->drawImage(emotionSet->get(emotionIndex), px, py);
}
-void
-Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
+void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
{
int px = mPx + offsetX;
int py = mPy + offsetY;
@@ -601,14 +589,17 @@ Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
// Draw speech above this being
if (mSpeechTime > 0)
{
- graphics->setFont(speechFont);
- graphics->setColor(gcn::Color(255, 255, 255));
- graphics->drawText(mSpeech, px + 18, py - 60, gcn::Graphics::CENTER);
+ mSpeechBubble->setPosition(px - 50, py - 80 - (mSpeechBubble->getNumRows()*14) );
+ mSpeechBubble->setText( mSpeech );
+ mSpeechBubble->setVisible(true);
+ }
+ else if (mSpeechTime == 0)
+ {
+ mSpeechBubble->setVisible(false);
}
}
-Being::Type
-Being::getType() const
+Being::Type Being::getType() const
{
return UNKNOWN;
}
diff --git a/src/being.h b/src/being.h
index f4cdc743..9d04f383 100644
--- a/src/being.h
+++ b/src/being.h
@@ -44,6 +44,7 @@ class Map;
class Graphics;
class ImageSet;
class Particle;
+class SpeechBubble;
/**
* A position along a being's path.
@@ -115,10 +116,10 @@ class Being : public Sprite
Uint16 mX, mY; /**< Pixel coordinates of tile center */
Uint8 mEmotion; /**< Currently showing emotion */
Uint8 mEmotionTime; /**< Time until emotion disappears */
- Uint16 mAttackSpeed; /**< Attack speed */
+ Uint16 mAttackSpeed; /**< Attack speed */
Uint16 mWalkTime;
- Action mAction; /**< Action the being is performing */
- Uint16 mJob; /**< Job (player job, npc, monster, ) */
+ Action mAction; /**< Action the being is performing */
+ Uint16 mJob; /**< Job (player job, npc, monster, creature ) */
/**
* Constructor.
@@ -209,7 +210,7 @@ class Being : public Sprite
* Draws the speech text above the being.
*/
void
- drawSpeech(Graphics *graphics, int offsetX, int offsetY);
+ drawSpeech(Graphics* graphics, int offsetX, int offsetY);
/**
* Draws the emotion picture above the being.
@@ -389,8 +390,10 @@ class Being : public Sprite
std::list<Particle *> mChildParticleEffects;
private:
- int
- getOffset(int step) const;
+ int getOffset(int step) const;
+
+ // Speech Bubble components
+ SpeechBubble *mSpeechBubble;
Sint16 mStepX, mStepY;
Uint16 mStepTime;
diff --git a/src/engine.cpp b/src/engine.cpp
index b38ca0a8..e4b25c02 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -91,6 +91,17 @@ void Engine::changeMap(const std::string &mapPath)
if (newMap->hasProperty("minimap"))
{
mapImage = resman->getImage(newMap->getProperty("minimap"));
+
+ // Set the title for the Minimap
+ if (newMap->hasProperty("mapname"))
+ {
+ minimap->setCaption(newMap->getProperty("mapname"));
+ }
+ else
+ {
+ minimap->setCaption("Unknown");
+ logger->log("WARNING: Map file '%s' defines a minimap image but does not define a 'mapname' property", map_path.c_str());
+ }
}
minimap->setMapImage(mapImage);
beingManager->setMap(newMap);
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index bd224cf0..2127442a 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -29,11 +29,13 @@
#include <guichan/widgets/label.hpp>
#include <guichan/widgets/checkbox.hpp>
+#include <guichan/widgets/textbox.hpp>
#include "button.h"
#include "gui.h"
#include "item_amount.h"
#include "itemcontainer.h"
+#include "itempopup.h"
#include "scrollarea.h"
#include "sdlinput.h"
#include "viewport.h"
@@ -53,12 +55,14 @@ InventoryWindow::InventoryWindow():
Window(_("Inventory")),
mSplit(false)
{
- setResizable(true);
+ setResizable(false);
setCloseButton(true);
- setMinWidth(240);
- setMinHeight(172);
+ // LEEOR/TODO: Since this window is not resizable, do we really need to set these
+ // values or can we drop them?
+ setMinWidth(375);
+ setMinHeight(283);
// If you adjust these defaults, don't forget to adjust the trade window's.
- setDefaultSize(115, 25, 368, 326);
+ setDefaultSize(115, 25, 375, 283);
addKeyListener(this);
mUseButton = new Button(_("Use"), "use", this);
@@ -70,28 +74,18 @@ InventoryWindow::InventoryWindow():
mInvenScroll = new ScrollArea(mItems);
- mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
- mItemDescriptionLabel = new gcn::Label(
- strprintf(_("Description: %s"), ""));
- mItemEffectLabel = new gcn::Label(strprintf(_("Effect: %s"), ""));
- mWeightLabel = new gcn::Label(
- strprintf(_("Total Weight: %d - Maximum Weight: %d"), 0, 0));
-
- place(0, 0, mWeightLabel, 4);
- place(0, 1, mInvenScroll, 4).setPadding(3);
- place(0, 2, mItemNameLabel, 4);
- place(0, 3, mItemDescriptionLabel, 4);
- place(0, 4, mItemEffectLabel, 4);
- place(0, 5, mUseButton);
- place(1, 5, mDropButton);
- place(2, 5, mSplitButton);
+ place(0, 0, mInvenScroll, 100).setPadding(3);
+ place(0, 1, mUseButton);
+ place(1, 1, mDropButton);
+ place(2, 1, mSplitButton);
Layout &layout = getLayout();
layout.setColWidth(0, 48);
layout.setColWidth(1, 48);
layout.setColWidth(2, 48);
- layout.setRowHeight(1, Layout::AUTO_SET);
+ layout.setRowHeight(0, Layout::AUTO_SET);
loadWindowState("Inventory");
+
}
void InventoryWindow::logic()
@@ -103,9 +97,7 @@ void InventoryWindow::logic()
updateButtons();
// Update weight information
- mWeightLabel->setCaption(
- strprintf(_("Total Weight: %d - Maximum Weight: %d"),
- player_node->getTotalWeight(), player_node->getMaxWeight()));
+ // mWeightLabel->setCaption(strprintf(_("Total Weight: %d - Maximum Weight: %d"), player_node->getTotalWeight(), player_node->getMaxWeight()));
}
void InventoryWindow::action(const gcn::ActionEvent &event)
@@ -147,21 +139,13 @@ void InventoryWindow::action(const gcn::ActionEvent &event)
void InventoryWindow::valueChanged(const gcn::SelectionEvent &event)
{
Item *item = mItems->getItem();
- ItemInfo const *info = item ? &item->getInfo() : NULL;
-
- mItemNameLabel->setCaption(strprintf(_("Name: %s"),
- info ? info->getName().c_str() : ""));
- mItemEffectLabel->setCaption(strprintf(_("Effect: %s"),
- info ? info->getEffect().c_str() : ""));
- mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"),
- info ? info->getDescription().c_str() : ""));
if (mSplit)
{
- if (item && !item->isEquipment() && item->getQuantity() > 1) {
+ if (item && !item->isEquipment() && item->getQuantity() > 1)
+ {
mSplit = false;
- new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item,
- (item->getQuantity() - 1));
+ new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, (item->getQuantity() - 1));
}
}
}
@@ -174,9 +158,9 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
{
Item *item = mItems->getItem();
- if (!item) {
+ if (!item)
return;
- }
+
/* Convert relative to the window coordinates to absolute screen
* coordinates.
*/
@@ -230,3 +214,7 @@ void InventoryWindow::keyReleased(gcn::KeyEvent &event)
mSplit = false;
}
}
+InventoryWindow::~InventoryWindow()
+{
+
+}
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index 01fb118c..f9ff8ea2 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -84,6 +84,11 @@ class InventoryWindow : public Window,
*/
void valueChanged(const gcn::SelectionEvent &event);
+ /**
+ * Tracks when the mouse exits the window
+ */
+ ~InventoryWindow();
+
private:
void updateButtons(); /**< Updates button states. */
@@ -93,10 +98,6 @@ class InventoryWindow : public Window,
gcn::Button *mUseButton, *mDropButton, *mSplitButton;
gcn::ScrollArea *mInvenScroll; /**< Inventory Scroll Area. */
- gcn::Label *mItemNameLabel;
- gcn::Label *mItemDescriptionLabel;
- gcn::Label *mItemEffectLabel;
- gcn::Label *mWeightLabel;
bool mSplit;
};
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index eddb6011..4c528a16 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -65,6 +65,7 @@ ItemContainer::ItemContainer(Inventory *inventory,
mSelectionStatus(SEL_NONE),
mSwapItems(false)
{
+ mItemPopup = new ItemPopup();
setFocusable(true);
ResourceManager *resman = ResourceManager::getInstance();
@@ -281,14 +282,46 @@ void ItemContainer::mouseReleased(gcn::MouseEvent &event)
mSelectionStatus = SEL_NONE;
}
-int
-ItemContainer::getSlotIndex(const int posX, const int posY) const
+
+// Show ItemTooltip
+void ItemContainer::mouseMoved(gcn::MouseEvent &event)
+{
+ Item *item = mInventory->getItem( getSlotIndex(event.getX(), event.getY() ) );
+
+ if( item )
+ {
+ mItemPopup->setPosition(getParent()->getParent()->getX() + getParent()->getParent()->getWidth(), getParent()->getParent()->getY());
+
+ mItemPopup->setItem(item);
+
+ mItemPopup->setVisible(true);
+ }
+ else
+ {
+ mItemPopup->setVisible(false);
+ }
+}
+
+
+// Show ItemTooltip
+void ItemContainer::mouseEntered(gcn::MouseEvent &event)
+{
+
+}
+
+
+// Hide ItemTooltip
+void ItemContainer::mouseExited(gcn::MouseEvent &event)
+{
+ mItemPopup->setVisible(false);
+}
+
+int ItemContainer::getSlotIndex(const int posX, const int posY) const
{
if (getDimension().isPointInRect(posX, posY))
{
// Takes into account, boxes are overlapping each other.
- return (posY / (BOX_HEIGHT - 1)) * mGridColumns +
- (posX / (BOX_WIDTH - 1));
+ return (posY / (BOX_HEIGHT - 1)) * mGridColumns + (posX / (BOX_WIDTH - 1));
}
return Inventory::NO_SLOT_INDEX;
}
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index fad59171..9ae5c9c2 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -29,6 +29,8 @@
#include <guichan/widget.hpp>
+#include "itempopup.h"
+
#include <list>
class Image;
@@ -133,6 +135,10 @@ class ItemContainer : public gcn::Widget,
*/
void keyAction();
+ void mouseEntered(gcn::MouseEvent &event);
+ void mouseExited(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
+
/**
* Moves the highlight in the direction specified.
*
@@ -167,6 +173,8 @@ class ItemContainer : public gcn::Widget,
bool mSwapItems;
int mDragPosX, mDragPosY;
+ ItemPopup *mItemPopup;
+
typedef std::list<gcn::SelectionListener*> SelectionListenerList;
typedef SelectionListenerList::iterator SelectionListenerIterator;
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
new file mode 100644
index 00000000..cf719f9f
--- /dev/null
+++ b/src/gui/itempopup.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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
+ *
+ * $Id$
+ */
+
+#include "itempopup.h"
+#include <guichan/widgets/label.hpp>
+#include "widgets/layout.h"
+
+#include "gui.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+#include "../resources/iteminfo.h"
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+
+
+ItemPopup::ItemPopup()
+{
+
+ setResizable(false);
+ setTitleBarHeight(0);
+ loadSkin("graphics/gui/gui.xml");
+
+ // Item Name
+ mItemName = new gcn::Label("Label");
+ mItemName->setFont(gui->getFont());
+ mItemName->setPosition(2, 2);
+ mItemName->setWidth(getWidth() - 4);
+
+ // Item Description
+ mItemDesc = new TextBox();
+ mItemDesc->setEditable(false);
+ mItemDescScroll = new ScrollArea(mItemDesc);
+
+ mItemDescScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemDescScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemDescScroll->setDimension(gcn::Rectangle(0, 0, 196, 14));
+ mItemDescScroll->setOpaque(false);
+ mItemDescScroll->setPosition(2, 15);
+
+ // Item Effect
+ mItemEffect = new TextBox();
+ mItemEffect->setEditable(false);
+ mItemEffectScroll = new ScrollArea(mItemEffect);
+
+ mItemEffectScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemEffectScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemEffectScroll->setDimension(gcn::Rectangle(0, 0, 196, 14));
+ mItemEffectScroll->setOpaque(false);
+ mItemEffectScroll->setPosition(2, 35);
+
+ add(mItemName);
+ add(mItemDescScroll);
+ add(mItemEffectScroll);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+
+ mItemDesc->setTextWrapped( "" );
+ mItemEffect->setTextWrapped( "" );
+}
+
+void ItemPopup::setItem(Item *item)
+{
+
+ ItemInfo const *info = item ? &item->getInfo() : NULL;
+
+ mItemName->setCaption(info->getName());
+ mItemDesc->setTextWrapped( info->getDescription() );
+ mItemEffect->setTextWrapped( info->getEffect() );
+
+ int numRowsDesc = mItemDesc->getNumberOfRows();
+ int numRowsEffect = mItemEffect->getNumberOfRows();
+
+ if(info->getEffect() == "")
+ {
+ setContentSize(200, (numRowsDesc * 14) + 30);
+ } else {
+ setContentSize(200, (numRowsDesc * 14) + (numRowsEffect*14) + 30);
+ }
+
+ mItemDescScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsDesc * 14));
+
+ mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsEffect * 14));
+
+ mItemDescScroll->setPosition(2, 20);
+ mItemEffectScroll->setPosition(2, (numRowsDesc * 15) + 25);
+}
+
+unsigned int ItemPopup::getNumRows()
+{
+ return mItemDesc->getNumberOfRows(), mItemEffect->getNumberOfRows();
+}
diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h
new file mode 100644
index 00000000..499b2e0a
--- /dev/null
+++ b/src/gui/itempopup.h
@@ -0,0 +1,53 @@
+/*
+*
+ * 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
+ *
+ * $Id$
+ */
+
+#ifndef _LOM_ITEMPOPUP_H__
+#define _LOM_ITEMPOPUP_H__
+
+#include "textbox.h"
+#include "scrollarea.h"
+#include "window.h"
+
+#include "../item.h"
+
+class ItemPopup : public Window
+ {
+ public:
+
+ ItemPopup();
+
+ void setItem(Item *item);
+ unsigned int getNumRows();
+
+ private:
+ gcn::Label *mItemName;
+ TextBox *mItemDesc;
+ TextBox *mItemEffect;
+ ScrollArea *mItemDescScroll;
+ ScrollArea *mItemEffectScroll;
+
+ };
+
+#endif
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index f1b32d48..72d7ee51 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -40,14 +40,13 @@
#include "../utils/gettext.h"
-LoginDialog::LoginDialog(LoginData *loginData):
- Window(_("Login")), mLoginData(loginData)
+LoginDialog::LoginDialog(LoginData *loginData) : Window(_("Login")), mLoginData(loginData)
{
gcn::Label *userLabel = new gcn::Label(_("Name:"));
gcn::Label *passLabel = new gcn::Label(_("Password:"));
mUserField = new TextField(mLoginData->username);
mPassField = new PasswordField(mLoginData->password);
- mKeepCheck = new CheckBox(_("Keep"), mLoginData->remember);
+ mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember);
mOkButton = new Button(_("Ok"), "ok", this);
mCancelButton = new Button(_("Cancel"), "cancel", this);
mRegisterButton = new Button(_("Register"), "register", this);
@@ -74,9 +73,12 @@ LoginDialog::LoginDialog(LoginData *loginData):
setLocationRelativeTo(getParent());
setVisible(true);
- if (mUserField->getText().empty()) {
+ if (mUserField->getText().empty())
+ {
mUserField->requestFocus();
- } else {
+ }
+ else
+ {
mPassField->requestFocus();
}
@@ -87,8 +89,7 @@ LoginDialog::~LoginDialog()
{
}
-void
-LoginDialog::action(const gcn::ActionEvent &event)
+void LoginDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok" && canSubmit())
{
@@ -116,14 +117,12 @@ LoginDialog::action(const gcn::ActionEvent &event)
}
}
-void
-LoginDialog::keyPressed(gcn::KeyEvent &keyEvent)
+void LoginDialog::keyPressed(gcn::KeyEvent &keyEvent)
{
mOkButton->setEnabled(canSubmit());
}
-bool
-LoginDialog::canSubmit()
+bool LoginDialog::canSubmit()
{
return !mUserField->getText().empty() &&
!mPassField->getText().empty() &&
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index d205338f..4e5664d6 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -36,8 +36,11 @@ Minimap::Minimap():
Window(_("MiniMap")),
mMapImage(NULL)
{
- setDefaultSize(5, 25, 100, 100);
+ setDefaultSize(0, 0, 100, 100);
loadWindowState("MiniMap");
+ // LEEOR: The Window class needs to modified to accept
+ // setAlignment calls.
+ setAlignment(gcn::Graphics::CENTER);
}
Minimap::~Minimap()
@@ -60,7 +63,14 @@ void Minimap::setMapImage(Image *img)
if (mMapImage)
{
mMapImage->setAlpha(0.7);
+ setSize( mMapImage->getWidth() + 6, mMapImage->getHeight() + 23 );
+ setVisible(true);
}
+ else
+ {
+ setVisible(false);
+ }
+
}
void Minimap::draw(gcn::Graphics *graphics)
@@ -69,8 +79,7 @@ void Minimap::draw(gcn::Graphics *graphics)
if (mMapImage != NULL)
{
- static_cast<Graphics*>(graphics)->
- drawImage(mMapImage, getPadding(), getTitleBarHeight());
+ static_cast<Graphics*>(graphics)->drawImage(mMapImage, getPadding(), getTitleBarHeight());
}
Beings &beings = beingManager->getAll();
@@ -92,6 +101,10 @@ void Minimap::draw(gcn::Graphics *graphics)
graphics->setColor(gcn::Color(61, 52, 209));
break;
+ case Being::NPC:
+ graphics->setColor(gcn::Color(255, 255, 0));
+ break;
+
case Being::MONSTER:
graphics->setColor(gcn::Color(209, 52, 61));
break;
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
new file mode 100644
index 00000000..815238b9
--- /dev/null
+++ b/src/gui/speechbubble.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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
+ *
+ * $Id$
+ */
+
+#include "speechbubble.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+SpeechBubble::SpeechBubble()
+{
+ mSpeechBox = new TextBox();
+ mSpeechBox->setEditable(false);
+ mSpeechBox->setOpaque(false);
+
+ mSpeechArea = new ScrollArea(mSpeechBox);
+
+ // Height == Top Graphic (14px) + 1 Row of Text (15px) + Bottom Graphic (17px)
+ setContentSize(135, 46);
+ setTitleBarHeight(0);
+ loadSkin("graphics/gui/speechbubble.xml");
+
+ mSpeechArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setDimension(gcn::Rectangle(4, 15, 130, 28));
+ mSpeechArea->setOpaque(false);
+
+ add(mSpeechArea);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+
+ mSpeechBox->setTextWrapped( "" );
+}
+
+void SpeechBubble::setText(const std::string mText)
+{
+ mSpeechBox->setTextWrapped( mText );
+
+ int numRows = mSpeechBox->getNumberOfRows();
+
+ // 31 == speechbubble Top + Bottom graphic pixel heights
+ // 15 == height of each line of text (based on font heights)
+ setContentSize(135, 31 + (numRows * 15) );
+ mSpeechArea->setDimension(gcn::Rectangle(4, 15, 130, (31 + (numRows * 14)) - 18 ));
+}
+
+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..c4ca9109
--- /dev/null
+++ b/src/gui/speechbubble.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ * $Id$
+ */
+
+#ifndef _LOM_SPEECHBUBBLE_H__
+#define _LOM_SPEECHBUBBLE_H__
+
+#include "textbox.h"
+#include "scrollarea.h"
+#include "window.h"
+
+class SpeechBubble : public Window
+{
+ public:
+
+ SpeechBubble();
+
+ void setText(const std::string mText);
+ void setLocation(int x, int y);
+ unsigned int getNumRows();
+
+ private:
+ TextBox *mSpeechBox;
+ ScrollArea *mSpeechArea;
+};
+
+#endif
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 75288eb5..1e5dff50 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -28,6 +28,8 @@
#include <guichan/exception.hpp>
#include <guichan/widgets/icon.hpp>
+#include <libxml/tree.h>
+
#include "window.h"
#include "gui.h"
@@ -45,21 +47,31 @@
#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;
Image *Window::closeImage = NULL;
+bool mLoaded = false;
+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)));
}
+ */
+
+ void optionChanged(const std::string &)
+ {
+ Window::mAlphaChanged = true;
+ }
};
Window::Window(const std::string& caption, bool modal, Window *parent):
@@ -77,32 +89,20 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
{
logger->log("Window::Window(\"%s\")", caption.c_str());
- if (!windowContainer) {
- throw GCN_EXCEPTION("Window::Window. no windowContainer set");
+ if (!windowContainer)
+ {
+ throw GCN_EXCEPTION("Window::Window(): no windowContainer set");
}
- 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();
+ loadSkin("graphics/gui/gui.xml");
+
+ //if (instances == 0)
+ //{
+ //WindowConfigListener = new WindowConfigListener();
// Send GUI alpha changed for initialization
- windowConfigListener->optionChanged("guialpha");
- config.addListener("guialpha", windowConfigListener);
- }
+ //windowConfigListener->optionChanged("guialpha");
+ //config.addListener("guialpha", windowConfigListener);
+ //}
instances++;
@@ -110,6 +110,8 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
setPadding(3);
setTitleBarHeight(20);
+ setGuiAlpha();
+
// Add this window to the window container
windowContainer->add(this);
@@ -127,7 +129,7 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
Window::~Window()
{
- logger->log("Window::~Window(\"%s\")", getCaption().c_str());
+ logger->log("UNLOAD: Window::~Window(\"%s\")", getCaption().c_str());
std::string const &name = mConfigName;
if (!name.empty())
@@ -161,17 +163,15 @@ Window::~Window()
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();
}
+
+ // Clean up Border images.
+ for( int i = 0; i < 9; i++ )
+ {
+ border[i] = NULL;
+ }
+ delete border;
}
void Window::setWindowContainer(WindowContainer *wc)
@@ -181,9 +181,15 @@ void Window::setWindowContainer(WindowContainer *wc)
void Window::draw(gcn::Graphics *graphics)
{
+ if(mAlphaChanged)
+ setGuiAlpha();
+
+
Graphics *g = static_cast<Graphics*>(graphics);
- g->drawImageRect(0, 0, getWidth(), getHeight(), border);
+ //g->drawImageRect(0, 0, getWidth(), getHeight(), border);
+
+ g->drawImageRect(0, 0, getWidth(), getHeight(), border[0], border[2], border[6], border[8], border[1], border[5], border[7], border[3], border[4]);
// Draw title
if (getTitleBarHeight())
@@ -557,3 +563,184 @@ void Window::reflowLayout(int w, int h)
mLayout = NULL;
setContentSize(w, h);
}
+
+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[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 '%d'.", 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")
+ {
+ // Itarate 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[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[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[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[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[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[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[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[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[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");
+}
diff --git a/src/gui/window.h b/src/gui/window.h
index 9f5969f0..5c81ba6d 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -251,6 +251,11 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
ContainerPlacer getPlacer(int x, int y);
+ /**
+ * Loads a window skin
+ */
+ void Window::loadSkin(const std::string filename);
+
private:
/**
* Determines if the mouse is in a resize area and returns appropriate
@@ -285,7 +290,10 @@ 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 */
+
+ void setGuiAlpha();
+ static bool mAlphaChanged;
+ Image *border[9];
static Image *closeImage; /**< Close Button Image */
/**