mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 12:24:16 +00:00
Made ComboBox scrollable (#5581)
This commit is contained in:
parent
16996dfa16
commit
806d12bcb3
15 changed files with 214 additions and 158 deletions
|
|
@ -40,6 +40,7 @@ All notable changes to this project are documented in this file.
|
|||
- Added `step-size` to `SpinBox`
|
||||
- Added `TimePickerPopup` and `DatePickerPopup`.
|
||||
- Fixed accessible value and actions on ProgressIndicator, Spinner, Spinbox, CheckBox, Switch
|
||||
- Made `ComboBox` scrollable
|
||||
|
||||
### C++ API
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export component ComboBoxBase {
|
|||
public function move-selection-down() {
|
||||
root.select(Math.min(root.current-index + 1, root.model.length - 1));
|
||||
}
|
||||
|
||||
|
||||
function reset-current() {
|
||||
root.current-index = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { CosmicFontSettings, CosmicPalette, Icons } from "styling.slint";
|
||||
import { CosmicFontSettings, CosmicPalette, Icons, CosmicSizeSettings } from "styling.slint";
|
||||
import { MenuBorder, ListItem, StateLayerBase } from "components.slint";
|
||||
import { ComboBoxBase } from "../common/combobox-base.slint";
|
||||
import { ScrollView } from "./scrollview.slint";
|
||||
|
||||
export component ComboBox {
|
||||
in property <[string]> model <=> base.model;
|
||||
|
|
@ -13,6 +14,9 @@ export component ComboBox {
|
|||
in-out property <string> current-value <=> base.current-value;
|
||||
|
||||
callback selected <=> base.selected;
|
||||
|
||||
property <length> popup-padding: 4px;
|
||||
property <int> visible-items: 6;
|
||||
|
||||
min-width: max(160px, layout.min-height);
|
||||
min-height: max(32px, layout.min-height);
|
||||
|
|
@ -75,29 +79,35 @@ export component ComboBox {
|
|||
enabled: root.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
popup := PopupWindow {
|
||||
x: 0;
|
||||
// Position the popup so that the first element is over the popup.
|
||||
// Ideally it should be so that the current element is over the popup.
|
||||
y: root.height + 4px;
|
||||
width: root.width;
|
||||
height: root.visible-items * CosmicSizeSettings.item-height + 2 * root.popup-padding;
|
||||
|
||||
MenuBorder {
|
||||
VerticalLayout {
|
||||
padding: 8px;
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
padding: root.popup-padding;
|
||||
|
||||
for value[index] in root.model : ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: touch-area.has-hover;
|
||||
pressed: touch-area.pressed;
|
||||
|
||||
for value[index] in root.model : ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: touch-area.has-hover;
|
||||
pressed: touch-area.pressed;
|
||||
|
||||
touch-area := TouchArea {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
touch-area := TouchArea {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { Icons, CosmicPalette, CosmicFontSettings } from "styling.slint";
|
||||
import { Icons, CosmicPalette, CosmicFontSettings, CosmicSizeSettings } from "styling.slint";
|
||||
|
||||
export component StateLayerBase {
|
||||
in property <length> border-radius <=> overlay.border-radius;
|
||||
|
|
@ -99,7 +99,7 @@ export component ListItem {
|
|||
in property <length> pressed-y;
|
||||
|
||||
min-width: layout.min-width;
|
||||
min-height: max(40px, layout.min-height);
|
||||
min-height: max(CosmicSizeSettings.item-height, layout.min-height);
|
||||
vertical-stretch: 0;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -81,3 +81,7 @@ export global Icons {
|
|||
out property <image> edit: @image-url("_edit.svg");
|
||||
out property <image> calendar: @image-url("_calendar.svg");
|
||||
}
|
||||
|
||||
export global CosmicSizeSettings {
|
||||
out property <length> item-height: 40px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +1,49 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { CupertinoFontSettings, CupertinoPalette, Icons } from "styling.slint";
|
||||
import { CupertinoFontSettings, CupertinoPalette, Icons, CupertinoSizeSettings } from "styling.slint";
|
||||
import { MenuBorder, ListItem, FocusBorder } from "components.slint";
|
||||
import { ComboBoxBase } from "../common/combobox-base.slint";
|
||||
import { ScrollView } from "./scrollview.slint";
|
||||
|
||||
export component ComboBox {
|
||||
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;
|
||||
in property <[string]> model <=> base.model;
|
||||
in property <bool> enabled <=> base.enabled;
|
||||
out property <bool> has-focus <=> base.has-focus;
|
||||
in-out property <int> current-index <=> base.current-index;
|
||||
in-out property <string> current-value <=> base.current-value;
|
||||
|
||||
callback selected <=> i-base.selected;
|
||||
callback selected <=> base.selected;
|
||||
|
||||
private property <brush> background: CupertinoPalette.control-background;
|
||||
property <brush> background: CupertinoPalette.control-background;
|
||||
property <length> popup-padding: 4px;
|
||||
property <int> visible-items: 6;
|
||||
|
||||
min-width: max(160px, i-layout.min-width);
|
||||
min-height: max(22px, i-layout.min-height);
|
||||
min-width: max(160px, layout.min-width);
|
||||
min-height: max(22px, layout.min-height);
|
||||
horizontal-stretch: 1;
|
||||
vertical-stretch: 0;
|
||||
forward-focus: i-base;
|
||||
forward-focus: base;
|
||||
accessible-role: combobox;
|
||||
|
||||
states [
|
||||
disabled when !root.enabled : {
|
||||
i-text.color: CupertinoPalette.foreground-secondary;
|
||||
i-top-icon.colorize: CupertinoPalette.foreground-secondary;
|
||||
i-bottom-icon.colorize: CupertinoPalette.foreground-secondary;
|
||||
text.color: CupertinoPalette.foreground-secondary;
|
||||
top-icon.colorize: CupertinoPalette.foreground-secondary;
|
||||
bottom-icon.colorize: CupertinoPalette.foreground-secondary;
|
||||
root.background: CupertinoPalette.tertiary-control-background;
|
||||
}
|
||||
pressed when i-base.pressed : {
|
||||
pressed when base.pressed : {
|
||||
root.background: CupertinoPalette.secondary-control-background;
|
||||
}
|
||||
]
|
||||
|
||||
i-base := ComboBoxBase {
|
||||
base := ComboBoxBase {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
show-popup => {
|
||||
i-popup.show();
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,14 +75,14 @@ export component ComboBox {
|
|||
}
|
||||
}
|
||||
|
||||
i-layout := HorizontalLayout {
|
||||
layout := HorizontalLayout {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
spacing: 4px;
|
||||
|
||||
i-text := Text {
|
||||
text := Text {
|
||||
horizontal-alignment: left;
|
||||
vertical-alignment: center;
|
||||
font-size: CupertinoFontSettings.body.font-size;
|
||||
|
|
@ -129,13 +132,13 @@ export component ComboBox {
|
|||
padding: 4px;
|
||||
spacing: 4px;
|
||||
|
||||
i-top-icon := Image {
|
||||
top-icon := Image {
|
||||
x: (parent.width - self.width) / 2;
|
||||
colorize: CupertinoPalette.accent-foreground;
|
||||
source: Icons.chevron-up;
|
||||
}
|
||||
|
||||
i-bottom-icon := Image {
|
||||
bottom-icon := Image {
|
||||
x: (parent.width - self.width) / 2;
|
||||
colorize: CupertinoPalette.accent-foreground;
|
||||
source: Icons.chevron-down;
|
||||
|
|
@ -144,27 +147,31 @@ export component ComboBox {
|
|||
}
|
||||
}
|
||||
|
||||
i-popup := PopupWindow {
|
||||
popup := PopupWindow {
|
||||
x: 0;
|
||||
y: parent.height + 6px;
|
||||
min-width: root.width;
|
||||
width: root.width;
|
||||
height: root.visible-items * CupertinoSizeSettings.item-height + 2 * root.popup-padding;
|
||||
|
||||
MenuBorder {
|
||||
VerticalLayout {
|
||||
padding: 4px;
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
padding: root.popup-padding;
|
||||
|
||||
for value[index] in root.model : ListItem {
|
||||
padding-horizontal: 0;
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
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;
|
||||
for value[index] in root.model : ListItem {
|
||||
padding-horizontal: 0;
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: touch-area.has-hover;
|
||||
pressed: touch-area.pressed;
|
||||
pressed-x: touch-area.pressed-x;
|
||||
pressed-y: touch-area.pressed-y;
|
||||
|
||||
i-touch-area := TouchArea {
|
||||
clicked => {
|
||||
i-base.select(index);
|
||||
touch-area := TouchArea {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { CupertinoPalette, CupertinoFontSettings, Icons } from "styling.slint";
|
||||
import { CupertinoPalette, CupertinoFontSettings, Icons, CupertinoSizeSettings } from "styling.slint";
|
||||
|
||||
export component FocusBorder inherits Rectangle {
|
||||
in property <bool> has-focus;
|
||||
|
|
@ -55,7 +55,7 @@ export component ListItem {
|
|||
in property <length> pressed-y;
|
||||
|
||||
min-width: i-layout.min-width;
|
||||
min-height: max(22px, i-layout.min-height);
|
||||
min-height: max(CupertinoSizeSettings.item-height, i-layout.min-height);
|
||||
vertical-stretch: 0;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,3 +100,7 @@ export global Icons {
|
|||
out property <image> edit: @image-url("_edit.svg");
|
||||
out property <image> calendar: @image-url("_calendar.svg");
|
||||
}
|
||||
|
||||
export global CupertinoSizeSettings {
|
||||
out property <length> item-height: 22px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,59 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { FluentFontSettings, FluentPalette, Icons } from "styling.slint";
|
||||
import { FluentFontSettings, FluentPalette, Icons, FluentSizeSettings } from "styling.slint";
|
||||
import { MenuBorder, ListItem, FocusBorder } from "components.slint";
|
||||
import { ComboBoxBase } from "../common/combobox-base.slint";
|
||||
import { ScrollView } from "./scrollview.slint";
|
||||
|
||||
export component ComboBox {
|
||||
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;
|
||||
in property <[string]> model <=> base.model;
|
||||
in property <bool> enabled <=> base.enabled;
|
||||
out property <bool> has-focus <=> base.has-focus;
|
||||
in-out property <int> current-index <=> base.current-index;
|
||||
in-out property <string> current-value <=> base.current-value;
|
||||
|
||||
callback selected <=> i-base.selected;
|
||||
callback selected <=> base.selected;
|
||||
|
||||
min-width: max(160px, i-layout.min-height);
|
||||
min-height: max(32px, i-layout.min-height);
|
||||
property <length> popup-padding: 4px;
|
||||
property <int> visible-items: 6;
|
||||
|
||||
min-width: max(160px, layout.min-height);
|
||||
min-height: max(32px, layout.min-height);
|
||||
horizontal-stretch: 1;
|
||||
vertical-stretch: 0;
|
||||
forward-focus: i-base;
|
||||
forward-focus: base;
|
||||
|
||||
accessible-role: combobox;
|
||||
|
||||
states [
|
||||
disabled when !root.enabled : {
|
||||
i-background.background: FluentPalette.control-disabled;
|
||||
i-background.border-color: FluentPalette.border;
|
||||
i-text.color: FluentPalette.text-disabled;
|
||||
i-icon.colorize: FluentPalette.text-disabled;
|
||||
background.background: FluentPalette.control-disabled;
|
||||
background.border-color: FluentPalette.border;
|
||||
text.color: FluentPalette.text-disabled;
|
||||
icon.colorize: FluentPalette.text-disabled;
|
||||
}
|
||||
pressed when i-base.pressed : {
|
||||
i-background.background: FluentPalette.control-alt-tertiary;
|
||||
i-background.border-color: FluentPalette.border;
|
||||
i-text.color: FluentPalette.text-secondary;
|
||||
i-icon.colorize: FluentPalette.text-tertiary;
|
||||
pressed when base.pressed : {
|
||||
background.background: FluentPalette.control-alt-tertiary;
|
||||
background.border-color: FluentPalette.border;
|
||||
text.color: FluentPalette.text-secondary;
|
||||
icon.colorize: FluentPalette.text-tertiary;
|
||||
}
|
||||
hover when i-base.has-hover : {
|
||||
i-background.background: FluentPalette.control-secondary;
|
||||
hover when base.has-hover : {
|
||||
background.background: FluentPalette.control-secondary;
|
||||
}
|
||||
]
|
||||
|
||||
i-base := ComboBoxBase {
|
||||
base := ComboBoxBase {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
show-popup => {
|
||||
i-popup.show();
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
i-background := Rectangle {
|
||||
background := Rectangle {
|
||||
border-radius: 3px;
|
||||
background: FluentPalette.control-background;
|
||||
border-width: 1px;
|
||||
|
|
@ -57,12 +61,12 @@ export component ComboBox {
|
|||
|
||||
animate border-color { duration: 200ms; }
|
||||
|
||||
i-layout := HorizontalLayout {
|
||||
layout := HorizontalLayout {
|
||||
padding-left: 11px;
|
||||
padding-right: 11px;
|
||||
spacing: 8px;
|
||||
|
||||
i-text := Text {
|
||||
text := Text {
|
||||
horizontal-alignment: left;
|
||||
vertical-alignment: center;
|
||||
font-size: FluentFontSettings.body.font-size;
|
||||
|
|
@ -71,7 +75,7 @@ export component ComboBox {
|
|||
text: root.current-value;
|
||||
}
|
||||
|
||||
i-icon := Image {
|
||||
icon := Image {
|
||||
colorize: FluentPalette.text-secondary;
|
||||
width: 12px;
|
||||
source: Icons.dropdown;
|
||||
|
|
@ -83,30 +87,34 @@ export component ComboBox {
|
|||
}
|
||||
|
||||
// focus border
|
||||
if (root.has-focus && root.enabled) : FocusBorder {
|
||||
border-radius: i-background.border-radius;
|
||||
if root.has-focus && root.enabled : FocusBorder {
|
||||
border-radius: background.border-radius;
|
||||
}
|
||||
|
||||
i-popup := PopupWindow {
|
||||
popup := PopupWindow {
|
||||
x: 0;
|
||||
// Position the popup so that the first element is over the popup.
|
||||
// Ideally it should be so that the current element is over the popup.
|
||||
y: -4px;
|
||||
width: root.width;
|
||||
height: root.visible-items * FluentSizeSettings.item-height + 2 * root.popup-padding;
|
||||
|
||||
MenuBorder {
|
||||
VerticalLayout {
|
||||
padding: 4px;
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
padding: root.popup-padding;
|
||||
|
||||
for value[index] in root.model : ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: touch-area.has-hover;
|
||||
pressed: touch-area.pressed;
|
||||
|
||||
for value[index] in root.model : ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: i-touch-area.has-hover;
|
||||
pressed: i-touch-area.pressed;
|
||||
|
||||
i-touch-area := TouchArea {
|
||||
clicked => {
|
||||
i-base.select(index);
|
||||
touch-area := TouchArea {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { FluentPalette, FluentFontSettings } from "styling.slint";
|
||||
import { FluentPalette, FluentFontSettings, FluentSizeSettings } from "styling.slint";
|
||||
|
||||
export component FocusBorder inherits Rectangle {
|
||||
border-width: 2px;
|
||||
|
|
@ -43,7 +43,7 @@ export component ListItem {
|
|||
in property <length> pressed-y;
|
||||
|
||||
min-width: i-layout.min-width;
|
||||
min-height: max(40px, i-layout.min-height);
|
||||
min-height: max(FluentSizeSettings.item-height, i-layout.min-height);
|
||||
vertical-stretch: 0;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -111,3 +111,7 @@ export global Icons {
|
|||
out property <image> edit: @image-url("_edit.svg");
|
||||
out property <image> calendar: @image-url("_calendar.svg");
|
||||
}
|
||||
|
||||
export global FluentSizeSettings {
|
||||
out property <length> item-height: 40px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,51 +2,54 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
|
||||
import { MaterialPalette, MaterialFontSettings, Elevation, Icons } from "styling.slint";
|
||||
import { MaterialPalette, MaterialFontSettings, Elevation, Icons, MaterialSizeSettings } from "styling.slint";
|
||||
import { ListItem, StateLayer } from "components.slint";
|
||||
import { ComboBoxBase } from "../common/combobox-base.slint";
|
||||
import { ScrollView } from "./scrollview.slint";
|
||||
|
||||
export component ComboBox {
|
||||
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;
|
||||
in property <[string]> model <=> base.model;
|
||||
in property <bool> enabled <=> base.enabled;
|
||||
out property <bool> has-focus <=> base.has-focus;
|
||||
in-out property <int> current-index <=> base.current-index;
|
||||
in-out property <string> current-value <=> base.current-value;
|
||||
|
||||
callback selected <=> i-base.selected;
|
||||
callback selected <=> base.selected;
|
||||
|
||||
property <int> visible-items: 6;
|
||||
|
||||
min-width: max(160px, i-layout.min-width);
|
||||
min-height: max(22px, i-layout.min-height);
|
||||
min-width: max(160px, layout.min-width);
|
||||
min-height: max(22px, layout.min-height);
|
||||
horizontal-stretch: 1;
|
||||
vertical-stretch: 0;
|
||||
forward-focus: i-base;
|
||||
forward-focus: base;
|
||||
accessible-role: combobox;
|
||||
|
||||
states [
|
||||
disabled when !root.enabled : {
|
||||
i-background.border-color: MaterialPalette.control-foreground;
|
||||
i-background.opacity: 0.38;
|
||||
i-label.opacity: 0.38;
|
||||
i-icon.opacity: 0.38;
|
||||
background.border-color: MaterialPalette.control-foreground;
|
||||
background.opacity: 0.38;
|
||||
label.opacity: 0.38;
|
||||
icon.opacity: 0.38;
|
||||
}
|
||||
focused when root.has-focus : {
|
||||
i-background.border-width: 2px;
|
||||
i-background.border-color: MaterialPalette.accent-background;
|
||||
i-label.color: MaterialPalette.accent-background;
|
||||
i-icon.colorize: MaterialPalette.accent-background;
|
||||
background.border-width: 2px;
|
||||
background.border-color: MaterialPalette.accent-background;
|
||||
label.color: MaterialPalette.accent-background;
|
||||
icon.colorize: MaterialPalette.accent-background;
|
||||
}
|
||||
]
|
||||
|
||||
i-base := ComboBoxBase {
|
||||
base := ComboBoxBase {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
show-popup => {
|
||||
i-popup.show();
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
i-background := Rectangle {
|
||||
background := Rectangle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
|
|
@ -54,12 +57,12 @@ export component ComboBox {
|
|||
border-color: MaterialPalette.border;
|
||||
}
|
||||
|
||||
i-layout := HorizontalLayout {
|
||||
layout := HorizontalLayout {
|
||||
padding-left: 16px;
|
||||
padding-right: 12px;
|
||||
spacing: 16px;
|
||||
|
||||
i-label := Text {
|
||||
label := Text {
|
||||
text <=> root.current-value;
|
||||
color: MaterialPalette.control-foreground;
|
||||
vertical-alignment: center;
|
||||
|
|
@ -69,7 +72,7 @@ export component ComboBox {
|
|||
font-weight: MaterialFontSettings.body-large.font-weight;
|
||||
}
|
||||
|
||||
i-icon := Image {
|
||||
icon := Image {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
y: (parent.height - self.height) / 2;
|
||||
|
|
@ -78,12 +81,13 @@ export component ComboBox {
|
|||
}
|
||||
}
|
||||
|
||||
i-popup := PopupWindow {
|
||||
popup := PopupWindow {
|
||||
x: 0;
|
||||
y: root.height;
|
||||
width: root.width;
|
||||
height: root.visible-items * MaterialSizeSettings.item-height;
|
||||
|
||||
i-popup-container := Rectangle {
|
||||
popup-container := Rectangle {
|
||||
background: MaterialPalette.alternate-background;
|
||||
drop-shadow-color: MaterialPalette.shadow;
|
||||
drop-shadow-blur: Elevation.level2;
|
||||
|
|
@ -91,16 +95,20 @@ export component ComboBox {
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
for value[index] in root.model: ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: i-touch-area.has-hover;
|
||||
pressed: i-touch-area.pressed;
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
|
||||
i-touch-area := StateLayer {
|
||||
clicked => {
|
||||
i-base.select(index);
|
||||
for value[index] in root.model: ListItem {
|
||||
item: { text: value };
|
||||
is-selected: index == root.current-index;
|
||||
has-hover: touch-area.has-hover;
|
||||
pressed: touch-area.pressed;
|
||||
|
||||
touch-area := StateLayer {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { MaterialPalette, MaterialFontSettings } from "styling.slint";
|
||||
import { MaterialPalette, MaterialFontSettings, MaterialSizeSettings } from "styling.slint";
|
||||
|
||||
export component Ripple inherits Rectangle {
|
||||
in property <length> ripple-x;
|
||||
|
|
@ -101,7 +101,7 @@ export component ListItem {
|
|||
in property <length> pressed-y;
|
||||
|
||||
min-width: i-layout.min-width;
|
||||
min-height: max(48px, i-layout.min-height);
|
||||
min-height: max(MaterialSizeSettings.item-height, i-layout.min-height);
|
||||
vertical-stretch: 0;
|
||||
horizontal-stretch: 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,3 +83,7 @@ export global Icons {
|
|||
out property <image> edit: @image-url("_edit.svg");
|
||||
out property <image> calendar: @image-url("_calendar.svg");
|
||||
}
|
||||
|
||||
export global MaterialSizeSettings {
|
||||
out property <length> item-height: 48px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,58 +2,64 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
import { ComboBoxBase } from "../common/combobox-base.slint";
|
||||
import { ScrollView } from "./scrollview.slint";
|
||||
|
||||
export component ComboBox {
|
||||
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;
|
||||
in property <[string]> model <=> base.model;
|
||||
in property <bool> enabled <=> base.enabled;
|
||||
out property <bool> has-focus <=> base.has-focus;
|
||||
in-out property <int> current-index <=> base.current-index;
|
||||
in-out property <string> current-value <=> base.current-value;
|
||||
|
||||
callback selected <=> i-base.selected;
|
||||
callback selected <=> base.selected;
|
||||
|
||||
property <length> popup-height: 224px;
|
||||
|
||||
accessible-role: combobox;
|
||||
accessible-value <=> root.current-value;
|
||||
forward-focus: i-base;
|
||||
forward-focus: base;
|
||||
|
||||
HorizontalLayout {
|
||||
i-native := NativeComboBox {
|
||||
native := NativeComboBox {
|
||||
current-value <=> root.current-value;
|
||||
has-focus <=> root.has-focus;
|
||||
enabled <=> root.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
i-base := ComboBoxBase {
|
||||
base := ComboBoxBase {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
show-popup => {
|
||||
i-popup.show();
|
||||
popup.show();
|
||||
}
|
||||
}
|
||||
|
||||
i-popup := PopupWindow {
|
||||
popup := PopupWindow {
|
||||
x: 0;
|
||||
y: root.height;
|
||||
width: root.width;
|
||||
height: root.popup-height;
|
||||
|
||||
NativeComboBoxPopup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
spacing: 0px;
|
||||
ScrollView {
|
||||
VerticalLayout {
|
||||
alignment: start;
|
||||
|
||||
for value[index] in root.model: NativeStandardListViewItem {
|
||||
item: { text: value };
|
||||
is-selected: root.current-index == index;
|
||||
has-hover: ta.has-hover;
|
||||
combobox: true;
|
||||
|
||||
for value[index] in root.model: NativeStandardListViewItem {
|
||||
item: { text: value };
|
||||
is-selected: root.current-index == index;
|
||||
has-hover: ta.has-hover;
|
||||
combobox: true;
|
||||
|
||||
ta := TouchArea {
|
||||
clicked => {
|
||||
i-base.select(index);
|
||||
ta := TouchArea {
|
||||
clicked => {
|
||||
base.select(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue