slint/tools/lsp/ui/components/expandable-listview.slint
Tobias Hunger bdf173d08c live-preview: Update the down-arrow icon
... using the chevron-down icon from the codicons
icon set.
2024-09-18 21:30:18 +02:00

175 lines
5.9 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 { HorizontalBox, Palette, ScrollView } from "std-widgets.slint";
import { ComponentListItem, ComponentItem } from "../api.slint";
import { StateLayer } from "./state-layer.slint";
import { EditorSizeSettings, EditorAnimationSettings, Icons } from "./styling.slint";
import { BodyText } from "./body-text.slint";
import { BodyStrongText } from "./body-strong-text.slint";
import { StatusLineApi } from "status-line.slint";
component HeaderItemTemplate {
in property <bool> enabled: true;
in property <string> text;
out property <bool> open: true;
out property <length> offset: icon-image.width + content-layer.spacing;
min-width: content-layer.min-width;
min-height: max(EditorSizeSettings.item-height, content-layer.min-height);
touch-area := TouchArea {
clicked => {
root.open = !root.open;
}
}
state-layer := StateLayer {
width: 100%;
height: 100%;
has-hover: touch-area.has-hover;
pressed: touch-area.pressed;
}
content-layer := HorizontalBox {
icon-image := Image {
width: EditorSizeSettings.default-icon-width;
colorize: Palette.foreground;
source: Icons.chevron-down;
rotation-origin-x: self.width / 2;
rotation-origin-y: self.height / 2;
states [
closed when !root.open: {
rotation-angle: -0.25turn;
}
]
animate rotation-angle { duration: EditorAnimationSettings.roation-duration; }
}
BodyText {
text: root.text;
opacity: 0.7;
}
}
states [
disabled when !root.enabled: {
root.opacity: 0.5;
}
]
}
component ItemTemplate {
in property <bool> enabled: true;
in property <string> text;
in property <bool> can-drop-here;
in property <length> offset;
out property <length> absolute-mouse-x: touch-area.mouse-x - touch-area.x + touch-area.absolute-position.x;
out property <length> absolute-mouse-y: touch-area.mouse-y - touch-area.y + touch-area.absolute-position.y;
out property <bool> pressed <=> touch-area.pressed;
callback clicked <=> touch-area.clicked;
callback pointer-event <=> touch-area.pointer-event;
min-width: content-layer.min-width;
min-height: max(EditorSizeSettings.item-height, content-layer.min-height);
touch-area := TouchArea {
states [
dragging-no-drop when self.pressed && !root.can-drop-here: {
mouse-cursor: MouseCursor.no-drop;
}
dragging-can-drop when self.pressed && root.can-drop-here: {
mouse-cursor: MouseCursor.copy;
}
normal when !self.pressed: {
mouse-cursor: MouseCursor.default;
}
]
changed has-hover => {
if self.has-hover {
StatusLineApi.help-text = @tr("Drag onto canvas to add {}", text);
}
}
}
state-layer := StateLayer {
width: 100%;
height: 100%;
has-hover: touch-area.has-hover;
pressed: touch-area.pressed;
}
content-layer := HorizontalBox {
padding-left: self.padding + root.offset;
BodyText {
text: root.text;
}
}
states [
disabled when !root.enabled: {
root.opacity: 0.5;
}
]
}
export component ExpandableListView inherits ScrollView {
in property <[ComponentListItem]> known-components;
in property <length> preview-area-position-x;
in property <length> preview-area-position-y;
in property <length> preview-area-width;
in property <length> preview-area-height;
in-out property <ComponentItem> visible-component: {
name: "",
defined-at: "",
pretty-location: "",
is-user-defined: false,
is-currently-shown: false,
};
pure callback can-drop(index: int, x: length, y: length, on-drop-area: bool) -> bool;
callback drop(index: int, x: length, y: length);
callback show-preview-for(name: string, defined-at: string);
property <bool> preview-visible: preview-area-width > 0px && preview-area-height > 0px;
property <length> list-spacing: 10px;
VerticalLayout {
alignment: start;
for cli[index] in root.known-components: VerticalLayout {
property <int> my-category-index: index;
header-item := HeaderItemTemplate {
text: cli.category;
}
if header-item.open: VerticalLayout {
for ci[index] in cli.components: ItemTemplate {
property <length> drop-x: self.absolute-mouse-x - root.preview-area-position-x;
property <length> drop-y: self.absolute-mouse-y - root.preview-area-position-y;
property <bool> on-drop-area:
drop-x >= 0 && drop-x <= root.preview-area-width && drop-y >= 0 && drop-y <= root.preview-area-height;
property <ComponentItem> data: ci;
can-drop-here: !self.data.is-currently-shown && root.can-drop(self.data.index, drop-x, drop-y, on-drop-area);
enabled: root.preview-visible;
text: ci.name;
offset: header-item.offset;
height: self.min-height;
pointer-event(event) => {
if self.can-drop-here && event.kind == PointerEventKind.up && event.button == PointerEventButton.left {
root.drop(self.data.index, drop-x, drop-y);
}
}
init() => {
root.visible-component = ci;
}
}
}
}
}
}