mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
fix bullet indent, add clauses
This commit is contained in:
+11
-5
@@ -40,14 +40,19 @@ IMPLEMENT_REFLECTION(TextField) {
|
|||||||
TextLayoutP dummy_layout() {
|
TextLayoutP dummy_layout() {
|
||||||
auto layout = make_intrusive<TextLayout>();
|
auto layout = make_intrusive<TextLayout>();
|
||||||
auto line = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::LINE);
|
auto line = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::LINE);
|
||||||
|
auto clause = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::CLAUSE);
|
||||||
auto paragraph = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::PARAGRAPH);
|
auto paragraph = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::PARAGRAPH);
|
||||||
auto block = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::BLOCK);
|
auto block = make_intrusive<LineLayout>(0, 0, 0, LineLayout::Type::BLOCK);
|
||||||
|
clause ->lines.push_back(line);
|
||||||
paragraph->lines.push_back(line);
|
paragraph->lines.push_back(line);
|
||||||
block->lines.push_back(line);
|
block ->lines.push_back(line);
|
||||||
layout->lines.push_back(line);
|
layout ->lines.push_back(line);
|
||||||
block->paragraphs.push_back(paragraph);
|
paragraph->clauses.push_back(clause);
|
||||||
layout->paragraphs.push_back(paragraph);
|
block ->clauses.push_back(clause);
|
||||||
layout->blocks.push_back(block);
|
layout ->clauses.push_back(clause);
|
||||||
|
block ->paragraphs.push_back(paragraph);
|
||||||
|
layout ->paragraphs.push_back(paragraph);
|
||||||
|
layout ->blocks.push_back(block);
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +134,7 @@ void LineLayout::reflect(GetMember& handler) const {
|
|||||||
REFLECT_N("bottom", bottom());
|
REFLECT_N("bottom", bottom());
|
||||||
REFLECT_N("middle", middle());
|
REFLECT_N("middle", middle());
|
||||||
if (type > Type::LINE) REFLECT(lines);
|
if (type > Type::LINE) REFLECT(lines);
|
||||||
|
if (type > Type::CLAUSE) REFLECT(clauses);
|
||||||
if (type > Type::PARAGRAPH) REFLECT(paragraphs);
|
if (type > Type::PARAGRAPH) REFLECT(paragraphs);
|
||||||
if (type > Type::BLOCK) REFLECT(blocks);
|
if (type > Type::BLOCK) REFLECT(blocks);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ public:
|
|||||||
class LineLayout : public IntrusivePtrVirtualBase {
|
class LineLayout : public IntrusivePtrVirtualBase {
|
||||||
public:
|
public:
|
||||||
double width, top, height;
|
double width, top, height;
|
||||||
enum class Type { LINE, PARAGRAPH, BLOCK, ALL } type;
|
enum class Type { LINE, CLAUSE, PARAGRAPH, BLOCK, ALL } type;
|
||||||
vector<LineLayoutP> lines, paragraphs, blocks;
|
vector<LineLayoutP> lines, clauses, paragraphs, blocks;
|
||||||
|
|
||||||
LineLayout() {}
|
LineLayout() {}
|
||||||
LineLayout(double width, double top, double height, Type type) : width(width), top(top), height(height), type(type) {}
|
LineLayout(double width, double top, double height, Type type) : width(width), top(top), height(height), type(type) {}
|
||||||
|
|||||||
+28
-17
@@ -46,16 +46,20 @@ struct TextElementsFromString {
|
|||||||
|
|
||||||
const TextStyle& style;
|
const TextStyle& style;
|
||||||
Context& ctx;
|
Context& ctx;
|
||||||
|
vector<TextClause>& clauses;
|
||||||
vector<TextParagraph>& paragraphs;
|
vector<TextParagraph>& paragraphs;
|
||||||
|
|
||||||
TextElementsFromString(TextElements& out, const String& text, const TextStyle& style, Context& ctx)
|
TextElementsFromString(TextElements& out, const String& text, const TextStyle& style, Context& ctx)
|
||||||
: style(style), ctx(ctx), paragraphs(out.paragraphs)
|
: style(style), ctx(ctx), clauses(out.clauses), paragraphs(out.paragraphs)
|
||||||
{
|
{
|
||||||
out.start = 0;
|
out.start = 0;
|
||||||
out.end = text.size();
|
out.end = text.size();
|
||||||
|
clauses.emplace_back();
|
||||||
|
clauses.back().start = 0;
|
||||||
paragraphs.emplace_back();
|
paragraphs.emplace_back();
|
||||||
paragraphs.back().start = 0;
|
paragraphs.back().start = 0;
|
||||||
fromString(out.children, text, 0, text.size());
|
fromString(out.children, text, 0, text.size());
|
||||||
|
clauses.back().end = text.size();
|
||||||
paragraphs.back().end = text.size();
|
paragraphs.back().end = text.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +74,7 @@ private:
|
|||||||
if (text_start < pos) {
|
if (text_start < pos) {
|
||||||
// text element before this tag?
|
// text element before this tag?
|
||||||
addText(elements, text, text_start, pos);
|
addText(elements, text, text_start, pos);
|
||||||
addParagraphs(text, text_start, pos);
|
addClausesAndParagraphs(text, text_start, pos);
|
||||||
}
|
}
|
||||||
// a (formatting) tag
|
// a (formatting) tag
|
||||||
size_t tag_start = pos;
|
size_t tag_start = pos;
|
||||||
@@ -175,7 +179,8 @@ private:
|
|||||||
} else if (is_tag(text, tag_start, _("<bullet"))) {
|
} else if (is_tag(text, tag_start, _("<bullet"))) {
|
||||||
// start of bullet point, set margin before bullet here, but only once
|
// start of bullet point, set margin before bullet here, but only once
|
||||||
// subsequent times will align to this one
|
// subsequent times will align to this one
|
||||||
if (paragraphs.back().margin_before_bullet == paragraphs.back().start) {
|
if (!paragraphs.back().before_bullet_found) {
|
||||||
|
paragraphs.back().before_bullet_found = true;
|
||||||
paragraphs.back().margin_before_bullet = tag_start;
|
paragraphs.back().margin_before_bullet = tag_start;
|
||||||
}
|
}
|
||||||
if (li <= 0) {
|
if (li <= 0) {
|
||||||
@@ -184,7 +189,8 @@ private:
|
|||||||
} else if (is_tag(text, tag_start, _("</bullet"))) {
|
} else if (is_tag(text, tag_start, _("</bullet"))) {
|
||||||
// end of bullet point, set margin after bullet here, but only once
|
// end of bullet point, set margin after bullet here, but only once
|
||||||
// subsequent times will align to this one
|
// subsequent times will align to this one
|
||||||
if (paragraphs.back().margin_after_bullet == paragraphs.back().start) {
|
if (!paragraphs.back().after_bullet_found) {
|
||||||
|
paragraphs.back().after_bullet_found = true;
|
||||||
paragraphs.back().margin_after_bullet = pos;
|
paragraphs.back().margin_after_bullet = pos;
|
||||||
}
|
}
|
||||||
if (li <= 0) {
|
if (li <= 0) {
|
||||||
@@ -205,9 +211,9 @@ private:
|
|||||||
m.top += margins.back().top;
|
m.top += margins.back().top;
|
||||||
}
|
}
|
||||||
margins.emplace_back(m);
|
margins.emplace_back(m);
|
||||||
paragraphs.back().margin_left = m.left;
|
clauses.back().margin_left = m.left;
|
||||||
paragraphs.back().margin_right = m.right;
|
clauses.back().margin_right = m.right;
|
||||||
paragraphs.back().margin_top = m.top;
|
clauses.back().margin_top = m.top;
|
||||||
}
|
}
|
||||||
} else if (is_tag(text, tag_start, _("</margin"))) {
|
} else if (is_tag(text, tag_start, _("</margin"))) {
|
||||||
if (!margins.empty()) margins.pop_back();
|
if (!margins.empty()) margins.pop_back();
|
||||||
@@ -233,7 +239,7 @@ private:
|
|||||||
if (text_start < end) {
|
if (text_start < end) {
|
||||||
// remaining text at the end
|
// remaining text at the end
|
||||||
addText(elements, text, text_start, end);
|
addText(elements, text, text_start, end);
|
||||||
addParagraphs(text, text_start, end);
|
addClausesAndParagraphs(text, text_start, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +255,8 @@ private:
|
|||||||
// text, possibly mixed with symbols
|
// text, possibly mixed with symbols
|
||||||
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
|
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
|
||||||
LineBreak line_break = line > 0 ? LineBreak::LINE :
|
LineBreak line_break = line > 0 ? LineBreak::LINE :
|
||||||
soft_line > 0 ? LineBreak::SOFT : LineBreak::HARD;
|
soft_line > 0 ? LineBreak::SOFT :
|
||||||
|
LineBreak::HARD;
|
||||||
if (kwpph > 0 || param > 0) {
|
if (kwpph > 0 || param > 0) {
|
||||||
// bracket the text
|
// bracket the text
|
||||||
content = String(LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
|
content = String(LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
|
||||||
@@ -285,22 +292,25 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Find paragraph breaks in text
|
// Find clause and paragraph breaks in text
|
||||||
void addParagraphs(const String& text, size_t start, size_t end) {
|
void addClausesAndParagraphs(const String& text, size_t start, size_t end) {
|
||||||
if (line == 0 && soft_line > 0) return;
|
|
||||||
for (size_t i = start; i < end; ++i) {
|
for (size_t i = start; i < end; ++i) {
|
||||||
wxUniChar c = text.GetChar(i);
|
wxUniChar c = text.GetChar(i);
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
|
clauses.back().end = i + 1;
|
||||||
|
clauses.emplace_back();
|
||||||
|
clauses.back().start = i + 1;
|
||||||
|
if (!margins.empty()) {
|
||||||
|
clauses.back().margin_left = margins.back().left;
|
||||||
|
clauses.back().margin_right = margins.back().right;
|
||||||
|
clauses.back().margin_top = margins.back().top;
|
||||||
|
}
|
||||||
|
if (line < 1 && soft_line > 0) continue;
|
||||||
paragraphs.back().end = i + 1;
|
paragraphs.back().end = i + 1;
|
||||||
paragraphs.emplace_back();
|
paragraphs.emplace_back();
|
||||||
paragraphs.back().start = i + 1;
|
paragraphs.back().start = i + 1;
|
||||||
paragraphs.back().margin_before_bullet = i + 1;
|
paragraphs.back().margin_before_bullet = i + 1;
|
||||||
paragraphs.back().margin_after_bullet = i + 1;
|
paragraphs.back().margin_after_bullet = i + 1;
|
||||||
if (!margins.empty()) {
|
|
||||||
paragraphs.back().margin_left = margins.back().left;
|
|
||||||
paragraphs.back().margin_right = margins.back().right;
|
|
||||||
paragraphs.back().margin_top = margins.back().top;
|
|
||||||
}
|
|
||||||
if (!aligns.empty()) {
|
if (!aligns.empty()) {
|
||||||
paragraphs.back().alignment = aligns.back();
|
paragraphs.back().alignment = aligns.back();
|
||||||
}
|
}
|
||||||
@@ -333,6 +343,7 @@ private:
|
|||||||
|
|
||||||
void TextElements::clear() {
|
void TextElements::clear() {
|
||||||
children.clear();
|
children.clear();
|
||||||
|
clauses.clear();
|
||||||
paragraphs.clear();
|
paragraphs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-11
@@ -25,17 +25,18 @@ class SymbolFontRef;
|
|||||||
/// Information on a linebreak
|
/// Information on a linebreak
|
||||||
enum class LineBreak {
|
enum class LineBreak {
|
||||||
NO, // no line break ever
|
NO, // no line break ever
|
||||||
MAYBE, // break here when in "direction:vertical" mode
|
MAYBE, // break here when in "direction:vertical" mode (break as WRAP)
|
||||||
SPACE, // optional line break (' ')
|
SPACE, // optional line break, spacing as a soft break, ends a line, ( )
|
||||||
SOFT, // always a line break, spacing as a soft break, doesn't end paragraphs
|
WRAP, // always a line break, spacing as a soft break, ends a line, ( )
|
||||||
HARD, // always a line break ('\n')
|
SOFT, // always a line break, spacing as a soft break, ends a clause, (<soft-line>\n</soft-line>)
|
||||||
LINE, // line break with a separator line (<line>)
|
HARD, // always a line break, spacing as a hard break, ends a paragraph, (\n)
|
||||||
|
LINE, // always a line break, spacing as a line break, ends a block, (<line>\n</line>), has separator
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Information on a character in a TextElement
|
/// Information on a character in a TextElement
|
||||||
struct CharInfo {
|
struct CharInfo {
|
||||||
RealSize size; ///< Size of this character
|
RealSize size; ///< Size of this character
|
||||||
LineBreak break_after : 16; ///< How/when to break after it?
|
LineBreak break_after; ///< How/when to break after it?
|
||||||
bool soft : 1; ///< Is this a 'soft' character? soft characters are ignored for alignment
|
bool soft : 1; ///< Is this a 'soft' character? soft characters are ignored for alignment
|
||||||
bool bullet : 1; ///< Is this a bullet point?
|
bool bullet : 1; ///< Is this a bullet point?
|
||||||
|
|
||||||
@@ -146,14 +147,20 @@ public:
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : TextElements
|
// ----------------------------------------------------------------------------- : TextElements
|
||||||
|
|
||||||
|
class TextClause {
|
||||||
|
public:
|
||||||
|
double margin_left = 0., margin_right = 0., margin_top = 0.;
|
||||||
|
size_t start = String::npos, end = String::npos;
|
||||||
|
};
|
||||||
|
|
||||||
class TextParagraph {
|
class TextParagraph {
|
||||||
public:
|
public:
|
||||||
optional<Alignment> alignment;
|
optional<Alignment> alignment;
|
||||||
double margin_left = 0., margin_right = 0.;
|
bool before_bullet_found = false;
|
||||||
double margin_top = 0.; //, margin_bottom = 0.; // TODO: more margin options?
|
bool after_bullet_found = false;
|
||||||
size_t start = String::npos, end = String::npos;
|
|
||||||
size_t margin_before_bullet = 0; // position of the bullet tag
|
size_t margin_before_bullet = 0; // position of the bullet tag
|
||||||
size_t margin_after_bullet = 0; // position of the first character after the bullet tag
|
size_t margin_after_bullet = 0; // position of the first character after the bullet tag
|
||||||
|
size_t start = String::npos, end = String::npos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A list of text elements extracted from a string
|
/// A list of text elements extracted from a string
|
||||||
@@ -161,8 +168,12 @@ class TextElements : public CompoundTextElement {
|
|||||||
public:
|
public:
|
||||||
TextElements() : CompoundTextElement(String::npos,String::npos) {}
|
TextElements() : CompoundTextElement(String::npos,String::npos) {}
|
||||||
|
|
||||||
/// Information on the paragraphs/blocks in the string
|
/// Information on the clauses/paragraphs/blocks in the string
|
||||||
/// Text segments separated by newlines are considered paragraphs
|
/// Text segments separated by wrapping are considered lines
|
||||||
|
/// Text segments separated by soft newlines are considered clauses
|
||||||
|
/// Text segments separated by hard newlines are considered paragraphs
|
||||||
|
/// Text segments separated by line newlines are considered blocks
|
||||||
|
vector<TextClause> clauses;
|
||||||
vector<TextParagraph> paragraphs;
|
vector<TextParagraph> paragraphs;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|||||||
+61
-32
@@ -21,9 +21,9 @@ struct TextViewer::Line {
|
|||||||
LineBreak break_after; ///< Is there a saparator after this line?
|
LineBreak break_after; ///< Is there a saparator after this line?
|
||||||
optional<Alignment> alignment; ///< Alignment of this line
|
optional<Alignment> alignment; ///< Alignment of this line
|
||||||
bool justifying; ///< Is the text justified? Only true when *really* justifying.
|
bool justifying; ///< Is the text justified? Only true when *really* justifying.
|
||||||
double margin_left; ///< Left margin including the margin tag and bullet point
|
double margin_left_after_bullet; ///< Left margin including the margin tag and bullet point
|
||||||
double margin_left_before_bullet; ///< Left margin but just before the bullet point
|
double margin_left_before_bullet; ///< Left margin including the margin tag but just before the bullet point
|
||||||
double margin_right; ///< Rightmargin
|
double margin_right; ///< Right margin
|
||||||
bool bullet; ///< Does this line start with a bullet point?
|
bool bullet; ///< Does this line start with a bullet point?
|
||||||
|
|
||||||
Line()
|
Line()
|
||||||
@@ -357,7 +357,7 @@ void update_size(LineLayout& layout, TextViewer::Line const& l) {
|
|||||||
TextLayoutP TextViewer::extractLayoutInfo() const {
|
TextLayoutP TextViewer::extractLayoutInfo() const {
|
||||||
// store information about the content/layout
|
// store information about the content/layout
|
||||||
TextLayoutP layout = make_intrusive<TextLayout>();
|
TextLayoutP layout = make_intrusive<TextLayout>();
|
||||||
LineLayoutP paragraph, block;
|
LineLayoutP clause, paragraph, block;
|
||||||
for (auto const& l : lines) {
|
for (auto const& l : lines) {
|
||||||
LineLayoutP line = make_intrusive<LineLayout>(l.width(), l.top, l.line_height, LineLayout::Type::LINE);
|
LineLayoutP line = make_intrusive<LineLayout>(l.width(), l.top, l.line_height, LineLayout::Type::LINE);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
@@ -371,18 +371,29 @@ TextLayoutP TextViewer::extractLayoutInfo() const {
|
|||||||
block->paragraphs.push_back(paragraph);
|
block->paragraphs.push_back(paragraph);
|
||||||
layout->paragraphs.push_back(paragraph);
|
layout->paragraphs.push_back(paragraph);
|
||||||
}
|
}
|
||||||
|
if (!clause) {
|
||||||
|
clause = make_intrusive<LineLayout>(*line);
|
||||||
|
clause->type = LineLayout::Type::CLAUSE;
|
||||||
|
paragraph->clauses.push_back(clause);
|
||||||
|
block->clauses.push_back(clause);
|
||||||
|
layout->clauses.push_back(clause);
|
||||||
|
}
|
||||||
|
clause->lines.push_back(line);
|
||||||
paragraph->lines.push_back(line);
|
paragraph->lines.push_back(line);
|
||||||
block->lines.push_back(line);
|
block->lines.push_back(line);
|
||||||
layout->lines.push_back(line);
|
layout->lines.push_back(line);
|
||||||
if (l.line_height > 0) {
|
if (l.line_height > 0) {
|
||||||
|
update_size(*clause, l);
|
||||||
update_size(*paragraph, l);
|
update_size(*paragraph, l);
|
||||||
update_size(*block, l);
|
update_size(*block, l);
|
||||||
update_size(*layout, l);
|
update_size(*layout, l);
|
||||||
}
|
}
|
||||||
if (l.break_after == LineBreak::LINE) {
|
if (l.break_after == LineBreak::LINE) {
|
||||||
paragraph = block = nullptr;
|
clause = paragraph = block = nullptr;
|
||||||
} else if (l.break_after == LineBreak::HARD) {
|
} else if (l.break_after == LineBreak::HARD) {
|
||||||
paragraph = nullptr;
|
clause = paragraph = nullptr;
|
||||||
|
} else if (l.break_after == LineBreak::SOFT) {
|
||||||
|
clause = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i=0; i+1 < layout->blocks.size() ; ++i) {
|
for (size_t i=0; i+1 < layout->blocks.size() ; ++i) {
|
||||||
@@ -547,7 +558,7 @@ void TextViewer::prepareLinesTryScales(RotatedDC& dc, const String& text, const
|
|||||||
|
|
||||||
// Try to fit a blank line in the masked image, move down until it fits
|
// Try to fit a blank line in the masked image, move down until it fits
|
||||||
RealSize TextViewer::fitLineWidth(Line& line, RotatedDC& dc, const TextStyle& style) const {
|
RealSize TextViewer::fitLineWidth(Line& line, RotatedDC& dc, const TextStyle& style) const {
|
||||||
double margin_left = line.bullet ? line.margin_left_before_bullet : line.margin_left;
|
double margin_left = line.bullet ? line.margin_left_before_bullet : line.margin_left_after_bullet;
|
||||||
RealSize line_size(margin_left + lineLeft(dc, style, line.top), 0);
|
RealSize line_size(margin_left + lineLeft(dc, style, line.top), 0);
|
||||||
while (line.top < dc.getHeight() && line_size.width + 1 >= dc.getWidth() - style.padding_right - line.margin_right) {
|
while (line.top < dc.getHeight() && line_size.width + 1 >= dc.getWidth() - style.padding_right - line.margin_right) {
|
||||||
// nothing fits on this line, move down one pixel
|
// nothing fits on this line, move down one pixel
|
||||||
@@ -561,16 +572,20 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
// Try to layout the text at the current scale
|
// Try to layout the text at the current scale
|
||||||
lines.clear();
|
lines.clear();
|
||||||
|
|
||||||
|
// The current "clause" in the input string
|
||||||
|
size_t i_clause = 0;
|
||||||
|
assert(elements.clauses.size() > 0);
|
||||||
|
|
||||||
// The current "paragraph" in the input string
|
// The current "paragraph" in the input string
|
||||||
size_t i_para = 0;
|
size_t i_para = 0;
|
||||||
assert(elements.paragraphs.size() > 0);
|
assert(elements.paragraphs.size() > 0);
|
||||||
|
|
||||||
// first line
|
// first line
|
||||||
Line line;
|
Line line;
|
||||||
line.top = style.padding_top;
|
line.top = style.padding_top + elements.clauses[0].margin_top;
|
||||||
line.margin_left = elements.paragraphs[0].margin_left;
|
line.margin_left_after_bullet = elements.clauses[0].margin_left;
|
||||||
line.margin_left_before_bullet = elements.paragraphs[0].margin_left;
|
line.margin_left_before_bullet = elements.clauses[0].margin_left;
|
||||||
line.margin_right = elements.paragraphs[0].margin_right;
|
line.margin_right = elements.clauses[0].margin_right;
|
||||||
line.alignment = elements.paragraphs[0].alignment;
|
line.alignment = elements.paragraphs[0].alignment;
|
||||||
// size of the line so far
|
// size of the line so far
|
||||||
RealSize line_size = fitLineWidth(line, dc, style);
|
RealSize line_size = fitLineWidth(line, dc, style);
|
||||||
@@ -584,14 +599,26 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
// For each character ...
|
// For each character ...
|
||||||
for (size_t i = 0 ; i < chars.size() ; ++i) {
|
for (size_t i = 0 ; i < chars.size() ; ++i) {
|
||||||
const CharInfo& c = chars[i];
|
const CharInfo& c = chars[i];
|
||||||
|
assert(i_clause < elements.clauses.size());
|
||||||
assert(i_para < elements.paragraphs.size());
|
assert(i_para < elements.paragraphs.size());
|
||||||
assert(c.size.width == 0 || elements.paragraphs[i_para].start <= i && i < elements.paragraphs[i_para].end);
|
assert(c.size.width == 0 || elements.paragraphs[i_para].start <= i && i < elements.paragraphs[i_para].end);
|
||||||
|
// If we found the paragraph's bullet point, calculate the margins
|
||||||
|
if (i == elements.paragraphs[i_para].margin_after_bullet) {
|
||||||
|
for (size_t j = line.start; j < elements.paragraphs[i_para].margin_after_bullet; ++j) {
|
||||||
|
line.margin_left_after_bullet += chars[j].size.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == elements.paragraphs[i_para].margin_before_bullet) {
|
||||||
|
for (size_t j = line.start; j < elements.paragraphs[i_para].margin_before_bullet; ++j) {
|
||||||
|
line.margin_left_before_bullet += chars[j].size.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Should we break?
|
// Should we break?
|
||||||
bool word_too_long = false;
|
bool word_too_long = false;
|
||||||
bool break_now = false;
|
bool break_now = false;
|
||||||
bool accept_word = false; // the current word should be added to the line
|
bool accept_word = false; // the current word should be added to the line
|
||||||
bool hide_breaker = true; // hide the \n or _(' ') that caused a line break
|
bool hide_breaker = true; // hide the \n or _(' ') that caused a line break
|
||||||
if (c.break_after == LineBreak::SOFT || c.break_after == LineBreak::HARD || c.break_after == LineBreak::LINE) {
|
if (c.break_after >= LineBreak::WRAP) {
|
||||||
break_now = true;
|
break_now = true;
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
line.break_after = c.break_after;
|
line.break_after = c.break_after;
|
||||||
@@ -602,7 +629,7 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
break_now = true;
|
break_now = true;
|
||||||
accept_word = true;
|
accept_word = true;
|
||||||
hide_breaker = false;
|
hide_breaker = false;
|
||||||
line.break_after = LineBreak::SOFT;
|
line.break_after = LineBreak::WRAP;
|
||||||
}
|
}
|
||||||
// Add size of the character
|
// Add size of the character
|
||||||
if (c.break_after != LineBreak::LINE) {
|
if (c.break_after != LineBreak::LINE) {
|
||||||
@@ -612,12 +639,6 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
}
|
}
|
||||||
positions_word.push_back(word_size.width);
|
positions_word.push_back(word_size.width);
|
||||||
if (!c.soft) word_end_or_soft = i + 1;
|
if (!c.soft) word_end_or_soft = i + 1;
|
||||||
if (i < elements.paragraphs[i_para].margin_after_bullet) {
|
|
||||||
line.margin_left += c.size.width; // character in left margin
|
|
||||||
if (i < elements.paragraphs[i_para].margin_before_bullet) {
|
|
||||||
line.margin_left_before_bullet += c.size.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Did the word become too long?
|
// Did the word become too long?
|
||||||
if (!break_now) {
|
if (!break_now) {
|
||||||
double max_width = lineRight(dc, style, line.top) - line.margin_right;
|
double max_width = lineRight(dc, style, line.top) - line.margin_right;
|
||||||
@@ -635,12 +656,12 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
accept_word = true;
|
accept_word = true;
|
||||||
hide_breaker = false;
|
hide_breaker = false;
|
||||||
word_too_long = true;
|
word_too_long = true;
|
||||||
line.break_after = LineBreak::SOFT;
|
line.break_after = LineBreak::WRAP;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// line would become too long, break before the current word
|
// line would become too long, break before the current word
|
||||||
break_now = true;
|
break_now = true;
|
||||||
line.break_after = LineBreak::SOFT;
|
line.break_after = LineBreak::WRAP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -688,20 +709,28 @@ bool TextViewer::prepareLinesAtScale(RotatedDC& dc, const vector<CharInfo>& char
|
|||||||
line.top += line.line_height * line_height_multiplier;
|
line.top += line.line_height * line_height_multiplier;
|
||||||
line.start = word_start;
|
line.start = word_start;
|
||||||
line.positions.clear();
|
line.positions.clear();
|
||||||
if (line.break_after == LineBreak::LINE) line.line_height = 0;
|
if (line.break_after >= LineBreak::SOFT) {
|
||||||
|
// end of clause
|
||||||
|
assert(elements.clauses[i_clause].end == i + 1);
|
||||||
|
assert(i_clause + 1 < elements.clauses.size());
|
||||||
|
if (i_clause + 1 < elements.clauses.size()) ++i_clause;
|
||||||
|
assert(elements.clauses[i_clause].start == i + 1);
|
||||||
|
line.margin_right = elements.clauses[i_clause].margin_right;
|
||||||
|
//if (line.start == elements.clauses[i_clause].start) {
|
||||||
|
line.top += elements.clauses[i_clause].margin_top;
|
||||||
|
//}
|
||||||
|
}
|
||||||
if (line.break_after >= LineBreak::HARD) {
|
if (line.break_after >= LineBreak::HARD) {
|
||||||
// end of paragraph
|
// end of paragraph
|
||||||
// look at next paragraph
|
|
||||||
assert(elements.paragraphs[i_para].end == i + 1);
|
assert(elements.paragraphs[i_para].end == i + 1);
|
||||||
assert(i_para + 1 < elements.paragraphs.size());
|
assert(i_para + 1 < elements.paragraphs.size());
|
||||||
if (i_para+1 < elements.paragraphs.size()) ++i_para;
|
if (i_para + 1 < elements.paragraphs.size()) ++i_para;
|
||||||
assert(elements.paragraphs[i_para].start == i + 1);
|
assert(elements.paragraphs[i_para].start == i + 1);
|
||||||
line.margin_left = elements.paragraphs[i_para].margin_left;
|
line.margin_left_after_bullet = elements.clauses[i_clause].margin_left;
|
||||||
line.margin_left_before_bullet = elements.paragraphs[i_para].margin_left;
|
line.margin_left_before_bullet = elements.clauses[i_clause].margin_left;
|
||||||
line.margin_right = elements.paragraphs[i_para].margin_right;
|
|
||||||
line.top += elements.paragraphs[i_para].margin_top;
|
|
||||||
line.alignment = elements.paragraphs[i_para].alignment;
|
line.alignment = elements.paragraphs[i_para].alignment;
|
||||||
}
|
}
|
||||||
|
if (line.break_after == LineBreak::LINE) line.line_height = 0;
|
||||||
line.break_after = LineBreak::NO;
|
line.break_after = LineBreak::NO;
|
||||||
// is the first visible character of the line a bullet point?
|
// is the first visible character of the line a bullet point?
|
||||||
line.bullet = false;
|
line.bullet = false;
|
||||||
@@ -811,7 +840,7 @@ void TextViewer::alignParagraph(size_t start_line, size_t end_line, const vector
|
|||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (size_t li = start_line ; li < end_line ; ++li) {
|
for (size_t li = start_line ; li < end_line ; ++li) {
|
||||||
const Line& l = lines[li];
|
const Line& l = lines[li];
|
||||||
if ((soft && l.break_after == LineBreak::SOFT)
|
if ((soft && (l.break_after == LineBreak::SOFT || l.break_after == LineBreak::WRAP))
|
||||||
|| (hard && l.break_after == LineBreak::HARD)
|
|| (hard && l.break_after == LineBreak::HARD)
|
||||||
|| (line && l.break_after == LineBreak::LINE)) sum += l.line_height;
|
|| (line && l.break_after == LineBreak::LINE)) sum += l.line_height;
|
||||||
}
|
}
|
||||||
@@ -824,7 +853,7 @@ void TextViewer::alignParagraph(size_t start_line, size_t end_line, const vector
|
|||||||
Line& l = lines[li];
|
Line& l = lines[li];
|
||||||
l.top += add;
|
l.top += add;
|
||||||
// adjust next line by..
|
// adjust next line by..
|
||||||
if ((soft && l.break_after == LineBreak::SOFT)
|
if ((soft && (l.break_after == LineBreak::SOFT || l.break_after == LineBreak::WRAP))
|
||||||
|| (hard && l.break_after == LineBreak::HARD)
|
|| (hard && l.break_after == LineBreak::HARD)
|
||||||
|| (line && l.break_after == LineBreak::LINE)) add += to_add * l.line_height;
|
|| (line && l.break_after == LineBreak::LINE)) add += to_add * l.line_height;
|
||||||
}
|
}
|
||||||
@@ -847,12 +876,12 @@ void TextViewer::alignParagraph(size_t start_line, size_t end_line, const vector
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextViewer::Line::alignHorizontal(const vector<CharInfo>& chars, const TextStyle& style, const RealRect& s) {
|
void TextViewer::Line::alignHorizontal(const vector<CharInfo>& chars, const TextStyle& style, const RealRect& s) {
|
||||||
double margin_bullet = bullet ? margin_left_before_bullet : margin_left;
|
double margin_bullet = bullet ? margin_left_before_bullet : margin_left_after_bullet;
|
||||||
double width = this->width() - margin_bullet;
|
double width = this->width() - margin_bullet;
|
||||||
double target_width = s.width - margin_bullet - margin_right;
|
double target_width = s.width - margin_bullet - margin_right;
|
||||||
Alignment alignment = this->alignment.value_or(style.alignment);
|
Alignment alignment = this->alignment.value_or(style.alignment);
|
||||||
bool should_fill = (alignment & ALIGN_IF_OVERFLOW ? width > target_width : true)
|
bool should_fill = (alignment & ALIGN_IF_OVERFLOW ? width > target_width : true)
|
||||||
&& (alignment & ALIGN_IF_SOFTBREAK ? break_after == LineBreak::SOFT || !style.field().multi_line : true);
|
&& (alignment & ALIGN_IF_SOFTBREAK ? break_after == LineBreak::WRAP || break_after == LineBreak::SOFT || !style.field().multi_line : true);
|
||||||
if ((alignment & ALIGN_JUSTIFY_ALL) && should_fill) {
|
if ((alignment & ALIGN_JUSTIFY_ALL) && should_fill) {
|
||||||
// justify text, by characters
|
// justify text, by characters
|
||||||
justifying = true;
|
justifying = true;
|
||||||
|
|||||||
@@ -591,6 +591,7 @@ boost::json::object mse_to_json(const StyleP& style) {
|
|||||||
layoutv.emplace("content_width", wxString::Format(wxT("%.2f"), s->layout->width));
|
layoutv.emplace("content_width", wxString::Format(wxT("%.2f"), s->layout->width));
|
||||||
layoutv.emplace("content_height", wxString::Format(wxT("%.2f"), s->layout->height));
|
layoutv.emplace("content_height", wxString::Format(wxT("%.2f"), s->layout->height));
|
||||||
layoutv.emplace("content_lines", wxString::Format(wxT("%i"), s->layout->lines.size()));
|
layoutv.emplace("content_lines", wxString::Format(wxT("%i"), s->layout->lines.size()));
|
||||||
|
layoutv.emplace("content_clauses", wxString::Format(wxT("%i"), s->layout->clauses.size()));
|
||||||
layoutv.emplace("content_paragraphs", wxString::Format(wxT("%i"), s->layout->paragraphs.size()));
|
layoutv.emplace("content_paragraphs", wxString::Format(wxT("%i"), s->layout->paragraphs.size()));
|
||||||
layoutv.emplace("content_blocks", wxString::Format(wxT("%i"), s->layout->blocks.size()));
|
layoutv.emplace("content_blocks", wxString::Format(wxT("%i"), s->layout->blocks.size()));
|
||||||
boost::json::array separatorsv;
|
boost::json::array separatorsv;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ enum Alignment {
|
|||||||
ALIGN_FILL = ALIGN_STRETCH | ALIGN_JUSTIFY_WORDS | ALIGN_JUSTIFY_ALL,
|
ALIGN_FILL = ALIGN_STRETCH | ALIGN_JUSTIFY_WORDS | ALIGN_JUSTIFY_ALL,
|
||||||
// horizontal fill modifiers
|
// horizontal fill modifiers
|
||||||
ALIGN_IF_OVERFLOW = 0x1000, // only fill if text_width > box_width
|
ALIGN_IF_OVERFLOW = 0x1000, // only fill if text_width > box_width
|
||||||
ALIGN_IF_SOFTBREAK = 0x2000, // only fill before soft line breaks
|
ALIGN_IF_SOFTBREAK = 0x2000, // only fill before soft line breaks and wraps
|
||||||
// vertical
|
// vertical
|
||||||
ALIGN_TOP = 0x100,
|
ALIGN_TOP = 0x100,
|
||||||
ALIGN_MIDDLE = 0x200,
|
ALIGN_MIDDLE = 0x200,
|
||||||
|
|||||||
Reference in New Issue
Block a user