slint/tools/lsp/ui/components/widgets/gradient-basics.slint
Tobias Hunger 2512713a31 live-preview: Move more code out of ui.rs
... add unit tests and fix the bugs those discovered.
2025-04-15 16:34:44 +02:00

213 lines
6.5 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 { Preview } from "./color-basics.slint";
import { Api, BrushKind, GradientStop } from "../../api.slint";
component GradientDot inherits Rectangle {
in-out property <bool> selected: false;
out property <bool> has-hover <=> ta.has-hover;
in property <length> parent-width;
in-out property <[GradientStop]> gradient-stops;
in property <int> index;
in property <int> apply-update;
x: parent-width * self.gradient-stops[self.index].position - self.width / 2.0;
callback select-gradient-stop();
callback unselect-gradient-stop();
callback update-brush();
width: self.selected ? 20px : 10px;
height: self.selected ? 20px : 10px;
border-radius: self.width;
background: root.gradient-stops[root.index].color;
border-width: root.selected ? 2px : 1px;
border-color: root.selected ? black : gray;
Rectangle {
border-radius: self.width;
border-color: root.selected ? white : white.transparentize(0.5);
border-width: 1px;
}
ta := TouchArea {
private property <length> x-pos: self.mouse-x + root.x;
changed has-hover => {
if !root.selected && self.has-hover {
root.select-gradient-stop();
}
}
double-clicked => {
Api.remove-gradient-stop(root.gradient-stops, index);
root.update-brush();
}
moved => {
root.gradient-stops[root.index].position = Math.clamp(self.x-pos, 0, root.parent-width) / root.parent-width;
root.update-brush();
}
scroll-event(event) => {
if event.delta-y != 0 {
root.gradient-stops[root.index].position = Math.clamp(
root.gradient-stops[root.index].position + Math.clamp((event.delta-y / 1px), -0.01, +0.01),
0.0, 1.0);
root.update-brush();
return EventResult.accept;
}
return EventResult.reject;
}
}
}
export component GradientMainContent inherits HorizontalLayout {
in property <brush> current-brush;
in property <BrushKind> current-brush-kind;
in-out property <[GradientStop]> gradient-stops;
in-out property <float> current-position;
private property <float> current-position_: index-position(self.selected-index);
in-out property <color> current-color;
private property <color> current-color_: index-color(self.selected-index);
out property <bool> has-focus: ta.has-hover || self.dot-hover-count > 0;
out property <int> selected-index: -1;
callback update-brush();
private property <int> apply-update-to: -1;
changed current-color_ => {
self.current-color = current-color_;
}
changed current-color => {
if self.selected-index >= 0 && self.selected-index < self.gradient-stops.length {
self.gradient-stops[self.selected-index].color = current-color;
}
apply-model-change-to-ui();
}
changed current-position_ => {
self.current-position = current-position_;
}
changed current-position => {
if self.selected-index >= 0 && self.selected-index < self.gradient-stops.length {
self.gradient-stops[self.selected-index].position = current-position;
}
apply-model-change-to-ui();
}
pure function index-color(index: int) -> color {
if index >= 0 && index < self.gradient-stops.length {
return self.gradient-stops[index].color;
}
return Colors.transparent;
}
pure function index-position(index: int) -> float {
if index >= 0 && index < self.gradient-stops.length {
return self.gradient-stops[index].position;
}
return 0.0;
}
function apply-model-change-to-ui() {
if self.selected-index >= 0 {
self.apply-update-to = self.selected-index;
}
}
function apply-gradient-stops() {
if (self.selected-index < 0) || (self.selected-index >= self.gradient-stops.length) {
if self.gradient-stops.length > 0 {
self.selected-index = 0;
} else {
self.selected-index = -1;
}
}
}
init => {
apply-gradient-stops();
}
changed gradient-stops => {
apply-gradient-stops();
}
private property <int> dot-hover-count: 0;
grad := Preview {
width: 100%;
height: 40px;
if (current-brush-kind == BrushKind.radial): Rectangle {
width: parent.width * 2;
x: 0 - parent.width;
background: root.current-brush;
}
background: current-brush-kind == BrushKind.radial ? transparent : root.current-brush;
ta := TouchArea {
double-clicked => {
root.selected-index = Api.add-gradient-stop(root.gradient-stops, Api.suggest-gradient-stop-at-position(root.gradient-stops, self.mouse-x / self.width));
root.update-brush();
}
scroll-event(event) => {
if event.delta-y != 0 && root.selected-index >= 0 {
root.gradient-stops[root.selected-index].position = Math.clamp(
root.index-position(root.selected-index) + Math.clamp((event.delta-y / 1px), -0.01, +0.01),
0.0, 1.0);
root.update-brush();
root.apply-update-to = root.selected-index;
return EventResult.accept;
}
return EventResult.reject;
}
}
Rectangle {
height: 1px;
background: grey;
for i[index] in root.gradient-stops: GradientDot {
selected: root.selected-index == index;
gradient-stops <=> root.gradient-stops;
index: index;
changed has-hover => {
if self.has-hover {
root.dot-hover-count += 1;
} else {
root.dot-hover-count -= 1;
}
}
parent-width: grad.width;
select-gradient-stop() => {
root.selected-index = index;
}
update-brush() => {
root.update-brush();
}
}
}
}
}