aboutsummaryrefslogtreecommitdiff
path: root/dw/widget.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/widget.cc')
-rw-r--r--dw/widget.cc384
1 files changed, 312 insertions, 72 deletions
diff --git a/dw/widget.cc b/dw/widget.cc
index 7b0d4c99..d5c856d2 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 ();
@@ -120,32 +125,231 @@ Widget::~Widget ()
* \brief Calculates the intersection of widget->allocation and area, 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. Returns whether
+ * intersection is not empty.
*/
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);
- parentArea = *area;
- parentArea.x += parent->allocation.x;
- parentArea.y += parent->allocation.y;
+ DBG_IF_RTFL {
+ misc::StringBuffer sb;
+ iteratorStack->intoStringBuffer (&sb);
+ DBG_OBJ_MSGF ("draw", 2, "initial iteratorStack: %s", sb.getChars ());
+ }
- childArea.x = allocation.x;
- childArea.y = allocation.y;
- childArea.width = allocation.width;
- childArea.height = getHeight ();
+ Object *si = NULL;
- if (parentArea.intersectsWith (&childArea, intersection)) {
- intersection->x -= allocation.x;
- intersection->y -= allocation.y;
- return true;
+ if (iteratorStack->atRealTop ()) {
+ si = stackingIterator (false);
+ if (si) {
+ iteratorStack->push (si);
+ }
} else
- return false;
+ 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);
+ //if (interruptedWidget != NULL)
+ // DBG_OBJ_MSGF ("draw", 0,
+ // "===== Assertion failed: interruptedWidget = %p =====",
+ // interruptedWidget);
+}
+
+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 ());
+ }
+
+ // See comment in drawTotal().
+
+ // 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 ("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)
{
+ DBG_OBJ_ENTER ("construct", 0, "setParent", "%p", parent);
+
this->parent = parent;
layout = parent->layout;
@@ -170,7 +374,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)
@@ -490,6 +708,7 @@ void Widget::sizeRequest (Requisition *requisition)
}
if (needsResize ()) {
+ calcExtraSpace ();
/** \todo Check requisition == &(this->requisition) and do what? */
sizeRequestImpl (requisition);
this->requisition = *requisition;
@@ -631,7 +850,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
@@ -912,6 +1131,8 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ calcExtraSpace ();
+
// For backward compatibility (part 1/2):
extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
@@ -941,6 +1162,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.
*/
@@ -1084,6 +1323,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
@@ -1198,7 +1447,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);
@@ -1228,8 +1477,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);
@@ -1365,53 +1616,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)
{
@@ -1419,6 +1623,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).
*
@@ -1428,18 +1650,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)
{
}
@@ -1752,6 +1987,11 @@ void Widget::leaveNotifyImpl (EventCrossing *)
tooltip->onLeave();
}
+lout::object::Object *Widget::stackingIterator (bool atEnd)
+{
+ return NULL;
+}
+
void Widget::removeChild (Widget *child)
{
// Should be implemented.