mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-22 00:02:40 +00:00
Refactor out a reusable DraggablePanel (#8111)
This commit is contained in:
parent
7a1bc6f6d7
commit
cbb5b96ade
3 changed files with 144 additions and 135 deletions
86
tools/lsp/ui/components/draggable-panel.slint
Normal file
86
tools/lsp/ui/components/draggable-panel.slint
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// 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 <length> parent-window-width: WindowGlobal.window-width;
|
||||
property <length> parent-window-height: WindowGlobal.window-height;
|
||||
|
||||
property <length> panel-target-x;
|
||||
property <length> 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
|
||||
}
|
||||
}
|
11
tools/lsp/ui/components/layout-helpers.slint
Normal file
11
tools/lsp/ui/components/layout-helpers.slint
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// 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 <length> spacing;
|
||||
width: 100%;
|
||||
vl := VerticalLayout {
|
||||
spacing <=> root.spacing;
|
||||
@children
|
||||
}
|
||||
}
|
|
@ -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 <color> 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 <length> 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 <WidgetMode> widget-mode: edit;
|
||||
in property <PickerMode> picker-mode: brush;
|
||||
in-out property <BrushMode> brush-mode: color;
|
||||
|
||||
property <length> picker-target-x;
|
||||
property <length> 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 <length> initial-x: 0;
|
||||
in property <length> 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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue