import { Palette } from "std-widgets.slint"; export struct Node { x: length, y: length} export component Graph inherits Rectangle { in-out property <[Node]> nodes; in property node_min: { x: 0px, y: 0px }; in property node_max: { x: 100px, y: 255px }; property graph_padding: 40px; property axis_font_size: 14px; // Text { // x: 0; // text: "Fan PWM"; // } // Text { // x: root.width / 2; // y: root.height - self.height; // text: "Temperature"; // } graph := Rectangle { width: root.width - root.graph_padding * 2; height: root.height - root.graph_padding * 2; x: root.graph_padding; y: root.graph_padding; function scale_x_to_graph(x: length) -> length { ((x - node_min.x) / (node_max.x - node_min.x)) * graph.width } // function scale_y_to_graph(y: length) -> length { ((y - node_min.y) / (node_max.y - node_min.y)) * graph.height } // function scale_x_to_node(x: length) -> length { (x / graph.width) * (node_max.x - node_min.x) } // function scale_y_to_node(y: length) -> length { (y / graph.height) * (node_max.y - node_min.y) } // for n in 11: Path { viewbox-width: self.width / 1px; viewbox-height: self.height / 1px; stroke: Palette.alternate-foreground.darker(200%); stroke-width: 1px; MoveTo { x: scale_x_to_graph(n * 10px) / 1px; y: 0; // scale_y_to_graph(n*1px) / 1px; } LineTo { x: scale_x_to_graph(n * 10px) / 1px; y: graph.height / 1px; //scale_y_to_graph(n*1px) / 1px; } } for n in 11: Text { color: Palette.accent-background; font-size <=> root.axis_font_size; text: "\{n * 10}c"; x: scale_x_to_graph(n * 10px) - self.width / 3; y: graph.height + 2px; } for n in 11: Path { viewbox-width: self.width / 1px; viewbox-height: self.height / 1px; stroke: Palette.alternate-foreground.darker(200%); stroke-width: 1px; MoveTo { x: 0; //scale_x_to_graph(n*10px) / 1px; y: scale_y_to_graph(n * 25.5px) / 1px; } LineTo { x: graph.width / 1px; //scale_x_to_graph(n*10px) / 1px; y: scale_y_to_graph(n * 25.5px) / 1px; } } for n in 11: Text { color: Palette.accent-background; font-size <=> root.axis_font_size; text: "\{n * 10}%"; x: - self.width; y: graph.height - scale_y_to_graph(n * 25.5px) - self.height / 2; } for l[idx] in nodes: path := Rectangle { if idx + 1 != nodes.length: Path { viewbox-width: self.width / 1px; viewbox-height: self.height / 1px; stroke: Palette.control-foreground; stroke-width: 2px; MoveTo { x: scale_x_to_graph(nodes[idx].x) / 1px; y: graph.height / 1px - scale_y_to_graph(nodes[idx].y) / 1px; } LineTo { x: scale_x_to_graph(nodes[idx + 1].x) / 1px; y: graph.height / 1px - scale_y_to_graph(nodes[idx + 1].y) / 1px; } } } for n[idx] in nodes: Rectangle { states [ pressed when touch.pressed: { point.background: Palette.selection-background; tip.background: Palette.selection-background; tip.opacity: 1.0; } hover when touch.has-hover: { point.background: Palette.accent-background; tip.background: Palette.accent-background; tip.opacity: 1.0; } ] // point := Rectangle { background: Palette.control-foreground; x: scale_x_to_graph(n.x) - self.width / 2; y: graph.height - scale_y_to_graph(n.y) - self.height / 2; width: 18px; height: self.width; border-radius: self.width / 2; property pad: 1px; touch := TouchArea { function check() { if idx + 1 < nodes.length && idx > 0 { if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) > nodes[idx + 1].x { n.x = nodes[idx + 1].x - pad; } else if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) < nodes[idx - 1].x { n.x = nodes[idx - 1].x + pad; } if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) > nodes[idx + 1].y { n.y = nodes[idx + 1].y - pad; } else if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) < nodes[idx - 1].y { n.y = nodes[idx - 1].y + pad; } } else if idx == 0 { if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) < 0.0 { n.x = 1px; } else if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) > nodes[idx + 1].x { n.x = nodes[idx + 1].x - pad; } if n.y - scale_y_to_node(self.mouse-y - self.pressed-y) < 0.0 { n.y = 1px; } else if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) > nodes[idx + 1].y { n.y = nodes[idx + 1].y - pad; } } else if idx == nodes.length - 1 { if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) > scale_x_to_node(graph.width) { n.x = scale_x_to_node(graph.width - 1px); } else if n.x + scale_x_to_node(self.mouse-x - self.pressed-x) < nodes[idx - 1].x { n.x = nodes[idx - 1].x + pad; } if n.y - scale_y_to_node(self.mouse-y - self.pressed-y) > scale_y_to_node(graph.height) { n.y = scale_y_to_node(graph.height - 1px); } else if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) < nodes[idx - 1].y { n.y = nodes[idx - 1].y + pad; } } } // moved => { if (self.pressed) { n.x += scale_x_to_node(self.mouse-x - self.pressed-x); n.y -= scale_y_to_node(self.mouse-y - self.pressed-y); self.check(); // nodes[idx] = n; } } clicked => { self.check(); } mouse-cursor: move; } } tip := Rectangle { background: Palette.control-foreground; opacity: 0.3; border-radius: 12px; x: final_x_pos(); y: final_y_pos(); width: label.preferred-width + 14px; height: label.preferred-height + 4px; function x_pos() -> length { scale_x_to_graph(n.x) - label.preferred-width - 8px } // function final_x_pos() -> length { if x_pos() > 0 { x_pos() } else { x_pos() + label.preferred-width } } // function y_pos() -> length { graph.height - scale_y_to_graph(n.y) - self.height - 4px } // function final_y_pos() -> length { if y_pos() > 0 { y_pos() } else { y_pos() + label.preferred-height } } // function fan_pct() -> int { Math.floor(n.y / 1px) / 255 * 100 } // label := Text { color: Palette.accent-foreground; font-size: 14px; text: "\{Math.floor(n.x / 1px)}c, \{fan_pct()}%"; } } } } }