1 { Current issues:
2 - Radial gradient not rendered correctly (position, colors), saving to svg ok.
3 - Save polygon to svg empty
4 - Nonzero/even-odd winding rule not working
5 }
6
7 unit vtmain;
8
9 {$mode objfpc}{$H+}
10
11 interface
12
13 uses
14 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
15 ExtCtrls, ComCtrls, EditBtn, fpimage, fpvectorial, Types;
16
17 type
18
19 TRenderEvent = procedure(APage: TvVectorialPage;
20 AIntParam: Integer = MaxInt) of object;
21
22 TRenderParams = class
23 RefFile: String;
24 IntParam: Integer;
25 OnRender: TRenderEvent;
26 constructor Create(ARenderEvent: TRenderEvent; ARefFilename: String;
27 AIntParam: Integer = MaxInt);
28 end;
29
30 TRenderCoords = (rcBottomLeftCoords, rcTopLeftCoords);
31
32 { TMainForm }
33
34 TMainForm = class(TForm)
35 BtnSaveAsRef: TButton;
36 BtnSaveToFiles: TButton;
37 BtnViewBottomLeft: TButton;
38 BtnViewTopLeft: TButton;
39 CbFileFormat: TComboBox;
40 gbWRBottomLeft: TGroupBox;
41 gbRenderTest: TGroupBox;
42 gbBottomLeft: TGroupBox;
43 gbWRTopLeft: TGroupBox;
44 gbTopLeft: TGroupBox;
45 gbReferenceImageTest: TGroupBox;
46 GroupBox1: TGroupBox;
47 gbReadWriteTest: TGroupBox;
48 GbTree: TGroupBox;
49 Label1: TLabel;
50 Label14: TLabel;
51 LblBothImagesMustMatch1: TLabel;
52 RefImage: TImage;
53 Label10: TLabel;
54 Label11: TLabel;
55 Label13: TLabel;
56 Label6: TLabel;
57 Label7: TLabel;
58 Label8: TLabel;
59 LblBothImagesMustMatch: TLabel;
60 LblRefImgMustMatch: TLabel;
61 LblReadWriteInstructions: TLabel;
62 BottomLeftPaintbox: TPaintBox;
63 ScrollBox1: TScrollBox;
64 WRTopLeftPaintbox: TPaintBox;
65 TopLeftPaintbox: TPaintBox;
66 WRBottomLeftPaintbox: TPaintBox;
67 AllTestsPanel: TPanel;
68 Tree: TTreeView;
69 procedure BtnSaveToFilesClick(Sender: TObject);
70 procedure BtnSaveAsRefClick(Sender: TObject);
71 procedure BtnViewImageClick(Sender: TObject);
72 procedure CbFileFormatChange(Sender: TObject);
73 procedure FormCreate(Sender: TObject);
74 procedure FormDestroy(Sender: TObject);
75 procedure PaintBoxPaint(Sender: TObject);
76 procedure TreeCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
77 State: TCustomDrawState; var DefaultDraw: Boolean);
78 procedure TreeSelectionChanged(Sender: TObject);
79
80 private
81 { private declarations }
82 FDoc: array[TRenderCoords] of TvVectorialDocument;
83 FDocFromWMF: array[TRenderCoords] of TvVectorialDocument;
84 FDocFromSVG: array[TRenderCoords] of TvVectorialDocument;
GetFileFormatnull85 function GetFileFormat: TvVectorialFormat;
GetFileFormatExtnull86 function GetFileFormatExt: String;
87 procedure Populate;
88 procedure PrepareDoc(var ADoc: TvVectorialDocument; var APage: TvVectorialPage;
89 AUseTopLeftCoords: boolean);
90 procedure ReadIni;
91 procedure ShowFileImage(AFilename: String; AUseTopLeftCoords: Boolean;
92 APaintbox: TPaintbox);
93 procedure ShowRefImageTest;
94 procedure ShowRenderTestImages;
95 procedure ShowWriteReadTestImages;
96 procedure UpdateCmdStates;
97 procedure WriteIni;
98
99 // Simple shapes, solid fills and gradients
100 procedure Render_Shape(APage: TvVectorialPage; AIntParam: Integer);
101
102 // Complex shapes
103 procedure Render_Path_Hole_SolidFill(APage: TvVectorialPage;
104 AIntParam: Integer);
105 procedure Render_Path_Hole_GradientFill(APage: TvVectorialPage;
106 AIntParam: Integer);
107 procedure Render_SelfIntersectingPoly_SolidFill_EvenOdd(APage: TvVectorialPage;
108 AIntParam: Integer);
109 procedure Render_SelfIntersectingPoly_GradientFill_EvenOdd(APage: TvVectorialPage;
110 AIntParam: Integer);
111 procedure Render_SelfIntersectingPoly_SolidFill_NonZeroWinding(APage: TvVectorialPage;
112 AIntParam: Integer);
113 procedure Render_SelfIntersectingPoly_GradientFill_NonZeroWinding(APage: TvVectorialPage;
114 AIntParam: Integer);
115
116 // Arcs
117 procedure Render_Arc(APage: TvVectorialPage; AIntParam: Integer);
118
119 // Bezier
120 procedure Render_Bezier(Apage: TvVectorialPage; AIntParam: Integer);
121
122 // Text
123 procedure Render_Text(APage: TvVectorialpage; AIntParam: Integer);
124 procedure Render_Text_Fonts(APage: TvVectorialPage; AIntParam: Integer);
125 procedure Render_Text_Colors(APage: TvVectorialPage; AIntParam: Integer);
126 public
127 { public declarations }
128 end;
129
130 var
131 MainForm: TMainForm;
132
133
134 implementation
135
136 {$R *.lfm}
137
138 uses
139 Math, FPCanvas, IniFiles, LazFileUtils, LCLIntf,
140 fpvutils, vtprimitives;
141
142 const
143 IMG_FOLDER = 'images' + PathDelim;
144 NOT_SAVED = '(not saved)';
145
146
147 { TRenderParams }
148
149 constructor TRenderParams.Create(ARenderEvent: TRenderEvent;
150 ARefFilename: String; AIntParam: Integer = MaxInt);
151 begin
152 OnRender := ARenderEvent;
153 RefFile := ARefFileName;
154 IntParam := AIntParam;
155 end;
156
157
158 { TMainForm }
159
160 procedure TMainForm.BtnSaveAsRefClick(Sender: TObject);
161 var
162 bmp: TBitmap;
163 png: TPortableNetworkGraphic;
164 fn: String;
165 renderParams: TRenderParams;
166 page: TvVectorialPage;
167 begin
168 renderParams := TRenderParams(Tree.Selected.Data);
169 if RenderParams = nil then
170 exit;
171 if FDoc[rcBottomLeftCoords] = nil then
172 exit;
173
174 page := FDoc[rcBottomLeftCoords].GetPageAsVectorial(0);
175
176 bmp := TBitmap.Create;
177 try
178 bmp.SetSize(BottomLeftPaintbox.Width, BottomLeftPaintbox.Height);
179 bmp.Canvas.GetUpdatedHandle([csHandleValid]); // create the Handle needed by next line
180 page.DrawBackground(bmp.Canvas);
181 // bmp canvas has origin at top/left
182 page.Render(bmp.Canvas, 0, bmp.Height, 1.0, -1.0);
183 png := TPortableNetworkGraphic.Create;
184 try
185 png.Assign(bmp);
186 // renderParams := TRenderParams(Tree.Selected.Data);
187 ForceDirectory(IMG_FOLDER);
188 fn := IncludeTrailingPathDelimiter(IMG_FOLDER) + renderParams.RefFile;
189 png.SaveToFile(fn);
190 finally
191 png.Free;
192 end;
193 RefImage.Picture.Assign(bmp);
194 RefImage.Hint := fn;
195 finally
196 bmp.Free;
197 end;
198 end;
199
200 procedure TMainForm.BtnSaveToFilesClick(Sender: TObject);
201 var
202 fn: String;
203 renderParams: TRenderParams;
204 folder: String;
205 fmt: TvVectorialFormat;
206 ext: String;
207 begin
208 renderParams := TRenderParams(Tree.Selected.Data);
209 if RenderParams = nil then
210 exit;
211
212 fmt := GetFileFormat;
213 ext := GetFileFormatExt;
214 folder := IMG_FOLDER + ext + PathDelim;
215 ForceDirectory(folder);
216
217 if FDoc[rcBottomLeftCoords] <> nil then begin
218 fn := folder + 'bl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
219 FDoc[rcBottomLeftCoords].WriteToFile(fn, fmt);
220 ShowFileImage(fn, false, WRBottomLeftPaintbox);
221 end;
222
223 if FDoc[rcTopLeftCoords] <> nil then begin
224 fn := folder + 'tl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
225 FDoc[rcTopLeftCoords].WriteToFile(fn, fmt);
226 ShowFileImage(fn, true, WRTopLeftPaintbox);
227 end;
228
229 UpdateCmdStates;
230 end;
231
232 procedure TMainForm.BtnViewImageClick(Sender: TObject);
233 var
234 fn: String;
235 ext: String;
236 folder: String;
237 renderParams: TRenderParams;
238 begin
239 BtnSaveToFilesClick(nil);
240
241 renderParams := TRenderParams(Tree.Selected.Data);
242 if renderParams = nil then
243 exit;
244
245 ext := GetFileFormatExt;
246 folder := IMG_FOLDER + ext + PathDelim;
247
248 if Sender = BtnViewBottomLeft then
249 fn := folder + 'bl_' + ChangeFileExt(renderParams.RefFile, '.' + ext)
250 else if Sender = BtnViewTopLeft then
251 fn := folder + 'tl_' + ChangeFileExt(renderParams.RefFile, '.' + ext)
252 else
253 raise Exception.Create('BtnViewImageClick: this sender is not supported.');
254
255 if FileExists(fn) then
256 OpenDocument(fn);
257 end;
258
259 procedure TMainForm.CbFileFormatChange(Sender: TObject);
260 begin
261 ShowWriteReadTestImages;
262 UpdateCmdStates;
263 end;
264
265 procedure TMainForm.PrepareDoc(var ADoc: TvVectorialDocument;
266 var APage: TvVectorialPage; AUseTopLeftCoords: boolean);
267 var
268 r: TvRectangle;
269 begin
270 FreeAndNil(ADoc);
271 ADoc := TvVectorialDocument.Create;
272 APage := ADoc.AddPage;
273 APage.BackgroundColor := colWhite;
274 APage.Width := PAGE_SIZE;
275 APage.Height := PAGE_SIZE;
276 ADoc.Width := PAGE_SIZE;
277 ADoc.Height := PAGE_SIZE;
278 APage.UseTopLeftCoordinates := AUseTopLeftCoords;
279
280 // Add a frame around the page
281 r := TvRectangle.Create(APage);
282 r.X := 0;
283 if AUseTopLeftCoords then
284 r.Y := 0
285 else
286 r.Y := APage.Height;
287 r.CX := APage.Width - 1;
288 r.CY := APage.Height - 1;
289 r.Brush := CreateSimpleBrush(bsClear);
290 r.Pen := CreatePen(psSolid, 1, colSilver);
291 APage.AddEntity(r);
292 end;
293
294 procedure TMainForm.FormCreate(Sender: TObject);
295 begin
296 RefImage.Hint := NOT_SAVED;
297 WRBottomLeftPaintbox.Hint := NOT_SAVED;
298 WRTopLeftPaintbox.Hint := NOT_SAVED;
299
300 ReadIni;
301 Populate;
302 TreeSelectionChanged(nil);
303 end;
304
305 procedure TMainForm.FormDestroy(Sender: TObject);
306 var
307 parentnode, node: TTreeNode;
308 rc: TRenderCoords;
309 begin
310 parentnode := Tree.Items.GetFirstNode;
311 while parentnode <> nil do begin
312 node := parentnode.GetFirstChild;
313 while node <> nil do begin
314 TObject(node.Data).Free;
315 node := node.GetNextSibling;
316 end;
317 parentnode := parentnode.GetNextSibling;
318 end;
319
320 for rc in TRenderCoords do begin
321 FreeAndNil(FDoc[rc]);
322 FreeAndNil(FDocFromSVG[rc]);
323 FreeAndNil(FDocFromWMF[rc]);
324 end;
325
326 WriteIni;
327 end;
328
TMainForm.GetFileFormatnull329 function TMainForm.GetFileFormat: TvVectorialFormat;
330 begin
331 case CbFileFormat.ItemIndex of
332 0: Result := vfSVG;
333 1: Result := vfWindowsMetafileWMF;
334 else raise Exception.Create('Format not supported');
335 end;
336 end;
337
TMainForm.GetFileFormatExtnull338 function TMainForm.GetFileFormatExt: String;
339 begin
340 case CbFileFormat.ItemIndex of
341 0: Result := 'svg';
342 1: Result := 'wmf';
343 else raise Exception.Create('Format not supported');
344 end;
345 end;
346
347 procedure TMainForm.PaintBoxPaint(Sender: TObject);
348 var
349 doc: TvVectorialDocument;
350 page: TvVectorialPage;
351 w, h: Integer;
352 fmt: TvVectorialFormat;
353 rc: TRenderCoords;
354 begin
355 fmt := GetFileFormat;
356
357 if (Sender = BottomLeftPaintbox) or (Sender = WRBottomLeftPaintbox) then
358 rc := rcBottomLeftCoords
359 else
360 if (Sender = TopLeftPaintbox) or (Sender = WRTopLeftPaintbox) then
361 rc := rcTopLeftCoords
362 else
363 raise Exception.Create('This sender is not supported here.');
364
365 doc := nil;
366 if (Sender = BottomLeftPaintbox) or (Sender = TopLeftPaintbox) then
367 doc := FDoc[rc]
368 else
369 if (Sender = WRBottomLeftPaintbox) or (Sender = WRTopLeftPaintbox) then
370 case GetFileFormat of
371 vfSVG:
372 doc := FDocFromSVG[rc];
373 vfWindowsMetafileWMF:
374 doc := FDocFromWMF[rc];
375 else
376 raise Exception.Create('File format not supported.');
377 end;
378
379 w := TPaintbox(Sender).Width;
380 h := TPaintbox(Sender).Height;
381
382 if doc = nil then begin
383 TPaintbox(Sender).Canvas.Brush.Color := clDefault;
384 TPaintbox(Sender).Canvas.Brush.Style := bsSolid;
385 TPaintbox(Sender).Canvas.FillRect(0, 0, w, h);
386 exit;
387 end;
388
389 page := doc.GetPageAsVectorial(0);
390 page.DrawBackground(TPaintbox(Sender).Canvas);
391 if page.UseTopLeftCoordinates then
392 page.Render(TPaintbox(Sender).Canvas, 0, 0, 1.0, 1.0)
393 else
394 page.Render(TPaintbox(Sender).Canvas, 0, h, 1.0, -1.0);
395 end;
396
397 procedure TMainForm.Populate;
398 var
399 node, node0, node1: TTreeNode;
400 begin
401 Tree.Items.Clear;
402
403 { --------------------------------------------------}
404 node := Tree.Items.AddChild(nil, 'Simple shapes');
405 { --------------------------------------------------}
406 Tree.Items.AddChildObject(node, 'Circle (solid) - move up',
407 TRenderParams.Create(@Render_Shape, 'circle_solid.png', $0100));
408 Tree.Items.AddChildObject(node, 'Ellipse (solid) - moved up',
409 TRenderParams.Create(@Render_Shape, 'ellipse_solid.png', $0200));
410 Tree.Items.AddChildObject(node, 'Rectangle(solid) - moved up',
411 TRenderParams.Create(@Render_Shape, 'rect_solid.png', $0300));
412 Tree.Items.AddChildObject(node, 'Rounded rectangle (solid) - moved up',
413 TRenderParams.Create(@Render_Shape, 'rounded_rect_solid.png', $0400));
414 Tree.Items.AddChildObject(node, 'Polygon (solid) - moved up',
415 TRenderParams.Create(@Render_Shape, 'polygon_solid.png', $0500));
416
417 { --------------------------------------------------}
418 node := Tree.Items.AddChild(nil, 'Complex shapes');
419 { --------------------------------------------------}
420 Tree.Items.AddChildObject(node, 'Path with hole (solid fill)',
421 TRenderParams.Create(@Render_Path_Hole_SolidFill, 'path_hole_solid.png'));
422 Tree.Items.AddChildObject(node, 'Path with hole (gradient fill)',
423 TRenderParams.Create(@Render_Path_Hole_GradientFill, 'path_hole_gradient.png'));
424 Tree.Items.AddChildObject(node, 'Self-intersecting polygon (solid fill, even-odd rule) - tip at bottom',
425 TRenderParams.Create(@Render_SelfIntersectingPoly_SolidFill_EvenOdd, 'selfintersecting_poly_solid_eo.png'));
426 Tree.Items.AddChildObject(node, 'Self-intersecting polygon (gradient fill, even-odd rule) - tip at bottom',
427 TRenderParams.Create(@Render_SelfIntersectingPoly_GradientFill_EvenOdd, 'selfintersecting_poly_gradient_eo.png'));
428 Tree.Items.AddChildObject(node, 'Self-intersecting polygon (solid fill, nonzero winding rule) - tip at bottom',
429 TRenderParams.Create(@Render_SelfIntersectingPoly_SolidFill_NonZeroWinding, 'selfintersecting_poly_solid_nzw.png'));
430 Tree.Items.AddChildObject(node, 'Self-intersecting polygon (gradient fill, nonzero winding rule) - tip at bottom',
431 TRenderParams.Create(@Render_SelfIntersectingPoly_GradientFill_NonZeroWinding, 'selfintersecting_poly_gradient_nzw.png'));
432
433 { -----------------------------------------}
434 node0 := Tree.Items.AddChild(nil, 'Arcs');
435 { -----------------------------------------}
436 node1 := Tree.Items.AddChild(node0, 'circular');
437 node := Tree.Items.AddChild(node1, 'clockwise from point 1 to point 2');
438 Tree.Items.AddChildObject(node, 'Quadrant I',
439 TRenderParams.Create(@Render_Arc, 'arc_cw_q1.png', $0200));
440 Tree.Items.AddChildObject(node, 'Quadrant I+II',
441 TRenderParams.Create(@Render_Arc, 'arc_cw_q12.png', $0201));
442 Tree.Items.AddChildObject(node, 'Quadrant II',
443 TRenderParams.Create(@Render_Arc, 'arc_cw_q2.png', $0202));
444 Tree.Items.AddChildObject(node, 'Quadrant II+III',
445 TRenderParams.Create(@Render_Arc, 'arc_cw_q23.png', $0203));
446 Tree.Items.AddChildObject(node, 'Quadrant III',
447 TRenderParams.Create(@Render_Arc, 'arc_cw_q3.png', $0204));
448 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
449 TRenderParams.Create(@Render_Arc, 'arc_cw_q34.png', $0205));
450 Tree.Items.AddChildObject(node, 'Quadrant IV',
451 TRenderParams.Create(@Render_Arc, 'arc_cw_q4.png', $0206));
452 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
453 TRenderParams.Create(@Render_Arc, 'arc_cw_q41.png', $0207));
454
455 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
456 TRenderParams.Create(@Render_Arc, 'arc_cw_q1r.png', $0300));
457 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
458 TRenderParams.Create(@Render_Arc, 'arc_cw_q12r.png', $0301));
459 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
460 TRenderParams.Create(@Render_Arc, 'arc_cw_q2r.png', $0302));
461 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
462 TRenderParams.Create(@Render_Arc, 'arc_cw_q23r.png', $0303));
463 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
464 TRenderParams.Create(@Render_Arc, 'arc_cw_q3r.png', $0304));
465 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
466 TRenderParams.Create(@Render_Arc, 'arc_cw_q34r.png', $0305));
467 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
468 TRenderParams.Create(@Render_Arc, 'arc_cw_q4r.png', $0306));
469 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
470 TRenderParams.Create(@Render_Arc, 'arc_cw_q41r.png', $0307));
471
472 node := Tree.Items.AddChild(node1, 'counter-clockwise from point 1 to point 2');
473 Tree.Items.AddChildObject(node, 'Quadrant I',
474 TRenderParams.Create(@Render_Arc, 'arc_ccw_q1.png', $0000));
475 Tree.Items.AddChildObject(node, 'Quadrant I+II',
476 TRenderParams.Create(@Render_Arc, 'arc_ccw_q12.png', $0001));
477 Tree.Items.AddChildObject(node, 'Quadrant II',
478 TRenderParams.Create(@Render_Arc, 'arc_ccw_q2.png', $0002));
479 Tree.Items.AddChildObject(node, 'Quadrant II+III',
480 TRenderParams.Create(@Render_Arc, 'arc_ccw_q23.png', $0003));
481 Tree.Items.AddChildObject(node, 'Quadrant III',
482 TRenderParams.Create(@Render_Arc, 'arc_ccw_q3.png', $0004));
483 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
484 TRenderParams.Create(@Render_Arc, 'arc_ccw_q34.png', $0005));
485 Tree.Items.AddChildObject(node, 'Quadrant IV',
486 TRenderParams.Create(@Render_Arc, 'arc_ccw_q4.png', $0006));
487 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
488 TRenderParams.Create(@Render_Arc, 'arc_ccw_q41.png', $0007));
489
490 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
491 TRenderParams.Create(@Render_Arc, 'arc_ccw_q1r.png', $0100));
492 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
493 TRenderParams.Create(@Render_Arc, 'arc_ccw_q12r.png', $0101));
494 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
495 TRenderParams.Create(@Render_Arc, 'arc_ccw_q2r.png', $0102));
496 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
497 TRenderParams.Create(@Render_Arc, 'arc_ccw_q23r.png', $0103));
498 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
499 TRenderParams.Create(@Render_Arc, 'arc_ccw_q3r.png', $0104));
500 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
501 TRenderParams.Create(@Render_Arc, 'arc_ccw_q34r.png', $0105));
502 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
503 TRenderParams.Create(@Render_Arc, 'arc_ccw_q4r.png', $0106));
504 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
505 TRenderParams.Create(@Render_Arc, 'arc_ccw_q41r.png', $0107));
506
507 node1 := Tree.Items.AddChild(node0, 'elliptical');
508 node := Tree.Items.AddChild(node1, 'clockwise from point 1 to point 2');
509 Tree.Items.AddChildObject(node, 'Quadrant I',
510 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q1.png', $1200));
511 Tree.Items.AddChildObject(node, 'Quadrant I+II',
512 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q12.png', $1201));
513 Tree.Items.AddChildObject(node, 'Quadrant II',
514 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q2.png', $1202));
515 Tree.Items.AddChildObject(node, 'Quadrant II+III',
516 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q23.png', $1203));
517 Tree.Items.AddChildObject(node, 'Quadrant III',
518 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q3.png', $1204));
519 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
520 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q34.png', $1205));
521 Tree.Items.AddChildObject(node, 'Quadrant IV',
522 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q4.png', $1206));
523 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
524 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q41.png', $1207));
525
526 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
527 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q1r.png', $1300));
528 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
529 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q12r.png', $1301));
530 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
531 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q2r.png', $1302));
532 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
533 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q23r.png', $1303));
534 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
535 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q3r.png', $1304));
536 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
537 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q34r.png', $1305));
538 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
539 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q4r.png', $1306));
540 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
541 TRenderParams.Create(@Render_Arc, 'arc_ell_cw_q41r.png', $1307));
542
543 node := Tree.Items.AddChild(node1, 'counter-clockwise from point 1 to point 2');
544 Tree.Items.AddChildObject(node, 'Quadrant I',
545 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q1.png', $1000));
546 Tree.Items.AddChildObject(node, 'Quadrant I+II',
547 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q12.png', $1001));
548 Tree.Items.AddChildObject(node, 'Quadrant II',
549 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q2.png', $1002));
550 Tree.Items.AddChildObject(node, 'Quadrant II+III',
551 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q23.png', $1003));
552 Tree.Items.AddChildObject(node, 'Quadrant III',
553 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q3.png', $1004));
554 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
555 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q34.png', $1005));
556 Tree.Items.AddChildObject(node, 'Quadrant IV',
557 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q4.png', $1006));
558 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
559 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q41.png', $1007));
560
561 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
562 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q1r.png', $1100));
563 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
564 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q12r.png', $1101));
565 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
566 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q2r.png', $1102));
567 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
568 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q23r.png', $1103));
569 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
570 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q3r.png', $1104));
571 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
572 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q34r.png', $1105));
573 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
574 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q4r.png', $1106));
575 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
576 TRenderParams.Create(@Render_Arc, 'arc_ell_ccw_q41r.png', $1107));
577
578 node1 := Tree.Items.AddChild(node0, 'elliptical, rotated 30deg');
579 node := Tree.Items.AddChild(node1, 'clockwise from point 1 to point 2');
580 Tree.Items.AddChildObject(node, 'Quadrant I',
581 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q1.png', $2200));
582 Tree.Items.AddChildObject(node, 'Quadrant I+II',
583 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q12.png', $2201));
584 Tree.Items.AddChildObject(node, 'Quadrant II',
585 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q2.png', $2202));
586 Tree.Items.AddChildObject(node, 'Quadrant II+III',
587 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q23.png', $2203));
588 Tree.Items.AddChildObject(node, 'Quadrant III',
589 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q3.png', $2204));
590 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
591 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q34.png', $2205));
592 Tree.Items.AddChildObject(node, 'Quadrant IV',
593 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q4.png', $2206));
594 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
595 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q41.png', $2207));
596
597 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
598 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q1r.png', $2300));
599 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
600 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q12r.png', $2301));
601 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
602 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q2r.png', $2302));
603 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
604 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q23r.png', $2303));
605 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
606 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q3r.png', $2304));
607 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
608 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q34r.png', $2305));
609 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
610 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q4r.png', $2306));
611 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
612 TRenderParams.Create(@Render_Arc, 'arc_ellrot_cw_q41r.png', $2307));
613
614 node := Tree.Items.AddChild(node1, 'counter-clockwise from point 1 to point 2');
615 Tree.Items.AddChildObject(node, 'Quadrant I',
616 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q1.png', $2000));
617 Tree.Items.AddChildObject(node, 'Quadrant I+II',
618 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q12.png', $2001));
619 Tree.Items.AddChildObject(node, 'Quadrant II',
620 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q2.png', $2002));
621 Tree.Items.AddChildObject(node, 'Quadrant II+III',
622 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q23.png', $2003));
623 Tree.Items.AddChildObject(node, 'Quadrant III',
624 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q3.png', $2004));
625 Tree.Items.AddChildObject(node, 'Quadrant III+IV',
626 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q34.png', $2005));
627 Tree.Items.AddChildObject(node, 'Quadrant IV',
628 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q4.png', $2006));
629 Tree.Items.AddChildObject(node, 'Quadrant IV+I',
630 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q41.png', $2007));
631
632 Tree.Items.AddChildObject(node, 'Quadrant I, reverse',
633 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q1r.png', $2100));
634 Tree.Items.AddChildObject(node, 'Quadrant I+II, reverse',
635 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q12r.png', $2101));
636 Tree.Items.AddChildObject(node, 'Quadrant II, reverse',
637 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q2r.png', $2102));
638 Tree.Items.AddChildObject(node, 'Quadrant II+III, reverse',
639 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q23r.png', $2103));
640 Tree.Items.AddChildObject(node, 'Quadrant III, reverse',
641 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q3r.png', $2104));
642 Tree.Items.AddChildObject(node, 'Quadrant III+IV, reverse',
643 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q34r.png', $2105));
644 Tree.Items.AddChildObject(node, 'Quadrant IV, reverse',
645 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q4r.png', $2106));
646 Tree.Items.AddChildObject(node, 'Quadrant IV+I, reverse',
647 TRenderParams.Create(@Render_Arc, 'arc_ellrot_ccw_q41r.png', $2107));
648
649 { -----------------------------------------------}
650 node := Tree.Items.AddChild(nil, 'Bezier');
651 { -----------------------------------------------}
652 Tree.Items.AddChildObject(node, 'Single segment',
653 TRenderParams.Create(@Render_Bezier, 'bezier.png'));
654
655 { -----------------------------------------------}
656 node0 := Tree.Items.AddChild(nil, 'Gradients');
657 { -----------------------------------------------}
658 node := Tree.Items.AddChild(node0, 'horizontal');
659 Tree.Items.AddChildObject(node, 'Circle',
660 TRenderParams.Create(@Render_Shape, 'circle_gradienthor.png', $0101));
661 Tree.Items.AddChildObject(node, 'Ellipse',
662 TRenderParams.Create(@Render_Shape, 'ellipse_gradienthor.png', $0201));
663 Tree.Items.AddChildObject(node, 'Rectangle',
664 TRenderParams.Create(@Render_Shape, 'rect_gradienthor.png', $0301));
665 Tree.Items.AddChildObject(node, 'Rounded rectangle',
666 TRenderParams.Create(@Render_Shape, 'rounded_rect_gradienthor.png', $0401));
667 Tree.Items.AddChildObject(node, 'Polygon',
668 TRenderParams.Create(@Render_Shape, 'polygon_gradienthor.png', $0501));
669
670 node := Tree.Items.AddChild(node0, 'vertical');
671 Tree.Items.AddChildObject(node, 'Circle',
672 TRenderParams.Create(@Render_Shape, 'circle_gradientvert.png', $0102));
673 Tree.Items.AddChildObject(node, 'Ellipse',
674 TRenderParams.Create(@Render_Shape, 'ellipse_gradientvert.png', $0202));
675 Tree.Items.AddChildObject(node, 'Rectangle',
676 TRenderParams.Create(@Render_Shape, 'rect_gradientvert.png', $0302));
677 Tree.Items.AddChildObject(node, 'Rounded rectangle',
678 TRenderParams.Create(@Render_Shape, 'rounded_rect_gradientvert.png', $0402));
679 Tree.Items.AddChildObject(node, 'Polygon',
680 TRenderParams.Create(@Render_Shape, 'polygon_gradientvert.png', $0502));
681
682 node := Tree.Items.AddChild(node0, 'linear');
683 Tree.Items.AddChildObject(node, 'Circle',
684 TRenderParams.Create(@Render_Shape, 'circle_gradientlinear.png', $0103));
685 Tree.Items.AddChildObject(node, 'Ellipse',
686 TRenderParams.Create(@Render_Shape, 'ellipse_gradientlinear.png', $0203));
687 Tree.Items.AddChildObject(node, 'Rectangle',
688 TRenderParams.Create(@Render_Shape, 'rect_gradientlinear.png', $0303));
689 Tree.Items.AddChildObject(node, 'Rounded rectangle',
690 TRenderParams.Create(@Render_Shape, 'rounded_rect_gradientlinear.png', $0403));
691 Tree.Items.AddChildObject(node, 'Polygon',
692 TRenderParams.Create(@Render_Shape, 'polygon_gradientlinear.png', $0503));
693
694 node := Tree.Items.AddChild(node0, 'radial');
695 Tree.Items.AddChildObject(node, 'Circle',
696 TRenderParams.Create(@Render_Shape, 'circle_gradientradial.png', $0104));
697 Tree.Items.AddChildObject(node, 'Ellipse',
698 TRenderParams.Create(@Render_Shape, 'ellipse_gradientradial.png', $0204));
699 Tree.Items.AddChildObject(node, 'Rectangle',
700 TRenderParams.Create(@Render_Shape, 'rect_gradientradial.png', $0304));
701 Tree.Items.AddChildObject(node, 'Rounded rectangle',
702 TRenderParams.Create(@Render_Shape, 'rounded_rect_gradientradial.png', $0404));
703 Tree.Items.AddChildObject(node, 'Polygon',
704 TRenderParams.Create(@Render_Shape, 'polygon_gradientradial.png', $0504));
705
706 { -----------------------------------------------}
707 node0 := Tree.Items.AddChild(nil, 'Text');
708 { -----------------------------------------------}
709 node := Tree.Items.AddChild(node0, 'horizontal');
710 Tree.Items.AddChildObject(node, 'left aligned',
711 TRenderParams.Create(@Render_Text, 'text_left.png', $0000));
712 Tree.Items.AddChildObject(node, 'centered',
713 TRenderParams.Create(@Render_Text, 'text_center.png', $0001));
714 Tree.Items.AddChildObject(node, 'right aligned',
715 TRenderParams.Create(@Render_Text, 'text_right.png', $0002));
716
717 node := Tree.Items.AddChild(node0, 'rotated by 30 deg');
718 Tree.Items.AddChildObject(node, 'left aligned',
719 TRenderParams.Create(@Render_Text, 'text_left_30.png', $1000));
720 Tree.Items.AddChildObject(node, 'centered',
721 TRenderParams.Create(@Render_Text, 'text_center_30.png', $1001));
722 Tree.Items.AddChildObject(node, 'right aligned',
723 TRenderParams.Create(@Render_Text, 'text_right_30.png', $1002));
724
725 node := Tree.Items.AddChild(node0, 'vertical (90 deg, upward)');
726 Tree.Items.AddChildObject(node, 'left aligned',
727 TRenderParams.Create(@Render_Text, 'text_left_90.png', $2000));
728 Tree.Items.AddChildObject(node, 'centered',
729 TRenderParams.Create(@Render_Text, 'text_center_90.png', $2001));
730 Tree.Items.AddChildObject(node, 'right aligned',
731 TRenderParams.Create(@Render_Text, 'text_right_90.png', $2002));
732
733 node := Tree.Items.AddChild(node0, 'vertical (-90 deg, downward)');
734 Tree.Items.AddChildObject(node, 'left aligned',
735 TRenderParams.Create(@Render_Text, 'text_left_m90.png', $3000));
736 Tree.Items.AddChildObject(node, 'centered',
737 TRenderParams.Create(@Render_Text, 'text_center_m90.png', $3001));
738 Tree.Items.AddChildObject(node, 'right aligned',
739 TRenderParams.Create(@Render_Text, 'text_right_m90.png', $3002));
740
741 node := Tree.Items.AddChild(node0, 'Fonts');
742 Tree.Items.AddChildObject(node, 'Times New Roman + Courier New',
743 TRenderParams.Create(@Render_Text_Fonts, 'text_fonts.png'));
744 Tree.Items.AddChildObject(node0, 'Text colors',
745 TRenderParams.Create(@Render_Text_Colors, 'text_colors.png'));
746 end;
747
748 procedure TMainForm.Render_Shape(APage: TvVectorialPage;
749 AIntParam: Integer);
750 { AIntParam and $00FF = 0 --> solid fill
751 1 --> horizontal gradient
752 2 --> vertical gradient
753 3 --> linear gradient
754 4 --> radial gradient
755 AIntParam and $FF00 = $0100 --> circle
756 $0200 --> ellipse
757 $0300 --> rectangle
758 $0400 --> rounded rect
759 $0500 --> polygon (triangle) }
760 var
761 ent: TvEntityWithPenAndBrush;
762 begin
763 case AIntParam and $FF00 of
764 $0100: ent := CreateStdCircle(APage);
765 $0200: ent := CreateStdEllipse(APage);
766 $0300: ent := CreateStdRect(APage);
767 $0400: ent := CreateStdRoundedRect(APage);
768 $0500: ent := CreateStdPolygon(APage);
769 else raise Exception.Create('Shape not supported.');
770 end;
771 case AIntParam and $00FF of
772 $0000: ent.Brush := StdSolidBrush;
773 $0001: ent.Brush := StdHorizGradientBrush;
774 $0002: ent.Brush := StdVertGradientBrush;
775 $0003: ent.Brush := StdLinearGradientBrush;
776 $0004: ent.Brush := StdRadialGradientBrush;
777 else raise Exception.Create('Brush not supported');
778 end;
779 APage.AddEntity(ent);
780 end;
781
782 procedure TMainForm.Render_Arc(APage: TvVectorialPage; AIntParam: Integer);
783 //
784 // AIntParam and $000F = $0000 --> circular arc
785 // $1000 --> elliptical arc
786 // $2000 --> elliptical arc, rotated
787 // AIntParam and $000F = $0000 --> quarter 1
788 // $0001 --> quarter 1 + 2
789 // $0002 --> quarter 2
790 // $0003 --> quarter 2 + 3
791 // $0004 --> quarter 3
792 // $0005 --> quarter 3+4
793 // $0006 --> quarter 4
794 // $0007 --> quarter 4+1
795 // AIntParam and $0100 = $0100 --> start and end points exchanged
796 // AIntParan and $0200 = $0200 --> clockwise
797 const
798 ROT_ANGLE = 30;
799 RY_MULT = 0.6;
800 CX = 50;
801 CY = 55;
802 R = 30;
803 var
804 isReversed, isClockwise, isEllipse, isRotated: Boolean;
805 p: T3dPoint;
806 x1, y1, x2, y2, rx, ry: Double;
807 startAngle, endAngle, phi: Double;
808 begin
809 isReversed := AIntParam and $0100 <> 0;
810 isClockwise := AIntParam and $0200 <> 0;
811 isEllipse := AIntParam and $F000 <> 0;
812 isRotated := AIntParam and $F000 = $2000;
813
814 rx := R;
815 ry := IfThen(isEllipse, R * RY_MULT, R);
816 phi := IfThen(isRotated, DegToRad(ROT_ANGLE), 0.0);
817
818 startAngle := DegToRad((AIntParam and $000F) * 45); // 0°, 45°, 90°, ...
819 endAngle := startAngle + pi/2; // 90°, 135°, 180°, ...
820 x1 := CX + rx * cos(startAngle);
821 y1 := CY + ry * sin(startAngle);
822 x2 := CX + rx * cos(endAngle);
823 y2 := CY + ry * sin(endAngle);
824 if isRotated then begin
825 p := Rotate3DPointInXY(Make3DPoint(x1, y1), Make3DPoint(CX, CY), -phi);
826 // See comment at Rotate3DPointInXY regarding the negative sign of phi
827 x1 := p.x;
828 y1 := p.y;
829 p := Rotate3DPointInXY(Make3DPoint(x2, y2), Make3DPoint(CX, CY), -phi);
830 x2 := p.x;
831 y2 := p.y;
832 end;
833
834 if isReversed then
835 CreateArc(APage, x2, y2, x1, y1, CX, CY, rx, ry, phi, isClockwise)
836 else
837 CreateArc(APage, x1, y1, x2, y2, CX, CY, rx, ry, phi, isClockwise);
838 end;
839
840 procedure TMainForm.Render_Bezier(APage: TvVectorialpage; AIntParam: Integer);
841 const
842 X1 = 10;
843 Y1 = 25;
844 X2 = 30;
845 Y2 = 80;
846 X3 = 50;
847 Y3 = 70;
848 X4 = 90;
849 Y4 = 25;
850 begin
851 CreateBezier(APage, X1,Y1, X2,Y2, X3,Y3, X4,Y4);
852 end;
853
854 procedure TMainForm.Render_Path_Hole_SolidFill(APage: TvVectorialPage;
855 AIntParam: Integer);
856 var
857 obj: TPath;
858 begin
859 obj := CreatePathWithHole(APage); // no need to AddEntity!
860 obj.Brush.Color := colYellow;
861 obj.Brush.Style := bsSolid;
862 obj.Pen.Width := 3;
863 obj.Pen.Color := colBlue;
864 end;
865
866 procedure TMainForm.Render_Path_Hole_GradientFill(APage: TvVectorialPage;
867 AIntParam: Integer);
868 var
869 obj: TPath;
870 begin
871 obj := CreatePathWithHole(APage); // No need to AddEntity!
872 obj.Brush := StdLinearGradientBrush;
873 obj.Pen.Width := 3;
874 obj.Pen.Color := colBlue;
875 end;
876
877 procedure TMainForm.Render_SelfIntersectingPoly_SolidFill_EvenOdd(
878 APage: TvVectorialPage; AIntParam: Integer);
879 var
880 obj: TvPolygon;
881 begin
882 obj := CreateStdSelfIntersectingPolygon(APage);
883 obj.WindingRule := vcmEvenOddRule;
884 obj.Brush := StdSolidBrush;
885 APage.AddEntity(obj);
886 end;
887
888 procedure TMainForm.Render_SelfIntersectingPoly_GradientFill_EvenOdd(
889 APage: TvVectorialPage; AIntParam: Integer);
890 var
891 obj: TvPolygon;
892 begin
893 obj := CreateStdSelfIntersectingPolygon(APage);
894 obj.Brush := StdHorizGradientBrush;
895 obj.WindingRule := vcmEvenOddRule;
896 APage.AddEntity(obj);
897 end;
898
899 procedure TMainForm.Render_SelfIntersectingPoly_SolidFill_NonZeroWinding(
900 APage: TvVectorialPage; AIntParam: Integer);
901 var
902 obj: TvPolygon;
903 begin
904 obj := CreateStdSelfIntersectingPolygon(APage);
905 obj.WindingRule := vcmNonZeroWindingRule;
906 obj.Brush := StdSolidBrush;
907 APage.AddEntity(obj);
908 end;
909
910 procedure TMainForm.Render_SelfIntersectingPoly_GradientFill_NonZeroWinding(
911 APage: TvVectorialPage; AIntParam: Integer);
912 var
913 obj: TvPolygon;
914 begin
915 obj := CreateStdSelfIntersectingPolygon(APage);
916 obj.Brush := StdHorizGradientBrush;
917 obj.WindingRule := vcmNonzeroWindingRule;
918 APage.AddEntity(obj);
919 end;
920
921 procedure TMainForm.Render_Text(APage: TvVectorialPage; AIntParam: Integer);
922 { AIntParam and $000F = $0000 --> anchor at left
923 $0001 --> anchor at center
924 $0002 --> anchor at right
925 AIntParam and $F000 = $0000 --> horizontal
926 $1000 --> rotated 30deg
927 $2000 --> rotated 90deg
928 $3000 --> rotated -90deg }
929 const
930 XTEXT = 50;
931 YTEXT = 40; // we assume that y points up
932 L = 10;
933 var
934 txt: TvText;
935 p: TPath;
936 angle: double;
937 anchor: TvTextAnchor;
938 begin
939 case AIntParam and $000F of
940 $0000 : anchor := vtaStart;
941 $0001 : anchor := vtaMiddle;
942 $0002 : anchor := vtaEnd;
943 else raise Exception.Create('Text anchor not supported');
944 end;
945 case AIntParam and $F000 of
946 $0000 : angle := 0;
947 $1000 : angle := 30;
948 $2000 : angle := 90;
949 $3000 : angle := -90;
950 else raise Exception.Create('Text angle not supported.');
951 end;
952
953 // Draw "+" at the origin of the text
954 if APage.UseTopLeftCoordinates then begin
955 APage.StartPath (XTEXT - L, PAGE_SIZE - YTEXT);
956 APage.AddLineToPath(XTEXT + L, PAGE_SIZE - YTEXT);
957 APage.AddMoveToPath(XTEXT, PAGE_SIZE - YTEXT - L);
958 APage.AddLineToPath(XTEXT, PAGE_SIZE - YTEXT + L);
959 end else begin
960 APage.StartPath (XTEXT - L, YTEXT);
961 APage.AddLineToPath(XTEXT + L, YTEXT);
962 APage.AddMoveToPath(XTEXT, YTEXT - L);
963 APage.AddLineToPath(XTEXT, YTEXT + L);
964 end;
965 p := APage.EndPath;
966 p.Pen.Width := 1;
967 p.Pen.Color := colRed;
968
969 // Draw text
970 txt := TvText.Create(APage);
971 txt.X := XTEXT;
972 if APage.UseTopLeftCoordinates then
973 txt.Y := PAGE_SIZE - YTEXT else
974 txt.Y := YTEXT;
975 txt.Value.Add('ABC');
976 txt.Font.Size := 14;
977 txt.TextAnchor := anchor;
978 txt.Font.Orientation := angle;
979
980 APage.AddEntity(txt);
981 end;
982
983 procedure TMainForm.Render_Text_Fonts(APage: TvVectorialPage;
984 AIntParam: Integer);
985 var
986 txt: TvText;
987 begin
988 txt := TvText.Create(APage);
989 txt.X := 10;
990 txt.Y := 80;
991 txt.Font.Name := 'Times New Roman';
992 txt.Font.Size := 10;
993 txt.Value.Add('Times');
994 APage.AddEntity(txt);
995
996 txt := TvText.Create(APage);
997 txt.X := 10;
998 txt.Y := 60;
999 txt.Font.Name := 'Courier New';
1000 txt.Font.Size := 12;
1001 txt.Value.Add('Courier');
1002 APage.AddEntity(txt);
1003 end;
1004
1005 procedure TMainForm.Render_Text_Colors(APage: TvVectorialPage;
1006 AIntParam: Integer);
1007 var
1008 txt: TvText;
1009 begin
1010 txt := TvText.Create(APage);
1011 txt.X := 10;
1012 txt.Y := 80;
1013 txt.Font.Name := 'Times New Roman';
1014 txt.Font.Size := 14;
1015 txt.Font.Color := colRed;
1016 txt.Value.Add('Text');
1017 txt.Brush.Style := bsSolid;
1018 txt.Brush.Color := colYellow;
1019 txt.Brush.Kind := bkSimpleBrush;
1020 APage.AddEntity(txt);
1021 end;
1022
1023 procedure TMainForm.ReadIni;
1024 var
1025 ini: TCustomIniFile;
1026 L, T, W, H: Integer;
1027 rct: TRect;
1028 begin
1029 ini := TMemIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
1030 try
1031 L := ini.ReadInteger('MainForm', 'Left', Left);
1032 T := ini.ReadInteger('MainForm', 'Top', Top);
1033 W := ini.ReadInteger('MainForm', 'Width', Width);
1034 H := ini.ReadInteger('MainForm', 'Height', Height);
1035 rct := Screen.DesktopRect;
1036 if L + W > rct.Right - rct.Left then L := rct.Right - W;
1037 if L < 0 then L := rct.Left;
1038 if T + H > rct.Bottom - rct.Top then T := rct.Bottom - H;
1039 if T < 0 then T := rct.Top;
1040 SetBounds(L, T, W, H);
1041 finally
1042 ini.Free;
1043 end;
1044 end;
1045
1046 procedure TMainForm.WriteIni;
1047 var
1048 ini: TCustomIniFile;
1049 begin
1050 ini := TMemIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
1051 try
1052 if WindowState = wsNormal then
1053 begin
1054 ini.WriteInteger('MainForm', 'Left', Left);
1055 ini.WriteInteger('MainForm', 'Top', Top);
1056 ini.WriteInteger('MainForm', 'Width', Width);
1057 ini.WriteInteger('MainForm', 'Height', Height);
1058 end;
1059 finally
1060 ini.Free;
1061 end;
1062 end;
1063
1064 procedure TMainForm.ShowFileImage(AFilename: String; AUseTopLeftCoords: Boolean;
1065 APaintbox: TPaintbox);
1066 var
1067 ext: String;
1068 rc: TRenderCoords;
1069 begin
1070 if AUseTopLeftCoords then
1071 rc := rcTopLeftCoords else
1072 rc := rcBottomLeftCoords;
1073
1074 ext := Lowercase(ExtractFileExt(AFileName));
1075
1076 if not FileExists(AFileName) then begin
1077 case ext of
1078 '.svg': FreeAndNil(FDocFromSVG[rc]);
1079 '.wmf': FreeAndNil(FDocFromWMF[rc]);
1080 else raise Exception.Create('File type not supported');
1081 end;
1082 APaintbox.Hint := NOT_SAVED;
1083 APaintbox.Invalidate;
1084 exit;
1085 end;
1086
1087 if ext = '.svg' then begin
1088 FreeAndNil(FDocFromSVG[rc]);
1089 FDocFromSVG[rc] := TvVectorialDocument.Create;
1090 FDocFromSVG[rc].ReadFromFile(AFileName);
1091 end else
1092 if ext = '.wmf' then begin
1093 FreeAndNil(FDocFromWMF[rc]);
1094 FDocFromWMF[rc] := TvVectorialDocument.Create;
1095 FDocFromWMF[rc].ReadFromFile(AFilename);
1096 end;
1097 APaintbox.Hint := AFileName;
1098 APaintBox.Invalidate;
1099 end;
1100
1101 procedure TMainForm.ShowRefImageTest;
1102 var
1103 renderParams: TRenderParams;
1104 fn: String;
1105 begin
1106 if Tree.Selected = nil then
1107 exit;
1108
1109 renderParams := TRenderParams(Tree.Selected.Data);
1110 if renderParams = nil then
1111 begin
1112 RefImage.Picture := nil;
1113 exit;
1114 end;
1115
1116 fn := IncludeTrailingPathDelimiter(IMG_FOLDER) + renderParams.RefFile;
1117 if FileExists(fn) then begin
1118 RefImage.Picture.LoadFromFile(fn);
1119 RefImage.Hint := fn;
1120 end else begin
1121 RefImage.Picture := nil;
1122 RefImage.Hint := NOT_SAVED;
1123 end;
1124 end;
1125
1126 procedure TMainForm.ShowRenderTestImages;
1127 var
1128 renderParams: TRenderParams;
1129 page: TvVectorialPage = nil;
1130 begin
1131 if Tree.Selected = nil then
1132 exit;
1133
1134 renderParams := TRenderParams(Tree.Selected.Data);
1135 if renderParams = nil then
1136 begin
1137 BottomLeftPaintbox.Invalidate;
1138 TopLeftPaintbox.Invalidate;
1139 exit;
1140 end;
1141
1142 // Render document with bottom/left origin
1143 PrepareDoc(FDoc[rcBottomLeftCoords], page, false);
1144 renderParams.OnRender(page, renderParams.IntParam);
1145 BottomLeftPaintbox.Invalidate;
1146
1147 // Render document with top/left origin
1148 PrepareDoc(FDoc[rcTopLeftCoords], page, true);
1149 renderParams.OnRender(page, renderParams.IntParam);
1150 TopLeftPaintbox.Invalidate;
1151 end;
1152
1153 procedure TMainForm.ShowWriteReadTestImages;
1154 var
1155 renderParams: TRenderParams;
1156 folder: String;
1157 fn: String;
1158 ext: String;
1159 rc: TRenderCoords;
1160 begin
1161 for rc in TRenderCoords do begin
1162 FreeAndNil(FDocFromSVG[rc]);
1163 FreeAndNil(FDocFromWMF[rc]);
1164 end;
1165
1166 if Tree.Selected = nil then
1167 exit;
1168
1169 renderParams := TRenderParams(Tree.Selected.Data);
1170 if renderParams = nil then
1171 begin
1172 WRBottomLeftPaintbox.Invalidate;
1173 WRTopLeftPaintbox.Invalidate;
1174 exit;
1175 end;
1176
1177 ext := GetFileFormatExt;
1178 folder := IMG_FOLDER + ext + PathDelim;
1179
1180 fn := folder + 'bl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
1181 ShowFileImage(fn, false, WRBottomLeftPaintbox);
1182
1183 fn := folder + 'tl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
1184 ShowFileImage(fn, true, WRTopLeftPaintbox);
1185 end;
1186
1187 procedure TMainForm.TreeSelectionChanged(Sender: TObject);
1188 begin
1189 ShowRenderTestImages;
1190 ShowRefImageTest;
1191 ShowWriteReadTestImages;
1192 UpdateCmdStates;
1193 end;
1194
1195 procedure TMainForm.TreeCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
1196 State: TCustomDrawState; var DefaultDraw: Boolean);
1197 begin
1198 if Node.HasChildren then
1199 Sender.Canvas.Font.Style := [fsBold] else
1200 Sender.Canvas.Font.Style := [];
1201 end;
1202
1203 procedure TMainForm.UpdateCmdStates;
1204 var
1205 fn: String;
1206 folder: string;
1207 renderParams: TRenderParams;
1208 ext: String;
1209 rc: TRenderCoords;
1210 rcOK: array[TRenderCoords] of boolean = (false, false);
1211 begin
1212 BtnSaveAsRef.Enabled := Tree.Selected <> nil;
1213 BtnSaveToFiles.Enabled := Tree.Selected <> nil;
1214 BtnViewBottomLeft.Enabled := Tree.Selected <> nil;
1215 BtnViewTopLeft.Enabled := Tree.Selected <> nil;
1216
1217 if Tree.Selected <> nil then begin
1218 renderParams := TRenderParams(Tree.Selected.Data);
1219 if renderParams <> nil then begin
1220 ext := GetFileFormatExt;
1221 folder := IMG_FOLDER + ext + PathDelim;
1222 fn := folder + 'bl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
1223 rcOK[rcBottomLeftCoords] := FileExists(fn);
1224 fn := folder + 'tl_' + ChangeFileExt(renderParams.RefFile, '.' + ext);
1225 rcOK[rcTopLeftCoords] := FileExists(fn);
1226 end;
1227 end;
1228 BtnViewBottomLeft.Enabled := rcOK[rcBottomLeftcoords];
1229 BtnViewTopLeft.Enabled := rcOK[rcTopLeftCoords];
1230 end;
1231
1232 end.
1233
1234