ltk/widget/tab_strip/
mobile.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::layout::row::row;
use crate::layout::spacer::spacer;
use crate::types::{ Color, Length };
use crate::widget::flex::flex;
use crate::widget::pressable::pressable;
use crate::widget::{ container, text, Element };

use super::theme::{ BAR_ICON_SIZE, BAR_TITLE_SIZE };
use super::{ parts, TabItem, TabStrip, TabStripColors };

/// `[leading] active tab or the app's centre [counter] [trailing]`.
pub( super ) fn build<Msg: Clone + 'static>( strip: TabStrip<Msg> ) -> Element<Msg>
{
	let TabStrip { tabs, selected, on_overview, leading, trailing, center, colors, .. } = strip;
	let center  = center.unwrap_or_else( || title( tabs.get( selected ), &colors ) );
	let mut bar = row().spacing( Length::widget( 8.0 ) );
	for button in leading
	{
		bar = bar.push( button );
	}
	bar = bar.push( flex( center ) );
	if let Some( msg ) = on_overview
	{
		bar = bar.push( counter( tabs.len(), msg, colors.ink ) );
	}
	for button in trailing
	{
		bar = bar.push( button );
	}
	container( bar )
		.background( colors.strip )
		.padding_h( Length::widget( 8.0 ) )
		.padding_v( Length::widget( 5.0 ) )
		.into()
}

fn title<Msg: Clone + 'static>( tab: Option<&TabItem>, colors: &TabStripColors ) -> Element<Msg>
{
	let Some( tab ) = tab else { return spacer().into() };
	let mut line = row().spacing( Length::widget( 8.0 ) ).push( spacer().width( Length::widget( 4.0 ) ) );
	if let Some( icon ) = parts::icon( tab, Length::widget( BAR_ICON_SIZE ), colors.idle_ink )
	{
		line = line.push( icon );
	}
	line.push( flex( text( tab.label.clone() ).size( BAR_TITLE_SIZE ).weight( 600 ).color( colors.ink ) ) ).into()
}

/// Rounded square holding the number of open tabs.
fn counter<Msg: Clone + 'static>( count: usize, msg: Msg, ink: Color ) -> Element<Msg>
{
	let label = text( count.min( 99 ).to_string() ).size( 13.0 ).weight( 600 ).color( ink ).align_center();
	let badge = container( label )
		.border( ink, 2.0 )
		.radius( 7.0 )
		.padding_h( Length::widget( 5.0 ) )
		.padding_v( Length::widget( 3.0 ) );
	pressable( container( badge ).padding( Length::widget( 8.0 ) ) ).on_press( msg ).into()
}