LazMapViewer: Fixes issues with painting/multithreading. Issue #39063, patch by Yuliyan Ivanov.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9092 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-12-18 16:56:22 +00:00
parent 0866840b01
commit a5741193c0
5 changed files with 177 additions and 225 deletions

View File

@ -23,7 +23,7 @@ interface
uses
Classes, SysUtils, Controls, Graphics, FPImage, IntfGraphics, Forms, ImgList, LCLVersion,
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine;
MvTypes, MvGPSObj, MvEngine, MvMapProvider, MvDownloadEngine, MvDrawingEngine, mvCache;
Type
@ -54,9 +54,7 @@ Type
procedure CallAsyncInvalidate;
procedure DoAsyncInvalidate({%H-}Data: PtrInt);
procedure DrawObjects(const {%H-}TileId: TTileId; aLeft, aTop, aRight,aBottom: integer);
procedure DrawPointOfInterest(const {%H-}Area: TRealArea; APt: TGPSPointOfInterest);
procedure DrawPt(const {%H-}Area: TRealArea; APt: TGPSPoint);
procedure DrawTrack(const Area: TRealArea; trk: TGPSTrack);
procedure DrawGpsObj(const {%H-}Area: TRealArea; AObj: TGPSObj);
function GetCacheOnDisk: boolean;
function GetCachePath: String;
function GetCenter: TRealPoint;
@ -108,6 +106,7 @@ Type
procedure DoDrawStretchedTile(const TileId: TTileID; X, Y: Integer; TileImg: TLazIntfImage; const R: TRect);
procedure DoDrawTile(const TileId: TTileId; X,Y: integer; TileImg: TLazIntfImage);
procedure DoDrawTileInfo(const {%H-}TileID: TTileID; X,Y: Integer);
procedure DoTileDownloaded(const TileId: TTileId);
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean; override;
procedure DoOnResize; override;
@ -124,6 +123,9 @@ Type
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DrawPointOfInterest(const {%H-}Area: TRealArea; APt: TGPSPointOfInterest);
procedure DrawPt(const {%H-}Area: TRealArea; APt: TGPSPoint);
procedure DrawTrack(const Area: TRealArea; trk: TGPSTrack);
procedure ClearBuffer;
procedure GetMapProviders(lstProviders: TStrings);
function GetVisibleArea: TRealArea;
@ -266,13 +268,7 @@ var
begin
iObj := aTask-1;
Obj := FLst[iObj];
if Obj.InheritsFrom(TGPSTrack) then
Viewer.DrawTrack(FArea, TGPSTrack(Obj));
if Obj.InheritsFrom(TGPSPointOfInterest) then
Viewer.DrawPointOfInterest(FArea, TGPSPointOfInterest(Obj))
else
if Obj.InheritsFrom(TGPSPoint) then
Viewer.DrawPt(FArea, TGPSPoint(Obj));
Viewer.DrawGpsObj(FArea, Obj);
end;
function TDrawObjJob.Running: boolean;
@ -295,8 +291,6 @@ destructor TDrawObjJob.Destroy;
begin
inherited Destroy;
FreeAndNil(FLst);
if not(Cancelled) then
Viewer.CallAsyncInvalidate;
end;
@ -557,6 +551,7 @@ begin
Result:=inherited DoMouseWheel(Shift, WheelDelta, MousePos);
if IsActive then
Engine.MouseWheel(self,Shift,WheelDelta,MousePos,Result);
Invalidate;
end;
procedure TMapView.MouseDown(Button: TMouseButton; Shift: TShiftState;
@ -565,6 +560,7 @@ begin
inherited MouseDown(Button, Shift, X, Y);
if IsActive then
Engine.MouseDown(self,Button,Shift,X,Y);
Invalidate;
end;
procedure TMapView.MouseUp(Button: TMouseButton; Shift: TShiftState;
@ -573,6 +569,7 @@ begin
inherited MouseUp(Button, Shift, X, Y);
if IsActive then
Engine.MouseUp(self,Button,Shift,X,Y);
Invalidate;
end;
procedure TMapView.MouseMove(Shift: TShiftState; X, Y: Integer);
@ -580,6 +577,7 @@ begin
inherited MouseMove(Shift, X, Y);
if IsActive then
Engine.MouseMove(self,Shift,X,Y);
Invalidate;
end;
procedure TMapView.Notification(AComponent: TComponent; Operation: TOperation);
@ -594,6 +592,7 @@ begin
inherited DblClick;
if IsActive then
Engine.DblClick(self);
Invalidate;
end;
procedure TMapView.DoOnResize;
@ -604,13 +603,18 @@ begin
DrawingEngine.CreateBuffer(ClientWidth, ClientHeight);
if IsActive then
Engine.SetSize(ClientWidth, ClientHeight);
Invalidate;
end;
procedure TMapView.Paint;
begin
inherited Paint;
if IsActive then
DrawingEngine.PaintToCanvas(Canvas)
begin
Engine.Redraw;
DrawObjects(Default(TTileId), 0, 0, Canvas.Width, Canvas.Height);
DrawingEngine.PaintToCanvas(Canvas);
end
else
begin
Canvas.Brush.Color := InactiveColor;
@ -631,7 +635,7 @@ begin
if hasIntersectArea(objArea, visArea) then
begin
Area := IntersectArea(objArea, visArea);
Engine.Jobqueue.AddJob(TDrawObjJob.Create(self, Objs, Area), Engine);
Invalidate;
end
else
objs.Free;
@ -654,8 +658,6 @@ begin
if not trk.Visible or (trk.Points.Count = 0) then
exit;
GPSItems.Lock;
try
// Determine track color
if trk.LineColor = clDefault then
begin
@ -687,9 +689,6 @@ begin
pt1 := pt2;
iPt1 := iPt2;
end;
finally
GPSItems.Unlock;
end;
end;
procedure TMapView.DrawPointOfInterest(const Area: TRealArea; APt: TGPSPointOfInterest);
@ -701,8 +700,6 @@ var
bmp: TBitmap;
w, h: Integer;
begin
GPSItems.Lock;
try
pt := Engine.LonLatToScreen(APt.RealPoint);
// Draw point as symbol from image list ...
@ -746,9 +743,6 @@ begin
end;
extent := DrawingEngine.TextExtent(s);
DrawingEngine.TextOut(pt.X - extent.CX div 2, pt.Y + 5, s);
finally
GPSItems.Unlock;
end;
end;
procedure TMapView.DrawPt(const Area: TRealArea; APt: TGPSPoint);
@ -758,8 +752,6 @@ var
extent: TSize;
s: String;
begin
GPSItems.Lock;
try
if Assigned(FOnDrawGpsPoint) then begin
FOnDrawGpsPoint(Self, DrawingEngine, APt);
exit;
@ -796,6 +788,13 @@ begin
extent := DrawingEngine.TextExtent(s);
DrawingEngine.Textout(Pt.X - extent.CX div 2, Pt.Y + 5, s);
end;
procedure TMapView.DrawGpsObj(const Area: TRealArea; AObj: TGPSObj);
begin
GPSItems.Lock;
try
AObj.Draw(Self, Area);
finally
GPSItems.Unlock;
end;
@ -815,22 +814,25 @@ procedure TMapView.DrawObjects(const TileId: TTileId;
var
Area: TRealArea;
lst: TGPSObjList;
I: Integer;
begin
Area.TopLeft := Engine.ScreenToLonLat(Point(aLeft, aTop));
Area.BottomRight := Engine.ScreenToLonLat(Point(aRight, aBottom));
if GPSItems.Count > 0 then
begin
lst := GPSItems.GetObjectsInArea(Area);
if lst.Count > 0 then
Engine.Jobqueue.AddJob(TDrawObjJob.Create(self, lst, Area), Engine)
else
begin
try
if lst.Count > 0 then
begin
for I := 0 to Pred(lst.Count) do
DrawGpsObj(Area, lst[I]);
end;
finally
FreeAndNil(Lst);
CallAsyncInvalidate;
end;
end
else
CallAsyncInvalidate;
;
end;
procedure TMapView.DoAsyncInvalidate(Data: PtrInt);
@ -839,7 +841,7 @@ Begin
AsyncInvalidate := false;
end;
procedure TMapView.DoDrawStretchedTile(const TileId: TTileId; X, Y: Integer;
procedure TMapView.DoDrawStretchedTile(const TileId: TTileID; X, Y: Integer;
TileImg: TLazIntfImage; const R: TRect);
begin
if Assigned(TileImg) then
@ -850,7 +852,6 @@ begin
if FDebugTiles then
DoDrawTileInfo(TileID, X, Y);
DrawObjects(TileId, X, Y, X + TILE_SIZE, Y + TILE_SIZE);
end;
procedure TMapView.DoDrawTile(const TileId: TTileId; X, Y: integer;
@ -864,7 +865,6 @@ begin
if FDebugTiles then
DoDrawTileInfo(TileID, X, Y);
DrawObjects(TileId, X, Y, X + TILE_SIZE, Y + TILE_SIZE);
end;
procedure TMapView.DoDrawTileInfo(const TileID: TTileID; X, Y: Integer);
@ -877,6 +877,12 @@ begin
DrawingEngine.Line(X, Y + TILE_SIZE, X + TILE_SIZE, Y + TILE_SIZE);
end;
procedure TMapView.DoTileDownloaded(const TileId: TTileId);
begin
// TODO: Include tile information to optimize redraw.
CallAsyncInvalidate;
end;
function TMapView.IsActive: Boolean;
begin
if not(csDesigning in ComponentState) then
@ -911,6 +917,7 @@ begin
FEngine.CacheOnDisk := true;
FEngine.OnDrawTile := @DoDrawTile;
FEngine.OnDrawStretchedTile := @DoDrawStretchedTile;
FEngine.OnTileDownloaded := @DoTileDownloaded;
FEngine.DrawPreviewTiles := True;
FEngine.DrawTitleInGuiThread := false;
FEngine.DownloadEngine := FBuiltinDownloadEngine;
@ -1054,7 +1061,7 @@ end;
procedure TMapView.Redraw;
begin
Engine.Redraw;
Invalidate;
end;
function TMapView.GetVisibleArea: TRealArea;