Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
0e185510cThis file is pinned to the selected release. Download the original to open it in your design tool.
import { DevicePinoutListView } from "devicepinoutlistview.slint";
import {
Badge,
Button,
IconButton,
LineEdit,
ScrollView,
} from "../../widgets.slint";
import {
Backend,
Data,
DeviceInteractivePinoutSignalData,
DeviceTabData,
TabAction,
} from "../../api.slint";
component DevicePinoutShortcutsText inherits Text {
font-size: 11px;
color: Data.theme.control-text-muted;
accessible-role: none;
}
component DevicePinoutShortcutsOverlay inherits GridLayout {
width: self.preferred-width;
height: self.preferred-height;
spacing-horizontal: 5px;
Row {
DevicePinoutShortcutsText {
horizontal-alignment: right;
text: @tr("Next/previous signal:");
}
DevicePinoutShortcutsText {
horizontal-alignment: left;
text: "⇩⇧";
}
}
Row {
DevicePinoutShortcutsText {
horizontal-alignment: right;
text: @tr("Select \"(unconnected)\":");
}
DevicePinoutShortcutsText {
horizontal-alignment: left;
text: "⌫";
}
}
Row {
DevicePinoutShortcutsText {
horizontal-alignment: right;
text: @tr("Confirm selected signal:");
}
DevicePinoutShortcutsText {
horizontal-alignment: left;
text: "⏎";
}
}
Row {
DevicePinoutShortcutsText {
horizontal-alignment: right;
text: @tr("Exit interactive mode:");
}
DevicePinoutShortcutsText {
horizontal-alignment: left;
text: "Esc";
}
}
Row {
mouse-txt := DevicePinoutShortcutsText {
horizontal-alignment: right;
text: @tr("Or assign by mouse:");
}
Image {
width: 10px;
height: mouse-txt.preferred-height;
image-fit: contain;
colorize: mouse-txt.color;
source: @image-url("../../../../font-awesome/svgs/solid/computer-mouse.svg");
accessible-role: none;
}
}
}
component DeviceInteractiveSignalListView inherits ScrollView {
in-out property <[DeviceInteractivePinoutSignalData]> model;
in property <int> current-index;
in property <bool> read-only;
min-height: min(l.preferred-height, 50px);
min-width: l.min-width;
preferred-width: l.preferred-width;
preferred-height: l.preferred-height;
mouse-drag-pan-enabled: true;
callback signal-clicked(idx: int);
l := VerticalLayout {
for item[index] in model: item-ta := TouchArea {
mouse-cursor: pointer;
enabled: !read-only;
Rectangle {
property <bool> is-current: index == current-index;
background: {
if is-current {
item-ta.has-hover ? Data.theme.accent.with-alpha(0.8) : Data.theme.accent;
} else {
item-ta.has-hover ? Data.theme.control-hovered : transparent
}
};
HorizontalLayout {
padding-left: 6px;
padding-right: 6px;
spacing: 5px;
Image {
width: 13px;
height: 20px;
image-fit: contain;
colorize: name-txt.color;
source: {
if item.name.is-empty {
@image-url("../../../../font-awesome/svgs/solid/link-slash.svg")
} else if item.used {
@image-url("../../../../font-awesome/svgs/regular/square-check.svg")
} else {
@image-url("../../../../font-awesome/svgs/regular/square.svg")
}
};
accessible-role: none;
}
name-txt := Text {
horizontal-alignment: left;
vertical-alignment: center;
color: is-current ? Data.theme.accent-text : Data.theme.control-text;
font-italic: item.name.is-empty;
overflow: elide;
text: item.name.is-empty ? @tr("(unconnected)") : item.name;
}
}
}
clicked => {
signal-clicked(index);
}
}
}
}
export component DevicePinoutPanel inherits Rectangle {
in property <int> section-index;
in-out property <[DeviceTabData]> tabs;
in property <int> index;
in property <bool> read-only;
in property <bool> interactive;
in property <length> window-height;
background: interactive ? Data.theme.accent : Data.theme.control-checked;
border-color: self.background;
border-width: 2px;
border-radius: 5px;
clip: true;
VerticalLayout {
padding: 2px;
HorizontalLayout {
padding: 3px;
spacing: 8px;
title-txt := Text {
horizontal-stretch: 1;
font-size: 14px;
font-weight: 700;
color: interactive ? Data.theme.accent-text : Data.theme.control-text;
overflow: elide;
vertical-alignment: center;
text: @tr("Pinout");
accessible-role: none;
}
if interactive: Badge {
text-color: title-txt.color;
font-size: 11px;
font-weight: 700;
text: @tr("Pad {}/{}", tabs[index].interactive-pinout-number, tabs[index].pinout.length);
}
Rectangle {
horizontal-stretch: 1;
}
if (!tabs[index].datasheet-url.is-empty) && tabs[index].datasheet-url-error.is-empty: datasheet-btn := IconButton {
height: 18px;
style: hyperlink;
icon: @image-url("../../../../font-awesome/svgs/solid/file-pdf.svg");
tooltip: @tr("Open Datasheet");
tooltip-position: left;
status-tip: tabs[index].datasheet-url;
color-enabled: title-txt.color.with-alpha(0.7);
color-hovered: title-txt.color;
clicked => {
Backend.trigger-tab(section-index, index, TabAction.open-datasheet);
}
}
if (!read-only) && (!interactive) && (tabs[index].pinout.length > 0): reset-btn := IconButton {
height: 18px;
style: hyperlink;
icon: @image-url("../../../../bootstrap-icons/icons/bootstrap-reboot.svg");
tooltip: @tr("Reset All Connections");
tooltip-position: left;
status-tip: @tr("Reset all pads to 'unconnected' state");
color-enabled: title-txt.color.with-alpha(0.7);
color-hovered: title-txt.color;
clicked => {
Backend.trigger-tab(section-index, index, TabAction.device-pinout-reset);
}
}
if interactive: exit-btn := IconButton {
height: 18px;
style: hyperlink;
icon: @image-url("../../../../font-awesome/svgs/solid/circle-xmark.svg");
tooltip: @tr("Exit Interactive Mode") + " (Esc)";
tooltip-position: left;
color-enabled: title-txt.color.with-alpha(0.7);
color-hovered: title-txt.color;
clicked => {
Backend.trigger-tab(section-index, index, TabAction.abort);
}
}
}
if interactive: HorizontalLayout {
padding: 5px;
spacing: 5px;
Rectangle {
background: interactive-filter-edt.background;
border-color: Data.theme.control-border;
border-width: 1px;
HorizontalLayout {
padding: 1px;
padding-left: 8px;
padding-right: 8px;
spacing: 2px;
current-pad-name-txt := Text {
horizontal-stretch: 0;
font-size: 14px;
font-weight: 700;
horizontal-alignment: right;
vertical-alignment: center;
overflow: elide;
font-family: "Noto Sans Mono";
color: Data.theme.control-text-muted;
text: tabs[index].interactive-pinout-pad + ":";
accessible-label: "current pad";
}
interactive-filter-edt := LineEdit {
horizontal-stretch: 0;
text: tabs[index].interactive-pinout-filter;
placeholder-text: @tr("Type to filter signals...");
border-color: transparent;
frameless: true;
read-only: read-only;
accessible-label: "signal filter";
// Actually we want to gain the focus in the init()
// callback, but that leads to a crash :-/
Timer {
running: true;
interval: 200ms;
triggered => {
self.running = false;
parent.focus();
}
}
text-edited(text) => {
tabs[index].interactive-pinout-filter = text;
}
key-pressed(event) => {
if event.text == Key.UpArrow {
tabs[index].interactive-pinout-signal-index -= 1;
return accept;
} else if event.text == Key.DownArrow {
tabs[index].interactive-pinout-signal-index += 1;
return accept;
} else if event.text == Key.Return {
Backend.trigger-tab(section-index, index, TabAction.accept);
return accept;
} else if (event.text == Key.Escape) && (!self.text.is-empty) {
tabs[index].interactive-pinout-filter = "";
return accept;
} else if (event.text == Key.Backspace) && self.text.is-empty {
tabs[index].interactive-pinout-signal-index = -2; // Select "unconnected"
return accept;
}
reject
}
}
}
}
}
Rectangle {
min-width: 300px;
max-width: self.preferred-width * 1.5;
background: Data.theme.control;
VerticalLayout {
alignment: start;
padding-top: interactive ? 1px : 5px;
padding-bottom: 8px;
if interactive: interactive-view := DeviceInteractiveSignalListView {
vertical-stretch: 1;
model: tabs[index].interactive-pinout-signals;
current-index: tabs[index].interactive-pinout-signal-index;
read-only: read-only;
signal-clicked(idx) => {
tabs[index].interactive-pinout-signal-index = idx;
Backend.trigger-tab(section-index, index, TabAction.accept);
}
}
pinout-view := DevicePinoutListView {
max-height: interactive ? 0 : 9999px;
window-height: window-height;
model: tabs[index].pinout;
signal-names: tabs[index].signal-names;
read-only: read-only;
visible: !interactive;
}
if !interactive: VerticalLayout {
padding-left: 8px;
padding-right: 8px;
spacing: 8px;
// Workaround for broken layout (not growing
// horizontally) if the layout is empty.
Rectangle {
height: 3px;
}
if tabs[index].pinout.length == 0: Text {
preferred-width: 0; // Do not influence the layout.
horizontal-alignment: center;
color: Data.theme.control-text-muted;
font-italic: true;
wrap: word-wrap;
text: @tr("The package contains no pads, thus the pinout is empty.");
}
if (!read-only) && tabs[index].has-auto-connectable-pads: auto-connect-btn := Button {
text: @tr("Auto-Connect By Names");
icon: @image-url("../../../../font-awesome/svgs/solid/wand-magic-sparkles.svg");
status-tip: @tr("Try to automatically connect pads to signals by their name");
primary: true;
clicked => {
Backend.trigger-tab(section-index, index, TabAction.device-pinout-connect-auto);
}
}
if (!read-only) && tabs[index].has-unconnected-pads: interactive-connect-btn := Button {
text: @tr("Connect Interactively");
icon: @image-url("../../../../font-awesome/svgs/solid/hand-sparkles.svg");
status-tip: @tr("Connect the remaining pads one by one in an interactive mode");
primary: !tabs[index].has-auto-connectable-pads; // Exclusive-or
clicked => {
Backend.trigger-tab(section-index, index, TabAction.device-pinout-connect-interactively);
}
}
if (!read-only) && tabs[index].all-pads-unconnected: import-btn := Button {
text: @tr("Load From File");
icon: @image-url("../../../../font-awesome/svgs/solid/arrow-up-from-bracket.svg");
status-tip: @tr("Import the pinout from a CSV file with these columns:") + " Pad,Signal";
clicked => {
Backend.trigger-tab(section-index, index, TabAction.device-pinout-load-from-file);
}
}
}
}
if interactive: DevicePinoutShortcutsOverlay {
x: parent.width - self.width - 8px;
y: parent.height - self.height - 8px;
}
}
}
}