diff options
author | Sebastian Geerken <devnull@localhost> | 2014-09-25 11:39:53 +0200 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2014-09-25 11:39:53 +0200 |
commit | a3486120edf86a0248f0162e5cae2ab7250c9848 (patch) | |
tree | 98a079b7125debaf44e62111ac64668f2e05c8a7 | |
parent | bcebc40e56a88fac5fbdd4cc04d74d53ac6ec3ff (diff) |
Some work on mouse events (getWidgetAtPoint).
-rw-r--r-- | doc/dw-stacking-context.doc | 55 | ||||
-rw-r--r-- | dw/layout.cc | 13 | ||||
-rw-r--r-- | dw/oofawarewidget.cc | 52 | ||||
-rw-r--r-- | dw/oofawarewidget.hh | 4 | ||||
-rw-r--r-- | dw/ooffloatsmgr.cc | 18 | ||||
-rw-r--r-- | dw/ooffloatsmgr.hh | 5 | ||||
-rw-r--r-- | dw/oofpositionedmgr.cc | 18 | ||||
-rw-r--r-- | dw/oofpositionedmgr.hh | 2 | ||||
-rw-r--r-- | dw/outofflowmgr.hh | 2 | ||||
-rw-r--r-- | dw/stackingcontextmgr.cc | 47 | ||||
-rw-r--r-- | dw/stackingcontextmgr.hh | 6 | ||||
-rw-r--r-- | dw/textblock.cc | 33 | ||||
-rw-r--r-- | dw/textblock.hh | 2 | ||||
-rw-r--r-- | dw/widget.cc | 52 | ||||
-rw-r--r-- | dw/widget.hh | 2 |
15 files changed, 223 insertions, 88 deletions
diff --git a/doc/dw-stacking-context.doc b/doc/dw-stacking-context.doc index 47854546..6138ca5d 100644 --- a/doc/dw-stacking-context.doc +++ b/doc/dw-stacking-context.doc @@ -32,11 +32,11 @@ I'm here referring to the simplified description in <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section 9.9.1</a>. The table shows a recommended order for the implementations of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint -(for the latter, read from bottom to top)<sup>1</sup>: +(for the latter, read from bottom to top): <table> <tr> -<th> CSS specification <th> Drawing <th> Mouse events<sup>2</sup> +<th> CSS specification <th> Drawing <th> Mouse events <tr> <td> *1. the background and borders of the element forming the stacking context.* @@ -46,7 +46,7 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint <td> *2. the child stacking contexts with negative stack levels (most negative first).* <td> dw::core::StackingContextMgr::drawBottom (when defined) -<td> ... +<td> dw::core::StackingContextMgr::getBottomWidgetAtPoint (when defined) <tr> <td> *3. the in-flow, non-inline-level, non-positioned descendants.* @@ -56,13 +56,34 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint 1. all in-flow elements are drawn, 2. floats are drawn and - 3. positioned elements are drawn (latter two done by + 3. positioned elements with *z-index: auto* are drawn + (latter two done by dw::oof::OOFAwareWidget::drawOOF, in this order). This order differs from the specified order, but since floats and in-flow elements do not overlap, - this difference has no effect.<sup>3</sup> -<td rowspan="4"> ...<sup>3</sup> + this difference has no effect. + + Drawing in-line elements, floats and positioned + elements with *z-index: auto* and should avoid + duplicate calls: Widgets drawn by + dw::core::StackingContextMgr::drawBottom and by + dw::core::StackingContextMgr::drawTop should be + excluded here. This can be tested with + dw::core::StackingContextMgr::handledByStackingContextMgr. + +<td rowspan="4"> Likewise, the implementation should (i) test + dw::oof::OOFAwareWidget::getWidgetOOFAtPoint, and + (ii) search through the chilren. Also, duplicate + calls should be avoided using + dw::core::StackingContextMgr::handledByStackingContextMgr. + + There are already the implementations + dw::core::Widget::getWidgetAtPoint (ignoring + dw::oof::OutOfFlowMgr) and + dw::oof::OOFAwareWidget::getWidgetAtPoint (including + dw::oof::OutOfFlowMgr). + <tr> <td> *4. the non-positioned floats.* <tr> @@ -79,27 +100,15 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint <td> *6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.* <td rowspan="2"> dw::core::StackingContextMgr::drawTop (when defined) -<td rowspan="2"> ... +<td rowspan="2"> dw::core::StackingContextMgr::getTopWidgetAtPoint + (when defined) <tr> <td> *7. the child stacking contexts with positive stack levels (least positive first).* </table> -Notes: - -<sup>1</sup>) This is not quite in conformance with the specification: - this description refers to any widget, not only widgets - establishing a stacking context. Does this make a - difference? - -<sup>2</sup>) Handling mouse events is, at this time, not implemented - at all. - -<sup>3</sup>) Drawing (and handling mouse events, respectively) should - avoid dublicate calls: Widgets drawn by - dw::core::StackingContextMgr::drawBottom and by - dw::core::StackingContextMgr::drawTop should be excluded - elsewhere. This can be tested with - dw::core::StackingContextMgr::handledByStackingContextMgr. +Note: This is not quite in conformance with the specification: this +description refers to any widget, not only widgets establishing a +stacking context. Does this make a difference? */
\ No newline at end of file diff --git a/dw/layout.cc b/dw/layout.cc index d46d2455..600f2088 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -1100,12 +1100,17 @@ void Layout::leaveNotify (View *view, ButtonState state) */ Widget *Layout::getWidgetAtPoint (int x, int y) { - _MSG ("------------------------------------------------------------\n"); - _MSG ("widget at (%d, %d)\n", x, y); + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + Widget *widget; + if (topLevel && topLevel->wasAllocated ()) - return topLevel->getWidgetAtPoint (x, y, 0); + widget = topLevel->getWidgetAtPoint (x, y); else - return NULL; + widget = NULL; + + DBG_OBJ_MSGF ("events", 0, "=> %p", widget); + DBG_OBJ_LEAVE (); + return widget; } diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc index 62a1e8d6..99f297ff 100644 --- a/dw/oofawarewidget.cc +++ b/dw/oofawarewidget.cc @@ -255,12 +255,12 @@ void OOFAwareWidget::drawOOF (View *view, Rectangle *area) outOfFlowMgr[i]->draw(view, area); } -Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y, int level) +Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y) { for (int i = 0; i < NUM_OOFM; i++) { Widget *oofWidget = outOfFlowMgr[i] ? - outOfFlowMgr[i]->getWidgetAtPoint (x, y, level) : NULL; + outOfFlowMgr[i]->getWidgetAtPoint (x, y) : NULL; if (oofWidget) return oofWidget; } @@ -299,6 +299,54 @@ void OOFAwareWidget::removeChild (Widget *child) assert (isWidgetOOF (child)); } +core::Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y) +{ + if (x >= allocation.x && + y >= allocation.y && + x <= allocation.x + allocation.width && + y <= allocation.y + getHeight ()) { + + if (stackingContextMgr) { + Widget *scmWidget = + stackingContextMgr->getTopWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + + Widget *oofWidget = getWidgetOOFAtPoint (x, y); + if (oofWidget) + return oofWidget; + + Widget *childAtPoint = NULL; + Iterator *it = + iterator ((Content::Type) + (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT), + false); + + while (childAtPoint == NULL && it->next ()) { + Widget *child = it->getContent()->widget; + if (!StackingContextMgr::handledByStackingContextMgr (child) && + child->wasAllocated ()) + childAtPoint = child->getWidgetAtPoint (x, y); + } + + it->unref (); + + if (childAtPoint) + return childAtPoint; + + if (stackingContextMgr) { + Widget *scmWidget = + stackingContextMgr->getBottomWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + + return this; + } else + return NULL; +} + void OOFAwareWidget::borderChanged (int y, Widget *vloat) { assertNotReached (); diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh index afa5964a..81fafa10 100644 --- a/dw/oofawarewidget.hh +++ b/dw/oofawarewidget.hh @@ -169,7 +169,7 @@ protected: void sizeAllocateEnd (); void containerSizeChangedForChildrenOOF (); void drawOOF (core::View *view, core::Rectangle *area); - core::Widget *getWidgetOOFAtPoint (int x, int y, int level); + core::Widget *getWidgetOOFAtPoint (int x, int y); static bool isOOFContainer (Widget *widget, int oofmIndex); @@ -181,6 +181,8 @@ protected: void removeChild (Widget *child); + core::Widget *getWidgetAtPoint (int x, int y); + public: static int CLASS_ID; diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc index eecd4faa..8b1df1de 100644 --- a/dw/ooffloatsmgr.cc +++ b/dw/ooffloatsmgr.cc @@ -1458,23 +1458,23 @@ void OOFFloatsMgr::markExtremesChange (int ref) // Nothing to do here. } -Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y, int level) +Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y) { - Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level); + Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y); if (childAtPoint == NULL) - childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level); + childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y); return childAtPoint; } -Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, - int x, int y, int level) +Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x, + int y) { for (int i = 0; i < list->size(); i++) { // Could use binary search to be faster. - Float *vloat = list->get(i); - if (vloat->getWidget()->wasAllocated ()) { - Widget *childAtPoint = - vloat->getWidget()->getWidgetAtPoint (x, y, level + 1); + Widget *childWidget = list->get(i)->getWidget (); + if (!StackingContextMgr::handledByStackingContextMgr (childWidget) && + childWidget->wasAllocated ()) { + Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y); if (childAtPoint) return childAtPoint; } diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh index 47bcbab4..75bc596e 100644 --- a/dw/ooffloatsmgr.hh +++ b/dw/ooffloatsmgr.hh @@ -285,8 +285,7 @@ private: void drawFloats (SortedFloatsVector *list, core::View *view, core::Rectangle *area); - core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, - int level); + core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y); bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal); bool collidesH (Float *vloat, Float *other, SFVType type); @@ -343,7 +342,7 @@ public: void markSizeChange (int ref); void markExtremesChange (int ref); - core::Widget *getWidgetAtPoint (int x, int y, int level); + core::Widget *getWidgetAtPoint (int x, int y); static bool _isWidgetOutOfFlow (core::Widget *widget); static bool _isWidgetHandledByOOFM (core::Widget *widget); diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc index 4799ec8c..e5c31a98 100644 --- a/dw/oofpositionedmgr.cc +++ b/dw/oofpositionedmgr.cc @@ -226,18 +226,22 @@ void OOFPositionedMgr::markExtremesChange (int ref) { } -Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y, int level) +Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y) { - for (int i = 0; i < children->size(); i++) { + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y); + Widget *childAtPoint = NULL; + + for (int i = 0; i < children->size() && childAtPoint == NULL; i++) { Widget *childWidget = children->get(i)->widget; - if (childWidget->wasAllocated ()) { - Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y, level + 1); - if (childAtPoint) - return childAtPoint; + if (!StackingContextMgr::handledByStackingContextMgr (childWidget) && + childWidget->wasAllocated ()) { + childAtPoint = childWidget->getWidgetAtPoint (x, y); } } - return NULL; + DBG_OBJ_MSGF ("events", 0, "=> %p", childAtPoint); + DBG_OBJ_LEAVE (); + return childAtPoint; } void OOFPositionedMgr::tellPosition (Widget *widget, int x, int y) diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh index ad469b8f..8ddecd92 100644 --- a/dw/oofpositionedmgr.hh +++ b/dw/oofpositionedmgr.hh @@ -68,7 +68,7 @@ public: void markSizeChange (int ref); void markExtremesChange (int ref); - core::Widget *getWidgetAtPoint (int x, int y, int level); + core::Widget *getWidgetAtPoint (int x, int y); void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent, int externalIndex); diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh index 5b03562d..96091ded 100644 --- a/dw/outofflowmgr.hh +++ b/dw/outofflowmgr.hh @@ -29,7 +29,7 @@ public: virtual void markSizeChange (int ref) = 0; virtual void markExtremesChange (int ref) = 0; - virtual core::Widget *getWidgetAtPoint (int x, int y, int level) = 0; + virtual core::Widget *getWidgetAtPoint (int x, int y) = 0; virtual void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent, int externalIndex) = 0; diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc index b3573a3f..e57c73f0 100644 --- a/dw/stackingcontextmgr.cc +++ b/dw/stackingcontextmgr.cc @@ -101,6 +101,53 @@ void StackingContextMgr::draw (View *view, Rectangle *area, int startZIndex, DBG_OBJ_LEAVE (); } +Widget *StackingContextMgr::getTopWidgetAtPoint (int x, int y) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTop", "%d, %d", x, y); + Widget *widget = getWidgetAtPoint (x, y, 0, INT_MAX); + DBG_OBJ_MSGF ("events", 0, "=> %p", widget); + DBG_OBJ_LEAVE (); + return widget; +} + +Widget *StackingContextMgr::getBottomWidgetAtPoint (int x, int y) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y); + Widget *widget = getWidgetAtPoint (x, y, INT_MIN, -1); + DBG_OBJ_MSGF ("events", 0, "=> %p", widget); + DBG_OBJ_LEAVE (); + return widget; +} + +Widget *StackingContextMgr::getWidgetAtPoint (int x, int y, int startZIndex, + int endZIndex) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y); + + Widget *widgetAtPoint = NULL; + + for (int zIndex = min (maxZIndex, endZIndex); + zIndex >= max (minZIndex, startZIndex) && widgetAtPoint == NULL; + zIndex--) { + DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d", zIndex); + DBG_OBJ_MSG_START (); + + for (int i = 0; i < scWidgets->size () && widgetAtPoint == NULL; i++) { + Widget *child = scWidgets->get (i); + DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d", + child, child->getStyle()->zIndex); + if (child->getStyle()->zIndex == zIndex && child->wasAllocated ()) + widgetAtPoint = scWidgets->get(i)->getWidgetAtPoint (x, y); + } + + DBG_OBJ_MSG_END (); + } + + DBG_OBJ_MSGF ("events", 0, "=> %p", widgetAtPoint); + DBG_OBJ_LEAVE (); + return widgetAtPoint; +} + } // namespace core diff --git a/dw/stackingcontextmgr.hh b/dw/stackingcontextmgr.hh index cbb59231..684fac23 100644 --- a/dw/stackingcontextmgr.hh +++ b/dw/stackingcontextmgr.hh @@ -25,7 +25,8 @@ private: int minZIndex, maxZIndex; void draw (View *view, Rectangle *area, int startZIndex, int endZIndex); - + + Widget *getWidgetAtPoint (int x, int y, int startZIndex, int endZIndex); public: StackingContextMgr (Widget *widget); ~StackingContextMgr (); @@ -47,6 +48,9 @@ public: void drawBottom (View *view, Rectangle *area); void drawTop (View *view, Rectangle *area); + + Widget *getTopWidgetAtPoint (int x, int y); + Widget *getBottomWidgetAtPoint (int x, int y); }; } // namespace core diff --git a/dw/textblock.cc b/dw/textblock.cc index df38a8e7..e914c316 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -2642,12 +2642,8 @@ void Textblock::breakAdded () * This is an optimized version of the general * dw::core::Widget::getWidgetAtPoint method. */ -core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level) +core::Widget *Textblock::getWidgetAtPoint (int x, int y) { - //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n", - // 3 * level, "", getClassName (), this, allocation.x, allocation.y, - // allocation.width, allocation.ascent, allocation.descent); - int lineIndex, wordIndex; Line *line; @@ -2658,10 +2654,16 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level) return NULL; } - // First, search for widgets out of flow, notably floats, since - // there are cases where they overlap child textblocks. Should - // later be refined using z-index. - Widget *oofWidget = getWidgetOOFAtPoint (x, y, level); + // First, ... + if (stackingContextMgr) { + Widget *scmWidget = stackingContextMgr->getTopWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + + // Then, search for widgets out of flow, notably floats, since + // there are cases where they overlap child textblocks. + Widget *oofWidget = getWidgetOOFAtPoint (x, y); if (oofWidget) return oofWidget; @@ -2678,9 +2680,10 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level) if (word->content.type == core::Content::WIDGET_IN_FLOW) { core::Widget * childAtPoint; - if (word->content.widget->wasAllocated ()) { - childAtPoint = word->content.widget->getWidgetAtPoint (x, y, - level + 1); + if (!core::StackingContextMgr::handledByStackingContextMgr + (word->content.widget) && + word->content.widget->wasAllocated ()) { + childAtPoint = word->content.widget->getWidgetAtPoint (x, y); if (childAtPoint) { return childAtPoint; } @@ -2688,6 +2691,12 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level) } } + if (stackingContextMgr) { + Widget *scmWidget = stackingContextMgr->getBottomWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + return this; } diff --git a/dw/textblock.hh b/dw/textblock.hh index d376ba48..e55c2ce3 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -831,7 +831,7 @@ public: void addParbreak (int space, core::style::Style *style); void addLinebreak (core::style::Style *style); - core::Widget *getWidgetAtPoint (int x, int y, int level); + core::Widget *getWidgetAtPoint (int x, int y); void handOverBreak (core::style::Style *style); void changeLinkColor (int link, int newColor); void changeWordStyle (int from, int to, core::style::Style *style, diff --git a/dw/widget.cc b/dw/widget.cc index 64414008..19083f61 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -1389,42 +1389,50 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget) * * Used by dw::core::Layout:getWidgetAtPoint. */ -Widget *Widget::getWidgetAtPoint (int x, int y, int level) +Widget *Widget::getWidgetAtPoint (int x, int y) { - Iterator *it; - Widget *childAtPoint; - - //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n", - // 3 * level, "", getClassName (), this, allocation.x, allocation.y, - // allocation.width, allocation.ascent, allocation.descent); - if (x >= allocation.x && y >= allocation.y && x <= allocation.x + allocation.width && y <= allocation.y + getHeight ()) { - //_MSG ("%*s -> inside\n", 3 * level, ""); - /* - * Iterate over the children of this widget. Test recursively, whether - * the point is within the child (or one of its children...). If there - * is such a child, it is returned. Otherwise, this widget is returned. - */ - childAtPoint = NULL; - it = iterator ((Content::Type) - (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT), - false); + + if (stackingContextMgr) { + Widget *scmWidget = + stackingContextMgr->getTopWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + + // Iterate over the children of this widget. Test recursively, whether + // the point is within the child (or one of its children...). If there + // is such a child, it is returned. Otherwise, this widget is returned. + + Widget *childAtPoint = NULL; + Iterator *it = + iterator ((Content::Type) + (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT), + false); while (childAtPoint == NULL && it->next ()) { Widget *child = it->getContent()->widget; - if (child->wasAllocated ()) - childAtPoint = child->getWidgetAtPoint (x, y, level + 1); + if (!StackingContextMgr::handledByStackingContextMgr (child) && + child->wasAllocated ()) + childAtPoint = child->getWidgetAtPoint (x, y); } it->unref (); if (childAtPoint) return childAtPoint; - else - return this; + + if (stackingContextMgr) { + Widget *scmWidget = + stackingContextMgr->getBottomWidgetAtPoint (x, y); + if (scmWidget) + return scmWidget; + } + + return this; } else return NULL; } diff --git a/dw/widget.hh b/dw/widget.hh index ca98308e..9acb6605 100644 --- a/dw/widget.hh +++ b/dw/widget.hh @@ -492,7 +492,7 @@ public: inline Layout *getLayout () { return layout; } - virtual Widget *getWidgetAtPoint (int x, int y, int level); + virtual Widget *getWidgetAtPoint (int x, int y); void scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height); |