LazMapViewer: Fixed DrawPointOfInterest, DrawTrack issues with opacity. Added interactive TMapView point editor into IDE designer (double-click view to show)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9385 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
b026ed55c2
commit
df4eeaaf58
@ -3,27 +3,20 @@ inherited LayersPropertyEditForm: TLayersPropertyEditForm
|
||||
Height = 343
|
||||
Top = 250
|
||||
Width = 320
|
||||
Caption = 'LayersPropertyEditForm'
|
||||
Caption = 'MapView Layers'
|
||||
ClientHeight = 343
|
||||
ClientWidth = 320
|
||||
inherited ToolBar1: TToolBar
|
||||
Height = 52
|
||||
Width = 320
|
||||
inherited DividerToolButton: TToolButton
|
||||
Height = 50
|
||||
end
|
||||
inherited MoveUpButton: TToolButton
|
||||
Left = 116
|
||||
end
|
||||
inherited MoveDownButton: TToolButton
|
||||
Left = 171
|
||||
Height = 40
|
||||
end
|
||||
end
|
||||
inherited CollectionListBox: TListBox
|
||||
Height = 244
|
||||
Top = 52
|
||||
Height = 254
|
||||
Width = 320
|
||||
OnClick = CollectionListBoxClick
|
||||
TopIndex = -1
|
||||
end
|
||||
object Panel1: TPanel[2]
|
||||
Left = 0
|
||||
|
@ -29,7 +29,7 @@ interface
|
||||
uses
|
||||
Classes, SysUtils, Controls, GraphType, Graphics, FPImage, IntfGraphics,
|
||||
Forms, ImgList, LCLVersion, fgl,
|
||||
MvTypes, MvGeoMath, MvGPSObj, MvCache, MvExtraData, MvEngine, MvMapProvider,
|
||||
MvTypes, MvGeoMath, MvGPSObj, mvDragObj, MvCache, MvExtraData, MvEngine, MvMapProvider,
|
||||
MvDownloadEngine, MvDrawingEngine;
|
||||
|
||||
Type
|
||||
@ -39,6 +39,7 @@ Type
|
||||
|
||||
TMapViewOption =
|
||||
(
|
||||
mvoEditorEnabled, // Point/Track editor enabled
|
||||
mvoMouseDragging, // Allow dragging of the map with the mouse
|
||||
mvoMouseZooming, // Allow zooming into the map with the mouse
|
||||
mvoLatLonInDMS // Use Degrees, Minutes and Seconds for Lat/Lon
|
||||
@ -65,6 +66,7 @@ type
|
||||
TMapAreas = class;
|
||||
TGPSTileLayer = class;
|
||||
TGPSComboLayer = class;
|
||||
TMapEditMark = class;
|
||||
|
||||
TPointOfInterestDrawEvent = procedure(Sender: TObject;
|
||||
ADrawer: TMvCustomDrawingEngine; APoint: TPointOfInterest) of object;
|
||||
@ -104,7 +106,7 @@ type
|
||||
function HitTest(constref Area: TRealArea): TMapObjectList; virtual; abstract;
|
||||
property View: TMapView read GetView;
|
||||
property Layer: TMapLayer read GetLayer;
|
||||
PROPERTY GPSObj: TGPSObj read GetGPSObj;
|
||||
property GPSObj: TGPSObj read GetGPSObj;
|
||||
published
|
||||
property Caption: TCaption read FCaption write SetCaption;
|
||||
property Visible: Boolean read FVisible write SetVisible default True;
|
||||
@ -419,6 +421,11 @@ type
|
||||
end;
|
||||
|
||||
|
||||
// Additional (ooCustom) map observer operations
|
||||
TMapObserverCustomOperation = (mooSelectionCompleted, mooStartDrag, mooDrag,
|
||||
mooEndDrag, mooIsDirty);
|
||||
PMapObserverCustomOperation = ^TMapObserverCustomOperation;
|
||||
|
||||
{ TMapView }
|
||||
|
||||
TMapView = class(TCustomControl)
|
||||
@ -428,6 +435,11 @@ type
|
||||
FCenter: TMapCenter;
|
||||
FDownloadEngine: TMvCustomDownloadEngine;
|
||||
FBuiltinDownloadEngine: TMvCustomDownloadEngine;
|
||||
FOnEditDrag: TNotifyEvent;
|
||||
FOnEditEndDrag: TNotifyEvent;
|
||||
FOnEditIsDirty: TNotifyEvent;
|
||||
FOnEditSelectionCompleted: TNotifyEvent;
|
||||
FOnEditStartDrag: TNotifyEvent;
|
||||
FEngine: TMapViewerEngine;
|
||||
FBuiltinDrawingEngine: TMvCustomDrawingEngine;
|
||||
FDrawingEngine: TMvCustomDrawingEngine;
|
||||
@ -450,6 +462,8 @@ type
|
||||
FZoomMin: Integer;
|
||||
FBeforeDrawObjectsEvent: TNotifyEvent;
|
||||
FAfterDrawObjectsEvent: TNotifyEvent;
|
||||
FEditMark: TMapEditMark;
|
||||
FDragger: TDragObj;
|
||||
procedure CallAsyncInvalidate;
|
||||
procedure DoAsyncInvalidate({%H-}Data: PtrInt);
|
||||
procedure DrawObjects(const {%H-}TileId: TTileId; aLeft, aTop, aRight,aBottom: integer);
|
||||
@ -521,7 +535,7 @@ type
|
||||
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
||||
MousePos: TPoint): Boolean; override;
|
||||
procedure DoOnResize; override;
|
||||
function IsActive: Boolean;
|
||||
function IsActive: Boolean; inline;
|
||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
||||
X, Y: Integer); override;
|
||||
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
|
||||
@ -535,6 +549,18 @@ type
|
||||
function CreateLayers: TMapLayers; virtual;
|
||||
procedure UpdateLayers;
|
||||
|
||||
procedure CreateEditor;
|
||||
procedure DoneEditor;
|
||||
|
||||
function EditingEnabled: Boolean; inline;
|
||||
function DraggingEnabled: Boolean; inline;
|
||||
|
||||
procedure DoEditSelectionCompleted(Sender: TObject);
|
||||
procedure DoEditStartDrag(Sender: TObject);
|
||||
procedure DoEditDrag(Sender: TObject);
|
||||
procedure DoEditEndDrag(Sender: TObject);
|
||||
procedure DoEditIsDirty(Sender: TObject);
|
||||
|
||||
procedure ChangeCachePath(AOldLoc: TCacheLocation; ANewPath: String);
|
||||
class function CacheDirectory(ALoc: TCacheLocation; ACustomPath: String): String;
|
||||
|
||||
@ -576,6 +602,7 @@ type
|
||||
property Engine: TMapViewerEngine read FEngine;
|
||||
property GPSItems: TGPSObjectList read GetGPSItems;
|
||||
property GPSLayer[L: Integer]: TGPSObjectList read GetGPSLayer;
|
||||
property EditMark: TMapEditMark read FEditMark;
|
||||
published
|
||||
property Active: boolean read FActive write SetActive default false;
|
||||
property Align;
|
||||
@ -620,6 +647,11 @@ type
|
||||
property OnMouseLeave;
|
||||
property OnMouseMove;
|
||||
property OnMouseUp;
|
||||
property OnEditSelectionCompleted: TNotifyEvent read FOnEditSelectionCompleted write FOnEditSelectionCompleted;
|
||||
property OnEditStartDrag: TNotifyEvent read FOnEditStartDrag write FOnEditStartDrag;
|
||||
property OnEditDrag: TNotifyEvent read FOnEditDrag write FOnEditDrag;
|
||||
property OnEditEndDrag: TNotifyEvent read FOnEditEndDrag write FOnEditEndDrag;
|
||||
property OnEditIsDirty: TNotifyEvent read FOnEditIsDirty write FOnEditIsDirty;
|
||||
end;
|
||||
|
||||
{ TGPSTileLayerBase }
|
||||
@ -690,6 +722,115 @@ type
|
||||
property TileLayer: TGPSTileLayer read FTileLayer;
|
||||
end;
|
||||
|
||||
{ TMapEditMark }
|
||||
|
||||
TMapEditMark = class(TGPSObj)
|
||||
private
|
||||
FMapView: TMapView;
|
||||
FOnDirty: TNotifyEvent;
|
||||
FOnDrag: TNotifyEvent;
|
||||
FOnEndDrag: TNotifyEvent;
|
||||
FOnSelectionCompleted: TNotifyEvent;
|
||||
FOnStartDrag: TNotifyEvent;
|
||||
FRealPt: TRealPoint;
|
||||
FPt: TPoint;
|
||||
FSelection: TMapObjectList;
|
||||
FLit: TMapObjectList;
|
||||
FOrigins: TRealPointArray;
|
||||
FDragStarted: Boolean;
|
||||
FMarquee: Boolean;
|
||||
FMarqueeRect: TRect;
|
||||
FDirty: Boolean;
|
||||
FTruncSelection: Boolean;
|
||||
FClearSelection: Boolean;
|
||||
|
||||
function GetCurrentArea: TMapArea;
|
||||
function GetCurrentPoint: TMapPoint;
|
||||
function GetCurrentTrack: TMapTrack;
|
||||
function GetCursorShape: TCursor;
|
||||
function GetHasSelection: Boolean;
|
||||
|
||||
function AroundPt(X, Y: Integer; APt: TPoint): Boolean;
|
||||
procedure SelectFromMarquee;
|
||||
procedure MarkDirty;
|
||||
public
|
||||
constructor Create(AMapView: TMapView);
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure GetArea(out Area: TRealArea); override;
|
||||
procedure Draw({%H-}AView: TObject; {%H-}Area: TRealArea); override;
|
||||
procedure UpdateFrom(AObjs: TMapObjectList); virtual;
|
||||
|
||||
function ClickableAt({%H-}X, {%H-}Y: Integer): Boolean;
|
||||
function ClickAt(X, Y: Integer) : Boolean;
|
||||
procedure ClearSelection;
|
||||
procedure CompleteSelection;
|
||||
procedure Select(APoint: TMapPoint; ClearFirst: Boolean = False);
|
||||
function IsSelected(AObj: TObject): Boolean;
|
||||
|
||||
procedure DoStartDrag(Sender: TDragObj);
|
||||
procedure DoDrag(Sender: TDragObj);
|
||||
procedure DoEndDrag(Sender: TDragObj);
|
||||
|
||||
property Lon: Double read FRealPt.Lon write FRealPt.Lon;
|
||||
property Lat: Double read FRealPt.Lat write FRealPt.Lat;
|
||||
property RealPt: TRealPoint read FRealPt write FRealPt;
|
||||
|
||||
property CursorShape: TCursor read GetCursorShape;
|
||||
property HasSelection: Boolean read GetHasSelection;
|
||||
property CurrentPoint: TMapPoint read GetCurrentPoint;
|
||||
property CurrentTrack: TMapTrack read GetCurrentTrack;
|
||||
property CurrentArea: TMapArea read GetCurrentArea;
|
||||
property Selection: TMapObjectList read FSelection;
|
||||
property Dirty: Boolean read FDirty write FDirty;
|
||||
|
||||
property OnStartDrag: TNotifyEvent read FOnStartDrag write FOnStartDrag;
|
||||
property OnDrag: TNotifyEvent read FOnDrag write FOnDrag;
|
||||
property OnEndDrag: TNotifyEvent read FOnEndDrag write FOnEndDrag;
|
||||
property OnDirty: TNotifyEvent read FOnDirty write FOnDirty;
|
||||
property OnSelectionCompleted: TNotifyEvent read FOnSelectionCompleted write FOnSelectionCompleted;
|
||||
end;
|
||||
|
||||
{ TMapEditorListFilterEnumerator }
|
||||
|
||||
generic TMapEditorListFilterEnumerator<T: class> = class
|
||||
private
|
||||
type
|
||||
TItemClass = T;
|
||||
private
|
||||
FList: TMapObjectList;
|
||||
FCurrent: TItemClass;
|
||||
FIndex: Integer;
|
||||
public
|
||||
constructor Create(AList: TMapObjectList);
|
||||
function MoveNext: Boolean;
|
||||
property Current: TItemClass read FCurrent;
|
||||
function GetEnumerator: TMapEditorListFilterEnumerator;
|
||||
function Skip(ANum: Integer = 1): TMapEditorListFilterEnumerator;
|
||||
end;
|
||||
|
||||
TMapEditorPointsFilterEnumerator = specialize TMapEditorListFilterEnumerator<TMapPoint>;
|
||||
TMapEditorTracksFilterEnumerator = specialize TMapEditorListFilterEnumerator<TMapTrack>;
|
||||
TMapEditorAreasFilterEnumerator = specialize TMapEditorListFilterEnumerator<TMapArea>;
|
||||
|
||||
{ TMapEditorList }
|
||||
|
||||
TMapEditorList = class helper for TMapObjectList
|
||||
private
|
||||
function GetAreasOnly: TMapEditorAreasFilterEnumerator;
|
||||
function GetPointsOnly: TMapEditorPointsFilterEnumerator;
|
||||
function GetTracksOnly: TMapEditorTracksFilterEnumerator;
|
||||
public
|
||||
function IndexOfObj(const Item: TObject; out Index: Integer): Boolean;
|
||||
function DelIfPresent(const Item: TObject): Boolean;
|
||||
function AddIfNotPresent(const Item: TObject): Boolean; inline;
|
||||
|
||||
property Points: TMapEditorPointsFilterEnumerator read GetPointsOnly;
|
||||
property Tracks: TMapEditorTracksFilterEnumerator read GetTracksOnly;
|
||||
property Areas: TMapEditorAreasFilterEnumerator read GetAreasOnly;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@ -708,6 +849,7 @@ const
|
||||
BASE_Z_POI = BASE_Z_TRACK + RANGE_Z;
|
||||
|
||||
_TILELAYERS_ID_ = -42; // OwnerIDs of the tile layers
|
||||
_MAPEDITOR_ID_ = -42;
|
||||
|
||||
{ Converts a length given in millimeters to screen pixels }
|
||||
function mmToPx(AValue: Double): Integer;
|
||||
@ -881,6 +1023,9 @@ end;
|
||||
|
||||
function TMapArea.HitTest(constref Area: TRealArea): TMapObjectList;
|
||||
begin
|
||||
Result := Nil;
|
||||
if not Visible then
|
||||
Exit;
|
||||
Result := Points.HitTest(Area);
|
||||
if Assigned(Result) then
|
||||
Result.Add(Self);
|
||||
@ -1177,6 +1322,9 @@ end;
|
||||
|
||||
function TMapTrack.HitTest(constref Area: TRealArea): TMapObjectList;
|
||||
begin
|
||||
Result := Nil;
|
||||
if not Visible then
|
||||
Exit;
|
||||
Result := Points.HitTest(Area);
|
||||
if Assigned(Result) then
|
||||
Result.Add(Self);
|
||||
@ -1692,6 +1840,9 @@ end;
|
||||
|
||||
function TMapLayer.HitTest(constref Area: TRealArea): TMapObjectList;
|
||||
begin
|
||||
Result := Nil;
|
||||
if not Visible then
|
||||
Exit;
|
||||
Result := PointsOfInterest.HitTest(Area);
|
||||
Result := TMapObjectList.AddListToResult(Tracks.HitTest(Area), Result);
|
||||
Result := TMapObjectList.AddListToResult(Areas.HitTest(Area), Result);
|
||||
@ -2243,18 +2394,33 @@ procedure TMapView.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
||||
X, Y: Integer);
|
||||
begin
|
||||
inherited MouseDown(Button, Shift, X, Y);
|
||||
if IsActive and (mvoMouseDragging in FOptions) then
|
||||
if Button = mbLeft then
|
||||
|
||||
if EditingEnabled then
|
||||
begin
|
||||
if (Button = mbLeft) and FEditMark.ClickableAt(X, Y) then
|
||||
begin
|
||||
Engine.MouseDown(self,Button,Shift,X,Y);
|
||||
Invalidate;
|
||||
end;
|
||||
FEditMark.ClickAt(X, Y);
|
||||
FDragger.MouseDown(FEditMark, X, Y);
|
||||
end
|
||||
// With editor enabled, dragging is with the middle button
|
||||
else if (Button = mbMiddle) and DraggingEnabled then
|
||||
StartDragging(X, Y);
|
||||
end
|
||||
else
|
||||
// With editor disabled, dragging is with the left button
|
||||
if IsActive and DraggingEnabled then
|
||||
if Button = mbLeft then
|
||||
begin
|
||||
Engine.MouseDown(self,Button,Shift,X,Y);
|
||||
Invalidate;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.MouseUp(Button: TMouseButton; Shift: TShiftState;
|
||||
X, Y: Integer);
|
||||
begin
|
||||
inherited MouseUp(Button, Shift, X, Y);
|
||||
|
||||
if IsActive then
|
||||
if Button = mbLeft then
|
||||
begin
|
||||
@ -2262,17 +2428,54 @@ begin
|
||||
Engine.Redraw;
|
||||
Invalidate;
|
||||
end;
|
||||
|
||||
if EditingEnabled then
|
||||
begin
|
||||
FDragger.MouseUp(X, Y);
|
||||
FEditMark.CompleteSelection;
|
||||
if (Button = mbMiddle)
|
||||
then EndDragging(X, Y)
|
||||
else AbortDragging;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapView.MouseMove(Shift: TShiftState; X, Y: Integer);
|
||||
|
||||
procedure EditorMM;
|
||||
const
|
||||
DELTA = 5;
|
||||
var
|
||||
A: TRealArea;
|
||||
Hits: TMapObjectList;
|
||||
begin
|
||||
A.TopLeft := ScreenToLatLon(Point(X - DELTA, Y - DELTA));
|
||||
A.BottomRight := ScreenToLatLon(Point(X + DELTA, Y + DELTA));
|
||||
FDragger.MouseMove(X, Y);
|
||||
|
||||
// Update hits
|
||||
if not FDragger.InDrag then
|
||||
begin
|
||||
Hits := Layers.HitTest(A);
|
||||
try
|
||||
FEditMark.UpdateFrom(Hits);
|
||||
Screen.Cursor := FEditMark.CursorShape;
|
||||
finally
|
||||
Hits.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
inherited MouseMove(Shift, X, Y);
|
||||
|
||||
if IsActive then
|
||||
begin
|
||||
Engine.MouseMove(self,Shift,X,Y);
|
||||
if Engine.InDrag
|
||||
then Invalidate;
|
||||
end;
|
||||
if EditingEnabled then
|
||||
EditorMM
|
||||
end;
|
||||
|
||||
procedure TMapView.Notification(AComponent: TComponent; Operation: TOperation);
|
||||
@ -2451,6 +2654,7 @@ var
|
||||
trkColor, connColor: TColor;
|
||||
trkWidth, connWidth: Integer;
|
||||
OldOpacity: Single;
|
||||
OldPenStyle: TPenStyle;
|
||||
|
||||
procedure ClipDrawLine(P1, P2: TPoint); inline;
|
||||
begin
|
||||
@ -2480,11 +2684,13 @@ begin
|
||||
end;
|
||||
|
||||
OldOpacity := DrawingEngine.Opacity;
|
||||
OldPenStyle := DrawingEngine.PenStyle;
|
||||
try
|
||||
DrawingEngine.Opacity := trk.Opacity;
|
||||
|
||||
DrawingEngine.PenColor := trkColor;
|
||||
DrawingEngine.PenWidth := trkWidth;
|
||||
DrawingEngine.PenStyle := psSolid;
|
||||
|
||||
// Clipping rectangle
|
||||
if Cyclic then
|
||||
@ -2544,6 +2750,7 @@ begin
|
||||
EndSegm := TSegmentExtraData.MarkOf(trk.Points[I].ExtraData) = smEnd;
|
||||
end;
|
||||
finally
|
||||
DrawingEngine.PenStyle := OldPenStyle;
|
||||
DrawingEngine.Opacity := OldOpacity;
|
||||
end;
|
||||
end;
|
||||
@ -2609,6 +2816,8 @@ var
|
||||
s: String;
|
||||
bmp: TBitmap;
|
||||
w, h: Integer;
|
||||
OldOpacity: Single;
|
||||
OldPenStyle: TPenStyle;
|
||||
|
||||
procedure DrawOne(pt: TPoint);
|
||||
begin
|
||||
@ -2639,8 +2848,13 @@ var
|
||||
begin
|
||||
pt := Engine.LatLonToScreen(APt.RealPoint);
|
||||
|
||||
OldOpacity := DrawingEngine.Opacity;
|
||||
OldPenStyle := DrawingEngine.PenStyle;
|
||||
bmp := Nil;
|
||||
try
|
||||
DrawingEngine.Opacity := 1.0;
|
||||
DrawingEngine.PenStyle := psSolid;
|
||||
|
||||
// Draw point as symbol from image list ...
|
||||
if Assigned(FPOIImages) and (APt.ImageIndex <> -1) and (APt.ImageIndex < FPOIImages.Count) then
|
||||
begin
|
||||
@ -2670,6 +2884,8 @@ begin
|
||||
DrawOne(pt);
|
||||
finally
|
||||
bmp.Free;
|
||||
DrawingEngine.Opacity := OldOpacity;
|
||||
DrawingEngine.PenStyle := OldPenStyle;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2840,6 +3056,7 @@ var
|
||||
I: Integer;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
|
||||
Width := 150;
|
||||
Height := 150;
|
||||
|
||||
@ -2902,6 +3119,9 @@ begin
|
||||
FZoomMin := 1;
|
||||
FZoomMax := 19;
|
||||
Zoom := 1;
|
||||
|
||||
CreateEditor;
|
||||
|
||||
end;
|
||||
|
||||
destructor TMapView.Destroy;
|
||||
@ -2909,6 +3129,7 @@ var
|
||||
I: Integer;
|
||||
begin
|
||||
Active := False;
|
||||
DoneEditor;
|
||||
Engine.Jobqueue.RemoveAsyncCalls(Self);
|
||||
FFont.Free;
|
||||
FreeAndNil(FPOIImage);
|
||||
@ -3202,6 +3423,91 @@ begin
|
||||
FLayers[I].ComboLayer.TileLayer.ParentViewChanged;
|
||||
end;
|
||||
|
||||
procedure TMapView.CreateEditor;
|
||||
begin
|
||||
if Assigned(FEditMark) then
|
||||
DoneEditor;
|
||||
|
||||
FEditMark := TMapEditMark.Create(Self);
|
||||
FEditMark.UpdateFrom(Nil);
|
||||
FGPSItems[High(FGPSItems)].Add(FEditMark, _MAPEDITOR_ID_, MaxInt);
|
||||
FEditMark.Visible := True;
|
||||
|
||||
FEditMark.OnSelectionCompleted := @DoEditSelectionCompleted;
|
||||
FEditMark.OnStartDrag := @DoEditStartDrag;
|
||||
FEditMark.OnDrag := @DoEditDrag;
|
||||
FEditMark.OnEndDrag := @DoEditEndDrag;
|
||||
FEditMark.OnDirty := @DoEditIsDirty;
|
||||
|
||||
FDragger := TDragObj.Create;
|
||||
FDragger.OnDrag := @FEditMark.DoDrag;
|
||||
FDragger.OnEndDrag := @FEditMark.DoEndDrag;
|
||||
end;
|
||||
|
||||
procedure TMapView.DoneEditor;
|
||||
begin
|
||||
if not Assigned(FEditMark) then
|
||||
Exit;
|
||||
FDragger.Free;
|
||||
FGPSItems[High(FGPSItems)].Delete(FEditMark);
|
||||
FEditMark := Nil;
|
||||
end;
|
||||
|
||||
function TMapView.EditingEnabled: Boolean;
|
||||
begin
|
||||
Result := IsActive and (mvoEditorEnabled in Options);
|
||||
end;
|
||||
|
||||
function TMapView.DraggingEnabled: Boolean;
|
||||
begin
|
||||
Result := IsActive and (mvoMouseDragging in FOptions);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoEditSelectionCompleted(Sender: TObject);
|
||||
var
|
||||
What: TMapObserverCustomOperation = mooSelectionCompleted;
|
||||
begin
|
||||
FPONotifyObservers(Self, ooCustom, @What);
|
||||
if Assigned(FOnEditSelectionCompleted) then
|
||||
FOnEditSelectionCompleted(Self);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoEditStartDrag(Sender: TObject);
|
||||
var
|
||||
What: TMapObserverCustomOperation = mooStartDrag;
|
||||
begin
|
||||
FPONotifyObservers(Self, ooCustom, @What);
|
||||
if Assigned(FOnEditStartDrag) then
|
||||
FOnEditStartDrag(Self);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoEditDrag(Sender: TObject);
|
||||
var
|
||||
What: TMapObserverCustomOperation = mooDrag;
|
||||
begin
|
||||
FPONotifyObservers(Self, ooCustom, @What);
|
||||
if Assigned(FOnEditDrag) then
|
||||
FOnEditDrag(Self);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoEditEndDrag(Sender: TObject);
|
||||
var
|
||||
What: TMapObserverCustomOperation = mooEndDrag;
|
||||
begin
|
||||
FPONotifyObservers(Self, ooCustom, @What);
|
||||
if Assigned(FOnEditEndDrag) then
|
||||
FOnEditEndDrag(Self);
|
||||
end;
|
||||
|
||||
procedure TMapView.DoEditIsDirty(Sender: TObject);
|
||||
var
|
||||
What: TMapObserverCustomOperation = mooIsDirty;
|
||||
begin
|
||||
FPONotifyObservers(Self, ooCustom, @What);
|
||||
if Assigned(FOnEditIsDirty) then
|
||||
FOnEditIsDirty(Self);
|
||||
end;
|
||||
|
||||
procedure TMapView.ChangeCachePath(AOldLoc: TCacheLocation; ANewPath: String);
|
||||
var
|
||||
OldPath: String;
|
||||
@ -3407,5 +3713,410 @@ begin
|
||||
FEngine.Redraw;
|
||||
end;
|
||||
|
||||
{ TMapEditorListFilterEnumerator }
|
||||
|
||||
constructor TMapEditorListFilterEnumerator.Create(AList: TMapObjectList);
|
||||
begin
|
||||
FList := AList;
|
||||
FIndex := -1;
|
||||
end;
|
||||
|
||||
function TMapEditorListFilterEnumerator.MoveNext: Boolean;
|
||||
begin
|
||||
repeat Inc(FIndex);
|
||||
until (FIndex >= FList.Count) or (FList[FIndex] is TItemClass);
|
||||
Result := FIndex < FList.Count;
|
||||
if Result then
|
||||
FCurrent := TItemClass(FList[FIndex]);
|
||||
end;
|
||||
|
||||
function TMapEditorListFilterEnumerator.GetEnumerator: TMapEditorListFilterEnumerator;
|
||||
begin
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
function TMapEditorListFilterEnumerator.Skip(ANum: Integer
|
||||
): TMapEditorListFilterEnumerator;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
for I := 1 to ANum do
|
||||
MoveNext;
|
||||
Result := Self;
|
||||
end;
|
||||
|
||||
{ TMapEditMark }
|
||||
|
||||
function TMapEditMark.GetCursorShape: TCursor;
|
||||
begin
|
||||
if Assigned(FLit)
|
||||
then Result := crHandPoint
|
||||
else Result := crDefault;
|
||||
end;
|
||||
|
||||
function TMapEditMark.GetCurrentPoint: TMapPoint;
|
||||
begin
|
||||
if HasSelection
|
||||
then Result := TMapPoint(FSelection[0])
|
||||
else Result := Nil;
|
||||
end;
|
||||
|
||||
function TMapEditMark.GetCurrentArea: TMapArea;
|
||||
var
|
||||
A: TMapArea;
|
||||
Col: TCollection = Nil;
|
||||
begin
|
||||
Result := Nil;
|
||||
if Assigned(GetCurrentPoint) then
|
||||
Col := GetCurrentPoint.Collection;
|
||||
for A in FSelection.Areas do
|
||||
if Col = A.Points then
|
||||
Exit(A);
|
||||
end;
|
||||
|
||||
function TMapEditMark.GetCurrentTrack: TMapTrack;
|
||||
var
|
||||
T: TMapTrack;
|
||||
Col: TCollection = Nil;
|
||||
begin
|
||||
Result := Nil;
|
||||
if Assigned(GetCurrentPoint) then
|
||||
Col := GetCurrentPoint.Collection;
|
||||
for T in FSelection.Tracks do
|
||||
if Col = T.Points then
|
||||
Exit(T);
|
||||
end;
|
||||
|
||||
function TMapEditMark.GetHasSelection: Boolean;
|
||||
begin
|
||||
Result := (FSelection.Count > 0);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.CompleteSelection;
|
||||
var
|
||||
P: TMapPoint;
|
||||
T: TObject;
|
||||
begin
|
||||
if FClearSelection then
|
||||
begin
|
||||
FSelection.Clear;
|
||||
FClearSelection := False;
|
||||
FTruncSelection := False;
|
||||
end
|
||||
else if FTruncSelection and (FSelection.Count > 1) then
|
||||
begin
|
||||
// Find the container track/area for the first point
|
||||
T := CurrentTrack;
|
||||
if T = Nil then
|
||||
T := CurrentArea;
|
||||
|
||||
// Delete everything except the first point
|
||||
FSelection.DeleteRange(1, FSelection.Count - 1);
|
||||
|
||||
// Re-insert the container track/area
|
||||
if Assigned(T) then
|
||||
FSelection.Add(T);
|
||||
|
||||
FTruncSelection := False;
|
||||
end;
|
||||
if Assigned(FOnSelectionCompleted) then
|
||||
FOnSelectionCompleted(Self);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.Select(APoint: TMapPoint; ClearFirst: Boolean);
|
||||
begin
|
||||
if ClearFirst then
|
||||
FSelection.Clear;
|
||||
FSelection.Insert(0, APoint);
|
||||
FMapView.Invalidate;
|
||||
end;
|
||||
|
||||
function TMapEditMark.IsSelected(AObj: TObject): Boolean;
|
||||
begin
|
||||
Result := FSelection.IndexOf(AObj) >= 0;
|
||||
end;
|
||||
|
||||
function TMapEditMark.AroundPt(X, Y: Integer; APt: TPoint): Boolean;
|
||||
begin
|
||||
Result := InRange(X, APt.X - 5, APt.X + 5) and
|
||||
InRange(Y, APt.Y - 5, APt.Y + 5);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.SelectFromMarquee;
|
||||
var
|
||||
Hits: TMapObjectList;
|
||||
RA: TRealArea;
|
||||
O: TObject;
|
||||
begin
|
||||
RA.TopLeft := FMapView.ScreenToLatLon(FMarqueeRect.TopLeft);
|
||||
RA.BottomRight := FMapView.ScreenToLatLon(FMarqueeRect.BottomRight);
|
||||
Hits := FMapView.Layers.HitTest(RA);
|
||||
if Assigned(Hits) then
|
||||
try
|
||||
for O in Hits do
|
||||
FSelection.AddIfNotPresent(O);
|
||||
FMapView.Invalidate;
|
||||
finally
|
||||
Hits.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.MarkDirty;
|
||||
begin
|
||||
if not FDirty then
|
||||
begin
|
||||
FDirty := True;
|
||||
if Assigned(FOnDirty) then
|
||||
FOnDirty(Self);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TMapEditMark.Create(AMapView: TMapView);
|
||||
begin
|
||||
FMapView := AMapView;
|
||||
FSelection := TMapObjectList.Create;
|
||||
end;
|
||||
|
||||
destructor TMapEditMark.Destroy;
|
||||
begin
|
||||
FSelection.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.GetArea(out Area: TRealArea);
|
||||
begin
|
||||
Area.Init(FRealPt, FRealPt);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.Draw(AView: TObject; Area: TRealArea);
|
||||
var
|
||||
View: TMapView;
|
||||
DE: TMvCustomDrawingEngine;
|
||||
Trk: TMapTrack;
|
||||
Ar: TMapArea;
|
||||
TrkPoint: TMapPoint;
|
||||
I: Integer;
|
||||
|
||||
procedure MarkMP(P: TMapPoint);
|
||||
begin
|
||||
with View.LatLonToScreen(P.Latitude, P.Longitude) do
|
||||
DE.Ellipse(X - 4, Y - 4, X + 4, Y + 4);
|
||||
end;
|
||||
|
||||
begin
|
||||
View := TMapView(AView);
|
||||
DE := View.DrawingEngine;
|
||||
FPt := View.LatLonToScreen(RealPt);
|
||||
|
||||
DE.PenStyle := psSolid;
|
||||
DE.PenColor := clRed;
|
||||
DE.PenWidth := 3;
|
||||
DE.BrushColor := clGray;
|
||||
DE.BrushStyle := bsSolid;
|
||||
|
||||
if Assigned(FLit) then
|
||||
DE.Rectangle(FPt.X - 5, FPt.Y - 5, FPt.X + 5, FPt.Y + 5);
|
||||
|
||||
if HasSelection then
|
||||
begin
|
||||
DE.PenWidth := 2;
|
||||
DE.BrushStyle := bsClear;
|
||||
|
||||
for Trk in FSelection.Tracks do
|
||||
for I := 0 to Pred(Trk.Points.Count) do
|
||||
MarkMP(Trk.Points[I]);
|
||||
|
||||
for Ar in FSelection.Areas do
|
||||
for I := 0 to Pred(Ar.Points.Count) do
|
||||
MarkMP(Ar.Points[I]);
|
||||
|
||||
DE.PenWidth := 2;
|
||||
DE.BrushColor := clBlack;
|
||||
DE.BrushStyle := bsSolid;
|
||||
|
||||
for TrkPoint in FSelection.Points.Skip(1) do
|
||||
with View.LatLonToScreen(TrkPoint.Latitude, TrkPoint.Longitude) do
|
||||
DE.Rectangle(X - 5, Y - 5, X + 5, Y + 5);
|
||||
|
||||
DE.BrushColor := clLime;
|
||||
TrkPoint := (FSelection[0] as TMapPoint);
|
||||
with View.LatLonToScreen(TrkPoint.Latitude, TrkPoint.Longitude) do
|
||||
DE.Rectangle(X - 5, Y - 5, X + 5, Y + 5);
|
||||
end;
|
||||
|
||||
if FMarquee then
|
||||
begin
|
||||
DE.PenStyle := psSolid;
|
||||
DE.PenWidth := 1;
|
||||
DE.PenColor := clGray;
|
||||
DE.BrushStyle := bsClear;
|
||||
|
||||
with FMarqueeRect do
|
||||
DE.Rectangle(Left, Top, Right, Bottom);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.UpdateFrom(AObjs: TMapObjectList);
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
if Assigned(AObjs) and (AObjs.Count > 0) and (AObjs[0] is TMapPoint) then
|
||||
begin
|
||||
// Same point?
|
||||
if Assigned(FLit) and (AObjs[0] = FLit[0]) then
|
||||
Exit;
|
||||
Lat := TMapPoint(AObjs[0]).Latitude;
|
||||
Lon := TMapPoint(AObjs[0]).Longitude;
|
||||
FLit.Free;
|
||||
FLit := TMapObjectList.Create(AObjs);
|
||||
end
|
||||
else
|
||||
FreeAndNil(FLit);
|
||||
FMapView.Invalidate;
|
||||
end;
|
||||
|
||||
function TMapEditMark.ClickableAt(X, Y: Integer): Boolean;
|
||||
begin
|
||||
Result := True; //Visible;
|
||||
end;
|
||||
|
||||
function TMapEditMark.ClickAt(X, Y: Integer): Boolean;
|
||||
var
|
||||
O: TObject;
|
||||
H: Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
if Assigned(FLit) and AroundPt(X, Y, FPt) then
|
||||
begin
|
||||
FTruncSelection := not (ssCtrl in GetKeyShiftState);
|
||||
H := FSelection.DelIfPresent(FLit[0]);
|
||||
FTruncSelection := not H and FTruncSelection;
|
||||
FSelection.Insert(0, FLit[0]);
|
||||
for O in FLit do
|
||||
FSelection.AddIfNotPresent(O);
|
||||
FreeAndNil(FLit);
|
||||
end
|
||||
else
|
||||
FClearSelection := not (ssCtrl in GetKeyShiftState);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.ClearSelection;
|
||||
begin
|
||||
FClearSelection := True;
|
||||
CompleteSelection;
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.DoStartDrag(Sender: TDragObj);
|
||||
var
|
||||
I: Integer = 0;
|
||||
P: TMapPoint;
|
||||
begin
|
||||
FLit := Nil;
|
||||
CompleteSelection;
|
||||
SetLength(FOrigins, FSelection.Count);
|
||||
for P in FSelection.Points do
|
||||
begin
|
||||
FOrigins[I] := RealPoint(P.Latitude, P.Longitude);
|
||||
Inc(I);
|
||||
end;
|
||||
SetLength(FOrigins, I); // why bother?
|
||||
FMarquee := not AroundPt(Sender.StartX, Sender.StartY, FPt);
|
||||
if FMarquee then
|
||||
begin
|
||||
FMarqueeRect := Rect(Sender.StartX, Sender.StartY, Sender.EndX, Sender.EndY);
|
||||
Self.RealPt := FMapView.Center; // keep it in view
|
||||
FMapView.Invalidate;
|
||||
end;
|
||||
FDragStarted := True;
|
||||
if Assigned(FOnStartDrag) then
|
||||
FOnStartDrag(Self);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.DoDrag(Sender: TDragObj);
|
||||
var
|
||||
I: Integer = 0;
|
||||
RPt: TRealPoint;
|
||||
MapPoint: TMapPoint;
|
||||
begin
|
||||
if not FDragStarted then
|
||||
DoStartDrag(Sender);
|
||||
if FMarquee then
|
||||
begin
|
||||
FMarqueeRect := Rect(Sender.StartX, Sender.StartY, Sender.EndX, Sender.EndY);
|
||||
FMarqueeRect.NormalizeRect;
|
||||
FMapView.Invalidate;
|
||||
Exit;
|
||||
end;
|
||||
for MapPoint in FSelection.Points do
|
||||
begin
|
||||
MarkDirty;
|
||||
Rpt := FMapView.ScreenToLatLon(FMapView.LatLonToScreen(FOrigins[I]) +
|
||||
Point(Sender.OfsX, Sender.OfsY));
|
||||
MapPoint.Longitude := RPt.Lon;
|
||||
MapPoint.Latitude := RPt.Lat;
|
||||
Inc(I);
|
||||
end;
|
||||
//FMapView.Invalidate; // No need to
|
||||
if Assigned(FOnDrag) then
|
||||
FOnDrag(Self);
|
||||
end;
|
||||
|
||||
procedure TMapEditMark.DoEndDrag(Sender: TDragObj);
|
||||
begin
|
||||
if FMarquee then
|
||||
begin
|
||||
SelectFromMarquee;
|
||||
FMarquee := False;
|
||||
end;
|
||||
SetLength(FOrigins, 0);
|
||||
FDragStarted := False;
|
||||
if Assigned(FOnEndDrag) then
|
||||
FOnEndDrag(Self);
|
||||
end;
|
||||
|
||||
{ TMapEditorList }
|
||||
|
||||
function TMapEditorList.GetAreasOnly: TMapEditorAreasFilterEnumerator;
|
||||
begin
|
||||
Result := TMapEditorAreasFilterEnumerator.Create(Self);
|
||||
end;
|
||||
|
||||
function TMapEditorList.GetPointsOnly: TMapEditorPointsFilterEnumerator;
|
||||
begin
|
||||
Result := TMapEditorPointsFilterEnumerator.Create(Self);
|
||||
end;
|
||||
|
||||
function TMapEditorList.GetTracksOnly: TMapEditorTracksFilterEnumerator;
|
||||
begin
|
||||
Result := TMapEditorTracksFilterEnumerator.Create(Self);
|
||||
end;
|
||||
|
||||
function TMapEditorList.IndexOfObj(const Item: TObject; out Index: Integer
|
||||
): Boolean;
|
||||
begin
|
||||
Index := IndexOf(Item);
|
||||
Result := Index >= 0;
|
||||
end;
|
||||
|
||||
function TMapEditorList.DelIfPresent(const Item: TObject): Boolean;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := False;
|
||||
while IndexOfObj(Item, I) do
|
||||
begin
|
||||
Result := True;
|
||||
Delete(I);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMapEditorList.AddIfNotPresent(const Item: TObject): Boolean;
|
||||
begin
|
||||
Result := IndexOf(Item) < 0;
|
||||
if Result then
|
||||
Add(Item);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
380
components/lazmapviewer/source/mvmapviewerpatheditform.lfm
Normal file
380
components/lazmapviewer/source/mvmapviewerpatheditform.lfm
Normal file
@ -0,0 +1,380 @@
|
||||
object MapViewerPathEditForm: TMapViewerPathEditForm
|
||||
Left = 370
|
||||
Height = 90
|
||||
Top = 31
|
||||
Width = 292
|
||||
BorderStyle = bsToolWindow
|
||||
Caption = 'MapViewer Path Editor'
|
||||
ClientHeight = 90
|
||||
ClientWidth = 292
|
||||
OnClose = FormClose
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
OnShow = FormShow
|
||||
object pnlFrame: TPanel
|
||||
Left = 0
|
||||
Height = 90
|
||||
Top = 0
|
||||
Width = 292
|
||||
Align = alClient
|
||||
BevelColor = clRed
|
||||
ClientHeight = 90
|
||||
ClientWidth = 292
|
||||
TabOrder = 0
|
||||
object pnlTools: TPanel
|
||||
Left = 1
|
||||
Height = 33
|
||||
Top = 1
|
||||
Width = 290
|
||||
Align = alTop
|
||||
ClientHeight = 33
|
||||
ClientWidth = 290
|
||||
ParentShowHint = False
|
||||
ShowHint = True
|
||||
TabOrder = 0
|
||||
object btnSelect: TSpeedButton
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 2
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actSelect
|
||||
AllowAllUp = True
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Left = 2
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 0
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnNewTP: TSpeedButton
|
||||
AnchorSideLeft.Control = btnSelect
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 28
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actNewTP
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 1
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnDelTP: TSpeedButton
|
||||
AnchorSideLeft.Control = btnNewTP
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 54
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actDelTP
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 2
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnNewPOI: TSpeedButton
|
||||
AnchorSideLeft.Control = btnDelTP
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 82
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actNewPOI
|
||||
AllowAllUp = True
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Left = 2
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 5
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnNewArea: TSpeedButton
|
||||
AnchorSideLeft.Control = btnNewPOI
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 108
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actNewArea
|
||||
AllowAllUp = True
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 6
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnNewTrack: TSpeedButton
|
||||
AnchorSideLeft.Control = btnNewArea
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 134
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actNewTrack
|
||||
AllowAllUp = True
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 3
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnZoomIn: TSpeedButton
|
||||
AnchorSideLeft.Control = btnNewTrack
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 162
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actZoomIn
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Left = 2
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 7
|
||||
ShowCaption = False
|
||||
end
|
||||
object btnZoomOut: TSpeedButton
|
||||
AnchorSideLeft.Control = btnZoomIn
|
||||
AnchorSideLeft.Side = asrBottom
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideBottom.Control = pnlTools
|
||||
AnchorSideBottom.Side = asrBottom
|
||||
Left = 188
|
||||
Height = 27
|
||||
Top = 3
|
||||
Width = 26
|
||||
Action = actZoomOut
|
||||
Anchors = [akTop, akLeft, akBottom]
|
||||
BorderSpacing.Top = 2
|
||||
BorderSpacing.Bottom = 2
|
||||
Images = ilImages
|
||||
ImageIndex = 8
|
||||
ShowCaption = False
|
||||
end
|
||||
end
|
||||
object lblSelectedPt: TLabel
|
||||
AnchorSideLeft.Control = pnlFrame
|
||||
AnchorSideTop.Side = asrCenter
|
||||
Left = 1
|
||||
Height = 16
|
||||
Top = 39
|
||||
Width = 82
|
||||
Alignment = taRightJustify
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
AutoSize = False
|
||||
BorderSpacing.Right = 5
|
||||
Caption = 'Selection'
|
||||
ParentColor = False
|
||||
end
|
||||
object lblSelectedLayer: TLabel
|
||||
AnchorSideLeft.Control = pnlFrame
|
||||
AnchorSideTop.Side = asrCenter
|
||||
Left = 1
|
||||
Height = 16
|
||||
Top = 63
|
||||
Width = 82
|
||||
Alignment = taRightJustify
|
||||
Anchors = [akTop, akLeft, akRight]
|
||||
AutoSize = False
|
||||
BorderSpacing.Right = 5
|
||||
Caption = 'On Layer'
|
||||
ParentColor = False
|
||||
end
|
||||
object cbSelectedPt: TEdit
|
||||
AnchorSideTop.Control = pnlTools
|
||||
AnchorSideTop.Side = asrBottom
|
||||
AnchorSideRight.Control = pnlFrame
|
||||
AnchorSideRight.Side = asrBottom
|
||||
Left = 87
|
||||
Height = 22
|
||||
Top = 37
|
||||
Width = 201
|
||||
Anchors = [akTop, akRight]
|
||||
AutoSize = False
|
||||
BorderSpacing.Around = 3
|
||||
BorderStyle = bsNone
|
||||
ParentColor = True
|
||||
ParentShowHint = False
|
||||
ReadOnly = True
|
||||
ShowHint = True
|
||||
TabOrder = 1
|
||||
end
|
||||
object cbSelectedLayer: TEdit
|
||||
AnchorSideTop.Control = cbSelectedPt
|
||||
AnchorSideTop.Side = asrBottom
|
||||
AnchorSideRight.Control = pnlFrame
|
||||
AnchorSideRight.Side = asrBottom
|
||||
Left = 87
|
||||
Height = 22
|
||||
Top = 62
|
||||
Width = 201
|
||||
Anchors = [akTop, akRight]
|
||||
AutoSize = False
|
||||
BorderSpacing.Around = 3
|
||||
BorderStyle = bsNone
|
||||
ParentColor = True
|
||||
ParentShowHint = False
|
||||
ReadOnly = True
|
||||
ShowHint = True
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
object alEditActions: TActionList
|
||||
Images = ilImages
|
||||
Left = 120
|
||||
Top = 40
|
||||
object actZoomIn: TAction
|
||||
Caption = 'Zoom In'
|
||||
Hint = 'Zoom In'
|
||||
ImageIndex = 7
|
||||
OnExecute = actZoomInExecute
|
||||
end
|
||||
object actZoomOut: TAction
|
||||
Caption = 'actZoomOut'
|
||||
Hint = 'Zoom Out'
|
||||
ImageIndex = 8
|
||||
OnExecute = actZoomOutExecute
|
||||
end
|
||||
object actNewPOI: TAction
|
||||
AutoCheck = True
|
||||
Caption = 'New POI'
|
||||
Hint = 'New POI from current point'
|
||||
ImageIndex = 5
|
||||
OnExecute = actNewPOIExecute
|
||||
end
|
||||
object actNewTrack: TAction
|
||||
AutoCheck = True
|
||||
Caption = 'New Track'
|
||||
Hint = 'New Track from selected'
|
||||
ImageIndex = 3
|
||||
OnExecute = actNewTrackExecute
|
||||
end
|
||||
object actNewArea: TAction
|
||||
AutoCheck = True
|
||||
Caption = 'New Area'
|
||||
Hint = 'New Area from selected'
|
||||
ImageIndex = 6
|
||||
OnExecute = actNewAreaExecute
|
||||
end
|
||||
object actNewTP: TAction
|
||||
Caption = 'New Track Point'
|
||||
Hint = 'Insert new point'
|
||||
ImageIndex = 1
|
||||
OnExecute = actNewTPExecute
|
||||
end
|
||||
object actDelTP: TAction
|
||||
Caption = 'Del Track Point'
|
||||
Hint = 'Delete current point'
|
||||
ImageIndex = 2
|
||||
OnExecute = actDelTPExecute
|
||||
end
|
||||
object actSelect: TAction
|
||||
AutoCheck = True
|
||||
Caption = 'Select'
|
||||
Checked = True
|
||||
Hint = 'Select tool'
|
||||
ImageIndex = 0
|
||||
OnExecute = actSelectExecute
|
||||
end
|
||||
end
|
||||
object ilImages: TImageList
|
||||
Left = 192
|
||||
Top = 40
|
||||
Bitmap = {
|
||||
4C7A090000001000000010000000E60700000000000078DAED580D6C13F7154F
|
||||
0BEA87A05D3F0085323588064A23489DB1585BE9A4691B5369629385B8B4DBD4
|
||||
40B795765AA5314D8CD0A1DA673B1FE2435508495ADA8EB13A6D4D69853A8203
|
||||
1B29049A94C0285D52C850B77EC449C02626B1E32538F6DBEF5D7CE1E2F8CEE7
|
||||
6B577553FFD24F77F7FEEFF7BEFEEFDD39C9C810D7358220F4020F67E85BD758
|
||||
AD56DAB66D5BA8BCBCBC06F753D3E5DB6CB6D8C8C808B95CAE604545C549D8C8
|
||||
4C974F58B1588C5A5A5A2288C30F1BDF4A972FADF3E7CF13E218B2DBED4FEAE1
|
||||
F3EAEFEFA7EAEA6AAEC91ED4E6C674F9BC229108EDDDBB7708B19C73381C59E9
|
||||
F2A5D5DEDE1E713A9D03D0FB7E3A7CAE436767A788FDFBF7137A24867C7EAB85
|
||||
1F8D4609BA23959595A7366FDE7C480264BBD5F83E9F4F04AFC3870F5F41EEBB
|
||||
B4D6BFAFAF8F7D8677ECD831C8BD100E87C567F4C21DA9F8ECB3AAAA2A84332F
|
||||
46CCE7BABABAC4183C1ECF086C6C4FD5FFE00CC1CE4A16E06AAAA9A911630806
|
||||
8384DA8760FB2615FF61C02297710C1D1D1D140A8544DB2AE79F01FF3724917D
|
||||
1371F7211FEE1F87D66102EF5AA004D807740317800E602B90A3C6E53E874E23
|
||||
7002F994E2BA10BE6FC57511B001F002EB393F05DFCF020D4AEF10E433936B2D
|
||||
41BEE7114C24874A7E8A7CB7DB3D45BAD7C34F76AF75A9C5EFB1151E3F20988E
|
||||
693CBF4AE080948BDCB646FE54E010CE6F931E3E2FF4EA1CD8B808CCD5C3E77C
|
||||
13EB9108B57AF05E2ABEC7666A4951875CE08C5AFC4ABD10DF13805AAD7C6001
|
||||
303DEE97BFA31F4BEF2D8DFC0F8161E06C9C9F39A11E29F2FD5F9FFF3A470FC9
|
||||
91EEFC32479A19BDFC64F75A97D6F835CE7FB5DB4D53EA1CBD2FD63B7A9E98E0
|
||||
C7E97DACD6DEF347843F5565FE6F430C0DF158A2B576EF9A316EEF6A7E16E5CE
|
||||
9E7AB538EAED3DC5D08B483680E781D1F873B8AEDCBB34552EF5F6DE12990D09
|
||||
A36C5B6B3D6A1D3D2FC8F99CBBE63391E77B15B13A7BCFDA54F35FEFEC7D54C6
|
||||
1D46BD9EC6F5DF523D785FCEC777FA2ED9AC64D63B7A5F8AEB46107391188FBD
|
||||
AF10CF57E2F25D09F3CFEF0BFEADF32FCCDE93105DCBB9D73A7B7E3A212E8777
|
||||
559DC3FB07EE0FA5F96FB217967884C27D4D82A91BEF9D0B408747306F6DB4AE
|
||||
509D7FF736CB8DD06D044E34D9CCA54D56D3C23F5714DCDA642D58045B1B20F7
|
||||
C2CE7AA2E4F38FF7FEB31EBBA9A1D9FADDA4BDD958BE7CA6DA371EB27E8FB378
|
||||
B6D6EFECA4BC0553B8B17AF9F57AF863F19B8E34D94D457A67D763373F8077F5
|
||||
875C33DD366CA62D880DDF7FCB143D7CAE3DCEFE1062D9A43786B71C857310C3
|
||||
C503D6A2B9BAF3100AAB904BA55E7E9363C57DE0BFAB977FC06ACE452F9EF90C
|
||||
BD2000B55AF9FBAD0F2E68B65AA68B7E6DE61AC83E3E6835DFA195CF7D83EB30
|
||||
7096F9B09799F105AC0FEEEC2FE8CCBAD40D7C0A2C4F97CFBC0FB22E91883BFD
|
||||
9FC8F7725FA6C2C52E3AB1B881427CBDB7810AB4F2999BDB409488452E2A4AE0
|
||||
2F6FC90D10A323EBD203E37C17B5C73965B9BB691AFC6FE467C432A9A724DB13
|
||||
642E1A61598E9BAEE3E7EC46BA5ED473D1B026BE46D9577C6DB5E63E3D163FE7
|
||||
C43E95CE9ACF1836A6E3FA74E259ABF529F7A542AF3DA8852FD9607F8825C857
|
||||
3957EA53D106B8F23EFD3CD74F8C74B3C5401B2D86E8C992BC688881FBF61203
|
||||
9599EFA69BD4B8967BC95862887A2D79314A8E68F74306CA4FCA5D4C77633FC0
|
||||
7A6B9705E988FB6DF2FFE3151147F734D353A6CB928DC0AA5C5A30896F88FE55
|
||||
E25E38FB1A85BA774FC0C573AF8A7BAC839C0EC9B9ABF2E81E2946F6CBFA2DAF
|
||||
6FA0D5F7DD45E7DF3F4503FE8F4459F3AB47AEE68278C77D7F831E97E41C2FEB
|
||||
AE5E9A4DE60533A8F3641B75BDD72ECA784FD2433D7F2EF1B9B64A7CC69AFBB3
|
||||
45996F22BF4C56F75F4872AE15EB1E7B63A36883B9C7DFDC38397E03FD4CE217
|
||||
1B68BE24E73A73AD12EBD7879AAE5D161AE7279E01CEE5A0B4C775665FD2F9F1
|
||||
BD9C0BDDA6C4F31B8B217A49B977C6B9D0A1ECA43DB484EE471F0C2972790F3A
|
||||
AA3D6CA065F0319CC8455F5F419D0BB4CCD0CA3C2A86AFD1716E5E345A924769
|
||||
FD6F1DBE56238E1803DCB57A661975FA1D23E34BBCDE796CAE1BA034609EF0F7
|
||||
5941E6E32CA7D13EA2C8A7EA800EEB2684708BC8F73712753F47F4C97665F4BA
|
||||
92C650F58359EB581EEDAAA5D13382323AAA2836F44FC518C25DBB69A06D135D
|
||||
3EBE5E11C1D35B5463089CA8205FF3AF15E16FD94091CB5D936270AF9CF3C8D1
|
||||
D22C0A1C13C8E7F9A522FC7FF90D0D9E799E5877C26FED47BE4E117F27F9F73D
|
||||
41BED74B1511385846AC6BFDCEEDEB24EE9EA2D96680026F3C45BE177FA408FF
|
||||
9F7E4C83CD55C4BA5C3389FFC20F6750C47B8AFCDB0BC9B7E57B8A08EC5A43AC
|
||||
FB2BC3CDE3BEB72CFD9A19A0D03E2B5DDE59AA0AD6615DB9EF32C3B4377F9F37
|
||||
8DB4E2A17937AC4B38FB79C0923470CB7F6B1683C7BF3D6BA8CDE808B71A4F0F
|
||||
B51A438C709BF16F90D9794F8D1B7ED768196ACB1F843E2503EFC14E8922B7D5
|
||||
1853E28EDB804EA28DB19827FB7D67C56C11936DE40F0C1E35CC94F862BE497C
|
||||
29F1C772310AE3B1B7E6BF972E9F6B7AD57F7E3091A304792D65FCC1B4F9A8C1
|
||||
D5F88DA73F5BFC467BDAF56BCDB7E93DBF309FDFC92533E43DC03DA1A57F1803
|
||||
3B73BA2F3A164EFAFFD0988DFC01452EFBDD99F351C03E9F0242F6D96436B8AF
|
||||
B837C26DF9A7F85CC7CE16F7C897631E7466CF0CD8B3DF57B39172469F99372B
|
||||
20CCFF3BDBE817B2B7EA9A73D8602E3D9373DDFFEBFC2BDBD036FFAA3634CC7F
|
||||
0A7CE9E75F7BFCC9E73FC519D8F49EDF57F3FFF9CEFF7F002E39D971
|
||||
}
|
||||
end
|
||||
end
|
597
components/lazmapviewer/source/mvmapviewerpatheditform.pas
Normal file
597
components/lazmapviewer/source/mvmapviewerpatheditform.pas
Normal file
@ -0,0 +1,597 @@
|
||||
unit mvMapViewerPathEditForm;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
|
||||
Buttons, ActnList, PropEdits, mvMapViewer;
|
||||
|
||||
type
|
||||
|
||||
{ TMapViewerPathEditForm }
|
||||
|
||||
TMapViewerPathEditForm = class(TForm, IFPObserver)
|
||||
actDelTP: TAction;
|
||||
actNewArea: TAction;
|
||||
actSelect: TAction;
|
||||
actNewTP: TAction;
|
||||
actNewTrack: TAction;
|
||||
actNewPOI: TAction;
|
||||
actZoomOut: TAction;
|
||||
actZoomIn: TAction;
|
||||
alEditActions: TActionList;
|
||||
cbSelectedLayer: TEdit;
|
||||
cbSelectedPt: TEdit;
|
||||
ilImages: TImageList;
|
||||
lblSelectedPt: TLabel;
|
||||
lblSelectedLayer: TLabel;
|
||||
pnlFrame: TPanel;
|
||||
pnlTools: TPanel;
|
||||
btnSelect: TSpeedButton;
|
||||
btnNewTP: TSpeedButton;
|
||||
btnDelTP: TSpeedButton;
|
||||
btnNewPOI: TSpeedButton;
|
||||
btnNewArea: TSpeedButton;
|
||||
btnNewTrack: TSpeedButton;
|
||||
btnZoomIn: TSpeedButton;
|
||||
btnZoomOut: TSpeedButton;
|
||||
procedure actDelTPExecute(Sender: TObject);
|
||||
procedure actNewAreaExecute(Sender: TObject);
|
||||
procedure actNewPOIExecute(Sender: TObject);
|
||||
procedure actNewTPExecute(Sender: TObject);
|
||||
procedure actNewTrackExecute(Sender: TObject);
|
||||
procedure actSelectExecute(Sender: TObject);
|
||||
procedure actZoomInExecute(Sender: TObject);
|
||||
procedure actZoomOutExecute(Sender: TObject);
|
||||
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
private
|
||||
FMapLayer: TMapLayer;
|
||||
FMapView: TMapView;
|
||||
FInternalSelect: Boolean;
|
||||
procedure OnModified(Sender: TObject);
|
||||
procedure OnModifiedWithName(Sender: TObject; PropName: ShortString);
|
||||
procedure OnRefreshPropertyValues;
|
||||
procedure OnSetSelection(const ASelection: TPersistentSelectionList);
|
||||
procedure SetMapLayer(AValue: TMapLayer);
|
||||
procedure SetMapView(AValue: TMapView);
|
||||
procedure FPOObservedChanged(ASender: TObject; Operation: TFPObservedOperation; Data: Pointer);
|
||||
procedure SelectInOI(AView: TMapView; ForceUpdate: Boolean);
|
||||
procedure UpdateControls;
|
||||
public
|
||||
property MapView: TMapView read FMapView write SetMapView;
|
||||
property MapLayer: TMapLayer read FMapLayer write SetMapLayer;
|
||||
end;
|
||||
|
||||
var
|
||||
MapViewerPathEditForm: TMapViewerPathEditForm;
|
||||
|
||||
implementation
|
||||
|
||||
uses mvTypes, Math;
|
||||
|
||||
type
|
||||
TPersistentAccess = class(TPersistent);
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
{ TMapViewerPathEditForm }
|
||||
|
||||
procedure TMapViewerPathEditForm.FormCreate(Sender: TObject);
|
||||
begin
|
||||
if Assigned(GlobalDesignHook) then
|
||||
begin
|
||||
GlobalDesignHook.AddHandlerModified(@OnModified);
|
||||
GlobalDesignHook.AddHandlerModifiedWithName(@OnModifiedWithName);
|
||||
GlobalDesignHook.AddHandlerRefreshPropertyValues(@OnRefreshPropertyValues);
|
||||
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.FormClose(Sender: TObject;
|
||||
var CloseAction: TCloseAction);
|
||||
begin
|
||||
CloseAction := caHide;
|
||||
SetMapView(Nil);
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actSelectExecute(Sender: TObject);
|
||||
begin
|
||||
; //
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actNewPOIExecute(Sender: TObject);
|
||||
var
|
||||
CP: TMapPoint;
|
||||
NP: TPointOfInterest;
|
||||
R: TRealPoint;
|
||||
V: TMapView;
|
||||
begin
|
||||
V := MapView;
|
||||
if not Assigned(MapLayer) or not V.EditMark.HasSelection then
|
||||
Exit;
|
||||
|
||||
CP := MapView.EditMark.CurrentPoint;
|
||||
NP := MapLayer.PointsOfInterest.Add as TPointOfInterest;
|
||||
NP.Assign(CP);
|
||||
if CP is TPointOfInterest then
|
||||
begin
|
||||
NP.Caption := TPointOfInterest(CP).Caption;
|
||||
NP.ImageIndex := TPointOfInterest(CP).ImageIndex;
|
||||
end;
|
||||
R := MapView.ScreenToLatLon(CP.ToScreen + Point(10, 10));
|
||||
NP.Latitude := R.Lat;
|
||||
NP.Longitude := R.Lon;
|
||||
|
||||
MapView.EditMark.ClearSelection;
|
||||
MapView.EditMark.Selection.Insert(0, NP);
|
||||
|
||||
try
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.PersistentAdded(NP, True);
|
||||
finally
|
||||
MapView := V;
|
||||
SelectInOI(V, False);
|
||||
end;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actNewTrackExecute(Sender: TObject);
|
||||
var
|
||||
P, NP: TMapPoint;
|
||||
T, NT: TMapTrack;
|
||||
R: TRealPoint;
|
||||
I: Integer;
|
||||
V: TMapView;
|
||||
begin
|
||||
V := MapView;
|
||||
if not Assigned(MapLayer) or not V.EditMark.HasSelection or
|
||||
(V.EditMark.Selection.Count < 2) then
|
||||
Exit;
|
||||
|
||||
T := MapView.EditMark.CurrentTrack;
|
||||
NT := MapLayer.Tracks.Add as TMapTrack;
|
||||
|
||||
for P in V.EditMark.Selection.Points do
|
||||
begin
|
||||
NP := NT.Points.Add as TMapPoint;
|
||||
NP.Assign(P);
|
||||
R := MapView.ScreenToLatLon(P.ToScreen + Point(10, 10));
|
||||
NP.Latitude := R.Lat;
|
||||
NP.Longitude := R.Lon;
|
||||
end;
|
||||
|
||||
MapView.EditMark.ClearSelection;
|
||||
for I := 0 to Pred(NT.Points.Count) do
|
||||
begin
|
||||
MapView.EditMark.Selection.Add(NT.Points);
|
||||
MapView.EditMark.Selection.Insert(0, NT.Points[I]);
|
||||
end;
|
||||
|
||||
if Assigned(T) then
|
||||
begin // NT.Assign(T)?
|
||||
NT.LineColor := T.LineColor;
|
||||
NT.LineWidth := T.LineWidth;
|
||||
NT.ConnectColor := T.ConnectColor;
|
||||
NT.ConnectWidth := T.ConnectWidth;
|
||||
NT.Opacity := T.Opacity;
|
||||
end;
|
||||
|
||||
try
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.PersistentAdded(NT, True);
|
||||
finally
|
||||
MapView := V;
|
||||
SelectInOI(V, False);
|
||||
end;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actNewAreaExecute(Sender: TObject);
|
||||
var
|
||||
P, NP: TMapPoint;
|
||||
A, NA: TMapArea;
|
||||
R: TRealPoint;
|
||||
I: Integer;
|
||||
V: TMapView;
|
||||
begin
|
||||
V := MapView;
|
||||
if not Assigned(MapLayer) or not V.EditMark.HasSelection or
|
||||
(V.EditMark.Selection.Count < 3) then
|
||||
Exit;
|
||||
|
||||
A := MapView.EditMark.CurrentArea;
|
||||
NA := MapLayer.Areas.Add as TMapArea;
|
||||
|
||||
for P in V.EditMark.Selection.Points do
|
||||
begin
|
||||
NP := NA.Points.Add as TMapPoint;
|
||||
NP.Assign(P);
|
||||
R := MapView.ScreenToLatLon(P.ToScreen + Point(10, 10));
|
||||
NP.Latitude := R.Lat;
|
||||
NP.Longitude := R.Lon;
|
||||
end;
|
||||
|
||||
MapView.EditMark.ClearSelection;
|
||||
for I := 0 to Pred(NA.Points.Count) do
|
||||
begin
|
||||
MapView.EditMark.Selection.Add(NA.Points);
|
||||
MapView.EditMark.Selection.Insert(0, NA.Points[I]);
|
||||
end;
|
||||
|
||||
if Assigned(A) then
|
||||
begin // NA.Assign(A)?
|
||||
NA.LineColor := A.LineColor;
|
||||
NA.LineWidth := A.LineWidth;
|
||||
NA.FillColor := A.FillColor;
|
||||
NA.Opacity := A.Opacity;
|
||||
end;
|
||||
|
||||
try
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.PersistentAdded(NA, True);
|
||||
finally
|
||||
MapView := V;
|
||||
SelectInOI(V, False);
|
||||
end;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actNewTPExecute(Sender: TObject);
|
||||
var
|
||||
P, N: TMapPoint;
|
||||
L: TMapTrack;
|
||||
A: TMapArea;
|
||||
C: TCollection;
|
||||
I, I1, I2, J: Integer;
|
||||
V: TMapView;
|
||||
|
||||
procedure InsertPt(J: Integer; ANext: TMapPoint);
|
||||
var
|
||||
PN: TMapPoint;
|
||||
begin
|
||||
PN := C.Insert(J) as TMapPoint;
|
||||
PN.Latitude := (P.Latitude + ANext.Latitude) / 2;
|
||||
PN.Longitude := (P.Longitude + ANext.Longitude) / 2;
|
||||
MapView.EditMark.Selection.Add(C);
|
||||
MapView.EditMark.Selection.Insert(0, PN);
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.PersistentAdded(PN, True);
|
||||
end;
|
||||
|
||||
begin
|
||||
P := MapView.EditMark.CurrentPoint;
|
||||
L := MapView.EditMark.CurrentTrack;
|
||||
if Assigned(L) then
|
||||
C := L.Points
|
||||
else
|
||||
begin
|
||||
A := MapView.EditMark.CurrentArea;
|
||||
if not Assigned(A) then
|
||||
Exit;
|
||||
C := A.Points;
|
||||
end;
|
||||
I := P.Index;
|
||||
if I < 0 then
|
||||
Exit;
|
||||
I1 := (I + 1) mod C.Count; // Next point index
|
||||
if I > 0
|
||||
then I2 := Pred(I) // Prev point index
|
||||
else I2 := Pred(C.Count);
|
||||
V := MapView;
|
||||
try
|
||||
// If the next point on track/area is selected
|
||||
// then insert before next
|
||||
if MapView.EditMark.IsSelected(C.Items[I1]) then
|
||||
InsertPt(I1, C.Items[I1] as TMapPoint)
|
||||
// If the prev point on track/area is selected
|
||||
// then insert before current
|
||||
else if MapView.EditMark.IsSelected(C.Items[I2]) then
|
||||
InsertPt(I, C.Items[I2] as TMapPoint)
|
||||
// If the current point is not the last
|
||||
// then insert before next(last)
|
||||
else if I < Pred(C.Count) then
|
||||
InsertPt(I1, C.Items[I1] as TMapPoint)
|
||||
// else insert before current
|
||||
else
|
||||
InsertPt(I, C.Items[I2] as TMapPoint);
|
||||
finally
|
||||
MapView := V;
|
||||
SelectInOI(V, False);
|
||||
end;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actDelTPExecute(Sender: TObject);
|
||||
var
|
||||
Pt: TMapPoint;
|
||||
PtCol: TCollection;
|
||||
P: TPersistent;
|
||||
begin
|
||||
Pt := MapView.EditMark.CurrentPoint;
|
||||
PtCol := Pt.Collection;
|
||||
|
||||
if not (Pt is TPointOfInterest) then
|
||||
if PtCol.Count < 3 then
|
||||
; // TODO Just 3 points left?
|
||||
|
||||
if MessageDlg('Confirm deletion', 'Are you sure you want to delete ''' +
|
||||
Pt.DisplayName + '''?', mtConfirmation, mbYesNo, 0 ) <> mrYes then
|
||||
Exit;
|
||||
|
||||
// Exclude from the selection
|
||||
MapView.EditMark.Selection.DelIfPresent(PtCol);
|
||||
MapView.EditMark.Selection.DelIfPresent(Pt);
|
||||
|
||||
// Delete from the object inspector
|
||||
if Assigned(GlobalDesignHook) then
|
||||
begin
|
||||
GlobalDesignHook.Unselect(Pt);
|
||||
P := Pt; GlobalDesignHook.DeletePersistent(P);
|
||||
end;
|
||||
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actZoomInExecute(Sender: TObject);
|
||||
begin
|
||||
MapView.Zoom := MapView.Zoom + 1;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.actZoomOutExecute(Sender: TObject);
|
||||
begin
|
||||
MapView.Zoom := MapView.Zoom - 1;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.RemoveAllHandlersForObject(Self);
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.FormShow(Sender: TObject);
|
||||
begin
|
||||
if Assigned(FMapView) then
|
||||
FMapView.ControlStyle := FMapView.ControlStyle + [csDesignInteractive]
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.OnModified(Sender: TObject);
|
||||
begin
|
||||
;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.OnModifiedWithName(Sender: TObject;
|
||||
PropName: ShortString);
|
||||
begin
|
||||
;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.OnRefreshPropertyValues;
|
||||
begin
|
||||
;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.OnSetSelection(
|
||||
const ASelection: TPersistentSelectionList);
|
||||
var
|
||||
I, LC: Integer;
|
||||
V: TMapView = Nil;
|
||||
L: TMapLayer = Nil;
|
||||
L2: TMapLayer = Nil;
|
||||
PtCnt: Integer = 0;
|
||||
P: TMapPoint = Nil;
|
||||
|
||||
function GetMV(ANested: TPersistent): TMapView;
|
||||
begin
|
||||
Result := Nil;
|
||||
while Assigned(ANested) do
|
||||
if ANested is TMapView
|
||||
then Exit(TMapView(ANested))
|
||||
else ANested := TPersistentAccess(ANested).GetOwner;
|
||||
end;
|
||||
|
||||
function GetLA(ANested: TPersistent): TMapLayer;
|
||||
begin
|
||||
Result := Nil;
|
||||
while Assigned(ANested) do
|
||||
if ANested is TMapLayer
|
||||
then Exit(TMapLayer(ANested))
|
||||
else ANested := TPersistentAccess(ANested).GetOwner;
|
||||
end;
|
||||
|
||||
begin
|
||||
// Try to find the the containing map view
|
||||
for I := 0 to Pred(ASelection.Count) do
|
||||
begin
|
||||
V := GetMV(ASelection[I]);
|
||||
if Assigned(V) then
|
||||
Break;
|
||||
end;
|
||||
SetMapView(V);
|
||||
if Assigned(V) then
|
||||
begin
|
||||
LC := 0;
|
||||
for I := 0 to Pred(ASelection.Count) do
|
||||
begin
|
||||
// If not internal select (i.e. from designer tree view)
|
||||
if not FInternalSelect and (ASelection[I] is TMapPoint) then
|
||||
begin
|
||||
Inc(PtCnt);
|
||||
if not Assigned(P) then
|
||||
begin
|
||||
P := TMapPoint(ASelection[I]);
|
||||
V.EditMark.Select(P, True); // TODO Make it visible?
|
||||
end
|
||||
else
|
||||
V.EditMark.Select(TMapPoint(ASelection[I]), False);
|
||||
end;
|
||||
L2 := GetLA(ASelection[I]); // Containing layer
|
||||
if Assigned(L2) and L2.Visible and (L <> L2) then
|
||||
begin
|
||||
Inc(LC);
|
||||
L := L2;
|
||||
end;
|
||||
end;
|
||||
if LC = 1 // Just one layer?
|
||||
then MapLayer := L // Yes, assign it
|
||||
else MapLayer := Nil; // Multiple layers or no layer
|
||||
|
||||
// From the designer and no points into?
|
||||
if not FInternalSelect and not Assigned(P) then
|
||||
V.EditMark.ClearSelection;
|
||||
end;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.SetMapLayer(AValue: TMapLayer);
|
||||
begin
|
||||
if FMapLayer = AValue then Exit;
|
||||
FMapLayer := AValue;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.SetMapView(AValue: TMapView);
|
||||
begin
|
||||
if FMapView = AValue then
|
||||
Exit;
|
||||
// Detach the old FMapView
|
||||
if Assigned(FMapView) then
|
||||
begin
|
||||
FMapView.FPODetachObserver(Self);
|
||||
FMapView.ControlStyle := FMapView.ControlStyle - [csDesignInteractive];
|
||||
end;
|
||||
// Attach the new FMapView
|
||||
if Assigned(AValue) then
|
||||
begin
|
||||
AValue.FPOAttachObserver(Self);
|
||||
if Visible then
|
||||
AValue.ControlStyle := AValue.ControlStyle + [csDesignInteractive];
|
||||
end;
|
||||
FMapView := AValue;
|
||||
UpdateControls;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.FPOObservedChanged(ASender: TObject;
|
||||
Operation: TFPObservedOperation; Data: Pointer);
|
||||
var
|
||||
What: TMapObserverCustomOperation;
|
||||
V: TMapView;
|
||||
|
||||
procedure Clicked;
|
||||
begin
|
||||
if actSelect.Checked then
|
||||
Exit;
|
||||
//...
|
||||
end;
|
||||
|
||||
begin
|
||||
if Operation <> ooCustom then
|
||||
Exit;
|
||||
V := ASender as TMapView;
|
||||
What := PMapObserverCustomOperation(Data)^;
|
||||
case What of
|
||||
mooSelectionCompleted:
|
||||
SelectInOI(V, False);
|
||||
mooStartDrag:
|
||||
Clicked;
|
||||
mooIsDirty: ;
|
||||
mooDrag: ;
|
||||
mooEndDrag:
|
||||
if V.EditMark.Dirty then
|
||||
begin
|
||||
if Assigned(GlobalDesignHook) then
|
||||
GlobalDesignHook.Modified(Self, 'Layers');
|
||||
V.EditMark.Dirty := False;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.SelectInOI(AView: TMapView; ForceUpdate: Boolean);
|
||||
var
|
||||
I: Integer = 0;
|
||||
Sel: TPersistentSelectionList;
|
||||
P: TMapPoint;
|
||||
begin
|
||||
if not Assigned(GlobalDesignHook) or not Assigned(AView) then
|
||||
Exit;
|
||||
if AView.EditMark.Selection.Count < 1 then
|
||||
begin
|
||||
UpdateControls;
|
||||
Exit;
|
||||
end;
|
||||
// select in OI
|
||||
FInternalSelect := True;
|
||||
Sel := TPersistentSelectionList.Create;
|
||||
Sel.ForceUpdate := ForceUpdate;
|
||||
try
|
||||
for P in AView.EditMark.Selection.Points do
|
||||
begin
|
||||
Sel.Add(P);
|
||||
Inc(I);
|
||||
end;
|
||||
GlobalDesignHook.SetSelection(Sel);
|
||||
finally
|
||||
Sel.Free;
|
||||
FInternalSelect := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMapViewerPathEditForm.UpdateControls;
|
||||
var
|
||||
P: TMapPoint;
|
||||
PtTxt: String;
|
||||
PtCnt: Integer = 0;
|
||||
HaveView, HaveLayer, HaveSel, HavePt: Boolean;
|
||||
begin
|
||||
HaveView := Assigned(MapView);
|
||||
HaveSel := HaveView and MapView.EditMark.HasSelection;
|
||||
HavePt := HaveSel and (MapView.EditMark.Selection[0] is TMapPoint);
|
||||
HaveLayer := Assigned(MapLayer) and HaveSel;
|
||||
|
||||
if HaveView
|
||||
then Caption := MapView.Name + ': ' + TMapView.ClassName
|
||||
else Caption := TMapView.ClassName + ' (Not selected)';
|
||||
|
||||
// Update layer name
|
||||
if HaveLayer
|
||||
then cbSelectedLayer.Text := MapLayer.DisplayName
|
||||
else cbSelectedLayer.Text := '(none)';
|
||||
cbSelectedLayer.Hint := cbSelectedLayer.Text;
|
||||
|
||||
// Update currently selected point
|
||||
PtTxt := '(none)';
|
||||
if HavePt then
|
||||
begin
|
||||
for P in MapView.EditMark.Selection.Points do
|
||||
Inc(PtCnt);
|
||||
P := TMapPoint(MapView.EditMark.Selection[0]);
|
||||
if PtCnt > 0 then
|
||||
begin
|
||||
PtTxt := P.DisplayName;
|
||||
if PtTxt <> P.ClassName then
|
||||
PtTxt := PtTxt + ': ' + P.ClassName;
|
||||
if PtCnt > 1 then
|
||||
PtTxt := PtTxt + Format(' +%d more', [PtCnt - 1]);
|
||||
end;
|
||||
end;
|
||||
cbSelectedPt.Text := PtTxt;
|
||||
cbSelectedPt.Hint := PtTxt;
|
||||
|
||||
// Update actions
|
||||
actZoomIn.Enabled := HaveView and (MapView.Zoom < MapView.ZoomMax);
|
||||
actZoomOut.Enabled := HaveView and (MapView.Zoom > MapView.ZoomMin);
|
||||
actNewPOI.Enabled := HaveView and HaveLayer;
|
||||
actNewTrack.Enabled := HaveView and HaveLayer and InRange(PtCnt, 2, 10);
|
||||
actNewArea.Enabled := HaveView and HaveLayer and InRange(PtCnt, 3, 10);
|
||||
actNewTP.Enabled := HaveView and HavePt;
|
||||
actDelTP.Enabled := HaveView and HavePt;
|
||||
actSelect.Enabled := HaveView;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -17,10 +17,24 @@ unit
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, Forms, SysUtils, PropEdits, GraphPropEdits, ImgList, mvMapProvider;
|
||||
Classes, Forms, SysUtils, PropEdits, GraphPropEdits, ComponentEditors,
|
||||
ImgList, mvMapProvider;
|
||||
|
||||
type
|
||||
|
||||
{ TMapViewComponentEditor }
|
||||
|
||||
TMapViewComponentEditor = class(TComponentEditor)
|
||||
FOldDirtyHandler: TNotifyEvent;
|
||||
public
|
||||
constructor Create(AComponent: TComponent;
|
||||
ADesigner: TComponentEditorDesigner); override;
|
||||
procedure ExecuteVerb(Index: Integer); override;
|
||||
function GetVerb(Index: Integer): String; override;
|
||||
function GetVerbCount: Integer; override;
|
||||
procedure DoEdit;
|
||||
end;
|
||||
|
||||
{ TMapLayersPropertyEditor }
|
||||
|
||||
TMapLayersPropertyEditor = class(TCollectionPropertyEditor)
|
||||
@ -30,6 +44,15 @@ type
|
||||
override;
|
||||
end;
|
||||
|
||||
{ TMapTrackPointsPropertyEditor }
|
||||
|
||||
TMapTrackPointsPropertyEditor = class(TCollectionPropertyEditor)
|
||||
public
|
||||
class function ShowCollectionEditor(ACollection: TCollection;
|
||||
OwnerPersistent: TPersistent; const PropName: String): TCustomForm;
|
||||
override;
|
||||
end;
|
||||
|
||||
{ TMapProviderPropertyEditor }
|
||||
|
||||
TMapProviderPropertyEditor = class(TStringPropertyEditor)
|
||||
@ -78,12 +101,78 @@ procedure Register;
|
||||
implementation
|
||||
|
||||
uses
|
||||
Dialogs, IDEWindowIntf,
|
||||
StrUtils,
|
||||
mvGeoMath, mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine;
|
||||
UITypes, Dialogs, IDEWindowIntf, LazIDEIntf, StrUtils, mvGeoMath, mvMapViewer,
|
||||
mvGpsObj, mvLayersPropEditForm, mvEngine, mvMapViewerPathEditForm;
|
||||
|
||||
const
|
||||
NONE = '(none)';
|
||||
sNONE = '(none)';
|
||||
sEDITMapView = 'Edit MapView Points';
|
||||
|
||||
{ TMapTrackPointsPropertyEditor }
|
||||
|
||||
class function TMapTrackPointsPropertyEditor.ShowCollectionEditor(
|
||||
ACollection: TCollection; OwnerPersistent: TPersistent; const PropName: String
|
||||
): TCustomForm;
|
||||
begin
|
||||
Result := inherited ShowCollectionEditor(ACollection, OwnerPersistent, PropName
|
||||
);
|
||||
end;
|
||||
|
||||
{ TMapViewComponentEditor }
|
||||
|
||||
constructor TMapViewComponentEditor.Create(AComponent: TComponent;
|
||||
ADesigner: TComponentEditorDesigner);
|
||||
begin
|
||||
inherited Create(AComponent, ADesigner);
|
||||
end;
|
||||
|
||||
procedure TMapViewComponentEditor.ExecuteVerb(Index: Integer);
|
||||
begin
|
||||
case Index of
|
||||
0: DoEdit;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMapViewComponentEditor.GetVerb(Index: Integer): String;
|
||||
begin
|
||||
Result := '';
|
||||
case Index of
|
||||
0: Result := sEDITMapView;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMapViewComponentEditor.GetVerbCount: Integer;
|
||||
begin
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
procedure TMapViewComponentEditor.DoEdit;
|
||||
var
|
||||
V: TMapView;
|
||||
P: TPoint;
|
||||
begin
|
||||
if not Assigned(MapViewerPathEditForm) then
|
||||
MapViewerPathEditForm := TMapViewerPathEditForm.Create(
|
||||
LazarusIDE.OwningComponent);
|
||||
V := GetComponent as TMapView;
|
||||
if not (mvoEditorEnabled in V.Options) then
|
||||
case QuestionDlg(V.ClassName,
|
||||
V.Name + ' doesn''t have mvoEditorEnabled set in Options.' + LineEnding +
|
||||
LineEnding +
|
||||
'Do you want to enable the editor?',
|
||||
mtWarning,
|
||||
[mrYes, '&Enable and continue', mrCancel, '&Cancel', 'IsDefault', 'IsCancel'], 0 )
|
||||
of
|
||||
mrYes: V.Options := V.Options + [mvoEditorEnabled];
|
||||
otherwise
|
||||
Exit;
|
||||
end;
|
||||
MapViewerPathEditForm.MapView := V;
|
||||
P := V.ControlToScreen(Point(V.Width, 0));
|
||||
MapViewerPathEditForm.Left := P.X;
|
||||
MapViewerPathEditForm.Top := P.Y;
|
||||
MapViewerPathEditForm.Show;
|
||||
end;
|
||||
|
||||
{ TMapLayersPropertyEditor }
|
||||
|
||||
@ -112,12 +201,12 @@ function TPointElevationPropertyEditor.GetValue: string;
|
||||
begin
|
||||
Result := inherited GetValue;
|
||||
if GetFloatValue = NO_ELE then
|
||||
Result := NONE;
|
||||
Result := sNONE;
|
||||
end;
|
||||
|
||||
procedure TPointElevationPropertyEditor.SetValue(const NewValue: AnsiString);
|
||||
begin
|
||||
if (NewValue = NONE) or (NewValue = '')
|
||||
if (NewValue = sNONE) or (NewValue = '')
|
||||
then inherited SetFloatValue(NO_ELE)
|
||||
else inherited SetValue(NewValue);
|
||||
end;
|
||||
@ -157,12 +246,12 @@ function TPointDateTimePropertyEditor.GetValue: string;
|
||||
begin
|
||||
Result := inherited GetValue;
|
||||
if GetFloatValue = NO_DATE then
|
||||
Result := NONE;
|
||||
Result := sNONE;
|
||||
end;
|
||||
|
||||
procedure TPointDateTimePropertyEditor.SetValue(const NewValue: AnsiString);
|
||||
begin
|
||||
if (NewValue = NONE) or (NewValue = '')
|
||||
if (NewValue = sNONE) or (NewValue = '')
|
||||
then inherited SetFloatValue(NO_DATE)
|
||||
else inherited SetValue(NewValue);
|
||||
end;
|
||||
@ -212,7 +301,7 @@ begin
|
||||
Exit;
|
||||
MV.Engine.GetMapProviders(Providers);
|
||||
//if not (Inst is TMapView) then
|
||||
Proc(NONE);
|
||||
Proc(sNONE);
|
||||
Providers.Sort;
|
||||
for S in Providers do
|
||||
// TODO: When filtered it is not clear what is the full list.
|
||||
@ -227,21 +316,26 @@ function TMapProviderPropertyEditor.GetValue: AnsiString;
|
||||
begin
|
||||
Result := inherited GetValue;
|
||||
if Result = '' then
|
||||
Result := NONE;
|
||||
Result := sNONE;
|
||||
end;
|
||||
|
||||
procedure TMapProviderPropertyEditor.SetValue(const NewValue: AnsiString);
|
||||
begin
|
||||
if NewValue = NONE
|
||||
if NewValue = sNONE
|
||||
then inherited SetValue('')
|
||||
else inherited SetValue(NewValue);
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterComponentEditor(TMapView, TMapViewComponentEditor);
|
||||
|
||||
RegisterPropertyEditor(TypeInfo(TMapLayers),
|
||||
TMapView, 'Layers', TMapLayersPropertyEditor);
|
||||
|
||||
RegisterPropertyEditor(TypeInfo(TMapTrackPoints),
|
||||
TMapTrack, 'Points', TMapTrackPointsPropertyEditor);
|
||||
|
||||
RegisterPropertyEditor(TypeInfo(String),
|
||||
TMapView,'MapProvider',TMapProviderPropertyEditor);
|
||||
RegisterPropertyEditor(TypeInfo(String),
|
||||
|
Loading…
Reference in New Issue
Block a user