mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-21 15:52:19 +00:00

Some checks failed
autofix.ci / format_fix (push) Has been cancelled
autofix.ci / lint_typecheck (push) Has been cancelled
CI / files-changed (push) Has been cancelled
CI / build_and_test (--exclude bevy-example, ubuntu-22.04, 1.85) (push) Has been cancelled
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, --exclude bevy-example, windows-2022, 1.85) (push) Has been cancelled
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, macos-14, stable) (push) Has been cancelled
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, windows-2022, beta) (push) Has been cancelled
CI / build_and_test (--exclude ffmpeg --exclude gstreamer-player, windows-2022, stable) (push) Has been cancelled
CI / build_and_test (ubuntu-22.04, nightly) (push) Has been cancelled
CI / node_test (macos-14) (push) Has been cancelled
CI / node_test (windows-2022) (push) Has been cancelled
CI / cpp_test_driver (ubuntu-22.04) (push) Has been cancelled
CI / cpp_package_test (push) Has been cancelled
CI / vsce_build_test (push) Has been cancelled
CI / mcu (pico-st7789, thumbv6m-none-eabi) (push) Has been cancelled
CI / mcu (pico2-st7789, thumbv8m.main-none-eabihf) (push) Has been cancelled
CI / mcu (stm32h735g, thumbv7em-none-eabihf) (push) Has been cancelled
CI / mcu-embassy (push) Has been cancelled
CI / wasm_demo (push) Has been cancelled
CI / tree-sitter (push) Has been cancelled
CI / updater_test (0.3.0) (push) Has been cancelled
CI / esp-idf-quick (push) Has been cancelled
CI / android (push) Has been cancelled
CI / miri (push) Has been cancelled
CI / test-figma-inspector (push) Has been cancelled
CI / material-components (push) Has been cancelled
CI / node_test (ubuntu-22.04) (push) Has been cancelled
CI / python_test (macos-14) (push) Has been cancelled
CI / python_test (ubuntu-22.04) (push) Has been cancelled
CI / python_test (windows-2022) (push) Has been cancelled
CI / cpp_test_driver (macos-14) (push) Has been cancelled
CI / cpp_test_driver (windows-2022) (push) Has been cancelled
CI / cpp_cmake (macos-14, 1.85) (push) Has been cancelled
CI / cpp_cmake (ubuntu-22.04, stable) (push) Has been cancelled
CI / cpp_cmake (windows-2022, nightly) (push) Has been cancelled
CI / ffi_32bit_build (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / wasm (push) Has been cancelled
CI / fmt_test (push) Has been cancelled
425 lines
15 KiB
Text
425 lines
15 KiB
Text
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
|
import {
|
|
Api,
|
|
BrushKind,
|
|
ElementInformation,
|
|
GradientStop,
|
|
PreviewData,
|
|
PropertyInformation,
|
|
PropertyValue,
|
|
PropertyValueKind,
|
|
PropertyValueTable,
|
|
} from "./api.slint";
|
|
import { StatusLineApi } from "components/status-line.slint";
|
|
|
|
export enum WidgetMode { edit, preview, color-stop }
|
|
|
|
export enum PickerTab {
|
|
color,
|
|
gradient,
|
|
css-color,
|
|
globals
|
|
}
|
|
|
|
// Color and Brush properties are related, but while a <brush> can be a color,
|
|
// a <color> property cannot be a brush. This property type is used to ensure
|
|
// <color> properties do not show the more complex brush editor.
|
|
export enum BrushPropertyType {
|
|
color,
|
|
brush,
|
|
}
|
|
|
|
export enum BrushMode {
|
|
color,
|
|
conic,
|
|
linear,
|
|
radial,
|
|
css-color,
|
|
code,
|
|
}
|
|
|
|
export enum GradientType {
|
|
conic,
|
|
linear,
|
|
radial,
|
|
}
|
|
|
|
export enum ColorCodeType {
|
|
other,
|
|
css-color,
|
|
global
|
|
}
|
|
|
|
export global WindowGlobal {
|
|
in-out property <length> window-width;
|
|
in-out property <length> window-height;
|
|
}
|
|
|
|
export global TableData {
|
|
callback populate-table(property-group-id: string, preview-data: PreviewData);
|
|
callback show-brush-editor(selected-row: int, selected-col: int);
|
|
callback set-color-preview(value: string);
|
|
out property <string> property-group-id;
|
|
out property <PreviewData> preview-data;
|
|
out property <PropertyValueTable> current-table;
|
|
property <string> possible-error;
|
|
|
|
property <int> selected-row;
|
|
property <int> selected-col;
|
|
|
|
show-brush-editor(selected-row, selected-col) => {
|
|
self.selected-row = selected-row;
|
|
self.selected-col = selected-col;
|
|
WindowManager.show-floating-preview-widget(self.property-group-id, self.preview-data, self.current-table.values[selected-row][selected-col]);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
set-color-preview(value) => {
|
|
self.current-table.values[self.selected-row][self.selected-col].was-edited = true;
|
|
self.current-table.values[self.selected-row][self.selected-col].edited-value = value;
|
|
|
|
self.possible_error = Api.set-property-value-table(root.property-group-id, root.preview-data.name, root.current-table.values, root.current-table.is-array);
|
|
StatusLineApi.help-text = self.possible-error;
|
|
if self.possible-error == "" {
|
|
self.populate-table(root.property-group-id, root.preview-data);
|
|
}
|
|
}
|
|
}
|
|
|
|
export global PickerData {
|
|
out property <PickerTab> active-tab: PickerTab.color;
|
|
out property <BrushPropertyType> picker-mode: color;
|
|
out property <BrushMode> brush-mode: color;
|
|
// Used to remember the last used gradient type so it won't change if the user
|
|
// switches Picker tab
|
|
in-out property <GradientType> last-used-gradient-type: linear;
|
|
|
|
in-out property <float> hue;
|
|
in-out property <float> saturation;
|
|
in-out property <float> value;
|
|
// alpha is an int, instead of float to help snap values to whole percentage numbers
|
|
in-out property <int> alpha;
|
|
out property <color> current-color: hsv(hue, saturation, value, alpha / 100);
|
|
|
|
in-out property <BrushKind> current-brush-kind;
|
|
// As the brush can be updated via the Api.move-gradient-stop function it won't trigger a reactive update.
|
|
// So we need to keep track of the current brush ourselves and update it with update-brush();
|
|
out property <brush> current-brush;
|
|
in-out property <[GradientStop]> current-gradient-stops;
|
|
in-out property <float> current-angle;
|
|
in-out property <int> current-stop-index: 0;
|
|
property <float> current-stop-position: current-gradient-stops[current-stop-index].position;
|
|
property <color> current-stop-color: current-gradient-stops[current-stop-index].color;
|
|
|
|
callback rebuild-gradient-stops();
|
|
callback set-active-tab(picker-tab: PickerTab);
|
|
callback set-gradient-type(gradient-type: GradientType);
|
|
callback reset();
|
|
|
|
changed current-stop-index => {
|
|
update-brush();
|
|
if WindowManager.showing-color-stop-picker {
|
|
set-current-stop-as-color();
|
|
}
|
|
}
|
|
|
|
changed current-color => {
|
|
update-brush();
|
|
if WindowManager.showing-color-stop-picker {
|
|
current-gradient-stops[current-stop-index].color = current-color;
|
|
} else if WindowManager.widget-mode == WidgetMode.preview && current-brush-kind == BrushKind.solid {
|
|
WindowManager.update-preview-value(Api.color-to-data(root.current-color).text);
|
|
}
|
|
}
|
|
|
|
changed current-brush-kind => {
|
|
update-brush();
|
|
if WindowManager.widget-mode == WidgetMode.preview {
|
|
WindowManager.update-brush-preview();
|
|
}
|
|
}
|
|
|
|
changed current-angle => {
|
|
if WindowManager.widget-mode == WidgetMode.preview {
|
|
update-brush();
|
|
WindowManager.update-brush-preview();
|
|
}
|
|
}
|
|
|
|
changed current-stop-position => {
|
|
update-brush();
|
|
WindowManager.update-brush-preview();
|
|
}
|
|
|
|
changed current-stop-color => {
|
|
update-brush();
|
|
WindowManager.update-brush-preview();
|
|
}
|
|
|
|
changed active-tab => {
|
|
WindowManager.hide-color-stop-picker();
|
|
}
|
|
|
|
rebuild-gradient-stops => {
|
|
current-gradient-stops = Api.clone-gradient-stops(current-gradient-stops);
|
|
update-brush();
|
|
WindowManager.update-brush-preview();
|
|
}
|
|
|
|
set-active-tab(picker-tab) => {
|
|
active-tab = picker-tab;
|
|
if picker-tab == PickerTab.color {
|
|
current-brush-kind = BrushKind.solid;
|
|
brush-mode = BrushMode.color;
|
|
}
|
|
if picker-tab == PickerTab.gradient {
|
|
if last-used-gradient-type == GradientType.radial {
|
|
current-brush-kind = BrushKind.radial;
|
|
brush-mode = BrushMode.radial;
|
|
} else if last-used-gradient-type == GradientType.conic {
|
|
current-brush-kind = BrushKind.conic;
|
|
brush-mode = BrushMode.conic;
|
|
} else {
|
|
current-brush-kind = BrushKind.linear;
|
|
brush-mode = BrushMode.linear;
|
|
}
|
|
}
|
|
}
|
|
|
|
set-gradient-type(gradient-type) => {
|
|
last-used-gradient-type = gradient-type;
|
|
if gradient-type == GradientType.linear {
|
|
current-brush-kind = BrushKind.linear;
|
|
brush-mode = BrushMode.linear;
|
|
} else if gradient-type == GradientType.conic {
|
|
current-brush-kind = BrushKind.conic;
|
|
brush-mode = BrushMode.conic;
|
|
} else {
|
|
current-brush-kind = BrushKind.radial;
|
|
brush-mode = BrushMode.radial;
|
|
}
|
|
}
|
|
|
|
reset => {
|
|
brush-mode = BrushMode.color;
|
|
active-tab = PickerTab.color;
|
|
picker-mode = BrushPropertyType.color;
|
|
last-used-gradient-type = GradientType.linear;
|
|
}
|
|
|
|
public function set-current-stop-as-color() {
|
|
set-color(current-gradient-stops[current-stop-index].color);
|
|
}
|
|
|
|
public function update-brush() {
|
|
self.current-brush = Api.create-brush(current-brush-kind, current-angle, current-color, current-gradient-stops);
|
|
}
|
|
|
|
function set-svg-or-global-tab(property-value: PropertyValue) {
|
|
if PickerData.get-color-code-type(property-value) == ColorCodeType.css-color {
|
|
set-active-tab(PickerTab.css-color);
|
|
} else {
|
|
set-active-tab(PickerTab.globals);
|
|
}
|
|
}
|
|
|
|
public function init-with-property-value(property-value: PropertyValue) {
|
|
PickerData.current-brush-kind = property-value.brush-kind;
|
|
current-gradient-stops = Api.clone-gradient-stops(property-value.gradient-stops);
|
|
current-angle = property-value.value-float;
|
|
brush-mode = property-value.brush-kind == BrushKind.solid ? BrushMode.color : property-value.brush-kind == BrushKind.linear ? BrushMode.linear : BrushMode.radial;
|
|
|
|
if property-value.kind == PropertyValueKind.color {
|
|
picker-mode = BrushPropertyType.color;
|
|
if PickerData.get-color-code-type(property-value) == ColorCodeType.other {
|
|
set-active-tab(PickerTab.color);
|
|
} else {
|
|
set-svg-or-global-tab(property-value);
|
|
}
|
|
}
|
|
|
|
if property-value.kind == PropertyValueKind.brush {
|
|
picker-mode = BrushPropertyType.brush;
|
|
if PickerData.get-color-code-type(property-value) == ColorCodeType.other {
|
|
if property-value.brush-kind == BrushKind.solid {
|
|
set-active-tab(PickerTab.color);
|
|
} else {
|
|
set-active-tab(PickerTab.gradient);
|
|
}
|
|
} else {
|
|
set-svg-or-global-tab(property-value);
|
|
}
|
|
}
|
|
|
|
if property-value.brush-kind == BrushKind.solid {
|
|
if property-value.code == "" {
|
|
PickerData.set-default-color();
|
|
} else {
|
|
PickerData.set-color(property-value.value-brush);
|
|
}
|
|
} else {
|
|
PickerData.set-color(PickerData.current-gradient-stops[PickerData.current-stop-index].color);
|
|
if property-value.brush-kind == BrushKind.radial {
|
|
set-gradient-type(GradientType.radial)
|
|
}
|
|
if property-value.brush-kind == BrushKind.linear {
|
|
set-gradient-type(GradientType.linear)
|
|
}
|
|
if property-value.brush-kind == BrushKind.conic {
|
|
set-gradient-type(GradientType.conic)
|
|
}
|
|
}
|
|
|
|
update-brush();
|
|
}
|
|
|
|
public function set-color(color: color) {
|
|
PickerData.hue = color.to-hsv().hue;
|
|
PickerData.saturation = color.to-hsv().saturation;
|
|
PickerData.value = color.to-hsv().value;
|
|
PickerData.alpha = color.to-hsv().alpha * 100;
|
|
}
|
|
|
|
public function set-default-color() {
|
|
if Api.recent-colors.length > 0 {
|
|
set-color(Api.recent-colors[0]);
|
|
} else {
|
|
set-color(#2479f4);
|
|
}
|
|
}
|
|
|
|
pure public function get-color-code-type(property-value: PropertyValue) -> ColorCodeType {
|
|
if property-value.value-string == "" {
|
|
return ColorCodeType.other;
|
|
}
|
|
if Api.is-css-color(property-value.code) {
|
|
return ColorCodeType.css-color;
|
|
} else {
|
|
return ColorCodeType.global;
|
|
}
|
|
}
|
|
}
|
|
|
|
export global WindowManager {
|
|
out property <bool> showing-color-picker: false;
|
|
out property <bool> showing-table-editor: false;
|
|
out property <bool> showing-color-stop-picker: false;
|
|
out property <WidgetMode> widget-mode: edit;
|
|
|
|
property <ElementInformation> current-element-information;
|
|
out property <PropertyInformation> current-property-information;
|
|
in-out property <string> current-property-container-id;
|
|
in-out property <PreviewData> current-preview-data;
|
|
property component-factory <=> Api.preview-data;
|
|
|
|
property <string> possible_error;
|
|
property <string> brush-string;
|
|
|
|
callback show-floating-widget(property-information: PropertyInformation, element-information: ElementInformation);
|
|
callback show-floating-preview-widget(property-container-id: string, preview-data: PreviewData, property-value: PropertyValue);
|
|
callback show-floating-table-editor(property-group-id: string, preview-data: PreviewData);
|
|
callback hide-floating-widget();
|
|
callback hide-floating-color-widget();
|
|
callback apply-current-value(value: string);
|
|
callback update-preview-value(value: string);
|
|
callback update-brush-preview();
|
|
callback show-color-stop-picker();
|
|
callback hide-color-stop-picker();
|
|
|
|
show-floating-widget(property-information, element-information) => {
|
|
widget-mode = WidgetMode.edit;
|
|
current-property-information = property-information;
|
|
current-element-information = element-information;
|
|
|
|
PickerData.init-with-property-value(current-property-information.value);
|
|
showing-color-picker = true;
|
|
}
|
|
|
|
hide-floating-widget => {
|
|
showing-color-picker = false;
|
|
showing-table-editor = false;
|
|
showing-color-stop-picker = false;
|
|
current-element-information = { };
|
|
current-property-information = { };
|
|
widget-mode = WidgetMode.edit;
|
|
PickerData.reset()
|
|
}
|
|
|
|
show-floating-preview-widget(property-container-id, preview-data, property-value) => {
|
|
current-property-container-id = property-container-id;
|
|
current-preview-data = preview-data;
|
|
widget-mode = WidgetMode.preview;
|
|
|
|
PickerData.init-with-property-value(property-value);
|
|
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;
|
|
}
|
|
|
|
show-color-stop-picker => {
|
|
PickerData.set-current-stop-as-color();
|
|
showing-color-stop-picker = true;
|
|
}
|
|
|
|
hide-color-stop-picker => {
|
|
showing-color-stop-picker = false;
|
|
}
|
|
|
|
apply-current-value(text) => {
|
|
Api.set-code-binding(
|
|
current-element-information.source-uri,
|
|
current-element-information.source-version,
|
|
current-element-information.offset,
|
|
current-property-information.name,
|
|
text);
|
|
}
|
|
|
|
update-preview-value(text) => {
|
|
if WindowManager.showing-table-editor {
|
|
TableData.set-color-preview("\"\{text}\"");
|
|
} else {
|
|
self.possible_error = Api.set-json-preview-data(current-property-container-id, current-preview-data.name, "\"\{text}\"", check-new-value(current-property-container-id + current-preview-data.name));
|
|
}
|
|
}
|
|
|
|
update-brush-preview() => {
|
|
if widget-mode == WidgetMode.preview {
|
|
brush-string = Api.as-slint-brush(PickerData.current-brush-kind, PickerData.current-angle, PickerData.current-brush, PickerData.current-gradient-stops);
|
|
|
|
if WindowManager.showing-table-editor {
|
|
TableData.set-color-preview("\"\{brush-string}\"");
|
|
} else {
|
|
self.possible_error = Api.set-json-preview-data(current-property-container-id, current-preview-data.name, "\"\{brush-string}\"", check-new-value(current-property-container-id + current-preview-data.name));
|
|
}
|
|
}
|
|
}
|
|
|
|
hide-floating-color-widget() => {
|
|
if showing-table-editor {
|
|
showing-color-picker = false;
|
|
showing-color-stop-picker = false;
|
|
} else {
|
|
hide-floating-widget();
|
|
}
|
|
}
|
|
|
|
property <string> container-property-name;
|
|
function check-new-value(value: string) -> bool {
|
|
if container-property-name == value {
|
|
return false;
|
|
} else {
|
|
container-property-name = value;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|