Edouard@2885: // detachable_pages.ysl2 edouard@2875: // edouard@2875: // compute what elements are required by pages Edouard@2887: // and decide where to cut when removing/attaching edouard@2875: // pages elements on page switch Edouard@2779: Edouard@2887: const "hmi_pages_descs", "$parsed_widgets/widget[@type = 'Page']"; Edouard@2887: const "hmi_pages", "$hmi_elements[@id = $hmi_pages_descs/@id]"; Edouard@2877: Edouard@2877: const "default_page" choose { Edouard@2877: when "count($hmi_pages) > 1" { Edouard@2877: choose { Edouard@2887: when "$hmi_pages_descs/arg[1]/@value = 'Home'" > Home Edouard@2877: otherwise { Edouard@3117: error > No Home page defined! Edouard@2877: } Edouard@2877: } Edouard@2877: } Edouard@2877: when "count($hmi_pages) = 0" { Edouard@3117: error > No page defined! Edouard@2877: } edouard@2886: otherwise > «func:widget($hmi_pages/@id)/arg[1]/@value» Edouard@2877: } Edouard@2877: edouard@2941: emit "preamble:default-page" { edouard@2941: | edouard@2941: | var default_page = "«$default_page»"; Edouard@3653: const "screensaverpage", "$hmi_pages_descs[arg[1]/@value = 'ScreenSaver']"; Edouard@3653: const "delay" choose { Edouard@3653: when "$screensaverpage" { Edouard@3653: const "delaystr", "$screensaverpage/arg[2]/@value"; Edouard@3653: if "not(regexp:test($delaystr,'^[0-9]+$'))" Edouard@3653: error > ScreenSaver page has missing or malformed delay argument. Edouard@3653: value "$delaystr"; Edouard@3653: } Edouard@3653: otherwise > null Edouard@3653: } Edouard@3653: | var screensaver_delay = «$delay»; edouard@2941: } edouard@2941: edouard@2941: const "keypads_descs", "$parsed_widgets/widget[@type = 'Keypad']"; edouard@2941: const "keypads", "$hmi_elements[@id = $keypads_descs/@id]"; edouard@2941: edouard@2875: // returns all directly or indirectly refered elements edouard@2875: def "func:refered_elements" { edouard@2875: param "elems"; edouard@2875: const "descend", "$elems/descendant-or-self::svg:*"; edouard@2875: const "clones", "$descend[self::svg:use]"; edouard@2875: const "originals", "//svg:*[concat('#',@id) = $clones/@xlink:href]"; edouard@2875: choose { edouard@2875: when "$originals" edouard@2875: result "$descend | func:refered_elements($originals)"; edouard@2875: otherwise edouard@2875: result "$descend"; edouard@2875: } edouard@2875: } Edouard@2792: edouard@3165: // variable "overlapping_geometry" was added for optimization. edouard@3165: // It avoids calling func:overlapping_geometry 3 times for each page edouard@3165: // (apparently libxml doesn't cache exslt function results) edouard@3165: // in order to optimize further, func:overlapping_geometry edouard@3165: // should be implemented in python or even C, edouard@3165: // as this is still the main bottleneck here edouard@3165: const "_overlapping_geometry" { edouard@3165: foreach "$hmi_pages | $keypads" { Edouard@3170: const "k", "concat('overlapping:', @id)"; Edouard@3170: value "ns:ProgressStart($k, concat('collecting membership of ', @inkscape:label))"; edouard@3165: elt { edouard@3165: attrib "id" > «@id» edouard@3165: copy "func:overlapping_geometry(.)"; edouard@3165: } Edouard@3170: value "ns:ProgressEnd($k)"; Edouard@3170: } edouard@3165: } edouard@3165: edouard@3165: const "overlapping_geometry", "exsl:node-set($_overlapping_geometry)"; edouard@3165: edouard@2875: def "func:all_related_elements" { edouard@2875: param "page"; edouard@3165: const "page_overlapping_geometry", "$overlapping_geometry/elt[@id = $page/@id]/*"; edouard@3923: const "overlapping_candidates", "//svg:*[not(starts-with((ancestor::svg:g | .) /@inkscape:label, 'DISCARD:'))]"; edouard@3923: const "page_overlapping_elements", "$overlapping_candidates[@id = $page_overlapping_geometry/@Id]"; Edouard@3622: const "page_widgets_elements", """ Edouard@3622: $hmi_elements[not(@id=$page/@id) Edouard@3622: and descendant-or-self::svg:*/@id = $page_overlapping_elements/@id] Edouard@3622: /descendant-or-self::svg:*"""; Edouard@3622: const "page_sub_elements", "func:refered_elements($page | $page_overlapping_elements | $page_widgets_elements)"; edouard@2875: result "$page_sub_elements"; edouard@2875: } Edouard@2808: edouard@3165: edouard@2875: def "func:required_elements" { edouard@2875: param "pages"; edouard@2875: choose{ edouard@2875: when "$pages"{ edouard@2875: result """func:all_related_elements($pages[1]) edouard@2875: | func:required_elements($pages[position()!=1])"""; edouard@2875: }otherwise{ edouard@2875: result "/.."; Edouard@2844: } Edouard@2844: } edouard@2875: } Edouard@2844: Edouard@3186: const "required_page_elements", Edouard@3186: "func:required_elements($hmi_pages | $keypads)/ancestor-or-self::svg:*"; Edouard@3186: Edouard@3384: const "required_list_elements", "func:refered_elements(($hmi_lists | $hmi_textlists)[@id = $required_page_elements/@id])/ancestor-or-self::svg:*"; Edouard@3186: Edouard@3199: const "required_elements", "$defs | $required_list_elements | $required_page_elements"; edouard@2873: edouard@2875: const "discardable_elements", "//svg:*[not(@id = $required_elements/@id)]"; Edouard@2844: edouard@2875: def "func:sumarized_elements" { edouard@2875: param "elements"; edouard@2875: const "short_list", "$elements[not(ancestor::*/@id = $elements/@id)]"; edouard@3877: const "filled_groups", """$short_list/parent::svg:g[ edouard@3161: not(child::*[ edouard@2875: not(@id = $discardable_elements/@id) and edouard@3161: not(@id = $short_list/@id) edouard@2875: ])]"""; edouard@2875: const "groups_to_add", "$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]"; edouard@3161: result "$groups_to_add | $short_list[not(ancestor::*/@id = $filled_groups/@id)]"; edouard@2875: } Edouard@2844: edouard@2875: def "func:detachable_elements" { edouard@2875: param "pages"; edouard@2875: choose{ edouard@2875: when "$pages"{ edouard@2875: result """func:sumarized_elements(func:all_related_elements($pages[1])) edouard@2875: | func:detachable_elements($pages[position()!=1])"""; edouard@2875: }otherwise{ edouard@2875: result "/.."; Edouard@2846: } Edouard@2846: } edouard@2875: } Edouard@2846: edouard@2875: // Avoid nested detachables Edouard@2911: const "_detachable_elements", "func:detachable_elements($hmi_pages | $keypads)"; edouard@2875: const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]"; Edouard@2846: Edouard@3685: emit "declarations:page-class" { Edouard@3685: | class PageWidget extends Widget{} Edouard@3685: } Edouard@3685: edouard@2943: emit "declarations:detachable-elements" { edouard@2941: | edouard@2941: | var detachable_elements = { edouard@2941: foreach "$detachable_elements"{ edouard@2941: | "«@id»":[id("«@id»"), id("«../@id»")]`if "position()!=last()" > ,` edouard@2941: } edouard@2941: | } edouard@2941: } edouard@2941: Edouard@2888: const "forEach_widgets_ids", "$parsed_widgets/widget[@type = 'ForEach']/@id"; Edouard@3121: const "forEach_widgets", "$hmi_widgets[@id = $forEach_widgets_ids]"; Edouard@2888: const "in_forEach_widget_ids", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id"; Edouard@2888: Edouard@2877: template "svg:*", mode="page_desc" { Edouard@3117: if "ancestor::*[@id = $hmi_pages/@id]" error > HMI:Page «@id» is nested in another HMI:Page Edouard@3117: edouard@3165: edouard@2886: const "desc", "func:widget(@id)"; Edouard@3170: const "pagename", "$desc/arg[1]/@value"; Edouard@3170: const "msg", "concat('generating page description ', $pagename)"; Edouard@3170: value "ns:ProgressStart($pagename, $msg)"; Edouard@2877: const "page", "."; Edouard@2877: const "p", "$geometry[@Id = $page/@id]"; Edouard@2877: Edouard@2877: const "page_all_elements", "func:all_related_elements($page)"; Edouard@2877: Edouard@3121: const "all_page_widgets","$hmi_widgets[@id = $page_all_elements/@id and @id != $page/@id]"; Edouard@2901: const "page_managed_widgets","$all_page_widgets[not(@id=$in_forEach_widget_ids)]"; Edouard@3685: Edouard@3685: const "page_root_path", "$desc/path[not(@assign)]"; Edouard@3685: if "count($page_root_path)>1" Edouard@3685: error > Page id="«$page/@id»" : only one root path can be declared Edouard@3685: Edouard@2877: const "page_relative_widgets", Edouard@3685: "$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $page_root_path/@value)]"; Edouard@2877: Edouard@2877: // Take closest ancestor in detachable_elements Edouard@2877: // since nested detachable elements are filtered out edouard@3165: const "sumarized_page", edouard@3165: """func:sumarized_elements($page_all_elements)"""; edouard@3165: Edouard@2877: const "required_detachables", edouard@3165: """$sumarized_page/ Edouard@2877: ancestor-or-self::*[@id = $detachable_elements/@id]"""; Edouard@2877: Edouard@3170: | "«$pagename»": { Edouard@2877: | bbox: [«$p/@x», «$p/@y», «$p/@w», «$p/@h»], Edouard@3685: if "count($page_root_path)=1"{ Edouard@3685: if "count($page_root_path/@index)=0" Edouard@3685: warning > Page id="«$page/@id»" : No match for path "«$page_root_path/@value»" in HMI tree Edouard@3685: | page_index: «$page_root_path/@index», Edouard@3685: | page_class: "«$indexed_hmitree/*[@hmipath = $page_root_path/@value]/@class»", Edouard@2877: } edouard@3005: | widgets: [ Edouard@3685: | [hmi_widgets["«$page/@id»"], []], edouard@3005: foreach "$page_managed_widgets" { edouard@3005: const "widget_paths_relativeness" edouard@3005: foreach "func:widget(@id)/path" { Edouard@3685: value "func:is_descendant_path(@value, $page_root_path/@value)"; edouard@3005: if "position()!=last()" > , edouard@3005: } edouard@3005: | [hmi_widgets["«@id»"], [«$widget_paths_relativeness»]]`if "position()!=last()" > ,` Edouard@2877: } Edouard@2877: | ], Edouard@2903: | jumps: [ Edouard@2903: foreach "$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']" { Edouard@2903: | hmi_widgets["«@id»"]`if "position()!=last()" > ,` Edouard@2903: } Edouard@2903: | ], Edouard@2877: | required_detachables: { Edouard@2877: foreach "$required_detachables" { Edouard@2877: | "«@id»": detachable_elements["«@id»"]`if "position()!=last()" > ,` Edouard@2877: } Edouard@2877: | } edouard@3232: apply "$parsed_widgets/widget[@id = $all_page_widgets/@id]", mode="widget_page"{ Edouard@2901: with "page_desc", "$desc"; Edouard@2901: } Edouard@2877: | }`if "position()!=last()" > ,` Edouard@3170: value "ns:ProgressEnd($pagename)"; Edouard@2877: } Edouard@2877: edouard@3007: emit "definitions:page-desc" { edouard@2941: | edouard@2941: | var page_desc = { edouard@2941: apply "$hmi_pages", mode="page_desc"; edouard@2941: | } edouard@2941: } edouard@2941: edouard@3232: template "*", mode="widget_page"; Edouard@2901: edouard@2904: edouard@2940: emit "debug:detachable-pages" { edouard@2941: | Edouard@2888: | DETACHABLES: Edouard@2876: foreach "$detachable_elements"{ Edouard@2876: | «@id» Edouard@2876: } Edouard@3622: | DISCARDABLES: Edouard@3622: foreach "$discardable_elements"{ Edouard@3622: | «@id» Edouard@3622: } Edouard@2888: | In Foreach: Edouard@2888: foreach "$in_forEach_widget_ids"{ Edouard@2888: | «.» Edouard@2888: } edouard@3165: | Overlapping edouard@3165: apply "$overlapping_geometry", mode="testtree"; edouard@3165: }