Introduce ComboboxBase and in/decrement selection by scroll event (#3648)

This commit is contained in:
Florian Blasius 2023-10-11 12:55:49 +02:00 committed by GitHub
parent 2324b35d12
commit caecbb98ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 153 additions and 172 deletions

View file

@ -0,0 +1,73 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
export component ComboBoxBase {
private property <length> scroll-delta: 2px;
callback selected(string /* current-value */);
callback show-popup();
in property <[string]> model;
in property <bool> enabled <=> i-focus-scope.enabled;
out property <bool> has-focus <=> i-focus-scope.has-focus;
out property <bool> pressed <=> i-touch-area.pressed;
out property <bool> has-hover: i-touch-area.has-hover;
in-out property <int> current-index: 0;
in-out property <string> current-value: root.model[root.current-index];
forward-focus: i-focus-scope;
i-focus-scope := FocusScope {
key-pressed(event) => {
if (event.text == Key.UpArrow) {
root.move-selection-up();
return accept;
} else if (event.text == Key.DownArrow) {
root.move-selection-down();
return accept;
} else if (event.text == Key.Return) {
root.show-popup();
}
return reject;
}
i-touch-area := TouchArea {
clicked => {
root.focus();
root.show-popup();
}
scroll-event(event) => {
if (event.delta-y < -root.scroll-delta) {
root.move-selection-up();
return accept;
}
if (event.delta-y > root.scroll-delta) {
root.move-selection-down();
return accept;
}
reject
}
}
}
public function select(index: int) {
if (!root.enabled) {
return;
}
root.current-index = index;
root.current-value = root.model[root.current-index];
root.selected(root.current-value);
}
public function move-selection-up() {
root.select(Math.max(root.current-index - 1, 0));
}
public function move-selection-down() {
root.select(Math.min(root.current-index + 1, root.model.length - 1));
}
}

View file

@ -3,44 +3,31 @@
import { Typography, Palette, Icons } from "styling.slint";
import { MenuBorder, ListItem, FocusBorder } from "components.slint";
import { ComboBoxBase } from "../common/combobox-base.slint";
export component ComboBox {
private property <brush> background: Palette.surface;
callback selected(string /* current-value */);
callback selected <=> i-base.selected;
in property <[string]> model;
in property <bool> enabled <=> i-focus-scope.enabled;
out property <bool> has-focus <=> i-focus-scope.has-focus;
in-out property <int> current-index: 0;
in-out property <string> current-value: root.model[root.current-index];
in property <[string]> model <=> i-base.model;
in property <bool> enabled <=> i-base.enabled;
out property <bool> has-focus <=> i-base.has-focus;
in-out property <int> current-index <=> i-base.current-index;
in-out property <string> current-value <=> i-base.current-value;
min-width: max(160px, i-layout.min-width);
min-height: max(22px, i-layout.min-height);
horizontal-stretch: 1;
vertical-stretch: 0;
forward-focus: i-focus-scope;
forward-focus: i-base;
i-focus-scope := FocusScope {
key-pressed(event) => {
if (event.text == Key.UpArrow) {
root.move-selection-up();
return accept;
} else if (event.text == Key.DownArrow) {
i-base := ComboBoxBase {
width: 100%;
height: 100%;
root.move-selection-down();
return accept;
} else if (event.text == Key.Return) {
i-popup.show();
}
return reject;
}
i-touch-area := TouchArea {
clicked => {
root.focus();
i-popup.show();
}
show-popup => {
i-popup.show();
}
}
@ -159,27 +146,13 @@ export component ComboBox {
selected: index == root.current-index;
clicked => {
root.select(index);
i-base.select(index);
}
}
}
}
}
function select(index: int) {
root.current-index = index;
root.current-value = root.model[root.current-index];
root.selected(root.current-value);
}
function move-selection-up() {
root.select(Math.max(root.current-index - 1, 0));
}
function move-selection-down() {
root.select(Math.min(root.current-index + 1, root.model.length - 1));
}
states [
disabled when !root.enabled : {
i-text.color: Palette.foreground-secondary;
@ -187,7 +160,7 @@ export component ComboBox {
i-bottom-icon.colorize: Palette.foreground-secondary;
root.background: Palette.surface-tertiary;
}
pressed when i-touch-area.pressed : {
pressed when i-base.pressed : {
root.background: Palette.surface-secondary;
}
]

View file

@ -3,44 +3,29 @@
import { Typography, Palette, Icons } from "styling.slint";
import { MenuBorder, ListItem, FocusBorder } from "components.slint";
import { ComboBoxBase } from "../common/combobox-base.slint";
export component ComboBox {
callback selected(string /* current-value */);
callback selected <=> i-base.selected;
in property <[string]> model;
in property <bool> enabled <=> i-focus-scope.enabled;
out property <bool> has-focus <=> i-focus-scope.has-focus;
in-out property <int> current-index: 0;
in-out property <string> current-value: root.model[root.current-index];
in property <[string]> model <=> i-base.model;
in property <bool> enabled <=> i-base.enabled;
out property <bool> has-focus <=> i-base.has-focus;
in-out property <int> current-index <=> i-base.current-index;
in-out property <string> current-value <=> i-base.current-value;
min-width: max(160px, i-layout.min-height);
min-height: max(32px, i-layout.min-height);
horizontal-stretch: 1;
vertical-stretch: 0;
forward-focus: i-focus-scope;
forward-focus: i-base;
i-focus-scope := FocusScope {
key-pressed(event) => {
if (event.text == Key.UpArrow) {
root.move-selection-up();
return accept;
} else if (event.text == Key.DownArrow) {
i-base := ComboBoxBase {
width: 100%;
height: 100%;
root.move-selection-down();
return accept;
} else if (event.text == Key.Return) {
i-popup.show();
}
return reject;
}
i-touch-area := TouchArea {
enabled <=> root.enabled;
clicked => {
root.focus();
i-popup.show();
}
show-popup => {
i-popup.show();
}
}
@ -96,27 +81,13 @@ export component ComboBox {
selected: index == root.current-index;
clicked => {
root.select(index);
i-base.select(index);
}
}
}
}
}
function select(index: int) {
root.current-index = index;
root.current-value = root.model[root.current-index];
root.selected(root.current-value);
}
function move-selection-up() {
root.select(Math.max(root.current-index - 1, 0));
}
function move-selection-down() {
root.select(Math.min(root.current-index + 1, root.model.length - 1));
}
states [
disabled when !root.enabled : {
i-background.background: Palette.control-disabled;
@ -124,13 +95,13 @@ export component ComboBox {
i-text.color: Palette.text-disabled;
i-icon.colorize: Palette.text-disabled;
}
pressed when i-touch-area.pressed : {
pressed when i-base.pressed : {
i-background.background: Palette.control-alt-tertiary;
i-background.border-color: Palette.control-stroke;
i-text.color: Palette.text-secondary;
i-icon.colorize: Palette.text-tertiary;
}
hover when i-touch-area.has-hover : {
hover when i-base.has-hover : {
i-background.background: Palette.control-secondary;
}
]

View file

@ -4,36 +4,29 @@
import { Palette, Typography, Elevation, Icons } from "styling.slint";
import { ListItem } from "components.slint";
import { ComboBoxBase } from "../common/combobox-base.slint";
export component ComboBox {
callback selected(string /* current-value */);
callback selected <=> i-base.selected;
in property enabled <=> i-focus-scope.enabled;
in property <[string]> model;
out property <bool> has-focus <=> i-focus-scope.has-focus;
in-out property <int> current-index : 0;
in-out property <string> current-value: root.model[root.current-index];
in property <[string]> model <=> i-base.model;
in property <bool> enabled <=> i-base.enabled;
out property <bool> has-focus <=> i-base.has-focus;
in-out property <int> current-index <=> i-base.current-index;
in-out property <string> current-value <=> i-base.current-value;
min-width: max(160px, i-layout.min-width);
min-height: max(22px, i-layout.min-height);
horizontal-stretch: 1;
vertical-stretch: 0;
min-width: max(160px, i-layout.min-width);
min-height: max(56px, i-layout.min-height);
accessible-role: combobox;
accessible-value <=> root.current-value;
forward-focus: i-focus-scope;
forward-focus: i-base;
i-focus-scope := FocusScope {
key-pressed(event) => {
if (event.text == Key.UpArrow) {
root.current-index = Math.max(root.current-index - 1, 0);
root.current-value = root.model[root.current-index];
return accept;
} else if (event.text == Key.DownArrow) {
root.current-index = Math.min(root.current-index + 1, root.model.length - 1);
root.current-value = root.model[root.current-index];
return accept;
}
return reject;
i-base := ComboBoxBase {
width: 100%;
height: 100%;
show-popup => {
i-popup.show();
}
}
@ -69,15 +62,6 @@ export component ComboBox {
}
}
i-touch-area := TouchArea {
enabled <=> root.enabled;
clicked => {
root.focus();
i-popup.show();
}
}
i-popup := PopupWindow {
x: 0;
y: root.height;
@ -92,16 +76,12 @@ export component ComboBox {
}
VerticalLayout {
for value[idx] in root.model: ListItem {
for value[index] in root.model: ListItem {
text: value;
selected: idx == root.current-index;
selected: index == root.current-index;
clicked => {
if (root.enabled) {
root.current-index = idx;
root.current-value = value;
root.selected(root.current-value);
}
i-base.select(index);
}
}
}

View file

@ -7,6 +7,7 @@ import { LineEditInner, TextEdit, AboutSlint } from "../common/common.slint";
import { StyleMetrics, ScrollView } from "std-widgets-impl.slint";
import { StandardTableView } from "tableview.slint";
export { StyleMetrics, ScrollView, TextEdit, AboutSlint, StandardTableView }
import { ComboBoxBase } from "../common/combobox-base.slint";
export component Button {
in property<string> text <=> native.text;
@ -232,72 +233,55 @@ export component StandardListView inherits StandardListViewBase {
}
export component ComboBox inherits NativeComboBox {
in property <[string]> model;
in-out property <int> current-index : 0;
current-value: root.model[root.current-index];
out property has-focus <=> fs.has-focus;
enabled: true;
callback selected(string);
forward-focus: fs;
callback selected <=> i-base.selected;
in property <[string]> model <=> i-base.model;
in-out property <int> current-index <=> i-base.current-index;
out property has-focus <=> i-base.has-focus;
enabled: true;
accessible-role: combobox;
accessible-value <=> root.current-value;
current-value: root.model[root.current-index];
forward-focus: i-base;
i-base := ComboBoxBase {
width: 100%;
height: 100%;
current-value <=> root.current-value;
show-popup => {
i-popup.show();
}
}
i-popup := PopupWindow {
x: 0;
y: root.height;
width: root.width;
popup := PopupWindow {
x:0;
NativeComboBoxPopup {
width: 100%;
height: 100%;
}
y: root.height;
width: root.width;
VerticalLayout {
spacing: 0px;
for value[i] in root.model: NativeStandardListViewItem {
for value[index] in root.model: NativeStandardListViewItem {
item: { text: value };
is-selected: root.current-index == i;
is-selected: root.current-index == index;
has-hover: ta.has-hover;
combobox: true;
ta := TouchArea {
clicked => {
if (root.enabled) {
root.current-index = i;
root.current-value = value;
root.selected(root.current-value);
}
//is-open = false;
i-base.select(index);
}
}
}
}
}
fs := FocusScope {
key-pressed(event) => {
if (event.text == Key.UpArrow) {
root.current-index = Math.max(root.current-index - 1, 0);
root.current-value = root.model[root.current-index];
return accept;
} else if (event.text == Key.DownArrow) {
root.current-index = Math.min(root.current-index + 1, root.model.length - 1);
root.current-value = root.model[root.current-index];
return accept;
// PopupWindow can not get hidden again at this time, so do not allow to pop that up.
// } else if (event.text == Key.Return) {
// touch.clicked()
// return accept;
}
return reject;
}
touch := TouchArea {
enabled <=> root.enabled;
clicked => {
root.focus();
popup.show();
}
}
}
}
export component TabWidgetImpl inherits NativeTabWidget { }