diff options
author | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2007-04-15 01:22:17 +0000 |
---|---|---|
committer | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2007-04-15 01:22:17 +0000 |
commit | 59c80255ddd1de9698a75c49ec7a6a1b7c4c1069 (patch) | |
tree | 53236090da5c6c6fc92e948e94d4c2859ae163f8 /src | |
parent | a3770925c652e0d2bab15f5bd46fa740345a28d0 (diff) | |
download | mana-59c80255ddd1de9698a75c49ec7a6a1b7c4c1069.tar.gz mana-59c80255ddd1de9698a75c49ec7a6a1b7c4c1069.tar.bz2 mana-59c80255ddd1de9698a75c49ec7a6a1b7c4c1069.tar.xz mana-59c80255ddd1de9698a75c49ec7a6a1b7c4c1069.zip |
Reimplemented window resizing. It is now once again possible to resize windows
using their borders (except for the top one, since that's the title bar for
Guichan) and the resize grip in the bottom right is much easier to grab. Needs
some testing.
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-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 |
7 files changed, 305 insertions, 91 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2dd84177..ed5623fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,8 @@ MARK_AS_ADVANCED(SDL_INCLUDE_DIR) MARK_AS_ADVANCED(SDL_LIBRARY) SET(SRCS + gui/widgets/resizegrip.cpp + gui/widgets/resizegrip.h gui/browserbox.cpp gui/browserbox.h gui/buddywindow.cpp diff --git a/src/Makefile.am b/src/Makefile.am index a71414ed..d491ca4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,7 @@ bin_PROGRAMS = tmw -tmw_SOURCES = gui/browserbox.cpp \ +tmw_SOURCES = gui/widgets/resizegrip.cpp \ + gui/widgets/resizegrip.h \ + gui/browserbox.cpp \ gui/browserbox.h \ gui/buddywindow.cpp \ gui/buddywindow.h \ 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 |