# HG changeset patch # User Edouard Tisserant # Date 1621322537 -7200 # Node ID fe945f1f48b7e59f8b5993c047641980ad23a8f0 # Parent 8a9d4c794cbaacbec0a26d5d688d93c75bb8aa2f SVGHMI: WIP on Widget DnD UI : Added documentation to widgets, that is injected in widget parse tree during widget analysis diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/analyse_widget.xslt --- a/svghmi/analyse_widget.xslt Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/analyse_widget.xslt Tue May 18 09:22:17 2021 +0200 @@ -145,9 +145,529 @@ + + + + + + AnimateRotation - DEPRECATED, do not use. + + Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) + + + + AnimateRotation - DEPRECATED + + + speed + + + + + + + + Back widget brings focus back to previous page in history when clicked. + + + + Jump to previous page + + + + + + + + Button widget takes one boolean variable path, and reflect current true + + or false value by showing "active" or "inactive" labeled element + + respectively. Pressing and releasing button changes variable to true and + + false respectively. Potential inconsistency caused by quick consecutive + + presses on the button is mitigated by using a state machine that wait for + + previous state change to be reflected on variable before applying next one. + + + + Push button reflecting consistently given boolean variable + + + Boolean variable + + + + + + + + CircularBar widget changes the end angle of a "path" labeled arc according + + to value of the single accepted variable. + + + + If "min" a "max" labeled texts are provided, then they are used as + + respective minimum and maximum value. Otherwise, value is expected to be + + in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + + + Change end angle of Inkscape's arc + + + Value to display + + + + + + + + CircularSlider - DEPRECATED, to be replaced by PathSlider + + This widget moves "handle" labeled group along "range" labeled + + arc, according to value of the single accepted variable. + + + + If "min" a "max" labeled texts are provided, or if first and second + + argument are given, then they are used as respective minimum and maximum + + value. Otherwise, value is expected to be in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + During drag, "setpoint" labeled group is moved to position defined by user + + while "handle" reflects current value from variable. + + + + CircularSlider - DEPRECATED + + + minimum value + + + maximum value + + + Value to display + + + + + + + + CustomHtml widget allows insertion of HTML code in a svg:foreignObject. + + Widget content is replaced by foreignObject. HTML code is obtained from + + "code" labeled text content. HTML insert position and size is given with + + "container" labeled element. + + + + Custom HTML insert + + + + + + + + If Display widget is a svg:text element, then text content is replaced by + + value of given variables, space separated. + + + + Otherwise, if Display widget is a group containing a svg:text element + + labelled "format", then text content is replaced by printf-like formated + + string. In other words, if "format" labeled text is "%d %s %f", then 3 + + variables paths are expected : HMI_IN, HMI_STRING and HMI_REAL. + + + + In case Display widget is a svg::text element, it is also possible to give + + format string as first argument. + + + + Printf-like formated text display + + + printf-like format string when not given as svg:text + + + variables to be displayed + + + + + + + + DropDown widget let user select an entry in a list of texts, given as + + arguments. Single variable path is index of selection. + + + + It needs "text" (svg:text), "box" (svg:rect), "button" (svg:*), + + and "highlight" (svg:rect) labeled elements. + + + + When user clicks on "button", "text" is duplicated to display enties in the + + limit of available space in page, and "box" is extended to contain all + + texts. "highlight" is moved over pre-selected entry. + + + + When only one argument is given, and argment contains "#langs" then list of + + texts is automatically set to the list of human-readable languages supported + + by this HMI. + + + + Let user select text entry in a drop-down menu + + + drop-down menu entries + + + selection index + + + + + + + + ForEach widget is used to span a small set of widget over a larger set of + + repeated HMI_NODEs. + + + + Idea is somewhat similar to relative page, but it all happens inside the + + ForEach widget, no page involved. + + + + Together with relative Jump widgets it can be used to build a menu to reach + + relative pages covering many identical HMI_NODES siblings. + + + + ForEach widget takes a HMI_CLASS name as argument and a HMI_NODE path as + + variable. + + + + Direct sub-elements can be either groups of widget to be spanned, labeled + + "ClassName:offset", or buttons to control the spanning, labeled + + "ClassName:+/-number". + + + + span widgets over a set of repeated HMI_NODEs + + + HMI_CLASS name + + + where to find HMI_NODEs whose HMI_CLASS is class_name + + + + + + + + Input widget takes one variable path, and displays current value in + + optional "value" labeled sub-element. + + + + Click on optional "edit" labeled element opens keypad to edit value. + + + + Operation on current value is performed when click on sub-elements with + + label starting with '=', '+' or '-' sign. Value after sign is used as + + operand. + + + + Input field with predefined operation buttons + + + optional printf-like format + + + single variable to edit + + + + + + + + Send given variables as POST to http URL argument, spread returned JSON in + + SVG sub-elements of "data" labeled element. + + + + Documentation to be written. see svbghmi exemple. + + + + Http POST variables, spread JSON back + + + + + + single variable to edit + + + + + + + + Jump widget brings focus to a different page. Mandatory single argument + + gives name of the page. + + + + Optional single path is used as new reference when jumping to a relative + + page, it must point to a HMI_NODE. + + + + "active"+"inactive" labeled elements can be provided and reflect current + + page being shown. + + + + "disabled" labeled element, if provided, is shown instead of "active" or + + "inactive" widget when pointed HMI_NODE is null. + + + + Jump to given page + + + name of page to jump to + + + reference for relative jump + + + + + + + + Keypad - to be written + + + + Keypad + + + keypad can input those types + + + + + + + + + + + + + Meter widget moves the end of "needle" labeled path along "range" labeled + + path, according to value of the single accepted variable. + + + + Needle is reduced to a single segment. If "min" a "max" labeled texts + + are provided, or if first and second argument are given, then they are used + + as respective minimum and maximum value. Otherwise, value is expected to be + + in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + + + Moves "needle" along "range" + + + minimum value + + + maximum value + + + Value to display + + + + + + + + ScrollBar - documentation to be written + + + + ScrollBar + + + value + + + range + + + visible + + + + + + + + Slider - DEPRECATED - use ScrollBar or PathSlider instead + + + + Slider - DEPRECATED - use ScrollBar instead + + + value + + + range + + + visible + + + + + + + + Switch widget hides all subelements whose label do not match given + + variable current value representation. For exemple if given variable type + + is HMI_INT and value is 1, then elements with label '1' will be displayed. + + Label can have comments, so '1#some comment' would also match. If matching + + variable of type HMI_STRING, then double quotes must be used. For exemple, + + '"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. + + + + Show elements whose label match value. + + + value to compare to labels + + + + + + + + Button widget takes one boolean variable path, and reflect current true + + or false value by showing "active" or "inactive" labeled element + + respectively. Clicking or touching button toggles variable. + + + + Toggle button reflecting given boolean variable + + + Boolean variable + + + + + + + + + + + + + + + + + + + - + diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/analyse_widget.ysl2 --- a/svghmi/analyse_widget.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/analyse_widget.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,17 @@ include yslt_noindent.yml2 +in xsl decl widget_desc(%name, match="widget[@type='%name']", mode="widget_desc") alias template { + type > «@type» + content; +}; + +decl nothing alias - ; +decl widget_class(%name) alias - {nothing}; +decl widget_defs(%name) alias - {nothing}; +decl widget_page(%name) alias - {nothing}; +decl gen_index_xhtml alias - {nothing}; +decl emit(*name) alias - {nothing}; + istylesheet /* From Inkscape */ xmlns:svg="http://www.w3.org/2000/svg" @@ -13,8 +25,25 @@ const "hmi_elements", "//svg:*[starts-with(@inkscape:label, 'HMI:')]"; - template "/" - widgets + include widget_*.ysl2 + + template "@* | node()", mode="document" { + xsl:copy apply "@* | node()", mode="document"; + } + + template "widget", mode="document" { + xsl:copy { + apply "@* | node()", mode="document"; + defs apply ".", mode="widget_desc"; + } + } + + template "/" { + const "widgets" apply "$hmi_elements", mode="parselabel"; + const "widget_ns", "exsl:node-set($widgets)"; + widgets + apply "$widget_ns", mode="document"; + } } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/gen_index_xhtml.xslt Tue May 18 09:22:17 2021 +0200 @@ -1964,6 +1964,23 @@ } + + + + + + AnimateRotation - DEPRECATED, do not use. + + Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) + + + + AnimateRotation - DEPRECATED + + + speed + + class AnimateRotationWidget @@ -1995,6 +2012,8 @@ // change animation properties + // TODO : rewrite with proper es6 + for(let child of this.element.children){ if(child.nodeName == "animateTransform"){ @@ -2046,11 +2065,17 @@ } - - - - - + + + + + + Back widget brings focus back to previous page in history when clicked. + + + + Jump to previous page + class @@ -2080,6 +2105,31 @@ } + + + + + + Button widget takes one boolean variable path, and reflect current true + + or false value by showing "active" or "inactive" labeled element + + respectively. Pressing and releasing button changes variable to true and + + false respectively. Potential inconsistency caused by quick consecutive + + presses on the button is mitigated by using a state machine that wait for + + previous state change to be reflected on variable before applying next one. + + + + Push button reflecting consistently given boolean variable + + + Boolean variable + + @@ -2301,7 +2351,6 @@ - @@ -2310,6 +2359,35 @@ + + + + + + CircularBar widget changes the end angle of a "path" labeled arc according + + to value of the single accepted variable. + + + + If "min" a "max" labeled texts are provided, then they are used as + + respective minimum and maximum value. Otherwise, value is expected to be + + in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + + + Change end angle of Inkscape's arc + + + Value to display + + class CircularBarWidget @@ -2412,7 +2490,6 @@ - @@ -2427,6 +2504,47 @@ + + + + + + CircularSlider - DEPRECATED, to be replaced by PathSlider + + This widget moves "handle" labeled group along "range" labeled + + arc, according to value of the single accepted variable. + + + + If "min" a "max" labeled texts are provided, or if first and second + + argument are given, then they are used as respective minimum and maximum + + value. Otherwise, value is expected to be in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + During drag, "setpoint" labeled group is moved to position defined by user + + while "handle" reflects current value from variable. + + + + CircularSlider - DEPRECATED + + + minimum value + + + maximum value + + + Value to display + + class CircularSliderWidget @@ -2887,7 +3005,6 @@ - @@ -2904,6 +3021,24 @@ + + + + + + CustomHtml widget allows insertion of HTML code in a svg:foreignObject. + + Widget content is replaced by foreignObject. HTML code is obtained from + + "code" labeled text content. HTML insert position and size is given with + + "container" labeled element. + + + + Custom HTML insert + + class CustomHtmlWidget @@ -2950,7 +3085,6 @@ - @@ -2958,6 +3092,42 @@ + + + + + + If Display widget is a svg:text element, then text content is replaced by + + value of given variables, space separated. + + + + Otherwise, if Display widget is a group containing a svg:text element + + labelled "format", then text content is replaced by printf-like formated + + string. In other words, if "format" labeled text is "%d %s %f", then 3 + + variables paths are expected : HMI_IN, HMI_STRING and HMI_REAL. + + + + In case Display widget is a svg::text element, it is also possible to give + + format string as first argument. + + + + Printf-like formated text display + + + printf-like format string when not given as svg:text + + + variables to be displayed + + class DisplayWidget @@ -2978,7 +3148,6 @@ - @@ -3530,6 +3699,48 @@ + + + + + + DropDown widget let user select an entry in a list of texts, given as + + arguments. Single variable path is index of selection. + + + + It needs "text" (svg:text), "box" (svg:rect), "button" (svg:*), + + and "highlight" (svg:rect) labeled elements. + + + + When user clicks on "button", "text" is duplicated to display enties in the + + limit of available space in page, and "box" is extended to contain all + + texts. "highlight" is moved over pre-selected entry. + + + + When only one argument is given, and argment contains "#langs" then list of + + texts is automatically set to the list of human-readable languages supported + + by this HMI. + + + + Let user select text entry in a drop-down menu + + + drop-down menu entries + + + selection index + + class DropDownWidget @@ -4192,7 +4403,6 @@ - @@ -4219,9 +4429,54 @@ , + + + + + + ForEach widget is used to span a small set of widget over a larger set of + + repeated HMI_NODEs. + + + + Idea is somewhat similar to relative page, but it all happens inside the + + ForEach widget, no page involved. + + + + Together with relative Jump widgets it can be used to build a menu to reach + + relative pages covering many identical HMI_NODES siblings. + + + + ForEach widget takes a HMI_CLASS name as argument and a HMI_NODE path as + + variable. + + + + Direct sub-elements can be either groups of widget to be spanned, labeled + + "ClassName:offset", or buttons to control the spanning, labeled + + "ClassName:+/-number". + + + + span widgets over a set of repeated HMI_NODEs + + + HMI_CLASS name + + + where to find HMI_NODEs whose HMI_CLASS is class_name + + - ForEach widget @@ -4479,22 +4734,28 @@ Input widget takes one variable path, and displays current value in - optional "value" labeled sub-element. Click on optional "edit" labeled - - element opens keypad to edit value. Operation on current value is - - performed when click on sub-elements with label starting with '=', '+' - - or '-' sign. Value after sign is used as operand. + optional "value" labeled sub-element. + + + + Click on optional "edit" labeled element opens keypad to edit value. + + + + Operation on current value is performed when click on sub-elements with + + label starting with '=', '+' or '-' sign. Value after sign is used as + + operand. Input field with predefined operation buttons - + optional printf-like format - + single variable to edit @@ -4651,6 +4912,30 @@ }, + + + + + + Send given variables as POST to http URL argument, spread returned JSON in + + SVG sub-elements of "data" labeled element. + + + + Documentation to be written. see svbghmi exemple. + + + + Http POST variables, spread JSON back + + + + + + single variable to edit + + class JsonTableWidget @@ -5075,7 +5360,6 @@ - @@ -5120,6 +5404,44 @@ } + + + + + + Jump widget brings focus to a different page. Mandatory single argument + + gives name of the page. + + + + Optional single path is used as new reference when jumping to a relative + + page, it must point to a HMI_NODE. + + + + "active"+"inactive" labeled elements can be provided and reflect current + + page being shown. + + + + "disabled" labeled element, if provided, is shown instead of "active" or + + "inactive" widget when pointed HMI_NODE is null. + + + + Jump to given page + + + name of page to jump to + + + reference for relative jump + + class JumpWidget @@ -5238,7 +5560,6 @@ - @@ -5354,6 +5675,21 @@ + + + + + + Keypad - to be written + + + + Keypad + + + keypad can input those types + + @@ -5585,7 +5921,6 @@ - @@ -5645,9 +5980,13 @@ ], + + + + + - items: { @@ -5663,6 +6002,8 @@ + + styles: { @@ -5678,6 +6019,43 @@ }, + + + + + + Meter widget moves the end of "needle" labeled path along "range" labeled + + path, according to value of the single accepted variable. + + + + Needle is reduced to a single segment. If "min" a "max" labeled texts + + are provided, or if first and second argument are given, then they are used + + as respective minimum and maximum value. Otherwise, value is expected to be + + in between 0 and 100. + + + + If "value" labeled text is found, then its content is replaced by value. + + + + Moves "needle" along "range" + + + minimum value + + + maximum value + + + Value to display + + class MetterWidget @@ -5740,7 +6118,6 @@ - @@ -5755,6 +6132,35 @@ + + + + Mutlistateh widget hides all subelements whose label do not match given + + variable value representation. For exemple if given variable type + + is HMI_INT and value is 1, then elements with label '1' will be displayed. + + Label can have comments, so '1#some comment' would also match. If matching + + variable of type HMI_STRING, then double quotes must be used. For exemple, + + '"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. + + + + Click on widget changes variable value to next value in given list, or to + + first one if not initialized to value already part of the list. + + + + Show elements whose label match value. + + + value to compare to labels + + class MultiStateWidget @@ -5841,7 +6247,6 @@ - choices: [ @@ -5871,6 +6276,27 @@ ], + + + + + + ScrollBar - documentation to be written + + + + ScrollBar + + + value + + + range + + + visible + + class ScrollBarWidget @@ -6053,7 +6479,6 @@ - @@ -6084,6 +6509,27 @@ }, + + + + + + Slider - DEPRECATED - use ScrollBar or PathSlider instead + + + + Slider - DEPRECATED - use ScrollBar instead + + + value + + + range + + + visible + + class SliderWidget @@ -6764,7 +7210,6 @@ - @@ -6779,6 +7224,31 @@ + + + + + + Switch widget hides all subelements whose label do not match given + + variable current value representation. For exemple if given variable type + + is HMI_INT and value is 1, then elements with label '1' will be displayed. + + Label can have comments, so '1#some comment' would also match. If matching + + variable of type HMI_STRING, then double quotes must be used. For exemple, + + '"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. + + + + Show elements whose label match value. + + + value to compare to labels + + class SwitchWidget @@ -6809,7 +7279,6 @@ - choices: [ @@ -6842,6 +7311,25 @@ ], + + + + + + Button widget takes one boolean variable path, and reflect current true + + or false value by showing "active" or "inactive" labeled element + + respectively. Clicking or touching button toggles variable. + + + + Toggle button reflecting given boolean variable + + + Boolean variable + + class ToggleButtonWidget @@ -6926,7 +7414,6 @@ - diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/ui.py --- a/svghmi/ui.py Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/ui.py Tue May 18 09:22:17 2021 +0200 @@ -128,6 +128,7 @@ _conf_key = "SVGHMIWidgetLib" _preview_height = 200 +_preview_margin = 5 class WidgetLibBrowser(wx.Panel): def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize): @@ -142,24 +143,24 @@ self.Config = wx.ConfigBase.Get() self.libdir = self.RecallLibDir() - sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=0) - sizer.AddGrowableCol(0) - sizer.AddGrowableRow(1) + self.main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=0) + self.main_sizer.AddGrowableCol(0) + self.main_sizer.AddGrowableRow(1) self.libbutton = wx.Button(self, -1, _("Select SVG widget library")) self.widgetpicker = WidgetPicker(self, self.libdir) - self.preview = wx.Panel(self, size=(-1, _preview_height + 10)) - self.desc = wx.TextCtrl(self, size=wx.Size(-1, 80), + self.preview = wx.Panel(self, size=(-1, _preview_height + _preview_margin*2)) + self.desc = wx.TextCtrl(self, size=wx.Size(-1, 160), style=wx.TE_READONLY | wx.TE_MULTILINE) self.signature_sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.libbutton, flag=wx.GROW) - sizer.Add(self.widgetpicker, flag=wx.GROW) - sizer.Add(self.preview, flag=wx.GROW) - sizer.Add(self.desc, flag=wx.GROW) - sizer.Add(self.signature_sizer, flag=wx.GROW) - sizer.Layout() + self.main_sizer.Add(self.libbutton, flag=wx.GROW) + self.main_sizer.Add(self.widgetpicker, flag=wx.GROW) + self.main_sizer.Add(self.preview, flag=wx.GROW) + self.main_sizer.Add(self.desc, flag=wx.GROW) + self.main_sizer.Add(self.signature_sizer, flag=wx.GROW) + self.main_sizer.Layout() self.SetAutoLayout(True) - self.SetSizer(sizer) - sizer.Fit(self) + self.SetSizer(self.main_sizer) + self.main_sizer.Fit(self) self.Bind(wx.EVT_BUTTON, self.OnSelectLibDir, self.libbutton) self.preview.Bind(wx.EVT_PAINT, self.OnPaint) self.preview.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) @@ -169,6 +170,21 @@ self.msg = _("Drag selected Widget from here to Inkscape") self.tempf = None + self.paths_editors = [] + + def ResetSignature(self): + self.signature_sizer.Clear() + for editor in self.paths_editors: + editor.Destroy() + self.paths_editors = [] + self.main_sizer.Layout() + + def AddPathToSignature(self, path): + new_editor = wx.TextCtrl(self, size=wx.Size(-1, -1)) + self.paths_editors.append(new_editor) + self.signature_sizer.Add(new_editor, flag=wx.GROW) + self.main_sizer.Layout() + def RecallLibDir(self): conf = self.Config.Read(_conf_key) if len(conf) == 0: @@ -193,7 +209,7 @@ # Get Preview panel size sz = self.preview.GetClientSize() w = self.bmp.GetWidth() - dc.DrawBitmap(self.bmp, (sz.width - w)/2, 5) + dc.DrawBitmap(self.bmp, (sz.width - w)/2, _preview_margin) self.desc.SetValue(self.msg) @@ -270,7 +286,9 @@ self.bmp = wx.Bitmap(thumbpath) if have_thumb else None self.selected_SVG = svgpath if have_thumb else None - self.ValidateWidget() + + self.AnalyseWidgetAndUpdateUI() + except IOError: self.msg = _("Widget library must be writable") @@ -301,7 +319,8 @@ def GetSubHMITree(self, _context): return [self.hmitree_node.etree()] - def AnalyseWidget(self): + + def AnalyseWidgetAndUpdateUI(self): self.msg = "" try: @@ -313,7 +332,7 @@ svgdom = etree.parse(self.selected_SVG) - result = transform.transform(svgdom) + signature = transform.transform(svgdom) for entry in transform.get_error_log(): self.msg += "XSLT: " + entry.message + "\n" @@ -323,32 +342,39 @@ except XSLTApplyError as e: self.msg += "Widget analysis error: " + e.message else: - return result - - def UpdateUI(self, signature): - if signature is not None: + + self.ResetSignature() + print(etree.tostring(signature, pretty_print=True)) widgets = signature.getroot() + for defs in widgets.iter("defs"): + + # Keep double newlines (to mark paragraphs) + self.msg += defs.find("type").text + ":\n" + "\n\n".join(map( + lambda s:s.replace("\n"," ").replace(" ", " "), + defs.find("longdesc").text.split("\n\n"))) + for arg in defs.iter("arg"): + print(arg.get("name")) + print(arg.get("accepts")) + for path in defs.iter("path"): + self.AddPathToSignature(path) + print(path.get("name")) + print(path.get("accepts")) + for widget in widgets: widget_type = widget.get("type") print(widget_type) - for path in widget: + for path in widget.iterchildren("path"): path_value = path.get("value") path_accepts = map( str.strip, path.get("accepts", '')[1:-1].split(',')) - print(path_value, path_accepts) + print(path, path_value, path_accepts) def ValidateWidget(self): self.msg = "" - signature = self.AnalyseWidget() - - self.UpdateUI(signature) - - return - if self.tempf is not None: os.unlink(self.tempf.name) self.tempf = None diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_animaterotation.ysl2 --- a/svghmi/widget_animaterotation.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_animaterotation.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,18 @@ // widget_animaterotation.ysl2 +widget_desc("AnimateRotation") { + longdesc + || + AnimateRotation - DEPRECATED, do not use. + Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) + || + + shortdesc > AnimateRotation - DEPRECATED + + path name="speed" accepts="HMI_INT,HMI_REAL" > speed + +} + widget_class("AnimateRotation") { || frequency = 5; @@ -15,6 +28,7 @@ animate(){ // change animation properties + // TODO : rewrite with proper es6 for(let child of this.element.children){ if(child.nodeName == "animateTransform"){ if(this.speed > 0){ @@ -42,8 +56,3 @@ || } - -widget_defs("AnimateRotation") { - param "hmi_element"; - |, -} diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_back.ysl2 --- a/svghmi/widget_back.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_back.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,15 @@ // widget_back.ysl2 +widget_desc("Back") { + longdesc + || + Back widget brings focus back to previous page in history when clicked. + || + + shortdesc > Jump to previous page +} + +// TODO: use es6 widget_class("Back") || on_click(evt) { diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_button.ysl2 --- a/svghmi/widget_button.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_button.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,22 @@ // widget_button.ysl2 +widget_desc("Button") { + longdesc + || + Button widget takes one boolean variable path, and reflect current true + or false value by showing "active" or "inactive" labeled element + respectively. Pressing and releasing button changes variable to true and + false respectively. Potential inconsistency caused by quick consecutive + presses on the button is mitigated by using a state machine that wait for + previous state change to be reflected on variable before applying next one. + || + + shortdesc > Push button reflecting consistently given boolean variable + + path name="value" accepts="HMI_BOOL" > Boolean variable + +} + // Finite state machine decl fsm(name); decl state(name); @@ -151,6 +168,5 @@ } widget_defs("Button") { - param "hmi_element"; optional_labels("active inactive"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_circularbar.ysl2 --- a/svghmi/widget_circularbar.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_circularbar.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,26 @@ // widget_circularbar.ysl2 +widget_desc("CircularBar") { + longdesc + || + CircularBar widget changes the end angle of a "path" labeled arc according + to value of the single accepted variable. + + If "min" a "max" labeled texts are provided, then they are used as + respective minimum and maximum value. Otherwise, value is expected to be + in between 0 and 100. + + If "value" labeled text is found, then its content is replaced by value. + || + + shortdesc > Change end angle of Inkscape's arc + + // TODO: add min/max arguments + // TODO: add printf-like format + + path name="value" accepts="HMI_INT,HMI_REAL" > Value to display + +} widget_class("CircularBar") { || frequency = 10; @@ -52,7 +73,6 @@ } widget_defs("CircularBar") { - param "hmi_element"; labels("path"); optional_labels("value min max"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_circularslider.ysl2 --- a/svghmi/widget_circularslider.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_circularslider.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,33 @@ // widget_circuralslider.ysl2 +widget_desc("CircularSlider") { + longdesc + || + CircularSlider - DEPRECATED, to be replaced by PathSlider + This widget moves "handle" labeled group along "range" labeled + arc, according to value of the single accepted variable. + + If "min" a "max" labeled texts are provided, or if first and second + argument are given, then they are used as respective minimum and maximum + value. Otherwise, value is expected to be in between 0 and 100. + + If "value" labeled text is found, then its content is replaced by value. + During drag, "setpoint" labeled group is moved to position defined by user + while "handle" reflects current value from variable. + || + + shortdesc > CircularSlider - DEPRECATED + + arg name="min" count="optional" accepts="int,real" > minimum value + + arg name="min" count="optional" accepts="int,real" > maximum value + + // TODO: add printf-like format + + path name="value" accepts="HMI_INT,HMI_REAL" > Value to display + +} + widget_class("CircularSlider") || frequency = 5; @@ -230,7 +258,6 @@ || widget_defs("CircularSlider") { - param "hmi_element"; labels("handle range"); optional_labels("value min max setpoint"); |, diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_customhtml.ysl2 --- a/svghmi/widget_customhtml.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_customhtml.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,19 @@ // widget_customhtml.ysl2 +widget_desc("CustomHtml") { + longdesc + || + CustomHtml widget allows insertion of HTML code in a svg:foreignObject. + Widget content is replaced by foreignObject. HTML code is obtained from + "code" labeled text content. HTML insert position and size is given with + "container" labeled element. + || + + shortdesc > Custom HTML insert + + // TODO: support reload and POST based on variable content +} + widget_class("CustomHtml"){ || frequency = 5; @@ -25,6 +39,5 @@ widget_defs("CustomHtml") { - param "hmi_element"; labels("container code"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_display.ysl2 --- a/svghmi/widget_display.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_display.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,28 @@ // widget_display.ysl2 +widget_desc("Display") { + longdesc + || + If Display widget is a svg:text element, then text content is replaced by + value of given variables, space separated. + + Otherwise, if Display widget is a group containing a svg:text element + labelled "format", then text content is replaced by printf-like formated + string. In other words, if "format" labeled text is "%d %s %f", then 3 + variables paths are expected : HMI_IN, HMI_STRING and HMI_REAL. + + In case Display widget is a svg::text element, it is also possible to give + format string as first argument. + || + + shortdesc > Printf-like formated text display + + arg name="format" count="optional" accepts="string" > printf-like format string when not given as svg:text + + path name="fields" count="many" accepts="HMI_INT,HMI_REAL,HMI_STRING,HMI_BOOL" > variables to be displayed + +} + widget_class("Display") || @@ -11,8 +34,6 @@ || widget_defs("Display") { - param "hmi_element"; - const "format" optional_labels("format"); const "has_format","string-length($format)>0"; value "$format"; diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_dropdown.ysl2 --- a/svghmi/widget_dropdown.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_dropdown.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,33 @@ // widget_dropdown.ysl2 +widget_desc("DropDown") { + + longdesc + || + DropDown widget let user select an entry in a list of texts, given as + arguments. Single variable path is index of selection. + + It needs "text" (svg:text), "box" (svg:rect), "button" (svg:*), + and "highlight" (svg:rect) labeled elements. + + When user clicks on "button", "text" is duplicated to display enties in the + limit of available space in page, and "box" is extended to contain all + texts. "highlight" is moved over pre-selected entry. + + When only one argument is given, and argment contains "#langs" then list of + texts is automatically set to the list of human-readable languages supported + by this HMI. + || + + shortdesc > Let user select text entry in a drop-down menu + + arg name="entries" count="many" accepts="string" > drop-down menu entries + + path name="selection" accepts="HMI_INT" > selection index +} + +// TODO: support i18n of menu entries using svg:text elements with labels starting with "_" + widget_class("DropDown") { || dispatch(value) { @@ -332,7 +360,6 @@ } widget_defs("DropDown") { - param "hmi_element"; labels("text box button highlight"); // It is assumed that list content conforms to Array interface. > content: diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_foreach.ysl2 --- a/svghmi/widget_foreach.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_foreach.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,6 +1,34 @@ +// widget_foreach.ysl2 + +widget_desc("ForEach") { + + longdesc + || + ForEach widget is used to span a small set of widget over a larger set of + repeated HMI_NODEs. + + Idea is somewhat similar to relative page, but it all happens inside the + ForEach widget, no page involved. + + Together with relative Jump widgets it can be used to build a menu to reach + relative pages covering many identical HMI_NODES siblings. + + ForEach widget takes a HMI_CLASS name as argument and a HMI_NODE path as + variable. + + Direct sub-elements can be either groups of widget to be spanned, labeled + "ClassName:offset", or buttons to control the spanning, labeled + "ClassName:+/-number". + || + + shortdesc > span widgets over a set of repeated HMI_NODEs + + arg name="class_name" accepts="string" > HMI_CLASS name + + path name="root" accepts="HMI_NODE" > where to find HMI_NODEs whose HMI_CLASS is class_name +} widget_defs("ForEach") { - param "hmi_element"; if "count(path) != 1" error > ForEach widget «$hmi_element/@id» must have one HMI path given. if "count(arg) != 1" error > ForEach widget «$hmi_element/@id» must have one argument given : a class name. diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_input.ysl2 --- a/svghmi/widget_input.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_input.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -4,17 +4,20 @@ longdesc || Input widget takes one variable path, and displays current value in - optional "value" labeled sub-element. Click on optional "edit" labeled - element opens keypad to edit value. Operation on current value is - performed when click on sub-elements with label starting with '=', '+' - or '-' sign. Value after sign is used as operand. + optional "value" labeled sub-element. + + Click on optional "edit" labeled element opens keypad to edit value. + + Operation on current value is performed when click on sub-elements with + label starting with '=', '+' or '-' sign. Value after sign is used as + operand. || shortdesc > Input field with predefined operation buttons - arg accepts="string" > optional printf-like format + arg name="format" accepts="string" > optional printf-like format - path accepts="HMI_INT, HMI_REAL, HMI_STRING" > single variable to edit + path name="edit" accepts="HMI_INT, HMI_REAL, HMI_STRING" > single variable to edit } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_jsontable.ysl2 --- a/svghmi/widget_jsontable.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_jsontable.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,22 @@ // widget_jsontable.ysl2 +widget_desc("JsonTable") { + longdesc + || + Send given variables as POST to http URL argument, spread returned JSON in + SVG sub-elements of "data" labeled element. + + Documentation to be written. see svbghmi exemple. + || + + shortdesc > Http POST variables, spread JSON back + + arg name="url" accepts="string" > + + path name="edit" accepts="HMI_INT, HMI_REAL, HMI_STRING" > single variable to edit + +} + widget_class("JsonTable") || // arbitrary defaults to avoid missing entries in query @@ -262,7 +279,6 @@ } widget_defs("JsonTable") { - param "hmi_element"; labels("data"); const "data_elt", "$result_svg_ns//*[@id = $hmi_element/@id]/*[@inkscape:label = 'data']"; | visible: «count($data_elt/*[@inkscape:label])», diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_jump.ysl2 --- a/svghmi/widget_jump.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_jump.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,28 @@ // widget_jump.ysl2 +widget_desc("Jump") { + longdesc + || + Jump widget brings focus to a different page. Mandatory single argument + gives name of the page. + + Optional single path is used as new reference when jumping to a relative + page, it must point to a HMI_NODE. + + "active"+"inactive" labeled elements can be provided and reflect current + page being shown. + + "disabled" labeled element, if provided, is shown instead of "active" or + "inactive" widget when pointed HMI_NODE is null. + || + + shortdesc > Jump to given page + + arg name="page" accepts="string" > name of page to jump to + + path name="reference" count="optional" accepts="HMI_NODE" > reference for relative jump +} + widget_class("Jump") { || activable = false; @@ -60,7 +83,7 @@ } widget_defs("Jump") { - param "hmi_element"; + // TODO: ensure both active and inactive are provided const "activity" optional_labels("active inactive"); const "have_activity","string-length($activity)>0"; value "$activity"; diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_keypad.ysl2 --- a/svghmi/widget_keypad.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_keypad.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,17 @@ // widget_keypad.ysl2 +widget_desc("Keypad") { + longdesc + || + Keypad - to be written + || + + shortdesc > Keypad + + arg name="supported_types" accepts="string" > keypad can input those types + +} + emit "declarations:keypad" { | | var keypads = { @@ -111,7 +123,6 @@ || widget_defs("Keypad") { - param "hmi_element"; labels("Esc Enter BackSpace Keys Info Value"); optional_labels("Sign Space NumDot"); activable_labels("CapsLock Shift"); diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_list.ysl2 --- a/svghmi/widget_list.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_list.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,7 +1,9 @@ // widget_list.ysl2 +widget_desc("List") { + // TODO +} widget_defs("List") { - param "hmi_element"; | items: { foreach "$hmi_element/*[@inkscape:label]" { | «@inkscape:label»: "«@id»", @@ -10,7 +12,10 @@ } widget_defs("TextStyleList") { - param "hmi_element"; + // TODO +} + +widget_defs("TextStyleList") { | styles: { foreach "$hmi_element/*[@inkscape:label]" { const "style", "func:refered_elements(.)[self::svg:text]/@style"; diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_meter.ysl2 --- a/svghmi/widget_meter.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_meter.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,31 @@ // widget_meter.ysl2 +widget_desc("Meter") { + longdesc + || + Meter widget moves the end of "needle" labeled path along "range" labeled + path, according to value of the single accepted variable. + + Needle is reduced to a single segment. If "min" a "max" labeled texts + are provided, or if first and second argument are given, then they are used + as respective minimum and maximum value. Otherwise, value is expected to be + in between 0 and 100. + + If "value" labeled text is found, then its content is replaced by value. + || + + shortdesc > Moves "needle" along "range" + + arg name="min" count="optional" accepts="int,real" > minimum value + + arg name="max" count="optional" accepts="int,real" > maximum value + + // TODO: add printf-like format + + path name="value" accepts="HMI_INT,HMI_REAL" > Value to display + +} + widget_class("Metter"){ || frequency = 10; @@ -32,7 +58,6 @@ } widget_defs("Meter") { - param "hmi_element"; labels("needle range"); optional_labels("value min max"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_multistate.ysl2 --- a/svghmi/widget_multistate.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_multistate.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,28 @@ // widget_multistate.ysl2 +widget_defs("MultiState") { + + longdesc + || + Mutlistateh widget hides all subelements whose label do not match given + variable value representation. For exemple if given variable type + is HMI_INT and value is 1, then elements with label '1' will be displayed. + Label can have comments, so '1#some comment' would also match. If matching + variable of type HMI_STRING, then double quotes must be used. For exemple, + '"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. + + Click on widget changes variable value to next value in given list, or to + first one if not initialized to value already part of the list. + || + + shortdesc > Show elements whose label match value. + + // TODO: add optional format/precision argument to support floating points + + path name="value" accepts="HMI_INT,HMI_STRING" > value to compare to labels + +} + widget_class("MultiState") || frequency = 5; @@ -43,7 +66,6 @@ || widget_defs("MultiState") { - param "hmi_element"; | choices: [ const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+|false|true)(#.*)?$'"!; foreach "$result_svg_ns//*[@id = $hmi_element/@id]//*[regexp:test(@inkscape:label,$regex)]" { diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_scrollbar.ysl2 --- a/svghmi/widget_scrollbar.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_scrollbar.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,4 +1,17 @@ // widget_scrollbar.ysl2 +widget_desc("ScrollBar") { + longdesc + || + ScrollBar - documentation to be written + || + + shortdesc > ScrollBar + + path name="value" accepts="HMI_INT" > value + path name="range" accepts="HMI_INT" > range + path name="visible" accepts="HMI_INT" > visible + +} widget_class("ScrollBar") { || @@ -92,7 +105,6 @@ } widget_defs("ScrollBar") { - param "hmi_element"; labels("cursor range"); const "pagebuttons" optional_labels("pageup pagedown"); diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_slider.ysl2 --- a/svghmi/widget_slider.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_slider.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,19 @@ // widget_slider.ysl2 +widget_desc("Slider") { + longdesc + || + Slider - DEPRECATED - use ScrollBar or PathSlider instead + || + + shortdesc > Slider - DEPRECATED - use ScrollBar instead + + path name="value" accepts="HMI_INT" > value + path name="range" accepts="HMI_INT" > range + path name="visible" accepts="HMI_INT" > visible + +} + widget_class("Slider") || class SliderWidget extends Widget{ @@ -340,7 +354,6 @@ || widget_defs("Slider") { - param "hmi_element"; labels("handle range"); optional_labels("value min max setpoint"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_switch.ysl2 --- a/svghmi/widget_switch.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_switch.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,5 +1,25 @@ // widget_switch.ysl2 +widget_desc("Switch") { + longdesc + || + Switch widget hides all subelements whose label do not match given + variable current value representation. For exemple if given variable type + is HMI_INT and value is 1, then elements with label '1' will be displayed. + Label can have comments, so '1#some comment' would also match. If matching + variable of type HMI_STRING, then double quotes must be used. For exemple, + '"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. + || + + shortdesc > Show elements whose label match value. + + // TODO: add optional format/precision argument to support floating points + // TODO: support (in)equations and ranges + + path name="value" accepts="HMI_INT,HMI_STRING" > value to compare to labels + +} + widget_class("Switch") || frequency = 5; @@ -15,7 +35,6 @@ || widget_defs("Switch") { - param "hmi_element"; | choices: [ const "regex",!"'^(\"[^\"].*\"|\-?[0-9]+|false|true)(#.*)?$'"!; @@ -27,6 +46,7 @@ const "literal", "regexp:match(@inkscape:label,$regex)[2]"; | { | elt:id("«@id»"), + // TODO : use style.display = "none" to hide element | style:"«@style»", | value:«$literal» | }`if "position()!=last()" > ,` diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widget_tooglebutton.ysl2 --- a/svghmi/widget_tooglebutton.ysl2 Mon May 03 00:14:38 2021 +0200 +++ b/svghmi/widget_tooglebutton.ysl2 Tue May 18 09:22:17 2021 +0200 @@ -1,6 +1,20 @@ // widget_tooglebutton.ysl2 +widget_desc("ToggleButton") { + longdesc + || + Button widget takes one boolean variable path, and reflect current true + or false value by showing "active" or "inactive" labeled element + respectively. Clicking or touching button toggles variable. + || + + shortdesc > Toggle button reflecting given boolean variable + + path name="value" accepts="HMI_BOOL" > Boolean variable + +} + widget_class("ToggleButton") { || frequency = 5; @@ -44,6 +58,5 @@ } widget_defs("ToggleButton") { - param "hmi_element"; optional_labels("active inactive"); } diff -r 8a9d4c794cba -r fe945f1f48b7 svghmi/widgetlib/rounded_scrollbar.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/widgetlib/rounded_scrollbar.svg Tue May 18 09:22:17 2021 +0200 @@ -0,0 +1,95 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + +