diff --git a/doc/type/alignment.txt b/doc/type/alignment.txt index 64e9a9da..a080bc72 100644 --- a/doc/type/alignment.txt +++ b/doc/type/alignment.txt @@ -1,14 +1,18 @@ Enumeration: alignment Specifies how text and images are aligned in boxes. -An alignment consists of a vertical and a horizontal component. -Optionally there are some modifiers. +An alignment consists of: +* horizontal alignment +* vertical alignment +* (optional) how to fill the text box +* (optional) when to fill the text box --Script syntax-- In scripts, alignment is passed around as a string. --Possible values-- The value is a combination of one or more flags, separated by spaces. +These flags can appear in any order. ! Value Description | @left@ Horizontally, align at the left | @center@ Horizontally, align in the middle @@ -16,14 +20,16 @@ The value is a combination of one or more flags, separated by spaces. | @top@ Vertically, align at the top | @middle@ Vertically, align in the middle | @bottom@ Vertically, align at the bottom -| @justify@ Move characters apart or together to exactly fill the width of the box. -| @justify-words@ Move words apart or together to exactly fill the width of the box. -| @justify-overflow@ If the text becomes to long, move characters closer together. -| @stretch@ Stretch text, so it always fills the width of the box.
- For images; stretch them, but preserve the aspect ratio. -| @stretch-overflow@ Stretch (compress) the text when it becomes too long. +| @justify@ Fill the box exactly, by moving words apart/together. +| @justify-all@ Fill the box exactly, by moving individual characters apart/together. +| @stretch@ Fill the box exactly, by stretching the text.
+ For images: stretch them, but preserve the aspect ratio. +| @if-overflow@ Only apply @justify@, @justify-all@ and @stretch@ when the box is overfull. +| @force@ Also justify text at the end of a line in a multiline text field.
+ Normally only lines ending in a soft line break are justified. --Examples-- > alignment: top left > alignment: middle center +> alignment: top left force justify if-overflow > alignment: { "middle" + " " + "left" } diff --git a/src/data/field/text.cpp b/src/data/field/text.cpp index 2ba0adaa..162d4314 100644 --- a/src/data/field/text.cpp +++ b/src/data/field/text.cpp @@ -57,9 +57,9 @@ TextStyle::TextStyle(const TextFieldP& field) {} double TextStyle::getStretch() const { - if (content_width > 0 && ((alignment() & ALIGN_STRETCH) || (alignment() & ALIGN_STRETCH_OVERFLOW))) { + if (content_width > 0 && (alignment() & ALIGN_STRETCH)) { double factor = (width - padding_left - padding_right) / content_width; - if (alignment() == ALIGN_STRETCH || factor < 1.0) { + if (!(alignment() & ALIGN_IF_OVERFLOW) || factor < 1.0) { return factor; } } diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp index 34f100fc..9db6e714 100644 --- a/src/render/text/viewer.cpp +++ b/src/render/text/viewer.cpp @@ -49,7 +49,7 @@ struct TextViewer::Line { RealRect selectionRectangle(const Rotation& rot, size_t start, size_t end); /// Align the contents of this line *horizontally* inside the given rectangle - void alignHorizontal(const vector& chars, const RealRect& s); + void alignHorizontal(const vector& chars, const TextStyle& style, const RealRect& s); }; size_t TextViewer::Line::posToIndex(double x) const { @@ -755,16 +755,17 @@ void TextViewer::alignParagraph(size_t start_line, size_t end_line, const vector l.top += vdelta; // amount to shift all characters horizontally l.alignment = style.alignment; // TODO: set at another place - l.alignHorizontal(chars, s); + l.alignHorizontal(chars, style, s); } // TODO : work well with mask } -void TextViewer::Line::alignHorizontal(const vector& chars, const RealRect& s) { +void TextViewer::Line::alignHorizontal(const vector& chars, const TextStyle& style, const RealRect& s) { double width = this->width(); - if ((alignment & ALIGN_JUSTIFY) || - (alignment & ALIGN_JUSTIFY_OVERFLOW && width > s.width)) { - // justify text + bool should_fill = (alignment & ALIGN_IF_OVERFLOW ? width > s.width : true) + && (alignment & ALIGN_IF_SOFTBREAK ? break_after == BREAK_SOFT || !style.field().multi_line : true); + if ((alignment & ALIGN_JUSTIFY_ALL) && should_fill) { + // justify text, by characters justifying = true; double hdelta = s.width - width; // amount of space to distribute int count = (int)(end_or_soft - start); // distribute it among this many characters @@ -773,7 +774,7 @@ void TextViewer::Line::alignHorizontal(const vector& chars, const Real FOR_EACH(c, positions) { c += s.x + hdelta * i++ / count; } - } else if (alignment & ALIGN_JUSTIFY_WORDS) { + } else if ((alignment & ALIGN_JUSTIFY_WORDS) && should_fill) { // justify text, by words justifying = true; double hdelta = s.width - width; // amount of space to distribute @@ -787,7 +788,7 @@ void TextViewer::Line::alignHorizontal(const vector& chars, const Real c += s.x + hdelta * i / count; if (j < end_or_soft && chars[j++].break_after == BREAK_SPACE) i++; } - } else if (alignment & ALIGN_STRETCH_OVERFLOW && width >= s.width) { + } else if ((alignment & ALIGN_STRETCH) && should_fill) { // stretching, don't center or align right justifying = false; } else { diff --git a/src/util/alignment.cpp b/src/util/alignment.cpp index 9c6cbac2..8a2a5003 100644 --- a/src/util/alignment.cpp +++ b/src/util/alignment.cpp @@ -40,15 +40,19 @@ Alignment from_string(const String& s) { if (s.find(_("left")) !=String::npos) al = ALIGN_LEFT | (al & ~ALIGN_HORIZONTAL); if (s.find(_("center")) !=String::npos) al = ALIGN_CENTER | (al & ~ALIGN_HORIZONTAL); if (s.find(_("right")) !=String::npos) al = ALIGN_RIGHT | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("justify-words")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_HORIZONTAL); - if (s.find(_("justify-overflow")) !=String::npos) al = ALIGN_JUSTIFY_OVERFLOW | (al & ~ALIGN_JUSTIFY_OVERFLOW); - if (s.find(_("shrink-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW); // compatability - if (s.find(_("stretch-overflow")) !=String::npos) al = ALIGN_STRETCH_OVERFLOW | (al & ~ALIGN_STRETCH_OVERFLOW); - else if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH; + + if (s.find(_("justify")) !=String::npos) al = ALIGN_JUSTIFY_WORDS | (al & ~ALIGN_FILL); + if (s.find(_("justify-all")) !=String::npos) al = ALIGN_JUSTIFY_ALL | (al & ~ALIGN_FILL); + if (s.find(_("shrink")) !=String::npos) al = ALIGN_STRETCH | (al & ~ALIGN_FILL); + if (s.find(_("stretch")) !=String::npos) al = ALIGN_STRETCH | (al & ~ALIGN_FILL); // compatability + + if (s.find(_("overflow")) !=String::npos) al |= ALIGN_IF_OVERFLOW; + if (s.find(_("force")) ==String::npos) al |= ALIGN_IF_SOFTBREAK; // force = !if_softbreak + if (s.find(_("top")) !=String::npos) al = ALIGN_TOP | (al & ~ALIGN_VERTICAL); if (s.find(_("middle")) !=String::npos) al = ALIGN_MIDDLE | (al & ~ALIGN_VERTICAL); if (s.find(_("bottom")) !=String::npos) al = ALIGN_BOTTOM | (al & ~ALIGN_VERTICAL); + return static_cast(al); } @@ -56,20 +60,26 @@ Alignment from_string(const String& s) { String to_string(Alignment align) { String ret; // vertical - if (align & ALIGN_TOP) ret += _(" top"); - if (align & ALIGN_MIDDLE) ret += _(" middle"); - if (align & ALIGN_BOTTOM) ret += _(" bottom"); + if (align & ALIGN_TOP) ret += _("top "); + if (align & ALIGN_MIDDLE) ret += _("middle "); + if (align & ALIGN_BOTTOM) ret += _("bottom "); // horizontal - if (align & ALIGN_LEFT) ret += _(" left"); - if (align & ALIGN_LEFT) ret += _(" center"); - if (align & ALIGN_LEFT) ret += _(" right"); - if (align & ALIGN_LEFT) ret += _(" justify"); - if (align & ALIGN_LEFT) ret += _(" justify-words"); - if (align & ALIGN_JUSTIFY_OVERFLOW) ret += _(" justify-overflow"); - // modifier - if (align & ALIGN_STRETCH_OVERFLOW) ret += _(" stretch-overflow"); - if (align & ALIGN_STRETCH) ret += _(" stretch"); - return ret.substr(1); + if (align & ALIGN_LEFT) ret += _("left "); + if (align & ALIGN_CENTER) ret += _("center "); + if (align & ALIGN_RIGHT) ret += _("right "); + // fill + if (align & ALIGN_FILL) { + // force = !if_softbreak && some fill type + if (!(align & ALIGN_IF_SOFTBREAK)) ret += _("force "); + // fill + if (align & ALIGN_STRETCH) ret += _("stretch "); + if (align & ALIGN_JUSTIFY_WORDS) ret += _("justify "); + if (align & ALIGN_JUSTIFY_ALL) ret += _("justify-all "); + // modifier + if (align & ALIGN_IF_OVERFLOW) ret += _("if-overflow "); + } + ret.resize(ret.size() - 1); // drop trailing ' ' + return ret; } // we need custom io, because there can be both a horizontal and a vertical component diff --git a/src/util/alignment.hpp b/src/util/alignment.hpp index 2e376ab3..f9f1570c 100644 --- a/src/util/alignment.hpp +++ b/src/util/alignment.hpp @@ -20,18 +20,21 @@ enum Alignment { ALIGN_LEFT = 0x01 , ALIGN_CENTER = 0x02 , ALIGN_RIGHT = 0x04 -, ALIGN_JUSTIFY = 0x08 -, ALIGN_JUSTIFY_WORDS = 0x10 -, ALIGN_HORIZONTAL = ALIGN_LEFT | ALIGN_CENTER | ALIGN_RIGHT | ALIGN_JUSTIFY | ALIGN_JUSTIFY_WORDS +, ALIGN_HORIZONTAL = ALIGN_LEFT | ALIGN_CENTER | ALIGN_RIGHT +// horizontal filling +, ALIGN_STRETCH = 0x10 +, ALIGN_JUSTIFY_WORDS = 0x20 +, ALIGN_JUSTIFY_ALL = 0x40 +, ALIGN_FILL = ALIGN_STRETCH | ALIGN_JUSTIFY_WORDS | ALIGN_JUSTIFY_ALL +// horizontal fill modifiers +, ALIGN_IF_OVERFLOW = 0x1000 // only fill if text_width > box_width +, ALIGN_IF_SOFTBREAK = 0x2000 // only fill before soft line breaks // vertical , ALIGN_TOP = 0x100 , ALIGN_MIDDLE = 0x200 , ALIGN_BOTTOM = 0x400 , ALIGN_VERTICAL = ALIGN_TOP | ALIGN_MIDDLE | ALIGN_BOTTOM // modifiers -, ALIGN_JUSTIFY_OVERFLOW = 0x1000 -, ALIGN_STRETCH_OVERFLOW = 0x2000 -, ALIGN_STRETCH = 0x4000 // common combinations , ALIGN_TOP_LEFT = ALIGN_TOP | ALIGN_LEFT , ALIGN_TOP_CENTER = ALIGN_TOP | ALIGN_CENTER