mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-19 06:47:14 +00:00
367 lines
13 KiB
Text
367 lines
13 KiB
Text
// 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 { Palette } from "std-widgets.slint";
|
|
import { Api, PreviewData, PreviewDataKind, PropertyValue, PropertyValueKind, PropertyValueTable } from "../api.slint";
|
|
import { StatusLineApi } from "../components/status-line.slint";
|
|
import { EditorSizeSettings, Icons, EditorSpaceSettings } from "../components/styling.slint";
|
|
import { PropertyValueWidget } from "../components/property-widgets.slint";
|
|
import { TableData } from "../windowglobal.slint";
|
|
import { NameLabel } from "widgets/basics.slint";
|
|
|
|
export struct CellData {
|
|
property-group-id: string,
|
|
property-name: string,
|
|
|
|
row: int,
|
|
col: int,
|
|
|
|
x: length,
|
|
y: length,
|
|
width: length,
|
|
height: length}
|
|
|
|
export component EditWindow inherits PopupWindow {
|
|
close-policy: close-on-click-outside;
|
|
|
|
callback test(string) -> bool;
|
|
callback save(string);
|
|
callback close-editor();
|
|
|
|
in property <CellData> current-cell-data;
|
|
in-out property <PropertyValueTable> current-table;
|
|
in property <PreviewData> preview-data;
|
|
in property <string> property-container-id;
|
|
|
|
function is-brush(property-value: PropertyValue) -> bool {
|
|
return property-value.kind == PropertyValueKind.brush || property-value.kind == PropertyValueKind.color;
|
|
}
|
|
|
|
content := Rectangle {
|
|
changed height => {
|
|
parent.height = self.height;
|
|
}
|
|
|
|
drop-shadow-blur: 10px;
|
|
drop-shadow-color: black.transparentize(0.5);
|
|
drop-shadow-offset-x: 0;
|
|
drop-shadow-offset-y: 0;
|
|
border-radius: EditorSizeSettings.radius;
|
|
width: is-brush(root.current-table.values[root.current-cell-data.row][root.current-cell-data.col]) ? 260px : self.preferred-width;
|
|
height: self.preferred-height;
|
|
background: Palette.alternate-background;
|
|
|
|
hl := HorizontalLayout {
|
|
padding: EditorSpaceSettings.default-padding;
|
|
padding-left: EditorSpaceSettings.default-padding;
|
|
width: is-brush(root.current-table.values[root.current-cell-data.row][root.current-cell-data.col]) ? 220px : self.preferred-width;
|
|
|
|
NameLabel {
|
|
property-name: pvw.property-name;
|
|
property-value: pvw.property-value;
|
|
}
|
|
|
|
pvw := PropertyValueWidget {
|
|
property-value: root.current-table.values[root.current-cell-data.row][root.current-cell-data.col];
|
|
property-name: root.current-table.headers[root.current-cell-data.col];
|
|
enabled: true;
|
|
|
|
changed property-value => {
|
|
root.current-table.values[root.current-cell-data.row][root.current-cell-data.col] = self.property-value;
|
|
}
|
|
|
|
set-current-item() => {
|
|
TableData.show-brush-editor(root.current-cell-data.row, root.current-cell-data.col);
|
|
close-editor();
|
|
}
|
|
|
|
update-display-string(value) => {
|
|
root.current-table.values[root.current-cell-data.row][root.current-cell-data.col].display-string = value;
|
|
}
|
|
|
|
test-color-binding(text) => {
|
|
return root.test("\"\{text}\"");
|
|
}
|
|
test-brush-binding(kind, angle, color, stops) => {
|
|
return root.test(Api.as-json-brush(kind, angle, color, stops));
|
|
}
|
|
test-float-binding(text, unit) => {
|
|
return root.test(text);
|
|
}
|
|
test-code-binding(text) => {
|
|
return root.test(text);
|
|
}
|
|
test-string-binding(text, is_translated) => {
|
|
return root.test(is_translated ? "\"\{text}\"" : text);
|
|
}
|
|
|
|
set-bool-binding(value) => {
|
|
root.save(value ? "true" : "false");
|
|
}
|
|
set-color-binding(text) => {
|
|
root.save("\"\{text}\"");
|
|
}
|
|
set-brush-binding(kind, angle, color, stops) => {
|
|
root.save(Api.as-json-brush(kind, angle, color, stops));
|
|
}
|
|
set-float-binding(text, _unit) => {
|
|
root.save(text);
|
|
}
|
|
set-code-binding(text) => {
|
|
root.save(text);
|
|
}
|
|
set-string-binding(text, is_translated) => {
|
|
root.save(is_translated ? "\"\{text}\"" : text);
|
|
}
|
|
set-enum-binding(text) => {
|
|
root.save("\"\{text}\"");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component RowMarker inherits Rectangle {
|
|
in property <int> value;
|
|
in property <bool> header: false;
|
|
in property <bool> hovered;
|
|
in property <bool> show-menu: true;
|
|
width: 30px;
|
|
|
|
if (value > 0): Rectangle {
|
|
height: 30px;
|
|
background: header ? transparent : Palette.alternate-background;
|
|
VerticalLayout {
|
|
HorizontalLayout {
|
|
Text {
|
|
vertical-alignment: center;
|
|
horizontal-alignment: right;
|
|
text: value;
|
|
}
|
|
|
|
VerticalLayout {
|
|
alignment: LayoutAlignment.center;
|
|
padding: EditorSpaceSettings.default-padding / 4;
|
|
|
|
indicator := Image {
|
|
visible: hovered && show-menu;
|
|
colorize: Palette.foreground;
|
|
source: Icons.chevron-down;
|
|
width: 10px;
|
|
height: 10px;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
height: 1px;
|
|
background: Palette.border;
|
|
width: 100%;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component Cell inherits Rectangle {
|
|
in property <PropertyValue> property-value;
|
|
|
|
in property <bool> is-header: false;
|
|
in property <bool> is-writeable: false;
|
|
|
|
in property <string> text;
|
|
|
|
in-out property <color> bg-color: cell-clicked ? Palette.accent-background.transparentize(0.8) : transparent;
|
|
|
|
private property <bool> cell-clicked: false;
|
|
|
|
callback edit-clicked();
|
|
|
|
width: 100px;
|
|
height: 30px;
|
|
border-width: 1px;
|
|
border-color: Palette.border;
|
|
background: is-header ? Palette.foreground.transparentize(0.9) : bg-color;
|
|
|
|
HorizontalLayout {
|
|
Rectangle {
|
|
width: EditorSpaceSettings.default-padding / 2;
|
|
}
|
|
|
|
Text {
|
|
font-weight: is-header ? 700 : 400;
|
|
width: root.width - EditorSpaceSettings.default-padding;
|
|
height: root.height;
|
|
horizontal-alignment: TextHorizontalAlignment.left;
|
|
vertical-alignment: center;
|
|
overflow: TextOverflow.elide;
|
|
text: root.text;
|
|
}
|
|
}
|
|
|
|
if is-writeable: TouchArea {
|
|
clicked => {
|
|
root.edit-clicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
export component Spreadsheet {
|
|
in property <string> property-group-id;
|
|
in property <PreviewData> preview-data: {
|
|
name: "Addresses",
|
|
has-getter: true,
|
|
has-setter: true,
|
|
kind: PreviewDataKind.Table,
|
|
};
|
|
in-out property <PropertyValueTable> current-table: {
|
|
is-array: true,
|
|
headers: ["type", "street", "city", "state", "zip", "favorite", "color"],
|
|
values: [
|
|
[
|
|
{ kind: PropertyValueKind.string, display-string: "home" },
|
|
{ kind: PropertyValueKind.string, display-string: "123 Oak Lane" },
|
|
{ kind: PropertyValueKind.string, display-string: "Richmond" },
|
|
{ kind: PropertyValueKind.string, display-string: "VA" },
|
|
{ kind: PropertyValueKind.string, display-string: "23226" },
|
|
{ kind: PropertyValueKind.boolean, value-bool: true, display-string: "true" },
|
|
{ kind: PropertyValueKind.color, display-string: "#ff0000" }
|
|
],
|
|
[
|
|
{ kind: PropertyValueKind.string, display-string: "work" },
|
|
{ kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
|
|
{ kind: PropertyValueKind.string, display-string: "Richmond" },
|
|
{ kind: PropertyValueKind.string, display-string: "VA" },
|
|
{ kind: PropertyValueKind.string, display-string: "23219" },
|
|
{ kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" }
|
|
],
|
|
[
|
|
{ kind: PropertyValueKind.string, display-string: "world" },
|
|
{ kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
|
|
{ kind: PropertyValueKind.string, display-string: "Richmond" },
|
|
{ kind: PropertyValueKind.string, display-string: "VA" },
|
|
{ kind: PropertyValueKind.string, display-string: "23219" },
|
|
{ kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" },
|
|
{ kind: PropertyValueKind.color, display-string: "#ff0000" }
|
|
]
|
|
],
|
|
};
|
|
|
|
private property <length> selection-x;
|
|
private property <length> selection-y;
|
|
|
|
private property <CellData> current-cell-data;
|
|
|
|
VerticalLayout {
|
|
HorizontalLayout {
|
|
RowMarker { }
|
|
|
|
for header in root.current-table.headers: Cell {
|
|
is-header: true;
|
|
text: header;
|
|
}
|
|
}
|
|
|
|
for data-row[row] in root.current-table.values: HorizontalLayout {
|
|
RowMarker {
|
|
value: row + 1;
|
|
hovered: ta.has-hover;
|
|
show-menu: root.current-table.is-array;
|
|
|
|
ta := TouchArea {
|
|
visible: root.current-table.is-array;
|
|
clicked => {
|
|
root.selection-x = self.x;
|
|
root.selection-y = self.y;
|
|
row_menu.row-number = row;
|
|
row_menu.show({
|
|
x:self.mouse-x + ta.absolute-position.x - row_menu.absolute-position.x,
|
|
y:self.mouse-y + ta.absolute-position.y - row_menu.absolute-position.y
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
for value[col] in data-row: Cell {
|
|
text: value.display-string;
|
|
is-writeable: true;
|
|
|
|
edit-clicked() => {
|
|
root.current-cell-data = {
|
|
property-group-id: root.property-group-id,
|
|
property-name: preview-data.name,
|
|
property-value: root.current-table.values[row][col],
|
|
row: row,
|
|
col: col,
|
|
x: self.x,
|
|
y: parent.y,
|
|
width: self.width,
|
|
height: self.height
|
|
};
|
|
ew.show();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ew := EditWindow {
|
|
x: self.current-cell-data.x > 15px ? self.current-cell-data.x - EditorSpaceSettings.default-padding - 15px : (self.current-cell-data.x + self.current-cell-data.width > root.width ? root.width - ew.width : 0); // TODO the end needs to be windowWidth - current-cell.x < current.cell.width * 2;
|
|
y: self.current-cell-data.y - EditorSpaceSettings.default-padding;
|
|
current-cell-data <=> root.current-cell-data;
|
|
current-table: root.current-table;
|
|
preview-data <=> root.preview-data;
|
|
property-container-id <=> property-group-id;
|
|
|
|
private property <string> possible-error;
|
|
|
|
function edit(new-value: string) -> bool {
|
|
self.current-table.values[self.current-cell-data.row][self.current-cell-data.col].was-edited = true;
|
|
self.current-table.values[self.current-cell-data.row][self.current-cell-data.col].edited-value = new-value;
|
|
|
|
self.possible_error = Api.set-property-value-table(root.property-group-id, root.preview-data.name, root.current-table.values, root.current-table.is-array);
|
|
StatusLineApi.help-text = self.possible-error;
|
|
if self.possible-error == "" {
|
|
TableData.populate-table(root.property-group-id, root.preview-data);
|
|
}
|
|
return self.possible-error == "";
|
|
}
|
|
|
|
test(new-value) => {
|
|
return edit(new-value);
|
|
}
|
|
|
|
save(new-value) => {
|
|
edit(new-value);
|
|
self.close-editor();
|
|
}
|
|
|
|
close-editor => {
|
|
self.close();
|
|
}
|
|
}
|
|
|
|
row_menu := ContextMenuArea {
|
|
in-out property <int> row-number;
|
|
Menu {
|
|
MenuItem {
|
|
title: "Add Row Above";
|
|
activated() => {
|
|
Api.insert-row-into-value-table(root.current_table, row_menu.row-number);
|
|
}
|
|
}
|
|
|
|
MenuItem {
|
|
title: "Add Row Below";
|
|
activated() => {
|
|
Api.insert-row-into-value-table(root.current_table, row_menu.row-number + 1);
|
|
}
|
|
}
|
|
|
|
MenuItem {
|
|
title: "Remove Row";
|
|
activated() => {
|
|
Api.remove-row-from-value-table(root.current_table, row_menu.row-number);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|