#[allow(deprecated)]
use skia_safe::gradient_shader::GradientShaderColors;
#[allow(deprecated)]
use skia_safe::{
Canvas, Color, Color4f, Font, Paint, Path, PathBuilder, Point, RRect, Rect, TileMode,
gradient_shader,
};
use std::cell::RefCell;
use std::rc::Rc;
use crate::drawing::{Drawable, Plan};
use crate::layouts::{EdgeLayoutElement, Edges, HasPlanner, Layout};
use crate::story_board::{StoryBoard, easing};
pub struct VolumeBar {
planner: RefCell<Option<Rc<dyn Layout>>>,
font: Font,
vol_state: RefCell<StoryBoard>,
volume: RefCell<f32>,
bg_paint: Paint,
border_paint: Paint,
bar_rect: RRect,
icon_paint: Paint,
speaker_path: Path,
wave_paint: Paint,
wave_rect: Rect,
bg_track: Paint,
bg_track_rrect: RRect,
thumb_paint: Paint,
text_paint: Paint,
}
impl HasPlanner for VolumeBar {
fn planner(&self) -> &RefCell<Option<Rc<dyn Layout>>> {
&self.planner
}
fn set_planner(&self, p: Option<Rc<dyn Layout>>) {
*self.planner.borrow_mut() = p;
}
}
impl Drawable for VolumeBar {
fn get_horizontal_plan(&self) -> Plan {
Plan::Fit(46.0)
}
fn get_vertical_plan(&self) -> Plan {
Plan::Fit(220.0)
}
fn draw(&self, canvas: &Canvas) -> anyhow::Result<()> {
let slide_offset = {
let vol_state = self.vol_state.borrow();
f64::from(&*vol_state) as f32
};
if slide_offset >= 119.0 {
return Ok(());
}
let rect = self.get_planned_drawing_area(canvas);
let bar_w = 46.0;
let bar_h = 220.0;
canvas.save();
canvas.translate(Point::new(rect.left + slide_offset, rect.top));
canvas.draw_rrect(self.bar_rect, &self.bg_paint);
canvas.draw_rrect(self.bar_rect, &self.border_paint);
canvas.draw_path(&self.speaker_path, &self.icon_paint);
let current_volume = *self.volume.borrow();
if current_volume > 0.01 {
canvas.draw_arc(self.wave_rect, -45.0, 90.0, false, &self.wave_paint);
}
let track_w = 6.0;
let track_x = (bar_w - track_w) / 2.0;
let track_y_start = 50.0;
let track_y_end = bar_h - 40.0;
let track_h = track_y_end - track_y_start;
canvas.draw_rrect(self.bg_track_rrect, &self.bg_track);
if current_volume > 0.0 {
let fill_h = track_h * current_volume.clamp(0.0, 1.0);
let fill_y = track_y_end - fill_h;
let colors = [
Color::from_argb(255, 90, 160, 255),
Color::from_argb(255, 66, 133, 244),
];
#[allow(deprecated)]
let shader = gradient_shader::linear(
(Point::new(0.0, fill_y), Point::new(0.0, track_y_end)),
GradientShaderColors::Colors(&colors),
None,
TileMode::Clamp,
None,
None,
);
let mut active_track = Paint::default();
active_track.set_anti_alias(true);
if let Some(s) = shader {
active_track.set_shader(s);
} else {
active_track.set_color4f(Color4f::new(0.26, 0.52, 0.96, 1.0), None);
}
canvas.draw_rrect(
RRect::new_rect_xy(
Rect::from_xywh(track_x, fill_y, track_w, fill_h),
track_w / 2.0,
track_w / 2.0,
),
&active_track,
);
canvas.draw_circle(Point::new(bar_w / 2.0, fill_y), 6.0, &self.thumb_paint);
}
let vol_percent = (current_volume.clamp(0.0, 1.0) * 100.0).round() as i32;
let text = format!("{}", vol_percent);
let (text_width, _) = self.font.measure_str(&text, Some(&self.text_paint));
let text_x = (bar_w - text_width) / 2.0;
let text_y = bar_h - 16.0;
canvas.draw_str(
&text,
Point::new(text_x, text_y),
&self.font,
&self.text_paint,
);
canvas.restore();
Ok(())
}
}
impl VolumeBar {
pub fn new(font: &Font, volume: f32) -> Rc<Self> {
let bar_w = 46.0;
let bar_h = 220.0;
let mut bg_paint = Paint::default();
bg_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.08, 0.08, 0.1, 0.75), None);
let mut border_paint = Paint::default();
border_paint
.set_anti_alias(true)
.set_style(skia_safe::paint::Style::Stroke)
.set_stroke_width(1.5)
.set_color4f(Color4f::new(1.0, 1.0, 1.0, 0.12), None);
let bar_rect = RRect::new_rect_xy(Rect::from_xywh(0.0, 0.0, bar_w, bar_h), 14.0, 14.0);
let icon_y = 28.0;
let icon_center_x = bar_w / 2.0;
let mut icon_paint = Paint::default();
icon_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.65, 0.65, 0.7, 1.0), None);
let mut builder = PathBuilder::new();
builder.move_to(Point::new(icon_center_x - 4.0, icon_y - 3.0));
builder.line_to(Point::new(icon_center_x, icon_y - 3.0));
builder.line_to(Point::new(icon_center_x + 5.0, icon_y - 7.0));
builder.line_to(Point::new(icon_center_x + 5.0, icon_y + 7.0));
builder.line_to(Point::new(icon_center_x, icon_y + 3.0));
builder.line_to(Point::new(icon_center_x - 4.0, icon_y + 3.0));
builder.close();
let speaker_path = builder.detach();
let mut wave_paint = Paint::default();
wave_paint
.set_anti_alias(true)
.set_style(skia_safe::paint::Style::Stroke)
.set_stroke_width(1.5)
.set_color4f(Color4f::new(0.65, 0.65, 0.7, 1.0), None);
let wave_rect = Rect::from_xywh(icon_center_x - 4.0, icon_y - 5.0, 14.0, 10.0);
let track_w = 6.0;
let track_x = (bar_w - track_w) / 2.0;
let track_y_start = 50.0;
let track_h = (bar_h - 40.0) - track_y_start;
let mut bg_track = Paint::default();
bg_track
.set_anti_alias(true)
.set_color4f(Color4f::new(1.0, 1.0, 1.0, 0.2), None);
let bg_track_rrect = RRect::new_rect_xy(
Rect::from_xywh(track_x, track_y_start, track_w, track_h),
track_w / 2.0,
track_w / 2.0,
);
let mut thumb_paint = Paint::default();
thumb_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(1.0, 1.0, 1.0, 1.0), None);
let mut text_font = font.clone();
text_font.set_size(13.0);
let mut text_paint = Paint::default();
text_paint
.set_anti_alias(true)
.set_color4f(Color4f::new(0.95, 0.95, 0.95, 1.0), None);
Rc::new(Self {
planner: RefCell::new(None),
font: text_font,
vol_state: RefCell::new(StoryBoard::init(
120f64,
0f64,
3500f64,
false,
easing::cubic_fly_hover_out,
)),
volume: RefCell::new(volume),
bg_paint,
border_paint,
bar_rect,
icon_paint,
speaker_path,
wave_paint,
wave_rect,
bg_track,
bg_track_rrect,
thumb_paint,
text_paint,
})
}
pub fn to_layout_element(self: &Rc<Self>) -> EdgeLayoutElement {
let width = match self.get_horizontal_plan() {
Plan::Fit(w) => w,
_ => panic!("Invalid Argument"),
};
let height = match self.get_vertical_plan() {
Plan::Fit(h) => h,
_ => panic!("Invalid Argument"),
};
let right_margin = 70.0;
let top_margin = 300.0;
EdgeLayoutElement {
drawable: self.clone(),
l_edge: Edges::Right,
l_margin: right_margin + width,
t_edge: Edges::Top,
t_margin: top_margin,
r_edge: Edges::Right,
r_margin: right_margin,
b_edge: Edges::Top,
b_margin: top_margin + height,
}
}
pub fn set_vol(&self, v: f32) {
*self.volume.borrow_mut() = v;
}
pub fn show(&self) {
let mut vol_state = self.vol_state.borrow_mut();
let ui_vol_p = vol_state.get_progress();
if ui_vol_p > 0.12 && ui_vol_p < 0.88 {
vol_state.seek(0.15);
} else if ui_vol_p > 0.88 {
vol_state.restart();
}
}
}