<?xml version="1.0"?> <PropertyList> <nasal> <open> <![CDATA[ setprop("sim/gui/dialogs/metar/description[1]", "Simple and fast weather engine that interprets METAR data " ~ "directly or a set of manually defined parameters. Recommended for use with Multiplayer."); setprop("sim/gui/dialogs/metar/description[2]", "Advanced weather engine that gives more detailed and realistic results based on METAR " ~ "data and a set of predefined parameters. Click on 'Apply' to run the engine, as the engine " ~ "does not automatically load upon startup."); var normalize_string = func(src) { if( src == nil ) src = ""; var dst = ""; for( var i = 0; i < size(src); i+=1 ) { if( src[i] == `\n` or src[i] == `\r` ) src[i] = ` `; if (i == 0 and src[i] == ` `) continue; if( i != 0 and src[i] == ` ` and src[i-1] == ` ` ) continue; dst = dst ~ " "; dst[size(dst)-1] = src[i]; } return dst; } var GlobalWeatherDialogController = { new : func( dlgRoot ) { var obj = { parents: [GlobalWeatherDialogController] }; obj.dlgRoot = dlgRoot; obj.base = "sim/gui/dialogs/metar"; obj.baseN = props.globals.getNode( obj.base, 1 ); return obj; }, refresh : func { var scenarioName = getprop( me.base ~ "/source-selection"); if (getprop( me.base ~ "/mode/manual-weather")) { # In manual weather mode we have to disable live weather # fetch so the weather can be changed by the user in the # weather configuration dialog. setprop( "/environment/params/metar-updates-environment", 0 ); setprop( "/environment/realwx/enabled", 0 ); setprop( "/environment/config/enabled", 1 ); } else if( scenarioName == "Live data" ) { # If we've selected Live Data we need to force # a refresh of the Live Data setting. setprop( "/environment/realwx/enabled", 1 ); } }, open : func { # Determine the weather mode. if ( getprop("/nasal/local_weather/enabled") == 1) { # Local weather mode setprop( me.base ~ "/mode/global-weather", "0" ); setprop( me.base ~ "/mode/local-weather", "1" ); setprop( me.base ~ "/mode/manual-weather", "0" ); } else if ( getprop( "environment/params/metar-updates-environment" ) == 0 ) { # Manual weather mode setprop( me.base ~ "/mode/global-weather", "1" ); setprop( me.base ~ "/mode/local-weather", "0" ); setprop( me.base ~ "/mode/manual-weather", "1" ); } else { # Global weather mode setprop( me.base ~ "/mode/global-weather", "1" ); setprop( me.base ~ "/mode/local-weather", "0" ); setprop( me.base ~ "/mode/manual-weather", "0" ); } # initialize the METAR source selection if( getprop( "environment/realwx/enabled" ) ) { setprop( me.base ~ "/source-selection", "Live data" ); } else { # preset configured scenario var wsn = props.globals.getNode( "/environment/weather-scenarios" ); var current = getprop("/environment/weather-scenario", ""); var found = 0; if( wsn != nil ) { var scenarios = wsn.getChildren("scenario"); forindex (var i; scenarios ) { var metarN = scenarios[i].getNode("metar"); metarN == nil and continue; if( scenarios[i].getNode("name").getValue() == current ) { setprop( me.base ~ "/source-selection", scenarios[i].getNode("name").getValue() ); found = 1; break; } } } if( found == 0 ) setprop( me.base ~ "/source-selection", "Manual input" ); } setprop( me.base ~ "/metar-string", normalize_string(getprop("environment/metar/data")) ); gui.findElementByName( me.dlgRoot, "metar-string" ).getNode("legend", 1).setValue(normalize_string(getprop("environment/metar/data"))); # fill the METAR source combo box var combo = gui.findElementByName( me.dlgRoot, "source-selection" ); var wsn = props.globals.getNode( "/environment/weather-scenarios" ); if( wsn != nil ) { var scenarios = wsn.getChildren("scenario"); forindex (var i; scenarios ) { combo.getChild("value", i, 1).setValue(scenarios[i].getNode("name").getValue()); } } me.scenarioListenerId = setlistener( me.base ~ "/source-selection", func(n) { me.scenarioListener(n); }, 1, 1 ); me.metarListenerId = setlistener( "environment/metar/valid", func(n) { me.metarListener(n); }, 1, 1 ); # Update the dialog itself me.refresh(); }, close : func { removelistener( me.scenarioListenerId ); removelistener( me.metarListenerId ); }, apply : func { var scenarioName = getprop( me.base ~ "/source-selection"); var metar = getprop( "environment/metar/data" ); var global_weather_enabled = getprop( me.base ~ "/mode/global-weather"); var local_weather_enabled = getprop( me.base ~ "/mode/local-weather"); var manual_weather_enabled = getprop( me.base ~ "/mode/manual-weather"); # General weather settings based on scenario if (manual_weather_enabled == 1) { setprop( "/environment/params/metar-updates-environment", 0 ); setprop( "/environment/realwx/enabled", 0 ); setprop( "/environment/config/enabled", 1 ); metar = ""; } else if( scenarioName == "Live data" ) { setprop( "/environment/params/metar-updates-environment", 1 ); setprop( "/environment/realwx/enabled", 1 ); setprop( "/environment/config/enabled", 1 ); } else if( scenarioName == "Manual input" ) { setprop( "/environment/params/metar-updates-environment", 1 ); setprop( "/environment/realwx/enabled", 0 ); setprop( "/environment/config/enabled", 1 ); metar = getprop( me.base ~ "/metar-string" ); } else { setprop( "/environment/params/metar-updates-environment", 1 ); setprop( "/environment/realwx/enabled", 0 ); setprop( "/environment/config/enabled", 1 ); metar = getprop( me.base ~ "/metar-string" ); setprop("/environment/weather-scenario", scenarioName); } if( metar != nil ) { setprop( "environment/metar/data", normalize_string(metar) ); } # Clear any local weather that might be running if (getprop("/nasal/local_weather/loaded")) local_weather.clear_all(); setprop("/nasal/local_weather/enabled", "false"); if (local_weather_enabled) { # If Local Weather is enabled, re-initialize with updated # initial tile and tile selection. setprop("/nasal/local_weather/enabled", "true"); # Re-initialize local weather. settimer( func {local_weather.set_tile();}, 0.2); } }, findScenarioByName : func(name) { var wsn = props.globals.getNode( "/environment/weather-scenarios" ); if( wsn != nil ) { var scenarios = wsn.getChildren("scenario"); foreach (var scenario; scenarios ) { if( scenario.getNode("name").getValue() == name ) return scenario; } } return nil; }, scenarioListener : func( n ) { var description = ""; var metar = "nil"; var local_weather_props = nil; var scenario = me.findScenarioByName( n.getValue() ); if( scenario != nil ) { description = normalize_string(scenario.getNode("description", 1 ).getValue()); metar = normalize_string(scenario.getNode("metar", 1 ).getValue()); local_weather_props = scenario.getNode("local-weather"); } if (n.getValue() == "Live data") { # Special case - retrieve live data var metar = getprop( "environment/metar/data" ); } if (n.getValue() == "Manual input") { # Special case - retain current values var metar = getprop( me.base ~ "/metar-string" ); } setprop(me.base ~ "/description", description ); setprop(me.base ~ "/metar-string", metar ); # Set the wind from the METAR string. var result = []; var msplit = split(" ", string.uc(metar)); foreach (var word; msplit) { if ((size(word) > 6) and string.match(word, "*[0-9][0-9]KT")) { # We've got the wind definition word. Now to split it up. # Format is nnnmmKT or nnnmmGppKT # Direction is easy - the first 3 characters. var dir = chr(word[0]) ~ chr(word[1]) ~ chr(word[2]); if (dir == "VRB") { setprop("/local-weather/tmp/tile-orientation-deg", 360.0 * rand()); setprop("/local-weather/tmp/gust-angular-variation-deg", 180.0); setprop("/local-weather/tmp/gust-frequency-hz", 0.001); } else { setprop("/local-weather/tmp/tile-orientation-deg", dir); setprop("/local-weather/tmp/gust-angular-variation-deg", 0.0); setprop("/local-weather/tmp/gust-frequency-hz", 0.0); } # Next two are the base wind var spd = chr(word[3]) ~ chr(word[4]); setprop("/local-weather/tmp/windspeed-kt", spd); var gst = 0; if ((size(word) > 7) and (chr(word[5]) == 'G')) { # Gusty case gst = chr(word[6]) ~ chr(word[7]); } if ((gst > spd) and (spd > 0)) { setprop("/local-weather/tmp/gust-relative-strength", (gst - spd) / spd); setprop("/local-weather/tmp/gust-frequency-hz", 0.7); } else { setprop("/local-weather/tmp/gust-relative-strength", 0.0); } } } if (local_weather_props != nil) { # The local weather properties need to be set now, so they can # be configured by the user if they select Advanced Settings props.copy(local_weather_props, props.globals.getNode("/local-weather/tmp", 1)); } else { # If no local weather properties have been set, we'll read from the scenario # METAR setprop("/local-weather/tmp/tile-type", "manual"); setprop("/local-weather/tmp/tile-management", "METAR"); } me.refresh(); }, metarListener : func( n ) { var metar = getprop("environment/metar/data"); if( metar == nil or metar == "" ) metar = "NIL"; metar = normalize_string(metar); printlog( "info", "new METAR: " ~ metar ); setprop( me.base ~ "/metar-string", metar ); gui.dialog_update( "weather-conditions", "metar-string" ); }, }; var controller = GlobalWeatherDialogController.new( cmdarg() ); controller.open(); ]]> </open> <close> <![CDATA[ controller.close(); ]]> </close> </nasal> <!-- Control the weather --> <name>weather</name> <modal>false</modal> <resizable>false</resizable> <layout>vbox</layout> <default-padding>3</default-padding> <!-- Title bar with close button --> <group> <layout>hbox</layout> <default-padding>1</default-padding> <empty> <stretch>true</stretch> </empty> <text> <label>Weather Conditions</label> </text> <empty> <stretch>true</stretch> </empty> <button> <legend/> <key>Esc</key> <pref-width>16</pref-width> <pref-height>16</pref-height> <border>2</border> <binding> <command>dialog-close</command> </binding> </button> </group> <hrule/> <group> <layout>hbox</layout> <!-- only for a gap --> <group> <layout>vbox</layout> <default-padding>1</default-padding> <text> <label> </label> </text> </group> <group> <layout>vbox</layout> <text> <halign>left</halign> <label>Select Weather Engine</label> </text> <group> <layout>hbox</layout> <halign>left</halign> <group> <layout>table</layout> <!-- <pref-width>500</pref-width> --> <radio> <row>0</row> <col>0</col> <halign>left</halign> <name>simple-weather</name> <property>sim/gui/dialogs/metar/mode/global-weather</property> <live>true</live> <label>Basic Weather</label> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/global-weather</property> <value>1</value> </binding> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/local-weather</property> <value>0</value> </binding> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <value>0</value> </binding> <binding> <command>nasal</command> <script> controller.refresh(); </script> </binding> </radio> <checkbox> <row>0</row> <col>1</col> <halign>right</halign> <name>manual-weather-config</name> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <label>Manual Configuration</label> <live>true</live> <enable> <property>sim/gui/dialogs/metar/mode/global-weather</property> </enable> <binding> <command>dialog-apply</command> <object-name>manual-weather-config</object-name> </binding> <binding> <command>nasal</command> <script> controller.refresh(); </script> </binding> </checkbox> <empty> <row>0</row> <col>2</col> <stretch>true</stretch> </empty> <button> <row>0</row> <col>3</col> <halign>right</halign> <!-- <pref-width>170</pref-width> --> <legend>Manual Configuration ...</legend> <enable> <property>sim/gui/dialogs/metar/mode/manual-weather</property> </enable> <binding> <command>dialog-show</command> <dialog-name>weather-configuration</dialog-name> </binding> <!--<binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <value>1</value> </binding>--> </button> </group> </group> <textbox> <name>basic description</name> <halign>fill</halign> <stretch>true</stretch> <!-- <pref-width>250</pref-width> --> <pref-height>70</pref-height> <slider>15</slider> <editable>false</editable> <wrap>true</wrap> <live>true</live> <top-line>0</top-line> <property>sim/gui/dialogs/metar/description[1]</property> </textbox> <group> <layout>hbox</layout> <halign>left</halign> <group> <layout>table</layout> <!-- <pref-width>500</pref-width> --> <radio> <row>0</row> <col>0</col> <label>Detailed Weather</label> <halign>left</halign> <name>simple-weather</name> <property>sim/gui/dialogs/metar/mode/local-weather</property> <live>true</live> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/local-weather</property> <value>1</value> </binding> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/global-weather</property> <value>0</value> </binding> <binding> <command>property-assign</command> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <value>0</value> </binding> <binding> <command>nasal</command> <script> controller.refresh(); </script> </binding> </radio> <text> <row>0</row> <col>1</col> <label> </label> </text> <empty> <row>0</row> <col>2</col> <stretch>true</stretch> </empty> <button> <row>0</row> <col>3</col> <legend> Advanced Settings ...</legend> <halign>right</halign> <!-- <pref-width>170</pref-width> --> <enable> <property>sim/gui/dialogs/metar/mode/local-weather</property> <value>1</value> </enable> <binding> <command>dialog-show</command> <dialog-name>local-weather</dialog-name> </binding> </button> </group> </group> <textbox> <name>advance-description</name> <halign>fill</halign> <stretch>true</stretch> <!-- <pref-width>250</pref-width> --> <pref-height>90</pref-height> <slider>15</slider> <editable>false</editable> <wrap>true</wrap> <live>true</live> <top-line>0</top-line> <property>sim/gui/dialogs/metar/description[2]</property> </textbox> <!-- <group> <layout>table</layout> </group> --> <empty> <stretch>true</stretch> </empty> </group> <!-- only for a gap --> <group> <layout>vbox</layout> <default-padding>1</default-padding> <text> <label> </label> </text> </group> </group> <hrule/> <group> <layout>hbox</layout> <!-- only for a gap --> <group> <layout>vbox</layout> <default-padding>1</default-padding> <text> <label> </label> </text> </group> <group> <layout>vbox</layout> <halign>left</halign> <group> <layout>hbox</layout> <halign>left</halign> <group> <layout>table</layout> <text> <row>0</row> <col>0</col> <label>Weather Conditions</label> <halign>left</halign> </text> <text> <row>0</row> <col>1</col> <label> </label> <halign>left</halign> </text> <combo> <row>0</row> <col>2</col> <name>source-selection</name> <halign>fill</halign> <stretch>true</stretch> <pref-width>300</pref-width> <property>sim/gui/dialogs/metar/source-selection</property> <enable> <equals> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <value>0</value> </equals> </enable> <binding> <command>dialog-apply</command> <object-name>source-selection</object-name> </binding> <binding> <command>dialog-update</command> <object-name>metar-string</object-name> </binding> </combo> </group> </group> <group> <layout>hbox</layout> <text> <label>METAR Data</label> </text> <empty> <stretch>true</stretch> </empty> <text> <label> </label> </text> <text> <label>Data is valid</label> </text> <checkbox> <property>/environment/metar/valid</property> <label/> <live>true</live> <enable> <false/> </enable> </checkbox> </group> <group> <layout>hbox</layout> <textbox> <name>metar-string</name> <halign>fill</halign> <stretch>true</stretch> <!-- <pref-width>250</pref-width> --> <pref-height>70</pref-height> <slider>15</slider> <editable>true</editable> <wrap>true</wrap> <live>false</live> <top-line>0</top-line> <property>sim/gui/dialogs/metar/metar-string</property> <enable> <and> <equals> <property>sim/gui/dialogs/metar/mode/manual-weather</property> <value>0</value> </equals> <equals> <property>sim/gui/dialogs/metar/source-selection</property> <value>Manual input</value> </equals> </and> </enable> <binding> <command>dialog-apply</command> <object-name>metar-string</object-name> </binding> </textbox> </group> <group> <layout>hbox</layout> <text> <label>Description</label> </text> <empty> <stretch>true</stretch> </empty> </group> <textbox> <name>description</name> <halign>fill</halign> <stretch>true</stretch> <pref-width>450</pref-width> <pref-height>100</pref-height> <slider>15</slider> <editable>false</editable> <wrap>true</wrap> <live>true</live> <top-line>0</top-line> <property>sim/gui/dialogs/metar/description[0]</property> </textbox> </group> <!-- only for a gap --> <group> <layout>vbox</layout> <default-padding>1</default-padding> <text> <label> </label> </text> </group> </group> <hrule/> <group> <empty> <stretch>true</stretch> </empty> <layout>hbox</layout> <button> <legend>OK</legend> <equal>true</equal> <binding> <command>dialog-apply</command> <object-name>metar-string</object-name> </binding> <binding> <command>nasal</command> <script> controller.apply(); </script> </binding> <binding> <command>dialog-close</command> </binding> </button> <button> <legend>Apply</legend> <equal>true</equal> <binding> <command>dialog-apply</command> <object-name>metar-string</object-name> </binding> <binding> <command>nasal</command> <script> controller.apply(); </script> </binding> </button> <button> <legend>Close</legend> <equal>true</equal> <default>true</default> <key>Esc</key> <binding> <command>dialog-close</command> </binding> </button> <empty> <stretch>true</stretch> </empty> </group> </PropertyList>