// Copyright © SixtyFPS GmbH // 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 has_icon: root.icon.width > 0 && root.icon.height > 0; property has_selected_icon: root.selected_icon.width > 0 || root.selected_icon.height > 0; property 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 title; in property <[NavigationItem]> items; in property current_index: -1; in property 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 current_group; in_out property 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 current_group; in_out property 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(); } }