From 3a3e955d71690f0b971eb5ca8c19f34e56323331 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 22:14:49 +0200 Subject: [PATCH 1/6] Apply Guichan's changes from 4335d513e97c1f01f8bba5487932d1d5309459ca (Sept 23th 2008) http://code.google.com/p/guichan/issues/detail?id=82 --- ChangeLog | 5 + TODO | 2 +- include/guisan/widget.hpp | 168 +++++++++--- include/guisan/widgets/container.hpp | 5 +- include/guisan/widgets/dropdown.hpp | 14 +- include/guisan/widgets/scrollarea.hpp | 6 +- include/guisan/widgets/tab.hpp | 6 +- include/guisan/widgets/tabbedarea.hpp | 6 +- src/gui.cpp | 156 +++-------- src/rectangle.cpp | 2 +- src/widget.cpp | 358 +++++++++++++++++++++++++- src/widgets/container.cpp | 19 +- src/widgets/dropdown.cpp | 4 +- src/widgets/messagebox.cpp | 2 +- src/widgets/scrollarea.cpp | 16 +- src/widgets/tab.cpp | 2 - src/widgets/tabbedarea.cpp | 4 +- src/widgets/window.cpp | 4 +- 18 files changed, 551 insertions(+), 228 deletions(-) diff --git a/ChangeLog b/ChangeLog index 69e5c54..e02509b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ Version 1.1.0 ============= +* BasicContainer and Widget has been merged making every Widget + a possible container. The merge makes it a lot easier to + implement container widgets. With the merge there is no need + for container widgets to explicitly call drawChildren and + logicChildren as that is now handled automatically by Widget. * Rectangle has been enhanced with methods for adding rectangles, getting the intersection between rectangles and checking if a rectangle contains another rectangle. diff --git a/TODO b/TODO index 9ff0acf..cdc2290 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from 4335d513e97c1f01f8bba5487932d1d5309459ca +* Continue rebasing from cdd764791c06f6fcb4d1af4b23619f5ed6bba55a * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/include/guisan/widget.hpp b/include/guisan/widget.hpp index 5ebce37..843344d 100644 --- a/include/guisan/widget.hpp +++ b/include/guisan/widget.hpp @@ -61,13 +61,12 @@ #include #include "guisan/color.hpp" +#include "guisan/deathlistener.hpp" #include "guisan/rectangle.hpp" namespace gcn { class ActionListener; - class BasicContainer; - class DeathListener; class DefaultFont; class FocusHandler; class FocusListener; @@ -90,7 +89,7 @@ namespace gcn * @author Per Larsson. * @since 0.1.0 */ - class GCN_CORE_DECLSPEC Widget + class GCN_CORE_DECLSPEC Widget : public DeathListener { public: /** @@ -106,13 +105,21 @@ namespace gcn virtual ~Widget(); /** - * Draws the widget. It is called by the parent widget when it is time - * for the widget to draw itself. The graphics object is set up so - * that all drawing is relative to the widget, i.e coordinate (0,0) is - * the top left corner of the widget. It is not possible to draw - * outside of a widget's dimension. + * Draws the widget. + * The call to draw is initiated by the widget's parent. + * The graphics object is set up so that all drawing is relative + * to the widget, i.e coordinate (0,0) is the top left corner of the widget. + * It is not possible to draw outside of a widget's dimension. + * If a widget has children, the parent's draw function will always + * be called before the children's draw functions are called. + * + * NOTE: A widget with children won't draw its children unless + * the children area given by Widget::getChildrenArea returns a + * non-empty rectangle inside the widgets dimension. The children + * area is considered relative to the widget's position. * * @param graphics A graphics object to draw with. + * @see getChildrenArea * @since 0.1.0 */ virtual void draw(Graphics* graphics) = 0; @@ -191,7 +198,7 @@ namespace gcn /** * Gets the top widget, or top parent, of this widget. * - * @return The top widget, or top parent, of this widget. + * @return The top widget, or top parent, for this widget. * NULL if no top widget exists * (that is this widget doesn't have a parent). * @since 1.1.0 @@ -461,19 +468,48 @@ namespace gcn /** * Requests focus for the widget. A widget will only recieve focus * if it is focusable. + * + * @since 0.1.0 */ virtual void requestFocus(); /** * Requests a move to the top in the parent widget. + * + * @since 0.1.0 */ virtual void requestMoveToTop(); /** * Requests a move to the bottom in the parent widget. + * + * @since 0.1.0 */ virtual void requestMoveToBottom(); + /** + * Called whenever a widget should draw itself. The function will + * set up clip areas and call the draw function for this widget + * and for all its children. + * + * WARNING: This function is used internally and should not + * be called or overloaded unless you know what you + * are doing. + * @since 1.1.0 + */ + virtual void _draw(Graphics* graphics); + + /** + * Called whenever a widget should perform logic. The function will + * call the logic function for this widget and for all its children. + * + * WARNING: This function is used internally and should not + * be called or overloaded unless you know what you + * are doing. + * @since 1.1.0 + */ + virtual void _logic(); + /** * Sets the focus handler to be used. * @@ -881,6 +917,11 @@ namespace gcn * method is used when drawing children of a widget when computing * clip rectangles for the children. * + * NOTE: The returned rectangle should be relative to the widget, + * i.e a rectangle with x and y coordinate (0,0) and with + * width and height the same as the widget will let the + * children draw themselves in the whole widget. + * * An example of a widget that overloads this method is ScrollArea. * A ScrollArea has a view of its contant and that view is the * children area. The size of a ScrollArea's children area might @@ -888,10 +929,7 @@ namespace gcn * or not. * * @return The area of the widget occupied by the widget's children. - * @see BasicContainer - * @see BasicContainer::getChildrenArea - * @see BasicContainer::drawChildren - * @since 0.1.0 + * @since 0.5.0 */ virtual Rectangle getChildrenArea(); @@ -920,25 +958,25 @@ namespace gcn * Moves a widget to the top of this widget. The moved widget will be * drawn above all other widgets in this widget. * - * This method is safe to call at any times. + * This method is safe to call at any time. * * @param widget The widget to move to the top. * @see moveToBottom * @since 0.1.0 */ - virtual void moveToTop(Widget* widget) {} + virtual void moveToTop(Widget* widget); /** * Moves a widget in this widget to the bottom of this widget. * The moved widget will be drawn below all other widgets in this widget. * - * This method is safe to call at any times. + * This method is safe to call at any time. * * @param widget The widget to move to the bottom. * @see moveToTop * @since 0.1.0 */ - virtual void moveToBottom(Widget* widget) {} + virtual void moveToBottom(Widget* widget); /** * Focuses the next widget in the widget. @@ -946,7 +984,7 @@ namespace gcn * @see moveToBottom * @since 0.1.0 */ - virtual void focusNext() {} + virtual void focusNext(); /** * Focuses the previous widget in the widget. @@ -954,7 +992,7 @@ namespace gcn * @see moveToBottom * @since 0.1.0 */ - virtual void focusPrevious() {} + virtual void focusPrevious(); /** * Tries to show a specific part of a widget by moving it. Used if the @@ -964,7 +1002,7 @@ namespace gcn * @param area The area to show. * @since 0.1.0 */ - virtual void showWidgetPart(Widget* widget, Rectangle area) {} + virtual void showWidgetPart(Widget* widget, Rectangle area); /** * Sets an id of a widget. An id can be useful if a widget needs to be @@ -1002,6 +1040,10 @@ namespace gcn */ virtual void showPart(Rectangle rectangle); + // Inherited from DeathListener + + void death(const Event& event); + protected: /** * Distributes an action event to all action listeners @@ -1029,7 +1071,6 @@ namespace gcn * Distributes hidden events to all of the widget's listeners. * * @since 0.8.0 - * @author Olof Naessén */ void distributeHiddenEvent(); @@ -1037,51 +1078,93 @@ namespace gcn * Distributes shown events to all of the widget's listeners. * * @since 0.8.0 - * @author Olof Naessén */ void distributeShownEvent(); - typedef std::list MouseListenerList; - typedef MouseListenerList::iterator MouseListenerIterator; + /** + * Adds a child to the widget. + * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * + * @param widget The widget to add. + * @see remove, clear + * @since 1.1.0 + */ + void add(Widget* widget); + + /** + * Removes a child from the widget. + * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * + * @param widget The widget to remove. + * @see add, clear + * @since 1.1.0 + */ + virtual void remove(Widget* widget); + + /** + * Clears the widget from all its children. + * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * + * @see remove, clear + * @since 1.1.0 + */ + virtual void clear(); + + /** + * 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. + * + * @since 1.1.0 + */ + virtual Widget* findWidgetById(const std::string& id); + + /** + * Resizes the widget to fit it's children exactly. + * + * @since 1.1.0 + */ + void resizeToChildren(); + /** * Holds the mouse listeners of the widget. */ - MouseListenerList mMouseListeners; + std::list mMouseListeners; - typedef std::list KeyListenerList; /** * Holds the key listeners of the widget. */ - KeyListenerList mKeyListeners; - typedef KeyListenerList::iterator KeyListenerIterator; + std::list mKeyListeners; - typedef std::list ActionListenerList; /** * Holds the action listeners of the widget. */ - ActionListenerList mActionListeners; - typedef ActionListenerList::iterator ActionListenerIterator; + std::list mActionListeners; - typedef std::list DeathListenerList; /** * Holds the death listeners of the widget. */ - DeathListenerList mDeathListeners; - typedef DeathListenerList::iterator DeathListenerIterator; + std::list mDeathListeners; - typedef std::list FocusListenerList; /** * Holds the focus listeners of the widget. */ - FocusListenerList mFocusListeners; - typedef FocusListenerList::iterator FocusListenerIterator; + std::list mFocusListeners; - typedef std::list WidgetListenerList; /** * Holds the widget listeners of the widget. */ - WidgetListenerList mWidgetListeners; - typedef WidgetListenerList::iterator WidgetListenerIterator; + std::list mWidgetListeners; /** * Holds the foreground color of the widget. @@ -1170,6 +1253,11 @@ namespace gcn */ Font* mCurrentFont; + /** + * Holds all children of the widget. + */ + std::list mChildren; + /** * Holds the default font used by the widget. */ diff --git a/include/guisan/widgets/container.hpp b/include/guisan/widgets/container.hpp index d730a8a..6fb6d50 100644 --- a/include/guisan/widgets/container.hpp +++ b/include/guisan/widgets/container.hpp @@ -59,10 +59,10 @@ #include -#include "guisan/basiccontainer.hpp" #include "guisan/containerlistener.hpp" #include "guisan/graphics.hpp" #include "guisan/platform.hpp" +#include "guisan/widget.hpp" namespace gcn { @@ -74,7 +74,7 @@ namespace gcn * * @see Gui::setTop */ - class GCN_CORE_DECLSPEC Container: public BasicContainer + class GCN_CORE_DECLSPEC Container: public Widget { public: @@ -194,6 +194,7 @@ namespace gcn virtual void draw(Graphics* graphics); + virtual Rectangle getChildrenArea(); protected: /** diff --git a/include/guisan/widgets/dropdown.hpp b/include/guisan/widgets/dropdown.hpp index 1e4ec85..4e6fb72 100644 --- a/include/guisan/widgets/dropdown.hpp +++ b/include/guisan/widgets/dropdown.hpp @@ -58,20 +58,20 @@ #define GCN_DROPDOWN_HPP #include "guisan/actionlistener.hpp" -#include "guisan/basiccontainer.hpp" -#include "guisan/deathlistener.hpp" #include "guisan/focushandler.hpp" #include "guisan/focuslistener.hpp" #include "guisan/keylistener.hpp" -#include "guisan/listmodel.hpp" #include "guisan/mouselistener.hpp" #include "guisan/platform.hpp" #include "guisan/selectionlistener.hpp" -#include "guisan/widgets/listbox.hpp" -#include "guisan/widgets/scrollarea.hpp" +#include "guisan/widget.hpp" namespace gcn { + class ListBox; + class ListModel; + class ScrollArea; + /** * An implementation of a drop downable list from which an item can be * selected. The drop down consists of an internal ScrollArea and an @@ -90,11 +90,11 @@ namespace gcn */ class GCN_CORE_DECLSPEC DropDown : public ActionListener, - public BasicContainer, public KeyListener, public MouseListener, public FocusListener, - public SelectionListener + public SelectionListener, + public Widget { public: /** diff --git a/include/guisan/widgets/scrollarea.hpp b/include/guisan/widgets/scrollarea.hpp index abb9f19..0d87324 100644 --- a/include/guisan/widgets/scrollarea.hpp +++ b/include/guisan/widgets/scrollarea.hpp @@ -57,9 +57,9 @@ #ifndef GCN_SCROLLAREA_HPP #define GCN_SCROLLAREA_HPP -#include "guisan/basiccontainer.hpp" #include "guisan/mouselistener.hpp" #include "guisan/platform.hpp" +#include "guisan/widget.hpp" namespace gcn { @@ -73,8 +73,8 @@ namespace gcn * ScrollArea. */ class GCN_CORE_DECLSPEC ScrollArea: - public BasicContainer, - public MouseListener + public MouseListener, + public Widget { public: /** diff --git a/include/guisan/widgets/tab.hpp b/include/guisan/widgets/tab.hpp index a39ec73..12237ca 100644 --- a/include/guisan/widgets/tab.hpp +++ b/include/guisan/widgets/tab.hpp @@ -60,9 +60,9 @@ #include #include -#include "guisan/basiccontainer.hpp" #include "guisan/mouselistener.hpp" #include "guisan/platform.hpp" +#include "guisan/widget.hpp" namespace gcn { @@ -76,8 +76,8 @@ namespace gcn * @since 0.8.0 */ class GCN_CORE_DECLSPEC Tab: - public BasicContainer, - public MouseListener + public MouseListener, + public Widget { public: diff --git a/include/guisan/widgets/tabbedarea.hpp b/include/guisan/widgets/tabbedarea.hpp index 64fa111..7a0811d 100644 --- a/include/guisan/widgets/tabbedarea.hpp +++ b/include/guisan/widgets/tabbedarea.hpp @@ -62,10 +62,10 @@ #include #include "guisan/actionlistener.hpp" -#include "guisan/basiccontainer.hpp" #include "guisan/keylistener.hpp" #include "guisan/mouselistener.hpp" #include "guisan/platform.hpp" +#include "guisan/widget.hpp" namespace gcn { @@ -80,9 +80,9 @@ namespace gcn */ class GCN_CORE_DECLSPEC TabbedArea: public ActionListener, - public BasicContainer, public KeyListener, - public MouseListener + public MouseListener, + public Widget { friend class Tab; diff --git a/src/gui.cpp b/src/gui.cpp index 51b6488..1d4710a 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -6,11 +6,11 @@ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ * - * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson + * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson * * Js_./ * Per Larsson a.k.a finalman _RqZ{a<^_aa - * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a// + * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a// * _Qhm`] _f "'c 1!5m * Visit: http://guichan.darkbits.org )Qk

