--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/widget_scrollbar.ysl2 Thu Sep 02 21:36:29 2021 +0200
@@ -0,0 +1,122 @@
+// 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") {
+ ||
+ frequency = 10;
+ position = undefined;
+ range = undefined;
+ size = undefined;
+ mincursize = 0.1;
+
+ dispatch(value,oldval, index) {
+ switch(index) {
+ case 0:
+ this.range = Math.max(1,value);
+ break;
+ case 1:
+ this.position = value;
+ break;
+ case 2:
+ this.size = value;
+ break;
+ }
+
+ this.request_animate();
+ }
+
+ get_ratios() {
+ let range = this.range;
+ let size = Math.max(this.range * this.mincursize, Math.min(this.size, range));
+ let maxh = this.range_elt.height.baseVal.value;
+ let pixels = maxh;
+ let units = range;
+ return [size, maxh, range, pixels, units];
+ }
+
+ animate(){
+ if(this.position == undefined || this.range == undefined || this.size == undefined)
+ return;
+ let [size, maxh, range, pixels, units] = this.get_ratios();
+
+ let new_y = this.range_elt.y.baseVal.value + Math.round(Math.min(this.position,range-size) * pixels / units);
+ let new_height = Math.round(maxh * size/range);
+
+ this.cursor_elt.y.baseVal.value = new_y;
+ this.cursor_elt.height.baseVal.value = new_height;
+ }
+
+ init_mandatory() {
+ this.cursor_elt.onpointerdown = () => this.on_cursor_down();
+
+ this.bound_drag = this.drag.bind(this);
+ this.bound_drop = this.drop.bind(this);
+ }
+
+ apply_position(position){
+ this.position = Math.round(Math.max(Math.min(position, this.range - this.size), 0));
+ this.apply_hmi_value(1, this.position);
+ }
+
+ on_page_click(is_up){
+ this.apply_position(is_up ? this.position-this.size
+ : this.position+this.size);
+ }
+
+ on_cursor_down(e){
+ // get scrollbar -> root transform
+ let ctm = this.range_elt.getCTM();
+ // relative motion -> discard translation
+ ctm.e = 0;
+ ctm.f = 0;
+ // root -> scrollbar transform
+ this.invctm = ctm.inverse();
+ svg_root.addEventListener("pointerup", this.bound_drop, true);
+ svg_root.addEventListener("pointermove", this.bound_drag, true);
+ this.dragpos = this.position;
+ }
+
+ drop(e) {
+ svg_root.removeEventListener("pointerup", this.bound_drop, true);
+ svg_root.removeEventListener("pointermove", this.bound_drag, true);
+ }
+
+ drag(e) {
+ let [size, maxh, range, pixels, units] = this.get_ratios();
+ if(pixels == 0) return;
+ let point = new DOMPoint(e.movementX, e.movementY);
+ let movement = point.matrixTransform(this.invctm).y;
+ this.dragpos += movement * units / pixels;
+ this.apply_position(this.dragpos);
+ }
+ ||
+}
+
+widget_defs("ScrollBar") {
+ labels("cursor range");
+
+ const "pagebuttons" optional_labels("pageup pagedown");
+ const "have_pagebuttons","string-length($pagebuttons)>0";
+ value "$pagebuttons";
+
+ | init: function() {
+ | this.init_mandatory();
+
+ if "$have_pagebuttons" {
+ | this.pageup_elt.onclick = () => this.on_page_click(true);
+ | this.pagedown_elt.onclick = () => this.on_page_click(false);
+ }
+ | },
+}