diff options
-rw-r--r-- | dw/layout.cc | 1 | ||||
-rw-r--r-- | dw/style.cc | 12 | ||||
-rw-r--r-- | dw/style.hh | 17 | ||||
-rw-r--r-- | dw/textblock.cc | 342 | ||||
-rw-r--r-- | dw/textblock.hh | 95 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 18 | ||||
-rw-r--r-- | dw/types.hh | 3 | ||||
-rw-r--r-- | dw/widget.cc | 21 | ||||
-rw-r--r-- | dw/widget.hh | 3 | ||||
-rw-r--r-- | lout/identity.cc | 3 | ||||
-rw-r--r-- | src/cssparser.cc | 6 | ||||
-rw-r--r-- | src/html.cc | 7 | ||||
-rw-r--r-- | src/styleengine.cc | 3 | ||||
-rw-r--r-- | test/Makefile.am | 9 | ||||
-rw-r--r-- | test/dw_float_test.cc | 142 |
15 files changed, 652 insertions, 30 deletions
diff --git a/dw/layout.cc b/dw/layout.cc index 9dfd5e9b..d2610687 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -248,6 +248,7 @@ void Layout::addWidget (Widget *widget) topLevel = widget; widget->layout = this; + widget->notifySetAsTopLevel(); findtextState.setWidget (widget); diff --git a/dw/style.cc b/dw/style.cc index 2a1d4088..b0868c1f 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - #include <stdio.h> #include <string.h> #include <unistd.h> @@ -49,6 +47,8 @@ void StyleAttrs::initValues () valign = VALIGN_BASELINE; backgroundColor = NULL; width = height = lineHeight = LENGTH_AUTO; + vloat = FLOAT_NONE; + clear = CLEAR_NONE; textIndent = 0; margin.setVal (0); borderWidth.setVal (0); @@ -75,6 +75,8 @@ void StyleAttrs::resetValues () valign = VALIGN_BASELINE; textAlignChar = '.'; + vloat = FLOAT_NONE; /** \todo Correct? Check specification. */ + clear = CLEAR_NONE; /** \todo Correct? Check specification. */ backgroundColor = NULL; width = LENGTH_AUTO; height = LENGTH_AUTO; @@ -120,6 +122,8 @@ bool StyleAttrs::equals (object::Object *other) { valign == otherAttrs->valign && textAlignChar == otherAttrs->textAlignChar && textTransform == otherAttrs->textTransform && + vloat == otherAttrs->vloat && + clear == otherAttrs->clear && hBorderSpacing == otherAttrs->hBorderSpacing && vBorderSpacing == otherAttrs->vBorderSpacing && wordSpacing == otherAttrs->wordSpacing && @@ -160,6 +164,8 @@ int StyleAttrs::hashValue () { valign + textAlignChar + textTransform + + vloat + + clear + hBorderSpacing + vBorderSpacing + wordSpacing + @@ -252,6 +258,8 @@ void Style::copyAttrs (StyleAttrs *attrs) valign = attrs->valign; textAlignChar = attrs->textAlignChar; textTransform = attrs->textTransform; + vloat = attrs->vloat; + clear = attrs->clear; hBorderSpacing = attrs->hBorderSpacing; vBorderSpacing = attrs->vBorderSpacing; wordSpacing = attrs->wordSpacing; diff --git a/dw/style.hh b/dw/style.hh index 2422bfa9..6b492793 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -281,7 +281,6 @@ enum ListStylePosition { LIST_STYLE_POSITION_INSIDE, LIST_STYLE_POSITION_OUTSIDE }; - enum ListStyleType { LIST_STYLE_TYPE_DISC, LIST_STYLE_TYPE_CIRCLE, @@ -333,6 +332,19 @@ enum WhiteSpace { WHITE_SPACE_PRE_LINE, }; +enum FloatType { + FLOAT_NONE, + FLOAT_LEFT, + FLOAT_RIGHT +}; + +enum ClearType { + CLEAR_LEFT, + CLEAR_RIGHT, + CLEAR_BOTH, + CLEAR_NONE +}; + /** * \brief Type for representing all lengths within dw::core::style. * @@ -450,6 +462,9 @@ public: VAlignType valign; char textAlignChar; /* In future, strings will be supported. */ TextTransform textTransform; + + FloatType vloat; /* "float" is a keyword. */ + ClearType clear; int hBorderSpacing, vBorderSpacing, wordSpacing; Length width, height, lineHeight, textIndent; diff --git a/dw/textblock.cc b/dw/textblock.cc index c66fac23..6aa75a13 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -19,17 +19,19 @@ #include "textblock.hh" +#include "table.hh" // Yes, this is ugly. -- SG #include "../lout/msg.h" #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 +70,7 @@ Textblock::Textblock (bool limitTextWidth) nonTemporaryLines = 0; words = new misc::NotSoSimpleVector <Word> (1); anchors = new misc::SimpleVector <Anchor> (1); + leftFloatSide = rightFloatSide = NULL; //DBG_OBJ_SET_NUM(this, "num_lines", num_lines); @@ -121,6 +124,11 @@ Textblock::~Textblock () delete words; delete anchors; + if(leftFloatSide) + delete leftFloatSide; + if(rightFloatSide) + delete rightFloatSide; + /* Make sure we don't own widgets anymore. Necessary before call of parent class destructor. (???) */ words = NULL; @@ -244,7 +252,7 @@ void Textblock::getExtremesImpl (core::Extremes *extremes) int parMax; /* Calculate the extremes, based on the values in the line from where a rewrap is necessary. */ - + PRINTF ("GET_EXTREMES: complex case ...\n"); if (wrapRef == 0) { @@ -431,6 +439,11 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation) } } + if(leftFloatSide) + leftFloatSide->sizeAllocate(allocation); + if(rightFloatSide) + rightFloatSide->sizeAllocate(allocation); + for (int i = 0; i < anchors->size(); i++) { Anchor *anchor = anchors->getRef(i); int y; @@ -481,16 +494,70 @@ 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 neccessary. */ - if (ref != -1) { - if (wrapRef == -1) - wrapRef = ref; - else - wrapRef = misc::min (wrapRef, ref); + + int refEquiv = (ref == 0) ? 1 | (dw::core::style::FLOAT_NONE << 1) : ref; + + if (refEquiv != -1 && (refEquiv & 1)) { + switch((refEquiv >> 1) & 3) + { + case dw::core::style::FLOAT_NONE: + if (wrapRef == -1) + wrapRef = refEquiv >> 3; + else + wrapRef = misc::min (wrapRef, refEquiv >> 3); + //DBG_OBJ_SET_NUM (page, "wrap_ref", page->wrap_ref); + printf("wrapRef = %d\n", wrapRef); + break; + + case dw::core::style::FLOAT_LEFT: + leftFloatSide->queueResize(refEquiv); + break; + + case dw::core::style::FLOAT_RIGHT: + rightFloatSide->queueResize(refEquiv); + break; + } } PRINTF (" ... => %d\n", wrapRef); } +void Textblock::notifySetAsTopLevel() +{ + containingBox = this; +} + +void Textblock::notifySetParent() +{ + // Search for containing Box. It can be assumed that this widget has a + // parent, otherwise, notifySetAsToplevel would have been called. + containingBox = NULL; + Textblock *topmostTextblock = this; + + for(Widget *widget = getParent(); widget != NULL; + widget = widget->getParent()) + { + if(widget->instanceOf(Textblock::CLASS_ID)) + topmostTextblock = (Textblock*)widget; + } + + for(Widget *widget = getParent(); containingBox == NULL; + widget = widget->getParent()) + { + if(widget->getParent() == NULL) + // No other widget left. + containingBox = topmostTextblock; + else if(widget->instanceOf(Textblock::CLASS_ID)) + { + if(// this widget is a table cell + widget->getParent()->instanceOf(Table::CLASS_ID) || + // this widget is a float + widget->getStyle()->vloat != dw::core::style::FLOAT_NONE) + containingBox = (Textblock*)widget; + } + } +} + void Textblock::setWidth (int width) { /* If limitTextWidth is set to YES, a queueResize() may also be @@ -502,7 +569,11 @@ void Textblock::setWidth (int width) // words->size()); availWidth = width; +//<<<<<<< textblock.cc +// queueResize (false, dw::core::style::FLOAT_NONE, false); +//======= queueResize (0, false); +//>>>>>>> 1.24 mustQueueResize = false; redrawY = 0; } @@ -517,7 +588,11 @@ void Textblock::setAscent (int ascent) // words->size()); availAscent = ascent; +//<<<<<<< textblock.cc +// queueResize (false, dw::core::style::FLOAT_NONE, false); +//======= queueResize (0, false); +//>>>>>>> 1.24 mustQueueResize = false; } } @@ -531,7 +606,11 @@ void Textblock::setDescent (int descent) // words->size()); availDescent = descent; +//<<<<<<< textblock.cc +// queueResize (false, dw::core::style::FLOAT_NONE, false); +//======= queueResize (0, false); +//>>>>>>> 1.24 mustQueueResize = false; } } @@ -1264,6 +1343,11 @@ void Textblock::draw (core::View *view, core::Rectangle *area) drawLine (line, view, area); } + + if(leftFloatSide) + leftFloatSide->draw(view, area); + if(rightFloatSide) + rightFloatSide->draw(view, area); } /** @@ -1560,6 +1644,9 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style) // word->content.widget); wordWrap (words->size () - 1, false); + // ABC + word->content.widget->parentRef = 1 | (dw::core::style::FLOAT_NONE << 1) | ((lines->size () - 1) << 3); + printf("parentRef = %d\n", word->content.widget->parentRef); //DBG_OBJ_SET_NUM (word->content.widget, "parent_ref", // word->content.widget->parent_ref); @@ -1728,8 +1815,8 @@ void Textblock::addParbreak (int space, core::style::Style *style) if (!isfirst) { /* The page we searched for has been found. */ Word *word2; - int lineno = widget->parentRef; - + // ABC + int lineno = widget->parentRef >> 3; if (lineno > 0 && (word2 = textblock2->words->getRef(textblock2->lines @@ -1737,7 +1824,11 @@ void Textblock::addParbreak (int space, core::style::Style *style) word2->content.type == core::Content::BREAK) { if (word2->content.breakSpace < space) { word2->content.breakSpace = space; +//<<<<<<< textblock.cc +// textblock2->queueResize (false, 1 | (dw::core::style::FLOAT_NONE << 1) | (lineno << 3), false); +//======= textblock2->queueResize (lineno, false); +//>>>>>>> 1.24 textblock2->mustQueueResize = false; } } @@ -1793,6 +1884,22 @@ void Textblock::addLinebreak (core::style::Style *style) wordWrap (words->size () - 1, false); } +/** \todo This MUST be commented! */ +void Textblock::addFloatIntoGenerator (core::Widget *widget, core::style::Style *style) +{ + Word *word; + + widget->setStyle (style); + containingBox->addFloatIntoContainer(widget, this); + + word = addWord (0, 0, 0, false, style); + word->content.type = core::Content::FLOAT_REF; + word->content.breakSpace = 0; + word->content.widget = widget; + word->style = style; + wordWrap (words->size () - 1, false); +} + /** * \brief Search recursively through widget. @@ -1863,6 +1970,11 @@ void Textblock::handOverBreak (core::style::Style *style) */ void Textblock::flush () { +//<<<<<<< textblock.cc +// if (asap || mustQueueResize) { +// printf("queueResize(%s, -1, true)\n", asap ? "true" : "false"); +// queueResize (asap, -1, true); +//======= PRINTF ("[%p] FLUSH => %s (parentRef = %d)\n", this, mustQueueResize ? "true" : "false", parentRef); @@ -1935,6 +2047,214 @@ void Textblock::changeWordStyle (int from, int to, core::style::Style *style, // ---------------------------------------------------------------------- +/** \todo This MUST be commented! */ +void Textblock::addFloatIntoContainer(Widget *widget, + Textblock *floatGenerator) +{ + FloatSide *floatSide = NULL; + + switch(widget->getStyle()->vloat) + { + case dw::core::style::FLOAT_LEFT: + if(leftFloatSide == NULL) + leftFloatSide = new LeftFloatSide(this); + floatSide = leftFloatSide; + break; + + case dw::core::style::FLOAT_RIGHT: + if(rightFloatSide == NULL) + rightFloatSide = new RightFloatSide(this); + floatSide = rightFloatSide; + break; + + default: + //TODO lout::misc::fail("invalid value %d for float to be added", widget->getStyle()->vloat); + break; + } + + // ABC + widget->parentRef = 1 | (widget->getStyle()->vloat << 1) | (floatSide->size() << 3); + widget->parentRef = 0; + printf("parentRef = %d\n", widget->parentRef); + widget->setParent(this); + + floatSide->addFloat(widget, floatGenerator); +} + +void Textblock::handleFloatInContainer(Widget *widget, int lineNo, + int y, int lineWidth, int lineHeight) +{ + FloatSide *floatSide = NULL; + + switch(widget->getStyle()->vloat) + { + case dw::core::style::FLOAT_LEFT: + floatSide = leftFloatSide; + break; + + case dw::core::style::FLOAT_RIGHT: + floatSide = rightFloatSide; + break; + + default: + //TODO lout::misc::fail("invalid value %d for float to be handled", widget->getStyle()->vloat); + break; + } + + floatSide->handleFloat(widget, lineNo, y, lineWidth, lineHeight); +} + +Textblock::FloatSide::FloatSide(Textblock *floatContainer) +{ + this->floatContainer = floatContainer; + floats = new container::typed::Vector<Float>(1, false); + floatsByWidget = + new container::typed::HashTable<object::TypedPointer<dw::core::Widget>, Float>(true, true); +} + +Textblock::FloatSide::~FloatSide() +{ + delete floats; + delete floatsByWidget; +} + +void Textblock::FloatSide::addFloat(Widget *widget, Textblock *floatGenerator) +{ + Float *vloat = new Float(); + vloat->floatGenerator = floatGenerator; + vloat->widget = widget; + floats->put(vloat); + object::TypedPointer<Widget> *pointer = new object::TypedPointer<Widget>(widget); + floatsByWidget->put(pointer, vloat); +} + +void Textblock::FloatSide::handleFloat(Widget *widget, int lineNo, + int y, int lineWidth, int lineHeight) +{ + /** \todo lineHeight may change afterwards */ + object::TypedPointer<Widget> pointer(widget); + Float *vloat = floatsByWidget->get(&pointer); + + printf("searching %s in %s\n", pointer.toString(), floatsByWidget->toString()); + + dw::core::Requisition requisition; + widget->sizeRequest(&requisition); + + int effY; + /** \todo Check for another float. Futhermore: what, if the float does not fit + * into a line at all? */ + if(requisition.width > vloat->floatGenerator->availWidth - lineWidth) + effY = y + lineHeight; + else + effY = y; + + vloat->lineNo = lineNo; + vloat->y = effY; + vloat->width = requisition.width; + vloat->ascent = requisition.ascent; + vloat->descent = requisition.descent; +} + +int Textblock::FloatSide::calcBorder(int y, Textblock *viewdFrom) +{ + Float *vloat = findFloat(y); + if(vloat) { + int fromContainer = calcBorderFromContainer(vloat); + int fromThisViewedFrom = fromContainer - calcBorderDiff(viewdFrom); + //printf("fromThisViewedFrom = %d\n", fromThisViewedFrom); + return misc::max(fromThisViewedFrom, 0); + } else + return 0; +} + +Textblock::FloatSide::Float *Textblock::FloatSide::findFloat(int y) +{ + for(int i = 0; i < floats->size(); i++) + { + Float *vloat = floats->get(i); + if(y >= vloat->y && y < vloat->y + vloat->ascent + vloat->descent) + return vloat; + } + + return NULL; +} + +void Textblock::FloatSide::draw (core::View *view, core::Rectangle *area) +{ + for(int i = 0; i < floats->size(); i++) + { + Float *vloat = floats->get(i); + core::Rectangle childArea; + if (vloat->widget->intersects (area, &childArea)) + vloat->widget->draw (view, &childArea); + } +} + +void Textblock::FloatSide::queueResize(int ref) +{ + // TODO Float *vloat = floats->get(ref >> 3); + // TODO vloat->floatGenerator->queueResize(false, 1 | (dw::core::style::FLOAT_NONE << 1) | (vloat->lineNo << 3), true); +} + +int Textblock::LeftFloatSide::calcBorderFromContainer(Textblock::FloatSide::Float *vloat) +{ + return vloat->width + floatContainer->getStyle()->boxOffsetX() + + vloat->floatGenerator->getStyle()->boxOffsetX(); +} + +int Textblock::LeftFloatSide::calcBorderDiff(Textblock *child) +{ + return child->getStyle()->boxOffsetX(); +} + +void Textblock::LeftFloatSide::sizeAllocate(core::Allocation *containingBoxAllocation) +{ + for(int i = 0; i < floats->size(); i++) + { + Float *vloat = floats->get(i); + core::Allocation childAllocation; + childAllocation.x = + containingBoxAllocation->x + floatContainer->getStyle()->boxOffsetX() + + vloat->floatGenerator->getStyle()->boxOffsetX(); + childAllocation.y = containingBoxAllocation->y + vloat->y; + childAllocation.width = vloat->width; + childAllocation.ascent = vloat->ascent; + childAllocation.descent = vloat->descent; + vloat->widget->sizeAllocate(&childAllocation); + } +} + +int Textblock::RightFloatSide::calcBorderFromContainer(Textblock::FloatSide::Float *vloat) +{ + return vloat->width + floatContainer->getStyle()->boxRestWidth() + + vloat->floatGenerator->getStyle()->boxRestWidth(); +} + +int Textblock::RightFloatSide::calcBorderDiff(Textblock *child) +{ + return child->getStyle()->boxRestWidth(); +} + +void Textblock::RightFloatSide::sizeAllocate(core::Allocation *containingBoxAllocation) +{ + for(int i = 0; i < floats->size(); i++) + { + Float *vloat = floats->get(i); + core::Allocation childAllocation; + childAllocation.x = + containingBoxAllocation->x + containingBoxAllocation->width - + floatContainer->getStyle()->boxRestWidth() - vloat->width - + vloat->floatGenerator->getStyle()->boxRestWidth(); + childAllocation.y = containingBoxAllocation->y + vloat->y; + childAllocation.width = vloat->width; + childAllocation.ascent = vloat->ascent; + childAllocation.descent = vloat->descent; + vloat->widget->sizeAllocate(&childAllocation); + } +} + +// ---------------------------------------------------------------------- + Textblock::TextblockIterator::TextblockIterator (Textblock *textblock, core::Content::Type mask, bool atEnd): diff --git a/dw/textblock.hh b/dw/textblock.hh index 0c3c6870..8d8f91cc 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -18,10 +18,11 @@ namespace dw { * of paragraphs. * * <div style="border: 2px solid #ffff00; margin-top: 0.5em; - * margin-bottom: 0.5em; padding: 0.5em 1em; - * background-color: #ffffe0"><b>Info:</b> The recent changes (line - * breaking and hyphenation) have not yet been incorporated into this - * documentation. See \ref dw-line-breaking.</div> + * margin-bottom: 0.5em; padding: 0.5em 1em; background-color: + * #ffffe0"><b>Info:</b> The recent changes (line breaking and + * hyphenation on one hand, floats on the other hand) have not yet + * been incorporated into this documentation. See \ref + * dw-line-breaking and \ref dw-special-textflow.</div> * * <h3>Signals</h3> * @@ -144,6 +145,11 @@ namespace dw { class Textblock: public core::Widget { private: + // Hint: the following is somewhat chaotic, as a result of the merge + // of dillo_hyphen and dillo_floats + + // Part 1 -- Line-Breaking and Hyphenation + /** * This class encapsulates the badness/penalty calculation, and so * (i) makes changes (hopefully) simpler, and (ii) hides the @@ -207,6 +213,69 @@ private: void print (); }; + // Part 2 -- Floats + + Textblock *containingBox; + + class FloatSide + { + protected: + class Float: public lout::object::Object + { + public: + Textblock *floatGenerator; + core::Widget *widget; + int lineNo, y, width, ascent, descent; + }; + + Textblock *floatContainer; + lout::container::typed::Vector<Float> *floats; + lout::container::typed::HashTable<lout::object::TypedPointer<dw::core::Widget>, Float> *floatsByWidget; + + Float *findFloat(int y); + + virtual int calcBorderFromContainer(Float *vloat) = 0; + virtual int calcBorderDiff(Textblock *child) = 0; + + public: + FloatSide(Textblock *floatContainer); + virtual ~FloatSide(); + + inline int size() { return floats->size(); } + void addFloat(Widget *widget, Textblock *floatGenerator); + void handleFloat(Widget *widget, int lineNo, int y, int lineWidth, int lineHeight); + int calcBorder(int y, Textblock *viewdFrom); + virtual void sizeAllocate(core::Allocation *containingBoxAllocation) = 0; + void draw (core::View *view, core::Rectangle *area); + void queueResize(int ref); + }; + + class LeftFloatSide: public FloatSide + { + protected: + int calcBorderFromContainer(Float *vloat); + int calcBorderDiff(Textblock *child); + + public: + LeftFloatSide(Textblock *floatContainer) : FloatSide(floatContainer) { } + void sizeAllocate(core::Allocation *containingBoxAllocation); + }; + + class RightFloatSide: public FloatSide + { + protected: + int calcBorderFromContainer(Float *vloat); + int calcBorderDiff(Textblock *child); + + public: + RightFloatSide(Textblock *floatContainer) : FloatSide(floatContainer) { } + void sizeAllocate(core::Allocation *containingBoxAllocation); + }; + + FloatSide *leftFloatSide, *rightFloatSide; + + // End of merge chaos. + protected: enum { /** @@ -226,7 +295,8 @@ protected: * page->lines[0].top is always 0. */ int top, boxAscent, boxDescent, contentAscent, contentDescent, breakSpace, leftOffset; - + int boxLeft, boxRight; + /* This is similar to descent, but includes the bottom margins of the * widgets within this line. */ int marginDescent; @@ -419,6 +489,15 @@ protected: void calcTextSize (const char *text, size_t len, core::style::Style *style, core::Requisition *size); + void addFloatIntoContainer(core::Widget *widget, Textblock *floatGenerator); + void handleFloatInContainer(Widget *widget, int lineNo, + int y, int lineWidth, int lineHeight); + + inline int calcLeftFloatBorder(int y, Textblock *viewedFrom) + { return containingBox->leftFloatSide ? containingBox->leftFloatSide->calcBorder(y, viewedFrom) : 0; } + inline int calcRightFloatBorder(int y, Textblock *viewedFrom) + { return containingBox->rightFloatSide ? containingBox->rightFloatSide->calcBorder(y, viewedFrom) : 0; } + /** * \brief Returns the x offset (the indentation plus any offset needed for * centering or right justification) for the line. @@ -428,7 +507,7 @@ protected: */ inline int lineXOffsetContents (Line *line) { - return innerPadding + line->leftOffset + + return innerPadding + line->leftOffset + line->boxLeft + (line == lines->getFirstRef() ? line1OffsetEff : 0); } @@ -499,6 +578,8 @@ protected: void markSizeChange (int ref); void markExtremesChange (int ref); + void notifySetAsTopLevel(); + void notifySetParent(); void setWidth (int width); void setAscent (int ascent); void setDescent (int descent); @@ -558,6 +639,8 @@ public: void addParbreak (int space, core::style::Style *style); void addLinebreak (core::style::Style *style); + void addFloatIntoGenerator (core::Widget *widget, core::style::Style *style); + core::Widget *getWidgetAtPoint (int x, int y, int level); void handOverBreak (core::style::Style *style); void changeLinkColor (int link, int newColor); diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 8fb577d1..7947d22f 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -796,6 +796,11 @@ void Textblock::accumulateWordData (int wordIndex) int Textblock::calcAvailWidth (int lineIndex) { + // BUG: This method must also include Line::boxLeft and Line::boxRight + // (introduced by floats), but since the recent changes in line breaking + // (together with hyphenation), this line is often not yet created, so + // these values cannot be determined. + int availWidth = this->availWidth - getStyle()->boxDiffWidth() - innerPadding; if (limitTextWidth && @@ -805,9 +810,9 @@ int Textblock::calcAvailWidth (int lineIndex) if (lineIndex == 0) availWidth -= line1OffsetEff; - //PRINTF("[%p] CALC_AVAIL_WIDTH => %d - %d - %d = %d\n", - // this, this->availWidth, getStyle()->boxDiffWidth(), innerPadding, - // availWidth); + PRINTF ("[%p] CALC_AVAIL_WIDTH (%d of %d) => %d - %d - %d = %d\n", + this, lineIndex, lines->size(), this->availWidth, + getStyle()->boxDiffWidth(), innerPadding, availWidth); return availWidth; } @@ -916,8 +921,11 @@ void Textblock::rewrap () for (int i = firstWord; i < words->size (); i++) { Word *word = words->getRef (i); - if (word->content.type == core::Content::WIDGET) - calcWidgetSize (word->content.widget, &word->size); + if (word->content.type == core::Content::WIDGET && + // ABC + word->content.widget->parentRef == + (1 | (dw::core::style::FLOAT_NONE << 1) | ((lines->size () - 1) << 3))) + calcWidgetSize (word->content.widget, &word->size); wordWrap (i, false); diff --git a/dw/types.hh b/dw/types.hh index 65983fad..abed38e6 100644 --- a/dw/types.hh +++ b/dw/types.hh @@ -190,8 +190,9 @@ struct Content TEXT = 1 << 2, WIDGET = 1 << 3, BREAK = 1 << 4, + FLOAT_REF = 1 << 6, /** \todo A bit ugly. */ ALL = 0xff, - REAL_CONTENT = 0xff ^ (START | END), + REAL_CONTENT = 0xff ^ (START | END | FLOAT_REF), SELECTION_CONTENT = TEXT | WIDGET | BREAK }; diff --git a/dw/widget.cc b/dw/widget.cc index 8ca0681a..193c5aac 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -108,6 +108,8 @@ void Widget::setParent (Widget *parent) if (!buttonSensitiveSet) buttonSensitive = parent->buttonSensitive; + notifySetParent(); + //DBG_OBJ_ASSOC (widget, parent); //printf ("%p becomes a child of %p\n", this, parent); } @@ -567,6 +569,25 @@ void Widget::markExtremesChange (int ref) { } +/** + * \brief This method is called after a widget has been set as the top of a + * widget tree. + * + * A widget may override this method when it is necessary to be notified. + */ +void Widget::notifySetAsTopLevel() +{ +} + +/** + * \brief This method is called after a widget has been added to a parent. + * + * A widget may override this method when it is necessary to be notified. + */ +void Widget::notifySetParent() +{ +} + void Widget::setWidth (int width) { } diff --git a/dw/widget.hh b/dw/widget.hh index b751a282..e18344c7 100644 --- a/dw/widget.hh +++ b/dw/widget.hh @@ -178,6 +178,9 @@ protected: */ virtual void markExtremesChange (int ref); + virtual void notifySetAsTopLevel(); + virtual void notifySetParent(); + virtual bool buttonPressImpl (EventButton *event); virtual bool buttonReleaseImpl (EventButton *event); virtual bool motionNotifyImpl (EventMotion *event); diff --git a/lout/identity.cc b/lout/identity.cc index 7c650b24..ebe95ef0 100644 --- a/lout/identity.cc +++ b/lout/identity.cc @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - - #include "identity.hh" #include <stdio.h> @@ -78,6 +76,7 @@ void IdentifiableObject::registerName (const char *className, int *classId) } this->classId = klass->id; + *classId = klass->id; currentlyConstructedClass = klass; } diff --git a/src/cssparser.cc b/src/cssparser.cc index 8131372a..bd065234 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -76,6 +76,10 @@ static const char *const Css_display_enum_vals[] = { "table-cell", NULL }; +static const char *const Css_float_enum_vals[] = { + "none", "left", "right", NULL +}; + static const char *const Css_font_size_enum_vals[] = { "large", "larger", "medium", "small", "smaller", "xx-large", "xx-small", "x-large", "x-small", NULL @@ -183,7 +187,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"direction", {CSS_TYPE_UNUSED}, NULL}, {"display", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_display_enum_vals}, {"empty-cells", {CSS_TYPE_UNUSED}, NULL}, - {"float", {CSS_TYPE_UNUSED}, NULL}, + {"float", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_float_enum_vals}, {"font-family", {CSS_TYPE_SYMBOL, CSS_TYPE_UNUSED}, NULL}, {"font-size", {CSS_TYPE_ENUM, CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, Css_font_size_enum_vals}, diff --git a/src/html.cc b/src/html.cc index 22952609..d3c9f383 100644 --- a/src/html.cc +++ b/src/html.cc @@ -359,9 +359,14 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize) static void Html_add_textblock(DilloHtml *html, int space) { Textblock *textblock = new Textblock (prefs.limit_text_width); + Style *style = html->styleEngine->style (); HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ()); - HT2TB(html)->addWidget (textblock, html->styleEngine->style ()); + if (style->vloat == FLOAT_NONE) + HT2TB(html)->addWidget (textblock, style); + else + HT2TB(html)->addFloatIntoGenerator(textblock, style); + HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ()); S_TOP(html)->textblock = html->dw = textblock; S_TOP(html)->hand_over_break = true; diff --git a/src/styleengine.cc b/src/styleengine.cc index 19b9f371..ed272269 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -508,6 +508,9 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) { case CSS_PROPERTY_DISPLAY: attrs->display = (DisplayType) p->value.intVal; break; + case CSS_PROPERTY_FLOAT: + attrs->vloat = (FloatType) p->value.intVal; + break; case CSS_PROPERTY_LINE_HEIGHT: if (p->type == CSS_TYPE_ENUM) { //only valid enum value is "normal" attrs->lineHeight = dw::core::style::LENGTH_AUTO; diff --git a/test/Makefile.am b/test/Makefile.am index 15ab227b..bc851247 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -7,6 +7,7 @@ noinst_PROGRAMS = \ dw-anchors-test \ dw-example \ dw-find-test \ + dw-float-test \ dw-links \ dw-links2 \ dw-images-simple \ @@ -49,6 +50,14 @@ dw_find_test_LDADD = \ $(top_builddir)/lout/liblout.a \ @LIBFLTK_LIBS@ +dw_float_test_SOURCES = dw_float_test.cc +dw_float_test_LDADD = \ + ../dw/libDw-widgets.a \ + ../dw/libDw-fltk.a \ + ../dw/libDw-core.a \ + ../lout/liblout.a \ + @LIBFLTK_LIBS@ + dw_links_SOURCES = dw_links.cc dw_links_LDADD = \ $(top_builddir)/dw/libDw-widgets.a \ diff --git a/test/dw_float_test.cc b/test/dw_float_test.cc new file mode 100644 index 00000000..acafeafa --- /dev/null +++ b/test/dw_float_test.cc @@ -0,0 +1,142 @@ +#include <FL/Fl.H> +#include <FL/Fl_Window.H> + +#include "../dw/core.hh" +#include "../dw/fltkcore.hh" +#include "../dw/fltkviewport.hh" +#include "../dw/textblock.hh" + +using namespace dw; +using namespace dw::core; +using namespace dw::core::style; +using namespace dw::fltk; + +static Textblock *firstFloat; +static Style *wordStyle; + +static void addTextToFloatTimeout (void *data) +{ + printf("addTextToFloatTimeout\n"); + + const char *fWords[] = { "This", "is", "a", "float,", "which", "is", + "set", "aside", "from", "the", "main", + "text.", NULL }; + + for(int k = 0; fWords[k]; k++) { + firstFloat->addText(fWords[k], wordStyle); + firstFloat->addSpace(wordStyle); + } + + firstFloat->flush(); + + Fl::repeat_timeout (2, addTextToFloatTimeout, NULL); +} + +int main(int argc, char **argv) +{ + FltkPlatform *platform = new FltkPlatform (); + Layout *layout = new Layout (platform); + + Fl_Window *window = new Fl_Window(400, 600, "Dw Floats Example"); + window->begin(); + + FltkViewport *viewport = new FltkViewport (0, 0, 400, 600); + layout->attachView (viewport); + + StyleAttrs styleAttrs; + styleAttrs.initValues (); + styleAttrs.margin.setVal (5); + + FontAttrs fontAttrs; + fontAttrs.name = "Bitstream Charter"; + fontAttrs.size = 14; + fontAttrs.weight = 400; + fontAttrs.style = FONT_STYLE_NORMAL; + fontAttrs.letterSpacing = 0; + styleAttrs.font = core::style::Font::create (layout, &fontAttrs); + + styleAttrs.color = Color::create (layout, 0x000000); + styleAttrs.backgroundColor = Color::create (layout, 0xffffff); + + Style *widgetStyle = Style::create (layout, &styleAttrs); + + styleAttrs.borderWidth.setVal (1); + styleAttrs.setBorderColor (Color::create (layout, 0x808080)); + styleAttrs.setBorderStyle (BORDER_DASHED); + styleAttrs.width = createAbsLength(100); + styleAttrs.vloat = FLOAT_LEFT; + Style *leftFloatStyle = Style::create (layout, &styleAttrs); + + styleAttrs.width = createAbsLength(80); + styleAttrs.vloat = FLOAT_RIGHT; + Style *rightFloatStyle = Style::create (layout, &styleAttrs); + + Textblock *textblock = new Textblock (false); + textblock->setStyle (widgetStyle); + layout->setWidget (textblock); + + widgetStyle->unref(); + + styleAttrs.borderWidth.setVal (0); + styleAttrs.width = LENGTH_AUTO; + styleAttrs.vloat = FLOAT_NONE; + styleAttrs.margin.setVal (0); + styleAttrs.backgroundColor = NULL; + + wordStyle = Style::create (layout, &styleAttrs); + + for(int i = 1; i <= 10; i++) { + char buf[16]; + snprintf(buf, sizeof(buf), "%d%s", + i, (i == 1 ? "st" : (i == 2 ? "nd" : (i == 3 ? "rd" : "th")))); + + const char *words[] = { "This", "is", "the", buf, "paragraph.", + "Here", "comes", "some", "more", "text", + "to", "demonstrate", "word", "wrapping.", + NULL }; + + for(int j = 0; words[j]; j++) { + textblock->addText(words[j], wordStyle); + textblock->addSpace(wordStyle); + + if ((i == 3 || i == 5) && j == 8) { + textblock->addText("[float]", wordStyle); + textblock->addSpace(wordStyle); + + Textblock *vloat = new Textblock (false); + textblock->addFloatIntoGenerator(vloat, i == 3 ? leftFloatStyle : rightFloatStyle); + + const char *fWords[] = { "This", "is", "a", "float,", "which", "is", + "set", "aside", "from", "the", "main", + "text.", NULL }; + + for(int k = 0; fWords[k]; k++) { + vloat->addText(fWords[k], wordStyle); + vloat->addSpace(wordStyle); + } + + vloat->flush (); + + if(i == 3) + firstFloat = vloat; + } + } + + textblock->addParbreak(10, wordStyle); + } + + leftFloatStyle->unref(); + rightFloatStyle->unref(); + + textblock->flush (); + + window->resizable(viewport); + window->show(); + Fl::add_timeout (2, addTextToFloatTimeout, NULL); + int errorCode = Fl::run(); + + wordStyle->unref(); + delete layout; + + return errorCode; +} |