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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! [`control_bar`] — the floating control bar: a glass surface holding a
//! leading cluster, an optional centre, and a trailing cluster. Apple Music's
//! transport, a desktop agent app's composer, a floating toolbar.
//!
//! [`Shape`] is the only thing that differs between those; everything below is
//! shape-blind, which is why the module is named for the job rather than for
//! the stadium it started as.
//!
//! Two things it exists to get right.
//!
//! **The blur corners follow the border.** [`crate::material::material`] takes
//! a corner radius and paints the backdrop blur to it, and a mismatch frosts
//! square corners outside a round border. One radius comes out of [`Shape`] and
//! feeds both, so there is no second number to keep in step.
//!
//! **The centre is centred on the bar, not on what the clusters leave.** The
//! two rails are equal-flex and the centre is not: clusters of five controls
//! and three then keep the middle on axis. Flexing the centre between them
//! instead is the classic toolbar bug — it lands wherever the wider cluster
//! pushes it.
//!
//! That second rule is why the bar takes the **width it is given** rather than
//! hugging its controls. Equal rails need free space to be equal *about*; a
//! shrink-to-fit bar has none, and its middle then lands wherever the clusters
//! happen to put it. So width is the caller's, and a `max_w` is how a wide
//! window gets a floating bar instead of a docked one.
//!
//! Placement is the caller's too, and it is four lines. This bar floats *over*
//! content and must never reflow it — the same overlay-never-a-gutter rule
//! [`crate::scroll`] follows. A bar that *does* reflow its content is a dock,
//! not this: no blur, no float, and nothing here to reuse.
//!
//! ```ignore
//! div().relative().size_full()
//! .child(page)
//! .child(
//! div().absolute().bottom(px(20.0)).left_0().right_0()
//! .flex().justify_center()
//! .child(div().w_full().max_w(px(880.0)).child(
//! control_bar::control_bar(&theme, Shape::Pill, leading, Some(centre), trailing),
//! )),
//! )
//! ```
use ;
use ;
/// Height of the bar, and so half the radius of a [`Shape::Pill`]. One number
/// rather than a parameter: a stadium's radius has to be derived from it for
/// the material's blur to match the border, and a caller free to pick a height
/// is a caller free to get that wrong.
pub const BAR_HEIGHT: f32 = 56.0;
/// Gap between controls in a cluster, and the bar's own end inset. The inset
/// matches the gap so the first control sits as far from the bar's edge as it
/// does from its neighbour.
const BAR_GAP: f32 = 8.0;
/// How the bar's corners are cut. Two named cases rather than a radius, because
/// this is a choice between two shapes and not a continuum — and because a bare
/// number at the call site says nothing about which one you meant.
/// The bar. `centre` is optional — a toolbar with only clusters passes `None`
/// and the rails still hold their ends.
/// A circular control inside a bar: the ring, and its glyph at half the
/// diameter. `diameter` is a parameter because a transport's primary action is
/// deliberately bigger than its neighbours — that size difference is what makes
/// the cluster readable at a glance.
///
/// It builds the icon rather than taking one, the way [`row_tile`](crate::widgets::Scaffolding::row_tile)
/// does, because `tint` is not optional in the way it looks: gpui reads an
/// svg's colour off that element's own style and paints **nothing** when it is
/// unset, so a colour set on this button would silently not reach the glyph.
///
/// Caller adds id, click and its own `.hover(..)`: gpui panics on a second
/// hover call, and the wash differs by state (a lit toggle is not a resting
/// one). [`Theme::glass_hover`] is the wash to reach for.