1
0
Fork 0

Canvas MapLayers for Airport

Add RWY, TAXI, TWR, PARKING map layers
Add new static position controller
Update Select Airport dialog to use new MapLayers.
This commit is contained in:
Stuart Buchanan 2017-10-13 17:38:27 +01:00
parent 3283e9721f
commit d84c527ca7
11 changed files with 753 additions and 72 deletions

View file

@ -450,7 +450,7 @@ var Group = {
# Map
# ==============================================================================
# Class for a group element on a canvas with possibly geopgraphic positions
# Class for a group element on a canvas with possibly geographic positions
# which automatically get projected according to the specified projection.
# Each map consists of an arbitrary number of layers (canvas groups)
#
@ -502,6 +502,10 @@ var Map = {
return me;
},
getController: func()
{
return me.controller;
},
addLayer: func(factory, type_arg=nil, priority=nil, style=nil, opts=nil, visible=1)
{
if(contains(me.layers, type_arg))

View file

@ -0,0 +1,48 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'PARKING';
var parents = [SymbolLayer.Controller];
var __self__ = caller(0)[0];
SymbolLayer.Controller.add(name, __self__);
SymbolLayer.add(name, {
parents: [MultiSymbolLayer],
type: name, # Symbol type
df_controller: __self__, # controller to use by default -- this one
df_style: {
line_width: 3,
scale_factor: 1,
debug: 1,
color_default: [0,0.85,0.6],
label_font_color:[0,0.85,0.6],
label_font_size: 28,
text_offset: [10,0],
svg_path: nil
},
df_options: { # default configuration options
disable_position: 1,
},
});
var a_instance = nil;
var new = func(layer) {
var m = {
parents: [__self__],
layer: layer,
map: layer.map,
listeners: [],
};
m.addVisibilityListener();
return m;
};
var del = func() {
#print(name,".lcontroller.del()");
foreach (var l; me.listeners)
removelistener(l);
};
var searchCmd = func {
#print("Running query:", name);
var range = me.map.getRange();
if (range == nil) return;
return positioned.findAirportsWithinRange(me.map.getPosCoord(), range);
};

View file

@ -0,0 +1,46 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'PARKING';
var parents = [DotSym];
var __self__ = caller(0)[0];
DotSym.makeinstance( name, __self__ );
var element_type = "group"; # we want a group, becomes "me.element"
var rwys = nil;
var init = func {
var apt=airportinfo(me.model.id);
var style = me.layer.style;
var svg_path = style.svg_path;
var group = me.element.createChild("group", "parking-"~apt.id);
foreach(var park; apt.parking()) {
var p = me.element.createChild("group", "parking-"~park.name);
p.setGeoPosition(park.lat, park.lon);
if (svg_path != nil) {
canvas.parsesvg(p, svg_path);
} else {
p.createChild("path", name ~ " icon" )
.moveTo(-10,-10)
.lineTo(10,10)
.moveTo(10,-10)
.lineTo(-10,10)
.close()
.setColor(style.color_default)
.setStrokeLineWidth(style.line_width)
.setScale(style.scale_factor);
}
p.createChild("text", "parking-" ~ park.name)
.setDrawMode( canvas.Text.ALIGNMENT
+ canvas.Text.TEXT )
.setTranslation([style.scale_factor * style.text_offset[0], style.scale_factor * style.text_offset[1]])
.setText(park.name)
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
.setColor(style.label_font_color)
.setFontSize(style.label_font_size, 1.3)
.setScale(style.scale_factor);
}
};
var draw = func;

View file

@ -0,0 +1,41 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'RWY';
var parents = [SymbolLayer.Controller];
var __self__ = caller(0)[0];
SymbolLayer.Controller.add(name, __self__);
SymbolLayer.add(name, {
parents: [MultiSymbolLayer],
type: name, # Symbol type
df_controller: __self__, # controller to use by default -- this one
df_style: {
surface_color: canvas.SURFACECOLORS
},
df_options: { # default configuration options
disable_position: 1,
},
});
var a_instance = nil;
var new = func(layer) {
var m = {
parents: [__self__],
layer: layer,
map: layer.map,
listeners: [],
};
m.addVisibilityListener();
return m;
};
var del = func() {
#print(name,".lcontroller.del()");
foreach (var l; me.listeners)
removelistener(l);
};
var searchCmd = func {
#print("Running query:", name);
var range = me.map.getRange();
if (range == nil) return;
return positioned.findAirportsWithinRange(me.map.getPosCoord(), range);
};

137
Nasal/canvas/map/RWY.symbol Normal file
View file

@ -0,0 +1,137 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'RWY';
var parents = [DotSym];
var __self__ = caller(0)[0];
DotSym.makeinstance( name, __self__ );
var element_type = "group"; # we want a group, becomes "me.element"
var rwys = nil;
var SURFACECOLORS = {
1 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
2 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
3 : { type: "turf", r:0.2, g:0.5, b:0.2 },
4 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
5 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
# Helipads
6 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
7 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
8 : { type: "turf", r:0.2, g:0.5, b:0.2 },
9 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
0 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
};
var init = func {
var apt=airportinfo(me.model.id);
var rwys = apt.runwaysWithoutReciprocals();
foreach (var rw1; rwys)
{
var clr = me.style.surface_color[rw1.surface];
if (clr == nil) { clr = SURFACECOLORS[rw1.surface]};
if (clr == nil) { clr = SURFACECOLORS[0]};
var icon_rw =
me.element.createChild("path", "runway-" ~ rw1.id)
.setStrokeLineWidth(0.5)
.setColor(1.0,1.0,1.0)
.setColorFill(clr.r, clr.g, clr.b);
var rwy1 = Runway.new(rw1);
var beg_thr = rwy1.pointOffCenterline(rw1.threshold);
var beg_thr1 = rwy1.pointOffCenterline(rw1.threshold, 0.5 * rw1.width);
var beg_thr2 = rwy1.pointOffCenterline(rw1.threshold, -0.5 * rw1.width);
var beg1 = rwy1.pointOffCenterline(0, 0.5 * rw1.width);
var beg2 = rwy1.pointOffCenterline(0, -0.5 * rw1.width);
var rw2 = rw1.reciprocal;
var rwy2 = Runway.new(rw2);
var end_thr = rwy2.pointOffCenterline(rw2.threshold);
var end_thr1 = rwy2.pointOffCenterline(rw2.threshold, 0.5 * rw2.width);
var end_thr2 = rwy2.pointOffCenterline(rw2.threshold, -0.5 * rw2.width);
var end1 = rwy2.pointOffCenterline(0, 0.5 * rw2.width);
var end2 = rwy2.pointOffCenterline(0, -0.5 * rw2.width);
icon_rw.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_CLOSE_PATH ],
[ beg1[0], beg1[1],
beg2[0], beg2[1],
end1[0], end1[1],
end2[0], end2[1] ]
);
var icon_cl =
me.element.createChild("path", "centerline")
.setStrokeLineWidth(0.5)
.setColor(1,1,1)
.setStrokeDashArray([15, 10]);
icon_cl.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO ],
[ beg_thr[0], beg_thr[1],
end_thr[0], end_thr[1] ]
);
var icon_thr =
me.element.createChild("path", "threshold")
.setStrokeLineWidth(1.5)
.setColor(1,1,1);
icon_thr.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO ],
[ beg_thr1[0], beg_thr1[1],
beg_thr2[0], beg_thr2[1],
end_thr1[0], end_thr1[1],
end_thr2[0], end_thr2[1] ]
);
#draw helipads
foreach(var hp; keys(apt.helipads))
{
var hp = apt.runway(hp);
var clr = me.style.surface_color[hp.surface];
if (clr == nil) { clr = SURFACECOLORS[hp.surface]};
if (clr == nil) { clr = SURFACECOLORS[0]};
var icon_hp =
me.element.createChild("path", "helipad-" ~ hp.id)
.setStrokeLineWidth(0.5)
.setColor(1.0,1.0,1.0)
.setColorFill(clr.r, clr.g, clr.b);
var heli = Runway.new(hp);
var p1 = heli.pointOffCenterline(0.5 * hp.length, 0.5 * hp.width);
var p2 = heli.pointOffCenterline(0.5 * hp.length, -0.5 * hp.width);
var p3 = heli.pointOffCenterline(-0.5 * hp.length, -0.5 * hp.width);
var p4 = heli.pointOffCenterline(-0.5 * hp.length, 0.5 * hp.width);
icon_hp.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_CLOSE_PATH ],
[ p1[0], p1[1],
p2[0], p2[1],
p3[0], p3[1],
p4[0], p4[1] ]
);
}
}
};
var draw = func;

