From 54fdc78858a71f60bd8593acc7ae6a43772f26be Mon Sep 17 00:00:00 2001 From: twanvl Date: Sun, 2 Sep 2007 21:00:49 +0000 Subject: [PATCH] Added 'paragraph height' property to split a text field into multiple boxes. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@666 0fc631ac-6414-0410-93d0-97cfa31319b6 --- doc/type/style.txt | 2 ++ src/data/field/text.cpp | 2 ++ src/data/field/text.hpp | 1 + src/render/text/viewer.cpp | 54 +++++++++++++++++++++++++++----------- src/render/text/viewer.hpp | 2 ++ 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/doc/type/style.txt b/doc/type/style.txt index 4a81609d..50b04a83 100644 --- a/doc/type/style.txt +++ b/doc/type/style.txt @@ -76,6 +76,8 @@ The rest of the properties depend on the type of [[type:field]] this style is fo | ^^^ @line height soft max@ ^^^ ''disabled'' When there is still vertical room in the text box, increase the line heights to at most these values to spread the text more evenly. | ^^^ @line height hard max@ ^^^ ^^^ ^^^ | ^^^ @line height line max@ ^^^ ^^^ ^^^ +| ^^^ @paragraph height@ [[type:double]] ''flexible'' The height of paragraphs. If specified, each paragraph is given this much space, and aligned inside that space as specified by @alignment@.
+ A paragraph break is any line break that is not soft (i.e. caused by word wrap or a @""@ break). | ^^^ @mask@ [[type:filename]] ''none'' A mask that indicates where in the box text can be placed.
Text is never put in black areas of the box:
diff --git a/src/data/field/text.cpp b/src/data/field/text.cpp index 5ec457f1..abc90c8e 100644 --- a/src/data/field/text.cpp +++ b/src/data/field/text.cpp @@ -55,6 +55,7 @@ TextStyle::TextStyle(const TextFieldP& field) , line_height_soft_max(0.0) , line_height_hard_max(0.0) , line_height_line_max(0.0) + , paragraph_height(-1) , direction(LEFT_TO_RIGHT) {} @@ -114,6 +115,7 @@ IMPLEMENT_REFLECTION(TextStyle) { REFLECT(line_height_soft_max); REFLECT(line_height_hard_max); REFLECT(line_height_line_max); + REFLECT(paragraph_height); REFLECT_N("mask", mask_filename); REFLECT(direction); reflect_content(tag, *this); diff --git a/src/data/field/text.hpp b/src/data/field/text.hpp index c0aace94..c7ed4559 100644 --- a/src/data/field/text.hpp +++ b/src/data/field/text.hpp @@ -68,6 +68,7 @@ class TextStyle : public Style { double line_height_soft_max; ///< Maximum line height double line_height_hard_max; ///< Maximum line height double line_height_line_max; ///< Maximum line height + double paragraph_height; ///< Fixed height of paragraphs String mask_filename; ///< Filename of the mask ContourMask mask; ///< Mask to fit the text to (may be null) Direction direction; ///< In what direction is text layed out? diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp index ba2e78f2..930e541c 100644 --- a/src/render/text/viewer.cpp +++ b/src/render/text/viewer.cpp @@ -635,17 +635,37 @@ double TextViewer::lineRight(RotatedDC& dc, const TextStyle& style, double y) co void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const TextStyle& style) { - // Find height of the text, don't count the last lines if they are empty - double height = 0; - FOR_EACH_REVERSE(l, lines) { - height = l.top + l.line_height; - if (l.line_height) break; // not an empty line - } - // amount to shift all lines vertically + // Size of the box RealSize s = add_diagonal( dc.getInternalSize(), -RealSize(style.padding_left+style.padding_right, style.padding_top + style.padding_bottom)); - + if (style.paragraph_height <= 0) { + // whole text box alignment + alignParagraph(0, lines.size(), chars, style, RealRect(RealPoint(0,0),s)); + } else { + // per paragraph alignment + size_t start = 0; + int n = 0; + for (size_t last = 0 ; last < lines.size() ; ++last) { + if (lines[last].break_after != BREAK_SOFT || last == lines.size()) { + alignParagraph(start, last + 1, chars, style, RealRect(0, n*style.paragraph_height, s.width, style.paragraph_height)); + start = last + 1; + ++n; + } + } + } +} + +void TextViewer::alignParagraph(size_t start_line, size_t end_line, const vector& chars, const TextStyle& style, const RealRect& s) { + if (start_line >= end_line) return; + // Find height of the text, don't count the last lines if they are empty + double height = 0; + for (size_t li = end_line - 1 ; li + 1 > start_line ; --li) { + Line& l = lines[li]; + height = l.top + l.line_height; + if (l.line_height) break; // not an empty line + } + height -= lines[start_line].top; // stretch lines by increasing the space between them if (height < s.height) { double d_soft = max(0.0, style.line_height_soft_max - style.line_height_soft); @@ -662,7 +682,8 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const bool line = d_line >= stop; // sum of the line height we can apply this to? double sum = 0; - FOR_EACH(l, lines) { + for (size_t li = start_line ; li < end_line ; ++li) { + const Line& l = lines[li]; if ((soft && l.break_after == BREAK_SOFT) || (hard && l.break_after == BREAK_HARD) || (line && l.break_after == BREAK_LINE)) sum += l.line_height; @@ -672,7 +693,8 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const double to_add = min(stop, (s.height - height) / sum); // apply double add = 0; - FOR_EACH(l, lines) { + for (size_t li = start_line ; li < end_line ; ++li) { + Line& l = lines[li]; l.top += add; // adjust next line by.. if ((soft && l.break_after == BREAK_SOFT) @@ -684,9 +706,11 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const } if (style.alignment == ALIGN_TOP_LEFT) return; // align - double vdelta = align_delta_y(style.alignment, s.height, height); + double vdelta = align_delta_y(style.alignment, s.height, height) + + s.y - lines[start_line].top; // align all lines - FOR_EACH(l, lines) { + for (size_t li = start_line ; li < end_line ; ++li) { + Line& l = lines[li]; l.top += vdelta; // amount to shift all characters horizontally double width = l.positions[l.end_or_soft - l.start]; @@ -699,7 +723,7 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const if (count <= 0) count = 1; // prevent div by 0 int i = 0; FOR_EACH(c, l.positions) { - c += hdelta * i++ / count; + c += s.x + hdelta * i++ / count; } } else if (style.alignment & ALIGN_JUSTIFY_WORDS) { // justify text, by words @@ -712,13 +736,13 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const if (count == 0) count = 1; // prevent div by 0 int i = 0; size_t j = l.start; FOR_EACH(c, l.positions) { - c += hdelta * i / count; + c += s.x + hdelta * i / count; if (j < l.end_or_soft && chars[j++].break_after == BREAK_SPACE) i++; } } else { // simple alignment justifying = false; - double hdelta = align_delta_x(style.alignment, s.width, width); + double hdelta = s.x + align_delta_x(style.alignment, s.width, width); FOR_EACH(c, l.positions) { c += hdelta; } diff --git a/src/render/text/viewer.hpp b/src/render/text/viewer.hpp index b2368df4..0bac7d54 100644 --- a/src/render/text/viewer.hpp +++ b/src/render/text/viewer.hpp @@ -143,6 +143,8 @@ class TextViewer { bool prepareLinesScale(RotatedDC& dc, const vector& chars, const TextStyle& style, bool stop_if_too_long, vector& lines_out) const; /// Align the lines within the textbox void alignLines(RotatedDC& dc, const vector& chars, const TextStyle& style); + /// Align the lines of a single paragraph (a set of lines) + void alignParagraph(size_t start_line, size_t end_line, const vector& chars, const TextStyle& style, const RealRect& box); /// Find the line the given index is on, returns the first line if the index is not found const Line& findLine(size_t index) const;