SVGHMI: Remove recursive walk in parsed widget to find unique type and use xsl:key instead.
// detachable_pages.ysl2
//
// compute what elements are required by pages
// and decide where to cut when removing/attaching
// pages elements on page switch
const "hmi_pages_descs", "$parsed_widgets/widget[@type = 'Page']";
const "hmi_pages", "$hmi_elements[@id = $hmi_pages_descs/@id]";
const "default_page" choose {
when "count($hmi_pages) > 1" {
choose {
when "$hmi_pages_descs/arg[1]/@value = 'Home'" > Home
otherwise {
error > No Home page defined!
}
}
}
when "count($hmi_pages) = 0" {
error > No page defined!
}
otherwise > «func:widget($hmi_pages/@id)/arg[1]/@value»
}
emit "preamble:default-page" {
|
| var default_page = "«$default_page»";
}
const "keypads_descs", "$parsed_widgets/widget[@type = 'Keypad']";
const "keypads", "$hmi_elements[@id = $keypads_descs/@id]";
// returns all directly or indirectly refered elements
def "func:refered_elements" {
param "elems";
const "descend", "$elems/descendant-or-self::svg:*";
const "clones", "$descend[self::svg:use]";
const "originals", "//svg:*[concat('#',@id) = $clones/@xlink:href]";
choose {
when "$originals"
result "$descend | func:refered_elements($originals)";
otherwise
result "$descend";
}
}
def "func:all_related_elements" {
param "page";
const "page_overlapping_geometry", "func:overlapping_geometry($page)";
const "page_overlapping_elements", "//svg:*[@id = $page_overlapping_geometry/@Id]";
const "page_sub_elements", "func:refered_elements($page | $page_overlapping_elements)";
result "$page_sub_elements";
}
def "func:required_elements" {
param "pages";
choose{
when "$pages"{
result """func:all_related_elements($pages[1])
| func:required_elements($pages[position()!=1])""";
}otherwise{
result "/..";
}
}
}
const "required_elements",
"""//svg:defs/descendant-or-self::svg:*
| func:required_elements($hmi_pages | $keypads)/ancestor-or-self::svg:*""";
const "discardable_elements", "//svg:*[not(@id = $required_elements/@id)]";
def "func:sumarized_elements" {
param "elements";
const "short_list", "$elements[not(ancestor::*/@id = $elements/@id)]";
const "filled_groups", """$short_list/parent::svg:*[
not(descendant::*[
not(self::svg:g) and
not(@id = $discardable_elements/@id) and
not(@id = $short_list/descendant-or-self::*[not(self::svg:g)]/@id)
])]""";
const "groups_to_add", "$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]";
result "$groups_to_add | $short_list[not(ancestor::svg:g/@id = $filled_groups/@id)]";
}
def "func:detachable_elements" {
param "pages";
choose{
when "$pages"{
result """func:sumarized_elements(func:all_related_elements($pages[1]))
| func:detachable_elements($pages[position()!=1])""";
}otherwise{
result "/..";
}
}
}
// Avoid nested detachables
const "_detachable_elements", "func:detachable_elements($hmi_pages | $keypads)";
const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]";
emit "declarations:detachable-elements" {
|
| var detachable_elements = {
foreach "$detachable_elements"{
| "«@id»":[id("«@id»"), id("«../@id»")]`if "position()!=last()" > ,`
}
| }
}
const "forEach_widgets_ids", "$parsed_widgets/widget[@type = 'ForEach']/@id";
const "forEach_widgets", "$hmi_elements[@id = $forEach_widgets_ids]";
const "in_forEach_widget_ids", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id";
template "svg:*", mode="page_desc" {
if "ancestor::*[@id = $hmi_pages/@id]" error > HMI:Page «@id» is nested in another HMI:Page
const "desc", "func:widget(@id)";
const "page", ".";
const "p", "$geometry[@Id = $page/@id]";
const "page_all_elements", "func:all_related_elements($page)";
const "all_page_widgets","$hmi_elements[@id = $page_all_elements/@id and @id != $page/@id]";
const "page_managed_widgets","$all_page_widgets[not(@id=$in_forEach_widget_ids)]";
const "page_relative_widgets",
"$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]";
// Take closest ancestor in detachable_elements
// since nested detachable elements are filtered out
const "required_detachables",
"""func:sumarized_elements($page_all_elements)/
ancestor-or-self::*[@id = $detachable_elements/@id]""";
| "«$desc/arg[1]/@value»": {
//| widget: hmi_widgets["«@id»"],
| bbox: [«$p/@x», «$p/@y», «$p/@w», «$p/@h»],
if "$desc/path/@value" {
if "count($desc/path/@index)=0"
warning > Page id="«$page/@id»" : No match for path "«$desc/path/@value»" in HMI tree
| page_index: «$desc/path/@index»,
}
| widgets: [
foreach "$page_managed_widgets" {
const "widget_paths_relativeness"
foreach "func:widget(@id)/path" {
value "func:is_descendant_path(@value, $desc/path/@value)";
if "position()!=last()" > ,
}
| [hmi_widgets["«@id»"], [«$widget_paths_relativeness»]]`if "position()!=last()" > ,`
}
| ],
| jumps: [
foreach "$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']" {
| hmi_widgets["«@id»"]`if "position()!=last()" > ,`
}
| ],
| required_detachables: {
foreach "$required_detachables" {
| "«@id»": detachable_elements["«@id»"]`if "position()!=last()" > ,`
}
| }
/* TODO generate some code for init() instead */
apply "$parsed_widgets/widget[@id = $all_page_widgets/@id]", mode="per_page_widget_template"{
with "page_desc", "$desc";
}
| }`if "position()!=last()" > ,`
}
emit "definitions:page-desc" {
|
| var page_desc = {
apply "$hmi_pages", mode="page_desc";
| }
}
template "*", mode="per_page_widget_template";
emit "debug:detachable-pages" {
|
| DETACHABLES:
foreach "$detachable_elements"{
| «@id»
}
| In Foreach:
foreach "$in_forEach_widget_ids"{
| «.»
}
}