diff --git a/tools/lsp/ui/components/draggable-panel.slint b/tools/lsp/ui/components/draggable-panel.slint new file mode 100644 index 000000000..dc248a5db --- /dev/null +++ b/tools/lsp/ui/components/draggable-panel.slint @@ -0,0 +1,86 @@ +// Copyright © SixtyFPS GmbH +// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 + +import { Palette } from "std-widgets.slint"; +import { SimpleColumn } from "layout-helpers.slint"; +import { WindowGlobal } from "../windowglobal.slint"; + +export component DraggablePanel { + // Ensure to bing the parent window width and height so the panel can move if the window is resized + property parent-window-width: WindowGlobal.window-width; + property parent-window-height: WindowGlobal.window-height; + + property panel-target-x; + property panel-target-y; + + // If the parent window is resized, we need to make sure the panel is still visible + changed parent-window-width => { + if root.x + root.width > parent-window-width { + root.x = (parent-window-width - root.width).max(0); + } + } + + changed parent-window-height => { + if (root.y + root.height) > parent-window-height { + root.y = (parent-window-height - root.height).max(0); + } + } + + width: 300px; + height: content.height; + + hidden-input := TextInput { + visible: false; + } + + TouchArea { + changed pressed => { + // Workaround to ensure any item that has focus is de-focused + if self.pressed { + hidden-input.visible = true; + hidden-input.focus(); + hidden-input.clear-focus(); + hidden-input.visible = false; + } + } + moved => { + panel-target-x = ((root.x + self.mouse-x - self.pressed-x) / 1px).round() * 1px; + panel-target-y = ((root.y + self.mouse-y - self.pressed-y) / 1px).round() * 1px; + + if panel-target-x < 0px { + root.x = 0px; + } + if panel-target-x > 0px { + if panel-target-x < parent-window-width - root.width { + root.x = panel-target-x; + } else { + root.x = parent-window-width - root.width; + } + } + if panel-target-y < 0px { + root.y = 0px; + } + if panel-target-y > 0px { + if panel-target-y < parent-window-height - root.height { + root.y = panel-target-y; + } else { + root.y = parent-window-height - root.height; + } + } + } + } + + Rectangle { + background: Palette.background; + drop-shadow-blur: 24px; + drop-shadow-offset-y: 10px; + drop-shadow-color: rgba(0, 0, 0, 0.25); + border-width: 0.5px; + border-color: Palette.border; + border-radius: 13px; + } + + content := SimpleColumn { + @children + } +} diff --git a/tools/lsp/ui/components/layout-helpers.slint b/tools/lsp/ui/components/layout-helpers.slint new file mode 100644 index 000000000..748104124 --- /dev/null +++ b/tools/lsp/ui/components/layout-helpers.slint @@ -0,0 +1,11 @@ +// Copyright © SixtyFPS GmbH +// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 + +export component SimpleColumn { + in-out property spacing; + width: 100%; + vl := VerticalLayout { + spacing <=> root.spacing; + @children + } +} diff --git a/tools/lsp/ui/components/widgets/floating-color-picker-widget.slint b/tools/lsp/ui/components/widgets/floating-color-picker-widget.slint index e5f735bee..266e22b5c 100644 --- a/tools/lsp/ui/components/widgets/floating-color-picker-widget.slint +++ b/tools/lsp/ui/components/widgets/floating-color-picker-widget.slint @@ -6,7 +6,8 @@ import { WindowGlobal, WindowManager } from "../../windowglobal.slint"; import { Api, GradientStop } from "../../api.slint"; import { Icons } from "../../components/styling.slint"; import { BrushMode, PickerData, PickerMode, WidgetMode } from "../../properties-state.slint"; - +import { SimpleColumn } from "../../components/layout-helpers.slint"; +import { DraggablePanel } from "../../components/draggable-panel.slint"; export global Styles { out property section-color: Palette.color-scheme == ColorScheme.dark ? #3f3f3f : #f5f5f5; @@ -70,6 +71,7 @@ component ColorIndicator { width: 50%; background: hsv(hsv-color.hue, hsv-color.saturation, hsv-color.value); } + Rectangle { x: parent.width / 2; width: 50%; @@ -84,6 +86,7 @@ component ColorIndicator { horizontal-tiling: repeat; colorize: #e1e1e1; } + Rectangle { background: root.color; } @@ -344,15 +347,6 @@ component ColorModeColorAndApply { } } -component Column { - in-out property spacing; - width: 100%; - vl := VerticalLayout { - spacing <=> root.spacing; - @children - } -} - component VerticalSpacer { width: 100%; height: Styles.small-margin; @@ -378,7 +372,6 @@ component GradientSlider { TouchArea { changed pressed => { if self.pressed { - } } moved => { @@ -388,6 +381,7 @@ component GradientSlider { WindowManager.update-brush(); } } + Rectangle { x: parent.width / 2; y: 1px; @@ -572,7 +566,7 @@ component GradientStopValue { } } moved => { - PickerData.current-gradient-stops[stop-index].color = hsv(PickerData.current-gradient-stops[stop-index].color.to-hsv().hue, PickerData.current-gradient-stops[stop-index].color.to-hsv().saturation, PickerData.current-gradient-stops[stop-index].color.to-hsv().value, (initial-alpha + ((self.mouse-x - self.pressed-x) / 1px) / 100).clamp(0, 1) ); + PickerData.current-gradient-stops[stop-index].color = hsv(PickerData.current-gradient-stops[stop-index].color.to-hsv().hue, PickerData.current-gradient-stops[stop-index].color.to-hsv().saturation, PickerData.current-gradient-stops[stop-index].color.to-hsv().value, (initial-alpha + ((self.mouse-x - self.pressed-x) / 1px) / 100).clamp(0, 1)); WindowManager.update-brush(); } } @@ -581,7 +575,7 @@ component GradientStopValue { } } -component GradientPicker inherits Column { +component GradientPicker inherits SimpleColumn { Rectangle { height: 50px; @@ -615,8 +609,10 @@ component GradientPicker inherits Column { horizontal-tiling: repeat; colorize: #e1e1e1; } + Rectangle { - background: PickerData.current-brush;//@linear-gradient(-90deg, black 0%, #B62F2F 100%); + background: PickerData.current-brush; + //@linear-gradient(-90deg, black 0%, #B62F2F 100%); } Rectangle { @@ -664,7 +660,7 @@ component GradientPicker inherits Column { } } - Column { + SimpleColumn { spacing: 4px; for i[index] in PickerData.current-gradient-stops: GradientStopValue { stop-index: index; @@ -672,7 +668,7 @@ component GradientPicker inherits Column { } } -component HsvPicker inherits Column { +component HsvPicker inherits SimpleColumn { saturation-value-holder := Rectangle { height: self.width * 0.75; saturation-value := Rectangle { @@ -956,15 +952,12 @@ component HsvPicker inherits Column { } } -component ColorPicker { +component ColorPicker inherits DraggablePanel { property current-color <=> PickerData.current-color; in property widget-mode: edit; in property picker-mode: brush; in-out property brush-mode: color; - property picker-target-x; - property picker-target-y; - callback close <=> t-close.clicked; changed current-color => { @@ -974,105 +967,52 @@ component ColorPicker { } width: Styles.picker-width; - height: content.height; - hidden-input := TextInput { - visible: false; - } + title := Rectangle { + width: 100%; + height: 40px; - TouchArea { - changed pressed => { - if self.pressed { - hidden-input.visible = true; - hidden-input.focus(); - hidden-input.clear-focus(); - hidden-input.visible = false; + if picker-mode == PickerMode.brush: BrushTypeSelector { + brush-mode <=> root.brush-mode; + } + + Rectangle { + x: parent.width - self.width - 5px; + width: 25px; + height: self.width; + background: t-close.has-hover ? Styles.section-color : transparent; + border-radius: Styles.property-border-radius; + + t-close := TouchArea { } + + Image { + source: Icons.close; + colorize: Styles.text-color; } } - moved => { - picker-target-x = ((root.x + self.mouse-x - self.pressed-x) / 1px).round() * 1px; - picker-target-y = ((root.y + self.mouse-y - self.pressed-y) / 1px).round() * 1px; - if picker-target-x < 0px { - root.x = 0px; - } - if picker-target-x > 0px { - if picker-target-x < WindowGlobal.window-width - root.width { - root.x = picker-target-x; - } else { - root.x = WindowGlobal.window-width - root.width; - } - } - if picker-target-y < 0px { - root.y = 0px; - } - if picker-target-y > 0px { - if picker-target-y < WindowGlobal.window-height - root.height { - root.y = picker-target-y; - } else { - root.y = WindowGlobal.window-height - root.height; - } - } - } - } - - Rectangle { - background: Styles.background-color; - drop-shadow-blur: 24px; - drop-shadow-offset-y: 10px; - drop-shadow-color: rgba(0, 0, 0, 0.25); - border-width: 0.5px; - border-color: Styles.picker-border-color; - border-radius: 13px; - } - - content := Column { - title := Rectangle { + Rectangle { width: 100%; - height: 40px; - - if picker-mode == PickerMode.brush: BrushTypeSelector { - brush-mode <=> root.brush-mode; - } - - Rectangle { - x: parent.width - self.width - 5px; - width: 25px; - height: self.width; - background: t-close.has-hover ? Styles.section-color : transparent; - border-radius: Styles.property-border-radius; - - t-close := TouchArea { } - - Image { - source: Icons.close; - colorize: Styles.text-color; - } - } - - Rectangle { - width: 100%; - height: 1px; - x: 0; - y: parent.height - self.height; - background: Styles.divider-color; - } + height: 1px; + x: 0; + y: parent.height - self.height; + background: Styles.divider-color; } + } - if brush-mode == BrushMode.color: HsvPicker { } + if brush-mode == BrushMode.color: HsvPicker { } - if brush-mode == BrushMode.color: VerticalSpacer { } + if brush-mode == BrushMode.color: VerticalSpacer { } - if brush-mode == BrushMode.color: color-apply := ColorModeColorAndApply { - widget-mode: root.widget-mode; - } + if brush-mode == BrushMode.color: color-apply := ColorModeColorAndApply { + widget-mode: root.widget-mode; + } - if brush-mode == BrushMode.gradient: GradientPicker { } + if brush-mode == BrushMode.gradient: GradientPicker { } - footer := Rectangle { - width: 100%; - height: Styles.standard-margin; - } + footer := Rectangle { + width: 100%; + height: Styles.standard-margin; } } @@ -1083,34 +1023,6 @@ export component ColorPickerView { in property initial-x: 0; in property initial-y: 0; - changed width => { - if color-picker.x + color-picker.width > root.width { - color-picker.x = (root.width - color-picker.width).max(0); - } - } - - changed height => { - if (color-picker.y + color-picker.height) > root.height { - color-picker.y = (root.height - color-picker.height).max(0); - } - } - - pure function cursor-on-picker(mouse-x: length, mouse-y: length) -> bool { - if mouse-x < color-picker.x { - return false; - } - if mouse-y < color-picker.y { - return false; - } - if mouse-x > color-picker.x + color-picker.width { - return false; - } - if mouse-y > color-picker.y + color-picker.height { - return false; - } - return true; - } - TouchArea { changed pressed => { WindowManager.hide-floating-widget();