diff options
author | Sebastian Geerken <devnull@localhost> | 2013-06-04 21:30:49 +0200 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2013-06-04 21:30:49 +0200 |
commit | c1b240fd379183b3e44d4eb8f120146e85c970f6 (patch) | |
tree | b89a7bfc638e13683368b7982f659e15779f4adc /dw | |
parent | 5a915db6312e387721f61c82166ba7b30abe7738 (diff) |
Absolutely positioned elements: start.
Diffstat (limited to 'dw')
-rw-r--r-- | dw/outofflowmgr.cc | 220 | ||||
-rw-r--r-- | dw/outofflowmgr.hh | 61 |
2 files changed, 255 insertions, 26 deletions
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc index e85c630e..75457cb7 100644 --- a/dw/outofflowmgr.cc +++ b/dw/outofflowmgr.cc @@ -289,6 +289,16 @@ OutOfFlowMgr::TBInfo::~TBInfo () delete rightFloatsGB; } +OutOfFlowMgr::AbsolutelyPositioned::AbsolutelyPositioned (OutOfFlowMgr *oofm, + core::Widget *widget, + Textblock + *generatingBlock, + int externalIndex) +{ + this->widget = widget; + dirty = true; +} + OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock) { //printf ("OutOfFlowMgr::OutOfFlowMgr\n"); @@ -310,6 +320,8 @@ OutOfFlowMgr::OutOfFlowMgr (Textblock *containingBlock) leftFloatsMark = rightFloatsMark = 0; lastLeftTBIndex = lastRightTBIndex = 0; + absolutelyPositioned = new Vector<AbsolutelyPositioned> (1, true); + containingBlockWasAllocated = containingBlock->wasAllocated (); if (containingBlockWasAllocated) containingBlockAllocation = *(containingBlock->getAllocation()); @@ -336,6 +348,8 @@ OutOfFlowMgr::~OutOfFlowMgr () // last. delete leftFloatsAll; delete rightFloatsAll; + + delete absolutelyPositioned; } void OutOfFlowMgr::sizeAllocateStart (Allocation *containingBlockAllocation) @@ -354,9 +368,10 @@ void OutOfFlowMgr::sizeAllocateEnd () moveFromGBToCB (LEFT); moveFromGBToCB (RIGHT); - // 2. Floats have to be allocated + // 2. Floats and absolutely positioned blocks have to be allocated sizeAllocateFloats (LEFT); sizeAllocateFloats (RIGHT); + sizeAllocateAbsolutelyPositioned (); // 3. Textblocks have already been allocated, but we store some // information for later use. TODO: Update this comment! @@ -574,11 +589,13 @@ void OutOfFlowMgr::sizeAllocateFloats (Side side) void OutOfFlowMgr::draw (View *view, Rectangle *area) { - draw (leftFloatsCB, view, area); - draw (rightFloatsCB, view, area); + drawFloats (leftFloatsCB, view, area); + drawFloats (rightFloatsCB, view, area); + drawAbsolutelyPositioned (view, area); } -void OutOfFlowMgr::draw (SortedFloatsVector *list, View *view, Rectangle *area) +void OutOfFlowMgr::drawFloats (SortedFloatsVector *list, View *view, + Rectangle *area) { // This could be improved, since the list is sorted: search the // first float fitting into the area, and iterate until one is @@ -591,10 +608,20 @@ void OutOfFlowMgr::draw (SortedFloatsVector *list, View *view, Rectangle *area) } } +void OutOfFlowMgr::drawAbsolutelyPositioned (View *view, Rectangle *area) +{ + for (int i = 0; i < absolutelyPositioned->size(); i++) { + AbsolutelyPositioned *abspos = absolutelyPositioned->get(i); + core::Rectangle childArea; + if (abspos->widget->intersects (area, &childArea)) + abspos->widget->draw (view, &childArea); + } +} + bool OutOfFlowMgr::isWidgetOutOfFlow (core::Widget *widget) { - // Will be extended for absolute positions. - return widget->getStyle()->vloat != FLOAT_NONE; + // May be extended for fixed (and relative?) positions. + return isWidgetFloat (widget) || isWidgetAbsolutelyPositioned (widget); } void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock, @@ -618,7 +645,7 @@ void OutOfFlowMgr::addWidgetInFlow (Textblock *textblock, void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock, int externalIndex) { - if (widget->getStyle()->vloat != FLOAT_NONE) { + if (isWidgetFloat (widget)) { TBInfo *tbInfo = getTextblock (generatingBlock); Float *vloat = new Float (this, widget, generatingBlock, externalIndex); @@ -688,8 +715,15 @@ void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock, leftFloatsAll->size() + rightFloatsAll->size() - 1; floatsByWidget->put (new TypedPointer<Widget> (widget), vloat); + } else if (isWidgetAbsolutelyPositioned (widget)) { + AbsolutelyPositioned *abspos = + new AbsolutelyPositioned (this, widget, generatingBlock, + externalIndex); + absolutelyPositioned->put (abspos); + widget->parentRef = + createRefAbsolutelyPositioned (absolutelyPositioned->size() - 1); } else - // Will continue here for absolute positions. + // May be extended. assertNotReached(); } @@ -745,9 +779,10 @@ void OutOfFlowMgr::markSizeChange (int ref) // TODO May cause problems (endless resizing?) when float has no // defined position. vloat->generatingBlock->borderChanged (vloat->yReal, vloat->widget); - } else - // later: absolute positions - assertNotReached(); + } else if (isRefAbsolutelyPositioned (ref)) { + int i = getAbsolutelyPositionedIndexFromRef (ref); + absolutelyPositioned->get(i)->dirty = true; + } } @@ -758,14 +793,16 @@ void OutOfFlowMgr::markExtremesChange (int ref) Widget *OutOfFlowMgr::getWidgetAtPoint (int x, int y, int level) { - Widget *childAtPoint = getWidgetAtPoint (leftFloatsCB, x, y, level); + Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level); if (childAtPoint == NULL) - childAtPoint = getWidgetAtPoint (rightFloatsCB, x, y, level); + childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level); + if (childAtPoint == NULL) + childAtPoint = getAbsolutelyPositionedWidgetAtPoint (x, y, level); return childAtPoint; } -Widget *OutOfFlowMgr::getWidgetAtPoint (SortedFloatsVector *list, - int x, int y, int level) +Widget *OutOfFlowMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, + int x, int y, int level) { for (int i = 0; i < list->size(); i++) { // Could use binary search to be faster. @@ -778,9 +815,30 @@ Widget *OutOfFlowMgr::getWidgetAtPoint (SortedFloatsVector *list, return NULL; } +Widget *OutOfFlowMgr::getAbsolutelyPositionedWidgetAtPoint (int x, int y, + int level) +{ + for (int i = 0; i < absolutelyPositioned->size(); i++) { + AbsolutelyPositioned *abspos = absolutelyPositioned->get(i); + Widget *childAtPoint = abspos->widget->getWidgetAtPoint (x, y, level + 1); + if (childAtPoint) + return childAtPoint; + } + + return NULL; +} void OutOfFlowMgr::tellPosition (Widget *widget, int yReq) { + if (isWidgetFloat (widget)) + tellFloatPosition (widget, yReq); + + // Nothing to do for absolutely positioned blocks. +} + + +void OutOfFlowMgr::tellFloatPosition (Widget *widget, int yReq) +{ assert (yReq >= 0); Float *vloat = findFloatByWidget(widget); @@ -977,12 +1035,14 @@ void OutOfFlowMgr::getSize (int cbWidth, int cbHeight, //printf ("[%p] GET_SIZE (%d / %d floats)...\n", // containingBlock, leftFloatsCB->size(), rightFloatsCB->size()); - *oofWidth = cbWidth; /* This (or "<=" instead of "=") should be - the case for floats. */ + int oofWidthAbsPos, oofHeightAbsPos; + getAbsolutelyPositionedSize (&oofWidthAbsPos, &oofHeightAbsPos); int oofHeightLeft = getFloatsSize (leftFloatsCB); int oofHeightRight = getFloatsSize (rightFloatsCB); - *oofHeight = max (oofHeightLeft, oofHeightRight); + + *oofWidth = cbWidth; /* Floats should play no role for the width. */ + *oofHeight = max (oofHeightLeft, oofHeightRight, oofWidthAbsPos); //printf (" => %d x %d => %d x %d (%d / %d)\n", // cbWidth, cbHeight, *oofWidth, *oofHeight, @@ -1050,6 +1110,7 @@ void OutOfFlowMgr::getExtremes (int cbMinWidth, int cbMaxWidth, *oofMinWidth = *oofMaxWidth = 0; accumExtremes (leftFloatsCB, oofMinWidth, oofMaxWidth); accumExtremes (rightFloatsCB, oofMinWidth, oofMaxWidth); + // TODO Absolutely positioned elements } void OutOfFlowMgr::accumExtremes (SortedFloatsVector *list, int *oofMinWidth, @@ -1314,6 +1375,129 @@ int OutOfFlowMgr::getBorderDiff (Textblock *textblock, Float *vloat, Side side) } } +void OutOfFlowMgr::getAbsolutelyPositionedSize (int *oofWidthAbsPos, + int *oofHeightAbsPos) +{ + *oofWidthAbsPos = *oofHeightAbsPos = 0; + + for (int i = 0; i < absolutelyPositioned->size(); i++) { + AbsolutelyPositioned *abspos = absolutelyPositioned->get (i); + ensureAbsolutelyPositionedSizeAndPosition (abspos); + *oofWidthAbsPos = max (*oofWidthAbsPos, abspos->xCB + abspos->width); + *oofHeightAbsPos = max (*oofHeightAbsPos, abspos->yCB + abspos->height); + } +} + +void OutOfFlowMgr::ensureAbsolutelyPositionedSizeAndPosition + (AbsolutelyPositioned *abspos) +{ + // TODO Similar to floats, changes of the available size of the + // containing block are not noticed; which is a bit more severe as + // for floats. Find a general solution for both floats and + // absolutely positioned blocks. + + // TODO Compare to ensureFloatSize: some parts are + // missing. Nevertheless, a simpler approach should be focussed on. + + if (abspos->dirty) { + Style *style = abspos->widget->getStyle(); + int availWidth = containingBlock->getAvailWidth(); + int availHeight = + containingBlock->getAvailAscent() + containingBlock->getAvailDescent(); + + if (style->left == LENGTH_AUTO) + abspos->xCB = 0; + else + abspos->xCB = + calcValueForAbsolutelyPositioned (abspos, style->left, availWidth); + + if (style->top == LENGTH_AUTO) + abspos->yCB = 0; + else + abspos->yCB = + calcValueForAbsolutelyPositioned (abspos, style->top, availHeight); + + abspos->width = -1; // undefined + if (style->width != LENGTH_AUTO) + abspos->width = calcValueForAbsolutelyPositioned (abspos, style->width, + availWidth); + else if (style->right != LENGTH_AUTO) { + int right = calcValueForAbsolutelyPositioned (abspos, style->right, + availWidth); + abspos->width = max (0, availWidth - (abspos->xCB + right)); + } + + abspos->height = -1; // undefined + if (style->height != LENGTH_AUTO) + abspos->height = calcValueForAbsolutelyPositioned (abspos, + style->height, + availHeight); + else if (style->bottom != LENGTH_AUTO) { + int bottom = calcValueForAbsolutelyPositioned (abspos, style->bottom, + availHeight); + abspos->height = max (0, availHeight - (abspos->yCB + bottom)); + } + + if (abspos->width != -1) + abspos->widget->setWidth (abspos->width); + + if (abspos->height != -1) { + abspos->widget->setAscent (abspos->height); + abspos->widget->setDescent (0); // TODO + } + + if (abspos->width == -1 || abspos->height == -1) { + Requisition req; + abspos->widget->sizeRequest (&req); + + if (abspos->width == -1) + abspos->width = req.width; + + if (abspos->height == -1) + abspos->height = req.ascent + req.descent; + } + + abspos->dirty = false; + } +} + +int OutOfFlowMgr::calcValueForAbsolutelyPositioned + (AbsolutelyPositioned *abspos, Length styleLen, int refLen) +{ + assert (styleLen != LENGTH_AUTO); + if (isAbsLength (styleLen)) + return absLengthVal (styleLen); + else if (isPerLength (styleLen)) + return refLen * perLengthVal (styleLen); + else { + assertNotReached (); + return 0; // compiler happiness + } +} + +void OutOfFlowMgr::sizeAllocateAbsolutelyPositioned () +{ + for (int i = 0; i < absolutelyPositioned->size(); i++) { + Allocation *cbAllocation = getAllocation(containingBlock); + AbsolutelyPositioned *abspos = absolutelyPositioned->get (i); + ensureAbsolutelyPositionedSizeAndPosition (abspos); + + Allocation childAllocation; + childAllocation.x = cbAllocation->x + abspos->xCB; + childAllocation.y = cbAllocation->y + abspos->yCB; + childAllocation.width = abspos->width; + childAllocation.ascent = abspos->height; + childAllocation.descent = 0; // TODO + + abspos->widget->sizeAllocate (&childAllocation); + + printf ("[%p] allocating child %p at: (%d, %d), %d x (%d + %d)\n", + containingBlock, abspos->widget, childAllocation.x, + childAllocation.y, childAllocation.width, childAllocation.ascent, + childAllocation.descent); + } +} + // TODO Latest change: Check also Textblock::borderChanged: looks OK, // but the comment ("... (i) with canvas coordinates ...") looks wrong // (and looks as having always been wrong). diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh index 942a8a59..fd3b4f59 100644 --- a/dw/outofflowmgr.hh +++ b/dw/outofflowmgr.hh @@ -141,6 +141,18 @@ private: ~TBInfo (); }; + class AbsolutelyPositioned: public lout::object::Object + { + public: + core::Widget *widget; + int xCB, yCB; // relative to the containing block + int width, height; + bool dirty; + + AbsolutelyPositioned (OutOfFlowMgr *oofm, core::Widget *widget, + Textblock *generatingBlock, int externalIndex); + }; + // These two lists store all floats, in the order in which they are // defined. Only used for iterators. lout::container::typed::Vector<Float> *leftFloatsAll, *rightFloatsAll; @@ -155,6 +167,8 @@ private: lout::container::typed::Vector<TBInfo> *tbInfos; lout::container::typed::HashTable<lout::object::TypedPointer <Textblock>, TBInfo> *tbInfosByTextblock; + + lout::container::typed::Vector<AbsolutelyPositioned> *absolutelyPositioned; int lastLeftTBIndex, lastRightTBIndex, leftFloatsMark, rightFloatsMark; @@ -189,10 +203,13 @@ private: int tbx, int tby, int tbWidth, int tbHeight, int *floatPos, core::Widget **vloat); - void draw (SortedFloatsVector *list, core::View *view, - core::Rectangle *area); - core::Widget *getWidgetAtPoint (SortedFloatsVector *list, int x, int y, - int level); + void drawFloats (SortedFloatsVector *list, core::View *view, + core::Rectangle *area); + void drawAbsolutelyPositioned (core::View *view, core::Rectangle *area); + core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y, + int level); + core::Widget *getAbsolutelyPositionedWidgetAtPoint (int x, int y, int level); + bool collides (Float *vloat, Float *other, int *yReal); void checkCoverage (Float *vloat, int oldY); @@ -213,6 +230,21 @@ private: void ensureFloatSize (Float *vloat); int getBorderDiff (Textblock *textblock, Float *vloat, Side side); + void tellFloatPosition (core::Widget *widget, int yReq); + + void getAbsolutelyPositionedSize (int *oofWidthAbsPos, int *oofHeightAbsPos); + void ensureAbsolutelyPositionedSizeAndPosition (AbsolutelyPositioned + *abspos); + int calcValueForAbsolutelyPositioned (AbsolutelyPositioned *abspos, + core::style::Length styleLen, + int refLen); + void sizeAllocateAbsolutelyPositioned (); + + static inline bool isWidgetFloat (core::Widget *widget) + { return widget->getStyle()->vloat != core::style::FLOAT_NONE; } + static inline bool isWidgetAbsolutelyPositioned (core::Widget *widget) + { return widget->getStyle()->position == core::style::POSITION_ABSOLUTE; } + /* * Format for parent ref (see also below for isRefOutOfFlow, * createRefNormalFlow, and getLineNoFromRef. @@ -240,7 +272,6 @@ private: * +---+ - - - +---+---+- - - - - -+---+---+---+---+ * | index | 1 | 1 | * +---+ - - - +---+---+- - - - - -+---+---+---+---+ - */ inline static bool isRefFloat (int ref) @@ -249,14 +280,20 @@ private: { return ref != -1 && (ref & 7) == 1; } inline static bool isRefRightFloat (int ref) { return ref != -1 && (ref & 7) == 5; } + inline static bool isRefAbsolutelyPositioned (int ref) + { return ref != -1 && (ref & 3) == 3; } inline static int createRefLeftFloat (int index) { return (index << 3) | 1; } inline static int createRefRightFloat (int index) { return (index << 3) | 5; } + inline static int createRefAbsolutelyPositioned (int index) + { return (index << 2) | 3; } inline static int getFloatIndexFromRef (int ref) { return ref == -1 ? ref : (ref >> 3); } + inline static int getAbsolutelyPositionedIndexFromRef (int ref) + { return ref == -1 ? ref : (ref >> 2); } public: OutOfFlowMgr (Textblock *containingBlock); @@ -302,10 +339,18 @@ public: // for iterators inline int getNumWidgets () { - return leftFloatsAll->size() + rightFloatsAll->size(); } + return leftFloatsAll->size() + rightFloatsAll->size() + + absolutelyPositioned->size(); } + inline core::Widget *getWidget (int i) { - return i < leftFloatsAll->size() ? leftFloatsAll->get(i)->widget : - rightFloatsAll->get(i - leftFloatsAll->size())->widget; } + if (i < leftFloatsAll->size()) + return leftFloatsAll->get(i)->widget; + else if (i < leftFloatsAll->size() + rightFloatsAll->size()) + return rightFloatsAll->get(i - leftFloatsAll->size())->widget; + else + return absolutelyPositioned->get(i - (leftFloatsAll->size() + + rightFloatsAll->size()))->widget; + } }; } // namespace dw |