@@ -16,48 +16,6 @@ DECLARE_POINTER_TYPE(FontTextElement);
16
16
17
17
// ----------------------------------------------------------------------------- : TextElements
18
18
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
-
61
19
// Colors for <atom-param> tags
62
20
Color param_colors[] =
63
21
{ Color (0 ,170 ,0 )
@@ -72,33 +30,43 @@ const size_t param_colors_count = sizeof(param_colors) / sizeof(param_colors[0])
72
30
// Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls
73
31
struct TextElementsFromString {
74
32
// 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 ;
79
37
vector<Color> colors;
80
38
vector<double > sizes;
81
39
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;
89
46
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:
90
59
// 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) {
94
61
size_t text_start = start;
95
62
// for each character...
96
63
for (size_t pos = start ; pos < end ; ) {
97
64
Char c = text.GetChar (pos);
98
65
if (c == _ (' <' )) {
99
66
if (text_start < pos) {
100
67
// 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);
102
70
}
103
71
// a (formatting) tag
104
72
size_t tag_start = pos;
@@ -175,18 +143,54 @@ struct TextElementsFromString {
175
143
else if (is_substr (text, tag_start, _ (" </atom-param" ))) param -= 1 ;
176
144
else if (is_substr (text, tag_start, _ (" <atom" ))) {
177
145
// '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
178
153
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);
182
157
pos = skip_tag (text, end_tag);
183
158
} else if (is_substr (text, tag_start, _ ( " <error" ))) {
184
159
// error indicator
185
160
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);
189
164
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 ();
190
194
} else {
191
195
// ignore other tags
192
196
}
@@ -199,18 +203,19 @@ struct TextElementsFromString {
199
203
}
200
204
if (text_start < end) {
201
205
// 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);
203
208
}
204
209
}
205
210
206
211
private:
207
212
// / 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) {
209
214
String content = untag (text.substr (start, end - start));
210
215
assert (content.size () == end-start);
211
216
// use symbol font?
212
217
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));
214
219
} else {
215
220
// text, possibly mixed with symbols
216
221
DrawWhat what = soft > 0 ? DRAW_ACTIVE : DRAW_NORMAL;
@@ -221,8 +226,7 @@ struct TextElementsFromString {
221
226
content = String (LEFT_ANGLE_BRACKET) + content + RIGHT_ANGLE_BRACKET;
222
227
start -= 1 ;
223
228
end += 1 ;
224
- }
225
- if (style.always_symbol && style.symbol_font .valid ()) {
229
+ } else if (style.always_symbol && style.symbol_font .valid ()) {
226
230
// mixed symbols/text, autodetected by symbol font
227
231
size_t text_pos = 0 ;
228
232
size_t pos = 0 ;
@@ -233,20 +237,40 @@ struct TextElementsFromString {
233
237
if (text_pos < pos) {
234
238
// text before it?
235
239
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));
237
241
}
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));
239
243
text_pos = pos += n;
240
244
} else {
241
245
++pos;
242
246
}
243
247
}
244
248
if (text_pos < pos) {
245
249
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));
247
251
}
248
252
} 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
+ }
250
274
}
251
275
}
252
276
}
@@ -271,18 +295,12 @@ struct TextElementsFromString {
271
295
}
272
296
};
273
297
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 ( );
277
301
}
278
- /*
279
- // ----------------------------------------------------------------------------- : CompoundTextElement
280
302
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);
283
306
}
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