mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
Introduce ComboboxBase and in/decrement selection by scroll event (#3648)
This commit is contained in:
parent
2324b35d12
commit
caecbb98ac
5 changed files with 153 additions and 172 deletions
73
internal/compiler/widgets/common/combobox-base.slint
Normal file
73
internal/compiler/widgets/common/combobox-base.slint
Normal 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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 { }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue