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";
export component PropertyValueWidget inherits VerticalLayout {
in property <PropertyValue> property-value;
in-out property <PropertyValue> property-value;
in property <PreviewData> preview-data;
in property <string> property-name;
in property <bool> enabled;
@ -29,6 +29,8 @@ export component PropertyValueWidget inherits VerticalLayout {
in property <bool> strings-are-translatable: true;
in property <string> property-container-id;
callback update-display-string(value: string);
callback set-bool-binding(value: bool);
callback set-color-binding(text: string);
callback test-color-binding(text: string) -> bool;
@ -46,6 +48,11 @@ export component PropertyValueWidget inherits VerticalLayout {
callback reset-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 {
enabled <=> root.enabled;
property-name <=> root.property-name;
@ -54,6 +61,8 @@ export component PropertyValueWidget inherits VerticalLayout {
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 {
@ -71,6 +80,9 @@ export component PropertyValueWidget inherits VerticalLayout {
set-color-binding(text) => {
root.set-color-binding(text);
}
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => {
root.reset-action();
}
@ -94,6 +106,9 @@ export component PropertyValueWidget inherits VerticalLayout {
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() => {
root.reset-action();
}
@ -107,6 +122,8 @@ export component PropertyValueWidget inherits VerticalLayout {
property-name <=> root.property-name;
property-value <=> root.property-value;
update-display-string(value) => { root.update-display-string-impl(value); }
reset-action() => {
root.reset-action();
}
@ -123,6 +140,8 @@ export component PropertyValueWidget inherits VerticalLayout {
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 {
@ -136,6 +155,8 @@ export component PropertyValueWidget inherits VerticalLayout {
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 {
@ -149,6 +170,8 @@ export component PropertyValueWidget inherits VerticalLayout {
set-integer-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 {
@ -160,18 +183,21 @@ export component PropertyValueWidget inherits VerticalLayout {
has-reset-action: root.has-reset-action;
is-translatable <=> root.strings-are-translatable;
reset-action() => {
root.reset-action();
}
code-action() => {
root.code-action();
}
test-string-binding(text, is_translated) => {
return root.test-string-binding(text, is_translated);
}
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 <string> possible-error;
callback edit-in-spreadsheet(rp: PropertyContainer);
callback edit-in-table-editor(property-group-id: string, data: PreviewData);
function reset-action() {
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));
}
}
if root.preview-data.kind == PreviewDataKind.Table && false: MultiValueWidget {
edit-in-spreadsheet(property-group-name, data, values) => {
debug("edit-in-spreadsheet TRIGGERED: ", property-group-name, data, values);
if root.preview-data.kind == PreviewDataKind.Table: MultiValueWidget {
property-value <=> root.value;
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;
property-name: root.preview-data.name;
property-value <=> root.value;

View file

@ -1,31 +1,113 @@
// 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 { Button } from "std-widgets.slint";
import { EditorSpaceSettings } from "../components/styling.slint";
import { Button, Palette, StandardButton, ScrollView } from "std-widgets.slint";
import { EditorSpaceSettings, EditorPalette, Icons } from "../components/styling.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 {
width: Math.min(self.preferred-width, WindowGlobal.window-width * 0.9);
height: Math.min(self.preferred-height, WindowGlobal.window-height * 0.9);
component TableEditor inherits DraggablePanel {
property <string> property-group-id <=> TableData.property-group-id;
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 {
Spreadsheet {
property <length> content-height;
property <length> content-width;
close => {
WindowManager.hide-floating-widget();
}
width: 240px;
title := Rectangle {
width: 100%;
height: 40px;
Text {
text: "Edit Values";
color: EditorPalette.text-color;
}
HorizontalLayout {
alignment: end;
padding: 8px;
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;
Button {
text: "Close";
t-close := TouchArea {
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,43 +1,110 @@
// 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 { 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";
export struct CellData {
id: string,
value: PropertyValue,
property-group-id: string,
property-name: string,
row: int,
col: int,
x: length,
y: length,
width: length,
height: 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;
export component EditWindow inherits PopupWindow {
close-policy: close-on-click-outside;
callback test(string) -> bool;
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;
in property <CellData> current-cell-data;
in-out property <PropertyValueTable> current-table;
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: self.preferred-width;
height: self.preferred-height;
background: Palette.alternate-background;
hl := HorizontalLayout {
padding: EditorSpaceSettings.default-padding;
padding-left: EditorSpaceSettings.default-padding;
spacing: EditorSpaceSettings.default-spacing;
PropertyValueWidget {
property-value: root.current-table.values[root.current-cell-data.row][root.current-cell-data.col];
property-name: root.current-cell-data.property-group-id;
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> hovered;
width: 30px;
if (value > 0): Rectangle {
height: 30px;
background: header ? transparent : Palette.alternate-background;
@ -81,18 +149,20 @@ component RowMarker inherits Rectangle {
}
component Cell inherits Rectangle {
in property <CellData> cell-data;
in property <string> id;
in property <PropertyValue> property-value;
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;
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;
@ -116,128 +186,56 @@ component Cell inherits Rectangle {
if is-writeable: TouchArea {
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: {
name: "Addresses",
has-getter: true,
has-setter: true,
kind: PreviewDataKind.Table,
};
in property <PropertyValueTable> current-table: {
in-out property <PropertyValueTable> current-table: {
is-array: true,
headers: ["type", "street", "city", "state", "zip", "favorite","color"],
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"
}
{ 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" }
]
],
};
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);
}
private property <CellData> current-cell-data;
VerticalLayout {
HorizontalLayout {
@ -252,23 +250,31 @@ export component Spreadsheet inherits ScrollView {
for data-row[row] in root.current-table.values: HorizontalLayout {
RowMarker {
value: row + 1;
hovered: ta.has-hover ? true : false;
hovered: ta.has-hover;
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});
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.value-string;
text: value.display-string;
is-writeable: true;
edit-clicked(data) => {
root.current-cell = {
id: data.id,
value: value, // Now passing the properly typed CellValue
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,
@ -276,46 +282,69 @@ export component Spreadsheet inherits ScrollView {
width: self.width,
height: self.height
};
root.edit-window-visible = true;
ew.show();
}
}
}
}
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;
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;
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) => {
edit(new-value);
self.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 {
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);
}
}
}
}

View file

@ -62,6 +62,9 @@ export global EditorSizeSettings {
in property <length> property-bar-width: 360px;
in property <length> radius: 5px;
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 {
@ -78,10 +81,13 @@ export global EditorPalette {
out property <brush> interactive-element-selection-secondary: #48dc2a;
out property <brush> layout-element-selection-primary: #FFC5FC;
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-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 {

View file

@ -11,9 +11,10 @@ import { CheckBox } from "std-widgets.slint";
export component BooleanWidget inherits GridLayout {
in property <bool> enabled;
in property <string> property-name;
in property <PropertyValue> property-value;
in-out property <PropertyValue> property-value;
callback set-bool-binding(value: bool);
callback update-display-string(value: string);
spacing-vertical: EditorSpaceSettings.default-spacing;
width: 100%;
@ -36,10 +37,18 @@ export component BooleanWidget inherits GridLayout {
checkbox := CheckBox {
enabled: root.enabled;
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() => {
root.property-value.value-bool = self.checked;
debug("property-value is now:", root.property-value.value-bool);
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 reset-action();
callback update-display-string(value: string);
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]);
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 <brush> current-brush;
private property <[GradientStop]> current-gradient-stops;
@ -71,7 +78,7 @@ export component BrushWidget inherits GridLayout {
function set-color(text: string) {
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;
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) => {
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 <PropertyValue> property-value;
callback update-display-string(value: string);
callback code-action();
callback reset-action();

View file

@ -26,6 +26,9 @@ export component ColorWidget inherits VerticalLayout {
padding-left: 16px;
spacing: EditorSpaceSettings.default-spacing;
callback update-display-string(value: string);
width: 100%;
function apply-value() {
@ -73,6 +76,7 @@ export component ColorWidget inherits VerticalLayout {
set-color-binding(text) => {
root.set-color-binding(text);
}
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);
spacing-vertical: EditorSpaceSettings.default-spacing;
@ -46,6 +48,7 @@ export component EnumWidget inherits GridLayout {
model: root.property-value.visual-items;
selected(value) => {
root.update-display-string(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 <PropertyValue> property-value;
callback update-display-string(value: string);
callback test-float-binding(text: string, unit: string) -> bool;
callback set-float-binding(text: string, unit: string);
@ -30,6 +32,9 @@ export component FloatWidget inherits GridLayout {
}
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);
}

View file

@ -4,20 +4,12 @@
import { Palette, Button, ComboBox } from "std-widgets.slint";
import { WindowGlobal, WindowManager } from "../../windowglobal.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 { SimpleColumn } from "../../components/layout-helpers.slint";
import { DraggablePanel } from "../../components/draggable-panel.slint";
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;
}
@ -101,7 +93,7 @@ component BrushTypeSelector {
in-out property <BrushMode> brush-mode: color;
HorizontalLayout {
padding-left: Styles.small-margin;
padding-left: EditorSizeSettings.small-margin;
alignment: start;
Rectangle {
@ -113,8 +105,8 @@ component BrushTypeSelector {
Rectangle {
visible: is-active;
background: Styles.section-color;
border-radius: Styles.property-border-radius;
background: EditorPalette.section-color;
border-radius: EditorSizeSettings.property-border-radius;
}
TouchArea {
@ -152,8 +144,8 @@ component BrushTypeSelector {
Rectangle {
visible: is-active;
background: Styles.section-color;
border-radius: Styles.property-border-radius;
background: EditorPalette.section-color;
border-radius: EditorSizeSettings.property-border-radius;
}
TouchArea {
@ -190,8 +182,8 @@ component BrushTypeSelector {
Rectangle {
visible: is-active;
background: Styles.section-color;
border-radius: Styles.property-border-radius;
background: EditorPalette.section-color;
border-radius: EditorSizeSettings.property-border-radius;
}
TouchArea {
@ -230,11 +222,11 @@ component ColorModeColorAndApply {
alignment: center;
spacing: 10px;
Rectangle {
x: Styles.standard-margin;
x: EditorSizeSettings.standard-margin;
width: 170px;
height: 25px;
background: Styles.section-color;
border-radius: Styles.property-border-radius;
background: EditorPalette.section-color;
border-radius: EditorSizeSettings.property-border-radius;
border-width: 1px;
Rectangle {
@ -259,7 +251,7 @@ component ColorModeColorAndApply {
x: 35px;
font-family: "Inter";
font-size: 12px;
color: Styles.text-color;
color: EditorPalette.text-color;
text: Api.color-to-data(PickerData.current-color).short-text.to-uppercase();
letter-spacing: 0.8px;
}
@ -268,7 +260,7 @@ component ColorModeColorAndApply {
x: parent.width - 45px;
width: 1px;
height: parent.height;
background: Styles.background-color;
background: Palette.background;
}
Rectangle {
@ -283,7 +275,7 @@ component ColorModeColorAndApply {
horizontal-alignment: left;
font-family: "Inter";
font-size: 12px;
color: Styles.text-color;
color: EditorPalette.text-color;
text: PickerData.alpha;
text-cursor-width: 2px;
selection-background-color: #3984ec;
@ -337,7 +329,7 @@ component ColorModeColorAndApply {
}
if widget-mode == WidgetMode.edit: Button {
x: Styles.standard-margin;
x: EditorSizeSettings.standard-margin;
width: 100px;
text: "Apply";
clicked => {
@ -349,7 +341,7 @@ component ColorModeColorAndApply {
component VerticalSpacer {
width: 100%;
height: Styles.small-margin;
height: EditorSizeSettings.small-margin;
}
component GradientSlider {
@ -366,7 +358,7 @@ component GradientSlider {
Rectangle {
width: 24px;
height: self.width;
background: Styles.section-color;
background: EditorPalette.section-color;
border-radius: 5px;
TouchArea {
@ -391,7 +383,7 @@ component GradientSlider {
width: 10px;
rotation-angle: 45deg;
source: Icons.black-square;
colorize: Styles.section-color;
colorize: EditorPalette.section-color;
}
}
@ -409,10 +401,10 @@ component GradientStopValue {
height: 30px;
Rectangle {
x: Styles.standard-margin;
x: EditorSizeSettings.standard-margin;
width: 48px;
border-radius: Styles.property-border-radius;
background: Styles.section-color;
border-radius: EditorSizeSettings.property-border-radius;
background: EditorPalette.section-color;
TextInput {
x: 10px;
height: 15px;
@ -420,7 +412,7 @@ component GradientStopValue {
horizontal-alignment: left;
font-family: "Inter";
font-size: 12px;
color: Styles.text-color;
color: EditorPalette.text-color;
text: (PickerData.current-gradient-stops[stop-index].position * 100.0).round();
text-cursor-width: 2px;
selection-background-color: #3984ec;
@ -476,8 +468,8 @@ component GradientStopValue {
Rectangle {
x: 70px;
width: 140px;
border-radius: Styles.property-border-radius;
background: Styles.section-color;
border-radius: EditorSizeSettings.property-border-radius;
background: EditorPalette.section-color;
ColorIndicator {
x: 5px;
@ -498,7 +490,7 @@ component GradientStopValue {
x: 35px;
font-family: "Inter";
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();
letter-spacing: 0.8px;
}
@ -507,7 +499,7 @@ component GradientStopValue {
x: parent.width - 45px;
width: 1px;
height: parent.height;
background: Styles.background-color;
background: Palette.background;
}
Rectangle {
@ -520,7 +512,7 @@ component GradientStopValue {
horizontal-alignment: left;
font-family: "Inter";
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-cursor-width: 2px;
selection-background-color: #3984ec;
@ -580,8 +572,8 @@ component GradientPicker inherits SimpleColumn {
height: 50px;
ComboBox {
x: Styles.standard-margin;
y: Styles.standard-margin;
x: EditorSizeSettings.standard-margin;
y: EditorSizeSettings.standard-margin;
model: ["Linear", "Radial"];
current-value: "Linear";
}
@ -591,11 +583,11 @@ component GradientPicker inherits SimpleColumn {
height: 80px;
Rectangle {
width: parent.width - (Styles.standard-margin * 2);
width: parent.width - (EditorSizeSettings.standard-margin * 2);
height: 30px;
Rectangle {
border-radius: Styles.property-border-radius;
border-radius: EditorSizeSettings.property-border-radius;
clip: true;
background: white;
@ -618,7 +610,7 @@ component GradientPicker inherits SimpleColumn {
Rectangle {
border-radius: parent.border-radius;
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 {
height: 50px;
Text {
x: Styles.standard-margin;
y: Styles.standard-margin;
color: Styles.text-color;
x: EditorSizeSettings.standard-margin;
y: EditorSizeSettings.standard-margin;
color: EditorPalette.text-color;
text: "Stops";
font-family: "Inter";
font-size: 11px;
@ -648,14 +640,14 @@ component GradientPicker inherits SimpleColumn {
y: 10px;
width: 25px;
height: self.width;
background: t-plus.has-hover ? Styles.section-color : transparent;
border-radius: Styles.property-border-radius;
background: t-plus.has-hover ? EditorPalette.section-color : transparent;
border-radius: EditorSizeSettings.property-border-radius;
t-plus := TouchArea { }
Image {
source: Icons.plus;
colorize: Styles.text-color;
colorize: EditorPalette.text-color;
}
}
}
@ -672,8 +664,8 @@ component HsvPicker inherits SimpleColumn {
saturation-value-holder := Rectangle {
height: self.width * 0.75;
saturation-value := Rectangle {
width: parent.width - (Styles.standard-margin * 2);
height: parent.height - (Styles.standard-margin * 2);
width: parent.width - (EditorSizeSettings.standard-margin * 2);
height: parent.height - (EditorSizeSettings.standard-margin * 2);
Rectangle {
border-radius: 6px;
@ -693,7 +685,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle {
border-radius: parent.border-radius;
border-width: 1px;
border-color: Styles.text-color.with-alpha(10%);
border-color: EditorPalette.text-color.with-alpha(10%);
}
TouchArea {
@ -743,7 +735,7 @@ component HsvPicker inherits SimpleColumn {
// 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
// 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> rounded-end-width: main-height / 2;
VerticalLayout {
@ -752,8 +744,8 @@ component HsvPicker inherits SimpleColumn {
width: 100%;
height: 16px;
hue-picker := Rectangle {
x: Styles.standard-margin;
width: root.width - (Styles.standard-margin * 2);
x: EditorSizeSettings.standard-margin;
width: root.width - (EditorSizeSettings.standard-margin * 2);
height: main-height;
TouchArea {
moved => {
@ -800,7 +792,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle {
border-radius: parent.border-radius;
border-width: 1px;
border-color: Styles.text-color;
border-color: EditorPalette.text-color;
opacity: 10%;
}
}
@ -833,7 +825,7 @@ component HsvPicker inherits SimpleColumn {
width: 100%;
height: 16px;
Rectangle {
x: Styles.standard-margin;
x: EditorSizeSettings.standard-margin;
width: main-width + main-height;
height: main-height;
Rectangle {
@ -893,7 +885,7 @@ component HsvPicker inherits SimpleColumn {
Rectangle {
border-radius: parent.border-radius;
border-width: 1px;
border-color: Styles.text-color;
border-color: EditorPalette.text-color;
opacity: 10%;
}
}
@ -947,7 +939,7 @@ component HsvPicker inherits SimpleColumn {
height: 1px;
x: 0;
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;
width: 25px;
height: self.width;
background: t-close.has-hover ? Styles.section-color : transparent;
border-radius: Styles.property-border-radius;
background: t-close.has-hover ? EditorPalette.section-color : transparent;
border-radius: EditorSizeSettings.property-border-radius;
t-close := TouchArea { }
Image {
source: Icons.close;
colorize: Styles.text-color;
colorize: EditorPalette.text-color;
}
}
@ -996,7 +988,7 @@ component ColorPicker inherits DraggablePanel {
height: 1px;
x: 0;
y: parent.height - self.height;
background: Styles.divider-color;
background: EditorPalette.divider-color;
}
}
@ -1012,7 +1004,7 @@ component ColorPicker inherits DraggablePanel {
footer := Rectangle {
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 <PropertyValue> property-value;
callback update-display-string(value: string);
callback test-integer-binding(text: string) -> bool;
callback set-integer-binding(text: string);
@ -44,7 +46,8 @@ export component IntegerWidget inherits GridLayout {
}
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 {
in property <bool> enabled;
in property <string> property-name;
in property <string> property-name: preview-data.name;
in property <PropertyValue> property-value;
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;
width: 100%;
@ -37,7 +37,7 @@ export component MultiValueWidget inherits GridLayout {
Button {
text: preview-data.has-setter ? @tr("Edit") : @tr("View");
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 <string> tr-context-value;
callback update-display-string(value: string);
callback code-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);
}
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);
}

View file

@ -14,10 +14,9 @@ import { DrawAreaMode, PreviewView } from "./views/preview-view.slint";
import { OutOfDateBox } from "./components/out-of-date-box.slint";
import { PropertyView } from "./views/property-view.slint";
import { PreviewDataView } from "./views/preview-data-view.slint";
import { SpreadsheetDialog } from "./components/spreadsheet-dialog.slint";
import { WindowGlobal, WindowManager } from "windowglobal.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";
export { Api }
@ -34,6 +33,7 @@ export component PreviewUi inherits Window {
property <bool> show-left-sidebar;
property <bool> show-right-sidebar;
property <bool> show-floating-widget <=> WindowManager.showing-color-picker;
property <bool> show-floating-table-editor <=> WindowManager.showing-table-editor;
property <length> initial-floating-x;
title: "Slint Live-Preview";
@ -148,6 +148,13 @@ export component PreviewUi inherits Window {
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 {
init => {

View file

@ -1,7 +1,7 @@
// 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 { GradientStop } from "./api.slint";
import { Api, GradientStop, PreviewData, PropertyValueTable } from "./api.slint";
export enum WidgetMode { edit, preview }
@ -26,4 +26,17 @@ export global PickerData {
in-out property <brush> current-brush;
in-out property <[GradientStop]> current-gradient-stops;
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 { Api, PropertyContainer } from "../api.slint";
import { Api, PropertyContainer, PreviewData } from "../api.slint";
import { ExpandableGroup } from "../components/expandable-group.slint";
import { PreviewDataPropertyValueWidget } from "../components/property-widgets.slint";
import { EditorSpaceSettings } from "../components/styling.slint";
import { WindowManager } from "../windowglobal.slint";
export component PreviewDataView inherits ScrollView {
@ -45,6 +46,9 @@ export component PreviewDataView inherits ScrollView {
for p in ep.properties: PreviewDataPropertyValueWidget {
preview-data: p;
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>
// 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 { StatusLineApi } from "components/status-line.slint";
import { BrushMode, PickerData, PickerMode, WidgetMode } from "./properties-state.slint";
import { TableData } from "properties-state.slint";
export global WindowGlobal {
in-out property <length> window-width;
@ -15,19 +12,22 @@ export global WindowGlobal {
export global WindowManager {
out property <bool> showing-color-picker: false;
out property <bool> showing-table-editor: false;
out property <WidgetMode> widget-mode: edit;
out property <PickerMode> picker-mode: color;
out property <BrushMode> brush-mode: color;
property <ElementInformation> current-element-information;
out property <PropertyInformation> current-property-information;
property <string> current-property-container-id;
property <PreviewData> current-preview-data;
in-out property <string> current-property-container-id;
in-out property <PreviewData> current-preview-data;
property <string> possible_error;
property <string> brush-string;
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-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 apply-current-value(value: string);
callback update-preview-value(value: string);
@ -49,6 +49,7 @@ export global WindowManager {
hide-floating-widget => {
showing-color-picker = false;
showing-table-editor = false;
current-element-information = { };
current-property-information = { };
widget-mode = WidgetMode.edit;
@ -73,7 +74,7 @@ export global WindowManager {
show-floating-preview-brush-widget(property-container-id, preview-data, brush-kind, current-brush, current-gradient-stops) => {
widget-mode = WidgetMode.preview;
picker-mode = PickerMode.brush;
current-property-container-id = property-container-id;
current-property-container-id = property-container-id;
current-preview-data = preview-data;
if brush-kind == BrushKind.solid {
brush-mode = BrushMode.color;
@ -87,6 +88,11 @@ export global WindowManager {
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) => {
Api.set-code-binding(
current-element-information.source-uri,
@ -102,14 +108,13 @@ export global WindowManager {
StatusLineApi.help-text = self.possible-error;
}
property <string> brush-string;
update-brush() => {
PickerData.current-brush = Api.create-brush(BrushKind.linear, 90.0, PickerData.current-brush, PickerData.current-gradient-stops);
if widget-mode == WidgetMode.preview {
brush-string = Api.as-slint-brush(BrushKind.linear, PickerData.current-angle, PickerData.current-brush, PickerData.current-gradient-stops);
self.possible_error = Api.set-json-preview-data(current-property-container-id, current-preview-data.name, "\"\{brush-string}\"");
StatusLineApi.help-text = self.possible-error;
StatusLineApi.help-text = self.possible-error;
}
}
}