Loading files
94ec4b8feThis file is pinned to the selected release. Download the original to open it in your design tool.
import {
Badge,
IconButton,
ListViewItemButton,
PanelHeader,
ScrollView,
} from "widgets.slint";
import {
Backend,
BoardAction,
CategoryTabData,
ComponentTabData,
Data,
DeviceTabData,
EditorCommandSet as Cmd,
LibraryData,
LibraryElementAction,
OrganizationTabData,
PackageTabData,
ProjectAction,
ProjectData,
SchematicAction,
SymbolTabData,
TabType,
} from "api.slint";
enum ItemType {
schematic,
board,
library,
}
component DocumentsListItem inherits Rectangle {
in property <ItemType> type;
in property <string> text;
in property <image> icon;
in property <bool> selected: false;
in property <bool> can-rename: true;
callback clicked <=> ta.clicked;
callback schematic-action-triggered(a: SchematicAction);
callback board-action-triggered(a: BoardAction);
height: 27px;
background: {
if selected {
Data.theme.control-checked
} else if ta.has-hover {
Data.theme.control-hovered
} else {
transparent
}
};
ta := TouchArea {
HorizontalLayout {
padding: 3px;
padding-left: 5px;
padding-right: 5px;
spacing: 5px;
Rectangle {
width: self.height;
Image {
x: 2px;
y: self.x;
width: self.height;
height: parent.height - 2 * self.x;
colorize: txt.color;
image-fit: contain;
source: icon;
accessible-role: none;
}
}
txt := Text {
vertical-alignment: center;
overflow: elide;
color: Data.theme.base-text;
text: text;
}
if (ta.has-hover || selected) && (type == ItemType.schematic) && can-rename: rename-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 18px;
icon: Cmd.sheet-rename.icon;
tooltip: Cmd.sheet-rename.text;
clicked => {
schematic-action-triggered(SchematicAction.rename);
}
}
if (ta.has-hover || selected) && (type == ItemType.schematic): delete-schematic-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 18px;
icon: @image-url("../../font-awesome/svgs/solid/trash-can.svg");
tooltip: Cmd.sheet-remove.text;
clicked => {
schematic-action-triggered(SchematicAction.delete);
}
}
if (ta.has-hover || selected) && (type == ItemType.board): open-3d-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 20px;
icon: @image-url("../../bootstrap-icons/icons/badge-3d.svg");
tooltip: @tr("Open 3D View");
clicked => {
board-action-triggered(BoardAction.open-3d);
}
}
if (ta.has-hover || selected) && (type == ItemType.board): setup-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 18px;
icon: @image-url("../../font-awesome/svgs/solid/sliders.svg");
tooltip: Cmd.board-setup.text;
clicked => {
board-action-triggered(BoardAction.open-setup-dialog);
}
}
if (ta.has-hover || selected) && (type == ItemType.board): copy-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 18px;
icon: Cmd.board-copy.icon;
tooltip: Cmd.board-copy.text;
clicked => {
board-action-triggered(BoardAction.copy);
}
}
if (ta.has-hover || selected) && (type == ItemType.board): delete-board-btn := ListViewItemButton {
y: (parent.height - self.height) / 2;
height: 18px;
icon: @image-url("../../font-awesome/svgs/solid/trash-can.svg");
tooltip: Cmd.board-remove.text;
clicked => {
board-action-triggered(BoardAction.delete);
}
}
}
}
}
component ProjectSection inherits Rectangle {
in property <ProjectData> project;
in property <int> project-index;
VerticalLayout {
header-ta := TouchArea {
z: 10; // For the tooltip.
header := PanelHeader {
title: project.name.to-uppercase();
highlight: project-index == Data.current-project-index;
if (self.max-buttons >= 5) && project.unsaved-changes && project.writable: save-btn := IconButton {
cmd: Cmd.save;
icon-scale: 60%;
color-enabled: Data.theme.base-text-warning;
clicked => {
Backend.trigger-project(project-index, ProjectAction.save);
}
}
if self.max-buttons >= 4: new-sheet-btn := IconButton {
cmd: Cmd.sheet-new;
icon-scale: 60%;
clicked => {
Backend.trigger-project(project-index, ProjectAction.new-sheet);
}
}
if self.max-buttons >= 3: new-board-btn := IconButton {
cmd: Cmd.board-new;
icon: @image-url("../../bootstrap-icons/icons/motherboard.svg");
icon-scale: 60%;
clicked => {
Backend.trigger-project(project-index, ProjectAction.new-board);
}
}
if self.max-buttons >= 2: setup-dialog-btn := IconButton {
cmd: Cmd.project-setup;
icon-scale: 60%;
clicked => {
Backend.trigger-project(project-index, ProjectAction.open-setup-dialog);
}
}
if self.max-buttons >= 1: close-btn := IconButton {
cmd: Cmd.project-close;
icon-scale: 60%;
clicked => {
Backend.trigger-project(project-index, ProjectAction.close);
}
}
}
clicked => {
Data.set-current-project(project-index);
}
}
for schematic[index] in project.schematics: schematic-item := DocumentsListItem {
type: ItemType.schematic;
text: schematic.name;
can-rename: project.schematics.length > 1; // Because default name is hidden.
icon: @image-url("../../font-awesome/svgs/regular/image.svg");
selected: (Data.current-tab.type == TabType.schematic) && (Data.current-schematic-tab.project-index == project-index) && (Data.current-schematic-tab.schematic-index == index);
clicked => {
Backend.trigger-schematic(project-index, index, SchematicAction.open);
}
schematic-action-triggered(a) => {
Backend.trigger-schematic(project-index, index, a);
}
}
for board[index] in project.boards: board-item := DocumentsListItem {
type: ItemType.board;
text: board.name;
icon: @image-url("../../bootstrap-icons/icons/motherboard.svg");
selected: {
if Data.current-tab.type == TabType.board-2d {
(Data.current-board-2d-tab.project-index == project-index) && (Data.current-board-2d-tab.board-index == index)
} else if Data.current-tab.type == TabType.board-3d {
(Data.current-board-3d-tab.project-index == project-index) && (Data.current-board-3d-tab.board-index == index)
} else {
false
}
};
clicked => {
Backend.trigger-board(project-index, index, BoardAction.open-2d);
}
board-action-triggered(a) => {
Backend.trigger-board(project-index, index, a);
}
}
}
}
component LibrarySection inherits Rectangle {
in property <LibraryData> library;
in property <int> library-index;
VerticalLayout {
header-ta := TouchArea {
z: 10; // For the tooltip.
header := PanelHeader {
title: library.name.to-uppercase();
highlight: library-index == Data.current-library-index;
close-btn := IconButton {
tooltip: @tr("Close Library");
status-tip: @tr("Close this library and all its opened tabs");
icon: @image-url("../../font-awesome/svgs/solid/xmark.svg");
icon-scale: 60%;
clicked => {
Backend.trigger-library-element(library.path, LibraryElementAction.close);
}
}
}
clicked => {
Data.set-current-library(library-index);
}
}
overview-item := DocumentsListItem {
type: ItemType.library;
text: @tr("Library Overview");
icon: @image-url("../../bootstrap-icons/icons/database.svg");
selected: (Data.current-tab.type == TabType.library) && (Data.current-library-tab.library-index == library-index);
clicked => {
Backend.trigger-library-element(library.path, LibraryElementAction.open);
}
}
for section in Data.sections: VerticalLayout {
// Note: In the past, we had separate loops for each library type,
// to keep the documents sorted by type. However, this loop would
// iterate over invalid model items (std::nullopt), which causes
// the UI to freeze if assistive technologies are enabled. When
// going back to the old concept, make sure this freeze is fixed.
for tab[idx] in section.tabs: VerticalLayout {
if (tab.type == TabType.component-category) && (section.component-category-tabs[idx].library-index == library-index): DocumentsListItem {
property <CategoryTabData> derived-tab: section.component-category-tabs[idx];
type: ItemType.library;
text: tab.title;
icon: @image-url("../../bootstrap-icons/icons/folder.svg");
selected: (Data.current-tab.type == TabType.component-category) && (Data.current-component-category-tab.library-index == library-index) && (Data.current-component-category-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.package-category) && (section.package-category-tabs[idx].library-index == library-index): DocumentsListItem {
property <CategoryTabData> derived-tab: section.package-category-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../bootstrap-icons/icons/folder.svg");
selected: (Data.current-tab.type == TabType.package-category) && (Data.current-package-category-tab.library-index == library-index) && (Data.current-package-category-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.symbol) && (section.symbol-tabs[idx].library-index == library-index): DocumentsListItem {
property <SymbolTabData> derived-tab: section.symbol-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../../img/symbol.png");
selected: (Data.current-tab.type == TabType.symbol) && (Data.current-symbol-tab.library-index == library-index) && (Data.current-symbol-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.package) && (section.package-tabs[idx].library-index == library-index): DocumentsListItem {
property <PackageTabData> derived-tab: section.package-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../../img/footprint.png");
selected: (Data.current-tab.type == TabType.package) && (Data.current-package-tab.library-index == library-index) && (Data.current-package-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.component) && (section.component-tabs[idx].library-index == library-index): DocumentsListItem {
property <ComponentTabData> derived-tab: section.component-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../bootstrap-icons/icons/cpu.svg");
selected: (Data.current-tab.type == TabType.component) && (Data.current-component-tab.library-index == library-index) && (Data.current-component-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.device) && (section.device-tabs[idx].library-index == library-index): DocumentsListItem {
property <DeviceTabData> derived-tab: section.device-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../bootstrap-icons/icons/cpu-fill.svg");
selected: (Data.current-tab.type == TabType.device) && (Data.current-device-tab.library-index == library-index) && (Data.current-device-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
if (tab.type == TabType.organization) && (section.organization-tabs[idx].library-index == library-index): DocumentsListItem {
property <OrganizationTabData> derived-tab: section.organization-tabs[idx];
type: ItemType.library;
text: section.tabs[idx].title;
icon: @image-url("../../bootstrap-icons/icons/buildings.svg");
selected: (Data.current-tab.type == TabType.organization) && (Data.current-organization-tab.library-index == library-index) && (Data.current-organization-tab.path == derived-tab.path);
clicked => {
Backend.trigger-library-element(derived-tab.path, LibraryElementAction.open);
}
}
}
}
}
}
export component DocumentsPanel inherits ScrollView {
mouse-drag-pan-enabled: true;
VerticalLayout {
width: 100%;
alignment: start;
for project[project-index] in Data.projects: project-item := ProjectSection {
project: project;
project-index: project-index;
}
for library[library-index] in Data.libraries: library-item := LibrarySection {
library: library;
library-index: library-index;
}
}
}