diff options
Diffstat (limited to 'src/gui/widgets')
50 files changed, 4056 insertions, 348 deletions
diff --git a/src/gui/widgets/basiccontainer.cpp b/src/gui/widgets/basiccontainer.cpp new file mode 100644 index 000000000..d3dd62fc7 --- /dev/null +++ b/src/gui/widgets/basiccontainer.cpp @@ -0,0 +1,377 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2014 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/basiccontainer.h" + +#include <algorithm> + +#include "debug.h" + +BasicContainer::~BasicContainer() +{ + clear(); +} + +void BasicContainer::moveToTop(Widget* widget) +{ + for (WidgetListIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + if (*iter == widget) + { + mWidgets.erase(iter); + mWidgets.push_back(widget); + return; + } + } +} + +void BasicContainer::moveToBottom(Widget* widget) +{ + WidgetListIterator iter; + iter = std::find(mWidgets.begin(), mWidgets.end(), widget); + + if (iter == mWidgets.end()) + return; + + mWidgets.erase(iter); + mWidgets.insert(mWidgets.begin(), widget); +} + +void BasicContainer::death(const Event& event) +{ + WidgetListIterator iter; + iter = std::find(mWidgets.begin(), mWidgets.end(), event.getSource()); + + if (iter == mWidgets.end()) + return; + + mWidgets.erase(iter); +} + +Rect BasicContainer::getChildrenArea() +{ + return Rect(0, 0, getWidth(), getHeight()); +} + +void BasicContainer::focusNext() +{ + WidgetListConstIterator it; + + for (it = mWidgets.begin(); it != mWidgets.end(); ++ it) + { + if ((*it)->isFocused()) + break; + } + + WidgetListConstIterator 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; + } + + const 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) +{ + const Rect r = getChildrenArea(); + + if (!r.isPointInRect(x, y)) + return nullptr; + + x -= r.x; + y -= r.y; + + for (WidgetListReverseIterator it = mWidgets.rbegin(); + it != mWidgets.rend(); ++ it) + { + if ((*it)->isVisible() && (*it)->getDimension() + .isPointInRect(x, y)) + { + return (*it); + } + } + + return nullptr; +} + +void BasicContainer::logic() +{ + BLOCK_START("BasicContainer::logic") + logicChildren(); + BLOCK_END("BasicContainer::logic") +} + +void BasicContainer::_setFocusHandler(FocusHandler* focusHandler) +{ + Widget::_setFocusHandler(focusHandler); + + if (mInternalFocusHandler) + return; + + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + (*iter)->_setFocusHandler(focusHandler); + } +} + +void BasicContainer::add(Widget* widget) +{ + mWidgets.push_back(widget); + + if (!mInternalFocusHandler) + widget->_setFocusHandler(_getFocusHandler()); + else + widget->_setFocusHandler(mInternalFocusHandler); + + widget->_setParent(this); + widget->addDeathListener(this); +} + +void BasicContainer::remove(Widget* widget) +{ + for (WidgetListIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + if (*iter == widget) + { + mWidgets.erase(iter); + widget->_setFocusHandler(nullptr); + widget->_setParent(nullptr); + widget->removeDeathListener(this); + return; + } + } +} + +void BasicContainer::clear() +{ + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + (*iter)->_setFocusHandler(nullptr); + (*iter)->_setParent(nullptr); + (*iter)->removeDeathListener(this); + } + + mWidgets.clear(); +} + +void BasicContainer::drawChildren(Graphics* graphics) +{ + BLOCK_START("BasicContainer::drawChildren") + + graphics->pushClipArea(getChildrenArea()); + + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + Widget *const widget = *iter; + if (widget->isVisible()) + { + // If the widget has a frame, + // draw it before drawing the widget + if (widget->getFrameSize() > 0) + { + Rect rec = widget->getDimension(); + const int frame = widget->getFrameSize(); + const int frame2 = frame * 2; + rec.x -= frame; + rec.y -= frame; + rec.width += frame2; + rec.height += frame2; + graphics->pushClipArea(rec); + BLOCK_START("BasicContainer::drawChildren 1") + widget->drawFrame(graphics); + BLOCK_END("BasicContainer::drawChildren 1") + graphics->popClipArea(); + } + + graphics->pushClipArea(widget->getDimension()); + BLOCK_START("BasicContainer::drawChildren 2") + widget->draw(graphics); + BLOCK_END("BasicContainer::drawChildren 2") + graphics->popClipArea(); + } + } + + graphics->popClipArea(); + BLOCK_END("BasicContainer::drawChildren") +} + +void BasicContainer::logicChildren() +{ + BLOCK_START("BasicContainer::logicChildren") + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + (*iter)->logic(); + } + BLOCK_END("BasicContainer::logicChildren") +} + +void BasicContainer::showWidgetPart(Widget *const widget, Rect area) +{ + const Rect 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); + + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + if (!mInternalFocusHandler) + (*iter)->_setFocusHandler(_getFocusHandler()); + else + (*iter)->_setFocusHandler(mInternalFocusHandler); + } +} + +Widget* BasicContainer::findWidgetById(const std::string& id) +{ + for (WidgetListConstIterator iter = mWidgets.begin(); + iter != mWidgets.end(); ++ iter) + { + if ((*iter)->getId() == id) + return (*iter); + + BasicContainer *const basicContainer + = dynamic_cast<BasicContainer *const>(*iter); + + if (basicContainer) + { + Widget *const widget = basicContainer->findWidgetById(id); + + if (widget) + return widget; + } + } + + return nullptr; +} diff --git a/src/gui/widgets/basiccontainer.h b/src/gui/widgets/basiccontainer.h new file mode 100644 index 000000000..6e753a445 --- /dev/null +++ b/src/gui/widgets/basiccontainer.h @@ -0,0 +1,215 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2014 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_BASICCONTAINER_H +#define GUI_WIDGETS_BASICCONTAINER_H + +#include <vector> + +#include "gui/widgets/widget.h" + +#include "listeners/deathlistener.h" + +/** + * 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 BasicContainer : public Widget, + public DeathListener +{ + public: + explicit BasicContainer(const Widget2 *const widget) : + Widget(widget), + DeathListener(), + mWidgets() + { } + + A_DELETE_COPY(BasicContainer) + + /** + * 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 *const widget, Rect area); + + // Inherited from Widget + + virtual void moveToTop(Widget* widget); + + virtual void moveToBottom(Widget* widget); + + virtual Rect getChildrenArea() A_WARN_UNUSED; + + 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) A_WARN_UNUSED; + + + // 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) A_WARN_UNUSED; + + /** + * Typedef. + */ + typedef std::vector<Widget *> WidgetList; + + /** + * Typedef. + */ + typedef WidgetList::iterator WidgetListIterator; + + /** + * Typedef. + */ + typedef WidgetList::const_iterator WidgetListConstIterator; + + /** + * Typedef. + */ + typedef WidgetList::reverse_iterator WidgetListReverseIterator; + + /** + * Typedef. + */ + typedef WidgetList::const_reverse_iterator WidgetListCReverseIterator; + + /** + * Holds all widgets of the basic container. + */ + WidgetList mWidgets; +}; + +#endif // GUI_WIDGETS_BASICCONTAINER_H diff --git a/src/gui/widgets/basiccontainer2.cpp b/src/gui/widgets/basiccontainer2.cpp new file mode 100644 index 000000000..9bd4d1593 --- /dev/null +++ b/src/gui/widgets/basiccontainer2.cpp @@ -0,0 +1,129 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2014 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/basiccontainer2.h" + +#include "debug.h" + +BasicContainer2::BasicContainer2(const Widget2 *const widget) : + BasicContainer(widget), + mOpaque(true) +{ +} + +BasicContainer2::~BasicContainer2() +{ +} + +void BasicContainer2::draw(Graphics* graphics) +{ + BLOCK_START("BasicContainer2::draw") + if (isOpaque()) + { + graphics->setColor(getBaseColor()); + graphics->fillRectangle(Rect(0, 0, getWidth(), getHeight())); + } + + drawChildren(graphics); + BLOCK_END("BasicContainer2::draw") +} + +void BasicContainer2::setOpaque(bool opaque) +{ + mOpaque = opaque; +} + +bool BasicContainer2::isOpaque() const +{ + return mOpaque; +} + +void BasicContainer2::add(Widget* widget) +{ + BasicContainer::add(widget); +} + +void BasicContainer2::add(Widget* widget, int x, int y) +{ + widget->setPosition(x, y); + BasicContainer::add(widget); +} + +void BasicContainer2::remove(Widget* widget) +{ + BasicContainer::remove(widget); +} + +void BasicContainer2::clear() +{ + BasicContainer::clear(); +} + +Widget* BasicContainer2::findWidgetById(const std::string &id) +{ + return BasicContainer::findWidgetById(id); +} diff --git a/src/gui/widgets/basiccontainer2.h b/src/gui/widgets/basiccontainer2.h new file mode 100644 index 000000000..c6f1d996b --- /dev/null +++ b/src/gui/widgets/basiccontainer2.h @@ -0,0 +1,174 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2014 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_BASICCONTAINER2_H +#define GUI_WIDGETS_BASICCONTAINER2_H + +#include "gui/widgets/basiccontainer.h" + +/** + * 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 BasicContainer2: public BasicContainer +{ + public: + /** + * Constructor. A container is opauqe as default, if you want a + * none opaque container call setQpaque(false). + * + * @see setOpaque, isOpaque + */ + explicit BasicContainer2(const Widget2 *const widget); + + /** + * Destructor. + */ + virtual ~BasicContainer2(); + + /** + * 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 // GUI_WIDGETS_BASICCONTAINER2_H diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp index 3cb6d823d..308c75413 100644 --- a/src/gui/widgets/button.cpp +++ b/src/gui/widgets/button.cpp @@ -20,6 +20,49 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/button.h" #include "client.h" @@ -53,8 +96,17 @@ static std::string const data[Button::BUTTON_COUNT] = Skin *Button::button[BUTTON_COUNT]; Button::Button(const Widget2 *const widget) : - gcn::Button(widget), + Widget(widget), + MouseListener(), + KeyListener(), + FocusListener(), WidgetListener(), + mCaption(), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4), mDescription(), mVertexes2(new ImageCollection), mEnabledColor(getThemeColor(Theme::BUTTON)), @@ -86,8 +138,17 @@ Button::Button(const Widget2 *const widget, const std::string &restrict caption, const std::string &restrict actionEventId, ActionListener *const listener) : - gcn::Button(widget, caption), + Widget(widget), + MouseListener(), + KeyListener(), + FocusListener(), WidgetListener(), + mCaption(caption), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4), mDescription(), mVertexes2(new ImageCollection), mEnabledColor(getThemeColor(Theme::BUTTON)), @@ -125,8 +186,17 @@ Button::Button(const Widget2 *const widget, const int imageWidth, const int imageHeight, const std::string &restrict actionEventId, ActionListener *const listener) : - gcn::Button(widget, caption), + Widget(widget), + MouseListener(), + KeyListener(), + FocusListener(), WidgetListener(), + mCaption(caption), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4), mDescription(), mVertexes2(new ImageCollection), mEnabledColor(getThemeColor(Theme::BUTTON)), @@ -164,8 +234,17 @@ Button::Button(const Widget2 *const widget, const int imageWidth, const int imageHeight, const std::string &restrict actionEventId, ActionListener *const listener) : - gcn::Button(widget), + Widget(widget), + MouseListener(), + KeyListener(), + FocusListener(), WidgetListener(), + mCaption(), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4), mDescription(), mVertexes2(new ImageCollection), mEnabledColor(getThemeColor(Theme::BUTTON)), @@ -203,8 +282,17 @@ Button::Button(const Widget2 *const widget, const std::string &restrict imageName, const std::string &restrict actionEventId, ActionListener *const listener) : - gcn::Button(widget, caption), + Widget(widget), + MouseListener(), + KeyListener(), + FocusListener(), WidgetListener(), + mCaption(caption), + mHasMouse(false), + mKeyPressed(false), + mMousePressed(false), + mAlignment(Graphics::CENTER), + mSpacing(4), mDescription(), mVertexes2(new ImageCollection), mEnabledColor(getThemeColor(Theme::BUTTON)), @@ -239,10 +327,14 @@ Button::Button(const Widget2 *const widget, void Button::init() { - setFrameSize(0); - + addMouseListener(this); + addKeyListener(this); + addFocusListener(this); addWidgetListener(this); + setFocusable(true); + setFrameSize(0); + if (mInstances == 0) { if (Theme::instance()) @@ -584,11 +676,6 @@ void Button::adjustSize() } } -void Button::setCaption(const std::string& caption) -{ - mCaption = caption; -} - void Button::keyPressed(KeyEvent& keyEvent) { const int action = keyEvent.getActionId(); @@ -614,8 +701,45 @@ void Button::keyReleased(KeyEvent& keyEvent) } } - bool Button::isPressed2() const { return (mPressed || isPressed()); } + +bool Button::isPressed() const +{ + if (mMousePressed) + return mHasMouse; + else + return mKeyPressed; +} + +void Button::focusLost(const Event& event A_UNUSED) +{ + mMousePressed = false; + mKeyPressed = false; +} + +void Button::mousePressed(MouseEvent& mouseEvent) +{ + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + mMousePressed = true; + mouseEvent.consume(); + } +} + +void Button::mouseEntered(MouseEvent& mouseEvent A_UNUSED) +{ + mHasMouse = true; +} + +void Button::mouseExited(MouseEvent& mouseEvent A_UNUSED) +{ + mHasMouse = false; +} + +void Button::mouseDragged(MouseEvent& mouseEvent) +{ + mouseEvent.consume(); +} diff --git a/src/gui/widgets/button.h b/src/gui/widgets/button.h index 039475150..6eba9b3c0 100644 --- a/src/gui/widgets/button.h +++ b/src/gui/widgets/button.h @@ -20,10 +20,57 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_BUTTON_H #define GUI_WIDGETS_BUTTON_H -#include "gui/base/widgets/button.hpp" +#include "gui/widgets/widget.h" + +#include "listeners/focuslistener.h" +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" #include "listeners/widgetlistener.h" #include "localconsts.h" @@ -40,7 +87,10 @@ const std::string BUTTON_PLAY = "buttonplay.png"; * * \ingroup GUI */ -class Button final : public gcn::Button, +class Button final : public Widget, + public MouseListener, + public KeyListener, + public FocusListener, public WidgetListener { public: @@ -139,14 +189,79 @@ class Button final : public gcn::Button, void adjustSize(); - void setCaption(const std::string& caption); - void keyPressed(KeyEvent &keyEvent) override final; void keyReleased(KeyEvent &keyEvent) override final; bool isPressed2() const A_WARN_UNUSED; + /** + * 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) + { mCaption = caption; } + + /** + * Gets the caption of the button. + * + * @return The caption of the button. + */ + const std::string& getCaption() const + { return mCaption; } + + /** + * 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) + { mAlignment = alignment; } + + /** + * Gets the alignment of the caption. + * + * @return The alignment of the caption. + * @see setAlignment, Graphics + */ + Graphics::Alignment getAlignment() const + { return mAlignment; } + + /** + * 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) + { mSpacing = spacing; } + + /** + * Gets the spacing between the border of the button and its caption. + * + * @return spacing. + * @see setSpacing + */ + unsigned int getSpacing() const + { return mSpacing; } + + void focusLost(const Event& event) override final; + + void mousePressed(MouseEvent& mouseEvent) override final; + + void mouseEntered(MouseEvent& mouseEvent) override final; + + void mouseExited(MouseEvent& mouseEvent) override final; + + void mouseDragged(MouseEvent& mouseEvent) override final; + enum { BUTTON_STANDARD = 0, // 0 @@ -157,12 +272,50 @@ class Button final : public gcn::Button, }; private: + /** + * 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; + void init(); static Skin *button[BUTTON_COUNT]; /**< Button state graphics */ static int mInstances; /**< Number of button instances */ static float mAlpha; + /** + * 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; + std::string mDescription; ImageCollection *mVertexes2; Color mEnabledColor; diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp index 9fb63b2e8..f01495bcf 100644 --- a/src/gui/widgets/checkbox.cpp +++ b/src/gui/widgets/checkbox.cpp @@ -20,12 +20,53 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/checkbox.h" #include "client.h" -#include "events/keyevent.h" - #include "input/keydata.h" #include "resources/image.h" @@ -44,7 +85,11 @@ CheckBox::CheckBox(const Widget2 *const widget, const bool selected, ActionListener *const listener, const std::string &restrict eventId) : - gcn::CheckBox(widget, caption, selected), + Widget(widget), + MouseListener(), + KeyListener(), + mSelected(selected), + mCaption(), mPadding(0), mImagePadding(0), mImageSize(9), @@ -52,6 +97,12 @@ CheckBox::CheckBox(const Widget2 *const widget, mHasMouse(false), mDrawBox(true) { + setCaption(caption); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + mForegroundColor2 = getThemeColor(Theme::CHECKBOX_OUTLINE); if (instances == 0) { @@ -200,3 +251,20 @@ void CheckBox::adjustSize() setWidth(mImagePadding + mImageSize + mSpacing + getFont()->getWidth(mCaption) + mPadding); } + +void CheckBox::mouseClicked(MouseEvent& mouseEvent) +{ + if (mouseEvent.getButton() == MouseEvent::LEFT) + toggleSelected(); +} + +void CheckBox::mouseDragged(MouseEvent& mouseEvent) +{ + mouseEvent.consume(); +} + +void CheckBox::toggleSelected() +{ + mSelected = !mSelected; + distributeActionEvent(); +} diff --git a/src/gui/widgets/checkbox.h b/src/gui/widgets/checkbox.h index 28eadb75c..5711e766f 100644 --- a/src/gui/widgets/checkbox.h +++ b/src/gui/widgets/checkbox.h @@ -20,10 +20,56 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_CHECKBOX_H #define GUI_WIDGETS_CHECKBOX_H -#include "gui/base/widgets/checkbox.hpp" +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" + +#include "gui/widgets/widget.h" #include "localconsts.h" @@ -34,7 +80,9 @@ class Skin; * * \ingroup GUI */ -class CheckBox final : public gcn::CheckBox +class CheckBox final : public Widget, + public MouseListener, + public KeyListener { public: /** @@ -82,7 +130,61 @@ class CheckBox final : public gcn::CheckBox void adjustSize(); + /** + * Checks if the check box is selected. + * + * @return True if the check box is selected, false otherwise. + * @see setSelected + */ + bool isSelected() const + { return mSelected; } + + /** + * 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(const bool selected) + { mSelected = selected; } + + /** + * Gets the caption of the check box. + * + * @return The caption of the check box. + * @see setCaption + */ + const std::string &getCaption() const + { return mCaption; } + + /** + * 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) + { mCaption = caption; } + + void mouseClicked(MouseEvent& mouseEvent) override final; + + void mouseDragged(MouseEvent& mouseEvent) override final; + private: + void toggleSelected(); + + /** + * True if the check box is selected, false otherwise. + */ + bool mSelected; + + /** + * Holds the caption of the check box. + */ + std::string mCaption; + int mPadding; int mImagePadding; int mImageSize; diff --git a/src/gui/widgets/container.cpp b/src/gui/widgets/container.cpp index 93d74dc8d..52d11c4e8 100644 --- a/src/gui/widgets/container.cpp +++ b/src/gui/widgets/container.cpp @@ -27,7 +27,7 @@ #include "debug.h" Container::Container(const Widget2 *const widget) : - gcn::Container(widget) + BasicContainer2(widget) { setOpaque(false); } diff --git a/src/gui/widgets/container.h b/src/gui/widgets/container.h index 17d6b2af4..262d7327a 100644 --- a/src/gui/widgets/container.h +++ b/src/gui/widgets/container.h @@ -23,7 +23,7 @@ #ifndef GUI_WIDGETS_CONTAINER_H #define GUI_WIDGETS_CONTAINER_H -#include "gui/base/widgets/container.hpp" +#include "gui/widgets/basiccontainer2.h" /** * A widget container. @@ -34,7 +34,7 @@ * * This container is also non-opaque by default. */ -class Container : public gcn::Container +class Container : public BasicContainer2 { public: explicit Container(const Widget2 *const widget); diff --git a/src/gui/widgets/desktop.cpp b/src/gui/widgets/desktop.cpp index a77516c62..0ff1b17c9 100644 --- a/src/gui/widgets/desktop.cpp +++ b/src/gui/widgets/desktop.cpp @@ -24,7 +24,9 @@ #include "configuration.h" #include "main.h" -#include "gui/widgets/label.h" +#include "gui/widgets/browserbox.h" + +#include "input/inputmanager.h" #include "resources/image.h" #include "resources/imagehelper.h" @@ -35,9 +37,11 @@ Desktop::Desktop(const Widget2 *const widget) : Container(widget), + LinkHandler(), WidgetListener(), mWallpaper(nullptr), - mVersionLabel(nullptr), + mVersionLabel(new BrowserBox(this, BrowserBox::AUTO_WRAP, false, + "browserbox.xml")), mSkin(nullptr), mBackgroundColor(getThemeColor(Theme::BACKGROUND, 128)), mBackgroundGrayColor(getThemeColor(Theme::BACKGROUND_GRAY)), @@ -57,15 +61,16 @@ Desktop::Desktop(const Widget2 *const widget) : const std::string appName = branding.getValue("appName", std::string()); if (appName.empty()) { - mVersionLabel = new Label(this, FULL_VERSION); + mVersionLabel->addRow(FULL_VERSION); } else { - mVersionLabel = new Label(this, strprintf("%s (%s)", FULL_VERSION, + mVersionLabel->addRow(strprintf("%s (%s)", FULL_VERSION, appName.c_str())); } - - mVersionLabel->setBackgroundColor(getThemeColor(Theme::BACKGROUND, 128)); + mVersionLabel->addRow("copyright", + "(C) ManaPlus developers, http://manaplus.org"); + mVersionLabel->setLinkHandler(this); } Desktop::~Desktop() @@ -100,6 +105,7 @@ void Desktop::reloadWallpaper() void Desktop::widgetResized(const Event &event A_UNUSED) { + mVersionLabel->setSize(getWidth(), getHeight()); setBestFittingWallpaper(); } @@ -138,10 +144,6 @@ void Desktop::draw(Graphics *graphics) graphics->fillRectangle(Rect(0, 0, width, height)); } - // Draw a thin border under the application version... - graphics->setColor(mBackgroundColor); - graphics->fillRectangle(Rect(mVersionLabel->getDimension())); - Container::draw(graphics); BLOCK_END("Desktop::draw") } @@ -198,3 +200,9 @@ void Desktop::setBestFittingWallpaper() logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); } } + +void Desktop::handleLink(const std::string &link, MouseEvent *event A_UNUSED) +{ + if (link == "copyright") + inputManager.executeAction(Input::KEY_WINDOW_ABOUT); +} diff --git a/src/gui/widgets/desktop.h b/src/gui/widgets/desktop.h index f0fd500ea..f3b0cd371 100644 --- a/src/gui/widgets/desktop.h +++ b/src/gui/widgets/desktop.h @@ -24,12 +24,14 @@ #include "gui/widgets/container.h" +#include "gui/widgets/linkhandler.h" + #include "listeners/widgetlistener.h" #include "localconsts.h" +class BrowserBox; class Image; -class Label; class Skin; /** @@ -46,7 +48,8 @@ class Skin; * \ingroup GUI */ class Desktop final : public Container, - private WidgetListener + public LinkHandler, + public WidgetListener { public: explicit Desktop(const Widget2 *const widget); @@ -66,11 +69,13 @@ class Desktop final : public Container, void postInit(); + void handleLink(const std::string &link, + MouseEvent *event) override final; private: void setBestFittingWallpaper(); Image *mWallpaper; - Label *mVersionLabel; + BrowserBox *mVersionLabel; Skin *mSkin; Color mBackgroundColor; Color mBackgroundGrayColor; diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index dfc17e17b..b1a3c4ac1 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -60,7 +60,7 @@ DropDown::DropDown(const Widget2 *const widget, ActionListener *const listener, const std::string &eventId): ActionListener(), - gcn::BasicContainer(widget), + BasicContainer(widget), KeyListener(), MouseListener(), FocusListener(), diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h index 8e463a2c1..2208880b3 100644 --- a/src/gui/widgets/dropdown.h +++ b/src/gui/widgets/dropdown.h @@ -23,7 +23,7 @@ #ifndef GUI_WIDGETS_DROPDOWN_H #define GUI_WIDGETS_DROPDOWN_H -#include "gui/base/basiccontainer.hpp" +#include "gui/widgets/basiccontainer.h" #include "listeners/actionlistener.h" #include "listeners/focuslistener.h" @@ -46,7 +46,7 @@ class Skin; * your list. */ class DropDown final : public ActionListener, - public gcn::BasicContainer, + public BasicContainer, public KeyListener, public MouseListener, public FocusListener, diff --git a/src/gui/widgets/guitable.cpp b/src/gui/widgets/guitable.cpp index 70ebb77d6..128281fe9 100644 --- a/src/gui/widgets/guitable.cpp +++ b/src/gui/widgets/guitable.cpp @@ -101,7 +101,7 @@ GuiTable::GuiTable(const Widget2 *const widget, KeyListener(), mModel(nullptr), mTopWidget(nullptr), - mActionListeners(), + mActionListeners2(), mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), mSelectedRow(-1), mSelectedColumn(-1), @@ -266,8 +266,8 @@ void GuiTable::setSelectedColumn(const int selected) void GuiTable::uninstallActionListeners() { - delete_all(mActionListeners); - mActionListeners.clear(); + delete_all(mActionListeners2); + mActionListeners2.clear(); } void GuiTable::installActionListeners() @@ -285,7 +285,7 @@ void GuiTable::installActionListeners() Widget *const widget = mModel->getElementAt(row, column); if (widget) { - mActionListeners.push_back(new GuiTableActionListener( + mActionListeners2.push_back(new GuiTableActionListener( this, widget, row, column)); } } diff --git a/src/gui/widgets/guitable.h b/src/gui/widgets/guitable.h index fb0c34784..7cec854a8 100644 --- a/src/gui/widgets/guitable.h +++ b/src/gui/widgets/guitable.h @@ -183,7 +183,7 @@ private: Widget *mTopWidget; /** Vector for compactness; used as a list in practice. */ - std::vector<GuiTableActionListener *> mActionListeners; + std::vector<GuiTableActionListener *> mActionListeners2; /** * Holds the background color of the table. diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp index 56c949964..b500ec7bb 100644 --- a/src/gui/widgets/label.cpp +++ b/src/gui/widgets/label.cpp @@ -19,6 +19,49 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/label.h" #include "gui/font.h" @@ -30,7 +73,9 @@ Skin *Label::mSkin = nullptr; int Label::mInstances = 0; Label::Label(const Widget2 *const widget) : - gcn::Label(widget), + Widget(widget), + mCaption(), + mAlignment(Graphics::LEFT), mPadding(0) { init(); @@ -38,9 +83,17 @@ Label::Label(const Widget2 *const widget) : Label::Label(const Widget2 *const widget, const std::string &caption) : - gcn::Label(widget, caption), + Widget(widget), + mCaption(caption), + mAlignment(Graphics::LEFT), mPadding(0) { + const Font *const font = getFont(); + if (font) + { + setWidth(font->getWidth(caption)); + setHeight(font->getHeight()); + } init(); } diff --git a/src/gui/widgets/label.h b/src/gui/widgets/label.h index 616f6cc79..d205ed77b 100644 --- a/src/gui/widgets/label.h +++ b/src/gui/widgets/label.h @@ -19,10 +19,53 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_LABEL_H #define GUI_WIDGETS_LABEL_H -#include "gui/base/widgets/label.hpp" +#include "gui/widgets/widget.h" #include "localconsts.h" @@ -34,7 +77,7 @@ class Skin; * * \ingroup GUI */ -class Label final : public gcn::Label +class Label final : public Widget { public: /** @@ -69,11 +112,61 @@ class Label final : public gcn::Label void resizeTo(const int maxSize, const int minSize); + /** + * Gets the caption of the label. + * + * @return The caption of the label. + * @see setCaption + */ + const std::string &getCaption() const + { return mCaption; } + + /** + * 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) + { mCaption = 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) + { mAlignment = 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 + { return mAlignment; } + static Skin *mSkin; static int mInstances; private: + /** + * Holds the caption of the label. + */ + std::string mCaption; + + /** + * Holds the alignment of the caption. + */ + Graphics::Alignment mAlignment; + int mPadding; }; diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp index 24722510b..668334fd5 100644 --- a/src/gui/widgets/layout.cpp +++ b/src/gui/widgets/layout.cpp @@ -24,7 +24,7 @@ #include "logger.h" -#include "gui/base/widgets/container.hpp" +#include "gui/widgets/basiccontainer2.h" #include <cassert> diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h index 288c282a0..27af0840d 100644 --- a/src/gui/widgets/layout.h +++ b/src/gui/widgets/layout.h @@ -27,13 +27,8 @@ #include <vector> +class BasicContainer2; class LayoutCell; - -namespace gcn -{ - class Container; -} - class Widget; /** @@ -42,7 +37,7 @@ class Widget; class ContainerPlacer final { public: - explicit ContainerPlacer(gcn::Container *c = nullptr, + explicit ContainerPlacer(BasicContainer2 *c = nullptr, LayoutCell *lc = nullptr) : mContainer(c), mCell(lc) {} @@ -66,7 +61,7 @@ class ContainerPlacer final const int w = 1, const int h = 1); private: - gcn::Container *mContainer; + BasicContainer2 *mContainer; LayoutCell *mCell; }; diff --git a/src/gui/widgets/layouthelper.cpp b/src/gui/widgets/layouthelper.cpp index c225c7543..a8cf28bea 100644 --- a/src/gui/widgets/layouthelper.cpp +++ b/src/gui/widgets/layouthelper.cpp @@ -22,11 +22,11 @@ #include "gui/widgets/layouthelper.h" -#include "gui/base/widgets/container.hpp" +#include "gui/widgets/basiccontainer2.h" #include "debug.h" -LayoutHelper::LayoutHelper(gcn::Container *const container) : +LayoutHelper::LayoutHelper(BasicContainer2 *const container) : WidgetListener(), mLayout(), mContainer(container) diff --git a/src/gui/widgets/layouthelper.h b/src/gui/widgets/layouthelper.h index 32e3d9e34..78e34f419 100644 --- a/src/gui/widgets/layouthelper.h +++ b/src/gui/widgets/layouthelper.h @@ -38,7 +38,7 @@ class LayoutHelper final : public WidgetListener /** * Constructor. */ - explicit LayoutHelper(gcn::Container *const container); + explicit LayoutHelper(BasicContainer2 *const container); A_DELETE_COPY(LayoutHelper) @@ -82,7 +82,7 @@ class LayoutHelper final : public WidgetListener private: Layout mLayout; /**< Layout handler */ - gcn::Container *mContainer; /**< Managed container */ + BasicContainer2 *mContainer; /**< Managed container */ }; #endif // GUI_WIDGETS_LAYOUTHELPER_H diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp index c6e431634..6f0c192c6 100644 --- a/src/gui/widgets/listbox.cpp +++ b/src/gui/widgets/listbox.cpp @@ -20,22 +20,63 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/listbox.h" #include "client.h" -#include "events/keyevent.h" - #include "input/keydata.h" +#include "listeners/selectionlistener.h" + #include "gui/focushandler.h" #include "gui/font.h" #include "gui/gui.h" #include "gui/models/listmodel.h" -#include "render/graphics.h" - #include "debug.h" float ListBox::mAlpha = 1.0; @@ -43,7 +84,13 @@ float ListBox::mAlpha = 1.0; ListBox::ListBox(const Widget2 *const widget, ListModel *const listModel, const std::string &skin) : - gcn::ListBox(widget, listModel), + Widget(widget), + MouseListener(), + KeyListener(), + mSelected(-1), + mListModel(listModel), + mWrappingEnabled(false), + mSelectionListeners(), mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), mForegroundSelectedColor(getThemeColor(Theme::LISTBOX_SELECTED)), mForegroundSelectedColor2(getThemeColor(Theme::LISTBOX_SELECTED_OUTLINE)), @@ -56,6 +103,11 @@ ListBox::ListBox(const Widget2 *const widget, mDistributeMousePressed(true), mCenterText(false) { + setWidth(100); + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + mForegroundColor = getThemeColor(Theme::LISTBOX); mForegroundColor2 = getThemeColor(Theme::LISTBOX_OUTLINE); @@ -313,3 +365,59 @@ int ListBox::getSelectionByMouse(const int y) const return -1; return (y - mPadding) / getRowHeight(); } + +void ListBox::setSelected(const int selected) +{ + if (!mListModel) + { + mSelected = -1; + } + else + { + if (selected < 0) + mSelected = -1; + else if (selected >= mListModel->getNumberOfElements()) + mSelected = mListModel->getNumberOfElements() - 1; + else + mSelected = selected; + } + + Rect scroll; + + if (mSelected < 0) + scroll.y = 0; + else + scroll.y = getRowHeight() * mSelected; + + scroll.height = getRowHeight(); + showPart(scroll); + + distributeValueChangedEvent(); +} + +void ListBox::setListModel(ListModel *const listModel) +{ + mSelected = -1; + mListModel = listModel; + adjustSize(); +} + +void ListBox::addSelectionListener(SelectionListener *const selectionListener) +{ + mSelectionListeners.push_back(selectionListener); +} + +void ListBox::removeSelectionListener(SelectionListener *const + selectionListener) +{ + mSelectionListeners.remove(selectionListener); +} + +void ListBox::distributeValueChangedEvent() +{ + FOR_EACH (SelectionListenerIterator, iter, mSelectionListeners) + { + SelectionEvent event(this); + (*iter)->valueChanged(event); + } +} diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h index 64faa6eb5..f784b3237 100644 --- a/src/gui/widgets/listbox.h +++ b/src/gui/widgets/listbox.h @@ -20,12 +20,58 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_LISTBOX_H #define GUI_WIDGETS_LISTBOX_H #include "gui/color.h" -#include "gui/base/widgets/listbox.hpp" +#include "gui/widgets/widget.h" + +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" #include "localconsts.h" @@ -33,6 +79,7 @@ class Skin; class KeyEvent; class ListModel; class MouseEvent; +class SelectionListener; class Widget2; /** @@ -42,7 +89,9 @@ class Widget2; * * \ingroup GUI */ -class ListBox : public gcn::ListBox +class ListBox : public Widget, + public MouseListener, + public KeyListener { public: /** @@ -103,13 +152,137 @@ class ListBox : public gcn::ListBox int getPressedIndex() const { return mPressedIndex; } - unsigned int getRowHeight() const override A_WARN_UNUSED + virtual unsigned int getRowHeight() const A_WARN_UNUSED { return mRowHeight; } void setRowHeight(unsigned int n) { mRowHeight = n; } + /** + * 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 + { return mSelected; } + + /** + * 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(const 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() const + { return mListModel; } + + /** + * 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 + { return mWrappingEnabled; } + + /** + * 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(const bool wrappingEnabled) + { mWrappingEnabled = 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 *const selectionListener); + + /** + * Removes a selection listener from the list box. + * + * @param selectionListener The selection listener to remove. + * @since 0.8.0 + */ + void removeSelectionListener(SelectionListener *const + selectionListener); + + /** + * Distributes a value changed event to all selection listeners + * of the list box. + * + * @since 0.8.0 + */ + void distributeValueChangedEvent(); + protected: + /** + * 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; + Color mHighlightColor; Color mForegroundSelectedColor; Color mForegroundSelectedColor2; diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp index 7ef543511..2ba452620 100644 --- a/src/gui/widgets/playerbox.cpp +++ b/src/gui/widgets/playerbox.cpp @@ -36,7 +36,8 @@ PlayerBox::PlayerBox(Widget2 *const widget, Being *const being, const std::string &skin, const std::string &selectedSkin) : - ScrollArea(widget), + Widget(widget), + MouseListener(), mBeing(being), mAlpha(1.0), mBackground(), @@ -54,7 +55,8 @@ PlayerBox::PlayerBox(Widget2 *const widget, PlayerBox::PlayerBox(Widget2 *const widget, const std::string &skin, const std::string &selectedSkin) : - ScrollArea(widget), + Widget(widget), + MouseListener(), mBeing(nullptr), mAlpha(1.0), mBackground(), @@ -82,6 +84,7 @@ PlayerBox::~PlayerBox() void PlayerBox::init(std::string name, std::string selectedName) { setFrameSize(2); + addMouseListener(this); Theme *const theme = Theme::instance(); if (theme) @@ -153,10 +156,10 @@ void PlayerBox::drawFrame(Graphics *graphics) void PlayerBox::mouseReleased(MouseEvent& event) { - ScrollArea::mouseReleased(event); if (event.getButton() == MouseEvent::LEFT) { if (!mActionEventId.empty()) distributeActionEvent(); + event.consume(); } } diff --git a/src/gui/widgets/playerbox.h b/src/gui/widgets/playerbox.h index 7481dc9db..1a9067378 100644 --- a/src/gui/widgets/playerbox.h +++ b/src/gui/widgets/playerbox.h @@ -23,7 +23,9 @@ #ifndef GUI_WIDGETS_PLAYERBOX_H #define GUI_WIDGETS_PLAYERBOX_H -#include "gui/base/widgets/scrollarea.hpp" +#include "gui/widgets/widget.h" + +#include "listeners/mouselistener.h" #include "localconsts.h" @@ -35,7 +37,8 @@ class Skin; * * \ingroup GUI */ -class PlayerBox final : public gcn::ScrollArea +class PlayerBox final : public Widget, + public MouseListener { public: /** diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp index bb9ae46f9..411216455 100644 --- a/src/gui/widgets/radiobutton.cpp +++ b/src/gui/widgets/radiobutton.cpp @@ -20,12 +20,53 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/radiobutton.h" #include "client.h" -#include "events/keyevent.h" - #include "input/keydata.h" #include "resources/image.h" @@ -39,17 +80,32 @@ int RadioButton::instances = 0; Skin *RadioButton::mSkin = nullptr; float RadioButton::mAlpha = 1.0; +RadioButton::GroupMap RadioButton::mGroupMap; + RadioButton::RadioButton(const Widget2 *const widget, const std::string &restrict caption, const std::string &restrict group, const bool marked): - gcn::RadioButton(widget, caption, group, marked), + Widget(widget), + MouseListener(), + KeyListener(), + mSelected(false), + mCaption(), + mGroup(), mPadding(0), mImagePadding(0), mImageSize(9), mSpacing(2), mHasMouse(false) { + setCaption(caption); + setGroup(group); + setSelected(marked); + + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + mForegroundColor = getThemeColor(Theme::RADIOBUTTON); mForegroundColor2 = getThemeColor(Theme::RADIOBUTTON_OUTLINE); if (instances == 0) @@ -77,6 +133,8 @@ RadioButton::RadioButton(const Widget2 *const widget, RadioButton::~RadioButton() { + setGroup(""); + if (gui) gui->removeDragged(this); @@ -196,3 +254,57 @@ void RadioButton::adjustSize() setWidth(mImagePadding + mImageSize + mSpacing + font->getWidth(mCaption) + mPadding); } + +void RadioButton::setSelected(const bool selected) +{ + if (selected && !mGroup.empty()) + { + for (GroupIterator iter = mGroupMap.lower_bound(mGroup), + iterEnd = mGroupMap.upper_bound(mGroup); + iter != iterEnd; + ++ iter) + { + if (iter->second && iter->second->isSelected()) + iter->second->setSelected(false); + } + } + + mSelected = selected; +} + +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 != "") + { + for (GroupIterator iter = mGroupMap.lower_bound(mGroup), + iterEnd = mGroupMap.upper_bound(mGroup); + iter != iterEnd; + ++ iter) + { + if (iter->second == this) + { + mGroupMap.erase(iter); + break; + } + } + } + + if (!group.empty()) + mGroupMap.insert(std::pair<std::string, RadioButton *>(group, this)); + + mGroup = group; +} diff --git a/src/gui/widgets/radiobutton.h b/src/gui/widgets/radiobutton.h index 2deb9a772..5aa0d9289 100644 --- a/src/gui/widgets/radiobutton.h +++ b/src/gui/widgets/radiobutton.h @@ -20,10 +20,56 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_RADIOBUTTON_H #define GUI_WIDGETS_RADIOBUTTON_H -#include "gui/base/widgets/radiobutton.hpp" +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" + +#include "gui/widgets/widget.h" #include "localconsts.h" @@ -32,7 +78,10 @@ class Skin; /** * Guichan based RadioButton with custom look */ -class RadioButton final : public gcn::RadioButton +class RadioButton final : public Widget, + public MouseListener, + public KeyListener + { public: /** @@ -53,7 +102,7 @@ class RadioButton final : public gcn::RadioButton /** * Draws the radiobutton, not the caption. */ - void drawBox(Graphics* graphics) override final; + void drawBox(Graphics* graphics); /** * Implementation of the draw methods. @@ -77,10 +126,102 @@ class RadioButton final : public gcn::RadioButton void adjustSize(); + /** + * Checks if the radio button is selected. + * + * @return True if the radio button is selecte, false otherwise. + * @see setSelected + */ + bool isSelected() const + { return mSelected; } + + /** + * Sets the radio button to selected or not. + * + * @param selected True if the radio button should be selected, + * false otherwise. + * @see isSelected + */ + void setSelected(const bool selected); + + /** + * Gets the caption of the radio button. + * + * @return The caption of the radio button. + * @see setCaption + */ + const std::string &getCaption() const + { return mCaption; } + + /** + * 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) + { mCaption = caption; } + + void mouseClicked(MouseEvent& mouseEvent) override final; + + void mouseDragged(MouseEvent& mouseEvent) override final; + + /** + * 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 + { return mGroup; } + private: static int instances; static Skin *mSkin; static float mAlpha; + + /** + * 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; + int mPadding; int mImagePadding; int mImageSize; diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp index dcc3a871b..47b8b0985 100644 --- a/src/gui/widgets/scrollarea.cpp +++ b/src/gui/widgets/scrollarea.cpp @@ -20,6 +20,49 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/scrollarea.h" #include "client.h" @@ -53,21 +96,44 @@ ScrollArea::ScrollArea(Widget2 *const widget2, Widget *const widget, const bool opaque, const std::string &skin) : - gcn::ScrollArea(widget2, widget), + BasicContainer(widget2), + MouseListener(), WidgetListener(), + mVertexes(new ImageCollection), + mVertexes2(new ImageCollection), + mHPolicy(SHOW_AUTO), + mVPolicy(SHOW_AUTO), + mVScroll(0), + mHScroll(0), + mScrollbarWidth(12), + mUpButtonScrollAmount(10), + mDownButtonScrollAmount(10), + mLeftButtonScrollAmount(10), + mRightButtonScrollAmount(10), + mHorizontalMarkerDragOffset(0), + mVerticalMarkerDragOffset(0), mX(0), mY(0), mClickX(0), mClickY(0), - mVertexes(new ImageCollection), - mVertexes2(new ImageCollection), mXOffset(0), mYOffset(0), mDrawWidth(0), mDrawHeight(0), + mVBarVisible(false), + mHBarVisible(false), + mUpButtonPressed(false), + mDownButtonPressed(false), + mLeftButtonPressed(false), + mRightButtonPressed(false), + mIsVerticalMarkerDragged(false), + mIsHorizontalMarkerDragged(false), + mOpaque(true), mHasMouse(false), mRedraw(true) { + setContent(widget); + addMouseListener(this); mOpaque = opaque; init(skin); } @@ -102,6 +168,8 @@ ScrollArea::~ScrollArea() mVertexes = nullptr; delete mVertexes2; mVertexes2 = nullptr; + + setContent(nullptr); } void ScrollArea::init(std::string skinName) @@ -178,20 +246,30 @@ void ScrollArea::logic() return; } - gcn::ScrollArea::logic(); + checkPolicies(); + + setVerticalScrollAmount(getVerticalScrollAmount()); + setHorizontalScrollAmount(getHorizontalScrollAmount()); + Widget *const content = getContent(); + if (content) + { + const int frameSize = content->getFrameSize(); + content->setPosition(-mHScroll + frameSize, -mVScroll + frameSize); + content->logic(); + } // When no scrollbar in a certain direction, adapt content size to match // the content dimension exactly. if (content) { const unsigned int frameSize = 2 * content->getFrameSize(); - if (mHPolicy == gcn::ScrollArea::SHOW_NEVER) + if (mHPolicy == ScrollArea::SHOW_NEVER) { content->setWidth((mVBarVisible ? (mDimension.width - mScrollbarWidth) : mDimension.width) - frameSize); } - if (mVPolicy == gcn::ScrollArea::SHOW_NEVER) + if (mVPolicy == ScrollArea::SHOW_NEVER) { content->setHeight((mHBarVisible ? (mDimension.height - mScrollbarWidth) : mDimension.height) - frameSize); @@ -377,11 +455,9 @@ void ScrollArea::setOpaque(bool opaque) setFrameSize(mOpaque ? 2 : 0); } -void ScrollArea::drawButton(Graphics *const graphics, - const BUTTON_DIR dir) +Image *ScrollArea::getImageByState(Rect &dim, const BUTTON_DIR dir) { int state = 0; - Rect dim; switch (dir) { @@ -405,52 +481,35 @@ void ScrollArea::drawButton(Graphics *const graphics, default: logger->log("ScrollArea::drawButton unknown dir: " + toString(static_cast<unsigned>(dir))); - return; + return nullptr; } + return buttons[dir][state]; +} - if (buttons[dir][state]) - graphics->drawImage(buttons[dir][state], dim.x, dim.y); +void ScrollArea::drawButton(Graphics *const graphics, + const BUTTON_DIR dir) +{ + Rect dim; + const Image *const image = getImageByState(dim, dir); + + if (image) + graphics->drawImage(image, dim.x, dim.y); } void ScrollArea::calcButton(Graphics *const graphics, const BUTTON_DIR dir) { - int state = 0; Rect dim; + const Image *const image = getImageByState(dim, dir); - switch (dir) - { - case UP: - state = mUpButtonPressed ? 1 : 0; - dim = getUpButtonDimension(); - break; - case DOWN: - state = mDownButtonPressed ? 1 : 0; - dim = getDownButtonDimension(); - break; - case LEFT: - state = mLeftButtonPressed ? 1 : 0; - dim = getLeftButtonDimension(); - break; - case RIGHT: - state = mRightButtonPressed ? 1 : 0; - dim = getRightButtonDimension(); - break; - case BUTTONS_DIR: - default: - logger->log("ScrollArea::drawButton unknown dir: " - + toString(static_cast<unsigned>(dir))); - return; - } - - if (buttons[dir][state]) + if (image) { static_cast<Graphics*>(graphics)->calcTileCollection( - mVertexes, buttons[dir][state], dim.x, dim.y); + mVertexes, image, dim.x, dim.y); } } -void ScrollArea::drawVBar(Graphics *const graphics) +void ScrollArea::drawVBar(Graphics *const graphics) const { const Rect &dim = getVerticalBarDimension(); @@ -500,7 +559,7 @@ void ScrollArea::calcVBar(Graphics *const graphics) } } -void ScrollArea::drawHBar(Graphics *const graphics) +void ScrollArea::drawHBar(Graphics *const graphics) const { const Rect &dim = getHorizontalBarDimension(); @@ -803,7 +862,13 @@ void ScrollArea::mouseReleased(MouseEvent& event) event.consume(); } } - gcn::ScrollArea::mouseReleased(event); + mUpButtonPressed = false; + mDownButtonPressed = false; + mLeftButtonPressed = false; + mRightButtonPressed = false; + mIsHorizontalMarkerDragged = false; + mIsVerticalMarkerDragged = false; + event.consume(); mRedraw = true; } @@ -1066,3 +1131,290 @@ Rect ScrollArea::getRightButtonDimension() const mScrollbarWidth, mScrollbarWidth); } + +void ScrollArea::setContent(Widget* widget) +{ + if (widget) + { + clear(); + add(widget); + widget->setPosition(0, 0); + } + else + { + clear(); + } + + checkPolicies(); +} + +Widget* ScrollArea::getContent() +{ + if (!mWidgets.empty()) + return *mWidgets.begin(); + + return nullptr; +} + +void ScrollArea::setHorizontalScrollPolicy(const ScrollPolicy hPolicy) +{ + mHPolicy = hPolicy; + checkPolicies(); +} + +void ScrollArea::setVerticalScrollPolicy(const ScrollPolicy vPolicy) +{ + mVPolicy = vPolicy; + checkPolicies(); +} + +void ScrollArea::setScrollPolicy(const ScrollPolicy hPolicy, + const ScrollPolicy vPolicy) +{ + mHPolicy = hPolicy; + mVPolicy = vPolicy; + checkPolicies(); +} + +void ScrollArea::setVerticalScrollAmount(const int vScroll) +{ + const int max = getVerticalMaxScroll(); + + mVScroll = vScroll; + + if (vScroll > max) + mVScroll = max; + + if (vScroll < 0) + mVScroll = 0; +} + +void ScrollArea::setHorizontalScrollAmount(int hScroll) +{ + const int max = getHorizontalMaxScroll(); + + mHScroll = hScroll; + + if (hScroll > max) + mHScroll = max; + else if (hScroll < 0) + mHScroll = 0; +} + +void ScrollArea::setScrollAmount(const int hScroll, const int vScroll) +{ + setHorizontalScrollAmount(hScroll); + setVerticalScrollAmount(vScroll); +} + +int ScrollArea::getHorizontalMaxScroll() +{ + checkPolicies(); + + const Widget *const content = getContent(); + if (!content) + return 0; + + const int value = content->getWidth() - getChildrenArea().width + + 2 * content->getFrameSize(); + + if (value < 0) + return 0; + + return value; +} + +int ScrollArea::getVerticalMaxScroll() +{ + checkPolicies(); + + const Widget *const content = getContent(); + if (!content) + return 0; + + int value; + + value = content->getHeight() - getChildrenArea().height + + 2 * content->getFrameSize(); + + if (value < 0) + return 0; + + return value; +} + +void ScrollArea::setScrollbarWidth(const int width) +{ + if (width > 0) + mScrollbarWidth = width; +} + +void ScrollArea::showWidgetPart(Widget *const widget, Rect area) +{ + const Widget *const content = getContent(); + if (widget != content) + return; + + BasicContainer::showWidgetPart(widget, area); + + setHorizontalScrollAmount(content->getFrameSize() + - content->getX()); + setVerticalScrollAmount(content->getFrameSize() + - content->getY()); +} + +Rect ScrollArea::getChildrenArea() +{ + const Rect area = Rect(0, 0, + mVBarVisible ? (getWidth() - mScrollbarWidth) : getWidth(), + mHBarVisible ? (getHeight() - mScrollbarWidth) : getHeight()); + + if (area.width < 0 || area.height < 0) + return Rect(); + + return area; +} + +Widget *ScrollArea::getWidgetAt(int x, int y) +{ + if (getChildrenArea().isPointInRect(x, y)) + return getContent(); + + return nullptr; +} + +void ScrollArea::setWidth(int width) +{ + Widget::setWidth(width); + checkPolicies(); +} + +void ScrollArea::setHeight(int height) +{ + Widget::setHeight(height); + checkPolicies(); +} + +void ScrollArea::setDimension(const Rect& dimension) +{ + Widget::setDimension(dimension); + checkPolicies(); +} + +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::checkPolicies() +{ + const int w = getWidth(); + const int h = getHeight(); + + mHBarVisible = false; + mVBarVisible = false; + + const Widget *const content = getContent(); + if (!content) + { + mHBarVisible = (mHPolicy == SHOW_ALWAYS); + mVBarVisible = (mVPolicy == SHOW_ALWAYS); + return; + } + + if (mHPolicy == SHOW_AUTO && + mVPolicy == SHOW_AUTO) + { + if (content->getWidth() <= w + && content->getHeight() <= h) + { + mHBarVisible = false; + mVBarVisible = false; + } + + if (content->getWidth() > w) + { + mHBarVisible = true; + } + + if ((content->getHeight() > h) + || (mHBarVisible && content->getHeight() + > h - mScrollbarWidth)) + { + mVBarVisible = true; + } + + if (mVBarVisible && content->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 = (content->getWidth() > w); + } + else // (mVPolicy == SHOW_ALWAYS) + { + mHBarVisible = (content->getWidth() + > w - mScrollbarWidth); + } + break; + + default: + break; + } + + switch (mVPolicy) + { + case SHOW_NEVER: + mVBarVisible = false; + break; + + case SHOW_ALWAYS: + mVBarVisible = true; + break; + + case SHOW_AUTO: + if (mHPolicy == SHOW_NEVER) + { + mVBarVisible = (content->getHeight() > h); + } + else // (mHPolicy == SHOW_ALWAYS) + { + mVBarVisible = (content->getHeight() + > h - mScrollbarWidth); + } + break; + default: + break; + } +} diff --git a/src/gui/widgets/scrollarea.h b/src/gui/widgets/scrollarea.h index 7d2b39a96..0b0cae2c3 100644 --- a/src/gui/widgets/scrollarea.h +++ b/src/gui/widgets/scrollarea.h @@ -20,11 +20,55 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_SCROLLAREA_H #define GUI_WIDGETS_SCROLLAREA_H -#include "gui/base/widgets/scrollarea.hpp" +#include "gui/widgets/basiccontainer.h" +#include "listeners/mouselistener.h" #include "listeners/widgetlistener.h" #include "localconsts.h" @@ -41,11 +85,28 @@ class ImageCollection; * * \ingroup GUI */ -class ScrollArea final : public gcn::ScrollArea, +class ScrollArea final : public BasicContainer, + public MouseListener, public WidgetListener { 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. * * @param content the initial content to show in the scroll area @@ -135,6 +196,234 @@ class ScrollArea final : public gcn::ScrollArea, Rect getRightButtonDimension() const; + /** + * 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(const 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 + { return mHPolicy; } + + /** + * Sets the vertical scrollbar policy. See enum with policies. + * + * @param vPolicy The policy for the vertical scrollbar. + * @see getVerticalScrollPolicy + */ + void setVerticalScrollPolicy(const ScrollPolicy vPolicy); + + /** + * Gets the vertical scrollbar policy. See enum with policies. + * + * @return The policy for the vertical scrollbar. + * @see setVerticalScrollPolicy, setScrollPolicy + */ + ScrollPolicy getVerticalScrollPolicy() const + { return mVPolicy; } + + /** + * 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(const ScrollPolicy hPolicy, + const ScrollPolicy vPolicy); + + /** + * Sets the amount to scroll vertically. + * + * @param vScroll The amount to scroll. + * @see getVerticalScrollAmount + */ + void setVerticalScrollAmount(const int vScroll); + + /** + * Gets the amount that is scrolled vertically. + * + * @return The scroll amount on vertical scroll. + * @see setVerticalScrollAmount, setScrollAmount + */ + int getVerticalScrollAmount() const + { return mVScroll; } + + /** + * 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 + { return mHScroll; } + + /** + * 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(const int hScroll, const 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(const int width); + + /** + * Gets the width of the scroll bars. + * + * @return the width of the ScrollBar. + * @see setScrollbarWidth + */ + int getScrollbarWidth() const + { return mScrollbarWidth; } + + /** + * 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(const int amount) + { mLeftButtonScrollAmount = 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(const int amount) + { mRightButtonScrollAmount = 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(const int amount) + { mUpButtonScrollAmount = 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(const int amount) + { mDownButtonScrollAmount = 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 + { return mLeftButtonScrollAmount; } + + /** + * 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 + { return mRightButtonScrollAmount; } + + /** + * 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 + { return mUpButtonScrollAmount; } + + /** + * 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 + { return mDownButtonScrollAmount; } + + void showWidgetPart(Widget *const widget, Rect area) override final; + + Rect getChildrenArea() override final; + + Widget *getWidgetAt(int x, int y) override final; + + void setWidth(int width); + + void setHeight(int height); + + void setDimension(const Rect& dimension); + + void mouseWheelMovedUp(MouseEvent& mouseEvent) override final; + + void mouseWheelMovedDown(MouseEvent& mouseEvent) override final; + protected: enum BUTTON_DIR { @@ -150,18 +439,25 @@ class ScrollArea final : public gcn::ScrollArea, */ void init(std::string skinName); + /** + * Checks the policies for the scroll bars. + */ + void checkPolicies(); + void drawButton(Graphics *const graphics, const BUTTON_DIR dir); void calcButton(Graphics *const graphics, const BUTTON_DIR dir); - void drawVBar(Graphics *const graphics) override final; - void drawHBar(Graphics *const graphics) override final; - void drawVMarker(Graphics *const graphics) override final; - void drawHMarker(Graphics *const graphics) override final; + void drawVBar(Graphics *const graphics) const; + void drawHBar(Graphics *const graphics) const; + void drawVMarker(Graphics *const graphics); + void drawHMarker(Graphics *const graphics); void calcVBar(Graphics *const graphics); void calcHBar(Graphics *const graphics); void calcVMarker(Graphics *const graphics); void calcHMarker(Graphics *const graphics); + Image *getImageByState(Rect &dim, const BUTTON_DIR dir); + void updateCalcFlag(Graphics *const graphics); static int instances; @@ -176,14 +472,119 @@ class ScrollArea final : public gcn::ScrollArea, static ImageRect hBackground; static Image *buttons[4][2]; - int mX, mY; - int mClickX, mClickY; ImageCollection *mVertexes; ImageCollection *mVertexes2; + + /** + * Holds the horizontal scroll bar policy. + */ + ScrollPolicy mHPolicy; + + /** + * Holds the vertical scroll bar policy. + */ + ScrollPolicy mVPolicy; + + /** + * 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 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; + + /** + * Holds the horizontal markers drag offset. + */ + int mHorizontalMarkerDragOffset; + + /** + * Holds the vertical markers drag offset. + */ + int mVerticalMarkerDragOffset; + + int mX; + int mY; + int mClickX; + int mClickY; int mXOffset; int mYOffset; int mDrawWidth; int mDrawHeight; + + /** + * 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; + + /** + * True if the vertical marked is dragged. + */ + bool mIsVerticalMarkerDragged; + + /** + * True if the horizontal marked is dragged. + */ + bool mIsHorizontalMarkerDragged; + + /** + * True if the scroll area should be opaque (that is + * display its background), false otherwise. + */ + bool mOpaque; + bool mHasMouse; bool mRedraw; }; diff --git a/src/gui/widgets/setupitem.cpp b/src/gui/widgets/setupitem.cpp index 218efe8a2..4c32b0572 100644 --- a/src/gui/widgets/setupitem.cpp +++ b/src/gui/widgets/setupitem.cpp @@ -769,7 +769,7 @@ void SetupItemSlider::createControls() mSlider = new Slider(this, mMin, mMax); mSlider->setActionEventId(mEventName); mSlider->addActionListener(mParent); - mSlider->setValue2(atof(mValue.c_str())); + mSlider->setValue(atof(mValue.c_str())); mSlider->setHeight(30); mWidget = mSlider; @@ -798,7 +798,7 @@ void SetupItemSlider::toWidget() if (!mSlider) return; - mSlider->setValue2(atof(mValue.c_str())); + mSlider->setValue(atof(mValue.c_str())); } void SetupItemSlider::action(const ActionEvent &event A_UNUSED) @@ -893,7 +893,7 @@ void SetupItemSlider2::createControls() mSlider = new Slider(this, mMin, mMax); mSlider->setActionEventId(mEventName); mSlider->addActionListener(mParent); - mSlider->setValue2(atof(mValue.c_str())); + mSlider->setValue(atof(mValue.c_str())); mSlider->setHeight(30); mWidget = mSlider; @@ -952,7 +952,7 @@ void SetupItemSlider2::toWidget() int val = roundDouble(atof(mValue.c_str())); if (mInvert) val = mInvertValue - val; - mSlider->setValue2(val); + mSlider->setValue(val); updateLabel(); } diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp index 7a9b38050..700d31416 100644 --- a/src/gui/widgets/slider.cpp +++ b/src/gui/widgets/slider.cpp @@ -20,6 +20,49 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/slider.h" #include "client.h" @@ -47,8 +90,16 @@ static std::string const data[2] = Slider::Slider(Widget2 *const widget, const double scaleEnd) : - gcn::Slider(widget, scaleEnd), + Widget(widget), + MouseListener(), + KeyListener(), + mValue(0), + mStepLength(scaleEnd / 10), + mScaleStart(0), + mScaleEnd(scaleEnd), + mOrientation(HORIZONTAL), mVertexes(new ImageCollection), + mMarkerLength(10), mHasMouse(false), mRedraw(true) { @@ -58,8 +109,16 @@ Slider::Slider(Widget2 *const widget, Slider::Slider(Widget2 *const widget, const double scaleStart, const double scaleEnd) : - gcn::Slider(widget, scaleStart, scaleEnd), + Widget(widget), + MouseListener(), + KeyListener(), + mValue(scaleStart), + mStepLength((scaleEnd - scaleStart) / 10), + mScaleStart(scaleStart), + mScaleEnd(scaleEnd), + mOrientation(HORIZONTAL), mVertexes(new ImageCollection), + mMarkerLength(10), mHasMouse(false), mRedraw(true) { @@ -83,6 +142,12 @@ Slider::~Slider() void Slider::init() { + setFocusable(true); + setFrameSize(1); + + addMouseListener(this); + addKeyListener(this); + setFrameSize(0); // Load resources @@ -289,22 +354,18 @@ void Slider::mouseExited(MouseEvent& event A_UNUSED) void Slider::mousePressed(MouseEvent &mouseEvent) { + const int x = mouseEvent.getX(); + const int y = mouseEvent.getY(); + const int width = mDimension.width; + const int height = mDimension.height; + if (mouseEvent.getButton() == MouseEvent::LEFT - && mouseEvent.getX() >= 0 - && mouseEvent.getX() <= getWidth() - && mouseEvent.getY() >= 0 - && mouseEvent.getY() <= getHeight()) + && x >= 0 && x <= width && y >= 0 && y <= height) { - if (getOrientation() == HORIZONTAL) - { - setValue2(markerPositionToValue( - mouseEvent.getX() - getMarkerLength() / 2)); - } + if (mOrientation == HORIZONTAL) + setValue(markerPositionToValue(x - mMarkerLength / 2)); else - { - setValue2(markerPositionToValue(getHeight() - - mouseEvent.getY() - getMarkerLength() / 2)); - } + setValue(markerPositionToValue(height - y - mMarkerLength / 2)); distributeActionEvent(); } @@ -312,15 +373,14 @@ void Slider::mousePressed(MouseEvent &mouseEvent) void Slider::mouseDragged(MouseEvent &mouseEvent) { - if (getOrientation() == HORIZONTAL) + if (mOrientation == HORIZONTAL) { - setValue2(markerPositionToValue(mouseEvent.getX() - - getMarkerLength() / 2)); + setValue(markerPositionToValue(mouseEvent.getX() - mMarkerLength / 2)); } else { - setValue2(markerPositionToValue(getHeight() - - mouseEvent.getY() - getMarkerLength() / 2)); + setValue(markerPositionToValue( + mDimension.height - mouseEvent.getY() - mMarkerLength / 2)); } distributeActionEvent(); @@ -330,17 +390,15 @@ void Slider::mouseDragged(MouseEvent &mouseEvent) void Slider::mouseWheelMovedUp(MouseEvent &mouseEvent) { - setValue2(getValue() + getStepLength()); + setValue(mValue + mStepLength); distributeActionEvent(); - mouseEvent.consume(); } void Slider::mouseWheelMovedDown(MouseEvent &mouseEvent) { - setValue2(getValue() - getStepLength()); + setValue(mValue - mStepLength); distributeActionEvent(); - mouseEvent.consume(); } @@ -348,17 +406,17 @@ void Slider::keyPressed(KeyEvent& keyEvent) { const int action = keyEvent.getActionId(); - if (getOrientation() == HORIZONTAL) + if (mOrientation == HORIZONTAL) { if (action == Input::KEY_GUI_RIGHT) { - setValue2(getValue() + getStepLength()); + setValue(mValue + mStepLength); distributeActionEvent(); keyEvent.consume(); } else if (action == Input::KEY_GUI_LEFT) { - setValue2(getValue() - getStepLength()); + setValue(mValue - mStepLength); distributeActionEvent(); keyEvent.consume(); } @@ -367,21 +425,72 @@ void Slider::keyPressed(KeyEvent& keyEvent) { if (action == Input::KEY_GUI_UP) { - setValue2(getValue() + getStepLength()); + setValue(mValue + mStepLength); distributeActionEvent(); keyEvent.consume(); } else if (action == Input::KEY_GUI_DOWN) { - setValue2(getValue() - getStepLength()); + setValue(mValue - mStepLength); distributeActionEvent(); keyEvent.consume(); } } } -void Slider::setValue2(const double value) +void Slider::setScale(const double scaleStart, const double scaleEnd) +{ + mScaleStart = scaleStart; + mScaleEnd = scaleEnd; +} + +void Slider::setValue(const double value) { - setValue(value); mRedraw = true; + if (value > mScaleEnd) + { + mValue = mScaleEnd; + return; + } + + if (value < mScaleStart) + { + mValue = mScaleStart; + return; + } + + mValue = value; +} + +double Slider::markerPositionToValue(const int v) const +{ + int w; + if (mOrientation == HORIZONTAL) + w = mDimension.width; + else + w = mDimension.height; + + const double pos = v / (static_cast<double>(w) - mMarkerLength); + return (1.0 - pos) * mScaleStart + pos * mScaleEnd; +} + +int Slider::valueToMarkerPosition(const double value) const +{ + int v; + if (mOrientation == HORIZONTAL) + v = mDimension.width; + else + v = mDimension.height; + + const int w = static_cast<int>((v - mMarkerLength) + * (value - mScaleStart) + / (mScaleEnd - mScaleStart)); + + if (w < 0) + return 0; + + if (w > v - mMarkerLength) + return v - mMarkerLength; + + return w; } diff --git a/src/gui/widgets/slider.h b/src/gui/widgets/slider.h index 2f21127d1..23d06de48 100644 --- a/src/gui/widgets/slider.h +++ b/src/gui/widgets/slider.h @@ -20,10 +20,56 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_SLIDER_H #define GUI_WIDGETS_SLIDER_H -#include "gui/base/widgets/slider.hpp" +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" + +#include "gui/widgets/widget.h" #include "localconsts.h" @@ -34,10 +80,22 @@ class ImageCollection; * * \ingroup GUI */ -class Slider final : public gcn::Slider +class Slider final : 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 with scale start equal to 0. */ explicit Slider(Widget2 *const widget, @@ -87,7 +145,125 @@ class Slider final : public gcn::Slider void keyPressed(KeyEvent& keyEvent) override final; - void setValue2(const double value); + /** + * 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(const double scaleStart, const double scaleEnd); + + /** + * Gets the start value of the scale. + * + * @return The start value of the scale. + * @see setScaleStart, setScale + */ + double getScaleStart() const + { return mScaleStart; } + + /** + * Sets the start value of the scale. + * + * @param scaleStart The start value of the scale. + * @see getScaleStart + */ + void setScaleStart(const double scaleStart) + { mScaleStart = scaleStart; } + + /** + * Gets the end value of the scale. + * + * @return The end value of the scale. + * @see setScaleEnd, setScale + */ + double getScaleEnd() const + { return mScaleEnd; } + + /** + * Sets the end value of the scale. + * + * @param scaleEnd The end value of the scale. + * @see getScaleEnd + */ + void setScaleEnd(const double scaleEnd) + { mScaleEnd = scaleEnd; } + + /** + * Sets the current selected value. + * + * @param value The current selected value. + * @see getValue + */ + void setValue(const double value); + + /** + * Gets the current selected value. + * + * @return The current selected value. + * @see setValue + */ + double getValue() const + { return mValue; } + + /** + * Gets the length of the marker. + * + * @return The length of the marker. + * @see setMarkerLength + */ + int getMarkerLength() const + { return mMarkerLength; } + + /** + * Sets the length of the marker. + * + * @param length The length for the marker. + * @see getMarkerLength + */ + void setMarkerLength(const int length) + { mMarkerLength = length; } + + /** + * 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(const Orientation orientation) + { mOrientation = 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 + { return mOrientation; } + + /** + * 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(const double length) + { mStepLength = 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 + { return mStepLength; } enum SLIDER_ENUM { @@ -108,10 +284,70 @@ class Slider final : public gcn::Slider */ void init(); + /** + * 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 + */ + double markerPositionToValue(const 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 + */ + int valueToMarkerPosition(const double value) const; + + /** + * Gets the marker position of the current selected value. + * + * @return The marker position of the current selected value. + */ + int getMarkerPosition() const + { return valueToMarkerPosition(getValue()); } + static ImageRect buttons[2]; static float mAlpha; static int mInstances; + + /** + * 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 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; + ImageCollection *mVertexes; + + /** + * Holds the length of the marker. + */ + int mMarkerLength; + bool mHasMouse; bool mRedraw; }; diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index d2bb24720..445f17982 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -75,19 +75,17 @@ #include "gui/widgets/scrollarea.h" #include "gui/widgets/tabs/tab.h" -#include "gui/base/widgets/container.hpp" - #include "debug.h" TabbedArea::TabbedArea(const Widget2 *const widget) : ActionListener(), - gcn::BasicContainer(widget), + BasicContainer(widget), KeyListener(), MouseListener(), WidgetListener(), mSelectedTab(nullptr), - mTabContainer(new gcn::Container(widget)), - mWidgetContainer(new gcn::Container(widget)), + mTabContainer(new BasicContainer2(widget)), + mWidgetContainer(new BasicContainer2(widget)), mTabsToDelete(), mTabs(), mTabsWidth(0), @@ -768,7 +766,7 @@ void TabbedArea::death(const Event &event) if (tab) removeTab(tab); else - gcn::BasicContainer::death(event); + BasicContainer::death(event); } void TabbedArea::selectNextTab() diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index dbaa4334b..0e7a032f0 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -70,7 +70,7 @@ #include "listeners/mouselistener.h" #include "listeners/widgetlistener.h" -#include "gui/base/widgets/container.hpp" +#include "gui/widgets/basiccontainer2.h" #include "listeners/actionlistener.h" @@ -82,7 +82,7 @@ class Tab; * A tabbed area, the same as the guichan tabbed area in 0.8, but extended */ class TabbedArea final : public ActionListener, - public gcn::BasicContainer, + public BasicContainer, public KeyListener, public MouseListener, public WidgetListener @@ -251,8 +251,8 @@ class TabbedArea final : public ActionListener, void updateTabsWidth(); Tab* mSelectedTab; - gcn::Container* mTabContainer; - gcn::Container* mWidgetContainer; + BasicContainer2* mTabContainer; + BasicContainer2* mWidgetContainer; std::vector<Tab*> mTabsToDelete; TabContainer mTabs; diff --git a/src/gui/widgets/tabs/chattab.cpp b/src/gui/widgets/tabs/chattab.cpp index fe979ae5a..8fe9d707b 100644 --- a/src/gui/widgets/tabs/chattab.cpp +++ b/src/gui/widgets/tabs/chattab.cpp @@ -72,8 +72,8 @@ ChatTab::ChatTab(const Widget2 *const widget, mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); mTextOutput->setAlwaysUpdate(false); - mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, - gcn::ScrollArea::SHOW_ALWAYS); + mScrollArea->setScrollPolicy(ScrollArea::SHOW_NEVER, + ScrollArea::SHOW_ALWAYS); mScrollArea->setScrollAmount(0, 1); if (chatWindow) diff --git a/src/gui/widgets/tabs/setup_colors.cpp b/src/gui/widgets/tabs/setup_colors.cpp index ac6bf2837..eb7e695f4 100644 --- a/src/gui/widgets/tabs/setup_colors.cpp +++ b/src/gui/widgets/tabs/setup_colors.cpp @@ -84,19 +84,19 @@ Setup_Colors::Setup_Colors(const Widget2 *const widget) : // TRANSLATORS: settings colors tab name setName(_("Colors")); mColorBox->addSelectionListener(this); - mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); mPreview->setOpaque(false); // don't do anything with links mPreview->setLinkHandler(nullptr); mPreviewBox->setHeight(20); - mPreviewBox->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, - gcn::ScrollArea::SHOW_NEVER); + mPreviewBox->setScrollPolicy(ScrollArea::SHOW_NEVER, + ScrollArea::SHOW_NEVER); mGradTypeSlider->setWidth(180); mGradTypeSlider->setActionEventId("slider_grad"); - mGradTypeSlider->setValue2(0); + mGradTypeSlider->setValue(0); mGradTypeSlider->addActionListener(this); mGradTypeSlider->setEnabled(false); @@ -128,7 +128,7 @@ Setup_Colors::Setup_Colors(const Widget2 *const widget) : mGradDelayText->setEnabled(false); mGradDelaySlider->setWidth(180); - mGradDelaySlider->setValue2(mGradDelayText->getValue()); + mGradDelaySlider->setValue(mGradDelayText->getValue()); mGradDelaySlider->setActionEventId("slider_graddelay"); mGradDelaySlider->addActionListener(this); mGradDelaySlider->setEnabled(false); @@ -139,7 +139,7 @@ Setup_Colors::Setup_Colors(const Widget2 *const widget) : mRedText->setEnabled(false); mRedSlider->setWidth(180); - mRedSlider->setValue2(mRedText->getValue()); + mRedSlider->setValue(mRedText->getValue()); mRedSlider->setActionEventId("slider_red"); mRedSlider->addActionListener(this); mRedSlider->setEnabled(false); @@ -150,7 +150,7 @@ Setup_Colors::Setup_Colors(const Widget2 *const widget) : mGreenText->setEnabled(false); mGreenSlider->setWidth(180); - mGreenSlider->setValue2(mGreenText->getValue()); + mGreenSlider->setValue(mGreenText->getValue()); mGreenSlider->setActionEventId("slider_green"); mGreenSlider->addActionListener(this); mGreenSlider->setEnabled(false); @@ -161,7 +161,7 @@ Setup_Colors::Setup_Colors(const Widget2 *const widget) : mBlueText->setEnabled(false); mBlueSlider->setWidth(180); - mBlueSlider->setValue2(mBlueText->getValue()); + mBlueSlider->setValue(mBlueText->getValue()); mBlueSlider->setActionEventId("slider_blue"); mBlueSlider->addActionListener(this); mBlueSlider->setEnabled(false); @@ -356,7 +356,7 @@ void Setup_Colors::valueChanged(const SelectionEvent &event A_UNUSED) setEntry(mGreenSlider, mGreenText, col->g); setEntry(mBlueSlider, mBlueText, col->b); - mGradTypeSlider->setValue2(grad); + mGradTypeSlider->setValue(grad); updateGradType(); mGradTypeSlider->setEnabled(true); } @@ -365,7 +365,7 @@ void Setup_Colors::setEntry(Slider *const s, TextField *const t, const int value) { if (s) - s->setValue2(value); + s->setValue(value); if (t) t->setText(toString(value)); } @@ -384,7 +384,7 @@ void Setup_Colors::cancel() userPalette->rollback(); const int type = userPalette->getColorTypeAt(mSelected); const Color *const col = &userPalette->getColor(type); - mGradTypeSlider->setValue2(userPalette->getGradientType(type)); + mGradTypeSlider->setValue(userPalette->getGradientType(type)); const int delay = userPalette->getGradientDelay(type); setEntry(mGradDelaySlider, mGradDelayText, delay); setEntry(mRedSlider, mRedText, col->r); diff --git a/src/gui/widgets/tabs/setup_players.cpp b/src/gui/widgets/tabs/setup_players.cpp index 01bb60f53..b04a25e22 100644 --- a/src/gui/widgets/tabs/setup_players.cpp +++ b/src/gui/widgets/tabs/setup_players.cpp @@ -100,5 +100,10 @@ Setup_Players::Setup_Players(const Widget2 *const widget) : new SetupItemCheckBox(_("Use special diagonal speed in players moving"), "", "useDiagonalSpeed", this, "useDiagonalSpeedEvent"); + // TRANSLATORS: settings option + new SetupItemCheckBox(_("Emulate right mouse button by long mouse click" + " (usefull for touch interfaces)"), + "", "longmouseclick", this, "longmouseclickEvent"); + setDimension(Rect(0, 0, 550, 350)); } diff --git a/src/gui/widgets/tabs/setup_relations.cpp b/src/gui/widgets/tabs/setup_relations.cpp index 1458ecd25..ca060477f 100644 --- a/src/gui/widgets/tabs/setup_relations.cpp +++ b/src/gui/widgets/tabs/setup_relations.cpp @@ -221,7 +221,7 @@ Setup_Relations::Setup_Relations(const Widget2 *const widget) : mPlayerTitleTable->setLinewiseSelection(true); - mPlayerScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mPlayerScrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); mPlayerTable->setActionEventId(ACTION_TABLE); mPlayerTable->setLinewiseSelection(true); mPlayerTable->addActionListener(this); diff --git a/src/gui/widgets/tabs/setup_video.cpp b/src/gui/widgets/tabs/setup_video.cpp index f55dceaa4..416ae8c3c 100644 --- a/src/gui/widgets/tabs/setup_video.cpp +++ b/src/gui/widgets/tabs/setup_video.cpp @@ -227,7 +227,7 @@ Setup_Video::Setup_Video(const Widget2 *const widget) : ScrollArea *const scrollArea = new ScrollArea(this, mModeList, true, "setup_video_background.xml"); scrollArea->setWidth(150); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + scrollArea->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER); mOpenGLDropDown->setSelected(renderToIndex[mOpenGLEnabled]); @@ -241,9 +241,9 @@ Setup_Video::Setup_Video(const Widget2 *const widget) : ? toString(mAltFps) : _("None"))); mAltFpsLabel->setWidth(150); mFpsSlider->setEnabled(mFps > 0); - mFpsSlider->setValue2(mFps); + mFpsSlider->setValue(mFps); mAltFpsSlider->setEnabled(mAltFps > 0); - mAltFpsSlider->setValue2(mAltFps); + mAltFpsSlider->setValue(mAltFps); mFpsCheckBox->setSelected(mFps > 0); // Pre-select the current video mode. @@ -419,9 +419,9 @@ void Setup_Video::cancel() mOpenGLDropDown->setSelected(renderToIndex[mOpenGLEnabled]); mCustomCursorCheckBox->setSelected(mCustomCursorEnabled); mFpsSlider->setEnabled(mFps > 0); - mFpsSlider->setValue2(mFps); + mFpsSlider->setValue(mFps); mAltFpsSlider->setEnabled(mAltFps > 0); - mAltFpsSlider->setValue2(mAltFps); + mAltFpsSlider->setValue(mAltFps); mFpsLabel->setCaption(mFpsCheckBox->isSelected() // TRANSLATORS: video settings label ? toString(mFps) : _("None")); @@ -542,7 +542,7 @@ void Setup_Video::action(const ActionEvent &event) mFpsLabel->setCaption(text); mFpsSlider->setEnabled(mFps > 0); - mFpsSlider->setValue2(mFps); + mFpsSlider->setValue(mFps); } else if (id == "altfpslimitslider") { @@ -556,7 +556,7 @@ void Setup_Video::action(const ActionEvent &event) // TRANSLATORS: video settings label mAltFpsLabel->setCaption(_("Alt FPS limit: ") + text); mAltFpsSlider->setEnabled(mAltFps > 0); - mAltFpsSlider->setValue2(mAltFps); + mAltFpsSlider->setValue(mAltFps); } else if (id == "enableresize") { diff --git a/src/gui/widgets/tabs/setup_visual.cpp b/src/gui/widgets/tabs/setup_visual.cpp index 9666b224a..860b1d516 100644 --- a/src/gui/widgets/tabs/setup_visual.cpp +++ b/src/gui/widgets/tabs/setup_visual.cpp @@ -203,6 +203,13 @@ Setup_Visual::Setup_Visual(const Widget2 *const widget) : new SetupItemCheckBox(_("Allow screensaver to run"), "", "allowscreensaver", this, "allowscreensaverEvent"); + + // TRANSLATORS: settings group + new SetupItemLabel(_("Screenshots"), "", this); + + new SetupItemCheckBox(_("Add water mark into screenshots"), + "", "addwatermark", this, "addwatermarkEvent"); + setDimension(Rect(0, 0, 550, 350)); } diff --git a/src/gui/widgets/tabs/tab.cpp b/src/gui/widgets/tabs/tab.cpp index 96ae76787..ede69619e 100644 --- a/src/gui/widgets/tabs/tab.cpp +++ b/src/gui/widgets/tabs/tab.cpp @@ -91,7 +91,7 @@ static std::string const data[Tab::TAB_COUNT] = Skin *Tab::tabImg[Tab::TAB_COUNT]; Tab::Tab(const Widget2 *const widget) : - gcn::BasicContainer(widget), + BasicContainer(widget), MouseListener(), WidgetListener(), mLabel(new Label(this)), diff --git a/src/gui/widgets/tabs/tab.h b/src/gui/widgets/tabs/tab.h index 1f52cde88..246d90650 100644 --- a/src/gui/widgets/tabs/tab.h +++ b/src/gui/widgets/tabs/tab.h @@ -66,7 +66,7 @@ #ifndef GUI_WIDGETS_TABS_TAB_H #define GUI_WIDGETS_TABS_TAB_H -#include "gui/base/basiccontainer.hpp" +#include "gui/widgets/basiccontainer.h" #include "listeners/mouselistener.h" #include "listeners/widgetlistener.h" @@ -81,7 +81,7 @@ class TabbedArea; /** * A tab, the same as the Guichan tab in 0.8, but extended */ -class Tab : public gcn::BasicContainer, +class Tab : public BasicContainer, public MouseListener, public WidgetListener { diff --git a/src/gui/widgets/textbox.cpp b/src/gui/widgets/textbox.cpp index a1ce0e61d..5f565259b 100644 --- a/src/gui/widgets/textbox.cpp +++ b/src/gui/widgets/textbox.cpp @@ -20,9 +20,50 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "gui/widgets/textbox.h" +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "events/keyevent.h" +#include "gui/widgets/textbox.h" #include "input/keydata.h" @@ -34,9 +75,23 @@ #include "debug.h" TextBox::TextBox(const Widget2 *const widget) : - gcn::TextBox(widget), - mMinWidth(getWidth()) + Widget(widget), + MouseListener(), + KeyListener(), + mTextRows(), + mCaretColumn(0), + mCaretRow(0), + mMinWidth(getWidth()), + mEditable(true), + mOpaque(true) { + setText(""); + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); + adjustSize(); + mForegroundColor = getThemeColor(Theme::TEXTBOX); setOpaque(false); setFrameSize(0); @@ -163,7 +218,33 @@ void TextBox::setTextWrapped(const std::string &text, const int minDimension) mMinWidth = minWidth; - gcn::TextBox::setText(wrappedStream.str()); + setText(wrappedStream.str()); +} + +void TextBox::setText(const std::string& text) +{ + mCaretColumn = 0; + mCaretRow = 0; + + mTextRows.clear(); + + size_t pos; + size_t lastPos = 0; + int length; + do + { + pos = text.find("\n", lastPos); + + if (pos != std::string::npos) + length = static_cast<int>(pos - lastPos); + else + length = static_cast<int>(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::keyPressed(KeyEvent& keyEvent) @@ -391,3 +472,156 @@ void TextBox::setForegroundColorAll(const Color &color1, mForegroundColor = color1; mForegroundColor2 = color2; } + +std::string TextBox::getText() const +{ + if (mTextRows.empty()) + return std::string(""); + + int i; + std::string text; + + const int sz = static_cast<int>(mTextRows.size()); + for (i = 0; i < sz - 1; ++ i) + text.append(mTextRows[i]).append("\n"); + text.append(mTextRows[i]); + + return text; +} + +void TextBox::setTextRow(const int row, const std::string& text) +{ + mTextRows[row] = text; + + if (mCaretRow == row) + setCaretColumn(mCaretColumn); + + adjustSize(); +} + +void TextBox::setCaretPosition(unsigned int position) +{ + for (int row = 0, sz = static_cast<int>(mTextRows.size()); + row < sz; row ++) + { + if (position <= mTextRows[row].size()) + { + mCaretRow = row; + mCaretColumn = position; + return; // we are done + } + else + { + position--; + } + } + + // position beyond end of text + mCaretRow = static_cast<int>(mTextRows.size() - 1); + mCaretColumn = static_cast<int>(mTextRows[mCaretRow].size()); +} + +void TextBox::setCaretRow(const int row) +{ + mCaretRow = row; + + const int sz = static_cast<int>(mTextRows.size()); + if (mCaretRow >= sz) + mCaretRow = sz - 1; + + if (mCaretRow < 0) + mCaretRow = 0; + + setCaretColumn(mCaretColumn); +} + +unsigned int TextBox::getCaretPosition() const +{ + int pos = 0, row; + + for (row = 0; row < mCaretRow; row++) + pos += static_cast<int>(mTextRows[row].size()); + + return pos + mCaretColumn; +} + +void TextBox::setCaretColumn(const int column) +{ + mCaretColumn = column; + + const int sz = static_cast<int>(mTextRows[mCaretRow].size()); + if (mCaretColumn > sz) + mCaretColumn = sz; + + if (mCaretColumn < 0) + mCaretColumn = 0; +} + +void TextBox::setCaretRowColumn(const int row, const int column) +{ + setCaretRow(row); + setCaretColumn(column); +} + +void TextBox::scrollToCaret() +{ + const Font *const font = getFont(); + Rect scroll; + scroll.x = font->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)); + scroll.y = font->getHeight() * mCaretRow; + scroll.width = font->getWidth(" "); + // add 2 for some extra space + scroll.height = font->getHeight() + 2; + showPart(scroll); +} + +void TextBox::addRow(const std::string &row) +{ + mTextRows.push_back(row); + adjustSize(); +} + +void TextBox::mousePressed(MouseEvent& mouseEvent) +{ + if (mouseEvent.getButton() == MouseEvent::LEFT) + { + const int height = getFont()->getHeight(); + if (!height) + return; + + mCaretRow = mouseEvent.getY() / height; + + const int sz = static_cast<int>(mTextRows.size()); + if (mCaretRow >= sz) + mCaretRow = sz - 1; + + mCaretColumn = getFont()->getStringIndexAt( + mTextRows[mCaretRow], mouseEvent.getX()); + } +} + +void TextBox::mouseDragged(MouseEvent& mouseEvent) +{ + mouseEvent.consume(); +} + +void TextBox::drawCaret(Graphics *const graphics, const int x, const int y) +{ + graphics->setColor(mForegroundColor); + graphics->drawLine(x, getFont()->getHeight() + y, x, y); +} + +void TextBox::adjustSize() +{ + int width = 0; + const Font *const font = getFont(); + for (size_t i = 0, sz = mTextRows.size(); i < sz; ++i) + { + const int w = font->getWidth(mTextRows[i]); + if (width < w) + width = w; + } + + setWidth(width + 1); + setHeight(static_cast<int>(font->getHeight() * mTextRows.size())); +} diff --git a/src/gui/widgets/textbox.h b/src/gui/widgets/textbox.h index 3f78fd247..e5cfbc7c9 100644 --- a/src/gui/widgets/textbox.h +++ b/src/gui/widgets/textbox.h @@ -20,10 +20,56 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_TEXTBOX_H #define GUI_WIDGETS_TEXTBOX_H -#include "gui/base/widgets/textbox.hpp" +#include "gui/widgets/widget.h" + +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" #include "localconsts.h" @@ -34,7 +80,9 @@ * * \ingroup GUI */ -class TextBox final : public gcn::TextBox +class TextBox final : public Widget, + public MouseListener, + public KeyListener { public: /** @@ -66,8 +114,210 @@ class TextBox final : public gcn::TextBox void setForegroundColorAll(const Color &color1, const Color &color2); + /** + * 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(const int row) const + { return mTextRows[row]; } + + /** + * 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(const 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 + { return static_cast<int>(mTextRows.size()); } + + /** + * 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 + { return mCaretRow; } + + /** + * Sets the row where the caret should be currently located. + * + * @param The row where the caret should be currently located. + * @see getCaretRow + */ + void setCaretRow(const 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(const 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(const int row, const int column); + + /** + * Scrolls the text to the caret if the text box is in a scroll area. + * + * @see ScrollArea + */ + void scrollToCaret(); + + /** + * Checks if the text box is editable. + * + * @return True it the text box is editable, false otherwise. + * @see setEditable + */ + bool isEditable() const + { return mEditable; } + + /** + * Sets the text box to be editable or not. + * + * @param editable True if the text box should be editable, false otherwise. + */ + void setEditable(const bool editable) + { mEditable = editable; } + + /** + * Adds a row of text to the end of the text. + * + * @param row The row to add. + */ + 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() const + { return mOpaque; } + + /** + * 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(const bool opaque) + { mOpaque = opaque; } + + void fontChanged() override final + { adjustSize(); } + + void mousePressed(MouseEvent& mouseEvent) override final; + + void mouseDragged(MouseEvent& mouseEvent) override final; + private: + /** + * 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. + */ + void drawCaret(Graphics *const graphics, const int x, const int y); + + /** + * Adjusts the text box's size to fit the text. + */ + 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; + int mMinWidth; + + /** + * True if the text box is editable, false otherwise. + */ + bool mEditable; + + /** + * True if the text box is editable, false otherwise. + */ + bool mOpaque; }; #endif // GUI_WIDGETS_TEXTBOX_H diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 78a2826d5..7fe8c1bf3 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -20,14 +20,55 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 "gui/widgets/textfield.h" #include "client.h" #include "input/inputmanager.h" -#include "events/keyevent.h" - #include "gui/font.h" #include "gui/gui.h" #include "gui/viewport.h" @@ -54,9 +95,13 @@ TextField::TextField(const Widget2 *restrict const widget, ActionListener *restrict const listener, const std::string &restrict eventId, const bool sendAlwaysEvents): - gcn::TextField(widget, text), + Widget(widget), FocusListener(), - mSendAlwaysEvents(sendAlwaysEvents), + KeyListener(), + MouseListener(), + mText(text), + mCaretPosition(0), + mXScroll(0), mCaretColor(&getThemeColor(Theme::CARET)), mPopupMenu(nullptr), mMinimum(0), @@ -64,8 +109,14 @@ TextField::TextField(const Widget2 *restrict const widget, mLastEventPaste(false), mPadding(1), mNumeric(false), - mLoseFocusOnTab(loseFocusOnTab) + mLoseFocusOnTab(loseFocusOnTab), + mAllowSpecialActions(true), + mSendAlwaysEvents(sendAlwaysEvents) { + setFocusable(true); + addMouseListener(this); + addKeyListener(this); + setFrameSize(2); mForegroundColor = getThemeColor(Theme::TEXTFIELD); mForegroundColor2 = getThemeColor(Theme::TEXTFIELD_OUTLINE); @@ -271,40 +322,22 @@ void TextField::keyPressed(KeyEvent &keyEvent) mLastEventPaste = 0; bool consumed(false); - handleSDLKeys(val, consumed); - - if (consumed) - { - if (mSendAlwaysEvents) - distributeActionEvent(); - - keyEvent.consume(); - fixScroll(); - return; - } #endif - if (consumed) + const int action = keyEvent.getActionId(); + if (!inputManager.isActionActive(static_cast<int>( + Input::KEY_GUI_CTRL))) { - keyEvent.consume(); + if (!handleNormalKeys(action, consumed)) + { + if (consumed) + keyEvent.consume(); + return; + } } else { - const int action = keyEvent.getActionId(); - if (!inputManager.isActionActive(static_cast<int>( - Input::KEY_GUI_CTRL))) - { - if (!handleNormalKeys(action, consumed)) - { - if (consumed) - keyEvent.consume(); - return; - } - } - else - { - handleCtrlKeys(action, consumed); - } + handleCtrlKeys(action, consumed); } if (mSendAlwaysEvents) @@ -413,16 +446,18 @@ void TextField::handleCtrlKeys(const int action, bool &consumed) consumed = true; break; } -#ifdef USE_SDL2 case Input::KEY_GUI_B: { - moveCaretBack(); - consumed = true; + if (mAllowSpecialActions) + { + moveCaretBack(); + consumed = true; + } break; } - case Input::KEY_GUI_C: + case Input::KEY_GUI_F: { - handleCopy(); + moveCaretForward(); consumed = true; break; } @@ -438,118 +473,54 @@ void TextField::handleCtrlKeys(const int action, bool &consumed) consumed = true; break; } - case Input::KEY_GUI_F: - { - moveCaretBack(); - consumed = true; - break; - } case Input::KEY_GUI_H: { deleteCharLeft(mText, &mCaretPosition); consumed = true; break; } - case Input::KEY_GUI_U: - { - caretDeleteToStart(); - consumed = true; - break; - } case Input::KEY_GUI_K: { mText = mText.substr(0, mCaretPosition); consumed = true; break; } - case Input::KEY_GUI_V: - { - handlePaste(); - consumed = true; - break; - } - case Input::KEY_GUI_W: - { - caretDeleteWord(); - consumed = true; - break; - } -#endif - default: - break; - } -} - -#ifndef USE_SDL2 -void TextField::handleSDLKeys(const int val, bool &consumed) -{ - switch (val) - { - case 2: // Ctrl+b + case Input::KEY_GUI_U: { - moveCaretBack(); + caretDeleteToStart(); consumed = true; break; } - - case 6: // Ctrl+f + case Input::KEY_GUI_C: { - moveCaretForward(); + handleCopy(); consumed = true; break; } - - case 4: // Ctrl+d + case Input::KEY_GUI_V: { - caretDelete(); - consumed = true; - break; - } - - case 8: // Ctrl+h - deleteCharLeft(mText, &mCaretPosition); - consumed = true; - break; - - case 5: // Ctrl+e - mCaretPosition = static_cast<int>(mText.size()); - consumed = true; - break; - - case 11: // Ctrl+k - mText = mText.substr(0, mCaretPosition); - consumed = true; - break; - - case 21: // Ctrl+u - caretDeleteToStart(); - consumed = true; - break; - - case 3: // Ctrl+c - handleCopy(); - consumed = true; - break; - - case 22: // Control code 22, SYNCHRONOUS IDLE, sent on Ctrl+v +#ifdef USE_SDL2 + handlePaste(); +#else // hack to prevent paste key sticking if (mLastEventPaste && mLastEventPaste > cur_time) break; handlePaste(); mLastEventPaste = cur_time + 2; +#endif consumed = true; break; - - case 23: // Ctrl+w + } + case Input::KEY_GUI_W: + { caretDeleteWord(); consumed = true; break; - + } default: break; } } -#endif void TextField::moveCaretBack() { @@ -751,9 +722,11 @@ void TextField::mousePressed(MouseEvent &mouseEvent) } } } - else + else if (mouseEvent.getButton() == MouseEvent::LEFT) { - gcn::TextField::mousePressed(mouseEvent); + mCaretPosition = getFont()->getStringIndexAt( + mText, mouseEvent.getX() + mXScroll); + fixScroll(); } } @@ -768,3 +741,16 @@ void TextField::focusGained(const Event &event A_UNUSED) void TextField::focusLost(const Event &event A_UNUSED) { } + +void TextField::setText(const std::string& text) +{ + const size_t sz = text.size(); + if (sz < mCaretPosition) + mCaretPosition = sz; + mText = text; +} + +void TextField::mouseDragged(MouseEvent& mouseEvent) +{ + mouseEvent.consume(); +} diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h index ccc1b16d6..93ae155be 100644 --- a/src/gui/widgets/textfield.h +++ b/src/gui/widgets/textfield.h @@ -20,12 +20,57 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* _______ __ __ __ ______ __ __ _______ __ __ + * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ + * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / + * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / + * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / + * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / + * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ + * + * 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 GUI_WIDGETS_TEXTFIELD_H #define GUI_WIDGETS_TEXTFIELD_H #include "listeners/focuslistener.h" +#include "listeners/keylistener.h" +#include "listeners/mouselistener.h" -#include "gui/base/widgets/textfield.hpp" +#include "gui/widgets/widget.h" #include "localconsts.h" @@ -36,8 +81,10 @@ class PopupMenu; * * \ingroup GUI */ -class TextField : public gcn::TextField, - public FocusListener +class TextField : public Widget, + public FocusListener, + public KeyListener, + public MouseListener { public: /** @@ -139,26 +186,71 @@ class TextField : public gcn::TextField, void caretDeleteWord(); + void setAllowSpecialActions(const bool b) + { mAllowSpecialActions = b; } + + std::string getTextBeforeCaret() const + { return mText.substr(0, mCaretPosition); } + + /** + * 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 + { return mText; } + + /** + * 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 + { return mCaretPosition; } + + void mouseDragged(MouseEvent& mouseEvent) override final; + protected: - void drawCaret(Graphics* graphics, int x) override final; + void drawCaret(Graphics* graphics, int x); void fixScroll(); void fontChanged(); - bool mSendAlwaysEvents; - bool handleNormalKeys(const int action, bool &consumed); void handleCtrlKeys(const int action, bool &consumed); -#ifndef USE_SDL2 - void handleSDLKeys(const int val, bool &consumed); -#endif - static Skin *mSkin; - private: + /** + * 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; + const Color *mCaretColor; PopupMenu *mPopupMenu; static int instances; @@ -170,6 +262,8 @@ class TextField : public gcn::TextField, int mPadding; bool mNumeric; bool mLoseFocusOnTab; + bool mAllowSpecialActions; + bool mSendAlwaysEvents; }; #endif // GUI_WIDGETS_TEXTFIELD_H diff --git a/src/gui/widgets/widget.h b/src/gui/widgets/widget.h index 17f016c76..3af00d247 100644 --- a/src/gui/widgets/widget.h +++ b/src/gui/widgets/widget.h @@ -196,7 +196,7 @@ class Widget : public Widget2 * has no parent. * @since 0.1.0 */ - virtual Widget* getParent() const A_WARN_UNUSED + Widget* getParent() const A_WARN_UNUSED { return mParent; } /** @@ -959,7 +959,7 @@ class Widget : public Widget2 * @param area The area to show. * @since 0.1.0 */ - virtual void showWidgetPart(Widget* widget A_UNUSED, + virtual void showWidgetPart(Widget *const widget A_UNUSED, Rect area A_UNUSED) { } diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index ec83af9a8..5a636013b 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -91,7 +91,7 @@ int Window::mouseResize = 0; Window::Window(const std::string &caption, const bool modal, Window *const parent, std::string skin) : - gcn::Container(nullptr), + BasicContainer2(nullptr), MouseListener(), WidgetListener(), mCaption(caption), @@ -668,9 +668,9 @@ void Window::setVisible(const bool visible, const bool forceSticky) mResizeHandles = 0; if (mStickyButtonLock) - gcn::Container::setVisible(visible); + BasicContainer2::setVisible(visible); else - gcn::Container::setVisible((!forceSticky && mSticky) || visible); + BasicContainer2::setVisible((!forceSticky && mSticky) || visible); if (visible) { if (mPlayVisibleSound) diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index 6369990bb..2c4ee5e5f 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -71,7 +71,7 @@ #include "listeners/mouselistener.h" #include "listeners/widgetlistener.h" -#include "gui/base/widgets/container.hpp" +#include "gui/widgets/basiccontainer2.h" #include "localconsts.h" @@ -88,7 +88,7 @@ class WindowContainer; * * \ingroup GUI */ -class Window : public gcn::Container, +class Window : public BasicContainer2, public MouseListener, private WidgetListener { @@ -498,7 +498,7 @@ class Window : public gcn::Container, * @return The title bar height. * @see setTitleBarHeight */ - unsigned int getTitleBarHeight() + unsigned int getTitleBarHeight() const { return mTitleBarHeight; } /** |