logic(); + mTop->_logic(); } void Gui::draw() @@ -181,25 +180,7 @@ namespace gcn } mGraphics->_beginDraw(); - - // If top has a frame, - // draw it before drawing top - if (mTop->getFrameSize() > 0) - { - Rectangle rec = mTop->getDimension(); - rec.x -= mTop->getFrameSize(); - rec.y -= mTop->getFrameSize(); - rec.width += 2 * mTop->getFrameSize(); - rec.height += 2 * mTop->getFrameSize(); - mGraphics->pushClipArea(rec); - mTop->drawFrame(mGraphics); - mGraphics->popClipArea(); - } - - mGraphics->pushClipArea(mTop->getDimension()); - mTop->draw(mGraphics); - mGraphics->popClipArea(); - + mTop->_draw(mGraphics); mGraphics->_endDraw(); } @@ -231,37 +212,25 @@ namespace gcn void Gui::handleMouseInput() { while (!mInput->isMouseQueueEmpty()) - { - MouseInput mouseInput = mInput->dequeueMouseInput(); - - switch (mouseInput.getType()) - { - case MouseInput::Pressed: - handleMousePressed(mouseInput); - break; - case MouseInput::Released: - handleMouseReleased(mouseInput); - break; - case MouseInput::Moved: - handleMouseMoved(mouseInput); - break; - case MouseInput::WheelMovedDown: - handleMouseWheelMovedDown(mouseInput); - break; - case MouseInput::WheelMovedUp: - handleMouseWheelMovedUp(mouseInput); - break; - default: - throw GCN_EXCEPTION("Unknown mouse input type."); - break; - } - - // Save the current mouse state. It's needed to send - // mouse exited events and mouse entered events when - // the mouse exits a widget and when a widget releases - // modal mouse input focus. - mLastMouseX = mouseInput.getX(); - mLastMouseY = mouseInput.getY(); + { + MouseInput mouseInput = mInput->dequeueMouseInput(); + + switch (mouseInput.getType()) + { + case MouseInput::Pressed: handleMousePressed(mouseInput); break; + case MouseInput::Released: handleMouseReleased(mouseInput); break; + case MouseInput::Moved: handleMouseMoved(mouseInput); break; + case MouseInput::WheelMovedDown: handleMouseWheelMovedDown(mouseInput); break; + case MouseInput::WheelMovedUp: handleMouseWheelMovedUp(mouseInput); break; + default: throw GCN_EXCEPTION("Unknown mouse input type."); break; + } + + // Save the current mouse state. It's needed to send + // mouse exited events and mouse entered events when + // the mouse exits a widget and when a widget releases + // modal mouse input focus. + mLastMouseX = mouseInput.getX(); + mLastMouseY = mouseInput.getY(); } } @@ -342,7 +311,7 @@ namespace gcn mFocusHandler->tabNext(); } } - } // end while + } } void Gui::handleMouseMoved(const MouseInput& mouseInput) @@ -429,73 +398,6 @@ namespace gcn } } } - /* - // Check all widgets below the mouse to see if they are - // present in the "widget with mouse" queue. If a widget - // is not then it should be added and an entered event should - // be sent to it. - Widget* parent = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); - Widget* widget = parent; - - // If a widget has modal mouse input focus then it will - // always be returned from getMouseEventSource, but we only want to send - // mouse entered events if the mouse has actually entered the widget with - // modal mouse input focus, hence we need to check if that's the case. If - // it's not we should simply ignore to send any mouse entered events. - if (mFocusHandler->getModalMouseInputFocused() != NULL - && widget == mFocusHandler->getModalMouseInputFocused() - && Widget::widgetExists(widget)) - { - int x, y; - widget->getAbsolutePosition(x, y); - - if (x > mouseInput.getX() - || y > mouseInput.getY() - || x + widget->getWidth() <= mouseInput.getX() - || y + widget->getHeight() <= mouseInput.getY()) - { - parent = NULL; - } - } - - while (parent != NULL) - { - parent = (Widget*)widget->getParent(); - - // Check if the widget is present in the "widget with mouse" queue. - bool widgetIsPresentInQueue = false; - std::deque::iterator iter; - for (iter = mWidgetWithMouseQueue.begin(); - iter != mWidgetWithMouseQueue.end(); - iter++) - { - if (*iter == widget) - { - widgetIsPresentInQueue = true; - break; - } - } - - // Widget is not present, send an entered event and add - // it to the "widget with mouse" queue. - if (!widgetIsPresentInQueue - && Widget::widgetExists(widget)) - { - distributeMouseEvent(widget, - MouseEvent::Entered, - mouseInput.getButton(), - mouseInput.getX(), - mouseInput.getY(), - true, - true); - mWidgetWithMouseQueue.push_front(widget); - } - - Widget* swap = widget; - widget = parent; - parent = (Widget*)swap->getParent(); - } - */ if (mFocusHandler->getDraggedWidget() != NULL) { distributeMouseEvent(mFocusHandler->getDraggedWidget(), @@ -749,7 +651,7 @@ namespace gcn break; } - parent = (Widget*)widget->getParent(); + parent = widget->getParent(); if (widget->isEnabled() || force) { @@ -808,7 +710,7 @@ namespace gcn Widget* swap = widget; widget = parent; - parent = (Widget*)swap->getParent(); + parent = swap->getParent(); // If a non modal focused widget has been reach // and we have modal focus cancel the distribution. @@ -856,7 +758,7 @@ namespace gcn break; } - parent = (Widget*)widget->getParent(); + parent = widget->getParent(); if (widget->isEnabled()) { @@ -884,7 +786,7 @@ namespace gcn Widget* swap = widget; widget = parent; - parent = (Widget*)swap->getParent(); + parent = swap->getParent(); // If a non modal focused widget has been reach // and we have modal focus cancel the distribution. diff --git a/src/rectangle.cpp b/src/rectangle.cpp index fceca5c..8d1328d 100644 --- a/src/rectangle.cpp +++ b/src/rectangle.cpp @@ -142,7 +142,7 @@ namespace gcn bool Rectangle::isEmpty() const { - return width < 0 || height < 0; + return width <= 0 || height <= 0; } Rectangle Rectangle::operator+(const Rectangle& rh) const diff --git a/src/widget.cpp b/src/widget.cpp index 8bcd035..76d3027 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -75,6 +75,8 @@ #include "guisan/mouselistener.hpp" #include "guisan/widgetlistener.hpp" +#include + namespace gcn { Font* Widget::mGlobalFont = NULL; @@ -102,12 +104,17 @@ namespace gcn Widget::~Widget() { - DeathListenerIterator iter; + std::list::const_iterator childrenIter; + for (childrenIter = mChildren.begin(); childrenIter != mChildren.end(); childrenIter++) + { + (*childrenIter)->removeDeathListener(this); + } - for (iter = mDeathListeners.begin(); iter != mDeathListeners.end(); ++iter) + std::list::const_iterator deathIter; + for (deathIter = mDeathListeners.begin(); deathIter != mDeathListeners.end(); ++deathIter) { Event event(this); - (*iter)->death(event); + (*deathIter)->death(event); } _setFocusHandler(NULL); @@ -392,6 +399,20 @@ namespace gcn } mFocusHandler = focusHandler; + + if (mInternalFocusHandler != NULL) + { + return; + } + + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + if (widgetExists(*iter)) + { + (*iter)->_setFocusHandler(focusHandler); + } + } } FocusHandler* Widget::_getFocusHandler() @@ -514,9 +535,7 @@ namespace gcn bool Widget::widgetExists(const Widget* widget) { - bool result = false; - - std::list::iterator iter; + std::list::const_iterator iter; for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) { if (*iter == widget) @@ -525,7 +544,7 @@ namespace gcn } } - return result; + return false; } bool Widget::isTabInEnabled() const @@ -639,6 +658,25 @@ namespace gcn Widget *Widget::getWidgetAt(int x, int y) { + Rectangle r = getChildrenArea(); + + if (!r.isContaining(x, y)) + { + return NULL; + } + + x -= r.x; + y -= r.y; + + std::list::const_reverse_iterator iter; + for (iter = mChildren.rbegin(); iter != mChildren.rend(); iter++) + { + Widget* widget = (*iter); + if (widget->isVisible() && widget->getDimension().isContaining(x, y)) + { + return widget; + } + } return NULL; } @@ -670,6 +708,19 @@ namespace gcn void Widget::setInternalFocusHandler(FocusHandler* focusHandler) { mInternalFocusHandler = focusHandler; + + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + if (mInternalFocusHandler == NULL) + { + (*iter)->_setFocusHandler(_getFocusHandler()); + } + else + { + (*iter)->_setFocusHandler(mInternalFocusHandler); + } + } } void Widget::setId(const std::string& id) @@ -684,7 +735,7 @@ namespace gcn void Widget::distributeResizedEvent() { - WidgetListenerIterator iter; + std::list::const_iterator iter; for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) { @@ -695,7 +746,7 @@ namespace gcn void Widget::distributeMovedEvent() { - WidgetListenerIterator iter; + std::list::const_iterator iter; for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) { @@ -706,7 +757,7 @@ namespace gcn void Widget::distributeHiddenEvent() { - WidgetListenerIterator iter; + std::list::const_iterator iter; for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) { @@ -717,7 +768,7 @@ namespace gcn void Widget::distributeActionEvent() { - ActionListenerIterator iter; + std::list::const_iterator iter; for (iter = mActionListeners.begin(); iter != mActionListeners.end(); ++iter) { ActionEvent actionEvent(this, mActionEventId); @@ -727,7 +778,7 @@ namespace gcn void Widget::distributeShownEvent() { - WidgetListenerIterator iter; + std::list::const_iterator iter; for (iter = mWidgetListeners.begin(); iter != mWidgetListeners.end(); ++iter) { @@ -762,6 +813,287 @@ namespace gcn std::list Widget::getWidgetsIn(const Rectangle& area, Widget* ignore) { - return std::list(); + std::list result; + + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + Widget* widget = (*iter); + if (ignore != widget && widget->getDimension().isIntersecting(area)) + { + result.push_back(widget); + } + } + + return result; + } + + void Widget::resizeToChildren() + { + int w = 0, h = 0; + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + Widget* widget = (*iter); + if (widget->getX() + widget->getWidth() > w) + { + w = widget->getX() + widget->getWidth(); + } + + if (widget->getY() + widget->getHeight() > h) + { + h = widget->getY() + widget->getHeight(); + } + } + + setSize(w, h); + } + + Widget* Widget::findWidgetById(const std::string& id) + { + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + Widget* widget = (*iter); + + if (widget->getId() == id) + { + return widget; + } + + Widget* child = widget->findWidgetById(id); + + if (child != NULL) + { + return child; + } + } + + return NULL; + } + + void Widget::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 Widget::clear() + { + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + Widget* widget = (*iter); + widget->_setFocusHandler(NULL); + widget->_setParent(NULL); + widget->removeDeathListener(this); + } + + mChildren.clear(); + } + + void Widget::remove(Widget* widget) + { + std::list::iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + if (*iter == widget) + { + mChildren.erase(iter); + widget->_setFocusHandler(NULL); + widget->_setParent(NULL); + widget->removeDeathListener(this); + return; + } + } + + throw GCN_EXCEPTION("There is no such widget in this container."); + } + + void Widget::add(Widget* widget) + { + mChildren.push_back(widget); + + if (mInternalFocusHandler == NULL) + { + widget->_setFocusHandler(_getFocusHandler()); + } + else + { + widget->_setFocusHandler(mInternalFocusHandler); + } + + widget->_setParent(this); + widget->addDeathListener(this); + } + + void Widget::moveToTop(Widget* widget) + { + std::list::iterator iter; + iter = std::find(mChildren.begin(), mChildren.end(), widget); + + if (iter == mChildren.end()) + { + throw GCN_EXCEPTION("There is no such widget in this widget."); + } + + mChildren.remove(widget); + mChildren.push_back(widget); + } + + void Widget::moveToBottom(Widget* widget) + { + std::list::iterator iter; + iter = find(mChildren.begin(), mChildren.end(), widget); + + if (iter == mChildren.end()) + { + throw GCN_EXCEPTION("There is no such widget in this widget."); + } + + mChildren.remove(widget); + mChildren.push_front(widget); + } + + void Widget::focusNext() + { + std::list::const_iterator iter; + + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + if ((*iter)->isFocused()) + { + break; + } + } + + std::list::const_iterator end = iter; + + if (iter == mChildren.end()) + { + iter = mChildren.begin(); + } + + iter++; + + for (; iter != end; iter++) + { + if (iter == mChildren.end()) + { + iter = mChildren.begin(); + } + + if ((*iter)->isFocusable()) + { + (*iter)->requestFocus(); + return; + } + } + } + + void Widget::focusPrevious() + { + std::list::const_reverse_iterator iter; + + for (iter = mChildren.rbegin(); iter != mChildren.rend(); iter++) + { + if ((*iter)->isFocused()) + { + break; + } + } + + std::list::const_reverse_iterator end = iter; + iter++; + + if (iter == mChildren.rend()) + { + iter = mChildren.rbegin(); + } + + for (; iter != end; iter++) + { + if (iter == mChildren.rend()) + { + iter = mChildren.rbegin(); + } + + if ((*iter)->isFocusable()) + { + (*iter)->requestFocus(); + return; + } + } + } + + void Widget::_draw(Graphics* graphics) + { + if (mBorderSize > 0) + { + Rectangle rec = mDimension; + rec.x -= mBorderSize; + rec.y -= mBorderSize; + rec.width += 2 * mBorderSize; + rec.height += 2 * mBorderSize; + graphics->pushClipArea(rec); + drawFrame(graphics); + graphics->popClipArea(); + } + + graphics->pushClipArea(mDimension); + draw(graphics); + + graphics->pushClipArea(getChildrenArea()); + + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + Widget* widget = (*iter); + if (widget->isVisible()) + { + widget->_draw(graphics); + } + } + + graphics->popClipArea(); + graphics->popClipArea(); + } + + void Widget::_logic() + { + logic(); + + std::list::const_iterator iter; + for (iter = mChildren.begin(); iter != mChildren.end(); iter++) + { + (*iter)->_logic(); + } + } + + void Widget::death(const Event& event) + { + mChildren.remove(event.getSource()); } } diff --git a/src/widgets/container.cpp b/src/widgets/container.cpp index fdedce0..cc65187 100644 --- a/src/widgets/container.cpp +++ b/src/widgets/container.cpp @@ -82,8 +82,6 @@ namespace gcn graphics->setColor(getBaseColor()); graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); } - - drawChildren(graphics); } void Container::setOpaque(bool opaque) @@ -98,31 +96,31 @@ namespace gcn void Container::add(Widget* widget) { - BasicContainer::add(widget); + Widget::add(widget); distributeWidgetAddedEvent(widget); } void Container::add(Widget* widget, int x, int y) { widget->setPosition(x, y); - BasicContainer::add(widget); + Widget::add(widget); distributeWidgetAddedEvent(widget); } void Container::remove(Widget* widget) { - BasicContainer::remove(widget); + Widget::remove(widget); distributeWidgetRemovedEvent(widget); } void Container::clear() { - BasicContainer::clear(); + Widget::clear(); } Widget* Container::findWidgetById(const std::string &id) { - return BasicContainer::findWidgetById(id); + return Widget::findWidgetById(id); } void Container::addContainerListener(ContainerListener* containerListener) { @@ -163,6 +161,11 @@ namespace gcn void Container::resizeToContent() { - BasicContainer::resizeToContent(); + Widget::resizeToChildren(); + } + + Rectangle Container::getChildrenArea() + { + return Rectangle(0, 0, getWidth(), getHeight()); } } // namespace gcn diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 6a2de42..7fd8bff 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -211,7 +211,7 @@ namespace gcn graphics->drawRectangle( Rectangle(0, mFoldedUpHeight, getWidth(), getHeight() - mFoldedUpHeight)); - drawChildren(graphics); + //drawChildren(graphics); } } @@ -489,7 +489,7 @@ namespace gcn { mScrollArea = NULL; } - BasicContainer::death(event); + Widget::death(event); } void DropDown::action(const ActionEvent& actionEvent) diff --git a/src/widgets/messagebox.cpp b/src/widgets/messagebox.cpp index 4236f67..2b664b6 100644 --- a/src/widgets/messagebox.cpp +++ b/src/widgets/messagebox.cpp @@ -418,7 +418,7 @@ namespace gcn void MessageBox::resizeToContent() { - WidgetListIterator it; + std::list::const_iterator it; int w = 0, h = 0; for (it = mWidgets.begin(); it != mWidgets.end(); it++) diff --git a/src/widgets/scrollarea.cpp b/src/widgets/scrollarea.cpp index 40e5be8..abcf507 100644 --- a/src/widgets/scrollarea.cpp +++ b/src/widgets/scrollarea.cpp @@ -156,9 +156,9 @@ namespace gcn Widget* ScrollArea::getContent() { - if (!mWidgets.empty()) + if (!mChildren.empty()) { - return *mWidgets.begin(); + return *mChildren.begin(); } return NULL; @@ -286,14 +286,11 @@ namespace gcn void ScrollArea::setScrollbarWidth(int width) { - if (width > 0) - { - mScrollbarWidth = width; - } - else + if (width <= 0) { throw GCN_EXCEPTION("Width should be greater then 0."); } + mScrollbarWidth = width; } int ScrollArea::getScrollbarWidth() const @@ -453,8 +450,6 @@ namespace gcn mScrollbarWidth, mScrollbarWidth)); } - - drawChildren(graphics); } void ScrollArea::drawHBar(Graphics* graphics) @@ -825,7 +820,6 @@ namespace gcn mHBarVisible = false; mVBarVisible = false; - if (!getContent()) { mHBarVisible = (mHPolicy == ShowAlways); @@ -1138,7 +1132,7 @@ namespace gcn throw GCN_EXCEPTION("Widget not content widget"); } - BasicContainer::showWidgetPart(widget, area); + Widget::showWidgetPart(widget, area); setHorizontalScrollAmount(getContent()->getFrameSize() - getContent()->getX()); setVerticalScrollAmount(getContent()->getFrameSize() - getContent()->getY()); diff --git a/src/widgets/tab.cpp b/src/widgets/tab.cpp index defae08..2d5223e 100644 --- a/src/widgets/tab.cpp +++ b/src/widgets/tab.cpp @@ -159,8 +159,6 @@ namespace gcn graphics->setColor(baseColor); graphics->fillRectangle(Rectangle(0, 0, currentClipArea.width, currentClipArea.height)); - drawChildren(graphics); - if (mTabbedArea != NULL && mTabbedArea->isFocused() && mTabbedArea->isTabSelected(this)) { graphics->setColor(Color(0x000000)); diff --git a/src/widgets/tabbedarea.cpp b/src/widgets/tabbedarea.cpp index deb346a..84f79e9 100644 --- a/src/widgets/tabbedarea.cpp +++ b/src/widgets/tabbedarea.cpp @@ -313,7 +313,7 @@ namespace gcn mTabContainer->getHeight()); } - drawChildren(graphics); + //drawChildren(graphics); } void TabbedArea::adjustSize() @@ -484,7 +484,7 @@ namespace gcn } else { - BasicContainer::death(event); + //BasicContainer::death(event); } } diff --git a/src/widgets/window.cpp b/src/widgets/window.cpp index 3af1ab6..b85b688 100644 --- a/src/widgets/window.cpp +++ b/src/widgets/window.cpp @@ -202,7 +202,7 @@ namespace gcn d.x + d.width - 1, d.y + d.height - 1); - drawChildren(graphics); + //drawChildren(graphics); int textX; int textY; @@ -324,7 +324,7 @@ namespace gcn void Window::resizeToContent() { - BasicContainer::resizeToContent(); + resizeToContent(); setSize(getWidth() + 2 * getPadding(), getHeight() + getPadding() + getTitleBarHeight()); } } From a0b5bb55aa9a67858e0b91748338a928b6fe9b3c Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 22:19:04 +0200 Subject: [PATCH 2/6] Apply Guichan's changes from cdd764791c06f6fcb4d1af4b23619f5ed6bba55a (Sept 24th 2008) BasicContainer has been removed. --- TODO | 2 +- include/guisan/basiccontainer.hpp | 240 --------------- src/basiccontainer.cpp | 470 ------------------------------ 3 files changed, 1 insertion(+), 711 deletions(-) delete mode 100644 include/guisan/basiccontainer.hpp delete mode 100644 src/basiccontainer.cpp diff --git a/TODO b/TODO index cdc2290..6915103 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from cdd764791c06f6fcb4d1af4b23619f5ed6bba55a +* Continue rebasing from 0cb290edbfcadb86d3f94e75f478ea01f47668ae * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/include/guisan/basiccontainer.hpp b/include/guisan/basiccontainer.hpp deleted file mode 100644 index 040d0df..0000000 --- a/include/guisan/basiccontainer.hpp +++ /dev/null @@ -1,240 +0,0 @@ -/* _______ __ __ __ ______ __ __ _______ __ __ - * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ - * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / - * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / - * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / - * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / - * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ - * - * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson - * - * Js_./ - * Per Larsson a.k.a finalman _RqZ{a<^_aa - * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a// - * _Qhm`] _f "'c 1!5m - * Visit: http://guichan.darkbits.org )Qk

