lazarus-ccr/components/lazmapviewer/source/addons/plugins/markers/mvmarkerplugins.pas

947 lines
28 KiB
ObjectPascal

unit mvMarkerPlugins;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Contnrs,
Graphics, Controls, Forms, LCLIntf,
mvMapViewer, mvDrawingEngine, mvPluginCommon, mvGPSObj, mvGeoMath, mvTypes;
type
{ TMarkerHintPlugin }
{ Event allowing to create a different hint window class for custom drawing
of the hint. }
TMarkerCreateHintWindowEvent = procedure(AMapView: TMapView;
out AHintWindow: THintWindow) of object;
{ Event to define the hint text for the marker at the given point.
Return an empty string when no hint should be displayed. }
TMarkerHintEvent = procedure (AMapView: TMapView; APoint: TGPSPoint;
var AHint: String) of object;
TMarkerHintPlugin = class(TMvMarkerPlugin)
private
const
DEFAULT_HINT_OFFSET_X = 0;
DEFAULT_HINT_OFFSET_Y = 15;
DEFAULT_HIDE_INTERVAL = 1000;
private
FAutoHideHint: Boolean;
FHideInterval: Integer;
FHintOffsetX: Integer;
FHintOffsetY: Integer;
FHintWindow: THintWindow;
FShowHint: Boolean;
FOnCreateHintWindow: TMarkerCreateHintWindowEvent;
FOnHint: TMarkerHintEvent;
protected
function CreateHintWindow(AMapView: TMapView): THintWindow; virtual;
procedure DisplayHint(AMapView: TMapView; APoint: TGPSPoint; X, Y: Integer); virtual;
procedure HideHint; virtual;
protected
procedure MouseMove(AMapView: TMapView; {%H-}AShift: TShiftState; X,Y: Integer;
var Handled: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
published
property AutoHideHint: Boolean read FAutoHideHint write FAutoHideHint default false;
property HideInterval: Integer read FHideInterval write FHideInterval default 0;
property HintOffsetX: Integer read FHintOffsetX write FHintOffsetX default DEFAULT_HINT_OFFSET_X;
property HintOffsetY: Integer read FHintOffsetY write FHintOffsetY default DEFAULT_HINT_OFFSET_Y;
property ShowHint: Boolean read FShowHint write FShowHint default true;
property OnCreateHintWindow: TMarkerCreateHintWindowEvent read FOnCreateHintWindow write FOnCreateHintWindow;
property OnHint: TMarkerHintEvent read FOnHint write FOnHint;
end;
{ TMarkerClickPlugin }
TMarkerCanClickEvent = procedure (AMapView: TMapView; APoint: TGPSPoint; var CanClick: Boolean) of object;
TMarkerClickEvent = procedure (AMapView: TMapView; APoint: TGPSPoint) of object;
TMarkerClickPlugin = class(TMvMarkerPlugin)
private
FCursor: TCursor;
FShift: TShiftState;
FOnCanClick: TMarkerCanClickEvent;
FOnMarkerClick: TMarkerClickEvent;
protected
FMouseDownOnMarker: Boolean;
FMousePoint: TPoint;
FOrigGpsPoint: TGPSPoint;
FSavedCursor: TCursor;
procedure MouseDown(AMapView: TMapView; {%H-}Button: TMouseButton;
AShift: TShiftState; X,Y: Integer; var Handled: Boolean); override;
procedure MouseMove(AMapView: TMapView; {%H-}AShift: TShiftState;
X,Y: Integer; var Handled: Boolean); override;
procedure MouseUp({%H-}AMapView: TMapView; {%H-}Button: TMouseButton;
{%H-}AShift: TShiftState; {%H-}X,{%H-}Y: Integer; var {%H-}Handled: Boolean); override;
procedure SetMapView(AValue: TMapView); override;
public
constructor Create(AOwner: TComponent); override;
published
property Cursor: TCursor read FCursor write FCursor default crHandPoint;
property Shift: TShiftState read FShift write FShift default [ssLeft];
property OnCanClick: TMarkerCanClickEvent read FOnCanClick write FOnCanClick;
property OnMarkerClick: TMarkerClickEvent read FOnMarkerClick write FOnMarkerClick;
end;
{ TMarkerSelectAndDragPlugin }
TMarkerDrawPointEvent = procedure (AMapView: TMapView;
ADrawingEngine: TMvCustomDrawingEngine; AGPSPoint: TGPSPoint;
AScreenPoint: TPoint; AMarkerSize: Integer) of object;
TMarkerClickMode = (mcmAddToSelection, mcmToggleSelection);
TMarkerSelectAndDragPlugin = class(TMarkerClickPlugin)
private
FClickMode: TMarkerClickMode;
FDragCursor: TCursor;
FDragging: Boolean;
FMultiSelect: Boolean;
FSelection: TGPSPointList;
FOrigSelection: array of TRealPoint; // Selection before dragging starts
FOnDrawPoint: TMarkerDrawPointEvent;
FOnSelectionChange: TNotifyEvent;
procedure SetMultiSelect(AValue: Boolean);
protected
procedure AddToSelection(AMapView: TMapView; APoint: TGPSPoint);
procedure DeleteFromList(AMapView: TMapView; APoint: TGPSPoint);
procedure DoSelectionChange(AMapView: TMapView);
procedure DragStart(AMapView: TMapView);
procedure DragTo(AMapView: TMapView; X, Y: Integer);
procedure DragEnd(AMapView: TMapView);
procedure DrawPoint(AMapView: TMapView; ADrawingEngine: TMvCustomDrawingEngine;
AGpsPoint: TGPSPoint; AScreenPoint: TPoint; AMarkerSize: Integer);
procedure DrawSelection(AMapView: TMapView);
procedure MoveSelectionBy(AMapView: TMapView; dx, dy: Integer);
procedure ToggleSelected(AMapView: TMapView; APoint: TGPSPoint);
protected
procedure AfterDrawObjects(AMapView: TMapView; var {%H-}Handled: Boolean); override;
procedure MouseDown(AMapView: TMapView; {%H-}Button: TMouseButton;
AShift: TShiftState; X,Y: Integer; var Handled: Boolean); override;
procedure MouseMove(AMapView: TMapView; {%H-}AShift: TShiftState;
X,Y: Integer; var Handled: Boolean); override;
procedure MouseUp(AMapView: TMapView; {%H-}Button: TMouseButton;
AShift: TShiftState; X,Y: Integer; var Handled: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function ConvertSelectedPointsToMapArea(AMapView: TMapView; ALayer: TMapLayer): TMapArea;
function ConvertSelectedPointsToMapTrack(AMapView: TMapView; ALayer: TMapLayer): TMapTrack;
procedure DeleteSelectedPoints(AMapView: TMapView);
property Selection: TGPSPointList read FSelection;
published
property ClickMode: TMarkerClickMode read FClickMode write FClickMode default mcmAddToSelection;
property DragCursor: TCursor read FDragCursor write FDragCursor default crSizeAll;
property MultiSelect: Boolean read FMultiSelect write SetMultiSelect default false;
property OnDrawPoint: TMarkerDrawPointEvent read FOnDrawPoint write FOnDrawPoint;
property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
end;
{ TDraggableMarkerPlugin }
TDraggableMarkerPlugin = class;
TDraggableMarkerCanMoveEvent = function (Sender : TDraggableMarkerPlugin; AMarker : TGPSPoint) : Boolean of object;
TDraggableMarkerMovedEvent = procedure (Sender : TDraggableMarkerPlugin; AMarker : TGPSPoint; AOrgPosition : TRealPoint) of object;
{ TDraggableMarkerData }
PDraggableMarkerData = ^TDraggableMarkerData;
TDraggableMarkerData = record
FDraggedMarker : TGPSPoint;
FOrgPosition : TRealPoint;
end;
TDraggableMarkerPlugin = class(TMvMultiMapsPlugin)
private
const
DEFAULT_TOLERANCE = 5;
private
FDraggableMarkerCanMoveEvent : TDraggableMarkerCanMoveEvent;
FDraggableMarkerMovedEvent : TDraggableMarkerMovedEvent;
FDragMouseButton: TMouseButton;
FTolerance: Integer;
function GetFirstMarkerAtMousePos(const AMapView: TMapView; const AX, AY : Integer) : TGPSPoint;
function GetDraggedMarker(AMapView : TMapView) : TGPSPoint;
function GetOrgPosition(AMapView : TMapView): TRealPoint;
protected
procedure MouseDown(AMapView: TMapView; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState;
X, Y: Integer; var Handled: Boolean); override;
procedure MouseMove(AMapView: TMapView; {%H-}AShift: TShiftState; X,Y: Integer;
var Handled: Boolean); override;
procedure MouseUp(AMapView: TMapView; {%H-}Button: TMouseButton; {%H-}Shift: TShiftState;
{%H-}X, {%H-}Y: Integer; var Handled: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
procedure Assign(Source: TPersistent); override;
property DraggedMarker[AMapView : TMapView] : TGPSPoint read GetDraggedMarker;
property OrgPosition[AMapView : TMapView] : TRealPoint read GetOrgPosition;
published
property DraggableMarkerCanMoveEvent : TDraggableMarkerCanMoveEvent read FDraggableMarkerCanMoveEvent write FDraggableMarkerCanMoveEvent;
property DraggableMarkerMovedEvent : TDraggableMarkerMovedEvent read FDraggableMarkerMovedEvent write FDraggableMarkerMovedEvent;
property DragMouseButton : TMouseButton read FDragMouseButton write FDragMouseButton default mbLeft;
property Tolerance: Integer read FTolerance write FTolerance default DEFAULT_TOLERANCE;
end;
implementation
uses
Types;
function IfThen(AValue: Boolean; ACursor1, ACursor2: TCursor): TCursor;
begin
if AValue then Result := ACursor1 else Result := ACursor2;
end;
{ TMarkerHintPlugin }
constructor TMarkerHintPlugin.Create(AOwner: TComponent);
begin
inherited;
FHintOffsetX := DEFAULT_HINT_OFFSET_X;
FHintOffsetY := DEFAULT_HINT_OFFSET_Y;
FHideInterval := DEFAULT_HIDE_INTERVAL;
FShowHint := true;
end;
function TMarkerHintPlugin.CreateHintWindow(AMapView: TMapView): THintWindow;
begin
if Assigned(FOnCreateHintWindow) then
FOnCreateHintWindow(AMapView, Result)
else
Result := THintWindow.Create(self);
end;
procedure TMarkerHintPlugin.DisplayHint(AMapView: TMapView; APoint: TGPSPoint;
X, Y: Integer);
var
hintTxt: String;
hintRct: TRect;
hintPt: TPoint;
dx, dy: Integer;
begin
if APoint.Name <> '' then
hintTxt := Format('%s' + LineEnding + '(%s / %s)', [
APoint.Name, LatToStr(APoint.Lat, true), LonToStr(APoint.Lon, true)
])
else
hintTxt := Format('(%s / %s)', [LatToStr(APoint.Lat, true), LonToStr(APoint.Lon, true)]);
if Assigned(FOnHint) then
FOnHint(AMapView, APoint, hintTxt);
if (hintTxt = '') or not FShowHint then
exit;
if not Assigned(FHintWindow) then
FHintWindow := CreateHintWindow(AMapView);
FHintWindow.AutoHide := FAutoHideHint;
FHintWindow.HideInterval := FHideInterval;
hintRct := FHintWindow.CalcHintRect(AMapView.Width, hintTxt, nil);
hintPt := AMapView.ClientToScreen(Point(X, Y));
if FHintOffsetX = -1 then
dx := - hintRct.Width div 2
else
dx := FHintOffsetX;
if FHintOffsetY = -1 then
dy := - hintRct.Height div 2
else
dy := FHintOffsetY;
OffsetRect(hintRct, hintPt.X + dx, hintPt.Y + dy);
FHintWindow.ActivateHint(hintRct, hintTxt);
end;
procedure TMarkerHintPlugin.HideHint;
begin
FreeAndNil(FHintWindow);
end;
procedure TMarkerHintPlugin.MouseMove(AMapView: TMapView; AShift: TShiftState;
X,Y: Integer; var Handled: Boolean);
var
gpsPoint: TGPSPoint;
begin
if Handled then
exit;
gpsPoint := FindNearestMarker(AMapView, X, Y);
if gpsPoint = nil then
HideHint
else
DisplayHint(AMapView, gpsPoint, X, Y);
end;
{ TMarkerClickPlugin }
constructor TMarkerClickPlugin.Create(AOwner: TComponent);
begin
inherited;
FCursor := crHandPoint;
FSavedCursor := crDefault;
FShift := [ssLeft];
end;
procedure TMarkerClickPlugin.MouseDown(AMapView: TMapView; Button: TMouseButton;
AShift: TShiftState; X, Y: Integer; var Handled: Boolean);
var
canClick: Boolean;
begin
if Handled then
exit;
FOrigGPSPoint := FindNearestMarker(AMapView, X, Y);
if Assigned(FOrigGPSPoint) and (AShift = FShift) then
begin
if Assigned(FOnCanClick) then
begin
canClick := true;
FOnCanClick(AMapView, FOrigGPSPoint, canClick);
if not canClick then
exit;
end;
if Assigned(FOnMarkerClick) then
FOnMarkerClick(AMapView, FOrigGPSPoint);
FMouseDownOnMarker := true;
FMousePoint := Point(X, Y);
Handled := true;
end;
end;
procedure TMarkerClickPlugin.MouseMove(AMapView: TMapView;
{%H-}AShift: TShiftState; X,Y: Integer; var Handled: Boolean);
var
gpsPoint: TGPSPoint;
canClick: Boolean;
begin
if Handled then
exit;
gpsPoint := FindNearestMarker(AMapView, X, Y);
if Assigned(gpsPoint) then
begin
canClick := true;
if Assigned(FOnCanClick) then
FOnCanClick(AMapView, gpsPoint, canClick);
end else
canClick := false;
if not FMouseDownOnMarker then
AMapView.Cursor := IfThen(canClick, FCursor, FSavedCursor);
end;
procedure TMarkerClickPlugin.MouseUp(AMapView: TMapView; Button: TMouseButton;
AShift: TShiftState; X, Y: Integer; var Handled: Boolean);
begin
FMouseDownOnMarker := false;
end;
{ Store the original MapView cursor. Is used when the mouse is not over a
clickable point. If no MapView is assigned to the plugin it is assumed that
the MapView has the default cursor. }
procedure TMarkerClickPlugin.SetMapView(AValue: TMapView);
begin
inherited;
if Assigned(MapView) then
FSavedCursor := MapView.Cursor
else
FSavedCursor := crDefault;
end;
{ TMarkerSelectAndDragPlugin }
type
TMarkerData = record
Lat, Lon: Double;
Elevation: Double;
DateTime: TDateTime;
end;
function GPSPointToMarkerData(P: TGPSPoint): TMarkerData;
begin
Result.Lat := P.Lat;
Result.Lon := P.Lon;
Result.Elevation := P.Elevation;
Result.DateTime := P.DateTime;
end;
procedure MarkerDataToGPSPoint(M: TMarkerData; P: TGPSPoint);
begin
P.Lat := M.Lat;
P.Lon := M.Lon;
P.Elevation := M.Elevation;
P.DateTime := M.DateTime;
end;
constructor TMarkerSelectAndDragPlugin.Create(AOwner: TComponent);
begin
inherited;
FDragCursor := crSizeAll;
FSelection := TGPSPointList.Create(false); // false = do not free objects
end;
destructor TMarkerSelectAndDragPlugin.Destroy;
begin
FSelection.Free;
inherited;
end;
procedure TMarkerSelectAndDragPlugin.AddToSelection(AMapView: TMapView;
APoint: TGPSPoint);
var
idx: Integer;
begin
if FMultiSelect then
begin
idx := FSelection.IndexOf(APoint);
if idx > -1 then
FSelection.Move(idx, FSelection.Count-1)
else
FSelection.Add(APoint);
end else
begin
FSelection.Clear;
FSelection.Add(APoint);
end;
DoSelectionChange(AMapView);
end;
function TMarkerSelectAndDragPlugin.ConvertSelectedPointsToMapArea(
AMapView: TMapView; ALayer: TMapLayer): TMapArea;
var
M: TMarkerData;
P: TMapPoint;
begin
if FSelection.Count < 2 then
raise EMvPluginException.Create('Selection must contain at least 3 points');
Result := ALayer.Areas.Add as TMapArea;
while FSelection.Count > 0 do
begin
M := GPSPointToMarkerData(FSelection[0]);
DeleteFromList(AMapView, FSelection[0]);
FSelection.Delete(0);
P := Result.Points.Add as TMapPoint;
MarkerDataToGPSPoint(M, TGPSPoint(P.GPSObj));
end;
Update;
DoSelectionChange(AMapView);
end;
function TMarkerSelectAndDragPlugin.ConvertSelectedPointsToMapTrack(
AMapView: TMapView; ALayer: TMapLayer): TMapTrack;
var
M: TMarkerData;
P: TMapPoint;
begin
if FSelection.Count < 2 then
raise EMvPluginException.Create('Selection must contain at least 2 points');
Result := ALayer.Tracks.Add as TMapTrack;
while FSelection.Count > 0 do
begin
M := GPSPointToMarkerData(FSelection[0]);
DeleteFromList(AMapView, FSelection[0]);
FSelection.Delete(0);
P := Result.Points.Add as TMapPoint;
MarkerDataToGPSPoint(M, TGPSPoint(P.GPSObj));
end;
Update;
DoSelectionChange(AMapView);
end;
procedure TMarkerSelectAndDragPlugin.AfterDrawObjects(AMapView: TMapView;
var {%H-}Handled: Boolean);
begin
inherited;
DrawSelection(AMapView);
end;
procedure TMarkerSelectAndDragPlugin.DeleteSelectedPoints(AMapView: TMapView);
var
i: Integer;
begin
for i := FSelection.Count-1 downto 0 do
begin
DeleteFromList(AMapView, FSelection[i]);
FSelection.Delete(i);
end;
Update;
end;
procedure TMarkerSelectAndDragPlugin.DoSelectionChange(AMapView: TMapView);
begin
if Assigned(FOnSelectionChange) then
FOnSelectionChange(AMapView);
end;
procedure TMarkerSelectAndDragPlugin.DragStart(AMapView: TMapView);
var
i: Integer;
begin
AMapView.Cursor := DragCursor;
FDragging := true;
// Save original selection point coordinates in case they must be restored later.
SetLength(FOrigSelection, FSelection.Count);
for i := 0 to High(FOrigSelection) do
FOrigSelection[i] := FSelection[i].RealPoint;
end;
procedure TMarkerSelectAndDragPlugin.DragTo(AMapView: TMapView; X, Y: Integer);
var
dX, dY: Integer;
begin
if FDragging then
begin
// AMapView.Cursor := DragCursor;
dX := X - FMousePoint.X;
dY := Y - FMousePoint.Y;
MoveSelectionBy(AMapView, dX, dY);
Update;
FMousePoint := Point(X, Y);
end;
end;
procedure TMarkerSelectAndDragPlugin.DragEnd(AMapView: TMapView);
begin
FDragging := false;
AMapView.Cursor := FSavedCursor;
end;
{ Draw the selection marker for the given point. The drawing engine already
has been setup for the correct settings. }
procedure TMarkerSelectAndDragPlugin.DrawPoint(AMapView: TMapView;
ADrawingEngine: TMvCustomDrawingEngine; AGpsPoint: TGPSPoint;
AScreenPoint: TPoint; AMarkerSize: Integer);
begin
if Assigned(FOnDrawPoint) then
FOnDrawPoint(AMapView, ADrawingEngine, AGPSPoint, AScreenPoint, AMarkerSize)
else
ADrawingEngine.Rectangle(
AScreenPoint.X - AMarkerSize,
AScreenPoint.Y - AMarkerSize,
AScreenPoint.X + AMarkerSize,
AScreenPoint.Y + AMarkerSize
);
end;
procedure TMarkerSelectAndDragPlugin.DrawSelection(AMapView: TMapView);
const
MARKER_SIZE = 5;
var
i, j: Integer;
P: TPoint;
markerSize: Integer;
DE: TMvCustomDrawingEngine;
pts: TPointArray;
begin
if FSelection.Count = 0 then
exit;
DE := AMapView.DrawingEngine;
DE.PenColor := clRed;
DE.PenStyle := psSolid;
DE.PenWidth := 2;
DE.BrushColor := clBlack;
DE.BrushStyle := bsSolid;
markerSize := AMapView.Scale96ToFont(MARKER_SIZE);
for i := 0 to FSelection.Count - 1 do
begin
if i = FSelection.Count - 1 then
begin
// The last point is marked as being "focused"
DE.PenWidth := 3;
DE.BrushColor := clLime;
inc(markerSize, 1);
end;
P := AMapView.LatLonToScreen(FSelection[i].RealPoint);
pts := AMapView.CyclicPointsOf(P);
for j := 0 to High(pts) do
DrawPoint(AMapView, DE, FSelection[i], pts[j], markerSize);
end;
end;
procedure TMarkerSelectAndDragPlugin.MoveSelectionBy(AMapView: TMapView; dx, dy: Integer);
var
i: Integer;
P: TPoint;
rPt: TRealPoint;
begin
for i := 0 to FSelection.Count-1 do
begin
P := AMapView.LatLonToScreen(FSelection[i].RealPoint);
P.X := P.X + dx;
P.Y := P.Y + dy;
rPt := AMapView.ScreenToLatLon(P);
FSelection[i].MoveTo(rPt.Lon, rPt.Lat);
end;
end;
procedure TMarkerSelectAndDragPlugin.MouseDown(AMapView: TMapView;
{%H-}Button: TMouseButton; {%H-}AShift: TShiftState;
X, Y: Integer; var Handled: Boolean);
begin
inherited;
if FMouseDownOnMarker then
begin
case FClickMode of
mcmAddToSelection : AddToSelection(AMapView, FOrigGPSPoint);
mcmToggleSelection: ToggleSelected(AMapView, FOrigGPSPoint);
end;
Update;
Handled := true;
end else
begin
FSelection.Clear;
Update;
end;
end;
procedure TMarkerSelectAndDragPlugin.MouseMove(AMapView: TMapView;
{%H-}AShift: TShiftState; X,Y: Integer; var Handled: Boolean);
const
SENSITIVITY = 5;
var
R: TRect;
begin
inherited;
if FMouseDownOnMarker then
begin
if not FDragging then
begin
// The mouse must be moved by more than SENSITIVITY pixels for dragging to
// start
R := Rect(X - SENSITIVITY, Y - SENSITIVITY, X + SENSITIVITY, Y + SENSITIVITY);
if not PtInRect(R, Point(X, Y)) then
begin
FDragging := false;
exit;
end;
DragStart(AMapView);
end;
DragTo(AMapView, X, Y);
Handled := true;
end;
end;
procedure TMarkerSelectAndDragPlugin.MouseUp(AMapView: TMapView;
{%H-}Button: TMouseButton; {%H-}AShift: TShiftState;
X, Y: Integer; var Handled: Boolean);
begin
inherited;
if FDragging then
DragEnd(AMapView);
end;
{ Searches for the given point in all the point lists of the mapviewer
(GPSItems, Layers, Tracks, Areas, POIs). If found, the point is removed
from the list and destroyed. }
procedure TMarkerSelectAndDragPlugin.DeleteFromList(AMapView: TMapView;
APoint: TGPSPoint);
var
i, j, k: Integer;
gpsLayer: TGPSObjectList;
gpsPolyline: TGPSPolyLine;
item: TGPSObj;
p: TMapPoint;
mapLayer: TMapLayer;
mapTrack: TMapTrack;
mapArea: TMapArea;
function IsSamePoint(AItem: TGPSObj): Boolean;
begin
Result := (AItem is TGPSPoint) and TGPSPoint(AItem).RealPoint.Equal(APoint.RealPoint);
end;
begin
// Check the 10 layers of GPSItems
for i := 0 to 9 do
begin
gpsLayer := AMapView.GPSLayer[i];
for j := 0 to gpsLayer.Count-1 do
begin
item := gpsLayer[j];
if IsSamePoint(item) then
begin
gpsLayer.Delete(item);
exit;
end;
if (item is TGPSPolyline) then
begin
gpsPolyLine := TGPSPolyLine(item);
for k := 0 to gpsPolyLine.Points.Count-1 do
begin
item := gpsPolyLine.Points[k];
if IsSamePoint(item) then
begin
gpsPolyLine.Points.Delete(k);
exit;
end;
end;
end;
end;
end;
// Check the map layers
for i := 0 to AMapView.Layers.Count-1 do
begin
mapLayer := AMapView.Layers[i];
// Points of interest?
for j := 0 to mapLayer.PointsOfInterest.Count-1 do
begin
p := mapLayer.PointsOfInterest[j];
if IsSamePoint(p.GPSObj) then
begin
mapLayer.PointsOfInterest.Delete(j);
exit;
end;
end;
// Tracks?
for j := 0 to mapLayer.Tracks.Count-1 do
begin
mapTrack := mapLayer.Tracks[j];
for k := 0 to mapTrack.Points.Count-1 do
begin
p := mapTrack.Points[k];
if IsSamePoint(p.GPSObj) then
begin
mapTrack.Points.Delete(k);
exit;
end;
end;
end;
// Areas?
for j := 0 to mapLayer.Areas.Count-1 do
begin
mapArea := mapLayer.Areas[j];
for k := 0 to mapArea.Points.Count-1 do
begin
p := mapArea.Points[k];
if IsSamePoint(p.GPSObj) then
begin
mapArea.Points.Delete(k);
exit;
end;
end;
end;
end;
end;
procedure TMarkerSelectAndDragPlugin.SetMultiSelect(AValue: Boolean);
begin
if FMultiSelect = AValue then exit;
FMultiSelect := AValue;
if not FMultiSelect then
begin
FSelection.Clear;
FSelection.Add(FOrigGPSPoint);
end;
Update;
end;
procedure TMarkerSelectAndDragPlugin.ToggleSelected(AMapView: TMapView;
APoint: TGPSPoint);
var
idx: Integer;
begin
idx := FSelection.IndexOf(APoint);
if idx = -1 then
begin
if not FMultiSelect then
FSelection.Clear;
FSelection.Add(APoint);
end else
FSelection.Delete(idx);
DoSelectionChange(AMapView);
end;
{ TDraggableMarkerPlugin }
constructor TDraggableMarkerPlugin.Create(AOwner: TComponent);
begin
inherited;
FTolerance := DEFAULT_TOLERANCE;
end;
procedure TDraggableMarkerPlugin.Assign(Source: TPersistent);
begin
if Source is TDraggableMarkerPlugin then
begin
FDraggableMarkerCanMoveEvent := TDraggableMarkerPlugin(Source).DraggableMarkerCanMoveEvent;
FDraggableMarkerMovedEvent := TDraggableMarkerPlugin(Source).DraggableMarkerMovedEvent;
FDragMouseButton := TDraggableMarkerPlugin(Source).DragMouseButton;
FTolerance := TDraggableMarkerPlugin(Source).Tolerance;
end;
inherited;
end;
function TDraggableMarkerPlugin.GetFirstMarkerAtMousePos(const AMapView: TMapView;
const AX, AY: Integer): TGPSPoint;
function FindInList(AGpsList: TGpsObjList): TGpsPoint;
var
i: Integer;
begin
if Assigned(AGpsList) then
for i := AGpsList.Count-1 downto 0 do
begin
if (AGpsList[i] is TGpsPoint) then
begin
Result := TGpsPoint(AGpsList[i]);
if (not Assigned(FDraggableMarkerCanMoveEvent)) or
DraggableMarkerCanMoveEvent(Self, Result)
then
exit;
end;
end;
Result := nil;
end;
var
aArea : TRealArea;
gpsList: TGpsObjList;
layer: TMapLayer;
i : Integer;
begin
Result := Nil;
aArea.TopLeft := AMapView.ScreenToLatLon(Point(AX - FTolerance, AY - FTolerance));
aArea.BottomRight := AMapView.ScreenToLatLon(Point(AX + FTolerance, AY + FTolerance));
// Search in GPSItems for all gps-type-of-points
gpsList := AMapView.GPSItems.GetObjectsInArea(aArea);
try
Result := FindInList(gpsList);
if Result <> nil then
exit;
finally
gpsList.Free;
end;
// Search in all layers for all map-type points
for i := AMapView.Layers.Count-1 downto 0 do
begin
layer := AMapView.Layers[i];
gpsList := layer.GetObjectsInArea(aArea);
try
Result := FindInList(gpsList);
if Result <> nil then
exit;
finally
gpsList.Free;
end;
end;
end;
function TDraggableMarkerPlugin.GetDraggedMarker(AMapView: TMapView): TGPSPoint;
var
lDraggableMarkerData : TDraggableMarkerData;
cnt : Integer;
begin
Result := Nil;
cnt := GetMapViewData(AMapView,lDraggableMarkerData,SizeOf(lDraggableMarkerData));
if (cnt >= SizeOf(lDraggableMarkerData)) then
Result := lDraggableMarkerData.FDraggedMarker;
end;
function TDraggableMarkerPlugin.GetOrgPosition(AMapView : TMapView): TRealPoint;
var
lDraggableMarkerData : TDraggableMarkerData;
cnt : Integer;
begin
Result.InitXY(0.0,0.0);
cnt := GetMapViewData(AMapView,lDraggableMarkerData,SizeOf(lDraggableMarkerData));
if (cnt >= SizeOf(lDraggableMarkerData)) then
Result := lDraggableMarkerData.FOrgPosition;
end;
procedure TDraggableMarkerPlugin.MouseDown(AMapView: TMapView; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer; var Handled: Boolean);
var
lDraggableMarkerData : TDraggableMarkerData;
begin
if Handled then Exit;
if not MapViewEnabled[AMapView] then Exit;
if FDragMouseButton <> Button then Exit;
lDraggableMarkerData.FDraggedMarker := GetFirstMarkerAtMousePos(AMapView,X,Y);
if Assigned(lDraggableMarkerData.FDraggedMarker) then
begin
lDraggableMarkerData.FOrgPosition.Lon:= lDraggableMarkerData.FDraggedMarker.Lon;
lDraggableMarkerData.FOrgPosition.Lat:= lDraggableMarkerData.FDraggedMarker.Lat;
SetMapViewData(AMapView,lDraggableMarkerData,SizeOf(lDraggableMarkerData));
Handled := True;
end;
end;
procedure TDraggableMarkerPlugin.MouseMove(AMapView: TMapView;
AShift: TShiftState; X, Y: Integer; var Handled: Boolean);
var
pt : TPoint;
rpt : TRealPoint;
ele : Double;
dt : TDateTime;
lDraggableMarkerData : TDraggableMarkerData;
cnt : Integer;
begin
cnt := GetMapViewData(AMapView,lDraggableMarkerData,SizeOf(lDraggableMarkerData));
if not MapViewEnabled[AMapView] then Exit;
if (cnt >= SizeOf(lDraggableMarkerData)) and
Assigned(lDraggableMarkerData.FDraggedMarker) then
begin
pt.X := X;
pt.Y := Y;
rpt := AMapView.ScreenToLatLon(pt);
ele := lDraggableMarkerData.FDraggedMarker.Elevation;
dt := lDraggableMarkerData.FDraggedMarker.DateTime;
lDraggableMarkerData.FDraggedMarker.MoveTo(rpt.Lon, rpt.Lat,ele,dt);
AMapView.Invalidate;
Handled := True; // Prevent the dragging of the map!!
end
else
begin
if Assigned(GetFirstMarkerAtMousePos(AMapView,X,Y)) then
begin
AMapView.Cursor := crHandPoint;
Handled := True;
end
else if not Handled then
AMapView.Cursor := crDefault;
end
end;
procedure TDraggableMarkerPlugin.MouseUp(AMapView: TMapView; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer; var Handled: Boolean);
var
lpDraggableMarkerData : PDraggableMarkerData;
begin
if not MapViewEnabled[AMapView] then Exit;
if FDragMouseButton <> Button then Exit;
lpDraggableMarkerData := MapViewDataPtr[AMapView];
if Assigned(lpDraggableMarkerData) and Assigned(lpDraggableMarkerData^.FDraggedMarker) then
begin
if Assigned(FDraggableMarkerMovedEvent) then
FDraggableMarkerMovedEvent(Self,lpDraggableMarkerData^.FDraggedMarker,lpDraggableMarkerData^.FOrgPosition);
Handled := True;
lpDraggableMarkerData^.FDraggedMarker := Nil;
end;
end;
initialization
RegisterPluginClass(TMarkerHintPlugin, 'Marker hint');
RegisterPluginClass(TMarkerClickPlugin, 'Marker click');
RegisterPluginClass(TMarkerSelectAndDragPlugin, 'Marker select and drag');
RegisterPluginClass(TDraggableMarkerPlugin, 'Draggable marker');
end.