|
1 // widget_scrollbar.ysl2 |
|
2 widget_desc("ScrollBar") { |
|
3 longdesc |
|
4 || |
|
5 ScrollBar - documentation to be written |
|
6 || |
|
7 |
|
8 shortdesc > ScrollBar |
|
9 |
|
10 path name="value" accepts="HMI_INT" > value |
|
11 path name="range" accepts="HMI_INT" > range |
|
12 path name="visible" accepts="HMI_INT" > visible |
|
13 |
|
14 } |
|
15 |
|
16 widget_class("ScrollBar") { |
|
17 || |
|
18 frequency = 10; |
|
19 position = undefined; |
|
20 range = undefined; |
|
21 size = undefined; |
|
22 mincursize = 0.1; |
|
23 |
|
24 dispatch(value,oldval, index) { |
|
25 switch(index) { |
|
26 case 0: |
|
27 this.range = Math.max(1,value); |
|
28 break; |
|
29 case 1: |
|
30 this.position = value; |
|
31 break; |
|
32 case 2: |
|
33 this.size = value; |
|
34 break; |
|
35 } |
|
36 |
|
37 this.request_animate(); |
|
38 } |
|
39 |
|
40 get_ratios() { |
|
41 let range = this.range; |
|
42 let size = Math.max(this.range * this.mincursize, Math.min(this.size, range)); |
|
43 let maxh = this.range_elt.height.baseVal.value; |
|
44 let pixels = maxh; |
|
45 let units = range; |
|
46 return [size, maxh, range, pixels, units]; |
|
47 } |
|
48 |
|
49 animate(){ |
|
50 if(this.position == undefined || this.range == undefined || this.size == undefined) |
|
51 return; |
|
52 let [size, maxh, range, pixels, units] = this.get_ratios(); |
|
53 |
|
54 let new_y = this.range_elt.y.baseVal.value + Math.round(Math.min(this.position,range-size) * pixels / units); |
|
55 let new_height = Math.round(maxh * size/range); |
|
56 |
|
57 this.cursor_elt.y.baseVal.value = new_y; |
|
58 this.cursor_elt.height.baseVal.value = new_height; |
|
59 } |
|
60 |
|
61 init_mandatory() { |
|
62 this.cursor_elt.onpointerdown = () => this.on_cursor_down(); |
|
63 |
|
64 this.bound_drag = this.drag.bind(this); |
|
65 this.bound_drop = this.drop.bind(this); |
|
66 } |
|
67 |
|
68 apply_position(position){ |
|
69 this.position = Math.round(Math.max(Math.min(position, this.range - this.size), 0)); |
|
70 this.apply_hmi_value(1, this.position); |
|
71 } |
|
72 |
|
73 on_page_click(is_up){ |
|
74 this.apply_position(is_up ? this.position-this.size |
|
75 : this.position+this.size); |
|
76 } |
|
77 |
|
78 on_cursor_down(e){ |
|
79 // get scrollbar -> root transform |
|
80 let ctm = this.range_elt.getCTM(); |
|
81 // relative motion -> discard translation |
|
82 ctm.e = 0; |
|
83 ctm.f = 0; |
|
84 // root -> scrollbar transform |
|
85 this.invctm = ctm.inverse(); |
|
86 svg_root.addEventListener("pointerup", this.bound_drop, true); |
|
87 svg_root.addEventListener("pointermove", this.bound_drag, true); |
|
88 this.dragpos = this.position; |
|
89 } |
|
90 |
|
91 drop(e) { |
|
92 svg_root.removeEventListener("pointerup", this.bound_drop, true); |
|
93 svg_root.removeEventListener("pointermove", this.bound_drag, true); |
|
94 } |
|
95 |
|
96 drag(e) { |
|
97 let [size, maxh, range, pixels, units] = this.get_ratios(); |
|
98 if(pixels == 0) return; |
|
99 let point = new DOMPoint(e.movementX, e.movementY); |
|
100 let movement = point.matrixTransform(this.invctm).y; |
|
101 this.dragpos += movement * units / pixels; |
|
102 this.apply_position(this.dragpos); |
|
103 } |
|
104 || |
|
105 } |
|
106 |
|
107 widget_defs("ScrollBar") { |
|
108 labels("cursor range"); |
|
109 |
|
110 const "pagebuttons" optional_labels("pageup pagedown"); |
|
111 const "have_pagebuttons","string-length($pagebuttons)>0"; |
|
112 value "$pagebuttons"; |
|
113 |
|
114 | init: function() { |
|
115 | this.init_mandatory(); |
|
116 |
|
117 if "$have_pagebuttons" { |
|
118 | this.pageup_elt.onclick = () => this.on_page_click(true); |
|
119 | this.pagedown_elt.onclick = () => this.on_page_click(false); |
|
120 } |
|
121 | }, |
|
122 } |