source: branches/2.19_branch/Components/RichTextDisplayUnit.pas@ 324

Last change on this file since 324 was 15, checked in by RBRi, 19 years ago

+ components stuff

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1Unit RichTextDisplayUnit;
2
3Interface
4
5uses
6 Classes,
7 CanvasFontManager,
8 RichTextStyleUnit, RichTextLayoutUnit;
9
10// Selection start and end should both be nil if no selection is to be applied
11Procedure DrawRichTextLayout( const FontManager: TCanvasFontManager;
12 const Layout: TRichTextLayout;
13 const SelectionStart: PChar;
14 const SelectionEnd: PChar;
15 const StartLine: longint;
16 const EndLine: longint;
17 const StartPoint: TPoint );
18
19// Print as much of the given layout as will fit on the page,
20// starting at StartY and StartLine
21// EndY is set to the final Y output position used + 1.
22// EndLine is set to the last line printed + 1
23Procedure PrintRichTextLayout( const FontManager: TCanvasFontManager;
24 const Layout: TRichTextLayout;
25 const StartLine: longint;
26 var EndLine: longint;
27 const StartY: longint;
28 var EndY: longint );
29
30Implementation
31
32uses
33 SysUtils,
34 Forms, Graphics,
35 ACLString, ACLUtility,
36 RichTextDocumentUnit;
37
38// For the given point in the text, update selected if the point
39// is at start or end of selection
40// Returns true if changed
41function SelectionChange( P: PChar;
42 SelectionStart: PChar;
43 SelectionEnd: PChar;
44 var NextSelected: boolean ): boolean;
45begin
46 Result := false;
47 if P = SelectionStart then
48 begin
49 Result := true;
50 if SelectionStart < SelectionEnd then
51 // reached start of selection
52 NextSelected := true
53 else
54 // reached end
55 NextSelected := false;
56 end
57 else if P = SelectionEnd then
58 begin
59 Result := true;
60 if SelectionStart < SelectionEnd then
61 // reached end of selection
62 NextSelected := false
63 else
64 // reached start
65 NextSelected := true;
66 end;
67end;
68
69function InvertRGB( Arg: TColor ): TColor;
70begin
71 Result := SysColorToRGB( Arg ); // in case it's a system color e.g. button face
72 Result := Result xor $ffffff; // now invert the RGB components
73end;
74
75// Draw a string at the given location with given color/selected state
76Procedure DrawRichTextString( FontManager: TCanvasFontManager;
77 Var X: longint;
78 Y: longint;
79 S: PChar;
80 Len: longint;
81 Selected: Boolean;
82 PenColor: TColor;
83 BackColor: TColor );
84var
85 Point: TPoint;
86begin
87 if Len = 0 then
88 exit;
89
90 Point.X := X;
91 Point.Y := Y;
92{ if FDebug then
93 begin
94 // generate a random dark color
95 Canvas.Brush.Color := random( 191 ) * 65536 //r
96 + random( 191 ) * 256 //g
97 + random( 191 ); //b
98 Canvas.Pen.Color := clWhite;
99 end
100 else}
101
102 if Selected then
103 begin
104 FontManager.Canvas.Brush.Color := InvertRGB( BackColor );
105 FontManager.Canvas.Pen.Color := InvertRGB( PenColor );
106 end
107 else
108 begin
109 FontManager.Canvas.Brush.Color := BackColor;
110 FontManager.Canvas.Pen.Color := PenColor;
111 end;
112 FontManager.DrawString( Point, Len, S );
113 X := Point.X;
114end;
115
116var
117 // global, so that we don't reallocate every drawline
118 StringToDraw: TAString = nil;
119
120// Draw the specified line at the specified
121// (physical) location
122Procedure DrawRichTextLine( FontManager: TCanvasFontManager;
123 Layout: TRichTextLayout;
124 SelectionStart: PChar;
125 SelectionEnd: PChar;
126
127 Line: TLayoutLine;
128 Start: TPoint );
129var
130 X, Y: longint;
131 Element: TTextElement;
132 StartedDrawing: boolean;
133 Style: TTextDrawStyle;
134 P: PChar;
135 NextP: PChar;
136 EndP: PChar;
137
138 BitmapIndex: longint;
139 Bitmap: TBitmap;
140
141 BitmapRect: TRect;
142
143 TextBlockStart: PChar;
144
145 Selected: boolean;
146 NextSelected: boolean;
147
148 NewMarginX: longint;
149
150 procedure DrawTextBlock;
151 var
152 PhysX: longint;
153 begin
154 PhysX := X div FontWidthPrecisionFactor;
155
156 DrawRichTextString( FontManager,
157 PhysX,
158 Y,
159 StringToDraw.AsPChar,
160 StringToDraw.Length,
161 Selected,
162 Style.Color,
163 Style.BackgroundColor );
164 X := PhysX * FontWidthPrecisionFactor;
165 StringToDraw.AssignString( '' );
166 end;
167
168
169begin
170 P := Line.Text;
171 EndP := Line.Text + Line.Length;
172
173 if P = EndP then
174 begin
175 // Empty line
176 exit;
177 end;
178
179 Selected := false;
180 if SelectionStart <= Line.Text then
181 // selection start is above.
182 Selected := true;
183 if SelectionEnd <= Line.Text then
184 // selection end is above.
185 Selected := not Selected;
186
187 if StringToDraw = nil then
188 StringToDraw := TAString.Create;
189
190 Style := Line.Style;
191 FontManager.SetFont( Style.Font );
192 StartedDrawing := false;
193
194 TextBlockStart := P;
195
196 Y := Start.Y + Line.MaxDescender;
197
198 while P < EndP do
199 begin
200 Element := ExtractNextTextElement( P, NextP );
201
202 if SelectionChange( P,
203 SelectionStart,
204 SelectionEnd,
205 NextSelected ) then
206 begin
207 DrawTextBlock;
208 TextBlockStart := P;
209 Selected := NextSelected;
210 end;
211
212 case Element.ElementType of
213 teWordBreak,
214 teText,
215 teImage:
216 begin
217 if not StartedDrawing then
218 begin
219 // we haven't yet started drawing:
220 // so work out alignment
221 X := Start.X * FontWidthPrecisionFactor
222 + Layout.GetStartX( Style, Line );
223 StartedDrawing := true;
224 end;
225
226 // Now do the drawing
227 if Element.ElementType = teImage then
228 begin
229 DrawTextBlock;
230 TextBlockStart := NextP;
231
232 try
233 BitmapIndex := StrToInt( Element.Tag.Arguments );
234 except
235 BitmapIndex := -1;
236 end;
237 if Layout.IsValidBitmapIndex( BitmapIndex ) then
238 begin
239 Bitmap := Layout.Images.GetBitmapReference( BitmapIndex );
240
241 BitmapRect.Left := X div FontWidthPrecisionFactor;
242 BitmapRect.Bottom := Start.Y;
243 BitmapRect.Right := BitmapRect.Left
244 + Bitmap.Width
245 * Layout.HorizontalImageScale;
246 BitmapRect.Top := BitmapRect.Bottom
247 + Bitmap.Height
248 * Layout.VerticalImageScale;;
249
250 Bitmap.Draw( FontManager.Canvas,
251 BitmapRect );
252
253
254 inc( X,
255 trunc( Bitmap.Width
256 * FontWidthPrecisionFactor
257 * Layout.HorizontalImageScale ) );
258 end;
259 end
260 else
261 begin
262 // character (or word break)
263 // build up the successive characters...
264 StringToDraw.AddString( Element.Character );
265 end;
266 end;
267
268 teStyle:
269 begin
270 DrawTextBlock;
271 TextBlockStart := NextP;
272
273 if ( Element.Tag.TagType = ttItalicOff )
274 and ( faItalic in Style.Font.Attributes )
275 and ( not FontManager.IsFixed )
276 then
277 // end of italic; add a space
278 inc( X, FontManager.CharWidth( ' ' ) );
279
280 Layout.PerformStyleTag( Element.Tag,
281 Style,
282 X );
283 NewMarginX := ( Start.X + Style.LeftMargin ) * FontWidthPrecisionFactor;
284 if NewMarginX > X then
285 begin
286 //skip across...
287 X := NewMarginX;
288 end;
289 end;
290 end;
291 P := NextP;
292 end;
293
294 DrawTextBlock;
295end;
296
297Procedure DrawRichTextLayout( const FontManager: TCanvasFontManager;
298 const Layout: TRichTextLayout;
299 const SelectionStart: PChar;
300 const SelectionEnd: PChar;
301 const StartLine: longint;
302 const EndLine: longint;
303 const StartPoint: TPoint );
304Var
305 Line: TLayoutLine;
306 LineIndex: longint;
307
308 Y: longint;
309
310 BottomOfLine: longint;
311begin
312 assert( StartLine >= 0 );
313 assert( StartLine <= Layout.FNumLines );
314 assert( EndLine >= 0 );
315 assert( EndLine <= Layout.FNumLines );
316 assert( StartLine <= EndLine );
317
318 if Layout.FNumLines = 0 then
319 // no text to draw
320 exit;
321
322 Y := StartPoint.Y
323 - Layout.FRichTextSettings.Margins.Top;
324
325 LineIndex := 0;
326
327 repeat
328 Line := Layout.FLines[ LineIndex ];
329 BottomOfLine := Y - Line.Height + 1; // bottom pixel row is top - height + 1
330
331 if // the line is in the range to be drawn
332 ( LineIndex >= StartLine )
333 and ( LineIndex <= EndLine )
334
335 // and the line is within the cliprect
336 and ( BottomOfLine <= FontManager.Canvas.ClipRect.Top )
337 and ( Y > FontManager.Canvas.ClipRect.Bottom ) then
338 begin
339 // draw it. First decided whether selection is started or not.
340 DrawRichTextLine( FontManager,
341 Layout,
342 SelectionStart,
343 SelectionEnd,
344 Line,
345 Point( StartPoint.X,
346 BottomOfLine ) );
347
348 end;
349 dec( Y, Line.Height );
350
351 if Y < 0 then
352 // past bottom of output canvas
353 break;
354
355 inc( LineIndex );
356
357 if LineIndex >= Layout.FNumLines then
358 // end of text
359 break;
360
361 until false;
362
363End;
364
365Procedure PrintRichTextLayout( const FontManager: TCanvasFontManager;
366 const Layout: TRichTextLayout;
367 const StartLine: longint;
368 var EndLine: longint;
369 const StartY: longint;
370 var EndY: longint );
371Var
372 Selected: boolean;
373 Line: TLayoutLine;
374 LineIndex: longint;
375
376 Y: longint;
377
378 BottomOfLine: longint;
379
380 LinesPrinted: longint;
381begin
382 assert( StartLine >= 0 );
383 assert( StartLine <= Layout.FNumLines );
384
385 if Layout.FNumLines = 0 then
386 // no text to draw
387 exit;
388
389 Y := StartY;
390// - Layout.FRichTextSettings.Margins.Top;
391
392 Selected := false; // it's not going to change.
393
394 LinesPrinted := 0;
395
396 LineIndex := StartLine;
397
398 repeat
399 Line := Layout.FLines[ LineIndex ];
400 BottomOfLine := Y - Line.Height + 1; // bottom pixel row is top - height + 1
401
402 if BottomOfLine < Layout.FRichTextSettings.Margins.Bottom then
403 // past bottom of page (less margin)
404 if LinesPrinted > 0 then
405 // stop, as long as we've printed at least 1 line
406 break;
407
408 // draw it
409 DrawRichTextLine( FontManager,
410 Layout,
411 nil,
412 nil,
413 Line,
414 Point( 0,
415 BottomOfLine ) );
416
417 dec( Y, Line.Height );
418
419 inc( LinesPrinted );
420
421 inc( LineIndex );
422
423 if LineIndex >= Layout.FNumLines then
424 // end of text
425 break;
426
427 until false;
428
429 EndY := Y;
430 EndLine := LineIndex;
431End;
432
433Initialization
434End.
Note: See TracBrowser for help on using the repository browser.