// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial import { md } from "md.slint"; component SpinBoxButton inherits Rectangle { callback clicked <=> touch.clicked; in-out property pressed: self.enabled && touch.pressed; in-out property enabled <=> touch.enabled; in-out property icon-opacity: 1; in-out property icon-fill: md.sys.color.on-primary; width: root.height; container := Rectangle { width: 100%; height: 100%; border-radius: max(self.width, self.height) / 2; background: md.sys.color.primary; } state-layer := Rectangle { x:0;y:0; opacity: 0; width: container.width; height: container.height; border-radius: container.border-radius; background: md.sys.color.on-primary; animate opacity { duration: 250ms; easing: ease; } } Rectangle { width: 100%; height: 100%; @children } touch := TouchArea { } states [ disabled when !root.enabled : { container.background: md.sys.color.on-surface; container.opacity: 0.12; icon-opacity: 0.38; icon-fill: md.sys.color.on-surface; } pressed when touch.pressed : { state-layer.opacity: 0.12; } hover when touch.has-hover : { state-layer.opacity: 0.08; } ] } // Increment and decrement a value in the given range. export component SpinBox { in-out property value; in property minimum; in property maximum: 100; in property enabled <=> fs.enabled; out property has-focus <=> fs.has-focus; forward-focus: fs; horizontal-stretch: 1; vertical-stretch: 0; min-width: 60px; height: 56px; accessible-role: spinbox; accessible-value: root.value; accessible-value-minimum: root.minimum; accessible-value-maximum: root.maximum; accessible-value-step: (root.maximum - root.minimum) / 100; fs := FocusScope { key-pressed(event) => { if (root.enabled && event.text == Key.UpArrow && root.value < root.maximum) { root.value += 1; accept } else if (root.enabled && event.text == Key.DownArrow && root.value > root.minimum) { root.value -= 1; accept } else { reject } } } container := Rectangle { width: 100%; height: 100%; border-radius: 4px; border-width: 1px; border-color: md.sys.color.outline; } layout := HorizontalLayout { padding-top: 8px; padding-bottom: 8px; padding-left: 16px; padding-right: 12px; spacing: 16px; label := Text { text: root.value; height: 100%; color: md.sys.color.on-surface; vertical-alignment: center; // FIXME after Roboto font can be loaded //font-family: md.sys.typescale.body-large.font; font-size: md.sys.typescale.body-large.size; font-weight: md.sys.typescale.body-large.weight; } VerticalLayout { spacing: 4px; SpinBoxButton { enabled: root.enabled; Path { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; width: 44%; height: 44%; commands: "M14.15 30.75 12 28.6l12-12 12 11.95-2.15 2.15L24 20.85Z"; opacity: parent.icon-opacity; fill: parent.icon-fill; } clicked => { if (root.value < root.maximum) { root.value += 1; } root.focus(); } } SpinBoxButton { enabled: root.enabled; Path { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; width: 44%; height: 44%; commands: "m24 30.75-12-12 2.15-2.15L24 26.5l9.85-9.85L36 18.8Z"; opacity: parent.icon-opacity; fill: parent.icon-fill; } clicked => { if (root.value > root.minimum) { root.value -= 1; } root.focus(); } } } } states [ disabled when !root.enabled : { container.border-color: md.sys.color.on-surface; container.opacity: 0.38; label.opacity: 0.38; } focused when root.has-focus : { container.border-width: 2px; container.border-color: md.sys.color.primary; label.color: md.sys.color.primary; } ] }