diff options
Diffstat (limited to 'dw/widget.cc')
-rw-r--r-- | dw/widget.cc | 372 |
1 files changed, 302 insertions, 70 deletions
diff --git a/dw/widget.cc b/dw/widget.cc index 18748c4f..c02b007f 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -91,6 +91,8 @@ Widget::Widget () deleteCallbackFunc = NULL; widgetImgRenderer = NULL; + + stackingContextMgr = NULL; } Widget::~Widget () @@ -104,6 +106,9 @@ Widget::~Widget () delete widgetImgRenderer; } + if (stackingContextMgr) + delete stackingContextMgr; + if (style) style->unref (); @@ -125,25 +130,218 @@ Widget::~Widget () */ bool Widget::intersects (Rectangle *area, Rectangle *intersection) { - Rectangle parentArea, childArea; + DBG_OBJ_ENTER ("draw", 0, "intersects", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + bool r; + + if (wasAllocated ()) { + Rectangle parentArea, childArea; + + parentArea = *area; + parentArea.x += parent->allocation.x; + parentArea.y += parent->allocation.y; + + DBG_OBJ_MSGF ("draw", 2, "parentArea: %d, %d, %d * %d", + parentArea.x, parentArea.y, parentArea.width, + parentArea.height); + + childArea.x = allocation.x; + childArea.y = allocation.y; + childArea.width = allocation.width; + childArea.height = getHeight (); + + DBG_OBJ_MSGF ("draw", 2, "childArea: %d, %d, %d * %d", + childArea.x, childArea.y, childArea.width, + childArea.height); + + if (parentArea.intersectsWith (&childArea, intersection)) { + DBG_OBJ_MSGF ("draw", 2, "intersection: %d, %d, %d * %d", + intersection->x, intersection->y, intersection->width, + intersection->height); + + intersection->x -= allocation.x; + intersection->y -= allocation.y; + r = true; + + DBG_OBJ_MSGF ("draw", 1, "=> %d, %d, %d * %d", + intersection->x, intersection->y, intersection->width, + intersection->height); + } else { + r = false; + DBG_OBJ_MSG ("draw", 1, "=> no intersection"); + } + } else { + r = false; + DBG_OBJ_MSG ("draw", 1, "=> not allocated"); + } + + DBG_OBJ_LEAVE (); + return r; +} + +void Widget::drawTotal (View *view, Rectangle *area, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("draw", 0, "drawTotal", "%d, %d, %d * %d", + area->x, area->y, area->width, area->height); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "initial iteratorStack: %s", sb.getChars ()); + } + + Object *si = NULL; + + if (iteratorStack->atRealTop ()) { + si = stackingIterator (false); + if (si) { + iteratorStack->push (si); + } + } else + iteratorStack->forward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "iteratorStack before: %s", + sb.getChars ()); + } + + draw (view, area, iteratorStack, interruptedWidget); + DBG_OBJ_MSGF ("draw", 1, "=> %p", *interruptedWidget); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "iteratorStack after: %s", + sb.getChars ()); + } + + // A value for *interruptedWidget other than NULL indicates a + // widget with a complex drawing process, for which + // stackingIterator() must return something non-NULL, so that the + // interrupted drawing process can be continued. (TODO: Not quite + // correct when forward() was called instead of push().) + + // assert (*interruptedWidget == NULL || si != NULL); + + if (*interruptedWidget == NULL) { + if (si) + iteratorStack->pop (); + } else + iteratorStack->backward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("draw", 2, "final iteratorStack: %s", sb.getChars ()); + } + + DBG_OBJ_LEAVE (); +} + +void Widget::drawToplevel (View *view, Rectangle *area) +{ + assert (parent == NULL); + + StackingIteratorStack iteratorStack; + Widget *interruptedWidget = NULL; + drawTotal (view, area, &iteratorStack, &interruptedWidget); + + // Everything should be finished at this point. + assert (interruptedWidget == NULL); +} + +Widget *Widget::getWidgetAtPoint (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + // Suitable for simple widgets, without children. + + if (wasAllocated () && x >= allocation.x && y >= allocation.y && + x <= allocation.x + allocation.width && y <= allocation.y + getHeight ()) + return this; + else + return NULL; +} + +Widget *Widget::getWidgetAtPointTotal (int x, int y, + StackingIteratorStack *iteratorStack, + Widget **interruptedWidget) +{ + DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTotal", "%d, %d", x, y); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "initial iteratorStack: %s", sb.getChars ()); + } + + Object *si = NULL; + + if (iteratorStack->atRealTop ()) { + si = stackingIterator (true); + if (si) { + iteratorStack->push (si); + } + } else + iteratorStack->forward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "iteratorStack before: %s", + sb.getChars ()); + } + + Widget *widget = getWidgetAtPoint (x, y, iteratorStack, interruptedWidget); + DBG_OBJ_MSGF ("events", 1, "=> %p (i: %p)", widget, *interruptedWidget); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "iteratorStack after: %s", + sb.getChars ()); + } - parentArea = *area; - parentArea.x += parent->allocation.x; - parentArea.y += parent->allocation.y; + // See comment in drawTotal(). - childArea.x = allocation.x; - childArea.y = allocation.y; - childArea.width = allocation.width; - childArea.height = getHeight (); + // assert (*interruptedWidget == NULL || si != NULL); - if (parentArea.intersectsWith (&childArea, intersection)) { - intersection->x -= allocation.x; - intersection->y -= allocation.y; - return true; + if (*interruptedWidget == NULL) { + if (si) + iteratorStack->pop (); } else - return false; + iteratorStack->backward (); + + DBG_IF_RTFL { + misc::StringBuffer sb; + iteratorStack->intoStringBuffer (&sb); + DBG_OBJ_MSGF ("events", 2, "final iteratorStack: %s", sb.getChars ()); + } + + DBG_OBJ_LEAVE (); + return widget; } +Widget *Widget::getWidgetAtPointToplevel (int x, int y) +{ + assert (parent == NULL); + + StackingIteratorStack iteratorStack; + Widget *interruptedWidget = NULL; + Widget *widget = + getWidgetAtPointTotal (x, y, &iteratorStack, &interruptedWidget); + + // Everything should be finished at this point. + assert (interruptedWidget == NULL); + + return widget; +} + + void Widget::setParent (Widget *parent) { this->parent = parent; @@ -170,6 +368,18 @@ void Widget::setParent (Widget *parent) // Textblock. DBG_OBJ_SET_PTR ("container", container); + // If at all, stackingContextMgr should have set *before*, see also + // Widget::setStyle() and Layout::addWidget(). + if (stackingContextMgr) { + Widget *stackingContextWidget = parent; + while (stackingContextWidget && + stackingContextWidget->stackingContextMgr == NULL) + stackingContextWidget = stackingContextWidget->parent; + assert (stackingContextWidget); + stackingContextWidget->stackingContextMgr->addChildSCWidget (this); + } else + stackingContextWidget = parent->stackingContextWidget; + notifySetParent(); } @@ -490,6 +700,7 @@ void Widget::sizeRequest (Requisition *requisition) } if (needsResize ()) { + calcExtraSpace (); /** \todo Check requisition == &(this->requisition) and do what? */ sizeRequestImpl (requisition); this->requisition = *requisition; @@ -613,7 +824,7 @@ int Widget::getAvailHeight (bool forceValue) } else if (style::isPerLength (getStyle()->height)) { DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%", 100 * style::perLengthVal_useThisOnlyForDebugging - (getStyle()->height)); + (getStyle()->height)); // Notice that here -- unlike getAvailWidth() -- // layout->hScrollbarThickness is not considered here; // something like canvasWidthGreater (analogue to @@ -894,6 +1105,8 @@ void Widget::getExtremes (Extremes *extremes) } if (extremesChanged ()) { + calcExtraSpace (); + // For backward compatibility (part 1/2): extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1; @@ -923,6 +1136,24 @@ void Widget::getExtremes (Extremes *extremes) } /** + * \brief Calculates dw::core::Widget::extraSpace. + * + * Delegated to dw::core::Widget::calcExtraSpaceImpl. Called both from + * dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes. + */ +void Widget::calcExtraSpace () +{ + extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0; + calcExtraSpaceImpl (); + + DBG_OBJ_SET_NUM ("extraSpace.top", extraSpace.top); + DBG_OBJ_SET_NUM ("extraSpace.bottom", extraSpace.bottom); + DBG_OBJ_SET_NUM ("extraSpace.left", extraSpace.left); + DBG_OBJ_SET_NUM ("extraSpace.right", extraSpace.right); + +} + +/** * \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when * needed. */ @@ -1066,6 +1297,16 @@ void Widget::setStyle (style::Style *style) layout->updateCursor (); } + // After Layout::addWidget() (as toplevel widget) or Widget::setParent() + // (which also sets layout), changes of the style cannot be considered + // anymore. (Should print a warning?) + if (layout == NULL && + StackingContextMgr::isEstablishingStackingContext (this)) { + stackingContextMgr = new StackingContextMgr (this); + DBG_OBJ_ASSOC_CHILD (stackingContextMgr); + stackingContextWidget = this; + } + if (sizeChanged) queueResize (0, true); else @@ -1180,7 +1421,7 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area, // TODO Handle inverse drawing the same way as in drawWidgetBox? // Maybe this method (drawBox) is anyway obsolete when extraSpace - // is fully supported (as in the "dillo_grows" repository). + // is fully supported (as here, in the "dillo_grows" repository). int xPad, yPad, widthPad, heightPad; getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); @@ -1210,8 +1451,10 @@ void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse) canvasArea.width = area->width; canvasArea.height = area->height; - style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y, - allocation.width, getHeight (), style, inverse); + int xMar, yMar, widthMar, heightMar; + getMarginArea (&xMar, &yMar, &widthMar, &heightMar); + style::drawBorder (view, layout, &canvasArea, xMar, yMar, widthMar, + heightMar, style, inverse); int xPad, yPad, widthPad, heightPad; getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); @@ -1347,53 +1590,6 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget) return widget1; } - -/** - * \brief Search recursively through widget. - * - * Used by dw::core::Layout:getWidgetAtPoint. - */ -Widget *Widget::getWidgetAtPoint (int x, int y, int level) -{ - 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); - - while (childAtPoint == NULL && it->next ()) { - Widget *child = it->getContent()->widget; - if (child->wasAllocated ()) - childAtPoint = child->getWidgetAtPoint (x, y, level + 1); - } - - it->unref (); - - if (childAtPoint) - return childAtPoint; - else - return this; - } else - return NULL; -} - - void Widget::scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height) { @@ -1401,6 +1597,24 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos, x + allocation.x, y + allocation.y, width, height); } +void Widget::getMarginArea (int *xMar, int *yMar, int *widthMar, int *heightMar) +{ + *xMar = allocation.x + extraSpace.left; + *yMar = allocation.y + extraSpace.top; + *widthMar = allocation.width - (extraSpace.left + extraSpace.right); + *heightMar = getHeight () - (extraSpace.top + extraSpace.bottom); +} + +void Widget::getBorderArea (int *xBor, int *yBor, int *widthBor, int *heightBor) +{ + getMarginArea (xBor, yBor, widthBor, heightBor); + + *xBor += style->margin.left; + *yBor += style->margin.top; + *widthBor -= style->margin.left + style->margin.right; + *heightBor -= style->margin.top + style->margin.bottom; +} + /** * \brief Return the padding area (content plus padding). * @@ -1410,18 +1624,31 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos, void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad) { - *xPad = allocation.x + style->margin.left + style->borderWidth.left; - *yPad = allocation.y + style->margin.top + style->borderWidth.top; - *widthPad = allocation.width - style->margin.left - style->borderWidth.left - - style->margin.right - style->borderWidth.right; - *heightPad = getHeight () - style->margin.top - style->borderWidth.top - - style->margin.bottom - style->borderWidth.bottom; + getBorderArea (xPad, yPad, widthPad, heightPad); + + *xPad += style->borderWidth.left; + *yPad += style->borderWidth.top; + *widthPad -= style->borderWidth.left + style->borderWidth.right; + *heightPad -= style->borderWidth.top + style->borderWidth.bottom; } void Widget::sizeAllocateImpl (Allocation *allocation) { } +/** + * \brief The actual implementation for calculating + * dw::core::Widget::extraSpace. + * + * The implementation gets a clean value of + * dw::core::Widget::extraSpace, which is only corrected. To make sure + * all possible influences are considered, the implementation of the + * base class should be called, too. + */ +void Widget::calcExtraSpaceImpl () +{ +} + void Widget::markSizeChange (int ref) { } @@ -1734,6 +1961,11 @@ void Widget::leaveNotifyImpl (EventCrossing *) tooltip->onLeave(); } +lout::object::Object *Widget::stackingIterator (bool atEnd) +{ + return NULL; +} + void Widget::removeChild (Widget *child) { // Should be implemented. |