// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial global Palette := { property window-background: #eee; property widget-background: #ddd; property widget-stroke: #888; property window-border: #ccc; property text-color: #666; property hyper-blue: #90d1ff; } //------ MdiWindow ---- MdiWindow := Rectangle { property title; property window-x <=> window.x; property window-y <=> window.y; property is-open: true; width: 100%; height: 100%; window := Rectangle { background: Palette.window-background; border-width: 2px; border-color: Palette.window-border; border-radius: 6px; drop-shadow-blur: 25px; drop-shadow-color: Palette.window-border; property open-width: l.preferred-width; property open-height: l.preferred-height; width: l.preferred-width; height: l.preferred-height; states [ open when is-open : { width: open-width; height: open-height; expand.angle: 0deg; } ] transitions [ in open : { animate width, height, expand.angle { duration: 150ms; easing: ease; } } out open : { animate width, height, expand.angle { duration: 150ms; easing: ease; } } ] clip: true; TouchArea {} l := VerticalLayout { padding: window.border-width; alignment: is-open ? stretch : start; title_bar := TouchArea { moved => { if (pressed) { window-x += mouse-x - pressed-x; window-y += mouse-y - pressed-y; } } HorizontalLayout { padding: window.border-width; spacing: window.border-width * 2; expand := TouchArea { width: 30px; property angle: -90deg; clicked => { is-open = !is-open; } Path { MoveTo { x: cos(expand.angle) * -1 - sin(expand.angle) * -1; y: sin(expand.angle) * -1 + cos(expand.angle) * -1; } LineTo { x: cos(expand.angle) * 1 - sin(expand.angle) * -1; y: sin(expand.angle) * 1 + cos(expand.angle) * -1; } LineTo { x: cos(expand.angle) * 0 - sin(expand.angle) * 1; y: sin(expand.angle) * 0 + cos(expand.angle) * 1; } LineTo { x: cos(expand.angle) * -1 - sin(expand.angle) * -1; y: sin(expand.angle) * -1 + cos(expand.angle) * -1; } stroke-width: window.border-width * (expand.has-hover ? 1.5 : 1); stroke: parent.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke; viewbox-x: -1.5; viewbox-y: -1.5; viewbox-height: 3; viewbox-width: 3; } } Text { text: title; horizontal-alignment: center; color: Palette.text-color; } close_button := TouchArea { width: 30px; clicked => { root.visible = false; } Path { MoveTo { x: -1; y: -1; } LineTo { x: 1; y: 1; } MoveTo { x: -1; y: 1; } LineTo { x: 1; y: -1; } stroke-width: window.border-width * (close-button.has-hover ? 1.5 : 1); stroke: parent.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke; viewbox-x: -1.5; viewbox-y: -1.5; viewbox-height: 3; viewbox-width: 3; } } } } if is-open : VerticalLayout { Rectangle { height: window.border-width; background: window.border-color; } @children } } if is-open : resize-handle := TouchArea { width: 20px; height: width; x: parent.width - width; y: parent.height - height; mouse-cursor: MouseCursor.nwse-resize; Path { MoveTo { x: 0; y: 1; } LineTo { x: 1; y: 0; } MoveTo { x: 0.4; y: 1; } LineTo { x: 1; y: 0.4; } MoveTo { x: 0.8; y: 1; } LineTo { x: 1; y: 0.8; } stroke-width: window.border-width; stroke: Palette.window-border; viewbox-height: 1.2; viewbox-width: 1.2; } moved => { if (pressed) { window.open-width = max(l.min-width, min(l.max-width, window.open-width + mouse-x - pressed-x)); window.open-height = max(l.min-height, min(l.max-height, window.open-height + mouse-y - pressed-y)); } } } } } //------ Widgets ------ import {LineEdit, TextEdit, ComboBox, GridBox, VerticalBox, HorizontalBox, StyleMetrics} from "std-widgets.slint"; Label := Text { color: Palette.text-color; } Button := TouchArea { min-height: t.min-height; min-width: t.min-width + 10px; property text <=> t.text; Rectangle { border-width: 1.5px; border-color: root.has-hover ? Palette.widget-stroke : transparent; border-radius: 3px; background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background; t := Label { width: 100%; horizontal-alignment: center; } } } CheckBox := TouchArea { property checked; property text <=> t.text; clicked => { checked = !checked; } HorizontalLayout { spacing: 5px; VerticalLayout { alignment: center; Rectangle { width: 20px; height: 20px; border-width: 1.5px; border-color: root.has-hover ? Palette.widget-stroke : transparent; border-radius: 3px; background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background; if checked : Path { stroke: root.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke; stroke-width: root.pressed ? 2.5px : 2px; viewbox-height: 1; viewbox-width: 1; MoveTo { x: 0.2; y: 0.5; } LineTo { x: 0.5; y: 0.8; } LineTo { x: 0.8; y: 0.2; } } } } t := Label { } } } RadioButton := TouchArea { property checked; property text <=> t.text; HorizontalLayout { spacing: 5px; VerticalLayout { alignment: center; Rectangle { width: 20px; height: 20px; border-width: 1.5px; border-color: root.has-hover ? Palette.widget-stroke : transparent; border-radius: width / 2; background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background; if checked : Rectangle { background: root.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke; border-radius: width / 2; width: parent.width / 2; height: parent.width / 2; x: parent.width / 4; y: parent.width / 4; } } } t := Label { } } } SelectableLabel := TouchArea { min-height: t.min-height; min-width: t.min-width + 10px; property checked; property text <=> t.text; Rectangle { border-width: 1.5px; border-color: root.has-hover ? Palette.widget-stroke : transparent; border-radius: 3px; background: root.checked ? Palette.hyper-blue : root.pressed ? Palette.widget-background.darker(30%) : root.has-hover ? Palette.widget-background : transparent; t := Label { width: 100%; horizontal-alignment: center; } } } Slider := Rectangle { property maximum: 100; property minimum: 0; property value; property enabled <=> touch.enabled; callback changed(float); min-height: 24px; min-width: 100px; horizontal-stretch: 1; vertical-stretch: 0; Rectangle { width: parent.width; height: parent.height / 2; y: (parent.height - height) / 2; border-radius: 2px; background: Palette.widget-background; } handle := Rectangle { width: height; height: parent.height; border-radius: height / 2; border-color: touch.has-hover ? Palette.widget-stroke.darker(100%) : Palette.widget-stroke; border-width: touch.pressed ? 4px : touch.has-hover ? 3px : 2px; background: touch.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background; x: (root.width - handle.width) * max(0, min(1, (value - minimum)/(maximum - minimum))); } touch := 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(root.minimum, min(root.maximum, pressed-value + (touch.mouse-x - touch.pressed-x) * (maximum - minimum) / (root.width - handle.width))); root.changed(value); } } } } Hyperlink := Text { color: Palette.hyper-blue; TouchArea { mouse-cursor: pointer; } property link; } DragValue := TouchArea { property value; min-height: t.min-height; min-width: Math.max(t.min-width + 10px, 50px); Rectangle { border-width: 1.5px; border-color: root.has-hover ? Palette.widget-stroke : transparent; border-radius: 3px; background: root.pressed ? Palette.widget-background.darker(30%) : Palette.widget-background; t := Label { width: 100%; horizontal-alignment: center; text: round(value); } } moved => { if (pressed) { value = _pressed-value +(mouse-x - pressed-x) / 2px; } } pointer-event(e) => { if (e.kind == PointerEventKind.down) { _pressed-value = value; } } property _pressed-value; mouse-cursor: MouseCursor.ew-resize; } ProgressBar := Rectangle { property value; min-height: 24px; min-width: 100px; background: StyleMetrics.textedit-background; border-radius: height / 2; Rectangle { height: 100%; width: height + (parent.width - height) * max(0, min(1, value / 100)); border-radius: height / 2; background: Palette.hyper-blue; } Label { height: 100%; vertical-alignment: center; x: height/2; text: round(value) + "%"; } } //------ Demo apps ------- Gallery := GridBox { callback unsel(); unsel => { r1.checked = false; r2.checked = false; r3.checked = false; } Row { Text { text: "Label:"; } Label { text: "Welcome to the widget gallery!"; } } Row { Text { text: "Hyperlink:"; } Hyperlink { text: "Slint homepage"; link: "https://slint-ui.com"; } } Row { Text { text: "TextEdit:"; } LineEdit { placeholder-text: "WriteSomething here";} } Row { Text { text: "Button:"; } HorizontalLayout { alignment: start; Button { text: "Click me!"; clicked => { cb.checked = !cb.checked; } } } } Row { Text { text: "Checkbox:"; } cb := CheckBox { text: "Checkbox"; } } Row { Text { text: "RadioButton:"; } HorizontalBox { alignment: start; r1 := RadioButton { text: "First"; clicked => { unsel(); r1.checked = true; } } r2 := RadioButton { text: "Second"; clicked => { unsel(); r2.checked = true; } } r3 := RadioButton { text: "Third"; clicked => { unsel(); r3.checked = true; } } } } Row { Text { text: "SelectableLabel:"; } HorizontalBox { alignment: start; SelectableLabel { text: "First"; checked <=> r1.checked; clicked => { unsel(); r1.checked = true; } } SelectableLabel { text: "Second"; checked <=> r2.checked; clicked => { unsel(); r2.checked = true; } } SelectableLabel { text: "Third"; checked <=> r3.checked; clicked => { unsel(); r3.checked = true; } } } } Row { Text { text: "ComboBox:"; } HorizontalBox { alignment: start; ComboBox { model: ["First", "Second", "Third"]; selected => { r1.checked = current-index == 0; r2.checked = current-index == 1; r3.checked = current-index == 2; } } Label { text: "Take your pick"; } } } Row { Text { text: "Slider:"; } sl := Slider { } } Row { Text { text: "DragValue:"; } HorizontalLayout { alignment: start; DragValue { value <=> sl.value; } } } Row { Text { text: "ProgressBar:"; } ProgressBar { value <=> sl.value; } } Rectangle {} } TextEditDemo := VerticalLayout { preferred-height: 150px; preferred-width: 300px; TextEdit { text: "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"; } } Demo := Window { preferred-width: 1024px; preferred-height: 800px; background: white; w1 := MdiWindow { title: "🗄 Widget Gallery"; window-x: 30px; window-y: 20px; Gallery { } } w2 := MdiWindow { visible: false; title: "🗉 TextEdit"; window-x: 230px; window-y: 520px; TextEditDemo { } } side-panel := Rectangle { border-color: resize-side-panel.has-hover ? Palette.window-border.darker(100%) : Palette.window-border; border-width: 2px; background: Palette.window-background; x: parent.width - width; width: side-panel-l.preferred-width; height: 100%; side-panel-l := VerticalBox { alignment: start; Label { font-weight: 500; text: "Slint Demos"; horizontal-alignment: center; } Rectangle { height: 2px; background: Palette.window-border; } Label { preferred-width: 0px; text: "This is a demo which is based on the demo from the egui framework"; wrap: word-wrap; horizontal-alignment: center; } Rectangle { height: 2px; background: Palette.window-border; } CheckBox { text: w1.title; checked <=> w1.visible; } CheckBox { text: w2.title; checked <=> w2.visible; } } resize-side-panel := TouchArea { height: 100%; width: 4px; mouse-cursor: ew-resize; moved => { if (pressed) { side-panel.width = max(side-panel-l.min-width, min(root.width, side-panel.width - (mouse-x - pressed-x))); } } } } }