patchwire/ui/window.slint

253 lines
7.6 KiB
Text
Raw Permalink Normal View History

2024-08-14 18:29:07 -05:00
import { ScrollView, HorizontalBox, Button } from "std-widgets.slint";
struct Port {
x: length,
y: length,
name: string,
}
struct Node {
x: length,
y: length,
z: float,
ports-width: [length],
text: string,
in-ports: [Port],
out-ports: [Port],
}
component Node inherits Rectangle {
in-out property <[Node]> nodes;
in property <int> idx;
private property <Node> node: nodes[idx];
callback port_clicked(int, bool);
x: node.x;
y: node.y;
width: self.preferred-width;
height: self.preferred-height;
drop-shadow-blur: 5px;
drop-shadow-color: black;
border-radius: 8px;
VerticalLayout {
spacing: -heading.border-width;
heading := Rectangle {
border-radius: root.border-radius;
border-bottom-right-radius: self.border-bottom-left-radius;
border-bottom-left-radius: {
if node.in-ports.length == 0 && node.out-ports.length == 0 {
root.border-radius
} else {
0px
}
};
background: #383838;
border-width: 1px;
border-color: white.with-alpha(0.15);
HorizontalLayout {
padding: 5px;
spacing: 10px;
Text {
color: white;
text: node.text;
}
}
}
Rectangle {
background: #303030;
border-width: heading.border-width;
border-color: heading.border-color;
border-bottom-right-radius: root.border-radius;
border-bottom-left-radius: self.border-bottom-right-radius;
HorizontalLayout {
for ports[idx] in [node.in-ports, node.out-ports]: ports-layout := VerticalLayout {
private property <bool> is-input: idx == 0;
alignment: start;
padding-top: 5px;
padding-bottom: 5px;
spacing: 5px;
for idx in ports.length: port-layout := HorizontalLayout {
alignment: is-input ? start : end;
x: 15px / 2 * (is-input ? -1 : 1);
Rectangle {
area := TouchArea {
clicked => {
root.port_clicked(idx, is-input);
}
}
border-radius: 3px;
background: #f8e45c;
min-width: 15px;
height: 20px;
drop-shadow-blur: 5px;
drop-shadow-color: black;
HorizontalLayout {
padding: 2px;
Text {
color: black;
horizontal-alignment: center;
text: ports[idx].name;
}
}
init => {
ports[idx].y = //
heading.preferred-height//
+ ports-layout.padding-top//
+ port-layout.preferred-height / 2//
+ (ports-layout.spacing + port-layout.preferred-height) * idx;
}
}
}
}
}
}
}
for idx in node.out-ports.length: Rectangle {
init => {
node.out-ports[idx].x = root.preferred-width;
}
}
TouchArea {
moved => {
if self.pressed {
nodes[idx].x += self.mouse-x - self.pressed-x;
nodes[idx].y += self.mouse-y - self.pressed-y;
}
}
mouse-cursor: move;
}
}
struct Link { x1: length, x2: length, y1: length, y2: length, color: brush, }
component Link inherits Path {
in property <Link> link;
viewbox-width: self.width / 1px;
viewbox-height: self.height / 1px;
stroke: link.color;
stroke-width: 5px;
MoveTo {
x: link.x1 / 1px;
y: link.y1 / 1px;
}
// LineTo {
// x: link.x2 / 1px;
// y: link.y2 / 1px;
// }
private property <int> h: link.y2 / 1px - link.y1 / 1px;
private property <int> w: link.x2 / 1px - link.x1 / 1px;
private property <{ x: int, y: int}> c1: {
x: max(abs(h / 2), abs(w / 2)),
y: max(h / 4, -w / 4),
};
private property <{ x: int, y: int}> c2: {
x: max(abs(h / 2), abs(w / 2)),
y: min(h / 4, w / 4 + abs(h)),
};
CubicTo {
x: link.x2 / 1px;
y: link.y2 / 1px;
control-1-x: link.x1 / 1px + c1.x;
control-1-y: link.y1 / 1px + c1.y;
control-2-x: link.x2 / 1px - c2.x;
control-2-y: link.y2 / 1px - c2.y;
}
}
struct Connection { node1: int, port1: int, node2: int, port2: int, color: brush}
export component MainWindow inherits Window {
background: #242424;
min-width: 800px;
min-height: 400px;
in-out property window_title <=> self.title;
in-out property <[Node]> nodes;
in-out property <[Connection]> connections;
property <[Link]> links;
property <Connection> PendingConnection: { node1: -1, port1: -1, node2: -1, port2: -1, color: #ffa500 };
callback add_connection_helper(Connection);
preferred-height: 500px;
preferred-width: 500px;
public pure function create-link-object(start: { node: int, port: int}, end: { node: int, port: int}, color: brush) -> Link {
{
x1: nodes[start.node].x + nodes[start.node].out-ports[start.port].x,
y1: nodes[start.node].y + nodes[start.node].out-ports[start.port].y,
x2: nodes[end.node].x + nodes[end.node].in-ports[end.port].x,
y2: nodes[end.node].y + nodes[end.node].in-ports[end.port].y,
color: color,
}
}
VerticalLayout {
ScrollView {
for c in connections: Link {
link: root.create-link-object({ node: c.node1, port: c.port1 }, { node: c.node2, port: c.port2 }, c.color);
}
for node[idx] in nodes: Node {
nodes <=> nodes;
idx: idx;
port_clicked(port, is-input) => {
debug("Node", idx, "Port", port, "Input", is-input);
if (root.PendingConnection.node1 == -1) {
if (!is-input) {
root.PendingConnection.node1 = idx;
root.PendingConnection.port1 = port;
root.PendingConnection.color = #ffa500;
} else {
root.PendingConnection.node1 = -1;
}
} else if (root.PendingConnection.node1 != idx) {
if (is-input) {
root.PendingConnection.node2 = idx;
root.PendingConnection.port2 = port;
// Use rust code to add the connection because we can't do it in pure slint
// Ugh
root.add_connection_helper(root.PendingConnection);
}
root.PendingConnection.node1 = -1;
}
}
}
}
Rectangle {
height: 10%;
}
}
}