followme_e-tron/Nasal/texture-selector.nas

190 lines
8.9 KiB
Plaintext

#//Sidi Liang, 2020
#//Docs WIP
#//Texture Selector for Followme EV
#//Quick start:
#//Aircraft liveries with dedicated selection dialog: (The same applies to any texture defined in PropertyList XML):
#// var liveryPath = props.getNode("sim/aircraft-dir").getValue()~"/Models/Liveries/FollowmeEV/";
#// var liverySelector = TextureSelector.new(name: "Livery-Selector", path: liveryPath, fileType: ".xml", textureProp: "texture-fuse", enableMultiplayer: 1, defaultValue: "Yellow(Default)");
#//Pure texture, custom dialog(without multiplayer):
#// var path = props.getNode("/",1).getValue("sim/aircraft-dir") ~ '/Models/plate/texture';
#// var plateSelector = TextureSelector.new(path, ".png", 1, 1, "sim/gui/dialogs/vehicle_config/dialog", "group[4]/combo/");
var TextureSelector = { #//Tmp Note: path MUST end with "/"
new: func(name, path, fileType = nil, enableNone = 0, customDialog = 0, customDialogBase = "",
customDialogPosition = "", texturePropertyBase = "sim/model/livery/", textureProp = "livery", textureNameProp = "name",
textureDataNode = nil, enableMultiplayer = 0, multiplayerProperty = "/sim/multiplay/generic/string[19]",
texturePrePath = "", defaultValue = ""){
var m = {parents:[TextureSelector]};
if(customDialog == 1){
m.dialogNode = props.getNode(customDialogBase, 1);
}else{
m.dialogBaseNode = props.getNode("/sim/gui/dialogs/TextureSelector", 1).getNode(name, 1).getNode("dialog", 1);
m.dialog = TextureSelectorDialog.new(dialogBase : m.dialogBaseNode, defaultV: defaultValue, name: name);
m.dialogLis = setlistener(m.dialogBaseNode.getNode("opened", 1), func m.dialogTriggered());
}
if(textureDataNode == nil) textureDataNode = props.getNode("/TextureSelector/liveries/", 1);
m.name = name;
m.path = path;
m.fileType = fileType;
m.enableNone = enableNone;
m.customDialog = customDialog;
m.dialogCustom = customDialogPosition;
m.texturePropertyBase = texturePropertyBase;
m.textureProp = textureProp;
m.texturePrePath = texturePrePath;#//Tmp Node: must end with /
m.textureNameProp = textureNameProp;
m.textureDataNode = textureDataNode;
m.defaultValue = defaultValue;
m.enableMultiplayer = enableMultiplayer;
m.multiplayerProperty = multiplayerProperty;
m.updateList();
if(defaultValue and me.fileType == ".xml") m.setTextureByNameXML(defaultValue);
else if(defaultValue) props.getNode(m.texturePropertyBase, 1).getNode(m.textureProp, 1).setValue(m.texturePrePath ~ defaultValue ~ m.fileType);
if(enableMultiplayer) props.getNode(multiplayerProperty, 1).alias(props.getNode(m.texturePropertyBase, 1).getNode(m.textureProp, 1));
return m;
},
path: "", #//path containing texture file
fileType: "",
enableNone: 0,
customDialog: 0,
dialogCustom:"list/",
texturePropertyBase: "sim/model/livery/",
textureProp:"livery",
textureNameProp:"name",
defaultValue:"",
dialogNode:nil,
dialog:nil,
current:nil,
textureDataNode:props.getNode("/TextureSelector/liveries/", 1),
enableMultiplayer: 0, #//The property will be transmitted via MP if enabled.
multiplayerProperty: "/sim/multiplay/generic/string[19]", #// The multiplayer property. Only be used if enableMultiplayer is set to 1. Default to be /sim/multiplay/generic/string[19](The last string property in the MP Protocol)
scan: func(path = nil, fileType = nil){
if(path == nil and me.path) path = me.path;
else return 1;
if(fileType == nil and me.fileType) fileType = me.fileType;
else return 1;
var data = [];
var files = directory(path);
if (size(files)) {
foreach (var file; files) {
if (substr(file, 0 - size(fileType)) != fileType)
continue;
append(data, [substr(file, 0, size(file) - size(fileType)), path ~ file]);
}
#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]);
}
return data;
},
scanXML: func(path = nil){
if(path == nil and me.path) path = me.path;
else return 1;
var fileType = ".xml";
var names = [];
var files = directory(path);
if (size(files)) {
var i = 0;
foreach (var file; files) {
if (substr(file, 0 - size(fileType)) != fileType)
continue;
var node = me.textureDataNode.getChild(me.textureProp, i, 1); #//Temporary solution, to be improved
n = io.read_properties(me.path ~ file, node);
var data = [];
append(data, n.getNode(me.texturePropertyBase ~ me.textureNameProp).getValue());
append(names, data);
i+=1;
}
}
return names;
},
updateList: func(){
var allItems = nil;
if(me.fileType != ".xml") allItems = me.scan();
else allItems = me.scanXML();
var data = nil;
if(me.customDialog) data = me.dialogNode.getNode(me.dialogCustom, 1); #//Pass the custom dialog if used
else data = me.dialog.list;
data.removeChildren("value");
if(me.enableNone){
data.getChild("value", 0, 1).setValue("NONE");
forindex(var i; allItems){
data.getChild("value", i+1, 1).setValue(allItems[i][0]);
}
}else{
forindex(var i; allItems){
data.getChild("value", i, 1).setValue(allItems[i][0]);
}
}
},
dialogTriggered: func(){
if(me.dialogBaseNode.getNode("opened", 1).getValue() == 1){
print("Dialog opened");
me.updateList();
me.resultLis = setlistener(me.dialog.result, func(){
var selected = me.dialog.result.getValue();
if(selected != "none"){
me.current = selected;
if(me.fileType == ".xml") me.setTextureByNameXML(selected);
else props.getNode(me.texturePropertyBase, 1).getNode(me.textureProp, 1).setValue(me.texturePrePath ~ me.current ~ me.fileType);
}else{
#fileNode.setValue(nameNode.getValue());
}
});
}else{
removelistener(me.resultLis);
}
},
setTextureByNameXML: func(name){
allTextures = me.textureDataNode.getChildren(me.textureProp);
foreach(var texture; allTextures){
var tmp = texture.getNode(me.texturePropertyBase);
if(tmp.getNode(me.textureNameProp).getValue() == name){
print(tmp.getNode(me.textureProp).getValue());
props.copy(tmp, props.getNode(me.texturePropertyBase));
#if(me.enableMultiplayer){
# props.getNode(me.multiplayerProperty, 1).setValue(texture.getNode(me.texturePropertyBase).getNode(me.textureProp).getValue());
#}
break;
}
}
},
};
var TextureSelectorDialog = {
new: func(dialogBase, dialogFile = "Aircraft/followme_e-tron/gui/dialogs/livery-select.xml", defaultV = "", name = "Texture selection"){
var m = gui.Dialog.new(dialogBase, dialogFile, name);
m.parents = [TextureSelectorDialog, gui.Dialog];
m.dialogNode = dialogBase;
m.dialogFile = dialogFile;
m.title = name;
m.list = m.dialogNode.getNode("list", 1);
m.result = props.getNode(m.list.getPath() ~ "/result", 1);
m.defaultValue = defaultV;
m.nasal = m.dialogNode.getNode("nasal", 1);
m.openScript = m.nasal.getNode("open", 1);
m.closeScript = m.nasal.getNode("close", 1);
m.openScript.setValue('print("' ~ m.title ~ ' dialog opened");
props.getNode(cmdarg().getPath()).getNode("opened"), 1).setValue(1);');
m.closeScript.setValue('followme.playAudio("repair.wav");
props.getNode(cmdarg().getPath()).getNode("opened", 1).setValue(0);');
m.reload();
#Reload when the GUI is reloaded
m.reload_listener = setlistener("/sim/signals/reinit-gui", func(n) m.reload());
return m;
},
reload: func(){
me.list.getNode("property").setValue(me.result.getPath());
me.result.setValue(me.result.getValue() or me.defaultValue);
me.openScript.setValue('print("' ~ me.title ~ ' dialog opened");
props.getNode(cmdarg().getPath()~"/opened", 1).setValue(1);');
me.closeScript.setValue('followme.playAudio("repair.wav");
props.getNode(cmdarg().getPath()).getNode("opened", 1).setValue(0);');
me.dialogNode.getNode("group/text/label").setValue(me.title);
me.dialogNode.getNode("group/button/binding/script").setValue('gui.Dialog.instance["' ~ me.dialogNode.getNode("name").getValue() ~ '"].close()');
}
};