summaryrefslogtreecommitdiff
path: root/src/guichan/basiccontainer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/guichan/basiccontainer.cpp')
-rw-r--r--src/guichan/basiccontainer.cpp390
1 files changed, 390 insertions, 0 deletions
diff --git a/src/guichan/basiccontainer.cpp b/src/guichan/basiccontainer.cpp
new file mode 100644
index 000000000..85f0b1b2f
--- /dev/null
+++ b/src/guichan/basiccontainer.cpp
@@ -0,0 +1,390 @@
+/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ *
+ *
+ * Per Larsson a.k.a finalman
+ * Olof Naessén a.k.a jansem/yakslem
+ *
+ * Visit: http://guichan.sourceforge.net
+ *
+ * License: (BSD)
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Guichan nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * For comments regarding functions please see the header file.
+ */
+
+#include "guichan/basiccontainer.hpp"
+
+#include <algorithm>
+
+#include "guichan/exception.hpp"
+#include "guichan/focushandler.hpp"
+#include "guichan/graphics.hpp"
+#include "guichan/mouseinput.hpp"
+
+namespace gcn
+{
+ BasicContainer::~BasicContainer()
+ {
+ clear();
+ }
+
+ void BasicContainer::moveToTop(Widget* widget)
+ {
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ if (*iter == widget)
+ {
+ mWidgets.erase(iter);
+ mWidgets.push_back(widget);
+ return;
+ }
+ }
+
+ throw GCN_EXCEPTION("There is no such widget in this container.");
+ }
+
+ void BasicContainer::moveToBottom(Widget* widget)
+ {
+ WidgetListIterator iter;
+ iter = find(mWidgets.begin(), mWidgets.end(), widget);
+
+ if (iter == mWidgets.end())
+ {
+ throw GCN_EXCEPTION("There is no such widget in this container.");
+ }
+ mWidgets.erase(iter);
+ mWidgets.push_front(widget);
+ }
+
+ void BasicContainer::death(const Event& event)
+ {
+ WidgetListIterator iter;
+ iter = find(mWidgets.begin(), mWidgets.end(), event.getSource());
+
+ if (iter == mWidgets.end())
+ {
+ throw GCN_EXCEPTION("There is no such widget in this container.");
+ }
+
+ mWidgets.erase(iter);
+ }
+
+ Rectangle BasicContainer::getChildrenArea()
+ {
+ return Rectangle(0, 0, getWidth(), getHeight());
+ }
+
+ void BasicContainer::focusNext()
+ {
+ WidgetListIterator it;
+
+ for (it = mWidgets.begin(); it != mWidgets.end(); it++)
+ {
+ if ((*it)->isFocused())
+ {
+ break;
+ }
+ }
+
+ WidgetListIterator end = it;
+
+ if (it == mWidgets.end())
+ {
+ it = mWidgets.begin();
+ }
+
+ it++;
+
+ for ( ; it != end; it++)
+ {
+ if (it == mWidgets.end())
+ {
+ it = mWidgets.begin();
+ }
+
+ if ((*it)->isFocusable())
+ {
+ (*it)->requestFocus();
+ return;
+ }
+ }
+ }
+
+ void BasicContainer::focusPrevious()
+ {
+ WidgetListReverseIterator it;
+
+ for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++)
+ {
+ if ((*it)->isFocused())
+ {
+ break;
+ }
+ }
+
+ WidgetListReverseIterator end = it;
+
+ it++;
+
+ if (it == mWidgets.rend())
+ {
+ it = mWidgets.rbegin();
+ }
+
+ for ( ; it != end; it++)
+ {
+ if (it == mWidgets.rend())
+ {
+ it = mWidgets.rbegin();
+ }
+
+ if ((*it)->isFocusable())
+ {
+ (*it)->requestFocus();
+ return;
+ }
+ }
+ }
+
+ Widget *BasicContainer::getWidgetAt(int x, int y)
+ {
+ Rectangle r = getChildrenArea();
+
+ if (!r.isPointInRect(x, y))
+ {
+ return NULL;
+ }
+
+ x -= r.x;
+ y -= r.y;
+
+ WidgetListReverseIterator it;
+ for (it = mWidgets.rbegin(); it != mWidgets.rend(); it++)
+ {
+ if ((*it)->isVisible() && (*it)->getDimension().isPointInRect(x, y))
+ {
+ return (*it);
+ }
+ }
+
+ return NULL;
+ }
+
+ void BasicContainer::logic()
+ {
+ logicChildren();
+ }
+
+ void BasicContainer::_setFocusHandler(FocusHandler* focusHandler)
+ {
+ Widget::_setFocusHandler(focusHandler);
+
+ if (mInternalFocusHandler != NULL)
+ {
+ return;
+ }
+
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ (*iter)->_setFocusHandler(focusHandler);
+ }
+ }
+
+ void BasicContainer::add(Widget* widget)
+ {
+ mWidgets.push_back(widget);
+
+ if (mInternalFocusHandler == NULL)
+ {
+ widget->_setFocusHandler(_getFocusHandler());
+ }
+ else
+ {
+ widget->_setFocusHandler(mInternalFocusHandler);
+ }
+
+ widget->_setParent(this);
+ widget->addDeathListener(this);
+ }
+
+ void BasicContainer::remove(Widget* widget)
+ {
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ if (*iter == widget)
+ {
+ mWidgets.erase(iter);
+ widget->_setFocusHandler(NULL);
+ widget->_setParent(NULL);
+ widget->removeDeathListener(this);
+ return;
+ }
+ }
+
+ throw GCN_EXCEPTION("There is no such widget in this container.");
+ }
+
+ void BasicContainer::clear()
+ {
+ WidgetListIterator iter;
+
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ (*iter)->_setFocusHandler(NULL);
+ (*iter)->_setParent(NULL);
+ (*iter)->removeDeathListener(this);
+ }
+
+ mWidgets.clear();
+ }
+
+ void BasicContainer::drawChildren(Graphics* graphics)
+ {
+ graphics->pushClipArea(getChildrenArea());
+
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ if ((*iter)->isVisible())
+ {
+ // If the widget has a frame,
+ // draw it before drawing the widget
+ if ((*iter)->getFrameSize() > 0)
+ {
+ Rectangle rec = (*iter)->getDimension();
+ rec.x -= (*iter)->getFrameSize();
+ rec.y -= (*iter)->getFrameSize();
+ rec.width += 2 * (*iter)->getFrameSize();
+ rec.height += 2 * (*iter)->getFrameSize();
+ graphics->pushClipArea(rec);
+ (*iter)->drawFrame(graphics);
+ graphics->popClipArea();
+ }
+
+ graphics->pushClipArea((*iter)->getDimension());
+ (*iter)->draw(graphics);
+ graphics->popClipArea();
+ }
+ }
+
+ graphics->popClipArea();
+ }
+
+ void BasicContainer::logicChildren()
+ {
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ (*iter)->logic();
+ }
+ }
+
+ void BasicContainer::showWidgetPart(Widget* widget, Rectangle area)
+ {
+ Rectangle widgetArea = getChildrenArea();
+
+ area.x += widget->getX();
+ area.y += widget->getY();
+
+ if (area.x + area.width > widgetArea.width)
+ {
+ widget->setX(widget->getX() - area.x - area.width + widgetArea.width);
+ }
+
+ if (area.y + area.height > widgetArea.height)
+ {
+ widget->setY(widget->getY() - area.y - area.height + widgetArea.height);
+ }
+
+ if (area.x < 0)
+ {
+ widget->setX(widget->getX() - area.x);
+ }
+
+ if (area.y < 0)
+ {
+ widget->setY(widget->getY() - area.y);
+ }
+ }
+
+
+ void BasicContainer::setInternalFocusHandler(FocusHandler* focusHandler)
+ {
+ Widget::setInternalFocusHandler(focusHandler);
+
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ if (mInternalFocusHandler == NULL)
+ {
+ (*iter)->_setFocusHandler(_getFocusHandler());
+ }
+ else
+ {
+ (*iter)->_setFocusHandler(mInternalFocusHandler);
+ }
+ }
+ }
+
+ Widget* BasicContainer::findWidgetById(const std::string& id)
+ {
+ WidgetListIterator iter;
+ for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++)
+ {
+ if ((*iter)->getId() == id)
+ {
+ return (*iter);
+ }
+
+ BasicContainer *basicContainer = dynamic_cast<BasicContainer*>(*iter);
+
+ if (basicContainer != NULL)
+ {
+ Widget *widget = basicContainer->findWidgetById(id);
+
+ if (widget != NULL)
+ {
+ return widget;
+ }
+ }
+ }
+
+ return NULL;
+ }
+}