// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: MIT import { Theme } from "theme.slint"; export component Carousel { in-out property selected-index; in property spacing; in property itemWidth; in property count: 0; callback move-right(); callback move-left(); callback move-focus-up(); move-right => { root.selected-index = min(root.selected-index + 1, root.count - 1); } move-left => { root.selected-index = max(root.selected-index - 1, 0); } private property center-x: (root.width - Theme.size-big) / 2; private property duration: Theme.duration-regular; forward-focus: focus-scope; height: Theme.size-big; preferred-width: 100%; focus-scope := FocusScope { key-pressed(event) => { if (event.text == Key.UpArrow) { root.move-focus-up(); return accept; } if (event.text == Key.RightArrow) { root.move-right(); return accept; } if (event.text == Key.LeftArrow) { root.move-left(); return accept; } return accept; } } swipe := SwipeGestureHandler { handle-swipe-left: true; handle-swipe-right: true; swiped => { if self.current-position.x > self.pressed-position.x + root.itemWidth / 2 { root.move-left(); } else if self.current-position.x < self.pressed-position.x - root.itemWidth / 2 { root.move-right(); } } TouchArea { clicked => { focus-scope.focus() } } Rectangle { clip: true; Rectangle { property viewport-x: root.center-x - root.selected-index * (root.itemWidth + root.spacing); animate viewport-x { duration: root.duration; easing: ease-in; } property swipe-offset: 0; x: self.viewport-x + swipe-offset; width: inner-layout.preferred-width; states [ swipping when swipe.swiping: { //x: self.viewport-x + swipe-offset; swipe-offset: (swipe.current-position.x - swipe.pressed-position.x).clamp(-root.itemWidth, root.itemWidth); out { animate swipe-offset { duration: root.duration; easing: ease-in; } } } ] inner-layout := HorizontalLayout { spacing <=> root.spacing; @children } } } } }