224 lines
7.3 KiB
Plaintext
224 lines
7.3 KiB
Plaintext
import { Theme } from "theme.slint";
|
||
import { IconButton } from "widgets.slint";
|
||
|
||
export struct TabInfo {
|
||
id: string,
|
||
title: string,
|
||
kind: string, // "welcome" | "terminal"
|
||
connected: bool,
|
||
}
|
||
|
||
// --- SingleTab -------------------------------------------------------------
|
||
component SingleTab inherits Rectangle {
|
||
in property <TabInfo> info;
|
||
in property <bool> active;
|
||
in property <bool> shown: true;
|
||
in property <bool> app-background-active: false;
|
||
in property <float> ui-opacity: 0.72;
|
||
callback selected();
|
||
callback closed();
|
||
|
||
height: shown ? 30px : 0px;
|
||
property <length> title-width: min(128px, max(34px, title-probe.preferred-width));
|
||
property <length> tab-width: info.kind == "welcome"
|
||
? max(72px, title-width + 34px)
|
||
: max(74px, title-width + 62px);
|
||
width: shown ? min(176px, tab-width) : 0px;
|
||
visible: shown;
|
||
horizontal-stretch: 0;
|
||
vertical-stretch: 0;
|
||
border-radius: Theme.radius-sm;
|
||
background: active ? (root.app-background-active ? Theme.bg-panel.with-alpha(root.ui-opacity) : Theme.bg-panel)
|
||
: (touch.has-hover ? Theme.bg-hover : transparent);
|
||
animate background { duration: 120ms; }
|
||
|
||
// Declared FIRST so the HorizontalLayout's children (close button) are at
|
||
// a higher z-order and receive their own click events.
|
||
touch := TouchArea {
|
||
mouse-cursor: pointer;
|
||
clicked => { root.selected(); }
|
||
}
|
||
|
||
title-probe := Text {
|
||
text: info.title;
|
||
font-size: Theme.fs-sm;
|
||
opacity: 0;
|
||
x: -1000px;
|
||
y: -1000px;
|
||
}
|
||
|
||
HorizontalLayout {
|
||
height: parent.height;
|
||
padding-left: 10px;
|
||
padding-right: 6px;
|
||
spacing: 8px;
|
||
alignment: center;
|
||
|
||
// Status indicator
|
||
Rectangle {
|
||
width: 8px;
|
||
height: parent.height;
|
||
|
||
Rectangle {
|
||
y: (parent.height - self.height) / 2;
|
||
width: parent.width;
|
||
height: 8px;
|
||
border-radius: 4px;
|
||
background: info.kind == "welcome" ? Theme.text-muted
|
||
: (info.connected ? Theme.success : Theme.warning);
|
||
}
|
||
}
|
||
|
||
Text {
|
||
text: info.title;
|
||
height: parent.height;
|
||
color: active ? Theme.text-primary : Theme.text-secondary;
|
||
font-size: Theme.fs-sm;
|
||
vertical-alignment: center;
|
||
overflow: elide;
|
||
horizontal-stretch: 1;
|
||
}
|
||
|
||
// Only show close button for non-welcome tabs
|
||
if info.kind != "welcome" : Rectangle {
|
||
width: 20px;
|
||
height: parent.height;
|
||
IconButton {
|
||
y: (parent.height - self.height) / 2;
|
||
glyph: "×";
|
||
size: 20px;
|
||
clicked => { root.closed(); }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- TabBar ----------------------------------------------------------------
|
||
export component TabBar inherits Rectangle {
|
||
in property <[TabInfo]> tabs;
|
||
in property <string> active-id;
|
||
in-out property <int> visible-start: 0;
|
||
in property <bool> app-background-active: false;
|
||
in property <float> ui-opacity: 0.72;
|
||
property <int> visible-count: 5;
|
||
callback tab-selected(string);
|
||
callback tab-closed(string);
|
||
callback new-tab();
|
||
callback previous-tab();
|
||
callback next-tab();
|
||
|
||
height: 36px;
|
||
background: root.app-background-active ? Theme.bg-panel-alt.with-alpha(root.ui-opacity) : Theme.bg-panel-alt;
|
||
|
||
HorizontalLayout {
|
||
height: parent.height;
|
||
padding-left: 3px;
|
||
padding-right: 100px; // reserve the overlaid theme/download/settings buttons
|
||
padding-top: 3px;
|
||
padding-bottom: 3px;
|
||
spacing: 2px;
|
||
|
||
Rectangle {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: Theme.radius-sm;
|
||
background: root.active-id == "welcome"
|
||
? Theme.bg-panel
|
||
: (folder-ta.has-hover ? Theme.bg-hover : transparent);
|
||
folder-ta := TouchArea {
|
||
mouse-cursor: pointer;
|
||
clicked => { root.new-tab(); }
|
||
}
|
||
Text {
|
||
width: parent.width;
|
||
height: parent.height;
|
||
text: "📂";
|
||
color: root.active-id == "welcome" ? Theme.text-primary : Theme.text-secondary;
|
||
font-size: Theme.fs-md;
|
||
horizontal-alignment: center;
|
||
vertical-alignment: center;
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
width: 56px;
|
||
height: 30px;
|
||
vertical-stretch: 0;
|
||
|
||
HorizontalLayout {
|
||
height: parent.height;
|
||
spacing: 0;
|
||
|
||
Rectangle {
|
||
width: 28px;
|
||
height: parent.height;
|
||
border-radius: Theme.radius-sm;
|
||
background: prev-ta.has-hover ? Theme.bg-hover : transparent;
|
||
prev-ta := TouchArea {
|
||
mouse-cursor: pointer;
|
||
clicked => { root.previous-tab(); }
|
||
}
|
||
Text {
|
||
width: parent.width;
|
||
height: parent.height;
|
||
text: "[<]";
|
||
color: Theme.text-secondary;
|
||
font-size: Theme.fs-xs;
|
||
horizontal-alignment: center;
|
||
vertical-alignment: center;
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
width: 28px;
|
||
height: parent.height;
|
||
border-radius: Theme.radius-sm;
|
||
background: next-ta.has-hover ? Theme.bg-hover : transparent;
|
||
next-ta := TouchArea {
|
||
mouse-cursor: pointer;
|
||
clicked => { root.next-tab(); }
|
||
}
|
||
Text {
|
||
width: parent.width;
|
||
height: parent.height;
|
||
text: "[>]";
|
||
color: Theme.text-secondary;
|
||
font-size: Theme.fs-xs;
|
||
horizontal-alignment: center;
|
||
vertical-alignment: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
horizontal-stretch: 1;
|
||
height: 30px;
|
||
clip: true;
|
||
|
||
tabs-flick := Flickable {
|
||
width: parent.width;
|
||
height: parent.height;
|
||
viewport-width: max(self.width, tabs-row.preferred-width);
|
||
viewport-height: self.height;
|
||
interactive: true;
|
||
|
||
tabs-row := HorizontalLayout {
|
||
height: parent.height;
|
||
spacing: 0px;
|
||
|
||
for tab[i] in root.tabs : SingleTab {
|
||
shown: i >= root.visible-start && i < root.visible-start + root.visible-count;
|
||
info: tab;
|
||
active: tab.id == root.active-id;
|
||
app-background-active: root.app-background-active;
|
||
ui-opacity: root.ui-opacity;
|
||
selected => { root.tab-selected(tab.id); }
|
||
closed => { root.tab-closed(tab.id); }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|