SVGHMI: change scroll buttons into single unicode triangle and center them. Use highlight rectangle duplicated and hidden to catch selection clicks so that the whole row is clickable. svghmi
authorEdouard Tisserant
Wed, 16 Dec 2020 15:44:24 +0100
branchsvghmi
changeset 3091 f475f39713aa
parent 3090 9e172e4e50c7
child 3092 96ffd8b1b016
SVGHMI: change scroll buttons into single unicode triangle and center them. Use highlight rectangle duplicated and hidden to catch selection clicks so that the whole row is clickable.
svghmi/gen_index_xhtml.xslt
svghmi/widget_dropdown.ysl2
tests/svghmi/svghmi_0@svghmi/svghmi.svg
--- a/svghmi/gen_index_xhtml.xslt	Tue Dec 15 13:43:21 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Wed Dec 16 15:44:24 2020 +0100
@@ -3062,6 +3062,12 @@
 </xsl:text>
   </xsl:template>
   <xsl:template mode="widget_class" match="widget[@type='DropDown']">
+    <xsl:text>    function numb_event(e) {
+</xsl:text>
+    <xsl:text>        e.stopPropagation();
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
     <xsl:text>    class DropDownWidget extends Widget{
 </xsl:text>
     <xsl:text>        dispatch(value) {
@@ -3082,11 +3088,11 @@
 </xsl:text>
     <xsl:text>            // Compute margins
 </xsl:text>
-    <xsl:text>            let text_bbox = this.text_elt.getBBox();
-</xsl:text>
-    <xsl:text>            let lmargin = text_bbox.x - this.box_bbox.x;
-</xsl:text>
-    <xsl:text>            let tmargin = text_bbox.y - this.box_bbox.y;
+    <xsl:text>            this.text_bbox = this.text_elt.getBBox();
+</xsl:text>
+    <xsl:text>            let lmargin = this.text_bbox.x - this.box_bbox.x;
+</xsl:text>
+    <xsl:text>            let tmargin = this.text_bbox.y - this.box_bbox.y;
 </xsl:text>
     <xsl:text>            this.margins = [lmargin, tmargin].map(x =&gt; Math.max(x,0));
 </xsl:text>
@@ -3118,6 +3124,8 @@
 </xsl:text>
     <xsl:text>            this.opened = false;
 </xsl:text>
+    <xsl:text>            this.clickables = [];
+</xsl:text>
     <xsl:text>        }
 </xsl:text>
     <xsl:text>        on_button_click() {
@@ -3180,13 +3188,13 @@
 </xsl:text>
     <xsl:text>            let count = 1;
 </xsl:text>
-    <xsl:text>            let txt = this.text_elt; 
+    <xsl:text>            let txt = this.text_elt;
 </xsl:text>
     <xsl:text>            let first = txt.firstElementChild;
 </xsl:text>
     <xsl:text>            // Real world (pixels) boundaries of current page
 </xsl:text>
-    <xsl:text>            let bounds = svg_root.getBoundingClientRect(); 
+    <xsl:text>            let bounds = svg_root.getBoundingClientRect();
 </xsl:text>
     <xsl:text>            this.lift = 0;
 </xsl:text>
@@ -3266,7 +3274,7 @@
 </xsl:text>
     <xsl:text>            // inhibit events not targetting spans (menu items)
 </xsl:text>
-    <xsl:text>            if(e.target.parentNode !== this.text_elt){
+    <xsl:text>            if([this.text_elt, this.element].indexOf(e.target.parentNode) == -1){
 </xsl:text>
     <xsl:text>                e.stopPropagation();
 </xsl:text>
@@ -3284,12 +3292,18 @@
 </xsl:text>
     <xsl:text>            // Stop hogging all click events
 </xsl:text>
+    <xsl:text>            svg_root.removeEventListener("pointerdown", numb_event, true);
+</xsl:text>
+    <xsl:text>            svg_root.removeEventListener("pointerup", numb_event, true);
+</xsl:text>
     <xsl:text>            svg_root.removeEventListener("click", this.bound_close_on_click_elsewhere, true);
 </xsl:text>
     <xsl:text>            // Restore position and sixe of widget elements
 </xsl:text>
     <xsl:text>            this.reset_text();
 </xsl:text>
+    <xsl:text>            this.reset_clickables();
+</xsl:text>
     <xsl:text>            this.reset_box();
 </xsl:text>
     <xsl:text>            // Put the button back in place
@@ -3306,11 +3320,55 @@
 </xsl:text>
     <xsl:text>        }
 </xsl:text>
+    <xsl:text>        // Make item (text span) clickable by overlaying a rectangle on top of it
+</xsl:text>
+    <xsl:text>        make_clickable(span, func) {
+</xsl:text>
+    <xsl:text>            let txt = this.text_elt;
+</xsl:text>
+    <xsl:text>            let first = txt.firstElementChild;
+</xsl:text>
+    <xsl:text>            let original_text_y = this.text_bbox.y;
+</xsl:text>
+    <xsl:text>            let highlight = this.highlight_elt;
+</xsl:text>
+    <xsl:text>            let original_h_y = highlight.getBBox().y;
+</xsl:text>
+    <xsl:text>            let clickable = highlight.cloneNode();
+</xsl:text>
+    <xsl:text>            let yoffset = span.getBBox().y - original_text_y;
+</xsl:text>
+    <xsl:text>            clickable.setAttribute("y", original_h_y + yoffset); 
+</xsl:text>
+    <xsl:text>            clickable.style.pointerEvents = "bounding-box";
+</xsl:text>
+    <xsl:text>            clickable.style.visibility = "hidden";
+</xsl:text>
+    <xsl:text>            //clickable.onclick = () =&gt; alert("love JS");
+</xsl:text>
+    <xsl:text>            clickable.onclick = func;
+</xsl:text>
+    <xsl:text>            this.element.appendChild(clickable);
+</xsl:text>
+    <xsl:text>            this.clickables.push(clickable)
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        reset_clickables() {
+</xsl:text>
+    <xsl:text>            while(this.clickables.length){
+</xsl:text>
+    <xsl:text>                this.element.removeChild(this.clickables.pop());
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
     <xsl:text>        // Set text content when content is smaller than menu (no scrolling)
 </xsl:text>
     <xsl:text>        set_complete_text(){
 </xsl:text>
-    <xsl:text>            let spans = this.text_elt.children; 
+    <xsl:text>            let spans = this.text_elt.children;
 </xsl:text>
     <xsl:text>            let c = 0;
 </xsl:text>
@@ -3320,7 +3378,9 @@
 </xsl:text>
     <xsl:text>                span.textContent = item;
 </xsl:text>
-    <xsl:text>                span.onclick = (evt) =&gt; this.bound_on_selection_click(c);
+    <xsl:text>                let sel = c;
+</xsl:text>
+    <xsl:text>                this.make_clickable(span, (evt) =&gt; this.bound_on_selection_click(sel));
 </xsl:text>
     <xsl:text>                c++;
 </xsl:text>
@@ -3338,7 +3398,7 @@
 </xsl:text>
     <xsl:text>            let contentlength = this.content.length;
 </xsl:text>
-    <xsl:text>            let spans = this.text_elt.children; 
+    <xsl:text>            let spans = this.text_elt.children;
 </xsl:text>
     <xsl:text>            let spanslength = spans.length;
 </xsl:text>
@@ -3352,7 +3412,7 @@
 </xsl:text>
     <xsl:text>                this.menu_offset = Math.min(
 </xsl:text>
-    <xsl:text>                    contentlength - spans.length + 1, 
+    <xsl:text>                    contentlength - spans.length + 1,
 </xsl:text>
     <xsl:text>                    this.menu_offset + spanslength);
 </xsl:text>
@@ -3360,12 +3420,14 @@
 </xsl:text>
     <xsl:text>                this.menu_offset = Math.max(
 </xsl:text>
-    <xsl:text>                    0, 
+    <xsl:text>                    0,
 </xsl:text>
     <xsl:text>                    this.menu_offset - spanslength);
 </xsl:text>
     <xsl:text>            }
 </xsl:text>
+    <xsl:text>            this.reset_clickables();
+</xsl:text>
     <xsl:text>            this.set_partial_text();
 </xsl:text>
     <xsl:text>        }
@@ -3376,7 +3438,7 @@
 </xsl:text>
     <xsl:text>        set_partial_text(){
 </xsl:text>
-    <xsl:text>            let spans = this.text_elt.children; 
+    <xsl:text>            let spans = this.text_elt.children;
 </xsl:text>
     <xsl:text>            let contentlength = this.content.length;
 </xsl:text>
@@ -3384,25 +3446,37 @@
 </xsl:text>
     <xsl:text>            let i = this.menu_offset, c = 0;
 </xsl:text>
+    <xsl:text>            let m = this.box_bbox;
+</xsl:text>
     <xsl:text>            while(c &lt; spanslength){
 </xsl:text>
     <xsl:text>                let span=spans[c];
 </xsl:text>
+    <xsl:text>                let onclickfunc;
+</xsl:text>
     <xsl:text>                // backward jump only present if not exactly at start
 </xsl:text>
     <xsl:text>                if(c == 0 &amp;&amp; i != 0){
 </xsl:text>
-    <xsl:text>                    span.textContent = "&#x2191;  &#x2191;  &#x2191;";
-</xsl:text>
-    <xsl:text>                    span.onclick = this.bound_on_backward_click;
+    <xsl:text>                    span.textContent = "&#x25B2;";
+</xsl:text>
+    <xsl:text>                    onclickfunc = this.bound_on_backward_click;
+</xsl:text>
+    <xsl:text>                    let o = span.getBBox();
+</xsl:text>
+    <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
 </xsl:text>
     <xsl:text>                // presence of forward jump when not right at the end
 </xsl:text>
     <xsl:text>                }else if(c == spanslength-1 &amp;&amp; i &lt; contentlength - 1){
 </xsl:text>
-    <xsl:text>                    span.textContent = "&#x2193;  &#x2193;  &#x2193;";
-</xsl:text>
-    <xsl:text>                    span.onclick = this.bound_on_forward_click;
+    <xsl:text>                    span.textContent = "&#x25BC;";
+</xsl:text>
+    <xsl:text>                    onclickfunc = this.bound_on_forward_click;
+</xsl:text>
+    <xsl:text>                    let o = span.getBBox();
+</xsl:text>
+    <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
 </xsl:text>
     <xsl:text>                // otherwise normal content
 </xsl:text>
@@ -3412,12 +3486,16 @@
 </xsl:text>
     <xsl:text>                    let sel = i;
 </xsl:text>
-    <xsl:text>                    span.onclick = (evt) =&gt; this.bound_on_selection_click(sel);
+    <xsl:text>                    onclickfunc = (evt) =&gt; this.bound_on_selection_click(sel);
+</xsl:text>
+    <xsl:text>                    span.removeAttribute("dx");
 </xsl:text>
     <xsl:text>                    i++;
 </xsl:text>
     <xsl:text>                }
 </xsl:text>
+    <xsl:text>                this.make_clickable(span, onclickfunc);
+</xsl:text>
     <xsl:text>                c++;
 </xsl:text>
     <xsl:text>            }
@@ -3478,6 +3556,10 @@
 </xsl:text>
     <xsl:text>            // disable interaction with background
 </xsl:text>
+    <xsl:text>            svg_root.addEventListener("pointerdown", numb_event, true);
+</xsl:text>
+    <xsl:text>            svg_root.addEventListener("pointerup", numb_event, true);
+</xsl:text>
     <xsl:text>            svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
 </xsl:text>
     <xsl:text>            // mark as open
@@ -3490,16 +3572,18 @@
 </xsl:text>
     <xsl:text>        reset_text(){
 </xsl:text>
-    <xsl:text>            let txt = this.text_elt; 
+    <xsl:text>            let txt = this.text_elt;
 </xsl:text>
     <xsl:text>            let first = txt.firstElementChild;
 </xsl:text>
     <xsl:text>            // remove attribute eventually added to first text line while opening
 </xsl:text>
-    <xsl:text>            first.removeAttribute("onclick");
+    <xsl:text>            first.onclick = null;
 </xsl:text>
     <xsl:text>            first.removeAttribute("dy");
 </xsl:text>
+    <xsl:text>            first.removeAttribute("dx");
+</xsl:text>
     <xsl:text>            // keep only the first line of text
 </xsl:text>
     <xsl:text>            for(let span of Array.from(txt.children).slice(1)){
@@ -3538,11 +3622,11 @@
 </xsl:text>
     <xsl:text>            let b = this.box_elt;
 </xsl:text>
-    <xsl:text>            b.x.baseVal.value = m.x - lmargin;
+    <xsl:text>            // b.x.baseVal.value = m.x - lmargin;
 </xsl:text>
     <xsl:text>            b.y.baseVal.value = m.y - tmargin;
 </xsl:text>
-    <xsl:text>            b.width.baseVal.value = 2 * lmargin + m.width;
+    <xsl:text>            // b.width.baseVal.value = 2 * lmargin + m.width;
 </xsl:text>
     <xsl:text>            b.height.baseVal.value = 2 * tmargin + m.height;
 </xsl:text>
@@ -3556,7 +3640,7 @@
     <xsl:call-template name="defs_by_labels">
       <xsl:with-param name="hmi_element" select="$hmi_element"/>
       <xsl:with-param name="labels">
-        <xsl:text>text box button</xsl:text>
+        <xsl:text>text box button highlight</xsl:text>
       </xsl:with-param>
     </xsl:call-template>
     <xsl:text>    // It is assumed that list content conforms to Array interface.
--- a/svghmi/widget_dropdown.ysl2	Tue Dec 15 13:43:21 2020 +0100
+++ b/svghmi/widget_dropdown.ysl2	Wed Dec 16 15:44:24 2020 +0100
@@ -2,6 +2,9 @@
 
 template "widget[@type='DropDown']", mode="widget_class"{
 ||
+    function numb_event(e) {
+        e.stopPropagation();
+    }
     class DropDownWidget extends Widget{
         dispatch(value) {
             if(!this.opened) this.set_selection(value);
@@ -12,9 +15,9 @@
             this.box_bbox = this.box_elt.getBBox()
 
             // Compute margins
-            let text_bbox = this.text_elt.getBBox();
-            let lmargin = text_bbox.x - this.box_bbox.x;
-            let tmargin = text_bbox.y - this.box_bbox.y;
+            this.text_bbox = this.text_elt.getBBox();
+            let lmargin = this.text_bbox.x - this.box_bbox.x;
+            let tmargin = this.text_bbox.y - this.box_bbox.y;
             this.margins = [lmargin, tmargin].map(x => Math.max(x,0));
 
             // Index of first visible element in the menu, when opened
@@ -30,6 +33,7 @@
             this.bound_on_backward_click = this.on_backward_click.bind(this);
             this.bound_on_forward_click = this.on_forward_click.bind(this);
             this.opened = false;
+            this.clickables = [];
         }
         on_button_click() {
             this.open();
@@ -61,10 +65,10 @@
         }
         grow_text(up_to) {
             let count = 1;
-            let txt = this.text_elt; 
+            let txt = this.text_elt;
             let first = txt.firstElementChild;
             // Real world (pixels) boundaries of current page
-            let bounds = svg_root.getBoundingClientRect(); 
+            let bounds = svg_root.getBoundingClientRect();
             this.lift = 0;
             while(count < up_to) {
                 let next = first.cloneNode();
@@ -104,7 +108,7 @@
         }
         close_on_click_elsewhere(e) {
             // inhibit events not targetting spans (menu items)
-            if(e.target.parentNode !== this.text_elt){
+            if([this.text_elt, this.element].indexOf(e.target.parentNode) == -1){
                 e.stopPropagation();
                 // close menu in case click is outside box
                 if(e.target !== this.box_elt)
@@ -113,9 +117,12 @@
         }
         close(){
             // Stop hogging all click events
+            svg_root.removeEventListener("pointerdown", numb_event, true);
+            svg_root.removeEventListener("pointerup", numb_event, true);
             svg_root.removeEventListener("click", this.bound_close_on_click_elsewhere, true);
             // Restore position and sixe of widget elements
             this.reset_text();
+            this.reset_clickables();
             this.reset_box();
             // Put the button back in place
             this.element.appendChild(this.button_elt);
@@ -124,15 +131,37 @@
             // Dispatch last cached value
             this.apply_cache();
         }
+        // Make item (text span) clickable by overlaying a rectangle on top of it
+        make_clickable(span, func) {
+            let txt = this.text_elt;
+            let first = txt.firstElementChild;
+            let original_text_y = this.text_bbox.y;
+            let highlight = this.highlight_elt;
+            let original_h_y = highlight.getBBox().y;
+            let clickable = highlight.cloneNode();
+            let yoffset = span.getBBox().y - original_text_y;
+            clickable.setAttribute("y", original_h_y + yoffset); 
+            clickable.style.pointerEvents = "bounding-box";
+            clickable.style.visibility = "hidden";
+            //clickable.onclick = () => alert("love JS");
+            clickable.onclick = func;
+            this.element.appendChild(clickable);
+            this.clickables.push(clickable)
+        }
+        reset_clickables() {
+            while(this.clickables.length){
+                this.element.removeChild(this.clickables.pop());
+            }
+        }
         // Set text content when content is smaller than menu (no scrolling)
         set_complete_text(){
-            let spans = this.text_elt.children; 
+            let spans = this.text_elt.children;
             let c = 0;
             for(let item of this.content){
                 let span=spans[c];
                 span.textContent = item;
                 let sel = c;
-                span.onclick = (evt) => this.bound_on_selection_click(sel);
+                this.make_clickable(span, (evt) => this.bound_on_selection_click(sel));
                 c++;
             }
         }
@@ -141,46 +170,55 @@
         // true  : downward, higher value
         scroll(forward){
             let contentlength = this.content.length;
-            let spans = this.text_elt.children; 
+            let spans = this.text_elt.children;
             let spanslength = spans.length;
             // reduce accounted menu size according to jumps
             if(this.menu_offset != 0) spanslength--;
             if(this.menu_offset < contentlength - 1) spanslength--;
             if(forward){
                 this.menu_offset = Math.min(
-                    contentlength - spans.length + 1, 
+                    contentlength - spans.length + 1,
                     this.menu_offset + spanslength);
             }else{
                 this.menu_offset = Math.max(
-                    0, 
+                    0,
                     this.menu_offset - spanslength);
             }
+            this.reset_clickables();
             this.set_partial_text();
         }
         // Setup partial view text content
         // with jumps at first and last entry when appropriate
         set_partial_text(){
-            let spans = this.text_elt.children; 
+            let spans = this.text_elt.children;
             let contentlength = this.content.length;
             let spanslength = spans.length;
             let i = this.menu_offset, c = 0;
+            let m = this.box_bbox;
             while(c < spanslength){
                 let span=spans[c];
+                let onclickfunc;
                 // backward jump only present if not exactly at start
                 if(c == 0 && i != 0){
-                    span.textContent = "↑  ↑  ↑";
-                    span.onclick = this.bound_on_backward_click;
+                    span.textContent = "▲";
+                    onclickfunc = this.bound_on_backward_click;
+                    let o = span.getBBox();
+                    span.setAttribute("dx", (m.width - o.width)/2);
                 // presence of forward jump when not right at the end
                 }else if(c == spanslength-1 && i < contentlength - 1){
-                    span.textContent = "↓  ↓  ↓";
-                    span.onclick = this.bound_on_forward_click;
+                    span.textContent = "▼";
+                    onclickfunc = this.bound_on_forward_click;
+                    let o = span.getBBox();
+                    span.setAttribute("dx", (m.width - o.width)/2);
                 // otherwise normal content
                 }else{
                     span.textContent = this.content[i];
                     let sel = i;
-                    span.onclick = (evt) => this.bound_on_selection_click(sel);
+                    onclickfunc = (evt) => this.bound_on_selection_click(sel);
+                    span.removeAttribute("dx");
                     i++;
                 }
+                this.make_clickable(span, onclickfunc);
                 c++;
             }
         }
@@ -211,17 +249,20 @@
             // Rise widget to top by moving it to last position among siblings
             this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
             // disable interaction with background
+            svg_root.addEventListener("pointerdown", numb_event, true);
+            svg_root.addEventListener("pointerup", numb_event, true);
             svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
             // mark as open
             this.opened = true;
         }
         // Put text element in normalized state
         reset_text(){
-            let txt = this.text_elt; 
+            let txt = this.text_elt;
             let first = txt.firstElementChild;
             // remove attribute eventually added to first text line while opening
-            first.removeAttribute("onclick");
+            first.onclick = null;
             first.removeAttribute("dy");
+            first.removeAttribute("dx");
             // keep only the first line of text
             for(let span of Array.from(txt.children).slice(1)){
                 txt.removeChild(span)
@@ -241,17 +282,18 @@
             let [lmargin, tmargin] = this.margins;
             let m = this.text_elt.getBBox();
             let b = this.box_elt;
-            b.x.baseVal.value = m.x - lmargin;
+            // b.x.baseVal.value = m.x - lmargin;
             b.y.baseVal.value = m.y - tmargin;
-            b.width.baseVal.value = 2 * lmargin + m.width;
+            // b.width.baseVal.value = 2 * lmargin + m.width;
             b.height.baseVal.value = 2 * tmargin + m.height;
         }
     }
 ||
 }
+
 template "widget[@type='DropDown']", mode="widget_defs" {
     param "hmi_element";
-    labels("text box button");
+    labels("text box button highlight");
 ||
     // It is assumed that list content conforms to Array interface.
     content: [
--- a/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Tue Dec 15 13:43:21 2020 +0100
+++ b/tests/svghmi/svghmi_0@svghmi/svghmi.svg	Wed Dec 16 15:44:24 2020 +0100
@@ -197,19 +197,20 @@
      inkscape:pageopacity="0"
      inkscape:pageshadow="2"
      inkscape:document-units="px"
-     inkscape:current-layer="g443"
+     inkscape:current-layer="g14237"
      showgrid="false"
      units="px"
-     inkscape:zoom="0.77167689"
-     inkscape:cx="379.87087"
-     inkscape:cy="462.91635"
-     inkscape:window-width="1848"
-     inkscape:window-height="1016"
-     inkscape:window-x="72"
+     inkscape:zoom="0.54565796"
+     inkscape:cx="147.6698"
+     inkscape:cy="180.09341"
+     inkscape:window-width="1600"
+     inkscape:window-height="836"
+     inkscape:window-x="0"
      inkscape:window-y="27"
      inkscape:window-maximized="1"
      showguides="true"
-     inkscape:guide-bbox="true" />
+     inkscape:guide-bbox="true"
+     inkscape:snap-global="false" />
   <use
      x="0"
      y="0"
@@ -2406,6 +2407,16 @@
        rx="2.4558709"
        ry="2.4558709"
        inkscape:label="box" />
+    <rect
+       inkscape:label="highlight"
+       ry="2.4558709"
+       rx="2.4558709"
+       y="943.10553"
+       x="864.00842"
+       height="92.71212"
+       width="391.99988"
+       id="rect5497"
+       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:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.75419331;stroke-linecap:butt;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" />
     <text
        id="text14183"
        y="1011.9975"
@@ -2442,7 +2453,7 @@
   <g
      inkscape:label="HMI:Input@/SELECTION"
      id="g446"
-     transform="matrix(0.28590269,0,0,0.28590269,1047.3881,408.87609)">
+     transform="matrix(0.28590269,0,0,0.28590269,85.246911,560.98603)">
     <text
        xml:space="preserve"
        style="font-style:normal;font-weight:normal;font-size:160px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
@@ -2519,7 +2530,7 @@
        inkscape:transform-center-x="1.0089177e-06" />
   </g>
   <g
-     transform="matrix(0.57180538,0,0,0.57180538,417.18774,31.574523)"
+     transform="matrix(0.57180538,0,0,0.57180538,-522.96165,161.69266)"
      id="g443"
      inkscape:label="HMI:Button@/SELECTION"
      style="stroke-width:1">
@@ -2542,7 +2553,7 @@
        height="95.723877"
        width="245.44583"
        id="rect433"
-       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:#fdfdfd;fill-opacity:1;fill-rule:nonzero;stroke:#ffd0b2;stroke-width:28.60938356;stroke-linecap:butt;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" />
+       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:#fdfdfd;fill-opacity:1;fill-rule:nonzero;stroke:#ffd0b2;stroke-width:28.60938263;stroke-linecap:butt;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" />
     <g
        style="stroke-width:1"
        inkscape:label="text"