mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-03 21:24:17 +00:00
350 lines
14 KiB
Text
350 lines
14 KiB
Text
// 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 { ListView, Palette } from "std-widgets.slint";
|
|
import { EditorFontSettings, EditorSizeSettings, EditorSpaceSettings, EditorPalette } from "./styling.slint";
|
|
import { Api, SelectionStackFrame } from "../api.slint";
|
|
|
|
component PopupInner inherits Rectangle {
|
|
in property <length> preview-width: 500px;
|
|
in property <length> preview-height: 900px;
|
|
private property <float> aspect-ratio: preview-width / preview-height;
|
|
in property <length> selection-x: 0px;
|
|
in property <length> selection-y: 0px;
|
|
in property <[SelectionStackFrame]> selection-stack: [
|
|
{
|
|
width: 100%,
|
|
height: 40%,
|
|
x: 10%,
|
|
y: 0%,
|
|
is-in-root-component: true,
|
|
is-layout: false,
|
|
is-interactive: true,
|
|
is-selected: false,
|
|
type-name: "TypeA",
|
|
file-name: "thumb.slint",
|
|
id: "some_a",
|
|
},
|
|
{
|
|
width: 50%,
|
|
height: 50%,
|
|
x: 0%,
|
|
y: 0%,
|
|
is-in-root-component: false,
|
|
is-layout: true,
|
|
is-interactive: false,
|
|
is-selected: false,
|
|
file-name: "thumb.slint",
|
|
type-name: "HorizontalLayout",
|
|
},
|
|
{
|
|
width: 50%,
|
|
height: 10%,
|
|
x: 20%,
|
|
y: 40%,
|
|
is-in-root-component: false,
|
|
is-layout: false,
|
|
is-interactive: false,
|
|
is-selected: false,
|
|
type-name: "Rectangle",
|
|
file-name: "tiling.slint",
|
|
id: "",
|
|
},
|
|
{
|
|
width: 50%,
|
|
height: 50%,
|
|
x: 50%,
|
|
y: 50%,
|
|
is-in-root-component: false,
|
|
is-interactive: false,
|
|
is-selected: true,
|
|
type-name: "TypeA",
|
|
file-name: "finger.slint",
|
|
id: "some_a",
|
|
},
|
|
{
|
|
width: 250%,
|
|
height: 50%,
|
|
x: 50%,
|
|
y: 50%,
|
|
is-in-root-component: false,
|
|
is-layout: false,
|
|
is-interactive: true,
|
|
is-selected: false,
|
|
type-name: "Button",
|
|
file-name: "finger.slint",
|
|
id: "alsoInteractive",
|
|
},
|
|
{
|
|
width: 50%,
|
|
height: 50%,
|
|
x: 0%,
|
|
y: 50%,
|
|
is-in-root-component: false,
|
|
is-layout: true,
|
|
is-interactive: false,
|
|
is-selected: false,
|
|
file-name: "finger.slint",
|
|
type-name: "VerticalLayout",
|
|
},
|
|
{
|
|
width: 5%,
|
|
height: 5%,
|
|
x: 25%,
|
|
y: 25%,
|
|
is-in-root-component: true,
|
|
is-layout: false,
|
|
is-interactive: false,
|
|
is-selected: false,
|
|
id: "words",
|
|
type-name: "Text",
|
|
},
|
|
{
|
|
width: 50%,
|
|
height: 100%,
|
|
x: 0%,
|
|
y: 0%,
|
|
is-in-root-component: true,
|
|
is-layout: false,
|
|
is-interactive: false,
|
|
is-selected: false,
|
|
type-name: "Window",
|
|
id: "",
|
|
}
|
|
];
|
|
private property <length> max-rect-size: 40px;
|
|
private property <length> frame-height: self.max-rect-size + EditorSpaceSettings.default-padding * 2;
|
|
|
|
private property <int> max-visible-frames: Math.floor(((900px / 1px) * 0.8) / (self.frame-height / 1px));
|
|
private property <int> visible-frames: Math.min(self.max-visible-frames, root.selection-stack.length);
|
|
border-radius: EditorSizeSettings.radius;
|
|
border-width: 0.5px;
|
|
background: Palette.background;
|
|
drop-shadow-blur: 10px;
|
|
drop-shadow-color: black;
|
|
border-color: lightgray;
|
|
|
|
width: 250px;
|
|
height: visible-frames * frame-height;
|
|
|
|
function select-frame(index: int) {
|
|
if index >= 0 {
|
|
list-view.viewport-y = (index - (self.visible-frames / 2)) * self.frame-height;
|
|
} else {
|
|
list-view.viewport-x = 0px;
|
|
}
|
|
}
|
|
|
|
list-view := ListView {
|
|
for frame[index] in root.selection-stack: frame-rect := Rectangle {
|
|
width: 100%;
|
|
|
|
if frame.is-selected: Rectangle {
|
|
background: Palette.accent-background;
|
|
init() => {
|
|
root.select-frame(index);
|
|
}
|
|
}
|
|
|
|
function frame-color(frame: SelectionStackFrame) -> brush {
|
|
return EditorPalette.interactive-element-selection-secondary;
|
|
}
|
|
function frame-background(frame: SelectionStackFrame) -> brush {
|
|
if frame.is-interactive {
|
|
return EditorPalette.interactive-element-selection-primary;
|
|
} else if frame.is-layout {
|
|
return transparent;
|
|
} else if frame.is-selected {
|
|
EditorPalette.general-element-selection-selected;
|
|
} else {
|
|
return EditorPalette.general-element-selection-primary;
|
|
}
|
|
}
|
|
|
|
function calculate_pos(p: length, percent: float) -> length {
|
|
return Math.round((p / 1px) * percent) * 1px;
|
|
}
|
|
function calculate_size(p: length, percent: float) -> length {
|
|
return Math.max(Math.round((p / 1px) * percent), 2) * 1px;
|
|
}
|
|
VerticalLayout {
|
|
padding-top: EditorSpaceSettings.default-padding / 2;
|
|
if !frame.is-in-root-component: Text {
|
|
x: EditorSpaceSettings.default-padding;
|
|
text: frame.file-name;
|
|
color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
|
|
font-size: EditorFontSettings.label-sub.font-size - 3px;
|
|
font-italic: true;
|
|
}
|
|
|
|
HorizontalLayout {
|
|
visible: (frame.type-name == "Window") ? false : true;
|
|
padding-left: EditorSpaceSettings.default-padding / 2.0;
|
|
spacing: EditorSpaceSettings.default-spacing / 2.0;
|
|
alignment: start;
|
|
|
|
VerticalLayout {
|
|
alignment: center;
|
|
padding-bottom: EditorSpaceSettings.default-padding / 2;
|
|
Rectangle {
|
|
function calculate_aspect_ratio_box(aspect-ratio: float, max-rect-length: length) -> length {
|
|
return Math.min(aspect-ratio, 1.0) * max-rect-length;
|
|
}
|
|
clip: true;
|
|
width: calculate_aspect_ratio_box(root.aspect-ratio, root.max-rect-size) + EditorSpaceSettings.default-padding;
|
|
height: calculate_aspect_ratio_box(1.0 / root.aspect-ratio, root.max-rect-size) + EditorSpaceSettings.default-padding / 2;
|
|
measure-rect := Rectangle {
|
|
width: calculate_aspect_ratio_box(root.aspect-ratio, root.max-rect-size);
|
|
height: calculate_aspect_ratio_box(1.0 / root.aspect-ratio, root.max-rect-size);
|
|
|
|
border-color: frame.is-selected ? EditorPalette.general-element-selection-selected.transparentize(0.5) : Palette.foreground.transparentize(0.65);
|
|
border-width: 1px;
|
|
placeholder-rect := Rectangle {
|
|
x: calculate_pos(measure-rect.width, frame.x);
|
|
y: calculate_pos(measure-rect.height, frame.y);
|
|
width: calculate_size(measure-rect.width, frame.width);
|
|
height: calculate_size(measure-rect.height, frame.height);
|
|
|
|
border-color: frame-rect.frame-color(frame);
|
|
border-width: 0.5px;
|
|
background: frame-rect.frame-background(frame);
|
|
if frame.is-layout: Rectangle {
|
|
border-color: EditorPalette.layout-element-selection-secondary;
|
|
border-width: 0.5px;
|
|
if (frame.type-name == "HorizontalLayout" || frame.type-name == "HorizontalBox"): HorizontalLayout {
|
|
spacing: 1px;
|
|
padding: 1px;
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
}
|
|
|
|
if (frame.type-name == "VerticalLayout" || frame.type-name == "VerticalBox"): VerticalLayout {
|
|
spacing: 1.5px;
|
|
padding: 1.5px;
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
}
|
|
if (frame.type-name == "GridLayout" || frame.type-name == "GridBox"): VerticalLayout {
|
|
spacing: 1px;
|
|
HorizontalLayout {
|
|
spacing: 1.5px;
|
|
padding: 1.5px;
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
}
|
|
|
|
HorizontalLayout {
|
|
spacing: 1.5px;
|
|
padding: 1.5px;
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
|
|
Rectangle {
|
|
background: EditorPalette.layout-element-selection-primary;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VerticalLayout {
|
|
padding-left: EditorSpaceSettings.default-padding;
|
|
spacing: EditorSpaceSettings.default-spacing / 2;
|
|
alignment: center;
|
|
|
|
if frame.id != "": Text {
|
|
text: frame.id;
|
|
color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
|
|
font-weight: EditorFontSettings.bold-font-weight;
|
|
font-size: EditorFontSettings.label.font-size;
|
|
}
|
|
|
|
Text {
|
|
text: frame.type-name + (frame.is-interactive ? " (TouchArea)" : "");
|
|
color: frame.is-selected ? Palette.accent-foreground : Palette.foreground;
|
|
font-size: EditorFontSettings.label-sub.font-size;
|
|
font-italic: true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
height: 1px;
|
|
background: Palette.foreground.transparentize(0.9);
|
|
}
|
|
}
|
|
TouchArea {
|
|
clicked() => {
|
|
Api.select-element(frame.element-path, frame.element-offset, frame.x * root.preview-width, frame.y * root.preview-height);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export component SelectionPopup {
|
|
public function show-selection-stack(x: length, y: length) {
|
|
self.selection-x = x;
|
|
self.selection-y = y;
|
|
self.selection-stack = Api.selection-stack-at(self.selection-x, self.selection-y);
|
|
|
|
popup.show();
|
|
}
|
|
|
|
public function close-selection-stack() {
|
|
self.selection-x = 0;
|
|
self.selection-y = 0;
|
|
self.selection-stack = [];
|
|
|
|
popup.close();
|
|
}
|
|
|
|
in property <length> preview-width;
|
|
in property <length> preview-height;
|
|
|
|
private property <[SelectionStackFrame]> selection-stack;
|
|
private property <length> selection-x;
|
|
private property <length> selection-y;
|
|
|
|
popup := PopupWindow {
|
|
x: 20px;
|
|
y: 20px;
|
|
|
|
in property <length> preview-width: root.preview-width;
|
|
in property <length> preview-height: root.preview-height;
|
|
in property <[SelectionStackFrame]> selection-stack: root.selection-stack;
|
|
in property <length> selection-x: root.selection-x;
|
|
in property <length> selection-y: root.selection-y;
|
|
|
|
VerticalLayout {
|
|
inner := PopupInner {
|
|
preview-width <=> popup.preview-width;
|
|
preview-height <=> popup.preview-height;
|
|
selection-stack <=> popup.selection-stack;
|
|
selection-x <=> popup.selection-x;
|
|
selection-y <=> popup.selection-y;
|
|
}
|
|
}
|
|
}
|
|
}
|