aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dw/layout.cc1
-rw-r--r--dw/style.cc12
-rw-r--r--dw/style.hh17
-rw-r--r--dw/textblock.cc342
-rw-r--r--dw/textblock.hh95
-rw-r--r--dw/textblock_linebreaking.cc18
-rw-r--r--dw/types.hh3
-rw-r--r--dw/widget.cc21
-rw-r--r--dw/widget.hh3
-rw-r--r--lout/identity.cc3
-rw-r--r--src/cssparser.cc6
-rw-r--r--src/html.cc7
-rw-r--r--src/styleengine.cc3
-rw-r--r--test/Makefile.am9
-rw-r--r--test/dw_float_test.cc142
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;
+}