166 lines
4.1 KiB
Plaintext
166 lines
4.1 KiB
Plaintext
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import { Palette } from "std-widgets.slint";
|
|
|
|
export struct SideBarEntry {
|
|
icon: image,
|
|
label: string,
|
|
}
|
|
|
|
component SideBarButton inherits Rectangle {
|
|
in property <bool> selected;
|
|
in property <bool> has-focus;
|
|
in property <image> icon;
|
|
|
|
callback clicked <=> touch.clicked;
|
|
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: 8px;
|
|
|
|
highlight := Rectangle {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: parent.border-radius;
|
|
background: Palette.control-background;
|
|
opacity: 0;
|
|
|
|
animate opacity { duration: 150ms; }
|
|
}
|
|
|
|
icon-display := Image {
|
|
source: root.icon;
|
|
width: 24px;
|
|
height: 24px;
|
|
colorize: Palette.foreground;
|
|
x: (parent.width - self.width) / 2;
|
|
y: (parent.height - self.height) / 2;
|
|
|
|
animate colorize { duration: 150ms; }
|
|
}
|
|
|
|
touch := TouchArea {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
states [
|
|
selected when root.selected: {
|
|
highlight.opacity: 1;
|
|
highlight.background: Palette.accent-background;
|
|
icon-display.colorize: Palette.accent-foreground;
|
|
}
|
|
pressed when touch.pressed && !root.selected: {
|
|
highlight.opacity: 0.55;
|
|
}
|
|
hover when touch.has-hover && !root.selected: {
|
|
highlight.opacity: 0.4;
|
|
}
|
|
focused when root.has-focus && !root.selected: {
|
|
highlight.opacity: 0.4;
|
|
}
|
|
]
|
|
}
|
|
|
|
component SideBarItem inherits Rectangle {
|
|
in property <int> tab-index;
|
|
in property <bool> selected;
|
|
in property <bool> has-focus;
|
|
in property <image> icon;
|
|
in property <string> label;
|
|
|
|
callback clicked <=> button.clicked;
|
|
|
|
accessible-role: tab;
|
|
accessible-label: root.label;
|
|
accessible-item-index: root.tab-index;
|
|
accessible-item-selectable: true;
|
|
accessible-item-selected: root.selected;
|
|
accessible-action-default => {
|
|
self.clicked();
|
|
}
|
|
|
|
button := SideBarButton {
|
|
Tooltip {
|
|
Text {
|
|
text: root.label;
|
|
}
|
|
}
|
|
icon: root.icon;
|
|
selected: root.selected;
|
|
has-focus: root.has-focus;
|
|
}
|
|
}
|
|
|
|
export component SideBar inherits Rectangle {
|
|
in property <[SideBarEntry]> model: [];
|
|
in property <string> title: "Gopher64";
|
|
in property <bool> portrait;
|
|
in-out property <int> current-item: 0;
|
|
|
|
Rectangle {
|
|
width: 100%;
|
|
height: 100%;
|
|
background: Palette.background.darker(0.2);
|
|
}
|
|
|
|
// Bottom bar in portrait: icons in a row, centered vertically in the bar.
|
|
portrait-strip := HorizontalLayout {
|
|
visible: root.portrait;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 4px;
|
|
spacing: 4px;
|
|
alignment: space-evenly;
|
|
|
|
accessible-role: tab-list;
|
|
accessible-label: root.title;
|
|
accessible-item-count: root.model.length;
|
|
|
|
for item[index] in root.model: VerticalLayout {
|
|
alignment: center;
|
|
|
|
SideBarItem {
|
|
clicked => {
|
|
root.current-item = index;
|
|
}
|
|
|
|
tab-index: index;
|
|
icon: item.icon;
|
|
label: item.label;
|
|
selected: index == root.current-item;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Left rail in landscape: icons in a column, centered horizontally in the bar.
|
|
landscape-strip := VerticalLayout {
|
|
visible: !root.portrait;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 4px;
|
|
spacing: 4px;
|
|
alignment: space-evenly;
|
|
|
|
accessible-role: tab-list;
|
|
accessible-label: root.title;
|
|
accessible-item-count: root.model.length;
|
|
|
|
for item[index] in root.model: HorizontalLayout {
|
|
alignment: center;
|
|
|
|
SideBarItem {
|
|
clicked => {
|
|
root.current-item = index;
|
|
}
|
|
|
|
tab-index: index;
|
|
icon: item.icon;
|
|
label: item.label;
|
|
selected: index == root.current-item;
|
|
}
|
|
}
|
|
}
|
|
}
|