diff options
Diffstat (limited to 'dw/widget.cc')
-rw-r--r-- | dw/widget.cc | 276 |
1 files changed, 197 insertions, 79 deletions
diff --git a/dw/widget.cc b/dw/widget.cc index 464459ba..252ff8c8 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 (); @@ -117,35 +122,111 @@ Widget::~Widget () /** - * \brief Calculates the intersection of widget->allocation and area, returned - * in intersection (in widget coordinates!). + * \brief Calculates the intersection of the visible allocation + * (i. e. the intersection with the visible parent allocation) and + * "area" (in widget coordinates referring to "refWidget"), + * returned in intersection (in widget coordinates). * - * Typically used by containers when - * drawing their children. Returns whether intersection is not empty. + * Typically used by containers when drawing their children (passing + * "this" as "refWidget"). Returns whether intersection is not empty. */ -bool Widget::intersects (Rectangle *area, Rectangle *intersection) +bool Widget::intersects (Widget *refWidget, Rectangle *area, + Rectangle *intersection) { - Rectangle parentArea, childArea; + DBG_OBJ_ENTER ("draw", 0, "intersects", "%p, [%d, %d, %d * %d]", + refWidget, area->x, area->y, area->width, area->height); + bool r; - parentArea = *area; - parentArea.x += parent->allocation.x; - parentArea.y += parent->allocation.y; + if (wasAllocated ()) { + *intersection = *area; + intersection->x += refWidget->allocation.x; + intersection->y += refWidget->allocation.y; + + r = true; + // "RefWidget" is excluded; it is assumed that "area" its already within + // its allocation. + for (Widget *widget = this; r && widget != refWidget; + widget = widget->parent) { + assert (widget != NULL); // refWidget must be ancestor. + + Rectangle widgetArea, newIntersection; + widgetArea.x = widget->allocation.x; + widgetArea.y = widget->allocation.y; + widgetArea.width = widget->allocation.width; + widgetArea.height = widget->getHeight (); + + if (intersection->intersectsWith (&widgetArea, &newIntersection)) { + DBG_OBJ_MSGF ("draw", 1, "new intersection: %d, %d, %d * %d", + newIntersection.x, newIntersection.y, + newIntersection.width, newIntersection.height); + *intersection = newIntersection; + } else { + DBG_OBJ_MSG ("draw", 1, "no new intersection"); + r = false; + } + } - childArea.x = allocation.x; - childArea.y = allocation.y; - childArea.width = allocation.width; - childArea.height = getHeight (); + if (r) { + intersection->x -= allocation.x; + intersection->y -= allocation.y; - if (parentArea.intersectsWith (&childArea, intersection)) { - intersection->x -= allocation.x; - intersection->y -= allocation.y; - return true; - } else - return false; + DBG_OBJ_MSGF ("draw", 1, "final intersection: %d, %d, %d * %d", + intersection->x, intersection->y, + intersection->width, intersection->height); + } + } else { + r = false; + DBG_OBJ_MSG ("draw", 1, "not allocated"); + } + + if (r) + DBG_OBJ_MSGF ("draw", 1, "=> true: %d, %d, %d * %d", + intersection->x, intersection->y, + intersection->width, intersection->height); + else + DBG_OBJ_MSG ("draw", 1, "=> false"); + + DBG_OBJ_LEAVE (); + return r; +} + +/** + * See \ref dw-interrupted-drawing for details. + */ +void Widget::drawInterruption (View *view, Rectangle *area, + DrawingContext *context) +{ + Rectangle thisArea; + if (intersects (layout->topLevel, context->getToplevelArea (), &thisArea)) + draw (view, &thisArea, context); + + context->addWidgetProcessedAsInterruption (this); +} + +Widget *Widget::getWidgetAtPoint (int x, int y, + GettingWidgetAtPointContext *context) +{ + // Suitable for simple widgets, without children. + + if (inAllocation (x, y)) + return this; + else + return NULL; +} + +Widget *Widget::getWidgetAtPointInterrupted (int x, int y, + GettingWidgetAtPointContext + *context) +{ + Widget *widgetAtPoint = getWidgetAtPoint (x, y, context); + context->addWidgetProcessedAsInterruption (this); + return widgetAtPoint; } void Widget::setParent (Widget *parent) { + DBG_OBJ_ENTER ("construct", 0, "setParent", "%p", parent); + this->parent = parent; layout = parent->layout; @@ -170,7 +251,21 @@ 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(); + + DBG_OBJ_LEAVE (); } void Widget::setQuasiParent (Widget *quasiParent) @@ -472,7 +567,8 @@ bool Widget::usesAvailHeight () * \brief This method is a wrapper for Widget::sizeRequestImpl(); it calls * the latter only when needed. */ -void Widget::sizeRequest (Requisition *requisition) +void Widget::sizeRequest (Requisition *requisition, bool posDefined, int x, + int y) { assert (!queueResizeEntered ()); @@ -490,8 +586,9 @@ void Widget::sizeRequest (Requisition *requisition) } if (needsResize ()) { + calcExtraSpace (); /** \todo Check requisition == &(this->requisition) and do what? */ - sizeRequestImpl (requisition); + sizeRequestImpl (requisition, posDefined, x, y); this->requisition = *requisition; unsetFlags (NEEDS_RESIZE); @@ -519,7 +616,7 @@ int Widget::getMinWidth (Extremes *extremes, bool forceValue) { DBG_IF_RTFL { if (extremes) - DBG_OBJ_ENTER ("resize", 0, "getMinWidth", "[%d (%d) / %d (%d), %s", + DBG_OBJ_ENTER ("resize", 0, "getMinWidth", "[%d (%d) / %d (%d)], %s", extremes->minWidth, extremes->minWidthIntrinsic, extremes->maxWidth, extremes->maxWidthIntrinsic, forceValue ? "true" : "false"); @@ -627,7 +724,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 @@ -909,6 +1006,8 @@ void Widget::getExtremes (Extremes *extremes) } if (extremesChanged ()) { + calcExtraSpace (); + // For backward compatibility (part 1/2): extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1; @@ -939,6 +1038,28 @@ 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); +} + +Widget *Widget::sizeRequestReference () +{ + return NULL; +} + +/** * \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when * needed. */ @@ -1082,6 +1203,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 @@ -1196,7 +1327,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); @@ -1226,8 +1357,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); @@ -1363,53 +1496,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) { @@ -1417,6 +1503,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). * @@ -1426,18 +1530,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) { } @@ -1753,6 +1870,7 @@ void Widget::leaveNotifyImpl (EventCrossing *) tooltip->onLeave(); } + void Widget::removeChild (Widget *child) { // Should be implemented. |