slint/tools/lsp/ui/components/expandable-listview.slint
2025-06-26 15:39:18 +02:00

149 lines
4.2 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.rotation-duration; }
}
BodyText {
text: root.text;
opacity: 0.7;
}
}
states [
disabled when !root.enabled: {
root.opacity: 0.5;
}
]
}
component ItemTemplate {
in property <ComponentItem> data;
in property <bool> enabled: true;
in property <string> text;
in property <bool> can-drop-here;
in property <length> offset;
out property <bool> pressed <=> touch-area.pressed;
callback clicked <=> touch-area.clicked;
min-width: content-layer.min-width;
min-height: max(EditorSizeSettings.item-height, content-layer.min-height);
DragArea {
mime-type: "application/x-slint-component";
data: data.index;
touch-area := TouchArea {
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 <bool> preview-is-current;
in-out property <ComponentItem> visible-component: {
name: "",
defined-at: "",
pretty-location: "",
is-user-defined: false,
is-currently-shown: false,
};
callback show-preview-for(name: string, defined-at: string);
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 {
data: ci;
text: ci.name;
offset: header-item.offset;
height: self.min-height;
init() => {
root.visible-component = ci;
}
}
}
}
}
}