// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 import { CosmicPalette, Icons } from "styling.slint"; import { StateLayerBase } from "components.slint"; export component ScrollBar { in property enabled; out property has-hover: touch-area.has-hover; in-out property horizontal; in-out property maximum; in-out property page-size; in-out property value; in property policy: ScrollBarPolicy.as-needed; callback scrolled(); private property track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset; private property step-size: 10px; private property offset: 2px; opacity: 0.7; visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0); Rectangle { border-radius: thumb.border-radius; background: CosmicPalette.neutral-5-background; clip: true; thumb := Rectangle { width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(min(32px, root.width), root.track-size * root.page-size / (root.maximum + root.page-size)); height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(min(32px, root.height), root.track-size * (root.page-size / (root.maximum + root.page-size))); x: !root.horizontal ? (parent.width - self.width) / 2 : root.offset + (root.track-size - thumb.width) * (-root.value / root.maximum); y: root.horizontal ? (parent.height - self.height) / 2 : root.offset + (root.track-size - thumb.height) * (-root.value / root.maximum); border-radius: (root.horizontal ? self.height : self.width) / 2; background: CosmicPalette.neutral-6-background; StateLayerBase { width: 100%; height: 100%; border-radius: parent.border-radius; pressed: touch-area.pressed; has-hover: touch-area.has-hover; } animate width, height { duration: 100ms; easing: ease-out; } } } touch-area := TouchArea { property pressed-value; width: parent.width; height: parent.height; pointer-event(event) => { if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) { self.pressed-value = -root.value; } } moved => { if (self.enabled && self.pressed) { root.value = -max(0px, min(root.maximum, self.pressed-value + ( root.horizontal ? (touch-area.mouse-x - touch-area.pressed-x) * (root.maximum / (root.track-size - thumb.width)) : (touch-area.mouse-y - touch-area.pressed-y) * (root.maximum / (root.track-size - thumb.height)) ))); root.scrolled(); } } scroll-event(event) => { if (root.horizontal && event.delta-x != 0) { root.value = max(-root.maximum, min(0px, root.value + event.delta-x)); return accept; } else if (!root.horizontal && event.delta-y != 0) { root.value = max(-root.maximum, min(0px, root.value + event.delta-y)); return accept; } reject } } } export component ScrollView { in property enabled: true; out property visible-width <=> flickable.width; out property visible-height <=> flickable.height; in-out property viewport-width <=> flickable.viewport-width; in-out property viewport-height <=> flickable.viewport-height; in-out property viewport-x <=> flickable.viewport-x; in-out property viewport-y <=> flickable.viewport-y; in property vertical-scrollbar-policy <=> vertical-bar.policy; in property horizontal-scrollbar-policy <=> horizontal-bar.policy; in property mouse-drag-pan-enabled <=> flickable.interactive; // FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus in-out property has-focus; callback scrolled <=> flickable.flicked; min-height: 50px; min-width: 50px; horizontal-stretch: 1; vertical-stretch: 1; preferred-height: 100%; preferred-width: 100%; flickable := Flickable { interactive: false; viewport-y <=> vertical-bar.value; viewport-x <=> horizontal-bar.value; width: 100%; height: 100%; @children } vertical-bar := ScrollBar { enabled: root.enabled; x: parent.width - self.width; y: 0; width: 8px; height: horizontal-bar.visible ? parent.height - horizontal-bar.height : parent.height; horizontal: false; maximum: flickable.viewport-height - flickable.height; page-size: flickable.height; scrolled => {root.scrolled()} } horizontal-bar := ScrollBar { enabled: root.enabled; width: vertical-bar.visible ? parent.width - vertical-bar.width : parent.width; height: 8px; y: parent.height - self.height; x: 0; horizontal: true; maximum: flickable.viewport-width - flickable.width; page-size: flickable.width; scrolled => {root.scrolled()} } }