parent
67520fc0e8
commit
e8744d1070
@ -1,5 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "rust_ui_bootloader.h"
|
||||
#include "rust_ui_common.h"
|
||||
|
@ -0,0 +1,62 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape,
|
||||
shape::Renderer,
|
||||
};
|
||||
|
||||
pub struct Bar {
|
||||
area: Rect,
|
||||
color: Color,
|
||||
bg_color: Color,
|
||||
radius: i16,
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
pub fn new(color: Color, bg_color: Color, radius: i16) -> Self {
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
color,
|
||||
bg_color,
|
||||
radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Bar {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
display::rect_fill_rounded(self.area, self.color, self.bg_color, self.radius as u8);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::Bar::new(self.area)
|
||||
.with_bg(self.color)
|
||||
.with_radius(self.radius)
|
||||
.render(target);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Bar {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Bar");
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
use crate::{
|
||||
io::BinaryData,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
geometry::{Alignment2D, Offset, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Jpeg {
|
||||
area: Rect,
|
||||
image: BinaryData<'static>,
|
||||
scale: u8,
|
||||
}
|
||||
|
||||
impl Jpeg {
|
||||
pub fn new(image: BinaryData<'static>, scale: u8) -> Self {
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
image,
|
||||
scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Jpeg {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
// SAFETY: We expect no existing mutable reference. Resulting reference is
|
||||
// discarded before returning to micropython.
|
||||
let jpeg_data = unsafe { self.image.data() };
|
||||
|
||||
if let Some((size, _)) = display::tjpgd::jpeg_info(jpeg_data) {
|
||||
let off = Offset::new(size.x / (2 << self.scale), size.y / (2 << self.scale));
|
||||
display::tjpgd::jpeg(jpeg_data, self.area.center() - off, self.scale);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::JpegImage::new_image(self.area.center(), self.image)
|
||||
.with_align(Alignment2D::CENTER)
|
||||
.with_scale(self.scale)
|
||||
.render(target);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Jpeg {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Jpeg");
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
#[cfg(feature = "jpeg")]
|
||||
use crate::ui::geometry::Offset;
|
||||
use crate::ui::{
|
||||
component::{image::Image, Component, Event, EventCtx, Never},
|
||||
display,
|
||||
geometry::{Alignment2D, Rect},
|
||||
};
|
||||
|
||||
pub struct Painter<F> {
|
||||
area: Rect,
|
||||
func: F,
|
||||
}
|
||||
|
||||
impl<F> Painter<F> {
|
||||
pub fn new(func: F) -> Self {
|
||||
Self {
|
||||
func,
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Component for Painter<F>
|
||||
where
|
||||
F: FnMut(Rect),
|
||||
{
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
(self.func)(self.area);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<F> crate::trace::Trace for Painter<F> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Painter");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_painter(image: Image) -> Painter<impl FnMut(Rect)> {
|
||||
let f = move |area: Rect| image.draw(area.center(), Alignment2D::CENTER);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
||||
#[cfg(feature = "jpeg")]
|
||||
pub fn jpeg_painter<'a>(
|
||||
image: impl Fn() -> &'a [u8],
|
||||
size: Offset,
|
||||
scale: u8,
|
||||
) -> Painter<impl FnMut(Rect)> {
|
||||
let off = Offset::new(size.x / (2 << scale), size.y / (2 << scale));
|
||||
let f = move |area: Rect| display::tjpgd::jpeg(image(), area.center() - off, scale);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
||||
pub fn rect_painter(fg: display::Color, bg: display::Color) -> Painter<impl FnMut(Rect)> {
|
||||
let f = move |area: Rect| display::rect_fill_rounded(area, fg, bg, 2);
|
||||
Painter::new(f)
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Point, Rect},
|
||||
shape::{Canvas, DrawingCache, Renderer, Shape, ShapeClone},
|
||||
};
|
||||
|
||||
use without_alloc::alloc::LocalAllocLeakExt;
|
||||
|
||||
// Shape of horizontal solid/dotted line
|
||||
pub struct HorizontalLine {
|
||||
/// Position of the left-top point
|
||||
pos: Point,
|
||||
// Length of the line
|
||||
length: i16,
|
||||
/// Line thickness (default 1)
|
||||
thickness: u8,
|
||||
/// Steps of dots (default 0 - full line)
|
||||
step: u8,
|
||||
/// Color
|
||||
color: Color,
|
||||
}
|
||||
|
||||
impl HorizontalLine {
|
||||
pub fn new(pos: Point, length: i16) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
length,
|
||||
thickness: 1,
|
||||
step: 0,
|
||||
color: Color::white(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_color(self, color: Color) -> Self {
|
||||
Self { color, ..self }
|
||||
}
|
||||
|
||||
pub fn with_thickness(self, thickness: u8) -> Self {
|
||||
Self { thickness, ..self }
|
||||
}
|
||||
|
||||
pub fn with_step(self, step: u8) -> Self {
|
||||
Self { step, ..self }
|
||||
}
|
||||
|
||||
pub fn render<'s>(self, renderer: &mut impl Renderer<'s>) {
|
||||
renderer.render_shape(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Shape<'s> for HorizontalLine {
|
||||
fn bounds(&self) -> Rect {
|
||||
let size = Offset::new(self.length, self.thickness as i16);
|
||||
Rect::from_top_left_and_size(self.pos, size)
|
||||
}
|
||||
|
||||
fn cleanup(&mut self, _cache: &DrawingCache) {}
|
||||
|
||||
fn draw(&mut self, canvas: &mut dyn Canvas, _cache: &DrawingCache) {
|
||||
if self.step <= self.thickness {
|
||||
// Solid line
|
||||
let size = Offset::new(self.length, self.thickness as i16);
|
||||
let r = Rect::from_top_left_and_size(self.pos, size);
|
||||
canvas.fill_rect(r, self.color, 255);
|
||||
} else {
|
||||
// Dotted line
|
||||
let thickness = self.thickness as i16;
|
||||
for x in (0..self.length - thickness).step_by(self.step as usize) {
|
||||
let r = Rect::from_top_left_and_size(
|
||||
self.pos + Offset::x(x),
|
||||
Offset::uniform(thickness),
|
||||
);
|
||||
canvas.fill_rect(r, self.color, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> ShapeClone<'s> for HorizontalLine {
|
||||
fn clone_at_bump<T>(self, bump: &'s T) -> Option<&'s mut dyn Shape<'s>>
|
||||
where
|
||||
T: LocalAllocLeakExt<'s>,
|
||||
{
|
||||
let clone = bump.alloc_t()?;
|
||||
Some(clone.uninit.init(HorizontalLine { ..self }))
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Point, Rect},
|
||||
shape::{Canvas, DrawingCache, Renderer, Shape, ShapeClone},
|
||||
};
|
||||
|
||||
use without_alloc::alloc::LocalAllocLeakExt;
|
||||
|
||||
static CELLS: [Offset; 24] = [
|
||||
Offset::new(1, -4),
|
||||
Offset::new(2, -4),
|
||||
Offset::new(3, -3),
|
||||
Offset::new(4, -2),
|
||||
Offset::new(4, -1),
|
||||
Offset::new(4, 0),
|
||||
Offset::new(4, 1),
|
||||
Offset::new(4, 2),
|
||||
Offset::new(3, 3),
|
||||
Offset::new(2, 4),
|
||||
Offset::new(1, 4),
|
||||
Offset::new(0, 4),
|
||||
Offset::new(-1, 4),
|
||||
Offset::new(-2, 4),
|
||||
Offset::new(-3, 3),
|
||||
Offset::new(-4, 2),
|
||||
Offset::new(-4, 1),
|
||||
Offset::new(-4, 0),
|
||||
Offset::new(-4, -1),
|
||||
Offset::new(-4, -2),
|
||||
Offset::new(-3, -3),
|
||||
Offset::new(-2, -4),
|
||||
Offset::new(-1, -4),
|
||||
Offset::new(0, -4),
|
||||
];
|
||||
|
||||
pub struct LoaderCircular {
|
||||
/// Position of point (0,0)
|
||||
pos: Point,
|
||||
/// Value 0..1000
|
||||
value: u16,
|
||||
/// Color
|
||||
color: Color,
|
||||
/// Scale (length of square size)
|
||||
scale: i16,
|
||||
}
|
||||
|
||||
impl LoaderCircular {
|
||||
pub fn new(pos: Point, value: u16) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
value,
|
||||
color: Color::white(),
|
||||
scale: 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_color(self, color: Color) -> Self {
|
||||
Self { color, ..self }
|
||||
}
|
||||
|
||||
pub fn with_scale(self, scale: i16) -> Self {
|
||||
Self { scale, ..self }
|
||||
}
|
||||
|
||||
fn cells(&self) -> &[Offset] {
|
||||
let value = self.value.clamp(0, 1000);
|
||||
let last = (CELLS.len() * value as usize) / 1000;
|
||||
&CELLS[..last]
|
||||
}
|
||||
|
||||
fn cell_rect(&self, offset: Offset) -> Rect {
|
||||
let pt = Point::new(
|
||||
self.pos.x + (offset.x * self.scale) - self.scale / 2,
|
||||
self.pos.y + (offset.y * self.scale) - self.scale / 2,
|
||||
);
|
||||
Rect::from_top_left_and_size(pt, Offset::uniform(self.scale))
|
||||
}
|
||||
|
||||
pub fn render<'s>(self, renderer: &mut impl Renderer<'s>) {
|
||||
renderer.render_shape(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Shape<'s> for LoaderCircular {
|
||||
fn bounds(&self) -> Rect {
|
||||
let cells = self.cells();
|
||||
|
||||
if cells.is_empty() {
|
||||
Rect::zero()
|
||||
} else {
|
||||
let mut b = self.cell_rect(cells[0]);
|
||||
cells[1..]
|
||||
.iter()
|
||||
.for_each(|c| b = b.union(self.cell_rect(*c)));
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
fn cleanup(&mut self, _cache: &DrawingCache) {}
|
||||
|
||||
fn draw(&mut self, canvas: &mut dyn Canvas, _cache: &DrawingCache) {
|
||||
for c in self.cells().iter() {
|
||||
canvas.fill_rect(self.cell_rect(*c), self.color, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> ShapeClone<'s> for LoaderCircular {
|
||||
fn clone_at_bump<T>(self, bump: &'s T) -> Option<&'s mut dyn Shape>
|
||||
where
|
||||
T: LocalAllocLeakExt<'s>,
|
||||
{
|
||||
let clone = bump.alloc_t()?;
|
||||
Some(clone.uninit.init(LoaderCircular { ..self }))
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Point, Rect},
|
||||
shape::{Canvas, DrawingCache, Renderer, Shape, ShapeClone},
|
||||
};
|
||||
|
||||
use without_alloc::alloc::LocalAllocLeakExt;
|
||||
|
||||
use core::f32::consts::SQRT_2;
|
||||
|
||||
const STAR_COUNT: usize = 8;
|
||||
const RADIUS: i16 = 3;
|
||||
const DIAGONAL: i16 = ((RADIUS as f32 * SQRT_2) / 2_f32) as i16;
|
||||
|
||||
// Offset of the normal point and then the extra offset for the main point
|
||||
static STARS: [(Offset, Offset); STAR_COUNT] = [
|
||||
(Offset::y(-RADIUS), Offset::y(-1)),
|
||||
(Offset::new(DIAGONAL, -DIAGONAL), Offset::new(1, -1)),
|
||||
(Offset::x(RADIUS), Offset::x(1)),
|
||||
(Offset::new(DIAGONAL, DIAGONAL), Offset::new(1, 1)),
|
||||
(Offset::y(RADIUS), Offset::y(1)),
|
||||
(Offset::new(-DIAGONAL, DIAGONAL), Offset::new(-1, 1)),
|
||||
(Offset::x(-RADIUS), Offset::x(-1)),
|
||||
(Offset::new(-DIAGONAL, -DIAGONAL), Offset::new(-1, -1)),
|
||||
];
|
||||
|
||||
/// A shape of a TS3 small loader
|
||||
pub struct LoaderSmall {
|
||||
/// Position of point (0,0)
|
||||
pos: Point,
|
||||
/// Value 0..1000
|
||||
value: u16,
|
||||
/// Color
|
||||
color: Color,
|
||||
}
|
||||
|
||||
impl LoaderSmall {
|
||||
pub fn new(pos: Point, value: u16) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
value,
|
||||
color: Color::white(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_color(self, color: Color) -> Self {
|
||||
Self { color, ..self }
|
||||
}
|
||||
|
||||
pub fn render<'s>(self, renderer: &mut impl Renderer<'s>) {
|
||||
renderer.render_shape(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Shape<'_> for LoaderSmall {
|
||||
fn bounds(&self) -> Rect {
|
||||
Rect::from_top_left_and_size(self.pos, Offset::uniform(1)).expand(RADIUS + 1)
|
||||
}
|
||||
|
||||
fn cleanup(&mut self, _cache: &DrawingCache) {}
|
||||
|
||||
fn draw(&mut self, canvas: &mut dyn Canvas, _cache: &DrawingCache) {
|
||||
// Calculate index of the highlighted star
|
||||
let sel_idx = (STAR_COUNT * self.value as usize / 1000) % STAR_COUNT;
|
||||
|
||||
for (i, (star_offset, hili_offset)) in STARS.iter().enumerate() {
|
||||
if (sel_idx + 1) % STAR_COUNT != i {
|
||||
// Draw a star if it's not behind the highlighted one (clockwise)
|
||||
let star_pos = self.pos + *star_offset;
|
||||
canvas.draw_pixel(star_pos, self.color);
|
||||
if sel_idx == i {
|
||||
// Higlight the main star
|
||||
canvas.draw_pixel(star_pos + *hili_offset, self.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> ShapeClone<'s> for LoaderSmall {
|
||||
fn clone_at_bump<T>(self, bump: &'s T) -> Option<&'s mut dyn Shape>
|
||||
where
|
||||
T: LocalAllocLeakExt<'s>,
|
||||
{
|
||||
let clone = bump.alloc_t()?;
|
||||
Some(clone.uninit.init(LoaderSmall { ..self }))
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::{Offset, Point, Rect},
|
||||
shape::{Canvas, DrawingCache, Renderer, Shape, ShapeClone},
|
||||
};
|
||||
|
||||
use without_alloc::alloc::LocalAllocLeakExt;
|
||||
|
||||
use core::f32::consts::SQRT_2;
|
||||
|
||||
const STAR_COUNT: usize = 8;
|
||||
const STAR_SMALL: i16 = 2;
|
||||
const STAR_MEDIUM: i16 = 4;
|
||||
const STAR_LARGE: i16 = 6;
|
||||
|
||||
const RADIUS: i16 = 13;
|
||||
const DIAGONAL: i16 = ((RADIUS as f32 * SQRT_2) / 2_f32) as i16;
|
||||
|
||||
// Offset of the normal point and then the extra offset for the main point
|
||||
static STARS: [Offset; STAR_COUNT] = [
|
||||
Offset::y(-RADIUS),
|
||||
Offset::new(DIAGONAL, -DIAGONAL),
|
||||
Offset::x(RADIUS),
|
||||
Offset::new(DIAGONAL, DIAGONAL),
|
||||
Offset::y(RADIUS),
|
||||
Offset::new(-DIAGONAL, DIAGONAL),
|
||||
Offset::x(-RADIUS),
|
||||
Offset::new(-DIAGONAL, -DIAGONAL),
|
||||
];
|
||||
|
||||
/// A shape of a TS3 starry loader
|
||||
pub struct LoaderStarry {
|
||||
/// Position of point (0,0)
|
||||
pos: Point,
|
||||
/// Value 0..1000
|
||||
value: u16,
|
||||
/// Color
|
||||
color: Color,
|
||||
}
|
||||
|
||||
impl LoaderStarry {
|
||||
pub fn new(pos: Point, value: u16) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
value,
|
||||
color: Color::white(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_color(self, color: Color) -> Self {
|
||||
Self { color, ..self }
|
||||
}
|
||||
|
||||
pub fn render<'s>(self, renderer: &mut impl Renderer<'s>) {
|
||||
renderer.render_shape(self);
|
||||
}
|
||||
|
||||
fn draw_large_star(&self, canvas: &mut dyn Canvas, offset: Offset) {
|
||||
let r = Rect::from_center_and_size(self.pos + offset, Offset::uniform(STAR_LARGE));
|
||||
canvas.fill_round_rect(r, 2, self.color, 255);
|
||||
}
|
||||
|
||||
fn draw_medium_star(&self, canvas: &mut dyn Canvas, offset: Offset) {
|
||||
let r = Rect::from_center_and_size(self.pos + offset, Offset::uniform(STAR_MEDIUM));
|
||||
canvas.fill_round_rect(r, 1, self.color, 255);
|
||||
}
|
||||
|
||||
fn draw_small_star(&self, canvas: &mut dyn Canvas, offset: Offset) {
|
||||
let r = Rect::from_center_and_size(self.pos + offset, Offset::uniform(STAR_SMALL));
|
||||
canvas.fill_rect(r, self.color, 255);
|
||||
}
|
||||
}
|
||||
|
||||
impl Shape<'_> for LoaderStarry {
|
||||
fn bounds(&self) -> Rect {
|
||||
Rect::from_top_left_and_size(self.pos, Offset::uniform(1)).expand(RADIUS + STAR_LARGE)
|
||||
}
|
||||
|
||||
fn cleanup(&mut self, _cache: &DrawingCache) {}
|
||||
|
||||
fn draw(&mut self, canvas: &mut dyn Canvas, _cache: &DrawingCache) {
|
||||
// Calculate the index of the big star
|
||||
let sel_idx = (STAR_COUNT * self.value as usize / 1000) % STAR_COUNT;
|
||||
|
||||
for (i, c) in STARS.iter().enumerate() {
|
||||
if i == sel_idx {
|
||||
self.draw_large_star(canvas, *c);
|
||||
} else if (sel_idx + 1) % 8 == i || (sel_idx - 1) % 8 == i {
|
||||
self.draw_medium_star(canvas, *c);
|
||||
} else {
|
||||
self.draw_small_star(canvas, *c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> ShapeClone<'s> for LoaderStarry {
|
||||
fn clone_at_bump<T>(self, bump: &'s T) -> Option<&'s mut dyn Shape>
|
||||
where
|
||||
T: LocalAllocLeakExt<'s>,
|
||||
{
|
||||
let clone = bump.alloc_t()?;
|
||||
Some(clone.uninit.init(LoaderStarry { ..self }))
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
pub mod dotted_line;
|
||||
pub mod loader_circular;
|
||||
pub mod loader_small;
|
||||
pub mod loader_starry;
|
||||
|
||||
pub use dotted_line::HorizontalLine;
|
||||
pub use loader_circular::LoaderCircular;
|
||||
pub use loader_small::LoaderSmall;
|
||||
pub use loader_starry::LoaderStarry;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue