1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3import { Palette, Measurements, Colors } from "../../common.slint";
4import { AppState } from "../../appState.slint";
5
6export component FancySlider inherits Rectangle {
7 in-out property <float> value: 0.0;
8 in property <float> minValue: 0;
9 in property <float> maxValue: 1;
10 in property <image> icon;
11 out property <bool> active;
12 in property <color> colorize-icon: Palette.slider-background;
13 in-out property <duration> anim-duration: 300ms;
14 in-out property <bool> first-touch: false;
15 in-out property <length> initial-position;
16 in-out property <float> initial-value;
17 in-out property <float> previous-value;
18 in-out property <float> change-value;
19
20 callback toggle();
21
22 toggle => {
23 if value > 0.05 {
24 previous-value = value;
25 anim-duration = 50ms;
26 animated-value = 0;
27 } else {
28 anim-duration = 300ms;
29 // previous value is less than 10% between min and max
30 if previous-value < 0.1 {
31 animated-value = 1;
32 } else {
33 animated-value = previous-value;
34 }
35 }
36 }
37
38 in-out property <float> animated-value: value;
39 animate animated-value {
40 duration: anim-duration;
41 easing: ease-in-out-sine;
42 }
43 changed animated-value => {
44 value = animated-value;
45 }
46
47 height: 15px;
48 border-radius: self.height / 2;
49
50 TouchArea {
51 width: 100%;
52 height: 300%;
53 y: parent.height / 2 - self.height / 2;
54
55 clicked => {
56 if self.mouse-x == initial-position {
57 anim-duration = 300ms;
58 animated-value = (self.mouse-x / self.width) * (maxValue - minValue) + minValue;
59 }
60 }
61 moved => {
62 if !first-touch {
63 first-touch = true;
64 initial-position = self.mouse-x;
65 initial-value = (self.mouse-x / self.width) * (maxValue - minValue) + minValue;
66 previous-value = value;
67 anim-duration = 0ms;
68 } else {
69 change-value = ((self.mouse-x / self.width) * (maxValue - minValue) + minValue) - initial-value;
70 value = Math.clamp(previous-value + change-value, minValue, maxValue);
71 animated-value = value;
72 }
73 }
74
75 changed pressed => {
76 if !self.pressed {
77 first-touch = false;
78 }
79 }
80 }
81
82 Rectangle {
83 clip: true;
84 border-radius: root.border-radius;
85 background: Palette.slider-background;
86 border-color: Palette.lamp-foreground;
87 Rectangle {
88 x: 0;
89 background: Palette.slider-foreground;
90 opacity: 0.2 + 0.2 * (self.width / parent.width);
91 width: parent.width * (value - minValue) / (maxValue - minValue);
92 height: 100%;
93 border-radius: !AppState.graphics-accelerator-available ? self.width / 2 : 0px;
94 }
95
96 VerticalLayout {
97 alignment: center;
98 x: - parent.width / 2 + 10px;
99 Image {
100 colorize: root.colorize-icon;
101 height: 60%;
102 source: root.icon;
103 }
104 }
105 }
106
107 Rectangle {
108 border-radius: root.border-radius;
109 border-width: 1px;
110 border-color: @linear-gradient(180deg, white.transparentize(20%) 0%, white.transparentize(85%) 50%, #ffffff.transparentize(92%) 100%);
111 background: @linear-gradient(180deg, white.transparentize(100%) 0%, white.transparentize(100%) 60%, #ffffff.transparentize(50%) 100%);
112 }
113}
114