[ui] flatten desktop surfaces and controls

This commit is contained in:
dijunkun
2026-10-26 14:53:09 +08:00
parent 38d0ce7728
commit ee8dbf4508
18 changed files with 337 additions and 428 deletions
+8 -8
View File
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { ScrollView, TextEdit } from "std-widgets.slint";
import { SettingsDialog, SettingsButton } from "settings_controls.slint";
import { WorkbenchStyle } from "workbench_controls.slint";
@@ -27,11 +27,11 @@ export global AboutStrings {
out property <string> back: GalleryStrings.tr("返回", "Back", "Назад");
}
export component AboutNavigationGroup inherits ShadowSurface {
export component AboutNavigationGroup inherits FlatSurface {
height: rows.preferred-height + 2px;
background: WorkbenchStyle.surface;
border-radius: UiRadius.control;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
clip: true;
rows := VerticalLayout {
x: 1px; y: 1px; width: parent.width - 2px;
@@ -42,13 +42,13 @@ export component AboutNavigationGroup inherits ShadowSurface {
export component AboutRowSeparator inherits Rectangle {
height: 1px;
ShadowSeparator {
SurfaceSeparator {
x: 14px; width: parent.width - 30px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
export component AboutNavigationRow inherits ShadowSurface {
export component AboutNavigationRow inherits FlatSurface {
in property <string> title;
in property <string> subtitle;
in property <string> icon;
@@ -61,7 +61,7 @@ export component AboutNavigationRow inherits ShadowSurface {
background: touch.pressed ? WorkbenchStyle.pressed-surface
: touch.has-hover ? WorkbenchStyle.hover-surface : WorkbenchStyle.surface;
border-radius: root.grouped ? 0px : UiRadius.control;
shadow-enabled: !root.grouped; shadow-color: UiShadow.edge;
outline-enabled: !root.grouped; outline-color: UiSurface.edge;
accessible-role: button;
accessible-label: root.title + (root.subtitle != "" ? ", " + root.subtitle : "")
+ (root.detail != "" ? ", " + root.detail : "");
@@ -227,7 +227,7 @@ export component AboutPanel inherits SettingsDialog {
footer := VerticalLayout {
x: 24px; y: parent.height - self.height - 24px;
width: parent.width - 48px; height: self.preferred-height; spacing: 12px;
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
HorizontalLayout {
alignment: end;
SettingsButton { text: AboutStrings.back; clicked => { root.back(); } }
+29 -46
View File
@@ -1,4 +1,4 @@
import { ShadowSurface, UiShadow } from "ui_shadow.slint";
import { FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
export global FloatingBarStyle {
out property <length> corner-radius: UiRadius.menu;
@@ -199,15 +199,14 @@ export component ImageButton inherits Rectangle {
}
}
export component CompactComboBox inherits ShadowSurface {
shadow-compact: true;
export component CompactComboBox inherits FlatSurface {
in property <[string]> model;
in-out property <int> current-index: 0;
in property <bool> enabled: true;
in property <bool> subtle: false;
in property <bool> show-arrow: true;
in property <color> normal-shadow-color: UiShadow.edge;
in property <color> hover-shadow-color: UiShadow.hover;
in property <color> normal-outline-color: ButtonStyle.border;
in property <color> hover-outline-color: ButtonStyle.hover-border;
property <bool> popup-animation-enabled: false;
property <float> popup-progress: 0.0;
callback selected(int);
@@ -234,17 +233,13 @@ export component CompactComboBox inherits ShadowSurface {
background: !root.enabled ? ControlStyle.disabled
: combo-touch.pressed ? ButtonStyle.pressed
: combo-popup.is-open || combo-touch.has-hover ? ButtonStyle.hover : ButtonStyle.surface;
border-width: 1px;
border-color: !root.enabled ? ButtonStyle.disabled-border
: combo-popup.is-open ? UiShadow.focus
outline-focused: root.enabled && combo-popup.is-open;
outline-color: !root.enabled ? ButtonStyle.disabled-border
: combo-popup.is-open ? UiSurface.focus
: combo-touch.pressed ? ButtonStyle.pressed-border
: combo-touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-enabled: root.enabled && !combo-touch.pressed;
shadow-focused: root.enabled && combo-popup.is-open;
shadow-color: combo-popup.is-open ? UiShadow.focus
: root.enabled && combo-touch.has-hover ? root.hover-shadow-color : root.normal-shadow-color;
: combo-touch.has-hover ? root.hover-outline-color : root.normal-outline-color;
border-radius: UiRadius.control;
animate background, border-color, shadow-color { duration: 120ms; }
animate background, outline-color { duration: 120ms; }
accessible-role: combobox;
accessible-enabled: root.enabled;
accessible-expandable: true;
@@ -267,7 +262,7 @@ export component CompactComboBox inherits ShadowSurface {
width: 18px; height: parent.height;
// Switch glyphs so the software renderer also shows the open state.
text: combo-popup.is-open ? FontAwesomeIcons.angle-up : FontAwesomeIcons.angle-down;
color: !root.enabled ? #98a2b3 : combo-popup.is-open ? UiShadow.focus : ControlStyle.icon;
color: !root.enabled ? #98a2b3 : combo-popup.is-open ? UiSurface.focus : ControlStyle.icon;
font-family: "Font Awesome 6 Free";
font-weight: 900;
font-size: 10px;
@@ -306,7 +301,7 @@ export component CompactComboBox inherits ShadowSurface {
height: root.model.length * 23px + 8px;
close-policy: close-on-click-outside;
ShadowSurface {
FlatSurface {
// Keep the reveal anchored to the popup's top edge while the
// content settles downward into its final position.
y: (1.0 - root.popup-progress) * -8px;
@@ -314,7 +309,7 @@ export component CompactComboBox inherits ShadowSurface {
height: parent.height * root.popup-progress;
opacity: root.popup-progress;
background: white;
shadow-color: root.normal-shadow-color;
outline-color: root.normal-outline-color;
border-radius: UiRadius.menu;
clip: true;
for choice[index] in root.model: Rectangle {
@@ -333,7 +328,7 @@ export component CompactComboBox inherits ShadowSurface {
}
if index == root.current-index: Text {
x: parent.width - 20px; width: 14px; height: parent.height;
text: FontAwesomeIcons.check; color: UiShadow.focus;
text: FontAwesomeIcons.check; color: UiSurface.focus;
font-family: "Font Awesome 6 Free"; font-weight: 900; font-size: 10px;
horizontal-alignment: center; vertical-alignment: center;
accessible-role: none;
@@ -353,23 +348,20 @@ export component CompactComboBox inherits ShadowSurface {
}
}
}
ShadowSurface {
FlatSurface {
width: parent.width;
height: parent.height;
background: transparent;
clip: true;
shadow-color: root.normal-shadow-color;
outline-color: root.normal-outline-color;
border-radius: UiRadius.menu;
border-width: 1px;
border-color: ButtonStyle.border;
z: 2;
}
}
}
}
export component ImGuiCheckBox inherits ShadowSurface {
shadow-compact: true;
export component ImGuiCheckBox inherits FlatSurface {
in-out property <bool> checked;
in property <bool> enabled: true;
@@ -378,7 +370,7 @@ export component ImGuiCheckBox inherits ShadowSurface {
background: !root.enabled ? ControlStyle.disabled
: root.checked ? (check-touch.pressed ? #254cc0 : check-touch.has-hover ? #4574f0 : #3564e3)
: check-touch.pressed ? ControlStyle.pressed : check-touch.has-hover ? ControlStyle.hover : ControlStyle.surface;
shadow-color: check-touch.has-hover && root.enabled ? UiShadow.focus : UiShadow.edge;
outline-color: check-touch.has-hover && root.enabled ? UiSurface.focus : UiSurface.edge;
border-radius: 4px;
if root.checked: Text {
text: FontAwesomeIcons.check;
@@ -419,8 +411,7 @@ export component MiniToggleSwitch inherits Rectangle {
}
}
export component CompactButton inherits ShadowSurface {
shadow-compact: true;
export component CompactButton inherits FlatSurface {
in property <string> text;
in property <length> text-size: ImGuiFontStyle.body;
in property <bool> primary: false;
@@ -434,15 +425,13 @@ export component CompactButton inherits ShadowSurface {
: button-touch.pressed ? (root.primary ? #82b8f2 : ButtonStyle.pressed)
: button-touch.has-hover ? (root.primary ? #b8d9fb : ButtonStyle.hover)
: root.primary ? #a8d0fa : root.quiet ? transparent : ButtonStyle.surface;
border-width: root.quiet ? 0px : 1px;
border-color: !root.enabled ? ButtonStyle.disabled-border
: root.primary ? UiShadow.focus
outline-enabled: !root.quiet;
outline-color: !root.enabled ? ButtonStyle.disabled-border
: root.primary ? UiSurface.focus
: button-touch.pressed ? ButtonStyle.pressed-border
: button-touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-enabled: root.enabled && !root.quiet && !button-touch.pressed;
shadow-color: root.primary ? UiShadow.focus : button-touch.has-hover ? UiShadow.hover : UiShadow.edge;
border-radius: UiRadius.control;
animate background, border-color { duration: 100ms; }
animate background, outline-color { duration: 100ms; }
Text {
text: root.text;
color: root.enabled ? #24272d : #8e9298;
@@ -454,7 +443,7 @@ export component CompactButton inherits ShadowSurface {
button-touch := TouchArea { enabled: root.enabled; mouse-cursor: pointer; clicked => { root.clicked(); } }
}
export component PrimaryButton inherits ShadowSurface {
export component PrimaryButton inherits FlatSurface {
in property <string> text;
in property <length> text-size: 12px;
in property <bool> enabled: true;
@@ -466,9 +455,7 @@ export component PrimaryButton inherits ShadowSurface {
: touch.pressed ? #254cc0
: touch.has-hover ? #4574f0
: #3564e3;
shadow-compact: true;
shadow-enabled: root.enabled && !touch.pressed;
shadow-color: UiShadow.focus;
outline-enabled: false;
border-radius: UiRadius.control;
animate background { duration: 100ms; }
@@ -487,7 +474,7 @@ export component PrimaryButton inherits ShadowSurface {
}
}
export component SecondaryButton inherits ShadowSurface {
export component SecondaryButton inherits FlatSurface {
in property <string> text;
in property <length> text-size: 12px;
in property <bool> enabled: true;
@@ -498,15 +485,11 @@ export component SecondaryButton inherits ShadowSurface {
background: !root.enabled ? ControlStyle.disabled
: touch.pressed ? ButtonStyle.pressed
: touch.has-hover ? ButtonStyle.hover : ButtonStyle.surface;
border-width: 1px;
border-color: !root.enabled ? ButtonStyle.disabled-border
outline-color: !root.enabled ? ButtonStyle.disabled-border
: touch.pressed ? ButtonStyle.pressed-border
: touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-color: touch.has-hover ? UiShadow.hover : UiShadow.edge;
shadow-compact: true;
shadow-enabled: root.enabled && !touch.pressed;
border-radius: UiRadius.control;
animate background, border-color { duration: 100ms; }
animate background, outline-color { duration: 100ms; }
Text {
text: root.text;
@@ -565,8 +548,8 @@ export component SectionTitle inherits Text {
vertical-alignment: center;
}
export component DialogSurface inherits ShadowSurface {
export component DialogSurface inherits FlatSurface {
background: white;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
}
@@ -1,4 +1,4 @@
import { ShadowSurface, UiShadow } from "ui_shadow.slint";
import { FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ScrollView } from "std-widgets.slint";
import { RoundedLineEdit } from "rounded_line_edit.slint";
@@ -21,13 +21,13 @@ export component DeviceGroupDialog inherits Rectangle {
callback cancel();
background: #00000040;
TouchArea {}
dialog := ShadowSurface {
dialog := FlatSurface {
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
width: min(360px, parent.width - 40px);
height: 208px + group-list.height + (root.error == "" ? 0px : 32px);
background: white; border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
TouchArea {}
Text {
x: 18px; y: 16px; height: 24px;
@@ -42,10 +42,10 @@ export component DeviceGroupDialog inherits Rectangle {
x: 18px; y: 67px; width: parent.width - 36px; height: 16px;
text: "ID " + root.device-id; color: #858c97; font-size: 11px;
}
group-list := ShadowSurface {
group-list := FlatSurface {
x: 18px; y: 95px; width: parent.width - 36px;
height: min(5, max(1, root.options.length)) * 32px + 2px;
background: #fbfcfd; shadow-color: UiShadow.edge; border-radius: UiRadius.surface;
background: #fbfcfd; outline-color: UiSurface.edge; border-radius: UiRadius.surface;
clip: true;
ScrollView {
x: 1px; y: 1px; width: parent.width - 2px; height: parent.height - 2px;
@@ -81,10 +81,10 @@ export component DeviceGroupDialog inherits Rectangle {
border-width: UiRadius.surface; border-radius: 2 * UiRadius.surface;
border-color: white;
}
ShadowSurface {
FlatSurface {
width: parent.width; height: parent.height;
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
}
}
RoundedLineEdit {
@@ -1,4 +1,4 @@
import { ShadowSeparator, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, UiSurface } from "ui_surface.slint";
import { FileTransferEntry } from "stream_window.slint";
import { DialogSurface, FontAwesomeIcons, IconButton, ImGuiFontStyle } from "common.slint";
import { WorkbenchStyle, WorkbenchButton } from "workbench_controls.slint";
@@ -27,7 +27,7 @@ export component FileTransferNotification inherits Window {
DialogSurface {
width: parent.width; height: parent.height;
background: WorkbenchStyle.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
Text {
x: 16px; y: 8px;
width: parent.width - 64px - (root.remote-id == "" ? 0px : 108px);
@@ -51,9 +51,9 @@ export component FileTransferNotification inherits Window {
pressed-background: WorkbenchStyle.pressed-surface;
clicked => { root.dismissed(); }
}
ShadowSeparator {
SurfaceSeparator {
x: 16px; y: 40px; width: parent.width - 32px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
Text {
x: 16px; y: 47px; width: parent.width - 32px; height: 18px;
@@ -97,7 +97,7 @@ export component FileTransferNotification inherits Window {
text: root.cancel-text;
text-size: ImGuiFontStyle.base;
text-color: WorkbenchStyle.muted;
normal-shadow-color: UiShadow.edge;
normal-outline-color: UiSurface.edge;
clicked => { root.cancel-requested(); }
}
}
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { CompactButton, FontAwesomeIcons, ControlStyle } from "common.slint";
@@ -89,11 +89,11 @@ export component GalleryMenuButton inherits Rectangle {
color: root.enabled ? #62666d : #8e9298;
horizontal-alignment: center; vertical-alignment: center;
}
if root.compact-trigger: ShadowSurface {
if root.compact-trigger: FlatSurface {
background: more-touch.pressed || popup.is-open ? ControlStyle.selected : more-touch.has-hover ? ControlStyle.hover : white;
border-radius: UiRadius.menu;
shadow-color: trigger-focus.has-focus ? UiShadow.focus : UiShadow.edge;
animate background, shadow-color { duration: 120ms; }
outline-color: trigger-focus.has-focus ? UiSurface.focus : UiSurface.edge;
animate background, outline-color { duration: 120ms; }
for dot in 3: Rectangle {
x: parent.width / 2 - 6px + dot * 5px;
y: (parent.height - self.height) / 2;
@@ -117,12 +117,12 @@ export component GalleryMenuButton inherits Rectangle {
forward-focus: popup-focus;
popup-focus := FocusScope {
key-pressed(event) => { return root.handle-key(event); }
ShadowSurface {
background: white; shadow-color: UiShadow.edge; border-radius: UiRadius.menu;
FlatSurface {
background: white; outline-color: UiSurface.edge; border-radius: UiRadius.menu;
clip: true;
if root.destructive-index > 0: ShadowSeparator {
if root.destructive-index > 0: SurfaceSeparator {
x: 10px; y: root.menu-padding + root.destructive-index * root.row-height + (root.divider-spacing - 1px) / 2;
width: parent.width - 20px; height: 1px; shadow-color: UiShadow.separator;
width: parent.width - 20px; height: 1px; outline-color: UiSurface.separator;
}
for item[index] in root.items: Rectangle {
private property <bool> destructive: index == root.destructive-index;
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { GalleryStrings } from "device_strings.slint";
import { CompactButton } from "common.slint";
@@ -191,13 +191,13 @@ export component GalleryNetworkDialog inherits Rectangle {
callback close();
background: #00000042;
TouchArea { clicked => { root.close(); } }
ShadowSurface {
FlatSurface {
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
width: min(760px, parent.width - 32px);
height: min(120px + root.list-height, parent.height - 32px);
background: white; border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
TouchArea {}
FocusScope {
init => { self.focus(); }
@@ -238,7 +238,7 @@ export component GalleryNetworkDialog inherits Rectangle {
for device[index] in root.devices: NetworkRow {
y: index * root.row-height; width: list.viewport-width; height: root.row-height;
device: device; background: mod(index, 2) == 0 ? white : #f8fafc;
ShadowSeparator { y: parent.height - 1px; height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { y: parent.height - 1px; height: 1px; outline-color: UiSurface.separator; }
}
}
if root.devices.length == 0: NetworkEmptyState {
+40 -40
View File
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { GalleryStrings } from "device_strings.slint";
import { RemoteCursor } from "remote_cursor.slint";
@@ -492,13 +492,13 @@ export component GalleryView inherits Rectangle {
width: parent.width - self.x - (tile-touch.has-hover && !root.batch ? DeviceCardStyle.toolbar-width + 12px : root.batch ? 35px : 9px);
height: 24px; text: tile.name; color: tile.online ? #24272d : DeviceCardStyle.offline-text; font-size: 12px; overflow: elide; vertical-alignment: center;
}
if root.batch && !root.simplified: ShadowSurface {
if root.batch && !root.simplified: FlatSurface {
x: parent.width - 27px; y: parent.height - 27px;
width: 18px; height: 18px; border-radius: 4px;
background: tile.selected ? (tile-touch.pressed ? #254cc0 : tile-touch.has-hover ? #4574f0 : #3564e3)
: tile-touch.pressed ? ControlStyle.pressed : tile-touch.has-hover ? ControlStyle.hover : ControlStyle.surface;
shadow-color: tile.selected ? UiShadow.focus : tile-touch.has-hover ? UiShadow.hover : UiShadow.edge;
animate background, shadow-color { duration: 120ms; }
outline-color: tile.selected ? UiSurface.focus : tile-touch.has-hover ? UiSurface.hover : UiSurface.edge;
animate background, outline-color { duration: 120ms; }
if tile.selected: Text {
text: FontAwesomeIcons.check; color: white;
font-family: "Font Awesome 6 Free"; font-weight: 900; font-size: 11px;
@@ -533,27 +533,27 @@ export component GalleryView inherits Rectangle {
}
}
// Draw each table line once, continuously across occupied and empty cells.
for column in root.columns + 1: ShadowSeparator {
for column in root.columns + 1: SurfaceSeparator {
visible: root.count > 0;
x: min(column * root.card-width, grid.table-width - 1px);
y: 0px;
width: 1px; height: grid.table-height;
vertical: true; shadow-color: root.resizing || (grid.has-hover && grid.edge-x != 0 && grid.column-line == column)
? UiShadow.focus : UiShadow.separator;
vertical: true; outline-color: root.resizing || (grid.has-hover && grid.edge-x != 0 && grid.column-line == column)
? UiSurface.focus : UiSurface.separator;
}
for row in root.rows + 1: ShadowSeparator {
for row in root.rows + 1: SurfaceSeparator {
visible: root.count > 0;
x: 0px;
y: min(row * root.card-height, grid.table-height - 1px);
width: grid.table-width; height: 1px;
shadow-color: root.resizing || (grid.has-hover && grid.edge-y != 0 && grid.row-line == row)
? UiShadow.focus : UiShadow.separator;
outline-color: root.resizing || (grid.has-hover && grid.edge-y != 0 && grid.row-line == row)
? UiSurface.focus : UiSurface.separator;
}
if root.drag-target >= 0: ShadowSurface {
if root.drag-target >= 0: FlatSurface {
x: mod(root.drag-target, root.columns) * root.card-width + 1px;
y: floor(root.drag-target / root.columns) * root.card-height + 1px;
width: root.card-width - 2px; height: root.card-height - 2px;
background: #76aeea26; shadow-color: UiShadow.focus;
background: #76aeea26; outline-color: UiSurface.focus;
}
if root.count == 0: Text {
text: root.simplified
@@ -599,11 +599,11 @@ export component GalleryView inherits Rectangle {
}
GalleryButton { width: 100px; primary: true; enabled: !root.focused.connected || root.controlling || (root.focused.has-frame && !root.focused.stale); text: root.focused.connected ? (root.controlling ? GalleryStrings.tr("释放操控", "Release", "Отпустить") : GalleryStrings.tr("接管操控", "Control", "Управлять")) : GalleryStrings.tr("连接", "Connect", "Подключить"); clicked => { root.action(root.focused.connected ? (root.controlling ? "release" : "control") : "connect", root.focused.id); } }
}
ShadowSurface {
FlatSurface {
x: 0px; y: rail.visible ? focus-divider.y + focus-divider.height : 36px;
width: parent.width; height: parent.height - self.y;
background: root.focused.online ? #eff1f4 : DeviceCardStyle.offline-background; border-radius: UiRadius.surface;
shadow-color: root.controlling ? UiShadow.focus : UiShadow.edge;
outline-color: root.controlling ? UiSurface.focus : UiSurface.edge;
video := Rectangle {
x: 4px; y: 4px; width: parent.width - 8px; height: parent.height - 8px;
background: root.focused.online ? #24272d : DeviceCardStyle.offline-preview;
@@ -670,12 +670,12 @@ export component GalleryView inherits Rectangle {
// Collapse the focused tile and its gap without changing the page model.
width: tile.id == root.focused.id ? 0px : root.rail-slot-width;
height: root.rail-card-height; visible: tile.id != root.focused.id;
rail-card := ShadowSurface {
rail-card := FlatSurface {
private property <string> presence: tile.online ? GalleryStrings.tr("在线", "Online", "В сети")
: tile.presence-known ? GalleryStrings.tr("离线", "Offline", "Не в сети") : GalleryStrings.tr("未知", "Unknown", "Неизвестно");
private property <string> details: tile.name + "\n" + tile.host-name + "\nID: " + tile.id + "\n" + tile.group-names + "\n" + self.presence;
width: root.rail-preview-width + 10px; height: root.rail-card-height; border-radius: UiRadius.surface;
background: tile.online ? #f5f6f8 : DeviceCardStyle.offline-background; shadow-color: UiShadow.edge;
background: tile.online ? #f5f6f8 : DeviceCardStyle.offline-background; outline-color: UiSurface.edge;
accessible-role: button;
accessible-label: self.details;
accessible-action-default => { root.action("focus", tile.id); }
@@ -716,9 +716,9 @@ export component GalleryView inherits Rectangle {
visible: root.focus-rail-visible;
x: 0px; y: rail.y + rail.height; width: parent.width; height: 12px;
private property <bool> highlighted: divider-touch.has-hover || root.focus-resizing || divider-focus.has-focus;
ShadowSeparator {
SurfaceSeparator {
x: 0px; y: 5px; width: parent.width; height: 1px;
shadow-color: focus-divider.highlighted ? UiShadow.focus : UiShadow.separator;
outline-color: focus-divider.highlighted ? UiSurface.focus : UiSurface.separator;
}
Rectangle {
x: (parent.width - self.width) / 2; y: 4px; width: 36px; height: 3px; border-radius: 1.5px;
@@ -777,7 +777,7 @@ export component GalleryView inherits Rectangle {
}
Rectangle {
y: parent.height - 44px; height: 44px; background: #fafbfc;
ShadowSeparator { y: 0px; width: parent.width; height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { y: 0px; width: parent.width; height: 1px; outline-color: UiSurface.separator; }
}
// Connection status and pagination remain available in every selection state.
footer := Rectangle {
@@ -794,8 +794,8 @@ export component GalleryView inherits Rectangle {
}
network-button := SecondaryButton {
x: connection-count.x + connection-count.width + 12px;
min-width: 64px; width: 64px; height: parent.height;
shadow-color: UiShadow.edge; border-radius: UiRadius.control;
width: 64px; height: parent.height;
outline-color: UiSurface.edge; border-radius: UiRadius.control;
text: GalleryStrings.tr("网络状态", "Network", "Сеть");
accessible-role: button;
accessible-label: self.text;
@@ -843,11 +843,11 @@ export component GalleryView inherits Rectangle {
horizontal-alignment: center; vertical-alignment: center;
}
}
if root.dragging: ShadowSurface {
if root.dragging: FlatSurface {
x: clamp(grid.x + root.drag-x + 14px, 8px, parent.width - self.width - 8px);
y: clamp(grid.y + root.drag-y + 14px, 8px, footer.y - self.height - 12px);
width: 224px; height: max(54px, drag-hint.y + drag-hint.height + 9px); z: 10;
background: #fffffff2; shadow-color: UiShadow.focus; border-radius: UiRadius.surface;
background: white; outline-color: UiSurface.focus; border-radius: UiRadius.surface;
Rectangle {
x: 8px; y: 9px; width: 64px; height: 36px;
background: root.dragged-tile.online ? #24272d : DeviceCardStyle.offline-preview;
@@ -865,20 +865,20 @@ export component GalleryView inherits Rectangle {
font-size: 10px; color: #527ca8; wrap: word-wrap;
}
}
if root.swap-save-failed: ShadowSurface {
if root.swap-save-failed: FlatSurface {
x: (parent.width - self.width) / 2; y: footer.y - self.height - 14px;
width: min(420px, parent.width - 32px); height: 36px; z: 10;
background: #fff2f0; shadow-color: UiShadow.edge; border-radius: UiRadius.surface;
background: #fff2f0; outline-color: UiSurface.edge; border-radius: UiRadius.surface;
Text { x: 12px; y: 0px; width: parent.width - 24px; height: parent.height; font-size: 12px; color: #9d4339; vertical-alignment: center;
text: GalleryStrings.tr("换位未保存,请重试", "Couldn't save positions. Please try again.", "Не удалось сохранить порядок. Повторите попытку."); overflow: elide;
}
}
// Device details are rendered by MainWindow; resize hints stay local.
if root.device-tooltip-visible && (root.device-tooltip-id == "resize-grid" || root.device-tooltip-id == "resize-focus"): ShadowSurface {
if root.device-tooltip-visible && (root.device-tooltip-id == "resize-grid" || root.device-tooltip-id == "resize-focus"): FlatSurface {
x: clamp(root.device-tooltip-x, 8px, parent.width - self.width - 8px);
y: clamp(root.device-tooltip-y + self.height > footer.y ? root.device-tooltip-y - self.height - 8px : root.device-tooltip-y, 4px, parent.height - self.height - 4px);
width: min(320px, parent.width - 16px); height: device-tooltip-label.preferred-height + 16px;
background: #22252bf2; shadow-color: UiShadow.edge; border-radius: UiRadius.control;
background: #22252bf2; outline-color: UiSurface.edge; border-radius: UiRadius.control;
device-tooltip-label := Text {
x: 8px; y: 8px; width: parent.width - 16px;
text: root.device-tooltip-text; color: white; font-size: 11px; wrap: word-wrap;
@@ -887,9 +887,9 @@ export component GalleryView inherits Rectangle {
if root.adding: Rectangle {
background: #00000042;
TouchArea {}
add-dialog := ShadowSurface {
add-dialog := FlatSurface {
x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; width: 400px; height: 306px;
background: white; border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge;
function submit() {
if root.add-device(device-id.text, password.text, group.text, remember.checked) {
password.text = "";
@@ -934,18 +934,18 @@ export component GalleryView inherits Rectangle {
if root.importing: Rectangle {
background: #00000042;
TouchArea {}
ShadowSurface {
FlatSurface {
x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; width: 440px; height: 378px;
background: white; border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge;
Text { x: 18px; y: 16px; height: 24px; text: GalleryStrings.tr("从近期连接添加", "Add from recent connections", "Добавить из недавних"); font-size: 16px; }
Text { x: 18px; y: 44px; width: 404px; height: 18px; text: GalleryStrings.tr("加入桌面墙后,可通过批量选择连接", "Add to DeskHub, then select devices to connect.", "Добавьте в DeskHub, затем выберите устройства для подключения."); color: #62666d; font-size: 11px; }
ImGuiCheckBox { x: 18px; y: 74px; enabled: root.recent-available > 0; checked: root.recent-devices.length > 0 && root.recent-selected == root.recent-available; }
Text { x: 45px; y: 74px; height: 21px; text: GalleryStrings.tr("全选", "Select all", "Выбрать все"); color: root.recent-available > 0 ? #24272d : #92969e; font-size: 12px; vertical-alignment: center; }
TouchArea { x: 18px; y: 74px; width: 144px; height: 21px; enabled: root.recent-available > 0; clicked => { root.action("recent-all", ""); } }
Text { x: 224px; y: 74px; width: 198px; height: 21px; text: GalleryStrings.tr("待添加 ", "To add ", "К добавлению ") + root.recent-selected + " / " + root.recent-available; horizontal-alignment: right; vertical-alignment: center; font-size: 12px; color: #62666d; }
ShadowSurface {
FlatSurface {
x: 18px; y: 102px; width: 404px; height: 160px;
shadow-color: UiShadow.edge; border-radius: UiRadius.surface; clip: true;
outline-color: UiSurface.edge; border-radius: UiRadius.surface; clip: true;
recent-list := ScrollView {
x: 1px; y: 1px; width: parent.width - 2px; height: parent.height - 2px;
viewport-width: self.width - 12px;
@@ -975,10 +975,10 @@ export component GalleryView inherits Rectangle {
border-width: UiRadius.surface; border-radius: 2 * UiRadius.surface;
border-color: white;
}
ShadowSurface {
FlatSurface {
width: parent.width; height: parent.height;
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
}
}
Text { x: 18px; y: 274px; width: 60px; height: 30px; text: GalleryStrings.tr("分组", "Group", "Группа"); font-size: 12px; vertical-alignment: center; }
@@ -990,10 +990,10 @@ export component GalleryView inherits Rectangle {
}
if root.confirming: Rectangle {
background: #00000042; TouchArea {}
ShadowSurface {
FlatSurface {
x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2;
width: 360px; height: confirmation-list.height + 118px;
background: white; border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge;
Text {
x: 20px; y: 18px; width: parent.width - 132px; height: 24px;
text: root.action-code == "disconnect" ? GalleryStrings.tr("断开连接", "Disconnect devices", "Отключение") : root.action-name;
@@ -1004,10 +1004,10 @@ export component GalleryView inherits Rectangle {
background: #eff3f8; border-radius: UiRadius.surface;
Text { text: GalleryStrings.device-count(root.selected-count); color: #626e7d; font-size: 11px; horizontal-alignment: center; vertical-alignment: center; }
}
confirmation-list := ShadowSurface {
confirmation-list := FlatSurface {
x: 20px; y: 58px; width: parent.width - 40px;
height: clamp(root.selected-devices.length * 52px + 2px, 54px, 210px);
background: #fcfdfe; shadow-color: UiShadow.edge; border-radius: UiRadius.surface; clip: true;
background: #fcfdfe; outline-color: UiSurface.edge; border-radius: UiRadius.surface; clip: true;
confirmation-scroll := ScrollView {
x: 1px; y: 1px; width: parent.width - 2px; height: parent.height - 2px;
viewport-width: self.width - 12px;
@@ -1023,7 +1023,7 @@ export component GalleryView inherits Rectangle {
Rectangle { x: 9px; y: 7px; width: 6px; height: 6px; border-radius: 3px; background: device.connected ? #27a762 : #a0a6b0; }
Text { x: 21px; width: parent.width - 27px; height: parent.height; text: device.connected ? GalleryStrings.tr("已连接", "Connected", "Подключено") : GalleryStrings.tr("未连接", "Not connected", "Нет соединения"); color: device.connected ? #348259 : #858d98; font-size: 10px; vertical-alignment: center; }
}
if index + 1 < root.selected-devices.length: ShadowSeparator { x: 12px; y: parent.height - 1px; width: parent.width - 24px; height: 1px; shadow-color: UiShadow.separator; }
if index + 1 < root.selected-devices.length: SurfaceSeparator { x: 12px; y: parent.height - 1px; width: parent.width - 24px; height: 1px; outline-color: UiSurface.separator; }
}
}
}
+15 -15
View File
@@ -1,14 +1,14 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ScrollView } from "std-widgets.slint";
import { FontAwesomeIcons, ControlStyle } from "common.slint";
// Shared by history and DeskHub; system choices precede the named groups.
export component GroupFilter inherits ShadowSurface {
export component GroupFilter inherits FlatSurface {
in property <[string]> model;
in property <int> system-count: 2;
in property <bool> enabled: true;
// An embedded picker shares its enclosing field's shadow and focus glow.
// An embedded picker shares its enclosing field's outline and focus state.
in property <bool> embedded: false;
in property <bool> show-indicator: true;
in property <length> popup-min-width: 0px;
@@ -16,9 +16,9 @@ export component GroupFilter inherits ShadowSurface {
in property <int> text-weight: 400;
in property <color> text-color: #30343b;
in property <color> normal-background: ControlStyle.surface;
in property <color> normal-shadow-color: UiShadow.edge;
in property <color> hover-shadow-color: UiShadow.hover;
in property <color> focus-shadow-color: UiShadow.focus;
in property <color> normal-outline-color: UiSurface.edge;
in property <color> hover-outline-color: UiSurface.hover;
in property <color> focus-outline-color: UiSurface.focus;
in-out property <int> current-index: 0;
out property <bool> has-focus: trigger-focus.has-focus || popup.is-open;
out property <bool> has-hover: root.enabled && trigger-touch.has-hover && !popup.is-open;
@@ -40,12 +40,12 @@ export component GroupFilter inherits ShadowSurface {
: !root.enabled ? ControlStyle.disabled
: trigger-touch.pressed || popup.is-open ? ControlStyle.pressed
: trigger-touch.has-hover ? ControlStyle.hover : root.normal-background;
shadow-enabled: !root.embedded;
shadow-focused: popup.is-open || trigger-focus.has-focus;
shadow-color: popup.is-open || trigger-focus.has-focus ? root.focus-shadow-color
: trigger-touch.has-hover ? root.hover-shadow-color : root.normal-shadow-color;
outline-enabled: !root.embedded;
outline-focused: popup.is-open || trigger-focus.has-focus;
outline-color: popup.is-open || trigger-focus.has-focus ? root.focus-outline-color
: trigger-touch.has-hover ? root.hover-outline-color : root.normal-outline-color;
border-radius: UiRadius.control;
animate background, shadow-color { duration: 100ms; easing: ease-out; }
animate background, outline-color { duration: 100ms; easing: ease-out; }
forward-focus: trigger-focus;
accessible-role: combobox;
accessible-enabled: root.enabled;
@@ -140,13 +140,13 @@ export component GroupFilter inherits ShadowSurface {
forward-focus: popup-focus;
popup-focus := FocusScope {
key-pressed(event) => { return root.handle-key(event); }
ShadowSurface {
FlatSurface {
y: (1 - root.popup-progress) * -4px;
width: parent.width; height: parent.height;
opacity: root.popup-progress;
background: white;
clip: true;
shadow-color: root.normal-shadow-color; border-radius: UiRadius.menu;
outline-color: root.normal-outline-color; border-radius: UiRadius.menu;
ScrollView {
x: 4px; y: 4px; width: parent.width - 8px; height: parent.height - 8px;
viewport-width: self.width;
@@ -154,9 +154,9 @@ export component GroupFilter inherits ShadowSurface {
viewport-y <=> root.scroll-y;
Rectangle {
width: parent.width; height: root.list-height;
if root.has-divider: ShadowSeparator {
if root.has-divider: SurfaceSeparator {
x: 6px; y: root.system-count * 26px + 3px;
width: parent.width - 12px; height: 1px; shadow-color: UiShadow.separator;
width: parent.width - 12px; height: 1px; outline-color: UiSurface.separator;
}
for choice[index] in root.model: Rectangle {
y: index * 26px + (root.has-divider && index >= root.system-count ? 6px : 0px);
@@ -1,9 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<defs>
<radialGradient id="edge">
<stop offset="95%" stop-color="white"/>
<stop offset="100%" stop-color="white" stop-opacity="0"/>
</radialGradient>
</defs>
<circle cx="32" cy="32" r="32" fill="url(#edge)"/>
<circle cx="32" cy="32" r="31" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 139 B

+101 -122
View File
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { LanStrings } from "lan_strings.slint";
import { AboutPanel, AboutPage, AboutComponent, AboutStrings, AboutNavigationRow, AboutNavigationGroup, AboutRowSeparator } from "about_panel.slint";
import { UiRadius } from "ui_radius.slint";
@@ -210,7 +210,7 @@ component DialogPromptText inherits Rectangle {
}
// Use the same plain-text field for connection and password changes.
component PasswordInput inherits ShadowSurface {
component PasswordInput inherits FlatSurface {
in-out property <string> text;
in property <int> max-length: 0;
in property <length> text-size: ImGuiFontStyle.base;
@@ -221,9 +221,8 @@ component PasswordInput inherits ShadowSurface {
width: 70px;
height: 23px;
background: editor.has-focus ? ControlStyle.input-focused : ControlStyle.input-surface;
shadow-color: root.error ? UiShadow.error : editor.has-focus ? UiShadow.focus : UiShadow.edge;
shadow-focused: editor.has-focus || root.error;
shadow-compact: true;
outline-color: root.error ? UiSurface.error : editor.has-focus ? UiSurface.focus : UiSurface.edge;
outline-focused: editor.has-focus || root.error;
border-radius: UiRadius.control;
clip: true;
forward-focus: editor;
@@ -943,10 +942,10 @@ export component MainWindow inherits Window {
clicked => { root.close-main-window(); }
}
}
ShadowSeparator {
SurfaceSeparator {
y: parent.height - 1px;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
@@ -1030,10 +1029,10 @@ export component MainWindow inherits Window {
}
close-touch := TouchArea { clicked => { root.close-main-window(); } }
}
ShadowSeparator {
SurfaceSeparator {
y: parent.height - 1px;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
@@ -1096,12 +1095,12 @@ export component MainWindow inherits Window {
// Slint owns the client area below the native macOS title bar. Draw
// the boundary here because AppKit's titlebar separator is not shown
// reliably when winit creates a window without an NSToolbar.
ShadowSeparator {
SurfaceSeparator {
x: 0px;
y: 0px;
width: parent.width;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
z: 7;
}
@@ -1168,13 +1167,13 @@ export component MainWindow inherits Window {
clicked => { root.gallery-action("release", ""); root.menu-open = !root.menu-open; }
}
// Unread messages take precedence so the menu has only one indicator.
if !root.gallery-mode && root.update-available && root.announcement-unread <= 0: ShadowSurface {
if !root.gallery-mode && root.update-available && root.announcement-unread <= 0: FlatSurface {
x: menu-button.x + menu-button.width - self.width + 4px;
y: menu-button.y - 1px;
width: 16px;
height: 16px;
border-radius: 8px;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
background: WorkbenchStyle.accent;
opacity: root.menu-open || mod(animation-tick(), 2s) < 1s ? 1 : 0;
z: 9;
@@ -1208,13 +1207,13 @@ export component MainWindow inherits Window {
clicked => { root.gallery-action("release", ""); root.menu-open = !root.menu-open; }
}
}
if !root.gallery-mode && root.announcement-unread > 0: ShadowSurface {
if !root.gallery-mode && root.announcement-unread > 0: FlatSurface {
x: menu-button.x + menu-button.width - self.width + 4px;
y: menu-button.y - 1px;
width: max(16px, unread-badge-label.preferred-width + 8px);
height: 16px;
border-radius: 8px;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
background: #d92d20;
z: 9;
accessible-role: button;
@@ -1286,7 +1285,7 @@ export component MainWindow inherits Window {
lan-port-editor.select-all();
}
}
local-address-field := ShadowSurface {
local-address-field := FlatSurface {
x: 16px; y: 90px; width: parent.width - 32px; height: 40px;
// Size the endpoint as one line; reserve five port digits so
// editing never shifts the IP or changes the font size.
@@ -1305,14 +1304,13 @@ export component MainWindow inherits Window {
// parent's stacking order above the following password row.
z: 1;
background: ControlStyle.input-surface; border-radius: UiRadius.control;
shadow-compact: true;
shadow-color: !root.lan-mode ? UiShadow.edge
: root.lan-endpoint-error != "" ? UiShadow.error
: lan-ip-picker.has-focus || root.lan-port-editing ? UiShadow.focus
: UiShadow.edge;
animate shadow-color { duration: 120ms; }
outline-color: !root.lan-mode ? UiSurface.edge
: root.lan-endpoint-error != "" ? UiSurface.error
: lan-ip-picker.has-focus || root.lan-port-editing ? UiSurface.focus
: UiSurface.edge;
animate outline-color { duration: 120ms; }
if !root.lan-mode: Text { x: 12px; width: parent.width - 64px; height: parent.height; text: root.local-id; font-size: 24px; font-weight: 600; letter-spacing: 1px; overflow: elide; color: WorkbenchStyle.text; vertical-alignment: center; }
ShadowSeparator { x: parent.width - 48px; y: 10px; width: 1px; height: parent.height - 20px; vertical: true; shadow-color: UiShadow.separator; }
SurfaceSeparator { x: parent.width - 48px; y: 10px; width: 1px; height: parent.height - 20px; vertical: true; outline-color: UiSurface.separator; }
lan-ip-picker := GroupFilter {
visible: root.lan-mode;
x: 4px; y: 2px;
@@ -1325,9 +1323,9 @@ export component MainWindow inherits Window {
model: root.lan-interfaces; system-count: 0;
current-index <=> root.lan-interface-draft-index;
enabled: root.lan-mode && !root.lan-password-pending && root.lan-interfaces.length > 0;
normal-shadow-color: UiShadow.edge;
hover-shadow-color: UiShadow.hover;
focus-shadow-color: WorkbenchStyle.accent;
normal-outline-color: UiSurface.edge;
hover-outline-color: UiSurface.hover;
focus-outline-color: WorkbenchStyle.accent;
accessible-label: GalleryStrings.tr("切换本机 IP", "Switch local IP", "Сменить локальный IP");
selected(index) => {
root.copy-feedback = CopyFeedback.idle;
@@ -1352,7 +1350,7 @@ export component MainWindow inherits Window {
font-weight: 600; color: WorkbenchStyle.text;
horizontal-alignment: center; vertical-alignment: center;
}
lan-port-field := ShadowSurface {
lan-port-field := FlatSurface {
visible: root.lan-mode;
x: lan-ip-picker.x + lan-ip-picker.width + 2px; y: 2px;
width: lan-port-metrics.preferred-width * local-address-field.lan-font-scale + 4px;
@@ -1360,8 +1358,8 @@ export component MainWindow inherits Window {
background: lan-port-editor.has-focus ? ControlStyle.input-focused
: lan-port-hover.has-hover ? ControlStyle.hover : transparent;
border-radius: UiRadius.control;
shadow-color: lan-port-editor.has-focus ? UiShadow.focus : transparent;
animate background, shadow-color { duration: 120ms; }
outline-color: lan-port-editor.has-focus ? UiSurface.focus : transparent;
animate background, outline-color { duration: 120ms; }
lan-port-hover := TouchArea {
enabled: root.lan-mode && !root.lan-password-pending;
mouse-cursor: text;
@@ -1444,13 +1442,12 @@ export component MainWindow inherits Window {
}
}
Text { x: 16px; y: 138px; height: 18px; text: UiStrings.password; font-size: 12px; color: WorkbenchStyle.muted; }
ShadowSurface {
FlatSurface {
x: 16px; y: 158px; width: parent.width - 32px; height: 36px;
background: ControlStyle.input-surface; border-radius: UiRadius.control;
shadow-color: UiShadow.edge;
shadow-compact: true;
outline-color: UiSurface.edge;
Text { x: 12px; width: parent.width - 132px; height: parent.height; text: root.active-password == "" ? "—" : root.active-password-visible ? root.active-password : "••••••"; font-size: 20px; font-weight: 500; letter-spacing: 2px; color: WorkbenchStyle.text; vertical-alignment: center; }
ShadowSeparator { x: parent.width - 118px; y: 8px; width: 1px; height: parent.height - 16px; vertical: true; shadow-color: UiShadow.separator; }
SurfaceSeparator { x: parent.width - 118px; y: 8px; width: 1px; height: parent.height - 16px; vertical: true; outline-color: UiSurface.separator; }
WorkbenchButton {
x: parent.width - 112px; y: 0px; width: 36px; quiet: true;
icon: root.active-password-visible ? FontAwesomeIcons.eye : FontAwesomeIcons.eye-slash;
@@ -1477,14 +1474,13 @@ export component MainWindow inherits Window {
Text { x: 16px; y: 14px; width: parent.width - 32px; height: 24px; overflow: elide; text: UiStrings.remote-desktop; font-size: 16px; font-weight: 600; color: WorkbenchStyle.text; }
Text { x: 16px; y: 38px; width: parent.width - 32px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("输入 IP:端口,通过局域网连接", "Enter IP:port to connect over LAN", "Введите IP:порт для подключения по LAN") : GalleryStrings.tr("输入设备 ID,连接远程桌面", "Enter a device ID to start a remote session", "Введите ID для удалённого подключения"); font-size: 11px; color: WorkbenchStyle.muted; overflow: elide; }
Text { x: 16px; y: 68px; height: 18px; text: root.lan-mode ? GalleryStrings.tr("远端 IP / 端口", "Remote IP / Port", "Удалённый IP / Порт") : UiStrings.remote-id; font-size: 12px; color: WorkbenchStyle.muted; }
ShadowSurface {
FlatSurface {
x: 16px; y: 90px; width: parent.width - 32px; height: 40px;
background: remote-id-editor.has-focus ? ControlStyle.input-focused : ControlStyle.input-surface;
shadow-compact: true;
border-radius: UiRadius.control;
shadow-color: root.connection-input-error != "" ? UiShadow.error : remote-id-editor.has-focus ? UiShadow.focus : UiShadow.edge;
shadow-focused: remote-id-editor.has-focus || root.connection-input-error != "";
animate shadow-color { duration: 120ms; }
outline-color: root.connection-input-error != "" ? UiSurface.error : remote-id-editor.has-focus ? UiSurface.focus : UiSurface.edge;
outline-focused: remote-id-editor.has-focus || root.connection-input-error != "";
animate outline-color { duration: 120ms; }
if root.remote-id-input == "": Text {
x: 12px; width: parent.width - 24px; height: parent.height;
text: root.lan-mode ? "192.168.1.20:52888" : GalleryStrings.tr("请输入 9 位设备 ID", "Enter a 9-digit device ID", "Введите ID из 9 цифр");
@@ -1538,24 +1534,23 @@ export component MainWindow inherits Window {
x: parent.width - self.width - 20px; y: 0px;
width: 155px; height: 32px;
normal-background: white;
normal-shadow-color: UiShadow.edge;
hover-shadow-color: UiShadow.hover;
focus-shadow-color: WorkbenchStyle.accent;
normal-outline-color: UiSurface.edge;
hover-outline-color: UiSurface.hover;
focus-outline-color: WorkbenchStyle.accent;
model: root.recent-groups;
current-index <=> root.recent-group-index;
selected(index) => { root.recent-group-selected(index); }
}
recent-list := ShadowSurface {
recent-list := FlatSurface {
x: 20px;
y: 36px;
width: parent.width - 40px;
height: 142px;
// A continuous inset surface groups the cards into one
// horizontal scrolling lane, including its scrollbar.
background: root.recent-connections.length > 0 ? #e6edf6 : transparent;
shadow-enabled: root.recent-connections.length > 0;
shadow-color: UiShadow.edge;
// A light flat surface groups the cards and their scrollbar.
background: root.recent-connections.length > 0 ? #f5f7fb : transparent;
outline-enabled: root.recent-connections.length > 0;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
clip: true;
@@ -1627,11 +1622,10 @@ export component MainWindow inherits Window {
width: parent.width;
height: root.recent-preview-height;
background: !connection-card.available ? DeviceCardStyle.offline-preview :
connection.platform == "windows" ? @linear-gradient(135deg, #1f61b3, #337ac4) :
connection.platform == "macos" ? @linear-gradient(135deg, #6e4aad, #8c63c4) :
connection.platform == "linux" ? @linear-gradient(135deg, #a14f14, #ba631f) :
connection.platform == "ios" ? @linear-gradient(135deg, #146e66, #1f8278) :
@linear-gradient(135deg, #596675, #737d8c);
connection.platform == "windows" ? #296ebc :
connection.platform == "macos" ? #7d57b9 :
connection.platform == "linux" ? #ad591a :
connection.platform == "ios" ? #19786f : #667282;
if connection.has-thumbnail: Image {
width: parent.width;
height: parent.height;
@@ -1678,7 +1672,7 @@ export component MainWindow inherits Window {
width: parent.width;
height: 44px;
background: white;
ShadowSeparator { x: 0px; y: 0px; width: parent.width; height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { x: 0px; y: 0px; width: parent.width; height: 1px; outline-color: UiSurface.separator; }
Text {
x: 12px; y: 5px; height: 19px;
width: parent.width - 56px;
@@ -1812,11 +1806,11 @@ export component MainWindow inherits Window {
}
}
}
ShadowSurface {
FlatSurface {
width: parent.width; height: 124px;
border-radius: UiRadius.surface;
shadow-color: card-touch.has-hover || card-menu.menu-open ? UiShadow.hover : UiShadow.edge;
animate shadow-color { duration: 120ms; }
outline-color: card-touch.has-hover || card-menu.menu-open ? UiSurface.hover : UiSurface.edge;
animate outline-color { duration: 120ms; }
}
}
}
@@ -1873,10 +1867,10 @@ export component MainWindow inherits Window {
y: parent.height - 28px;
height: 28px;
background: white;
ShadowSeparator {
SurfaceSeparator {
y: 0px;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
Rectangle {
x: 20px; y: 11px; width: 6px; height: 6px; border-radius: 3px;
@@ -1927,7 +1921,7 @@ export component MainWindow inherits Window {
// Shared device details sit outside the clipped recent list and wall rail,
// below the modal layer (z >= 39).
if (root.gallery-mode ? gallery.hovered-device.id != "" : root.recent-tooltip-visible)
&& !root.connection-dialog-open && !root.lan-open: device-tip := ShadowSurface {
&& !root.connection-dialog-open && !root.lan-open: device-tip := FlatSurface {
private property <string> device-name: root.gallery-mode ? gallery.hovered-device.name : root.recent-tooltip-name;
private property <string> host-name: root.gallery-mode ? gallery.hovered-device.host-name : root.recent-tooltip-host;
private property <string> device-id: root.gallery-mode ? gallery.hovered-device.id : root.recent-tooltip-id;
@@ -1954,11 +1948,8 @@ export component MainWindow inherits Window {
self.label-width + max(tooltip-id.preferred-width, tooltip-groups.preferred-width) + 32px));
height: tooltip-groups.y + tooltip-groups.height + 10px;
background: WorkbenchStyle.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.menu;
drop-shadow-color: #14294424;
drop-shadow-blur: 14px;
drop-shadow-offset-y: 4px;
z: 20;
tooltip-name-label := Text {
@@ -1997,11 +1988,11 @@ export component MainWindow inherits Window {
color: WorkbenchStyle.muted; font-size: 10px;
wrap: word-wrap;
}
tooltip-divider := ShadowSeparator {
tooltip-divider := SurfaceSeparator {
x: 12px; y: tooltip-name.y + tooltip-name.height
+ (device-tip.has-host-name ? tooltip-host.height + 3px : 0px) + 8px;
width: parent.width - 24px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
tooltip-id-label := Text {
x: 12px; y: tooltip-divider.y + 7px;
@@ -2048,7 +2039,7 @@ export component MainWindow inherits Window {
}
// Expand downward from the application toolbar.
if !root.gallery-mode && root.menu-open: ShadowSurface {
if !root.gallery-mode && root.menu-open: FlatSurface {
x: menu-button.x + menu-button.width - self.width;
y: menu-button.y + menu-button.height + 6px;
width: max(128px, max(menu-settings-label.preferred-width,
@@ -2056,7 +2047,7 @@ export component MainWindow inherits Window {
menu-about-label.preferred-width + (root.update-available ? menu-update-badge.width + 8px : 0px))) + 28px);
height: application-menu-content.preferred-height;
background: WorkbenchStyle.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.menu;
z: 10;
TouchArea { }
@@ -2089,9 +2080,9 @@ export component MainWindow inherits Window {
}
Rectangle {
height: 7px;
ShadowSeparator {
SurfaceSeparator {
x: 8px; y: 3px; width: parent.width - 16px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
menu-messages := Rectangle {
@@ -2138,9 +2129,9 @@ export component MainWindow inherits Window {
}
Rectangle {
height: 7px;
ShadowSeparator {
SurfaceSeparator {
x: 8px; y: 3px; width: parent.width - 16px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
menu-about := Rectangle {
@@ -2311,7 +2302,7 @@ export component MainWindow inherits Window {
DialogPromptText { prompt: UiStrings.edit-alias; }
RoundedLineEdit {
height: 28px;
normal-shadow-color: UiShadow.edge;
normal-outline-color: UiSurface.edge;
text <=> root.alias-input;
accepted => {
root.recent-edit-alias(root.alias-remote-id, root.alias-input);
@@ -2386,7 +2377,7 @@ export component MainWindow inherits Window {
y: (parent.height - self.height) / 2;
width: min(420px, parent.width - 40px);
height: disconnect-content.preferred-height;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
TouchArea { scroll-event(event) => { accept } }
disconnect-content := VerticalLayout {
padding: 24px;
@@ -2535,8 +2526,7 @@ export component MainWindow inherits Window {
y: (parent.height - self.height) / 2;
width: min(400px, parent.width - 40px);
height: permission-content.preferred-height;
background: #f8fafc; shadow-color: UiShadow.edge;
drop-shadow-color: #14294424; drop-shadow-blur: 24px; drop-shadow-offset-y: 8px;
background: #f8fafc; outline-color: UiSurface.edge;
TouchArea { clicked => { focus-sink.focus(); } }
permission-content := VerticalLayout {
padding: 24px; spacing: 20px;
@@ -2607,7 +2597,7 @@ export component MainWindow inherits Window {
}
VerticalLayout {
spacing: 12px;
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
Text {
text: GalleryStrings.tr("请在系统设置中允许 CrossDesk 访问。如系统提示重新打开应用,请按提示操作。",
"Allow CrossDesk access in System Settings. Reopen the app if macOS asks you to.",
@@ -2628,13 +2618,12 @@ export component MainWindow inherits Window {
// Center every content section; the scrollbar sits in the right margin.
private property <length> content-inset: 26px;
private property <length> scrollbar-gutter: 22px;
private property <length> shadow-gutter: 6px;
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
width: min(400px, parent.width - 40px);
height: min(446px, parent.height - 16px);
background: #f8fafc; border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
drop-shadow-color: #14294424; drop-shadow-blur: 24px; drop-shadow-offset-y: 8px;
background: #f8fafc; border-radius: UiRadius.surface; outline-color: UiSurface.edge;
TouchArea { clicked => { focus-sink.focus(); } }
Text {
x: settings-dialog.content-inset; y: 18px;
@@ -2642,12 +2631,12 @@ export component MainWindow inherits Window {
text: UiStrings.settings; font-size: 20px; font-weight: 600; color: #22324a;
}
// Match the compact connection-mode switch, centered in the tab row.
ShadowSurface {
FlatSurface {
x: settings-dialog.content-inset; y: 62px;
width: parent.width - 2 * settings-dialog.content-inset; height: 28px;
background: WorkbenchStyle.field-surface; border-radius: UiRadius.control;
border-width: 1px; border-color: WorkbenchStyle.accent;
shadow-compact: true; shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
Rectangle {
x: root.settings-tab == 1 ? parent.width / 2 + 1px : 2px;
y: 2px; width: (parent.width - 6px) / 2; height: parent.height - 4px;
@@ -2672,9 +2661,9 @@ export component MainWindow inherits Window {
}
}
if root.settings-tab == 0: settings-scroll := ScrollView {
x: settings-dialog.content-inset - settings-dialog.shadow-gutter; y: 108px;
x: settings-dialog.content-inset; y: 108px;
width: parent.width - 2 * settings-dialog.content-inset
+ settings-dialog.scrollbar-gutter + settings-dialog.shadow-gutter;
+ settings-dialog.scrollbar-gutter;
height: parent.height - 174px - (root.settings-save-error == "" ? 0px : 28px);
viewport-width: self.visible-width;
viewport-height: settings-content.preferred-height;
@@ -2688,9 +2677,7 @@ export component MainWindow inherits Window {
width: settings-scroll.viewport-width;
height: settings-scroll.viewport-height;
settings-content := VerticalLayout {
// Keep the six outer shadow layers inside the scroll clip
// without moving or narrowing the settings cards.
padding: 0px; padding-left: settings-dialog.shadow-gutter;
padding: 0px;
padding-right: settings-dialog.scrollbar-gutter; padding-bottom: 4px;
spacing: 14px;
SettingsGroup {
@@ -2785,9 +2772,9 @@ export component MainWindow inherits Window {
width: parent.width - 2 * settings-dialog.content-inset; height: 24px;
text: root.settings-save-error; font-size: 11px; color: #c53e3e; wrap: word-wrap;
}
ShadowSeparator {
SurfaceSeparator {
x: settings-dialog.content-inset; y: parent.height - 64px;
width: parent.width - 2 * settings-dialog.content-inset; height: 1px; shadow-color: UiShadow.separator;
width: parent.width - 2 * settings-dialog.content-inset; height: 1px; outline-color: UiSurface.separator;
}
HorizontalLayout {
x: settings-dialog.content-inset; y: parent.height - 50px;
@@ -2813,8 +2800,7 @@ export component MainWindow inherits Window {
x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2;
width: min(460px, parent.width - 32px);
height: min(380px, parent.height - 24px);
background: #f8fafc; shadow-color: UiShadow.edge;
drop-shadow-color: #14294424; drop-shadow-blur: 18px; drop-shadow-offset-y: 6px;
background: #f8fafc; outline-color: UiSurface.edge;
TouchArea { clicked => { focus-sink.focus(); } }
Text {
x: 24px; y: 18px; width: parent.width - 48px; height: 26px;
@@ -2867,8 +2853,7 @@ export component MainWindow inherits Window {
x: (parent.width - self.width) / 2;
y: (parent.height - self.height) / 2;
width: 360px; height: root.self-host-settings-error == "" ? 266px : 322px;
border-radius: UiRadius.surface; shadow-color: UiShadow.edge; background: #f8fafc;
drop-shadow-color: #14294424; drop-shadow-blur: 18px; drop-shadow-offset-y: 6px;
border-radius: UiRadius.surface; outline-color: UiSurface.edge; background: #f8fafc;
TouchArea { clicked => { focus-sink.focus(); } }
Text {
x: 18px; y: 18px; width: parent.width - 36px; height: 24px;
@@ -2878,21 +2863,21 @@ export component MainWindow inherits Window {
RoundedLineEdit {
x: 18px; y: 80px; width: parent.width - 36px; height: 30px;
surrounding-background: #f8fafc;
normal-shadow-color: UiShadow.edge;
normal-outline-color: UiSurface.edge;
text <=> root.server-host;
}
Text { x: 18px; y: 120px; width: parent.width - 36px; height: 20px; text: UiStrings.server-port; color: #34445a; font-size: 12px; overflow: elide; vertical-alignment: center; }
RoundedLineEdit {
x: 18px; y: 144px; width: parent.width - 36px; height: 30px;
surrounding-background: #f8fafc;
normal-shadow-color: UiShadow.edge;
normal-outline-color: UiSurface.edge;
text <=> root.server-port; input-type: InputType.number;
}
if root.self-host-settings-error != "": Text {
x: 18px; y: 186px; width: parent.width - 36px; height: 48px;
text: root.self-host-settings-error; color: #c53e3e; font-size: 11px; wrap: word-wrap;
}
ShadowSeparator { x: 18px; y: parent.height - 66px; width: parent.width - 36px; height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { x: 18px; y: parent.height - 66px; width: parent.width - 36px; height: 1px; outline-color: UiSurface.separator; }
SettingsButton { x: parent.width - 114px; y: parent.height - 50px; width: 92px; primary: true; text: UiStrings.ok; clicked => { if root.save-self-hosted-settings() { root.self-host-settings-open = false; } } }
SettingsButton { x: parent.width - 204px; y: parent.height - 50px; width: 80px; text: UiStrings.cancel; clicked => { root.cancel-self-hosted-settings(); root.self-host-settings-open = false; } }
}
@@ -2930,7 +2915,7 @@ export component MainWindow inherits Window {
color: WorkbenchStyle.muted; font-size: 12px; wrap: word-wrap;
font-family: "CrossDesk Message Spacing";
}
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
HorizontalLayout {
alignment: end;
SettingsButton {
@@ -2998,11 +2983,11 @@ export component MainWindow inherits Window {
width: about-scroll.width; height: self.preferred-height;
// Keep the expanding scrollbar outside the content.
padding: 0px; padding-right: 22px; spacing: 16px;
ShadowSurface {
FlatSurface {
height: max(80px, product-info.preferred-height + 32px);
background: WorkbenchStyle.surface;
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
Image {
x: 16px; y: (parent.height - self.height) / 2;
width: 56px; height: 56px;
@@ -3019,11 +3004,11 @@ export component MainWindow inherits Window {
}
}
}
if root.update-available: ShadowSurface {
if root.update-available: FlatSurface {
height: update-summary.preferred-height + 24px;
background: WorkbenchStyle.field-surface;
border-radius: UiRadius.control;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
update-summary := VerticalLayout {
x: 12px; y: 12px; width: parent.width - 24px;
height: self.preferred-height;
@@ -3093,7 +3078,7 @@ export component MainWindow inherits Window {
x: 24px; y: parent.height - self.height - 24px;
width: parent.width - 48px; height: self.preferred-height;
spacing: 16px;
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
if root.update-status-text != "": Text {
text: root.update-status-text;
color: root.update-check-status == UpdateCheckStatus.failed ? #b3261e
@@ -3137,10 +3122,7 @@ export component MainWindow inherits Window {
// Use the same content area for sizing and centering the dialog.
height: min(488px, parent.height - 32px);
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
drop-shadow-color: #07142b24;
drop-shadow-blur: 24px;
drop-shadow-offset-y: 8px;
outline-color: UiSurface.edge;
VerticalLayout {
padding: 24px;
@@ -3193,9 +3175,9 @@ export component MainWindow inherits Window {
font-weight: 600;
vertical-alignment: center;
}
ShadowSurface {
FlatSurface {
background: WorkbenchStyle.field-surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.control;
// Inset the viewport so text and the scrollbar stay clear
// of the rounded frame, including at either scroll limit.
@@ -3242,7 +3224,7 @@ export component MainWindow inherits Window {
VerticalLayout {
vertical-stretch: 0;
spacing: 16px;
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
if root.update-install-status != "": Text {
text: root.update-install-status;
font-size: 12px;
@@ -3315,7 +3297,7 @@ export component MainWindow inherits Window {
width: min(440px, parent.width - 40px);
height: update-confirm-content.preferred-height;
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
TouchArea {}
update-confirm-content := VerticalLayout {
padding: 24px;
@@ -3369,10 +3351,7 @@ export component MainWindow inherits Window {
width: 512px;
height: wayland-notice-content.preferred-height;
border-radius: UiRadius.surface;
shadow-color: UiShadow.edge;
drop-shadow-color: #07142b30;
drop-shadow-blur: 28px;
drop-shadow-offset-y: 10px;
outline-color: UiSurface.edge;
wayland-notice-content := VerticalLayout {
padding: 24px; spacing: 18px;
@@ -3393,9 +3372,9 @@ export component MainWindow inherits Window {
}
}
ShadowSurface {
FlatSurface {
background: #fff8eb;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
VerticalLayout {
@@ -3416,9 +3395,9 @@ export component MainWindow inherits Window {
}
}
ShadowSurface {
FlatSurface {
background: #f3f7fd;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
VerticalLayout {
@@ -3439,7 +3418,7 @@ export component MainWindow inherits Window {
}
}
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
HorizontalLayout {
height: 34px; alignment: end;
PrimaryButton {
@@ -3472,8 +3451,8 @@ export component MainWindow inherits Window {
text-size: ImGuiFontStyle.prominent;
text-weight: 600;
}
ShadowSurface {
background: #f7f8fa; shadow-color: UiShadow.edge; border-radius: UiRadius.surface;
FlatSurface {
background: #f7f8fa; outline-color: UiSurface.edge; border-radius: UiRadius.surface;
Text { x: 14px; y: 22px; width: parent.width - 28px; height: parent.height - 24px; text: UiStrings.service-setup-message; color: #3d434d; wrap: word-wrap; vertical-alignment: center; }
}
if root.portable-service-status != "": Text {
@@ -3544,13 +3523,13 @@ export component MainWindow inherits Window {
z: 250;
}
if root.custom-titlebar: ShadowSurface {
if root.custom-titlebar: FlatSurface {
x: 0px;
y: 0px;
width: root.width;
height: root.height;
background: transparent;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius:
root.wayland-titlebar ? root.wayland-corner-radius : 0px;
z: 200;
+8 -8
View File
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ScrollView } from "std-widgets.slint";
import { IconButton, FontAwesomeIcons, ControlStyle } from "common.slint";
@@ -91,11 +91,11 @@ export component MessagePanel inherits SettingsDialog {
text: root.notice-text; font-size: 12px; wrap: word-wrap; color: #b3261e;
}
}
message-content := ShadowSurface {
message-content := FlatSurface {
x: 24px; y: root.content-top + (root.notice-text == "" ? 0px : notice.height + 12px);
width: parent.width - 48px; height: parent.height - self.y - 24px;
background: WorkbenchStyle.surface;
border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
border-radius: UiRadius.surface; outline-color: UiSurface.edge;
if root.items.length > 0 || root.selected-id != "": Rectangle {
x: 1px; y: 1px; width: content-divider.x - 1px; height: parent.height - 2px;
background: WorkbenchStyle.field-surface;
@@ -113,14 +113,14 @@ export component MessagePanel inherits SettingsDialog {
announcement-entries := VerticalLayout {
width: announcements-scroll.viewport-width; spacing: 10px; padding: 0px;
alignment: start;
for item in root.items: ShadowSurface {
for item in root.items: FlatSurface {
height: 64px;
background: root.selected-id == item.id
? (entry-touch.pressed ? ControlStyle.selected-pressed : entry-touch.has-hover ? ControlStyle.selected-hover : ControlStyle.selected)
: entry-touch.pressed ? WorkbenchStyle.pressed-surface
: entry-touch.has-hover ? WorkbenchStyle.hover-surface : WorkbenchStyle.surface;
border-radius: UiRadius.control;
shadow-color: root.selected-id == item.id ? UiShadow.focus : UiShadow.edge;
outline-color: root.selected-id == item.id ? UiSurface.focus : UiSurface.edge;
Text {
x: 10px; y: 9px; width: parent.width - 30px; height: 20px;
text: item.title; overflow: elide; font-size: 13px;
@@ -155,10 +155,10 @@ export component MessagePanel inherits SettingsDialog {
color: WorkbenchStyle.muted; font-size: 13px;
horizontal-alignment: center; vertical-alignment: center;
}
content-divider := ShadowSeparator {
content-divider := SurfaceSeparator {
x: announcement-list.x + announcement-list.width + 8px;
y: 1px; width: 1px; height: parent.height - 2px;
vertical: true; shadow-color: UiShadow.separator;
vertical: true; outline-color: UiSurface.separator;
visible: root.items.length > 0 || root.selected-id != "";
accessible-role: none;
}
@@ -207,7 +207,7 @@ export component MessagePanel inherits SettingsDialog {
clicked => { root.request-delete(root.selected-id, root.selected-revision); }
}
}
ShadowSeparator { height: 1px; shadow-color: UiShadow.separator; }
SurfaceSeparator { height: 1px; outline-color: UiSurface.separator; }
StyledText {
vertical-stretch: 0;
text: root.selected-body;
@@ -1,4 +1,4 @@
import { ShadowSurface, UiShadow } from "ui_shadow.slint";
import { FlatSurface, UiSurface } from "ui_surface.slint";
import { LineEdit } from "std-widgets.slint";
import { UiRadius } from "ui_radius.slint";
import { ControlStyle } from "common.slint";
@@ -11,7 +11,7 @@ export component RoundedLineEdit inherits Rectangle {
in property <InputType> input-type: InputType.text;
in property <bool> enabled: true;
in property <length> font-size: 12px;
in property <color> normal-shadow-color: UiShadow.edge;
in property <color> normal-outline-color: UiSurface.edge;
in property <brush> surrounding-background: white;
callback accepted();
callback edited();
@@ -40,7 +40,7 @@ export component RoundedLineEdit inherits Rectangle {
: editor.has-focus ? ControlStyle.input-focus-tint : ControlStyle.input-tint;
}
// The software renderer clips children to rectangular bounds. Mask the
// standard editor's corners before drawing our soft focus edge on top.
// standard editor's corners before drawing the focus outline on top.
Rectangle {
x: -root.border-radius; y: -root.border-radius;
width: parent.width + 2 * root.border-radius;
@@ -49,13 +49,12 @@ export component RoundedLineEdit inherits Rectangle {
border-radius: 2 * root.border-radius;
border-color: root.surrounding-background;
}
ShadowSurface {
FlatSurface {
width: parent.width; height: parent.height;
border-radius: root.border-radius;
clip: true;
shadow-color: editor.has-focus ? UiShadow.focus : root.normal-shadow-color;
shadow-focused: editor.has-focus;
shadow-compact: true;
outline-color: editor.has-focus ? UiSurface.focus : root.normal-outline-color;
outline-focused: editor.has-focus;
background: transparent;
}
}
+17 -14
View File
@@ -1,7 +1,7 @@
import { ShadowSurface, UiShadow } from "ui_shadow.slint";
import { FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ScrollView } from "std-widgets.slint";
import { FontAwesomeIcons, FloatingBarStyle, ControlStyle } from "common.slint";
import { FontAwesomeIcons, FloatingBarStyle, ButtonStyle } from "common.slint";
export struct ControllerEntry {
remote-id: string,
@@ -20,7 +20,7 @@ export global ServerStrings {
in property <string> cancel: "取消";
}
component SessionButton inherits ShadowSurface {
component SessionButton inherits FlatSurface {
in property <string> text;
in property <bool> danger: false;
in property <bool> enabled: true;
@@ -30,10 +30,13 @@ component SessionButton inherits ShadowSurface {
width: label.preferred-width + 20px;
height: 28px;
border-radius: UiRadius.control;
shadow-color: root.danger ? UiShadow.error : UiShadow.edge;
outline-enabled: !root.danger;
outline-color: root.pointer-feedback && touch.pressed ? ButtonStyle.pressed-border
: root.pointer-feedback && touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
background: root.danger ? (root.pointer-feedback && touch.pressed ? #b42318 : root.pointer-feedback && touch.has-hover ? #f04438 : #d92d20)
: (root.pointer-feedback && touch.pressed ? ControlStyle.pressed
: root.pointer-feedback && touch.has-hover ? ControlStyle.hover : ControlStyle.surface);
: (root.pointer-feedback && touch.pressed ? ButtonStyle.pressed
: root.pointer-feedback && touch.has-hover ? ButtonStyle.hover : ButtonStyle.surface);
animate background, outline-color { duration: 120ms; }
opacity: root.enabled ? 1 : 0.5;
accessible-role: button;
accessible-label: root.text;
@@ -73,9 +76,9 @@ component SessionButton inherits ShadowSurface {
// Restore hover feedback only after a fresh pointer move or press.
clicked => { root.pointer-feedback = false; root.keyboard-focus = false; keyboard.focus(); root.clicked(); }
}
if root.enabled && keyboard.has-focus && root.keyboard-focus: ShadowSurface {
if root.enabled && keyboard.has-focus && root.keyboard-focus: FlatSurface {
x: 2px; y: 2px; width: parent.width - 4px; height: parent.height - 4px;
border-radius: UiRadius.control - 2px; shadow-color: root.danger ? white : UiShadow.focus;
border-radius: UiRadius.control - 2px; outline-color: root.danger ? white : UiSurface.focus;
}
}
@@ -108,10 +111,10 @@ export component ServerStatusBar inherits Window {
return reject;
}
}
ShadowSurface {
FlatSurface {
x: 0px; y: 0px; width: parent.width; height: parent.height;
background: touch.pressed ? #dfe3e9 : touch.has-hover ? #f3f4f6 : white;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: FloatingBarStyle.corner-radius;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
@@ -171,9 +174,9 @@ export component ServerWindow inherits Window {
if event.text == Key.Escape { root.dismiss-panel(); return accept; }
return reject;
}
ShadowSurface {
FlatSurface {
width: root.width; height: root.height;
background: white; shadow-color: UiShadow.edge;
background: white; outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
Text {
x: 10px; y: 10px; width: parent.width - 20px; height: 24px;
@@ -193,9 +196,9 @@ export component ServerWindow inherits Window {
width: parent.width - (root.controllers.length > 1 ? disconnect.width + 4px : status.preferred-width + 8px);
height: parent.height; border-radius: UiRadius.control;
background: root.controllers.length > 1 && index == root.selected-controller ? #eef5fd : select-touch.has-hover ? #f3f4f6 : transparent;
if root.controllers.length > 1: ShadowSurface {
if root.controllers.length > 1: FlatSurface {
x: 4px; y: (parent.height - 13px) / 2; width: 13px; height: 13px;
border-radius: 7px; shadow-color: index == root.selected-controller ? UiShadow.focus : UiShadow.edge;
border-radius: 7px; outline-color: index == root.selected-controller ? UiSurface.focus : UiSurface.edge;
if index == root.selected-controller: Rectangle { x: 3px; y: 3px; width: 7px; height: 7px; border-radius: 4px; background: #2463c7; }
}
name := Text {
+12 -19
View File
@@ -1,11 +1,10 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { CompactComboBox, ToggleSwitch, DialogSurface, IconButton, FontAwesomeIcons, ControlStyle, ButtonStyle } from "common.slint";
import { WorkbenchStyle } from "workbench_controls.slint";
// Shared visual treatment for the global settings pages.
export component SettingsButton inherits ShadowSurface {
shadow-compact: true;
export component SettingsButton inherits FlatSurface {
in property <string> text;
in property <image> icon;
in property <bool> primary: false;
@@ -20,14 +19,11 @@ export component SettingsButton inherits ShadowSurface {
: root.primary ? (touch.pressed ? #1e4fa3 : touch.has-hover ? #2866c9 : #3275dc)
: touch.pressed ? ButtonStyle.pressed : touch.has-hover ? ButtonStyle.hover
: root.quiet ? transparent : ButtonStyle.surface;
border-width: root.quiet || root.primary ? 0px : 1px;
border-color: !root.enabled ? ButtonStyle.disabled-border
outline-enabled: !root.quiet && !root.primary;
outline-color: !root.enabled ? ButtonStyle.disabled-border
: touch.pressed ? ButtonStyle.pressed-border
: touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-enabled: root.enabled && !root.quiet && !touch.pressed;
shadow-color: root.primary ? UiShadow.focus
: touch.has-hover ? UiShadow.hover : UiShadow.edge;
animate background, border-color { duration: 120ms; }
animate background, outline-color { duration: 120ms; }
accessible-role: button; accessible-label: root.text;
accessible-enabled: root.enabled;
accessible-action-default => { if root.enabled { root.clicked(); } }
@@ -68,10 +64,7 @@ export component SettingsDialog inherits DialogSurface {
callback action();
callback close();
background: #f8fafc;
shadow-color: UiShadow.edge;
drop-shadow-color: #14294424;
drop-shadow-blur: 24px;
drop-shadow-offset-y: 8px;
outline-color: UiSurface.edge;
TouchArea { }
HorizontalLayout {
x: 24px; y: 18px; width: parent.width - 48px; height: 28px;
@@ -120,8 +113,8 @@ export component SettingsDialog inherits DialogSurface {
export component SettingsSelect inherits CompactComboBox {
subtle: true;
show-arrow: true;
normal-shadow-color: UiShadow.edge;
hover-shadow-color: UiShadow.hover;
normal-outline-color: UiSurface.edge;
hover-outline-color: UiSurface.hover;
height: 28px;
}
@@ -133,9 +126,9 @@ export component SettingsGroup inherits Rectangle {
x: 2px; y: 0px; width: parent.width - 4px; height: 18px; text: root.title;
font-size: 11px; font-weight: 600; color: #718096; vertical-alignment: center;
}
ShadowSurface {
FlatSurface {
y: 24px; width: parent.width; height: parent.height - self.y;
background: white; border-radius: UiRadius.surface; shadow-color: UiShadow.edge;
background: white; border-radius: UiRadius.surface; outline-color: UiSurface.edge;
VerticalLayout { padding: 0px; spacing: 0px; @children }
}
}
@@ -151,8 +144,8 @@ export component SettingsRow inherits Rectangle {
text: root.label; color: root.enabled ? #34445a : #9ba5b3;
font-size: 12px; overflow: elide; vertical-alignment: center;
}
if root.divider: ShadowSeparator {
x: 12px; y: parent.height - 1px; width: parent.width - 24px; height: 1px; shadow-color: UiShadow.separator;
if root.divider: SurfaceSeparator {
x: 12px; y: parent.height - 1px; width: parent.width - 24px; height: 1px; outline-color: UiSurface.separator;
}
@children
}
+24 -34
View File
@@ -1,4 +1,4 @@
import { ShadowSeparator, ShadowSurface, UiShadow } from "ui_shadow.slint";
import { SurfaceSeparator, FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ComboBox, ScrollView } from "std-widgets.slint";
import { RemoteCursor } from "remote_cursor.slint";
@@ -85,13 +85,10 @@ struct ControlBarTooltip {
}
// Shared surface treatment for the capsule and its detached detail cards.
component StreamControlSurface inherits ShadowSurface {
component StreamControlSurface inherits FlatSurface {
background: white;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: 16px;
drop-shadow-color: #1d35571a;
drop-shadow-blur: 10px;
drop-shadow-offset-y: 2px;
}
// Keep the compact 16px icons inside roomier circular targets. This remains
@@ -246,22 +243,18 @@ component VideoSettingRow inherits VerticalLayout {
Text { text: root.label; color: #5c626c; font-size: 11px; height: 18px; }
HorizontalLayout {
spacing: 4px;
for option[index] in root.options: ShadowSurface {
for option[index] in root.options: FlatSurface {
height: 27px;
background: !root.enabled ? ControlStyle.disabled
: root.selected == index ? (option-touch.pressed ? ButtonStyle.selected-pressed : option-touch.has-hover ? ButtonStyle.selected-hover : ButtonStyle.selected)
: option-touch.pressed ? ButtonStyle.pressed
: option-touch.has-hover ? ButtonStyle.hover : ButtonStyle.surface;
border-radius: UiRadius.control;
border-width: 1px;
border-color: !root.enabled ? ButtonStyle.disabled-border
outline-color: !root.enabled ? ButtonStyle.disabled-border
: root.selected == index ? ButtonStyle.selected-pressed
: option-touch.pressed ? ButtonStyle.pressed-border
: option-touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-compact: true;
shadow-enabled: root.enabled && !option-touch.pressed;
shadow-color: root.enabled && root.selected == index ? UiShadow.focus : UiShadow.edge;
animate background, border-color { duration: 120ms; }
animate background, outline-color { duration: 120ms; }
Text { text: option; color: !root.enabled ? #8b8f95
: root.selected == index ? white : #30343b;
font-weight: root.selected == index ? 600 : 400;
@@ -914,10 +907,10 @@ export component StreamWindow inherits Window {
clicked => { root.close-stream-window(); }
}
}
ShadowSeparator {
SurfaceSeparator {
y: parent.height - 1px;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
@@ -937,11 +930,11 @@ export component StreamWindow inherits Window {
z: 10;
HorizontalLayout {
spacing: 1px;
for tab[index] in root.tabs: tab-item := ShadowSurface {
for tab[index] in root.tabs: tab-item := FlatSurface {
width: min(190px, max(110px, (parent.width - 12px) / root.tabs.length));
background: index == root.selected-tab ? white : tab-touch.has-hover || root.dragging-tab == index ? #e5e7eb : #d8dbe0;
shadow-enabled: root.dragging-tab == index;
shadow-color: UiShadow.focus;
outline-enabled: root.dragging-tab == index;
outline-color: UiSurface.focus;
Rectangle {
width: parent.width - 27px;
height: parent.height;
@@ -1214,11 +1207,11 @@ export component StreamWindow inherits Window {
tooltip: root.fullscreen-enabled ? StreamStrings.exit-fullscreen : StreamStrings.fullscreen;
clicked => { root.close-control-menus(); root.toggle-fullscreen(); }
}
if root.control-content-visible: ShadowSeparator {
if root.control-content-visible: SurfaceSeparator {
opacity: root.control-content-progress;
x: close-button.x - 6px; y: 12px;
width: 1px; height: 14px;
vertical: true; shadow-color: UiShadow.separator;
vertical: true; outline-color: UiSurface.separator;
}
close-button := ControlBarButton {
reveal-progress: root.control-content-progress;
@@ -1423,12 +1416,12 @@ export component StreamWindow inherits Window {
vertical-alignment: center;
overflow: elide;
}
if index < root.stats-rows.length - 2: ShadowSeparator {
if index < root.stats-rows.length - 2: SurfaceSeparator {
x: 4px;
y: parent.height - 1px;
width: parent.width - 8px;
height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
}
@@ -1437,16 +1430,16 @@ export component StreamWindow inherits Window {
text: StreamStrings.stats-encoder + "\n" + StreamStrings.stats-decoder;
font-size: ImGuiFontStyle.small;
}
ShadowSurface {
FlatSurface {
x: 0px;
y: root.stats-header-height + root.stats-rows.length * stats-table.row-height
+ 70px;
width: parent.width; height: 44px;
background: #f7f9fc; border-radius: UiRadius.control;
shadow-color: UiShadow.edge;
ShadowSeparator {
outline-color: UiSurface.edge;
SurfaceSeparator {
x: 8px; y: 22px; width: parent.width - 16px; height: 1px;
shadow-color: UiShadow.separator;
outline-color: UiSurface.separator;
}
for codec[index] in [
{ label: StreamStrings.stats-encoder, value: root.stats-encoder },
@@ -1762,11 +1755,8 @@ export component StreamWindow inherits Window {
y: min(max(64px, parent.height * 0.18), max(16px, parent.height - self.height - 16px));
width: min(400px, parent.width - 48px);
height: remote-update-message.y + remote-update-message.height + 84px;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
drop-shadow-color: #07142b30;
drop-shadow-blur: 32px;
drop-shadow-offset-y: 12px;
z: 14;
TouchArea {
mouse-cursor: default;
@@ -1806,10 +1796,10 @@ export component StreamWindow inherits Window {
}
// Transfer progress overlay at bottom-left.
if root.file-transfer-visible: ShadowSurface {
if root.file-transfer-visible: FlatSurface {
x: root.file-panel-x; y: root.file-panel-y;
width: root.file-panel-width; height: root.file-panel-height;
background: #fffffff0; shadow-color: UiShadow.edge; border-radius: UiRadius.surface; z: 7;
background: white; outline-color: UiSurface.edge; border-radius: UiRadius.surface; z: 7;
// Header/padding and drags leaving the panel belong to local UI.
TouchArea {
mouse-cursor: default;
@@ -1858,11 +1848,11 @@ export component StreamWindow inherits Window {
}
}
if root.custom-titlebar && !root.fullscreen-enabled: ShadowSurface {
if root.custom-titlebar && !root.fullscreen-enabled: FlatSurface {
width: parent.width;
height: parent.height;
background: transparent;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius:
root.window-maximized ? 0px : root.window-corner-radius;
z: 200;
-63
View File
@@ -1,63 +0,0 @@
// Shared surface shadows use ordinary rectangles and gradients because Slint's
// software renderer does not draw drop-shadow-* effects. Keep layout and hit
// areas unchanged; only the decorative shadow extends beyond the surface.
export global UiShadow {
out property <color> edge: #20334e;
out property <color> hover: #315d92;
out property <color> focus: #3564e3;
out property <color> error: #d65252;
out property <color> separator: #20334e14;
}
export component ShadowSurface inherits Rectangle {
in property <color> shadow-color: UiShadow.edge;
in property <bool> shadow-enabled: true;
in property <bool> shadow-focused: false;
// Small controls need a tighter falloff than cards and dialogs.
in property <bool> shadow-compact: false;
border-width: 0px;
border-top-left-radius: root.border-radius;
border-top-right-radius: root.border-radius;
border-bottom-left-radius: root.border-radius;
border-bottom-right-radius: root.border-radius;
// Diffuse outwards, with more weight below the surface. A clipped surface
// keeps a faint inner falloff so native popup edges remain distinguishable.
for layer in (root.shadow-compact ? 3 : 6): Rectangle {
visible: root.shadow-enabled;
private property <length> inset: root.clip ? layer * 0.5px : -(layer + 1) * 1px;
private property <float> weight: (root.shadow-compact
? (layer == 0 ? 0.09 : layer == 1 ? 0.035 : 0.01)
: (layer == 0 ? 0.09 : layer == 1 ? 0.07
: layer == 2 ? 0.05 : layer == 3 ? 0.03 : layer == 4 ? 0.015 : 0.005))
* (root.shadow-focused ? 2.5 : 1);
x: self.inset; y: self.inset;
width: max(0px, root.width - 2 * self.inset);
height: max(0px, root.height - 2 * self.inset);
border-top-left-radius: max(0px, root.border-top-left-radius - self.inset);
border-top-right-radius: max(0px, root.border-top-right-radius - self.inset);
border-bottom-left-radius: max(0px, root.border-bottom-left-radius - self.inset);
border-bottom-right-radius: max(0px, root.border-bottom-right-radius - self.inset);
border-width: 1px;
border-color: @linear-gradient(180deg,
root.shadow-color.mix(transparent, self.weight * 0.45) 0%,
root.shadow-color.mix(transparent, self.weight) 100%);
}
@children
}
export component ShadowSeparator inherits Rectangle {
in property <bool> vertical: false;
in property <color> shadow-color: UiShadow.separator;
height: 1px;
Rectangle {
x: root.vertical ? -2px : 0px;
y: root.vertical ? 0px : -1px;
width: root.vertical ? 5px : root.width;
height: root.vertical ? root.height : 6px;
background: root.vertical
? @linear-gradient(90deg, transparent 0%, root.shadow-color 50%, transparent 100%)
: @linear-gradient(180deg, transparent 0%, root.shadow-color 50%, transparent 100%);
}
}
+35
View File
@@ -0,0 +1,35 @@
// Flat surfaces share solid outlines in software and GPU renderers.
// Interaction states use their actual colors, including focus and validation.
export global UiSurface {
out property <color> edge: #d7dfe9;
out property <color> hover: #8eabd2;
out property <color> focus: #3564e3;
out property <color> error: #d65252;
out property <color> separator: #e1e7ef;
}
export component FlatSurface inherits Rectangle {
in property <color> outline-color: UiSurface.edge;
in property <bool> outline-enabled: true;
in property <bool> outline-focused: false;
border-width: !root.outline-enabled ? 0px : root.outline-focused ? 2px : 1px;
border-color: root.outline-color;
border-top-left-radius: root.border-radius;
border-top-right-radius: root.border-radius;
border-bottom-left-radius: root.border-radius;
border-bottom-right-radius: root.border-radius;
@children
}
export component SurfaceSeparator inherits Rectangle {
in property <bool> vertical: false;
in property <color> outline-color: UiSurface.separator;
height: 1px;
Rectangle {
width: root.vertical ? 1px : root.width;
height: root.vertical ? root.height : 1px;
background: root.outline-color;
}
}
@@ -1,4 +1,4 @@
import { ShadowSurface, UiShadow } from "ui_shadow.slint";
import { FlatSurface, UiSurface } from "ui_surface.slint";
import { UiRadius } from "ui_radius.slint";
import { ControlStyle, ButtonStyle } from "common.slint";
// Colors and spacing for the connection workbench; shapes are shared app-wide.
@@ -15,12 +15,11 @@ export global WorkbenchStyle {
out property <color> success: #18835a;
}
export component WorkbenchButton inherits ShadowSurface {
shadow-compact: true;
export component WorkbenchButton inherits FlatSurface {
in property <string> text;
in property <length> text-size: 13px;
in property <color> text-color: root.destructive || root.primary ? white : WorkbenchStyle.text;
in property <color> normal-shadow-color: UiShadow.edge;
in property <color> normal-outline-color: ButtonStyle.border;
in property <color> normal-background: ButtonStyle.surface;
in property <string> icon;
in property <string> tooltip;
@@ -46,17 +45,12 @@ export component WorkbenchButton inherits ShadowSurface {
width: 112px;
height: 36px;
border-radius: UiRadius.control;
border-width: root.show-focus || (!root.quiet && !root.soft && !root.primary && !root.destructive) ? 1px : 0px;
border-color: !root.enabled ? ButtonStyle.disabled-border
outline-enabled: root.show-focus || (!root.quiet && !root.soft && !root.primary && !root.destructive);
outline-focused: root.show-focus;
outline-color: !root.enabled ? ButtonStyle.disabled-border
: root.show-focus ? WorkbenchStyle.accent
: touch.pressed ? ButtonStyle.pressed-border
: touch.has-hover ? ButtonStyle.hover-border : ButtonStyle.border;
shadow-enabled: root.enabled && (root.show-focus || (!root.soft && !root.quiet && !touch.pressed));
shadow-focused: root.show-focus;
shadow-color: root.destructive ? UiShadow.error
: root.show-focus || root.primary ? UiShadow.focus
: touch.has-hover ? UiShadow.hover
: root.quiet ? transparent : root.normal-shadow-color;
: touch.has-hover ? ButtonStyle.hover-border : root.normal-outline-color;
background: root.destructive
? (touch.pressed ? #912018 : touch.has-hover ? #b42318 : #d92d20)
: root.soft
@@ -67,7 +61,7 @@ export component WorkbenchButton inherits ShadowSurface {
? (touch.pressed ? #254cc0 : touch.has-hover ? #4574f0 : WorkbenchStyle.accent)
: (touch.pressed ? ButtonStyle.pressed : touch.has-hover ? ButtonStyle.hover : root.quiet ? transparent : root.normal-background);
opacity: root.enabled ? 1 : 0.45;
animate background, border-color, shadow-color { duration: 120ms; }
animate background, outline-color { duration: 120ms; }
forward-focus: button-focus;
accessible-role: button;
accessible-label: root.tooltip != "" ? root.tooltip : root.text;
@@ -97,6 +91,11 @@ export component WorkbenchButton inherits ShadowSurface {
accessible-role: none;
}
}
if root.show-focus && (root.primary || root.destructive): Rectangle {
x: 3px; y: 3px; width: parent.width - 6px; height: parent.height - 6px;
border-radius: max(0px, root.border-radius - 3px);
border-width: 1px; border-color: white;
}
button-focus := FocusScope {
enabled: root.enabled;
focus-gained(reason) => {
@@ -155,7 +154,7 @@ export component WorkbenchButton inherits ShadowSurface {
}
// A raised surface keeps transient action feedback distinct from the workbench.
export component WorkbenchNotice inherits ShadowSurface {
export component WorkbenchNotice inherits FlatSurface {
in property <string> text;
in property <string> icon;
in property <bool> error: false;
@@ -164,11 +163,8 @@ export component WorkbenchNotice inherits ShadowSurface {
width: min(root.width-limit, max(280px, message.preferred-width + 64px));
height: 64px;
background: root.error ? #fff1f0 : #e9f6ef;
shadow-color: root.error ? UiShadow.error : UiShadow.edge;
outline-color: root.error ? UiSurface.error : UiSurface.edge;
border-radius: UiRadius.surface;
drop-shadow-color: #14294424;
drop-shadow-blur: 24px;
drop-shadow-offset-y: 6px;
accessible-role: AccessibleRole.text;
accessible-label: root.text;
Text {
@@ -196,8 +192,8 @@ export component WorkbenchNotice inherits ShadowSurface {
}
}
export component WorkbenchCard inherits ShadowSurface {
export component WorkbenchCard inherits FlatSurface {
background: WorkbenchStyle.surface;
shadow-color: UiShadow.edge;
outline-color: UiSurface.edge;
border-radius: UiRadius.surface;
}