Loading files
c730ec352This file is pinned to the selected release. Download the original to open it in your design tool.
import { ControlIconButton } from "iconbutton.slint";
import { LinkText } from "linktext.slint";
import { TextInput } from "textinput.slint";
import { ToolTip } from "tooltip.slint";
import {
Backend,
Data,
Helpers,
Int64,
LengthEditData,
LengthEditParseResult,
LengthUnit,
} from "../api.slint";
export component LengthEdit inherits Rectangle {
in property <LengthEditData> data: {
minimum: Data.min-length,
};
in-out property <Int64> value: data.value;
in-out property <LengthUnit> unit: data.unit;
in property <Int64> minimum: data.minimum;
in property <image> icon;
in property <string> tooltip;
in property <string> min-width-text: "123.456";
in property <bool> can-increase: data.can-increase;
in property <bool> can-decrease: data.can-decrease;
in property <bool> can-change-unit: true;
in property <bool> auto-supported: false;
in-out property <bool> auto-checked: false;
in property <bool> has-dropdown: false;
in property <bool> enabled: true;
property <LengthEditParseResult> parse-result;
property <bool> disable-update: false;
property <bool> auto-hovered: false;
callback value-changed(Int64);
value-changed(value) => {
self.value = value;
}
callback value-accepted(Int64);
callback unit-changed(LengthUnit);
unit-changed(unit) => {
self.unit = unit;
}
callback auto-toggled(bool);
auto-toggled(checked) => {
self.auto-checked = checked;
}
callback increase-triggered;
callback decrease-triggered;
callback dropdown-triggered;
public function select-all() {
edt.select-all();
}
function update-text-from-value() {
edt.text = Backend.format-length(root.value, root.unit);
parse-result.valid = true;
}
// Accessibility
accessible-role: spinbox;
accessible-description: tooltip;
accessible-enabled: enabled;
accessible-value: edt.text + " " + Helpers.get-unit-accessibility-label(root.unit);
accessible-action-increment => {
disable-update = false;
increase-triggered();
}
accessible-action-decrement => {
disable-update = false;
decrease-triggered();
}
accessible-action-set-value(s) => {
edt.text = s;
edt.edited();
}
changed value => {
if !disable-update {
update-text-from-value();
}
}
changed unit => {
if !disable-update {
update-text-from-value();
}
}
preferred-height: 25px;
background: enabled ? Data.theme.control : Data.theme.control-disabled;
border-color: {
if !enabled {
Data.theme.control-border-disabled
} else if edt.has-focus {
if !parse-result.valid {
Data.theme.base-text-error
} else {
Data.theme.accent
}
} else if !parse-result.valid {
Data.theme.control-border.mix(Data.theme.base-text-error, 0.6)
} else {
Data.theme.control-border
}
};
border-width: 1px;
forward-focus: edt;
// A bit ugly: Ensure enough space for numbers in the typical range.
metrics-edt := TextInput {
width: 0;
height: 0;
font-size: 13px;
single-line: true;
wrap: no-wrap;
text: min-width-text;
visible: false;
accessible-role: none;
}
ta := TouchArea {
enabled: enabled;
l := HorizontalLayout {
padding-left: 5px;
padding-right: 1px;
padding-top: self.padding-right;
padding-bottom: self.padding-top;
spacing: 5px;
if icon.width > 0: Rectangle {
width: 12px;
Image {
width: 100%;
height: self.width;
image-fit: contain;
colorize: enabled ? Data.theme.control-text : Data.theme.control-text-disabled;
source: icon;
accessible-role: none;
}
if has-dropdown: Rectangle {
x: (parent.width - self.width) / 2;
y: parent.height - self.height;
width: 8px;
height: 5px;
Path {
commands: "M 100 0 L 50 40 L 0 0 Z";
fill: enabled ? Data.theme.control-text : Data.theme.control-text-disabled;
}
}
}
if auto-supported: VerticalLayout {
alignment: center;
Rectangle {
width: auto-btn.preferred-width + 4px;
height: auto-btn.preferred-height + 2px;
background: {
if auto-checked && (!enabled) {
Data.theme.control-disabled.mix(Data.theme.control-checked, 0.5)
} else if auto-checked {
Data.theme.control-checked
} else {
transparent
}
};
border-color: {
if !enabled {
Data.theme.control-border-disabled
} else {
Data.theme.control-border
}
};
border-width: 1px;
border-radius: 5px;
auto-btn := LinkText {
horizontal-alignment: center;
vertical-alignment: center;
font-size: 10.5px;
text-color: {
if auto-checked {
Data.theme.control-text
} else {
Data.theme.control-text-muted
}
};
text-color-disabled: Data.theme.control-text-disabled;
text-color-hovered: Data.theme.control-text;
text: "AUTO";
enabled: enabled;
clicked => {
root.auto-toggled(!auto-checked);
}
}
}
}
edt := TextInput {
min-width: max(self.preferred-width, metrics-edt.preferred-width);
font-size: 13px;
single-line: true;
horizontal-alignment: right;
vertical-alignment: center;
color: {
if !enabled {
Data.theme.control-text-disabled
} else if auto-supported && auto-checked {
Data.theme.control-text-muted
} else {
Data.theme.control-text
}
};
enabled: enabled;
accessible-role: none;
changed has-focus => {
if !self.has-focus {
disable-update = false;
update-text-from-value();
}
}
init => {
update-text-from-value();
}
edited => {
disable-update = true;
parse-result = Backend.parse-length-input(self.text, unit, minimum);
if parse-result.valid {
if parse-result.evaluated-value != value {
value-changed(parse-result.evaluated-value);
}
if can-change-unit && (parse-result.evaluated-unit != unit) {
unit-changed(parse-result.evaluated-unit);
}
}
}
accepted => {
disable-update = false;
update-text-from-value();
value-accepted(parse-result.evaluated-value);
}
key-pressed(event) => {
if event.text == Key.UpArrow {
if can-increase {
disable-update = false;
increase-triggered();
}
return accept;
} else if event.text == Key.DownArrow {
if can-decrease {
disable-update = false;
decrease-triggered();
}
return accept;
} else if (event.text == Key.PageUp) && enabled && can-change-unit {
disable-update = false;
unit-changed(Helpers.get-previous-unit(unit));
return accept;
} else if (event.text == Key.PageDown) && enabled && can-change-unit {
disable-update = false;
unit-changed(Helpers.get-next-unit(unit));
return accept;
} else if (event.text == "a") && auto-supported {
auto-toggled(!auto-checked);
return accept;
} else if (event.text == Key.Escape) && disable-update {
disable-update = false;
update-text-from-value();
return accept;
}
reject
}
}
HorizontalLayout {
if can-increase || can-decrease: VerticalLayout {
up-btn := ControlIconButton {
width: 15px;
enabled: enabled && can-increase;
background-color: transparent;
icon: @image-url("../../../font-awesome/svgs/solid/caret-up.svg");
icon-offset-y: 1px;
accessible-label: "increase";
clicked => {
disable-update = false;
increase-triggered();
}
}
down-btn := ControlIconButton {
width: 15px;
enabled: enabled && can-decrease;
background-color: transparent;
icon: @image-url("../../../font-awesome/svgs/solid/caret-down.svg");
icon-offset-y: -1px;
accessible-label: "decrease";
clicked => {
disable-update = false;
decrease-triggered();
}
}
}
Rectangle {
y: (parent.height - self.height) / 2;
width: 1px;
height: 15px;
background: Data.theme.control-border.with-alpha(0.5);
}
unit-btn := LinkText {
width: self.preferred-width + 8px;
horizontal-alignment: center;
vertical-alignment: center;
text-color: Data.theme.control-text.mix(Data.theme.control-text-muted, 0.5);
text-color-disabled: enabled ? Data.theme.control-text-muted : Data.theme.control-text-disabled;
text-color-hovered: Data.theme.control-text;
text: Helpers.get-unit-short-str(root.unit);
enabled: enabled && can-change-unit;
// Accessibility
accessible-description: "unit";
accessible-label: Helpers.get-unit-accessibility-label(unit);
accessible-expandable: true;
accessible-action-expand => {
unit-btn.clicked();
}
clicked => {
unit-popup.show();
}
unit-popup := PopupWindow {
x: (parent.width - self.preferred-width) / 2;
y: parent.height;
Rectangle {
background: Data.theme.control;
border-color: Data.theme.control-border;
border-width: 1px;
VerticalLayout {
padding: 5px;
spacing: 5px;
for unit in Helpers.all-length-units: unit-item-btn := LinkText {
text: Helpers.get-unit-short-str(unit);
text-color: Data.theme.control-text-muted;
text-color-hovered: Data.theme.control-text;
font-weight: (unit == root.unit) ? 600 : 400;
horizontal-alignment: center;
accessible-label: Helpers.get-unit-accessibility-label(unit);
clicked => {
unit-changed(unit);
}
}
}
}
}
}
}
}
pointer-event(event) => {
if has-dropdown && (event.kind == PointerEventKind.down) {
dropdown-triggered();
}
}
scroll-event(event) => {
if event.delta-y > 0 {
if can-increase {
disable-update = false;
increase-triggered();
}
return accept;
} else if event.delta-y < 0 {
if can-decrease {
disable-update = false;
decrease-triggered();
}
return accept;
}
reject
}
}
if ta.has-hover && (!ta.pressed) && (!tooltip.is-empty) && (!auto-hovered): tt := ToolTip {
x: (parent.width - self.width) / 2;
y: parent.height + 5px;
text: tooltip;
}
}