diff --git a/Aircraft/Instruments-3d/GPSmap196/animation.nas b/Aircraft/Instruments-3d/GPSmap196/animation.nas
new file mode 100644
index 0000000..eaeda82
--- /dev/null
+++ b/Aircraft/Instruments-3d/GPSmap196/animation.nas
@@ -0,0 +1 @@
+print("Loading animation.nas");
diff --git a/Aircraft/Instruments-3d/GPSmap196/gpsmap196.nas b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.nas
index 27088bc..7bde67f 100644
--- a/Aircraft/Instruments-3d/GPSmap196/gpsmap196.nas
+++ b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.nas
@@ -1,48 +1,83 @@
-
-
+##
+# this is where we will handle all animations for instruments through properties & timers
+# (yet to come)
+# NOTE: this will file will be moved into $FG_ROOT/Nasal/canvas at some point
+io.include("animation.nas");
+
+###
+# helpers for creating a MFD instrument with pages, modes, buttons etc
+# NOTE: this will file will be moved into $FG_ROOT/Nasal/canvas at some point
+io.include("mfd.nas");
+
+##
+# the setup of the various pages supported by this device
+#
+io.include("gpsmap196.pages");
+
+
+##
+# top-level instrument class
+#
var GPSmap196 = {
id:0,
############
- new: func(placement='gps196.screen') {
- print("Load Garmin GPSmap196 canvas");
+ new: func(placement='gps196.screen', name='GPSmap196-screen') {
+ print("Loading Garmin GPSmap196 canvas");
m = { parents : [GPSmap196] };
+
m.buttons = {};
- m.pages = {panel:nil, map:nil, route:nil, position:nil};
m.gmt = props.globals.getNode("sim/time/gmt");
m.node = props.globals.initNode("/instrumentation/gps196",GPSmap196.id+=1);
m.selectedPage = m.node.initNode("selected-page", 0, "INT");
+ m.gpsmap196Screen = canvas.new({
+ "name": name,
+ "size": [512, 512], # TODO: make configurable via ctor
+ "view": [320, 240], # TODO: make configurable via ctor
+ "mipmapping": 1
+ });
+
+ m.gpsmap196Screen.addPlacement({"node": placement});
+ m.root = m.gpsmap196Screen.createGroup();
+
+ # set up a page manager class for managing all our pages
+ m.page_mgr = MFDPageMgr.new( root:m.root );
+
+ ## initialize all button properties
var buttons = [ 'rocker-up', 'button-in', 'button-dto', 'button-out',
'button-menu', 'button-nrst', 'button-page', 'button-quit',
'button-down', 'rocker-left', 'button-power', 'rocker-right',
'button-enter' ];
- # to access, use: m.buttons['rocker-up']
- foreach(var btn; buttons)
- m.buttons[btn] = m.node.initNode("inputs/"~btn, 0, "BOOL");
+ # to access, use e.g.: me.buttons['rocker-up']
+ foreach(var btn; buttons) {
+ var p = m.buttons[btn] = m.node.initNode("inputs/"~btn, 0, "BOOL");
+ # now set up a listener for each button so that the page manager gets notified for event handling
+ setlistener(p, m.page_mgr.makeEventHandler(btn) )
+ }
- m.gpsmap196Screen = canvas.new({
- "name": "GPSmap196-screen",
- "size": [512, 512],
- "view": [320, 240],
- "mipmapping": 1
- });
- m.gpsmap196Screen.addPlacement({"node": placement});
- m.root = m.gpsmap196Screen.createGroup();
+ # now add a few pages to the page manager, using a list with hashes containing a name and the class implementing the page
+ foreach(var page; [
+ # you can uncomment these to add other pages (see gpsmap196.pages)
+ #{name:'page-position', class:MFDPositionPage},
+ #{name:'page-route', class:MFDRoutePage},
+ {name:'page-map', class:MFDMapPage},
+ {name:'page-panel', class:MFDPanelPage}] ) # add new pages here (class names in gpsmap196.pages)
+ m.page_mgr.registerPage(page.name, page.class );
+
+ # set starting/main page
+ m.page_mgr.setActivePage("page-map");
m.timers = [];
- m.initMap();
- m.initPanel();
-if(0){
- m.initRoute();
- m.initPosition();
-}
- append( m.timers, var update_timer=maketimer(0.1, func m.update()) );
+
+if(0) {
+ append( m.timers, var update_timer=maketimer(0.85, func m.update()) );
update_timer.start();
+}
return m;
},
@@ -51,79 +86,19 @@ if(0){
del: func {
foreach(var t; me.timers) {
t.stop();
- t=nil;
}
+ me.timers = nil;
print("GPSmap196: cleanup finished");
},
############
- initRoute: func() {
- canvas.parsesvg(var data = me.root.createChild("group", "page-route"), 'Aircraft/Instruments-3d/GPSmap196/pages/page-route.svg');
- me.pages.route = data;
- data.hide();
- },
-
- ############
- initPosition: func() {
- canvas.parsesvg(var data = me.root.createChild("group", "page-position"), 'Aircraft/Instruments-3d/GPSmap196/pages/page-position.svg');
- me.pages.position = data;
- data.hide();
- },
-
- ############
- initPanel: func() {
- canvas.parsesvg(var data = me.root.createChild("group", "page-panel"), 'Aircraft/Instruments-3d/GPSmap196/pages/page-panel.svg');
- me.pages.panel = data;
- data.hide();
- },
-
- ############
- initMap:func() {
- me.pages.map = me.root.createChild("map").hide();
- me.pages.map.setController("Aircraft position");
- me.pages.map.setRange(10);
-
- me.pages.map.setTranslation(
- me.gpsmap196Screen.get("view[0]")/2,
- me.gpsmap196Screen.get("view[1]")/2
- );
- var style = {scale_factor:0.3, line_width:2, animation_test:0, color_default:[1,0,0], color_tuned:[0,1,1]};
- var r = func(name,vis=1,zindex=nil) return caller(0)[0];
- foreach(var type; [r('DME',0),r('APT'), ] )
- me.pages.map.addLayer(factory: canvas.SymbolLayer, type_arg: type.name, visible: type.vis, priority: type.zindex,style:style);
-
- canvas.parsesvg( var symbol=me.pages.map.createChild("group","airplane-symbol"), 'Nasal/canvas/map/boeingAirplane.svg');
- symbol.setScale( 0.25 );
- },
-
- ############
update: func() {
-
- if(me.buttons['button-page'].getBoolValue()){
- me.selectedPage.setIntValue( me.selectedPage.getValue() + 1 );
- if(me.selectedPage.getValue() > 3) me.selectedPage.setIntValue(0);
- }
-
- me.pages.map.hide();
- me.pages.panel.hide();
-if(0){
- me.pages.route.hide();
- me.pages.position.hide();
-}
-
- if(me.selectedPage.getValue() == 0)
- me.pages.map.show();
- elsif(me.selectedPage.getValue() == 1)
- me.pages.panel.show();
-# elsif(me.selectedPage.getValue() == 2)
-# me.pages.route.show();
-# elsif(me.selectedPage.getValue() == 3)
-# me.pages.position.show();
-
+ print("no longer used....");
}
};
+# FIXME: handle reset/re-init
setlistener("sim/signals/fdm-initialized", func() {
gpsmap196Canvas = GPSmap196.new();
});
diff --git a/Aircraft/Instruments-3d/GPSmap196/gpsmap196.pages b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.pages
new file mode 100644
index 0000000..57c681f
--- /dev/null
+++ b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.pages
@@ -0,0 +1,109 @@
+##
+# this file contains all MFD pages for the gpsmap196
+# for generic MFD functionality, please extend mfd.nas directly
+# animations should not be handled here, see animation.nas instead
+
+var dummy_event_handler = func return func(event) {
+ print(me.page," event received of type:", event);
+};
+
+
+##
+# a MFD position page
+var MFDPositionPage = {
+ new: func(group,page,mgr) {
+ return { manager:mgr,
+ parents: [MFDPositionPage, MFDPage.new(
+ root:group,
+ page:page,
+ filename:'Aircraft/Instruments-3d/GPSmap196/page-position.svg'),
+ MFDPositionPage],
+ };
+ }, # new
+ handleEvent: dummy_event_handler(),
+};
+
+
+##
+# a MFD route page
+var MFDRoutePage = {
+ new: func(group,page,mgr) {
+ return {manager:mgr,
+ parents: [MFDRoutePage, MFDPage.new(
+ root:group,
+ page:page,
+ filename:'Aircraft/Instruments-3d/GPSmap196/pages/page-route.svg')],
+ };
+ }, # new
+
+ handleEvent: dummy_event_handler(),
+};
+
+
+##
+# a MFD panel page
+var MFDPanelPage = {
+ new: func(group,page, mgr) {
+ return { manager: mgr,
+ parents: [MFDPanelPage, MFDPage.new(
+ root:group,
+ page:page,
+ filename:'Aircraft/Instruments-3d/GPSmap196/pages/page-panel.svg')],
+ };
+ }, # new
+
+ handleEvent: func(event) { # dummy_event_handler(),
+ print("Panel page event triggered:", event);
+
+ # NOTE: this is prepared to be fully replaced, but it's better than the old code
+ if (event == 'button-page')
+ me.manager.setActivePage('page-map');
+
+ },# handleEvent
+};
+
+##
+# a MFD page for mapping
+# this uses the MapStructure framework, so not a single SVG file here
+#
+var MFDMapPage = {
+ new: func(group, page, mgr) {
+ var m = {parents:[ MFDMapPage, MFDPage ]};
+
+ var map = group.createChild("map").hide();
+ map.setController("Aircraft position");
+ map.setRange(10);
+
+ # FIXME
+ map.setTranslation(
+ 320 /2, # me.gpsmap196Screen.get("view[0]")/2,
+ 240 / 2 # me.gpsmap196Screen.get("view[1]")/2
+ );
+ # styling
+ var style = { scale_factor:0.3, line_width:2, animation_test:0,
+ color_default:[1,0,0], color_tuned:[0,1,1]};
+ var r = func(name,vis=1,zindex=nil) return caller(0)[0];
+ foreach(var type; [r('DME',0),r('VOR'), ] )
+ map.addLayer( factory: canvas.SymbolLayer,
+ type_arg: type.name,
+ visible: type.vis,
+ priority: type.zindex,
+ style:style);
+ m.page = page;
+ m.group = map;
+ m.manager = mgr;
+ print("Map setup completed");
+ return m; # ??
+ },
+
+ handleEvent: func(event) {
+ print("Panel page event triggered:", event);
+
+ # NOTE: this is prepared to be fully replaced, but it's better than the old code
+ if (event == 'button-page')
+ me.manager.setActivePage('page-panel');
+
+ }, # handleEvent
+};
+
+
diff --git a/Aircraft/Instruments-3d/GPSmap196/gpsmap196.xml b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.xml
index 7267326..f53989a 100644
--- a/Aircraft/Instruments-3d/GPSmap196/gpsmap196.xml
+++ b/Aircraft/Instruments-3d/GPSmap196/gpsmap196.xml
@@ -153,6 +153,7 @@
<property>instrumentation/gps196/inputs/button-page</property>
<value type="bool">true</value>
</binding>
+<!--
<mod-up>
<binding>
<command>property-assign</command>
@@ -160,6 +161,7 @@
<value type="bool">false</value>
</binding>
</mod-up>
+-->
</action>
</animation>
diff --git a/Aircraft/Instruments-3d/GPSmap196/mfd.nas b/Aircraft/Instruments-3d/GPSmap196/mfd.nas
new file mode 100644
index 0000000..9d6604e
--- /dev/null
+++ b/Aircraft/Instruments-3d/GPSmap196/mfd.nas
@@ -0,0 +1,95 @@
+##
+# helpers for creating canvas-based multi-function-displays (MFDs)
+#
+# NOTE: this file should NOT contain anything that is specific to a single device
+# move device-specific code into gpsmap196.nas, edit gpsmap196.pages to extend pages
+#
+# TODO: keep on extending this for instruments/frameworks like:
+#
+# - navdisplay.mfd
+# - Avidyne/Entegra (extra500)
+# - kln89
+# - Primus G1000
+#
+var initPage = func(group, page, filename) {
+ canvas.parsesvg(var new_page = group.createChild("group", page), filename);
+ new_page.hide();
+ return new_page;
+};
+
+
+###
+# MFD page helper class,needs to be implemented by all pages
+# currently assumes that each page is SVG based (requires filenames)
+var MFDPage = {
+ new: func(root, page, filename) {
+ var m = {parents:[MFDPage]};
+ m.page = page;
+ m.group = initPage(root, page, filename); # FIXME
+ return m;
+ },
+ hide: func me.group.hide(),
+ show: func me.group.show(),
+
+ handleEvent: func die("abstract handleEvent() method not yet implemented by sub-class:",me.page),
+};
+
+
+
+##
+# manages MFD pages
+# TODO: add button handling here, along with event management
+var MFDPageMgr = {
+ new: func(root) {
+ var m ={parents:[MFDPageMgr]};
+ m.active=nil;
+ m.pagelist = [];
+ m.pages = {};
+ m.listeners = [];
+ m.root = root;
+ return m;
+ },
+ del: func {
+ foreach(var l; me.listeners)
+ removelistener(l);
+ },
+ # FIXME: this is just to support all those button listeners for now ...
+ # will replace it sooner or later with a helper class for managing buttons/keys
+ registerEvent: func (node) {
+ append(me.listeners, setlistener(node, func me.handleEvents() ));
+ },
+ registerPage: func(name, class) {
+ # call the constructor for the class to create a new page
+ append(me.pagelist, me.pages[name]=class.new(me.root, name, me));
+ # initialize if needed
+ if (typeof(me.active) == nil) me.active=name;
+ },
+ nextPage: func {
+ },
+ prevPage: func {
+
+ },
+ setActivePage: func(name) {
+ # hide the currently active page
+ if (me.active and (var curr=me.pages[me.active]) != nil) curr.hide();
+ # set the new active page
+ me.active=name;
+ # and show it
+ me.update();
+ },
+ getActivePageName: func return me.active,
+ getActivePage: func return me.pages[me.active],
+ update: func me.pages[me.active].show(),
+
+ # TODO: we can filter events here to process them via the page manager
+ # and not pass them through onto the page ...
+ makeEventHandler: func(event) {
+ return func {
+ print(event, ":Active page:", me.getActivePageName());
+ # dispatch events to active page
+ me.getActivePage().handleEvent(event);
+ }
+ },
+};
+
+
diff --git a/Aircraft/Instruments-3d/GPSmap196/widget/gpsmap196-widget.nas b/Aircraft/Instruments-3d/GPSmap196/widget/gpsmap196-widget.nas
index 4ec98bd..0f13fe4 100644
--- a/Aircraft/Instruments-3d/GPSmap196/widget/gpsmap196-widget.nas
+++ b/Aircraft/Instruments-3d/GPSmap196/widget/gpsmap196-widget.nas
@@ -28,8 +28,8 @@ canvas.parsesvg(root, "Aircraft/Instruments-3d/GPSmap196/widget/gpsmap196-widget
# An helper function who add the event listener for each button
var setButtonListener = func(btn, prop) {
- root.getElementById(btn).addEventListener("mousedown", func(e) { setprop("instrumentation/gps196/inputs/"~prop, 1); });
- root.getElementById(btn).addEventListener("mouseup", func(e) { setprop("instrumentation/gps196/inputs/"~prop, 0); });
+ root.getElementById(btn).addEventListener("click", func(e) { setprop("instrumentation/gps196/inputs/"~prop, 1); });
+ # root.getElementById(btn).addEventListener("mouseup", func(e) { setprop("instrumentation/gps196/inputs/"~prop, 0); });
root.getElementById(btn).set("z-index", 11);
}