SVGHMI: Easier way to match HMI tree elements to paths. ForEach widget now looks for paths and indexes of all items, and enforce path to be consistent with ForEach items sub widgets
// hmi_tree.ysl2
// HMI Tree computed from VARIABLES.CSV in svghmi.py
const "hmitree", "ns:GetHMITree()";
const "_categories" {
noindex > HMI_PLC_STATUS
noindex > HMI_CURRENT_PAGE
}
const "categories", "exsl:node-set($_categories)";
// HMI Tree Index
const "_indexed_hmitree" apply "$hmitree", mode="index";
const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)";
template "*", mode="index" {
param "index", "0";
param "parentpath", "''";
const "content" {
const "path"
choose {
when "count(ancestor::*)=0" > /
when "count(ancestor::*)=1" > /«@name»
otherwise > «$parentpath»/«@name»
}
choose {
when "not(local-name() = $categories/noindex)" {
xsl:copy {
attrib "index" > «$index»
attrib "hmipath" > «$path»
foreach "@*" xsl:copy;
}
apply "*[1]", mode="index"{
with "index", "$index + 1";
with "parentpath" > «$path»
}
}
otherwise {
apply "*[1]", mode="index"{
with "index", "$index";
with "parentpath" > «$path»
}
}
}
}
copy "$content";
apply "following-sibling::*[1]", mode="index" {
with "index", "$index + count(exsl:node-set($content)/*)";
with "parentpath" > «$parentpath»
}
}
// Parses:
// "HMI:WidgetType:param1:param2@path1@path2"
//
// Into:
// widget type="WidgetType" id="blah456" {
// arg value="param1";
// arg value="param2";
// path value="path1" index="345";
// path value="path2";
// }
//
template "*", mode="parselabel" {
const "label","@inkscape:label";
const "description", "substring-after($label,'HMI:')";
const "_args", "substring-before($description,'@')";
const "args" choose {
when "$_args" value "$_args";
otherwise value "$description";
}
const "_type", "substring-before($args,':')";
const "type" choose {
when "$_type" value "$_type";
otherwise value "$args";
}
if "$type" widget {
attrib "id" > «@id»
attrib "type" > «$type»
foreach "str:split(substring-after($args, ':'), ':')" {
arg {
attrib "value" > «.»
}
}
const "paths", "substring-after($description,'@')";
foreach "str:split($paths, '@')" {
if "string-length(.) > 0" path {
attrib "value" > «.»
const "path", ".";
const "item", "$indexed_hmitree/*[@hmipath = $path]";
if "count($item) = 1"
attrib "index" > «$item/@index»
}
}
}
}
const "_parsed_widgets" apply "$hmi_elements", mode="parselabel";
const "parsed_widgets","exsl:node-set($_parsed_widgets)";
def "func:widget" {
param "id";
result "$parsed_widgets/widget[@id = $id]";
}
def "func:is_descendant_path" {
param "descend";
param "ancest";
// TODO : use HMI tree to answer more accurately
result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
}
// Debug data
template "*", mode="testtree"{
param "indent", "''";
> «$indent» «local-name()»
foreach "@*" > «local-name()»="«.»"
> \n
apply "*", mode="testtree" {
with "indent" value "concat($indent,'>')"
};
}
function "debug_hmitree" {
| Raw HMI tree
apply "$hmitree", mode="testtree";
|
| Indexed HMI tree
apply "$indexed_hmitree", mode="testtree";
|
| Parsed Widgets
copy "_parsed_widgets";
apply "$parsed_widgets", mode="testtree";
}
!debug_output_calls.append("debug_hmitree")