# HG changeset patch # User Dino Kosic <44305363+kraskrom@users.noreply.github.com> # Date 1733905895 -3600 # Node ID fabc5d6c5a8ccf1b129a133253a65dc7a69fba7a # Parent e4f648e0595a67b78a2f7a4d1412d0298b473545 SVGHMI: Make Back widget activable. (#52) diff -r e4f648e0595a -r fabc5d6c5a8c exemples/svghmi_jumps/svghmi_0@svghmi/svghmi.svg --- a/exemples/svghmi_jumps/svghmi_0@svghmi/svghmi.svg Wed Dec 11 09:30:07 2024 +0100 +++ b/exemples/svghmi_jumps/svghmi_0@svghmi/svghmi.svg Wed Dec 11 09:31:35 2024 +0100 @@ -2,21 +2,21 @@ <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" sodipodi:docname="svghmi.svg" id="hmi0" version="1.1" viewBox="0 0 1280 720" height="720" - width="1280"> + width="1280" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> <metadata id="metadata8"> <rdf:RDF> @@ -40,24 +40,27 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1850" - inkscape:window-height="1036" + inkscape:window-width="1854" + inkscape:window-height="1011" id="namedview4" showgrid="false" - inkscape:zoom="0.46354778" - inkscape:cx="-544.27948" - inkscape:cy="655.56978" + inkscape:zoom="1.04375" + inkscape:cx="626.58683" + inkscape:cy="1233.5329" inkscape:window-x="0" - inkscape:window-y="27" + inkscape:window-y="0" inkscape:window-maximized="1" - inkscape:current-layer="g2496" + inkscape:current-layer="g845" showguides="true" inkscape:guide-bbox="true" borderlayer="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" - fit-margin-bottom="0" /> + fit-margin-bottom="0" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" /> <use sodipodi:insensitive="true" x="0" @@ -133,14 +136,25 @@ id="g845" transform="translate(0,660.00004)"> <rect - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffa32a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.77952766;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" - id="rect839" - width="244.72002" - height="70.089722" - x="517.64001" - y="324.95514" - ry="21.355932" - rx="21.355932" /> + style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffa32a;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:5.07063;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + id="rect851-6-36-7" + width="214.92937" + height="74.929367" + x="532.53534" + y="320.53528" + ry="12.800982" + rx="18.525251" + inkscape:label="active" /> + <rect + style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffa32a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.84883;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + id="rect851-6-36" + width="220" + height="80" + x="530" + y="317.99997" + ry="13.667253" + rx="18.962297" + inkscape:label="inactive" /> <text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" diff -r e4f648e0595a -r fabc5d6c5a8c svghmi/analyse_widget.xslt --- a/svghmi/analyse_widget.xslt Wed Dec 11 09:30:07 2024 +0100 +++ b/svghmi/analyse_widget.xslt Wed Dec 11 09:31:35 2024 +0100 @@ -288,6 +288,12 @@ <longdesc> <xsl:text>Back widget brings focus back to previous page in history when clicked. </xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>"active" + "inactive" labeled elements can be provided and reflect whether +</xsl:text> + <xsl:text>widget is pressed or not. +</xsl:text> </longdesc> <shortdesc> <xsl:text>Jump to previous page</xsl:text> @@ -545,6 +551,15 @@ <path name="root" accepts="HMI_NODE"> <xsl:text> where to find HMI_NODEs whose HMI_CLASS is class_name</xsl:text> </path> + <path name="position" accepts="HMI_INT"> + <xsl:text>position of HMI_NODE mapped to first item, among similar siblings</xsl:text> + </path> + <path name="range" accepts="HMI_INT" count="optional"> + <xsl:text> count of HMI_NODE siblings</xsl:text> + </path> + <path name="size" accepts="HMI_INT" count="optional"> + <xsl:text> count of visible items</xsl:text> + </path> </xsl:template> <xsl:template match="widget[@type='Image']" mode="widget_desc"> <type> @@ -627,7 +642,7 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text>If first path is pointint to HMI_NODE variable is used as new reference + <xsl:text>If first path is pointing to HMI_NODE variable is used as new reference </xsl:text> <xsl:text>when jumping to a relative page. </xsl:text> diff -r e4f648e0595a -r fabc5d6c5a8c svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Wed Dec 11 09:30:07 2024 +0100 +++ b/svghmi/gen_index_xhtml.xslt Wed Dec 11 09:31:35 2024 +0100 @@ -2740,6 +2740,12 @@ <longdesc> <xsl:text>Back widget brings focus back to previous page in history when clicked. </xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>"active" + "inactive" labeled elements can be provided and reflect whether +</xsl:text> + <xsl:text>widget is pressed or not. +</xsl:text> </longdesc> <shortdesc> <xsl:text>Jump to previous page</xsl:text> @@ -2750,37 +2756,96 @@ <xsl:text>BackWidget</xsl:text> <xsl:text> extends Widget{ </xsl:text> - <xsl:text> on_click(evt) { -</xsl:text> - <xsl:text> if(jump_history.length > 1){ -</xsl:text> - <xsl:text> let page_name, index; + <xsl:text> onmouseup(evt) { +</xsl:text> + <xsl:text> svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); +</xsl:text> + <xsl:text> this.activity_state = false; +</xsl:text> + <xsl:text> this.request_animate(); +</xsl:text> + <xsl:text> let page_name, index; +</xsl:text> + <xsl:text> if (jump_history.length > 1) { </xsl:text> <xsl:text> do { </xsl:text> <xsl:text> jump_history.pop(); // forget current page </xsl:text> - <xsl:text> if(jump_history.length == 0) return; + <xsl:text> if (jump_history.length == 0) return; </xsl:text> <xsl:text> [page_name, index] = jump_history[jump_history.length-1]; </xsl:text> - <xsl:text> } while(page_name == "ScreenSaver") // never go back to ScreenSaver -</xsl:text> - <xsl:text> switch_page(page_name, index); + <xsl:text> } while (page_name == "ScreenSaver") // never go back to ScreenSaver +</xsl:text> + <xsl:text> fading_page_switch(page_name, index); </xsl:text> <xsl:text> } </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> onmousedown(){ +</xsl:text> + <xsl:text> svg_root.addEventListener("pointerup", this.bound_onmouseup, true); +</xsl:text> + <xsl:text> this.activity_state = true; +</xsl:text> + <xsl:text> this.request_animate(); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> init() { </xsl:text> - <xsl:text> this.element.onclick = this.on_click.bind(this); + <xsl:text> this.bound_onmouseup = this.onmouseup.bind(this); +</xsl:text> + <xsl:text> this.activity_state = false; +</xsl:text> + <xsl:text> this.element.addEventListener("pointerdown", this.onmousedown.bind(this)); </xsl:text> <xsl:text> } </xsl:text> <xsl:text>} </xsl:text> </xsl:template> + <xsl:template match="widget[@type='Back']" mode="widget_defs"> + <xsl:param name="hmi_element"/> + <xsl:variable name="disability"> + <xsl:call-template name="defs_by_labels"> + <xsl:with-param name="hmi_element" select="$hmi_element"/> + <xsl:with-param name="labels"> + <xsl:text>/disabled</xsl:text> + </xsl:with-param> + <xsl:with-param name="mandatory" select="'no'"/> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="$disability"/> + <xsl:variable name="has_disability" select="string-length($disability)>0"/> + <xsl:text> activable_sub:{ +</xsl:text> + <xsl:variable name="activity"> + <xsl:call-template name="defs_by_labels"> + <xsl:with-param name="hmi_element" select="$hmi_element"/> + <xsl:with-param name="labels"> + <xsl:text>/active /inactive</xsl:text> + </xsl:with-param> + <xsl:with-param name="mandatory"> + <xsl:text>warn</xsl:text> + </xsl:with-param> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="$activity"/> + <xsl:variable name="has_activity" select="string-length($activity)>0"/> + <xsl:text> }, +</xsl:text> + <xsl:text> has_activity: </xsl:text> + <xsl:value-of select="$has_activity"/> + <xsl:text>, +</xsl:text> + </xsl:template> <xsl:template match="widget[@type='Button']" mode="widget_desc"> <type> <xsl:value-of select="@type"/> @@ -4454,6 +4519,15 @@ <path name="root" accepts="HMI_NODE"> <xsl:text> where to find HMI_NODEs whose HMI_CLASS is class_name</xsl:text> </path> + <path name="position" accepts="HMI_INT"> + <xsl:text>position of HMI_NODE mapped to first item, among similar siblings</xsl:text> + </path> + <path name="range" accepts="HMI_INT" count="optional"> + <xsl:text> count of HMI_NODE siblings</xsl:text> + </path> + <path name="size" accepts="HMI_INT" count="optional"> + <xsl:text> count of visible items</xsl:text> + </path> </xsl:template> <xsl:template match="widget[@type='ForEach']" mode="widget_defs"> <xsl:param name="hmi_element"/> @@ -5606,7 +5680,7 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text>If first path is pointint to HMI_NODE variable is used as new reference + <xsl:text>If first path is pointing to HMI_NODE variable is used as new reference </xsl:text> <xsl:text>when jumping to a relative page. </xsl:text> @@ -5694,7 +5768,7 @@ </xsl:text> <xsl:text> target_page_is_current_page = false; </xsl:text> - <xsl:text> button_beeing_pressed = false; + <xsl:text> button_being_pressed = false; </xsl:text> <xsl:text> </xsl:text> @@ -5710,9 +5784,9 @@ </xsl:text> <xsl:text> this.indexes[0] + this.offset : undefined; </xsl:text> - <xsl:text> this.button_beeing_pressed = false; -</xsl:text> - <xsl:text> this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed; + <xsl:text> this.button_being_pressed = false; +</xsl:text> + <xsl:text> this.activity_state = this.target_page_is_current_page || this.button_being_pressed; </xsl:text> <xsl:text> fading_page_switch(this.args[0], index); </xsl:text> @@ -5730,7 +5804,7 @@ </xsl:text> <xsl:text> svg_root.addEventListener("pointerup", this.bound_onmouseup, true); </xsl:text> - <xsl:text> this.button_beeing_pressed = true; + <xsl:text> this.button_being_pressed = true; </xsl:text> <xsl:text> this.activity_state = true; </xsl:text> @@ -5754,7 +5828,7 @@ </xsl:text> <xsl:text> this.target_page_is_current_page = ((ref_name == undefined || ref_name == page_name) && index == ref_index); </xsl:text> - <xsl:text> this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed; + <xsl:text> this.activity_state = this.target_page_is_current_page || this.button_being_pressed; </xsl:text> <xsl:text> // Since called from animate, update activity directly </xsl:text> diff -r e4f648e0595a -r fabc5d6c5a8c svghmi/widget_back.ysl2 --- a/svghmi/widget_back.ysl2 Wed Dec 11 09:30:07 2024 +0100 +++ b/svghmi/widget_back.ysl2 Wed Dec 11 09:31:35 2024 +0100 @@ -4,25 +4,45 @@ longdesc || Back widget brings focus back to previous page in history when clicked. + + "active" + "inactive" labeled elements can be provided and reflect whether + widget is pressed or not. || shortdesc > Jump to previous page } -widget_class("Back") - || - on_click(evt) { - if(jump_history.length > 1){ - let page_name, index; - do { - jump_history.pop(); // forget current page - if(jump_history.length == 0) return; - [page_name, index] = jump_history[jump_history.length-1]; - } while(page_name == "ScreenSaver") // never go back to ScreenSaver - switch_page(page_name, index); - } +widget_class("Back") { +|| + onmouseup(evt) { + svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); + this.activity_state = false; + this.request_animate(); + let page_name, index; + if (jump_history.length > 1) { + do { + jump_history.pop(); // forget current page + if (jump_history.length == 0) return; + [page_name, index] = jump_history[jump_history.length-1]; + } while (page_name == "ScreenSaver") // never go back to ScreenSaver + fading_page_switch(page_name, index); } - init() { - this.element.onclick = this.on_click.bind(this); - } - || + } + + onmousedown(){ + svg_root.addEventListener("pointerup", this.bound_onmouseup, true); + this.activity_state = true; + this.request_animate(); + } + + init() { + this.bound_onmouseup = this.onmouseup.bind(this); + this.activity_state = false; + this.element.addEventListener("pointerdown", this.onmousedown.bind(this)); + } +|| +} + +widget_defs("Back") { + activable(); +} diff -r e4f648e0595a -r fabc5d6c5a8c svghmi/widget_jump.ysl2 --- a/svghmi/widget_jump.ysl2 Wed Dec 11 09:30:07 2024 +0100 +++ b/svghmi/widget_jump.ysl2 Wed Dec 11 09:31:35 2024 +0100 @@ -6,7 +6,7 @@ Jump widget brings focus to a different page. Mandatory first argument gives name of the page. - If first path is pointint to HMI_NODE variable is used as new reference + If first path is pointing to HMI_NODE variable is used as new reference when jumping to a relative page. Additional arguments are unordered options: @@ -53,7 +53,7 @@ activable = false; frequency = 2; target_page_is_current_page = false; - button_beeing_pressed = false; + button_being_pressed = false; onmouseup(evt) { svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); @@ -61,8 +61,8 @@ const index = (this.is_relative && this.indexes.length > 0) ? this.indexes[0] + this.offset : undefined; - this.button_beeing_pressed = false; - this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed; + this.button_being_pressed = false; + this.activity_state = this.target_page_is_current_page || this.button_being_pressed; fading_page_switch(this.args[0], index); this.notify(); } @@ -71,7 +71,7 @@ onmousedown(){ if(this.enable_state) { svg_root.addEventListener("pointerup", this.bound_onmouseup, true); - this.button_beeing_pressed = true; + this.button_being_pressed = true; this.activity_state = true; this.request_animate(); } @@ -83,7 +83,7 @@ const ref_index = this.indexes.length > 0 ? this.indexes[0] + this.offset : undefined; const ref_name = this.args[0]; this.target_page_is_current_page = ((ref_name == undefined || ref_name == page_name) && index == ref_index); - this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed; + this.activity_state = this.target_page_is_current_page || this.button_being_pressed; // Since called from animate, update activity directly if(this.enable_displayed_state && this.has_activity) { this.animate_activity();