View file

@ -0,0 +1,41 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'TAXI';
var parents = [SymbolLayer.Controller];
var __self__ = caller(0)[0];
SymbolLayer.Controller.add(name, __self__);
SymbolLayer.add(name, {
parents: [MultiSymbolLayer],
type: name, # Symbol type
df_controller: __self__, # controller to use by default -- this one
df_style: {
surface_color: canvas.SURFACECOLORS,
},
df_options: { # default configuration options
disable_position: 1,
},
});
var a_instance = nil;
var new = func(layer) {
var m = {
parents: [__self__],
layer: layer,
map: layer.map,
listeners: [],
};
m.addVisibilityListener();
return m;
};
var del = func() {
#print(name,".lcontroller.del()");
foreach (var l; me.listeners)
removelistener(l);
};
var searchCmd = func {
#print("Running query:", name);
var range = me.map.getRange();
if (range == nil) return;
return positioned.findAirportsWithinRange(me.map.getPosCoord(), range);
};

View file

@ -0,0 +1,60 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'TAXI';
var parents = [DotSym];
var __self__ = caller(0)[0];
DotSym.makeinstance( name, __self__ );
var element_type = "group"; # we want a group, becomes "me.element"
var rwys = nil;
var SURFACECOLORS = {
1 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
2 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
3 : { type: "turf", r:0.2, g:0.5, b:0.2 },
4 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
5 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
# Helipads
6 : { type: "asphalt", r:0.2, g:0.2, b:0.2 },
7 : { type: "concrete", r:0.3, g:0.3, b:0.3 },
8 : { type: "turf", r:0.2, g:0.5, b:0.2 },
9 : { type: "dirt", r:0.4, g:0.3, b:0.3 },
0 : { type: "gravel", r:0.35, g:0.3, b:0.3 },
};
var init = func {
var apt=airportinfo(me.model.id);
foreach (var taxi; apt.taxiways)
{
var clr = me.style.surface_color[taxi.surface];
if (clr == nil) { clr = SURFACECOLORS[taxi.surface]};
if (clr == nil) { clr = SURFACECOLORS[0]};
var taxi_paths =
me.element.createChild("path", "runway-" ~ taxi.id)
.setStrokeLineWidth(0.5)
.setColor(clr.r, clr.g, clr.b)
.setColorFill(clr.r, clr.g, clr.b);
var txi = Runway.new(taxi);
var beg1 = txi.pointOffCenterline(0, 0.5 * taxi.width);
var beg2 = txi.pointOffCenterline(0, -0.5 * taxi.width);
var end1 = txi.pointOffCenterline(taxi.length, 0.5 * taxi.width);
var end2 = txi.pointOffCenterline(taxi.length, -0.5 * taxi.width);
taxi_paths.setColorFill(clr.r, clr.g, clr.b)
.setDataGeo
(
[ canvas.Path.VG_MOVE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_LINE_TO,
canvas.Path.VG_CLOSE_PATH ],
[ beg1[0], beg1[1],
beg2[0], beg2[1],
end2[0], end2[1],
end1[0], end1[1] ]
);
}
};
var draw = func;

View file

@ -0,0 +1,42 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'TWR';
var parents = [SymbolLayer.Controller];
var __self__ = caller(0)[0];
SymbolLayer.Controller.add(name, __self__);
SymbolLayer.add(name, {
parents: [MultiSymbolLayer],
type: name, # Symbol type
df_controller: __self__, # controller to use by default -- this one
df_style: {
color: { r:0.2, g:0.2, b:1.2 },
line_width: 1,
},
df_options: { # default configuration options
disable_position: 1,
},
});
var a_instance = nil;
var new = func(layer) {
var m = {
parents: [__self__],
layer: layer,
map: layer.map,
listeners: [],
};
m.addVisibilityListener();
return m;
};
var del = func() {
#print(name,".lcontroller.del()");
foreach (var l; me.listeners)
removelistener(l);
};
var searchCmd = func {
#print("Running query:", name);
var range = me.map.getRange();
if (range == nil) return;
return positioned.findAirportsWithinRange(me.map.getPosCoord(), range);
};

View file

@ -0,0 +1,31 @@
# See: http://wiki.flightgear.org/MapStructure
# Class things:
var name = 'TWR';
var parents = [DotSym];
var __self__ = caller(0)[0];
DotSym.makeinstance( name, __self__ );
var element_type = "group"; # we want a group, becomes "me.element"
var init = func {
var apt=airportinfo(me.model.id);
var clr = me.style.color;
var line_width = me.style.line_width;
var icon_tower =
me.element.createChild("path", "tower")
.setStrokeLineWidth(line_width)
.setScale(1.5)
.setColor(clr.r, clr.g, clr.b)
.moveTo(-3, 0)
.vert(-10)
.line(-3, -10)
.horiz(12)
.line(-3, 10)
.vert(10);
icon_tower.setGeoPosition(apt.tower().lat, apt.tower().lon);
};
var draw = func;

