svghmi/hmi_tree.ysl2
author Edouard Tisserant
Mon, 15 Mar 2021 11:25:24 +0100
branchsvghmi
changeset 3188 c173452bf894
parent 3129 f2709923c82c
child 3205 62753288be74
permissions -rw-r--r--
SVGHMI: Fixed problems happening when value is higher than maximum or lower than minimum in Input widget. "max" and "min" string was getting into keypad text field, was not diplayed systematically, and was staying forever sometime.
// hmi_tree.ysl2


// HMI Tree computed from VARIABLES.CSV in svghmi.py
const "hmitree", "ns:GetHMITree()";

const "_categories" {
    noindex > HMI_PLC_STATUS
    noindex > HMI_CURRENT_PAGE
}
const "categories", "exsl:node-set($_categories)";

// HMI Tree Index
const "_indexed_hmitree" apply "$hmitree", mode="index";
const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)";

emit "preamble:hmi-tree" {
    | var hmi_hash = [«$hmitree/@hash»];
    |
    | var heartbeat_index = «$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index»;
    |
    | var hmitree_types = [

    foreach "$indexed_hmitree/*" 
    |     /* «@index»  «@hmipath» */ "«substring(local-name(), 5)»"`if "position()!=last()" > ,`

    | ];
    |
}

template "*", mode="index" {
    param "index", "0";
    param "parentpath", "''";
    const "content" {
        const "path"
            choose {
                when "count(ancestor::*)=0" > /
                when "count(ancestor::*)=1" > /«@name»
                otherwise > «$parentpath»/«@name»
            }
        choose {
            when "not(local-name() = $categories/noindex)" {
                xsl:copy {
                    attrib "index" > «$index»
                    attrib "hmipath" > «$path»
                    foreach "@*" xsl:copy;
                }
                apply "*[1]", mode="index"{
                     with "index", "$index + 1";
                     with "parentpath" > «$path»
                }
            }
            otherwise {
                apply "*[1]", mode="index"{
                    with "index", "$index";
                    with "parentpath" > «$path»
                }
            }
        }
    }

    copy "$content";
    apply "following-sibling::*[1]", mode="index" {
        with "index", "$index + count(exsl:node-set($content)/*)";
        with "parentpath" > «$parentpath»
    }
}

//  Parses:
//  "HMI:WidgetType:param1:param2@path1,path1min,path1max@path2"
//
//  Into:
//  widget type="WidgetType" id="blah456" {
//      arg value="param1";
//      arg value="param2";
//      path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL";
//      path value="/path1" index="348" type="HMI_INT";
//      path value="path4" index="path4" type="HMI_LOCAL";
//  }
//
template "*", mode="parselabel" {
    const "label","@inkscape:label";
    const "id","@id";
    const "description", "substring-after($label,'HMI:')";

    const "_args", "substring-before($description,'@')";
    const "args" choose {
        when "$_args" value "$_args";
        otherwise value "$description";
    }

    const "_type", "substring-before($args,':')";
    const "type" choose {
        when "$_type" value "$_type";
        otherwise value "$args";
    }

    if "$type" widget {
        attrib "id" > «$id»
        attrib "type" > «$type»
        foreach "str:split(substring-after($args, ':'), ':')" {
            arg {
                attrib "value" > «.»
            }
        }
        const "paths", "substring-after($description,'@')";
        foreach "str:split($paths, '@')" {
            if "string-length(.) > 0" path {
                const "pathminmax", "str:split(.,',')";
                const "path", "$pathminmax[1]";
                const "pathminmaxcount", "count($pathminmax)";
                attrib "value" > «$path»
                choose {
                    when "$pathminmaxcount = 3" {
                        attrib "min" > «$pathminmax[2]»
                        attrib "max" > «$pathminmax[3]»
                    }
                    when "$pathminmaxcount = 2" {
                        error > Widget id:«$id» label:«$label» has wrong syntax of path section «$pathminmax»
                    }
                }
                choose {
                    when "regexp:test($path,'^\.[a-zA-Z0-9_]+$')" {
                        attrib "type" > PAGE_LOCAL
                    }
                    when "regexp:test($path,'^[a-zA-Z0-9_]+$')" {
                        attrib "type" > HMI_LOCAL
                    }
                    otherwise {
                        const "item", "$indexed_hmitree/*[@hmipath = $path]";
                        const "pathtype", "local-name($item)";
                        if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
                            error > Widget id:«$id» label:«$label» path section «$pathminmax» use min and max on non mumeric value
                        }
                        if "count($item) = 1" {
                            attrib "index" > «$item/@index»
                            attrib "type" > «$pathtype»
                        }
                    }
                }
            }
        }
    }
}

const "_parsed_widgets" {
    widget type="VarInitPersistent" {
        arg value="0";
        path value="lang";
    }
    apply "$hmi_elements", mode="parselabel";
}

const "parsed_widgets","exsl:node-set($_parsed_widgets)";

def "func:widget" {
    param "id";
    result "$parsed_widgets/widget[@id = $id]";
}

def "func:is_descendant_path" {
    param "descend";
    param "ancest";
    // TODO : use HMI tree to answer more accurately
    result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
}

def "func:same_class_paths" {
    param "a";
    param "b";
    const "class_a", "$indexed_hmitree/*[@hmipath = $a]/@class";
    const "class_b", "$indexed_hmitree/*[@hmipath = $b]/@class";
    result "$class_a and $class_b and $class_a = $class_b";
}

// Debug data
template "*", mode="testtree"{
    param "indent", "''";
    > «$indent» «local-name()» 
    foreach "@*" > «local-name()»="«.»" 
    > \n
    apply "*", mode="testtree" {
        with "indent" value "concat($indent,'>')"
    };
}

emit "debug:hmi-tree" {
    | Raw HMI tree
    apply "$hmitree", mode="testtree";
    |
    | Indexed HMI tree
    apply "$indexed_hmitree", mode="testtree";
    |
    | Parsed Widgets
    copy "_parsed_widgets";
    apply "$parsed_widgets", mode="testtree";
}