1
0
Fork 0

- gui.OverlaySelector: add optional sort criterion, add selection by index,

add next(), and previous() methods.
- aircraft.nas: deprecate formation class
This commit is contained in:
mfranz 2008-10-15 15:27:56 +00:00
parent 6a72126327
commit 5d576f0e3d
3 changed files with 112 additions and 104 deletions

View file

@ -3,7 +3,6 @@
# constants
# ==============================================================================
var D2R = math.pi / 180;
@ -11,7 +10,6 @@ var R2D = 180 / math.pi;
# helper functions
# ==============================================================================
@ -26,18 +24,14 @@ var makeNode = func(n) {
}
# returns arg[1]-th optional argument of vector arg[0] or default value arg[2]
# returns args[index] if available and non-nil, or default otherwise
#
var optarg = func {
if (size(arg[0]) > arg[1] and arg[0][arg[1]] != nil)
arg[0][arg[1]];
else
arg[2];
var optarg = func(args, index, default) {
size(args) > index and args[index] != nil ? args[index] : default;
}
# door
# ==============================================================================
# class for objects moving at constant speed, with the ability to
@ -189,10 +183,8 @@ var light = {
# light.switch(bool) -> set light switch (also affects other lights
# that use the same switch)
switch: func(v) { me.switchN.setBoolValue(v); me },
# light.toggle() -> toggle light switch
toggle: func { me.switchN.setBoolValue(!me.switchN.getValue()); me },
# light.cont() -> continuous light
cont: func {
if (!me.continuous) {
@ -202,7 +194,6 @@ var light = {
}
me;
},
# light.blink() -> blinking light (default)
# light.blink(3) -> when switched on, only run three blink sequences;
# second optional arg defines state after the sequences
@ -217,7 +208,6 @@ var light = {
}
me;
},
_switch_: func {
var switch = me.switchN.getBoolValue();
switch != me.lastswitch or return;
@ -232,7 +222,6 @@ var light = {
me._loop_(me.loopid);
}
},
_loop_: func(id) {
id == me.loopid or return;
if (!me.count) {
@ -251,6 +240,7 @@ var light = {
};
# lowpass
# ==============================================================================
# class that implements a variable-interval EWMA (Exponentially Weighted
@ -293,6 +283,7 @@ var lowpass = {
};
# angular lowpass
# ==============================================================================
# same as above, but for angles. Filters sin/cos separately and calculates the
@ -321,6 +312,7 @@ var angular_lowpass = {
};
# data
# ==============================================================================
# class that loads and saves properties to aircraft-specific data files in
@ -408,6 +400,7 @@ var data = {
};
# timer
# ==============================================================================
# class that implements timer that can be started, stopped, reset, and can
@ -522,7 +515,7 @@ var livery = {
if (me.dir[-1] != `/`)
me.dir ~= "/";
me.name_path = name_path;
me.sort_path = sort_path != nil ? sort_path : name_path;
me.sort_path = sort_path or name_path;
me.rescan();
aircraft.data.add(name_path);
me.dialog = gui.Dialog.new("livery-select");
@ -634,7 +627,7 @@ var livery_update = {
# formation
# formation *** DEPRECATED ***
# =============================================================================
# A modification of the livery class. This class maintains formation
# XML files (see Blackburn Buccaneer for an example). Files are regular
@ -690,6 +683,7 @@ var formation = {
},
# select by index (out-of-bounds indices are wrapped)
set: func(i) {
print("***\n*** use of aircraft.formation is deprecated; use gui.OverlaySelector\n***");
if (i < 0)
i = size(me.data) - 1;
if (i >= size(me.data))
@ -1016,7 +1010,6 @@ var HUD = {
# module initialization
# ==============================================================================
#
_setlistener("/sim/signals/nasal-dir-initialized", func {
props.initNode("/sim/time/delta-sec", 0);
props.initNode("/sim/time/delta-realtime-sec", 0.00000001);

View file

@ -214,7 +214,7 @@ var Dialog = {
if (m.prop.getName() != "dialog")
die("Dialog class: node name must end with '/dialog'");
m.listener = setlistener("/sim/signals/reinit-gui", func { m.load() }, 1);
m.listener = setlistener("/sim/signals/reinit-gui", func m.load(), 1);
}
return Dialog.instance[m.name] = m;
},
@ -264,6 +264,106 @@ var Dialog = {
};
##
# Overlay selector. Displays a list of overlay XML files and copies the
# chosen one to the property tree. The class allows to select liveries,
# insignia, decals, variants, etc. Usually the overlay properties are
# fed to "select" and "material" animations.
#
# SYNOPSIS:
# OverlaySelector.new(<title>, <dir>, <nameprop> [, <sortprop> [, <callback>]]);
#
# title ... dialog title
# dir ... directory where to find the XML overlay files,
# relative to FG_ROOT
# nameprop ... property in an overlay file that contains the name
# The result is written to this property in the
# property tree. Attach a listener to this property
# if you want changes reported.
# sortprop ... property in an overlay file that should be used
# as sorting criterion, if alphabetic sorting by
# name is undesirable
# callback ... callback function
#
# EXAMPLE:
# aircraft.data.add("sim/model/pilot"); # autosave the pilot
# var pilots_dialog = gui.OverlaySelector.new("Pilots",
# "Aircraft/foo/Models/Pilots",
# "sim/model/pilot");
#
# pilots_dialog.open(); # or ... close(), or toggle()
#
#
var OverlaySelector = {
new: func(title, dir, nameprop, sortprop = nil, callback = nil) {
var name = "overlay-select-";
var data = props.globals.getNode("/sim/gui/dialogs/", 1);
var i = nil;
for (i = 1; 1; i += 1)
if (data.getNode(name ~ i, 0) == nil)
break;
data = data.getNode(name ~= i, 1);
var m = Dialog.new(data.getNode("dialog", 1), "gui/dialogs/overlay-select.xml", name);
m.parents = [OverlaySelector, Dialog];
m.dir = getprop("/sim/fg-root") ~ "/" ~ dir;
if (m.dir[-1] != `/`)
m.dir ~= '/';
m.nameprop = nameprop;
m.sortprop = sortprop or nameprop;
m.callback = callback or func { nil };
m.result = props.initNode(data.getNode("result", 1), "");
m.listener = setlistener(m.result, func(n) m.select(n.getValue()));
m.prop.getNode("group/text/label").setValue(title);
m.list = m.prop.getNode("list");
m.list.getNode("property").setValue(m.result.getPath());
m.rescan();
m.select(getprop(m.nameprop) or "");
return m;
},
del: func {
removelistener(me.listener);
me.data.remove();
},
rescan: func {
me.data = [];
foreach (var file; directory(me.dir)) {
if (substr(file, -4) != ".xml")
continue;
var n = io.read_properties(me.dir ~ file);
var name = n.getNode(me.nameprop, 1).getValue() or "[NO NAME]";
var index = n.getNode(me.sortprop, 1).getValue() or 0;
append(me.data, [name, index, n.getValues()]);
me.data = sort(me.data, func(a, b) num(a[1]) == nil or num(b[1]) == nil
? cmp(a[1], b[1]) : a[1] - b[1]);
}
me.list.removeChildren("value");
forindex (var i; me.data)
me.list.getChild("value", i, 1).setValue(me.data[i][0]);
},
set: func(index) {
me.current = math.mod(index, size(me.data));
props.globals.setValues(me.data[me.current][2]);
me.callback(me.data[me.current]);
},
select: func(name) {
forindex (var i; me.data)
if (me.data[i][0] == name)
me.set(i);
},
next: func {
me.set(me.current + 1);
},
previous: func {
me.set(me.current - 1);
},
};
##
# FileSelector class (derived from Dialog class).
#
@ -398,91 +498,6 @@ settimer(func {
}, 0);
##
# Overlay selector. Displays a list of overlay XML files and copies the
# chosen one to the property tree. The class allows to select liveries,
# insignia, decals, variants, etc. Usually the overlay properties are
# fed to "select" and "material" animations.
#
# SYNOPSIS:
# OverlaySelector.new(<title>, <dir>, <nameprop>);
#
# title ... dialog title
# dir ... directory where to find the XML overlay files,
# relative to FG_ROOT
# nameprop ... property in an overlay file that contains the name
# The result is written to this property in the
# property tree. You can attach a listener here to
# get changes reported.
#
# EXAMPLE:
# aircraft.data.add("sim/model/pilot"); # autosave the pilot
# var pilots_dialog = gui.OverlaySelector.new("Pilots",
# "Aircraft/foo/Models/Pilots",
# "sim/model/pilot");
#
# pilots_dialog.open(); # or ... close(), or toggle()
#
#
var OverlaySelector = {
new: func(title, dir, nameprop) {
var name = "overlay-select-";
var data = props.globals.getNode("/sim/gui/dialogs/", 1);
var i = nil;
for (i = 1; 1; i += 1)
if (data.getNode(name ~ i, 0) == nil)
break;
data = data.getNode(name ~= i, 1);
var m = Dialog.new(data.getNode("dialog", 1), "gui/dialogs/overlay-select.xml", name);
m.parents = [OverlaySelector, Dialog];
m.dir = getprop("/sim/fg-root") ~ "/" ~ dir;
m.nameprop = nameprop;
m.result = data.getNode("result", 1);
m.cblistener = setlistener(m.result, func m.set());
m.prop.getNode("group/text/label").setValue(title);
m.list = m.prop.getNode("list");
m.list.getNode("property").setValue(m.result.getPath());
m.rescan();
m.set(getprop(m.nameprop));
return m;
},
del: func {
removelistener(me.cblistener);
me.data.remove();
},
rescan: func {
me.options = [];
foreach (var file; directory(me.dir)) {
if (substr(file, -4) != ".xml")
continue;
var n = io.read_properties(me.dir ~ "/" ~ file);
var name = n.getNode(me.nameprop, 1).getValue() or "[NO NAME]";
append(me.options, [name, n.getValues()]);
me.options = sort(me.options, func(a, b) cmp(a[0], b[0]));
}
me.list.removeChildren("value");
forindex (var i; me.options)
me.list.getChild("value", i, 1).setValue(me.options[i][0]);
},
set: func(which = nil) {
if (!size(me.options))
return;
var choice = which or me.result.getValue() or me.options[0][0];
foreach (var o; me.options) {
if (o[0] == choice) {
props.globals.setValues(o[1]);
setprop(me.nameprop, choice);
}
}
},
};
##
# Apply whole dialog or list of widgets. This copies the widgets'
# visible contents to the respective <property>.

View file

@ -12,7 +12,7 @@
# "ALIAS" return from getType to detect them (to avoid cycles while
# walking the tree).
#
Node = {
var Node = {
getType : func { wrap(_getType(me._g, arg)) },
getAttribute : func { wrap(_getAttribute(me._g, arg)) },
setAttribute : func { wrap(_setAttribute(me._g, arg)) },