-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
319 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
If `true` loading bar is shown above content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
If `true` loading bar is shown above content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
If `true` loading bar is shown above content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
If `true` loading bar is shown above content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
use iced::advanced::layout::Limits; | ||
use iced::advanced::layout::Node; | ||
use iced::advanced::renderer; | ||
use iced::advanced::widget::tree::State; | ||
use iced::advanced::widget::tree::Tag; | ||
use iced::advanced::widget::Tree; | ||
use iced::advanced::Clipboard; | ||
use iced::advanced::Layout; | ||
use iced::advanced::Shell; | ||
use iced::advanced::Widget; | ||
use iced::event::Status; | ||
use iced::mouse::Cursor; | ||
use iced::{window, Color}; | ||
use iced::Border; | ||
use iced::Element; | ||
use iced::Event; | ||
use iced::Length; | ||
use iced::Rectangle; | ||
use iced::Shadow; | ||
use iced::Size; | ||
use std::time::{Duration, Instant}; | ||
|
||
pub struct LoadingBar<Theme> | ||
where | ||
Theme: StyleSheet, | ||
{ | ||
width: Length, | ||
segment_width: f32, | ||
height: Length, | ||
rate: Duration, | ||
style: <Theme as StyleSheet>::Style, | ||
} | ||
|
||
impl<Theme> Default for LoadingBar<Theme> | ||
where | ||
Theme: StyleSheet, | ||
{ | ||
fn default() -> Self { | ||
Self { | ||
width: Length::Fill, | ||
segment_width: 200.0, | ||
height: Length::Fixed(1.0), | ||
rate: Duration::from_secs_f32(1.0), | ||
style: <Theme as StyleSheet>::Style::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<Theme> LoadingBar<Theme> | ||
where | ||
Theme: StyleSheet, | ||
{ | ||
#[must_use] | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
#[must_use] | ||
pub fn width(mut self, width: Length) -> Self { | ||
self.width = width; | ||
self | ||
} | ||
|
||
#[must_use] | ||
pub fn segment_width(mut self, segment_width: f32) -> Self { | ||
self.segment_width = segment_width; | ||
self | ||
} | ||
|
||
#[must_use] | ||
pub fn height(mut self, height: Length) -> Self { | ||
self.height = height; | ||
self | ||
} | ||
|
||
#[must_use] | ||
pub fn style(mut self, style: <Theme as StyleSheet>::Style) -> Self { | ||
self.style = style; | ||
self | ||
} | ||
} | ||
|
||
struct LoadingBarState { | ||
last_update: Instant, | ||
t: f32, | ||
} | ||
|
||
fn is_visible(bounds: &Rectangle) -> bool { | ||
bounds.width > 0.0 && bounds.height > 0.0 | ||
} | ||
|
||
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer> for LoadingBar<Theme> | ||
where | ||
Renderer: renderer::Renderer, | ||
Theme: StyleSheet, | ||
{ | ||
fn size(&self) -> Size<Length> { | ||
Size::new(self.width, self.height) | ||
} | ||
|
||
fn layout(&self, _tree: &mut Tree, _renderer: &Renderer, limits: &Limits) -> Node { | ||
Node::new(limits.width(self.width).height(self.height).resolve( | ||
self.width, | ||
self.height, | ||
Size::new(f32::INFINITY, f32::INFINITY), | ||
)) | ||
} | ||
|
||
fn draw( | ||
&self, | ||
state: &Tree, | ||
renderer: &mut Renderer, | ||
theme: &Theme, | ||
_style: &renderer::Style, | ||
layout: Layout<'_>, | ||
_cursor: Cursor, | ||
_viewport: &Rectangle, | ||
) { | ||
let bounds = layout.bounds(); | ||
|
||
if !is_visible(&bounds) { | ||
return; | ||
} | ||
|
||
let position = bounds.position(); | ||
let size = bounds.size(); | ||
let styling = theme.appearance(&self.style); | ||
|
||
renderer.fill_quad( | ||
renderer::Quad { | ||
bounds: Rectangle { | ||
x: position.x, | ||
y: position.y, | ||
width: size.width, | ||
height: size.height, | ||
}, | ||
border: Border::default(), | ||
shadow: Shadow::default(), | ||
}, | ||
styling.background_color, | ||
); | ||
|
||
let state = state.state.downcast_ref::<LoadingBarState>(); | ||
|
||
// works but quick and hacky | ||
renderer.fill_quad( | ||
renderer::Quad { | ||
bounds: Rectangle { | ||
x: position.x + (size.width * state.t * 1.3) - self.segment_width, | ||
y: position.y, | ||
width: self.segment_width, | ||
height: size.height, | ||
}, | ||
border: Border::default(), | ||
shadow: Shadow::default(), | ||
}, | ||
styling.loading_bar_color, | ||
); | ||
} | ||
|
||
fn tag(&self) -> Tag { | ||
Tag::of::<LoadingBarState>() | ||
} | ||
|
||
fn state(&self) -> State { | ||
State::new(LoadingBarState { | ||
last_update: Instant::now(), | ||
t: 0.0, | ||
}) | ||
} | ||
|
||
fn on_event( | ||
&mut self, | ||
state: &mut Tree, | ||
event: Event, | ||
layout: Layout<'_>, | ||
_cursor: Cursor, | ||
_renderer: &Renderer, | ||
_clipboard: &mut dyn Clipboard, | ||
shell: &mut Shell<'_, Message>, | ||
_viewport: &Rectangle, | ||
) -> Status { | ||
const FRAMES_PER_SECOND: u64 = 60; | ||
|
||
let bounds = layout.bounds(); | ||
|
||
if let Event::Window(_id, window::Event::RedrawRequested(now)) = event { | ||
if is_visible(&bounds) { | ||
let state = state.state.downcast_mut::<LoadingBarState>(); | ||
let duration = (now - state.last_update).as_secs_f32(); | ||
let increment = if self.rate == Duration::ZERO { | ||
0.0 | ||
} else { | ||
duration * 1.0 / self.rate.as_secs_f32() | ||
}; | ||
|
||
state.t += increment; | ||
|
||
if state.t > 1.0 { | ||
state.t -= 1.0; | ||
} | ||
|
||
shell.request_redraw(window::RedrawRequest::At( | ||
now + Duration::from_millis(1000 / FRAMES_PER_SECOND), | ||
)); | ||
state.last_update = now; | ||
|
||
return Status::Captured; | ||
} | ||
} | ||
|
||
Status::Ignored | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub struct Appearance { | ||
pub background_color: Color, | ||
pub loading_bar_color: Color, | ||
} | ||
|
||
pub trait StyleSheet { | ||
type Style: Default; | ||
fn appearance(&self, style: &Self::Style) -> Appearance; | ||
} | ||
|
||
|
||
impl<'a, Message, Theme, Renderer> From<LoadingBar<Theme>> for Element<'a, Message, Theme, Renderer> | ||
where | ||
Renderer: renderer::Renderer + 'a, | ||
Theme: 'a + StyleSheet, | ||
{ | ||
fn from(spinner: LoadingBar<Theme>) -> Self { | ||
Self::new(spinner) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod loading_bar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use crate::ui::custom_widgets::loading_bar; | ||
use crate::ui::custom_widgets::loading_bar::{Appearance, LoadingBar}; | ||
use crate::ui::theme::{Element, ThemableWidget}; | ||
use crate::ui::GauntletTheme; | ||
|
||
#[derive(Default)] | ||
pub enum LoadingBarStyle { | ||
#[default] | ||
Default, | ||
} | ||
|
||
impl loading_bar::StyleSheet for GauntletTheme { | ||
type Style = LoadingBarStyle; | ||
|
||
fn appearance(&self, _style: &Self::Style) -> Appearance { | ||
Appearance { | ||
background_color: self.loading_bar.background_color.to_iced(), | ||
loading_bar_color: self.loading_bar.loading_bar_color.to_iced(), | ||
} | ||
} | ||
} | ||
|
||
impl<'a, Message: 'a> ThemableWidget<'a, Message> for LoadingBar<GauntletTheme> { | ||
type Kind = LoadingBarStyle; | ||
|
||
fn themed(self, _kind: LoadingBarStyle) -> Element<'a, Message> { | ||
self.into() | ||
} | ||
} |
Oops, something went wrong.