lcvectorclipboard.pas 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit LCVectorClipboard;
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, SysUtils, Clipbrd, LCLType, LCVectorOriginal, BGRATransform, BGRABitmapTypes;
  7. function CopyShapesToClipboard(AShapes: array of TVectorShape; const AMatrix: TAffineMatrix): boolean;
  8. procedure PasteShapesFromClipboard(ATargetContainer: TVectorOriginal; const ATargetMatrix: TAffineMatrix; const ABounds: TRectF);
  9. function ClipboardHasShapes: boolean;
  10. implementation
  11. uses math;
  12. var
  13. vectorClipboardFormat : TClipboardFormat;
  14. function CopyShapesToClipboard(AShapes: array of TVectorShape; const AMatrix: TAffineMatrix): boolean;
  15. var
  16. tempContainer: TVectorOriginal;
  17. mem: TMemoryStream;
  18. i, j: Integer;
  19. s: TVectorShape;
  20. multiSel: IVectorMultishape;
  21. begin
  22. result:= false;
  23. if length(AShapes)=0 then exit;
  24. tempContainer := TVectorOriginal.Create;
  25. mem := TMemoryStream.Create;
  26. try
  27. for i := 0 to high(AShapes) do
  28. begin
  29. if AShapes[i] is VectorMultiselectionFactory then
  30. begin
  31. multiSel := AShapes[i].GetAsMultishape;
  32. for j := 0 to multiSel.ShapeCount-1 do
  33. begin
  34. s := multiSel.GetShape(j).Duplicate;
  35. s.Transform(AMatrix);
  36. tempContainer.AddShape(s);
  37. end;
  38. end else
  39. begin
  40. s := AShapes[i].Duplicate;
  41. s.Transform(AMatrix);
  42. tempContainer.AddShape(s);
  43. end;
  44. end;
  45. tempContainer.SaveToStream(mem);
  46. Clipboard.Clear;
  47. mem.Position:= 0;
  48. result := Clipboard.AddFormat(vectorClipboardFormat, mem);
  49. finally
  50. mem.Free;
  51. tempContainer.Free;
  52. end;
  53. end;
  54. procedure PasteShapesFromClipboard(ATargetContainer: TVectorOriginal; const ATargetMatrix: TAffineMatrix; const ABounds: TRectF);
  55. var
  56. tempContainer: TVectorOriginal;
  57. mem: TMemoryStream;
  58. i: Integer;
  59. pastedShape: TVectorShape;
  60. pastedShapes: TVectorShapes;
  61. invMatrix, m: TAffineMatrix;
  62. pastedBounds: TRectF;
  63. ofs: TPointF;
  64. begin
  65. if not IsAffineMatrixInversible(ATargetMatrix) then exit;
  66. invMatrix := AffineMatrixInverse(ATargetMatrix);
  67. if Clipboard.HasFormat(vectorClipboardFormat) then
  68. begin
  69. mem := TMemoryStream.Create;
  70. tempContainer := TVectorOriginal.Create;
  71. try
  72. if Clipboard.GetFormat(vectorClipboardFormat, mem) then
  73. begin
  74. mem.Position:= 0;
  75. tempContainer.LoadFromStream(mem);
  76. pastedBounds := EmptyRectF;
  77. ofs := PointF(0, 0);
  78. if not ABounds.IsEmpty then
  79. begin
  80. for i := 0 to tempContainer.ShapeCount-1 do
  81. pastedBounds := pastedBounds.Union(pastedBounds,
  82. tempContainer.Shape[i].GetAlignBounds(InfiniteRect, AffineMatrixIdentity), true);
  83. if (pastedBounds.Left < ABounds.Left) and (pastedBounds.Right < ABounds.Right) then
  84. ofs.x := ceil(ABounds.Left - pastedBounds.Left) else
  85. if (pastedBounds.Right > ABounds.Right) and (pastedBounds.Left > ABounds.Left) then
  86. ofs.x := floor(ABounds.Right - pastedBounds.Right);
  87. if (pastedBounds.Top < ABounds.Top) and (pastedBounds.Bottom < ABounds.Bottom) then
  88. ofs.y := ceil(ABounds.Top - pastedBounds.Top) else
  89. if (pastedBounds.Bottom > ABounds.Bottom) and (pastedBounds.Top > ABounds.Top) then
  90. ofs.y := floor(ABounds.Bottom - pastedBounds.Bottom);
  91. end;
  92. m := invMatrix*AffineMatrixTranslation(ofs.x,ofs.y);
  93. ATargetContainer.DeselectShapes;
  94. pastedShapes := TVectorShapes.Create;
  95. for i := 0 to tempContainer.ShapeCount-1 do
  96. begin
  97. pastedShape := tempContainer.Shape[i].Duplicate;
  98. pastedShape.Transform(m);
  99. pastedShapes.Add(pastedShape);
  100. end;
  101. ATargetContainer.AddShapes(pastedShapes);
  102. ATargetContainer.SelectShapes(pastedShapes);
  103. pastedShapes.Free;
  104. end;
  105. finally
  106. tempContainer.Free;
  107. mem.Free;
  108. end;
  109. end;
  110. end;
  111. function ClipboardHasShapes: boolean;
  112. begin
  113. result := Clipboard.HasFormat(vectorClipboardFormat);
  114. end;
  115. initialization
  116. vectorClipboardFormat := RegisterClipboardFormat('TVectorOriginal');
  117. end.