// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial // cSpell: ignore combobox spinbox import { LineEditInner, TextEdit, AboutSlint } from "../common/common.slint"; import { StyleMetrics, ScrollView } from "std-widgets-impl.slint"; export { StyleMetrics, ScrollView, TextEdit, AboutSlint } // FIXME: the font-size should be removed but is required right now to compile the printer-demo export component Button inherits NativeButton { // FIXME: remove in-out property font-size; accessible-checkable <=> root.checkable; accessible-checked <=> root.checked; accessible-label <=> root.text; accessible-role: button; checkable: false; enabled: true; } export component StandardButton inherits NativeButton { in property kind <=> self.standard-button-kind; accessible-checkable <=> root.checkable; accessible-checked <=> root.checked; accessible-label <=> root.text; accessible-role: button; is-standard-button: true; checkable: false; } export component CheckBox inherits NativeCheckBox { accessible-checkable: true; accessible-checked <=> root.checked; accessible-label <=> root.text; accessible-role: checkbox; } export component SpinBox inherits NativeSpinBox { // FIXME: remove in-out property font-size; accessible-role: spinbox; accessible-value: root.value; accessible-value-minimum: root.minimum; accessible-value-maximum: root.maximum; accessible-value-step: (root.maximum - root.minimum) / 100; } export component Slider inherits NativeSlider { accessible-role: slider; accessible-value: root.value; accessible-value-minimum: root.minimum; accessible-value-maximum: root.maximum; accessible-value-step: (root.maximum - root.minimum) / 100; out property has-focus: fs.has-focus; fs := FocusScope { x:0; width: 0px; key-pressed(event) => { if (root.enabled && event.text == Key.RightArrow) { root.value = Math.min(root.value + 1, root.maximum); accept } else if (root.enabled && event.text == Key.LeftArrow) { root.value = Math.max(root.value - 1, root.minimum); accept } else { reject } } } } export component GroupBox inherits NativeGroupBox { GridLayout { padding-left: root.native-padding-left; padding-right: root.native-padding-right; padding-top: root.native-padding-top; padding-bottom: root.native-padding-bottom; @children } } export component LineEdit inherits NativeLineEdit { in property font-size <=> inner.font-size; in-out property text <=> inner.text; in property placeholder-text <=> inner.placeholder-text; in property input-type <=> inner.input-type; in property horizontal-alignment <=> inner.horizontal-alignment; in property read-only <=> inner.read-only; enabled: true; has-focus: inner.has-focus; forward-focus: inner; callback accepted <=> inner.accepted; callback edited <=> inner.edited; horizontal-stretch: 1; vertical-stretch: 0; HorizontalLayout { padding-left: root.native-padding-left; padding-right: root.native-padding-right; padding-top: root.native-padding-top; padding-bottom: root.native-padding-bottom; inner := LineEditInner { placeholder-color: self.enabled ? StyleMetrics.placeholder-color : StyleMetrics.placeholder-color-disabled; enabled <=> root.enabled; } } } export component ListView inherits ScrollView { @children } component StandardListViewBase inherits ListView { in property<[StandardListViewItem]> model; in-out property current-item: -1; for item[i] in root.model : NativeStandardListViewItem { item: item; index: i; is-selected: root.current-item == i; has-hover: ta.has-hover; ta := TouchArea { clicked => { root.current-item = i; } } } } export component StandardListView inherits StandardListViewBase { FocusScope { key-pressed(event) => { if (event.text == Key.UpArrow && root.current-item > 0) { root.current-item -= 1; accept } else if (event.text == Key.DownArrow && root.current-item + 1 < root.model.length) { root.current-item += 1; accept } else { reject } } } } export component ComboBox inherits NativeComboBox { in property <[string]> model; in-out property current-index : -1; enabled: true; open-popup => { popup.show(); } callback selected(string); accessible-role: combobox; accessible-value <=> root.current-value; popup := PopupWindow { x:0; Rectangle { background: NativeStyleMetrics.window-background; } NativeComboBoxPopup { width: 100%; height: 100%; } y: root.height; width: root.width; VerticalLayout { spacing: 0px; for value[i] in root.model: NativeStandardListViewItem { item: { text: value }; is-selected: root.current-index == i; has-hover: ta.has-hover; ta := TouchArea { clicked => { if (root.enabled) { root.current-index = i; root.current-value = value; root.selected(root.current-value); } //is-open = false; } } } } } 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; } } } export component TabWidgetImpl inherits NativeTabWidget { } export component TabImpl inherits NativeTab { accessible-role: tab; accessible-label <=> root.title; } export component TabBarImpl inherits Rectangle { // injected properties: in-out property current; // The currently selected tab in-out property current-focused: fs.has-focus ? root.current : -1; // The currently focused tab in-out property num-tabs; // The total number of tabs accessible-role: tab; accessible-delegate-focus: root.current; HorizontalLayout { spacing: 0px; // Qt renders Tabs next to each other and renders "spacing" as part of the tab itself alignment: NativeStyleMetrics.tab-bar-alignment; @children } fs := FocusScope { x:0; width: 0px; // Do not react on clicks key-pressed(event) => { if (event.text == Key.LeftArrow) { root.current = Math.max(root.current - 1, 0); return accept; } if (event.text == Key.RightArrow) { root.current = Math.min(root.current + 1, root.num-tabs - 1); return accept; } return reject; } } } export component TabWidget inherits TabWidget {} export component VerticalBox inherits VerticalLayout { spacing: NativeStyleMetrics.layout-spacing; padding: NativeStyleMetrics.layout-spacing; } export component HorizontalBox inherits HorizontalLayout { spacing: NativeStyleMetrics.layout-spacing; padding: NativeStyleMetrics.layout-spacing; } export component GridBox inherits GridLayout { spacing: NativeStyleMetrics.layout-spacing; padding: NativeStyleMetrics.layout-spacing; } export component StandardTableView { callback sort-ascending(int); callback sort-descending(int); out property current-sort-column: -1; in-out property <[TableColumn]> columns; in property <[[StandardListViewItem]]> rows; horizontal-stretch: 1; vertical-stretch: 1; function sort(index: int) { if (current-sort-column != index) { columns[current-sort-column].sort-order = SortOrder.unsorted; } if(columns[index].sort-order == SortOrder.ascending) { columns[index].sort-order = SortOrder.descending; sort-descending(index); } else { columns[index].sort-order = SortOrder.ascending; sort-ascending(index); } current-sort-column = index; } scroll-view := NativeScrollView { vertical-max: fli.viewport-height > fli.height ? fli.viewport-height - fli.height : 0phx; vertical-page-size: fli.height; horizontal-max: fli.viewport-width > fli.width ? fli.viewport-width - fli.width : 0phx; horizontal-page-size: fli.width; fli := Flickable { x: scroll-view.native-padding-left; width: scroll-view.width - scroll-view.native-padding-left - scroll-view.native-padding-right; y: scroll-view.native-padding-top + header.height; height: scroll-view.height - self.y - scroll-view.native-padding-bottom; interactive: false; viewport-y <=> scroll-view.vertical-value; viewport-x <=> scroll-view.horizontal-value; VerticalLayout { alignment: start; for row[i] in rows : Rectangle { width: max(row-layout.preferred-width, fli.width); row-ta := TouchArea {} row-layout := HorizontalLayout { for cell[index] in row : Rectangle { horizontal-stretch: columns[index].horizontal-stretch; min-width: max(columns[index].min-width, columns[index].width); preferred-width: self.min-width; max-width: (index < columns.length && columns[index].width >= 1px) ? max(columns[index].min-width, columns[index].width) : 100000px; HorizontalLayout { NativeStandardListViewItem { item: cell; index: i; //is-selected: root.current-item == i; has-hover: row-ta.has-hover; } } } } } } } } header := Rectangle { clip: true; height: header-layout.preferred-height; x: scroll-view.native-padding-left; y: scroll-view.native-padding-top; width: fli.width; header-layout := HorizontalLayout { width: max(self.preferred-width, parent.width); x: fli.viewport-x; for column[index] in columns : NativeTableHeaderSection { item: column; horizontal-stretch: column.horizontal-stretch; min-width: max(column.min-width, column.width); preferred-width: self.min-width; max-width: (index < columns.length && column.width >= 1px) ? max(column.min-width, column.width) : 100000px; TouchArea { clicked => { sort(index); } } TouchArea { width: 10px; x: parent.width - self.width / 2; moved => { if (self.pressed) { column.width = max(1px, parent.width + (self.mouse-x - self.pressed-x)); } } mouse-cursor: ew-resize; } } } } }