svghmi/widget_foreach.ysl2
author Edouard Tisserant
Thu, 04 Jun 2020 11:14:21 +0200
branchsvghmi
changeset 2980 2a21d6060d64
parent 2959 ae549ba1a116
child 3003 9771a724af09
permissions -rw-r--r--
SVGHMI: add "unsubscribable" property to widgets in order to generalize what already happens for jump buttons.
In most cases jump buttons do not really subscribe to pointed HMI variable, path is given as a relative page jump path. When widget.unsubscribable is set to true, no subscription is made on page switch, but still offset is updated.
This fixes bug happening on relative jump buttons without "disabled" element where offset did not change on relative page switch.

template "widget[@type='ForEach']", mode="widget_defs" {
    param "hmi_element";

    const "class","arg[1]/@value";

    const "base_path","path/@value";
    const "hmi_index_base", "$indexed_hmitree/*[@hmipath = $base_path]";
    const "hmi_tree_base", "$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]";
    const "hmi_tree_items", "$hmi_tree_base/*[@class = $class]";
    const "hmi_index_items", "$indexed_hmitree/*[@path = $hmi_tree_items/@path]"; 
    const "items_paths", "$hmi_index_items/@hmipath"; 
    |     index_pool: [
    foreach "$hmi_index_items" {
    |       «@index»`if "position()!=last()" > ,`
    }
    |     ],
    |     init: function() {
    const "prefix","concat($class,':')";
    const "buttons_regex","concat('^',$prefix,'[+\-][0-9]+')";
    const "buttons", "$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]"; 
    foreach "$buttons" {
        const "op","substring-after(@inkscape:label, $prefix)";
    |         id("«@id»").setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_click('«$op»', evt)");
    }
    |
    |         this.items = [
    const "items_regex","concat('^',$prefix,'[0-9]+')";
    const "unordered_items","$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]";
    foreach "$unordered_items" {
        const "elt_label","concat($prefix, string(position()))"; 
        const "elt","$unordered_items[@inkscape:label = $elt_label]";
        const "pos","position()";
        const "item_path", "$items_paths[$pos]";
    |           [ /* item="«$elt_label»" path="«$item_path»" */
        if "count($elt)=0" error > Missing item labeled «$elt_label» in ForEach widget «$hmi_element/@id»
        foreach "func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]" {
            if "not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))"
                error > Widget id="«@id»" label="«@inkscape:label»" is having wrong path. Accroding to ForEach widget ancestor id="«$hmi_element/@id»", path should be descendant of "«$item_path»".
    |             hmi_widgets["«@id»"]`if "position()!=last()" > ,`
        }
    |           ]`if "position()!=last()" > ,`
    }
    |         ]
    |     },
    |     item_offset: 0,
}

template "widget[@type='ForEach']", mode="widget_class"
||
class ForEachWidget extends Widget{
    unsub(){
        for(let item of this.items){
            for(let widget of item) {
                widget.unsub();
            }
        }
        this.offset = 0;
    }

    foreach_widgets_do(new_offset, todo){
        this.offset = new_offset;
        for(let i = 0; i < this.items.length; i++) {
            let item = this.items[i];
            let orig_item_index = this.index_pool[i];
            let item_index = this.index_pool[i+this.item_offset];
            let item_index_offset = item_index - orig_item_index;
            for(let widget of item) {
                todo(widget).call(widget, new_offset + item_index_offset);
            }
        }
    }

    sub(new_offset=0){
        this.foreach_widgets_do(new_offset, w=>w.sub);
    }

    apply_cache() {
        this.foreach_widgets_do(this.offset, w=>w.apply_cache);
    }

    on_click(opstr, evt) {
        let new_item_offset = eval(String(this.item_offset)+opstr);
        if(new_item_offset + this.items.length > this.index_pool.length) {
            if(this.item_offset + this.items.length == this.index_pool.length)
                new_item_offset = 0;
            else
                new_item_offset = this.index_pool.length - this.items.length;
        } else if(new_item_offset < 0) {
            if(this.item_offset == 0)
                new_item_offset = this.index_pool.length - this.items.length;
            else
                new_item_offset = 0;
        }
        this.item_offset = new_item_offset;
        this.unsub();
        this.sub(this.offset);
        update_subscriptions();
        need_cache_apply.push(this);
        jumps_need_update = true;
        requestHMIAnimation();
    }
}
||