View file

@ -0,0 +1,74 @@
# Class things:
var parents = [Map.Controller];
var __self__ = caller(0)[0];
Map.Controller.add("Static position", __self__);
#Map.df_controller = __self__;
##
# A controller to handle static updates of position, for example an airport
# diagram or non-moving map.
#
# Note that in contrast to the Aircraft Controllers, update_pos() or
# update_layers() must be called explicitly to trigger an update of the map.
##
var new = func(map, source='main') {
var m = {
parents: [__self__],
map: map,
_pos: nil, _time: nil, _range: nil,
_alt: 0, _hdg: 0,
};
m._pos = geo.Coord.new();
m._pos.set_latlon(0.0,0.0);
m.update_pos();
return m;
};
var del = func(map) {
if (map != me.map) die();
};
var setHeading = func(hdg) { me._hdg = hdg; };
var setAltitude = func(alt) { me._alt = alt; };
var getHeading = func() { return me._hdg; };
var getAltitude = func() { return me._alt; };
var setPosition = func(lat, lon) {
me._pos.set_latlon(lat, lon);
me.update_pos();
};
var applyOffset = func(x, y) {
# Apply an offset in screen coordinates, e.g. from a mouse event
var crs = 0.0;
if (x != 0.0) {
# Calculate course in degrees
crs = 90.0 + 180.0 / math.pi * math.atan(y/x);
if (x < 0.0 ) crs = crs + 180.0;
} else {
if (y < 0.0) crs = 0.0;
if (y > 0.0) crs = 180.0
}
# Screen resolution m/pixel is range/screen_range
var screen_range = me.map.getScreenRange() or 200;
var screen_resolution = me.map.getRange() * globals.NM2M / screen_range;
me._pos.apply_course_distance(crs, math.sqrt(x*x + y*y) * screen_resolution);
me.update_pos();
};
# Controller methods
var update_pos = func {
me.map.setPos(lat: me._pos.lat(), lon: me._pos.lon(),
hdg: me._hdg,,
alt: me._alt,);
me.map.update();
};
var update_layers = func {
me.map.update();
};
var get_position = func {
return [ me._pos.lat(), me._pos.lon() ];
}

View file

