// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.0 OR LicenseRef-Slint-commercial import { Palette, Typography, Icons } from "styling.slint"; component SpinBoxButton inherits Rectangle { callback clicked <=> i-touch-area.clicked; in-out property pressed: self.enabled && i-touch-area.pressed; in-out property enabled <=> i-touch-area.enabled; in-out property icon-opacity: 1; in-out property icon-fill: Palette.on-primary; width: root.height; i-background := Rectangle { width: 100%; height: 100%; border-radius: max(self.width, self.height) / 2; background: Palette.primary; } i-state-layer := Rectangle { x: 0; y: 0; opacity: 0; width: i-background.width; height: i-background.height; border-radius: i-background.border-radius; background: Palette.on-primary; animate opacity { duration: 250ms; easing: ease; } } Rectangle { width: 100%; height: 100%; @children } i-touch-area := TouchArea { } states [ disabled when !root.enabled : { i-background.background: Palette.on-surface; i-background.opacity: 0.12; icon-opacity: 0.38; icon-fill: Palette.on-surface; } pressed when i-touch-area.pressed : { i-state-layer.opacity: 0.12; } hover when i-touch-area.has-hover : { i-state-layer.opacity: 0.08; } ] } // Increment and decrement a value in the given range. export component SpinBox { in property minimum; in property maximum: 100; in property enabled <=> i-focus-scope.enabled; out property has-focus <=> i-focus-scope.has-focus; in-out property value; forward-focus: i-focus-scope; horizontal-stretch: 1; vertical-stretch: 0; min-height: max(56px, i-layout.min-height); 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; i-focus-scope := 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 } } } i-background := Rectangle { width: 100%; height: 100%; border-radius: 4px; border-width: 1px; border-color: Palette.outline; } i-layout := HorizontalLayout { padding-top: 8px; padding-bottom: 8px; padding-left: 16px; padding-right: 12px; spacing: 16px; i-text := Text { text: root.value; height: 100%; color: Palette.on-surface; vertical-alignment: center; // FIXME after Roboto font can be loaded //font-family: Typography.body-large.font; font-size: Typography.body-large.font-size; font-weight: Typography.body-large.font-weight; } VerticalLayout { spacing: 4px; SpinBoxButton { enabled: root.enabled; Image { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; source: Icons.arrow-drop-up; opacity: parent.icon-opacity; colorize: parent.icon-fill; } clicked => { if (root.value < root.maximum) { root.value += 1; } root.focus(); } } SpinBoxButton { enabled: root.enabled; Image { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; source: Icons.arrow-drop-down; opacity: parent.icon-opacity; colorize: parent.icon-fill; } clicked => { if (root.value > root.minimum) { root.value -= 1; } root.focus(); } } } } states [ disabled when !root.enabled : { i-background.border-color: Palette.on-surface; i-background.opacity: 0.38; i-text.opacity: 0.38; } focused when root.has-focus : { i-background.border-width: 2px; i-background.border-color: Palette.primary; i-text.color: Palette.primary; } ] }