gpui & ui: Use shader for dashed dividers (#23839)
TODO: - [x] BackgroundOrientation - [x] PatternDash - [x] `pattern_horizontal_dash` & `pattern_vertical_dash` - [x] Metal dash shader - [x] Blade dash shader - [x] Update ui::Divider to use new pattern --- This PR introduces proper dashed dividers using the new `PatternDash` background shader.  Before this we were using 128 elements to create a dashed divider, which is both expensive, and would not scale beyond a certain size. This allows us to simplify the divider element as well. Changes: - Adds `BackgroundOrientation` to `gpui::color::Background` to allow specifying a direction for a pattern - Adds the PatternDash pattern variant - Updates `ui::Divider`'s dashed variants to be more efficient Misc: - Documents the `ui::Divider` component - Treat `.metal` files as `C` in the Zed project until we get some metal syntax highlighting. Release Notes: - N/A
This commit is contained in:
parent
8442e2b9d8
commit
e5943975f9
8 changed files with 210 additions and 106 deletions
|
@ -39,6 +39,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"file_types": {
|
"file_types": {
|
||||||
|
"C": ["metal"],
|
||||||
"Dockerfile": ["Dockerfile*[!dockerignore]"],
|
"Dockerfile": ["Dockerfile*[!dockerignore]"],
|
||||||
"Git Ignore": ["dockerignore"]
|
"Git Ignore": ["dockerignore"]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, linear_color_stop, linear_gradient, pattern_slash, prelude::*, px, rgb, size, App,
|
div, linear_color_stop, linear_gradient, pattern_horizontal_dash, pattern_slash,
|
||||||
AppContext, Application, Bounds, Context, Window, WindowBounds, WindowOptions,
|
pattern_vertical_dash, prelude::*, px, rgb, size, App, AppContext, Application, Bounds,
|
||||||
|
Context, Window, WindowBounds, WindowOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PatternExample;
|
struct PatternExample;
|
||||||
|
@ -19,6 +20,58 @@ impl Render for PatternExample {
|
||||||
.text_xl()
|
.text_xl()
|
||||||
.text_color(rgb(0x000000))
|
.text_color(rgb(0x000000))
|
||||||
.child("Pattern Example")
|
.child("Pattern Example")
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.gap_4()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(160.0))
|
||||||
|
.h(px(1.0))
|
||||||
|
.bg(pattern_horizontal_dash(gpui::red())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(160.0))
|
||||||
|
.h(px(4.0))
|
||||||
|
.bg(pattern_horizontal_dash(gpui::red())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(160.0))
|
||||||
|
.h(px(8.0))
|
||||||
|
.bg(pattern_horizontal_dash(gpui::red())),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(1.0))
|
||||||
|
.h(px(160.0))
|
||||||
|
.bg(pattern_vertical_dash(gpui::blue())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(4.0))
|
||||||
|
.h(px(160.0))
|
||||||
|
.bg(pattern_vertical_dash(gpui::blue())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(8.0))
|
||||||
|
.h(px(160.0))
|
||||||
|
.bg(pattern_vertical_dash(gpui::blue())),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
|
|
@ -548,12 +548,33 @@ impl<'de> Deserialize<'de> for Hsla {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The orientation of a background.
|
||||||
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum BackgroundOrientation {
|
||||||
|
/// The background is oriented horizontally.
|
||||||
|
#[default]
|
||||||
|
Horizontal = 0,
|
||||||
|
/// The background is oriented vertically.
|
||||||
|
Vertical = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BackgroundOrientation {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
BackgroundOrientation::Horizontal => write!(f, "Horizontal"),
|
||||||
|
BackgroundOrientation::Vertical => write!(f, "Vertical"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) enum BackgroundTag {
|
pub(crate) enum BackgroundTag {
|
||||||
Solid = 0,
|
Solid = 0,
|
||||||
LinearGradient = 1,
|
LinearGradient = 1,
|
||||||
PatternSlash = 2,
|
PatternSlash = 2,
|
||||||
|
PatternDash = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A color space for color interpolation.
|
/// A color space for color interpolation.
|
||||||
|
@ -589,6 +610,7 @@ pub struct Background {
|
||||||
pub(crate) solid: Hsla,
|
pub(crate) solid: Hsla,
|
||||||
pub(crate) angle: f32,
|
pub(crate) angle: f32,
|
||||||
pub(crate) colors: [LinearColorStop; 2],
|
pub(crate) colors: [LinearColorStop; 2],
|
||||||
|
pub(crate) orientation: BackgroundOrientation,
|
||||||
/// Padding for alignment for repr(C) layout.
|
/// Padding for alignment for repr(C) layout.
|
||||||
pad: u32,
|
pad: u32,
|
||||||
}
|
}
|
||||||
|
@ -602,6 +624,7 @@ impl Default for Background {
|
||||||
color_space: ColorSpace::default(),
|
color_space: ColorSpace::default(),
|
||||||
angle: 0.0,
|
angle: 0.0,
|
||||||
colors: [LinearColorStop::default(), LinearColorStop::default()],
|
colors: [LinearColorStop::default(), LinearColorStop::default()],
|
||||||
|
orientation: BackgroundOrientation::default(),
|
||||||
pad: 0,
|
pad: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -616,6 +639,26 @@ pub fn pattern_slash(color: Hsla) -> Background {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a dash pattern background
|
||||||
|
pub fn pattern_horizontal_dash(color: Hsla) -> Background {
|
||||||
|
Background {
|
||||||
|
tag: BackgroundTag::PatternDash,
|
||||||
|
orientation: BackgroundOrientation::Horizontal,
|
||||||
|
solid: color,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a vertical dash pattern background
|
||||||
|
pub fn pattern_vertical_dash(color: Hsla) -> Background {
|
||||||
|
Background {
|
||||||
|
tag: BackgroundTag::PatternDash,
|
||||||
|
solid: color,
|
||||||
|
orientation: BackgroundOrientation::Vertical,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a LinearGradient background color.
|
/// Creates a LinearGradient background color.
|
||||||
///
|
///
|
||||||
/// The gradient line's angle of direction. A value of `0.` is equivalent to to top; increasing values rotate clockwise from there.
|
/// The gradient line's angle of direction. A value of `0.` is equivalent to to top; increasing values rotate clockwise from there.
|
||||||
|
@ -694,6 +737,7 @@ impl Background {
|
||||||
BackgroundTag::Solid => self.solid.is_transparent(),
|
BackgroundTag::Solid => self.solid.is_transparent(),
|
||||||
BackgroundTag::LinearGradient => self.colors.iter().all(|c| c.color.is_transparent()),
|
BackgroundTag::LinearGradient => self.colors.iter().all(|c| c.color.is_transparent()),
|
||||||
BackgroundTag::PatternSlash => self.solid.is_transparent(),
|
BackgroundTag::PatternSlash => self.solid.is_transparent(),
|
||||||
|
BackgroundTag::PatternDash => self.solid.is_transparent(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,6 +359,7 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 2u: {
|
case 2u: {
|
||||||
|
// Slash pattern
|
||||||
let base_pattern_size = bounds.size.y / 5.0;
|
let base_pattern_size = bounds.size.y / 5.0;
|
||||||
let width = base_pattern_size * 0.5;
|
let width = base_pattern_size * 0.5;
|
||||||
let slash_spacing = 0.89;
|
let slash_spacing = 0.89;
|
||||||
|
@ -374,6 +375,21 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
|
||||||
background_color = sold_color;
|
background_color = sold_color;
|
||||||
background_color.a *= saturate(0.5 - distance);
|
background_color.a *= saturate(0.5 - distance);
|
||||||
}
|
}
|
||||||
|
case 3u: {
|
||||||
|
// Dash pattern
|
||||||
|
let dash_width = 8.0;
|
||||||
|
let gap_width = 8.0;
|
||||||
|
let pattern_width = dash_width + gap_width;
|
||||||
|
let relative_position = position - bounds.origin;
|
||||||
|
|
||||||
|
// Use a dot product to select x or y based on orientation
|
||||||
|
let orientation_vector = vec2<f32>(1.0 - f32(background.angle != 0.0), f32(background.angle != 0.0));
|
||||||
|
let pattern_position = fmod(dot(relative_position, orientation_vector), pattern_width);
|
||||||
|
|
||||||
|
let distance = pattern_position - dash_width;
|
||||||
|
background_color = sold_color;
|
||||||
|
background_color.a *= step(-distance, 0.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return background_color;
|
return background_color;
|
||||||
|
|
|
@ -797,7 +797,7 @@ float4 over(float4 below, float4 above) {
|
||||||
GradientColor prepare_fill_color(uint tag, uint color_space, Hsla solid,
|
GradientColor prepare_fill_color(uint tag, uint color_space, Hsla solid,
|
||||||
Hsla color0, Hsla color1) {
|
Hsla color0, Hsla color1) {
|
||||||
GradientColor out;
|
GradientColor out;
|
||||||
if (tag == 0 || tag == 2) {
|
if (tag == 0 || tag == 2 || tag == 3) {
|
||||||
out.solid = hsla_to_rgba(solid);
|
out.solid = hsla_to_rgba(solid);
|
||||||
} else if (tag == 1) {
|
} else if (tag == 1) {
|
||||||
out.color0 = hsla_to_rgba(color0);
|
out.color0 = hsla_to_rgba(color0);
|
||||||
|
@ -874,13 +874,10 @@ float4 fill_color(Background background,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
// This pattern is full of magic numbers to make it line up perfectly
|
// Slash pattern
|
||||||
// when vertically stacked. Make sure you know what you are doing
|
|
||||||
// if you change this!
|
|
||||||
|
|
||||||
float base_pattern_size = bounds.size.height / 5;
|
float base_pattern_size = bounds.size.height / 5;
|
||||||
float width = base_pattern_size * 0.5;
|
float width = base_pattern_size * 0.5;
|
||||||
float slash_spacing = .89;
|
float slash_spacing = .89; // exact number to make vertical elements line up
|
||||||
float radians = M_PI_F / 4.0;
|
float radians = M_PI_F / 4.0;
|
||||||
float2x2 rotation = rotate2d(radians);
|
float2x2 rotation = rotate2d(radians);
|
||||||
float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
|
float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
|
||||||
|
@ -891,6 +888,22 @@ float4 fill_color(Background background,
|
||||||
color.a *= saturate(0.5 - distance);
|
color.a *= saturate(0.5 - distance);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 3: {
|
||||||
|
// Dash pattern
|
||||||
|
float dash_width = 8.0;
|
||||||
|
float gap_width = 8.0;
|
||||||
|
float pattern_width = dash_width + gap_width;
|
||||||
|
float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
|
||||||
|
|
||||||
|
// Use a dot product to select x or y based on orientation
|
||||||
|
float2 orientation_vector = float2(1.0 - background.orientation, background.orientation);
|
||||||
|
float pattern_position = fmod(dot(relative_position, orientation_vector), pattern_width);
|
||||||
|
|
||||||
|
float distance = pattern_position - dash_width;
|
||||||
|
color = solid_color;
|
||||||
|
color.a *= step(-distance, 0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
|
|
|
@ -583,6 +583,7 @@ impl Style {
|
||||||
.map(|stop| stop.color)
|
.map(|stop| stop.color)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
BackgroundTag::PatternSlash => color.solid,
|
BackgroundTag::PatternSlash => color.solid,
|
||||||
|
BackgroundTag::PatternDash => color.solid,
|
||||||
},
|
},
|
||||||
None => Hsla::default(),
|
None => Hsla::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
#![allow(missing_docs)]
|
use gpui::{pattern_horizontal_dash, pattern_vertical_dash, Background, Hsla, IntoElement};
|
||||||
use gpui::{Hsla, IntoElement};
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
enum DividerStyle {
|
|
||||||
Solid,
|
|
||||||
Dashed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum DividerDirection {
|
enum DividerDirection {
|
||||||
Horizontal,
|
Horizontal,
|
||||||
|
@ -18,12 +11,15 @@ enum DividerDirection {
|
||||||
/// The color of a [`Divider`].
|
/// The color of a [`Divider`].
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub enum DividerColor {
|
pub enum DividerColor {
|
||||||
Border,
|
/// The default border color.
|
||||||
#[default]
|
#[default]
|
||||||
|
Border,
|
||||||
|
/// Usually a de-emphasized border color.
|
||||||
BorderVariant,
|
BorderVariant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DividerColor {
|
impl DividerColor {
|
||||||
|
/// Returns the divider's HSLA color.
|
||||||
pub fn hsla(self, cx: &mut App) -> Hsla {
|
pub fn hsla(self, cx: &mut App) -> Hsla {
|
||||||
match self {
|
match self {
|
||||||
DividerColor::Border => cx.theme().colors().border,
|
DividerColor::Border => cx.theme().colors().border,
|
||||||
|
@ -32,71 +28,29 @@ impl DividerColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A component that can be used to separate sections of content.
|
||||||
|
///
|
||||||
|
/// Can be rendered horizontally or vertically.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Divider {
|
pub struct Divider {
|
||||||
style: DividerStyle,
|
|
||||||
direction: DividerDirection,
|
direction: DividerDirection,
|
||||||
color: DividerColor,
|
color: DividerColor,
|
||||||
inset: bool,
|
inset: bool,
|
||||||
|
is_dashed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderOnce for Divider {
|
impl RenderOnce for Divider {
|
||||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
match self.style {
|
let color = self.color.hsla(cx);
|
||||||
DividerStyle::Solid => self.render_solid(cx).into_any_element(),
|
let background = if self.is_dashed {
|
||||||
DividerStyle::Dashed => self.render_dashed(cx).into_any_element(),
|
match self.direction {
|
||||||
}
|
DividerDirection::Horizontal => pattern_horizontal_dash(color),
|
||||||
}
|
DividerDirection::Vertical => pattern_vertical_dash(color),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Background::from(color)
|
||||||
|
};
|
||||||
|
|
||||||
impl Divider {
|
|
||||||
pub fn horizontal() -> Self {
|
|
||||||
Self {
|
|
||||||
style: DividerStyle::Solid,
|
|
||||||
direction: DividerDirection::Horizontal,
|
|
||||||
color: DividerColor::default(),
|
|
||||||
inset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vertical() -> Self {
|
|
||||||
Self {
|
|
||||||
style: DividerStyle::Solid,
|
|
||||||
direction: DividerDirection::Vertical,
|
|
||||||
color: DividerColor::default(),
|
|
||||||
inset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn horizontal_dashed() -> Self {
|
|
||||||
Self {
|
|
||||||
style: DividerStyle::Dashed,
|
|
||||||
direction: DividerDirection::Horizontal,
|
|
||||||
color: DividerColor::default(),
|
|
||||||
inset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vertical_dashed() -> Self {
|
|
||||||
Self {
|
|
||||||
style: DividerStyle::Dashed,
|
|
||||||
direction: DividerDirection::Vertical,
|
|
||||||
color: DividerColor::default(),
|
|
||||||
inset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inset(mut self) -> Self {
|
|
||||||
self.inset = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn color(mut self, color: DividerColor) -> Self {
|
|
||||||
self.color = color;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_solid(self, cx: &mut App) -> impl IntoElement {
|
|
||||||
div()
|
div()
|
||||||
.map(|this| match self.direction {
|
.map(|this| match self.direction {
|
||||||
DividerDirection::Horizontal => {
|
DividerDirection::Horizontal => {
|
||||||
|
@ -106,38 +60,60 @@ impl Divider {
|
||||||
this.w_px().h_full().when(self.inset, |this| this.my_1p5())
|
this.w_px().h_full().when(self.inset, |this| this.my_1p5())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.bg(self.color.hsla(cx))
|
.bg(background)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// TODO: Use canvas or a shader here
|
|
||||||
// This obviously is a short term approach
|
impl Divider {
|
||||||
pub fn render_dashed(self, cx: &mut App) -> impl IntoElement {
|
/// Creates a solid horizontal divider.
|
||||||
let segment_count = 128;
|
pub fn horizontal() -> Self {
|
||||||
let segment_count_f = segment_count as f32;
|
Self {
|
||||||
let segment_min_w = 6.;
|
direction: DividerDirection::Horizontal,
|
||||||
let base = match self.direction {
|
color: DividerColor::default(),
|
||||||
DividerDirection::Horizontal => h_flex(),
|
inset: false,
|
||||||
DividerDirection::Vertical => v_flex(),
|
is_dashed: false,
|
||||||
};
|
}
|
||||||
let (w, h) = match self.direction {
|
}
|
||||||
DividerDirection::Horizontal => (px(segment_min_w), px(1.)),
|
|
||||||
DividerDirection::Vertical => (px(1.), px(segment_min_w)),
|
/// Creates a solid vertical divider.
|
||||||
};
|
pub fn vertical() -> Self {
|
||||||
let color = self.color.hsla(cx);
|
Self {
|
||||||
let total_min_w = segment_min_w * segment_count_f * 2.; // * 2 because of the gap
|
direction: DividerDirection::Vertical,
|
||||||
|
color: DividerColor::default(),
|
||||||
base.min_w(px(total_min_w))
|
inset: false,
|
||||||
.map(|this| {
|
is_dashed: false,
|
||||||
if self.direction == DividerDirection::Horizontal {
|
}
|
||||||
this.w_full().h_px()
|
}
|
||||||
} else {
|
|
||||||
this.w_px().h_full()
|
/// Creates a dashed horizontal divider.
|
||||||
}
|
pub fn horizontal_dashed() -> Self {
|
||||||
})
|
Self {
|
||||||
.gap(px(segment_min_w))
|
direction: DividerDirection::Horizontal,
|
||||||
.overflow_hidden()
|
color: DividerColor::default(),
|
||||||
.children(
|
inset: false,
|
||||||
(0..segment_count).map(|_| div().flex_grow().flex_shrink_0().w(w).h(h).bg(color)),
|
is_dashed: true,
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a dashed vertical divider.
|
||||||
|
pub fn vertical_dashed() -> Self {
|
||||||
|
Self {
|
||||||
|
direction: DividerDirection::Vertical,
|
||||||
|
color: DividerColor::default(),
|
||||||
|
inset: false,
|
||||||
|
is_dashed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pads the divider with a margin.
|
||||||
|
pub fn inset(mut self) -> Self {
|
||||||
|
self.inset = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the color of the divider.
|
||||||
|
pub fn color(mut self, color: DividerColor) -> Self {
|
||||||
|
self.color = color;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use theme::all_theme_colors;
|
||||||
use ui::{
|
use ui::{
|
||||||
element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
|
element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
|
||||||
Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
|
Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
|
||||||
Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, ElevationIndex, Facepile,
|
Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, Divider, ElevationIndex, Facepile,
|
||||||
IconDecoration, Indicator, Switch, Table, TintColor, Tooltip,
|
IconDecoration, Indicator, Switch, Table, TintColor, Tooltip,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue