// detachable_elements.ysl2
//
// compute what elements are required by pages
// and decide where to cut when removing/attaching
// pages elements on page switch
const "hmi_pages", "$hmi_elements[func:parselabel(@inkscape:label)/widget/@type = 'Page']";
const "default_page" choose {
when "count($hmi_pages) > 1" {
const "Home_page",
"$hmi_pages[func:parselabel(@inkscape:label)/widget/arg[1]/@value = 'Home']";
choose {
when "$Home_page" > Home
otherwise {
error "No Home page defined!";
}
}
}
when "count($hmi_pages) = 0" {
error "No page defined!";
}
otherwise > «func:parselabel($hmi_pages/@inkscape:label)/widget/arg[1]/@value»
}
// 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)/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)";
const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]";
def "func:is_descendant_path" {
param "descend";
param "ancest";
result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
}
template "svg:*", mode="page_desc" {
const "desc", "func:parselabel(@inkscape:label)/widget";
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_relative_widgets",
"$all_page_widgets[func:is_descendant_path(func:parselabel(@inkscape:label)/widget/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»,
}
| relative_widgets: [
foreach "$page_relative_widgets" {
| hmi_widgets["«@id»"]`if "position()!=last()" > ,`
}
| ],
| absolute_widgets: [
foreach "$all_page_widgets[not(@id = $page_relative_widgets/@id)]" {
| hmi_widgets["«@id»"]`if "position()!=last()" > ,`
}
| ],
| required_detachables: {
foreach "$required_detachables" {
| "«@id»": detachable_elements["«@id»"]`if "position()!=last()" > ,`
}
| }
| }`if "position()!=last()" > ,`
}
function "debug_detachables" {
foreach "$detachable_elements"{
| «@id»
}
}
!debug_output_calls.append("debug_detachables")