slint/internal/compiler/widgets/fluent/std-widgets.slint
2022-02-02 16:16:55 +01:00

510 lines
16 KiB
Text

// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
import { LineEditInner, TextEdit, AboutSlint } from "../common/common.slint";
import { StandardButton } from "../common/standardbutton.slint";
import { StyleMetrics, ScrollView, Button, Palette } from "std-widgets-impl.slint";
export { StyleMetrics, ScrollView, Button, StandardButton, TextEdit, AboutSlint }
export CheckBox := Rectangle {
callback toggled;
property <string> text <=> text.text;
property <bool> checked;
property<bool> enabled <=> touch.enabled;
min-height: 20px;
horizontal-stretch: 0;
vertical-stretch: 0;
HorizontalLayout {
spacing: 8px;
VerticalLayout {
alignment: center;
Rectangle {
border-width: 1px;
border-radius: 2px;
/* border-color: !enabled ? Palette.neutralLighter : Palette.neutralSecondaryAlt;
background: !enabled ? Palette.white
: touch.pressed ? Palette.neutralLight
: touch.has-hover ? Palette.neutralLighter
: Palette.themePrimary;*/
border-color: checked ? background : !enabled ? Palette.neutralTertiaryAlt : Palette.neutralSecondaryAlt;
background: !checked ? Palette.white
: !enabled ? Palette.neutralTertiaryAlt
: touch.has-hover || touch.pressed ? Palette.themeDark
: Palette.themePrimary;
animate background { duration: 250ms; easing: ease; }
//width: height;
vertical-stretch: 0;
width: 20px;
height: 20px;
if (checked || touch.has-hover || touch.pressed) : Path {
width: 66%;
height: 66%;
x: (parent.width - width) / 2;
y: (parent.height - height) / 2;
commands: "M23.5 11.875a.968.968 0 0 1-.289.711l-8.25 8.25c-.192.193-.43.289-.711.289s-.519-.096-.711-.289l-4.75-4.75a.965.965 0 0 1-.289-.711c0-.125.027-.25.082-.375s.129-.234.223-.328a.953.953 0 0 1 .695-.297c.135 0 .266.025.391.074.125.05.231.121.32.215l4.039 4.047 7.539-7.547a.886.886 0 0 1 .32-.215c.125-.049.255-.074.391-.074a1.004 1.004 0 0 1 .922.625.97.97 0 0 1 .078.375z";
fill: checked ? Palette.white : Palette.neutralSecondaryAlt;
}
}
}
text := Text {
color: !enabled ? Palette.neutralTertiary : Palette.neutralDark;
horizontal-alignment: left;
vertical-alignment: center;
vertical-stretch: 1;
}
}
touch := TouchArea {
clicked => {
if (root.enabled) {
root.checked = !root.checked;
root.toggled();
}
}
}
}
SpinBoxButton := Rectangle {
callback clicked <=> touch.clicked;
property<string> text; // text and font-size are not used, but present in the other styles
property <length> font-size;
property<bool> enabled <=> touch.enabled;
background: !enabled ? transparent
: touch.pressed ? Palette.neutralLight
: touch.has-hover ? Palette.neutralLighter
: Palette.white;
property <color> symbol-color: !enabled ? Palette.neutralTertiary
: touch.pressed || touch.has-hover ? Palette.neutralPrimary
: Palette.neutralSecondary;
touch := TouchArea { }
}
export SpinBox := FocusScope {
property <bool> checked;
property <int> value;
property <int> minimum;
property <int> maximum: 100;
property <bool> enabled: true;
property <image> icon;
property <length> font-size <=> button.font-size;
min-height: max(32px, l.min-height);
horizontal-stretch: 1;
vertical-stretch: 0;
Rectangle {
background: !enabled ? Palette.neutralLighter : Palette.white;
}
l := GridLayout {
padding-left: 8px;
padding-top: 3px;
padding-bottom: 3px;
text := Text {
rowspan: 2;
text: value;
color: !enabled ? Palette.neutralTertiary : Palette.neutralDark;
horizontal-alignment: left;
vertical-alignment: center;
}
Rectangle { width: 8px; }
button := SpinBoxButton {
width: 25px;
enabled: root.enabled;
Path {
commands: "M978.2,688.9l-84.2,82.1c-15.7,15.3-41.1,15.3-56.7,0l-341-304.2L162.6,764.5c-15.5,15.1-41,15.1-56.6,0l-84.3-82.1c-15.6-15.2-15.6-39.9,0-55.2l446.6-398.2c15.7-15.3,41-15.3,56.7,0l6.9,6.7l446.3,398.1C993.9,649,993.9,673.7,978.2,688.9z";
fill: parent.symbol-color;
height: 33%;
x: (parent.width - width) / 2;
y: (parent.height - height) / 2;
}
clicked => {
if (root.value < root.maximum) {
root.value += 1;
}
}
}
SpinBoxButton {
row: 1; col: 2;
enabled: root.enabled;
Path {
commands: "M21.8,311.1l84.2-82.1c15.7-15.2,41-15.2,56.7,0l341.1,304.1l333.7-297.5c15.5-15.2,41-15.2,56.6,0l84.3,82.1c15.6,15.2,15.6,40,0,55.2L531.7,771c-15.7,15.3-41,15.3-56.7,0l-6.9-6.7L21.8,366.3C6.1,351,6.1,326.3,21.8,311.1z";
fill: parent.symbol-color;
height: 33%;
x: (parent.width - width) / 2;
y: (parent.height - height) / 2;
}
clicked => {
if (root.value > root.minimum) {
root.value -= 1;
}
}
}
}
Rectangle {
x: enabled && has-focus ? -2px : 0px;
y: x;
width: parent.width - 2*x;
height: parent.height - 2*y;
border-radius: 2px;
border-width: !enabled ? 0px : has-focus ? 3px : 1px;
border-color: !enabled ? Palette.neutralLighter
: has-focus ? Palette.themeSecondary
: Palette.neutralDark;
}
}
export Slider := Rectangle {
property<float> maximum: 100;
property<float> minimum: 0;
property<float> value;
property<bool> enabled <=> touch.enabled;
callback changed(float);
min-height: 24px;
min-width: 100px;
horizontal-stretch: 1;
vertical-stretch: 0;
Rectangle {
width: parent.width - parent.min-height;
x: parent.height / 2;
height: parent.min-height / 4;
y: (parent.height - height) / 2;
border-radius: height/2;
background: !root.enabled ? Palette.neutralLighter
: touch.has-hover ? Palette.themeLight
: Palette.neutralTertiaryAlt;
}
Rectangle {
width: (parent.width - parent.min-height) * ((value - minimum) / (maximum - minimum));
x: parent.height / 2;
height: parent.min-height / 4;
y: (parent.height - height) / 2;
border-radius: height/2;
background: !root.enabled ? Palette.neutralTertiary
: touch.has-hover ? Palette.themeSecondary
: Palette.neutralSecondary;
}
handle := Rectangle {
width: height;
height: parent.height;
border-width: 3px;
border-radius: height / 2;
border-color: !root.enabled ? Palette.neutralTertiaryAlt
: touch.has-hover ? Palette.themePrimary
: Palette.neutralSecondary;
background: Palette.white;
x: (root.width - handle.width) * (value - minimum)/(maximum - minimum);
}
touch := TouchArea {
width: parent.width;
height: parent.height;
property <float> pressed-value;
pointer-event(event) => {
if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {
pressed-value = root.value;
}
}
moved => {
if (enabled && pressed) {
value = max(root.minimum, min(root.maximum,
pressed-value + (touch.mouse-x - touch.pressed-x) * (maximum - minimum) / (root.width - handle.width)));
root.changed(value);
}
}
}
}
export GroupBox := VerticalLayout {
property <string> title <=> label.text;
property<bool> enabled: true;
spacing: 8px;
padding-top: 16px;
padding-bottom: 8px;
label := Text {
vertical-stretch: 0;
color: !enabled ? Palette.neutralTertiary : Palette.neutralDark;
font-weight: 600;
}
Rectangle {
vertical-stretch: 1;
GridLayout {
@children
}
}
}
export TabWidgetImpl := Rectangle {
property <length> content-x: 0;
property <length> content-y: tabbar-preferred-height;
property <length> content-height: height - tabbar-preferred-height;
property <length> content-width: width;
property <length> tabbar-x: 0;
property <length> tabbar-y: 0;
property <length> tabbar-height: tabbar-preferred-height;
property <length> tabbar-width: width;
property <length> tabbar-preferred-height;
property <length> tabbar-preferred-width;
property <length> content-min-height;
property <length> content-min-width;
property <int> current-index;
preferred-width: content-min-width;
min-width: content-min-width;
preferred-height: content-min-height + tabbar-preferred-height;
min-height: content-min-height + tabbar-preferred-height;
}
export TabImpl := Rectangle {
property<string> title <=> t.text;
//property<image> icon;
property<bool> enabled : true;
property<bool> pressed;
property<int> current;
property<int> tab-index;
property<int> num-tabs;
min-height: t.preferred-height + 16px;
preferred-width: t.preferred-width + 16px;
background: !enabled ? Palette.neutralLighter
: touch.pressed ? Palette.neutralLight
: touch.has-hover ? Palette.neutralLighter
: Palette.white;
horizontal-stretch: 0;
vertical-stretch: 0;
touch := TouchArea {
clicked => {
fs.focus(); // focus ourselves so that the previous tab don't keep the focus
current = tab-index;
}
}
t:= Text {
width: parent.width;
height: parent.height;
vertical-alignment: center;
horizontal-alignment: center;
color: !enabled ? Palette.neutralTertiary : Palette.neutralPrimary;
font-weight: root.current == root.tab-index ? 600 : 500;
}
Rectangle {
height: 3px;
width: touch.has-hover && root.current == root.tab-index ? parent.width : parent.width - 16px;
animate width { duration: 250ms; easing: ease-out; }
background: root.current == root.tab-index ? Palette.themeSecondary : transparent;
y: parent.height - height;
x: (parent.width - width) / 2;
}
fs := FocusScope {}
}
export TabBarImpl := HorizontalLayout {
spacing: 8px;
alignment: start;
}
export TabWidget := TabWidget {}
export LineEdit := Rectangle {
property <length> font-size <=> inner.font-size;
property <string> text <=> inner.text;
property <string> placeholder-text <=> inner.placeholder-text;
property <bool> has-focus: inner.has-focus;
property <bool> enabled <=> inner.enabled;
callback accepted <=> inner.accepted;
callback edited <=> inner.edited;
forward-focus: inner;
// border-color: root.has-focus ? Palette.highlight-background : #ffffff;
horizontal-stretch: 1;
vertical-stretch: 0;
min-height: max(32px, l.min-height);
background: !enabled ? Palette.neutralLighter : Palette.white;
border-radius: 2px;
border-width: !enabled ? 0px : has-focus ? 2px : 1px;
border-color: !enabled ? Palette.neutralLighter
: has-focus ? Palette.themeSecondary
: Palette.neutralPrimary;
l := HorizontalLayout {
padding-left: 8px;
padding-right: 8px;
padding-top: 3px;
padding-bottom: 3px;
inner := LineEditInner {
placeholder-color: !enabled ? Palette.neutralTertiary : Palette.neutralSecondary;
}
}
}
export ListView := ScrollView {
@children
}
export StandardListView := ListView {
property<[StandardListViewItem]> model;
property<int> current-item: -1;
for item[idx] in model : Rectangle {
l := HorizontalLayout {
padding: 8px;
spacing: 0px;
t := Text {
text: item.text;
color: Palette.neutralPrimary;
}
}
background: idx == root.current-item ? Palette.neutralLighter
: touch.has-hover ? Palette.neutralLighterAlt : transparent;
touch := TouchArea {
width: parent.width;
height: parent.height;
clicked => { current-item = idx; }
}
}
FocusScope {
key-pressed(event) => {
if (event.text == Keys.UpArrow && current-item > 0) {
current-item -= 1;
return accept;
} else if (event.text == Keys.DownArrow && current-item + 1 < model.length) {
current-item += 1;
return accept;
}
reject
}
}
}
export ComboBox := FocusScope {
property <[string]> model;
property <int> current-index : -1;
property <string> current-value;
//property <bool> is-open: false;
property<bool> enabled <=> touch.enabled;
callback selected(string);
Rectangle {
background: !enabled ? Palette.neutralLighter : Palette.white;
border-radius: 2px;
border-width: !enabled ? 0px : has-focus ? 3px : 1px;
border-color: !enabled ? Palette.neutralLighter
: has-focus ? Palette.themeSecondary
: Palette.neutralPrimary;
}
horizontal-stretch: 1;
vertical-stretch: 0;
min-width: 170px;
min-height: max(32px, l.min-height);
l := HorizontalLayout {
padding-left: 8px;
padding-right: 8px;
padding-bottom: 3px;
padding-top: 3px;
spacing: 8px;
t := Text {
text <=> root.current-value;
horizontal-alignment: left;
vertical-alignment: center;
horizontal-stretch: 1;
color: !enabled ? Palette.neutralTertiary
: root.has-focus || touch.has-hover ? Palette.neutralPrimary
: Palette.neutralSecondary;
min-width: 0;
}
Rectangle {
width: 25px;
Path {
x: (parent.width - width) / 2;
y: (parent.height - height) / 2;
height: 8px;
width: 25px;
commands: "M21.8,311.1l84.2-82.1c15.7-15.2,41-15.2,56.7,0l341.1,304.1l333.7-297.5c15.5-15.2,41-15.2,56.6,0l84.3,82.1c15.6,15.2,15.6,40,0,55.2L531.7,771c-15.7,15.3-41,15.3-56.7,0l-6.9-6.7L21.8,366.3C6.1,351,6.1,326.3,21.8,311.1z";
fill: t.color;
}
}
}
touch := TouchArea {
clicked => {
root.focus();
popup.show();
}
}
popup := PopupWindow {
y: root.height;
width: root.width;
Rectangle {
border-color: Palette.neutralLighter;
border-width: 1px;
/*drop-shadow-color: Palette.neutralTertiary;
drop-shadow-blur: 5px;*/
background: Palette.white;
}
VerticalLayout {
for value[idx] in root.model: Rectangle {
background: idx == root.current-index ? Palette.neutralLighter
: item-area.has-hover ? Palette.neutralLighterAlt : transparent;
VerticalLayout {
padding: 10px;
Text {
text: value;
}
}
item-area := TouchArea {
width: 100%;
height: 100%;
clicked => {
if (root.enabled) {
root.current-index = idx;
root.current-value = value;
root.selected(root.current-value);
}
}
}
}
}
}
}
export VerticalBox := VerticalLayout {
spacing: StyleMetrics.layout-spacing;
padding: StyleMetrics.layout-padding;
}
export HorizontalBox := HorizontalLayout {
spacing: StyleMetrics.layout-spacing;
padding: StyleMetrics.layout-padding;
}
export GridBox := GridLayout {
spacing: StyleMetrics.layout-spacing;
padding: StyleMetrics.layout-padding;
}