Commit 968faec3 authored by twanvl's avatar twanvl

Cleaned up the Alignment type, it is now much more orthogonal.

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