slint/ui-libraries/material/ui/components/navigation_drawer.slint

211 lines
7.5 KiB
Text

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { Drawer, ModalDrawer, DrawerHeader } from "./drawer.slint";
import { NavigationItem, NavigationGroup } from "../items/navigation_item.slint";
import { HorizontalDivider } from "./divider.slint";
import { StateLayerArea } from "./state_layer.slint";
import { MaterialPalette } from "../styling/material_palette.slint";
import { Icon } from "./icon.slint";
import { MaterialText } from "./material_text.slint";
import { Typography } from "../styling/typography.slint";
import { MaterialStyleMetrics } from "../styling/material_style_metrics.slint";
import { Animations } from "../styling/animations.slint";
import { BaseNavigationItemTemplate } from "./base_navigation.slint";
component NavigationItemTempalte inherits BaseNavigationItemTemplate {
property <bool> has_icon: root.icon.width > 0 && root.icon.height > 0;
property <bool> has_selected_icon: root.selected_icon.width > 0 || root.selected_icon.height > 0;
property <color> color: MaterialPalette.on_surface_variant;
min_height: max(MaterialStyleMetrics.size_56, layout.min_height);
background_layer := Rectangle {
border_radius: self.height / 2;
state_layer := StateLayerArea {
border_radius: parent.border_radius;
color: root.selected ? transparent : root.color;
layout := HorizontalLayout {
padding_left: MaterialStyleMetrics.padding_16;
padding_right: MaterialStyleMetrics.padding_24;
padding_top: MaterialStyleMetrics.padding_16;
padding_bottom: self.padding_top;
spacing: MaterialStyleMetrics.spacing_12;
VerticalLayout {
alignment: center;
if !root.has_icon && !root.has_selected_icon : Rectangle {
width: MaterialStyleMetrics.icon_size_24;
height: self.width;
Rectangle {
width: 12px;
height: self.width;
border_radius: self.width / 2;
background: root.color;
}
}
if root.has_icon || root.has_selected_icon : Icon {
source: root.icon;
colorize: root.color;
states [
selected when root.selected && root.has_selected_icon : {
source: root.selected_icon;
}
]
}
}
MaterialText {
horizontal_stretch: 1;
text: root.text;
style: Typography.label_large;
color: root.color;
vertical_alignment: center;
}
if root.badge != "" : MaterialText {
text: root.badge;
style: Typography.label_large;
color: root.color;
vertical_alignment: center;
}
}
clicked => {
root.clicked();
}
pointer_event(event) => {
root.pointer_event(event, {
x: self.mouse_x,
y: self.mouse_y,
});
}
}
animate background { duration: Animations.opacity_duration; easing: Animations.opacity_easing; }
}
states [
selected when root.selected : {
background_layer.background: MaterialPalette.secondary_container;
root.color: MaterialPalette.on_secondary_container;
}
]
animate color { duration: Animations.opacity_duration; easing: Animations.opacity_easing; }
}
component NavigationGroupTemplate {
in property <string> title;
in property <[NavigationItem]> items;
in property <int> current_index: -1;
in property <bool> has_divider;
callback select(index: int);
callback item_pointer_event(index: int, event: PointerEvent, position: Point);
VerticalLayout {
alignment: start;
if root.title != 0 : DrawerHeader {
title: root.title;
}
for item[index] in root.items : NavigationItemTempalte {
icon: item.icon;
selected_icon: item.selected_icon;
text: item.text;
badge: item.badge;
selected: index == root.current_index;
index: index;
clicked => {
root.select(index);
}
pointer_event(event, position) => {
root.item_pointer_event(index, event, {
x: self.x + position.x,
y: self.y + position.y,
});
}
}
if root.has_divider : HorizontalDivider {}
}
}
export component NavigationDrawer inherits Drawer {
callback selected(group-index: int, item_index: int);
callback item_pointer_event(group_index: int, item_index: int, event: PointerEvent, position: Point);
in property <[NavigationGroup]> groups;
in_out property <int> current_group;
in_out property <int> current_index;
accessible-role: tab-list;
// accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-index;
// accessible-label: root.title;
accessible-item-count: root.groups.length;
for group[group_index] in root.groups : NavigationGroupTemplate {
title: group.title;
items: group.items;
current_index: group_index == root.current_group ? root.current_index : -1;
has_divider: root.groups.length > 1 && group_index < root.groups.length - 1;
select(index) => {
root.select(group_index, index);
}
item_pointer_event(index, event, position) => {
root.item_pointer_event(group_index, index, event, { x: self.x + position.x, y: self.y + position.y });
}
}
function select(group_index: int, item_index: int) {
if group_index < 0 || group_index >= root.groups.length || item_index < 0 || item_index >= root.groups[group_index].items.length {
return;
}
root.current_group = group_index;
root.current_index = item_index;
root.selected(group_index, item_index);
}
}
export component ModalNavigationDrawer inherits ModalDrawer {
in property <[NavigationGroup]> groups;
in_out property <int> current_group;
in_out property <int> current_index;
accessible-role: tab-list;
// accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-index;
// accessible-label: root.title;
accessible-item-count: root.groups.length;
for group[group_index] in root.groups : NavigationGroupTemplate {
title: group.title;
items: group.items;
current_index: group_index == root.current_group ? root.current_index : -1;
has_divider: root.groups.length > 1 && group_index < root.groups.length - 1;
select(index) => {
root.select(group_index, index);
}
}
function select(group_index: int, item_index: int) {
if group_index < 0 || group_index >= root.groups.length || item_index < 0 || item_index >= root.groups[group_index].items.length {
return;
}
root.current_group = group_index;
root.current_index = item_index;
root.close();
}
}