live-preview data tab floating table editor (#8123)

Adds a table editor based on the color picker floating draggable panel.

This includes behaviours that keep the panel inside the bounds of the live preview window and light / dark mode.
This commit is contained in:
Nigel Breslaw 2025-04-13 14:57:50 +03:00 committed by GitHub
parent 6d01eec4db
commit 2da6bf4add
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 481 additions and 278 deletions

View file

@ -20,7 +20,7 @@ import { StringWidget } from "./widgets/string-widget.slint";
import { WindowGlobal, WindowManager } from "../windowglobal.slint"; import { WindowGlobal, WindowManager } from "../windowglobal.slint";
export component PropertyValueWidget inherits VerticalLayout { export component PropertyValueWidget inherits VerticalLayout {
in property <PropertyValue> property-value; in-out property <PropertyValue> property-value;
in property <PreviewData> preview-data; in property <PreviewData> preview-data;
in property <string> property-name; in property <string> property-name;
in property <bool> enabled; in property <bool> enabled;
@ -29,6 +29,8 @@ export component PropertyValueWidget inherits VerticalLayout {
in property <bool> strings-are-translatable: true; in property <bool> strings-are-translatable: true;
in property <string> property-container-id; in property <string> property-container-id;
callback update-display-string(value: string);
callback set-bool-binding(value: bool); callback set-bool-binding(value: bool);
callback set-color-binding(text: string); callback set-color-binding(text: string);
callback test-color-binding(text: string) -> bool; callback test-color-binding(text: string) -> bool;
@ -46,6 +48,11 @@ export component PropertyValueWidget inherits VerticalLayout {
callback reset-action(); callback reset-action();
callback code-action(); callback code-action();
function update-display-string-impl(value: string) {
self.property-value.display-string = value;
self.update-display-string(value);
}
if root.property-value.kind == PropertyValueKind.boolean: BooleanWidget { if root.property-value.kind == PropertyValueKind.boolean: BooleanWidget {
enabled <=> root.enabled; enabled <=> root.enabled;
property-name <=> root.property-name; property-name <=> root.property-name;
@ -54,6 +61,8 @@ export component PropertyValueWidget inherits VerticalLayout {
set-bool-binding(value) => { set-bool-binding(value) => {
root.set-bool-binding(value); root.set-bool-binding(value);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
} }
if root.property-value.kind == PropertyValueKind.color: ColorWidget { if root.property-value.kind == PropertyValueKind.color: ColorWidget {
@ -71,6 +80,9 @@ export component PropertyValueWidget inherits VerticalLayout {
set-color-binding(text) => { set-color-binding(text) => {
root.set-color-binding(text); root.set-color-binding(text);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => { reset-action() => {
root.reset-action(); root.reset-action();
} }
@ -94,6 +106,9 @@ export component PropertyValueWidget inherits VerticalLayout {
set-brush-binding(kind, angle, color, stops) => { set-brush-binding(kind, angle, color, stops) => {
root.set-brush-binding(kind, angle, color, stops); root.set-brush-binding(kind, angle, color, stops);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => { reset-action() => {
root.reset-action(); root.reset-action();
} }
@ -107,6 +122,8 @@ export component PropertyValueWidget inherits VerticalLayout {
property-name <=> root.property-name; property-name <=> root.property-name;
property-value <=> root.property-value; property-value <=> root.property-value;
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => { reset-action() => {
root.reset-action(); root.reset-action();
} }
@ -123,6 +140,8 @@ export component PropertyValueWidget inherits VerticalLayout {
set-enum-binding(text) => { set-enum-binding(text) => {
root.set-enum-binding(text); root.set-enum-binding(text);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
} }
if root.property-value.kind == PropertyValueKind.float: FloatWidget { if root.property-value.kind == PropertyValueKind.float: FloatWidget {
@ -136,6 +155,8 @@ export component PropertyValueWidget inherits VerticalLayout {
set-float-binding(text, unit) => { set-float-binding(text, unit) => {
root.set-float-binding(text, unit); root.set-float-binding(text, unit);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
} }
if root.property-value.kind == PropertyValueKind.integer: IntegerWidget { if root.property-value.kind == PropertyValueKind.integer: IntegerWidget {
@ -149,6 +170,8 @@ export component PropertyValueWidget inherits VerticalLayout {
set-integer-binding(text) => { set-integer-binding(text) => {
root.set-code-binding(text); root.set-code-binding(text);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
} }
if root.property-value.kind == PropertyValueKind.string: StringWidget { if root.property-value.kind == PropertyValueKind.string: StringWidget {
@ -160,18 +183,21 @@ export component PropertyValueWidget inherits VerticalLayout {
has-reset-action: root.has-reset-action; has-reset-action: root.has-reset-action;
is-translatable <=> root.strings-are-translatable; is-translatable <=> root.strings-are-translatable;
reset-action() => {
root.reset-action();
}
code-action() => {
root.code-action();
}
test-string-binding(text, is_translated) => { test-string-binding(text, is_translated) => {
return root.test-string-binding(text, is_translated); return root.test-string-binding(text, is_translated);
} }
set-string-binding(text, is_translated) => { set-string-binding(text, is_translated) => {
root.set-string-binding(text, is_translated); root.set-string-binding(text, is_translated);
} }
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => {
root.reset-action();
}
code-action() => {
root.code-action();
}
} }
} }
@ -279,7 +305,7 @@ export component PreviewDataPropertyValueWidget inherits VerticalLayout {
private property <PropertyValue> value: Api.get-property-value(root.property-container-id, root.preview-data.name); private property <PropertyValue> value: Api.get-property-value(root.property-container-id, root.preview-data.name);
private property <string> possible-error; private property <string> possible-error;
callback edit-in-spreadsheet(rp: PropertyContainer); callback edit-in-table-editor(property-group-id: string, data: PreviewData);
function reset-action() { function reset-action() {
self.set-code-binding(self.value.code); self.set-code-binding(self.value.code);
@ -347,12 +373,16 @@ export component PreviewDataPropertyValueWidget inherits VerticalLayout {
return(root.set-code-binding(is_translated ? "\"\{text}\"" : text)); return(root.set-code-binding(is_translated ? "\"\{text}\"" : text));
} }
} }
if root.preview-data.kind == PreviewDataKind.Table && false: MultiValueWidget { if root.preview-data.kind == PreviewDataKind.Table: MultiValueWidget {
edit-in-spreadsheet(property-group-name, data, values) => { property-value <=> root.value;
debug("edit-in-spreadsheet TRIGGERED: ", property-group-name, data, values); preview-data: root.preview-data;
property-group-id: root.property-container-id;
edit-in-table-editor(property-group-id, data) => {
root.edit-in-table-editor(property-group-id, data);
} }
} }
if root.preview-data.kind == PreviewDataKind.Json || (root.preview-data.kind == PreviewDataKind.Table && true): JsonWidget { if root.preview-data.kind == PreviewDataKind.Json: JsonWidget {
enabled: root.preview-data.has-setter; enabled: root.preview-data.has-setter;
property-name: root.preview-data.name; property-name: root.preview-data.name;
property-value <=> root.value; property-value <=> root.value;

View file

@ -1,31 +1,113 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // 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 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { Button } from "std-widgets.slint"; import { Button, Palette, StandardButton, ScrollView } from "std-widgets.slint";
import { EditorSpaceSettings } from "../components/styling.slint"; import { EditorSpaceSettings, EditorPalette, Icons } from "../components/styling.slint";
import { Spreadsheet } from "../components/spreadsheet.slint"; import { Spreadsheet } from "../components/spreadsheet.slint";
import { Api, PreviewData, PropertyValueTable } from "../api.slint";
import { WindowGlobal } from "../windowglobal.slint"; import { WindowGlobal, WindowManager } from "../windowglobal.slint";
import { EditorSizeSettings } from "styling.slint";
import { TableData } from "../properties-state.slint";
import { DraggablePanel } from "draggable-panel.slint";
export component SpreadsheetDialog inherits Dialog { component TableEditor inherits DraggablePanel {
width: Math.min(self.preferred-width, WindowGlobal.window-width * 0.9); property <string> property-group-id <=> TableData.property-group-id;
height: Math.min(self.preferred-height, WindowGlobal.window-height * 0.9); property <PreviewData> preview-data <=> TableData.preview-data;
property <PropertyValueTable> current-table <=> TableData.current-table;
private property <length> initial-x;
private property <length> initial-y;
title: "Edit Values"; callback close();
VerticalLayout { property <length> content-height;
Spreadsheet { property <length> content-width;
close => {
WindowManager.hide-floating-widget();
} }
HorizontalLayout { width: 240px;
alignment: end;
padding: 8px;
Button { title := Rectangle {
text: "Close"; width: 100%;
height: 40px;
Text {
text: "Edit Values";
color: EditorPalette.text-color;
}
Rectangle {
x: parent.width - self.width - 5px;
width: 25px;
height: self.width;
background: t-close.has-hover ? EditorPalette.section-color : transparent;
border-radius: EditorSizeSettings.property-border-radius;
t-close := TouchArea {
clicked => { clicked => {
root.close();
}
}
Image {
source: Icons.close;
colorize: EditorPalette.text-color;
}
}
Rectangle {
width: 100%;
height: 1px;
x: 0;
y: parent.height - self.height;
background: EditorPalette.divider-color;
}
}
Rectangle {
width: 100%;
height: root.content-height;
ScrollView {
viewport-width: spread-sheet.preferred-width;
viewport-height: spread-sheet.preferred-height;
height: 100%;
width: root.width;
spread-sheet := Spreadsheet {
init => {
root.content-height = spread-sheet.preferred-height + 4px;
root.content-width = spread-sheet.preferred-width + 2 * EditorSpaceSettings.default-padding;
root.width = Math.min(root.content-width, WindowGlobal.window-width * 0.9);
}
property-group-id <=> root.property-group-id;
preview-data <=> root.preview-data;
current-table <=> root.current-table;
} }
} }
} }
footer := Rectangle {
width: 100%;
height: EditorSizeSettings.standard-margin;
}
}
export component TableEditorView {
width: 100%;
height: 100%;
in property <length> initial-x: 0;
in property <length> initial-y: 0;
TouchArea {
changed pressed => {
WindowManager.hide-floating-widget();
}
}
table-editor := TableEditor {
x: root.initial-x;
y: root.initial-y;
} }
} }

View file

@ -1,24 +1,39 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // 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 // 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 { Palette } from "std-widgets.slint";
import { Api, ColorData, ElementInformation, PreviewData, PreviewDataKind, PropertyDeclaration, PropertyGroup, PropertyInformation, PropertyValue, PropertyValueKind, PropertyValueTable } from "../api.slint"; import { Api, PreviewData, PreviewDataKind, PropertyValue, PropertyValueKind, PropertyValueTable } from "../api.slint";
import { EditorSizeSettings, Icons, EditorAnimationSettings, EditorSpaceSettings, EditorSizeSettings, EditorFontSettings, EditorPalette } from "../components/styling.slint"; import { StatusLineApi } from "../components/status-line.slint";
import { EditorSizeSettings, Icons, EditorSpaceSettings } from "../components/styling.slint";
import { PropertyValueWidget } from "../components/property-widgets.slint"; import { PropertyValueWidget } from "../components/property-widgets.slint";
export struct CellData { export struct CellData {
id: string, property-group-id: string,
value: PropertyValue, property-name: string,
row: int, row: int,
col: int, col: int,
x: length, x: length,
y: length, y: length,
width: length, width: length,
height: 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;
content := Rectangle {
changed height => {
parent.height = self.height;
}
export component EditWindow inherits Rectangle {
in property <CellData> current-cell;
drop-shadow-blur: 10px; drop-shadow-blur: 10px;
drop-shadow-color: black.transparentize(0.5); drop-shadow-color: black.transparentize(0.5);
drop-shadow-offset-x: 0; drop-shadow-offset-x: 0;
@ -27,17 +42,69 @@ export component EditWindow inherits Rectangle {
width: self.preferred-width; width: self.preferred-width;
height: self.preferred-height; height: self.preferred-height;
background: Palette.alternate-background; background: Palette.alternate-background;
callback save(string); hl := HorizontalLayout {
callback close-editor();
HorizontalLayout {
padding: EditorSpaceSettings.default-padding; padding: EditorSpaceSettings.default-padding;
padding-left: EditorSpaceSettings.default-padding + 15px; padding-left: EditorSpaceSettings.default-padding;
spacing: EditorSpaceSettings.default-spacing; spacing: EditorSpaceSettings.default-spacing;
PropertyValueWidget { PropertyValueWidget {
property-value: current-cell.value; property-value: root.current-table.values[root.current-cell-data.row][root.current-cell-data.col];
visible: true; property-name: root.current-cell-data.property-group-id;
property-name: current-cell.id;
enabled: true; enabled: true;
changed property-value => {
root.current-table.values[root.current-cell-data.row][root.current-cell-data.col] = self.property-value;
}
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) => {
debug("set-bool-binding");
root.save(value ? "true" : "false");
}
set-color-binding(text) => {
debug("set-color-binding");
root.save("\"\{text}\"");
}
set-brush-binding(kind, angle, color, stops) => {
debug("set-brush-binding");
root.save(Api.as-json-brush(kind, angle, color, stops));
}
set-float-binding(text, _unit) => {
debug("set-float-binding");
root.save(text);
}
set-code-binding(text) => {
debug("set-code-binding");
root.save(text);
}
set-string-binding(text, is_translated) => {
debug("set-string-binding");
root.save(is_translated ? "\"\{text}\"" : text);
}
set-enum-binding(text) => {
debug("set-enum-binding");
root.save("\"\{text}\"");
}
}
} }
} }
} }
@ -47,6 +114,7 @@ component RowMarker inherits Rectangle {
in property <bool> header: false; in property <bool> header: false;
in property <bool> hovered; in property <bool> hovered;
width: 30px; width: 30px;
if (value > 0): Rectangle { if (value > 0): Rectangle {
height: 30px; height: 30px;
background: header ? transparent : Palette.alternate-background; background: header ? transparent : Palette.alternate-background;
@ -81,18 +149,20 @@ component RowMarker inherits Rectangle {
} }
component Cell inherits Rectangle { component Cell inherits Rectangle {
in property <CellData> cell-data; in property <PropertyValue> property-value;
in property <string> id;
in property <bool> is-header: false; in property <bool> is-header: false;
in property <bool> is-writeable: 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; 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; height: 30px;
border-width: 1px; border-width: 1px;
border-color: Palette.border; border-color: Palette.border;
@ -116,128 +186,56 @@ component Cell inherits Rectangle {
if is-writeable: TouchArea { if is-writeable: TouchArea {
clicked => { clicked => {
root.edit-clicked({ id: root.id, value: cell-data.value, row: 0, col: 0 }); root.edit-clicked();
} }
} }
} }
export component Spreadsheet inherits ScrollView { export component Spreadsheet {
in property <string> property-group-id;
in property <PreviewData> preview-data: { in property <PreviewData> preview-data: {
name: "Addresses", name: "Addresses",
has-getter: true, has-getter: true,
has-setter: true, has-setter: true,
kind: PreviewDataKind.Table, kind: PreviewDataKind.Table,
}; };
in property <PropertyValueTable> current-table: { in-out property <PropertyValueTable> current-table: {
is-array: true, is-array: true,
headers: ["type", "street", "city", "state", "zip", "favorite","color"], headers: ["type", "street", "city", "state", "zip", "favorite", "color"],
values: [ values: [
[ [
{ { kind: PropertyValueKind.string, display-string: "home" },
kind: PropertyValueKind.string, { kind: PropertyValueKind.string, display-string: "123 Oak Lane" },
value-string: "home" { kind: PropertyValueKind.string, display-string: "Richmond" },
}, { { kind: PropertyValueKind.string, display-string: "VA" },
kind: PropertyValueKind.string, { kind: PropertyValueKind.string, display-string: "23226" },
value-string: "123 Oak Lane" { kind: PropertyValueKind.boolean, value-bool: true, display-string: "true" },
}, { { kind: PropertyValueKind.color, display-string: "#ff0000" }
kind: PropertyValueKind.string, ],
value-string: "Richmond" [
}, { { kind: PropertyValueKind.string, display-string: "work" },
kind: PropertyValueKind.string, { kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
value-string: "VA" { kind: PropertyValueKind.string, display-string: "Richmond" },
}, { { kind: PropertyValueKind.string, display-string: "VA" },
kind: PropertyValueKind.string, { kind: PropertyValueKind.string, display-string: "23219" },
value-string: "23226" { kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" }
}, { ],
kind: PropertyValueKind.boolean, [
value-bool: true, { kind: PropertyValueKind.string, display-string: "world" },
value-string: "True" { kind: PropertyValueKind.string, display-string: "456 Corporate Blvd" },
}, { { kind: PropertyValueKind.string, display-string: "Richmond" },
kind: PropertyValueKind.color, { kind: PropertyValueKind.string, display-string: "VA" },
value-string: "#ff0000" { kind: PropertyValueKind.string, display-string: "23219" },
} { kind: PropertyValueKind.boolean, value-bool: false, display-string: "false" },
], [ { kind: PropertyValueKind.color, display-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-x;
private property <length> selection-y; private property <length> selection-y;
public function edit-in-spreadsheet(container-name: string, preview-data: PreviewData) { private property <CellData> current-cell-data;
debug("Setting up Spreadsheet:", container-name, preview-data);
}
VerticalLayout { VerticalLayout {
HorizontalLayout { HorizontalLayout {
@ -252,23 +250,31 @@ export component Spreadsheet inherits ScrollView {
for data-row[row] in root.current-table.values: HorizontalLayout { for data-row[row] in root.current-table.values: HorizontalLayout {
RowMarker { RowMarker {
value: row + 1; value: row + 1;
hovered: ta.has-hover ? true : false; hovered: ta.has-hover;
ta := TouchArea { ta := TouchArea {
clicked => { clicked => {
root.selection-x = self.x; root.selection-x = self.x;
root.selection-y = self.y; 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});
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 { for value[col] in data-row: Cell {
text: value.value-string; text: value.display-string;
is-writeable: true; is-writeable: true;
edit-clicked(data) => {
root.current-cell = { edit-clicked() => {
id: data.id, root.current-cell-data = {
value: value, // Now passing the properly typed CellValue property-group-id: root.property-group-id,
property-name: preview-data.name,
property-value: root.current-table.values[row][col],
row: row, row: row,
col: col, col: col,
x: self.x, x: self.x,
@ -276,46 +282,69 @@ export component Spreadsheet inherits ScrollView {
width: self.width, width: self.width,
height: self.height height: self.height
}; };
root.edit-window-visible = true; ew.show();
} }
} }
} }
} }
if (edit-window-visible): ew := EditWindow { 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; 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: current-cell.y - EditorSpaceSettings.default-padding; y: self.current-cell-data.y - EditorSpaceSettings.default-padding;
current-cell: current-cell; current-cell-data <=> root.current-cell-data;
current-table: root.current-table;
private property <string> possible-error;
function edit(new-value: string) -> bool {
debug("EW: edit(...): Model has \{root.current-table.values.length} rows");
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;
return self.possible-error == "";
}
test(new-value) => {
return edit(new-value);
}
save(new-value) => { save(new-value) => {
// Update the specific field based on col index edit(new-value);
// if (current-cell.col == 0) { self.close-editor();
// 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 => { close-editor => {
root.edit-window-visible = false; debug("EW: Received close-editor");
self.close();
} }
} }
row_menu:= ContextMenuArea {
in property <int> position; row_menu := ContextMenuArea {
in-out property <int> row-number;
Menu { Menu {
MenuItem { MenuItem {
title: "Add Row Above"; title: "Add Row Above";
activated() => {
Api.insert-row-into-value-table(root.current_table, row_menu.row-number);
} }
}
MenuItem { MenuItem {
title: "Add Row Below"; title: "Add Row Below";
activated() => {
Api.insert-row-into-value-table(root.current_table, row_menu.row-number + 1);
} }
}
MenuItem { MenuItem {
title: "Remove Row"; title: "Remove Row";
activated() => {
Api.remove-row-from-value-table(root.current_table, row_menu.row-number);
}
} }
} }
} }

View file

@ -62,6 +62,9 @@ export global EditorSizeSettings {
in property <length> property-bar-width: 360px; in property <length> property-bar-width: 360px;
in property <length> radius: 5px; in property <length> radius: 5px;
in property <length> side-bar-width: 280px; in property <length> side-bar-width: 280px;
out property <length> standard-margin: 16px;
out property <length> small-margin: 12px;
out property <length> property-border-radius: 5px;
} }
export global EditorPalette { export global EditorPalette {
@ -78,10 +81,13 @@ export global EditorPalette {
out property <brush> interactive-element-selection-secondary: #48dc2a; out property <brush> interactive-element-selection-secondary: #48dc2a;
out property <brush> layout-element-selection-primary: #FFC5FC; out property <brush> layout-element-selection-primary: #FFC5FC;
out property <brush> layout-element-selection-secondary: #ff8af9; out property <brush> layout-element-selection-secondary: #ff8af9;
out property <brush> shadow-gradient: @linear-gradient(0deg, Palette.foreground.transparentize(1),Palette.foreground.transparentize(0.75)); out property <brush> shadow-gradient: @linear-gradient(0deg, Palette.foreground.transparentize(1), Palette.foreground.transparentize(0.75));
out property <brush> state-hovered: root.dark-color-scheme ? #ffffff.with-alpha(0.1) : #000000.with-alpha(0.1); out property <brush> state-hovered: root.dark-color-scheme ? #ffffff.with-alpha(0.1) : #000000.with-alpha(0.1);
out property <brush> state-pressed: root.dark-color-scheme ? #ffffff.with-alpha(0.2) : #000000.with-alpha(0.2); out property <brush> state-pressed: root.dark-color-scheme ? #ffffff.with-alpha(0.2) : #000000.with-alpha(0.2);
out property <color> text-color: Palette.color-scheme == ColorScheme.dark ? white : #383838;
out property <color> section-color: Palette.color-scheme == ColorScheme.dark ? #3f3f3f : #f5f5f5;
out property <color> divider-color: Palette.color-scheme == ColorScheme.dark ? #444444 : #e6e6e6;
} }
export global EditorAnimationSettings { export global EditorAnimationSettings {

View file

@ -11,9 +11,10 @@ import { CheckBox } from "std-widgets.slint";
export component BooleanWidget inherits GridLayout { export component BooleanWidget inherits GridLayout {
in property <bool> enabled; in property <bool> enabled;
in property <string> property-name; in property <string> property-name;
in property <PropertyValue> property-value; in-out property <PropertyValue> property-value;
callback set-bool-binding(value: bool); callback set-bool-binding(value: bool);
callback update-display-string(value: string);
spacing-vertical: EditorSpaceSettings.default-spacing; spacing-vertical: EditorSpaceSettings.default-spacing;
width: 100%; width: 100%;
@ -36,10 +37,18 @@ export component BooleanWidget inherits GridLayout {
checkbox := CheckBox { checkbox := CheckBox {
enabled: root.enabled; enabled: root.enabled;
checked: root.property-value.value-bool; checked: root.property-value.value-bool;
text: self.checked ? "True" : "False"; text: self.display-string();
function display-string() -> string {
return self.checked ? "true" : "false";
}
toggled() => { toggled() => {
root.property-value.value-bool = self.checked;
debug("property-value is now:", root.property-value.value-bool);
root.set-bool-binding(self.checked); root.set-bool-binding(self.checked);
root.update-display-string(self.display-string());
} }
} }
} }

View file

@ -23,9 +23,16 @@ export component BrushWidget inherits GridLayout {
callback code-action(); callback code-action();
callback reset-action(); callback reset-action();
callback update-display-string(value: string);
callback test-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> bool; callback test-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) -> bool;
callback set-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]); callback set-brush-binding(kind: BrushKind, angle: float, color: color, stops: [GradientStop]);
function set-brush-binding_impl(kind: BrushKind, angle: float, color: color, stops: [GradientStop]) {
self.update-display-string(kind == BrushKind.solid ? "Solid Color" : kind == BrushKind.linear ? "Linear Gradient" : "Radial Gradient");
self.set-brush-binding(kind, angle, color, stops);
}
private property <color> current-color; private property <color> current-color;
private property <brush> current-brush; private property <brush> current-brush;
private property <[GradientStop]> current-gradient-stops; private property <[GradientStop]> current-gradient-stops;
@ -71,7 +78,7 @@ export component BrushWidget inherits GridLayout {
function set-color(text: string) { function set-color(text: string) {
root.current-color = Api.string-to-color(text); root.current-color = Api.string-to-color(text);
root.set-brush-binding(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops); root.set-brush-binding-impl(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops);
} }
@ -122,7 +129,7 @@ export component BrushWidget inherits GridLayout {
// enabled <=> root.enabled; // enabled <=> root.enabled;
set-color-binding(text) => { set-color-binding(text) => {
root.set-brush-binding(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops); root.set-brush-binding-impl(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops);
} }
test-color-binding(text) => { test-color-binding(text) => {
return root.test-brush-binding(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops); return root.test-brush-binding(root.current-brush-kind, root.current-angle, root.current-color, root.current-gradient-stops);
@ -152,6 +159,5 @@ export component BrushWidget inherits GridLayout {
} }
} }
} }
} }

View file

@ -11,6 +11,8 @@ export component CodeWidget inherits GridLayout {
in property <string> property-name; in property <string> property-name;
in property <PropertyValue> property-value; in property <PropertyValue> property-value;
callback update-display-string(value: string);
callback code-action(); callback code-action();
callback reset-action(); callback reset-action();

View file

@ -26,6 +26,9 @@ export component ColorWidget inherits VerticalLayout {
padding-left: 16px; padding-left: 16px;
spacing: EditorSpaceSettings.default-spacing; spacing: EditorSpaceSettings.default-spacing;
callback update-display-string(value: string);
width: 100%; width: 100%;
function apply-value() { function apply-value() {
@ -73,6 +76,7 @@ export component ColorWidget inherits VerticalLayout {
set-color-binding(text) => { set-color-binding(text) => {
root.set-color-binding(text); root.set-color-binding(text);
} }
test-color-binding(text) => { test-color-binding(text) => {
return root.test-color-binding(text); return root.test-color-binding(text);
} }

View file

@ -19,6 +19,8 @@ export component EnumWidget inherits GridLayout {
} }
} }
callback update-display-string(value: string);
callback set-enum-binding(text: string); callback set-enum-binding(text: string);
spacing-vertical: EditorSpaceSettings.default-spacing; spacing-vertical: EditorSpaceSettings.default-spacing;
@ -46,6 +48,7 @@ export component EnumWidget inherits GridLayout {
model: root.property-value.visual-items; model: root.property-value.visual-items;
selected(value) => { selected(value) => {
root.update-display-string(property-value.value-string + "." + value);
root.set-enum-binding(property-value.value-string + "." + value); root.set-enum-binding(property-value.value-string + "." + value);
} }
} }

View file

@ -13,6 +13,8 @@ export component FloatWidget inherits GridLayout {
in property <string> property-name; in property <string> property-name;
in property <PropertyValue> property-value; in property <PropertyValue> property-value;
callback update-display-string(value: string);
callback test-float-binding(text: string, unit: string) -> bool; callback test-float-binding(text: string, unit: string) -> bool;
callback set-float-binding(text: string, unit: string); callback set-float-binding(text: string, unit: string);
@ -30,6 +32,9 @@ export component FloatWidget inherits GridLayout {
} }
function set-binding() { function set-binding() {
if number.text != "" {
root.update-display-string("\{number.text}\{self.current-unit}");
}
root.set-float-binding(number.text == "" ? "" : number.text, self.current-unit); root.set-float-binding(number.text == "" ? "" : number.text, self.current-unit);
} }

View file

@ -4,20 +4,12 @@
import { Palette, Button, ComboBox } from "std-widgets.slint"; import { Palette, Button, ComboBox } from "std-widgets.slint";
import { WindowGlobal, WindowManager } from "../../windowglobal.slint"; import { WindowGlobal, WindowManager } from "../../windowglobal.slint";
import { Api, GradientStop } from "../../api.slint"; import { Api, GradientStop } from "../../api.slint";
import { Icons } from "../../components/styling.slint"; import { Icons, EditorPalette, EditorSizeSettings } from "../../components/styling.slint";
import { BrushMode, PickerData, PickerMode, WidgetMode } from "../../properties-state.slint"; import { BrushMode, PickerData, PickerMode, WidgetMode } from "../../properties-state.slint";
import { SimpleColumn } from "../../components/layout-helpers.slint"; import { SimpleColumn } from "../../components/layout-helpers.slint";
import { DraggablePanel } from "../../components/draggable-panel.slint"; import { DraggablePanel } from "../../components/draggable-panel.slint";
export global Styles { export global Styles {
out property <color> section-color: Palette.color-scheme == ColorScheme.dark ? #3f3f3f : #f5f5f5;
out property <color> text-color: Palette.color-scheme == ColorScheme.dark ? white : #383838;
out property <color> divider-color: Palette.color-scheme == ColorScheme.dark ? #444444 : #e6e6e6;
out property <color> background-color: Palette.color-scheme == ColorScheme.dark ? #2c2c2c : white;
out property <brush> picker-border-color: Palette.color-scheme == ColorScheme.dark ? #ffffff17 : transparent;
out property <length> standard-margin: 16px;
out property <length> small-margin: 12px;
out property <length> property-border-radius: 5px;
out property <length> picker-width: 240px; out property <length> picker-width: 240px;
} }
@ -101,7 +93,7 @@ component BrushTypeSelector {
in-out property <BrushMode> brush-mode: color; in-out property <BrushMode> brush-mode: color;
HorizontalLayout { HorizontalLayout {
padding-left: Styles.small-margin; padding-left: EditorSizeSettings.small-margin;
alignment: start; alignment: start;
Rectangle { Rectangle {
@ -113,8 +105,8 @@ component BrushTypeSelector {
Rectangle { Rectangle {
visible: is-active; visible: is-active;
background: Styles.section-color; background: EditorPalette.section-color;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
} }
TouchArea { TouchArea {
@ -152,8 +144,8 @@ component BrushTypeSelector {
Rectangle { Rectangle {
visible: is-active; visible: is-active;
background: Styles.section-color; background: EditorPalette.section-color;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
} }
TouchArea { TouchArea {
@ -190,8 +182,8 @@ component BrushTypeSelector {
Rectangle { Rectangle {
visible: is-active; visible: is-active;
background: Styles.section-color; background: EditorPalette.section-color;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
} }
TouchArea { TouchArea {
@ -230,11 +222,11 @@ component ColorModeColorAndApply {
alignment: center; alignment: center;
spacing: 10px; spacing: 10px;
Rectangle { Rectangle {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
width: 170px; width: 170px;
height: 25px; height: 25px;
background: Styles.section-color; background: EditorPalette.section-color;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
border-width: 1px; border-width: 1px;
Rectangle { Rectangle {
@ -259,7 +251,7 @@ component ColorModeColorAndApply {
x: 35px; x: 35px;
font-family: "Inter"; font-family: "Inter";
font-size: 12px; font-size: 12px;
color: Styles.text-color; color: EditorPalette.text-color;
text: Api.color-to-data(PickerData.current-color).short-text.to-uppercase(); text: Api.color-to-data(PickerData.current-color).short-text.to-uppercase();
letter-spacing: 0.8px; letter-spacing: 0.8px;
} }
@ -268,7 +260,7 @@ component ColorModeColorAndApply {
x: parent.width - 45px; x: parent.width - 45px;
width: 1px; width: 1px;
height: parent.height; height: parent.height;
background: Styles.background-color; background: Palette.background;
} }
Rectangle { Rectangle {
@ -283,7 +275,7 @@ component ColorModeColorAndApply {
horizontal-alignment: left; horizontal-alignment: left;
font-family: "Inter"; font-family: "Inter";
font-size: 12px; font-size: 12px;
color: Styles.text-color; color: EditorPalette.text-color;
text: PickerData.alpha; text: PickerData.alpha;
text-cursor-width: 2px; text-cursor-width: 2px;
selection-background-color: #3984ec; selection-background-color: #3984ec;
@ -337,7 +329,7 @@ component ColorModeColorAndApply {
} }
if widget-mode == WidgetMode.edit: Button { if widget-mode == WidgetMode.edit: Button {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
width: 100px; width: 100px;
text: "Apply"; text: "Apply";
clicked => { clicked => {
@ -349,7 +341,7 @@ component ColorModeColorAndApply {
component VerticalSpacer { component VerticalSpacer {
width: 100%; width: 100%;
height: Styles.small-margin; height: EditorSizeSettings.small-margin;
} }
component GradientSlider { component GradientSlider {
@ -366,7 +358,7 @@ component GradientSlider {
Rectangle { Rectangle {
width: 24px; width: 24px;
height: self.width; height: self.width;
background: Styles.section-color; background: EditorPalette.section-color;
border-radius: 5px; border-radius: 5px;
TouchArea { TouchArea {
@ -391,7 +383,7 @@ component GradientSlider {
width: 10px; width: 10px;
rotation-angle: 45deg; rotation-angle: 45deg;
source: Icons.black-square; source: Icons.black-square;
colorize: Styles.section-color; colorize: EditorPalette.section-color;
} }
} }
@ -409,10 +401,10 @@ component GradientStopValue {
height: 30px; height: 30px;
Rectangle { Rectangle {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
width: 48px; width: 48px;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
background: Styles.section-color; background: EditorPalette.section-color;
TextInput { TextInput {
x: 10px; x: 10px;
height: 15px; height: 15px;
@ -420,7 +412,7 @@ component GradientStopValue {
horizontal-alignment: left; horizontal-alignment: left;
font-family: "Inter"; font-family: "Inter";
font-size: 12px; font-size: 12px;
color: Styles.text-color; color: EditorPalette.text-color;
text: (PickerData.current-gradient-stops[stop-index].position * 100.0).round(); text: (PickerData.current-gradient-stops[stop-index].position * 100.0).round();
text-cursor-width: 2px; text-cursor-width: 2px;
selection-background-color: #3984ec; selection-background-color: #3984ec;
@ -476,8 +468,8 @@ component GradientStopValue {
Rectangle { Rectangle {
x: 70px; x: 70px;
width: 140px; width: 140px;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
background: Styles.section-color; background: EditorPalette.section-color;
ColorIndicator { ColorIndicator {
x: 5px; x: 5px;
@ -498,7 +490,7 @@ component GradientStopValue {
x: 35px; x: 35px;
font-family: "Inter"; font-family: "Inter";
font-size: 12px; font-size: 12px;
color: Styles.text-color; color: EditorPalette.text-color;
text: Api.color-to-data(PickerData.current-gradient-stops[stop-index].color).short-text.to-uppercase(); text: Api.color-to-data(PickerData.current-gradient-stops[stop-index].color).short-text.to-uppercase();
letter-spacing: 0.8px; letter-spacing: 0.8px;
} }
@ -507,7 +499,7 @@ component GradientStopValue {
x: parent.width - 45px; x: parent.width - 45px;
width: 1px; width: 1px;
height: parent.height; height: parent.height;
background: Styles.background-color; background: Palette.background;
} }
Rectangle { Rectangle {
@ -520,7 +512,7 @@ component GradientStopValue {
horizontal-alignment: left; horizontal-alignment: left;
font-family: "Inter"; font-family: "Inter";
font-size: 12px; font-size: 12px;
color: Styles.text-color; color: EditorPalette.text-color;
text: (PickerData.current-gradient-stops[stop-index].color.to-hsv().alpha * 100.0).round(); text: (PickerData.current-gradient-stops[stop-index].color.to-hsv().alpha * 100.0).round();
text-cursor-width: 2px; text-cursor-width: 2px;
selection-background-color: #3984ec; selection-background-color: #3984ec;
@ -580,8 +572,8 @@ component GradientPicker inherits SimpleColumn {
height: 50px; height: 50px;
ComboBox { ComboBox {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
y: Styles.standard-margin; y: EditorSizeSettings.standard-margin;
model: ["Linear", "Radial"]; model: ["Linear", "Radial"];
current-value: "Linear"; current-value: "Linear";
} }
@ -591,11 +583,11 @@ component GradientPicker inherits SimpleColumn {
height: 80px; height: 80px;
Rectangle { Rectangle {
width: parent.width - (Styles.standard-margin * 2); width: parent.width - (EditorSizeSettings.standard-margin * 2);
height: 30px; height: 30px;
Rectangle { Rectangle {
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
clip: true; clip: true;
background: white; background: white;
@ -618,7 +610,7 @@ component GradientPicker inherits SimpleColumn {
Rectangle { Rectangle {
border-radius: parent.border-radius; border-radius: parent.border-radius;
border-width: 1px; border-width: 1px;
border-color: Styles.text-color.with-alpha(10%); border-color: EditorPalette.text-color.with-alpha(10%);
} }
} }
@ -635,9 +627,9 @@ component GradientPicker inherits SimpleColumn {
Rectangle { Rectangle {
height: 50px; height: 50px;
Text { Text {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
y: Styles.standard-margin; y: EditorSizeSettings.standard-margin;
color: Styles.text-color; color: EditorPalette.text-color;
text: "Stops"; text: "Stops";
font-family: "Inter"; font-family: "Inter";
font-size: 11px; font-size: 11px;
@ -648,14 +640,14 @@ component GradientPicker inherits SimpleColumn {
y: 10px; y: 10px;
width: 25px; width: 25px;
height: self.width; height: self.width;
background: t-plus.has-hover ? Styles.section-color : transparent; background: t-plus.has-hover ? EditorPalette.section-color : transparent;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
t-plus := TouchArea { } t-plus := TouchArea { }
Image { Image {
source: Icons.plus; source: Icons.plus;
colorize: Styles.text-color; colorize: EditorPalette.text-color;
} }
} }
} }
@ -672,8 +664,8 @@ component HsvPicker inherits SimpleColumn {
saturation-value-holder := Rectangle { saturation-value-holder := Rectangle {
height: self.width * 0.75; height: self.width * 0.75;
saturation-value := Rectangle { saturation-value := Rectangle {
width: parent.width - (Styles.standard-margin * 2); width: parent.width - (EditorSizeSettings.standard-margin * 2);
height: parent.height - (Styles.standard-margin * 2); height: parent.height - (EditorSizeSettings.standard-margin * 2);
Rectangle { Rectangle {
border-radius: 6px; border-radius: 6px;
@ -693,7 +685,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle { Rectangle {
border-radius: parent.border-radius; border-radius: parent.border-radius;
border-width: 1px; border-width: 1px;
border-color: Styles.text-color.with-alpha(10%); border-color: EditorPalette.text-color.with-alpha(10%);
} }
TouchArea { TouchArea {
@ -743,7 +735,7 @@ component HsvPicker inherits SimpleColumn {
// The following properties are used to size the hue picker and control the // The following properties are used to size the hue picker and control the
// thumb to now go past the visual bounds. But the TouchArea is intentionally larger // thumb to now go past the visual bounds. But the TouchArea is intentionally larger
// to be usable. // to be usable.
property <length> main-width: root.width - (Styles.standard-margin * 2) - main-height; property <length> main-width: root.width - (EditorSizeSettings.standard-margin * 2) - main-height;
property <length> main-height: 16px; property <length> main-height: 16px;
property <length> rounded-end-width: main-height / 2; property <length> rounded-end-width: main-height / 2;
VerticalLayout { VerticalLayout {
@ -752,8 +744,8 @@ component HsvPicker inherits SimpleColumn {
width: 100%; width: 100%;
height: 16px; height: 16px;
hue-picker := Rectangle { hue-picker := Rectangle {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
width: root.width - (Styles.standard-margin * 2); width: root.width - (EditorSizeSettings.standard-margin * 2);
height: main-height; height: main-height;
TouchArea { TouchArea {
moved => { moved => {
@ -800,7 +792,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle { Rectangle {
border-radius: parent.border-radius; border-radius: parent.border-radius;
border-width: 1px; border-width: 1px;
border-color: Styles.text-color; border-color: EditorPalette.text-color;
opacity: 10%; opacity: 10%;
} }
} }
@ -833,7 +825,7 @@ component HsvPicker inherits SimpleColumn {
width: 100%; width: 100%;
height: 16px; height: 16px;
Rectangle { Rectangle {
x: Styles.standard-margin; x: EditorSizeSettings.standard-margin;
width: main-width + main-height; width: main-width + main-height;
height: main-height; height: main-height;
Rectangle { Rectangle {
@ -893,7 +885,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle { Rectangle {
border-radius: parent.border-radius; border-radius: parent.border-radius;
border-width: 1px; border-width: 1px;
border-color: Styles.text-color; border-color: EditorPalette.text-color;
opacity: 10%; opacity: 10%;
} }
} }
@ -947,7 +939,7 @@ component HsvPicker inherits SimpleColumn {
height: 1px; height: 1px;
x: 0; x: 0;
y: parent.height - self.height; y: parent.height - self.height;
background: Styles.divider-color; background: EditorPalette.divider-color;
} }
} }
} }
@ -980,14 +972,14 @@ component ColorPicker inherits DraggablePanel {
x: parent.width - self.width - 5px; x: parent.width - self.width - 5px;
width: 25px; width: 25px;
height: self.width; height: self.width;
background: t-close.has-hover ? Styles.section-color : transparent; background: t-close.has-hover ? EditorPalette.section-color : transparent;
border-radius: Styles.property-border-radius; border-radius: EditorSizeSettings.property-border-radius;
t-close := TouchArea { } t-close := TouchArea { }
Image { Image {
source: Icons.close; source: Icons.close;
colorize: Styles.text-color; colorize: EditorPalette.text-color;
} }
} }
@ -996,7 +988,7 @@ component ColorPicker inherits DraggablePanel {
height: 1px; height: 1px;
x: 0; x: 0;
y: parent.height - self.height; y: parent.height - self.height;
background: Styles.divider-color; background: EditorPalette.divider-color;
} }
} }
@ -1012,7 +1004,7 @@ component ColorPicker inherits DraggablePanel {
footer := Rectangle { footer := Rectangle {
width: 100%; width: 100%;
height: Styles.standard-margin; height: EditorSizeSettings.standard-margin;
} }
} }

View file

@ -11,6 +11,8 @@ export component IntegerWidget inherits GridLayout {
in property <string> property-name; in property <string> property-name;
in property <PropertyValue> property-value; in property <PropertyValue> property-value;
callback update-display-string(value: string);
callback test-integer-binding(text: string) -> bool; callback test-integer-binding(text: string) -> bool;
callback set-integer-binding(text: string); callback set-integer-binding(text: string);
@ -44,7 +46,8 @@ export component IntegerWidget inherits GridLayout {
} }
accepted(text) => { accepted(text) => {
set-integer-binding(text); root.update-display-string(text);
root.set-integer-binding(text);
} }
} }
} }

View file

@ -10,12 +10,12 @@ import { Button } from "std-widgets.slint";
export component MultiValueWidget inherits GridLayout { export component MultiValueWidget inherits GridLayout {
in property <bool> enabled; in property <bool> enabled;
in property <string> property-name; in property <string> property-name: preview-data.name;
in property <PropertyValue> property-value; in property <PropertyValue> property-value;
in property <PreviewData> preview-data; in property <PreviewData> preview-data;
in property <string> property-group-name; in property <string> property-group-id;
callback edit-in-spreadsheet(property-group-name: string, data: PreviewData, values: [[PropertyValue]]); callback edit-in-table-editor(property-group-id: string, data: PreviewData);
spacing-vertical: EditorSpaceSettings.default-spacing; spacing-vertical: EditorSpaceSettings.default-spacing;
width: 100%; width: 100%;
@ -37,7 +37,7 @@ export component MultiValueWidget inherits GridLayout {
Button { Button {
text: preview-data.has-setter ? @tr("Edit") : @tr("View"); text: preview-data.has-setter ? @tr("Edit") : @tr("View");
clicked => { clicked => {
root.edit-in-spreadsheet(root.property-group-name, root.preview-data, [[ ]]); root.edit-in-table-editor(root.property-group-id, root.preview-data);
} }
} }
} }

View file

@ -26,6 +26,8 @@ export component StringWidget inherits GridLayout {
private property <bool> is-translated; private property <bool> is-translated;
private property <string> tr-context-value; private property <string> tr-context-value;
callback update-display-string(value: string);
callback code-action(); callback code-action();
callback reset-action(); callback reset-action();
@ -36,6 +38,7 @@ export component StringWidget inherits GridLayout {
return test-string-binding(Api.string-to-code(text-rle.text, self.is-translated, self.tr-context-value, "", ""), self.is-translated); return test-string-binding(Api.string-to-code(text-rle.text, self.is-translated, self.tr-context-value, "", ""), self.is-translated);
} }
function ssb() { function ssb() {
update-display-string("\"\{text-rle.text}\"");
set-string-binding(Api.string-to-code(text-rle.text, self.is-translated, self.tr-context-value, "", ""), self.is-translated); set-string-binding(Api.string-to-code(text-rle.text, self.is-translated, self.tr-context-value, "", ""), self.is-translated);
} }

View file

@ -14,10 +14,9 @@ import { DrawAreaMode, PreviewView } from "./views/preview-view.slint";
import { OutOfDateBox } from "./components/out-of-date-box.slint"; import { OutOfDateBox } from "./components/out-of-date-box.slint";
import { PropertyView } from "./views/property-view.slint"; import { PropertyView } from "./views/property-view.slint";
import { PreviewDataView } from "./views/preview-data-view.slint"; import { PreviewDataView } from "./views/preview-data-view.slint";
import { SpreadsheetDialog } from "./components/spreadsheet-dialog.slint";
import { WindowGlobal, WindowManager } from "windowglobal.slint"; import { WindowGlobal, WindowManager } from "windowglobal.slint";
import { ColorPickerView, Styles as PickerStyles } from "components/widgets/floating-color-picker-widget.slint"; import { ColorPickerView, Styles as PickerStyles } from "components/widgets/floating-color-picker-widget.slint";
import { TableEditorView } from "components/spreadsheet-dialog.slint";
import "./assets/Inter-VariableFont.ttf"; import "./assets/Inter-VariableFont.ttf";
export { Api } export { Api }
@ -34,6 +33,7 @@ export component PreviewUi inherits Window {
property <bool> show-left-sidebar; property <bool> show-left-sidebar;
property <bool> show-right-sidebar; property <bool> show-right-sidebar;
property <bool> show-floating-widget <=> WindowManager.showing-color-picker; property <bool> show-floating-widget <=> WindowManager.showing-color-picker;
property <bool> show-floating-table-editor <=> WindowManager.showing-table-editor;
property <length> initial-floating-x; property <length> initial-floating-x;
title: "Slint Live-Preview"; title: "Slint Live-Preview";
@ -148,6 +148,13 @@ export component PreviewUi inherits Window {
y: (parent.height / 10); y: (parent.height / 10);
} }
if show-floating-table-editor: TableEditorView {
init => {
self.initial-x = root.initial-floating-x;
self.initial-y = 50px;
}
}
if show-floating-widget: ColorPickerView { if show-floating-widget: ColorPickerView {
init => { init => {

View file

@ -1,7 +1,7 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // 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 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { GradientStop } from "./api.slint"; import { Api, GradientStop, PreviewData, PropertyValueTable } from "./api.slint";
export enum WidgetMode { edit, preview } export enum WidgetMode { edit, preview }
@ -27,3 +27,16 @@ export global PickerData {
in-out property <[GradientStop]> current-gradient-stops; in-out property <[GradientStop]> current-gradient-stops;
in-out property <float> current-angle; in-out property <float> current-angle;
} }
export global TableData {
callback populate-table(property-group-id: string, preview-data: PreviewData);
out property <string> property-group-id;
out property <PreviewData> preview-data;
out property <PropertyValueTable> current-table;
populate-table(property-group-id, preview-data) => {
self.property-group-id = property-group-id;
self.preview-data = preview-data;
self.current-table = Api.get-property-value-table(property-group-id, preview-data.name);
}
}

View file

@ -3,10 +3,11 @@
import { Palette, ScrollView, VerticalBox } from "std-widgets.slint"; import { Palette, ScrollView, VerticalBox } from "std-widgets.slint";
import { Api, PropertyContainer } from "../api.slint"; import { Api, PropertyContainer, PreviewData } from "../api.slint";
import { ExpandableGroup } from "../components/expandable-group.slint"; import { ExpandableGroup } from "../components/expandable-group.slint";
import { PreviewDataPropertyValueWidget } from "../components/property-widgets.slint"; import { PreviewDataPropertyValueWidget } from "../components/property-widgets.slint";
import { EditorSpaceSettings } from "../components/styling.slint"; import { EditorSpaceSettings } from "../components/styling.slint";
import { WindowManager } from "../windowglobal.slint";
export component PreviewDataView inherits ScrollView { export component PreviewDataView inherits ScrollView {
@ -45,6 +46,9 @@ export component PreviewDataView inherits ScrollView {
for p in ep.properties: PreviewDataPropertyValueWidget { for p in ep.properties: PreviewDataPropertyValueWidget {
preview-data: p; preview-data: p;
property-container-id: ep.container-id; property-container-id: ep.container-id;
edit-in-table-editor(property-group-id, data) => {
WindowManager.show-floating-table-editor(property-group-id, data);
}
} }
} }
} }

View file

@ -1,12 +1,9 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // 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 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
import { Api, BrushKind, ColorData, ElementInformation, GradientStop, PropertyInformation, PropertyValue, PropertyValueKind, PreviewData } from "./api.slint"; import { Api, BrushKind, ColorData, ElementInformation, GradientStop, PropertyInformation, PropertyValue, PropertyValueKind, PreviewData } from "./api.slint";
import { StatusLineApi } from "components/status-line.slint"; import { StatusLineApi } from "components/status-line.slint";
import { BrushMode, PickerData, PickerMode, WidgetMode } from "./properties-state.slint"; import { BrushMode, PickerData, PickerMode, WidgetMode } from "./properties-state.slint";
import { TableData } from "properties-state.slint";
export global WindowGlobal { export global WindowGlobal {
in-out property <length> window-width; in-out property <length> window-width;
@ -15,19 +12,22 @@ export global WindowGlobal {
export global WindowManager { export global WindowManager {
out property <bool> showing-color-picker: false; out property <bool> showing-color-picker: false;
out property <bool> showing-table-editor: false;
out property <WidgetMode> widget-mode: edit; out property <WidgetMode> widget-mode: edit;
out property <PickerMode> picker-mode: color; out property <PickerMode> picker-mode: color;
out property <BrushMode> brush-mode: color; out property <BrushMode> brush-mode: color;
property <ElementInformation> current-element-information; property <ElementInformation> current-element-information;
out property <PropertyInformation> current-property-information; out property <PropertyInformation> current-property-information;
property <string> current-property-container-id; in-out property <string> current-property-container-id;
property <PreviewData> current-preview-data; in-out property <PreviewData> current-preview-data;
property <string> possible_error; property <string> possible_error;
property <string> brush-string;
callback show-floating-widget(PropertyInformation, ElementInformation); callback show-floating-widget(PropertyInformation, ElementInformation);
callback show-floating-preview-widget(property-container-id: string, preview-data: PreviewData, property-value: PropertyValue); callback show-floating-preview-widget(property-container-id: string, preview-data: PreviewData, property-value: PropertyValue);
callback show-floating-preview-brush-widget(property-container-id: string, preview-data: PreviewData, brush-kind: BrushKind, current-brush: brush, current-gradient-stops: [GradientStop]); callback show-floating-preview-brush-widget(property-container-id: string, preview-data: PreviewData, brush-kind: BrushKind, current-brush: brush, current-gradient-stops: [GradientStop]);
callback show-floating-table-editor(property-group-id: string, preview-data: PreviewData);
callback hide-floating-widget(); callback hide-floating-widget();
callback apply-current-value(value: string); callback apply-current-value(value: string);
callback update-preview-value(value: string); callback update-preview-value(value: string);
@ -49,6 +49,7 @@ export global WindowManager {
hide-floating-widget => { hide-floating-widget => {
showing-color-picker = false; showing-color-picker = false;
showing-table-editor = false;
current-element-information = { }; current-element-information = { };
current-property-information = { }; current-property-information = { };
widget-mode = WidgetMode.edit; widget-mode = WidgetMode.edit;
@ -87,6 +88,11 @@ export global WindowManager {
showing-color-picker = true; showing-color-picker = true;
} }
show-floating-table-editor(property-group-id, preview-data) => {
TableData.populate-table(property-group-id, preview-data);
showing-table-editor = true;
}
apply-current-value(text) => { apply-current-value(text) => {
Api.set-code-binding( Api.set-code-binding(
current-element-information.source-uri, current-element-information.source-uri,
@ -102,7 +108,6 @@ export global WindowManager {
StatusLineApi.help-text = self.possible-error; StatusLineApi.help-text = self.possible-error;
} }
property <string> brush-string;
update-brush() => { update-brush() => {
PickerData.current-brush = Api.create-brush(BrushKind.linear, 90.0, PickerData.current-brush, PickerData.current-gradient-stops); PickerData.current-brush = Api.create-brush(BrushKind.linear, 90.0, PickerData.current-brush, PickerData.current-gradient-stops);
if widget-mode == WidgetMode.preview { if widget-mode == WidgetMode.preview {