aboutsummaryrefslogtreecommitdiff
path: root/dw/widget.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/widget.cc')
-rw-r--r--dw/widget.cc875
1 files changed, 801 insertions, 74 deletions
diff --git a/dw/widget.cc b/dw/widget.cc
index a3d85d0a..628aa2b4 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -62,6 +62,7 @@ void Widget::WidgetImgRenderer::draw (int x, int y, int width, int height)
// ----------------------------------------------------------------------
+bool Widget::adjustMinWidth = false;
int Widget::CLASS_ID = -1;
Widget::Widget ()
@@ -69,8 +70,10 @@ Widget::Widget ()
DBG_OBJ_CREATE ("dw::core::Widget");
registerName ("dw::core::Widget", &CLASS_ID);
- flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED | HAS_CONTENTS);
- parent = generator = NULL;
+ flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED);
+ parent = quasiParent = generator = container = NULL;
+ DBG_OBJ_SET_PTR ("container", container);
+
layout = NULL;
allocation.x = -1;
@@ -79,6 +82,8 @@ Widget::Widget ()
allocation.ascent = 1;
allocation.descent = 0;
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+
style = NULL;
bgColor = NULL;
buttonSensitive = true;
@@ -153,16 +158,38 @@ void Widget::setParent (Widget *parent)
//printf ("The %s %p becomes a child of the %s %p\n",
// getClassName(), this, parent->getClassName(), parent);
+ // Determine the container. Currently rather simple; will become
+ // more complicated when absolute and fixed positions are
+ // supported.
+ container = NULL;
+ for (Widget *widget = getParent (); widget != NULL && container == NULL;
+ widget = widget->getParent())
+ if (widget->isPossibleContainer ())
+ container = widget;
+ // If there is no possible container widget, there is
+ // (surprisingly!) also no container (i. e. the viewport is
+ // used). Does not occur in dillo, where the toplevel widget is a
+ // Textblock.
+ DBG_OBJ_SET_PTR ("container", container);
+
notifySetParent();
}
+void Widget::setQuasiParent (Widget *quasiParent)
+{
+ this->quasiParent = quasiParent;
+
+ // More to do? Compare with setParent().
+
+ DBG_OBJ_SET_PTR ("quasiParent", quasiParent);
+}
+
void Widget::queueDrawArea (int x, int y, int width, int height)
{
/** \todo Maybe only the intersection? */
- DBG_OBJ_MSGF ("draw", 0, "<b>queueDrawArea</b> (%d, %d, %d, %d)",
- x, y, width, height);
- DBG_OBJ_MSG_START ();
+ DBG_OBJ_ENTER ("draw", 0, "queueDrawArea", "%d, %d, %d, %d",
+ x, y, width, height);
_MSG("Widget::queueDrawArea alloc(%d %d %d %d) wid(%d %d %d %d)\n",
allocation.x, allocation.y,
@@ -171,17 +198,21 @@ void Widget::queueDrawArea (int x, int y, int width, int height)
if (layout)
layout->queueDraw (x + allocation.x, y + allocation.y, width, height);
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
}
/**
* \brief This method should be called, when a widget changes its size.
+ *
+ * A "fast" queueResize will ignore the anchestors, and furthermore
+ * not trigger the idle function. Used only within
+ * viewportSizeChanged, and not available outside Layout and Widget.
*/
-void Widget::queueResize (int ref, bool extremesChanged)
+void Widget::queueResize (int ref, bool extremesChanged, bool fast)
{
- DBG_OBJ_MSGF ("resize", 0, "<b>queueResize</b> (%d, %s)",
- ref, extremesChanged ? "true" : "false");
- DBG_OBJ_MSG_START ();
+ DBG_OBJ_ENTER ("resize", 0, "queueResize", "%d, %s, %s",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
// queueResize() can be called recursively; calls are queued, so
// that actualQueueResize() is clean.
@@ -189,38 +220,60 @@ void Widget::queueResize (int ref, bool extremesChanged)
if (queueResizeEntered ()) {
DBG_OBJ_MSG ("resize", 1, "put into queue");
layout->queueQueueResizeList->put (new Layout::QueueResizeItem
- (this, ref, extremesChanged));
+ (this, ref, extremesChanged, fast));
} else {
- actualQueueResize (ref, extremesChanged);
-
+ actualQueueResize (ref, extremesChanged, fast);
+
+ DBG_IF_RTFL {
+ if (layout == NULL)
+ DBG_OBJ_MSG ("resize", 1, "layout is not set");
+ else if (layout->queueQueueResizeList->size () == 0)
+ DBG_OBJ_MSG ("resize", 1, "queue item list is empty");
+ }
+
while (layout != NULL && layout->queueQueueResizeList->size () > 0) {
+ DBG_IF_RTFL {
+ DBG_OBJ_MSGF ("resize", 1, "queue item list has %d elements:",
+ layout->queueQueueResizeList->size ());
+ DBG_OBJ_MSG_START ();
+ for (int i = 0; i < layout->queueQueueResizeList->size (); i++) {
+ DBG_OBJ_MSGF
+ ("resize", 1,
+ "#%d: widget = %p, ref = %d, extremesChanged = %s, "
+ "fast = %s",
+ i, layout->queueQueueResizeList->get(i)->widget,
+ layout->queueQueueResizeList->get(i)->ref,
+ layout->queueQueueResizeList->get(i)->extremesChanged ?
+ "true" : "false",
+ layout->queueQueueResizeList->get(i)->fast ?
+ "true" : "false");
+ }
+ DBG_OBJ_MSG_END ();
+ DBG_OBJ_MSG ("resize", 1, "taking #0 out of list");
+ }
+
Layout::QueueResizeItem *item = layout->queueQueueResizeList->get (0);
- DBG_OBJ_MSGF ("resize", 1, "taken out of queue queue (size = %d)",
- layout->queueQueueResizeList->size ());
- item->widget->actualQueueResize (item->ref, item->extremesChanged);
+ item->widget->actualQueueResize (item->ref, item->extremesChanged,
+ item->fast);
layout->queueQueueResizeList->remove (0); // hopefully not too large
}
}
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
}
-void Widget::actualQueueResize (int ref, bool extremesChanged)
+void Widget::actualQueueResize (int ref, bool extremesChanged, bool fast)
{
assert (!queueResizeEntered ());
- DBG_OBJ_MSGF ("resize", 0, "<b>actualQueueResize</b> (%d, %s)",
- ref, extremesChanged ? "true" : "false");
- DBG_OBJ_MSG_START ();
+ DBG_OBJ_ENTER ("resize", 0, "actualQueueResize", "%d, %s, %s",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
enterQueueResize ();
Widget *widget2, *child;
- //printf("The %stop-level %s %p with parentRef = %d has changed its size. "
- // "Layout = %p.\n",
- // parent ? "non-" : "", getClassName(), this, parentRef, layout);
-
Flags resizeFlag, extremesFlag;
if (layout) {
@@ -243,36 +296,173 @@ void Widget::actualQueueResize (int ref, bool extremesChanged)
setFlags (extremesFlag);
markExtremesChange (ref);
}
-
- for (widget2 = parent, child = this; widget2;
- child = widget2, widget2 = widget2->parent) {
- //printf (" Setting %s and ALLOCATE_QUEUED for the "
- // "%stop-level %s %p with parentRef = %d\n",
- // resizeFlag == RESIZE_QUEUED ? "RESIZE_QUEUED" : "NEEDS_RESIZE",
- // widget2->parent ? "non-" : "", widget2->getClassName(), widget2,
- // widget2->parentRef);
-
- if (layout && !widget2->resizeQueued ())
- layout->queueResizeList->put (widget2);
-
- widget2->setFlags (resizeFlag);
- widget2->markSizeChange (child->parentRef);
- widget2->setFlags (ALLOCATE_QUEUED);
-
- if (extremesChanged) {
- widget2->setFlags (extremesFlag);
- widget2->markExtremesChange (child->parentRef);
+
+ if (fast) {
+ if (parent) {
+ // In this case, queueResize is called from top (may be a
+ // random entry point) to bottom, so markSizeChange and
+ // markExtremesChange have to be called explicitly for the
+ // parent. The tests (needsResize etc.) are uses to check
+ // whether queueResize has been called for the parent, or
+ // whether this widget is the enty point.
+ if (parent->needsResize () || parent->resizeQueued ())
+ parent->markSizeChange (parentRef);
+ if (parent->extremesChanged () || parent->extremesQueued ())
+ parent->markExtremesChange (parentRef);
+ }
+ } else {
+ for (widget2 = parent, child = this; widget2;
+ child = widget2, widget2 = widget2->parent) {
+ if (layout && !widget2->resizeQueued ())
+ layout->queueResizeList->put (widget2);
+
+ DBG_OBJ_MSGF ("resize", 2, "setting %s and ALLOCATE_QUEUED for %p",
+ resizeFlag == RESIZE_QUEUED ?
+ "RESIZE_QUEUED" : "NEEDS_RESIZE",
+ widget2);
+
+ widget2->setFlags (resizeFlag);
+ widget2->markSizeChange (child->parentRef);
+ widget2->setFlags (ALLOCATE_QUEUED);
+
+ if (extremesChanged) {
+ widget2->setFlags (extremesFlag);
+ widget2->markExtremesChange (child->parentRef);
+ }
}
- }
- if (layout)
- layout->queueResize (extremesChanged);
+ if (layout)
+ layout->queueResize (extremesChanged);
+ }
leaveQueueResize ();
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::containerSizeChanged ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChanged");
+
+ // If there is a container widget (not the viewport), which has not
+ // changed its size (which can be determined by the respective
+ // flags: this method is called recursively), this widget will
+ // neither change its size. Also, the recursive iteration can be
+ // stopped, since the children of this widget will
+ if (container == NULL ||
+ container->needsResize () || container->resizeQueued () ||
+ container->extremesChanged () || container->extremesQueued ()) {
+ // Viewport (container == NULL) or container widget has changed
+ // its size.
+ if (affectedByContainerSizeChange ())
+ queueResizeFast (0, true);
+
+ // Even if *this* widget is not affected, children may be, so
+ // iterate over children.
+ containerSizeChangedForChildren ();
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool Widget::affectedByContainerSizeChange ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "affectedByContainerSizeChange");
+
+ bool ret;
+
+ // This standard implementation is suitable for all widgets which
+ // call correctRequisition() and correctExtremes(), even in the way
+ // how Textblock and Image do (see comments there). Has to be kept
+ // in sync.
+
+ if (container == NULL) {
+ if (style::isAbsLength (getStyle()->width) &&
+ style::isAbsLength (getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (getStyle()->width) ||
+ style::isPerLength (getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (getStyle()->width == style::LENGTH_AUTO ?
+ usesAvailWidth () : false) ||
+ (getStyle()->height == style::LENGTH_AUTO ?
+ usesAvailHeight () : false);
+ } else
+ ret = container->affectsSizeChangeContainerChild (this);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+ return ret;
+}
+
+bool Widget::affectsSizeChangeContainerChild (Widget *child)
+{
+ DBG_OBJ_ENTER ("resize", 0, "affectsSizeChangeContainerChild", "%p", child);
+
+ bool ret;
+
+ // From the point of view of the container. This standard
+ // implementation should be suitable for most (if not all)
+ // containers.
+
+ if (style::isAbsLength (child->getStyle()->width) &&
+ style::isAbsLength (child->getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (child->getStyle()->width) ||
+ style::isPerLength (child->getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (child->getStyle()->width == style::LENGTH_AUTO ?
+ child->usesAvailWidth () : false) ||
+ (child->getStyle()->height == style::LENGTH_AUTO ?
+ child->usesAvailHeight () : false);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+ return ret;
+}
+
+void Widget::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ // Working, but inefficient standard implementation.
+ Iterator *it = iterator ((Content::Type)(Content::WIDGET_IN_FLOW |
+ Content::WIDGET_OOF_CONT),
+ false);
+ while (it->next ())
+ it->getContent()->widget->containerSizeChanged ();
+ it->unref ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailWidth() is called.
+ */
+bool Widget::usesAvailWidth ()
+{
+ return false;
}
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailHeight() is called.
+ */
+bool Widget::usesAvailHeight ()
+{
+ return false;
+}
/**
* \brief This method is a wrapper for Widget::sizeRequestImpl(); it calls
@@ -282,8 +472,7 @@ void Widget::sizeRequest (Requisition *requisition)
{
assert (!queueResizeEntered ());
- DBG_OBJ_MSG ("resize", 0, "<b>sizeRequest</b>");
- DBG_OBJ_MSG_START ();
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
enterSizeRequest ();
@@ -319,7 +508,240 @@ void Widget::sizeRequest (Requisition *requisition)
leaveSizeRequest ();
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Used to evaluate Widget::adjustMinWidth.
+ *
+ * If extremes == NULL, getExtremes is called.
+ */
+int Widget::getMinWidth (Extremes *extremes)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "getMinWidth");
+ int minWidth;
+
+ if (adjustMinWidth) {
+ Extremes extremes2;
+ if (extremes == NULL) {
+ getExtremes (&extremes2);
+ extremes = &extremes2;
+ }
+
+ minWidth = extremes->minWidthIntrinsic;
+ } else
+ minWidth = 0;
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", minWidth);
+ DBG_OBJ_LEAVE ();
+
+ return minWidth;
+}
+
+/**
+ * Return available width including margin/border/padding
+ * (extraSpace?), not only the content width.
+ */
+int Widget::getAvailWidth (bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize", 0, "getAvailWidth", "%s",
+ forceValue ? "true" : "false");
+
+ int width;
+
+ if (parent == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (getStyle()->width));
+ width = style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ } else {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ if (style::isPerLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->width));
+ width = applyPerWidth (viewportWidth, getStyle()->width);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ width = viewportWidth;
+ }
+ }
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ width = parent->getAvailWidthOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ width = quasiParent->getAvailWidthOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ if (width != -1)
+ width = misc::max (width, getMinWidth (NULL));
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+
+ return width;
+}
+
+/**
+ * Return available height including margin/border/padding
+ * (extraSpace?), not only the content height.
+ */
+int Widget::getAvailHeight (bool forceValue)
+{
+ // TODO Correct by ... not extremes, but ...? (Height extremes?)
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailHeight", "%s",
+ forceValue ? "true" : "false");
+
+ int height;
+
+ if (parent == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (getStyle()->height));
+ height = style::absLengthVal (getStyle()->height) + boxDiffHeight ();
+ } else if (style::isPerLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->height));
+ // Notice that here -- unlike getAvailWidth() --
+ // layout->hScrollbarThickness is not considered here;
+ // something like canvasWidthGreater (analogue to
+ // canvasHeightGreater) would be complicated and lead to
+ // possibly contradictory self-references.
+ height = applyPerHeight (layout->viewportHeight, getStyle()->height);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ height = layout->viewportHeight;
+ }
+
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ height = quasiParent->getAvailHeightOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ height = quasiParent->getAvailHeightOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+void Widget::correctRequisition (Requisition *requisition,
+ void (*splitHeightFun) (int, int *, int *))
+{
+ // TODO Correct height by ... not extremes, but ...? (Height extremes?)
+
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisition", "%d * (%d + %d), ...",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+
+ if (container == NULL && quasiParent == NULL) {
+ if (style::isAbsLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (getStyle()->width));
+ requisition->width =
+ misc::max (style::absLengthVal (getStyle()->width)
+ + boxDiffWidth (),
+ getMinWidth (NULL));
+ } else if (style::isPerLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->width));
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ requisition->width =
+ misc::max (applyPerWidth (viewportWidth, getStyle()->width),
+ getMinWidth (NULL));
+ }
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (style::isAbsLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (getStyle()->height));
+ splitHeightFun (style::absLengthVal (getStyle()->height)
+ + boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ } else if (style::isPerLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->height));
+#if 0
+ // TODO Percentage heights are somewhat more complicated. Has
+ // to be clarified.
+
+ // For layout->viewportHeight, see comment in getAvailHeight().
+ splitHeightFun (applyPerHeight (layout->viewportHeight,
+ getStyle()->height),
+ &requisition->ascent, &requisition->descent);
+#endif
+ }
+ } else if (container)
+ container->correctRequisitionOfChild (this, requisition, splitHeightFun);
+ else // if (quasiParent)
+ // Here, quasiParent plays the same role as the container.
+ quasiParent->correctRequisitionOfChild (this, requisition,
+ splitHeightFun);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctExtremes (Extremes *extremes)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremes", "%d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ if (container == NULL && quasiParent == NULL) {
+ if (style::isAbsLength (getStyle()->width))
+ extremes->minWidth = extremes->maxWidth =
+ misc::max (style::absLengthVal (getStyle()->width)
+ + boxDiffWidth (),
+ getMinWidth (extremes));
+ else if (style::isPerLength (getStyle()->width)) {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ extremes->minWidth = extremes->maxWidth =
+ misc::max (applyPerWidth (viewportWidth, getStyle()->width),
+ getMinWidth (extremes));
+ }
+ } else if (container)
+ container->correctExtremesOfChild (this, extremes);
+ else // if (quasiParent)
+ // Here, quasiParent plays the same role as the container.
+ quasiParent->correctExtremesOfChild (this, extremes);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
}
/**
@@ -329,7 +751,7 @@ void Widget::getExtremes (Extremes *extremes)
{
assert (!queueResizeEntered ());
- DBG_OBJ_MSG ("resize", 0, "<b>getExtremes</b>");
+ DBG_OBJ_ENTER0 ("resize", 0, "getExtremes");
DBG_OBJ_MSG_START ();
enterGetExtremes ();
@@ -344,18 +766,32 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ // For backward compatibility (part 1/2):
+ extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
+
getExtremesImpl (extremes);
+
+ // For backward compatibility (part 2/2):
+ if (extremes->minWidthIntrinsic == -1)
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ if (extremes->maxWidthIntrinsic == -1)
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+
this->extremes = *extremes;
unsetFlags (EXTREMES_CHANGED);
DBG_OBJ_SET_NUM ("extremes.minWidth", extremes->minWidth);
+ DBG_OBJ_SET_NUM ("extremes.minWidthIntrinsic",
+ extremes->minWidthIntrinsic);
DBG_OBJ_SET_NUM ("extremes.maxWidth", extremes->maxWidth);
+ DBG_OBJ_SET_NUM ("extremes.maxWidthIntrinsic",
+ extremes->maxWidthIntrinsic);
} else
*extremes = this->extremes;
leaveGetExtremes ();
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
}
/**
@@ -369,10 +805,9 @@ void Widget::sizeAllocate (Allocation *allocation)
assert (!getExtremesEntered ());
assert (resizeIdleEntered ());
- DBG_OBJ_MSGF ("resize", 0, "<b>sizeAllocate</b> (%d, %d; %d * (%d + %d))",
- allocation->x, allocation->y, allocation->width,
- allocation->ascent, allocation->descent);
- DBG_OBJ_MSG_START ();
+ DBG_OBJ_ENTER ("resize", 0, "sizeAllocate", "%d, %d; %d * (%d + %d)",
+ allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
DBG_OBJ_MSGF ("resize", 1,
"old allocation (%d, %d; %d * (%d + %d)); needsAllocate: %s",
@@ -435,7 +870,7 @@ void Widget::sizeAllocate (Allocation *allocation)
leaveSizeAllocate ();
- DBG_OBJ_MSG_END ();
+ DBG_OBJ_LEAVE ();
}
bool Widget::buttonPress (EventButton *event)
@@ -507,6 +942,28 @@ void Widget::setStyle (style::Style *style)
queueResize (0, true);
else
queueDraw ();
+
+ // These should better be attributed to the style itself, and a
+ // script processing RTFL messages could transfer it to something
+ // equivalent:
+
+ DBG_OBJ_SET_NUM ("style.margin.top", style->margin.top);
+ DBG_OBJ_SET_NUM ("style.margin.bottom", style->margin.bottom);
+ DBG_OBJ_SET_NUM ("style.margin.left", style->margin.left);
+ DBG_OBJ_SET_NUM ("style.margin.right", style->margin.right);
+
+ DBG_OBJ_SET_NUM ("style.border-width.top", style->borderWidth.top);
+ DBG_OBJ_SET_NUM ("style.border-width.bottom", style->borderWidth.bottom);
+ DBG_OBJ_SET_NUM ("style.border-width.left", style->borderWidth.left);
+ DBG_OBJ_SET_NUM ("style.border-width.right", style->borderWidth.right);
+
+ DBG_OBJ_SET_NUM ("style.padding.top", style->padding.top);
+ DBG_OBJ_SET_NUM ("style.padding.bottom", style->padding.bottom);
+ DBG_OBJ_SET_NUM ("style.padding.left", style->padding.left);
+ DBG_OBJ_SET_NUM ("style.padding.right", style->padding.right);
+
+ DBG_OBJ_SET_NUM ("style.border-spacing (h)", style->hBorderSpacing);
+ DBG_OBJ_SET_NUM ("style.border-spacing (v)", style->vBorderSpacing);
}
/**
@@ -781,14 +1238,6 @@ void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad,
- style->margin.bottom - style->borderWidth.bottom;
}
-void Widget::getExtremesImpl (Extremes *extremes)
-{
- /* Simply return the requisition width */
- Requisition requisition;
- sizeRequest (&requisition);
- extremes->minWidth = extremes->maxWidth = requisition.width;
-}
-
void Widget::sizeAllocateImpl (Allocation *allocation)
{
}
@@ -801,6 +1250,264 @@ void Widget::markExtremesChange (int ref)
{
}
+int Widget::applyPerWidth (int containerWidth, style::Length perWidth)
+{
+ return style::multiplyWithPerLength (containerWidth, perWidth)
+ + boxDiffWidth ();
+}
+
+int Widget::applyPerHeight (int containerHeight, style::Length perHeight)
+{
+ return style::multiplyWithPerLength (containerHeight, perHeight)
+ + boxDiffHeight ();
+}
+
+int Widget::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ // This is a halfway suitable implementation for all
+ // containers. For simplification, this will be used during the
+ // development; then, a differentiation could be possible.
+
+ // TODO Correct by extremes?
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailWidthOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int width;
+
+ if (child->getStyle()->width == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ int availWidth = getAvailWidth (forceValue);
+ if (availWidth == -1)
+ width = -1;
+ else
+ width = misc::max (availWidth - boxDiffWidth (), 0);
+ } else {
+ // In most cases, the toplevel widget should be a container, so
+ // the container is non-NULL when the parent is non-NULL. Just
+ // in case ...:
+ Widget *effContainer =
+ child->container ? child->container : child->parent;
+
+ if (effContainer == this) {
+ if (style::isAbsLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (child->getStyle()->width));
+ width = misc::max (style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth (), 0);
+ } else {
+ assert (style::isPerLength (child->getStyle()->width));
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->width));
+
+ int availWidth = getAvailWidth (forceValue);
+ if (availWidth == -1)
+ width = -1;
+ else
+ width =
+ misc::max (child->applyPerWidth (availWidth - boxDiffWidth (),
+ child->getStyle()->width),
+ 0);
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ width = effContainer->getAvailWidthOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ if (width != -1)
+ width = misc::max (width, child->getMinWidth (NULL));
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+
+ return width;
+}
+
+int Widget::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ // TODO Correct by extremes? (Height extemes?)
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailHeightOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int height;
+
+ if (child->getStyle()->height == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ int availHeight = getAvailHeight (forceValue);
+ if (availHeight == -1)
+ height = -1;
+ else
+ height = misc::max (availHeight - boxDiffHeight (), 0);
+ } else {
+ // In most cases, the toplevel widget should be a container, so
+ // the container is non-NULL when the parent is non-NULL. Just
+ // in case ...:
+ Widget *effContainer =
+ child->container ? child->container : child->parent;
+
+ if (effContainer == this) {
+ if (style::isAbsLength (child->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (child->getStyle()->height));
+ height = misc::max (style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight (), 0);
+ } else {
+ assert (style::isPerLength (child->getStyle()->height));
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->height));
+
+ int availHeight = getAvailHeight (forceValue);
+ if (availHeight == -1)
+ height = -1;
+ else
+ height =
+ misc::max (child->applyPerHeight (availHeight -
+ boxDiffHeight (),
+ child->getStyle()->height),
+ 0);
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ height = effContainer->getAvailHeightOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+void Widget::correctRequisitionOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisitionOfChild",
+ "%p, %d * (%d + %d), ...", child, requisition->width,
+ requisition->ascent, requisition->descent);
+
+ correctReqWidthOfChild (child, requisition);
+ correctReqHeightOfChild (child, requisition, splitHeightFun);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctReqWidthOfChild (Widget *child, Requisition *requisition)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctReqWidthOfChild", "%p, %d * (%d + %d)",
+ child, requisition->width, requisition->ascent,
+ requisition->descent);
+
+ if (style::isAbsLength (child->getStyle()->width))
+ requisition->width =
+ misc::max (style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth (),
+ child->getMinWidth (NULL));
+ else if (style::isPerLength (child->getStyle()->width)) {
+ int availWidth = getAvailWidth (false);
+ if (availWidth != -1) {
+ int containerWidth = availWidth - boxDiffWidth ();
+ requisition->width =
+ misc::max (child->applyPerWidth (containerWidth,
+ child->getStyle()->width),
+ child->getMinWidth (NULL));
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctReqHeightOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*))
+{
+ // TODO Correct height by extremes? (Height extemes?)
+
+ DBG_OBJ_ENTER ("resize", 0, "correctReqHeightOfChild",
+ "%p, %d * (%d + %d), ...", child, requisition->width,
+ requisition->ascent, requisition->descent);
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (style::isAbsLength (child->getStyle()->height))
+ splitHeightFun (style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ else if (style::isPerLength (child->getStyle()->height)) {
+#if 0
+ // TODO Percentage heights are somewhat more complicated. Has to
+ // be clarified. See also Widget::correctRequisition.
+
+ int availHeight = getAvailHeight (false);
+ if (availHeight != -1) {
+ int containerHeight = availHeight - boxDiffHeight ();
+ splitHeightFun (child->applyPerHeight (containerHeight,
+ child->getStyle()->height),
+ &requisition->ascent, &requisition->descent);
+ }
+#endif
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctExtremesOfChild (Widget *child, Extremes *extremes)
+{
+ // See comment in correctRequisitionOfChild.
+
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremesOfChild",
+ "%p, %d (%d) / %d (%d)",
+ child, extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ if (style::isAbsLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (child->getStyle()->width));
+ extremes->minWidth = extremes->maxWidth =
+ misc::max (style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth (),
+ child->getMinWidth (extremes));
+ } else if (style::isPerLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->width));
+ int availWidth = getAvailWidth (false);
+ if (availWidth != -1) {
+ int containerWidth = availWidth - boxDiffWidth ();
+ DBG_OBJ_MSGF ("resize", 1, "containerWidth = %d - %d = %d",
+ availWidth, boxDiffWidth (), containerWidth);
+ extremes->minWidth = extremes->maxWidth =
+ misc::max (child->applyPerWidth (containerWidth,
+ child->getStyle()->width),
+ child->getMinWidth (extremes));
+ }
+ } else
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
/**
* \brief This method is called after a widget has been set as the top of a
* widget tree.
@@ -820,16 +1527,16 @@ void Widget::notifySetParent()
{
}
-void Widget::setWidth (int width)
-{
-}
-
-void Widget::setAscent (int ascent)
+bool Widget::isBlockLevel ()
{
+ // Most widgets are not block-level.
+ return false;
}
-void Widget::setDescent (int descent)
+bool Widget::isPossibleContainer ()
{
+ // In most (all?) cases identical to:
+ return isBlockLevel ();
}
bool Widget::buttonPressImpl (EventButton *event)
@@ -849,7 +1556,7 @@ bool Widget::motionNotifyImpl (EventMotion *event)
void Widget::enterNotifyImpl (EventCrossing *)
{
- core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
if (tooltip)
tooltip->onEnter();
@@ -857,7 +1564,7 @@ void Widget::enterNotifyImpl (EventCrossing *)
void Widget::leaveNotifyImpl (EventCrossing *)
{
- core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
if (tooltip)
tooltip->onLeave();
@@ -869,5 +1576,25 @@ void Widget::removeChild (Widget *child)
misc::assertNotReached ();
}
+// ----------------------------------------------------------------------
+
+void splitHeightPreserveAscent (int height, int *ascent, int *descent)
+{
+ *descent = height - *ascent;
+ if (*descent < 0) {
+ *descent = 0;
+ *ascent = height;
+ }
+}
+
+void splitHeightPreserveDescent (int height, int *ascent, int *descent)
+{
+ *ascent = height - *descent;
+ if (*ascent < 0) {
+ *ascent = 0;
+ *descent = height;
+ }
+}
+
} // namespace core
} // namespace dw