
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9659 8e941d3f-bd1b-0410-a28a-d453659cc2b4
470 lines
13 KiB
ObjectPascal
470 lines
13 KiB
ObjectPascal
{
|
|
Property editors for LazMapViewer
|
|
Copyright (C) 2019 user alpine at Lazarus forum https://forum.lazarus.freepascal.org
|
|
|
|
License: modified LGPL with linking exception (like RTL, FCL and LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution,
|
|
for details about the license.
|
|
|
|
See also: https://wiki.lazarus.freepascal.org/FPC_modified_LGPL
|
|
}
|
|
unit
|
|
mvMapViewerPropEdits;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Forms, SysUtils, LCLIntf, LCLType, ImgList, LazLoggerBase,
|
|
PropEdits, GraphPropEdits, ComponentEditors,
|
|
mvMapProvider;
|
|
|
|
type
|
|
|
|
{ TMapViewComponentEditor }
|
|
|
|
TMapViewComponentEditor = class(TComponentEditor)
|
|
private
|
|
//FOldDirtyHandler: TNotifyEvent;
|
|
protected
|
|
procedure DoShowPointsEditor;
|
|
procedure DoShowLayerEditor;
|
|
public
|
|
constructor Create(AComponent: TComponent;
|
|
ADesigner: TComponentEditorDesigner); override;
|
|
procedure ExecuteVerb(Index: Integer); override;
|
|
function GetVerb(Index: Integer): String; override;
|
|
function GetVerbCount: Integer; override;
|
|
end;
|
|
|
|
{ TMapLayersPropertyEditor }
|
|
|
|
TMapLayersPropertyEditor = class(TCollectionPropertyEditor)
|
|
public
|
|
class function ShowCollectionEditor(ACollection: TCollection;
|
|
OwnerPersistent: TPersistent; const PropName: String): TCustomForm;
|
|
override;
|
|
end;
|
|
|
|
{ TMapTrackPointsPropertyEditor }
|
|
|
|
TMapTrackPointsPropertyEditor = class(TCollectionPropertyEditor)
|
|
public
|
|
class function ShowCollectionEditor(ACollection: TCollection;
|
|
OwnerPersistent: TPersistent; const PropName: String): TCustomForm;
|
|
override;
|
|
end;
|
|
|
|
{ TMapProviderPropertyEditor }
|
|
|
|
TMapProviderPropertyEditor = class(TStringPropertyEditor)
|
|
public
|
|
function GetAttributes: TPropertyAttributes; override;
|
|
procedure GetValues(Proc: TGetStrProc); override;
|
|
function GetValue: AnsiString; override;
|
|
procedure SetValue(const NewValue: AnsiString); override;
|
|
end;
|
|
|
|
{ TPointOfInterestImageIndexPropertyEditor }
|
|
|
|
TPointOfInterestImageIndexPropertyEditor = class(TImageIndexPropertyEditor)
|
|
protected
|
|
function GetImageList: TCustomImageList; override;
|
|
end;
|
|
|
|
{ TPointDateTimePropertyEditor }
|
|
|
|
TPointDateTimePropertyEditor = class(TDateTimePropertyEditor)
|
|
public
|
|
function GetValue: string; override;
|
|
procedure SetValue(const NewValue: AnsiString); override;
|
|
end;
|
|
|
|
{ TPointElevationPropertyEditor }
|
|
|
|
TPointElevationPropertyEditor = class(TFloatPropertyEditor)
|
|
public
|
|
function GetValue: string; override;
|
|
procedure SetValue(const NewValue: AnsiString); override;
|
|
end;
|
|
|
|
{ TLatLonDMSPropertyEditor }
|
|
|
|
TLatLonDMSPropertyEditor = class(TFloatPropertyEditor)
|
|
private
|
|
function UseDMS: Boolean;
|
|
protected
|
|
procedure EnsureRange(var AValue: Double); virtual;
|
|
procedure GetRange(out AMin, AMax: Double); virtual; abstract;
|
|
public
|
|
procedure SetValue(const NewValue: AnsiString); override;
|
|
end;
|
|
|
|
{ TLatDMSPropertyEditor }
|
|
|
|
TLatDMSPropertyEditor = class(TLatLonDMSPropertyEditor)
|
|
protected
|
|
procedure GetRange(out AMin, AMax: Double); override;
|
|
public
|
|
function GetValue: string; override;
|
|
end;
|
|
|
|
{ TLonDMSPropertyEditor }
|
|
|
|
TLonDMSPropertyEditor = class(TLatLonDMSPropertyEditor)
|
|
protected
|
|
procedure GetRange(out AMin, AMax: Double); override;
|
|
public
|
|
function GetValue: string; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.UITypes, Dialogs, IDEWindowIntf, LazIDEIntf,
|
|
mvMapViewer, mvGpsObj, mvLayersPropEditForm, mvEngine, mvGeoMath,
|
|
mvMapViewerPathEditDsgForm, mvPluginCommon;
|
|
|
|
const
|
|
sNONE = '(none)';
|
|
sEDITMapView = 'Edit MapView Points';
|
|
sLayerEditor = 'Layer Editor...';
|
|
|
|
{ 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: DoShowLayerEditor;
|
|
1: DoShowPointsEditor;
|
|
end;
|
|
end;
|
|
|
|
function TMapViewComponentEditor.GetVerb(Index: Integer): String;
|
|
begin
|
|
Result := '';
|
|
case Index of
|
|
0: Result := sLayerEditor;
|
|
1: Result := sEDITMapView;
|
|
end;
|
|
end;
|
|
|
|
function TMapViewComponentEditor.GetVerbCount: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
procedure TMapViewComponentEditor.DoShowPointsEditor;
|
|
|
|
function FindPopupPoint(AMapView: TMapView): TPoint;
|
|
var
|
|
R: TRect;
|
|
Orig: TPoint; // Top/left corner of map in screen coordinates
|
|
P: TPoint; // EditMark position in screen coordinates
|
|
W, H: Integer; // Width and heigh tof editor form
|
|
begin
|
|
R := Screen.WorkAreaRect;
|
|
W := MapViewerPathEditDsgForm.Width;
|
|
H := MapViewerPathEditDsgForm.Height;
|
|
Orig := AMapView.ClientToScreen(Point(0, 0));
|
|
Result := Orig;
|
|
|
|
// Make sure that the editor form is fully visible vertically
|
|
if Result.Y < R.Top then
|
|
Result.Y := R.Top
|
|
else
|
|
if Result.Y + H > R.Bottom then
|
|
Result.Y := R.Bottom - H - GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSIZEFRAME);
|
|
|
|
// Check position at the right of the map
|
|
Result.X := Orig.X + AMapView.Width;
|
|
if Result.X + W <= R.Right then
|
|
exit;
|
|
|
|
// Check position at the left of the map
|
|
Result.X := Orig.X - W;
|
|
if Result.X >= R.Left then
|
|
exit;
|
|
|
|
if AMapView.EditMark.Visible then
|
|
begin
|
|
// Check position inside. Make sure that the EditMark is not covered by
|
|
// the editor form.
|
|
P := AMapView.LatLonToScreen(AMapView.EditMark.RealPt);
|
|
// Check form position at the right of the EditMark
|
|
Result.X := Orig.X + P.X + 10;
|
|
if Result.X <= R.Right then
|
|
exit;
|
|
// Check form position at the left of the EditMark
|
|
Result.X := Orig.X + P.X - W - 10;
|
|
if Result.X >= R.Left then
|
|
exit;
|
|
end;
|
|
|
|
// Fallback: center
|
|
Result.X := Orig.X + (AMapView.Width - W) div 2;
|
|
end;
|
|
|
|
var
|
|
V: TMapView;
|
|
P: TPoint;
|
|
begin
|
|
if not Assigned(MapViewerPathEditDsgForm) then
|
|
MapViewerPathEditDsgForm := TMapViewerPathEditDsgForm.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;
|
|
P := FindPopupPoint(V);
|
|
MapViewerPathEditDsgForm.MapView := V;
|
|
MapViewerPathEditDsgForm.Left := P.X;
|
|
MapViewerPathEditDsgForm.Top := P.Y;
|
|
MapViewerPathEditDsgForm.Show;
|
|
end;
|
|
|
|
procedure TMapViewComponentEditor.DoShowLayerEditor;
|
|
var
|
|
V: TMapView;
|
|
begin
|
|
V := GetComponent as TMapView;
|
|
if LayersPropertyEditForm = nil then
|
|
LayersPropertyEditForm := TLayersPropertyEditForm.Create(Application);
|
|
LayersPropertyEditForm.SetCollection(V.Layers, V, 'Layers');
|
|
LayersPropertyEditForm.actAdd.Visible := true;
|
|
LayersPropertyEditForm.actDel.Visible := true;
|
|
LayersPropertyEditForm.AddButton.Left := 0;
|
|
LayersPropertyEditForm.DeleteButton.Left := 1;
|
|
LayersPropertyEditForm.DividerToolButton.Show;
|
|
LayersPropertyEditForm.DividerToolButton.Left := LayersPropertyEditForm.DeleteButton.Left + 1;
|
|
SetPopupModeParentForPropertyEditor(LayersPropertyEditForm);
|
|
LayersPropertyEditForm.EnsureVisible;
|
|
LayersPropertyEditForm.UpdateButtons;
|
|
//Result := LayersPropertyEditForm;
|
|
end;
|
|
|
|
|
|
{ TMapLayersPropertyEditor }
|
|
|
|
class function TMapLayersPropertyEditor.ShowCollectionEditor(
|
|
ACollection: TCollection; OwnerPersistent: TPersistent; const PropName: String
|
|
): TCustomForm;
|
|
begin
|
|
if LayersPropertyEditForm = Nil then
|
|
LayersPropertyEditForm := TLayersPropertyEditForm.Create(Application);
|
|
LayersPropertyEditForm.SetCollection(ACollection, OwnerPersistent, PropName);
|
|
LayersPropertyEditForm.actAdd.Visible := true;
|
|
LayersPropertyEditForm.actDel.Visible := true;
|
|
LayersPropertyEditForm.AddButton.Left := 0;
|
|
LayersPropertyEditForm.DeleteButton.Left := 1;
|
|
LayersPropertyEditForm.DividerToolButton.Show;
|
|
LayersPropertyEditForm.DividerToolButton.Left := LayersPropertyEditForm.DeleteButton.Left + 1;
|
|
SetPopupModeParentForPropertyEditor(LayersPropertyEditForm);
|
|
LayersPropertyEditForm.EnsureVisible;
|
|
LayersPropertyEditForm.UpdateButtons;
|
|
Result := LayersPropertyEditForm;
|
|
end;
|
|
|
|
{ TPointElevationPropertyEditor }
|
|
|
|
function TPointElevationPropertyEditor.GetValue: string;
|
|
begin
|
|
Result := inherited GetValue;
|
|
if GetFloatValue = NO_ELE then
|
|
Result := sNONE;
|
|
end;
|
|
|
|
procedure TPointElevationPropertyEditor.SetValue(const NewValue: AnsiString);
|
|
begin
|
|
if (NewValue = sNONE) or (NewValue = '')
|
|
then inherited SetFloatValue(NO_ELE)
|
|
else inherited SetValue(NewValue);
|
|
end;
|
|
|
|
{ TLatLonDMSPropertyEditor }
|
|
|
|
procedure TLatLonDMSPropertyEditor.EnsureRange(var AValue: Double);
|
|
var
|
|
min, max: Double;
|
|
begin
|
|
GetRange(min, max);
|
|
if AValue < min then
|
|
AValue := min
|
|
else if AValue > max then
|
|
AValue := max;
|
|
end;
|
|
|
|
procedure TLatLonDMSPropertyEditor.SetValue(const NewValue: AnsiString);
|
|
var
|
|
Deg: Double;
|
|
FS: TFormatSettings;
|
|
begin
|
|
if not (UseDMS and TryStrDMSToDeg(NewValue, Deg)) then
|
|
begin
|
|
FS := DefaultFormatSettings;
|
|
FS.DecimalSeparator := '.'; //after all, this is Pascal, so we expect a period
|
|
if not TryStrToFloat(NewValue, Deg, FS) then
|
|
//if this failed, assume the user entered DS from his current locale
|
|
Deg := StrToFloat(NewValue, DefaultFormatSettings);
|
|
end;
|
|
EnsureRange(Deg);
|
|
SetFloatValue(Deg);
|
|
end;
|
|
|
|
function TLatLonDMSPropertyEditor.UseDMS: Boolean;
|
|
var
|
|
Inst: TPersistent;
|
|
begin
|
|
Inst := GetComponent(0);
|
|
Result := (Inst is TMapPoint) and TMapPoint(Inst).LatLonInDMS
|
|
or (Inst is TMapCenter) and TMapCenter(Inst).LatLonInDMS;
|
|
end;
|
|
|
|
|
|
{ TLatDMSPropertyEditor }
|
|
|
|
procedure TLatDMSPropertyEditor.GetRange(out AMin, AMax: Double);
|
|
begin
|
|
AMin := -90.0;
|
|
AMax := +90.0;
|
|
end;
|
|
|
|
function TLatDMSPropertyEditor.GetValue: string;
|
|
begin
|
|
if not UseDMS then
|
|
Result := inherited GetValue
|
|
else
|
|
Result := LatToStr(GetFloatValue, True);
|
|
end;
|
|
|
|
{ TLonDMSPropertyEditor }
|
|
|
|
procedure TLonDMSPropertyEditor.GetRange(out AMin, AMax: Double);
|
|
begin
|
|
AMin := -180.0;
|
|
AMax := +180.0;
|
|
end;
|
|
|
|
function TLonDMSPropertyEditor.GetValue: string;
|
|
begin
|
|
if not UseDMS then
|
|
Result := inherited GetValue
|
|
else
|
|
Result := LonToStr(GetFloatValue, True);
|
|
end;
|
|
|
|
{ TPointDateTimePropertyEditor }
|
|
|
|
function TPointDateTimePropertyEditor.GetValue: string;
|
|
begin
|
|
Result := inherited GetValue;
|
|
if GetFloatValue = NO_DATE then
|
|
Result := sNONE;
|
|
end;
|
|
|
|
procedure TPointDateTimePropertyEditor.SetValue(const NewValue: AnsiString);
|
|
begin
|
|
if (NewValue = sNONE) or (NewValue = '')
|
|
then inherited SetFloatValue(NO_DATE)
|
|
else inherited SetValue(NewValue);
|
|
end;
|
|
|
|
{ TPointOfInterestImageIndexPropertyEditor }
|
|
|
|
function TPointOfInterestImageIndexPropertyEditor.GetImageList: TCustomImageList;
|
|
var
|
|
P: TPersistent;
|
|
begin
|
|
Result := Nil;
|
|
P := GetComponent(0);
|
|
if (P is TMapPointOfInterest) then
|
|
begin
|
|
Result := TMapPointOfInterest(P).View.POIImages;
|
|
end;
|
|
end;
|
|
|
|
{ TMapProviderPropertyEditor }
|
|
|
|
function TMapProviderPropertyEditor.GetAttributes: TPropertyAttributes;
|
|
begin
|
|
Result := [paValueList, paPickList, paRevertable];
|
|
end;
|
|
|
|
procedure TMapProviderPropertyEditor.GetValues(Proc: TGetStrProc);
|
|
var
|
|
Providers: TStringList;
|
|
S: String;
|
|
Inst: TPersistent;
|
|
MV: TMapView;
|
|
{%H-}Filter: Boolean = False;
|
|
{%H-}PT: TProjectionType;
|
|
begin
|
|
Inst := GetComponent(0);
|
|
Providers := TStringList.Create;
|
|
try
|
|
if Inst is TMapView then
|
|
MV := TMapView(Inst)
|
|
else if Inst is TMapLayer then
|
|
begin
|
|
MV := TMapLayer(Inst).View;
|
|
Filter := True;
|
|
PT := MV.Engine.MapProjectionType;
|
|
end
|
|
else
|
|
Exit;
|
|
MV.Engine.GetMapProviders(Providers);
|
|
//if not (Inst is TMapView) then
|
|
Proc(sNONE);
|
|
Providers.Sort;
|
|
for S in Providers do
|
|
// TODO: When filtered it is not clear what is the full list.
|
|
//if not Filter or (PT = MV.Engine.MapProviderByName(S).ProjectionType) then
|
|
Proc(S);
|
|
finally
|
|
Providers.Free;
|
|
end;
|
|
end;
|
|
|
|
function TMapProviderPropertyEditor.GetValue: AnsiString;
|
|
begin
|
|
Result := inherited GetValue;
|
|
if Result = '' then
|
|
Result := sNONE;
|
|
end;
|
|
|
|
procedure TMapProviderPropertyEditor.SetValue(const NewValue: AnsiString);
|
|
begin
|
|
if NewValue = sNONE
|
|
then inherited SetValue('')
|
|
else inherited SetValue(NewValue);
|
|
end;
|
|
|
|
end.
|
|
|