mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 21:34:50 +00:00

Don't make our widgets inherit element that we didn't want to expose in the API The other styles will be synchronized with later
253 lines
9.9 KiB
Text
253 lines
9.9 KiB
Text
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
|
|
|
import { ColorSchemeSelector } from "color-scheme.slint";
|
|
|
|
export global Palette {
|
|
in-out property<bool> dark-color-scheme: ColorSchemeSelector.dark-color-scheme;
|
|
|
|
// The colors in light mode are default palette. In the
|
|
// Fluent UI Theme Designer they match the colors produced
|
|
// with Primary Color = #0078d4, Text Color = #201f1e and Background Color = #ffffff
|
|
// The dark mode colors are produced in the Fluent UI Theme Designer by swapping
|
|
// Text Color and Background Color from light mode, applying the variations below
|
|
// and darkening the "white" and brightening the "neutralLight" variants for improved
|
|
// contrast (esp. on buttons).
|
|
|
|
out property<color> themeDarker: #004578;
|
|
out property<color> themeDark: #005a9e;
|
|
out property<color> themeDarkAlt: #106ebe;
|
|
out property<color> themePrimary: #0078d4;
|
|
out property<color> themeSecondary: #2b88d8;
|
|
out property<color> themeTertiary: #71afe5;
|
|
out property<color> themeLight: #c7e0f4;
|
|
out property<color> themeLighter: #deecf9;
|
|
out property<color> themeLighterAlt: #eff6fc;
|
|
out property<color> black: !root.dark-color-scheme ? #000000 : #f8f8f8;
|
|
out property<color> blackTranslucent40: rgba(0,0,0,0.4);
|
|
out property<color> neutralDark: !root.dark-color-scheme ? #201f1e : #f4f4f4;
|
|
out property<color> neutralPrimary: !root.dark-color-scheme ? #323130 : #ffffff;
|
|
out property<color> neutralPrimaryAlt: !root.dark-color-scheme ? #3b3a39 : #dadada;
|
|
out property<color> neutralSecondary: !root.dark-color-scheme ? #605e5c : #d0d0d0;
|
|
out property<color> neutralSecondaryAlt: #8a8886;
|
|
out property<color> neutralTertiary: !root.dark-color-scheme ? #a19f9d : #c8c8c8;
|
|
out property<color> neutralTertiaryAlt: !root.dark-color-scheme ? #c8c6c4 : #6d6d6d;
|
|
out property<color> neutralQuaternary: #d2d0ce;
|
|
out property<color> neutralQuaternaryAlt: !root.dark-color-scheme ? #e1dfdd : #484848;
|
|
out property<color> neutralLight: !root.dark-color-scheme ? #edebe9 : #3f3f3f;
|
|
out property<color> neutralLighter: !root.dark-color-scheme ? #f3f2f1 : #313131;
|
|
out property<color> neutralLighterAlt: !root.dark-color-scheme ? #faf9f8 : #282828;
|
|
out property<color> accent: #0078d4;
|
|
out property<color> white: !root.dark-color-scheme ? #ffffff : #1f1f1f;
|
|
out property<color> whiteTranslucent40: rgba(255,255,255,0.4);
|
|
out property<color> yellowDark: #d29200;
|
|
out property<color> yellow: #ffb900;
|
|
out property<color> yellowLight: #fff100;
|
|
out property<color> orange: #d83b01;
|
|
out property<color> orangeLight: #ea4300;
|
|
out property<color> orangeLighter: #ff8c00;
|
|
out property<color> redDark: #a4262c;
|
|
out property<color> red: #e81123;
|
|
out property<color> magentaDark: #5c005c;
|
|
out property<color> magenta: #b4009e;
|
|
out property<color> magentaLight: #e3008c;
|
|
out property<color> purpleDark: #32145a;
|
|
out property<color> purple: #5c2d91;
|
|
out property<color> purpleLight: #b4a0ff;
|
|
out property<color> blueDark: #002050;
|
|
out property<color> blueMid: #00188f;
|
|
out property<color> blue: #0078d4;
|
|
out property<color> blueLight: #00bcf2;
|
|
out property<color> tealDark: #004b50;
|
|
out property<color> teal: #008272;
|
|
out property<color> tealLight: #00b294;
|
|
out property<color> greenDark: #004b1c;
|
|
out property<color> green: #107c10;
|
|
out property<color> greenLight: #bad80a;
|
|
}
|
|
|
|
|
|
export global StyleMetrics {
|
|
out property<length> layout-spacing: 8px;
|
|
out property<length> layout-padding: 8px;
|
|
out property<length> text-cursor-width: 2px;
|
|
out property<brush> window-background: Palette.white;
|
|
out property<color> default-text-color: Palette.neutralDark;
|
|
out property<brush> textedit-background: Palette.white;
|
|
out property<color> textedit-text-color: Palette.neutralPrimary;
|
|
out property<brush> textedit-background-disabled: Palette.neutralLighter;
|
|
out property<color> textedit-text-color-disabled: Palette.neutralTertiary;
|
|
out property<bool> dark-color-scheme: Palette.dark-color-scheme;
|
|
}
|
|
|
|
export component Button {
|
|
callback clicked;
|
|
in property<string> text <=> text.text;
|
|
out property<bool> has-focus: fs.has-focus;
|
|
out property<bool> pressed: self.enabled && touch.pressed;
|
|
in property<bool> enabled <=> touch.enabled;
|
|
in property<bool> checkable;
|
|
in-out property<bool> checked;
|
|
in property<image> icon;
|
|
// FIXME: remove
|
|
in property<length> font-size <=> text.font-size;
|
|
|
|
accessible-role: button;
|
|
accessible-label <=> text.text;
|
|
|
|
Rectangle {
|
|
border-width: 1px;
|
|
border-radius: 2px;
|
|
border-color: !root.enabled ? Palette.neutralLighter : Palette.neutralSecondaryAlt;
|
|
background: !root.enabled ? Palette.neutralLighter
|
|
: (touch.pressed || root.checked) ? Palette.neutralLight
|
|
: touch.has-hover ? Palette.neutralLighter
|
|
: Palette.white;
|
|
}
|
|
horizontal-stretch: 0;
|
|
vertical-stretch: 0;
|
|
min-height: max(32px, l.min-height);
|
|
l := HorizontalLayout {
|
|
padding-left: 16px;
|
|
padding-right: 16px;
|
|
spacing: 8px;
|
|
padding-top: 3px;
|
|
padding-bottom: 3px;
|
|
|
|
if (root.icon.width > 0 && root.icon.height > 0): Image {
|
|
source <=> root.icon;
|
|
width: 24px;
|
|
}
|
|
|
|
text := Text {
|
|
color: !root.enabled ? Palette.neutralTertiary : Palette.neutralDark;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
touch := TouchArea {
|
|
clicked => {
|
|
if (root.checkable) {
|
|
root.checked = !root.checked;
|
|
}
|
|
root.clicked();
|
|
}
|
|
}
|
|
|
|
fs := FocusScope {
|
|
x:0;
|
|
width: 0px; // Do not react on clicks
|
|
enabled <=> root.enabled;
|
|
key-pressed(event) => {
|
|
if (event.text == " " || event.text == "\n") {
|
|
touch.clicked();
|
|
return accept;
|
|
}
|
|
return reject;
|
|
}
|
|
}
|
|
|
|
Rectangle { // Focus rectangle
|
|
x: 3px;
|
|
y: self.x;
|
|
width: parent.width - 2*self.x;
|
|
height: parent.height - 2*self.y;
|
|
border-width: root.enabled && root.has-focus? 1px : 0px;
|
|
border-color: Palette.black;
|
|
}
|
|
}
|
|
|
|
component ScrollBar inherits Rectangle {
|
|
background: Palette.white;
|
|
// border-color: Palette.button-background;
|
|
border-width: 1px;
|
|
in-out property <bool> horizontal;
|
|
in-out property<length> maximum;
|
|
in-out property<length> page-size;
|
|
// this is always negative and bigger than -maximum
|
|
in-out property<length> value;
|
|
|
|
handle := Rectangle {
|
|
width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : parent.width * (root.page-size / (root.maximum + root.page-size));
|
|
height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : parent.height * (root.page-size / (root.maximum + root.page-size));
|
|
|
|
border-radius: (root.horizontal ? self.height : self.width) / 2;
|
|
background: touch-area.pressed ? Palette.themePrimary :
|
|
touch-area.has-hover ? Palette.themeSecondary : Palette.neutralTertiary;
|
|
x: !root.horizontal ? 0phx : (root.width - handle.width) * (-root.value / root.maximum);
|
|
y: root.horizontal ? 0phx : (root.height - handle.height) * (-root.value / root.maximum);
|
|
}
|
|
touch-area := TouchArea {
|
|
width: parent.width;
|
|
height: parent.height;
|
|
property <length> pressed-value;
|
|
pointer-event(event) => {
|
|
if (event.button == PointerEventButton.left && event.kind == PointerEventKind.down) {
|
|
self.pressed-value = -root.value;
|
|
}
|
|
}
|
|
moved => {
|
|
if (self.enabled && self.pressed) {
|
|
root.value = -max(0px, min(root.maximum, self.pressed-value + (
|
|
root.horizontal ? (touch-area.mouse-x - touch-area.pressed-x) * (root.maximum / (root.width - handle.width))
|
|
: (touch-area.mouse-y - touch-area.pressed-y) * (root.maximum / (root.height - handle.height))
|
|
)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export component ScrollView {
|
|
in-out property <length> viewport-width <=> fli.viewport-width;
|
|
in-out property <length> viewport-height <=> fli.viewport-height;
|
|
in-out property <length> viewport-x <=> fli.viewport-x;
|
|
in-out property <length> viewport-y <=> fli.viewport-y;
|
|
out property <length> visible-width <=> fli.width;
|
|
out property <length> visible-height <=> fli.height;
|
|
in property <bool> enabled: true;
|
|
// FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus
|
|
in-out property <bool> has-focus;
|
|
min-height: 50px;
|
|
min-width: 50px;
|
|
horizontal-stretch: 1;
|
|
vertical-stretch: 1;
|
|
|
|
Rectangle {
|
|
border-radius: 2px;
|
|
border-width: !root.enabled ? 0px : root.has-focus ? 2px : 1px;
|
|
border-color: !root.enabled ? Palette.neutralLighter
|
|
: root.has-focus ? Palette.themeSecondary
|
|
: Palette.neutralPrimary;
|
|
}
|
|
|
|
fli := Flickable {
|
|
@children
|
|
x: 2px;
|
|
y: 2px;
|
|
interactive: false;
|
|
viewport-y <=> vbar.value;
|
|
viewport-x <=> hbar.value;
|
|
width: parent.width - vbar.width - 4px;
|
|
height: parent.height - hbar.height - 4px;
|
|
}
|
|
vbar := ScrollBar {
|
|
width: 16px;
|
|
x: fli.width + fli.x;
|
|
y: fli.y;
|
|
height: fli.height;
|
|
horizontal: false;
|
|
maximum: fli.viewport-height - fli.height;
|
|
page-size: fli.height;
|
|
}
|
|
hbar := ScrollBar {
|
|
height: 16px;
|
|
y: fli.height + fli.y;
|
|
x: fli.x;
|
|
width: fli.width;
|
|
horizontal: true;
|
|
maximum: fli.viewport-width - fli.width;
|
|
page-size: fli.width;
|
|
}
|
|
}
|