1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4export component SliderBase {
5 in property <bool> enabled <=> touch-area.enabled;
6 in property <float> minimum: 0;
7 in property <float> maximum: 100;
8 in property <float> step: 1;
9 in property <Orientation> orientation;
10 in property <length> handle-x;
11 in property <length> handle-y;
12 in property <length> handle-width;
13 in property <length> handle-height;
14 out property <bool> pressed <=> touch-area.enabled;
15 out property <bool> has-hover <=> touch-area.has-hover;
16 out property <bool> vertical: root.orientation == Orientation.vertical;
17 out property <bool> has-focus <=> focus-scope.has-focus;
18 out property <bool> handle-has-hover: touch-area.mouse-x >= root.handle-x && touch-area.mouse-x <= root.handle-x + root.handle-width &&
19 touch-area.mouse-y >= root.handle-y && touch-area.mouse-y <= root.handle-y + root.handle-height;
20 out property <bool> handle-pressed;
21 in-out property <float> value: minimum;
22
23 callback changed(value: float);
24 callback released(value: float);
25
26 private property <length> ref-size: !root.vertical ? root.handle-width : root.handle-height;
27
28 forward-focus: focus-scope;
29
30 touch-area := TouchArea {
31 property <float> pressed-value;
32
33 width: 100%;
34 height: 100%;
35
36 pointer-event(event) => {
37 if (event.button != PointerEventButton.left) {
38 return;
39 }
40
41 if (event.kind == PointerEventKind.up) {
42 if (root.handle-pressed) {
43 root.released(root.value);
44 }
45 root.handle-pressed = false;
46 return;
47 }
48
49
50 if (!root.handle-has-hover) {
51 root.set-value((!root.vertical ? root.size-to-value(touch-area.mouse-x, root.width) :
52 root.size-to-value(touch-area.mouse-y, root.height)) + root.minimum);
53 }
54
55 self.pressed-value = value;
56 focus-scope.focus();
57 root.handle-pressed = true;
58 }
59
60 moved => {
61 if (!self.enabled) {
62 return;
63 }
64
65 root.set-value(self.pressed-value + (!vertical ? root.size-to-value(touch-area.mouse-x - touch-area.pressed-x, root.width - root.ref-size) :
66 root.size-to-value(touch-area.mouse-y - touch-area.pressed-y, root.height - root.ref-size))
67 );
68 }
69 }
70
71 focus-scope := FocusScope {
72 x: 0;
73 y: 0;
74 width: 0;
75 height: 0;
76 enabled: root.enabled;
77
78 key-pressed(event) => {
79 if (!self.enabled || root.step <= 0) {
80 return reject;
81 }
82
83 if ((!vertical && event.text == Key.RightArrow) || (vertical && event.text == Key.DownArrow)) {
84 root.set-value(root.value + root.step);
85 return accept;
86 } else if ((!vertical && event.text == Key.LeftArrow) || (vertical && event.text == Key.UpArrow)) {
87 root.set-value(root.value - root.step);
88 return accept;
89 } else if (event.text == Key.Home) {
90 root.set-value(root.minimum);
91 return accept;
92 } else if (event.text == Key.End) {
93 root.set-value(root.maximum);
94 return accept;
95 }
96
97 reject
98 }
99
100 key-released(event) => {
101 if (!self.enabled) {
102 return reject;
103 }
104 if (!vertical && event.text == Key.RightArrow) || (vertical && event.text == Key.DownArrow)
105 || (!vertical && event.text == Key.LeftArrow) || (vertical && event.text == Key.UpArrow)
106 || event.text == Key.Home || event.text == Key.End {
107 root.released(root.value);
108 }
109 return accept;
110 }
111 }
112
113 pure function size-to-value(size: length, range: length) -> float {
114 size * (root.maximum - root.minimum) / range;
115 }
116
117 function set-value(value: float) {
118 if (root.value == value) {
119 return;
120 }
121
122 root.value = max(root.minimum, min(root.maximum, value));
123 root.changed(root.value);
124 }
125}
126