diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/inventorywindow.cpp | 7 | ||||
-rw-r--r-- | src/gui/widgets/resizegrip.cpp | 65 | ||||
-rw-r--r-- | src/gui/widgets/resizegrip.h | 61 | ||||
-rw-r--r-- | src/gui/window.cpp | 191 | ||||
-rw-r--r-- | src/gui/window.h | 66 |
5 files changed, 300 insertions, 90 deletions
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index e533c16c..982aaaf3 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -165,8 +165,8 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) if (!item) return; - /* Convert relative to the window coordinates to - * absolute screen coordinates. + /* Convert relative to the window coordinates to absolute screen + * coordinates. */ int mx = event.getX() + getX(); int my = event.getY() + getY(); @@ -178,7 +178,8 @@ void InventoryWindow::mouseDragged(gcn::MouseEvent &event) { int tmpWidth = getWidth(), tmpHeight = getHeight(); Window::mouseDragged(event); - if (getWidth() != tmpWidth || getHeight() != tmpHeight) { + if (getWidth() != tmpWidth || getHeight() != tmpHeight) + { updateWidgets(); } } diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp new file mode 100644 index 00000000..50a6fce4 --- /dev/null +++ b/src/gui/widgets/resizegrip.cpp @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#include "resizegrip.h" + +#include <guichan/graphics.hpp> + +#include "../../graphics.h" + +#include "../../resources/image.h" +#include "../../resources/resourcemanager.h" + +Image *ResizeGrip::gripImage = 0; +int ResizeGrip::mInstances = 0; + +ResizeGrip::ResizeGrip() +{ + if (mInstances == 0) + { + // Load the grip image + ResourceManager *resman = ResourceManager::getInstance(); + gripImage = resman->getImage("graphics/gui/resize.png"); + } + + mInstances++; + + setWidth(gripImage->getWidth() + 2); + setHeight(gripImage->getHeight() + 2); +} + +ResizeGrip::~ResizeGrip() +{ + mInstances--; + + if (mInstances == 0) + { + gripImage->decRef(); + } +} + +void +ResizeGrip::draw(gcn::Graphics *graphics) +{ + dynamic_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0); +} diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h new file mode 100644 index 00000000..04be3db3 --- /dev/null +++ b/src/gui/widgets/resizegrip.h @@ -0,0 +1,61 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_RESIZEGRIP_H +#define _TMW_RESIZEGRIP_H + +#include <guichan/widget.hpp> + +class Image; + +/** + * Resize grip. The resize grip is part of a resizable Window. It relies on the + * fact that uncaught mouse events are automatically routed to the parent + * window. + * + * \ingroup GUI + */ +class ResizeGrip : public gcn::Widget +{ + public: + /** + * Constructor. + */ + ResizeGrip(); + + /** + * Destructor. + */ + ~ResizeGrip(); + + /** + * Draws the resize grip. + */ + void draw(gcn::Graphics *graphics); + + private: + static Image *gripImage; /**< Resize grip image */ + static int mInstances; /**< Number of resize grip instances */ +}; + +#endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 4f26af79..bd3e7eb5 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -24,10 +24,13 @@ #include "window.h" #include <guichan/exception.hpp> +#include <guichan/widgets/icon.hpp> #include "gccontainer.h" #include "windowcontainer.h" +#include "widgets/resizegrip.h" + #include "../configlistener.h" #include "../configuration.h" #include "../graphics.h" @@ -36,11 +39,10 @@ #include "../resources/image.h" #include "../resources/resourcemanager.h" -ConfigListener *Window::windowConfigListener = NULL; -WindowContainer *Window::windowContainer = NULL; +ConfigListener *Window::windowConfigListener = 0; +WindowContainer *Window::windowContainer = 0; int Window::instances = 0; ImageRect Window::border; -Image *Window::resizeGrip; class WindowConfigListener : public ConfigListener { @@ -54,13 +56,13 @@ class WindowConfigListener : public ConfigListener Window::Window(const std::string& caption, bool modal, Window *parent): gcn::Window(caption), + mGrip(0), mParent(parent), mWindowName("window"), - mSnapSize(8), mShowTitle(true), mModal(modal), mResizable(false), - mMouseResize(false), + mMouseResize(0), mSticky(false), mMinWinWidth(100), mMinWinHeight(28), @@ -87,7 +89,6 @@ Window::Window(const std::string& caption, bool modal, Window *parent): 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); - resizeGrip = resman->getImage("graphics/gui/resize.png"); dBorders->decRef(); windowConfigListener = new WindowConfigListener(); // Send GUI alpha changed for initialization @@ -151,10 +152,10 @@ Window::~Window() delete border.grid[6]; delete border.grid[7]; delete border.grid[8]; - resizeGrip->decRef(); } delete mChrome; + delete mGrip; } void Window::setWindowContainer(WindowContainer *wc) @@ -162,22 +163,15 @@ void Window::setWindowContainer(WindowContainer *wc) windowContainer = wc; } -void Window::draw(gcn::Graphics* graphics) +void Window::draw(gcn::Graphics *graphics) { - Graphics *g = (Graphics*)graphics; + Graphics *g = static_cast<Graphics*>(graphics); g->drawImageRect(0, 0, getWidth(), getHeight(), border); - // Draw grip - if (mResizable) - { - g->drawImage(Window::resizeGrip, - getWidth() - resizeGrip->getWidth(), - getHeight() - resizeGrip->getHeight()); - } - // Draw title - if (mShowTitle) { + if (mShowTitle) + { graphics->setFont(getFont()); graphics->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT); } @@ -203,6 +197,37 @@ void Window::setContentSize(int width, int height) setContentHeight(height); } +void Window::setWidth(int width) +{ + gcn::Window::setWidth(width); + + if (mGrip) + { + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + } +} + +void Window::setHeight(int height) +{ + gcn::Window::setHeight(height); + + if (mGrip) + { + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + } +} + +void Window::setDimension(const gcn::Rectangle &dimension) +{ + gcn::Window::setDimension(dimension); + + if (mGrip) + { + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + } +} + void Window::setLocationRelativeTo(gcn::Widget* widget) { int wx, wy; @@ -238,6 +263,19 @@ void Window::setMaxHeight(unsigned int height) void Window::setResizable(bool r) { mResizable = r; + + if (mResizable) + { + mGrip = new ResizeGrip(); + mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); + mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); + gcn::Window::add(mGrip); + } + else + { + delete mGrip; + mGrip = 0; + } } bool Window::isResizable() @@ -250,16 +288,18 @@ void Window::setSticky(bool sticky) mSticky = sticky; } -bool Window::isSticky() { +bool Window::isSticky() +{ return mSticky; } -void Window::setVisible(bool visible) { - if(isSticky()) +void Window::setVisible(bool visible) +{ + if (isSticky()) { gcn::Window::setVisible(true); - } - else + } + else { gcn::Window::setVisible(visible); } @@ -285,15 +325,27 @@ void Window::mousePressed(gcn::MouseEvent &event) // Let Guichan move window to top and figure out title bar drag gcn::Window::mousePressed(event); - int x = event.getX(); - int y = event.getY(); + const int x = event.getX(); + const int y = event.getY(); + mMouseResize = 0; - // Activate resizing if the left mouse button was pressed on the grip - mMouseResize = - isResizable() && - event.getButton() == gcn::MouseEvent::LEFT && - getGripDimension().isPointInRect(x, y) && - !getChildrenArea().isPointInRect(x, y); + // Activate resizing handles as appropriate + if (event.getSource() == this && isResizable() && + event.getButton() == gcn::MouseEvent::LEFT && + !getChildrenArea().isPointInRect(x, y)) + { + mMouseResize |= (x > getWidth() - resizeBorderWidth) ? RIGHT : + (x < resizeBorderWidth) ? LEFT : 0; + mMouseResize |= (y > getHeight() - resizeBorderWidth) ? BOTTOM : + (y < resizeBorderWidth) ? TOP : 0; + } + else if (event.getSource() == mGrip) + { + mDragOffsetX = x + mGrip->getX(); + mDragOffsetY = y + mGrip->getY(); + mMouseResize |= BOTTOM | RIGHT; + mIsMoving = false; + } } void Window::mouseDragged(gcn::MouseEvent &event) @@ -301,20 +353,47 @@ void Window::mouseDragged(gcn::MouseEvent &event) // Let Guichan handle title bar drag gcn::Window::mouseDragged(event); - // Keep guichan window inside screen - int newX = std::max(0, getX()); - int newY = std::max(0, getY()); - newX = std::min(windowContainer->getWidth() - getWidth(), newX); - newY = std::min(windowContainer->getHeight() - getHeight(), newY); - setPosition(newX, newY); + // Keep guichan window inside screen when it may be moved + if (isMovable() && mIsMoving) + { + int newX = std::max(0, getX()); + int newY = std::max(0, getY()); + newX = std::min(windowContainer->getWidth() - getWidth(), newX); + newY = std::min(windowContainer->getHeight() - getHeight(), newY); + setPosition(newX, newY); + } if (mMouseResize && !mIsMoving) { + const int dx = event.getX() - mDragOffsetX + + ((event.getSource() == mGrip) ? mGrip->getX() : 0); + const int dy = event.getY() - mDragOffsetY + + ((event.getSource() == mGrip) ? mGrip->getY() : 0); gcn::Rectangle newDim = getDimension(); - // We're dragging bottom right - newDim.width += event.getX() - mDragOffsetX; - newDim.height += event.getY() - mDragOffsetY; + if (mMouseResize & (TOP | BOTTOM)) + { + int newHeight = newDim.height + ((mMouseResize & TOP) ? -dy : dy); + newDim.height = std::min(mMaxWinHeight, + std::max(mMinWinHeight, newHeight)); + + if (mMouseResize & TOP) + { + newDim.y -= newDim.height - getHeight(); + } + } + + if (mMouseResize & (LEFT | RIGHT)) + { + int newWidth = newDim.width + ((mMouseResize & LEFT) ? -dx : dx); + newDim.width = std::min(mMaxWinWidth, + std::max(mMinWinWidth, newWidth)); + + if (mMouseResize & LEFT) + { + newDim.x -= newDim.width - getWidth(); + } + } // Keep guichan window inside screen (supports resizing any side) if (newDim.x < 0) @@ -336,29 +415,16 @@ void Window::mouseDragged(gcn::MouseEvent &event) newDim.height = windowContainer->getHeight() - newDim.y; } - // Keep the window at least its minimum size - if (newDim.width < mMinWinWidth) - { - newDim.width = mMinWinWidth; - } - else if (newDim.width > mMaxWinWidth) - { - newDim.width = mMaxWinWidth; - } - - if (newDim.height < mMinWinHeight) + // Update mouse offset when dragging bottom or right border + if (mMouseResize & BOTTOM) { - newDim.height = mMinWinHeight; + mDragOffsetY += newDim.height - getHeight(); } - else if (newDim.height > mMaxWinHeight) + if (mMouseResize & RIGHT) { - newDim.height = mMaxWinHeight; + mDragOffsetX += newDim.width - getWidth(); } - // Update mouse offset when dragging bottom or right border - mDragOffsetX += newDim.width - getWidth(); - mDragOffsetY += newDim.height - getHeight(); - // Set the new window and content dimensions setDimension(newDim); const gcn::Rectangle area = getChildrenArea(); @@ -366,15 +432,6 @@ void Window::mouseDragged(gcn::MouseEvent &event) } } -gcn::Rectangle -Window::getGripDimension() -{ - return gcn::Rectangle(getWidth() - resizeGrip->getWidth(), - getHeight() - resizeGrip->getHeight(), - getWidth(), - getHeight()); -} - void Window::loadWindowState() { diff --git a/src/gui/window.h b/src/gui/window.h index 9ac02287..1180d91c 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -30,11 +30,10 @@ class ConfigListener; class GCContainer; -class Image; class ImageRect; +class ResizeGrip; class WindowContainer; - /** * A window. This window can be dragged around and has a title bar. Windows are * invisible by default. @@ -100,6 +99,21 @@ class Window : public gcn::Window void setContentSize(int width, int height); /** + * Sets the width of this window. + */ + void setWidth(int width); + + /** + * Sets the height of this window. + */ + void setHeight(int height); + + /** + * Sets the position and size of this window. + */ + void setDimension(const gcn::Rectangle &dimension); + + /** * Sets the location relative to the given widget. */ void setLocationRelativeTo(gcn::Widget *widget); @@ -168,16 +182,15 @@ class Window : public gcn::Window void scheduleDelete(); /** - * Window dragging and resizing mouse related. These methods also makes - * sure the window is not dragged/resized outside of the screen. + * Starts window resizing when appropriate. */ void mousePressed(gcn::MouseEvent &event); - void mouseDragged(gcn::MouseEvent &event); /** - * Gets the position of the resize grip. + * Implements window resizing and makes sure the window is not + * dragged/resized outside of the screen. */ - gcn::Rectangle getGripDimension(); + void mouseDragged(gcn::MouseEvent &event); /** * Sets the name of the window. This is not the window title. @@ -214,37 +227,50 @@ class Window : public gcn::Window */ virtual void resetToDefaultSize(); + enum ResizeHandles + { + TOP = 0x01, + RIGHT = 0x02, + BOTTOM = 0x04, + LEFT = 0x08 + }; + protected: - GCContainer *mChrome; /**< Contained container */ + GCContainer *mChrome; /**< Contained container */ + ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ std::string mWindowName; /**< Name of the window */ - int mSnapSize; /**< Snap distance to window edge */ bool mShowTitle; /**< Window has a title bar */ bool mModal; /**< Window is modal */ - bool mResizable; /**< Window can be resized */ - bool mMouseResize; /**< Window is being resized */ - bool mSticky; /**< Window resists minimzation */ - int mMinWinWidth; /**< Minimum window width */ - int mMinWinHeight; /**< Minimum window height */ - int mMaxWinWidth; /**< Maximum window width */ - int mMaxWinHeight; /**< Maximum window height */ + bool mResizable; /**< Window can be resized */ + int mMouseResize; /**< Window is being resized */ + bool mSticky; /**< Window resists minimization */ + int mMinWinWidth; /**< Minimum window width */ + int mMinWinHeight; /**< Minimum window height */ + int mMaxWinWidth; /**< Maximum window width */ + int mMaxWinHeight; /**< Maximum window height */ int mDefaultX; /**< Default window X position */ int mDefaultY; /**< Default window Y position */ int mDefaultWidth; /**< Default window width */ int mDefaultHeight; /**< Default window height */ /** The window container windows add themselves to. */ - static WindowContainer* windowContainer; + static WindowContainer *windowContainer; /** - * The config listener that listens to changes relevant to all - * windows + * The config listener that listens to changes relevant to all windows. */ static ConfigListener *windowConfigListener; static int instances; /**< Number of Window instances */ static ImageRect border; /**< The window border and background */ - static Image *resizeGrip; /**< The grip to resize window */ + + /** + * The width of the resize border. Is independent of the actual window + * border width, and determines mostly the size of the corner area + * where two borders are moved at the same time. + */ + static const int resizeBorderWidth = 10; }; #endif |