// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial export global Palette := { property themeDarker: #004578; property themeDark: #005a9e; property themeDarkAlt: #106ebe; property themePrimary: #0078d4; property themeSecondary: #2b88d8; property themeTertiary: #71afe5; property themeLight: #c7e0f4; property themeLighter: #deecf9; property themeLighterAlt: #eff6fc; property black: #000000; property blackTranslucent40: rgba(0,0,0,0.4); property neutralDark: #201f1e; property neutralPrimary: #323130; property neutralPrimaryAlt: #3b3a39; property neutralSecondary: #605e5c; property neutralSecondaryAlt: #8a8886; property neutralTertiary: #a19f9d; property neutralTertiaryAlt: #c8c6c4; property neutralQuaternary: #d2d0ce; property neutralQuaternaryAlt: #e1dfdd; property neutralLight: #edebe9; property neutralLighter: #f3f2f1; property neutralLighterAlt: #faf9f8; property accent: #0078d4; property white: #ffffff; property whiteTranslucent40: rgba(255,255,255,0.4); property yellowDark: #d29200; property yellow: #ffb900; property yellowLight: #fff100; property orange: #d83b01; property orangeLight: #ea4300; property orangeLighter: #ff8c00; property redDark: #a4262c; property red: #e81123; property magentaDark: #5c005c; property magenta: #b4009e; property magentaLight: #e3008c; property purpleDark: #32145a; property purple: #5c2d91; property purpleLight: #b4a0ff; property blueDark: #002050; property blueMid: #00188f; property blue: #0078d4; property blueLight: #00bcf2; property tealDark: #004b50; property teal: #008272; property tealLight: #00b294; property greenDark: #004b1c; property green: #107c10; property greenLight: #bad80a; } export global StyleMetrics := { property layout-spacing: 8px; property layout-padding: 8px; property text-cursor-width: 2px; property window-background: Palette.white; property default-text-color: Palette.neutralDark; property textedit-background: Palette.white; property textedit-text-color: Palette.neutralPrimary; property textedit-background-disabled: Palette.neutralLighter; property textedit-text-color-disabled: Palette.neutralTertiary; } export Button := Rectangle { callback clicked <=> touch.clicked; property text <=> text.text; property has-focus <=> fs.has-focus; property pressed: self.enabled && touch.pressed; property enabled <=> touch.enabled; property icon; property font-size <=> text.font-size; accessible-role: button; accessible-label <=> text.text; border-width: 1px; border-radius: 2px; border-color: !enabled ? Palette.neutralLighter : Palette.neutralSecondaryAlt; background: !enabled ? Palette.neutralLighter : touch.pressed ? 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 (icon.width > 0 && icon.height > 0): Image { source <=> icon; width: 24px; } text := Text { color: !enabled ? Palette.neutralTertiary : Palette.neutralDark; horizontal-alignment: center; vertical-alignment: center; font-weight: 600; } } touch := TouchArea {} fs := FocusScope { 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: x; width: parent.width - 2*x; height: parent.height - 2*y; border-width: enabled && has-focus? 1px : 0px; border-color: Palette.black; } } ScrollBar := Rectangle { background: Palette.white; // border-color: Palette.button-background; border-width: 1px; property horizontal; property maximum; property page-size; // this is always negative and bigger than -maximum property value; handle := Rectangle { width: !horizontal ? parent.width : maximum <= 0phx ? 0phx : parent.width * (page-size / (maximum + page-size)); height: horizontal ? parent.height : maximum <= 0phx ? 0phx : parent.height * (page-size / (maximum + page-size)); border-radius: (horizontal ? self.height : self.width) / 2; background: touch-area.pressed ? Palette.themePrimary : touch-area.has-hover ? Palette.themeSecondary : Palette.neutralTertiary; x: !horizontal ? 0phx : (root.width - handle.width) * (-value / maximum); y: horizontal ? 0phx : (root.height - handle.height) * (-value / 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) { pressed-value = -root.value; } } moved => { if (enabled && pressed) { value = -max(0px, min(root.maximum, pressed-value + ( horizontal ? (touch-area.mouse-x - touch-area.pressed-x) * (maximum / (root.width - handle.width)) : (touch-area.mouse-y - touch-area.pressed-y) * (maximum / (root.height - handle.height)) ))); } } } } export ScrollView := Rectangle { property viewport-width <=> fli.viewport-width; property viewport-height <=> fli.viewport-height; property viewport-x <=> fli.viewport-x; property viewport-y <=> fli.viewport-y; property visible-width <=> fli.width; property visible-height <=> fli.height; property enabled: true; property has-focus; min-height: 50px; min-width: 50px; horizontal-stretch: 1; vertical-stretch: 1; border-radius: 2px; border-width: !enabled ? 0px : has-focus ? 2px : 1px; border-color: !enabled ? Palette.neutralLighter : 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; } }