use crate::frame::context::UpdateType;
use crate::render::rectangle::param::RectParam;
use crate::render::{RenderParam, WrcRender};
use crate::response::Response;
use crate::size::border::Border;
use crate::size::radius::Radius;
use crate::size::rect::Rect;
use crate::style::color::Color;
use crate::style::ClickStyle;
use crate::ui::Ui;
use crate::widgets::{Widget, WidgetChange, WidgetSize};
use crate::{Offset, Pos};
pub struct ScrollBar {
id: String,
fill_render: RenderParam<RectParam>,
slider_render: RenderParam<RectParam>,
context_size: f32,
focused: bool,
offset: Offset,
changed: bool,
}
impl ScrollBar {
fn new() -> ScrollBar {
let mut fill_style = ClickStyle::new();
fill_style.fill.inactive = Color::rgb(215, 215, 215); fill_style.fill.hovered = Color::TRANSPARENT; fill_style.fill.clicked = Color::TRANSPARENT; let mut slider_style = ClickStyle::new();
slider_style.fill.inactive = Color::rgb(56, 182, 244);
slider_style.fill.hovered = Color::rgb(56, 182, 244);
slider_style.fill.clicked = Color::rgb(56, 182, 244);
slider_style.border.inactive = Border::new(0.0).radius(Radius::same(0));
slider_style.border.hovered = Border::new(0.0).radius(Radius::same(0));
slider_style.border.clicked = Border::new(0.0).radius(Radius::same(0));
ScrollBar {
id: crate::gen_unique_id(),
fill_render: RenderParam::new(RectParam::new(Rect::new().with_size(10.0, 20.0), fill_style)),
slider_render: RenderParam::new(RectParam::new(Rect::new().with_size(10.0, 10.0), slider_style)),
context_size: 0.0,
focused: false,
offset: Offset::new(Pos::new()),
changed: false,
}
}
pub fn horizontal() -> ScrollBar {
let mut res = ScrollBar::new();
res.fill_render.param.rect.set_size(300.0, 5.0);
res.slider_render.param.rect.set_size(30.0, 5.0);
res
}
pub fn vertical() -> ScrollBar {
let mut res = ScrollBar::new();
res.fill_render.param.rect.set_size(5.0, 300.0);
res.slider_render.param.rect.set_size(5.0, 30.0);
res
}
pub fn set_vbar_value_by_offset(&mut self, offset: f32) -> f32 {
let oy = self.slider_offset_y(offset);
let roy = self.slider_render.param.rect.offset_y_limit(self.offset.y + oy, self.fill_render.param.rect.dy());
self.offset.y = roy;
self.changed = true;
self.context_offset_y(-roy)
}
pub fn set_hbar_value_by_offset(&mut self, offset: f32) -> f32 {
let ox = self.slider_offset_x(offset);
let rox = self.slider_render.param.rect.offset_x_limit(self.offset.x + ox, self.fill_render.param.rect.dx());
self.offset.x = rox;
self.changed = true;
self.context_offset_x(-rox)
}
pub fn offset(&mut self) -> f32 {
if self.height() > self.width() { self.context_offset_y(-self.offset.y)
} else { self.context_offset_x(-self.offset.x)
}
}
pub fn set_width(&mut self, w: f32) {
self.fill_render.param.rect.set_width(w);
}
pub fn set_height(&mut self, h: f32) {
self.fill_render.param.rect.set_height(h);
}
pub fn width(&self) -> f32 {
self.fill_render.param.rect.width()
}
pub fn height(&self) -> f32 {
self.fill_render.param.rect.height()
}
pub fn set_context_height(&mut self, context_height: f32) {
self.context_size = context_height;
let mut slider_height = if self.context_size < self.fill_render.param.rect.height() {
self.fill_render.param.rect.height()
} else {
self.fill_render.param.rect.height() * self.fill_render.param.rect.height() / self.context_size
};
if slider_height < 32.0 { slider_height = 32.0; }
self.slider_render.param.rect.set_height(slider_height);
self.changed = true;
}
pub fn set_context_width(&mut self, context_width: f32) {
self.context_size = context_width;
let mut slider_width = if self.context_size < self.fill_render.param.rect.width() {
self.fill_render.param.rect.width()
} else {
self.fill_render.param.rect.width() * self.fill_render.param.rect.width() / self.context_size
};
if slider_width < 32.0 { slider_width = 32.0; }
self.slider_render.param.rect.set_width(slider_width);
self.changed = true;
}
fn slider_offset_y(&self, cy: f32) -> f32 {
let scrollable_content = self.context_size - self.fill_render.param.rect.height();
let scrollable_slider = self.fill_render.param.rect.height() - self.slider_render.param.rect.height();
let scroll_ratio = cy / scrollable_content; scroll_ratio * scrollable_slider }
fn slider_offset_x(&self, cx: f32) -> f32 {
let scrollable_context = self.context_size - self.fill_render.param.rect.width();
let scrollable_slider = self.fill_render.param.rect.width() - self.slider_render.param.rect.width();
let scroll_ratio = cx / scrollable_context;
scroll_ratio * scrollable_slider
}
fn context_offset_y(&self, oy: f32) -> f32 {
let scrollable_content = self.context_size - self.fill_render.param.rect.height();
let scrollable_slider = self.fill_render.param.rect.height() - self.slider_render.param.rect.height();
if scrollable_slider == 0.0 { return 0.0; }
let scroll_ratio = oy / scrollable_slider; scroll_ratio * scrollable_content }
fn context_offset_x(&self, ox: f32) -> f32 {
let scrollable_content = self.context_size - self.fill_render.param.rect.width();
let scrollable_slider = self.fill_render.param.rect.width() - self.slider_render.param.rect.width();
if scrollable_slider == 0.0 { return 0.0; }
let scroll_ratio = ox / scrollable_slider;
scroll_ratio * scrollable_content
}
fn init(&mut self, ui: &mut Ui) {
self.fill_render.init_rectangle(ui, false, false);
self.slider_render.param.rect = self.fill_render.param.rect.clone_with_size(&self.slider_render.param.rect);
self.slider_render.init_rectangle(ui, false, false);
}
fn update_buffer(&mut self, ui: &mut Ui) {
if self.changed { ui.widget_changed |= WidgetChange::Value; }
if ui.widget_changed.contains(WidgetChange::Position) {
self.fill_render.param.rect.offset_to_rect(&ui.draw_rect);
self.slider_render.param.rect.offset_to_rect(&ui.draw_rect);
self.fill_render.update(ui, false, false);
self.slider_render.param.rect.offset(&self.offset);
self.slider_render.update(ui, false, false);
}
if ui.widget_changed.contains(WidgetChange::Value) {
self.slider_render.update(ui, false, false);
}
}
pub(crate) fn redraw(&mut self, ui: &mut Ui) {
self.update_buffer(ui);
let pass = ui.pass.as_mut().unwrap();
if self.context_size > self.fill_render.param.rect.height() && self.height() > self.width() { ui.context.render.rectangle.render(&self.fill_render, pass);
ui.context.render.rectangle.render(&self.slider_render, pass);
}
if self.context_size > self.fill_render.param.rect.width() && self.width() > self.height() { ui.context.render.rectangle.render(&self.fill_render, pass);
ui.context.render.rectangle.render(&self.slider_render, pass);
}
}
}
impl Widget for ScrollBar {
fn update(&mut self, ui: &mut Ui) -> Response<'_> {
match ui.update_type {
UpdateType::Init | UpdateType::ReInit => self.init(ui),
UpdateType::MouseMove => {
if self.focused && ui.device.device_input.mouse.pressed {
if self.height() > self.width() { let oy = ui.device.device_input.mouse.offset_y();
let roy = self.slider_render.param.rect.offset_y_limit(self.offset.y + oy, self.fill_render.param.rect.dy());
self.offset.y = roy;
} else { let ox = ui.device.device_input.mouse.offset_x();
let rox = self.slider_render.param.rect.offset_x_limit(self.offset.x + ox, self.fill_render.param.rect.dx());
self.offset.x = rox;
}
ui.context.window.request_redraw();
self.changed = true;
}
}
UpdateType::MousePress => self.focused = ui.device.device_input.pressed_at(&self.slider_render.param.rect),
_ => {
if self.changed {
self.changed = false;
self.slider_render.update(ui, false, false);
}
}
}
Response::new(&self.id, WidgetSize::same(self.fill_render.param.rect.width(), self.fill_render.param.rect.height()))
}
}