@@ -16,48 +16,6 @@ DECLARE_POINTER_TYPE(FontTextElement);
1616
1717// ----------------------------------------------------------------------------- : TextElements
1818
19- void TextElements::draw (RotatedDC& dc, double scale, const RealRect& rect, const double * xs, DrawWhat what, size_t start, size_t end) const {
20- FOR_EACH_CONST (e, elements) {
21- size_t start_ = max (start, e->start );
22- size_t end_ = min (end, e->end );
23- if (start_ < end_) {
24- e->draw (dc, scale,
25- RealRect (rect.x + xs[start_-start] - xs[0 ], rect.y ,
26- xs[end_-start] - xs[start_-start], rect.height ),
27- xs + start_ - start, what, start_, end_);
28- }
29- if (end <= e->end ) return ; // nothing can be after this
30- }
31- }
32-
33- void TextElements::getCharInfo (RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const {
34- FOR_EACH_CONST (e, elements) {
35- // characters before this element, after the previous
36- while (out.size () < e->start ) {
37- out.push_back (CharInfo ());
38- }
39- e->getCharInfo (dc, scale, out);
40- }
41- while (out.size () < end) {
42- out.push_back (CharInfo ());
43- }
44- }
45-
46- double TextElements::minScale () const {
47- double m = 0.0001 ;
48- FOR_EACH_CONST (e, elements) {
49- m = max (m, e->minScale ());
50- }
51- return m;
52- }
53- double TextElements::scaleStep () const {
54- double m = 1 ;
55- FOR_EACH_CONST (e, elements) {
56- m = min (m, e->scaleStep ());
57- }
58- return m;
59- }
60-
6119// Colors for <atom-param> tags
6220Color param_colors[] =
6321 { Color (0 ,170 ,0 )
@@ -72,33 +30,43 @@ const size_t param_colors_count = sizeof(param_colors) / sizeof(param_colors[0])
7230// Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls
7331struct TextElementsFromString {
7432 // What formatting is enabled?
75- int bold, italic, symbol;
76- int soft, kwpph, param, line, soft_line;
77- int code, code_kw, code_string, param_ref, error ;
78- int param_id;
33+ int bold = 0 , italic = 0 , symbol = 0 ;
34+ int soft = 0 , kwpph = 0 , param = 0 , line = 0 , soft_line = 0 ;
35+ int code = 0 , code_kw = 0 , code_string = 0 , param_ref = 0 ;
36+ int param_id = 0 ;
7937 vector<Color> colors;
8038 vector<double > sizes;
8139 vector<String> fonts;
82- // / put angle brackets around the text?
83- bool bracket;
84-
85- TextElementsFromString ()
86- : bold(0 ), italic(0 ), symbol(0 ), soft(0 ), kwpph(0 ), param(0 ), line(0 ), soft_line(0 )
87- , code(0 ), code_kw(0 ), code_string(0 ), param_ref(0 ), error(0 )
88- , param_id(0 ), bracket(false ) {}
40+ vector<pair<double ,double >> margins;
41+ vector<Alignment> aligns;
42+
43+ const TextStyle& style;
44+ Context& ctx;
45+ vector<TextParagraph>& paragraphs;
8946
47+ TextElementsFromString (TextElements& out, const String& text, const TextStyle& style, Context& ctx)
48+ : style(style), ctx(ctx), paragraphs(out.paragraphs)
49+ {
50+ out.start = 0 ;
51+ out.end = text.size ();
52+ paragraphs.emplace_back ();
53+ paragraphs.back ().start = 0 ;
54+ fromString (out.children , text, 0 , text.size ());
55+ paragraphs.back ().end = text.size ();
56+ }
57+
58+ private:
9059 // read TextElements from a string
91- void fromString (TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
92- te.elements .clear ();
93- end = min (end, text.size ());
60+ void fromString (vector<TextElementP>& elements, const String& text, size_t start, size_t end) {
9461 size_t text_start = start;
9562 // for each character...
9663 for (size_t pos = start ; pos < end ; ) {
9764 Char c = text.GetChar (pos);
9865 if (c == _ (' <' )) {
9966 if (text_start < pos) {
10067 // text element before this tag?
101- addText (te, text, text_start, pos, style, ctx);
68+ addText (elements, text, text_start, pos);
69+ addParagraphs (text, text_start, pos);
10270 }
10371 // a (formatting) tag
10472 size_t tag_start = pos;
@@ -175,18 +143,54 @@ struct TextElementsFromString {
175143 else if (is_substr (text, tag_start, _ (" </atom-param" ))) param -= 1 ;
176144 else if (is_substr (text, tag_start, _ (" <atom" ))) {
177145 // 'atomic' indicator
146+ #if 0
147+ // it would be nice if we could have semi-transparent brushes
148+ Color color = style.font.color; color.a /= 5;
149+ #else
150+ Color fg = style.font .color ;
151+ Color color = fg.r +fg.g +fg.b < 255 *2 ? Color (210 ,210 ,210 ) : Color (60 ,60 ,60 );
152+ #endif
178153 size_t end_tag = min (end, match_close_tag (text, tag_start));
179- intrusive_ptr<AtomTextElement> e ( new AtomTextElement (pos, end_tag) );
180- fromString (e->elements , text, pos, end_tag, style, ctx );
181- te. elements .push_back (e);
154+ intrusive_ptr<AtomTextElement> e = make_intrusive< AtomTextElement> (pos, end_tag, color );
155+ fromString (e->children , text, pos, end_tag);
156+ elements.push_back (e);
182157 pos = skip_tag (text, end_tag);
183158 } else if (is_substr (text, tag_start, _ ( " <error" ))) {
184159 // error indicator
185160 size_t end_tag = min (end, match_close_tag (text, tag_start));
186- intrusive_ptr<ErrorTextElement> e ( new ErrorTextElement (pos, end_tag) );
187- fromString (e->elements , text, pos, end_tag, style, ctx );
188- te. elements .push_back (e);
161+ intrusive_ptr<ErrorTextElement> e = make_intrusive< ErrorTextElement> (pos, end_tag);
162+ fromString (e->children , text, pos, end_tag);
163+ elements.push_back (e);
189164 pos = skip_tag (text, end_tag);
165+ } else if (is_substr (text, tag_start, _ (" </li" ))) {
166+ // end of bullet point, set margin here
167+ paragraphs.back ().margin_end_char = pos;
168+ } else if (is_substr (text, tag_start, _ (" <margin" ))) {
169+ size_t colon = text.find_first_of (_ (" >:" ), tag_start);
170+ if (colon < pos - 1 && text.GetChar (colon) == _ (' :' )) {
171+ size_t colon2 = text.find_first_of (_ (" >:" ), colon+1 );
172+ double margin_left = 0 ., margin_right = 0 .;
173+ text.substr (colon + 1 , colon2 - colon - 2 ).ToDouble (&margin_left);
174+ text.substr (colon2 + 1 , pos - colon2 - 2 ).ToDouble (&margin_right);
175+ if (!margins.empty ()) {
176+ margin_left += margins.back ().first ;
177+ margin_right += margins.back ().second ;
178+ }
179+ margins.emplace_back (margin_left, margin_right);
180+ paragraphs.back ().margin_left = margin_left;
181+ paragraphs.back ().margin_right = margin_right;
182+ }
183+ } else if (is_substr (text, tag_start, _ (" </margin" ))) {
184+ if (!margins.empty ()) margins.pop_back ();
185+ } else if (is_substr (text, tag_start, _ (" <align" ))) {
186+ size_t colon = text.find_first_of (_ (" >:" ), tag_start);
187+ if (colon < pos - 1 && text.GetChar (colon) == _ (' :' )) {
188+ Alignment align = alignment_from_string (text.substr (colon+1 , pos-colon-2 ));
189+ aligns.push_back (align);
190+ paragraphs.back ().alignment = align;
191+ }
192+ } else if (is_substr (text, tag_start, _ (" </align" ))) {
193+ if (!aligns.empty ()) aligns.pop_back ();
190194 } else {
191195 // ignore other tags
192196 }
@@ -199,18 +203,19 @@ struct TextElementsFromString {
199203 }
200204 if (text_start < end) {
201205 // remaining text at the end
202- addText (te, text, text_start, end, style, ctx);
206+ addText (elements, text, text_start, end);
207+ addParagraphs (text, text_start, end);
203208 }
204209 }
205210
206211private:
207212 // / Create a text element for a piece of text, text[start..end)
208- void addText (TextElements& te , const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx ) {
213+ void addText (vector<TextElementP>& elements , const String& text, size_t start, size_t end) {
209214 String content = untag (text.substr (start, end - start));
210215 assert (content.size () == end-start);
211216 // use symbol font?
212217 if (symbol > 0 && style.symbol_font .valid ()) {
213- te. elements .push_back (make_intrusive<SymbolTextElement>(content, start, end, style.symbol_font , &ctx));
218+ elements.push_back (make_intrusive<SymbolTextElement>(content, start, end, style.symbol_font , &ctx));
214219 } else {
215220 // text, possibly mixed with symbols
216221 DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
@@ -221,8 +226,7 @@ struct TextElementsFromString {
221226 content = String (LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
222227 start -= 1 ;
223228 end += 1 ;
224- }
225- if (style.always_symbol && style.symbol_font .valid ()) {
229+ } else if (style.always_symbol && style.symbol_font .valid ()) {
226230 // mixed symbols/text, autodetected by symbol font
227231 size_t text_pos = 0 ;
228232 size_t pos = 0 ;
@@ -233,20 +237,40 @@ struct TextElementsFromString {
233237 if (text_pos < pos) {
234238 // text before it?
235239 if (!font) font = makeFont (style);
236- te. elements .push_back (make_intrusive<FontTextElement>(content.substr (text_pos, pos-text_pos), start+text_pos, start+pos, font, what, line_break));
240+ elements.push_back (make_intrusive<FontTextElement>(content.substr (text_pos, pos-text_pos), start+text_pos, start+pos, font, what, line_break));
237241 }
238- te. elements .push_back (make_intrusive<SymbolTextElement>(content.substr (pos,n), start+pos, start+pos+n, style.symbol_font , &ctx));
242+ elements.push_back (make_intrusive<SymbolTextElement>(content.substr (pos,n), start+pos, start+pos+n, style.symbol_font , &ctx));
239243 text_pos = pos += n;
240244 } else {
241245 ++pos;
242246 }
243247 }
244248 if (text_pos < pos) {
245249 if (!font) font = makeFont (style);
246- te. elements .push_back (make_intrusive<FontTextElement>(content.substr (text_pos), start+text_pos, end, font, what, line_break));
250+ elements.push_back (make_intrusive<FontTextElement>(content.substr (text_pos), start+text_pos, end, font, what, line_break));
247251 }
248252 } else {
249- te.elements .push_back (make_intrusive<FontTextElement>(content, start, end, makeFont (style), what, line_break));
253+ elements.push_back (make_intrusive<FontTextElement>(content, start, end, makeFont (style), what, line_break));
254+ }
255+ }
256+ }
257+ // Find paragraph breaks in text
258+ void addParagraphs (const String& text, size_t start, size_t end) {
259+ if (line == 0 && soft_line > 0 ) return ;
260+ for (size_t i = start; i < end; ++i) {
261+ wxUniChar c = text.GetChar (i);
262+ if (c == ' \n ' ) {
263+ paragraphs.back ().end = i + 1 ;
264+ paragraphs.emplace_back ();
265+ paragraphs.back ().start = i + 1 ;
266+ paragraphs.back ().margin_end_char = i + 1 ;
267+ if (!margins.empty ()) {
268+ paragraphs.back ().margin_left = margins.back ().first ;
269+ paragraphs.back ().margin_right = margins.back ().second ;
270+ }
271+ if (!aligns.empty ()) {
272+ paragraphs.back ().alignment = aligns.back ();
273+ }
250274 }
251275 }
252276 }
@@ -271,18 +295,12 @@ struct TextElementsFromString {
271295 }
272296};
273297
274- void TextElements::fromString ( const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx ) {
275- TextElementsFromString f ;
276- f. fromString (* this , text, start, end, style, ctx );
298+ void TextElements::clear ( ) {
299+ children. clear () ;
300+ paragraphs. clear ( );
277301}
278- /*
279- // ----------------------------------------------------------------------------- : CompoundTextElement
280302
281- void CompoundTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
282- elements.draw(dc, scale, rect, what, start, end);
303+ void TextElements::fromString (const String& text, const TextStyle& style, Context& ctx) {
304+ clear ();
305+ TextElementsFromString f (*this , text, style, ctx);
283306}
284- RealSize CompoundTextElement::charSize(RotatedDC& dc, double scale, size_t index) const {
285- return elements.charSize(rot, scale, index);
286- }
287-
288- */
0 commit comments