CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent), MCP server 接入外部 Agent 工具,GUI 开发中。
127 lines
4.0 KiB
Plaintext
127 lines
4.0 KiB
Plaintext
// 自绘无边框标题栏(D16 §1):Metro 一体感 + accent 顶线。
|
||
// 拖拽/最大化/最小化/关闭只发回调,原生窗口操作由 main.rs 接到 Slint Window 平台上
|
||
// (Slint DSL 内无法移动原生窗口)。
|
||
import { Theme } from "../theme/tokens.slint";
|
||
import { Metrics } from "../theme/metrics.slint";
|
||
import { UiText, TextRole } from "label.slint";
|
||
import { AppIcon, IconKind } from "icons.slint";
|
||
|
||
component WindowButton inherits Rectangle {
|
||
in property <IconKind> icon: IconKind.minimize;
|
||
/// 关闭键:hover 用 Metro 红底白字
|
||
in property <bool> danger: false;
|
||
callback clicked();
|
||
|
||
width: Metrics.titlebar-button-width;
|
||
height: Metrics.titlebar-height;
|
||
background: touch.pressed
|
||
? (danger ? Theme.state-danger-hover : Theme.bg-pressed)
|
||
: touch.has-hover ? (danger ? Theme.state-danger : Theme.bg-hover) : transparent;
|
||
animate background { duration: Theme.motion-fast; }
|
||
|
||
AppIcon {
|
||
kind: root.icon;
|
||
icon-size: 12px;
|
||
x: (root.width - self.width) / 2;
|
||
y: (root.height - self.height) / 2;
|
||
tint: root.danger && touch.has-hover ? Theme.fg-on-accent : Theme.fg-primary;
|
||
}
|
||
|
||
touch := TouchArea {
|
||
mouse-cursor: pointer;
|
||
clicked => { root.clicked(); }
|
||
}
|
||
}
|
||
|
||
export component TitleBar inherits Rectangle {
|
||
in property <string> title: "Unlucky Launcher";
|
||
in property <string> subtitle: "";
|
||
in property <bool> maximized: false;
|
||
|
||
callback toggle-maximize();
|
||
callback minimize();
|
||
callback request-close();
|
||
|
||
height: Metrics.titlebar-height;
|
||
background: Theme.bg-titlebar;
|
||
|
||
// accent 顶线(Metro 强调色贯穿)
|
||
Rectangle {
|
||
x: 0;
|
||
y: 0;
|
||
width: root.width;
|
||
height: Metrics.accent-line;
|
||
background: Theme.accent;
|
||
}
|
||
|
||
// 拖拽区:交给原生 `WindowMoveArea`(Slint 1.18 内置,拖过阈值才移动窗口,
|
||
// 并保持子元素可交互)。只覆盖左侧,右侧三个窗口按钮留出来。
|
||
// 平台不支持「系统级窗口移动」时该元素退化为无操作(Qt/部分 Wayland 组合),
|
||
// winit on Windows/macOS/X11 可用——Win7 落在这条路上。
|
||
WindowMoveArea {
|
||
x: 0;
|
||
y: Metrics.accent-line;
|
||
width: root.width - 3 * Metrics.titlebar-button-width;
|
||
height: root.height - Metrics.accent-line;
|
||
}
|
||
|
||
// 应用标记 + 标题
|
||
HorizontalLayout {
|
||
x: Metrics.gap-3;
|
||
y: Metrics.accent-line;
|
||
width: root.width - 3 * Metrics.titlebar-button-width - 2 * Metrics.gap-3;
|
||
height: root.height - Metrics.accent-line;
|
||
spacing: Metrics.gap-2;
|
||
|
||
Rectangle {
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: Metrics.radius-sm;
|
||
background: Theme.accent;
|
||
UiText {
|
||
text: "U";
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
color: Theme.fg-on-accent;
|
||
horizontal-alignment: center;
|
||
vertical-alignment: center;
|
||
}
|
||
}
|
||
|
||
UiText {
|
||
role: TextRole.caption;
|
||
text: root.title;
|
||
font-weight: 600;
|
||
horizontal-stretch: 1;
|
||
}
|
||
|
||
UiText {
|
||
role: TextRole.caption;
|
||
text: root.subtitle;
|
||
color: Theme.fg-secondary;
|
||
}
|
||
}
|
||
|
||
HorizontalLayout {
|
||
x: root.width - 3 * Metrics.titlebar-button-width;
|
||
y: Metrics.accent-line;
|
||
width: 3 * Metrics.titlebar-button-width;
|
||
height: root.height - Metrics.accent-line;
|
||
spacing: 0px;
|
||
|
||
WindowButton {
|
||
icon: IconKind.minimize;
|
||
clicked => { root.minimize(); }
|
||
}
|
||
WindowButton {
|
||
icon: root.maximized ? IconKind.restore : IconKind.maximize;
|
||
clicked => { root.toggle-maximize(); }
|
||
}
|
||
WindowButton {
|
||
icon: IconKind.close;
|
||
danger: true;
|
||
clicked => { root.request-close(); }
|
||
}
|
||
}
|
||
}
|