mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-27 18:36:12 +00:00
126 lines
4.5 KiB
Text
126 lines
4.5 KiB
Text
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
import { MaterialStyleMetrics } from "../styling/material_style_metrics.slint";
|
|
import { MaterialPalette } from "../styling/material_palette.slint";
|
|
import { StateLayer } from "./state_layer.slint";
|
|
|
|
export component Slider {
|
|
in property <bool> enabled;
|
|
in_out property <float> value;
|
|
in property <float> minimum;
|
|
in property <float> divisions: 0;
|
|
in property <float> maximum: 100;
|
|
|
|
callback released(value: float);
|
|
|
|
property <float> steps: root.divisions > 0 ? (root.maximum - root.minimum) / root.divisions : 1;
|
|
|
|
min_height: 20px;
|
|
accessible-role: slider;
|
|
accessible-enabled: root.enabled;
|
|
accessible-value: root.value;
|
|
accessible-value-minimum: root.minimum;
|
|
accessible-value-maximum: root.maximum;
|
|
accessible-value-step: min(steps, (root.maximum - root.minimum) / 100);
|
|
forward-focus: focus_scope;
|
|
|
|
focus_scope := FocusScope {
|
|
touch_area := TouchArea {
|
|
track := Rectangle {
|
|
x: 0;
|
|
height: MaterialStyleMetrics.size_4;
|
|
background: MaterialPalette.surface_container_highest;
|
|
border_radius: self.height / 2;
|
|
|
|
Rectangle {
|
|
x: 0;
|
|
width: root.value_to_length(track.width, root.value);
|
|
border_radius: track.border_radius;
|
|
background: thumb.background;
|
|
}
|
|
|
|
if root.divisions > 0 : Rectangle {
|
|
width: 100%;
|
|
height: 100%;
|
|
|
|
for i in (root.maximum - root.minimum) / root.steps : Rectangle {
|
|
x: root.value_to_length(track.width, (i + 1) * root.steps) - self.width / 2;
|
|
height: parent.height / 2;
|
|
width: self.height;
|
|
border_radius: self.height / 2;
|
|
background: MaterialPalette.outline;
|
|
}
|
|
}
|
|
}
|
|
|
|
state_layer := StateLayer {
|
|
x: root.value_to_length(track.width - thumb_area.width, root.value) - (self.width - thumb_area.width) / 2;
|
|
height: root.height + MaterialStyleMetrics.size_24;
|
|
width: self.height;
|
|
border_radius: self.height / 2;
|
|
pressed: touch_area.pressed;
|
|
has_hover: touch_area.has_hover;
|
|
has_focus: focus_scope.has_focus;
|
|
enabled: root.enabled;
|
|
background: thumb.background;
|
|
display_background: thumb_area.pressed || thumb_area.has_hover || focus_scope.has_focus;
|
|
|
|
thumb_area := TouchArea {
|
|
height: root.height;
|
|
width: self.height;
|
|
|
|
thumb := Rectangle {
|
|
border_radius: self.height / 2;
|
|
background: MaterialPalette.primary;
|
|
}
|
|
|
|
moved => {
|
|
root.set_value(root.length_to_value(state_layer.x + self.x + self.mouse_x, track.width));
|
|
}
|
|
|
|
pointer_event(event) => {
|
|
if event.kind == PointerEventKind.up {
|
|
root.released(root.value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pointer_event(event) => {
|
|
if event.kind == PointerEventKind.down && event.button == PointerEventButton.left {
|
|
root.set_value(root.length_to_value(self.mouse_x, track.width));
|
|
}
|
|
if event.kind == PointerEventKind.up {
|
|
root.released(root.value);
|
|
}
|
|
}
|
|
}
|
|
|
|
key_pressed(event) => {
|
|
if event.text == Key.LeftArrow {
|
|
root.set_value(root.value - root.steps);
|
|
return accept;
|
|
}
|
|
|
|
if event.text == Key.RightArrow {
|
|
root.set_value(root.value + root.steps);
|
|
return accept;
|
|
}
|
|
|
|
reject
|
|
}
|
|
}
|
|
|
|
pure function value_to_length(width: length, value: float) -> length {
|
|
clamp(width * (value - root.minimum) / (root.maximum - root.minimum), 0, width)
|
|
}
|
|
|
|
pure function length_to_value(x: length, width: length) -> float {
|
|
x * (root.maximum - root.minimum) / width
|
|
}
|
|
|
|
function set_value(value: float) {
|
|
root.value = clamp(round(value / root.steps) * root.steps, root.minimum, root.maximum)
|
|
}
|
|
}
|