ws?a-?' ._/L #' - * binary forms, with or without )4d[#7r, . ' )d`)[ - * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam' - * that the following conditions are met: j<. a J@\ - * this list of conditions and the j(]1u - -#include "guisan/deathlistener.hpp" -#include "guisan/platform.hpp" -#include "guisan/widget.hpp" - -namespace gcn -{ - /** - * A base class for containers. The class implements the most - * common things for a container. If you are implementing a - * container, consider inheriting from this class. - * - * @see Container - * @since 0.6.0 - */ - class GCN_CORE_DECLSPEC BasicContainer : public Widget, public DeathListener - { - public: - /** - * Constructor. - */ - BasicContainer(); - - /** - * Destructor - */ - virtual ~BasicContainer(); - - // Inherited from Widget - - /** - * Shows a certain part of a widget in the basic container. - * Used when widgets want a specific part to be visible in - * its parent. An example is a TextArea that wants a specific - * part of its text to be visible when a TextArea is a child - * of a ScrollArea. - * - * @param widget The widget whom wants a specific part of - * itself to be visible. - * @param rectangle The rectangle to be visible. - */ - virtual void showWidgetPart(Widget* widget, Rectangle area); - - virtual void moveToTop(Widget* widget); - - virtual void moveToBottom(Widget* widget); - - virtual Rectangle getChildrenArea(); - - virtual void focusNext(); - - virtual void focusPrevious(); - - virtual void logic(); - - virtual void _setFocusHandler(FocusHandler* focusHandler); - - void setInternalFocusHandler(FocusHandler* focusHandler); - - virtual Widget *getWidgetAt(int x, int y); - - virtual std::list getWidgetsIn(const Rectangle& area, Widget* ignore = NULL); - - // Inherited from DeathListener - - virtual void death(const Event& event); - - protected: - /** - * Moves a widget to the top. Normally one wants to use - * Widget::moveToTop instead. - * - * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION - * INSIDE ANY LISTENER FUNCTIONS! - * - * @param widget The widget to move to the top. - * @since 1.1.0 - */ - void _moveToTopWithNoChecks(Widget* widget); - - /** - * Moves a widget to the bottom. Normally one wants to use - * Widget::moveToBottom instead. - * - * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION - * INSIDE ANY LISTENER FUNCTIONS! - * - * @param The widget to move to the bottom. - * @since 1.1.0 - */ - void _moveToBottomWithNoChecks(Widget* widget); - - /** - * Adds a widget to the basic container. - * - * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION - * INSIDE ANY LISTENER FUNCTIONS! - * - * @param widget The widget to add. - * @see remove, clear - */ - void add(Widget* widget); - - /** - * Removes a widget from the basic container. - * - * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION - * INSIDE ANY LISTENER FUNCTIONS! - * - * @param widget The widget to remove. - * @see add, clear - */ - virtual void remove(Widget* widget); - - /** - * Clears the basic container from all widgets. - * - * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION - * INSIDE ANY LISTENER FUNCTIONS! - * - * @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 Guisan, such as - * the ability to create a Guisan 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); - - /** - * Resizes the BasicContainer to fit it's content exactly. - */ - void resizeToContent(); - - typedef std::list WidgetList; - typedef WidgetList::iterator WidgetListIterator; - typedef WidgetList::reverse_iterator WidgetListReverseIterator; - - /** - * Holds all widgets of the basic container. - */ - WidgetList mWidgets; - - /** - * Holds a widget that should be moved to the top. - */ - Widget* mWidgetToBeMovedToTheTop; - - /** - * Holds a widget that should be moved to the bottom. - */ - Widget* mWidgetToBeMovedToTheBottom; - - /** - * True if logic is currently being processed, false otherwise. - */ - bool mLogicIsProcessing; - }; -} - -#endif // end GCN_BASICCONTAINER_HPP diff --git a/src/basiccontainer.cpp b/src/basiccontainer.cpp deleted file mode 100644 index d109b39..0000000 --- a/src/basiccontainer.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* _______ __ __ __ ______ __ __ _______ __ __ - * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ - * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / - * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / - * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / - * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / - * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ - * - * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson - * - * Js_./ - * Per Larsson a.k.a finalman _RqZ{a<^_aa - * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a// - * _Qhm`] _f "'c 1!5m - * Visit: http://guichan.darkbits.org )Qk

ws?a-?' ._/L #' - * binary forms, with or without )4d[#7r, . ' )d`)[ - * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam' - * that the following conditions are met: j<. a J@\ - * this list of conditions and the j(]1u - -#include "guisan/exception.hpp" -#include "guisan/focushandler.hpp" -#include "guisan/graphics.hpp" -#include "guisan/mouseinput.hpp" - -namespace gcn -{ - BasicContainer::BasicContainer() : - mWidgetToBeMovedToTheTop(NULL), - mWidgetToBeMovedToTheBottom(NULL), - mLogicIsProcessing(false) - {} - - BasicContainer::~BasicContainer() - { - clear(); - } - - void BasicContainer::moveToTop(Widget* widget) - { - WidgetListIterator iter = std::find(mWidgets.begin(), mWidgets.end(), widget); - - if (iter == mWidgets.end()) - { - throw GCN_EXCEPTION("There is no such widget in this container."); - } - - if (mLogicIsProcessing) - mWidgetToBeMovedToTheTop = widget; - else - _moveToTopWithNoChecks(widget); - } - - void BasicContainer::moveToBottom(Widget* widget) - { - WidgetListIterator iter = find(mWidgets.begin(), mWidgets.end(), widget); - - if (iter == mWidgets.end()) - { - throw GCN_EXCEPTION("There is no such widget in this container."); - } - if (mLogicIsProcessing) - mWidgetToBeMovedToTheBottom = widget; - else - _moveToBottomWithNoChecks(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.isContaining(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().isContaining(x, y)) - { - return (*it); - } - } - - return NULL; - } - - void BasicContainer::logic() - { - mLogicIsProcessing = true; - mWidgetToBeMovedToTheTop = NULL; - mWidgetToBeMovedToTheBottom = NULL; - logicChildren(); - mLogicIsProcessing = false; - - if (mWidgetToBeMovedToTheTop != NULL) - { - _moveToTopWithNoChecks(mWidgetToBeMovedToTheTop); - mWidgetToBeMovedToTheTop = NULL; - } - - if (mWidgetToBeMovedToTheBottom != NULL) - { - _moveToTopWithNoChecks(mWidgetToBeMovedToTheBottom); - mWidgetToBeMovedToTheBottom = NULL; - } - } - - 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(*iter); - - if (basicContainer != NULL) - { - Widget *widget = basicContainer->findWidgetById(id); - - if (widget != NULL) - { - return widget; - } - } - } - - return NULL; - } - - void BasicContainer::_moveToTopWithNoChecks(Widget* widget) - { - mWidgets.remove(widget); - mWidgets.push_back(widget); - } - - void BasicContainer::_moveToBottomWithNoChecks(Widget* widget) - { - mWidgets.remove(widget); - mWidgets.push_front(widget); - } - - void BasicContainer::resizeToContent() - { - int w = 0, h = 0; - - for (WidgetListIterator it = mWidgets.begin(); it != mWidgets.end(); it++) - { - if ((*it)->getX() + (*it)->getWidth() > w) - { - w = (*it)->getX() + (*it)->getWidth(); - } - - if ((*it)->getY() + (*it)->getHeight() > h) - { - h = (*it)->getY() + (*it)->getHeight(); - } - } - - setSize(w, h); - } - - std::list BasicContainer::getWidgetsIn(const Rectangle& area, Widget* ignore) - { - std::list result; - - for (std::list::const_iterator iter = mWidgets.begin(); iter != mWidgets.end(); iter++) - { - Widget* widget = (*iter); - if (ignore != widget && widget->getDimension().isIntersecting(area)) - result.push_back(widget); - } - - return result; - } -} From b28a6a92aa6875dc7d7443971a27e4de3059ea26 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 22:24:53 +0200 Subject: [PATCH 3/6] Apply Guichan's changes from 0cb290edbfcadb86d3f94e75f478ea01f47668ae (Sept 24th 2008) BasicContainer has been removed. --- TODO | 2 +- src/widget.cpp | 1 - src/widgets/listbox.cpp | 1 - src/widgets/textbox.cpp | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/TODO b/TODO index 6915103..309c8f5 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from 0cb290edbfcadb86d3f94e75f478ea01f47668ae +* Continue rebasing from d2fbab450909969af1b5c835ce61e4e27deba4bd * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/src/widget.cpp b/src/widget.cpp index 76d3027..fe3b1b9 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -62,7 +62,6 @@ #include "guisan/actionevent.hpp" #include "guisan/actionlistener.hpp" -#include "guisan/basiccontainer.hpp" #include "guisan/deathlistener.hpp" #include "guisan/defaultfont.hpp" #include "guisan/event.hpp" diff --git a/src/widgets/listbox.cpp b/src/widgets/listbox.cpp index 213d42c..af92d8f 100644 --- a/src/widgets/listbox.cpp +++ b/src/widgets/listbox.cpp @@ -60,7 +60,6 @@ #include "guisan/widgets/listbox.hpp" -#include "guisan/basiccontainer.hpp" #include "guisan/font.hpp" #include "guisan/graphics.hpp" #include "guisan/key.hpp" diff --git a/src/widgets/textbox.cpp b/src/widgets/textbox.cpp index 4e8618b..8fee1cc 100644 --- a/src/widgets/textbox.cpp +++ b/src/widgets/textbox.cpp @@ -60,7 +60,6 @@ #include "guisan/widgets/textbox.hpp" -#include "guisan/basiccontainer.hpp" #include "guisan/font.hpp" #include "guisan/graphics.hpp" #include "guisan/key.hpp" From 0e7e72e40a3b2b843f6a782802789c20d156a6c9 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 22:50:49 +0200 Subject: [PATCH 4/6] Apply Guichan's changes from d2fbab450909969af1b5c835ce61e4e27deba4bd (Sept 24th 2008) Widget does not need to be a death listener. Widget::mWidgets has been renamed to Widget:mWidgetInstances so it's not confused with Widget::mChildren. Container::getChildren now returns the value of the newly added protected function Widget::getChildren. --- TODO | 2 +- include/guisan/widget.hpp | 22 +++++++++++++--------- include/guisan/widgets/dropdown.hpp | 3 --- include/guisan/widgets/listbox.hpp | 5 ----- src/widget.cpp | 24 +++++++++++++----------- src/widgets/container.cpp | 2 +- src/widgets/dropdown.cpp | 1 - 7 files changed, 28 insertions(+), 31 deletions(-) diff --git a/TODO b/TODO index 309c8f5..3927611 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from d2fbab450909969af1b5c835ce61e4e27deba4bd +* Continue rebasing from 44fb97c5b578da71350a8eb84d836768fbf5ffed * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/include/guisan/widget.hpp b/include/guisan/widget.hpp index 843344d..f37e5f2 100644 --- a/include/guisan/widget.hpp +++ b/include/guisan/widget.hpp @@ -61,12 +61,12 @@ #include #include "guisan/color.hpp" -#include "guisan/deathlistener.hpp" #include "guisan/rectangle.hpp" namespace gcn { class ActionListener; + class DeathListener; class DefaultFont; class FocusHandler; class FocusListener; @@ -83,13 +83,13 @@ namespace gcn * every widget should have. * * NOTE: Functions begining with underscore "_" should not - * be overloaded unless you know what you are doing + * be overloaded unless you know what you are doing. * * @author Olof Naessén - * @author Per Larsson. + * @author Per Larsson * @since 0.1.0 */ - class GCN_CORE_DECLSPEC Widget : public DeathListener + class GCN_CORE_DECLSPEC Widget { public: /** @@ -1040,10 +1040,6 @@ namespace gcn */ virtual void showPart(Rectangle rectangle); - // Inherited from DeathListener - - void death(const Event& event); - protected: /** * Distributes an action event to all action listeners @@ -1136,6 +1132,14 @@ namespace gcn */ void resizeToChildren(); + /** + * Gets the children of the widget. + * + * @return A list of the widgets children. + * @since 1.1.0 + */ + const std::list& getChildren() const; + /** * Holds the mouse listeners of the widget. */ @@ -1271,7 +1275,7 @@ namespace gcn /** * Holds a list of all instances of widgets. */ - static std::list mWidgets; + static std::list mWidgetInstances; }; } diff --git a/include/guisan/widgets/dropdown.hpp b/include/guisan/widgets/dropdown.hpp index 4e6fb72..3a07db0 100644 --- a/include/guisan/widgets/dropdown.hpp +++ b/include/guisan/widgets/dropdown.hpp @@ -164,9 +164,6 @@ namespace gcn * changes an event will be sent to all selection listeners of the * drop down. * - * If you delete your selection listener, be sure to also remove it - * using removeSelectionListener(). - * * @param selectionListener the selection listener to add. * @since 0.8.0 */ diff --git a/include/guisan/widgets/listbox.hpp b/include/guisan/widgets/listbox.hpp index f6f9061..0b47508 100644 --- a/include/guisan/widgets/listbox.hpp +++ b/include/guisan/widgets/listbox.hpp @@ -173,9 +173,6 @@ namespace gcn * 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 */ @@ -204,12 +201,10 @@ namespace gcn virtual void logic(); - // Inherited from KeyListener virtual void keyPressed(KeyEvent& keyEvent); - // Inherited from MouseListener virtual void mousePressed(MouseEvent& mouseEvent); diff --git a/src/widget.cpp b/src/widget.cpp index fe3b1b9..bb7b6b0 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -80,7 +80,7 @@ namespace gcn { Font* Widget::mGlobalFont = NULL; DefaultFont Widget::mDefaultFont; - std::list Widget::mWidgets; + std::list Widget::mWidgetInstances; Widget::Widget() : mForegroundColor(0x000000), @@ -98,15 +98,20 @@ namespace gcn mEnabled(true), mCurrentFont(NULL) { - mWidgets.push_back(this); + mWidgetInstances.push_back(this); } Widget::~Widget() { + if (mParent != NULL) + { + mParent->remove(this); + } + std::list::const_iterator childrenIter; for (childrenIter = mChildren.begin(); childrenIter != mChildren.end(); childrenIter++) { - (*childrenIter)->removeDeathListener(this); + (*childrenIter)->_setParent(NULL); } std::list::const_iterator deathIter; @@ -118,7 +123,7 @@ namespace gcn _setFocusHandler(NULL); - mWidgets.remove(this); + mWidgetInstances.remove(this); } void Widget::drawFrame(Graphics* graphics) @@ -517,7 +522,7 @@ namespace gcn mGlobalFont = font; std::list::iterator iter; - for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) + for (iter = mWidgetInstances.begin(); iter != mWidgetInstances.end(); ++iter) { if ((*iter)->mCurrentFont == NULL) { @@ -535,7 +540,7 @@ namespace gcn bool Widget::widgetExists(const Widget* widget) { std::list::const_iterator iter; - for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) + for (iter = mWidgetInstances.begin(); iter != mWidgetInstances.end(); ++iter) { if (*iter == widget) { @@ -907,7 +912,6 @@ namespace gcn Widget* widget = (*iter); widget->_setFocusHandler(NULL); widget->_setParent(NULL); - widget->removeDeathListener(this); } mChildren.clear(); @@ -923,7 +927,6 @@ namespace gcn mChildren.erase(iter); widget->_setFocusHandler(NULL); widget->_setParent(NULL); - widget->removeDeathListener(this); return; } } @@ -945,7 +948,6 @@ namespace gcn } widget->_setParent(this); - widget->addDeathListener(this); } void Widget::moveToTop(Widget* widget) @@ -1091,8 +1093,8 @@ namespace gcn } } - void Widget::death(const Event& event) + const std::list& Widget::getChildren() const { - mChildren.remove(event.getSource()); + return mChildren; } } diff --git a/src/widgets/container.cpp b/src/widgets/container.cpp index cc65187..965c8c8 100644 --- a/src/widgets/container.cpp +++ b/src/widgets/container.cpp @@ -156,7 +156,7 @@ namespace gcn const std::list& Container::getChildren() const { - return mWidgets; + return Widget::getChildren(); } void Container::resizeToContent() diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 7fd8bff..f1197ee 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -489,7 +489,6 @@ namespace gcn { mScrollArea = NULL; } - Widget::death(event); } void DropDown::action(const ActionEvent& actionEvent) From 9d974fd41e7d3e07cf6c8c1fab259e5e7ce2f0ea Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 23:10:39 +0200 Subject: [PATCH 5/6] Fix compilation. Remove basiccontainer.cpp/hpp from projects. Fix infinite recursive call. --- CMakeLists.txt | 1 - Guisan.vcxproj | 2 -- SConstruct | 1 - demo/ff/src/ffcontainer.cpp | 6 +----- src/SConscript | 1 - src/widgets/inputbox.cpp | 2 +- src/widgets/messagebox.cpp | 4 ++-- src/widgets/window.cpp | 2 +- 8 files changed, 5 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24cdb69..a7b9910 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ FILE(GLOB GUISAN_HEADER include/guisan.hpp) FILE(GLOB GUISAN_HEADERS include/guisan/actionevent.hpp include/guisan/actionlistener.hpp - include/guisan/basiccontainer.hpp include/guisan/cliprectangle.hpp include/guisan/color.hpp include/guisan/containerevent.hpp diff --git a/Guisan.vcxproj b/Guisan.vcxproj index 0f3bcd7..49635ca 100644 --- a/Guisan.vcxproj +++ b/Guisan.vcxproj @@ -137,7 +137,6 @@ - @@ -196,7 +195,6 @@ - diff --git a/SConstruct b/SConstruct index 82a8c99..3cd57e2 100644 --- a/SConstruct +++ b/SConstruct @@ -60,7 +60,6 @@ SConscript('examples/SConscript') common_headers = [ 'include/guisan/actionevent.hpp', 'include/guisan/actionlistener.hpp', - 'include/guisan/basiccontainer.hpp', 'include/guisan/cliprectangle.hpp', 'include/guisan/color.hpp', 'include/guisan/containerevent.hpp', diff --git a/demo/ff/src/ffcontainer.cpp b/demo/ff/src/ffcontainer.cpp index 2b5917a..3c1d715 100644 --- a/demo/ff/src/ffcontainer.cpp +++ b/demo/ff/src/ffcontainer.cpp @@ -110,14 +110,10 @@ void FFContainer::draw(gcn::Graphics* graphics) { graphics->setColor(c * (1.0 - i / 18.0)); graphics->fillRectangle(gcn::Rectangle(4, (i * height + 4), - getWidth()-8, (i * height ) + height)); + getWidth()-8, (i * height ) + height)); } } - graphics->pushClipArea(gcn::Rectangle(0, mCurrentSlide, getWidth(), getHeight())); - drawChildren(graphics); - graphics->popClipArea(); - for (i = 5; i < getHeight()-10; i+=5) { graphics->drawImage(mVertical, 0, i); diff --git a/src/SConscript b/src/SConscript index da82d60..bab7509 100644 --- a/src/SConscript +++ b/src/SConscript @@ -6,7 +6,6 @@ Import("env") main_sources = [ 'actionevent.cpp', - 'basiccontainer.cpp', 'cliprectangle.cpp', 'color.cpp', 'containerevent.cpp', diff --git a/src/widgets/inputbox.cpp b/src/widgets/inputbox.cpp index bcf1e99..472c2ea 100644 --- a/src/widgets/inputbox.cpp +++ b/src/widgets/inputbox.cpp @@ -203,7 +203,7 @@ namespace gcn d.x + d.width - 1, d.y + d.height - 1); - drawChildren(graphics); + //drawChildren(graphics); int textX; int textY; diff --git a/src/widgets/messagebox.cpp b/src/widgets/messagebox.cpp index 2b664b6..dc8c401 100644 --- a/src/widgets/messagebox.cpp +++ b/src/widgets/messagebox.cpp @@ -310,7 +310,7 @@ namespace gcn d.x + d.width - 1, d.y + d.height - 1); - drawChildren(graphics); + //drawChildren(graphics); int textX; int textY; @@ -421,7 +421,7 @@ namespace gcn std::list::const_iterator it; int w = 0, h = 0; - for (it = mWidgets.begin(); it != mWidgets.end(); it++) + for (it = mChildren.begin(); it != mChildren.end(); it++) { if ((*it)->getX() + (*it)->getWidth() > w) { diff --git a/src/widgets/window.cpp b/src/widgets/window.cpp index b85b688..c3c9f9b 100644 --- a/src/widgets/window.cpp +++ b/src/widgets/window.cpp @@ -324,7 +324,7 @@ namespace gcn void Window::resizeToContent() { - resizeToContent(); + Container::resizeToContent(); setSize(getWidth() + 2 * getPadding(), getHeight() + getPadding() + getTitleBarHeight()); } } From 7798bb27c9dcd1f0c5b802bf87a469d327d09792 Mon Sep 17 00:00:00 2001 From: Jarod42 Date: Thu, 12 Sep 2024 23:52:50 +0200 Subject: [PATCH 6/6] Apply Guichan's changes from 44fb97c5b578da71350a8eb84d836768fbf5ffed (Sept 28th 2008) http://code.google.com/p/guichan/issues/detail?id=89 --- TODO | 2 +- src/widget.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 3927611..0d222c7 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from 44fb97c5b578da71350a8eb84d836768fbf5ffed +* Continue rebasing from 636e1837a62cb3126d6a8554856c1219160161a9 * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/src/widget.cpp b/src/widget.cpp index bb7b6b0..8edf6a6 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1066,13 +1066,16 @@ namespace gcn graphics->pushClipArea(mDimension); draw(graphics); - graphics->pushClipArea(getChildrenArea()); + const Rectangle& childrenArea = getChildrenArea(); + graphics->pushClipArea(childrenArea); std::list::const_iterator iter; for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { Widget* widget = (*iter); - if (widget->isVisible()) + // Only draw a widget if it's visible and if it visible + // inside the children area. + if (widget->isVisible() && childrenArea.isIntersecting(widget->getDimension())) { widget->_draw(graphics); }