
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9673 8e941d3f-bd1b-0410-a28a-d453659cc2b4
926 lines
24 KiB
ObjectPascal
926 lines
24 KiB
ObjectPascal
unit mvMapViewerPathEditForm;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Math, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
|
|
ExtCtrls, Buttons, ActnList, mvMapViewer, mvGpsObj, mvTypes, Types;
|
|
|
|
type
|
|
|
|
TMapViewerPathEditMode = (pemSelect, pemAddPOI, pemAddTrack, pemAddArea);
|
|
|
|
{ TMapViewerPathEditForm }
|
|
|
|
TMapViewerPathEditForm = class(TForm, IFPObserver)
|
|
actDelTP: TAction;
|
|
actNewArea: TAction;
|
|
actSelect: TAction;
|
|
actNewTP: TAction;
|
|
actNewTrack: TAction;
|
|
actNewPOI: TAction;
|
|
actZoomOut: TAction;
|
|
actZoomIn: TAction;
|
|
alEditActions: TActionList;
|
|
Bevel: TBevel;
|
|
cbLon: TEdit;
|
|
cbSelectedLayer: TComboBox;
|
|
cbSelectedPt: TEdit;
|
|
cbLat: TEdit;
|
|
edCaption: TEdit;
|
|
ilImages: TImageList;
|
|
lblInfoText: TLabel;
|
|
lblInfoTitle: TLabel;
|
|
lblCaption: TLabel;
|
|
lblLat: TLabel;
|
|
lblLon: TLabel;
|
|
lblSelectedLayer: TLabel;
|
|
lblSelectedPt: TLabel;
|
|
pnlSel: TPanel;
|
|
pnlInfo: TPanel;
|
|
pnlFrame: TPanel;
|
|
ToolBar: TToolBar;
|
|
tbSelect: TToolButton;
|
|
tbZoomIn: TToolButton;
|
|
tbZoomOut: TToolButton;
|
|
tbNewPOI: TToolButton;
|
|
tbNewArea: TToolButton;
|
|
tbNewTrack: TToolButton;
|
|
ToolButton6: TToolButton;
|
|
tbNewTrackPoint: TToolButton;
|
|
tbDeleteTrackPoint: TToolButton;
|
|
ToolButton9: TToolButton;
|
|
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 cbLatLonEditingDone(Sender: TObject);
|
|
procedure cbLatEnter(Sender: TObject);
|
|
procedure cbLatLonExit(Sender: TObject);
|
|
procedure cbLonEnter(Sender: TObject);
|
|
procedure cbSelectedLayerDropDown(Sender: TObject);
|
|
procedure cbSelectedLayerSelect(Sender: TObject);
|
|
procedure edCaptionEditingDone(Sender: TObject);
|
|
procedure FormActivate(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
private
|
|
FPointCnt: Integer;
|
|
FMapLayer: TMapLayer;
|
|
FMapView: TMapView;
|
|
FInternalSelect: Boolean;
|
|
FTempPolyLine: TGPSPolyLine;
|
|
FEditMode: TMapViewerPathEditMode;
|
|
FSkipAPoint: Boolean;
|
|
FActivated: Boolean;
|
|
procedure AddTempPolylineOrRevert(ANewEditMode: TMapViewerPathEditMode);
|
|
procedure SetEditMode(AValue: TMapViewerPathEditMode);
|
|
procedure CancelAddMode;
|
|
procedure AddTempPoint;
|
|
procedure NewTrackFromTemp;
|
|
procedure NewAreaFromTemp;
|
|
procedure NewPOIFromTemp;
|
|
procedure SetMapLayer(AValue: TMapLayer);
|
|
procedure SetMapView(AValue: TMapView);
|
|
procedure FPOObservedChanged(ASender: TObject; Operation: TFPObservedOperation; Data: Pointer);
|
|
procedure DrawTempTrack(Sender: TObject; AGPSObj: TGPSObj; AArea: TRealArea);
|
|
procedure DrawTempArea(Sender: TObject; AGPSObj: TGPSObj; {%H-}AArea: TRealArea);
|
|
procedure DrawTempMark(AView: TMapView; APt: TRealPoint);
|
|
protected
|
|
procedure UpdateControls;
|
|
procedure UpdateInfoPanel;
|
|
procedure UpdateLayerItems;
|
|
function GetOwnerOfType(ANested: TPersistent; AClass: TClass): TPersistent;
|
|
procedure PersistentAdded({%H-}APersistent: TPersistent; {%H-}Select: Boolean); virtual;
|
|
procedure DeletePersistent({%H-}APersistent: TPersistent); virtual;
|
|
procedure UnselectPersistent({%H-}APersistent: TPersistent); virtual;
|
|
procedure ObjectModified({%H-}AObject: TObject; {%H-}PropName: ShortString = ''); virtual;
|
|
procedure SelectInOI(AView: TMapView; {%H-}ForceUpdate: Boolean); virtual;
|
|
property InternalSelect: Boolean read FInternalSelect write FInternalSelect;
|
|
public
|
|
destructor Destroy; override;
|
|
property MapView: TMapView read FMapView write SetMapView;
|
|
property MapLayer: TMapLayer read FMapLayer write SetMapLayer;
|
|
property EditMode: TMapViewerPathEditMode read FEditMode write SetEditMode;
|
|
end;
|
|
|
|
var
|
|
MapViewerPathEditForm: TMapViewerPathEditForm;
|
|
|
|
implementation
|
|
|
|
uses
|
|
mvGeoMath;
|
|
|
|
const
|
|
EditModeHints: array[TMapViewerPathEditMode] of String = (
|
|
'Select/drag mode|Click point to select. CTRL-click to add to selection.', // pemSelect
|
|
'POI mode|Click to add point.', // pemAddPOI
|
|
'Track mode|Click to add point, CTRL-click to add last point.', // pemAddTrack
|
|
'Area mode|Click to add point, CTRL-click to add last point.' // pemAddArea
|
|
);
|
|
|
|
type
|
|
TPersistentAccess = class(TPersistent);
|
|
|
|
{$R *.lfm}
|
|
|
|
function MapItemCaption(AItem: TMapItem): String;
|
|
begin
|
|
Result := AItem.DisplayName;
|
|
if Result <> AItem.ClassName then
|
|
Result := Result + ': ' + AItem.ClassName;
|
|
if Assigned(AItem.Collection) then
|
|
Result := Format('%d - ', [AItem.Index]) + Result;
|
|
end;
|
|
|
|
{ TMapViewerPathEditForm }
|
|
|
|
procedure TMapViewerPathEditForm.actSelectExecute(Sender: TObject);
|
|
begin
|
|
if (FTempPolyLine <> nil) and (FTempPolyLine.Points.Count > 0) then
|
|
AddTempPolyLineOrRevert(pemSelect);
|
|
EditMode := pemSelect;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.actNewPOIExecute(Sender: TObject);
|
|
begin
|
|
if (FTempPolyLine <> nil) and (FTempPolyLine.Points.Count > 0) then
|
|
AddTempPolyLineOrRevert(pemAddPOI);
|
|
EditMode := pemAddPOI;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.actNewTrackExecute(Sender: TObject);
|
|
begin
|
|
if (FTempPolyLine <> nil) and (FTempPolyLine.Points.Count > 0) then
|
|
AddTempPolyLineOrRevert(pemAddTrack);
|
|
EditMode := pemAddTrack;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.actNewAreaExecute(Sender: TObject);
|
|
begin
|
|
if (FTempPolyLine <> nil) and (FTempPolyLine.Points.Count > 0) then
|
|
AddTempPolyLineOrRevert(pemAddArea);
|
|
EditMode := pemAddArea;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.actNewTPExecute(Sender: TObject);
|
|
var
|
|
P: TMapPoint;
|
|
L: TMapTrack;
|
|
A: TMapArea;
|
|
C: TCollection;
|
|
I, I1, I2: 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);
|
|
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;
|
|
PtId: Integer;
|
|
PtCol: TCollection;
|
|
P: TPersistent;
|
|
begin
|
|
Pt := MapView.EditMark.CurrentPoint;
|
|
PtCol := Pt.Collection;
|
|
PtId := Pt.ID;
|
|
|
|
if (Pt is TMapAreaPoint) and (PtCol.Count < 4) or
|
|
(Pt is TMapTrackPoint) and (PtCol.Count < 3)
|
|
then
|
|
Exit; // Not enough 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);
|
|
|
|
// No points left?
|
|
if MapView.EditMark.HasSelection and
|
|
not (MapView.EditMark.Selection[0] is TMapPoint) then
|
|
MapView.EditMark.ClearSelection; // Clear the whole selection
|
|
|
|
// Delete from the object inspector
|
|
UnselectPersistent(Pt);
|
|
P := Pt; DeletePersistent(P);
|
|
|
|
// In case DeletePersistent() isn't overriden (stub)
|
|
if PtCol.FindItemID(PtId) = Pt then
|
|
PtCol.Delete(Pt.Index);
|
|
|
|
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;
|
|
|
|
{ When points for a new track or a new area are being added, but the user
|
|
selects another edit mode ("ANewEditMode"), the already prepared points
|
|
would be lost. --> We ask whether the track/area should be used or discarded. }
|
|
procedure TMapViewerPathEditForm.AddTempPolylineOrRevert(ANewEditMode: TMapViewerPathEditMode);
|
|
const
|
|
TRACK_AREA: array[boolean] of String = ('track', 'area');
|
|
var
|
|
msg: String;
|
|
begin
|
|
msg := Format(
|
|
'Click on "OK" to add the new %s.' + LineEnding +
|
|
'Click on "Cancel" to discard it.', [
|
|
TRACK_AREA[FEditMode = pemAddArea]
|
|
]);
|
|
if MessageDlg(msg, mtConfirmation, [mbOK, mbCancel], 0) = mrOK then
|
|
begin
|
|
case FEditMode of
|
|
pemAddArea: NewAreaFromTemp;
|
|
pemAddTrack: NewTrackFromTemp;
|
|
end;
|
|
// Tool button checked state was changed in previous command --> restore it.
|
|
case ANewEditMode of
|
|
pemSelect: actSelect.Checked := true;
|
|
pemAddPOI: actNewPOI.Checked := true;
|
|
pemAddArea: actNewArea.Checked := true;
|
|
pemAddTrack: actNewTrack.Checked := true;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbLatLonEditingDone(Sender: TObject);
|
|
var
|
|
E: TEdit;
|
|
Deg: Double;
|
|
R: Boolean;
|
|
P: TMapPoint;
|
|
IsLat: Boolean;
|
|
begin
|
|
E := Sender as TEdit;
|
|
if not E.Modified then
|
|
Exit;
|
|
R := TryStrDMSToDeg(E.Text, Deg);
|
|
if not R then
|
|
raise EArgumentException.Create('Invalid value.');
|
|
// Assignment
|
|
IsLat := Sender = cbLat;
|
|
for P in MapView.EditMark.Selection.Points do
|
|
begin
|
|
if IsLat
|
|
then P.Latitude := Deg
|
|
else P.Longitude := Deg;
|
|
ObjectModified(P, '');
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbLatEnter(Sender: TObject);
|
|
begin
|
|
cbLat.Caption := LatToStr(MapView.EditMark.CurrentPoint.Latitude,
|
|
mvoLatLonInDMS in MapView.Options);
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbLatLonExit(Sender: TObject);
|
|
begin
|
|
UpdateControls;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbLonEnter(Sender: TObject);
|
|
begin
|
|
cbLon.Caption := LonToStr(MapView.EditMark.CurrentPoint.Longitude,
|
|
mvoLatLonInDMS in MapView.Options);
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbSelectedLayerDropDown(Sender: TObject);
|
|
begin
|
|
UpdateLayerItems;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.cbSelectedLayerSelect(Sender: TObject);
|
|
begin
|
|
if cbSelectedLayer.ItemIndex = 0
|
|
then MapLayer := Nil
|
|
else MapLayer := MapView.Layers[Pred(cbSelectedLayer.ItemIndex)];
|
|
UpdateControls;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.edCaptionEditingDone(Sender: TObject);
|
|
var
|
|
E: TEdit;
|
|
P: TMapPoint;
|
|
begin
|
|
E := Sender as TEdit;
|
|
if not E.Modified then
|
|
Exit;
|
|
for P in MapView.EditMark.Selection.Points do
|
|
begin
|
|
if (P is TMapPointOfInterest) then
|
|
begin
|
|
P.Caption := edCaption.Text;
|
|
ObjectModified(P, '');
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.FormActivate(Sender: TObject);
|
|
var
|
|
w: Integer;
|
|
begin
|
|
if not FActivated then
|
|
begin
|
|
AutoSize := false;
|
|
w := MaxValue([lblSelectedPt.Width, lblLat.Width, lblLon.Width, lblCaption.Width]);
|
|
cbSelectedPt.Left := w + lblSelectedPt.BorderSpacing.Left + lblSelectedPt.BorderSpacing.Right;
|
|
cbSelectedLayer.Left := cbSelectedPt.Left + pnlSel.Left;
|
|
AutoSize := true;
|
|
FActivated := true;
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.FormShow(Sender: TObject);
|
|
begin
|
|
UpdateInfoPanel;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.UpdateInfoPanel;
|
|
var
|
|
sa: TStringArray;
|
|
begin
|
|
sa := EditModeHints[FEditMode].Split('|');
|
|
lblInfoTitle.Caption := sa[0];
|
|
lblInfoText.Caption := sa[1];
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.UpdateLayerItems;
|
|
var
|
|
L: TCollectionItem;
|
|
begin
|
|
cbSelectedLayer.Items.Clear;
|
|
cbSelectedLayer.Items.Add('(none)'); // At 0
|
|
if Assigned(MapView) then
|
|
for L in MapView.Layers do
|
|
cbSelectedLayer.Items.Add(MapItemCaption(TMapLayer(L)));
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.SetMapLayer(AValue: TMapLayer);
|
|
begin
|
|
if FMapLayer = AValue then Exit;
|
|
FMapLayer := AValue;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.SetEditMode(AValue: TMapViewerPathEditMode);
|
|
|
|
procedure AddTempLine(ALine: TGPSPolyLine);
|
|
begin
|
|
FTempPolyLine := ALine;
|
|
MapView.GPSItems.Add(FTempPolyLine, {_MAPEDITOR_ID_=}-42, MaxInt);
|
|
end;
|
|
|
|
procedure RemoveTempLine;
|
|
begin
|
|
if Assigned(FTempPolyLine) then
|
|
begin
|
|
MapView.GPSItems.Delete(FTempPolyLine);
|
|
FTempPolyLine := Nil;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if FEditMode = AValue then Exit;
|
|
case AValue of
|
|
pemSelect:
|
|
begin
|
|
RemoveTempLine;
|
|
actSelect.Checked := True;
|
|
MapView.EditMark.CursorShape := crDefault;
|
|
end;
|
|
pemAddTrack:
|
|
begin
|
|
MapView.EditMark.ClearSelection;
|
|
RemoveTempLine;
|
|
AddTempLine(TGPSTrack.Create);
|
|
with TGPSTrack(FTempPolyLine) do
|
|
begin
|
|
LineWidth := 0.4;
|
|
LineColor := clBlack;
|
|
Opacity := 0.4;
|
|
OnDrawObj := @DrawTempTrack;
|
|
end;
|
|
MapView.EditMark.CursorShape := crCross;
|
|
edCaption.Enabled := false;
|
|
lblCaption.Enabled := false;
|
|
end;
|
|
pemAddArea:
|
|
begin
|
|
MapView.EditMark.ClearSelection;
|
|
RemoveTempLine;
|
|
AddTempLine(TGPSArea.Create);
|
|
with TGPSArea(FTempPolyLine) do
|
|
begin
|
|
LineColor := clNone;
|
|
FillColor := clBlack;
|
|
Opacity := 0.2;
|
|
OnDrawObj := @DrawTempArea;
|
|
end;
|
|
MapView.EditMark.CursorShape := crCross;
|
|
edCaption.Enabled := false;
|
|
lblCaption.Enabled := false;
|
|
end;
|
|
pemAddPOI:
|
|
begin
|
|
MapView.EditMark.ClearSelection;
|
|
RemoveTempLine;
|
|
AddTempLine(TGPSTrack.Create);
|
|
MapView.EditMark.CursorShape := crCross;
|
|
edCaption.Enabled := true;
|
|
lblCaption.Enabled := true;
|
|
end;
|
|
end;
|
|
FEditMode := AValue;
|
|
UpdateInfoPanel;
|
|
MapView.Invalidate;
|
|
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.Layers.FPODetachObserver(Self);
|
|
FMapView.ControlStyle := FMapView.ControlStyle - [csDesignInteractive];
|
|
EditMode := pemSelect; // Should free the FTempPolyLine if allocated
|
|
end;
|
|
// Attach the new FMapView
|
|
if Assigned(AValue) then
|
|
begin
|
|
AValue.FPOAttachObserver(Self);
|
|
AValue.Layers.FPOAttachObserver(Self);
|
|
if Visible then
|
|
AValue.ControlStyle := AValue.ControlStyle + [csDesignInteractive];
|
|
end;
|
|
FMapLayer := Nil;
|
|
FMapView := AValue;
|
|
UpdateControls;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.CancelAddMode;
|
|
begin
|
|
EditMode := pemSelect;
|
|
UpdateControls;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.AddTempPoint;
|
|
var
|
|
P: TPoint;
|
|
RealPt: TRealPoint;
|
|
begin
|
|
if not (EditMode in [pemAddPOI, pemAddTrack, pemAddArea]) then
|
|
Exit;
|
|
P := Mouse.CursorPos;
|
|
P := MapView.ScreenToControl(P);
|
|
RealPt := MapView.ScreenToLatLon(P);
|
|
FTempPolyLine.Points.Add(TGPSPoint.CreateFrom(RealPt));
|
|
if EditMode = pemAddPOI then
|
|
NewPOIFromTemp
|
|
else
|
|
if ssCtrl in GetKeyShiftState then
|
|
case EditMode of
|
|
pemAddTrack: NewTrackFromTemp;
|
|
pemAddArea: NewAreaFromTemp;
|
|
end;
|
|
MapView.Invalidate;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.NewTrackFromTemp;
|
|
var
|
|
Trk: TMapTrack;
|
|
I: Integer;
|
|
P: TMapTrackPoint;
|
|
begin
|
|
if not Assigned(MapLayer) then
|
|
Exit;
|
|
if FTempPolyLine.Points.Count < 2 then
|
|
Exit;
|
|
Trk := TMapTrack(MapLayer.Tracks.Add);
|
|
for I := 0 to Pred(FTempPolyLine.Points.Count) do
|
|
begin
|
|
P := TMapTrackPoint(Trk.Points.Add);
|
|
P.RealPoint := FTempPolyLine.Points[I].RealPoint;
|
|
MapView.EditMark.Select(P);
|
|
end;
|
|
CancelAddMode;
|
|
try
|
|
PersistentAdded(Trk, True);
|
|
finally
|
|
SelectInOI(MapView, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.NewAreaFromTemp;
|
|
var
|
|
Ar: TMapArea;
|
|
I: Integer;
|
|
P: TMapAreaPoint;
|
|
begin
|
|
if not Assigned(MapLayer) then
|
|
Exit;
|
|
if FTempPolyLine.Points.Count < 3 then
|
|
Exit;
|
|
Ar := TMapArea(MapLayer.Areas.Add);
|
|
for I := 0 to Pred(FTempPolyLine.Points.Count) do
|
|
begin
|
|
P := TMapAreaPoint(Ar.Points.Add);
|
|
P.RealPoint := FTempPolyLine.Points[I].RealPoint;
|
|
MapView.EditMark.Select(P);
|
|
end;
|
|
CancelAddMode;
|
|
try
|
|
PersistentAdded(Ar, True);
|
|
finally
|
|
SelectInOI(MapView, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.NewPOIFromTemp;
|
|
var
|
|
P: TMapPointOfInterest;
|
|
begin
|
|
if not Assigned(MapLayer) then
|
|
Exit;
|
|
if FTempPolyLine.Points.Count < 1 then
|
|
Exit;
|
|
P := TMapPointOfInterest(MapLayer.PointsOfInterest.Add);
|
|
P.RealPoint := FTempPolyLine.Points[0].RealPoint;
|
|
CancelAddMode;
|
|
try
|
|
PersistentAdded(P, True);
|
|
finally
|
|
SelectInOI(MapView, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.FPOObservedChanged(ASender: TObject;
|
|
Operation: TFPObservedOperation; Data: Pointer);
|
|
var
|
|
What: TMapObserverCustomOperation;
|
|
V: TMapView;
|
|
|
|
procedure MapViewChanged;
|
|
begin
|
|
if Operation = ooFree then
|
|
begin
|
|
FMapView := Nil; // Too late to call anyhing
|
|
FTempPolyLine := Nil; // Probably dangling
|
|
FMapLayer := Nil; // Ditto
|
|
UpdateControls;
|
|
Exit;
|
|
end;
|
|
|
|
if Operation <> ooCustom then
|
|
Exit;
|
|
|
|
V := ASender as TMapView;
|
|
What := PMapObserverCustomOperation(Data)^;
|
|
case What of
|
|
|
|
mooSelectionCompleted:
|
|
begin
|
|
if EditMode = pemSelect then
|
|
SelectInOI(V, False)
|
|
else if FSkipAPoint then
|
|
FSkipAPoint := False
|
|
else
|
|
AddTempPoint;
|
|
end;
|
|
|
|
mooStartDrag:
|
|
if EditMode in [pemAddTrack, pemAddArea] then
|
|
begin
|
|
FSkipAPoint := True; // Skip the 2-nd drag point
|
|
V.EditMark.DoEndDrag(Nil);
|
|
end;
|
|
|
|
mooDrag: ;
|
|
|
|
mooIsDirty: ;
|
|
|
|
mooEndDrag:
|
|
if V.EditMark.Dirty then
|
|
begin
|
|
ObjectModified(Self, 'Layers');
|
|
V.EditMark.Dirty := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure LayersChanged;
|
|
begin
|
|
if Operation = ooFree then
|
|
begin
|
|
MapLayer := Nil;
|
|
Exit;
|
|
end;
|
|
V := (ASender as TMapLayers).View;
|
|
if (Operation = ooDeleteItem) and (Data = Pointer(FMapLayer)) then
|
|
begin
|
|
V.EditMark.ClearSelection;
|
|
MapLayer := Nil;
|
|
// The old layer is still around! Can't UpdateControls!
|
|
end
|
|
else if Operation = ooChange then
|
|
UpdateControls;
|
|
end;
|
|
|
|
begin
|
|
if ASender is TMapView then
|
|
MapViewChanged
|
|
else if ASender is TMapLayers then
|
|
LayersChanged;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.DrawTempTrack(Sender: TObject;
|
|
AGPSObj: TGPSObj; AArea: TRealArea);
|
|
var
|
|
T: TGPSTrack;
|
|
I: Integer;
|
|
begin
|
|
T := TGPSTrack(AGPSObj);
|
|
MapView.DrawTrack(AArea, T);
|
|
for I := 0 to Pred(T.Points.Count) do
|
|
DrawTempMark(MapView, T.Points[I].RealPoint)
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.DrawTempArea(Sender: TObject;
|
|
AGPSObj: TGPSObj; AArea: TRealArea);
|
|
var
|
|
A: TGPSArea;
|
|
I: Integer;
|
|
begin
|
|
A := TGPSArea(AGPSObj);
|
|
MapView.DrawArea(AArea, A);
|
|
for I := 0 to Pred(A.Points.Count) do
|
|
DrawTempMark(MapView, A.Points[I].RealPoint)
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.DrawTempMark(AView: TMapView; APt: TRealPoint);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
P := AView.LatLonToScreen(APt);
|
|
with AView.DrawingEngine do
|
|
begin
|
|
PenStyle := psSolid;
|
|
PenColor := clRed;
|
|
PenWidth := 2;
|
|
Opacity := 1.0;
|
|
Line(P.X - 4, P.Y - 4, P.X + 4, P.Y + 4);
|
|
Line(P.X - 4, P.Y + 4, P.X + 4, P.Y - 4);
|
|
end;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.SelectInOI(AView: TMapView; ForceUpdate: Boolean);
|
|
var
|
|
L, L2: TMapLayer;
|
|
P: TMapPoint;
|
|
LC: Integer = 0;
|
|
begin
|
|
if not Assigned(AView) then
|
|
Exit;
|
|
L := Nil;
|
|
for P in AView.EditMark.Selection.Points do
|
|
begin
|
|
L2 := TMapLayer(GetOwnerOfType(P, TMapLayer));
|
|
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
|
|
UpdateControls;
|
|
end;
|
|
|
|
destructor TMapViewerPathEditForm.Destroy;
|
|
begin
|
|
EditMode := pemSelect;
|
|
MapView := Nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.UpdateControls;
|
|
var
|
|
P, P0: TMapPoint;
|
|
PtTxt: String;
|
|
PtCnt: Integer = 0;
|
|
HaveView, HaveLayer, HaveSel, HavePt: Boolean;
|
|
VaryingLat, VaryingLon: Boolean;
|
|
Erasable: Boolean = False;
|
|
begin
|
|
HaveView := Assigned(MapView);
|
|
HaveSel := HaveView and MapView.EditMark.HasSelection;
|
|
HavePt := HaveSel and (MapView.EditMark.Selection[0] is TMapPoint);
|
|
HaveLayer := Assigned(MapLayer);
|
|
|
|
if not HaveLayer then
|
|
begin
|
|
if HavePt then
|
|
MapLayer := (MapView.EditMark.Selection[0] as TMapPoint).Layer
|
|
else if HaveView and (MapView.Layers.Count > 0) then
|
|
MapLayer := MapView.Layers.Last;
|
|
HaveLayer := Assigned(MapLayer);
|
|
end;
|
|
|
|
if HaveView
|
|
then Caption := MapView.Name + ': ' + TMapView.ClassName
|
|
else Caption := TMapView.ClassName + ' (Not selected)';
|
|
|
|
// Update layer name
|
|
if HaveLayer
|
|
then cbSelectedLayer.Text := MapItemCaption(MapLayer)
|
|
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);
|
|
P0 := TMapPoint(MapView.EditMark.Selection[0]);
|
|
|
|
VaryingLat := False;
|
|
for P in MapView.EditMark.Selection.Points.Skip(1) do
|
|
if P.Latitude <> P0.Latitude then
|
|
begin
|
|
VaryingLat := True;
|
|
Break;
|
|
end;
|
|
|
|
VaryingLon := False;
|
|
for P in MapView.EditMark.Selection.Points.Skip(1) do
|
|
if P.Longitude <> P0.Longitude then
|
|
begin
|
|
VaryingLon := True;
|
|
Break;
|
|
end;
|
|
|
|
if VaryingLat
|
|
then cbLat.Caption := '(varying)'
|
|
else cbLat.Caption := LatToStr(P0.Latitude, mvoLatLonInDMS in MapView.Options);
|
|
|
|
if VaryingLon
|
|
then cbLon.Caption := '(varying)'
|
|
else cbLon.Caption := LonToStr(P0.Longitude, mvoLatLonInDMS in MapView.Options);
|
|
|
|
edCaption.Text := P0.Caption;
|
|
|
|
FPointCnt := PtCnt;
|
|
if PtCnt > 0 then
|
|
begin
|
|
PtTxt := MapItemCaption(P);
|
|
if PtCnt > 1 then
|
|
PtTxt := PtTxt + Format(' +%d more', [PtCnt - 1]);
|
|
end;
|
|
|
|
if P0.Collection is TMapTrackPoints then
|
|
Erasable := P0.Collection.Count > 2
|
|
else if P0.Collection is TMapAreaPoints then
|
|
Erasable := P0.Collection.Count > 3
|
|
else
|
|
Erasable := True;
|
|
end
|
|
else
|
|
begin
|
|
FPointCnt := 0;
|
|
cbLat.Caption := '';
|
|
cbLon.Caption := '';
|
|
edCaption.Text := '';
|
|
end;
|
|
|
|
cbSelectedPt.Text := PtTxt;
|
|
cbSelectedPt.Hint := PtTxt;
|
|
|
|
cbLat.Enabled := HavePt;
|
|
lblLat.Enabled := HavePt;
|
|
cbLon.Enabled := HavePt;
|
|
lblLon.Enabled := HavePt;
|
|
edCaption.Enabled := HavePt and (P0 is TMapPointOfInterest);
|
|
lblCaption.Enabled := edCaption.Enabled;
|
|
|
|
// 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;
|
|
actNewArea.Enabled := HaveView and HaveLayer;
|
|
actNewTP.Enabled := HaveView and HavePt;
|
|
actDelTP.Enabled := HaveView and HavePt and Erasable;
|
|
actSelect.Enabled := HaveView;
|
|
end;
|
|
|
|
function TMapViewerPathEditForm.GetOwnerOfType(ANested: TPersistent;
|
|
AClass: TClass): TPersistent;
|
|
begin
|
|
Result := Nil;
|
|
while Assigned(ANested) do
|
|
if ANested is AClass
|
|
then Exit(ANested)
|
|
else ANested := TPersistentAccess(ANested).GetOwner;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.PersistentAdded(APersistent: TPersistent;
|
|
Select: Boolean);
|
|
begin
|
|
;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.DeletePersistent(APersistent: TPersistent);
|
|
begin
|
|
;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.UnselectPersistent(APersistent: TPersistent);
|
|
begin
|
|
;
|
|
end;
|
|
|
|
procedure TMapViewerPathEditForm.ObjectModified(AObject: TObject;
|
|
PropName: ShortString);
|
|
begin
|
|
;
|
|
end;
|
|
|
|
end.
|
|
|