// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 import { MaterialPalette, MaterialFontSettings, MaterialSizeSettings } from "styling.slint"; export component Ripple inherits Rectangle { in property ripple-x; in property ripple-y; in property active; in property has-effect; in property ripple-color <=> i-circle.background; states [ active when root.active && root.has-effect: { i-circle.width: root.width * 2 * 1.4142; in { animate i-circle.width { duration: 2s; easing: ease-out; } } } ] i-circle := Rectangle { x: root.ripple-x - self.width / 2; y: root.ripple-y - self.width / 2; height: self.width; border-radius: self.width / 2; } } // A touch area that also represents a visual state. export component StateLayer inherits TouchArea { in property focusable; in property checked-background; in property ripple-color; in property has-ripple; in property border-radius; out property has-focus <=> i-focus-scope.has-focus; in-out property background; in-out property checked; forward-focus: i-focus-scope; states [ pressed when root.pressed: { i-ripple.opacity: 0.12; } checked when root.checked: { i-ripple.opacity: 1.0; i-ripple.background: root.checked-background; } hover when root.has-hover: { i-ripple.opacity: 0.08; } focused when root.has-focus: { i-ripple.opacity: 0.12; } ] i-ripple := Ripple { width: 100%; height: 100%; opacity: 0; active: root.pressed; ripple-x: root.pressed-x; ripple-y: root.pressed-y; clip: true; border-radius: root.border-radius; background: root.background; ripple-color: root.ripple-color; has-effect: root.has-ripple; animate opacity { duration: 250ms; easing: ease; } animate background { duration: 250ms; } } i-focus-scope := FocusScope { x: 0; width: 0px; // Do not react on clicks enabled: root.enabled && root.focusable; key-pressed(event) => { if (event.text == " " || event.text == "\n") { root.clicked(); return accept; } return reject; } } } // A selectable item that is used by `StandardListView` and `ComboBox`. export component ListItem { in property item; in-out property is_selected; in property has_hover; in property has_focus; in property pressed; in property index; in property pressed-x; in property pressed-y; min-width: i-layout.min-width; min-height: max(MaterialSizeSettings.item-height, i-layout.min-height); vertical-stretch: 0; horizontal-stretch: 1; accessible-role: list-item; accessible-label: root.item.text; accessible-item-selectable: true; accessible-item-selected: root.is-selected; accessible-item-index: root.index; states [ pressed when root.pressed: { i-ripple.opacity: 0.12; } checked when root.is-selected: { i-ripple.opacity: 1.0; i-ripple.background: MaterialPalette.control-background; } hover when root.has-hover: { i-ripple.opacity: 0.08; } focused when root.has-focus: { i-ripple.opacity: 0.12; } ] i-ripple := Ripple { opacity: 0; active: root.pressed; ripple-x: root.pressed-x; ripple-y: root.pressed-y; clip: true; border-radius: 4px; background: MaterialPalette.accent-background; ripple-color: MaterialPalette.accent-ripple; has-effect: true; animate opacity { duration: 250ms; easing: ease; } animate background { duration: 250ms; } } if (root.has-focus) : Rectangle { border-radius: 4px; border-width: 2px; border-color: MaterialPalette.accent-background; } i-layout := HorizontalLayout { padding-left: 12px; padding-right: 12px; label := Text { text: root.item.text; color: MaterialPalette.control-foreground; vertical-alignment: center; // FIXME after Roboto font can be loaded //font-family: MaterialFontSettings.label-large.font; font-size: MaterialFontSettings.label-large.font-size; font-weight: MaterialFontSettings.label-large.font-weight; accessible-role: none; } } @children }