Files
asusctl/rog-control-center/ui/widgets/graph.slint
mihai2mn 3d0caa39e1 feat(rog-control-center): Major UI/UX improvements and new features
- Add software RGB animations for static-only keyboards (rainbow, color cycle)
- Add custom fan curve control via direct sysfs for unsupported laptops
- Add real-time system status bar (CPU/GPU temps, fan speeds, power draw)
- Add tray icon tooltip with live system stats
- Add power profile change notifications (Fn+F5)
- Add dGPU status notifications
- Add ROG theme with dark palette and accent colors
- Add Screenpad, Slash, and SuperGFX page stubs
- Improve fan curve graph UI
- Various UI refinements and fixes

Co-Authored-By: Gemini <noreply@google.com>
2026-01-15 20:09:40 +01:00

246 lines
9.6 KiB
Plaintext

import { Palette } from "std-widgets.slint";
import { RogPalette } from "../themes/rog_theme.slint";
export struct Node { x: length, y: length}
export component Graph inherits Rectangle {
in-out property <[Node]> nodes;
in property <Node> node_min: { x: 0px, y: 0px };
in property <Node> node_max: { x: 100px, y: 255px };
property <length> graph_padding: 40px;
property <length> 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: RogPalette.control-border;
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: RogPalette.text-secondary;
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: RogPalette.control-border;
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: RogPalette.text-secondary;
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: RogPalette.accent;
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: RogPalette.accent;
tip.background: RogPalette.accent;
tip.opacity: 1.0;
}
hover when touch.has-hover: {
point.background: RogPalette.accent;
tip.background: RogPalette.accent;
tip.opacity: 1.0;
}
]
//
point := Rectangle {
background: RogPalette.text-primary;
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 <length> 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;
}
// Y-Axis: Monotonic Non-Decreasing
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; // Allow equality
} 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; // Allow equality
} else if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) < 0.0 {
n.y = 0px;
}
} 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;
}
// Y-Axis: <= Next Point
if n.y - scale_y_to_node(self.mouse-y - self.pressed-y) < 0.0 {
n.y = 0px; // Allow 0 RPM
} 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; // Allow equality
}
} 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;
}
// Y-Axis: >= Previous Point
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);
} 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; // Allow equality
} else if n.y + scale_y_to_node(self.height - self.mouse-y - self.pressed-y) < 0.0 {
n.y = 0px;
}
}
}
//
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: RogPalette.control-background;
opacity: 0.3;
x: final_x_pos();
y: final_y_pos();
width: label.preferred-width;
height: label.preferred-height;
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: RogPalette.text-primary;
font-size: 16px;
text: "\{Math.floor(n.x / 1px)}c, \{fan_pct()}%";
}
}
}
}
}