diff options
Diffstat (limited to 'dw/textblock.cc')
-rw-r--r-- | dw/textblock.cc | 224 |
1 files changed, 173 insertions, 51 deletions
diff --git a/dw/textblock.cc b/dw/textblock.cc index bfce0561..ff94486b 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -23,13 +23,14 @@ #include "../lout/misc.hh" #include <stdio.h> -#include <math.h> +#include <math.h> // remove again? +#include <limits.h> /* * Local variables */ - /* The tooltip under mouse pointer in current textblock. No ref. hold. - * (having one per view looks not worth the extra clutter). */ +/* The tooltip under mouse pointer in current textblock. No ref. hold. + * (having one per view looks not worth the extra clutter). */ static dw::core::style::Tooltip *hoverTooltip = NULL; @@ -68,6 +69,7 @@ Textblock::Textblock (bool limitTextWidth) nonTemporaryLines = 0; words = new misc::NotSoSimpleVector <Word> (1); anchors = new misc::SimpleVector <Anchor> (1); + outOfFlowMgr = NULL; //DBG_OBJ_SET_NUM(this, "num_lines", num_lines); @@ -105,8 +107,9 @@ Textblock::~Textblock () for (int i = 0; i < words->size(); i++) { Word *word = words->getRef (i); - if (word->content.type == core::Content::WIDGET) + if (word->content.type == core::Content::WIDGET_IN_FLOW) delete word->content.widget; + /** \todo Widget references? What about texts? */ word->style->unref (); word->spaceStyle->unref (); } @@ -121,6 +124,9 @@ Textblock::~Textblock () delete words; delete anchors; + if(outOfFlowMgr) + delete outOfFlowMgr; + /* Make sure we don't own widgets anymore. Necessary before call of parent class destructor. (???) */ words = NULL; @@ -187,7 +193,7 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition) */ void Textblock::getWordExtremes (Word *word, core::Extremes *extremes) { - if (word->content.type == core::Content::WIDGET) { + if (word->content.type == core::Content::WIDGET_IN_FLOW) { if (word->content.widget->usesHints ()) word->content.widget->getExtremes (extremes); else { @@ -359,7 +365,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) redrawY = misc::min (redrawY, lineYOffsetWidget (line)); } - if (word->content.type == core::Content::WIDGET) { + if (word->content.type == core::Content::WIDGET_IN_FLOW) { /** \todo Justification within the line is done here. */ childAllocation.x = xCursor + allocation->x; /* align=top: @@ -431,6 +437,9 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) } } + if(outOfFlowMgr) + outOfFlowMgr->sizeAllocate(allocation); + for (int i = 0; i < anchors->size(); i++) { Anchor *anchor = anchors->getRef(i); int y; @@ -461,16 +470,25 @@ void Textblock::resizeDrawImpl () void Textblock::markSizeChange (int ref) { - markChange (ref); + if (OutOfFlowMgr::isRefOutOfFlow (ref)) { + assert (outOfFlowMgr != NULL); + outOfFlowMgr->markSizeChange (ref); + } else + markChange (ref); } void Textblock::markExtremesChange (int ref) { - markChange (ref); + if (OutOfFlowMgr::isRefOutOfFlow (ref)) { + assert (outOfFlowMgr != NULL); + outOfFlowMgr->markExtremesChange (ref); + } else + markChange (ref); } /* - * Implementation for both mark_size_change and mark_extremes_change. + * Implementation for both markSizeChange and markExtremesChange. + * Only used for normal flow. */ void Textblock::markChange (int ref) { @@ -481,16 +499,66 @@ void Textblock::markChange (int ref) and (ii) a word may have parentRef == -1 , when it is not yet added to a line. In the latter case, nothing has to be done now, but addLine(...) will do everything necessary. */ + if (ref != -1) { if (wrapRef == -1) - wrapRef = ref; + wrapRef = OutOfFlowMgr::getLineNoFromRef (ref); else - wrapRef = misc::min (wrapRef, ref); + wrapRef = misc::min (wrapRef, OutOfFlowMgr::getLineNoFromRef (ref)); } PRINTF (" ... => %d\n", wrapRef); } +void Textblock::notifySetAsTopLevel() +{ + printf ("%p becomes toplevel\n", this); + containingBlock = this; + printf ("-> %p is its own containing block\n", this); +} + +bool Textblock::isContainingBlock (Widget *widget) +{ + return + // Of course, only textblocks are considered as containing + // blocks. + widget->instanceOf (Textblock::CLASS_ID) && + // The second condition: that this block is "out of flow", in a + // wider sense. + (// The toplevel widget is "out of flow", since there is no + // parent, and so no context. + widget->getParent() == NULL || + // A similar reasoning applies to a widget with another parent + // than a textblock (typical example: a table cell (this is + // also a text block) within a table widget). + !widget->getParent()->instanceOf (Textblock::CLASS_ID) || + // Finally, "out of flow" in a narrower sense: floats and + // absolute positions. + OutOfFlowMgr::isWidgetOutOfFlow (widget)); +} + +void Textblock::notifySetParent () +{ + printf ("%p becomes a child of %p\n", this, getParent()); + + // Search for containing Box. + containingBlock = NULL; + + for (Widget *widget = this; widget != NULL && containingBlock == NULL; + widget = widget->getParent()) + if (isContainingBlock (widget)) { + containingBlock = (Textblock*)widget; + + if (containingBlock == this) + printf ("-> %p is its own containing block\n", this); + else + printf ("-> %p becomes containing block of %p\n", + containingBlock, this); + } + + assert (containingBlock != NULL); +} + void Textblock::setWidth (int width) { /* If limitTextWidth is set to YES, a queueResize() may also be @@ -502,7 +570,7 @@ void Textblock::setWidth (int width) // words->size()); availWidth = width; - queueResize (0, false); + queueResize (OutOfFlowMgr::createRefNormalFlow (0), false); mustQueueResize = false; redrawY = 0; } @@ -517,7 +585,7 @@ void Textblock::setAscent (int ascent) // words->size()); availAscent = ascent; - queueResize (0, false); + queueResize (OutOfFlowMgr::createRefNormalFlow (0), false); mustQueueResize = false; } } @@ -531,7 +599,7 @@ void Textblock::setDescent (int descent) // words->size()); availDescent = descent; - queueResize (0, false); + queueResize (OutOfFlowMgr::createRefNormalFlow (0), false); mustQueueResize = false; } } @@ -1107,10 +1175,10 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area) if (xWidget + word->size.width + word->effSpace >= area->x) { if (word->content.type == core::Content::TEXT || - word->content.type == core::Content::WIDGET) { + word->content.type == core::Content::WIDGET_IN_FLOW) { if (word->size.width > 0) { - if (word->content.type == core::Content::WIDGET) { + if (word->content.type == core::Content::WIDGET_IN_FLOW) { core::Widget *child = word->content.widget; core::Rectangle childArea; @@ -1272,6 +1340,9 @@ void Textblock::draw (core::View *view, core::Rectangle *area) drawLine (line, view, area); } + + if(outOfFlowMgr) + outOfFlowMgr->draw(view, area); } /** @@ -1544,37 +1615,37 @@ void Textblock::addText0 (const char *text, size_t len, bool canBeHyphenated, */ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) { - Word *word; - core::Requisition size; - /* We first assign -1 as parent_ref, since the call of widget->size_request * will otherwise let this Textblock be rewrapped from the beginning. * (parent_ref is actually undefined, but likely has the value 0.) At the, * end of this function, the correct value is assigned. */ widget->parentRef = -1; - PRINTF ("%p becomes child of %p\n", widget, this); - - widget->setParent (this); widget->setStyle (style); + + if (OutOfFlowMgr::isWidgetOutOfFlow (widget)) { + if (containingBlock->outOfFlowMgr == NULL) + containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock); + + widget->setParent (containingBlock); + containingBlock->outOfFlowMgr->addWidget (widget); + Word *word = addWord (0, 0, 0, false, style); + word->content.type = core::Content::WIDGET_OOF_REF; + word->content.breakSpace = 0; + word->content.widget = widget; + word->style = style; + } else { + widget->setParent (this); - calcWidgetSize (widget, &size); - word = addWord (size.width, size.ascent, size.descent, false, style); - - word->content.type = core::Content::WIDGET; - word->content.widget = widget; - - //DBG_OBJ_ARRSET_PTR (page, "words.%d.content.widget", words->size() - 1, - // word->content.widget); + core::Requisition size; + calcWidgetSize (widget, &size); + Word *word = + addWord (size.width, size.ascent, size.descent, false, style); + word->content.type = core::Content::WIDGET_IN_FLOW; + word->content.widget = widget; + } wordWrap (words->size () - 1, false); - //DBG_OBJ_SET_NUM (word->content.widget, "parent_ref", - // word->content.widget->parent_ref); - - //DEBUG_MSG(DEBUG_REWRAP_LEVEL, - // "Assigning parent_ref = %d to added word %d, " - // "in page with %d word(s)\n", - // lines->size () - 1, words->size() - 1, words->size()); } /** @@ -1711,7 +1782,7 @@ void Textblock::addParbreak (int space, core::style::Style *style) /* A break may not be the first word of a page, or directly after the bullet/number (which is the first word) in a list item. (See - also comment in Dw_page_size_request.) */ + also comment in sizeRequest.) */ if (words->size () == 0 || (hasListitemValue && words->size () == 1)) { /* This is a bit hackish: If a break is added as the @@ -1720,23 +1791,23 @@ void Textblock::addParbreak (int space, core::style::Style *style) a widget is used as a text box (lists, blockquotes, list items etc) -- then we simply adjust the break before, in a way that the space is in any case visible. */ - Widget *widget; - - /* Find the widget where to adjust the breakSpace. */ - for (widget = this; - widget->getParent() && - widget->getParent()->instanceOf (Textblock::CLASS_ID); + /* Find the widget where to adjust the breakSpace. (Only + consider normal flow, no floats etc.) */ + for (Widget *widget = this; + widget->getParent() != NULL && + widget->getParent()->instanceOf (Textblock::CLASS_ID) && + !OutOfFlowMgr::isRefOutOfFlow (widget->parentRef); widget = widget->getParent ()) { Textblock *textblock2 = (Textblock*)widget->getParent (); int index = textblock2->hasListitemValue ? 1 : 0; bool isfirst = (textblock2->words->getRef(index)->content.type - == core::Content::WIDGET + == core::Content::WIDGET_IN_FLOW && textblock2->words->getRef(index)->content.widget == widget); if (!isfirst) { - /* The page we searched for has been found. */ + /* The text block we searched for has been found. */ Word *word2; - int lineno = widget->parentRef; + int lineno = OutOfFlowMgr::getLineNoFromRef (widget->parentRef); if (lineno > 0 && (word2 = @@ -1745,7 +1816,8 @@ void Textblock::addParbreak (int space, core::style::Style *style) word2->content.type == core::Content::BREAK) { if (word2->content.breakSpace < space) { word2->content.breakSpace = space; - textblock2->queueResize (lineno, false); + textblock2->queueResize + (OutOfFlowMgr::createRefNormalFlow (lineno), false); textblock2->mustQueueResize = false; } } @@ -1753,6 +1825,7 @@ void Textblock::addParbreak (int space, core::style::Style *style) } /* Otherwise continue to examine parents. */ } + /* Return in any case. */ return; } @@ -1801,7 +1874,6 @@ void Textblock::addLinebreak (core::style::Style *style) wordWrap (words->size () - 1, false); } - /** * \brief Search recursively through widget. * @@ -1831,7 +1903,7 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level) for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) { Word *word = words->getRef (wordIndex); - if (word->content.type == core::Content::WIDGET) { + if (word->content.type == core::Content::WIDGET_IN_FLOW) { core::Widget * childAtPoint; childAtPoint = word->content.widget->getWidgetAtPoint (x, y, level + 1); @@ -1913,7 +1985,7 @@ void Textblock::changeLinkColor (int link, int newColor) old_style->unref(); break; } - case core::Content::WIDGET: + case core::Content::WIDGET_IN_FLOW: { core::Widget *widget = word->content.widget; styleAttrs = *widget->getStyle(); styleAttrs.color = core::style::Color::create (layout, @@ -1941,4 +2013,54 @@ void Textblock::changeWordStyle (int from, int to, core::style::Style *style, { } +void Textblock::borderChanged (int y) +{ + printf ("[%p] border has changed: %d\n", this, y); + borderChanged (y + allocation.y, true); +} + +void Textblock::borderChanged (int yCanvas, bool extremesChanges) +{ + // Notice that this method is, unlike the other "borderChanged", + // called (i) with canvas coordinates, not widget coordinates, and + // (ii) for all nested textblocks, not only the containing block. + + // findLineIndex expects widget coordinates + int lineIndex = findLineIndex (yCanvas - allocation.y); + // Nothing to do at all, when lineIndex >= lines->size (), + // i. e. the change is below the bottom od this widget. + if (lineIndex < lines->size ()) { + int wrapLineIndex; + if (lineIndex < 0) + // Rewrap all. + wrapLineIndex = 0; + else + wrapLineIndex = lineIndex; + + queueResize (OutOfFlowMgr::createRefNormalFlow (wrapLineIndex), + extremesChanges); + + for (int i = wrapLineIndex; i < lines->size (); i++) { + Word *word = words->getRef (lines->getRef(i)->firstWord); + if (word->content.type == core::Content::WIDGET_IN_FLOW && + word->content.widget->instanceOf (Textblock::CLASS_ID)) { + Textblock *childBlock = (Textblock*)word->content.widget; + // extremes only change for the containing block, so we pass + // extremesChanges = false for all other widgets. + childBlock->borderChanged (yCanvas, false); + } + } + } +} + +core::style::Style *Textblock::getCBStyle () +{ + return getStyle(); +} + +core::Allocation *Textblock::getCBAllocation () +{ + return &allocation; +} + } // namespace dw |