From 732d52d4fcb3a1ae644e6d82b2b69fbfa2efaf51 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Sun, 5 Jun 2005 18:17:04 +0000 Subject: Using custom focus handler to work around problem with multiple widgets requesting modal focus using a stack based approach. --- src/Makefile.am | 6 +++-- src/gui/focushandler.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++ src/gui/focushandler.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++ src/gui/gui.cpp | 5 ++++ src/gui/gui.h | 1 + src/gui/inttextbox.cpp | 10 +++----- src/gui/inttextbox.h | 44 ++++++++++++++++++++++---------- src/gui/window.cpp | 14 ---------- src/gui/window.h | 1 - src/gui/windowcontainer.h | 3 +++ 10 files changed, 177 insertions(+), 36 deletions(-) create mode 100644 src/gui/focushandler.cpp create mode 100644 src/gui/focushandler.h diff --git a/src/Makefile.am b/src/Makefile.am index 85878bbb..2c579825 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,8 @@ tmw_SOURCES = graphic/spriteset.cpp \ gui/confirm_dialog.h \ gui/equipment.cpp \ gui/equipment.h \ + gui/focushandler.cpp \ + gui/focushandler.h \ gui/gui.cpp \ gui/gui.h \ gui/help.cpp \ @@ -142,7 +144,7 @@ INCLUDES = \ -DTMW_DATADIR=\""$(pkgdatadir)/"\" # the library search path. -tmw_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) -lguichan_sdl -lguichan `pkg-config --libs libxml-2.0` +tmw_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) `pkg-config --libs libxml-2.0` tmw_CXXFLAGS = -Wall $(OPENGL_CFLAGS) $(LIBSDL_CFLAGS) `pkg-config --cflags libxml-2.0` -tmw_LDADD = $(LIBSDL_LIBS) -lguichan $(OPENGL_LIBS) -lphysfs +tmw_LDADD = $(LIBSDL_LIBS) -lguichan_sdl -lguichan $(OPENGL_LIBS) -lphysfs tmw_TARGET = tmw diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp new file mode 100644 index 00000000..94d54f50 --- /dev/null +++ b/src/gui/focushandler.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 "focushandler.h" + + +void FocusHandler::requestModalFocus(gcn::Widget *widget) +{ + /* If there is another widget with modal focus, remove its modal focus + * and put it on the modal widget stack. + */ + if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget) + { + modalStack.push_front(mModalFocusedWidget); + mModalFocusedWidget = NULL; + } + + gcn::FocusHandler::requestModalFocus(widget); +} + +void FocusHandler::releaseModalFocus(gcn::Widget *widget) +{ + modalStack.remove(widget); + + if (mModalFocusedWidget == widget) + { + gcn::FocusHandler::releaseModalFocus(widget); + + /* Check if there were any previously modal widgets that'd still like + * to regain their modal focus. + */ + if (modalStack.size() > 0) + { + gcn::FocusHandler::requestModalFocus(modalStack.front()); + modalStack.pop_front(); + } + } +} + +void FocusHandler::remove(gcn::Widget *widget) +{ + releaseModalFocus(widget); + + gcn::FocusHandler::remove(widget); +} diff --git a/src/gui/focushandler.h b/src/gui/focushandler.h new file mode 100644 index 00000000..39eda8bb --- /dev/null +++ b/src/gui/focushandler.h @@ -0,0 +1,64 @@ +/* + * 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_FOCUSHANDLER_H +#define _TMW_FOCUSHANDLER_H + +#include + +/** + * The focus handler. This focus handler does exactly the same as the Guichan + * focus handler, but keeps a stack of modal widgets to be able to handle + * multiple modal focus requests. + */ +class FocusHandler : public gcn::FocusHandler +{ + public: + /** + * Sets modal focus to a widget. When there is already a modal widget + * then that widget loses modal focus and will regain it after this + * widget releases his modal focus. + */ + void requestModalFocus(gcn::Widget *widget); + + /** + * Releases modal focus of a widget. When this widget had modal focus + * and there are other widgets that had also requested modal focus, + * then modal focus will be transfered to the last of those. + */ + void releaseModalFocus(gcn::Widget *widget); + + /** + * Removes a widget from the focus handler. Also makes sure no dangling + * pointers remain in modal focus stack. + */ + void remove(gcn::Widget *widget); + + private: + /** + * Stack of widgets that have requested modal forcus. + */ + std::list modalStack; +}; + +#endif diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index e3b5a0bb..73e77073 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -24,6 +24,7 @@ #include "gui.h" #include "window.h" #include "windowcontainer.h" +#include "focushandler.h" #include "../engine.h" #include "../net/protocol.h" #include "../main.h" @@ -60,6 +61,10 @@ Gui::Gui(Graphics *graphics) gcn::Image::setImageLoader(imageLoader); + // Set focus handler + delete mFocusHandler; + mFocusHandler = new FocusHandler(); + // Initialize top GUI widget guiTop = new WindowContainer(); guiTop->setDimension(gcn::Rectangle(0, 0, screen->w, screen->h)); diff --git a/src/gui/gui.h b/src/gui/gui.h index 1c8ccb34..057753d4 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -77,6 +77,7 @@ class Gui : public gcn::Gui, public gcn::MouseListener #endif gcn::ImageLoader *imageLoader; /**< For loading images */ gcn::ImageFont *guiFont; /**< The global GUI font */ + gcn::FocusHandler *focusHandler; /**< The focus handler */ }; extern Gui *gui; /**< The GUI system */ diff --git a/src/gui/inttextbox.cpp b/src/gui/inttextbox.cpp index e28040d2..16650799 100644 --- a/src/gui/inttextbox.cpp +++ b/src/gui/inttextbox.cpp @@ -23,13 +23,13 @@ #include "inttextbox.h" -IntTextBox::IntTextBox() - : value(0) +IntTextBox::IntTextBox(): + value(0) { } -IntTextBox::IntTextBox(int i) - : value(i) +IntTextBox::IntTextBox(int i): + value(i) { } @@ -72,5 +72,3 @@ void IntTextBox::setInt(int i) setText(s.str()); setCaretPosition(s.str().length() + 1); } - - diff --git a/src/gui/inttextbox.h b/src/gui/inttextbox.h index eda5ff78..c9eec49e 100644 --- a/src/gui/inttextbox.h +++ b/src/gui/inttextbox.h @@ -30,27 +30,45 @@ #include "textbox.h" /** - * IntTextBox - * TextBox which only accepts numbers as input + * TextBox which only accepts numbers as input. */ class IntTextBox : public TextBox { - int min; //min value - int max; //max value - - int value; //current value - - IntTextBox(const std::string&) { } - public: + /** + * Constructor. + */ IntTextBox(); - IntTextBox(int); - void keyPress(const gcn::Key &); + /** + * Constructor, sets initial value. + */ + IntTextBox(int value); + + /** + * Sets the minimum and maximum values of the text box. + */ + void setRange(int minimum, int maximum); - void setRange(int, int); + /** + * Returns the value in the text box. + */ int getInt(); - void setInt(int); + + /** + * Set the value of the text box to the specified value. + */ + void setInt(int value); + + /** + * Responds to key presses. + */ + void keyPress(const gcn::Key &key); + + private: + int min; /**< Minimum value */ + int max; /**< Maximum value */ + int value; /**< Current value */ }; #endif diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 1245c977..980f8270 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -32,7 +32,6 @@ ImageRect Window::border; Window::Window(const std::string& caption, bool modal, Window *parent): gcn::Window(caption), - prevModal(NULL), parent(parent), snapSize(8), modal(modal), @@ -85,9 +84,6 @@ Window::Window(const std::string& caption, bool modal, Window *parent): if (modal) { - gcn::FocusHandler *focusHandler = _getFocusHandler(); - prevModal = focusHandler->getModalFocused(); - focusHandler->releaseModalFocus(prevModal); requestModalFocus(); } } @@ -114,16 +110,6 @@ Window::~Window() config.removeListener("guialpha", this); delete chrome; - - if (hasModalFocus()) - { - releaseModalFocus(); - } - - if (prevModal) - { - prevModal->requestModalFocus(); - } } void Window::setWindowContainer(WindowContainer *wc) diff --git a/src/gui/window.h b/src/gui/window.h index c9fa1f12..95db2f4b 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -153,7 +153,6 @@ class Window : public gcn::Window, public ConfigListener protected: gcn::Container *chrome; /**< Contained container */ - gcn::Widget *prevModal; /**< Previous modal widget */ Window *parent; /**< The parent window */ int snapSize; /**< Snap distance to window edge */ bool modal; /**< Window is modal */ diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h index b0596f33..c2cf59fd 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -53,6 +53,9 @@ class WindowContainer : public gcn::Container { void scheduleDelete(gcn::Widget *widget); protected: + /** + * List of widgets that are scheduled to be deleted. + */ std::list deathList; }; -- cgit v1.2.3-70-g09d2