svghmi/detachable_pages.ysl2
changeset 3302 c89fc366bebd
parent 3232 7bdb766c2a4d
child 3320 9fe5b4a04acc
equal deleted inserted replaced
2744:577118ebd179 3302:c89fc366bebd
       
     1 // detachable_pages.ysl2
       
     2 //
       
     3 // compute what elements are required by pages
       
     4 // and decide where to cut when removing/attaching
       
     5 // pages elements on page switch
       
     6 
       
     7 const "hmi_pages_descs", "$parsed_widgets/widget[@type = 'Page']";
       
     8 const "hmi_pages", "$hmi_elements[@id = $hmi_pages_descs/@id]";
       
     9 
       
    10 const "default_page" choose {
       
    11     when "count($hmi_pages) > 1" {
       
    12         choose {
       
    13             when "$hmi_pages_descs/arg[1]/@value = 'Home'" > Home
       
    14             otherwise {
       
    15                 error > No Home page defined!
       
    16             }
       
    17         }
       
    18     }
       
    19     when "count($hmi_pages) = 0" {
       
    20         error > No page defined!
       
    21     }
       
    22     otherwise > «func:widget($hmi_pages/@id)/arg[1]/@value»
       
    23 }
       
    24 
       
    25 emit "preamble:default-page" {
       
    26     |
       
    27     | var default_page = "«$default_page»";
       
    28 }
       
    29 
       
    30 const "keypads_descs", "$parsed_widgets/widget[@type = 'Keypad']";
       
    31 const "keypads", "$hmi_elements[@id = $keypads_descs/@id]";
       
    32 
       
    33 // returns all directly or indirectly refered elements
       
    34 def "func:refered_elements" {
       
    35     param "elems";
       
    36     const "descend", "$elems/descendant-or-self::svg:*";
       
    37     const "clones", "$descend[self::svg:use]";
       
    38     const "originals", "//svg:*[concat('#',@id) = $clones/@xlink:href]";
       
    39     choose {
       
    40         when "$originals"
       
    41             result "$descend | func:refered_elements($originals)";
       
    42         otherwise
       
    43             result "$descend";
       
    44     }
       
    45 }
       
    46 
       
    47 // variable "overlapping_geometry" was added for optimization.
       
    48 // It avoids calling func:overlapping_geometry 3 times for each page
       
    49 // (apparently libxml doesn't cache exslt function results)
       
    50 // in order to optimize further, func:overlapping_geometry 
       
    51 // should be implemented in python or even C,
       
    52 // as this is still the main bottleneck here
       
    53 const "_overlapping_geometry" {
       
    54     foreach "$hmi_pages | $keypads" {
       
    55         const "k", "concat('overlapping:', @id)";
       
    56         value "ns:ProgressStart($k, concat('collecting membership of ', @inkscape:label))";
       
    57         elt {
       
    58             attrib "id" > «@id»
       
    59             copy "func:overlapping_geometry(.)";
       
    60         }
       
    61         value "ns:ProgressEnd($k)";
       
    62     }
       
    63 }
       
    64 
       
    65 const "overlapping_geometry", "exsl:node-set($_overlapping_geometry)";
       
    66 
       
    67 def "func:all_related_elements" {
       
    68     param "page";
       
    69     const "page_overlapping_geometry", "$overlapping_geometry/elt[@id = $page/@id]/*";
       
    70     const "page_overlapping_elements", "//svg:*[@id = $page_overlapping_geometry/@Id]";
       
    71     const "page_sub_elements", "func:refered_elements($page | $page_overlapping_elements)";
       
    72     result "$page_sub_elements";
       
    73 }
       
    74 
       
    75 
       
    76 def "func:required_elements" {
       
    77     param "pages"; 
       
    78     choose{
       
    79         when "$pages"{
       
    80             result """func:all_related_elements($pages[1])
       
    81                       | func:required_elements($pages[position()!=1])""";
       
    82         }otherwise{
       
    83             result "/..";
       
    84         }
       
    85     }
       
    86 }
       
    87 
       
    88 const "required_page_elements",
       
    89     "func:required_elements($hmi_pages | $keypads)/ancestor-or-self::svg:*";
       
    90 
       
    91 const "hmi_lists_descs", "$parsed_widgets/widget[@type = 'List']";
       
    92 const "hmi_lists", "$hmi_elements[@id = $hmi_lists_descs/@id]";
       
    93 
       
    94 const "required_list_elements", "func:refered_elements($hmi_lists[@id = $required_page_elements/@id])";
       
    95 
       
    96 const "required_elements", "$defs | $required_list_elements | $required_page_elements";
       
    97 
       
    98 const "discardable_elements", "//svg:*[not(@id = $required_elements/@id)]";
       
    99 
       
   100 def "func:sumarized_elements" {
       
   101     param "elements";
       
   102     const "short_list", "$elements[not(ancestor::*/@id = $elements/@id)]";
       
   103     const "filled_groups", """$short_list/parent::*[
       
   104         not(child::*[
       
   105             not(@id = $discardable_elements/@id) and
       
   106             not(@id = $short_list/@id)
       
   107         ])]""";
       
   108     const "groups_to_add", "$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]";
       
   109     result "$groups_to_add | $short_list[not(ancestor::*/@id = $filled_groups/@id)]";
       
   110 }
       
   111 
       
   112 def "func:detachable_elements" {
       
   113     param "pages";
       
   114     choose{
       
   115         when "$pages"{
       
   116             result """func:sumarized_elements(func:all_related_elements($pages[1]))
       
   117                       | func:detachable_elements($pages[position()!=1])""";
       
   118         }otherwise{
       
   119             result "/..";
       
   120         }
       
   121     }
       
   122 }
       
   123 
       
   124 // Avoid nested detachables
       
   125 const "_detachable_elements", "func:detachable_elements($hmi_pages | $keypads)";
       
   126 const "detachable_elements", "$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]";
       
   127 
       
   128 emit "declarations:detachable-elements" {
       
   129     |
       
   130     | var detachable_elements = {
       
   131     foreach "$detachable_elements"{
       
   132     |     "«@id»":[id("«@id»"), id("«../@id»")]`if "position()!=last()" > ,`
       
   133     }
       
   134     | }
       
   135 }
       
   136 
       
   137 const "forEach_widgets_ids", "$parsed_widgets/widget[@type = 'ForEach']/@id";
       
   138 const "forEach_widgets", "$hmi_widgets[@id = $forEach_widgets_ids]";
       
   139 const "in_forEach_widget_ids", "func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id";
       
   140 
       
   141 template "svg:*", mode="page_desc" {
       
   142     if "ancestor::*[@id = $hmi_pages/@id]" error > HMI:Page «@id» is nested in another HMI:Page
       
   143 
       
   144 
       
   145     const "desc", "func:widget(@id)";
       
   146     const "pagename", "$desc/arg[1]/@value";
       
   147     const "msg", "concat('generating page description ', $pagename)";
       
   148     value "ns:ProgressStart($pagename, $msg)";
       
   149     const "page", ".";
       
   150     const "p", "$geometry[@Id = $page/@id]";
       
   151 
       
   152     const "page_all_elements", "func:all_related_elements($page)";
       
   153 
       
   154     const "all_page_widgets","$hmi_widgets[@id = $page_all_elements/@id and @id != $page/@id]";
       
   155     const "page_managed_widgets","$all_page_widgets[not(@id=$in_forEach_widget_ids)]";
       
   156     const "page_relative_widgets",
       
   157         "$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]";
       
   158 
       
   159     // Take closest ancestor in detachable_elements
       
   160     // since nested detachable elements are filtered out
       
   161     const "sumarized_page", 
       
   162         """func:sumarized_elements($page_all_elements)""";
       
   163 
       
   164     const "required_detachables", 
       
   165         """$sumarized_page/
       
   166            ancestor-or-self::*[@id = $detachable_elements/@id]""";
       
   167 
       
   168     |   "«$pagename»": {
       
   169     //|     widget: hmi_widgets["«@id»"],
       
   170     |     bbox: [«$p/@x», «$p/@y», «$p/@w», «$p/@h»],
       
   171     if "$desc/path/@value" {
       
   172         if "count($desc/path/@index)=0"
       
   173             warning > Page id="«$page/@id»" : No match for path "«$desc/path/@value»" in HMI tree
       
   174     |     page_index: «$desc/path/@index»,
       
   175     }
       
   176     |     widgets: [
       
   177     foreach "$page_managed_widgets" {
       
   178         const "widget_paths_relativeness" 
       
   179             foreach "func:widget(@id)/path" {
       
   180                 value "func:is_descendant_path(@value, $desc/path/@value)";
       
   181                 if "position()!=last()" > ,
       
   182             }
       
   183     |         [hmi_widgets["«@id»"], [«$widget_paths_relativeness»]]`if "position()!=last()" > ,`
       
   184     }
       
   185     |     ],
       
   186     |     jumps: [
       
   187     foreach "$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']" {
       
   188     |         hmi_widgets["«@id»"]`if "position()!=last()" > ,`
       
   189     }
       
   190     |     ],
       
   191     |     required_detachables: {
       
   192     foreach "$required_detachables" {
       
   193     |         "«@id»": detachable_elements["«@id»"]`if "position()!=last()" > ,`
       
   194     }
       
   195     |     }
       
   196     apply "$parsed_widgets/widget[@id = $all_page_widgets/@id]", mode="widget_page"{
       
   197         with "page_desc", "$desc";
       
   198     }
       
   199     |   }`if "position()!=last()" > ,`
       
   200     value "ns:ProgressEnd($pagename)";
       
   201 }
       
   202 
       
   203 emit "definitions:page-desc" {
       
   204     |
       
   205     | var page_desc = {
       
   206     apply "$hmi_pages", mode="page_desc";
       
   207     | }
       
   208 }
       
   209 
       
   210 template "*", mode="widget_page";
       
   211 
       
   212 
       
   213 emit "debug:detachable-pages" {
       
   214     |
       
   215     | DETACHABLES:
       
   216     foreach "$detachable_elements"{
       
   217         |  «@id»
       
   218     }
       
   219     | In Foreach:
       
   220     foreach "$in_forEach_widget_ids"{
       
   221         |  «.»
       
   222     }
       
   223     | Overlapping 
       
   224     apply "$overlapping_geometry", mode="testtree";
       
   225 }