// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial import { ColorSchemeSelector } from "color-scheme.slint"; export global Palette { in-out property 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 themeDarker: #004578; out property themeDark: #005a9e; out property themeDarkAlt: #106ebe; out property themePrimary: #0078d4; out property themeSecondary: #2b88d8; out property themeTertiary: #71afe5; out property themeLight: #c7e0f4; out property themeLighter: #deecf9; out property themeLighterAlt: #eff6fc; out property black: !root.dark-color-scheme ? #000000 : #f8f8f8; out property blackTranslucent40: rgba(0,0,0,0.4); out property neutralDark: !root.dark-color-scheme ? #201f1e : #f4f4f4; out property neutralPrimary: !root.dark-color-scheme ? #323130 : #ffffff; out property neutralPrimaryAlt: !root.dark-color-scheme ? #3b3a39 : #dadada; out property neutralSecondary: !root.dark-color-scheme ? #605e5c : #d0d0d0; out property neutralSecondaryAlt: #8a8886; out property neutralTertiary: !root.dark-color-scheme ? #a19f9d : #c8c8c8; out property neutralTertiaryAlt: !root.dark-color-scheme ? #c8c6c4 : #6d6d6d; out property neutralQuaternary: #d2d0ce; out property neutralQuaternaryAlt: !root.dark-color-scheme ? #e1dfdd : #484848; out property neutralLight: !root.dark-color-scheme ? #edebe9 : #3f3f3f; out property neutralLighter: !root.dark-color-scheme ? #f3f2f1 : #313131; out property neutralLighterAlt: !root.dark-color-scheme ? #faf9f8 : #282828; out property accent: #0078d4; out property white: !root.dark-color-scheme ? #ffffff : #1f1f1f; out property whiteTranslucent40: rgba(255,255,255,0.4); out property yellowDark: #d29200; out property yellow: #ffb900; out property yellowLight: #fff100; out property orange: #d83b01; out property orangeLight: #ea4300; out property orangeLighter: #ff8c00; out property redDark: #a4262c; out property red: #e81123; out property magentaDark: #5c005c; out property magenta: #b4009e; out property magentaLight: #e3008c; out property purpleDark: #32145a; out property purple: #5c2d91; out property purpleLight: #b4a0ff; out property blueDark: #002050; out property blueMid: #00188f; out property blue: #0078d4; out property blueLight: #00bcf2; out property tealDark: #004b50; out property teal: #008272; out property tealLight: #00b294; out property greenDark: #004b1c; out property green: #107c10; out property greenLight: #bad80a; } export global StyleMetrics { out property layout-spacing: 8px; out property layout-padding: 8px; out property text-cursor-width: 2px; out property window-background: Palette.white; out property default-text-color: Palette.neutralDark; out property textedit-background: Palette.white; out property textedit-text-color: Palette.neutralPrimary; out property textedit-background-disabled: Palette.neutralLighter; out property textedit-text-color-disabled: Palette.neutralTertiary; out property dark-color-scheme: Palette.dark-color-scheme; } export component Button { callback clicked; in property text <=> text.text; out property has-focus: fs.has-focus; out property pressed: self.enabled && touch.pressed; in property enabled <=> touch.enabled; in property checkable; in-out property checked; in property icon; 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: enabled ? Palette.white : Palette.neutralLighter; // border-color: Palette.button-background; border-width: 1px; in-out property horizontal; in-out property maximum; in-out property page-size; // this is always negative and bigger than -maximum in-out property value; in property enabled; handle := Rectangle { width: !root.horizontal ? parent.width : root.maximum <= 0phx ? 0phx : max(32px, parent.width * root.page-size / (root.maximum + root.page-size)); height: root.horizontal ? parent.height : root.maximum <= 0phx ? 0phx : max(32px, 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 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 viewport-width <=> fli.viewport-width; in-out property viewport-height <=> fli.viewport-height; in-out property viewport-x <=> fli.viewport-x; in-out property viewport-y <=> fli.viewport-y; out property visible-width <=> fli.width; out property visible-height <=> fli.height; in property 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 has-focus; min-height: 50px; min-width: 50px; horizontal-stretch: 1; vertical-stretch: 1; preferred-height: 100%; preferred-width: 100%; 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 { enabled: root.enabled; 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 { enabled: root.enabled; 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; } corner := Rectangle { x: fli.width + fli.x; y: fli.height + fli.y; height: 16px; width: 16px; background: root.enabled ? transparent : Palette.neutralLighter; } }