diff options
author | Andrei Karas <akaras@inbox.ru> | 2011-05-30 20:09:31 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2011-05-30 20:09:31 +0300 |
commit | fc7928bab206892653a5a7279b384f2bcd323ea4 (patch) | |
tree | f1373ab222c03dd2372a4d16d67ee1f1e348d55b | |
parent | d548e9bc6c987a4834ce3d65b33108f55e0f7a2c (diff) | |
download | plus-fc7928bab206892653a5a7279b384f2bcd323ea4.tar.gz plus-fc7928bab206892653a5a7279b384f2bcd323ea4.tar.bz2 plus-fc7928bab206892653a5a7279b384f2bcd323ea4.tar.xz plus-fc7928bab206892653a5a7279b384f2bcd323ea4.zip |
Add guichan files to automake
77 files changed, 19064 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d10d10840..711c803ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,6 +21,83 @@ else manaplus_SOURCES = endif +manaplus_SOURCES += guichan/actionevent.hpp \ + guichan/actionlistener.hpp \ + guichan/basiccontainer.hpp \ + guichan/cliprectangle.hpp \ + guichan/color.hpp \ + guichan/event.hpp \ + guichan/exception.hpp \ + guichan/focushandler.hpp \ + guichan/focuslistener.hpp \ + guichan/font.hpp \ + guichan/graphics.hpp \ + guichan/gui.hpp \ + guichan/image.hpp \ + guichan/imageloader.hpp \ + guichan/input.hpp \ + guichan/key.hpp \ + guichan/keyinput.hpp \ + guichan/keylistener.hpp \ + guichan/listmodel.hpp \ + guichan/mouseevent.hpp \ + guichan/mouseinput.hpp \ + guichan/mouselistener.hpp \ + guichan/platform.hpp \ + guichan/rectangle.hpp \ + guichan/selectionevent.hpp \ + guichan/widget.hpp \ + guichan/widgetlistener.hpp \ + guichan/widgets/button.hpp \ + guichan/widgets/checkbox.hpp \ + guichan/widgets/container.hpp \ + guichan/widgets/dropdown.hpp \ + guichan/widgets/icon.hpp \ + guichan/widgets/imagebutton.hpp \ + guichan/widgets/label.hpp \ + guichan/widgets/listbox.hpp \ + guichan/widgets/radiobutton.hpp \ + guichan/widgets/scrollarea.hpp \ + guichan/widgets/slider.hpp \ + guichan/widgets/tabbedarea.hpp \ + guichan/widgets/tab.hpp \ + guichan/widgets/textbox.hpp \ + guichan/widgets/textfield.hpp \ + guichan/widgets/window.hpp + +manaplus_SOURCES += guichan/actionevent.cpp \ + guichan/basiccontainer.cpp \ + guichan/cliprectangle.cpp \ + guichan/color.cpp \ + guichan/event.cpp \ + guichan/exception.cpp \ + guichan/focushandler.cpp \ + guichan/font.cpp \ + guichan/graphics.cpp \ + guichan/gui.cpp \ + guichan/image.cpp \ + guichan/mouseevent.cpp \ + guichan/mouseinput.cpp \ + guichan/rectangle.cpp \ + guichan/selectionevent.cpp \ + guichan/widget.cpp \ + guichan/widgets/button.cpp \ + guichan/widgets/checkbox.cpp \ + guichan/widgets/container.cpp \ + guichan/widgets/dropdown.cpp \ + guichan/widgets/icon.cpp \ + guichan/widgets/imagebutton.cpp \ + guichan/widgets/label.cpp \ + guichan/widgets/listbox.cpp \ + guichan/widgets/radiobutton.cpp \ + guichan/widgets/scrollarea.cpp \ + guichan/widgets/slider.cpp \ + guichan/widgets/tabbedarea.cpp \ + guichan/widgets/tab.cpp \ + guichan/widgets/textbox.cpp \ + guichan/widgets/textfield.cpp \ + guichan/widgets/window.cpp + manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \ gui/widgets/avatarlistbox.h \ gui/widgets/battletab.cpp \ diff --git a/src/guichan/actionevent.cpp b/src/guichan/actionevent.cpp new file mode 100644 index 000000000..57bca04bb --- /dev/null +++ b/src/guichan/actionevent.cpp @@ -0,0 +1,69 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/actionevent.hpp" + +namespace gcn +{ + ActionEvent::ActionEvent(Widget* source, const std::string& id) + :Event(source), + mId(id) + { + + } + + ActionEvent::~ActionEvent() + { + + } + + const std::string& ActionEvent::getId() const + { + return mId; + } +} + diff --git a/src/guichan/actionevent.hpp b/src/guichan/actionevent.hpp new file mode 100644 index 000000000..c897e9b4b --- /dev/null +++ b/src/guichan/actionevent.hpp @@ -0,0 +1,114 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_ACTIONEVENT_HPP +#define GCN_ACTIONEVENT_HPP + +#include "guichan/event.hpp" +#include "guichan/platform.hpp" + +#include <string> + +namespace gcn +{ + class Widget; + + /** + * Represents an action event. An action event is an event + * that can be fired by a widget whenever an action has occured. + * What exactly an action is is up to the widget that fires + * the action event. An example is a Button which fires an action + * event as soon as the Button is clicked, another example is + * TextField which fires an action event as soon as the enter + * key is pressed. + * + * Any object can listen for actions from widgets by implementing + * the ActionListener interface. + * + * If you have implement a widget of your own it's a good idea to + * let the widget fire action events whenever you feel an action + * has occured so action listeners of the widget can be informed + * of the state of the widget. + * + * @see Widget::addActionListener, Widget::removeActionListener, + * Widget::distributeActionEvent + * @author Olof Naessén + * @since 0.6.0 + */ + class GCN_CORE_DECLSPEC ActionEvent: public Event + { + public: + + /** + * Constructor. + * + * @param source The source widget of the event. + * @param id An identifier of the event. + */ + ActionEvent(Widget* source, const std::string& id); + + /** + * Destructor. + */ + virtual ~ActionEvent(); + + /** + * Gets the identifier of the event. An identifier can + * be used to distinguish from two actions from the same + * widget or to let many widgets fire the same widgets + * that should be treated equally. + * + * @return The identifier of the event. + */ + const std::string& getId() const; + + protected: + /** + * Holds the identifier of the event. + */ + std::string mId; + }; +} + +#endif // GCN_ACTIONEVENT_HPP + diff --git a/src/guichan/actionlistener.hpp b/src/guichan/actionlistener.hpp new file mode 100644 index 000000000..0f750099c --- /dev/null +++ b/src/guichan/actionlistener.hpp @@ -0,0 +1,93 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_ACTIONLISTENER_HPP +#define GCN_ACTIONLISTENER_HPP + +#include <string> + +#include "guichan/actionevent.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * Interface for listening for action events from widgets. + * + * @see Widget::addActionListener, Widget::removeActionListener, + * ActionEvent + * @author Olof Naessén + * @author Per Larsson + */ + class GCN_CORE_DECLSPEC ActionListener + { + public: + + /** + * Destructor. + */ + virtual ~ActionListener() { } + + /** + * Called when an action is recieved from a widget. It is used + * to be able to recieve a notification that an action has + * occured. + * + * @param actionEvent The event of the action. + * @since 0.6.0 + */ + virtual void action(const ActionEvent& actionEvent) = 0; + + protected: + /** + * Constructor. + * + * You should not be able to make an instance of ActionListener, + * therefore its constructor is protected. + */ + ActionListener() { } + + }; +} + +#endif // end GCN_ACTIONLISTENER_HPP diff --git a/src/guichan/basiccontainer.cpp b/src/guichan/basiccontainer.cpp new file mode 100644 index 000000000..85f0b1b2f --- /dev/null +++ b/src/guichan/basiccontainer.cpp @@ -0,0 +1,390 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/basiccontainer.hpp" + +#include <algorithm> + +#include "guichan/exception.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/graphics.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + BasicContainer::~BasicContainer() + { + clear(); + } + + void BasicContainer::moveToTop(Widget* widget) + { + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + if (*iter == widget) + { + mWidgets.erase(iter); + mWidgets.push_back(widget); + return; + } + } + + throw GCN_EXCEPTION("There is no such widget in this container."); + } + + void BasicContainer::moveToBottom(Widget* widget) + { + WidgetListIterator iter; + iter = find(mWidgets.begin(), mWidgets.end(), widget); + + if (iter == mWidgets.end()) + { + throw GCN_EXCEPTION("There is no such widget in this container."); + } + mWidgets.erase(iter); + mWidgets.push_front(widget); + } + + void BasicContainer::death(const Event& event) + { + WidgetListIterator iter; + iter = find(mWidgets.begin(), mWidgets.end(), event.getSource()); + + if (iter == mWidgets.end()) + { + throw GCN_EXCEPTION("There is no such widget in this container."); + } + + mWidgets.erase(iter); + } + + Rectangle BasicContainer::getChildrenArea() + { + return Rectangle(0, 0, getWidth(), getHeight()); + } + + void BasicContainer::focusNext() + { + WidgetListIterator it; + + for (it = mWidgets.begin(); it != mWidgets.end(); it++) + { + if ((*it)->isFocused()) + { + break; + } + } + + WidgetListIterator end = it; + + if (it == mWidgets.end()) + { + it = mWidgets.begin(); + } + + it++; + + for ( ; it != end; it++) + { + if (it == mWidgets.end()) + { + it = mWidgets.begin(); + } + + if ((*it)->isFocusable()) + { + (*it)->requestFocus(); + return; + } + } + } + + void BasicContainer::focusPrevious() + { + WidgetListReverseIterator it; + + for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++) + { + if ((*it)->isFocused()) + { + break; + } + } + + WidgetListReverseIterator end = it; + + it++; + + if (it == mWidgets.rend()) + { + it = mWidgets.rbegin(); + } + + for ( ; it != end; it++) + { + if (it == mWidgets.rend()) + { + it = mWidgets.rbegin(); + } + + if ((*it)->isFocusable()) + { + (*it)->requestFocus(); + return; + } + } + } + + Widget *BasicContainer::getWidgetAt(int x, int y) + { + Rectangle r = getChildrenArea(); + + if (!r.isPointInRect(x, y)) + { + return NULL; + } + + x -= r.x; + y -= r.y; + + WidgetListReverseIterator it; + for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++) + { + if ((*it)->isVisible() && (*it)->getDimension().isPointInRect(x, y)) + { + return (*it); + } + } + + return NULL; + } + + void BasicContainer::logic() + { + logicChildren(); + } + + void BasicContainer::_setFocusHandler(FocusHandler* focusHandler) + { + Widget::_setFocusHandler(focusHandler); + + if (mInternalFocusHandler != NULL) + { + return; + } + + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + (*iter)->_setFocusHandler(focusHandler); + } + } + + void BasicContainer::add(Widget* widget) + { + mWidgets.push_back(widget); + + if (mInternalFocusHandler == NULL) + { + widget->_setFocusHandler(_getFocusHandler()); + } + else + { + widget->_setFocusHandler(mInternalFocusHandler); + } + + widget->_setParent(this); + widget->addDeathListener(this); + } + + void BasicContainer::remove(Widget* widget) + { + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + if (*iter == widget) + { + mWidgets.erase(iter); + widget->_setFocusHandler(NULL); + widget->_setParent(NULL); + widget->removeDeathListener(this); + return; + } + } + + throw GCN_EXCEPTION("There is no such widget in this container."); + } + + void BasicContainer::clear() + { + WidgetListIterator iter; + + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + (*iter)->_setFocusHandler(NULL); + (*iter)->_setParent(NULL); + (*iter)->removeDeathListener(this); + } + + mWidgets.clear(); + } + + void BasicContainer::drawChildren(Graphics* graphics) + { + graphics->pushClipArea(getChildrenArea()); + + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + if ((*iter)->isVisible()) + { + // If the widget has a frame, + // draw it before drawing the widget + if ((*iter)->getFrameSize() > 0) + { + Rectangle rec = (*iter)->getDimension(); + rec.x -= (*iter)->getFrameSize(); + rec.y -= (*iter)->getFrameSize(); + rec.width += 2 * (*iter)->getFrameSize(); + rec.height += 2 * (*iter)->getFrameSize(); + graphics->pushClipArea(rec); + (*iter)->drawFrame(graphics); + graphics->popClipArea(); + } + + graphics->pushClipArea((*iter)->getDimension()); + (*iter)->draw(graphics); + graphics->popClipArea(); + } + } + + graphics->popClipArea(); + } + + void BasicContainer::logicChildren() + { + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + (*iter)->logic(); + } + } + + void BasicContainer::showWidgetPart(Widget* widget, Rectangle area) + { + Rectangle widgetArea = getChildrenArea(); + + area.x += widget->getX(); + area.y += widget->getY(); + + if (area.x + area.width > widgetArea.width) + { + widget->setX(widget->getX() - area.x - area.width + widgetArea.width); + } + + if (area.y + area.height > widgetArea.height) + { + widget->setY(widget->getY() - area.y - area.height + widgetArea.height); + } + + if (area.x < 0) + { + widget->setX(widget->getX() - area.x); + } + + if (area.y < 0) + { + widget->setY(widget->getY() - area.y); + } + } + + + void BasicContainer::setInternalFocusHandler(FocusHandler* focusHandler) + { + Widget::setInternalFocusHandler(focusHandler); + + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + if (mInternalFocusHandler == NULL) + { + (*iter)->_setFocusHandler(_getFocusHandler()); + } + else + { + (*iter)->_setFocusHandler(mInternalFocusHandler); + } + } + } + + Widget* BasicContainer::findWidgetById(const std::string& id) + { + WidgetListIterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + { + if ((*iter)->getId() == id) + { + return (*iter); + } + + BasicContainer *basicContainer = dynamic_cast<BasicContainer*>(*iter); + + if (basicContainer != NULL) + { + Widget *widget = basicContainer->findWidgetById(id); + + if (widget != NULL) + { + return widget; + } + } + } + + return NULL; + } +} diff --git a/src/guichan/basiccontainer.hpp b/src/guichan/basiccontainer.hpp new file mode 100644 index 000000000..7a0b67141 --- /dev/null +++ b/src/guichan/basiccontainer.hpp @@ -0,0 +1,180 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_BASICCONTAINER_HPP +#define GCN_BASICCONTAINER_HPP + +#include <list> + +#include "guichan/deathlistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * A base class for containers. The class implements the most + * common things for a container. If you are implementing a + * container, consider inheriting from this class. + * + * @see Container + * @since 0.6.0 + */ + class GCN_CORE_DECLSPEC BasicContainer : public Widget, public DeathListener + { + public: + /** + * Destructor + */ + virtual ~BasicContainer(); + + /** + * Shows a certain part of a widget in the basic container. + * Used when widgets want a specific part to be visible in + * its parent. An example is a TextArea that wants a specific + * part of its text to be visible when a TextArea is a child + * of a ScrollArea. + * + * @param widget The widget whom wants a specific part of + * itself to be visible. + * @param rectangle The rectangle to be visible. + */ + virtual void showWidgetPart(Widget* widget, Rectangle area); + + + // Inherited from Widget + + virtual void moveToTop(Widget* widget); + + virtual void moveToBottom(Widget* widget); + + virtual Rectangle getChildrenArea(); + + virtual void focusNext(); + + virtual void focusPrevious(); + + virtual void logic(); + + virtual void _setFocusHandler(FocusHandler* focusHandler); + + void setInternalFocusHandler(FocusHandler* focusHandler); + + virtual Widget *getWidgetAt(int x, int y); + + + // Inherited from DeathListener + + virtual void death(const Event& event); + + protected: + /** + * Adds a widget to the basic container. + * + * @param widget The widget to add. + * @see remove, clear + */ + void add(Widget* widget); + + /** + * Removes a widget from the basic container. + * + * @param widget The widget to remove. + * @see add, clear + */ + virtual void remove(Widget* widget); + + /** + * Clears the basic container from all widgets. + * + * @see remove, clear + */ + virtual void clear(); + + /** + * Draws the children widgets of the basic container. + * + * @param graphics A graphics object to draw with. + */ + virtual void drawChildren(Graphics* graphics); + + /** + * Calls logic for the children widgets of the basic + * container. + */ + virtual void logicChildren(); + + /** + * Finds a widget given an id. This function can be useful + * when implementing a GUI generator for Guichan, such as + * the ability to create a Guichan GUI from an XML file. + * + * @param id The id to find a widget by. + * @return The widget with the corrosponding id, + NULL of no widget is found. + */ + virtual Widget* findWidgetById(const std::string& id); + + /** + * Typedef. + */ + typedef std::list<Widget *> WidgetList; + + /** + * Typedef. + */ + typedef WidgetList::iterator WidgetListIterator; + + /** + * Typedef. + */ + typedef WidgetList::reverse_iterator WidgetListReverseIterator; + + /** + * Holds all widgets of the basic container. + */ + WidgetList mWidgets; + }; +} + +#endif // end GCN_BASICCONTAINER_HPP diff --git a/src/guichan/cliprectangle.cpp b/src/guichan/cliprectangle.cpp new file mode 100644 index 000000000..f73df1e84 --- /dev/null +++ b/src/guichan/cliprectangle.cpp @@ -0,0 +1,76 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/cliprectangle.hpp" + +namespace gcn +{ + ClipRectangle::ClipRectangle() + { + x = y = width = height = xOffset = yOffset = 0; + } + + ClipRectangle::ClipRectangle(int x, int y, int width, int height, int xOffset, int yOffset) + { + this->x = x; + this->y = y; + this->width = width; + this->height = height; + this->xOffset = xOffset; + this->yOffset = yOffset; + } + + const ClipRectangle& ClipRectangle::operator=(const Rectangle& other) + { + x = other.x; + y = other.y; + width = other.width; + height = other.height; + + return *this; + } +} diff --git a/src/guichan/cliprectangle.hpp b/src/guichan/cliprectangle.hpp new file mode 100644 index 000000000..792c40bb9 --- /dev/null +++ b/src/guichan/cliprectangle.hpp @@ -0,0 +1,109 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_CLIPRECTANGLE_HPP +#define GCN_CLIPRECTANGLE_HPP + +#include "guichan/rectangle.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * A rectangle used when dealing with clipping. A clip rectangle is + * a regular rectangle extended with variables for x offsets and y + * offsets. The offsets are used for calculations from relative + * screen coordinates to actual screen coordinates. + */ + class GCN_CORE_DECLSPEC ClipRectangle : public Rectangle + { + public: + + /** + * Constructor. + */ + ClipRectangle(); + + /** + * Constructor. + * + * @param x The rectangle x coordinate. + * @param y The rectangle y coordinate. + * @param width The rectangle width. + * @param height The rectangle height. + * @param xOffset The offset of the x coordinate. Used to for + * calculating the actual screen coordinate from + * the relative screen coordinate. + * @param yOffset The offset of the y coordinate. Used to for + * calculating the actual screen coordinate from + * the relative screen coordinate. + */ + ClipRectangle(int x, + int y, + int width, + int height, + int xOffset, + int yOffset); + + /** + * Copy constructor. Copies x, y, width and height + * field from a rectangle to a clip rectangle. + * + * @param other The rectangle to copy data from. + * @returns A clip rectangle with data copyied from a rectangle. + */ + const ClipRectangle& operator=(const Rectangle& other); + + /** + * Holds the x offset of the x coordinate. + */ + int xOffset; + + /** + * Holds the y offset of the y coordinate. + */ + int yOffset; + }; +} + +#endif // end GCN_CLIPRECTANGLE_HPP diff --git a/src/guichan/color.cpp b/src/guichan/color.cpp new file mode 100644 index 000000000..15f9ea0ee --- /dev/null +++ b/src/guichan/color.cpp @@ -0,0 +1,143 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/color.hpp" + +namespace gcn +{ + Color::Color() + : r(0), + g(0), + b(0), + a(255) + { + } + + Color::Color(int color) + : r( (color >> 16) & 0xFF), + g( (color >> 8) & 0xFF), + b( color & 0xFF), + a(255) + { + } + + Color::Color(int ar, int ag, int ab, int aa) + : r(ar), + g(ag), + b(ab), + a(aa) + { + } + + Color Color::operator+(const Color& color) const + { + Color result(r + color.r, + g + color.g, + b + color.b, + 255); + + result.r = (result.r>255?255:(result.r<0?0:result.r)); + result.g = (result.g>255?255:(result.g<0?0:result.g)); + result.b = (result.b>255?255:(result.b<0?0:result.b)); + + return result; + } + + Color Color::operator-(const Color& color) const + { + Color result(r - color.r, + g - color.g, + b - color.b, + 255); + + result.r = (result.r>255?255:(result.r<0?0:result.r)); + result.g = (result.g>255?255:(result.g<0?0:result.g)); + result.b = (result.b>255?255:(result.b<0?0:result.b)); + + return result; + } + + Color Color::operator*(float value) const + { + Color result((int)(r * value), + (int)(g * value), + (int)(b * value), + a); + + result.r = (result.r>255?255:(result.r<0?0:result.r)); + result.g = (result.g>255?255:(result.g<0?0:result.g)); + result.b = (result.b>255?255:(result.b<0?0:result.b)); + + return result; + } + + bool Color::operator==(const Color& color) const + { + return r == color.r && g == color.g && b == color.b && a == color.a; + } + + bool Color::operator!=(const Color& color) const + { + return !(r == color.r && g == color.g && b == color.b && a == color.a); + } + + std::ostream& operator<<(std::ostream& out, + const Color& color) + { + out << "Color [r = " + << color.r + << ", g = " + << color.g + << ", b = " + << color.b + << ", a = " + << color.a + << "]"; + + return out; + } +} diff --git a/src/guichan/color.hpp b/src/guichan/color.hpp new file mode 100644 index 000000000..b7e324c07 --- /dev/null +++ b/src/guichan/color.hpp @@ -0,0 +1,173 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_COLOR_HPP +#define GCN_COLOR_HPP + +#include "guichan/platform.hpp" + +#include <iostream> + +namespace gcn +{ + /** + * Represents a color with red, green, blue and alpha components. + */ + class GCN_CORE_DECLSPEC Color + { + public: + + /** + * Constructor. Initializes the color to black. + */ + Color(); + + /** + * Constructor. Constructs a color from the bytes in an integer. + * Call it with a hexadecimal constant for HTML-style color representation. + * The alpha component is 255 by default. + * + * EXAMPLE: Color(0xff50a0) constructs a very nice pinkish color. + * + * NOTE: Because of this constructor, integers will be automatically + * casted to a color by your compiler. + * + * @param color The color to initialise the object with. + */ + Color(int color); + + /** + * Constructor. The default alpha value is 255. + * + * @param r Red color component (range 0-255). + * @param g Green color component (range 0-255). + * @param b Blue color component (range 0-255). + * @param a Alpha, used for transparency. A value of 0 means + * totaly transparent, 255 is totaly opaque. + */ + Color(int r, int g, int b, int a = 255); + + /** + * Adds the RGB values of two colors together. The values will be + * clamped if they go out of range. + * + * WARNING: This function will reset the alpha value of the + * returned color to 255. + * + * @param color A color to add to this color. + * @return The added colors with an alpha value set to 255. + */ + Color operator+(const Color& color) const; + + /** + * Subtracts the RGB values of one color from another. + * The values will be clamped if they go out of range. + * + * WARNING: This function will reset the alpha value of the + * returned color to 255. + * + * @param color A color to subtract from this color. + * @return The subtracted colors with an alpha value set to 255. + */ + Color operator-(const Color& color) const; + + /** + * Multiplies the RGB values of a color with a float value. + * The values will be clamped if they go out of range. + * + * @param value The value to multiply the color with. + * @return The multiplied colors. The alpha value will, unlike + * the add and subtract operations, be multiplied as + * well. + */ + Color operator*(float value) const; + + /** + * Compares two colors. + * + * @return True if the two colors have the same RGBA components + * false otherwise. + */ + bool operator==(const Color& color) const; + + /** + * Compares two colors. + * + * @return True if the two colors have different RGBA components, + * false otherwise. + */ + bool operator!=(const Color& color) const; + + /** + * Output operator for output. + * + * @param out The stream to output to. + * @param color The color to output. + */ + friend std::ostream& operator<<(std::ostream& out, + const Color& Color); + + /** + * Holds the red color component (range 0-255). + */ + int r; + + /** + * Holds the green color component (range 0-255). + */ + int g; + + /** + * Holds the blue color component (range 0-255). + */ + int b; + + /** + * Holds the alpha color component. A value of 0 means totally + * transparent while a value of 255 is considered opaque. + */ + int a; + }; +} + +#endif // end GCN_COLOR_HPP diff --git a/src/guichan/event.cpp b/src/guichan/event.cpp new file mode 100644 index 000000000..4292d5a3f --- /dev/null +++ b/src/guichan/event.cpp @@ -0,0 +1,68 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/event.hpp" + +namespace gcn +{ + Event::Event(Widget* source) + :mSource(source) + { + + } + + Event::~Event() + { + + } + + Widget* Event::getSource() const + { + return mSource; + } +} + diff --git a/src/guichan/event.hpp b/src/guichan/event.hpp new file mode 100644 index 000000000..107e34fc2 --- /dev/null +++ b/src/guichan/event.hpp @@ -0,0 +1,94 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_EVENT_HPP +#define GCN_EVENT_HPP + +#include "guichan/platform.hpp" + +namespace gcn +{ + class Widget; + + /** + * Base class for all events. All events in Guichan should + * inherit from this class. + * + * @author Olof Naessén + * @since 0.6.0 + */ + class GCN_CORE_DECLSPEC Event + { + public: + + /** + * Constructor. + * + * @param source The source widget of the event. + */ + Event(Widget* source); + + /** + * Destructor. + */ + virtual ~Event(); + + /** + * Gets the source widget of the event. The function + * is used to tell which widget fired an event. + * + * @return The source widget of the event. + */ + Widget* getSource() const; + + + protected: + + /** + * Holds the source widget of the event. + */ + Widget* mSource; + }; +} + +#endif // end GCN_EVENT_HPP diff --git a/src/guichan/exception.cpp b/src/guichan/exception.cpp new file mode 100644 index 000000000..e82a7bf32 --- /dev/null +++ b/src/guichan/exception.cpp @@ -0,0 +1,101 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/exception.hpp" + +namespace gcn +{ + Exception::Exception() + : mFunction("?"), + mMessage(""), + mFilename("?"), + mLine(0) + { + + } + + Exception::Exception(const std::string& message) + : mFunction("?"), + mMessage(message), + mFilename("?"), + mLine(0) + { + + } + + Exception::Exception(const std::string& message, + const std::string& function, + const std::string& filename, + unsigned int line) + : mFunction(function), + mMessage(message), + mFilename(filename), + mLine(line) + { + + } + + const std::string& Exception::getFunction() const + { + return mFunction; + } + + const std::string& Exception::getMessage() const + { + return mMessage; + } + + const std::string& Exception::getFilename() const + { + return mFilename; + } + + unsigned int Exception::getLine() const + { + return mLine; + } +} diff --git a/src/guichan/exception.hpp b/src/guichan/exception.hpp new file mode 100644 index 000000000..3ccf39e20 --- /dev/null +++ b/src/guichan/exception.hpp @@ -0,0 +1,177 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_EXCEPTION_HPP +#define GCN_EXCEPTION_HPP + +#include <string> + +#include "guichan/platform.hpp" + +#ifndef __FUNCTION__ +#define __FUNCTION__ "?" +#endif + +/* + * A macro used to create a standard exception object. + * What it basicly does is that it creates a new exception + * and automatically sets the filename and line number where + * the exception occured by using other compiler macros. + */ +#define GCN_EXCEPTION(mess) gcn::Exception(mess, \ + __FUNCTION__, \ + __FILE__, \ + __LINE__) + +namespace gcn +{ + + /** + * An exception containing a message, a file and a line number + * where the exception occured. Guichan will only throw exceptions + * of this class. + * + * You can use this class for your own exceptions that has + * something to do with a GUI exception. A nifty feature of the + * excpetion class is that it can tell you from which line and + * file it was thrown. To make things easier when throwing + * exceptions there exists a macro for creating exceptions + * which automatically sets the filename and line number. + * + * EXAMPLE: @code + * throw GCN_EXCEPTION("my error message"); + * @endcode + */ + class GCN_CORE_DECLSPEC Exception + { + public: + + /** + * Constructor. + */ + Exception(); + + /** + * Constructor. + * + * @param message The error message of the exception. + */ + Exception(const std::string& message); + + /** + * Constructor. + * + * NOTE: Don't use this constructor. Use the GCN_EXCEPTION macro instead. + * This constructor merely exists for the GCN_EXCEPTION macro to + * use. + * + * @param message The error message of the exception. + * @param function The function name where the exception occured. + * @param filename The name of the file where the exception occured. + * @param line The line number in the source code where the exception + * occured. + */ + Exception(const std::string& message, + const std::string& function, + const std::string& filename, + unsigned int line); + + /** + * Gets the function name where the exception occured. + * + * @return The function name where the exception occured. + */ + const std::string& getFunction() const; + + /** + * Gets the error message of the exception. + * + * @return The error message of the exception. + */ + const std::string& getMessage() const; + + /** + * Gets the filename where the exception occured. + * + * @return The filename where the exception occured. + */ + const std::string& getFilename() const; + + /** + * Gets the line number where the exception occured. + * + * @return The line number where the exception occured. + */ + unsigned int getLine() const; + + protected: + /** + * Holds the name of the function name where the + * exception occured. + */ + std::string mFunction; + + /** + * Holds the error message of the exception. + */ + std::string mMessage; + + /** + * Holds the filename where the exception occured. + */ + std::string mFilename; + + /** + * Holds the line number where the exception occured. + */ + unsigned int mLine; + }; +} + +#endif // end GCN_EXCEPTION_HPP + +/* + * "Final Fantasy XI is the BEST!... It's even better then water!" + * - Astrolite + * I believe it's WoW now days. + */ diff --git a/src/guichan/focushandler.cpp b/src/guichan/focushandler.cpp new file mode 100644 index 000000000..069a72857 --- /dev/null +++ b/src/guichan/focushandler.cpp @@ -0,0 +1,587 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/focushandler.hpp" + +#include "guichan/focuslistener.hpp" +#include "guichan/exception.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + FocusHandler::FocusHandler() + :mFocusedWidget(NULL), + mModalFocusedWidget(NULL), + mModalMouseInputFocusedWidget(NULL), + mDraggedWidget(NULL), + mLastWidgetWithMouse(NULL), + mLastWidgetWithModalFocus(NULL), + mLastWidgetWithModalMouseInputFocus(NULL), + mLastWidgetPressed(NULL) + { + + } + + void FocusHandler::requestFocus(Widget* widget) + { + if (widget == NULL + || widget == mFocusedWidget) + { + return; + } + + unsigned int i = 0; + int toBeFocusedIndex = -1; + for (i = 0; i < mWidgets.size(); ++i) + { + if (mWidgets[i] == widget) + { + toBeFocusedIndex = i; + break; + } + } + + if (toBeFocusedIndex < 0) + { + throw GCN_EXCEPTION("Trying to focus a none existing widget."); + } + + Widget *oldFocused = mFocusedWidget; + + if (oldFocused != widget) + { + mFocusedWidget = mWidgets.at(toBeFocusedIndex); + + if (oldFocused != NULL) + { + Event focusEvent(oldFocused); + distributeFocusLostEvent(focusEvent); + } + + Event focusEvent(mWidgets.at(toBeFocusedIndex)); + distributeFocusGainedEvent(focusEvent); + } + } + + void FocusHandler::requestModalFocus(Widget* widget) + { + if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget) + { + throw GCN_EXCEPTION("Another widget already has modal focus."); + } + + mModalFocusedWidget = widget; + + if (mFocusedWidget != NULL + && !mFocusedWidget->isModalFocused()) + { + focusNone(); + } + } + + void FocusHandler::requestModalMouseInputFocus(Widget* widget) + { + if (mModalMouseInputFocusedWidget != NULL + && mModalMouseInputFocusedWidget != widget) + { + throw GCN_EXCEPTION("Another widget already has modal input focus."); + } + + mModalMouseInputFocusedWidget = widget; + } + + void FocusHandler::releaseModalFocus(Widget* widget) + { + if (mModalFocusedWidget == widget) + { + mModalFocusedWidget = NULL; + } + } + + void FocusHandler::releaseModalMouseInputFocus(Widget* widget) + { + if (mModalMouseInputFocusedWidget == widget) + { + mModalMouseInputFocusedWidget = NULL; + } + } + + Widget* FocusHandler::getFocused() const + { + return mFocusedWidget; + } + + Widget* FocusHandler::getModalFocused() const + { + return mModalFocusedWidget; + } + + Widget* FocusHandler::getModalMouseInputFocused() const + { + return mModalMouseInputFocusedWidget; + } + + void FocusHandler::focusNext() + { + int i; + int focusedWidget = -1; + for (i = 0; i < (int)mWidgets.size(); ++i) + { + if (mWidgets[i] == mFocusedWidget) + { + focusedWidget = i; + } + } + int focused = focusedWidget; + + // i is a counter that ensures that the following loop + // won't get stuck in an infinite loop + i = (int)mWidgets.size(); + do + { + ++focusedWidget; + + if (i==0) + { + focusedWidget = -1; + break; + } + + --i; + + if (focusedWidget >= (int)mWidgets.size()) + { + focusedWidget = 0; + } + + if (focusedWidget == focused) + { + return; + } + } + while (!mWidgets.at(focusedWidget)->isFocusable()); + + if (focusedWidget >= 0) + { + mFocusedWidget = mWidgets.at(focusedWidget); + + Event focusEvent(mFocusedWidget); + distributeFocusGainedEvent(focusEvent); + } + + if (focused >= 0) + { + Event focusEvent(mWidgets.at(focused)); + distributeFocusLostEvent(focusEvent); + } + } + + void FocusHandler::focusPrevious() + { + if (mWidgets.size() == 0) + { + mFocusedWidget = NULL; + return; + } + + int i; + int focusedWidget = -1; + for (i = 0; i < (int)mWidgets.size(); ++i) + { + if (mWidgets[i] == mFocusedWidget) + { + focusedWidget = i; + } + } + int focused = focusedWidget; + + // i is a counter that ensures that the following loop + // won't get stuck in an infinite loop + i = (int)mWidgets.size(); + do + { + --focusedWidget; + + if (i==0) + { + focusedWidget = -1; + break; + } + + --i; + + if (focusedWidget <= 0) + { + focusedWidget = mWidgets.size() - 1; + } + + if (focusedWidget == focused) + { + return; + } + } + while (!mWidgets.at(focusedWidget)->isFocusable()); + + if (focusedWidget >= 0) + { + mFocusedWidget = mWidgets.at(focusedWidget); + Event focusEvent(mFocusedWidget); + distributeFocusGainedEvent(focusEvent); + } + + if (focused >= 0) + { + Event focusEvent(mWidgets.at(focused)); + distributeFocusLostEvent(focusEvent); + } + } + + bool FocusHandler::isFocused(const Widget* widget) const + { + return mFocusedWidget == widget; + } + + void FocusHandler::add(Widget* widget) + { + mWidgets.push_back(widget); + } + + void FocusHandler::remove(Widget* widget) + { + if (isFocused(widget)) + { + mFocusedWidget = NULL; + } + + WidgetIterator iter; + + for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) + { + if ((*iter) == widget) + { + mWidgets.erase(iter); + break; + } + } + + if (mDraggedWidget == widget) + { + mDraggedWidget = NULL; + return; + } + + if (mLastWidgetWithMouse == widget) + { + mLastWidgetWithMouse = NULL; + return; + } + + if (mLastWidgetWithModalFocus == widget) + { + mLastWidgetWithModalFocus = NULL; + return; + } + + if (mLastWidgetWithModalMouseInputFocus == widget) + { + mLastWidgetWithModalMouseInputFocus = NULL; + return; + } + + if (mLastWidgetPressed == widget) + { + mLastWidgetPressed = NULL; + return; + } + } + + void FocusHandler::focusNone() + { + if (mFocusedWidget != NULL) + { + Widget* focused = mFocusedWidget; + mFocusedWidget = NULL; + + Event focusEvent(focused); + distributeFocusLostEvent(focusEvent); + } + } + + void FocusHandler::tabNext() + { + if (mFocusedWidget != NULL) + { + if (!mFocusedWidget->isTabOutEnabled()) + { + return; + } + } + + if (mWidgets.size() == 0) + { + mFocusedWidget = NULL; + return; + } + + int i; + int focusedWidget = -1; + for (i = 0; i < (int)mWidgets.size(); ++i) + { + if (mWidgets[i] == mFocusedWidget) + { + focusedWidget = i; + } + } + int focused = focusedWidget; + bool done = false; + + // i is a counter that ensures that the following loop + // won't get stuck in an infinite loop + i = (int)mWidgets.size(); + do + { + ++focusedWidget; + + if (i==0) + { + focusedWidget = -1; + break; + } + + --i; + + if (focusedWidget >= (int)mWidgets.size()) + { + focusedWidget = 0; + } + + if (focusedWidget == focused) + { + return; + } + + if (mWidgets.at(focusedWidget)->isFocusable() && + mWidgets.at(focusedWidget)->isTabInEnabled() && + (mModalFocusedWidget == NULL || + mWidgets.at(focusedWidget)->isModalFocused())) + { + done = true; + } + } + while (!done); + + if (focusedWidget >= 0) + { + mFocusedWidget = mWidgets.at(focusedWidget); + Event focusEvent(mFocusedWidget); + distributeFocusGainedEvent(focusEvent); + } + + if (focused >= 0) + { + Event focusEvent(mWidgets.at(focused)); + distributeFocusLostEvent(focusEvent); + } + } + + void FocusHandler::tabPrevious() + { + if (mFocusedWidget != NULL) + { + if (!mFocusedWidget->isTabOutEnabled()) + { + return; + } + } + + if (mWidgets.size() == 0) + { + mFocusedWidget = NULL; + return; + } + + int i; + int focusedWidget = -1; + for (i = 0; i < (int)mWidgets.size(); ++i) + { + if (mWidgets[i] == mFocusedWidget) + { + focusedWidget = i; + } + } + int focused = focusedWidget; + bool done = false; + + // i is a counter that ensures that the following loop + // won't get stuck in an infinite loop + i = (int)mWidgets.size(); + do + { + --focusedWidget; + + if (i==0) + { + focusedWidget = -1; + break; + } + + --i; + + if (focusedWidget <= 0) + { + focusedWidget = mWidgets.size() - 1; + } + + if (focusedWidget == focused) + { + return; + } + + if (mWidgets.at(focusedWidget)->isFocusable() && + mWidgets.at(focusedWidget)->isTabInEnabled() && + (mModalFocusedWidget == NULL || + mWidgets.at(focusedWidget)->isModalFocused())) + { + done = true; + } + } + while (!done); + + if (focusedWidget >= 0) + { + mFocusedWidget = mWidgets.at(focusedWidget); + Event focusEvent(mFocusedWidget); + distributeFocusGainedEvent(focusEvent); + } + + if (focused >= 0) + { + Event focusEvent(mWidgets.at(focused)); + distributeFocusLostEvent(focusEvent); + } + } + + void FocusHandler::distributeFocusLostEvent(const Event& focusEvent) + { + Widget* sourceWidget = focusEvent.getSource(); + + std::list<FocusListener*> focusListeners = sourceWidget->_getFocusListeners(); + + // Send the event to all focus listeners of the widget. + for (std::list<FocusListener*>::iterator it = focusListeners.begin(); + it != focusListeners.end(); + ++it) + { + (*it)->focusLost(focusEvent); + } + } + + void FocusHandler::distributeFocusGainedEvent(const Event& focusEvent) + { + Widget* sourceWidget = focusEvent.getSource(); + + std::list<FocusListener*> focusListeners = sourceWidget->_getFocusListeners(); + + // Send the event to all focus listeners of the widget. + for (std::list<FocusListener*>::iterator it = focusListeners.begin(); + it != focusListeners.end(); + ++it) + { + (*it)->focusGained(focusEvent); + } + } + + Widget* FocusHandler::getDraggedWidget() + { + return mDraggedWidget; + } + + void FocusHandler::setDraggedWidget(Widget* draggedWidget) + { + mDraggedWidget = draggedWidget; + } + + Widget* FocusHandler::getLastWidgetWithMouse() + { + return mLastWidgetWithMouse; + } + + void FocusHandler::setLastWidgetWithMouse(Widget* lastWidgetWithMouse) + { + mLastWidgetWithMouse = lastWidgetWithMouse; + } + + Widget* FocusHandler::getLastWidgetWithModalFocus() + { + return mLastWidgetWithModalFocus; + } + + void FocusHandler::setLastWidgetWithModalFocus(Widget* lastWidgetWithModalFocus) + { + mLastWidgetWithModalFocus = lastWidgetWithModalFocus; + } + + Widget* FocusHandler::getLastWidgetWithModalMouseInputFocus() + { + return mLastWidgetWithModalMouseInputFocus; + } + + void FocusHandler::setLastWidgetWithModalMouseInputFocus(Widget* lastWidgetWithModalMouseInputFocus) + { + mLastWidgetWithModalMouseInputFocus = lastWidgetWithModalMouseInputFocus; + } + + Widget* FocusHandler::getLastWidgetPressed() + { + return mLastWidgetPressed; + } + + void FocusHandler::setLastWidgetPressed(Widget* lastWidgetPressed) + { + mLastWidgetPressed = lastWidgetPressed; + } +} diff --git a/src/guichan/focushandler.hpp b/src/guichan/focushandler.hpp new file mode 100644 index 000000000..0e2d84099 --- /dev/null +++ b/src/guichan/focushandler.hpp @@ -0,0 +1,398 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_FOCUSHANDLER_HPP +#define GCN_FOCUSHANDLER_HPP + +#include <vector> + +#include "guichan/event.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Widget; + + /** + * Handles focus for widgets in a Gui. Each Gui has at least one + * focus handler. + + * You will probably not use the focus handler directly as Widget + * has functions that automatically uses the active focus handler. + * + * @see Widget::isFocus, Widget::isModalFocused, + * Widget::isModalMouseInputFocused, Widget::requestFocus, + * Widget::requestModalFocus, Widget::requestModalMouseInputFocus, + * Widget::releaseModalFocus, Widget::relaseModalMouseInputFocus, + * Widget::setFocusable, Widget::isFocusable, FocusListener + * + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC FocusHandler + { + public: + + /** + * Constructor. + */ + FocusHandler(); + + /** + * Destructor. + */ + virtual ~FocusHandler() { }; + + /** + * Requests focus for a widget. Focus will only be granted to a widget + * if it's focusable and if no other widget has modal focus. + * If a widget receives focus a focus event will be sent to the + * focus listeners of the widget. + * + * @param widget The widget to request focus for. + * @see isFocused, Widget::requestFocus + */ + virtual void requestFocus(Widget* widget); + + /** + * Requests modal focus for a widget. Focus will only be granted + * to a widget if it's focusable and if no other widget has modal + * focus. + * + * @param widget The widget to request modal focus for. + * @throws Exception when another widget already has modal focus. + * @see releaseModalFocus, Widget::requestModalFocus + */ + virtual void requestModalFocus(Widget* widget); + + /** + * Requests modal mouse input focus for a widget. Focus will only + * be granted to a widget if it's focusable and if no other widget + * has modal mouse input focus. + * + * Modal mouse input focus means no other widget then the widget with + * modal mouse input focus will receive mouse input. The widget with + * modal mouse input focus will also receive mouse input no matter what + * the mouse input is or where the mouse input occurs. + * + * @param widget The widget to focus for modal mouse input focus. + * @throws Exception when another widget already has modal mouse input + * focus. + * @see releaseModalMouseInputFocus, Widget::requestModalMouseInputFocus + */ + virtual void requestModalMouseInputFocus(Widget* widget); + + /** + * Releases modal focus if the widget has modal focus. + * If the widget doesn't have modal focus no relase will occur. + * + * @param widget The widget to release modal focus for. + * @see reuqestModalFocus, Widget::releaseModalFocus + */ + virtual void releaseModalFocus(Widget* widget); + + /** + * Releases modal mouse input focus if the widget has modal mouse input + * focus. If the widget doesn't have modal mouse input focus no relase + * will occur. + * + * @param widget the widget to release modal mouse input focus for. + * @see requestModalMouseInputFocus, Widget::releaseModalMouseInputFocus + */ + virtual void releaseModalMouseInputFocus(Widget* widget); + + /** + * Checks if a widget is focused. + * + * @param widget The widget to check. + * @return True if the widget is focused, false otherwise. + * @see Widget::isFocused + */ + virtual bool isFocused(const Widget* widget) const; + + /** + * Gets the widget with focus. + * + * @return The widget with focus. NULL if no widget has focus. + */ + virtual Widget* getFocused() const; + + /** + * Gets the widget with modal focus. + * + * @return The widget with modal focus. NULL if no widget has + * modal focus. + */ + virtual Widget* getModalFocused() const; + + /** + * Gets the widget with modal mouse input focus. + * + * @return The widget with modal mouse input focus. NULL if + * no widget has modal mouse input focus. + */ + virtual Widget* getModalMouseInputFocused() const; + + /** + * Focuses the next widget added to a conainer. + * If no widget has focus the first widget gets focus. The order + * in which the widgets are focused is determined by the order + * they were added to a container. + * + * @see focusPrevious + */ + virtual void focusNext(); + + /** + * Focuses the previous widget added to a contaienr. + * If no widget has focus the first widget gets focus. The order + * in which the widgets are focused is determined by the order + * they were added to a container. + * + * @see focusNext + */ + virtual void focusPrevious(); + + /** + * Adds a widget to by handles by the focus handler. + * + * @param widget The widget to add. + * @see remove + */ + virtual void add(Widget* widget); + + /** + * Removes a widget from the focus handler. + * + * @param widget The widget to remove. + * @see add + */ + virtual void remove(Widget* widget); + + /** + * Focuses nothing. A focus event will also be sent to the + * focused widget's focus listeners if a widget has focus. + */ + virtual void focusNone(); + + /** + * Focuses the next widget which allows tabbing in unless + * the current focused Widget disallows tabbing out. + * + * @see tabPrevious + */ + virtual void tabNext(); + + /** + * Focuses the previous widget which allows tabbing in unless + * current focused widget disallows tabbing out. + * + * @see tabNext + */ + virtual void tabPrevious(); + + /** + * Gets the widget being dragged. Used by the Gui class to + * keep track of the dragged widget. + * + * @return the widget being dragged. + * @see setDraggedWidget + */ + virtual Widget* getDraggedWidget(); + + /** + * Sets the widget being dragged. Used by the Gui class to + * keep track of the dragged widget. + * + * @param draggedWidget The widget being dragged. + * @see getDraggedWidget + */ + virtual void setDraggedWidget(Widget* draggedWidget); + + /** + * Gets the last widget with the mouse. Used by the Gui class + * to keep track the last widget with the mouse. + * + * @return The last widget with the mouse. + * @see setLastWidgetWithMouse + */ + virtual Widget* getLastWidgetWithMouse(); + + /** + * Sets the last widget with the mouse. Used by the Gui class + * to keep track the last widget with the mouse. + * + * @param lastWidgetWithMouse The last widget with the mouse. + * @see getLastWidgetWithMouse + */ + virtual void setLastWidgetWithMouse(Widget* lastWidgetWithMouse); + + /** + * Gets the last widget with modal focus. + * + * @return The last widget with modal focus. + * @see setLastWidgetWithModalFocus + */ + virtual Widget* getLastWidgetWithModalFocus(); + + /** + * Sets the last widget with modal focus. + * + * @param lastWidgetWithModalFocus The last widget with modal focus. + * @see getLastWidgetWithModalFocus + */ + virtual void setLastWidgetWithModalFocus(Widget* lastWidgetWithModalFocus); + + /** + * Gets the last widget with modal mouse input focus. + * + * @return The last widget with modal mouse input focus. + * @see setLastWidgetWithModalMouseInputFocus + */ + virtual Widget* getLastWidgetWithModalMouseInputFocus(); + + /** + * Sets the last widget with modal mouse input focus. + * + * @param lastMouseWithModalMouseInputFocus The last widget with + * modal mouse input focus. + * @see getLastWidgetWithModalMouseInputFocus + */ + virtual void setLastWidgetWithModalMouseInputFocus(Widget* lastWidgetWithModalMouseInputFocus); + + /** + * Gets the last widget pressed. Used by the Gui class to keep track + * of pressed widgets. + * + * @return The last widget pressed. + * @see setLastWidgetPressed + */ + virtual Widget* getLastWidgetPressed(); + + /** + * Sets the last widget pressed. Used by the Gui class to keep track + * of pressed widgets. + * + * @param lastWidgetPressed The last widget pressed. + * @see getLastWidgetPressed + */ + virtual void setLastWidgetPressed(Widget* lastWidgetPressed); + + protected: + /** + * Distributes a focus lost event. + * + * @param focusEvent the event to distribute. + * @since 0.7.0 + */ + virtual void distributeFocusLostEvent(const Event& focusEvent); + + /** + * Distributes a focus gained event. + * + * @param focusEvent the event to distribute. + * @since 0.7.0 + */ + virtual void distributeFocusGainedEvent(const Event& focusEvent); + + /** + * Typedef. + */ + typedef std::vector<Widget*> WidgetVector; + + /** + * Typedef. + */ + typedef WidgetVector::iterator WidgetIterator; + + /** + * Holds the widgets currently being handled by the + * focus handler. + */ + WidgetVector mWidgets; + + /** + * Holds the focused widget. NULL if no widget has focus. + */ + Widget* mFocusedWidget; + + /** + * Holds the modal focused widget. NULL if no widget has + * modal focused. + */ + Widget* mModalFocusedWidget; + + /** + * Holds the modal mouse input focused widget. NULL if no widget + * is being dragged. + */ + Widget* mModalMouseInputFocusedWidget; + + /** + * Holds the dragged widget. NULL if no widget is + * being dragged. + */ + Widget* mDraggedWidget; + + /** + * Holds the last widget with the mouse. + */ + Widget* mLastWidgetWithMouse; + + /** + * Holds the last widget with modal focus. + */ + Widget* mLastWidgetWithModalFocus; + + /** + * Holds the last widget with modal mouse input focus. + */ + Widget* mLastWidgetWithModalMouseInputFocus; + + /** + * Holds the last widget pressed. + */ + Widget* mLastWidgetPressed; + }; +} + +#endif // end GCN_FOCUSHANDLER_HPP diff --git a/src/guichan/focuslistener.hpp b/src/guichan/focuslistener.hpp new file mode 100644 index 000000000..418a6859b --- /dev/null +++ b/src/guichan/focuslistener.hpp @@ -0,0 +1,95 @@ +/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ *
+ *
+ * Per Larsson a.k.a finalman
+ * Olof Naessén a.k.a jansem/yakslem
+ *
+ * Visit: http://guichan.sourceforge.net
+ *
+ * License: (BSD)
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Guichan nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GCN_FOCUSLISTENER_HPP
+#define GCN_FOCUSLISTENER_HPP
+
+#include <string>
+
+#include "guichan/event.hpp"
+#include "guichan/platform.hpp"
+
+namespace gcn
+{
+ /**
+ * Interface for listening for focus events from widgets.
+ *
+ * @see Widget::addFocusListener, Widget::removeFocusListener
+ * @author Olof Naessén
+ * @since 0.7.0
+ */
+ class GCN_CORE_DECLSPEC FocusListener
+ {
+ public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~FocusListener() { }
+
+ /**
+ * Called when a widget gains focus.
+ *
+ * @param event Discribes the event.
+ */
+ virtual void focusGained(const Event& event) { };
+
+ /**
+ * Called when a widget loses focus.
+ *
+ * @param event Discribes the event.
+ */
+ virtual void focusLost(const Event& event) { };
+
+ protected:
+ /**
+ * Constructor.
+ *
+ * You should not be able to make an instance of FocusListener,
+ * therefore its constructor is protected.
+ */
+ FocusListener() { }
+ };
+}
+
+#endif // end GCN_FOCUSLISTENER_HPP
diff --git a/src/guichan/font.cpp b/src/guichan/font.cpp new file mode 100644 index 000000000..5583cdb57 --- /dev/null +++ b/src/guichan/font.cpp @@ -0,0 +1,71 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/font.hpp" + +#include <string> + +namespace gcn +{ + int Font::getStringIndexAt(const std::string& text, int x) const + { + unsigned int i; + int size = 0; + + for (i = 0; i < text.size(); ++i) + { + size = getWidth(text.substr(0,i)); + + if (size > x) + { + return i; + } + } + + return text.size(); + } +} diff --git a/src/guichan/font.hpp b/src/guichan/font.hpp new file mode 100644 index 000000000..cda4028b8 --- /dev/null +++ b/src/guichan/font.hpp @@ -0,0 +1,111 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_FONT_HPP +#define GCN_FONT_HPP + +#include <string> +#include "guichan/platform.hpp" + +namespace gcn +{ + class Graphics; + + /** + * Interface for a font. + * + * @see ImageFont + */ + class GCN_CORE_DECLSPEC Font + { + public: + + /** + * Destructor. + */ + virtual ~Font(){ } + + /** + * Gets the width of a string. The width of a string is not necesserily + * the sum of all the widths of it's glyphs. + * + * @param text The string to return the width of. + * @return The width of a string. + */ + virtual int getWidth(const std::string& text) const = 0; + + /** + * Gets the height of the glyphs in the font. + * + * @return The height of the glyphs int the font. + */ + virtual int getHeight() const = 0; + + /** + * Gets a string index in a string providing an x coordinate. + * Used to retrive a string index (for a character in a + * string) at a certain x position. It is especially useful + * when a mouse clicks in a TextField and you want to know which + * character was clicked. + * + * @return A string index in a string providing an x coordinate. + */ + virtual int getStringIndexAt(const std::string& text, int x) const; + + /** + * Draws a string. + * + * NOTE: You normally won't use this function to draw text since + * Graphics contains better functions for drawing text. + * + * @param graphics A Graphics object to use for drawing. + * @param text The string to draw. + * @param x The x coordinate where to draw the string. + * @param y The y coordinate where to draw the string. + */ + virtual void drawString(Graphics* graphics, const std::string& text, + int x, int y) = 0; + }; +} + +#endif // end GCN_FONT_HPP diff --git a/src/guichan/graphics.cpp b/src/guichan/graphics.cpp new file mode 100644 index 000000000..688362c12 --- /dev/null +++ b/src/guichan/graphics.cpp @@ -0,0 +1,187 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/graphics.hpp" + +#include "guichan/exception.hpp" +#include "guichan/font.hpp" +#include "guichan/image.hpp" + +namespace gcn +{ + + Graphics::Graphics() + { + mFont = NULL; + } + + bool Graphics::pushClipArea(Rectangle area) + { + // Ignore area with a negate width or height + // by simple pushing an empty clip area + // to the stack. + if (area.width < 0 || area.height < 0) + { + ClipRectangle carea; + mClipStack.push(carea); + return true; + } + + if (mClipStack.empty()) + { + ClipRectangle carea; + carea.x = area.x; + carea.y = area.y; + carea.width = area.width; + carea.height = area.height; + carea.xOffset = area.x; + carea.yOffset = area.y; + mClipStack.push(carea); + return true; + } + + const ClipRectangle &top = mClipStack.top(); + ClipRectangle carea; + carea = area; + carea.xOffset = top.xOffset + carea.x; + carea.yOffset = top.yOffset + carea.y; + carea.x += top.xOffset; + carea.y += top.yOffset; + + // Clamp the pushed clip rectangle. + if (carea.x < top.x) + { + carea.x = top.x; + } + + if (carea.y < top.y) + { + carea.y = top.y; + } + + if (carea.x + carea.width > top.x + top.width) + { + carea.width = top.x + top.width - carea.x; + + if (carea.width < 0) + { + carea.width = 0; + } + } + + if (carea.y + carea.height > top.y + top.height) + { + carea.height = top.y + top.height - carea.y; + + if (carea.height < 0) + { + carea.height = 0; + } + } + + bool result = carea.isIntersecting(top); + + mClipStack.push(carea); + + return result; + } + + void Graphics::popClipArea() + { + + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("Tried to pop clip area from empty stack."); + } + + mClipStack.pop(); + } + + const ClipRectangle& Graphics::getCurrentClipArea() + { + if (mClipStack.empty()) + { + throw GCN_EXCEPTION("The clip area stack is empty."); + } + + return mClipStack.top(); + } + + void Graphics::drawImage(const Image* image, int dstX, int dstY) + { + drawImage(image, 0, 0, dstX, dstY, image->getWidth(), image->getHeight()); + } + + void Graphics::setFont(Font* font) + { + mFont = font; + } + + void Graphics::drawText(const std::string& text, int x, int y, + Alignment alignment) + { + if (mFont == NULL) + { + throw GCN_EXCEPTION("No font set."); + } + + switch (alignment) + { + case LEFT: + mFont->drawString(this, text, x, y); + break; + case CENTER: + mFont->drawString(this, text, x - mFont->getWidth(text) / 2, y); + break; + case RIGHT: + mFont->drawString(this, text, x - mFont->getWidth(text), y); + break; + default: + throw GCN_EXCEPTION("Unknown alignment."); + } + } +} diff --git a/src/guichan/graphics.hpp b/src/guichan/graphics.hpp new file mode 100644 index 000000000..d21eab24b --- /dev/null +++ b/src/guichan/graphics.hpp @@ -0,0 +1,291 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_GRAPHICS_HPP +#define GCN_GRAPHICS_HPP + +#include <iosfwd> +#include <stack> + +#include "guichan/cliprectangle.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Color; + class Font; + class Image; + + /** + * Abstract class for providing drawing primitve functions. + * It contains all vital functions for drawing. + * + * Guichan contains implementations of Graphics for common + * libraries like the Allegro library, the HGE library, + * the OpenGL library, the OpenLayer library, and the SDL library. + * To make Guichan usable with other libraries, a Graphics class + * must be implemented. + * + * In Graphics you can set clip areas to limit drawing to certain + * areas of the screen. Clip areas are put on a stack, which + * means that you can push smaller and smaller clip areas onto the + * stack. All coordinates will be relative to the top most clip area. + * In most cases you won't have to worry about the clip areas, + * unless you want to implement some really complex widget. + * Pushing and poping of clip areas are handled automatically by + * container widgets when their child widgets are drawn. + * + * IMPORTANT: Remember to pop each clip area that you pushed on the stack + * after you are done with it. + * + * If you feel that Graphics is to restrictive for your needs, + * there is no one stopping you from using your own code for drawing + * in widgets. You could for instance use pure SDL in the drawing of + * widgets bypassing Graphics. This might however hurt portability of + * your application. + * + * If you implement a Graphics class not present in Guichan we would + * be very happy to add it to Guichan. + * + * @see AllegroGraphics, HGEGraphics, OpenLayerGraphics, OpenGLGraphics, + * SDLGraphics, Image + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC Graphics + { + public: + /** + * Alignments for text drawing. + */ + enum Alignment + { + LEFT = 0, + CENTER, + RIGHT + }; + + /** + * Constructor. + */ + Graphics(); + + /** + * Destructor. + */ + virtual ~Graphics() { } + + /** + * Initializes drawing. Called by the Gui when Gui::draw() is called. + * It is needed by some implementations of Graphics to perform + * preparations before drawing. An example of such an implementation + * is the OpenGLGraphics. + * + * NOTE: You will never need to call this function yourself, unless + * you use a Graphics object outside of Guichan. + * + * @see _endDraw, Gui::draw + */ + virtual void _beginDraw() { } + + /** + * Deinitializes drawing. Called by the Gui when a Gui::draw() is done. + * done. It should reset any state changes made by _beginDraw(). + * + * NOTE: You will never need to call this function yourself, unless + * you use a Graphics object outside of Guichan. + * + * @see _beginDraw, Gui::draw + */ + virtual void _endDraw() { } + + /** + * Pushes a clip area onto the stack. The x and y coordinates in the + * rectangle is relative to the last pushed clip area. + * If the new area falls outside the current clip area, it will be + * clipped as necessary. + * + * If a clip area is outside of the top clip area a clip area with + * zero width and height will be pushed. + * + * @param area The clip area to be pushed onto the stack. + * @return False if the the new area lays outside the current clip + * area. + */ + virtual bool pushClipArea(Rectangle area); + + /** + * Removes the top most clip area from the stack. + * + * @throws Exception if the stack is empty. + */ + virtual void popClipArea(); + + /** + * Gets the current clip area. Usefull if you want to do drawing + * bypassing Graphics. + * + * @return The current clip area. + */ + virtual const ClipRectangle& getCurrentClipArea(); + + /** + * Draws a part of an image. + * + * NOTE: Width and height arguments will not scale the image but + * specifies the size of the part to be drawn. If you want + * to draw the whole image there is a simplified version of + * this function. + * + * EXAMPLE: @code drawImage(myImage, 10, 10, 20, 20, 40, 40); @endcode + * Will draw a rectangular piece of myImage starting at + * coordinate (10, 10) in myImage, with width and height 40. + * The piece will be drawn with it's top left corner at + * coordinate (20, 20). + * + * @param image The image to draw. + * @param srcX The source image x coordinate. + * @param srcY The source image y coordinate. + * @param dstX The destination x coordinate. + * @param dstY The destination y coordinate. + * @param width The width of the piece. + * @param height The height of the piece. + */ + virtual void drawImage(const Image* image, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height) = 0; + /** + * Draws an image. A simplified version of the other drawImage. + * It will draw a whole image at the coordinate you specify. + * It is equivalent to calling: + * @code drawImage(myImage, 0, 0, dstX, dstY, image->getWidth(), \ + image->getHeight()); @endcode + */ + virtual void drawImage(const Image* image, int dstX, int dstY); + + /** + * Draws a single point/pixel. + * + * @param x The x coordinate. + * @param y The y coordinate. + */ + virtual void drawPoint(int x, int y) = 0; + + /** + * Ddraws a line. + * + * @param x1 The first x coordinate. + * @param y1 The first y coordinate. + * @param x2 The second x coordinate. + * @param y2 The second y coordinate. + */ + virtual void drawLine(int x1, int y1, int x2, int y2) = 0; + + /** + * Draws a simple, non-filled, rectangle with a one pixel width. + * + * @param rectangle The rectangle to draw. + */ + virtual void drawRectangle(const Rectangle& rectangle) = 0; + + /** + * Draws a filled rectangle. + * + * @param rectangle The filled rectangle to draw. + */ + virtual void fillRectangle(const Rectangle& rectangle) = 0; + + /** + * Sets the color to use when drawing. + * + * @param color A color. + * @see getColor + */ + virtual void setColor(const Color& color) = 0; + + /** + * Gets the color to use when drawing. + * + * @return The color used when drawing. + * @see setColor + */ + virtual const Color& getColor() const = 0; + + /** + * Sets the font to use when drawing text. + * + * @param font The font to use when drawing. + */ + virtual void setFont(Font* font); + + /** + * Draws text. + * + * @param text The text to draw. + * @param x The x coordinate where to draw the text. + * @param y The y coordinate where to draw the text. + * @param alignment The alignemnt to use when drawing. + * @throws Exception when no font has been set. + */ + virtual void drawText(const std::string& text, + int x, + int y, + Alignment alignment = LEFT); + + protected: + /** + * Holds the clip area stack. + */ + std::stack<ClipRectangle> mClipStack; + + /** + * Holds the current font. + */ + Font* mFont; + }; +} + +#endif // end GCN_GRAPHICS_HPP diff --git a/src/guichan/gui.cpp b/src/guichan/gui.cpp new file mode 100644 index 000000000..ae9adea13 --- /dev/null +++ b/src/guichan/gui.cpp @@ -0,0 +1,995 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/gui.hpp" + +#include "guichan/basiccontainer.hpp" +#include "guichan/exception.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/graphics.hpp" +#include "guichan/input.hpp" +#include "guichan/keyinput.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/mouseinput.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + Gui::Gui() + :mTop(NULL), + mGraphics(NULL), + mInput(NULL), + mTabbing(true), + mShiftPressed(false), + mMetaPressed(false), + mControlPressed(false), + mAltPressed(false), + mLastMousePressButton(0), + mLastMousePressTimeStamp(0), + mLastMouseX(0), + mLastMouseY(0), + mClickCount(1), + mLastMouseDragButton(0) + { + mFocusHandler = new FocusHandler(); + } + + Gui::~Gui() + { + if (Widget::widgetExists(mTop)) + { + setTop(NULL); + } + + delete mFocusHandler; + } + + void Gui::setTop(Widget* top) + { + if (mTop != NULL) + { + mTop->_setFocusHandler(NULL); + } + if (top != NULL) + { + top->_setFocusHandler(mFocusHandler); + } + + mTop = top; + } + + Widget* Gui::getTop() const + { + return mTop; + } + + void Gui::setGraphics(Graphics* graphics) + { + mGraphics = graphics; + } + + Graphics* Gui::getGraphics() const + { + return mGraphics; + } + + void Gui::setInput(Input* input) + { + mInput = input; + } + + Input* Gui::getInput() const + { + return mInput; + } + + void Gui::logic() + { + if (mTop == NULL) + { + throw GCN_EXCEPTION("No top widget set"); + } + + handleModalFocus(); + handleModalMouseInputFocus(); + + if (mInput != NULL) + { + mInput->_pollInput(); + + handleKeyInput(); + handleMouseInput(); + + } // end if + + mTop->logic(); + } + + void Gui::draw() + { + if (mTop == NULL) + { + throw GCN_EXCEPTION("No top widget set"); + } + if (mGraphics == NULL) + { + throw GCN_EXCEPTION("No graphics set"); + } + + if (!mTop->isVisible()) + { + return; + } + + mGraphics->_beginDraw(); + + // If top has a frame, + // draw it before drawing top + if (mTop->getFrameSize() > 0) + { + Rectangle rec = mTop->getDimension(); + rec.x -= mTop->getFrameSize(); + rec.y -= mTop->getFrameSize(); + rec.width += 2 * mTop->getFrameSize(); + rec.height += 2 * mTop->getFrameSize(); + mGraphics->pushClipArea(rec); + mTop->drawFrame(mGraphics); + mGraphics->popClipArea(); + } + + mGraphics->pushClipArea(mTop->getDimension()); + mTop->draw(mGraphics); + mGraphics->popClipArea(); + + mGraphics->_endDraw(); + } + + void Gui::focusNone() + { + mFocusHandler->focusNone(); + } + + void Gui::setTabbingEnabled(bool tabbing) + { + mTabbing = tabbing; + } + + bool Gui::isTabbingEnabled() + { + return mTabbing; + } + + void Gui::addGlobalKeyListener(KeyListener* keyListener) + { + mKeyListeners.push_back(keyListener); + } + + void Gui::removeGlobalKeyListener(KeyListener* keyListener) + { + mKeyListeners.remove(keyListener); + } + + void Gui::handleMouseInput() + { + while (!mInput->isMouseQueueEmpty()) + { + MouseInput mouseInput = mInput->dequeueMouseInput(); + + // Save the current mouse state. It will be needed if modal focus + // changes or modal mouse input focus changes. + mLastMouseX = mouseInput.getX(); + mLastMouseY = mouseInput.getY(); + + switch (mouseInput.getType()) + { + case MouseInput::PRESSED: + handleMousePressed(mouseInput); + break; + case MouseInput::RELEASED: + handleMouseReleased(mouseInput); + break; + case MouseInput::MOVED: + handleMouseMoved(mouseInput); + break; + case MouseInput::WHEEL_MOVED_DOWN: + handleMouseWheelMovedDown(mouseInput); + break; + case MouseInput::WHEEL_MOVED_UP: + handleMouseWheelMovedUp(mouseInput); + break; + default: + throw GCN_EXCEPTION("Unknown mouse input type."); + break; + } + } + } + + void Gui::handleKeyInput() + { + while (!mInput->isKeyQueueEmpty()) + { + KeyInput keyInput = mInput->dequeueKeyInput(); + + // Save modifiers state + mShiftPressed = keyInput.isShiftPressed(); + mMetaPressed = keyInput.isMetaPressed(); + mControlPressed = keyInput.isControlPressed(); + mAltPressed = keyInput.isAltPressed(); + + KeyEvent keyEventToGlobalKeyListeners(NULL, + mShiftPressed, + mControlPressed, + mAltPressed, + mMetaPressed, + keyInput.getType(), + keyInput.isNumericPad(), + keyInput.getKey()); + + distributeKeyEventToGlobalKeyListeners(keyEventToGlobalKeyListeners); + + // If a global key listener consumes the event it will not be + // sent further to the source of the event. + if (keyEventToGlobalKeyListeners.isConsumed()) + { + continue; + } + + bool keyEventConsumed = false; + + // Send key inputs to the focused widgets + if (mFocusHandler->getFocused() != NULL) + { + KeyEvent keyEvent(getKeyEventSource(), + mShiftPressed, + mControlPressed, + mAltPressed, + mMetaPressed, + keyInput.getType(), + keyInput.isNumericPad(), + keyInput.getKey()); + + + if (!mFocusHandler->getFocused()->isFocusable()) + { + mFocusHandler->focusNone(); + } + else + { + distributeKeyEvent(keyEvent); + } + + keyEventConsumed = keyEvent.isConsumed(); + } + + // If the key event hasn't been consumed and + // tabbing is enable check for tab press and + // change focus. + if (!keyEventConsumed + && mTabbing + && keyInput.getKey().getValue() == Key::TAB + && keyInput.getType() == KeyInput::PRESSED) + { + if (keyInput.isShiftPressed()) + { + mFocusHandler->tabPrevious(); + } + else + { + mFocusHandler->tabNext(); + } + } + + } // end while + } + + void Gui::handleMouseMoved(const MouseInput& mouseInput) + { + // Check if the mouse leaves the application window. + if (!mWidgetWithMouseQueue.empty() + && (mouseInput.getX() < 0 + || mouseInput.getY() < 0 + || !mTop->getDimension().isPointInRect(mouseInput.getX(), mouseInput.getY())) + ) + { + // Distribute an event to all widgets in the "widget with mouse" queue. + while (!mWidgetWithMouseQueue.empty()) + { + Widget* widget = mWidgetWithMouseQueue.front(); + + if (Widget::widgetExists(widget)) + { + distributeMouseEvent(widget, + MouseEvent::EXITED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY(), + true, + true); + } + + mWidgetWithMouseQueue.pop_front(); + } + + return; + } + + // Check if there is a need to send mouse exited events by + // traversing the "widget with mouse" queue. + bool widgetWithMouseQueueCheckDone = mWidgetWithMouseQueue.empty(); + while (!widgetWithMouseQueueCheckDone) + { + unsigned int iterations = 0; + std::deque<Widget*>::iterator iter; + for (iter = mWidgetWithMouseQueue.begin(); + iter != mWidgetWithMouseQueue.end(); + iter++) + { + Widget* widget = *iter; + + // If a widget in the "widget with mouse queue" doesn't + // exists anymore it should be removed from the queue. + if (!Widget::widgetExists(widget)) + { + mWidgetWithMouseQueue.erase(iter); + break; + } + else + { + int x, y; + widget->getAbsolutePosition(x, y); + + if (x > mouseInput.getX() + || y > mouseInput.getY() + || x + widget->getWidth() <= mouseInput.getX() + || y + widget->getHeight() <= mouseInput.getY() + || !widget->isVisible()) + { + distributeMouseEvent(widget, + MouseEvent::EXITED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY(), + true, + true); + mClickCount = 1; + mLastMousePressTimeStamp = 0; + mWidgetWithMouseQueue.erase(iter); + break; + } + } + + iterations++; + } + + widgetWithMouseQueueCheckDone = iterations == mWidgetWithMouseQueue.size(); + } + + // Check all widgets below the mouse to see if they are + // present in the "widget with mouse" queue. If a widget + // is not then it should be added and an entered event should + // be sent to it. + Widget* parent = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + Widget* widget = parent; + + // If a widget has modal mouse input focus then it will + // always be returned from getMouseEventSource, but we only wan't to send + // mouse entered events if the mouse has actually entered the widget with + // modal mouse input focus, hence we need to check if that's the case. If + // it's not we should simply ignore to send any mouse entered events. + if (mFocusHandler->getModalMouseInputFocused() != NULL + && widget == mFocusHandler->getModalMouseInputFocused() + && Widget::widgetExists(widget)) + { + int x, y; + widget->getAbsolutePosition(x, y); + + if (x > mouseInput.getX() + || y > mouseInput.getY() + || x + widget->getWidth() <= mouseInput.getX() + || y + widget->getHeight() <= mouseInput.getY()) + { + parent = NULL; + } + } + + while (parent != NULL) + { + parent = (Widget*)widget->getParent(); + + // Check if the widget is present in the "widget with mouse" queue. + bool widgetIsPresentInQueue = false; + std::deque<Widget*>::iterator iter; + for (iter = mWidgetWithMouseQueue.begin(); + iter != mWidgetWithMouseQueue.end(); + iter++) + { + if (*iter == widget) + { + widgetIsPresentInQueue = true; + break; + } + } + + // Widget is not present, send an entered event and add + // it to the "widget with mouse" queue. + if (!widgetIsPresentInQueue + && Widget::widgetExists(widget)) + { + distributeMouseEvent(widget, + MouseEvent::ENTERED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY(), + true, + true); + mWidgetWithMouseQueue.push_front(widget); + } + + Widget* swap = widget; + widget = parent; + parent = (Widget*)swap->getParent(); + } + + if (mFocusHandler->getDraggedWidget() != NULL) + { + distributeMouseEvent(mFocusHandler->getDraggedWidget(), + MouseEvent::DRAGGED, + mLastMouseDragButton, + mouseInput.getX(), + mouseInput.getY()); + } + else + { + Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + distributeMouseEvent(sourceWidget, + MouseEvent::MOVED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + } + } + + void Gui::handleMousePressed(const MouseInput& mouseInput) + { + Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + + if (mFocusHandler->getDraggedWidget() != NULL) + { + sourceWidget = mFocusHandler->getDraggedWidget(); + } + + int sourceWidgetX, sourceWidgetY; + sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); + + if ((mFocusHandler->getModalFocused() != NULL + && sourceWidget->isModalFocused()) + || mFocusHandler->getModalFocused() == NULL) + { + sourceWidget->requestFocus(); + } + + if (mouseInput.getTimeStamp() - mLastMousePressTimeStamp < 250 + && mLastMousePressButton == mouseInput.getButton()) + { + mClickCount++; + } + else + { + mClickCount = 1; + } + + distributeMouseEvent(sourceWidget, + MouseEvent::PRESSED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + + mFocusHandler->setLastWidgetPressed(sourceWidget); + + mFocusHandler->setDraggedWidget(sourceWidget); + mLastMouseDragButton = mouseInput.getButton(); + + mLastMousePressButton = mouseInput.getButton(); + mLastMousePressTimeStamp = mouseInput.getTimeStamp(); + } + + void Gui::handleMouseWheelMovedDown(const MouseInput& mouseInput) + { + Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + + if (mFocusHandler->getDraggedWidget() != NULL) + { + sourceWidget = mFocusHandler->getDraggedWidget(); + } + + int sourceWidgetX, sourceWidgetY; + sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); + + distributeMouseEvent(sourceWidget, + MouseEvent::WHEEL_MOVED_DOWN, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + } + + void Gui::handleMouseWheelMovedUp(const MouseInput& mouseInput) + { + Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + + if (mFocusHandler->getDraggedWidget() != NULL) + { + sourceWidget = mFocusHandler->getDraggedWidget(); + } + + int sourceWidgetX, sourceWidgetY; + sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); + + distributeMouseEvent(sourceWidget, + MouseEvent::WHEEL_MOVED_UP, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + } + + void Gui::handleMouseReleased(const MouseInput& mouseInput) + { + Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); + + if (mFocusHandler->getDraggedWidget() != NULL) + { + if (sourceWidget != mFocusHandler->getLastWidgetPressed()) + { + mFocusHandler->setLastWidgetPressed(NULL); + } + + sourceWidget = mFocusHandler->getDraggedWidget(); + } + + int sourceWidgetX, sourceWidgetY; + sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); + + distributeMouseEvent(sourceWidget, + MouseEvent::RELEASED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + + if (mouseInput.getButton() == mLastMousePressButton + && mFocusHandler->getLastWidgetPressed() == sourceWidget) + { + distributeMouseEvent(sourceWidget, + MouseEvent::CLICKED, + mouseInput.getButton(), + mouseInput.getX(), + mouseInput.getY()); + + mFocusHandler->setLastWidgetPressed(NULL); + } + else + { + mLastMousePressButton = 0; + mClickCount = 0; + } + + if (mFocusHandler->getDraggedWidget() != NULL) + { + mFocusHandler->setDraggedWidget(NULL); + } + } + + Widget* Gui::getWidgetAt(int x, int y) + { + // If the widget's parent has no child then we have found the widget.. + Widget* parent = mTop; + Widget* child = mTop; + + while (child != NULL) + { + Widget* swap = child; + int parentX, parentY; + parent->getAbsolutePosition(parentX, parentY); + child = parent->getWidgetAt(x - parentX, y - parentY); + parent = swap; + } + + return parent; + } + + Widget* Gui::getMouseEventSource(int x, int y) + { + Widget* widget = getWidgetAt(x, y); + + if (mFocusHandler->getModalMouseInputFocused() != NULL + && !widget->isModalMouseInputFocused()) + { + return mFocusHandler->getModalMouseInputFocused(); + } + + return widget; + } + + Widget* Gui::getKeyEventSource() + { + Widget* widget = mFocusHandler->getFocused(); + + while (widget->_getInternalFocusHandler() != NULL + && widget->_getInternalFocusHandler()->getFocused() != NULL) + { + widget = widget->_getInternalFocusHandler()->getFocused(); + } + + return widget; + } + + void Gui::distributeMouseEvent(Widget* source, + int type, + int button, + int x, + int y, + bool force, + bool toSourceOnly) + { + Widget* parent = source; + Widget* widget = source; + + if (mFocusHandler->getModalFocused() != NULL + && !widget->isModalFocused() + && !force) + { + return; + } + + if (mFocusHandler->getModalMouseInputFocused() != NULL + && !widget->isModalMouseInputFocused() + && !force) + { + return; + } + + MouseEvent mouseEvent(source, + mShiftPressed, + mControlPressed, + mAltPressed, + mMetaPressed, + type, + button, + x, + y, + mClickCount); + + while (parent != NULL) + { + // If the widget has been removed due to input + // cancel the distribution. + if (!Widget::widgetExists(widget)) + { + break; + } + + parent = (Widget*)widget->getParent(); + + if (widget->isEnabled() || force) + { + int widgetX, widgetY; + widget->getAbsolutePosition(widgetX, widgetY); + + mouseEvent.mX = x - widgetX; + mouseEvent.mY = y - widgetY; + + std::list<MouseListener*> mouseListeners = widget->_getMouseListeners(); + + // Send the event to all mouse listeners of the widget. + for (std::list<MouseListener*>::iterator it = mouseListeners.begin(); + it != mouseListeners.end(); + ++it) + { + switch (mouseEvent.getType()) + { + case MouseEvent::ENTERED: + (*it)->mouseEntered(mouseEvent); + break; + case MouseEvent::EXITED: + (*it)->mouseExited(mouseEvent); + break; + case MouseEvent::MOVED: + (*it)->mouseMoved(mouseEvent); + break; + case MouseEvent::PRESSED: + (*it)->mousePressed(mouseEvent); + break; + case MouseEvent::RELEASED: + (*it)->mouseReleased(mouseEvent); + break; + case MouseEvent::WHEEL_MOVED_UP: + (*it)->mouseWheelMovedUp(mouseEvent); + break; + case MouseEvent::WHEEL_MOVED_DOWN: + (*it)->mouseWheelMovedDown(mouseEvent); + break; + case MouseEvent::DRAGGED: + (*it)->mouseDragged(mouseEvent); + break; + case MouseEvent::CLICKED: + (*it)->mouseClicked(mouseEvent); + break; + default: + throw GCN_EXCEPTION("Unknown mouse event type."); + } + } + + if (toSourceOnly) + { + break; + } + + } + + Widget* swap = widget; + widget = parent; + parent = (Widget*)swap->getParent(); + + // If a non modal focused widget has been reach + // and we have modal focus cancel the distribution. + if (mFocusHandler->getModalFocused() != NULL + && !widget->isModalFocused()) + { + break; + } + + // If a non modal mouse input focused widget has been reach + // and we have modal mouse input focus cancel the distribution. + if (mFocusHandler->getModalMouseInputFocused() != NULL + && !widget->isModalMouseInputFocused()) + { + break; + } + } + } + + void Gui::distributeKeyEvent(KeyEvent& keyEvent) + { + Widget* parent = keyEvent.getSource(); + Widget* widget = keyEvent.getSource(); + + if (mFocusHandler->getModalFocused() != NULL + && !widget->isModalFocused()) + { + return; + } + + if (mFocusHandler->getModalMouseInputFocused() != NULL + && !widget->isModalMouseInputFocused()) + { + return; + } + + while (parent != NULL) + { + // If the widget has been removed due to input + // cancel the distribution. + if (!Widget::widgetExists(widget)) + { + break; + } + + parent = (Widget*)widget->getParent(); + + if (widget->isEnabled()) + { + std::list<KeyListener*> keyListeners = widget->_getKeyListeners(); + + // Send the event to all key listeners of the source widget. + for (std::list<KeyListener*>::iterator it = keyListeners.begin(); + it != keyListeners.end(); + ++it) + { + switch (keyEvent.getType()) + { + case KeyEvent::PRESSED: + (*it)->keyPressed(keyEvent); + break; + case KeyEvent::RELEASED: + (*it)->keyReleased(keyEvent); + break; + default: + throw GCN_EXCEPTION("Unknown key event type."); + } + } + } + + Widget* swap = widget; + widget = parent; + parent = (Widget*)swap->getParent(); + + // If a non modal focused widget has been reach + // and we have modal focus cancel the distribution. + if (mFocusHandler->getModalFocused() != NULL + && !widget->isModalFocused()) + { + break; + } + } + } + + void Gui::distributeKeyEventToGlobalKeyListeners(KeyEvent& keyEvent) + { + KeyListenerListIterator it; + + for (it = mKeyListeners.begin(); it != mKeyListeners.end(); it++) + { + switch (keyEvent.getType()) + { + case KeyEvent::PRESSED: + (*it)->keyPressed(keyEvent); + break; + case KeyEvent::RELEASED: + (*it)->keyReleased(keyEvent); + break; + default: + throw GCN_EXCEPTION("Unknown key event type."); + } + + if (keyEvent.isConsumed()) + { + break; + } + } + } + + void Gui::handleModalMouseInputFocus() + { + // Check if modal mouse input focus has been gained by a widget. + if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() + != mFocusHandler->getModalMouseInputFocused()) + && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() == NULL)) + { + handleModalFocusGained(); + mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused()); + } + // Check if modal mouse input focus has been released. + else if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() + != mFocusHandler->getModalMouseInputFocused()) + && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() != NULL)) + { + handleModalFocusReleased(); + mFocusHandler->setLastWidgetWithModalMouseInputFocus(NULL); + } + } + + void Gui::handleModalFocus() + { + // Check if modal focus has been gained by a widget. + if ((mFocusHandler->getLastWidgetWithModalFocus() + != mFocusHandler->getModalFocused()) + && (mFocusHandler->getLastWidgetWithModalFocus() == NULL)) + { + handleModalFocusGained(); + mFocusHandler->setLastWidgetWithModalFocus(mFocusHandler->getModalFocused()); + } + // Check if modal focus has been released. + else if ((mFocusHandler->getLastWidgetWithModalFocus() + != mFocusHandler->getModalFocused()) + && (mFocusHandler->getLastWidgetWithModalFocus() != NULL)) + { + handleModalFocusReleased(); + mFocusHandler->setLastWidgetWithModalFocus(NULL); + } + } + + void Gui::handleModalFocusGained() + { + // Distribute an event to all widgets in the "widget with mouse" queue. + while (!mWidgetWithMouseQueue.empty()) + { + Widget* widget = mWidgetWithMouseQueue.front(); + + if (Widget::widgetExists(widget)) + { + distributeMouseEvent(widget, + MouseEvent::EXITED, + mLastMousePressButton, + mLastMouseX, + mLastMouseY, + true, + true); + } + + mWidgetWithMouseQueue.pop_front(); + } + + mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused()); + } + + void Gui::handleModalFocusReleased() + { + // Check all widgets below the mouse to see if they are + // present in the "widget with mouse" queue. If a widget + // is not then it should be added and an entered event should + // be sent to it. + Widget* widget = getMouseEventSource(mLastMouseX, mLastMouseY); + Widget* parent = widget; + + while (parent != NULL) + { + parent = (Widget*)widget->getParent(); + + // Check if the widget is present in the "widget with mouse" queue. + bool widgetIsPresentInQueue = false; + std::deque<Widget*>::iterator iter; + for (iter = mWidgetWithMouseQueue.begin(); + iter != mWidgetWithMouseQueue.end(); + iter++) + { + if (*iter == widget) + { + widgetIsPresentInQueue = true; + break; + } + } + + // Widget is not present, send an entered event and add + // it to the "widget with mouse" queue. + if (!widgetIsPresentInQueue + && Widget::widgetExists(widget)) + { + distributeMouseEvent(widget, + MouseEvent::ENTERED, + mLastMousePressButton, + mLastMouseX, + mLastMouseY, + false, + true); + mWidgetWithMouseQueue.push_front(widget); + } + + Widget* swap = widget; + widget = parent; + parent = (Widget*)swap->getParent(); + } + } +} diff --git a/src/guichan/gui.hpp b/src/guichan/gui.hpp new file mode 100644 index 000000000..da5d71250 --- /dev/null +++ b/src/guichan/gui.hpp @@ -0,0 +1,504 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_GUI_HPP +#define GCN_GUI_HPP + +#include <list> +#include <deque> + +#include "guichan/keyevent.hpp" +#include "guichan/mouseevent.hpp" +#include "guichan/mouseinput.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class FocusHandler; + class Graphics; + class Input; + class KeyListener; + class Widget; + + // The following comment will appear in the doxygen main page. + /** + * @mainpage + * @section Introduction + * This documentation is mostly intended as a reference to the API. If you want to get started with Guichan, we suggest you check out the programs in the examples directory of the Guichan release. + * @n + * @n + * This documentation is, and will always be, work in progress. If you find any errors, typos or inconsistencies, or if you feel something needs to be explained in more detail - don't hesitate to tell us. + */ + + /** + * Contains a Guichan GUI. This is the core class of Guichan to which + * implementations of back ends are passed, to make Guichan work with + * a specific library, and to where the top widget (root widget of GUI) + * is added. If you want to be able to have more then one widget in your + * GUI, the top widget should be a container. + * + * A Gui object cannot work properly without passing back end + * implementations to it. A Gui object must have an implementation of a + * Graphics and an implementation of Input. + * + * NOTE: A complete GUI also must have the ability to load images. + * Images are loaded with the Image class, so to make Guichan + * able to load images an implementation of ImageLoader must be + * passed to Image. + * + * @see Graphics, Input, Image + */ + class GCN_CORE_DECLSPEC Gui + { + public: + + /** + * Constructor. + */ + Gui(); + + /** + * Destructor. + */ + virtual ~Gui(); + + /** + * Sets the top widget. The top widget is the root widget + * of the GUI. If you want a GUI to be able to contain more + * than one widget the top widget should be a container. + * + * @param top The top widget. + * @see Container + * @since 0.1.0 + */ + virtual void setTop(Widget* top); + + /** + * Gets the top widget. The top widget is the root widget + * of the GUI. + * + * @return The top widget. NULL if no top widget has been set. + * @since 0.1.0 + */ + virtual Widget* getTop() const; + + /** + * Sets the graphics object to use for drawing. + * + * @param graphics The graphics object to use for drawing. + * @see getGraphics, AllegroGraphics, HGEGraphics, + * OpenLayerGraphics, OpenGLGraphics, SDLGraphics + * @since 0.1.0 + */ + virtual void setGraphics(Graphics* graphics); + + /** + * Gets the graphics object used for drawing. + * + * @return The graphics object used for drawing. NULL if no + * graphics object has been set. + * @see setGraphics, AllegroGraphics, HGEGraphics, + * OpenLayerGraphics, OpenGLGraphics, SDLGraphics + * @since 0.1.0 + */ + virtual Graphics* getGraphics() const; + + /** + * Sets the input object to use for input handling. + * + * @param input The input object to use for input handling. + * @see getInput, AllegroInput, HGEInput, OpenLayerInput, + * SDLInput + * @since 0.1.0 + */ + virtual void setInput(Input* input); + + /** + * Gets the input object being used for input handling. + * + * @return The input object used for handling input. NULL if no + * input object has been set. + * @see setInput, AllegroInput, HGEInput, OpenLayerInput, + * SDLInput + * @since 0.1.0 + */ + virtual Input* getInput() const; + + /** + * Performs logic of the GUI. By calling this function all logic + * functions down in the GUI heirarchy will be called. When logic + * is called for Gui, user input will be handled. + * + * @see Widget::logic + * @since 0.1.0 + */ + virtual void logic(); + + /** + * Draws the GUI. By calling this funcion all draw functions + * down in the GUI hierarchy will be called. When draw is called + * the used Graphics object will be initialised and drawing of + * the top widget will commence. + * + * @see Widget::draw + * @since 0.1.0 + */ + virtual void draw(); + + /** + * Focuses none of the widgets in the Gui. + * + * @since 0.1.0 + */ + virtual void focusNone(); + + /** + * Sets tabbing enabled, or not. Tabbing is the usage of + * changing focus by utilising the tab key. + * + * @param tabbing True if tabbing should be enabled, false + * otherwise. + * @see isTabbingEnabled + * @since 0.1.0 + */ + virtual void setTabbingEnabled(bool tabbing); + + /** + * Checks if tabbing is enabled. + * + * @return True if tabbing is enabled, false otherwise. + * @see setTabbingEnabled + * @since 0.1.0 + */ + virtual bool isTabbingEnabled(); + + /** + * Adds a global key listener to the Gui. A global key listener + * will receive all key events generated from the GUI and global + * key listeners will receive the events before key listeners + * of widgets. + * + * @param keyListener The key listener to add. + * @see removeGlobalKeyListener + * @since 0.5.0 + */ + virtual void addGlobalKeyListener(KeyListener* keyListener); + + /** + * Removes global key listener from the Gui. + * + * @param keyListener The key listener to remove. + * @throws Exception if the key listener hasn't been added. + * @see addGlobalKeyListener + * @since 0.5.0 + */ + virtual void removeGlobalKeyListener(KeyListener* keyListener); + + protected: + /** + * Handles all mouse input. + * + * @since 0.6.0 + */ + virtual void handleMouseInput(); + + /** + * Handles key input. + * + * @since 0.6.0 + */ + virtual void handleKeyInput(); + + /** + * Handles mouse moved input. + * + * @param mouseInput The mouse input to handle. + * @since 0.6.0 + */ + virtual void handleMouseMoved(const MouseInput& mouseInput); + + /** + * Handles mouse pressed input. + * + * @param mouseInput The mouse input to handle. + * @since 0.6.0 + */ + virtual void handleMousePressed(const MouseInput& mouseInput); + + /** + * + * Handles mouse wheel moved down input. + * + * @param mouseInput The mouse input to handle. + * @since 0.6.0 + */ + virtual void handleMouseWheelMovedDown(const MouseInput& mouseInput); + + /** + * Handles mouse wheel moved up input. + * + * @param mouseInput The mouse input to handle. + * @since 0.6.0 + */ + virtual void handleMouseWheelMovedUp(const MouseInput& mouseInput); + + /** + * Handles mouse released input. + * + * @param mouseInput The mouse input to handle. + * @since 0.6.0 + */ + virtual void handleMouseReleased(const MouseInput& mouseInput); + + /** + * Handles modal focus. Modal focus needs to be checked at + * each logic iteration as it might be necessary to distribute + * mouse entered or mouse exited events. + * + * @since 0.8.0 + */ + virtual void handleModalFocus(); + + /** + * Handles modal mouse input focus. Modal mouse input focus needs + * to be checked at each logic iteration as it might be necessary to + * distribute mouse entered or mouse exited events. + * + * @since 0.8.0 + */ + virtual void handleModalMouseInputFocus(); + + /** + * Handles modal focus gained. If modal focus has been gained it might + * be necessary to distribute mouse entered or mouse exited events. + * + * @since 0.8.0 + */ + virtual void handleModalFocusGained(); + + /** + * Handles modal mouse input focus gained. If modal focus has been + * gained it might be necessary to distribute mouse entered or mouse + * exited events. + * + * @since 0.8.0 + */ + virtual void handleModalFocusReleased(); + + /** + * Distributes a mouse event. + * + * @param type The type of the event to distribute, + * @param button The button of the event (if any used) to distribute. + * @param x The x coordinate of the event. + * @param y The y coordinate of the event. + * @param fource indicates whether the distribution should be forced or not. + * A forced distribution distributes the event even if a widget + * is not enabled, not visible, another widget has modal + * focus or another widget has modal mouse input focus. + * Default value is false. + * @param toSourceOnly indicates whether the distribution should be to the + * source widget only or to it's parent's mouse listeners + * as well. + * + * @since 0.6.0 + */ + virtual void distributeMouseEvent(Widget* source, + int type, + int button, + int x, + int y, + bool force = false, + bool toSourceOnly = false); + + /** + * Distributes a key event. + * + * @param keyEvent The key event to distribute. + + * @since 0.6.0 + */ + virtual void distributeKeyEvent(KeyEvent& keyEvent); + + /** + * Distributes a key event to the global key listeners. + * + * @param keyEvent The key event to distribute. + * + * @since 0.6.0 + */ + virtual void distributeKeyEventToGlobalKeyListeners(KeyEvent& keyEvent); + + /** + * Gets the widget at a certain position. + * + * @return The widget at a certain position. + * @since 0.6.0 + */ + virtual Widget* getWidgetAt(int x, int y); + + /** + * Gets the source of the mouse event. + * + * @return The source widget of the mouse event. + * @since 0.6.0 + */ + virtual Widget* getMouseEventSource(int x, int y); + + /** + * Gets the source of the key event. + * + * @return The source widget of the key event. + * @since 0.6.0 + */ + virtual Widget* getKeyEventSource(); + + /** + * Holds the top widget. + */ + Widget* mTop; + + /** + * Holds the graphics implementation used. + */ + Graphics* mGraphics; + + /** + * Holds the input implementation used. + */ + Input* mInput; + + /** + * Holds the focus handler for the Gui. + */ + FocusHandler* mFocusHandler; + + /** + * True if tabbing is enabled, false otherwise. + */ + bool mTabbing; + + /** + * Typedef. + */ + typedef std::list<KeyListener*> KeyListenerList; + + /** + * Typedef. + */ + typedef KeyListenerList::iterator KeyListenerListIterator; + + /** + * Holds the global key listeners of the Gui. + */ + KeyListenerList mKeyListeners; + + /** + * True if shift is pressed, false otherwise. + */ + bool mShiftPressed; + + /** + * True if meta is pressed, false otherwise. + */ + bool mMetaPressed; + + /** + * True if control is pressed, false otherwise. + */ + bool mControlPressed; + + /** + * True if alt is pressed, false otherwise. + */ + bool mAltPressed; + + /** + * Holds the last mouse button pressed. + */ + unsigned int mLastMousePressButton; + + /** + * Holds the last mouse press time stamp. + */ + int mLastMousePressTimeStamp; + + /** + * Holds the last mouse x coordinate. + */ + int mLastMouseX; + + /** + * Holds the last mouse y coordinate. + */ + int mLastMouseY; + + /** + * Holds the current click count. Used to keep track + * of clicks for a the last pressed button. + */ + int mClickCount; + + /** + * Holds the last button used when a drag of a widget + * was initiated. Used to be able to release a drag + * when the same button is released. + */ + int mLastMouseDragButton; + + /** + * Holds a stack with all the widgets with the mouse. + * Used to properly distribute mouse events. + */ + std::deque<Widget*> mWidgetWithMouseQueue; + }; +} + +#endif // end GCN_GUI_HPP + +/* yakslem - "Women, it's a constant struggle." + * finalman - "Yes, but sometimes they succeed with their guesses." + * yaklsem - "...eh...I was talking about love." + * finalman - "Oh...ok..." + * An awkward silence followed. + */ diff --git a/src/guichan/image.cpp b/src/guichan/image.cpp new file mode 100644 index 000000000..fa3408a1b --- /dev/null +++ b/src/guichan/image.cpp @@ -0,0 +1,85 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/image.hpp" + +#include "guichan/exception.hpp" +#include "guichan/imageloader.hpp" + +namespace gcn +{ + + ImageLoader* Image::mImageLoader = NULL; + + Image::Image() + { + } + + Image::~Image() + { + } + + void Image::setImageLoader(ImageLoader* imageLoader) + { + mImageLoader = imageLoader; + } + + ImageLoader* Image::getImageLoader() + { + return mImageLoader; + } + + Image* Image::load(const std::string& filename, bool convertToDisplayFormat) + { + if (mImageLoader == NULL) + { + throw GCN_EXCEPTION("Trying to load an image but no image loader is set."); + } + + return mImageLoader->load(filename, convertToDisplayFormat); + } +} diff --git a/src/guichan/image.hpp b/src/guichan/image.hpp new file mode 100644 index 000000000..373a64884 --- /dev/null +++ b/src/guichan/image.hpp @@ -0,0 +1,190 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_IMAGE_HPP +#define GCN_IMAGE_HPP + +#include <string> + +#include "guichan/platform.hpp" + +namespace gcn +{ + class Color; + class ImageLoader; + + /** + * Holds an image. To be able to use this class you must first set an + * ImageLoader in Image by calling + * @code Image::setImageLoader(myImageLoader) @endcode + * The function is static. If this is not done, the constructor taking a + * filename will throw an exception. The ImageLoader you use must be + * compatible with the Graphics object you use. + * + * EXAMPLE: If you use SDLGraphics you should use SDLImageLoader. + * Otherwise your program might crash in a most bizarre way. + * @see AllegroImageLoader, HGEImageLoader, OpenLayerImageLoader, + * OpenGLAllegroImageLoader, OpenGLSDLImageLoader, SDLImageLoader + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC Image + { + public: + + /** + * Constructor. + */ + Image(); + + /** + * Destructor. + */ + virtual ~Image(); + + /** + * Loads an image by using the class' image laoder. All image loaders implemented + * in Guichan return a newly instantiated image which must be deleted in + * order to avoid a memory leak. + * + * NOTE: The functions getPixel and putPixel are only guaranteed to work + * before an image has been converted to display format. + * + * @param filename The file to load. + * @param convertToDisplayFormat True if the image should be converted + * to display, false otherwise. + * @since 0.5.0 + */ + static Image* load(const std::string& filename, bool convertToDisplayFormat = true); + + /** + * Gets the image loader used for loading images. + * + * @return The image loader used for loading images. + * @see setImageLoader, AllegroImageLoader, HGEImageLoader, + * OpenLayerImageLoader, OpenGLAllegroImageLoader, + * OpenGLSDLImageLoader, SDLImageLoader + * @since 0.1.0 + */ + static ImageLoader* getImageLoader(); + + /** + * Sets the ImageLoader to be used for loading images. + * + * IMPORTANT: The image loader is static and MUST be set before + * loading images! + * + * @param imageLoader The image loader to be used for loading images. + * @see getImageLoader, AllegroImageLoader, HGEImageLoader, + * OpenLayerImageLoader, OpenGLAllegroImageLoader, + * OpenGLSDLImageLoader, SDLImageLoader + * @since 0.1.0 + */ + static void setImageLoader(ImageLoader* imageLoader); + + /** + * Frees an image. + * + * @since 0.5.0 + */ + virtual void free() = 0; + + /** + * Gets the width of the image. + * + * @return The width of the image. + * + * @since 0.1.0 + */ + virtual int getWidth() const = 0; + + /** + * Gets the height of the image. + * + * @return The height of the image. + * + * @since 0.1.0 + */ + virtual int getHeight() const = 0; + + /** + * Gets the color of a pixel at coordinate (x, y) in the image. + * + * IMPORTANT: Only guaranteed to work before the image has been + * converted to display format. + * + * @param x The x coordinate. + * @param y The y coordinate. + * @return The color of the pixel. + * + * @since 0.5.0 + */ + virtual Color getPixel(int x, int y) = 0; + + /** + * Puts a pixel with a certain color at coordinate (x, y). + * + * @param x The x coordinate. + * @param y The y coordinate. + * @param color The color of the pixel to put. + * @since 0.5.0 + */ + virtual void putPixel(int x, int y, const Color& color) = 0; + + /** + * Converts the image, if possible, to display format. + * + * IMPORTANT: Only guaranteed to work before the image has been + * converted to display format. + * @since 0.5.0 + */ + virtual void convertToDisplayFormat() = 0; + + protected: + /** + * Holds the image loader to be used when loading images. + */ + static ImageLoader* mImageLoader; + }; +} + +#endif // end GCN_IMAGE_HPP diff --git a/src/guichan/imageloader.hpp b/src/guichan/imageloader.hpp new file mode 100644 index 000000000..f939f7244 --- /dev/null +++ b/src/guichan/imageloader.hpp @@ -0,0 +1,98 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_IMAGELOADER_HPP +#define GCN_IMAGELOADER_HPP + +#include <string> + +#include "guichan/platform.hpp" + +namespace gcn +{ + class Image; + + /** + * Abstract class for providing functions for loading images. + * + * Guichan contains implementations of ImageLoader for common + * libraries like the Allegro library, the HGE library, + * he OpenLayer library, and the SDL library. + * To make Guichan usable with other libraries, an ImageLoader + * class must be implemented. + * + * To make Guichan use an image loader, the image loader needs + * to be passed to the Image class using the static method + * Image::setImageLoader. + * + * @see Image::setImageLoader, Image::getImageLoader, + * AllegroImageLoader, HGEImageLoader, OpenLayerImageLoader, + * OpenGLAllegroImageLoader, OpenGLSDLImageLoader, + * SDLImageLoader + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC ImageLoader + { + public: + + /** + * Destructor. + */ + virtual ~ImageLoader() { } + + /** + * Loads an image. + * + * NOTE: The functions Image::getPixel and Image::putPixel + * are only guaranteed to work before an image has + * been converted to display format. + * + * @param filename The filename of the image to load. + * @param convertToDisplayFormat True if the image should be converted + * to display, false otherwise. + */ + virtual Image* load(const std::string& filename, bool convertToDisplayFormat = true) = 0; + }; +} + +#endif // end GCN_IMAGELOADER_HPP diff --git a/src/guichan/input.hpp b/src/guichan/input.hpp new file mode 100644 index 000000000..7510d3cb2 --- /dev/null +++ b/src/guichan/input.hpp @@ -0,0 +1,115 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_INPUT_HPP +#define GCN_INPUT_HPP + +#include "guichan/platform.hpp" + +namespace gcn +{ + class KeyInput; + class MouseInput; + + /** + * Abstract class for providing functions for user input. + * + * Guichan contains implementations of Input for common + * libraries like the Allegro library, the HGE library, + * and the SDL library. + * To make Guichan usable with other libraries, an Input + * class must be implemented. + * + * @see AllegroInput, HGEInput, OpenLayerInput, + * SDLInput + */ + class GCN_CORE_DECLSPEC Input + { + public: + + /** + * Destructor. + */ + virtual ~Input(){ } + + /** + * Checks if the key queue is empty, or not. + * + * @return True if the key queue is empty, + * false otherwise. + */ + virtual bool isKeyQueueEmpty() = 0; + + /** + * Dequeues the key input queue. + * + * @return The first key input in the key input queue. + */ + virtual KeyInput dequeueKeyInput() = 0; + + /** + * Checks if the mouse queue is empyt, or not. + * + * @return True if the mouse queue is empty, + * false otherwise. + */ + virtual bool isMouseQueueEmpty() = 0; + + /** + * Dequeues the mouse input queue. + * + * @return The first mouse input in the mouse input queue. + */ + virtual MouseInput dequeueMouseInput() = 0; + + /** + * Polls all exsisting input. Called when input should + * be polled. The function exists for compatibility reason + * where some libraries need to poll input at a certain + * logic rate. + */ + virtual void _pollInput() = 0; + }; +} + +#endif // end GCN_INPUT_HPP diff --git a/src/guichan/key.hpp b/src/guichan/key.hpp new file mode 100644 index 000000000..0b550dcca --- /dev/null +++ b/src/guichan/key.hpp @@ -0,0 +1,182 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_KEY_HPP +#define GCN_KEY_HPP + +#include "guichan/platform.hpp" + +// windows.h defines DELETE which breaks this file as we have a constant named +// DELETE, hence we undefine DELETE if it is defined and hope people don't use +// that windows define with Guichan. +#if defined (_WIN32) && defined(DELETE) +#undef DELETE +#endif + +namespace gcn +{ + /** + * Represents a key or a character. + */ + class GCN_CORE_DECLSPEC Key + { + public: + + /** + * Constructor. + * + * @param value The ascii or enum value for the key. + */ + Key(int value = 0); + + /** + * Checks if a key is a character. + * + * @return True if the key is a letter, number or whitespace, + * false otherwise. + */ + bool isCharacter() const; + + /** + * Checks if a key is a number. + * + * @return True if the key is a number (0-9), + * false otherwise. + */ + bool isNumber() const; + + /** + * Checks if a key is a letter. + * + * @return True if the key is a letter (a-z,A-Z), + * false otherwise. + */ + bool isLetter() const; + + /** + * Gets the value of the key. If an ascii value exists it + * will be returned. Otherwise an enum value will be returned. + * + * @return the value of the key. + */ + int getValue() const; + + /** + * Compares two keys. + * + * @param key The key to compare this key with. + * @return True if the keys are equal, false otherwise. + */ + bool operator==(const Key& key) const; + + /** + * Compares two keys. + * + * @param key The key to compare this key with. + * @return True if the keys are not equal, false otherwise. + */ + bool operator!=(const Key& key) const; + + /** + * An enum with key values. + */ + enum + { + SPACE = ' ', + TAB = '\t', + ENTER = '\n', + LEFT_ALT = 1000, + RIGHT_ALT, + LEFT_SHIFT, + RIGHT_SHIFT, + LEFT_CONTROL, + RIGHT_CONTROL, + LEFT_META, + RIGHT_META, + LEFT_SUPER, + RIGHT_SUPER, + INSERT, + HOME, + PAGE_UP, + DELETE, + END, + PAGE_DOWN, + ESCAPE, + CAPS_LOCK, + BACKSPACE, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + PRINT_SCREEN, + SCROLL_LOCK, + PAUSE, + NUM_LOCK, + ALT_GR, + LEFT, + RIGHT, + UP, + DOWN + }; + + protected: + /** + * Holds the value of the key. It may be an ascii value + * or an enum value. + */ + int mValue; + }; +} + +#endif // end GCN_KEY_HPP diff --git a/src/guichan/keyinput.hpp b/src/guichan/keyinput.hpp new file mode 100644 index 000000000..d3f85d27b --- /dev/null +++ b/src/guichan/keyinput.hpp @@ -0,0 +1,263 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_KEYINPUT_HPP +#define GCN_KEYINPUT_HPP + +#include "guichan/key.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * Internal class that represents key input. Generally you won't have to + * bother using this class unless you implement an Input class for + * a back end. + * + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC KeyInput + { + public: + + /** + * Constructor. + */ + KeyInput() { }; + + /** + * Constructor. + * + * @param key The key of the key input. + * @param type The type of key input. + */ + KeyInput(const Key& key, unsigned int type); + + /** + * Sets the type of the key input. + * + * @param type The type of key input. + * @see getType + */ + void setType(unsigned int type); + + /** + * Gets the type of the key input. + * + * @return the input type. + * @see setType + */ + int getType() const; + + /** + * Sets the key of the key input. + * + * @param key The key of the key input. + * @see getKey + */ + void setKey(const Key& key); + + /** + * Gets the key of the key input. + * + * @return The key of the key input. + * @see setKey + */ + const Key& getKey() const; + + /** + * Checks if shift is pressed. + * + * @return True if shift was pressed at the same + * time as the key, false otherwise. + * @see setShiftPressed + * @since 0.6.0 + */ + bool isShiftPressed() const; + + /** + * Sets shift to be pressed at the same time as the key, + * or not. + * + * @param pressed True if shift is pressed, false otherwise. + * @see isShiftPressed + * @since 0.6.0 + */ + void setShiftPressed(bool pressed); + + /** + * Checks if control is pressed. + * + * @return True if control was pressed at the same + * time as the key, false otherwise. + * @see setControlPressed + * @since 0.6.0 + */ + bool isControlPressed() const; + + /** + * Sets control to be pressed at the same time as the key, + * or not. + * + * @param pressed True if control is pressed, false otherwise. + * @see isControlPressed + * @since 0.6.0 + */ + void setControlPressed(bool pressed); + + /** + * Checks if alt is pressed. + * + * @return True if alt was pressed at the same + * time as the key, false otherwise. + * @see setAltPressed + * @since 0.6.0 + */ + bool isAltPressed() const; + + /** + * Sets the alt to be pressed at the same time as the key, + * or not. + * + * @param pressed True if alt is pressed at the same + * time as the key, , false otherwise. + * @see isAltPressed + * @since 0.6.0 + */ + void setAltPressed(bool pressed); + + /** + * Checks if meta is pressed. + * + * @return True if meta was pressed at the same + * time as the key, false otherwise. + * @see setMetaPressed + * @since 0.6.0 + */ + bool isMetaPressed() const; + + /** + * Sets meta to be pressed at the same time as the key, + * or not. + * + * @param pressed True if meta is pressed at the same + * time as the key, false otherwise. + * @see isMetaPressed + * @since 0.6.0 + */ + void setMetaPressed(bool pressed); + + /** + * Checks if the key was pressed at the numeric pad. + * + * @return True if key pressed at the numeric pad, + * false otherwise. + * @setNumericPad + * @since 0.6.0 + */ + bool isNumericPad() const; + + /** + * Sets the key to be pressed at the numeric pad. + * + * @param numpad True if the key was pressed at the numeric + * pad, false otherwise. + * @see isNumericPad + * @since 0.6.0 + */ + void setNumericPad(bool numpad); + + /** + * Key input types. This enum corresponds to the enum with event + * types on KeyEvent for easy mapping. + */ + enum + { + PRESSED = 0, + RELEASED + }; + + protected: + /** + * Holds the key of the key input. + */ + Key mKey; + + /** + * Holds the type of the key input. + */ + unsigned int mType; + + /** + * True if shift was pressed at the same time as the key, + * false otherwise. + */ + bool mShiftPressed; + + /** + * True if control was pressed at the same time as the key, + * false otherwise. + */ + bool mControlPressed; + + /** + * True if alt was pressed at the same time as the key, + * false otherwise. + */ + bool mAltPressed; + + /** + * True if meta was pressed at the same time as the key, + * false otherwise. + */ + bool mMetaPressed; + + /** + * True if the numeric pad was used when the key was pressed, + * false otherwise. + */ + bool mNumericPad; + }; +} + +#endif // end GCN_KEYINPUT_HPP diff --git a/src/guichan/keylistener.hpp b/src/guichan/keylistener.hpp new file mode 100644 index 000000000..7685558bd --- /dev/null +++ b/src/guichan/keylistener.hpp @@ -0,0 +1,95 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_KEYLISTENER_HPP +#define GCN_KEYLISTENER_HPP + +#include "guichan/keyevent.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Key; + + /** + * Interface for listening for key events from widgets. + * + * @see Widget::addKeyListener, Widget::removeKeyListener + */ + class GCN_CORE_DECLSPEC KeyListener + { + public: + + /** + * Destructor. + */ + virtual ~KeyListener() { } + + /** + * Called if a key is pressed when the widget has keyboard focus. + * If a key is held down the widget will generate multiple key + * presses. + * + * @param keyEvent Discribes the event. + */ + virtual void keyPressed(KeyEvent& keyEvent) { } + + /** + * Called if a key is released when the widget has keyboard focus. + * + * @param keyEvent Discribes the event. + */ + virtual void keyReleased(KeyEvent& keyEvent) { } + + protected: + /** + * Constructor. + * + * You should not be able to make an instance of KeyListener, + * therefore its constructor is protected. + */ + KeyListener() { } + }; +} + +#endif // end GCN_KEYLISTENER_HPP diff --git a/src/guichan/listmodel.hpp b/src/guichan/listmodel.hpp new file mode 100644 index 000000000..1beae317b --- /dev/null +++ b/src/guichan/listmodel.hpp @@ -0,0 +1,86 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_LISTMODEL_HPP +#define GCN_LISTMODEL_HPP + +#include <string> + +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * An interface for a model that represents a list. It is + * used in certain widgets, like the ListBox, to handle a + * lists with string elements. If you want to use widgets + * like ListBox, make a derived class from this class that + * represents your list. + */ + class GCN_CORE_DECLSPEC ListModel + { + + public: + /** + * Destructor. + */ + virtual ~ListModel() { } + + /** + * Gets the number of elements in the list. + * + * @return The number of elements in the list + */ + virtual int getNumberOfElements() = 0; + + /** + * Gets an element at a certain index in the list. + * + * @param i An index in the list. + * @return An element as a string at the a certain index. + */ + virtual std::string getElementAt(int i) = 0; + }; +} + +#endif // end GCN_LISTMODEL_HPP diff --git a/src/guichan/mouseevent.cpp b/src/guichan/mouseevent.cpp new file mode 100644 index 000000000..e036fdce5 --- /dev/null +++ b/src/guichan/mouseevent.cpp @@ -0,0 +1,100 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/mouseevent.hpp" + +namespace gcn +{ + MouseEvent::MouseEvent(Widget* source, + bool isShiftPressed, + bool isControlPressed, + bool isAltPressed, + bool isMetaPressed, + unsigned int type, + unsigned int button, + int x, + int y, + int clickCount) + :InputEvent(source, + isShiftPressed, + isControlPressed, + isAltPressed, + isMetaPressed), + mType(type), + mButton(button), + mX(x), + mY(y), + mClickCount(clickCount) + { + + } + + unsigned int MouseEvent::getButton() const + { + return mButton; + } + + int MouseEvent::getX() const + { + return mX; + } + + int MouseEvent::getY() const + { + return mY; + } + + int MouseEvent::getClickCount() const + { + return mClickCount; + } + + unsigned int MouseEvent::getType() const + { + return mType; + } +} diff --git a/src/guichan/mouseevent.hpp b/src/guichan/mouseevent.hpp new file mode 100644 index 000000000..280d373e6 --- /dev/null +++ b/src/guichan/mouseevent.hpp @@ -0,0 +1,200 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_MOUSEEVENT_HPP +#define GCN_MOUSEEVENT_HPP + +#include "guichan/inputevent.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Gui; + class Widget; + + /** + * Represents a mouse event. + * + * @author Olof Naessén + * @since 0.6.0 + */ + class GCN_CORE_DECLSPEC MouseEvent: public InputEvent + { + public: + + /** + * Constructor. + * + * @param source The source widget of the mouse event. + * @param isShiftPressed True if shift is pressed, false otherwise. + * @param isControlPressed True if control is pressed, false otherwise. + * @param isAltPressed True if alt is pressed, false otherwise. + * @param isMetaPressed True if meta is pressed, false otherwise. + * @param type The type of the mouse event. + * @param button The button of the mouse event. + * @param x The x coordinate of the event relative to the source widget. + * @param y The y coordinate of the event relative the source widget. + * @param clickCount The number of clicks generated with the same button. + * It's set to zero if another button is used. + */ + MouseEvent(Widget* source, + bool isShiftPressed, + bool isControlPressed, + bool isAltPressed, + bool isMetaPressed, + unsigned int type, + unsigned int button, + int x, + int y, + int clickCount); + + /** + * Gets the button of the mouse event. + * + * @return The button of the mouse event. + */ + unsigned int getButton() const; + + /** + * Gets the x coordinate of the mouse event. + * The coordinate relative to widget the mouse listener + * receiving the events have registered to. + * + * @return The x coordinate of the mouse event. + * @see Widget::addMouseListener, Widget::removeMouseListener + */ + int getX() const; + + /** + * Gets the y coordinate of the mouse event. + * The coordinate relative to widget the mouse listener + * receiving the events have registered to. + * + * @return The y coordinate of the mouse event. + * @see Widget::addMouseListener, Widget::removeMouseListener + */ + int getY() const; + + /** + * Gets the number of clicks generated with the same button. + * It's set to zero if another button is used. + * + * @return The number of clicks generated with the same button. + */ + int getClickCount() const; + + /** + * Gets the type of the event. + * + * @return The type of the event. + */ + unsigned int getType() const; + + /** + * Mouse event types. + */ + enum + { + MOVED = 0, + PRESSED, + RELEASED, + WHEEL_MOVED_DOWN, + WHEEL_MOVED_UP, + CLICKED, + ENTERED, + EXITED, + DRAGGED + + }; + + /** + * Mouse button types. + */ + enum + { + EMPTY = 0, + LEFT, + RIGHT, + MIDDLE + }; + + protected: + /** + * Holds the type of the mouse event. + */ + unsigned int mType; + + /** + * Holds the button of the mouse event. + */ + unsigned int mButton; + + /** + * Holds the x-coordinate of the mouse event. + */ + int mX; + + /** + * Holds the y-coordinate of the mouse event. + */ + int mY; + + /** + * The number of clicks generated with the same button. + * It's set to zero if another button is used. + */ + int mClickCount; + + /** + * Gui is a friend of this class in order to be able to manipulate + * the protected member variables of this class and at the same time + * keep the MouseEvent class as const as possible. Gui needs to + * update the x och y coordinates for the coordinates to be relative + * to widget the mouse listener receiving the events have registered + * to. + */ + friend class Gui; + }; +} + +#endif // GCN_MOUSEEVENT_HPP diff --git a/src/guichan/mouseinput.cpp b/src/guichan/mouseinput.cpp new file mode 100644 index 000000000..5af29c841 --- /dev/null +++ b/src/guichan/mouseinput.cpp @@ -0,0 +1,114 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + MouseInput::MouseInput(unsigned int button, + unsigned int type, + int x, + int y, + int timeStamp) + : mType(type), + mButton(button), + mTimeStamp(timeStamp), + mX(x), + mY(y) + { + } + + void MouseInput::setType(unsigned int type) + { + mType = type; + } + + unsigned int MouseInput::getType() const + { + return mType; + } + + void MouseInput::setButton(unsigned int button) + { + mButton = button; + } + + unsigned int MouseInput::getButton() const + { + return mButton; + } + + int MouseInput::getTimeStamp() const + { + return mTimeStamp; + } + + void MouseInput::setTimeStamp(int timeStamp) + { + mTimeStamp = timeStamp; + } + + void MouseInput::setX(int x) + { + mX = x; + } + + int MouseInput::getX() const + { + return mX; + } + + void MouseInput::setY(int y) + { + mY = y; + } + + int MouseInput::getY() const + { + return mY; + } +} diff --git a/src/guichan/mouseinput.hpp b/src/guichan/mouseinput.hpp new file mode 100644 index 000000000..e441d0160 --- /dev/null +++ b/src/guichan/mouseinput.hpp @@ -0,0 +1,235 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_MOUSEINPUT_HPP +#define GCN_MOUSEINPUT_HPP + +#include "guichan/platform.hpp" + +namespace gcn +{ + + /** + * Internal class that represents mouse input. Generally you won't have to + * bother using this class unless you implement an Input class for + * a back end. + * + * @author Olof Naessén + * @author Per Larsson + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC MouseInput + { + public: + + /** + * Constructor. + */ + MouseInput() { }; + + /** + * Constructor. + * + * @param button The button pressed. + * @param type The type of mouse input. + * @param x The mouse x coordinate. + * @param y The mouse y coordinate. + * @param timeStamp The timestamp of the mouse input. Used to + * check for double clicks. + */ + MouseInput(unsigned int button, + unsigned int type, + int x, + int y, + int timeStamp); + + /** + * Sets the type of the mouse input. + * + * @param type The type of the mouse input. Should be a value from the + * mouse event type enum + * @see getType + * @since 0.1.0 + */ + void setType(unsigned int type); + + /** + * Gets the type of the mouse input. + * + * @return The type of the mouse input. A value from the mouse event + * type enum. + * @see setType + * @since 0.1.0 + */ + unsigned int getType() const; + + /** + * Sets the button pressed. + * + * @param button The button pressed. Should be one of the values + * in the mouse event button enum. + * @see getButton. + * @since 0.1.0 + */ + void setButton(unsigned int button); + + /** + * Gets the button pressed. + * + * @return The button pressed. A value from the mouse event + * button enum. + * @see setButton + * @since 0.1.0 + */ + unsigned int getButton() const; + + /** + * Sets the timestamp for the mouse input. + * Used to check for double clicks. + * + * @param timeStamp The timestamp of the mouse input. + * @see getTimeStamp + * @since 0.1.0 + */ + void setTimeStamp(int timeStamp); + + /** + * Gets the time stamp of the input. + * Used to check for double clicks. + * + * @return The time stamp of the mouse input. + * @see setTimeStamp + * @since 0.1.0 + */ + int getTimeStamp() const; + + /** + * Sets the x coordinate of the mouse input. + * + * @param x The x coordinate of the mouse input. + * @see getX + * @since 0.6.0 + */ + void setX(int x); + + /** + * Gets the x coordinate of the mouse input. + * + * @return The x coordinate of the mouse input. + * @see setX + * @since 0.6.0 + */ + int getX() const; + + /** + * Sets the y coordinate of the mouse input. + * + * @param y The y coordinate of the mouse input. + * @see getY + * @since 0.6.0 + */ + void setY(int y); + + /** + * Gets the y coordinate of the mouse input. + * + * @return The y coordinate of the mouse input. + * @see setY + * @since 0.6.0 + */ + int getY() const; + + /** + * Mouse input event types. This enum partially corresponds + * to the enum with event types in MouseEvent for easy mapping. + */ + enum + { + MOVED = 0, + PRESSED, + RELEASED, + WHEEL_MOVED_DOWN, + WHEEL_MOVED_UP + }; + + /** + * Mouse button types. + */ + enum + { + EMPTY = 0, + LEFT, + RIGHT, + MIDDLE + }; + + protected: + /** + * Holds the type of the mouse input. + */ + unsigned int mType; + + /** + * Holds the button of the mouse input. + */ + unsigned int mButton; + + /** + * Holds the timestamp of the mouse input. Used to + * check for double clicks. + */ + int mTimeStamp; + + /** + * Holds the x coordinate of the mouse input. + */ + int mX; + + /** + * Holds the y coordinate of the mouse input. + */ + int mY; + }; +} + +#endif // end GCN_MOUSEINPUT_HPP diff --git a/src/guichan/mouselistener.hpp b/src/guichan/mouselistener.hpp new file mode 100644 index 000000000..345a66531 --- /dev/null +++ b/src/guichan/mouselistener.hpp @@ -0,0 +1,183 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_MOUSELISTENER_HPP +#define GCN_MOUSELISTENER_HPP + +#include "guichan/mouseevent.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * Interface for listening for mouse events from widgets. + * + * @see Widget::addMouseListener, Widget::removeMouseListener + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC MouseListener + { + public: + + /** + * Destructor. + */ + virtual ~MouseListener() { } + + /** + * Called when the mouse has entered into the widget area. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseEntered(MouseEvent& mouseEvent) + { + + } + + /** + * Called when the mouse has exited the widget area. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseExited(MouseEvent& mouseEvent) + { + + } + + /** + * Called when a mouse button has been pressed on the widget area. + * + * NOTE: A mouse press is NOT equal to a mouse click. + * Use mouseClickMessage to check for mouse clicks. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mousePressed(MouseEvent& mouseEvent) + { + + } + + /** + * Called when a mouse button has been released on the widget area. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseReleased(MouseEvent& mouseEvent) + { + + } + + /** + * Called when a mouse button is pressed and released (clicked) on + * the widget area. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseClicked(MouseEvent& mouseEvent) + { + + } + + /** + * Called when the mouse wheel has moved up on the widget area. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseWheelMovedUp(MouseEvent& mouseEvent) + { + + } + + /** + * Called when the mouse wheel has moved down on the widget area. + * + * @param mousEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseWheelMovedDown(MouseEvent& mouseEvent) + { + + } + + /** + * Called when the mouse has moved in the widget area and no mouse button + * has been pressed (i.e no widget is being dragged). + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseMoved(MouseEvent& mouseEvent) + { + + } + + /** + * Called when the mouse has moved and the mouse has previously been + * pressed on the widget. + * + * @param mouseEvent Describes the event. + * @since 0.6.0 + */ + virtual void mouseDragged(MouseEvent& mouseEvent) + { + + } + + protected: + /** + * Constructor. + * + * You should not be able to make an instance of MouseListener, + * therefore its constructor is protected. + */ + MouseListener() { } + }; +} + +#endif // end GCN_MOUSELISTENER_HPP diff --git a/src/guichan/platform.hpp b/src/guichan/platform.hpp new file mode 100644 index 000000000..e2ea89767 --- /dev/null +++ b/src/guichan/platform.hpp @@ -0,0 +1,79 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_PLATFORM_HPP +#define GCN_PLATFORM_HPP + +#if defined (__MINGW32__) && defined(GUICHAN_BUILD) +#define GCN_CORE_DECLSPEC __declspec(dllexport) + +#elif defined (__MINGW32__) && defined(GUICHAN_EXTENSION_BUILD) +#define GCN_EXTENSION_DECLSPEC __declspec(dllexport) +#define GCN_CORE_DECLSPEC __declspec(dllimport) + +#elif defined (__MINGW32__) && defined(GUICHAN_DLL_IMPORT) +#define GCN_CORE_DECLSPEC __declspec(dllimport) +#define GCN_EXTENSION_DECLSPEC __declspec(dllimport) + +#elif defined(_MSC_VER) && defined(GUICHAN_BUILD) +#define GCN_CORE_DECLSPEC _declspec(dllexport) + +#elif defined(_MSC_VER) && defined(GUICHAN_EXTENSION_BUILD) +#define GCN_CORE_DECLSPEC _declspec(dllimport) +#define GCN_EXTENSION_DECLSPEC _declspec(dllexport) + +#endif + +#ifndef GCN_CORE_DECLSPEC +#define GCN_CORE_DECLSPEC +#endif + +#ifndef GCN_EXTENSION_DECLSPEC +#define GCN_EXTENSION_DECLSPEC +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif // end GCN_PLATFORM_HPP diff --git a/src/guichan/qqq b/src/guichan/qqq new file mode 100644 index 000000000..54615aa81 --- /dev/null +++ b/src/guichan/qqq @@ -0,0 +1,75 @@ +actionevent.cpp +actionevent.hpp +actionlistener.hpp +basiccontainer.cpp +basiccontainer.hpp +cliprectangle.cpp +cliprectangle.hpp +color.cpp +color.hpp +event.cpp +event.hpp +exception.cpp +exception.hpp +focushandler.cpp +focushandler.hpp +focuslistener.hpp +font.cpp +font.hpp +graphics.cpp +graphics.hpp +gui.cpp +gui.hpp +image.cpp +image.hpp +imageloader.hpp +input.hpp +key.hpp +keyinput.hpp +keylistener.hpp +listmodel.hpp +mouseevent.cpp +mouseevent.hpp +mouseinput.cpp +mouseinput.hpp +mouselistener.hpp +platform.hpp +rectangle.cpp +rectangle.hpp +selectionevent.cpp +selectionevent.hpp +widget.cpp +widget.hpp +widgetlistener.hpp +widgets/button.cpp +widgets/button.hpp +widgets/checkbox.cpp +widgets/checkbox.hpp +widgets/container.cpp +widgets/container.hpp +widgets/dropdown.cpp +widgets/dropdown.hpp +widgets/icon.cpp +widgets/icon.hpp +widgets/imagebutton.cpp +widgets/imagebutton.hpp +widgets/label.cpp +widgets/label.hpp +widgets/listbox.cpp +widgets/listbox.hpp +widgets/radiobutton.cpp +widgets/radiobutton.hpp +widgets/scrollarea.cpp +widgets/scrollarea.hpp +widgets/slider.cpp +widgets/slider.hpp +widgets/tabbedarea.cpp +widgets/tabbedarea.hpp +widgets/tab.cpp +widgets/tab.hpp +widgets/textbox.cpp +widgets/textbox.hpp +widgets/textfield.cpp +widgets/textfield.hpp +widgets/window.cpp +widgets/window.hpp diff --git a/src/guichan/rectangle.cpp b/src/guichan/rectangle.cpp new file mode 100644 index 000000000..cb0e1aefd --- /dev/null +++ b/src/guichan/rectangle.cpp @@ -0,0 +1,133 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/rectangle.hpp" + +namespace gcn +{ + Rectangle::Rectangle() + : x(0), + y(0), + width(0), + height(0) + { + } + + Rectangle::Rectangle(int x_, int y_, int width_, int height_) + : x(x_), + y(y_), + width(width_), + height(height_) + { + } + + void Rectangle::setAll(int x_, int y_, int width_, int height_) + { + x = x_; + y = y_; + width = width_; + height = height_; + } + + bool Rectangle::isIntersecting(const Rectangle& rectangle) const + { + int x_ = x; + int y_ = y; + int width_ = width; + int height_ = height; + + x_ -= rectangle.x; + y_ -= rectangle.y; + + if (x_ < 0) + { + width_ += x_; + x_ = 0; + } + else if (x_ + width_ > rectangle.width) + { + width_ = rectangle.width - x_; + } + + if (y_ < 0) + { + height_ += y_; + y_ = 0; + } + else if (y_ + height_ > rectangle.height) + { + height_ = rectangle.height - y_; + } + + if (width_ <= 0 || height_ <= 0) + { + return false; + } + + return true; + } + + bool Rectangle::isPointInRect(int x_, int y_) const + { + return x_ >= x + && y_ >= y + && x_ < x + width + && y_ < y + height; + } + + std::ostream& operator<<(std::ostream& out, + const Rectangle& rectangle) + { + out << "Rectangle [x = " << rectangle.x + << ", y = " << rectangle.y + << ", width = " << rectangle.width + << ", height = " << rectangle.height + << "]"; + + return out; + } +} diff --git a/src/guichan/rectangle.hpp b/src/guichan/rectangle.hpp new file mode 100644 index 000000000..1d21654df --- /dev/null +++ b/src/guichan/rectangle.hpp @@ -0,0 +1,140 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_RECTANGLE_HPP +#define GCN_RECTANGLE_HPP + +#include "guichan/platform.hpp" + +#include <iostream> + +namespace gcn +{ + /** + * Represents a rectangle. + * + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC Rectangle + { + public: + + /** + * Constructor. The default rectangle is an empty rectangle + * at the coordinates (0,0). + */ + Rectangle(); + + /** + * Constructor. + * + * @param x The x coordinate of the rectangle. + * @param y The y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @since 0.1.0 + */ + Rectangle(int x, int y, int width, int height); + + /** + * Sets the dimension of a rectangle. + * + * @param x The x coordinate of the rectangle. + * @param y The y coordinate of the rectangle. + * @param width The width of the rectangle. + * @param height The height of the rectangle. + * @since 0.1.0 + */ + void setAll(int x, int y, int width, int height); + + /** + * Checks if another rectangle intersects with the rectangle. + * + * @param rectangle Another rectangle to check for intersection. + * @return True if the rectangles intersect, false otherwise. + * @since 0.1.0 + */ + bool isIntersecting(const Rectangle& rectangle) const; + + /** + * Checks if a point is inside the rectangle + * + * @param x The x coordinate of the point. + * @param y The y coordinate of the point. + * @return True if the point is inside the rectangle. + * @since 0.1.0 + */ + bool isPointInRect(int x, int y) const; + + /** + * Output operator for output. + * + * @param out The stream to output to. + * @param rectangle The rectangle to output. + */ + friend std::ostream& operator<<(std::ostream& out, + const Rectangle& rectangle); + + /** + * Holds the x coordinate of the rectangle. + */ + int x; + + /** + * Holds the x coordinate of the rectangle. + */ + int y; + + /** + * Holds the width of the rectangle. + */ + int width; + + /** + * Holds the height of the rectangle. + */ + int height; + }; +} + +#endif // end GCN_RECTANGEL_HPP diff --git a/src/guichan/selectionevent.cpp b/src/guichan/selectionevent.cpp new file mode 100644 index 000000000..964bbab92 --- /dev/null +++ b/src/guichan/selectionevent.cpp @@ -0,0 +1,63 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/selectionevent.hpp" + +namespace gcn +{ + SelectionEvent::SelectionEvent(Widget* source) + :Event(source) + { + + } + + SelectionEvent::~SelectionEvent() + { + + } +} + diff --git a/src/guichan/selectionevent.hpp b/src/guichan/selectionevent.hpp new file mode 100644 index 000000000..6724fa0d2 --- /dev/null +++ b/src/guichan/selectionevent.hpp @@ -0,0 +1,78 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_SELECTIONEVENT_HPP +#define GCN_SELECTIONEVENT_HPP + +#include "guichan/event.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Widget; + + /** + * Represents a selection event. + * + * @author Olof Naessén + * @since 0.8.0 + */ + class GCN_CORE_DECLSPEC SelectionEvent: public Event + { + public: + + /** + * Constructor. + * + * @param source source The widget of the selection event. + */ + SelectionEvent(Widget* source); + + /** + * Destructor. + */ + virtual ~SelectionEvent(); + }; +} + +#endif // end GCN_SELECTIONEVENT_HPP diff --git a/src/guichan/widget.cpp b/src/guichan/widget.cpp new file mode 100644 index 000000000..7dfc7e10d --- /dev/null +++ b/src/guichan/widget.cpp @@ -0,0 +1,735 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widget.hpp" + +#include "guichan/actionevent.hpp" +#include "guichan/actionlistener.hpp" +#include "guichan/basiccontainer.hpp" +#include "guichan/deathlistener.hpp" +#include "guichan/defaultfont.hpp" +#include "guichan/event.hpp" +#include "guichan/exception.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/graphics.hpp" +#include "guichan/keyinput.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/mouseinput.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/widgetlistener.hpp" + +namespace gcn +{ + Font* Widget::mGlobalFont = NULL; + DefaultFont Widget::mDefaultFont; + std::list<Widget*> Widget::mWidgets; + + Widget::Widget() + : mForegroundColor(0x000000), + mBackgroundColor(0xffffff), + mBaseColor(0x808090), + mSelectionColor(0xc3d9ff), + mFocusHandler(NULL), + mInternalFocusHandler(NULL), + mParent(NULL), + mFrameSize(0), + mFocusable(false), + mVisible(true), + mTabIn(true), + mTabOut(true), + mEnabled(true), + mCurrentFont(NULL) + { + mWidgets.push_back(this); + } + + Widget::~Widget() + { + DeathListenerIterator iter; + + for (iter = mDeathListeners.begin(); iter != mDeathListeners.end(); ++iter) + { + Event event(this); + (*iter)->death(event); + } + + _setFocusHandler(NULL); + + mWidgets.remove(this); + } + + void Widget::drawFrame(Graphics* graphics) + { + Color faceColor = getBaseColor(); + Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + int width = getWidth() + getFrameSize() * 2 - 1; + int height = getHeight() + getFrameSize() * 2 - 1; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + unsigned int i; + for (i = 0; i < getFrameSize(); ++i) + { + graphics->setColor(shadowColor); + graphics->drawLine(i,i, width - i, i); + graphics->drawLine(i,i + 1, i, height - i - 1); + graphics->setColor(highlightColor); + graphics->drawLine(width - i,i + 1, width - i, height - i); + graphics->drawLine(i,height - i, width - i - 1, height - i); + } + } + + void Widget::_setParent(Widget* parent) + { + mParent = parent; + } + + Widget* Widget::getParent() const + { + return mParent; + } + + void Widget::setWidth(int width) + { + Rectangle newDimension = mDimension; + newDimension.width = width; + + setDimension(newDimension); + } + + int Widget::getWidth() const + { + return mDimension.width; + } + + void Widget::setHeight(int height) + { + Rectangle newDimension = mDimension; + newDimension.height = height; + + setDimension(newDimension); + } + + int Widget::getHeight() const + { + return mDimension.height; + } + + void Widget::setX(int x) + { + Rectangle newDimension = mDimension; + newDimension.x = x; + + setDimension(newDimension); + } + + int Widget::getX() const + { + return mDimension.x; + } + + void Widget::setY(int y) + { + Rectangle newDimension = mDimension; + newDimension.y = y; + + setDimension(newDimension); + } + + int Widget::getY() const + { + return mDimension.y; + } + + void Widget::setPosition(int x, int y) + { + Rectangle newDimension = mDimension; + newDimension.x = x; + newDimension.y = y; + + setDimension(newDimension); + } + + void Widget::setDimension(const Rectangle& dimension) + { + Rectangle oldDimension = mDimension; + mDimension = dimension; + + if (mDimension.width != oldDimension.width + || mDimension.height != oldDimension.height) + { + distributeResizedEvent(); + } + + if (mDimension.x != oldDimension.x + || mDimension.y != oldDimension.y) + { + distributeMovedEvent(); + } + } + + void Widget::setFrameSize(unsigned int frameSize) + { + mFrameSize = frameSize; + } + + unsigned int Widget::getFrameSize() const + { + return mFrameSize; + } + + const Rectangle& Widget::getDimension() const + { + return mDimension; + } + + const std::string& Widget::getActionEventId() const + { + return mActionEventId; + } + + void Widget::setActionEventId(const std::string& actionEventId) + { + mActionEventId = actionEventId; + } + + bool Widget::isFocused() const + { + if (!mFocusHandler) + { + return false; + } + + return (mFocusHandler->isFocused(this)); + } + + void Widget::setFocusable(bool focusable) + { + if (!focusable && isFocused()) + { + mFocusHandler->focusNone(); + } + + mFocusable = focusable; + } + + bool Widget::isFocusable() const + { + return mFocusable && isVisible() && isEnabled(); + } + + void Widget::requestFocus() + { + if (mFocusHandler == NULL) + { + throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?)."); + } + + if (isFocusable()) + { + mFocusHandler->requestFocus(this); + } + } + + void Widget::requestMoveToTop() + { + if (mParent) + { + mParent->moveToTop(this); + } + } + + void Widget::requestMoveToBottom() + { + if (mParent) + { + mParent->moveToBottom(this); + } + } + + void Widget::setVisible(bool visible) + { + if (!visible && isFocused()) + { + mFocusHandler->focusNone(); + } + + if (visible) + { + distributeShownEvent(); + } + else if(!visible) + { + distributeHiddenEvent(); + } + + mVisible = visible; + } + + bool Widget::isVisible() const + { + if (getParent() == NULL) + { + return mVisible; + } + else + { + return mVisible && getParent()->isVisible(); + } + } + + void Widget::setBaseColor(const Color& color) + { + mBaseColor = color; + } + + const Color& Widget::getBaseColor() const + { + return mBaseColor; + } + + void Widget::setForegroundColor(const Color& color) + { + mForegroundColor = color; + } + + const Color& Widget::getForegroundColor() const + { + return mForegroundColor; + } + + void Widget::setBackgroundColor(const Color& color) + { + mBackgroundColor = color; + } + + const Color& Widget::getBackgroundColor() const + { + return mBackgroundColor; + } + + void Widget::setSelectionColor(const Color& color) + { + mSelectionColor = color; + } + + const Color& Widget::getSelectionColor() const + { + return mSelectionColor; + } + + void Widget::_setFocusHandler(FocusHandler* focusHandler) + { + if (mFocusHandler) + { + releaseModalFocus(); + mFocusHandler->remove(this); + } + + if (focusHandler) + { + focusHandler->add(this); + } + + mFocusHandler = focusHandler; + } + + FocusHandler* Widget::_getFocusHandler() + { + return mFocusHandler; + } + + void Widget::addActionListener(ActionListener* actionListener) + { + mActionListeners.push_back(actionListener); + } + + void Widget::removeActionListener(ActionListener* actionListener) + { + mActionListeners.remove(actionListener); + } + + void Widget::addDeathListener(DeathListener* deathListener) + { + mDeathListeners.push_back(deathListener); + } + + void Widget::removeDeathListener(DeathListener* deathListener) + { + mDeathListeners.remove(deathListener); + } + + void Widget::addKeyListener(KeyListener* keyListener) + { + mKeyListeners.push_back(keyListener); + } + + void Widget::removeKeyListener(KeyListener* keyListener) + { + mKeyListeners.remove(keyListener); + } + + void Widget::addFocusListener(FocusListener* focusListener) + { + mFocusListeners.push_back(focusListener); + } + + void Widget::removeFocusListener(FocusListener* focusListener) + { + mFocusListeners.remove(focusListener); + } + + void Widget::addMouseListener(MouseListener* mouseListener) + { + mMouseListeners.push_back(mouseListener); + } + + void Widget::removeMouseListener(MouseListener* mouseListener) + { + mMouseListeners.remove(mouseListener); + } + + void Widget::addWidgetListener(WidgetListener* widgetListener) + { + mWidgetListeners.push_back(widgetListener); + } + + void Widget::removeWidgetListener(WidgetListener* widgetListener) + { + mWidgetListeners.remove(widgetListener); + } + + void Widget::getAbsolutePosition(int& x, int& y) const + { + if (getParent() == NULL) + { + x = mDimension.x; + y = mDimension.y; + return; + } + + int parentX; + int parentY; + + getParent()->getAbsolutePosition(parentX, parentY); + + x = parentX + mDimension.x + getParent()->getChildrenArea().x; + y = parentY + mDimension.y + getParent()->getChildrenArea().y; + } + + Font* Widget::getFont() const + { + if (mCurrentFont == NULL) + { + if (mGlobalFont == NULL) + { + return &mDefaultFont; + } + + return mGlobalFont; + } + + return mCurrentFont; + } + + void Widget::setGlobalFont(Font* font) + { + mGlobalFont = font; + + std::list<Widget*>::iterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) + { + if ((*iter)->mCurrentFont == NULL) + { + (*iter)->fontChanged(); + } + } + } + + void Widget::setFont(Font* font) + { + mCurrentFont = font; + fontChanged(); + } + + bool Widget::widgetExists(const Widget* widget) + { + bool result = false; + + std::list<Widget*>::iterator iter; + for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) + { + if (*iter == widget) + { + return true; + } + } + + return result; + } + + bool Widget::isTabInEnabled() const + { + return mTabIn; + } + + void Widget::setTabInEnabled(bool enabled) + { + mTabIn = enabled; + } + + bool Widget::isTabOutEnabled() const + { + return mTabOut; + } + + void Widget::setTabOutEnabled(bool enabled) + { + mTabOut = enabled; + } + + void Widget::setSize(int width, int height) + { + Rectangle newDimension = mDimension; + newDimension.width = width; + newDimension.height = height; + + setDimension(newDimension); + } + + void Widget::setEnabled(bool enabled) + { + mEnabled = enabled; + } + + bool Widget::isEnabled() const + { + return mEnabled && isVisible(); + } + + void Widget::requestModalFocus() + { + if (mFocusHandler == NULL) + { + throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?)."); + } + + mFocusHandler->requestModalFocus(this); + } + + void Widget::requestModalMouseInputFocus() + { + if (mFocusHandler == NULL) + { + throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?)."); + } + + mFocusHandler->requestModalMouseInputFocus(this); + } + + void Widget::releaseModalFocus() + { + if (mFocusHandler == NULL) + { + return; + } + + mFocusHandler->releaseModalFocus(this); + } + + void Widget::releaseModalMouseInputFocus() + { + if (mFocusHandler == NULL) + { + return; + } + + mFocusHandler->releaseModalMouseInputFocus(this); + } + + bool Widget::isModalFocused() const + { + if (mFocusHandler == NULL) + { + throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?)."); + } + + if (getParent() != NULL) + { + return (mFocusHandler->getModalFocused() == this) + || getParent()->isModalFocused(); + } + + return mFocusHandler->getModalFocused() == this; + } + + bool Widget::isModalMouseInputFocused() const + { + if (mFocusHandler == NULL) + { + throw GCN_EXCEPTION("No focushandler set (did you add the widget to the gui?)."); + } + + if (getParent() != NULL) + { + return (mFocusHandler->getModalMouseInputFocused() == this) + || getParent()->isModalMouseInputFocused(); + } + + return mFocusHandler->getModalMouseInputFocused() == this; + } + + Widget *Widget::getWidgetAt(int x, int y) + { + return NULL; + } + + const std::list<MouseListener*>& Widget::_getMouseListeners() + { + return mMouseListeners; + } + + const std::list<KeyListener*>& Widget::_getKeyListeners() + { + return mKeyListeners; + } + + const std::list<FocusListener*>& Widget::_getFocusListeners() + { + return mFocusListeners; + } + + Rectangle Widget::getChildrenArea() + { + return Rectangle(0, 0, 0, 0); + } + + FocusHandler* Widget::_getInternalFocusHandler() + { + return mInternalFocusHandler; + } + + void Widget::setInternalFocusHandler(FocusHandler* focusHandler) + { + mInternalFocusHandler = focusHandler; + } + + void Widget::setId(const std::string& id) + { + mId = id; + } + + const std::string& Widget::getId() + { + return mId; + } + + void Widget::distributeResizedEvent() + { + WidgetListenerIterator iter; + + for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) + { + Event event(this); + (*iter)->widgetResized(event); + } + } + + void Widget::distributeMovedEvent() + { + WidgetListenerIterator iter; + + for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) + { + Event event(this); + (*iter)->widgetMoved(event); + } + } + + void Widget::distributeHiddenEvent() + { + WidgetListenerIterator iter; + + for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) + { + Event event(this); + (*iter)->widgetHidden(event); + } + } + + void Widget::distributeActionEvent() + { + ActionListenerIterator iter; + for (iter = mActionListeners.begin(); iter != mActionListeners.end(); ++iter) + { + ActionEvent actionEvent(this, mActionEventId); + (*iter)->action(actionEvent); + } + } + + void Widget::distributeShownEvent() + { + WidgetListenerIterator iter; + + for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) + { + Event event(this); + (*iter)->widgetShown(event); + } + } + + void Widget::showPart(Rectangle rectangle) + { + if (mParent != NULL) + { + mParent->showWidgetPart(this, rectangle); + } + } +} diff --git a/src/guichan/widget.hpp b/src/guichan/widget.hpp new file mode 100644 index 000000000..e702ffd62 --- /dev/null +++ b/src/guichan/widget.hpp @@ -0,0 +1,1194 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_WIDGET_HPP +#define GCN_WIDGET_HPP + +#include <list> +#include <string> + +#include "guichan/color.hpp" +#include "guichan/rectangle.hpp" + +namespace gcn +{ + class ActionListener; + class BasicContainer; + class DeathListener; + class DefaultFont; + class FocusHandler; + class FocusListener; + class Font; + class Graphics; + class KeyInput; + class KeyListener; + class MouseInput; + class MouseListener; + class WidgetListener; + + /** + * Abstract class for widgets of Guichan. It contains basic functions + * every widget should have. + * + * NOTE: Functions begining with underscore "_" should not + * be overloaded unless you know what you are doing + * + * @author Olof Naessén + * @author Per Larsson. + * @since 0.1.0 + */ + class GCN_CORE_DECLSPEC Widget + { + public: + /** + * Constructor. Resets member variables. Noteable, a widget is not + * focusable as default, therefore, widgets that are supposed to be + * focusable should overide this default in their own constructor. + */ + Widget(); + + /** + * Default destructor. + */ + virtual ~Widget(); + + /** + * Draws the widget. It is called by the parent widget when it is time + * for the widget to draw itself. The graphics object is set up so + * that all drawing is relative to the widget, i.e coordinate (0,0) is + * the top left corner of the widget. It is not possible to draw + * outside of a widget's dimension. + * + * @param graphics aA graphics object to draw with. + * @since 0.1.0 + */ + virtual void draw(Graphics* graphics) = 0; + + /** + * Called when a widget is given a chance to draw a frame around itself. + * The frame is not considered a part of the widget, it only allows a frame + * to be drawn around the widget, thus a frame will never be included when + * calculating if a widget should receive events from user input. Also + * a widget's frame will never be included when calculating a widget's + * position. + * + * The size of the frame is calculated using the widget's frame size. + * If a widget has a frame size of 10 pixels than the area the drawFrame + * function can draw to will be the size of the widget with an additional + * extension of 10 pixels in each direction. + * + * An example when drawFrame is a useful function is if a widget needs + * a glow around itself. + * + * @param graphics A graphics object to draw with. + * @see setFrameSize, getFrameSize + * @since 0.8.0 + */ + virtual void drawFrame(Graphics* graphics); + + /** + * Sets the size of the widget's frame. The frame is not considered a part of + * the widget, it only allows a frame to be drawn around the widget, thus a frame + * will never be included when calculating if a widget should receive events + * from user input. Also a widget's frame will never be included when calculating + * a widget's position. + * + * A frame size of 0 means that the widget has no frame. The default frame size + * is 0. + * + * @param frameSize The size of the widget's frame. + * @see getFrameSize, drawFrame + * @since 0.8.0 + */ + void setFrameSize(unsigned int frameSize); + + /** + * Gets the size of the widget's frame. The frame is not considered a part of + * the widget, it only allows a frame to be drawn around the widget, thus a frame + * will never be included when calculating if a widget should receive events + * from user input. Also a widget's frame will never be included when calculating + * a widget's position. + * + * A frame size of 0 means that the widget has no frame. The default frame size + * is 0. + * + * @return The size of the widget's frame. + * @see setFrameSize, drawFrame + * @since 0.8.0 + */ + unsigned int getFrameSize() const; + + /** + * Called for all widgets in the gui each time Gui::logic is called. + * You can do logic stuff here like playing an animation. + * + * @see Gui::logic + * @since 0.1.0 + */ + virtual void logic() { } + + /** + * Gets the widget's parent container. + * + * @return The widget's parent container. NULL if the widget + * has no parent. + * @since 0.1.0 + */ + virtual Widget* getParent() const; + + /** + * Sets the width of the widget. + * + * @param width The width of the widget. + * @see getWidth, setHeight, getHeight, setSize, + * setDimension, getDimensi + * @since 0.1.0 + */ + void setWidth(int width); + + /** + * Gets the width of the widget. + * + * @return The width of the widget. + * @see setWidth, setHeight, getHeight, setSize, + * setDimension, getDimension + * @since 0.1.0 + */ + int getWidth() const; + + /** + * Sets the height of the widget. + * + * @param height The height of the widget. + * @see getHeight, setWidth, getWidth, setSize, + * setDimension, getDimension + * @since 0.1.0 + */ + void setHeight(int height); + + /** + * Gets the height of the widget. + * + * @return The height of the widget. + * @see setHeight, setWidth, getWidth, setSize, + * setDimension, getDimension + * @since 0.1.0 + */ + int getHeight() const; + + /** + * Sets the size of the widget. + * + * @param width The width of the widget. + * @param height The height of the widget. + * @see setWidth, setHeight, getWidth, getHeight, + * setDimension, getDimension + * @since 0.1.0 + */ + void setSize(int width, int height); + + /** + * Sets the x coordinate of the widget. The coordinate is + * relateive to the widget's parent. + * + * @param x The x coordinate of the widget. + * @see getX, setY, getY, setPosition, setDimension, getDimension + * @since 0.1.0 + */ + void setX(int x); + + /** + * Gets the x coordinate of the widget. The coordinate is + * relative to the widget's parent. + * + * @return The x coordinate of the widget. + * @see setX, setY, getY, setPosition, setDimension, getDimension + * @since 0.1.0 + */ + int getX() const; + + /** + * Sets the y coordinate of the widget. The coordinate is + * relative to the widget's parent. + * + * @param y The y coordinate of the widget. + * @see setY, setX, getX, setPosition, setDimension, getDimension + * @since 0.1.0 + */ + void setY(int y); + + /** + * Gets the y coordinate of the widget. The coordinate is + * relative to the widget's parent. + * + * @return The y coordinate of the widget. + * @see setY, setX, getX, setPosition, setDimension, getDimension + * @since 0.1.0 + */ + int getY() const; + + /** + * Sets position of the widget. The position is relative + * to the widget's parent. + * + * @param x The x coordinate of the widget. + * @param y The y coordinate of the widget. + * @see setX, getX, setY, getY, setDimension, getDimension + * @since 0.1.0 + */ + void setPosition(int x, int y); + + /** + * Sets the dimension of the widget. The dimension is + * relative to the widget's parent. + * + * @param dimension The dimension of the widget. + * @see getDimension, setX, getX, setY, getY, setPosition + * @since 0.1.0 + */ + void setDimension(const Rectangle& dimension); + + /** + * Gets the dimension of the widget. The dimension is + * relative to the widget's parent. + * + * @return The dimension of the widget. + * @see getDimension, setX, getX, setY, getY, setPosition + * @since 0.1.0 + */ + const Rectangle& getDimension() const; + + /** + * Sets the widget to be fosusable, or not. + * + * @param focusable True if the widget should be focusable, + * false otherwise. + * @see isFocusable + * @since 0.1.0 + */ + void setFocusable(bool focusable); + + /** + * Checks if a widget is focsable. + * + * @return True if the widget should be focusable, false otherwise. + * @see setFocusable + * @since 0.1.0 + */ + bool isFocusable() const; + + /** + * Checks if the widget is focused. + * + * @return True if the widget is focused, false otherwise. + * @since 0.1.0 + */ + virtual bool isFocused() const; + + /** + * Sets the widget to enabled, or not. A disabled + * widget will never recieve mouse or key events. + * + * @param enabled True if widget should be enabled, + * false otherwise. + * @see isEnabled + * @since 0.1.0 + */ + void setEnabled(bool enabled); + + /** + * Checks if the widget is enabled. A disabled + * widget will never recieve mouse or key events. + * + * @return True if widget is enabled, false otherwise. + * @see setEnabled + * @since 0.1.0 + */ + bool isEnabled() const; + + /** + * Sets the widget to be visible, or not. + * + * @param visible True if widget should be visible, false otherwise. + * @see isVisible + * @since 0.1.0 + */ + void setVisible(bool visible); + + /** + * Checks if the widget is visible. + * + * @return True if widget is be visible, false otherwise. + * @see setVisible + * @since 0.1.0 + */ + bool isVisible() const; + + /** + * Sets the base color of the widget. + * + * @param color The baseground color. + * @see getBaseColor + * @since 0.1.0 + */ + void setBaseColor(const Color& color); + + /** + * Gets the base color. + * + * @return The base color. + * @see setBaseColor + * @since 0.1.0 + */ + const Color& getBaseColor() const; + + /** + * Sets the foreground color. + * + * @param color The foreground color. + * @see getForegroundColor + * @since 0.1.0 + */ + void setForegroundColor(const Color& color); + + /** + * Gets the foreground color. + * + * @see setForegroundColor + * @since 0.1.0 + */ + const Color& getForegroundColor() const; + + /** + * Sets the background color. + * + * @param color The background Color. + * @see setBackgroundColor + * @since 0.1.0 + */ + void setBackgroundColor(const Color& color); + + /** + * Gets the background color. + * + * @see setBackgroundColor + * @since 0.1.0 + */ + const Color& getBackgroundColor() const; + + /** + * Sets the selection color. + * + * @param color The selection color. + * @see getSelectionColor + * @since 0.6.0 + */ + void setSelectionColor(const Color& color); + + /** + * Gets the selection color. + * + * @return The selection color. + * @see setSelectionColor + * @since 0.6.0 + */ + const Color& getSelectionColor() const; + + /** + * Requests focus for the widget. A widget will only recieve focus + * if it is focusable. + */ + virtual void requestFocus(); + + /** + * Requests a move to the top in the parent widget. + */ + virtual void requestMoveToTop(); + + /** + * Requests a move to the bottom in the parent widget. + */ + virtual void requestMoveToBottom(); + + /** + * Sets the focus handler to be used. + * + * WARNING: This function is used internally and should not + * be called or overloaded unless you know what you + * are doing. + * + * @param focusHandler The focus handler to use. + * @see _getFocusHandler + * @since 0.1.0 + */ + virtual void _setFocusHandler(FocusHandler* focusHandler); + + /** + * Gets the focus handler used. + * + * WARNING: This function is used internally and should not + * be called or overloaded unless you know what you + * are doing. + * + * @return The focus handler used. + * @see _setFocusHandler + * @since 0.1.0 + */ + virtual FocusHandler* _getFocusHandler(); + + /** + * Adds an action listener to the widget. When an action event + * is fired by the widget the action listeners of the widget + * will get notified. + * + * @param actionListener The action listener to add. + * @see removeActionListener + * @since 0.1.0 + */ + void addActionListener(ActionListener* actionListener); + + /** + * Removes an added action listener from the widget. + * + * @param actionListener The action listener to remove. + * @see addActionListener + * @since 0.1.0 + */ + void removeActionListener(ActionListener* actionListener); + + /** + * Adds a death listener to the widget. When a death event is + * fired by the widget the death listeners of the widget will + * get notified. + * + * @param deathListener The death listener to add. + * @see removeDeathListener + * @since 0.1.0 + */ + void addDeathListener(DeathListener* deathListener); + + /** + * Removes an added death listener from the widget. + * + * @param deathListener The death listener to remove. + * @see addDeathListener + * @since 0.1.0 + */ + void removeDeathListener(DeathListener* deathListener); + + /** + * Adds a mouse listener to the widget. When a mouse event is + * fired by the widget the mouse listeners of the widget will + * get notified. + * + * @param mouseListener The mouse listener to add. + * @see removeMouseListener + * @since 0.1.0 + */ + void addMouseListener(MouseListener* mouseListener); + + /** + * Removes an added mouse listener from the widget. + * + * @param mouseListener The mouse listener to remove. + * @see addMouseListener + * @since 0.1.0 + */ + void removeMouseListener(MouseListener* mouseListener); + + /** + * Adds a key listener to the widget. When a key event is + * fired by the widget the key listeners of the widget will + * get notified. + * + * @param keyListener The key listener to add. + * @see removeKeyListener + * @since 0.1.0 + */ + void addKeyListener(KeyListener* keyListener); + + /** + * Removes an added key listener from the widget. + * + * @param keyListener The key listener to remove. + * @see addKeyListener + * @since 0.1.0 + */ + void removeKeyListener(KeyListener* keyListener); + + /** + * Adds a focus listener to the widget. When a focus event is + * fired by the widget the key listeners of the widget will + * get notified. + * + * @param focusListener The focus listener to add. + * @see removeFocusListener + * @since 0.7.0 + */ + void addFocusListener(FocusListener* focusListener); + + /** + * Removes an added focus listener from the widget. + * + * @param focusListener The focus listener to remove. + * @see addFocusListener + * @since 0.7.0 + */ + void removeFocusListener(FocusListener* focusListener); + + /** + * Adds a widget listener to the widget. When a widget event is + * fired by the widget the key listeners of the widget will + * get notified. + * + * @param widgetListener The widget listener to add. + * @see removeWidgetListener + * @since 0.8.0 + */ + void addWidgetListener(WidgetListener* widgetListener); + + /** + * Removes an added widget listener from the widget. + * + * @param widgetListener The widget listener to remove. + * @see addWidgetListener + * @since 0.8.0 + */ + void removeWidgetListener(WidgetListener* widgetListener); + + /** + * Sets the action event identifier of the widget. The identifier is + * used to be able to identify which action has occured. + * + * NOTE: An action event identifier should not be used to identify a + * certain widget but rather a certain event in your application. + * Several widgets can have the same action event identifer. + * + * @param actionEventId The action event identifier. + * @see getActionEventId + * @since 0.6.0 + */ + void setActionEventId(const std::string& actionEventId); + + /** + * Gets the action event identifier of the widget. + * + * @return The action event identifier of the widget. + * @see setActionEventId + * @since 0.6.0 + */ + const std::string& getActionEventId() const; + + /** + * Gets the absolute position on the screen for the widget. + * + * @param x The absolute x coordinate will be stored in this parameter. + * @param y The absolute y coordinate will be stored in this parameter. + * @since 0.1.0 + */ + virtual void getAbsolutePosition(int& x, int& y) const; + + /** + * Sets the parent of the widget. A parent must be a BasicContainer. + * + * WARNING: This function is used internally and should not + * be called or overloaded unless you know what you + * are doing. + * + * @param parent The parent of the widget. + * @see getParent + * @since 0.1.0 + */ + virtual void _setParent(Widget* parent); + + /** + * Gets the font set for the widget. If no font has been set, + * the global font will be returned. If no global font has been set, + * the default font will be returend. + * + * @return The font set for the widget. + * @see setFont, setGlobalFont + * @since 0.1.0 + */ + Font *getFont() const; + + /** + * Sets the global font to be used by default for all widgets. + * + * @param font The global font. + * @see getGlobalFont + * @since 0.1.0 + */ + static void setGlobalFont(Font* font); + + /** + * Sets the font for the widget. If NULL is passed, the global font + * will be used. + * + * @param font The font to set for the widget. + * @see getFont + * @since 0.1.0 + */ + void setFont(Font* font); + + /** + * Called when the font has changed. If the change is global, + * this function will only be called if the widget doesn't have a + * font already set. + * + * @since 0.1.0 + */ + virtual void fontChanged() { } + + /** + * Checks if a widget exists or not, that is if it still exists + * an instance of the object. + * + * @param widget The widget to check. + * @return True if an instance of the widget exists, false otherwise. + * @since 0.1.0 + */ + static bool widgetExists(const Widget* widget); + + /** + * Checks if tab in is enabled. Tab in means that you can set focus + * to this widget by pressing the tab button. If tab in is disabled + * then the focus handler will skip this widget and focus the next + * in its focus order. + * + * @return True if tab in is enabled, false otherwise. + * @see setTabInEnabled + * @since 0.1.0 + */ + bool isTabInEnabled() const; + + /** + * Sets tab in enabled, or not. Tab in means that you can set focus + * to this widget by pressing the tab button. If tab in is disabled + * then the FocusHandler will skip this widget and focus the next + * in its focus order. + * + * @param enabled True if tab in should be enabled, false otherwise. + * @see isTabInEnabled + * @since 0.1.0 + */ + void setTabInEnabled(bool enabled); + + /** + * Checks if tab out is enabled. Tab out means that you can lose + * focus to this widget by pressing the tab button. If tab out is + * disabled then the FocusHandler ignores tabbing and focus will + * stay with this widget. + * + * @return True if tab out is enabled, false otherwise. + * @see setTabOutEnabled + * @since 0.1.0 + */ + bool isTabOutEnabled() const; + + /** + * Sets tab out enabled. Tab out means that you can lose + * focus to this widget by pressing the tab button. If tab out is + * disabled then the FocusHandler ignores tabbing and focus will + * stay with this widget. + * + * @param enabled True if tab out should be enabled, false otherwise. + * @see isTabOutEnabled + * @since 0.1.0 + */ + void setTabOutEnabled(bool enabled); + + /** + * Requests modal focus. When a widget has modal focus, only that + * widget and it's children may recieve input. + * + * @throws Exception if another widget already has modal focus. + * @see releaseModalFocus, isModalFocused + * @since 0.4.0 + */ + virtual void requestModalFocus(); + + /** + * Requests modal mouse input focus. When a widget has modal input focus + * that widget will be the only widget receiving input even if the input + * occurs outside of the widget and no matter what the input is. + * + * @throws Exception if another widget already has modal focus. + * @see releaseModalMouseInputFocus, isModalMouseInputFocused + * @since 0.6.0 + */ + virtual void requestModalMouseInputFocus(); + + /** + * Releases modal focus. Modal focus will only be released if the + * widget has modal focus. + * + * @see requestModalFocus, isModalFocused + * @since 0.4.0 + */ + virtual void releaseModalFocus(); + + /** + * Releases modal mouse input focus. Modal mouse input focus will only + * be released if the widget has modal mouse input focus. + * + * @see requestModalMouseInputFocus, isModalMouseInputFocused + * @since 0.6.0 + */ + virtual void releaseModalMouseInputFocus(); + + /** + * Checks if the widget or it's parent has modal focus. + * + * @return True if the widget has modal focus, false otherwise. + * @see requestModalFocus, releaseModalFocus + * @since 0.8.0 + */ + virtual bool isModalFocused() const; + + /** + * Checks if the widget or it's parent has modal mouse input focus. + * + * @return True if the widget has modal mouse input focus, false + * otherwise. + * @see requestModalMouseInputFocus, releaseModalMouseInputFocus + * @since 0.8.0 + */ + virtual bool isModalMouseInputFocused() const; + + /** + * Gets a widget from a certain position in the widget. + * This function is used to decide which gets mouse input, + * thus it can be overloaded to change that behaviour. + * + * NOTE: This always returns NULL if the widget is not + * a container. + * + * @param x The x coordinate of the widget to get. + * @param y The y coordinate of the widget to get. + * @return The widget at the specified coodinate, NULL + * if no widget is found. + * @since 0.6.0 + */ + virtual Widget *getWidgetAt(int x, int y); + + /** + * Gets the mouse listeners of the widget. + * + * @return The mouse listeners of the widget. + * @since 0.6.0 + */ + virtual const std::list<MouseListener*>& _getMouseListeners(); + + /** + * Gets the key listeners of the widget. + * + * @return The key listeners of the widget. + * @since 0.6.0 + */ + virtual const std::list<KeyListener*>& _getKeyListeners(); + + /** + * Gets the focus listeners of the widget. + * + * @return The focus listeners of the widget. + * @since 0.7.0 + */ + virtual const std::list<FocusListener*>& _getFocusListeners(); + + /** + * Gets the area of the widget occupied by the widget's children. + * By default this method returns an empty rectangle as not all + * widgets are containers. If you want to make a container this + * method should return the area where the children resides. This + * method is used when drawing children of a widget when computing + * clip rectangles for the children. + * + * An example of a widget that overloads this method is ScrollArea. + * A ScrollArea has a view of its contant and that view is the + * children area. The size of a ScrollArea's children area might + * vary depending on if the scroll bars of the ScrollArea is shown + * or not. + * + * @return The area of the widget occupied by the widget's children. + * @see BasicContainer + * @see BasicContainer::getChildrenArea + * @see BasicContainer::drawChildren + * @since 0.1.0 + */ + virtual Rectangle getChildrenArea(); + + /** + * Gets the internal focus handler used. + * + * @return the internalFocusHandler used. If no internal focus handler + * is used, NULL will be returned. + * @see setInternalFocusHandler + * @since 0.1.0 + */ + virtual FocusHandler* _getInternalFocusHandler(); + + /** + * Sets the internal focus handler. An internal focus handler is + * needed if both a widget in the widget and the widget itself + * should be foucsed at the same time. + * + * @param focusHandler The internal focus handler to be used. + * @see getInternalFocusHandler + * @since 0.1.0 + */ + void setInternalFocusHandler(FocusHandler* internalFocusHandler); + + /** + * Moves a widget to the top of this widget. The moved widget will be + * drawn above all other widgets in this widget. + * + * @param widget The widget to move to the top. + * @see moveToBottom + * @since 0.1.0 + */ + virtual void moveToTop(Widget* widget) { }; + + /** + * Moves a widget in this widget to the bottom of this widget. + * The moved widget will be drawn below all other widgets in this widget. + * + * @param widget The widget to move to the bottom. + * @see moveToTop + * @since 0.1.0 + */ + virtual void moveToBottom(Widget* widget) { }; + + /** + * Focuses the next widget in the widget. + * + * @see moveToBottom + * @since 0.1.0 + */ + virtual void focusNext() { }; + + /** + * Focuses the previous widget in the widget. + * + * @see moveToBottom + * @since 0.1.0 + */ + virtual void focusPrevious() { }; + + /** + * Tries to show a specific part of a widget by moving it. Used if the + * widget should act as a container. + * + * @param widget The target widget. + * @param area The area to show. + * @since 0.1.0 + */ + virtual void showWidgetPart(Widget* widget, Rectangle area) { }; + + /** + * Sets an id of a widget. An id can be useful if a widget needs to be + * identified in a container. For example, if widgets are created by an + * XML document, a certain widget can be retrieved given that the widget + * has an id. + * + * @param id The id to set to the widget. + * @see getId, BasicContainer::findWidgetById + * @since 0.8.0 + */ + void setId(const std::string& id); + + /** + * Gets the id of a widget. An id can be useful if a widget needs to be + * identified in a container. For example, if widgets are created by an + * XML document, a certain widget can be retrieved given that the widget + * has an id. + * + * @param id The id to set to the widget. + * @see setId, BasicContainer::findWidgetById + * @since 0.8.0 + */ + const std::string& getId(); + + /** + * Shows a certain part of a widget in the widget's parent. + * Used when widgets want a specific part to be visible in + * its parent. An example is a TextArea that wants a specific + * part of its text to be visible when a TextArea is a child + * of a ScrollArea. + * + * @param rectangle The rectangle to be shown. + * @since 0.8.0 + */ + virtual void showPart(Rectangle rectangle); + + protected: + /** + * Distributes an action event to all action listeners + * of the widget. + * + * @since 0.8.0 + */ + void distributeActionEvent(); + + /** + * Distributes resized events to all of the widget's listeners. + * + * @since 0.8.0 + */ + void distributeResizedEvent(); + + /** + * Distributes moved events to all of the widget's listeners. + * + * @since 0.8.0 + */ + void distributeMovedEvent(); + + /** + * Distributes hidden events to all of the widget's listeners. + * + * @since 0.8.0 + * @author Olof Naessén + */ + void distributeHiddenEvent(); + + /** + * Distributes shown events to all of the widget's listeners. + * + * @since 0.8.0 + * @author Olof Naessén + */ + void distributeShownEvent(); + + /** + * Typdef. + */ + typedef std::list<MouseListener*> MouseListenerList; + + /** + * Typdef. + */ + typedef MouseListenerList::iterator MouseListenerIterator; + + /** + * Holds the mouse listeners of the widget. + */ + MouseListenerList mMouseListeners; + + /** + * Typdef. + */ + typedef std::list<KeyListener*> KeyListenerList; + + /** + * Holds the key listeners of the widget. + */ + KeyListenerList mKeyListeners; + + /** + * Typdef. + */ + typedef KeyListenerList::iterator KeyListenerIterator; + + /** + * Typdef. + */ + typedef std::list<ActionListener*> ActionListenerList; + + /** + * Holds the action listeners of the widget. + */ + ActionListenerList mActionListeners; + + /** + * Typdef. + */ + typedef ActionListenerList::iterator ActionListenerIterator; + + /** + * Typdef. + */ + typedef std::list<DeathListener*> DeathListenerList; + + /** + * Holds the death listeners of the widget. + */ + DeathListenerList mDeathListeners; + + /** + * Typdef. + */ + typedef DeathListenerList::iterator DeathListenerIterator; + + /** + * Typdef. + */ + typedef std::list<FocusListener*> FocusListenerList; + + /** + * Holds the focus listeners of the widget. + */ + FocusListenerList mFocusListeners; + + /** + * Typdef. + */ + typedef FocusListenerList::iterator FocusListenerIterator; + + typedef std::list<WidgetListener*> WidgetListenerList; + + /** + * Holds the widget listeners of the widget. + */ + WidgetListenerList mWidgetListeners; + + /** + * Typdef. + */ + typedef WidgetListenerList::iterator WidgetListenerIterator; + + /** + * Holds the foreground color of the widget. + */ + Color mForegroundColor; + + /** + * Holds the background color of the widget. + */ + Color mBackgroundColor; + + /** + * Holds the base color of the widget. + */ + Color mBaseColor; + + /** + * Holds the selection color of the widget. + */ + Color mSelectionColor; + + /** + * Holds the focus handler used by the widget. + */ + FocusHandler* mFocusHandler; + + /** + * Holds the focus handler used by the widget. NULL + * if no internal focus handler is used. + */ + FocusHandler* mInternalFocusHandler; + + /** + * Holds the parent of the widget. NULL if the widget + * has no parent. + */ + Widget* mParent; + + /** + * Holds the dimension of the widget. + */ + Rectangle mDimension; + + /** + * Holds the frame size of the widget. + */ + unsigned int mFrameSize; + + /** + * Holds the action event of the widget. + */ + std::string mActionEventId; + + /** + * True if the widget focusable, false otherwise. + */ + bool mFocusable; + + /** + * True if the widget visible, false otherwise. + */ + bool mVisible; + + /** + * True if the widget has tab in enabled, false otherwise. + */ + bool mTabIn; + + /** + * True if the widget has tab in enabled, false otherwise. + */ + bool mTabOut; + + /** + * True if the widget is enabled, false otherwise. + */ + bool mEnabled; + + /** + * Holds the id of the widget. + */ + std::string mId; + + /** + * Holds the font used by the widget. + */ + Font* mCurrentFont; + + /** + * Holds the default font used by the widget. + */ + static DefaultFont mDefaultFont; + + /** + * Holds the global font used by the widget. + */ + static Font* mGlobalFont; + + /** + * Holds a list of all instances of widgets. + */ + static std::list<Widget*> mWidgets; + }; +} + +#endif // end GCN_WIDGET_HPP diff --git a/src/guichan/widgetlistener.hpp b/src/guichan/widgetlistener.hpp new file mode 100644 index 000000000..5519761a5 --- /dev/null +++ b/src/guichan/widgetlistener.hpp @@ -0,0 +1,118 @@ +/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ *
+ *
+ * Per Larsson a.k.a finalman
+ * Olof Naessén a.k.a jansem/yakslem
+ *
+ * Visit: http://guichan.sourceforge.net
+ *
+ * License: (BSD)
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Guichan nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GCN_WIDGETLISTENER_HPP
+#define GCN_WIDGETLISTENER_HPP
+
+#include <string>
+
+#include "guichan/event.hpp"
+#include "guichan/platform.hpp"
+
+namespace gcn
+{
+ /**
+ * Interface for listening for events from widgets. When a widget's size,
+ * location or visibility changes, the relevant method of the listener is
+ * invoked.
+ *
+ * @see Widget::addWidgetListener, Widget::removeWidgetListener
+ * @author Olof Naessén
+ * @since 0.8.0
+ */
+ class GCN_CORE_DECLSPEC WidgetListener
+ {
+ public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~WidgetListener() { }
+
+ /**
+ * Invoked when a widget changes its size.
+ *
+ * @param event Describes the event.
+ * @since 0.8.0
+ */
+ virtual void widgetResized(const Event& event) { }
+
+ /**
+ * Invoked when a widget is moved.
+ *
+ * @param event Describes the event.
+ * @since 0.8.0
+ */
+ virtual void widgetMoved(const Event& event) { }
+
+ /**
+ * Invoked when a widget is hidden, i.e it's set to be
+ * not visible.
+ *
+ * @param event Describes the event.
+ * @since 0.8.0
+ */
+ virtual void widgetHidden(const Event& event) { }
+
+ /**
+ * Invoked when a widget is shown, i.e it's set to be
+ * visible.
+ *
+ * @param event Describes the event.
+ * @since 0.8.0
+ */
+ virtual void widgetShown(const Event& event) { }
+
+ protected:
+ /**
+ * Constructor.
+ *
+ * You should not be able to make an instance of WidgetListener,
+ * therefore its constructor is protected.
+ */
+ WidgetListener() { }
+
+ };
+}
+
+#endif // end GCN_WIDGETLISTENER_HPP
diff --git a/src/guichan/widgets/button.cpp b/src/guichan/widgets/button.cpp new file mode 100644 index 000000000..199f5c96e --- /dev/null +++ b/src/guichan/widgets/button.cpp @@ -0,0 +1,284 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/button.hpp" + +#include "guichan/exception.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseevent.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + Button::Button() + : mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4) + { + setFocusable(true); + adjustSize(); + setFrameSize(1); + + addMouseListener(this); + addKeyListener(this); + addFocusListener(this); + } + + Button::Button(const std::string& caption) + : mCaption(caption), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4) + { + setFocusable(true); + adjustSize(); + setFrameSize(1); + + addMouseListener(this); + addKeyListener(this); + addFocusListener(this); + } + + void Button::setCaption(const std::string& caption) + { + mCaption = caption; + } + + const std::string& Button::getCaption() const + { + return mCaption; + } + + void Button::setAlignment(Graphics::Alignment alignment) + { + mAlignment = alignment; + } + + Graphics::Alignment Button::getAlignment() const + { + return mAlignment; + } + + void Button::setSpacing(unsigned int spacing) + { + mSpacing = spacing; + } + + unsigned int Button::getSpacing() const + { + return mSpacing; + } + + void Button::draw(Graphics* graphics) + { + Color faceColor = getBaseColor(); + Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + + if (isPressed()) + { + faceColor = faceColor - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor + 0x303030; + shadowColor.a = alpha; + } + else + { + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(1, 1, getDimension().width-1, getHeight() - 1)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, getHeight() - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); + graphics->drawLine(1, getHeight() - 1, getWidth() - 1, getHeight() - 1); + + graphics->setColor(getForegroundColor()); + + int textX; + int textY = getHeight() / 2 - getFont()->getHeight() / 2; + + switch (getAlignment()) + { + case Graphics::LEFT: + textX = mSpacing; + break; + case Graphics::CENTER: + textX = getWidth() / 2; + break; + case Graphics::RIGHT: + textX = getWidth() - mSpacing; + break; + default: + throw GCN_EXCEPTION("Unknown alignment."); + } + + graphics->setFont(getFont()); + + if (isPressed()) + { + graphics->drawText(getCaption(), textX + 1, textY + 1, getAlignment()); + } + else + { + graphics->drawText(getCaption(), textX, textY, getAlignment()); + + if (isFocused()) + { + graphics->drawRectangle(Rectangle(2, 2, getWidth() - 4, + getHeight() - 4)); + } + } + } + + void Button::adjustSize() + { + setWidth(getFont()->getWidth(mCaption) + 2*mSpacing); + setHeight(getFont()->getHeight() + 2*mSpacing); + } + + bool Button::isPressed() const + { + if (mMousePressed) + { + return mHasMouse; + } + else + { + return mKeyPressed; + } + } + + void Button::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mMousePressed = true; + mouseEvent.consume(); + } + } + + void Button::mouseExited(MouseEvent& mouseEvent) + { + mHasMouse = false; + } + + void Button::mouseEntered(MouseEvent& mouseEvent) + { + mHasMouse = true; + } + + void Button::mouseReleased(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT + && mMousePressed + && mHasMouse) + { + mMousePressed = false; + distributeActionEvent(); + mouseEvent.consume(); + } + else if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mMousePressed = false; + mouseEvent.consume(); + } + } + + void Button::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void Button::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::ENTER + || key.getValue() == Key::SPACE) + { + mKeyPressed = true; + keyEvent.consume(); + } + } + + void Button::keyReleased(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if ((key.getValue() == Key::ENTER + || key.getValue() == Key::SPACE) + && mKeyPressed) + { + mKeyPressed = false; + distributeActionEvent(); + keyEvent.consume(); + } + } + + void Button::focusLost(const Event& event) + { + mMousePressed = false; + mKeyPressed = false; + } +} diff --git a/src/guichan/widgets/button.hpp b/src/guichan/widgets/button.hpp new file mode 100644 index 000000000..cfe097327 --- /dev/null +++ b/src/guichan/widgets/button.hpp @@ -0,0 +1,214 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_BUTTON_HPP +#define GCN_BUTTON_HPP + +#include <string> + +#include "guichan/focuslistener.hpp" +#include "guichan/graphics.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/mouseevent.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * An implementation of a regular clickable button. A button is capable of + * displaying a caption. + * + * If a button is clicked an action event will be sent to all action listener's + * of the button. + * + * @see ImageButton + */ + class GCN_CORE_DECLSPEC Button : public Widget, + public MouseListener, + public KeyListener, + public FocusListener + { + public: + /** + * Constructor. + */ + Button(); + + /** + * Constructor. The button will be automatically resized + * to fit the caption. + * + * @param caption The caption of the button. + */ + Button(const std::string& caption); + + /** + * Sets the caption of the button. It's advisable to call + * adjustSize after setting of the caption to adjust the + * button's size to fit the caption. + * + * @param caption The caption of the button. + * @see getCaption, adjustSize + */ + void setCaption(const std::string& caption); + + /** + * Gets the caption of the button. + * + * @return The caption of the button. + */ + const std::string& getCaption() const; + + /** + * Sets the alignment of the caption. The alignment is relative + * to the center of the button. + * + * @param alignment The alignment of the caption. + * @see getAlignment, Graphics + */ + void setAlignment(Graphics::Alignment alignment); + + /** + * Gets the alignment of the caption. + * + * @return The alignment of the caption. + * @see setAlignment, Graphics + */ + Graphics::Alignment getAlignment() const; + + /** + * Sets the spacing between the border of the button and its caption. + * + * @param spacing The default value for spacing is 4 and can be changed + * using this method. + * @see getSpacing + */ + void setSpacing(unsigned int spacing); + + /** + * Gets the spacing between the border of the button and its caption. + * + * @return spacing. + * @see setSpacing + */ + unsigned int getSpacing() const; + + /** + * Adjusts the button's size to fit the caption. + */ + void adjustSize(); + + + //Inherited from Widget + + virtual void draw(Graphics* graphics); + + + // Inherited from FocusListener + + virtual void focusLost(const Event& event); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseReleased(MouseEvent& mouseEvent); + + virtual void mouseEntered(MouseEvent& mouseEvent); + + virtual void mouseExited(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + virtual void keyReleased(KeyEvent& keyEvent); + + protected: + /** + * Checks if the button is pressed. Convenient method to use + * when overloading the draw method of the button. + * + * @return True if the button is pressed, false otherwise. + */ + bool isPressed() const; + + /** + * Holds the caption of the button. + */ + std::string mCaption; + + /** + * True if the mouse is ontop of the button, false otherwise. + */ + bool mHasMouse; + + /** + * True if a key has been pressed, false otherwise. + */ + bool mKeyPressed; + + /** + * True if a mouse has been pressed, false otherwise. + */ + bool mMousePressed; + + /** + * Holds the alignment of the caption. + */ + Graphics::Alignment mAlignment; + + /** + * Holds the spacing between the border and the caption. + */ + unsigned int mSpacing; + }; +} + +#endif // end GCN_BUTTON_HPP diff --git a/src/guichan/widgets/checkbox.cpp b/src/guichan/widgets/checkbox.cpp new file mode 100644 index 000000000..5f0a52612 --- /dev/null +++ b/src/guichan/widgets/checkbox.cpp @@ -0,0 +1,189 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/checkbox.hpp" + +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + + CheckBox::CheckBox() + { + setSelected(false); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + } + + CheckBox::CheckBox(const std::string &caption, bool selected) + { + setCaption(caption); + setSelected(selected); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + + adjustSize(); + } + + void CheckBox::draw(Graphics* graphics) + { + drawBox(graphics); + + graphics->setFont(getFont()); + graphics->setColor(getForegroundColor()); + + const int h = getHeight() + getHeight() / 2; + + graphics->drawText(getCaption(), h - 2, 0); + } + + void CheckBox::drawBox(Graphics *graphics) + { + const int h = getHeight() - 2; + const int alpha = getBaseColor().a; + Color faceColor = getBaseColor(); + faceColor.a = alpha; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(shadowColor); + graphics->drawLine(1, 1, h, 1); + graphics->drawLine(1, 1, 1, h); + + graphics->setColor(highlightColor); + graphics->drawLine(h, 1, h, h); + graphics->drawLine(1, h, h - 1, h); + + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(Rectangle(2, 2, h - 2, h - 2)); + + graphics->setColor(getForegroundColor()); + + if (isFocused()) + { + graphics->drawRectangle(Rectangle(0, 0, h + 2, h + 2)); + } + + if (mSelected) + { + graphics->drawLine(3, 5, 3, h - 2); + graphics->drawLine(4, 5, 4, h - 2); + + graphics->drawLine(5, h - 3, h - 2, 4); + graphics->drawLine(5, h - 4, h - 4, 5); + } + } + + bool CheckBox::isSelected() const + { + return mSelected; + } + + void CheckBox::setSelected(bool selected) + { + mSelected = selected; + } + + const std::string &CheckBox::getCaption() const + { + return mCaption; + } + + void CheckBox::setCaption(const std::string& caption) + { + mCaption = caption; + } + + void CheckBox::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::ENTER || + key.getValue() == Key::SPACE) + { + toggleSelected(); + keyEvent.consume(); + } + } + + void CheckBox::mouseClicked(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + toggleSelected(); + } + } + + void CheckBox::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void CheckBox::adjustSize() + { + int height = getFont()->getHeight(); + + setHeight(height); + setWidth(getFont()->getWidth(mCaption) + height + height / 2); + } + + void CheckBox::toggleSelected() + { + mSelected = !mSelected; + distributeActionEvent(); + } +} + diff --git a/src/guichan/widgets/checkbox.hpp b/src/guichan/widgets/checkbox.hpp new file mode 100644 index 000000000..ad43e2896 --- /dev/null +++ b/src/guichan/widgets/checkbox.hpp @@ -0,0 +1,173 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_CHECKBOX_HPP +#define GCN_CHECKBOX_HPP + +#include <string> + +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * An implementation of a check box where a user can select or deselect + * the check box and where the status of the check box is displayed to the user. + * A check box is capable of displaying a caption. + * + * If a check box's state changes an action event will be sent to all action + * listeners of the check box. + */ + class GCN_CORE_DECLSPEC CheckBox : + public Widget, + public MouseListener, + public KeyListener + { + public: + + /** + * Contructor. + */ + CheckBox(); + + /** + * Constructor. The check box will be automatically resized + * to fit the caption. + * + * @param caption The caption of the check box. + * @param marked True if the check box is selected, false otherwise. + */ + CheckBox(const std::string &caption, bool selected = false); + + /** + * Destructor. + */ + virtual ~CheckBox() { } + + /** + * Checks if the check box is selected. + * + * @return True if the check box is selected, false otherwise. + * @see setSelected + */ + bool isSelected() const; + + /** + * Sets the check box to be selected or not. + * + * @param selected True if the check box should be set as selected. + * @see isSelected + */ + void setSelected(bool selected); + + /** + * Gets the caption of the check box. + * + * @return The caption of the check box. + * @see setCaption + */ + const std::string &getCaption() const; + + /** + * Sets the caption of the check box. It's advisable to call + * adjustSize after setting of the caption to adjust the + * check box's size to fit the caption. + * + * @param caption The caption of the check box. + * @see getCaption, adjustSize + */ + void setCaption(const std::string& caption); + + /** + * Adjusts the check box's size to fit the caption. + */ + void adjustSize(); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mouseClicked(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + + protected: + /** + * Draws the box of the check box. + * + * @param graphics A Graphics object to draw with. + */ + virtual void drawBox(Graphics *graphics); + + /** + * Toggles the check box between being selected and + * not being selected. + */ + virtual void toggleSelected(); + + /** + * True if the check box is selected, false otherwise. + */ + bool mSelected; + + /** + * Holds the caption of the check box. + */ + std::string mCaption; + }; +} + +#endif // end GCN_CHECKBOX_HPP diff --git a/src/guichan/widgets/container.cpp b/src/guichan/widgets/container.cpp new file mode 100644 index 000000000..c9a845497 --- /dev/null +++ b/src/guichan/widgets/container.cpp @@ -0,0 +1,112 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/container.hpp" + +#include "guichan/exception.hpp" +#include "guichan/graphics.hpp" + +namespace gcn +{ + + Container::Container() + { + mOpaque = true; + } + + Container::~Container() + { + + } + + void Container::draw(Graphics* graphics) + { + if (isOpaque()) + { + graphics->setColor(getBaseColor()); + graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); + } + + drawChildren(graphics); + } + + void Container::setOpaque(bool opaque) + { + mOpaque = opaque; + } + + bool Container::isOpaque() const + { + return mOpaque; + } + + void Container::add(Widget* widget) + { + BasicContainer::add(widget); + } + + void Container::add(Widget* widget, int x, int y) + { + widget->setPosition(x, y); + BasicContainer::add(widget); + } + + void Container::remove(Widget* widget) + { + BasicContainer::remove(widget); + } + + void Container::clear() + { + BasicContainer::clear(); + } + + Widget* Container::findWidgetById(const std::string &id) + { + return BasicContainer::findWidgetById(id); + } +} diff --git a/src/guichan/widgets/container.hpp b/src/guichan/widgets/container.hpp new file mode 100644 index 000000000..4946b1f74 --- /dev/null +++ b/src/guichan/widgets/container.hpp @@ -0,0 +1,162 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_CONTAINER_HPP +#define GCN_CONTAINER_HPP + +#include <list> + +#include "guichan/basiccontainer.hpp" +#include "guichan/graphics.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * An implementation of a container able to contain other widgets. A widget's + * position in the container is relative to the container itself and not the screen. + * A container is the most common widget to use as the Gui's top widget as makes the Gui + * able to contain more than one widget. + * + * @see Gui::setTop + */ + class GCN_CORE_DECLSPEC Container: public BasicContainer + { + public: + + /** + * Constructor. A container is opauqe as default, if you want a + * none opaque container call setQpaque(false). + * + * @see setOpaque, isOpaque + */ + Container(); + + /** + * Destructor. + */ + virtual ~Container(); + + /** + * Sets the container to be opaque or not. If the container + * is opaque its background will be drawn, if it's not opaque + * its background will not be drawn, and thus making the container + * completely transparent. + * + * NOTE: This is not the same as to set visibility. A non visible + * container will not itself nor will it draw its content. + * + * @param opaque True if the container should be opaque, false otherwise. + * @see isOpaque + */ + void setOpaque(bool opaque); + + /** + * Checks if the container is opaque or not. + * + * @return True if the container is opaque, false otherwise. + * @see setOpaque + */ + bool isOpaque() const; + + /** + * Adds a widget to the container. + * + * @param widget The widget to add. + * @see remove, clear + */ + virtual void add(Widget* widget); + + /** + * Adds a widget to the container and also specifies the widget's + * position in the container. The position is relative to the container + * and not relative to the screen. + * + * @param widget The widget to add. + * @param x The x coordinate for the widget. + * @param y The y coordinate for the widget. + * @see remove, clear + */ + virtual void add(Widget* widget, int x, int y); + + /** + * Removes a widget from the Container. + * + * @param widget The widget to remove. + * @throws Exception when the widget has not been added to the + * container. + * @see add, clear + */ + virtual void remove(Widget* widget); + + /** + * Clears the container of all widgets. + * + * @see add, remove + */ + virtual void clear(); + + /** + * Finds a widget given an id. + * + * @param id The id to find a widget by. + * @return A widget with a corrosponding id, NULL if no widget + * is found. + * @see Widget::setId + */ + virtual Widget* findWidgetById(const std::string &id); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + protected: + /** + * True if the container is opaque, false otherwise. + */ + bool mOpaque; + }; +} + +#endif // end GCN_CONTAINER_HPP diff --git a/src/guichan/widgets/dropdown.cpp b/src/guichan/widgets/dropdown.cpp new file mode 100644 index 000000000..ad0a14cf5 --- /dev/null +++ b/src/guichan/widgets/dropdown.cpp @@ -0,0 +1,635 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "guichan/widgets/dropdown.hpp" + +#include "guichan/exception.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/listmodel.hpp" +#include "guichan/mouseinput.hpp" +#include "guichan/widgets/listbox.hpp" +#include "guichan/widgets/scrollarea.hpp" + +namespace gcn +{ + DropDown::DropDown(ListModel *listModel, + ScrollArea *scrollArea, + ListBox *listBox) + { + setWidth(100); + setFocusable(true); + mDroppedDown = false; + mPushed = false; + mIsDragged = false; + + setInternalFocusHandler(&mInternalFocusHandler); + + mInternalScrollArea = (scrollArea == NULL); + mInternalListBox = (listBox == NULL); + + if (mInternalScrollArea) + { + mScrollArea = new ScrollArea(); + } + else + { + mScrollArea = scrollArea; + } + + if (mInternalListBox) + { + mListBox = new ListBox(); + } + else + { + mListBox = listBox; + } + + mScrollArea->setContent(mListBox); + add(mScrollArea); + + mListBox->addActionListener(this); + mListBox->addSelectionListener(this); + + setListModel(listModel); + + if (mListBox->getSelected() < 0) + { + mListBox->setSelected(0); + } + + addMouseListener(this); + addKeyListener(this); + addFocusListener(this); + + adjustHeight(); + } + + DropDown::~DropDown() + { + if (widgetExists(mListBox)) + { + mListBox->removeActionListener(this); + mListBox->removeSelectionListener(this); + } + + if (mInternalScrollArea) + { + delete mScrollArea; + } + + if (mInternalListBox) + { + delete mListBox; + } + + setInternalFocusHandler(NULL); + } + + void DropDown::draw(Graphics* graphics) + { + int h; + + if (mDroppedDown) + { + h = mFoldedUpHeight; + } + else + { + h = getHeight(); + } + + Color faceColor = getBaseColor(); + Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + // Draw a border. + graphics->setColor(shadowColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, h - 2); + graphics->setColor(highlightColor); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, h - 1); + graphics->drawLine(0, h - 1, getWidth() - 1, h - 1); + + // Push a clip area so the other drawings don't need to worry + // about the border. + graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, h - 2)); + const Rectangle currentClipArea = graphics->getCurrentClipArea(); + + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(Rectangle(0, 0, currentClipArea.width, currentClipArea.height)); + + if (isFocused()) + { + graphics->setColor(getSelectionColor()); + graphics->fillRectangle(Rectangle(0, + 0, + currentClipArea.width - currentClipArea.height, + currentClipArea.height)); + graphics->setColor(getForegroundColor()); + } + + if (mListBox->getListModel() + && mListBox->getSelected() >= 0) + { + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + + graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0); + } + + // Push a clip area before drawing the button. + graphics->pushClipArea(Rectangle(currentClipArea.width - currentClipArea.height, + 0, + currentClipArea.height, + currentClipArea.height)); + drawButton(graphics); + graphics->popClipArea(); + graphics->popClipArea(); + + if (mDroppedDown) + { + // Draw a border around the children. + graphics->setColor(shadowColor); + graphics->drawRectangle(Rectangle(0, + mFoldedUpHeight, + getWidth(), + getHeight() - mFoldedUpHeight)); + drawChildren(graphics); + } + } + + void DropDown::drawButton(Graphics *graphics) + { + Color faceColor, highlightColor, shadowColor; + int offset; + int alpha = getBaseColor().a; + + if (mPushed) + { + faceColor = getBaseColor() - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor + 0x303030; + shadowColor.a = alpha; + offset = 1; + } + else + { + faceColor = getBaseColor(); + faceColor.a = alpha; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + offset = 0; + } + + const Rectangle currentClipArea = graphics->getCurrentClipArea(); + graphics->setColor(highlightColor); + graphics->drawLine(0, + 0, + currentClipArea.width - 1, + 0); + graphics->drawLine(0, + 1, + 0, + currentClipArea.height - 1); + graphics->setColor(shadowColor); + graphics->drawLine(currentClipArea.width - 1, + 1, + currentClipArea.width - 1, + currentClipArea.height - 1); + graphics->drawLine(1, + currentClipArea.height - 1, + currentClipArea.width - 2, + currentClipArea.height - 1); + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(1, + 1, + currentClipArea.width - 2, + currentClipArea.height - 2)); + + graphics->setColor(getForegroundColor()); + + int i; + int n = currentClipArea.height / 3; + int dx = currentClipArea.height / 2; + int dy = (currentClipArea.height * 2) / 3; + for (i = 0; i < n; i++) + { + graphics->drawLine(dx - i + offset, + dy - i + offset, + dx + i + offset, + dy - i + offset); + } + } + + int DropDown::getSelected() const + { + return mListBox->getSelected(); + } + + void DropDown::setSelected(int selected) + { + if (selected >= 0) + { + mListBox->setSelected(selected); + } + } + + void DropDown::keyPressed(KeyEvent& keyEvent) + { + if (keyEvent.isConsumed()) + return; + + Key key = keyEvent.getKey(); + + if ((key.getValue() == Key::ENTER || key.getValue() == Key::SPACE) + && !mDroppedDown) + { + dropDown(); + keyEvent.consume(); + } + else if (key.getValue() == Key::UP) + { + setSelected(getSelected() - 1); + keyEvent.consume(); + } + else if (key.getValue() == Key::DOWN) + { + setSelected(getSelected() + 1); + keyEvent.consume(); + } + } + + void DropDown::mousePressed(MouseEvent& mouseEvent) + { + // If we have a mouse press on the widget. + if (0 <= mouseEvent.getY() + && mouseEvent.getY() < getHeight() + && mouseEvent.getX() >= 0 + && mouseEvent.getX() < getWidth() + && mouseEvent.getButton() == MouseEvent::LEFT + && !mDroppedDown + && mouseEvent.getSource() == this) + { + mPushed = true; + dropDown(); + requestModalMouseInputFocus(); + } + // Fold up the listbox if the upper part is clicked after fold down + else if (0 <= mouseEvent.getY() + && mouseEvent.getY() < mFoldedUpHeight + && mouseEvent.getX() >= 0 + && mouseEvent.getX() < getWidth() + && mouseEvent.getButton() == MouseEvent::LEFT + && mDroppedDown + && mouseEvent.getSource() == this) + { + mPushed = false; + foldUp(); + releaseModalMouseInputFocus(); + } + // If we have a mouse press outside the widget + else if (0 > mouseEvent.getY() + || mouseEvent.getY() >= getHeight() + || mouseEvent.getX() < 0 + || mouseEvent.getX() >= getWidth()) + { + mPushed = false; + foldUp(); + } + } + + void DropDown::mouseReleased(MouseEvent& mouseEvent) + { + if (mIsDragged) + { + mPushed = false; + } + + // Released outside of widget. Can happen when we have modal input focus. + if ((0 > mouseEvent.getY() + || mouseEvent.getY() >= getHeight() + || mouseEvent.getX() < 0 + || mouseEvent.getX() >= getWidth()) + && mouseEvent.getButton() == MouseEvent::LEFT + && isModalMouseInputFocused()) + { + releaseModalMouseInputFocus(); + + if (mIsDragged) + { + foldUp(); + } + } + else if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mPushed = false; + } + + mIsDragged = false; + } + + void DropDown::mouseDragged(MouseEvent& mouseEvent) + { + mIsDragged = true; + + mouseEvent.consume(); + } + + void DropDown::setListModel(ListModel *listModel) + { + mListBox->setListModel(listModel); + + if (mListBox->getSelected() < 0) + { + mListBox->setSelected(0); + } + + adjustHeight(); + } + + ListModel *DropDown::getListModel() + { + return mListBox->getListModel(); + } + + void DropDown::adjustHeight() + { + if (mScrollArea == NULL) + { + throw GCN_EXCEPTION("Scroll area has been deleted."); + } + + if (mListBox == NULL) + { + throw GCN_EXCEPTION("List box has been deleted."); + } + + int listBoxHeight = mListBox->getHeight(); + + // We add 2 for the border + int h2 = getFont()->getHeight() + 2; + + setHeight(h2); + + // The addition/subtraction of 2 compensates for the seperation lines + // seperating the selected element view and the scroll area. + + if (mDroppedDown && getParent()) + { + int h = getParent()->getChildrenArea().height - getY(); + + if (listBoxHeight > h - h2 - 2) + { + mScrollArea->setHeight(h - h2 - 2); + setHeight(h); + } + else + { + setHeight(listBoxHeight + h2 + 2); + mScrollArea->setHeight(listBoxHeight); + } + } + + mScrollArea->setWidth(getWidth()); + // Resize the ListBox to exactly fit the ScrollArea. + mListBox->setWidth(mScrollArea->getChildrenArea().width); + mScrollArea->setPosition(0, 0); + } + + void DropDown::dropDown() + { + if (!mDroppedDown) + { + mDroppedDown = true; + mFoldedUpHeight = getHeight(); + adjustHeight(); + + if (getParent()) + { + getParent()->moveToTop(this); + } + } + + mListBox->requestFocus(); + } + + void DropDown::foldUp() + { + if (mDroppedDown) + { + mDroppedDown = false; + adjustHeight(); + mInternalFocusHandler.focusNone(); + } + } + + void DropDown::focusLost(const Event& event) + { + foldUp(); + mInternalFocusHandler.focusNone(); + } + + + void DropDown::death(const Event& event) + { + if (event.getSource() == mScrollArea) + { + mScrollArea = NULL; + } + + BasicContainer::death(event); + } + + void DropDown::action(const ActionEvent& actionEvent) + { + foldUp(); + releaseModalMouseInputFocus(); + distributeActionEvent(); + } + + Rectangle DropDown::getChildrenArea() + { + if (mDroppedDown) + { + // Calculate the children area (with the one pixel border in mind) + return Rectangle(1, + mFoldedUpHeight + 1, + getWidth() - 2, + getHeight() - mFoldedUpHeight - 2); + } + + return Rectangle(); + } + + void DropDown::setBaseColor(const Color& color) + { + if (mInternalScrollArea) + { + mScrollArea->setBaseColor(color); + } + + if (mInternalListBox) + { + mListBox->setBaseColor(color); + } + + Widget::setBaseColor(color); + } + + void DropDown::setBackgroundColor(const Color& color) + { + if (mInternalScrollArea) + { + mScrollArea->setBackgroundColor(color); + } + + if (mInternalListBox) + { + mListBox->setBackgroundColor(color); + } + + Widget::setBackgroundColor(color); + } + + void DropDown::setForegroundColor(const Color& color) + { + if (mInternalScrollArea) + { + mScrollArea->setForegroundColor(color); + } + + if (mInternalListBox) + { + mListBox->setForegroundColor(color); + } + + Widget::setForegroundColor(color); + } + + void DropDown::setFont(Font *font) + { + if (mInternalScrollArea) + { + mScrollArea->setFont(font); + } + + if (mInternalListBox) + { + mListBox->setFont(font); + } + + Widget::setFont(font); + } + + void DropDown::mouseWheelMovedUp(MouseEvent& mouseEvent) + { + if (isFocused() && mouseEvent.getSource() == this) + { + mouseEvent.consume(); + + if (mListBox->getSelected() > 0) + { + mListBox->setSelected(mListBox->getSelected() - 1); + } + } + } + + void DropDown::mouseWheelMovedDown(MouseEvent& mouseEvent) + { + if (isFocused() && mouseEvent.getSource() == this) + { + mouseEvent.consume(); + + mListBox->setSelected(mListBox->getSelected() + 1); + } + } + + void DropDown::setSelectionColor(const Color& color) + { + Widget::setSelectionColor(color); + + if (mInternalListBox) + { + mListBox->setSelectionColor(color); + } + } + + void DropDown::valueChanged(const SelectionEvent& event) + { + distributeValueChangedEvent(); + } + + void DropDown::addSelectionListener(SelectionListener* selectionListener) + { + mSelectionListeners.push_back(selectionListener); + } + + void DropDown::removeSelectionListener(SelectionListener* selectionListener) + { + mSelectionListeners.remove(selectionListener); + } + + void DropDown::distributeValueChangedEvent() + { + SelectionListenerIterator iter; + + for (iter = mSelectionListeners.begin(); iter != mSelectionListeners.end(); ++iter) + { + SelectionEvent event(this); + (*iter)->valueChanged(event); + } + } +} + diff --git a/src/guichan/widgets/dropdown.hpp b/src/guichan/widgets/dropdown.hpp new file mode 100644 index 000000000..090fff0ce --- /dev/null +++ b/src/guichan/widgets/dropdown.hpp @@ -0,0 +1,318 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_DROPDOWN_HPP +#define GCN_DROPDOWN_HPP + +#include "guichan/actionlistener.hpp" +#include "guichan/basiccontainer.hpp" +#include "guichan/deathlistener.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/focuslistener.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/listmodel.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/selectionlistener.hpp" +#include "guichan/widgets/listbox.hpp" +#include "guichan/widgets/scrollarea.hpp" + +namespace gcn { + /** + * An implementation of a drop downable list from which an item can be + * selected. The drop down consists of an internal ScrollArea and an + * internal ListBox. The drop down also uses an internal FocusHandler to + * handle the focus of the internal ScollArea and the internal ListBox. The + * scroll area and the list box can be passed to the drop down if a custom + * scroll area and or a custom list box is preferable. + * + * To be able display a list the drop down uses a user provided list model. + * A list model can be any class that implements the ListModel interface. + * + * If an item is selected in the drop down a select event will be sent to + * all selection listeners of the drop down. If an item is selected by + * using a mouse click or by using the enter or space key an action event + * will be sent to all action listeners of the drop down. + */ + class GCN_CORE_DECLSPEC DropDown : + public ActionListener, + public BasicContainer, + public KeyListener, + public MouseListener, + public FocusListener, + public SelectionListener + { + 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(ListModel *listModel = NULL, + ScrollArea *scrollArea = NULL, + ListBox *listBox = NULL); + + /** + * Destructor. + */ + virtual ~DropDown(); + + /** + * Gets the selected item as an index in the list model. + * + * @return the selected item as an index in the list model. + * @see setSelected + */ + int getSelected() const; + + /** + * Sets the selected item. The selected item is represented by + * an index from the list model. + * + * @param selected the selected item as an index from the list model. + * @see getSelected + */ + void setSelected(int selected); + + /** + * Sets the list model to use when displaying the list. + * + * @param listModel the list model to use. + * @see getListModel + */ + void setListModel(ListModel *listModel); + + /** + * Gets the list model used. + * + * @return the ListModel used. + * @see setListModel + */ + ListModel *getListModel(); + + /** + * Adjusts the height of the drop down to fit the height of the + * drop down's parent's height. It's used to not make the drop down + * draw itself outside of it's parent if folded down. + */ + void adjustHeight(); + + /** + * Adds a selection listener to the drop down. When the selection + * changes an event will be sent to all selection listeners of the + * drop down. + * + * If you delete your selection listener, be sure to also remove it + * using removeSelectionListener(). + * + * @param selectionListener the selection listener to add. + * @since 0.8.0 + */ + void addSelectionListener(SelectionListener* selectionListener); + + /** + * Removes a selection listener from the drop down. + * + * @param selectionListener the selection listener to remove. + * @since 0.8.0 + */ + void removeSelectionListener(SelectionListener* selectionListener); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + void setBaseColor(const Color& color); + + void setBackgroundColor(const Color& color); + + void setForegroundColor(const Color& color); + + void setFont(Font *font); + + void setSelectionColor(const Color& color); + + + // Inherited from BasicContainer + + virtual Rectangle getChildrenArea(); + + + // Inherited from FocusListener + + virtual void focusLost(const Event& event); + + + // Inherited from ActionListener + + virtual void action(const ActionEvent& actionEvent); + + + // Inherited from DeathListener + + virtual void death(const Event& event); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseReleased(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + + // Inherited from SelectionListener + + virtual void valueChanged(const SelectionEvent& event); + + protected: + /** + * Draws the button of the drop down. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawButton(Graphics *graphics); + + /** + * Sets the drop down to be dropped down. + */ + virtual void dropDown(); + + /** + * Sets the drop down to be folded up. + */ + virtual void foldUp(); + + /** + * Distributes a value changed event to all selection listeners + * of the drop down. + * + * @since 0.8.0 + */ + void distributeValueChangedEvent(); + + /** + * True if the drop down is dropped down, false otherwise. + */ + bool mDroppedDown; + + /** + * True if the drop down has been pushed with the mouse, false + * otherwise. + */ + bool mPushed; + + /** + * Holds what the height is if the drop down is folded up. Used when + * checking if the list of the drop down was clicked or if the upper + * part of the drop down was clicked on a mouse click. + */ + int mFoldedUpHeight; + + /** + * The scroll area used. + */ + ScrollArea* mScrollArea; + + /** + * The list box used. + */ + ListBox* mListBox; + + /** + * The internal focus handler used to keep track of focus for the + * internal list box. + */ + FocusHandler mInternalFocusHandler; + + /** + * True if an internal scroll area is used, false if a scroll area + * has been passed to the drop down which the drop down should not + * deleted in it's destructor. + */ + bool mInternalScrollArea; + + /** + * True if an internal list box is used, false if a list box + * has been passed to the drop down which the drop down should not + * deleted in it's destructor. + */ + bool mInternalListBox; + + /** + * True if the drop down is dragged. + */ + bool mIsDragged; + + /** + * Typedef. + */ + typedef std::list<SelectionListener*> SelectionListenerList; + + /** + * The selection listener's of the drop down. + */ + SelectionListenerList mSelectionListeners; + + /** + * Typedef. + */ + typedef SelectionListenerList::iterator SelectionListenerIterator; + }; +} + +#endif // end GCN_DROPDOWN_HPP diff --git a/src/guichan/widgets/icon.cpp b/src/guichan/widgets/icon.cpp new file mode 100644 index 000000000..687fadeab --- /dev/null +++ b/src/guichan/widgets/icon.cpp @@ -0,0 +1,116 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/icon.hpp" + +#include "guichan/graphics.hpp" +#include "guichan/image.hpp" +#include "guichan/rectangle.hpp" + +namespace gcn +{ + Icon::Icon() + : mImage(0) + , mInternalImage(false) + { + setSize(0, 0); + } + + Icon::Icon(const std::string& filename) + : mImage(0), + mInternalImage(false) + { + mImage = Image::load(filename); + mInternalImage = true; + setSize(mImage->getWidth(), + mImage->getHeight()); + } + + Icon::Icon(const Image* image) + : mImage(image), + mInternalImage(false) + { + setSize(mImage->getWidth(), + mImage->getHeight()); + } + + Icon::~Icon() + { + if (mInternalImage) + { + delete mImage; + } + } + + void Icon::setImage(const Image* image) + { + if (mInternalImage) + { + delete mImage; + } + + mImage = image; + mInternalImage = false; + setSize(mImage->getWidth(), + mImage->getHeight()); + } + + const Image* Icon::getImage() const + { + return mImage; + } + + void Icon::draw(Graphics* graphics) + { + if (mImage != NULL) + { + const int x = (getWidth() - mImage->getWidth()) / 2; + const int y = (getHeight() - mImage->getHeight()) / 2; + graphics->drawImage(mImage, x, y); + } + } +} diff --git a/src/guichan/widgets/icon.hpp b/src/guichan/widgets/icon.hpp new file mode 100644 index 000000000..f0f9ff566 --- /dev/null +++ b/src/guichan/widgets/icon.hpp @@ -0,0 +1,118 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_ICON_HPP +#define GCN_ICON_HPP + +#include "guichan/image.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * Implements an icon capable of displaying an image. + */ + class GCN_CORE_DECLSPEC Icon: public Widget + { + public: + /** + * Default constructor. + */ + Icon(); + + /** + * Constructor. + * + * @param filename The filename of the image to display. + */ + Icon(const std::string& filename); + + /** + * Constructor. + * + * @param image The image to display. + */ + Icon(const Image* image); + + /** + * Descructor. + */ + virtual ~Icon(); + + /** + * Sets the image to display. Existing image is freed automatically + * if it was loaded internally. + * + * @param image The image to display. + */ + void setImage(const Image* image); + + /** + * Gets the current image. + * + * @return The current image. + */ + const Image* getImage() const; + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + protected: + /** + * The image to display. + */ + const Image* mImage; + + /** + * True if the image has been loaded internally, false otherwise. + * An image not loaded internally should not be deleted in the + * destructor. + */ + bool mInternalImage; + }; +} + +#endif // end GCN_ICON_HPP diff --git a/src/guichan/widgets/imagebutton.cpp b/src/guichan/widgets/imagebutton.cpp new file mode 100644 index 000000000..f09bca30d --- /dev/null +++ b/src/guichan/widgets/imagebutton.cpp @@ -0,0 +1,166 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/imagebutton.hpp" + +#include "guichan/graphics.hpp" +#include "guichan/image.hpp" + +namespace gcn +{ + ImageButton::ImageButton() + : mImage(0), + mInternalImage(false) + { + setWidth(0); + setHeight(0); + } + + ImageButton::ImageButton(const std::string& filename) + : mImage(0), + mInternalImage(false) + { + mImage = Image::load(filename); + mInternalImage = true; + setWidth(mImage->getWidth() + mImage->getWidth() / 2); + setHeight(mImage->getHeight() + mImage->getHeight() / 2); + } + + ImageButton::ImageButton(const Image* image) + : mImage(image), + mInternalImage(false) + { + setWidth(mImage->getWidth() + mImage->getWidth() / 2); + setHeight(mImage->getHeight() + mImage->getHeight() / 2); + } + + ImageButton::~ImageButton() + { + if (mInternalImage) + { + delete mImage; + } + } + + void ImageButton::setImage(const Image* image) + { + if (mInternalImage) + { + delete mImage; + } + + mImage = image; + mInternalImage = false; + } + + const Image* ImageButton::getImage() const + { + return mImage; + } + + void ImageButton::draw(Graphics* graphics) + { + gcn::Color faceColor = getBaseColor(); + gcn::Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + + if (isPressed()) + { + faceColor = faceColor - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor + 0x303030; + shadowColor.a = alpha; + } + else + { + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(1, + 1, + getDimension().width - 1, + getHeight() - 1)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, getHeight() - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); + graphics->drawLine(1, getHeight() - 1, getWidth() - 1, getHeight() - 1); + + graphics->setColor(getForegroundColor()); + + const int textX = (getWidth() - (mImage ? mImage->getWidth() : 0) ) / 2; + const int textY = (getHeight() - (mImage ? mImage->getHeight() : 0) ) / 2; + + if (isPressed()) + { + if(mImage) + graphics->drawImage(mImage, textX + 1, textY + 1); + } + else + { + if(mImage) + graphics->drawImage(mImage, textX, textY); + + if (isFocused()) + { + graphics->drawRectangle(Rectangle(2, + 2, + getWidth() - 4, + getHeight() - 4)); + } + } + } +} diff --git a/src/guichan/widgets/imagebutton.hpp b/src/guichan/widgets/imagebutton.hpp new file mode 100644 index 000000000..1ab285ce9 --- /dev/null +++ b/src/guichan/widgets/imagebutton.hpp @@ -0,0 +1,123 @@ +/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ *
+ *
+ * Per Larsson a.k.a finalman
+ * Olof Naessén a.k.a jansem/yakslem
+ *
+ * Visit: http://guichan.sourceforge.net
+ *
+ * License: (BSD)
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Guichan nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GCN_IMAGEBUTTON_HPP
+#define GCN_IMAGEBUTTON_HPP
+
+#include "guichan/platform.hpp"
+#include "guichan/widgets/button.hpp"
+
+namespace gcn
+{
+ class Image;
+
+ /**
+ * An implementation of a regular clickable button. Unlike a normal button an image
+ * button is capable of displaying an image instead of a simple text caption.
+ * Whenever an image button is clicked an action event will be sent to the action
+ * listener's of the image button.
+ *
+ * @see Button
+ */
+ class GCN_CORE_DECLSPEC ImageButton : public gcn::Button
+ {
+ public:
+ /**
+ * Default constructor.
+ */
+ ImageButton();
+
+ /**
+ * Constructor.
+ *
+ * @param filename The filename of the image to display.
+ */
+ ImageButton(const std::string& filename);
+
+ /**
+ * Constructor.
+ *
+ * @param image The image to display.
+ */
+ ImageButton(const Image* image);
+
+ /**
+ * Destructor.
+ */
+ virtual ~ImageButton();
+
+ /**
+ * Sets the image to display. Existing Image is freed automatically,
+ * if it was loaded internally.
+ *
+ * @param image The image to display.
+ */
+ void setImage(const Image* image);
+
+ /**
+ * Gets current image.
+ *
+ * @return The current image.
+ */
+ const Image* getImage() const;
+
+
+ // Inherited from Widget
+
+ void draw(gcn::Graphics* graphics);
+
+ protected:
+ /**
+ * The image to display.
+ */
+ const Image* mImage;
+
+ /**
+ * True if the image has been loaded internally, false otherwise.
+ * An image not loaded internally should not be deleted in the
+ * destructor.
+ */
+ bool mInternalImage;
+ };
+}
+#endif
diff --git a/src/guichan/widgets/label.cpp b/src/guichan/widgets/label.cpp new file mode 100644 index 000000000..9b11206a6 --- /dev/null +++ b/src/guichan/widgets/label.cpp @@ -0,0 +1,120 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/label.hpp" + +#include "guichan/exception.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" + +namespace gcn +{ + Label::Label() + { + mAlignment = Graphics::LEFT; + } + + Label::Label(const std::string& caption) + { + mCaption = caption; + mAlignment = Graphics::LEFT; + + setWidth(getFont()->getWidth(caption)); + setHeight(getFont()->getHeight()); + } + + const std::string &Label::getCaption() const + { + return mCaption; + } + + void Label::setCaption(const std::string& caption) + { + mCaption = caption; + } + + void Label::setAlignment(Graphics::Alignment alignment) + { + mAlignment = alignment; + } + + Graphics::Alignment Label::getAlignment() const + { + return mAlignment; + } + + void Label::draw(Graphics* graphics) + { + int textX; + int textY = getHeight() / 2 - getFont()->getHeight() / 2; + + switch (getAlignment()) + { + case Graphics::LEFT: + textX = 0; + break; + case Graphics::CENTER: + textX = getWidth() / 2; + break; + case Graphics::RIGHT: + textX = getWidth(); + break; + default: + throw GCN_EXCEPTION("Unknown alignment."); + } + + graphics->setFont(getFont()); + graphics->setColor(getForegroundColor()); + graphics->drawText(getCaption(), textX, textY, getAlignment()); + } + + void Label::adjustSize() + { + setWidth(getFont()->getWidth(getCaption())); + setHeight(getFont()->getHeight()); + } +} diff --git a/src/guichan/widgets/label.hpp b/src/guichan/widgets/label.hpp new file mode 100644 index 000000000..4d6ea0006 --- /dev/null +++ b/src/guichan/widgets/label.hpp @@ -0,0 +1,133 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_LABEL_HPP +#define GCN_LABEL_HPP + +#include <string> + +#include "guichan/graphics.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * Implementation of a label capable of displaying a caption. + */ + class GCN_CORE_DECLSPEC Label: public Widget + { + public: + /** + * Constructor. + */ + Label(); + + /** + * Constructor. The label will be automatically resized + * to fit the caption. + * + * @param caption The caption of the label. + */ + Label(const std::string& caption); + + /** + * Gets the caption of the label. + * + * @return The caption of the label. + * @see setCaption + */ + const std::string &getCaption() const; + + /** + * Sets the caption of the label. It's advisable to call + * adjustSize after setting of the caption to adjust the + * label's size to fit the caption. + * + * @param caption The caption of the label. + * @see getCaption, adjustSize + */ + void setCaption(const std::string& caption); + + /** + * Sets the alignment of the caption. The alignment is relative + * to the center of the label. + * + * @param alignemnt The alignment of the caption of the label. + * @see getAlignment, Graphics + */ + void setAlignment(Graphics::Alignment alignment); + + /** + * Gets the alignment of the caption. The alignment is relative to + * the center of the label. + * + * @return The alignment of caption of the label. + * @see setAlignmentm Graphics + */ + Graphics::Alignment getAlignment() const; + + /** + * Adjusts the label's size to fit the caption. + */ + void adjustSize(); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + protected: + /** + * Holds the caption of the label. + */ + std::string mCaption; + + /** + * Holds the alignment of the caption. + */ + Graphics::Alignment mAlignment; + }; +} + +#endif // end GCN_LABEL_HPP diff --git a/src/guichan/widgets/listbox.cpp b/src/guichan/widgets/listbox.cpp new file mode 100644 index 000000000..9b20b8538 --- /dev/null +++ b/src/guichan/widgets/listbox.cpp @@ -0,0 +1,350 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/listbox.hpp" + +#include "guichan/basiccontainer.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/listmodel.hpp" +#include "guichan/mouseinput.hpp" +#include "guichan/selectionlistener.hpp" + +namespace gcn +{ + ListBox::ListBox() + : mSelected(-1), + mListModel(NULL), + mWrappingEnabled(false) + { + setWidth(100); + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + } + + ListBox::ListBox(ListModel *listModel) + : mSelected(-1), + mWrappingEnabled(false) + { + setWidth(100); + setListModel(listModel); + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + } + + void ListBox::draw(Graphics* graphics) + { + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); + + if (mListModel == NULL) + { + return; + } + + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + + // Check the current clip area so we don't draw unnecessary items + // that are not visible. + const ClipRectangle currentClipArea = graphics->getCurrentClipArea(); + int rowHeight = getRowHeight(); + + // Calculate the number of rows to draw by checking the clip area. + // The addition of two makes covers a partial visible row at the top + // and a partial visible row at the bottom. + int numberOfRows = currentClipArea.height / rowHeight + 2; + + if (numberOfRows > mListModel->getNumberOfElements()) + { + numberOfRows = mListModel->getNumberOfElements(); + } + + // Calculate which row to start drawing. If the list box + // has a negative y coordinate value we should check if + // we should drop rows in the begining of the list as + // they might not be visible. A negative y value is very + // common if the list box for instance resides in a scroll + // area and the user has scrolled the list box downwards. + int startRow; + if (getY() < 0) + { + startRow = -1 * (getY() / rowHeight); + } + else + { + startRow = 0; + } + + int i; + // The y coordinate where we start to draw the text is + // simply the y coordinate multiplied with the font height. + int y = rowHeight * startRow; + for (i = startRow; i < startRow + numberOfRows; ++i) + { + if (i == mSelected) + { + graphics->setColor(getSelectionColor()); + graphics->fillRectangle(Rectangle(0, y, getWidth(), rowHeight)); + graphics->setColor(getForegroundColor()); + } + + // If the row height is greater than the font height we + // draw the text with a center vertical alignment. + if (rowHeight > getFont()->getHeight()) + { + graphics->drawText(mListModel->getElementAt(i), 1, y + rowHeight / 2 - getFont()->getHeight() / 2); + } + else + { + graphics->drawText(mListModel->getElementAt(i), 1, y); + } + + y += rowHeight; + } + } + + void ListBox::logic() + { + adjustSize(); + } + + int ListBox::getSelected() const + { + return mSelected; + } + + void ListBox::setSelected(int selected) + { + if (mListModel == NULL) + { + mSelected = -1; + } + else + { + if (selected < 0) + { + mSelected = -1; + } + else if (selected >= mListModel->getNumberOfElements()) + { + mSelected = mListModel->getNumberOfElements() - 1; + } + else + { + mSelected = selected; + } + } + + Rectangle scroll; + + if (mSelected < 0) + { + scroll.y = 0; + } + else + { + scroll.y = getRowHeight() * mSelected; + } + + scroll.height = getRowHeight(); + showPart(scroll); + + distributeValueChangedEvent(); + } + + void ListBox::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE) + { + distributeActionEvent(); + keyEvent.consume(); + } + else if (key.getValue() == Key::UP) + { + setSelected(mSelected - 1); + + if (mSelected == -1) + { + if (mWrappingEnabled) + { + setSelected(getListModel()->getNumberOfElements() - 1); + } + else + { + setSelected(0); + } + } + + keyEvent.consume(); + } + else if (key.getValue() == Key::DOWN) + { + if (mWrappingEnabled + && getSelected() == getListModel()->getNumberOfElements() - 1) + { + setSelected(0); + } + else + { + setSelected(getSelected() + 1); + } + + keyEvent.consume(); + } + else if (key.getValue() == Key::HOME) + { + setSelected(0); + keyEvent.consume(); + } + else if (key.getValue() == Key::END) + { + setSelected(getListModel()->getNumberOfElements() - 1); + keyEvent.consume(); + } + } + + void ListBox::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + setSelected(mouseEvent.getY() / getRowHeight()); + distributeActionEvent(); + } + } + + void ListBox::mouseWheelMovedUp(MouseEvent& mouseEvent) + { + if (isFocused()) + { + if (getSelected() > 0 ) + { + setSelected(getSelected() - 1); + } + + mouseEvent.consume(); + } + } + + void ListBox::mouseWheelMovedDown(MouseEvent& mouseEvent) + { + if (isFocused()) + { + setSelected(getSelected() + 1); + + mouseEvent.consume(); + } + } + + void ListBox::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void ListBox::setListModel(ListModel *listModel) + { + mSelected = -1; + mListModel = listModel; + adjustSize(); + } + + ListModel* ListBox::getListModel() + { + return mListModel; + } + + void ListBox::adjustSize() + { + if (mListModel != NULL) + { + setHeight(getRowHeight() * mListModel->getNumberOfElements()); + } + } + + bool ListBox::isWrappingEnabled() const + { + return mWrappingEnabled; + } + + void ListBox::setWrappingEnabled(bool wrappingEnabled) + { + mWrappingEnabled = wrappingEnabled; + } + + void ListBox::addSelectionListener(SelectionListener* selectionListener) + { + mSelectionListeners.push_back(selectionListener); + } + + void ListBox::removeSelectionListener(SelectionListener* selectionListener) + { + mSelectionListeners.remove(selectionListener); + } + + void ListBox::distributeValueChangedEvent() + { + SelectionListenerIterator iter; + + for (iter = mSelectionListeners.begin(); iter != mSelectionListeners.end(); ++iter) + { + SelectionEvent event(this); + (*iter)->valueChanged(event); + } + } + + unsigned int ListBox::getRowHeight() const + { + return getFont()->getHeight(); + } +} diff --git a/src/guichan/widgets/listbox.hpp b/src/guichan/widgets/listbox.hpp new file mode 100644 index 000000000..b99f84aaa --- /dev/null +++ b/src/guichan/widgets/listbox.hpp @@ -0,0 +1,253 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_LISTBOX_HPP +#define GCN_LISTBOX_HPP + +#include <list> + +#include "guichan/keylistener.hpp" +#include "guichan/listmodel.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + class SelectionListener; + + /** + * An implementation of a list box where an item can be selected. + * + * To be able display a list the list box uses a user provided list model. + * A list model can be any class that implements the ListModel interface. + * + * If an item is selected in the list box a select event will be sent to + * all selection listeners of the list box. If an item is selected by using + * a mouse click or by using the enter or space key an action event will be + * sent to all action listeners of the list box. + */ + class GCN_CORE_DECLSPEC ListBox : + public Widget, + public MouseListener, + public KeyListener + { + public: + /** + * Constructor. + */ + ListBox(); + + /** + * Constructor. + * + * @param listModel the list model to use. + */ + ListBox(ListModel *listModel); + + /** + * Destructor. + */ + virtual ~ListBox() { } + + /** + * Gets the selected item as an index in the list model. + * + * @return the selected item as an index in the list model. + * @see setSelected + */ + int getSelected() const; + + /** + * Sets the selected item. The selected item is represented by + * an index from the list model. + * + * @param selected the selected item as an index from the list model. + * @see getSelected + */ + void setSelected(int selected); + + /** + * Sets the list model to use. + * + * @param listModel the list model to use. + * @see getListModel + */ + void setListModel(ListModel *listModel); + + /** + * Gets the list model used. + * + * @return the list model used. + * @see setListModel + */ + ListModel *getListModel(); + + /** + * Adjusts the size of the list box to fit it's list model. + */ + void adjustSize(); + + /** + * Checks whether the list box wraps when selecting items with a + * keyboard. + * + * Wrapping means that the selection of items will be wrapped. That is, + * if the first item is selected and up is pressed, the last item will + * get selected. If the last item is selected and down is pressed, the + * first item will get selected. + * + * @return true if wrapping is enabled, fasle otherwise. + * @see setWrappingEnabled + */ + bool isWrappingEnabled() const; + + /** + * Sets the list box to wrap or not when selecting items with a + * keyboard. + * + * Wrapping means that the selection of items will be wrapped. That is, + * if the first item is selected and up is pressed, the last item will + * get selected. If the last item is selected and down is pressed, the + * first item will get selected. + * + * @see isWrappingEnabled + */ + void setWrappingEnabled(bool wrappingEnabled); + + /** + * Adds a selection listener to the list box. When the selection + * changes an event will be sent to all selection listeners of the + * list box. + * + * If you delete your selection listener, be sure to also remove it + * using removeSelectionListener(). + * + * @param selectionListener The selection listener to add. + * @since 0.8.0 + */ + void addSelectionListener(SelectionListener* selectionListener); + + /** + * Removes a selection listener from the list box. + * + * @param selectionListener The selection listener to remove. + * @since 0.8.0 + */ + void removeSelectionListener(SelectionListener* selectionListener); + + /** + * Gets the height of a row. Should be overridden if another row + * height than the font height is preferred. + * + * @return The height of a row. + * @since 0.8.0 + */ + virtual unsigned int getRowHeight() const; + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + virtual void logic(); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + + protected: + /** + * Distributes a value changed event to all selection listeners + * of the list box. + * + * @since 0.8.0 + */ + void distributeValueChangedEvent(); + + /** + * The selected item as an index in the list model. + */ + int mSelected; + + /** + * The list model to use. + */ + ListModel *mListModel; + + /** + * True if wrapping is enabled, false otherwise. + */ + bool mWrappingEnabled; + + /** + * Typdef. + */ + typedef std::list<SelectionListener*> SelectionListenerList; + + /** + * The selection listeners of the list box. + */ + SelectionListenerList mSelectionListeners; + + /** + * Typedef. + */ + typedef SelectionListenerList::iterator SelectionListenerIterator; + }; +} + +#endif // end GCN_LISTBOX_HPP diff --git a/src/guichan/widgets/radiobutton.cpp b/src/guichan/widgets/radiobutton.cpp new file mode 100644 index 000000000..31fdec94d --- /dev/null +++ b/src/guichan/widgets/radiobutton.cpp @@ -0,0 +1,298 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/radiobutton.hpp" + +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + RadioButton::GroupMap RadioButton::mGroupMap; + + RadioButton::RadioButton() + { + setSelected(false); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + } + + RadioButton::RadioButton(const std::string &caption, + const std::string &group, + bool selected) + { + setCaption(caption); + setGroup(group); + setSelected(selected); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + + adjustSize(); + } + + RadioButton::~RadioButton() + { + // Remove us from the group list + setGroup(""); + } + + void RadioButton::draw(Graphics* graphics) + { + graphics->pushClipArea(Rectangle(1, + 1, + getWidth() - 1, + getHeight() - 1)); + drawBox(graphics); + graphics->popClipArea(); + + + graphics->setFont(getFont()); + graphics->setColor(getForegroundColor()); + + if (isFocused()) + { + int fh; + + if (getHeight()%2 == 0) + { + fh = getHeight() - 4; + } + else + { + fh = getHeight() - 3; + } + + int hh = (fh + 1) / 2; + + graphics->drawLine(0, hh + 1, hh + 1, 0); + graphics->drawLine(hh + 2, 1, fh + 2, hh + 1); + graphics->drawLine(fh + 1, hh + 2, hh + 1, fh + 2); + graphics->drawLine(hh + 1, fh + 2, 1, hh + 2); + } + + int h = getHeight() + getHeight() / 2; + + graphics->drawText(getCaption(), h - 2, 0); + } + + void RadioButton::drawBox(Graphics *graphics) + { + int h; + + if (getHeight()%2 == 0) + { + h = getHeight() - 4; + } + else + { + h = getHeight() - 3; + } + + int alpha = getBaseColor().a; + Color faceColor = getBaseColor(); + faceColor.a = alpha; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(getBackgroundColor()); + + int i; + int hh = (h + 1) / 2; + + for (i = 1; i <= hh; ++i) + { + graphics->drawLine(hh - i + 1, + i, + hh + i - 1, + i); + } + + for (i = 1; i < hh; ++i) + { + graphics->drawLine(hh - i + 1, + h - i, + hh + i - 1, + h - i); + } + + graphics->setColor(shadowColor); + graphics->drawLine(hh, 0, 0, hh); + graphics->drawLine(hh + 1, 1, h - 1, hh - 1); + + graphics->setColor(highlightColor); + graphics->drawLine(1, hh + 1, hh, h); + graphics->drawLine(hh + 1, h - 1, h, hh); + + graphics->setColor(getForegroundColor()); + + int hhh = hh - 3; + if (mSelected) + { + for (i = 0; i < hhh; ++i) + { + graphics->drawLine(hh - i, 4 + i, hh + i, 4 + i); + } + for (i = 0; i < hhh; ++i) + { + graphics->drawLine(hh - i, h - 4 - i, hh + i, h - 4 - i); + } + + } + } + + bool RadioButton::isSelected() const + { + return mSelected; + } + + void RadioButton::setSelected(bool selected) + { + if (selected && mGroup != "") + { + GroupIterator iter, iterEnd; + iterEnd = mGroupMap.upper_bound(mGroup); + + for (iter = mGroupMap.lower_bound(mGroup); + iter != iterEnd; + iter++) + { + if (iter->second->isSelected()) + { + iter->second->setSelected(false); + } + } + } + + mSelected = selected; + } + + const std::string &RadioButton::getCaption() const + { + return mCaption; + } + + void RadioButton::setCaption(const std::string caption) + { + mCaption = caption; + } + + void RadioButton::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::ENTER || + key.getValue() == Key::SPACE) + { + setSelected(true); + distributeActionEvent(); + keyEvent.consume(); + } + } + + void RadioButton::mouseClicked(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + setSelected(true); + distributeActionEvent(); + } + } + + void RadioButton::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void RadioButton::setGroup(const std::string &group) + { + if (mGroup != "") + { + GroupIterator iter, iterEnd; + iterEnd = mGroupMap.upper_bound(mGroup); + + for (iter = mGroupMap.lower_bound(mGroup); + iter != iterEnd; + iter++) + { + if (iter->second == this) + { + mGroupMap.erase(iter); + break; + } + } + } + + if (group != "") + { + mGroupMap.insert( + std::pair<std::string, RadioButton *>(group, this)); + } + + mGroup = group; + } + + const std::string &RadioButton::getGroup() const + { + return mGroup; + } + + void RadioButton::adjustSize() + { + int height = getFont()->getHeight(); + + setHeight(height); + setWidth(getFont()->getWidth(getCaption()) + height + height/2); + } +} diff --git a/src/guichan/widgets/radiobutton.hpp b/src/guichan/widgets/radiobutton.hpp new file mode 100644 index 000000000..0fb5b4123 --- /dev/null +++ b/src/guichan/widgets/radiobutton.hpp @@ -0,0 +1,211 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_RADIOBUTTON_HPP +#define GCN_RADIOBUTTON_HPP + +#include <map> +#include <string> + +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * An implementation of a radio button where a user can select or deselect + * the radio button and where the status of the radio button is displayed to the user. + * A radio button can belong to a group and when a radio button belongs to a + * group only one radio button can be selected in the group. A radio button is + * capable of displaying a caption. + * + * If a radio button's state changes an action event will be sent to all action + * listeners of the check box. + */ + class GCN_CORE_DECLSPEC RadioButton : + public Widget, + public MouseListener, + public KeyListener + { + public: + + /** + * Constructor. + */ + RadioButton(); + + /** + * Constructor. The radio button will be automatically resized + * to fit the caption. + * + * @param caption The caption of the radio button. + * @param group The group the radio button should belong to. + * @param selected True if the radio button should be selected. + */ + RadioButton(const std::string &caption, + const std::string &group, + bool selected = false); + + /** + * Destructor. + */ + virtual ~RadioButton(); + + /** + * Checks if the radio button is selected. + * + * @return True if the radio button is selecte, false otherwise. + * @see setSelected + */ + bool isSelected() const; + + /** + * Sets the radio button to selected or not. + * + * @param selected True if the radio button should be selected, + * false otherwise. + * @see isSelected + */ + void setSelected(bool selected); + + /** + * Gets the caption of the radio button. + * + * @return The caption of the radio button. + * @see setCaption + */ + const std::string &getCaption() const; + + /** + * Sets the caption of the radio button. It's advisable to call + * adjustSize after setting of the caption to adjust the + * radio button's size to fit the caption. + * + * @param caption The caption of the radio button. + * @see getCaption, adjustSize + */ + void setCaption(const std::string caption); + + /** + * Sets the group the radio button should belong to. Note that + * a radio button group is unique per application, not per Gui object + * as the group is stored in a static map. + * + * @param group The name of the group. + * @see getGroup + */ + void setGroup(const std::string &group); + + /** + * Gets the group the radio button belongs to. + * + * @return The group the radio button belongs to. + * @see setGroup + */ + const std::string &getGroup() const; + + /** + * Adjusts the radio button's size to fit the caption. + */ + void adjustSize(); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mouseClicked(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + protected: + /** + * Draws the box. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawBox(Graphics *graphics); + + /** + * True if the radio button is selected, false otherwise. + */ + bool mSelected; + + /** + * Holds the caption of the radio button. + */ + std::string mCaption; + + /** + * Holds the group of the radio button. + */ + std::string mGroup; + + /** + * Typdef. + */ + typedef std::multimap<std::string, RadioButton *> GroupMap; + + /** + * Typdef. + */ + typedef GroupMap::iterator GroupIterator; + + /** + * Holds all available radio button groups. + */ + static GroupMap mGroupMap; + }; +} + +#endif // end GCN_RADIOBUTTON_HPP diff --git a/src/guichan/widgets/scrollarea.cpp b/src/guichan/widgets/scrollarea.cpp new file mode 100644 index 000000000..8e935fc47 --- /dev/null +++ b/src/guichan/widgets/scrollarea.cpp @@ -0,0 +1,1246 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/scrollarea.hpp" + +#include "guichan/exception.hpp" +#include "guichan/graphics.hpp" + +namespace gcn +{ + ScrollArea::ScrollArea() + { + mVScroll = 0; + mHScroll = 0; + mHPolicy = SHOW_AUTO; + mVPolicy = SHOW_AUTO; + mScrollbarWidth = 12; + mUpButtonPressed = false; + mDownButtonPressed = false; + mLeftButtonPressed = false; + mRightButtonPressed = false; + mUpButtonScrollAmount = 10; + mDownButtonScrollAmount = 10; + mLeftButtonScrollAmount = 10; + mRightButtonScrollAmount = 10; + mIsVerticalMarkerDragged = false; + mIsHorizontalMarkerDragged =false; + mOpaque = true; + + addMouseListener(this); + } + + ScrollArea::ScrollArea(Widget *content) + { + mVScroll = 0; + mHScroll = 0; + mHPolicy = SHOW_AUTO; + mVPolicy = SHOW_AUTO; + mScrollbarWidth = 12; + mUpButtonPressed = false; + mDownButtonPressed = false; + mLeftButtonPressed = false; + mRightButtonPressed = false; + mUpButtonScrollAmount = 10; + mDownButtonScrollAmount = 10; + mLeftButtonScrollAmount = 10; + mRightButtonScrollAmount = 10; + mIsVerticalMarkerDragged = false; + mIsHorizontalMarkerDragged =false; + mOpaque = true; + + setContent(content); + addMouseListener(this); + } + + ScrollArea::ScrollArea(Widget *content, + ScrollPolicy hPolicy, + ScrollPolicy vPolicy) + { + mVScroll = 0; + mHScroll = 0; + mHPolicy = hPolicy; + mVPolicy = vPolicy; + mScrollbarWidth = 12; + mUpButtonPressed = false; + mDownButtonPressed = false; + mLeftButtonPressed = false; + mRightButtonPressed = false; + mUpButtonScrollAmount = 10; + mDownButtonScrollAmount = 10; + mLeftButtonScrollAmount = 10; + mRightButtonScrollAmount = 10; + mIsVerticalMarkerDragged = false; + mIsHorizontalMarkerDragged =false; + mOpaque = true; + + setContent(content); + addMouseListener(this); + } + + ScrollArea::~ScrollArea() + { + setContent(NULL); + } + + void ScrollArea::setContent(Widget* widget) + { + if (widget != NULL) + { + clear(); + add(widget); + widget->setPosition(0,0); + } + else + { + clear(); + } + + checkPolicies(); + } + + Widget* ScrollArea::getContent() + { + if (mWidgets.size() > 0) + { + return *mWidgets.begin(); + } + + return NULL; + } + + void ScrollArea::setHorizontalScrollPolicy(ScrollPolicy hPolicy) + { + mHPolicy = hPolicy; + checkPolicies(); + } + + ScrollArea::ScrollPolicy ScrollArea::getHorizontalScrollPolicy() const + { + return mHPolicy; + } + + void ScrollArea::setVerticalScrollPolicy(ScrollPolicy vPolicy) + { + mVPolicy = vPolicy; + checkPolicies(); + } + + ScrollArea::ScrollPolicy ScrollArea::getVerticalScrollPolicy() const + { + return mVPolicy; + } + + void ScrollArea::setScrollPolicy(ScrollPolicy hPolicy, ScrollPolicy vPolicy) + { + mHPolicy = hPolicy; + mVPolicy = vPolicy; + checkPolicies(); + } + + void ScrollArea::setVerticalScrollAmount(int vScroll) + { + int max = getVerticalMaxScroll(); + + mVScroll = vScroll; + + if (vScroll > max) + { + mVScroll = max; + } + + if (vScroll < 0) + { + mVScroll = 0; + } + } + + int ScrollArea::getVerticalScrollAmount() const + { + return mVScroll; + } + + void ScrollArea::setHorizontalScrollAmount(int hScroll) + { + int max = getHorizontalMaxScroll(); + + mHScroll = hScroll; + + if (hScroll > max) + { + mHScroll = max; + } + else if (hScroll < 0) + { + mHScroll = 0; + } + } + + int ScrollArea::getHorizontalScrollAmount() const + { + return mHScroll; + } + + void ScrollArea::setScrollAmount(int hScroll, int vScroll) + { + setHorizontalScrollAmount(hScroll); + setVerticalScrollAmount(vScroll); + } + + int ScrollArea::getHorizontalMaxScroll() + { + checkPolicies(); + + if (getContent() == NULL) + { + return 0; + } + + int value = getContent()->getWidth() - getChildrenArea().width + + 2 * getContent()->getFrameSize(); + + if (value < 0) + { + return 0; + } + + return value; + } + + int ScrollArea::getVerticalMaxScroll() + { + checkPolicies(); + + if (getContent() == NULL) + { + return 0; + } + + int value; + + value = getContent()->getHeight() - getChildrenArea().height + + 2 * getContent()->getFrameSize(); + + if (value < 0) + { + return 0; + } + + return value; + } + + void ScrollArea::setScrollbarWidth(int width) + { + if (width > 0) + { + mScrollbarWidth = width; + } + else + { + throw GCN_EXCEPTION("Width should be greater then 0."); + } + } + + int ScrollArea::getScrollbarWidth() const + { + return mScrollbarWidth; + } + + void ScrollArea::mousePressed(MouseEvent& mouseEvent) + { + int x = mouseEvent.getX(); + int y = mouseEvent.getY(); + + if (getUpButtonDimension().isPointInRect(x, y)) + { + setVerticalScrollAmount(getVerticalScrollAmount() + - mUpButtonScrollAmount); + mUpButtonPressed = true; + } + else if (getDownButtonDimension().isPointInRect(x, y)) + { + setVerticalScrollAmount(getVerticalScrollAmount() + + mDownButtonScrollAmount); + mDownButtonPressed = true; + } + else if (getLeftButtonDimension().isPointInRect(x, y)) + { + setHorizontalScrollAmount(getHorizontalScrollAmount() + - mLeftButtonScrollAmount); + mLeftButtonPressed = true; + } + else if (getRightButtonDimension().isPointInRect(x, y)) + { + setHorizontalScrollAmount(getHorizontalScrollAmount() + + mRightButtonScrollAmount); + mRightButtonPressed = true; + } + else if (getVerticalMarkerDimension().isPointInRect(x, y)) + { + mIsHorizontalMarkerDragged = false; + mIsVerticalMarkerDragged = true; + + mVerticalMarkerDragOffset = y - getVerticalMarkerDimension().y; + } + else if (getVerticalBarDimension().isPointInRect(x,y)) + { + if (y < getVerticalMarkerDimension().y) + { + setVerticalScrollAmount(getVerticalScrollAmount() + - (int)(getChildrenArea().height * 0.95)); + } + else + { + setVerticalScrollAmount(getVerticalScrollAmount() + + (int)(getChildrenArea().height * 0.95)); + } + } + else if (getHorizontalMarkerDimension().isPointInRect(x, y)) + { + mIsHorizontalMarkerDragged = true; + mIsVerticalMarkerDragged = false; + + mHorizontalMarkerDragOffset = x - getHorizontalMarkerDimension().x; + } + else if (getHorizontalBarDimension().isPointInRect(x,y)) + { + if (x < getHorizontalMarkerDimension().x) + { + setHorizontalScrollAmount(getHorizontalScrollAmount() + - (int)(getChildrenArea().width * 0.95)); + } + else + { + setHorizontalScrollAmount(getHorizontalScrollAmount() + + (int)(getChildrenArea().width * 0.95)); + } + } + } + + void ScrollArea::mouseReleased(MouseEvent& mouseEvent) + { + mUpButtonPressed = false; + mDownButtonPressed = false; + mLeftButtonPressed = false; + mRightButtonPressed = false; + mIsHorizontalMarkerDragged = false; + mIsVerticalMarkerDragged = false; + + mouseEvent.consume(); + } + + void ScrollArea::mouseDragged(MouseEvent& mouseEvent) + { + if (mIsVerticalMarkerDragged) + { + int pos = mouseEvent.getY() - getVerticalBarDimension().y - mVerticalMarkerDragOffset; + int length = getVerticalMarkerDimension().height; + + Rectangle barDim = getVerticalBarDimension(); + + if ((barDim.height - length) > 0) + { + setVerticalScrollAmount((getVerticalMaxScroll() * pos) + / (barDim.height - length)); + } + else + { + setVerticalScrollAmount(0); + } + } + + if (mIsHorizontalMarkerDragged) + { + int pos = mouseEvent.getX() - getHorizontalBarDimension().x - mHorizontalMarkerDragOffset; + int length = getHorizontalMarkerDimension().width; + + Rectangle barDim = getHorizontalBarDimension(); + + if ((barDim.width - length) > 0) + { + setHorizontalScrollAmount((getHorizontalMaxScroll() * pos) + / (barDim.width - length)); + } + else + { + setHorizontalScrollAmount(0); + } + } + + mouseEvent.consume(); + } + + void ScrollArea::draw(Graphics *graphics) + { + drawBackground(graphics); + + if (mVBarVisible) + { + drawUpButton(graphics); + drawDownButton(graphics); + drawVBar(graphics); + drawVMarker(graphics); + } + + if (mHBarVisible) + { + drawLeftButton(graphics); + drawRightButton(graphics); + drawHBar(graphics); + drawHMarker(graphics); + } + + if (mHBarVisible && mVBarVisible) + { + graphics->setColor(getBaseColor()); + graphics->fillRectangle(Rectangle(getWidth() - mScrollbarWidth, + getHeight() - mScrollbarWidth, + mScrollbarWidth, + mScrollbarWidth)); + } + + drawChildren(graphics); + } + + void ScrollArea::drawHBar(Graphics* graphics) + { + Rectangle dim = getHorizontalBarDimension(); + + graphics->pushClipArea(dim); + + int alpha = getBaseColor().a; + Color trackColor = getBaseColor() - 0x101010; + trackColor.a = alpha; + Color shadowColor = getBaseColor() - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(trackColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(shadowColor); + graphics->drawLine(0, 0, dim.width, 0); + + graphics->popClipArea(); + } + + void ScrollArea::drawVBar(Graphics* graphics) + { + Rectangle dim = getVerticalBarDimension(); + + graphics->pushClipArea(dim); + + int alpha = getBaseColor().a; + Color trackColor = getBaseColor() - 0x101010; + trackColor.a = alpha; + Color shadowColor = getBaseColor() - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(trackColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(shadowColor); + graphics->drawLine(0, 0, 0, dim.height); + + graphics->popClipArea(); + } + + void ScrollArea::drawBackground(Graphics *graphics) + { + if (isOpaque()) + { + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(getChildrenArea()); + } + } + + void ScrollArea::drawUpButton(Graphics* graphics) + { + Rectangle dim = getUpButtonDimension(); + graphics->pushClipArea(dim); + + Color highlightColor; + Color shadowColor; + Color faceColor; + int offset; + int alpha = getBaseColor().a; + + if (mUpButtonPressed) + { + faceColor = getBaseColor() - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = getBaseColor(); + shadowColor.a = alpha; + + offset = 1; + } + else + { + faceColor = getBaseColor(); + faceColor.a = alpha; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + offset = 0; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + + graphics->setColor(getForegroundColor()); + + int i; + int w = dim.height / 2; + int h = w / 2 + 2; + for (i = 0; i < w / 2; ++i) + { + graphics->drawLine(w - i + offset, + i + h + offset, + w + i + offset, + i + h + offset); + } + + graphics->popClipArea(); + } + + void ScrollArea::drawDownButton(Graphics* graphics) + { + Rectangle dim = getDownButtonDimension(); + graphics->pushClipArea(dim); + + Color highlightColor; + Color shadowColor; + Color faceColor; + int offset; + int alpha = getBaseColor().a; + + if (mDownButtonPressed) + { + faceColor = getBaseColor() - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = getBaseColor(); + shadowColor.a = alpha; + + offset = 1; + } + else + { + faceColor = getBaseColor(); + faceColor.a = alpha; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + offset = 0; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + + graphics->setColor(getForegroundColor()); + + int i; + int w = dim.height / 2; + int h = w + 1; + for (i = 0; i < w / 2; ++i) + { + graphics->drawLine(w - i + offset, + -i + h + offset, + w + i + offset, + -i + h + offset); + } + + graphics->popClipArea(); + } + + void ScrollArea::drawLeftButton(Graphics* graphics) + { + Rectangle dim = getLeftButtonDimension(); + graphics->pushClipArea(dim); + + Color highlightColor; + Color shadowColor; + Color faceColor; + int offset; + int alpha = getBaseColor().a; + + if (mLeftButtonPressed) + { + faceColor = getBaseColor() - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = getBaseColor(); + shadowColor.a = alpha; + + offset = 1; + } + else + { + faceColor = getBaseColor(); + faceColor.a = alpha; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + offset = 0; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + + graphics->setColor(getForegroundColor()); + + int i; + int w = dim.width / 2; + int h = w - 2; + for (i = 0; i < w / 2; ++i) + { + graphics->drawLine(i + h + offset, + w - i + offset, + i + h + offset, + w + i + offset); + } + + graphics->popClipArea(); + } + + void ScrollArea::drawRightButton(Graphics* graphics) + { + Rectangle dim = getRightButtonDimension(); + graphics->pushClipArea(dim); + + Color highlightColor; + Color shadowColor; + Color faceColor; + int offset; + int alpha = getBaseColor().a; + + if (mRightButtonPressed) + { + faceColor = getBaseColor() - 0x303030; + faceColor.a = alpha; + highlightColor = faceColor - 0x303030; + highlightColor.a = alpha; + shadowColor = getBaseColor(); + shadowColor.a = alpha; + + offset = 1; + } + else + { + faceColor = getBaseColor(); + faceColor.a = alpha; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + offset = 0; + } + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(0, 0, dim.width, dim.height)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + + graphics->setColor(getForegroundColor()); + + int i; + int w = dim.width / 2; + int h = w + 1; + for (i = 0; i < w / 2; ++i) + { + graphics->drawLine(-i + h + offset, + w - i + offset, + -i + h + offset, + w + i + offset); + } + + graphics->popClipArea(); + } + + void ScrollArea::drawVMarker(Graphics* graphics) + { + Rectangle dim = getVerticalMarkerDimension(); + graphics->pushClipArea(dim); + + int alpha = getBaseColor().a; + Color faceColor = getBaseColor(); + faceColor.a = alpha; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(1, 1, dim.width - 1, dim.height - 1)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + + graphics->popClipArea(); + } + + void ScrollArea::drawHMarker(Graphics* graphics) + { + Rectangle dim = getHorizontalMarkerDimension(); + graphics->pushClipArea(dim); + + int alpha = getBaseColor().a; + Color faceColor = getBaseColor(); + faceColor.a = alpha; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(faceColor); + graphics->fillRectangle(Rectangle(1, 1, dim.width - 1, dim.height - 1)); + + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, dim.width - 1, 0); + graphics->drawLine(0, 1, 0, dim.height - 1); + + graphics->setColor(shadowColor); + graphics->drawLine(1, dim.height - 1, dim.width - 1, dim.height - 1); + graphics->drawLine(dim.width - 1, 0, dim.width - 1, dim.height - 1); + + graphics->popClipArea(); + } + + void ScrollArea::logic() + { + checkPolicies(); + + setVerticalScrollAmount(getVerticalScrollAmount()); + setHorizontalScrollAmount(getHorizontalScrollAmount()); + + if (getContent() != NULL) + { + getContent()->setPosition(-mHScroll + getContent()->getFrameSize(), + -mVScroll + getContent()->getFrameSize()); + getContent()->logic(); + } + } + + void ScrollArea::checkPolicies() + { + int w = getWidth(); + int h = getHeight(); + + mHBarVisible = false; + mVBarVisible = false; + + + if (!getContent()) + { + mHBarVisible = (mHPolicy == SHOW_ALWAYS); + mVBarVisible = (mVPolicy == SHOW_ALWAYS); + return; + } + + if (mHPolicy == SHOW_AUTO && + mVPolicy == SHOW_AUTO) + { + if (getContent()->getWidth() <= w + && getContent()->getHeight() <= h) + { + mHBarVisible = false; + mVBarVisible = false; + } + + if (getContent()->getWidth() > w) + { + mHBarVisible = true; + } + + if ((getContent()->getHeight() > h) + || (mHBarVisible && getContent()->getHeight() > h - mScrollbarWidth)) + { + mVBarVisible = true; + } + + if (mVBarVisible && getContent()->getWidth() > w - mScrollbarWidth) + { + mHBarVisible = true; + } + + return; + } + + switch (mHPolicy) + { + case SHOW_NEVER: + mHBarVisible = false; + break; + + case SHOW_ALWAYS: + mHBarVisible = true; + break; + + case SHOW_AUTO: + if (mVPolicy == SHOW_NEVER) + { + mHBarVisible = getContent()->getWidth() > w; + } + else // (mVPolicy == SHOW_ALWAYS) + { + mHBarVisible = getContent()->getWidth() > w - mScrollbarWidth; + } + break; + + default: + throw GCN_EXCEPTION("Horizontal scroll policy invalid."); + } + + switch (mVPolicy) + { + case SHOW_NEVER: + mVBarVisible = false; + break; + + case SHOW_ALWAYS: + mVBarVisible = true; + break; + + case SHOW_AUTO: + if (mHPolicy == SHOW_NEVER) + { + mVBarVisible = getContent()->getHeight() > h; + } + else // (mHPolicy == SHOW_ALWAYS) + { + mVBarVisible = getContent()->getHeight() > h - mScrollbarWidth; + } + break; + default: + throw GCN_EXCEPTION("Vertical scroll policy invalid."); + } + } + + Rectangle ScrollArea::getUpButtonDimension() + { + if (!mVBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + return Rectangle(getWidth() - mScrollbarWidth, + 0, + mScrollbarWidth, + mScrollbarWidth); + } + + Rectangle ScrollArea::getDownButtonDimension() + { + if (!mVBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + if (mVBarVisible && mHBarVisible) + { + return Rectangle(getWidth() - mScrollbarWidth, + getHeight() - mScrollbarWidth*2, + mScrollbarWidth, + mScrollbarWidth); + } + + return Rectangle(getWidth() - mScrollbarWidth, + getHeight() - mScrollbarWidth, + mScrollbarWidth, + mScrollbarWidth); + } + + Rectangle ScrollArea::getLeftButtonDimension() + { + if (!mHBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + return Rectangle(0, + getHeight() - mScrollbarWidth, + mScrollbarWidth, + mScrollbarWidth); + } + + Rectangle ScrollArea::getRightButtonDimension() + { + if (!mHBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + if (mVBarVisible && mHBarVisible) + { + return Rectangle(getWidth() - mScrollbarWidth*2, + getHeight() - mScrollbarWidth, + mScrollbarWidth, + mScrollbarWidth); + } + + return Rectangle(getWidth() - mScrollbarWidth, + getHeight() - mScrollbarWidth, + mScrollbarWidth, + mScrollbarWidth); + } + + Rectangle ScrollArea::getChildrenArea() + { + Rectangle area = Rectangle(0, + 0, + mVBarVisible ? getWidth() - mScrollbarWidth : getWidth(), + mHBarVisible ? getHeight() - mScrollbarWidth : getHeight()); + + if (area.width < 0 || area.height < 0) + return Rectangle(); + + return area; + } + + Rectangle ScrollArea::getVerticalBarDimension() + { + if (!mVBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + if (mHBarVisible) + { + return Rectangle(getWidth() - mScrollbarWidth, + getUpButtonDimension().height, + mScrollbarWidth, + getHeight() + - getUpButtonDimension().height + - getDownButtonDimension().height + - mScrollbarWidth); + } + + return Rectangle(getWidth() - mScrollbarWidth, + getUpButtonDimension().height, + mScrollbarWidth, + getHeight() + - getUpButtonDimension().height + - getDownButtonDimension().height); + } + + Rectangle ScrollArea::getHorizontalBarDimension() + { + if (!mHBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + if (mVBarVisible) + { + return Rectangle(getLeftButtonDimension().width, + getHeight() - mScrollbarWidth, + getWidth() + - getLeftButtonDimension().width + - getRightButtonDimension().width + - mScrollbarWidth, + mScrollbarWidth); + } + + return Rectangle(getLeftButtonDimension().width, + getHeight() - mScrollbarWidth, + getWidth() + - getLeftButtonDimension().width + - getRightButtonDimension().width, + mScrollbarWidth); + } + + Rectangle ScrollArea::getVerticalMarkerDimension() + { + if (!mVBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + int length, pos; + Rectangle barDim = getVerticalBarDimension(); + + if (getContent() && getContent()->getHeight() != 0) + { + length = (barDim.height * getChildrenArea().height) + / getContent()->getHeight(); + } + else + { + length = barDim.height; + } + + if (length < mScrollbarWidth) + { + length = mScrollbarWidth; + } + + if (length > barDim.height) + { + length = barDim.height; + } + + if (getVerticalMaxScroll() != 0) + { + pos = ((barDim.height - length) * getVerticalScrollAmount()) + / getVerticalMaxScroll(); + } + else + { + pos = 0; + } + + return Rectangle(barDim.x, barDim.y + pos, mScrollbarWidth, length); + } + + Rectangle ScrollArea::getHorizontalMarkerDimension() + { + if (!mHBarVisible) + { + return Rectangle(0, 0, 0, 0); + } + + int length, pos; + Rectangle barDim = getHorizontalBarDimension(); + + if (getContent() && getContent()->getWidth() != 0) + { + length = (barDim.width * getChildrenArea().width) + / getContent()->getWidth(); + } + else + { + length = barDim.width; + } + + if (length < mScrollbarWidth) + { + length = mScrollbarWidth; + } + + if (length > barDim.width) + { + length = barDim.width; + } + + if (getHorizontalMaxScroll() != 0) + { + pos = ((barDim.width - length) * getHorizontalScrollAmount()) + / getHorizontalMaxScroll(); + } + else + { + pos = 0; + } + + return Rectangle(barDim.x + pos, barDim.y, length, mScrollbarWidth); + } + + void ScrollArea::showWidgetPart(Widget* widget, Rectangle area) + { + if (widget != getContent()) + { + throw GCN_EXCEPTION("Widget not content widget"); + } + + BasicContainer::showWidgetPart(widget, area); + + setHorizontalScrollAmount(getContent()->getFrameSize() - getContent()->getX()); + setVerticalScrollAmount(getContent()->getFrameSize() - getContent()->getY()); + } + + Widget *ScrollArea::getWidgetAt(int x, int y) + { + if (getChildrenArea().isPointInRect(x, y)) + { + return getContent(); + } + + return NULL; + } + + void ScrollArea::mouseWheelMovedUp(MouseEvent& mouseEvent) + { + if (mouseEvent.isConsumed()) + { + return; + } + + setVerticalScrollAmount(getVerticalScrollAmount() - getChildrenArea().height / 8); + + mouseEvent.consume(); + } + + void ScrollArea::mouseWheelMovedDown(MouseEvent& mouseEvent) + { + if (mouseEvent.isConsumed()) + { + return; + } + + setVerticalScrollAmount(getVerticalScrollAmount() + getChildrenArea().height / 8); + + mouseEvent.consume(); + } + + void ScrollArea::setWidth(int width) + { + Widget::setWidth(width); + checkPolicies(); + } + + void ScrollArea::setHeight(int height) + { + Widget::setHeight(height); + checkPolicies(); + } + + void ScrollArea::setDimension(const Rectangle& dimension) + { + Widget::setDimension(dimension); + checkPolicies(); + } + + void ScrollArea::setLeftButtonScrollAmount(int amount) + { + mLeftButtonScrollAmount = amount; + } + + void ScrollArea::setRightButtonScrollAmount(int amount) + { + mRightButtonScrollAmount = amount; + } + + void ScrollArea::setUpButtonScrollAmount(int amount) + { + mUpButtonScrollAmount = amount; + } + + void ScrollArea::setDownButtonScrollAmount(int amount) + { + mDownButtonScrollAmount = amount; + } + + int ScrollArea::getLeftButtonScrollAmount() const + { + return mLeftButtonScrollAmount; + } + + int ScrollArea::getRightButtonScrollAmount() const + { + return mRightButtonScrollAmount; + } + + int ScrollArea::getUpButtonScrollAmount() const + { + return mUpButtonScrollAmount; + } + + int ScrollArea::getDownButtonScrollAmount() const + { + return mDownButtonScrollAmount; + } + + void ScrollArea::setOpaque(bool opaque) + { + mOpaque = opaque; + } + + + bool ScrollArea::isOpaque() const + { + return mOpaque; + } +} + +/* + * Wow! This is a looooong source file. + */ diff --git a/src/guichan/widgets/scrollarea.hpp b/src/guichan/widgets/scrollarea.hpp new file mode 100644 index 000000000..0b2ccad92 --- /dev/null +++ b/src/guichan/widgets/scrollarea.hpp @@ -0,0 +1,590 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_SCROLLAREA_HPP +#define GCN_SCROLLAREA_HPP + +#include <string> + +#include "guichan/basiccontainer.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + /** + * Implementation if a scrollable area used to view widgets larger than the scroll area. + * A scroll area can be customized to always show scroll bars or to show them only when + * necessary. + */ + class GCN_CORE_DECLSPEC ScrollArea: + public BasicContainer, + public MouseListener + { + public: + + /** + * Scrollpolicies for the horizontal and vertical scrollbar. + * The policies are: + * + * SHOW_ALWAYS - Always show the scrollbars no matter what. + * SHOW_NEVER - Never show the scrollbars no matter waht. + * SHOW_AUTO - Show the scrollbars only when needed. That is if the + * content grows larger then the ScrollArea. + */ + enum ScrollPolicy + { + SHOW_ALWAYS = 0, + SHOW_NEVER, + SHOW_AUTO + }; + + /** + * Constructor. + */ + ScrollArea(); + + /** + * Constructor. + * + * @param content The content of the scroll area. + */ + ScrollArea(Widget *content); + + /** + * Constructor. + * + * @param content The content of the scroll area. + * @param hPolicy The policy for the horizontal scrollbar. See enum with + * policies. + * @param vPolicy The policy for the vertical scrollbar. See enum with + * policies. + */ + ScrollArea(Widget *content, + ScrollPolicy hPolicy, + ScrollPolicy vPolicy); + + /** + * Destructor. + */ + virtual ~ScrollArea(); + + /** + * Sets the content. + * + * @param widget The content of the scroll area. + */ + void setContent(Widget* widget); + + /** + * Gets the content. + * + * @return The content of the scroll area. + */ + Widget* getContent(); + + /** + * Sets the horizontal scrollbar policy. See enum with policies. + * + * @param hPolicy The policy for the horizontal scrollbar. + * @see getHorizontalScrollPolicy + */ + void setHorizontalScrollPolicy(ScrollPolicy hPolicy); + + /** + * Gets the horizontal scrollbar policy. See enum with policies. + * + * @return The policy for the horizontal scrollbar policy. + * @see setHorizontalScrollPolicy, setScrollPolicy + */ + ScrollPolicy getHorizontalScrollPolicy() const; + + /** + * Sets the vertical scrollbar policy. See enum with policies. + * + * @param vPolicy The policy for the vertical scrollbar. + * @see getVerticalScrollPolicy + */ + void setVerticalScrollPolicy(ScrollPolicy vPolicy); + + /** + * Gets the vertical scrollbar policy. See enum with policies. + * + * @return The policy for the vertical scrollbar. + * @see setVerticalScrollPolicy, setScrollPolicy + */ + ScrollPolicy getVerticalScrollPolicy() const; + + /** + * Sets the horizontal and vertical scrollbar policy. + * + * @param hPolicy The policy for the horizontal scrollbar. + * @param vPolicy The policy for the vertical scrollbar. + * @see getVerticalScrollPolicy, getHorizontalScrollPolicy + */ + void setScrollPolicy(ScrollPolicy hPolicy, ScrollPolicy vPolicy); + + /** + * Sets the amount to scroll vertically. + * + * @param vScroll The amount to scroll. + * @see getVerticalScrollAmount + */ + void setVerticalScrollAmount(int vScroll); + + /** + * Gets the amount that is scrolled vertically. + * + * @return The scroll amount on vertical scroll. + * @see setVerticalScrollAmount, setScrollAmount + */ + int getVerticalScrollAmount() const; + + /** + * Sets the amount to scroll horizontally. + * + * @param hScroll The amount to scroll. + * @see getHorizontalScrollAmount + */ + void setHorizontalScrollAmount(int hScroll); + + /** + * Gets the amount that is scrolled horizontally. + * + * @return The scroll amount on horizontal scroll. + * @see setHorizontalScrollAmount, setScrollAmount + */ + int getHorizontalScrollAmount() const; + + /** + * Sets the amount to scroll horizontally and vertically. + * + * @param hScroll The amount to scroll on horizontal scroll. + * @param vScroll The amount to scroll on vertical scroll. + * @see getHorizontalScrollAmount, getVerticalScrollAmount + */ + void setScrollAmount(int hScroll, int vScroll); + + /** + * Gets the maximum amount of horizontal scroll. + * + * @return The horizontal max scroll. + */ + int getHorizontalMaxScroll(); + + /** + * Gets the maximum amount of vertical scroll. + * + * @return The vertical max scroll. + */ + int getVerticalMaxScroll(); + + /** + * Sets the width of the scroll bars. + * + * @param width The width of the scroll bars. + * @see getScrollbarWidth + */ + void setScrollbarWidth(int width); + + /** + * Gets the width of the scroll bars. + * + * @return the width of the ScrollBar. + * @see setScrollbarWidth + */ + int getScrollbarWidth() const; + + /** + * Sets the amount to scroll in pixels when the left scroll button is + * pushed. + * + * @param amount The amount to scroll in pixels. + * @see getLeftButtonScrollAmount + */ + void setLeftButtonScrollAmount(int amount); + + /** + * Sets the amount to scroll in pixels when the right scroll button is + * pushed. + * + * @param amount The amount to scroll in pixels. + * @see getRightButtonScrollAmount + */ + void setRightButtonScrollAmount(int amount); + + /** + * Sets the amount to scroll in pixels when the up scroll button is + * pushed. + * + * @param amount The amount to scroll in pixels. + * @see getUpButtonScrollAmount + */ + void setUpButtonScrollAmount(int amount); + + /** + * Sets the amount to scroll in pixels when the down scroll button is + * pushed. + * + * @param amount The amount to scroll in pixels. + * @see getDownButtonScrollAmount + */ + void setDownButtonScrollAmount(int amount); + + /** + * Gets the amount to scroll in pixels when the left scroll button is + * pushed. + * + * @return The amount to scroll in pixels. + * @see setLeftButtonScrollAmount + */ + int getLeftButtonScrollAmount() const; + + /** + * Gets the amount to scroll in pixels when the right scroll button is + * pushed. + * + * @return The amount to scroll in pixels. + * @see setRightButtonScrollAmount + */ + int getRightButtonScrollAmount() const; + + /** + * Gets the amount to scroll in pixels when the up scroll button is + * pushed. + * + * @return The amount to scroll in pixels. + * @see setUpButtonScrollAmount + */ + int getUpButtonScrollAmount() const; + + /** + * Gets the amount to scroll in pixels when the down scroll button is + * pushed. + * + * @return The amount to scroll in pixels. + * @see setDownButtonScrollAmount + */ + int getDownButtonScrollAmount() const; + + /** + * Sets the scroll area to be opaque, that is sets the scoll area + * to display its background. + * + * @param opaque True if the scoll area should be opaque, false otherwise. + */ + 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. + */ + bool isOpaque() const; + + + // Inherited from BasicContainer + + virtual void showWidgetPart(Widget* widget, Rectangle area); + + virtual Rectangle getChildrenArea(); + + virtual Widget *getWidgetAt(int x, int y); + + + // Inherited from Widget + + virtual void draw(Graphics *graphics); + + virtual void logic(); + + void setWidth(int width); + + void setHeight(int height); + + void setDimension(const Rectangle& dimension); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseReleased(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(MouseEvent& mouseEvent); + + protected: + /** + * Draws the background of the scroll area, that is + * the area behind the content. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawBackground(Graphics *graphics); + + /** + * Draws the up button. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawUpButton(Graphics *graphics); + + /** + * Draws the down button. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawDownButton(Graphics *graphics); + + /** + * Draws the left button. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawLeftButton(Graphics *graphics); + + /** + * Draws the right button. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawRightButton(Graphics *graphics); + + /** + * Draws the vertical scroll bar. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawVBar(Graphics* graphics); + + /** + * Draws the horizontal scroll bar. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawHBar(Graphics* graphics); + + /** + * Draws the vertical marker. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawVMarker(Graphics* graphics); + + /** + * Draws the horizontal marker. + * + * @param graphics a Graphics object to draw with. + */ + virtual void drawHMarker(Graphics* graphics); + + /** + * Checks the policies for the scroll bars. + */ + virtual void checkPolicies(); + + /** + * Gets the up button dimension. + * + * @return the dimension of the up button. + */ + Rectangle getUpButtonDimension(); + + /** + * Gets the down button dimension. + * + * @return the dimension of the down button. + */ + Rectangle getDownButtonDimension(); + + /** + * Gets the left button dimension. + * + * @return the dimension of the left button. + */ + Rectangle getLeftButtonDimension(); + + /** + * Gets the right button dimension. + * + * @return the dimension of the right button. + */ + Rectangle getRightButtonDimension(); + + /** + * Gets the vertical scrollbar dimension. + * + * @return the dimension of the vertical scrollbar. + */ + Rectangle getVerticalBarDimension(); + + /** + * Gets the horizontal scrollbar dimension. + * + * @return the dimension of the horizontal scrollbar. + */ + Rectangle getHorizontalBarDimension(); + + /** + * Gets the vertical marker dimension. + * + * @return the dimension of the vertical marker. + */ + Rectangle getVerticalMarkerDimension(); + + /** + * Gets the horizontal marker dimension. + * + * @return the dimension of the horizontal marker. + */ + Rectangle getHorizontalMarkerDimension(); + + /** + * Holds the vertical scroll amount. + */ + int mVScroll; + + /** + * Holds the horizontal scroll amount. + */ + int mHScroll; + + /** + * Holds the width of the scroll bars. + */ + int mScrollbarWidth; + + /** + * Holds the horizontal scroll bar policy. + */ + ScrollPolicy mHPolicy; + + /** + * Holds the vertical scroll bar policy. + */ + ScrollPolicy mVPolicy; + + /** + * True if the vertical scroll bar is visible, false otherwise. + */ + bool mVBarVisible; + + /** + * True if the horizontal scroll bar is visible, false otherwise. + */ + bool mHBarVisible; + + /** + * True if the up button is pressed, false otherwise. + */ + bool mUpButtonPressed; + + /** + * True if the down button is pressed, false otherwise. + */ + bool mDownButtonPressed; + + /** + * True if the left button is pressed, false otherwise. + */ + bool mLeftButtonPressed; + + /** + * True if the right button is pressed, false otherwise. + */ + bool mRightButtonPressed; + + /** + * Holds the up button scroll amount. + */ + int mUpButtonScrollAmount; + + /** + * Holds the down button scroll amount. + */ + int mDownButtonScrollAmount; + + /** + * Holds the left button scroll amount. + */ + int mLeftButtonScrollAmount; + + /** + * Holds the right button scroll amount. + */ + int mRightButtonScrollAmount; + + /** + * True if the vertical marked is dragged. + */ + bool mIsVerticalMarkerDragged; + + /** + * True if the horizontal marked is dragged. + */ + bool mIsHorizontalMarkerDragged; + + /** + * Holds the horizontal markers drag offset. + */ + int mHorizontalMarkerDragOffset; + + /** + * Holds the vertical markers drag offset. + */ + int mVerticalMarkerDragOffset; + + /** + * True if the scroll area should be opaque (that is + * display its background), false otherwise. + */ + bool mOpaque; + }; +} + +#endif // end GCN_SCROLLAREA_HPP diff --git a/src/guichan/widgets/slider.cpp b/src/guichan/widgets/slider.cpp new file mode 100644 index 000000000..a32209124 --- /dev/null +++ b/src/guichan/widgets/slider.cpp @@ -0,0 +1,369 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/slider.hpp" + +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + Slider::Slider(double scaleEnd) + { + mDragged = false; + + mScaleStart = 0; + mScaleEnd = scaleEnd; + + setFocusable(true); + setFrameSize(1); + setOrientation(HORIZONTAL); + setValue(0); + setStepLength(scaleEnd / 10); + setMarkerLength(10); + + addMouseListener(this); + addKeyListener(this); + } + + Slider::Slider(double scaleStart, double scaleEnd) + { + mDragged = false; + + mScaleStart = scaleStart; + mScaleEnd = scaleEnd; + + setFocusable(true); + setFrameSize(1); + setOrientation(HORIZONTAL); + setValue(scaleStart); + setStepLength((scaleEnd - scaleStart)/ 10); + setMarkerLength(10); + + addMouseListener(this); + addKeyListener(this); + } + + void Slider::setScale(double scaleStart, double scaleEnd) + { + mScaleStart = scaleStart; + mScaleEnd = scaleEnd; + } + + double Slider::getScaleStart() const + { + return mScaleStart; + } + + void Slider::setScaleStart(double scaleStart) + { + mScaleStart = scaleStart; + } + + double Slider::getScaleEnd() const + { + return mScaleEnd; + } + + void Slider::setScaleEnd(double scaleEnd) + { + mScaleEnd = scaleEnd; + } + + void Slider::draw(gcn::Graphics* graphics) + { + Color shadowColor = getBaseColor() - 0x101010; + int alpha = getBaseColor().a; + shadowColor.a = alpha; + + graphics->setColor(shadowColor); + graphics->fillRectangle(gcn::Rectangle(0,0,getWidth(),getHeight())); + + drawMarker(graphics); + } + + void Slider::drawMarker(gcn::Graphics* graphics) + { + gcn::Color faceColor = getBaseColor(); + Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + graphics->setColor(faceColor); + + if (getOrientation() == HORIZONTAL) + { + int v = getMarkerPosition(); + graphics->fillRectangle(gcn::Rectangle(v + 1, 1, getMarkerLength() - 2, getHeight() - 2)); + graphics->setColor(highlightColor); + graphics->drawLine(v, 0, v + getMarkerLength() - 1,0); + graphics->drawLine(v, 0, v, getHeight() - 1); + graphics->setColor(shadowColor); + graphics->drawLine(v + getMarkerLength() - 1, 1, v + getMarkerLength() - 1, getHeight() - 1); + graphics->drawLine(v + 1, getHeight() - 1, v + getMarkerLength() - 1, getHeight() - 1); + + if (isFocused()) + { + graphics->setColor(getForegroundColor()); + graphics->drawRectangle(Rectangle(v + 2, 2, getMarkerLength() - 4, getHeight() - 4)); + } + } + else + { + int v = (getHeight() - getMarkerLength()) - getMarkerPosition(); + graphics->fillRectangle(gcn::Rectangle(1, v + 1, getWidth() - 2, getMarkerLength() - 2)); + graphics->setColor(highlightColor); + graphics->drawLine(0, v, 0, v + getMarkerLength() - 1); + graphics->drawLine(0, v, getWidth() - 1, v); + graphics->setColor(shadowColor); + graphics->drawLine(1, v + getMarkerLength() - 1, getWidth() - 1, v + getMarkerLength() - 1); + graphics->drawLine(getWidth() - 1, v + 1, getWidth() - 1, v + getMarkerLength() - 1); + + if (isFocused()) + { + graphics->setColor(getForegroundColor()); + graphics->drawRectangle(Rectangle(2, v + 2, getWidth() - 4, getMarkerLength() - 4)); + } + } + } + + void Slider::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT + && mouseEvent.getX() >= 0 + && mouseEvent.getX() <= getWidth() + && mouseEvent.getY() >= 0 + && mouseEvent.getY() <= getHeight()) + { + if (getOrientation() == HORIZONTAL) + { + setValue(markerPositionToValue(mouseEvent.getX() - getMarkerLength() / 2)); + } + else + { + setValue(markerPositionToValue(getHeight() - mouseEvent.getY() - getMarkerLength() / 2)); + } + + distributeActionEvent(); + } + } + + void Slider::mouseDragged(MouseEvent& mouseEvent) + { + if (getOrientation() == HORIZONTAL) + { + setValue(markerPositionToValue(mouseEvent.getX() - getMarkerLength() / 2)); + } + else + { + setValue(markerPositionToValue(getHeight() - mouseEvent.getY() - getMarkerLength() / 2)); + } + + distributeActionEvent(); + + mouseEvent.consume(); + } + + void Slider::setValue(double value) + { + if (value > getScaleEnd()) + { + mValue = getScaleEnd(); + return; + } + + if (value < getScaleStart()) + { + mValue = getScaleStart(); + return; + } + + mValue = value; + } + + double Slider::getValue() const + { + return mValue; + } + + int Slider::getMarkerLength() const + { + return mMarkerLength; + } + + void Slider::setMarkerLength(int length) + { + mMarkerLength = length; + } + + void Slider::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (getOrientation() == HORIZONTAL) + { + if (key.getValue() == Key::RIGHT) + { + setValue(getValue() + getStepLength()); + distributeActionEvent(); + keyEvent.consume(); + } + else if (key.getValue() == Key::LEFT) + { + setValue(getValue() - getStepLength()); + distributeActionEvent(); + keyEvent.consume(); + } + } + else + { + if (key.getValue() == Key::UP) + { + setValue(getValue() + getStepLength()); + distributeActionEvent(); + keyEvent.consume(); + } + else if (key.getValue() == Key::DOWN) + { + setValue(getValue() - getStepLength()); + distributeActionEvent(); + keyEvent.consume(); + } + } + } + + void Slider::setOrientation(Slider::Orientation orientation) + { + mOrientation = orientation; + } + + Slider::Orientation Slider::getOrientation() const + { + return mOrientation; + } + + double Slider::markerPositionToValue(int v) const + { + int w; + if (getOrientation() == HORIZONTAL) + { + w = getWidth(); + } + else + { + w = getHeight(); + } + + double pos = v / ((double)w - getMarkerLength()); + return (1.0 - pos) * getScaleStart() + pos * getScaleEnd(); + + } + + int Slider::valueToMarkerPosition(double value) const + { + int v; + if (getOrientation() == HORIZONTAL) + { + v = getWidth(); + } + else + { + v = getHeight(); + } + + int w = (int)((v - getMarkerLength()) + * (value - getScaleStart()) + / (getScaleEnd() - getScaleStart())); + + if (w < 0) + { + return 0; + } + + if (w > v - getMarkerLength()) + { + return v - getMarkerLength(); + } + + return w; + } + + void Slider::setStepLength(double length) + { + mStepLength = length; + } + + double Slider::getStepLength() const + { + return mStepLength; + } + + int Slider::getMarkerPosition() const + { + return valueToMarkerPosition(getValue()); + } + + void Slider::mouseWheelMovedUp(MouseEvent& mouseEvent) + { + setValue(getValue() + getStepLength()); + distributeActionEvent(); + + mouseEvent.consume(); + } + + void Slider::mouseWheelMovedDown(MouseEvent& mouseEvent) + { + setValue(getValue() - getStepLength()); + distributeActionEvent(); + + mouseEvent.consume(); + } +} diff --git a/src/guichan/widgets/slider.hpp b/src/guichan/widgets/slider.hpp new file mode 100644 index 000000000..eddf02c50 --- /dev/null +++ b/src/guichan/widgets/slider.hpp @@ -0,0 +1,300 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_SLIDER_HPP +#define GCN_SLIDER_HPP + +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * An implementation of a slider where a user can select different values by + * sliding between a start value and an end value of a scale. + * + * If the selected value is changed an action event will be sent to all + * action listeners of the slider. + */ + class GCN_CORE_DECLSPEC Slider : + public Widget, + public MouseListener, + public KeyListener + { + public: + + /** + * Draw orientations for the slider. A slider can be drawn vertically or + * horizontally. + */ + enum Orientation + { + HORIZONTAL = 0, + VERTICAL + }; + + /** + * Constructor. The default start value of the slider scale is zero. + * + * @param scaleEnd The end value of the slider scale. + */ + Slider(double scaleEnd = 1.0); + + /** + * Constructor. + * + * @param scaleStart The start value of the slider scale. + * @param scaleEnd The end value of the slider scale. + */ + Slider(double scaleStart, double scaleEnd); + + /** + * Destructor. + */ + virtual ~Slider() { } + + /** + * Sets the scale of the slider. + * + * @param scaleStart The start value of the scale. + * @param scaleEnd tThe end of value the scale. + * @see getScaleStart, getScaleEnd + */ + void setScale(double scaleStart, double scaleEnd); + + /** + * Gets the start value of the scale. + * + * @return The start value of the scale. + * @see setScaleStart, setScale + */ + double getScaleStart() const; + + /** + * Sets the start value of the scale. + * + * @param scaleStart The start value of the scale. + * @see getScaleStart + */ + void setScaleStart(double scaleStart); + + /** + * Gets the end value of the scale. + * + * @return The end value of the scale. + * @see setScaleEnd, setScale + */ + double getScaleEnd() const; + + /** + * Sets the end value of the scale. + * + * @param scaleEnd The end value of the scale. + * @see getScaleEnd + */ + void setScaleEnd(double scaleEnd); + + /** + * Gets the current selected value. + * + * @return The current selected value. + * @see setValue + */ + double getValue() const; + + /** + * Sets the current selected value. + * + * @param value The current selected value. + * @see getValue + */ + void setValue(double value); + + /** + * Sets the length of the marker. + * + * @param length The length for the marker. + * @see getMarkerLength + */ + void setMarkerLength(int length); + + /** + * Gets the length of the marker. + * + * @return The length of the marker. + * @see setMarkerLength + */ + int getMarkerLength() const; + + /** + * Sets the orientation of the slider. A slider can be drawn vertically + * or horizontally. + * + * @param orientation The orientation of the slider. + * @see getOrientation + */ + void setOrientation(Orientation orientation); + + /** + * Gets the orientation of the slider. A slider can be drawn vertically + * or horizontally. + * + * @return The orientation of the slider. + * @see setOrientation + */ + Orientation getOrientation() const; + + /** + * Sets the step length. The step length is used when the keys LEFT + * and RIGHT are pressed to step in the scale. + * + * @param length The step length. + * @see getStepLength + */ + void setStepLength(double length); + + /** + * Gets the step length. The step length is used when the keys LEFT + * and RIGHT are pressed to step in the scale. + * + * @return the step length. + * @see setStepLength + */ + double getStepLength() const; + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + + // Inherited from MouseListener. + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(MouseEvent& mouseEvent); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + protected: + /** + * Draws the marker. + * + * @param graphics A graphics object to draw with. + */ + virtual void drawMarker(gcn::Graphics* graphics); + + /** + * Converts a marker position to a value in the scale. + * + * @param position The position to convert. + * @return A scale value corresponding to the position. + * @see valueToMarkerPosition + */ + virtual double markerPositionToValue(int position) const; + + /** + * Converts a value to a marker position. + * + * @param value The value to convert. + * @return A marker position corresponding to the value. + * @see markerPositionToValue + */ + virtual int valueToMarkerPosition(double value) const; + + /** + * Gets the marker position of the current selected value. + * + * @return The marker position of the current selected value. + */ + virtual int getMarkerPosition() const; + + /** + * True if the slider is dragged, false otherwise. + */ + bool mDragged; + + /** + * Holds the current selected value. + */ + double mValue; + + /** + * Holds the step length. The step length is used when the keys LEFT + * and RIGHT are pressed to step in the scale. + */ + double mStepLength; + + /** + * Holds the length of the marker. + */ + int mMarkerLength; + + /** + * Holds the start value of the scale. + */ + double mScaleStart; + + /** + * Holds the end value of the scale. + */ + double mScaleEnd; + + /** + * Holds the orientation of the slider. A slider can be drawn + * vertically or horizontally. + */ + Orientation mOrientation; + }; +} + +#endif // end GCN_SLIDER_HPP diff --git a/src/guichan/widgets/tab.cpp b/src/guichan/widgets/tab.cpp new file mode 100644 index 000000000..8ba122b26 --- /dev/null +++ b/src/guichan/widgets/tab.cpp @@ -0,0 +1,181 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/tab.hpp" + +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/widgets/button.hpp" +#include "guichan/widgets/label.hpp" +#include "guichan/widgets/tabbedarea.hpp" + +namespace gcn +{ + Tab::Tab() + :mHasMouse(false), + mTabbedArea(NULL) + { + mLabel = new Label(); + mLabel->setPosition(4, 4); + add(mLabel); + + addMouseListener(this); + } + + Tab::~Tab() + { + delete mLabel; + } + + void Tab::adjustSize() + { + setSize(mLabel->getWidth() + 8, + mLabel->getHeight() + 8); + + if (mTabbedArea != NULL) + { + mTabbedArea->adjustTabPositions(); + } + } + + void Tab::setTabbedArea(TabbedArea* tabbedArea) + { + mTabbedArea = tabbedArea; + } + + TabbedArea* Tab::getTabbedArea() + { + return mTabbedArea; + } + + void Tab::setCaption(const std::string& caption) + { + mLabel->setCaption(caption); + mLabel->adjustSize(); + adjustSize(); + } + + const std::string& Tab::getCaption() const + { + return mLabel->getCaption(); + } + + void Tab::draw(Graphics *graphics) + { + const Color &faceColor = getBaseColor(); + const int alpha = getBaseColor().a; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + Color borderColor; + Color baseColor; + + if ((mTabbedArea != NULL && mTabbedArea->isTabSelected(this)) + || mHasMouse) + { + // Draw a border. + graphics->setColor(highlightColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, getHeight() - 1); + graphics->setColor(shadowColor); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); + + borderColor = highlightColor; + baseColor = getBaseColor(); + } + else + { + // Draw a border. + graphics->setColor(shadowColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, getHeight() - 1); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); + + baseColor = getBaseColor() - 0x151515; + baseColor.a = alpha; + } + + // Push a clip area so the other drawings don't need to worry + // about the border. + graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 1)); + const Rectangle currentClipArea = graphics->getCurrentClipArea(); + + graphics->setColor(baseColor); + graphics->fillRectangle(Rectangle(0, + 0, + currentClipArea.width, + currentClipArea.height)); + + drawChildren(graphics); + + if (mTabbedArea != NULL + && mTabbedArea->isFocused() + && mTabbedArea->isTabSelected(this)) + { + graphics->setColor(Color(0x000000)); + graphics->drawRectangle(Rectangle(2, + 2, + currentClipArea.width - 4, + currentClipArea.height - 4)); + } + + graphics->popClipArea(); + } + + void Tab::mouseEntered(MouseEvent& mouseEvent) + { + mHasMouse = true; + } + + void Tab::mouseExited(MouseEvent& mouseEvent) + { + mHasMouse = false; + } +} + diff --git a/src/guichan/widgets/tab.hpp b/src/guichan/widgets/tab.hpp new file mode 100644 index 000000000..bf89afccb --- /dev/null +++ b/src/guichan/widgets/tab.hpp @@ -0,0 +1,151 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_TAB_HPP +#define GCN_TAB_HPP + +#include <map> +#include <string> + +#include "guichan/basiccontainer.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Label; + class TabbedArea; + + /** + * An implementation of a simple tab to be used in a tabbed area. + * + * @see TabbedArea + * @since 0.8.0 + */ + class GCN_CORE_DECLSPEC Tab: + public BasicContainer, + public MouseListener + { + public: + + /** + * Constructor. + */ + Tab(); + + /** + * Destructor. + */ + virtual ~Tab(); + + /** + * Adjusts the size of the tab to fit the caption. If this tab was + * added to a TabbedArea, it will also adjust the tab positions. + */ + void adjustSize(); + + /** + * Sets the tabbed area the tab should be a part of. + * + * @param tabbedArea The tabbed area the tab should be a part of. + * @see getTabbedArea + */ + void setTabbedArea(TabbedArea* tabbedArea); + + /** + * Gets the tabbed are the tab is a part of. + * + * @return The tabbed are the tab is a part of. + * @see setTabbedArea + */ + TabbedArea* getTabbedArea(); + + /** + * Sets the caption of the tab. It's advisable to call + * adjustSize after setting the caption to make the tab + * fit the caption. + * + * @param caption The caption of the tab. + * @see getCaption, adjustSize + */ + void setCaption(const std::string& caption); + + /** + * Gets the caption of the tab. + * + * @return The caption of the tab. + * @see setCaption + */ + const std::string& getCaption() const; + + + // Inherited from Widget + + virtual void draw(Graphics *graphics); + + + // Inherited from MouseListener + + virtual void mouseEntered(MouseEvent& mouseEvent); + + virtual void mouseExited(MouseEvent& mouseEvent); + + protected: + /** + * Holds the label of the tab. + */ + Label* mLabel; + + /** + * True if the tab has the mouse, false otherwise. + */ + bool mHasMouse; + + /** + * Holds the tabbed area the tab is a part of. + */ + TabbedArea* mTabbedArea; + }; +} + +#endif // end GCN_TABBEDAREA_HPP diff --git a/src/guichan/widgets/tabbedarea.cpp b/src/guichan/widgets/tabbedarea.cpp new file mode 100644 index 000000000..e07d14c4d --- /dev/null +++ b/src/guichan/widgets/tabbedarea.cpp @@ -0,0 +1,482 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/tabbedarea.hpp" + +#include "guichan/exception.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" + +#include "guichan/widgets/container.hpp" +#include "guichan/widgets/tab.hpp" + +#include <algorithm> + +namespace gcn +{ + TabbedArea::TabbedArea() + :mSelectedTab(NULL), + mOpaque(false) + { + setFocusable(true); + addKeyListener(this); + addMouseListener(this); + + mTabContainer = new Container(); + mTabContainer->setOpaque(false); + mWidgetContainer = new Container(); + + add(mTabContainer); + add(mWidgetContainer); + } + + TabbedArea::~TabbedArea() + { + remove(mTabContainer); + remove(mWidgetContainer); + + delete mTabContainer; + delete mWidgetContainer; + + for (unsigned int i = 0; i < mTabsToDelete.size(); i++) + { + delete mTabsToDelete[i]; + } + } + + void TabbedArea::addTab(const std::string& caption, Widget* widget) + { + Tab* tab = new Tab(); + tab->setCaption(caption); + mTabsToDelete.push_back(tab); + + addTab(tab, widget); + } + + void TabbedArea::addTab(Tab* tab, Widget* widget) + { + tab->setTabbedArea(this); + tab->addActionListener(this); + + mTabContainer->add(tab); + mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget)); + + if (mSelectedTab == NULL) + { + setSelectedTab(tab); + } + + adjustTabPositions(); + adjustSize(); + } + + void TabbedArea::removeTabWithIndex(unsigned int index) + { + if (index >= mTabs.size()) + { + throw GCN_EXCEPTION("No such tab index."); + } + + removeTab(mTabs[index].first); + } + + void TabbedArea::removeTab(Tab* tab) + { + int tabIndexToBeSelected = - 1; + + if (tab == mSelectedTab) + { + int index = getSelectedTabIndex(); + + if (index == (int)mTabs.size() - 1 + && mTabs.size() >= 2) + { + tabIndexToBeSelected = index--; + } + else if (index == (int)mTabs.size() - 1 + && mTabs.size() == 1) + { + tabIndexToBeSelected = -1; + } + else + { + tabIndexToBeSelected = index; + } + } + + std::vector<std::pair<Tab*, Widget*> >::iterator iter; + for (iter = mTabs.begin(); iter != mTabs.end(); iter++) + { + if (iter->first == tab) + { + mTabContainer->remove(tab); + mTabs.erase(iter); + break; + } + } + + std::vector<Tab*>::iterator iter2; + for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++) + { + if (*iter2 == tab) + { + mTabsToDelete.erase(iter2); + delete tab; + break; + } + } + + if (tabIndexToBeSelected == -1) + { + mSelectedTab = NULL; + mWidgetContainer->clear(); + } + else + { + setSelectedTab(tabIndexToBeSelected); + } + + adjustSize(); + adjustTabPositions(); + } + + bool TabbedArea::isTabSelected(unsigned int index) const + { + if (index >= mTabs.size()) + { + throw GCN_EXCEPTION("No such tab index."); + } + + return mSelectedTab == mTabs[index].first; + } + + bool TabbedArea::isTabSelected(Tab* tab) + { + return mSelectedTab == tab; + } + + void TabbedArea::setSelectedTab(unsigned int index) + { + if (index >= mTabs.size()) + { + throw GCN_EXCEPTION("No such tab index."); + } + + setSelectedTab(mTabs[index].first); + } + + void TabbedArea::setSelectedTab(Tab* tab) + { + unsigned int i; + for (i = 0; i < mTabs.size(); i++) + { + if (mTabs[i].first == mSelectedTab) + { + mWidgetContainer->remove(mTabs[i].second); + } + } + + for (i = 0; i < mTabs.size(); i++) + { + if (mTabs[i].first == tab) + { + mSelectedTab = tab; + mWidgetContainer->add(mTabs[i].second); + } + } + } + + int TabbedArea::getSelectedTabIndex() const + { + unsigned int i; + for (i = 0; i < mTabs.size(); i++) + { + if (mTabs[i].first == mSelectedTab) + { + return i; + } + } + + return -1; + } + + Tab* TabbedArea::getSelectedTab() + { + return mSelectedTab; + } + + void TabbedArea::setOpaque(bool opaque) + { + mOpaque = opaque; + } + + bool TabbedArea::isOpaque() const + { + return mOpaque; + } + + void TabbedArea::draw(Graphics *graphics) + { + const Color &faceColor = getBaseColor(); + const int alpha = getBaseColor().a; + Color highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + Color shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + // Draw a border. + graphics->setColor(highlightColor); + graphics->drawLine(0, + mTabContainer->getHeight(), + 0, + getHeight() - 2); + graphics->setColor(shadowColor); + graphics->drawLine(getWidth() - 1, + mTabContainer->getHeight() + 1, + getWidth() - 1, + getHeight() - 1); + graphics->drawLine(1, + getHeight() - 1, + getWidth() - 1, + getHeight() - 1); + + if (isOpaque()) + { + graphics->setColor(getBaseColor()); + graphics->fillRectangle(Rectangle(1, 1, + getWidth() - 2, + getHeight() - 2)); + } + + // Draw a line underneath the tabs. + graphics->setColor(highlightColor); + graphics->drawLine(1, + mTabContainer->getHeight(), + getWidth() - 1, + mTabContainer->getHeight()); + + // If a tab is selected, remove the line right underneath + // the selected tab. + if (mSelectedTab != NULL) + { + graphics->setColor(getBaseColor()); + graphics->drawLine(mSelectedTab->getX() + 1, + mTabContainer->getHeight(), + mSelectedTab->getX() + mSelectedTab->getWidth() - 2, + mTabContainer->getHeight()); + + } + + drawChildren(graphics); + } + + void TabbedArea::logic() + { + } + + void TabbedArea::adjustSize() + { + int maxTabHeight = 0; + + for (unsigned int i = 0; i < mTabs.size(); i++) + { + if (mTabs[i].first->getHeight() > maxTabHeight) + { + maxTabHeight = mTabs[i].first->getHeight(); + } + } + + mTabContainer->setSize(getWidth() - 2, + maxTabHeight); + + mWidgetContainer->setPosition(1, maxTabHeight + 1); + mWidgetContainer->setSize(getWidth() - 2, + getHeight() - maxTabHeight - 2); + } + + void TabbedArea::adjustTabPositions() + { + int maxTabHeight = 0; + unsigned int i; + for (i = 0; i < mTabs.size(); i++) + { + if (mTabs[i].first->getHeight() > maxTabHeight) + { + maxTabHeight = mTabs[i].first->getHeight(); + } + } + + int x = 0; + for (i = 0; i < mTabs.size(); i++) + { + Tab* tab = mTabs[i].first; + tab->setPosition(x, maxTabHeight - tab->getHeight()); + x += tab->getWidth(); + } + } + + void TabbedArea::setWidth(int width) + { + Widget::setWidth(width); + adjustSize(); + } + + void TabbedArea::setHeight(int height) + { + Widget::setHeight(height); + adjustSize(); + } + + void TabbedArea::setSize(int width, int height) + { + Widget::setSize(width, height); + adjustSize(); + } + + void TabbedArea::setDimension(const Rectangle& dimension) + { + Widget::setDimension(dimension); + adjustSize(); + } + + void TabbedArea::keyPressed(KeyEvent& keyEvent) + { + if (keyEvent.isConsumed() || !isFocused()) + { + return; + } + + if (keyEvent.getKey().getValue() == Key::LEFT) + { + int index = getSelectedTabIndex(); + index--; + + if (index < 0) + { + return; + } + else + { + setSelectedTab(mTabs[index].first); + } + + keyEvent.consume(); + } + else if (keyEvent.getKey().getValue() == Key::RIGHT) + { + int index = getSelectedTabIndex(); + index++; + + if (index >= (int)mTabs.size()) + { + return; + } + else + { + setSelectedTab(mTabs[index].first); + } + + keyEvent.consume(); + } + } + + + void TabbedArea::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.isConsumed()) + { + return; + } + + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY()); + Tab* tab = dynamic_cast<Tab*>(widget); + + if (tab != NULL) + { + setSelectedTab(tab); + } + } + + // Request focus only if the source of the event + // is not focusble. If the source of the event + // is focused we don't want to steal the focus. + if (!mouseEvent.getSource()->isFocusable()) + { + requestFocus(); + } + } + + void TabbedArea::death(const Event& event) + { + Tab* tab = dynamic_cast<Tab*>(event.getSource()); + + if (tab != NULL) + { + removeTab(tab); + } + else + { + BasicContainer::death(event); + } + } + + void TabbedArea::action(const ActionEvent& actionEvent) + { + Widget* source = actionEvent.getSource(); + Tab* tab = dynamic_cast<Tab*>(source); + + if (tab == NULL) + { + throw GCN_EXCEPTION("Received an action from a widget that's not a tab!"); + } + + setSelectedTab(tab); + } +} diff --git a/src/guichan/widgets/tabbedarea.hpp b/src/guichan/widgets/tabbedarea.hpp new file mode 100644 index 000000000..843bbde81 --- /dev/null +++ b/src/guichan/widgets/tabbedarea.hpp @@ -0,0 +1,280 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_TABBEDAREA_HPP +#define GCN_TABBEDAREA_HPP + +#include <map> +#include <string> +#include <vector> + +#include "guichan/actionlistener.hpp" +#include "guichan/basiccontainer.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" + +namespace gcn +{ + class Container; + class Tab; + + /** + * An implementation of a tabbed area where a user can display a widget by + * selecting a tab. + * + * @since 0.8.0 + */ + class GCN_CORE_DECLSPEC TabbedArea: + public ActionListener, + public BasicContainer, + public KeyListener, + public MouseListener + { + friend class Tab; + + public: + /** + * Constructor. + */ + TabbedArea(); + + /** + * Destructor. + */ + virtual ~TabbedArea(); + + /** + * Sets the tabbed area to be opaque or not. If the tabbed area is + * opaque its background will be drawn, if it's not opaque its + * background will not be drawn. By default, a tabbed area is not + * opaque. + * + * The tabbed area's background is normally only visible behind the + * tabs, since the container holding the tab contents is opaque by + * default. + * + * @param opaque True if the tabbed area should be opaque, false + * otherwise. + * @see isOpaque + */ + void setOpaque(bool opaque); + + /** + * Checks if the tabbed area is opaque or not. + * + * @return true if the tabbed area is opaque, false otherwise. + * @see setOpaque + */ + bool isOpaque() const; + + /** + * Adds a tab to the tabbed area. The newly created tab will be + * automatically deleted by the tabbed area when it is removed. + * + * @param caption The caption of the tab to add. + * @param widget The widget to view when the tab is selected. + * @see removeTab, removeTabWithIndex + */ + virtual void addTab(const std::string& caption, Widget* widget); + + /** + * Adds a tab to the tabbed area. The tab will not be deleted by the + * tabbed area when it is removed. + * + * @param tab The tab widget for the tab. + * @param widget The widget to view when the tab is selected. + * @see removeTab, removeTabWithIndex + */ + virtual void addTab(Tab* tab, Widget* widget); + + /** + * Removes a tab from the tabbed area. + * + * @param index The index of the tab to remove. + * @see addTab + */ + virtual void removeTabWithIndex(unsigned int index); + + /** + * Removes a tab from the tabbed area. + * + * @param index The tab to remove. + * @see addTab + */ + virtual void removeTab(Tab* tab); + + /** + * Checks if a tab given an index is selected or not. + * + * @param index The index of the tab to check. + * @return True if the tab is selected, false otherwise. + * @see setSelectedTab + */ + virtual bool isTabSelected(unsigned int index) const; + + /** + * Checks if a tab is selected or not. + * + * @param index The tab to check. + * @return True if the tab is selected, false otherwise. + * @see setSelectedTab + */ + virtual bool isTabSelected(Tab* tab); + + /** + * Sets a tab given an index to be selected. + * + * @param index The index of the tab to be selected. + * @see isTabSelected, getSelectedTab + */ + virtual void setSelectedTab(unsigned int index); + + /** + * Sets a tab to be selected or not. + * + * @param index The tab to be selected. + * @see isTabSelected, getSelectedTab + */ + virtual void setSelectedTab(Tab* tab); + + /** + * Gets the index of the selected tab. + * + * @return The undex of the selected tab. + * If no tab is selected -1 will be returned. + * @see isTabSelected, setSelectedTab + */ + virtual int getSelectedTabIndex() const; + + /** + * Gets the selected tab. + * + * @return The selected tab. + * @see isTabSelected, setSelectedTab + */ + Tab* getSelectedTab(); + + + // Inherited from Widget + + virtual void draw(Graphics *graphics); + + virtual void logic(); + + void setWidth(int width); + + void setHeight(int height); + + void setSize(int width, int height); + + void setDimension(const Rectangle& dimension); + + + // Inherited from ActionListener + + void action(const ActionEvent& actionEvent); + + + // Inherited from DeathListener + + virtual void death(const Event& event); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + + protected: + /** + * Adjusts the size of the tab container and the widget container. + */ + void adjustSize(); + + /** + * Adjusts the positions of the tabs. + */ + void adjustTabPositions(); + + /** + * Holds the selected tab. + */ + Tab* mSelectedTab; + + /** + * Holds the container for the tabs. + */ + Container* mTabContainer; + + /** + * Holds the container for the widgets. + */ + Container* mWidgetContainer; + + /** + * Holds a vector of tabs to delete in the destructor. + * A tab that is to be deleted is a tab that has been + * internally created by the tabbed area. + */ + std::vector<Tab*> mTabsToDelete; + + /** + * A map between a tab and a widget to display when the + * tab is selected. + */ + std::vector<std::pair<Tab*, Widget*> > mTabs; + + /** + * True if the tabbed area is opaque, false otherwise. + */ + bool mOpaque; + }; +} + +#endif // end GCN_TABBEDAREA_HPP diff --git a/src/guichan/widgets/textbox.cpp b/src/guichan/widgets/textbox.cpp new file mode 100644 index 000000000..c57296f9c --- /dev/null +++ b/src/guichan/widgets/textbox.cpp @@ -0,0 +1,517 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/textbox.hpp" + +#include "guichan/basiccontainer.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + TextBox::TextBox() + { + mCaretColumn = 0; + mCaretRow = 0; + mEditable = true; + mOpaque = true; + + setText(""); + + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + adjustSize(); + } + + TextBox::TextBox(const std::string& text) + { + mCaretColumn = 0; + mCaretRow = 0; + mEditable = true; + mOpaque = true; + + setText(text); + + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + adjustSize(); + } + + void TextBox::setText(const std::string& text) + { + mCaretColumn = 0; + mCaretRow = 0; + + mTextRows.clear(); + + std::string::size_type pos, lastPos = 0; + int length; + do + { + pos = text.find("\n", lastPos); + + if (pos != std::string::npos) + { + length = pos - lastPos; + } + else + { + length = text.size() - lastPos; + } + std::string sub = text.substr(lastPos, length); + mTextRows.push_back(sub); + lastPos = pos + 1; + + } while (pos != std::string::npos); + + adjustSize(); + } + + void TextBox::draw(Graphics* graphics) + { + unsigned int i; + + if (mOpaque) + { + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); + } + + if (isFocused() && isEditable()) + { + drawCaret(graphics, getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)), mCaretRow * getFont()->getHeight()); + } + + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + + for (i = 0; i < mTextRows.size(); i++) + { + // Move the text one pixel so we can have a caret before a letter. + graphics->drawText(mTextRows[i], 1, i * getFont()->getHeight()); + } + } + + void TextBox::drawCaret(Graphics* graphics, int x, int y) + { + graphics->setColor(getForegroundColor()); + graphics->drawLine(x, getFont()->getHeight() + y, x, y); + } + + void TextBox::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mCaretRow = mouseEvent.getY() / getFont()->getHeight(); + + if (mCaretRow >= (int)mTextRows.size()) + { + mCaretRow = mTextRows.size() - 1; + } + + mCaretColumn = getFont()->getStringIndexAt(mTextRows[mCaretRow], mouseEvent.getX()); + } + } + + void TextBox::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void TextBox::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::LEFT) + { + --mCaretColumn; + if (mCaretColumn < 0) + { + --mCaretRow; + + if (mCaretRow < 0) + { + mCaretRow = 0; + mCaretColumn = 0; + } + else + { + mCaretColumn = mTextRows[mCaretRow].size(); + } + } + } + + else if (key.getValue() == Key::RIGHT) + { + ++mCaretColumn; + if (mCaretColumn > (int)mTextRows[mCaretRow].size()) + { + ++mCaretRow; + + if (mCaretRow >= (int)mTextRows.size()) + { + mCaretRow = mTextRows.size() - 1; + if (mCaretRow < 0) + { + mCaretRow = 0; + } + + mCaretColumn = mTextRows[mCaretRow].size(); + } + else + { + mCaretColumn = 0; + } + } + } + + else if (key.getValue() == Key::DOWN) + { + setCaretRow(mCaretRow + 1); + } + + else if (key.getValue() == Key::UP) + { + setCaretRow(mCaretRow - 1); + } + + else if (key.getValue() == Key::HOME) + { + mCaretColumn = 0; + } + + else if (key.getValue() == Key::END) + { + mCaretColumn = mTextRows[mCaretRow].size(); + } + + else if (key.getValue() == Key::ENTER && mEditable) + { + mTextRows.insert(mTextRows.begin() + mCaretRow + 1, + mTextRows[mCaretRow].substr(mCaretColumn, mTextRows[mCaretRow].size() - mCaretColumn)); + mTextRows[mCaretRow].resize(mCaretColumn); + ++mCaretRow; + mCaretColumn = 0; + } + + else if (key.getValue() == Key::BACKSPACE + && mCaretColumn != 0 + && mEditable) + { + mTextRows[mCaretRow].erase(mCaretColumn - 1, 1); + --mCaretColumn; + } + + else if (key.getValue() == Key::BACKSPACE + && mCaretColumn == 0 + && mCaretRow != 0 + && mEditable) + { + mCaretColumn = mTextRows[mCaretRow - 1].size(); + mTextRows[mCaretRow - 1] += mTextRows[mCaretRow]; + mTextRows.erase(mTextRows.begin() + mCaretRow); + --mCaretRow; + } + + else if (key.getValue() == Key::DELETE + && mCaretColumn < (int)mTextRows[mCaretRow].size() + && mEditable) + { + mTextRows[mCaretRow].erase(mCaretColumn, 1); + } + + else if (key.getValue() == Key::DELETE + && mCaretColumn == (int)mTextRows[mCaretRow].size() + && mCaretRow < ((int)mTextRows.size() - 1) + && mEditable) + { + mTextRows[mCaretRow] += mTextRows[mCaretRow + 1]; + mTextRows.erase(mTextRows.begin() + mCaretRow + 1); + } + + else if(key.getValue() == Key::PAGE_UP) + { + Widget* par = getParent(); + + if (par != NULL) + { + int rowsPerPage = par->getChildrenArea().height / getFont()->getHeight(); + mCaretRow -= rowsPerPage; + + if (mCaretRow < 0) + { + mCaretRow = 0; + } + } + } + + else if(key.getValue() == Key::PAGE_DOWN) + { + Widget* par = getParent(); + + if (par != NULL) + { + int rowsPerPage = par->getChildrenArea().height / getFont()->getHeight(); + mCaretRow += rowsPerPage; + + if (mCaretRow >= (int)mTextRows.size()) + { + mCaretRow = mTextRows.size() - 1; + } + } + } + + else if(key.getValue() == Key::TAB + && mEditable) + { + mTextRows[mCaretRow].insert(mCaretColumn,std::string(" ")); + mCaretColumn += 4; + } + + else if (key.isCharacter() + && mEditable) + { + mTextRows[mCaretRow].insert(mCaretColumn,std::string(1,(char)key.getValue())); + ++mCaretColumn; + } + + adjustSize(); + scrollToCaret(); + + keyEvent.consume(); + } + + void TextBox::adjustSize() + { + unsigned int i; + int width = 0; + for (i = 0; i < mTextRows.size(); ++i) + { + int w = getFont()->getWidth(mTextRows[i]); + if (width < w) + { + width = w; + } + } + + setWidth(width + 1); + setHeight(getFont()->getHeight() * mTextRows.size()); + } + + void TextBox::setCaretPosition(unsigned int position) + { + int row; + + for (row = 0; row < (int)mTextRows.size(); row++) + { + if (position <= mTextRows[row].size()) + { + mCaretRow = row; + mCaretColumn = position; + return; // we are done + } + else + { + position--; + } + } + + // position beyond end of text + mCaretRow = mTextRows.size() - 1; + mCaretColumn = mTextRows[mCaretRow].size(); + } + + unsigned int TextBox::getCaretPosition() const + { + int pos = 0, row; + + for (row = 0; row < mCaretRow; row++) + { + pos += mTextRows[row].size(); + } + + return pos + mCaretColumn; + } + + void TextBox::setCaretRowColumn(int row, int column) + { + setCaretRow(row); + setCaretColumn(column); + } + + void TextBox::setCaretRow(int row) + { + mCaretRow = row; + + if (mCaretRow >= (int)mTextRows.size()) + { + mCaretRow = mTextRows.size() - 1; + } + + if (mCaretRow < 0) + { + mCaretRow = 0; + } + + setCaretColumn(mCaretColumn); + } + + unsigned int TextBox::getCaretRow() const + { + return mCaretRow; + } + + void TextBox::setCaretColumn(int column) + { + mCaretColumn = column; + + if (mCaretColumn > (int)mTextRows[mCaretRow].size()) + { + mCaretColumn = mTextRows[mCaretRow].size(); + } + + if (mCaretColumn < 0) + { + mCaretColumn = 0; + } + } + + unsigned int TextBox::getCaretColumn() const + { + return mCaretColumn; + } + + const std::string& TextBox::getTextRow(int row) const + { + return mTextRows[row]; + } + + void TextBox::setTextRow(int row, const std::string& text) + { + mTextRows[row] = text; + + if (mCaretRow == row) + { + setCaretColumn(mCaretColumn); + } + + adjustSize(); + } + + unsigned int TextBox::getNumberOfRows() const + { + return mTextRows.size(); + } + + std::string TextBox::getText() const + { + if (mTextRows.size() == 0) + { + return std::string(""); + } + + int i; + std::string text; + + for (i = 0; i < (int)mTextRows.size() - 1; ++i) + { + text = text + mTextRows[i] + "\n"; + } + + text = text + mTextRows[i]; + + return text; + } + + void TextBox::fontChanged() + { + adjustSize(); + } + + void TextBox::scrollToCaret() + { + Rectangle scroll; + scroll.x = getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)); + scroll.y = getFont()->getHeight() * mCaretRow; + scroll.width = getFont()->getWidth(" "); + scroll.height = getFont()->getHeight() + 2; // add 2 for some extra space + + showPart(scroll); + } + + void TextBox::setEditable(bool editable) + { + mEditable = editable; + } + + bool TextBox::isEditable() const + { + return mEditable; + } + + void TextBox::addRow(const std::string row) + { + mTextRows.push_back(row); + adjustSize(); + } + + bool TextBox::isOpaque() + { + return mOpaque; + } + + void TextBox::setOpaque(bool opaque) + { + mOpaque = opaque; + } +} diff --git a/src/guichan/widgets/textbox.hpp b/src/guichan/widgets/textbox.hpp new file mode 100644 index 000000000..b00dcef20 --- /dev/null +++ b/src/guichan/widgets/textbox.hpp @@ -0,0 +1,289 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_TEXTBOX_HPP +#define GCN_TEXTBOX_HPP + +#include <ctime> +#include <string> +#include <vector> + +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +namespace gcn +{ + /** + * An implementation of a text box where a user can enter text that contains of many lines. + */ + class GCN_CORE_DECLSPEC TextBox: + public Widget, + public MouseListener, + public KeyListener + { + public: + /** + * Constructor. + */ + TextBox(); + + /** + * Constructor. + * + * @param text The default text of the text box. + */ + TextBox(const std::string& text); + + /** + * Sets the text of the text box. + * + * @param text The text of the text box. + * @see getText + */ + void setText(const std::string& text); + + /** + * Gets the text of the text box. + * + * @return The text of the text box. + * @see setText + */ + std::string getText() const; + + /** + * Gets a certain row from the text. + * + * @param row The number of the row to get from the text. + * @return A row from the text of the text box. + * @see setTextRow + */ + const std::string& getTextRow(int row) const; + + /** + * Sets the text of a certain row of the text. + * + * @param row The number of the row to set in the text. + * @param text The text to set in the given row number. + * @see getTextRow + */ + void setTextRow(int row, const std::string& text); + + /** + * Gets the number of rows in the text. + * + * @return The number of rows in the text. + */ + unsigned int getNumberOfRows() const; + + /** + * Gets the caret position in the text. + * + * @return The caret position in the text. + * @see setCaretPosition + */ + unsigned int getCaretPosition() const; + + /** + * Sets the position of the caret in the text. + * + * @param position the positon of the caret. + * @see getCaretPosition + */ + void setCaretPosition(unsigned int position); + + /** + * Gets the row number where the caret is currently located. + * + * @return The row number where the caret is currently located. + * @see setCaretRow + */ + unsigned int getCaretRow() const; + + /** + * Sets the row where the caret should be currently located. + * + * @param The row where the caret should be currently located. + * @see getCaretRow + */ + void setCaretRow(int row); + + /** + * Gets the column where the caret is currently located. + * + * @return The column where the caret is currently located. + * @see setCaretColumn + */ + unsigned int getCaretColumn() const; + + /** + * Sets the column where the caret should be currently located. + * + * @param The column where the caret should be currently located. + * @see getCaretColumn + */ + void setCaretColumn(int column); + + /** + * Sets the row and the column where the caret should be curretly + * located. + * + * @param row The row where the caret should be currently located. + * @param column The column where the caret should be currently located. + * @see getCaretRow, getCaretColumn + */ + void setCaretRowColumn(int row, int column); + + /** + * Scrolls the text to the caret if the text box is in a scroll area. + * + * @see ScrollArea + */ + virtual void scrollToCaret(); + + /** + * Checks if the text box is editable. + * + * @return True it the text box is editable, false otherwise. + * @see setEditable + */ + bool isEditable() const; + + /** + * Sets the text box to be editable or not. + * + * @param editable True if the text box should be editable, false otherwise. + */ + void setEditable(bool editable); + + /** + * Adds a row of text to the end of the text. + * + * @param row The row to add. + */ + virtual void addRow(const std::string row); + + /** + * Checks if the text box is opaque. An opaque text box will draw + * it's background and it's text. A non opaque text box only draw it's + * text making it transparent. + * + * @return True if the text box is opaque, false otherwise. + * @see setOpaque + */ + bool isOpaque(); + + /** + * Sets the text box to be opaque or not. An opaque text box will draw + * it's background and it's text. A non opaque text box only draw it's + * text making it transparent. + * + * @param opaque True if the text box should be opaque, false otherwise. + * @see isOpaque + */ + void setOpaque(bool opaque); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + virtual void fontChanged(); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + protected: + /** + * Draws the caret. Overloaded this method if you want to + * change the style of the caret. + * + * @param graphics a Graphics object to draw with. + * @param x the x position. + * @param y the y position. + */ + virtual void drawCaret(Graphics* graphics, int x, int y); + + /** + * Adjusts the text box's size to fit the text. + */ + virtual void adjustSize(); + + /** + * Holds all the rows of the text. + */ + std::vector<std::string> mTextRows; + + /** + * Holds the current column of the caret. + */ + int mCaretColumn; + + /** + * Holds the current row of the caret. + */ + int mCaretRow; + + /** + * True if the text box is editable, false otherwise. + */ + bool mEditable; + + /** + * True if the text box is editable, false otherwise. + */ + bool mOpaque; + }; +} + +#endif // end GCN_TEXTBOX_HPP diff --git a/src/guichan/widgets/textfield.cpp b/src/guichan/widgets/textfield.cpp new file mode 100644 index 000000000..e8fc9c5d6 --- /dev/null +++ b/src/guichan/widgets/textfield.cpp @@ -0,0 +1,280 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/textfield.hpp" + +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/key.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + TextField::TextField() + { + mCaretPosition = 0; + mXScroll = 0; + + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + } + + TextField::TextField(const std::string& text) + { + mCaretPosition = 0; + mXScroll = 0; + + mText = text; + adjustSize(); + + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + } + + void TextField::setText(const std::string& text) + { + if(text.size() < mCaretPosition ) + { + mCaretPosition = text.size(); + } + + mText = text; + } + + void TextField::draw(Graphics* graphics) + { + Color faceColor = getBaseColor(); + Color highlightColor, shadowColor; + int alpha = getBaseColor().a; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + // Draw a border. + graphics->setColor(shadowColor); + graphics->drawLine(0, 0, getWidth() - 1, 0); + graphics->drawLine(0, 1, 0, getHeight() - 2); + graphics->setColor(highlightColor); + graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); + graphics->drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1); + + // Push a clip area so the other drawings don't need to worry + // about the border. + graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 2)); + + graphics->setColor(getBackgroundColor()); + graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); + + if (isFocused()) + { + graphics->setColor(getSelectionColor()); + graphics->drawRectangle(Rectangle(0, 0, getWidth() - 2, getHeight() - 2)); + graphics->drawRectangle(Rectangle(1, 1, getWidth() - 4, getHeight() - 4)); + } + + if (isFocused()) + { + drawCaret(graphics, getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll); + } + + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + graphics->drawText(mText, 3 - mXScroll, 1); + + graphics->popClipArea(); + } + + void TextField::drawCaret(Graphics* graphics, int x) + { + // Check the current clip area as a clip area with a different + // size than the widget might have been pushed (which is the + // case in the draw method when we push a clip area after we have + // drawn a border). + const Rectangle clipArea = graphics->getCurrentClipArea(); + + graphics->setColor(getForegroundColor()); + graphics->drawLine(x, clipArea.height - 2, x, 1); + } + + void TextField::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mCaretPosition = getFont()->getStringIndexAt(mText, mouseEvent.getX() + mXScroll); + fixScroll(); + } + } + + void TextField::mouseDragged(MouseEvent& mouseEvent) + { + mouseEvent.consume(); + } + + void TextField::keyPressed(KeyEvent& keyEvent) + { + Key key = keyEvent.getKey(); + + if (key.getValue() == Key::LEFT && mCaretPosition > 0) + { + --mCaretPosition; + } + + else if (key.getValue() == Key::RIGHT && mCaretPosition < mText.size()) + { + ++mCaretPosition; + } + + else if (key.getValue() == Key::DELETE && mCaretPosition < mText.size()) + { + mText.erase(mCaretPosition, 1); + } + + else if (key.getValue() == Key::BACKSPACE && mCaretPosition > 0) + { + mText.erase(mCaretPosition - 1, 1); + --mCaretPosition; + } + + else if (key.getValue() == Key::ENTER) + { + distributeActionEvent(); + } + + else if (key.getValue() == Key::HOME) + { + mCaretPosition = 0; + } + + else if (key.getValue() == Key::END) + { + mCaretPosition = mText.size(); + } + + else if (key.isCharacter() + && key.getValue() != Key::TAB) + { + mText.insert(mCaretPosition, std::string(1,(char)key.getValue())); + ++mCaretPosition; + } + + if (key.getValue() != Key::TAB) + { + keyEvent.consume(); + } + + fixScroll(); + } + + void TextField::adjustSize() + { + setWidth(getFont()->getWidth(mText) + 7); + adjustHeight(); + + fixScroll(); + } + + void TextField::adjustHeight() + { + setHeight(getFont()->getHeight() + 4); + } + + void TextField::fixScroll() + { + if (isFocused()) + { + int caretX = getFont()->getWidth(mText.substr(0, mCaretPosition)); + + if (caretX - mXScroll >= getWidth() - 4) + { + mXScroll = caretX - getWidth() + 4; + } + else if (caretX - mXScroll <= 0) + { + mXScroll = caretX - getWidth() / 2; + + if (mXScroll < 0) + { + mXScroll = 0; + } + } + } + } + + void TextField::setCaretPosition(unsigned int position) + { + if (position > mText.size()) + { + mCaretPosition = mText.size(); + } + else + { + mCaretPosition = position; + } + + fixScroll(); + } + + unsigned int TextField::getCaretPosition() const + { + return mCaretPosition; + } + + const std::string& TextField::getText() const + { + return mText; + } + + void TextField::fontChanged() + { + fixScroll(); + } +} diff --git a/src/guichan/widgets/textfield.hpp b/src/guichan/widgets/textfield.hpp new file mode 100644 index 000000000..486660a8a --- /dev/null +++ b/src/guichan/widgets/textfield.hpp @@ -0,0 +1,177 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_TEXTFIELD_HPP +#define GCN_TEXTFIELD_HPP + +#include "guichan/keylistener.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widget.hpp" + +#include <string> + +namespace gcn +{ + /** + * An implementation of a text field where a user can enter a line of text. + */ + class GCN_CORE_DECLSPEC TextField: + public Widget, + public MouseListener, + public KeyListener + { + public: + /** + * Constructor. + */ + TextField(); + + /** + * Constructor. The text field will be automatically resized + * to fit the text. + * + * @param text The default text of the text field. + */ + TextField(const std::string& text); + + /** + * Sets the text of the text field. + * + * @param text The text of the text field. + * @see getText + */ + void setText(const std::string& text); + + /** + * Gets the text of the text field. + * + * @return The text of the text field. + * @see setText + */ + const std::string& getText() const; + + /** + * Adjusts the size of the text field to fit the text. + */ + void adjustSize(); + + /** + * Adjusts the height of the text field to fit caption. + */ + void adjustHeight(); + + /** + * Sets the caret position. As there is only one line of text + * in a text field the position is the caret's x coordinate. + * + * @param position The caret position. + * @see getCaretPosition + */ + void setCaretPosition(unsigned int position); + + /** + * Gets the caret position. As there is only one line of text + * in a text field the position is the caret's x coordinate. + * + * @return The caret position. + * @see setCaretPosition + */ + unsigned int getCaretPosition() const; + + + // Inherited from Widget + + virtual void fontChanged(); + + virtual void draw(Graphics* graphics); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + + // Inherited from KeyListener + + virtual void keyPressed(KeyEvent& keyEvent); + + protected: + /** + * Draws the caret. Overloaded this method if you want to + * change the style of the caret. + * + * @param graphics the Graphics object to draw with. + * @param x the caret's x-position. + */ + virtual void drawCaret(Graphics* graphics, int x); + + /** + * Scrolls the text horizontally so that the caret shows if needed. + * The method is used any time a user types in the text field so the + * caret always will be shown. + */ + void fixScroll(); + + /** + * Holds the text of the text box. + */ + std::string mText; + + /** + * Holds the caret position. + */ + unsigned int mCaretPosition; + + /** + * Holds the amount scrolled in x. If a user types more characters than + * the text field can display, due to the text field being to small, the + * text needs to scroll in order to show the last type character. + */ + int mXScroll; + }; +} + +#endif // end GCN_TEXTFIELD_HPP diff --git a/src/guichan/widgets/window.cpp b/src/guichan/widgets/window.cpp new file mode 100644 index 000000000..2ac4d553b --- /dev/null +++ b/src/guichan/widgets/window.cpp @@ -0,0 +1,308 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * For comments regarding functions please see the header file. + */ + +#include "guichan/widgets/window.hpp" + +#include "guichan/exception.hpp" +#include "guichan/font.hpp" +#include "guichan/graphics.hpp" +#include "guichan/mouseinput.hpp" + +namespace gcn +{ + Window::Window() + :mMoved(false) + { + setFrameSize(1); + setPadding(2); + setTitleBarHeight(16); + setAlignment(Graphics::CENTER); + addMouseListener(this); + setMovable(true); + setOpaque(true); + } + + Window::Window(const std::string& caption) + :mMoved(false) + { + setCaption(caption); + setFrameSize(1); + setPadding(2); + setTitleBarHeight(16); + setAlignment(Graphics::CENTER); + addMouseListener(this); + setMovable(true); + setOpaque(true); + } + + Window::~Window() + { + } + + void Window::setPadding(unsigned int padding) + { + mPadding = padding; + } + + unsigned int Window::getPadding() const + { + return mPadding; + } + + void Window::setTitleBarHeight(unsigned int height) + { + mTitleBarHeight = height; + } + + unsigned int Window::getTitleBarHeight() + { + return mTitleBarHeight; + } + + void Window::setCaption(const std::string& caption) + { + mCaption = caption; + } + + const std::string& Window::getCaption() const + { + return mCaption; + } + + void Window::setAlignment(Graphics::Alignment alignment) + { + mAlignment = alignment; + } + + Graphics::Alignment Window::getAlignment() const + { + return mAlignment; + } + + void Window::draw(Graphics* graphics) + { + const Color &faceColor = getBaseColor(); + Color highlightColor, shadowColor; + const int alpha = getBaseColor().a; + highlightColor = faceColor + 0x303030; + highlightColor.a = alpha; + shadowColor = faceColor - 0x303030; + shadowColor.a = alpha; + + Rectangle d = getChildrenArea(); + + // Fill the background around the content + graphics->setColor(faceColor); + // Fill top + graphics->fillRectangle(Rectangle(0,0,getWidth(),d.y - 1)); + // Fill left + graphics->fillRectangle(Rectangle(0,d.y - 1, d.x - 1, getHeight() - d.y + 1)); + // Fill right + graphics->fillRectangle(Rectangle(d.x + d.width + 1, + d.y - 1, + getWidth() - d.x - d.width - 1, + getHeight() - d.y + 1)); + // Fill bottom + graphics->fillRectangle(Rectangle(d.x - 1, + d.y + d.height + 1, + d.width + 2, + getHeight() - d.height - d.y - 1)); + + if (isOpaque()) + { + graphics->fillRectangle(d); + } + + // Construct a rectangle one pixel bigger than the content + d.x -= 1; + d.y -= 1; + d.width += 2; + d.height += 2; + + // Draw a border around the content + graphics->setColor(shadowColor); + // Top line + graphics->drawLine(d.x, + d.y, + d.x + d.width - 2, + d.y); + + // Left line + graphics->drawLine(d.x, + d.y + 1, + d.x, + d.y + d.height - 1); + + graphics->setColor(highlightColor); + // Right line + graphics->drawLine(d.x + d.width - 1, + d.y, + d.x + d.width - 1, + d.y + d.height - 2); + // Bottom line + graphics->drawLine(d.x + 1, + d.y + d.height - 1, + d.x + d.width - 1, + d.y + d.height - 1); + + drawChildren(graphics); + + int textX; + int textY; + + textY = ((int)getTitleBarHeight() - getFont()->getHeight()) / 2; + + switch (getAlignment()) + { + case Graphics::LEFT: + textX = 4; + break; + case Graphics::CENTER: + textX = getWidth() / 2; + break; + case Graphics::RIGHT: + textX = getWidth() - 4; + break; + default: + throw GCN_EXCEPTION("Unknown alignment."); + } + + graphics->setColor(getForegroundColor()); + graphics->setFont(getFont()); + graphics->pushClipArea(Rectangle(0, 0, getWidth(), getTitleBarHeight() - 1)); + graphics->drawText(getCaption(), textX, textY, getAlignment()); + graphics->popClipArea(); + } + + void Window::mousePressed(MouseEvent& mouseEvent) + { + if (mouseEvent.getSource() != this) + { + return; + } + + if (getParent() != NULL) + { + getParent()->moveToTop(this); + } + + mDragOffsetX = mouseEvent.getX(); + mDragOffsetY = mouseEvent.getY(); + + mMoved = mouseEvent.getY() <= (int)mTitleBarHeight; + } + + void Window::mouseReleased(MouseEvent& mouseEvent) + { + mMoved = false; + } + + void Window::mouseDragged(MouseEvent& mouseEvent) + { + if (mouseEvent.isConsumed() || mouseEvent.getSource() != this) + { + return; + } + + if (isMovable() && mMoved) + { + setPosition(mouseEvent.getX() - mDragOffsetX + getX(), + mouseEvent.getY() - mDragOffsetY + getY()); + } + + mouseEvent.consume(); + } + + Rectangle Window::getChildrenArea() + { + return Rectangle(getPadding(), + getTitleBarHeight(), + getWidth() - getPadding() * 2, + getHeight() - getPadding() - getTitleBarHeight()); + } + + void Window::setMovable(bool movable) + { + mMovable = movable; + } + + bool Window::isMovable() const + { + return mMovable; + } + + void Window::setOpaque(bool opaque) + { + mOpaque = opaque; + } + + bool Window::isOpaque() + { + return mOpaque; + } + + void Window::resizeToContent() + { + WidgetListIterator it; + + int w = 0, h = 0; + for (it = mWidgets.begin(); it != mWidgets.end(); it++) + { + if ((*it)->getX() + (*it)->getWidth() > w) + { + w = (*it)->getX() + (*it)->getWidth(); + } + + if ((*it)->getY() + (*it)->getHeight() > h) + { + h = (*it)->getY() + (*it)->getHeight(); + } + } + + setSize(w + 2* getPadding(), h + getPadding() + getTitleBarHeight()); + } +} diff --git a/src/guichan/widgets/window.hpp b/src/guichan/widgets/window.hpp new file mode 100644 index 000000000..373efd164 --- /dev/null +++ b/src/guichan/widgets/window.hpp @@ -0,0 +1,255 @@ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson + * + * + * Per Larsson a.k.a finalman + * Olof Naessén a.k.a jansem/yakslem + * + * Visit: http://guichan.sourceforge.net + * + * License: (BSD) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Guichan nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GCN_WINDOW_HPP +#define GCN_WINDOW_HPP + +#include <string> + +#include "guichan/mouselistener.hpp" +#include "guichan/platform.hpp" +#include "guichan/widgets/container.hpp" + +namespace gcn +{ + /** + * An implementation of a movable window that can contain other widgets. + */ + class GCN_CORE_DECLSPEC Window : public Container, + public MouseListener + { + public: + /** + * Constructor. + */ + Window(); + + /** + * Constructor. The window will be automatically resized in height + * to fit the caption. + * + * @param caption the caption of the window. + */ + Window(const std::string& caption); + + /** + * Destructor. + */ + virtual ~Window(); + + /** + * Sets the caption of the window. + * + * @param caption The caption of the window. + * @see getCaption + */ + void setCaption(const std::string& caption); + + /** + * Gets the caption of the window. + * + * @return the caption of the window. + * @see setCaption + */ + const std::string& getCaption() const; + + /** + * Sets the alignment of the caption. + * + * @param alignment The alignment of the caption. + * @see getAlignment, Graphics + */ + void setAlignment(Graphics::Alignment alignment); + + /** + * Gets the alignment of the caption. + * + * @return The alignment of caption. + * @see setAlignment, Graphics + */ + Graphics::Alignment getAlignment() const; + + /** + * Sets the padding of the window. The padding is the distance between the + * window border and the content. + * + * @param padding The padding of the window. + * @see getPadding + */ + void setPadding(unsigned int padding); + + /** + * Gets the padding of the window. The padding is the distance between the + * window border and the content. + * + * @return The padding of the window. + * @see setPadding + */ + unsigned int getPadding() const; + + /** + * Sets the title bar height. + * + * @param height The title height value. + * @see getTitleBarHeight + */ + void setTitleBarHeight(unsigned int height); + + /** + * Gets the title bar height. + * + * @return The title bar height. + * @see setTitleBarHeight + */ + unsigned int getTitleBarHeight(); + + /** + * Sets the window to be moveble or not. + * + * @param movable True if the window should be movable, false otherwise. + * @see isMovable + */ + void setMovable(bool movable); + + /** + * Checks if the window is movable. + * + * @return True if the window is movable, false otherwise. + * @see setMovable + */ + bool isMovable() const; + + /** + * Sets the window to be opaque or not. An opaque window will draw it's background + * and it's content. A non opaque window will only draw it's content. + * + * @param opaque True if the window should be opaque, false otherwise. + * @see isOpaque + */ + void setOpaque(bool opaque); + + /** + * Checks if the window is opaque. + * + * @return True if the window is opaque, false otherwise. + * @see setOpaque + */ + bool isOpaque(); + + /** + * Resizes the window to fit the content. + */ + virtual void resizeToContent(); + + + // Inherited from BasicContainer + + virtual Rectangle getChildrenArea(); + + + // Inherited from Widget + + virtual void draw(Graphics* graphics); + + + // Inherited from MouseListener + + virtual void mousePressed(MouseEvent& mouseEvent); + + virtual void mouseDragged(MouseEvent& mouseEvent); + + virtual void mouseReleased(MouseEvent& mouseEvent); + + protected: + /** + * Holds the caption of the window. + */ + std::string mCaption; + + /** + * Holds the alignment of the caption. + */ + Graphics::Alignment mAlignment; + + /** + * Holds the padding of the window. + */ + unsigned int mPadding; + + /** + * Holds the title bar height of the window. + */ + unsigned int mTitleBarHeight; + + /** + * True if the window is movable, false otherwise. + */ + bool mMovable; + + /** + * True if the window is opaque, false otherwise. + */ + bool mOpaque; + + /** + * Holds a drag offset as an x coordinate where the drag of the window + * started if the window is being dragged. It's used to move the window + * correctly when dragged. + */ + int mDragOffsetX; + + /** + * Holds a drag offset as an y coordinate where the drag of the window + * started if the window is being dragged. It's used to move the window + * correctly when dragged. + */ + int mDragOffsetY; + + /** + * True if the window is being moved, false otherwise. + */ + bool mMoved; + }; +} + +#endif // end GCN_WINDOW_HPP |