mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 02:39:28 +00:00

* added focus state to StandardLIstView * (wip) focus handling for qt style * Update CHANGELOG.md Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl> * Share StandardListView between all styles * Update internal/compiler/widgets/material-base/combobox.slint Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl> * code review feedback --------- Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl>
137 lines
No EOL
4.2 KiB
Text
137 lines
No EOL
4.2 KiB
Text
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
|
|
|
import { ListItem, ScrollView } from "std-widgets-impl.slint";
|
|
|
|
export component ListView inherits ScrollView {
|
|
@children
|
|
}
|
|
|
|
component StandardListViewBase inherits ListView {
|
|
in property <[StandardListViewItem]> model;
|
|
in-out property <int> current-item: -1;
|
|
|
|
callback current-item-changed(/* current-item */ int);
|
|
callback item-pointer-event( /* item-index */ int, /* event */ PointerEvent, /* absolute mouse position */ Point);
|
|
|
|
public function set-current-item(index: int) {
|
|
if (index < 0 || index >= model.length) {
|
|
return;
|
|
}
|
|
|
|
bring-into-view(index);
|
|
|
|
current-item = index;
|
|
focus-item = index;
|
|
current-item-changed(current-item);
|
|
}
|
|
|
|
private property <length> item-height: self.viewport-height / self.model.length;
|
|
private property <int> into-view-item: 0;
|
|
private property <length> into-view-item-y: root.item-y(root.into-view-item);
|
|
private property <length> current-item-y: root.item-y(root.focus-item);
|
|
private property <int> focus-item: 0;
|
|
|
|
pure function first-visible-item() -> int {
|
|
return min(root.model.length - 1, max(0, round(-root.viewport-y / root.item-height)));
|
|
}
|
|
|
|
pure function item-y(index: int) -> length {
|
|
return root.viewport-y + index * root.item-height;
|
|
}
|
|
|
|
function bring-into-view(index: int) {
|
|
if (index < 0 || index >= model.length) {
|
|
return;
|
|
}
|
|
|
|
into-view-item = index;
|
|
|
|
if (into-view-item-y < 0) {
|
|
self.viewport-y += 0 - into-view-item-y;
|
|
}
|
|
|
|
if (into-view-item-y + item-height > self.visible-height) {
|
|
self.viewport-y -= into-view-item-y + item-height - self.visible-height;
|
|
}
|
|
}
|
|
|
|
protected function focus-up() {
|
|
root.set-focus-item(root.focus-item - 1);
|
|
}
|
|
|
|
protected function focus-down() {
|
|
root.set-focus-item(root.focus-item + 1);
|
|
}
|
|
|
|
protected function select-focus-item() {
|
|
root.set-current-item(root.focus-item);
|
|
}
|
|
|
|
protected function focus-current-item() {
|
|
root.focus-item = max(0, root.current-item);
|
|
|
|
if (root.current-item-y + root.item-height < 0
|
|
|| root.current-item-y > root.height) {
|
|
root.focus-item = root.first-visible-item();
|
|
}
|
|
}
|
|
|
|
protected function set-focus-item(index: int) {
|
|
root.focus-item = min(root.model.length - 1, max(0, index));
|
|
root.bring-into-view(root.focus-item);
|
|
}
|
|
|
|
for item[index] in root.model : ListItem {
|
|
height: self.min-height;
|
|
item: item;
|
|
index: index;
|
|
is-selected: index == root.current-item;
|
|
has-focus: root.has-focus && index == root.focus-item;
|
|
has-hover: i-touch-area.has-hover;
|
|
pressed: i-touch-area.pressed;
|
|
pressed-x: i-touch-area.pressed-x;
|
|
pressed-y: i-touch-area.pressed-y;
|
|
|
|
i-touch-area := TouchArea {
|
|
clicked => {
|
|
root.set-current-item(index);
|
|
}
|
|
|
|
pointer-event(pe) => {
|
|
root.item-pointer-event(index, pe, {
|
|
x: self.absolute-position.x + self.mouse-x - root.absolute-position.x,
|
|
y: self.absolute-position.y + self.mouse-y - root.absolute-position.y,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export component StandardListView inherits StandardListViewBase {
|
|
forward-focus: i-focus-scope;
|
|
|
|
i-focus-scope := FocusScope {
|
|
x: 0;
|
|
width: 0; // Do not react on clicks
|
|
|
|
focus-changed-event => {
|
|
root.focus-current-item();
|
|
root.has-focus = self.has-focus;
|
|
}
|
|
|
|
key-pressed(event) => {
|
|
if (event.text == Key.UpArrow) {
|
|
root.focus-up();
|
|
return accept;
|
|
} else if (event.text == Key.DownArrow) {
|
|
root.focus-down();
|
|
return accept;
|
|
}else if (event.text == Key.Return) {
|
|
root.select-focus-item();
|
|
return accept;
|
|
}
|
|
reject
|
|
}
|
|
}
|
|
} |