// Copyright © SixtyFPS GmbH // 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 enabled; in_out property value; in property minimum; in property divisions: 0; in property maximum: 100; callback released(value: float); property 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) } }