@ -42,15 +42,16 @@
var MAX_RUNWAYS = 28; # number of entries at KEDW
var DIALOG = cmdarg();
var listeners = [];
## "prologue" currently required by the canvas-generic-map
var dialog_name ="airports"; #TODO: use substr() and cmdarg() to get this dynamically
var dialog_property = func(p) return "/sim/gui/dialogs/airports/"~p; #TODO: generalize using cmdarg
var DIALOG_CANVAS = gui.findElementByName(DIALOG, "airport-selection");
canvas.GenericMap.setupGUI(DIALOG_CANVAS, "canvas-control"); #TODO: this is not a method!
## end of canvas-generic-map prologue
setprop("/sim/gui/dialogs/airports/selected-airport/lat", 0);
setprop("/sim/gui/dialogs/airports/selected-airport/lon", 0);
setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
setprop("/sim/gui/dialogs/airports/mode", "search");
@ -115,9 +116,11 @@
setprop("/sim/gui/dialogs/airports/selected-airport/name", info.name);
setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lat, info.lon));
setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon);
setprop("/sim/gui/dialogs/airports/selected-airport/lat", info.lat);
setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation);
setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
AirportChart.getController().setPosition(info.lat, info.lon);
if (info.has_metar) {
# Retrieve an updated METAR, and indicate that we've not got one currently.
@ -247,11 +250,15 @@
canvas.register_callback(update_info); # FIXME: this is a workaround to run dialog-specific code in the canvas block
]]>
</open>
<close>
<close><![CDATA[
fgcommand("clear-metar", var n = props.Node.new({ "path": "/sim/gui/dialogs/airports/selected-airport/metar",
"station": airport_id}));
map.cleanup_listeners(); #TODO: We should be setting a signal when closing the dialog, so that cleanup code can be invoked automatically
</close>
#map.cleanup_listeners(); #TODO: We should be setting a signal when closing the dialog, so that cleanup code can be invoked automatically
AirportChart.del();
foreach (var l; listeners)
removelistener(l);
setsize(listeners, 0);
]]></close>
</nasal>
<group>
@ -648,86 +655,236 @@
<hrule><stretch>1</stretch></hrule>
</group>
<!-- Instantiate a generic canvas map and parametrize it via inclusion -->
<!-- TODO: use params and aliasing -->
<canvas include="/Nasal/canvas/generic-canvas-map.xml">
<canvas>
<name>canvas-map</name>
<valign>fill</valign>
<halign>fill</halign>
<stretch>true</stretch>
<pref-width>600</pref-width>
<pref-height>400</pref-height>
<nasal><load><![CDATA[
var myCanvas = canvas.get( cmdarg() );
var mapGrp = myCanvas.createGroup();
var AirportChart = mapGrp.createChild("map");
<name>airport-selection</name>
<valign>fill</valign>
<halign>fill</halign>
<stretch>true</stretch>
<pref-width>400</pref-width>
<pref-height>400</pref-height>
# Initialize the controller:
AirportChart.setController("Static position", "main");
var controller = AirportChart.getController();
<features>
<!-- TODO: use params and aliases to make this shorter -->
<!-- TODO: support styling, i.e. image sets/fonts and colors to be used -->
<!-- this will set up individual "layers" and map them to boolean "toggle" properties -->
<!-- providing an optional "description" tag here allows us to create all checkboxes procedurally -->
<dialog-root>/sim/gui/dialogs/airports</dialog-root>
<range-property>zoom</range-property>
# Initialize a range and screen resolution. Setting a range
# to 4nm means we pick up a good set of surrounding fixes
# We will use the screen range for zooming. If we use range
# then as we zoom in the airport center goes out of range
# and all the runways disappear.
AirportChart.setRange(4.0);
AirportChart.setScreenRange(500);
<!-- These are the ranges available for the map: var ranges = [0.1, 0.25, 0.5, 1, 2.5, 5] -->
var range_step = 1.5;
<ranges>
<range>0.1</range>
<range>0.25</range>
<range>0.5</range>
<range>1</range>
<range>2.5</range>
<range>5</range>
</ranges>
# Center the map's origin: FIXME: move to api.nas, i.e. allow maps to have a size/view that differs from the actual canvas ??
AirportChart.setTranslation(
myCanvas.get("view[0]")/2,
myCanvas.get("view[1]")/2
);
<!-- available layers and their toggle property (appended to dialog-root specified above) -->
##
# Styling: This is a bit crude at the moment, i.e. no dedicated APIs yet - but it's
# just there to prototype things for now
var Styles = {};
Styles.get = func(type) return Styles[type];
var Options = {};
Options.get = func(type) return Options[type];
<layer>
<name>runways</name> <!-- the name of the layer -->
<init-property>selected-airport/id</init-property> <!-- the init/input property that re-inits the layer MODEL -->
<property>display-runways</property> <!-- the property switch that toggles the layer on/off (show/hide) -->
<description>Show Runways</description> <!-- the checkbox label for the property -->
<default>enabled</default> <!-- default state -->
<hide-checkbox>true</hide-checkbox> <!-- if the checkbox should be shown or hidden -->
</layer>
<layer>
<name>taxiways</name>
<init-property>selected-airport/id</init-property>
<property>display-taxiways</property>
<description>Show Taxiways</description>
<default>enabled</default>
</layer>
## set up a few keys supported by the DME.symbol file to customize appearance:
Styles.DME = {};
Styles.DME.debug = 1; # HACK for benchmarking/debugging purposes
Styles.DME.animation_test = 0; # for prototyping animated symbols
<layer>
<name>parkings</name>
<init-property>selected-airport/id</init-property>
<property>display-parking</property>
<description>Show Parking</description>
<default>disabled</default>
</layer>
Styles.DME.scale_factor = 0.4; # 40% (applied to whole group)
Styles.DME.line_width = 3.0;
Styles.DME.color_tuned = [0,1,0]; #rgb
Styles.DME.color_default = [1,1,0]; #rgb
<layer>
<name>towers</name>
<init-property>selected-airport/id</init-property>
<property>display-tower</property>
<description>Show Tower</description>
<default>enabled</default>
</layer>
<!-- Uncomment this to add a navaid layer (not yet fully implemented, and no LOD yet)
<layer>
<name>navaids</name>
<init-property>selected-airport/id</init-property>
<property>display-navaids</property>
<description>Display Navaids within current range</description>
<default>disabled</default>
</layer>
-->
Styles.APT = {};
Styles.APT.scale_factor = 0.4; # 40% (applied to whole group)
Styles.APT.line_width = 3.0;
Styles.APT.color_default = [0,0.6,0.85]; #rgb
Styles.APT.label_font_color = Styles.APT.color_default;
Styles.APT.label_font_size=28;
</features>
Styles.PARKING = {};
Styles.PARKING.scale_factor = 0.4; # 40% (applied to whole group)
Styles.PARKING.line_width = 3.0;
Styles.PARKING.color_default = [0,0.85,0.6]; #rgb
Styles.PARKING.label_font_color = Styles.APT.color_default;
Styles.PARKING.label_font_size=28;
Styles.FLT = {};
Styles.FLT.line_width = 3;
Styles.FIX = {};
Styles.FIX.color = [1,0,0];
Styles.FIX.scale_factor = 0.4; # 40%
Styles.VOR = {};
Styles.VOR.range_line_width = 2;
Styles.VOR.radial_line_width = 1;
Styles.VOR.scale_factor = 0.6; # 60%
var ToggleLayerVisible = func(name) {
(var l = AirportChart.getLayer(name)).setVisible(l.getVisible());
};
var SetLayerVisible = func(name,n=1) {
AirportChart.getLayer(name).setVisible(n);
};
Styles.APS = {};
Styles.APS.scale_factor = 0.25;
var r = func(name,vis=1,zindex=nil) return caller(0)[0];
# TODO: we'll need some z-indexing here, right now it's in the layer order
foreach(var type; [r('TAXI',1,0),r('RWY',1,1),r('TWR',1,2),r('DME',0,3),r('VOR',0,4),r('NDB',0,5),r('FIX',0,6),r('PARKING',0,7)] ) {
AirportChart.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,
visible: type.vis, priority: 4,
style: Styles.get(type.name),
options: Options.get(type.name) );
(func {
# Notify MapStructure about layer visibility changes:
var name = type.name;
props.globals.initNode("/sim/gui/dialogs/map-canvas/draw-"~name, type.vis, "BOOL");
append(listeners,
setlistener("/sim/gui/dialogs/map-canvas/draw-"~name,
func(n) SetLayerVisible(name,n.getValue()))
);
})();
}
# Add some event listeners to handle mouse interactions
myCanvas.addEventListener("drag", func(e)
{
(func {
controller.applyOffset(-e.deltaX, -e.deltaY); })();
});
myCanvas.addEventListener("click", func(e)
{
(func {
controller.applyOffset(e.localX - myCanvas.get("view[0]")/2,
e.localY - myCanvas.get("view[1]")/2); })();
});
myCanvas.addEventListener("wheel", func(e)
{
var range = AirportChart.getScreenRange();
if (e.deltaY >0) {
if (range < 10000)
AirportChart.setScreenRange(range*range_step);
} else {
if (range > 100)
AirportChart.setScreenRange(range/range_step);
}
setprop("/sim/gui/dialogs/airports/zoom-range", AirportChart.getScreenRange());
});
if ((getprop("/sim/gui/dialogs/airports/selected-airport/lat") != nil) and
(getprop("/sim/gui/dialogs/airports/selected-airport/lon") != nil) )
{
# If we've got some values from a previous instantiation of the dialog
# then use them to display the correct position, consistent with the
# rest of the dialog.
AirportChart.getController().setPosition(
getprop("/sim/gui/dialogs/airports/selected-airport/lat"),
getprop("/sim/gui/dialogs/airports/selected-airport/lon"));
}
]]></load></nasal>
</canvas>
<group>
<name>canvas-control</name> <!-- this is the handle we use to procedurally add all "toggle layer" checkboxes and the zoom control-->
<layout>hbox</layout>
<checkbox>
<label>Nav data</label>
<halign>left</halign>
<property>/sim/gui/dialogs/map-canvas/draw-DME</property>
<live>true</live>
<binding>
<command>property-toggle</command>
</binding>
<binding>
<command>nasal</command>
<script>
var visible = ! getprop("/sim/gui/dialogs/map-canvas/draw-DME");
setprop("/sim/gui/dialogs/map-canvas/draw-DME", visible);
setprop("/sim/gui/dialogs/map-canvas/draw-VOR", visible);
setprop("/sim/gui/dialogs/map-canvas/draw-NDB", visible);
setprop("/sim/gui/dialogs/map-canvas/draw-FIX", visible);
</script>
<binding>
<command>dialog-apply</command>
</binding>
</binding>
</checkbox>
<checkbox>
<label>Parking</label>
<halign>left</halign>
<property>/sim/gui/dialogs/map-canvas/draw-PARKING</property>
<live>true</live>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>property-toggle</command>
</binding>
</checkbox>
<empty><stretch>1</stretch></empty>
<button>
<name>zoomout</name>
<legend>+</legend>
<pref-width>52</pref-width>
<pref-height>22</pref-height>
<binding>
<command>nasal</command>
<script>
var range = AirportChart.getScreenRange();
if (range &lt; 10000)
AirportChart.setScreenRange(range*range_step);
setprop("/sim/gui/dialogs/airports/zoom-range", AirportChart.getScreenRange());
</script>
</binding>
</button>
<text>
<name>zoomdisplay</name>
<label>MMMMMMMMMMMMM</label>
<format>Zoom %d</format>
<property>/sim/gui/dialogs/airports/zoom-range</property>
<live>true</live>
</text>
<button>
<name>zoomin</name>
<legend>-</legend>
<pref-width>52</pref-width>
<pref-height>22</pref-height>
<binding>
<command>nasal</command>
<script>
var range = AirportChart.getScreenRange();
if (range &gt; 100)
AirportChart.setScreenRange(range/range_step);
setprop("/sim/gui/dialogs/airports/zoom-range", AirportChart.getScreenRange());
</script>
</binding>
</button>
</group>
</group>
</group>