slint/tools/lsp/ui/components/spreadsheet.slint
szecket d2e839a7c4 live-preview: Use context menu
... in the spreadsheet.
2025-03-25 15:48:31 +01:00

322 lines
11 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, Button, LineEdit, CheckBox, ScrollView, VerticalBox } from "std-widgets.slint";
import { Api, ColorData, ElementInformation, PreviewData, PreviewDataKind, PropertyDeclaration, PropertyGroup, PropertyInformation, PropertyValue, PropertyValueKind, PropertyValueTable } from "../api.slint";
import { EditorSizeSettings, Icons, EditorAnimationSettings, EditorSpaceSettings, EditorSizeSettings, EditorFontSettings, EditorPalette } from "../components/styling.slint";
import { PropertyValueWidget } from "../components/property-widgets.slint";
export struct CellData {
id: string,
value: PropertyValue,
row: int,
col: int,
x: length,
y: length,
width: length,
height: length
}
export component EditWindow inherits Rectangle {
in property <CellData> current-cell;
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: self.preferred-width;
height: self.preferred-height;
background: Palette.alternate-background;
callback save(string);
callback close-editor();
HorizontalLayout {
padding: EditorSpaceSettings.default-padding;
padding-left: EditorSpaceSettings.default-padding + 15px;
spacing: EditorSpaceSettings.default-spacing;
PropertyValueWidget {
property-value: current-cell.value;
visible: true;
property-name: current-cell.id;
enabled: true;
}
}
}
component RowMarker inherits Rectangle {
in property <int> value;
in property <bool> header: false;
in property <bool> hovered;
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;
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 <CellData> cell-data;
in property <string> id;
in property <bool> is-header: false;
in property <bool> is-writeable: false;
in-out property <bool> is-editing: false;
in property <length> cell-width: 100px;
property <bool> cell-clicked: false;
in property <string> text: "";
in-out property <color> bg-color: cell-clicked ? Palette.accent-background.transparentize(0.8) : transparent;
callback edit-clicked(CellData);
width: cell-width;
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({ id: root.id, value: cell-data.value, row: 0, col: 0 });
}
}
}
export component Spreadsheet inherits ScrollView {
in property <PreviewData> preview-data: {
name: "Addresses",
has-getter: true,
has-setter: true,
kind: PreviewDataKind.Table,
};
in property <PropertyValueTable> current-table: {
is-array: true,
headers: ["type", "street", "city", "state", "zip", "favorite","color"],
values: [
[
{
kind: PropertyValueKind.string,
value-string: "home"
}, {
kind: PropertyValueKind.string,
value-string: "123 Oak Lane"
}, {
kind: PropertyValueKind.string,
value-string: "Richmond"
}, {
kind: PropertyValueKind.string,
value-string: "VA"
}, {
kind: PropertyValueKind.string,
value-string: "23226"
}, {
kind: PropertyValueKind.boolean,
value-bool: true,
value-string: "True"
}, {
kind: PropertyValueKind.color,
value-string: "#ff0000"
}
], [
{
kind: PropertyValueKind.string,
value-string: "work"
}, {
kind: PropertyValueKind.string,
value-string: "456 Corporate Blvd"
}, {
kind: PropertyValueKind.string,
value-string: "Richmond"
}, {
kind: PropertyValueKind.string,
value-string: "VA"
}, {
kind: PropertyValueKind.string,
value-string: "23219"
}, {
kind: PropertyValueKind.boolean,
value-bool: false,
value-string: "False"
}
], [
{
kind: PropertyValueKind.string,
value-string: "history"
}, {
kind: PropertyValueKind.string,
value-string: "123 Oak Lane"
}, {
kind: PropertyValueKind.string,
value-string: "Richmond"
}, {
kind: PropertyValueKind.string,
value-string: "VA"
}, {
kind: PropertyValueKind.string,
value-string: "23226"
}, {
kind: PropertyValueKind.boolean,
value-bool: false,
value-string: "False"
}, {
kind: PropertyValueKind.color,
value-string: "#aaff00"
}
], [
{
kind: PropertyValueKind.string,
value-string: "world"
}, {
kind: PropertyValueKind.string,
value-string: "456 Corporate Blvd"
}, {
kind: PropertyValueKind.string,
value-string: "Richmond"
}, {
kind: PropertyValueKind.string,
value-string: "VA"
}, {
kind: PropertyValueKind.string,
value-string: "23219"
}, {
kind: PropertyValueKind.boolean,
value-bool: false,
value-string: "False"
}, {
kind: PropertyValueKind.color,
value-string: "#ff0000"
}
]
],
};
property <CellData> current-cell;
property <bool> edit-window-visible: false;
private property <length> selection-x;
private property <length> selection-y;
public function edit-in-spreadsheet(container-name: string, preview-data: PreviewData) {
debug("Setting up Spreadsheet:", container-name, preview-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 ? true : false;
ta := TouchArea {
clicked => {
root.selection-x = self.x;
root.selection-y = self.y;
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.value-string;
is-writeable: true;
edit-clicked(data) => {
root.current-cell = {
id: data.id,
value: value, // Now passing the properly typed CellValue
row: row,
col: col,
x: self.x,
y: parent.y,
width: self.width,
height: self.height
};
root.edit-window-visible = true;
}
}
}
}
if (edit-window-visible): ew := EditWindow {
x: current-cell.x > 15px ? current-cell.x - EditorSpaceSettings.default-padding - 15px : 0; // TODO the end needs to be windowWidth - current-cell.x < current.cell.width * 2;
y: current-cell.y - EditorSpaceSettings.default-padding;
current-cell: current-cell;
save(new-value) => {
// Update the specific field based on col index
// if (current-cell.col == 0) {
// addresses[current-cell.row].type = new-value;
// } else if (current-cell.col == 1) {
// addresses[current-cell.row].street = new-value;
// } else if (current-cell.col == 2) {
// addresses[current-cell.row].city = new-value;
// } else if (current-cell.col == 3) {
// addresses[current-cell.row].state = new-value;
// } else if (current-cell.col == 4) {
// addresses[current-cell.row].zip = new-value;
// }
root.edit-window-visible = false;
}
close-editor => {
root.edit-window-visible = false;
}
}
row_menu:= ContextMenuArea {
in property <int> position;
Menu {
MenuItem {
title: "Add Row Above";
}
MenuItem {
title: "Add Row Below";
}
MenuItem {
title: "Remove Row";
}
}
}
}