diff --git a/CHANGELOG.md b/CHANGELOG.md index 2021327d..ac58b3a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,10 +59,16 @@ - Reduce latency & redraws with vertex operations especially smaller ones. - `Bin` `on_update` & `on_update_once` methods are now called at the end of a worker cycle. - This improves consistency when checking the `BinPostUpdate` of other `Bin` updates. + +## Changes to Interface + +- **BREAKING**: Removed legacy/obsolete widgets `CheckBox`, `OnOffButton`, `ScrollBar` and `Slider`. ## Changes to `Bin` -- **BREAKING** Remove method `toggle_hidden` and `set_hidden`. + +- **BREAKING**: Remove method `toggle_hidden` and `set_hidden`. - Use `style_modify` instead. +- **BREAKING**: Removed methods `add_drag_events`, `fade_in` and `fade_out`. - **BEHAVIOR**: Rewrote radius code to be more circular. - Added method `style_modify` & `style_modify_then`. - Added method `is_visible`. diff --git a/src/interface/bin/mod.rs b/src/interface/bin/mod.rs index 0c79daa4..922e25a7 100644 --- a/src/interface/bin/mod.rs +++ b/src/interface/bin/mod.rs @@ -21,14 +21,13 @@ use self::text_state::TextState; use crate::Basalt; use crate::image::{ImageCacheLifetime, ImageInfo, ImageKey, ImageMap}; use crate::input::{ - Char, InputHookCtrl, InputHookID, InputHookTarget, KeyCombo, LocalCursorState, LocalKeyState, - MouseButton, WindowState, + Char, InputHookCtrl, InputHookID, InputHookTarget, KeyCombo, LocalCursorState, LocalKeyState, WindowState, }; use crate::interface::{ BinStyle, BinStyleValidation, Color, DefaultFont, FloatWeight, Flow, ItfVertInfo, Opacity, - Position, TextBodyGuard, UnitValue, Visibility, ZIndex, scale_verts, + Position, TextBodyGuard, Visibility, ZIndex, scale_verts, }; -use crate::interval::{IntvlHookCtrl, IntvlHookID}; +use crate::interval::IntvlHookID; use crate::render::RendererMetricsLevel; use crate::window::Window; @@ -968,174 +967,6 @@ impl Bin { } } - pub fn add_drag_events(self: &Arc, target_op: Option>) { - let window = match self.window() { - Some(some) => some, - None => return, - }; - - #[derive(Default)] - struct Data { - target: Weak, - mouse_x: f32, - mouse_y: f32, - pos_from_t: UnitValue, - pos_from_b: UnitValue, - pos_from_l: UnitValue, - pos_from_r: UnitValue, - } - - let data = Arc::new(Mutex::new(None)); - let target_wk = target_op - .map(|v| Arc::downgrade(&v)) - .unwrap_or_else(|| Arc::downgrade(self)); - let data_cp = data.clone(); - - self.on_press(MouseButton::Middle, move |_, window, _| { - let [mouse_x, mouse_y] = window.cursor_pos(); - - let style = match target_wk.upgrade() { - Some(bin) => bin.style_copy(), - None => return InputHookCtrl::Remove, - }; - - *data_cp.lock() = Some(Data { - target: target_wk.clone(), - mouse_x, - mouse_y, - pos_from_t: style.pos_from_t, - pos_from_b: style.pos_from_b, - pos_from_l: style.pos_from_l, - pos_from_r: style.pos_from_r, - }); - - Default::default() - }); - - let data_cp = data.clone(); - - self.attach_input_hook( - self.basalt - .input_ref() - .hook() - .window(&window) - .on_cursor() - .call(move |_, window, _| { - let [mouse_x, mouse_y] = window.cursor_pos(); - let mut data_op = data_cp.lock(); - - let data = match &mut *data_op { - Some(some) => some, - None => return Default::default(), - }; - - let target = match data.target.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - let dx = mouse_x - data.mouse_x; - let dy = mouse_y - data.mouse_y; - - target - .style_update(BinStyle { - pos_from_t: data.pos_from_t.offset_pixels(dy), - pos_from_b: data.pos_from_b.offset_pixels(-dy), - pos_from_l: data.pos_from_l.offset_pixels(dx), - pos_from_r: data.pos_from_r.offset_pixels(-dx), - ..target.style_copy() - }) - .expect_valid(); - - target.trigger_children_update(); - Default::default() - }) - .finish() - .unwrap(), - ); - - self.on_release(MouseButton::Middle, move |_, _, _| { - *data.lock() = None; - Default::default() - }); - } - - pub fn fade_out(self: &Arc, millis: u64) { - let bin_wk = Arc::downgrade(self); - - let start_opacity = match self.style_inspect(|style| style.opacity) { - Opacity::Inheirt => 1.0, - Opacity::Fixed(opacity) => opacity, - Opacity::Multiply(mult) => mult, - }; - - let steps = (millis / 8) as i64; - let step_size = start_opacity / steps as f32; - let mut step_i = 0; - - self.basalt - .interval_ref() - .do_every(Duration::from_millis(8), None, move |_| { - if step_i > steps { - return IntvlHookCtrl::Remove; - } - - let bin = match bin_wk.upgrade() { - Some(some) => some, - None => return IntvlHookCtrl::Remove, - }; - - let opacity = start_opacity - (step_i as f32 * step_size); - let mut copy = bin.style_copy(); - copy.opacity = Opacity::Fixed(opacity); - - if step_i == steps { - copy.visibility = Visibility::Hide; - } - - bin.style_update(copy).expect_valid(); - bin.trigger_children_update(); - step_i += 1; - Default::default() - }); - } - - pub fn fade_in(self: &Arc, millis: u64, target: f32) { - let bin_wk = Arc::downgrade(self); - - let start_opacity = match self.style_inspect(|style| style.opacity) { - Opacity::Inheirt => 1.0, - Opacity::Fixed(opacity) => opacity, - Opacity::Multiply(mult) => mult, - }; - - let steps = (millis / 8) as i64; - let step_size = (target - start_opacity) / steps as f32; - let mut step_i = 0; - - self.basalt - .interval_ref() - .do_every(Duration::from_millis(8), None, move |_| { - if step_i > steps { - return IntvlHookCtrl::Remove; - } - - let bin = match bin_wk.upgrade() { - Some(some) => some, - None => return IntvlHookCtrl::Remove, - }; - - let opacity = (step_i as f32 * step_size) + start_opacity; - let mut copy = bin.style_copy(); - copy.opacity = Opacity::Fixed(opacity); - copy.visibility = Visibility::Show; - bin.style_update(copy).expect_valid(); - bin.trigger_children_update(); - step_i += 1; - Default::default() - }); - } - /// Attach an `InputHookID` to this `Bin`. When this `Bin` drops the hook will be removed. pub fn attach_input_hook(&self, hook_id: InputHookID) { self.input_hook_ids.lock().push(hook_id); diff --git a/src/interface/checkbox.rs b/src/interface/checkbox.rs deleted file mode 100644 index 6fa3a160..00000000 --- a/src/interface/checkbox.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::sync::Arc; - -use parking_lot::Mutex; - -use crate::input::{InputHookCtrl, MouseButton}; -use crate::interface::{Bin, BinStyle, Visibility}; -use crate::window::Window; - -/// ***Obsolete:** This is retained in a semi-working/untested state until widgets are implemented.* -pub struct CheckBox { - pub window: Arc, - pub inner_box: Arc, - pub outer_box: Arc, - checked: Mutex, - on_change: Mutex>>, -} - -impl CheckBox { - pub fn is_checked(&self) -> bool { - *self.checked.lock() - } - - pub fn set(&self, check: bool) { - *self.checked.lock() = check; - self.update(Some(check)); - self.call_on_change(Some(check)); - } - - pub fn check(&self) { - self.set(true); - } - - pub fn uncheck(&self) { - self.set(false); - } - - pub fn toggle(&self) { - let mut checked = self.checked.lock(); - *checked = !*checked; - self.update(Some(*checked)); - self.call_on_change(Some(*checked)); - } - - pub fn on_change(&self, func: F) { - self.on_change.lock().push(Box::new(func)); - } - - fn call_on_change(&self, checked_op: Option) { - let checked = match checked_op { - Some(some) => some, - None => self.is_checked(), - }; - - for func in self.on_change.lock().iter_mut() { - func(checked); - } - } - - fn update(&self, checked_op: Option) { - let checked = match checked_op { - Some(some) => some, - None => self.is_checked(), - }; - - self.inner_box - .style_update(BinStyle { - visibility: if checked { - Visibility::Show - } else { - Visibility::Hide - }, - ..self.inner_box.style_copy() - }) - .expect_valid(); - } - - pub fn new(window: Arc) -> Arc { - let mut bins = window.new_bins(2); - - let checkbox = Arc::new(CheckBox { - window, - inner_box: bins.pop().unwrap(), - outer_box: bins.pop().unwrap(), - checked: Mutex::new(false), - on_change: Mutex::new(Vec::new()), - }); - - checkbox.outer_box.add_child(checkbox.inner_box.clone()); - let checkbox_wk = Arc::downgrade(&checkbox); - - checkbox - .outer_box - .on_press(MouseButton::Left, move |_, _, _| { - match checkbox_wk.upgrade() { - Some(checkbox) => { - checkbox.toggle(); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - checkbox - } -} diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 75886550..b371ab19 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -1,11 +1,7 @@ //! System for storing interface related objects. mod bin; -pub mod checkbox; mod color; -pub mod on_off_button; -pub mod scroll_bar; -pub mod slider; mod style; use std::cmp::Reverse; diff --git a/src/interface/on_off_button.rs b/src/interface/on_off_button.rs deleted file mode 100644 index 485c082e..00000000 --- a/src/interface/on_off_button.rs +++ /dev/null @@ -1,277 +0,0 @@ -use std::sync::Arc; -use std::sync::atomic::{self, AtomicBool}; - -use parking_lot::Mutex; - -use crate::input::{InputHookCtrl, MouseButton}; -use crate::interface::UnitValue::Pixels; -use crate::interface::{Bin, BinStyle, Color, Position, TextAttrs, TextBody, TextHoriAlign}; -use crate::window::Window; - -/// ***Obsolete:** This is retained in a semi-working/untested state until widgets are implemented.* -pub struct OnOffButton { - pub container: Arc, - theme: OnOffButtonTheme, - enabled: AtomicBool, - on: Arc, - off: Arc, - on_change_fns: Mutex>>, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct OnOffButtonTheme { - /// Color of the container when off - pub color1: Color, - /// Color of the container when on - pub color2: Color, - /// Color of the inner slidy bit - pub color3: Color, - /// Color of the off text color - pub color4: Color, - /// Color of the on text color - pub color5: Color, -} - -impl Default for OnOffButtonTheme { - fn default() -> Self { - OnOffButtonTheme { - color1: Color::shex("ff0000d0"), - color2: Color::shex("00ff00d0"), - color3: Color::shex("000000f0"), - color4: Color::shex("ffffffff"), - color5: Color::shex("ffffffff"), - } - } -} - -impl OnOffButton { - pub fn new( - window: Arc, - theme: OnOffButtonTheme, - parent: Option>, - ) -> Arc { - let mut bins = window.new_bins(3); - let container = bins.pop().unwrap(); - let on = bins.pop().unwrap(); - let off = bins.pop().unwrap(); - container.add_child(on.clone()); - container.add_child(off.clone()); - - if let Some(parent) = parent.as_ref() { - parent.add_child(container.clone()); - } - - container - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(0.0), - pos_from_l: Pixels(0.0), - width: Pixels(60.0), - height: Pixels(24.0), - border_radius_tl: Pixels(3.0), - border_radius_bl: Pixels(3.0), - border_radius_tr: Pixels(3.0), - border_radius_br: Pixels(3.0), - back_color: theme.color1, - ..BinStyle::default() - }) - .expect_valid(); - - off.style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_l: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - padding_t: Pixels(5.0), - text_body: TextBody { - spans: vec!["Off".into()], - hori_align: TextHoriAlign::Center, - base_attrs: TextAttrs { - color: theme.color4, - height: Pixels(12.0), - ..Default::default() - }, - ..Default::default() - }, - ..BinStyle::default() - }) - .expect_valid(); - - on.style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_r: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - border_radius_tl: Pixels(3.0), - border_radius_bl: Pixels(3.0), - border_radius_tr: Pixels(3.0), - border_radius_br: Pixels(3.0), - back_color: theme.color3, - ..BinStyle::default() - }) - .expect_valid(); - - let ret = Arc::new(OnOffButton { - container, - theme, - enabled: AtomicBool::new(false), - on, - off, - on_change_fns: Mutex::new(Vec::new()), - }); - - let button_wk = Arc::downgrade(&ret); - - ret.on.on_press(MouseButton::Left, move |_, _, _| { - match button_wk.upgrade() { - Some(button) => { - button.toggle(); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - let button_wk = Arc::downgrade(&ret); - - ret.off.on_press(MouseButton::Left, move |_, _, _| { - match button_wk.upgrade() { - Some(button) => { - button.toggle(); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - let button_wk = Arc::downgrade(&ret); - - ret.container.on_press(MouseButton::Left, move |_, _, _| { - match button_wk.upgrade() { - Some(button) => { - button.toggle(); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - ret - } - - pub fn toggle(&self) -> bool { - let cur = self.enabled.load(atomic::Ordering::Relaxed); - self.set(!cur); - !cur - } - - pub fn is_on(&self) -> bool { - self.enabled.load(atomic::Ordering::Relaxed) - } - - pub fn on_change(&self, func: F) { - self.on_change_fns.lock().push(Box::new(func)); - } - - pub fn set(&self, on: bool) { - self.enabled.store(on, atomic::Ordering::Relaxed); - - if !on { - self.container - .style_update(BinStyle { - back_color: self.theme.color1, - ..self.container.style_copy() - }) - .expect_valid(); - - self.on - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_r: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - border_radius_tl: Pixels(3.0), - border_radius_bl: Pixels(3.0), - border_radius_tr: Pixels(3.0), - border_radius_br: Pixels(3.0), - back_color: self.theme.color3, - ..BinStyle::default() - }) - .expect_valid(); - - self.off - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_l: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - padding_t: Pixels(5.0), - text_body: TextBody { - spans: vec!["Off".into()], - hori_align: TextHoriAlign::Center, - base_attrs: TextAttrs { - color: self.theme.color4, - height: Pixels(12.0), - ..Default::default() - }, - ..Default::default() - }, - ..BinStyle::default() - }) - .expect_valid(); - } else { - self.container - .style_update(BinStyle { - back_color: self.theme.color2, - ..self.container.style_copy() - }) - .expect_valid(); - - self.on - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_r: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - padding_t: Pixels(5.0), - text_body: TextBody { - spans: vec!["On".into()], - hori_align: TextHoriAlign::Center, - base_attrs: TextAttrs { - color: self.theme.color5, - height: Pixels(12.0), - ..Default::default() - }, - ..Default::default() - }, - ..BinStyle::default() - }) - .expect_valid(); - - self.off - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(2.0), - pos_from_l: Pixels(2.0), - pos_from_b: Pixels(2.0), - width: Pixels(28.0), - border_radius_tl: Pixels(3.0), - border_radius_bl: Pixels(3.0), - border_radius_tr: Pixels(3.0), - border_radius_br: Pixels(3.0), - back_color: self.theme.color3, - ..BinStyle::default() - }) - .expect_valid(); - } - - for func in self.on_change_fns.lock().iter_mut() { - func(on); - } - } -} diff --git a/src/interface/scroll_bar.rs b/src/interface/scroll_bar.rs deleted file mode 100644 index 7a56c9a5..00000000 --- a/src/interface/scroll_bar.rs +++ /dev/null @@ -1,531 +0,0 @@ -use std::sync::Arc; - -use parking_lot::Mutex; - -use crate::image::ImageKey; -use crate::input::{InputHookCtrl, MouseButton}; -use crate::interface::UnitValue::{Pixels, Undefined}; -use crate::interface::{Bin, BinStyle, BinVertex, Color, Position}; -use crate::window::Window; - -pub struct ScrollBarStyle { - pub border_color: Color, - pub arrow_color: Color, - pub bar_color: Color, - pub back_color: Color, -} - -impl Default for ScrollBarStyle { - fn default() -> Self { - ScrollBarStyle { - back_color: Color::shex("35353c"), - bar_color: Color::shex("f0f0f0"), - arrow_color: Color::shex("f0f0f0"), - border_color: Color::shex("222227"), - } - } -} - -pub struct ScrollBar { - pub back: Arc, - pub up: Arc, - pub down: Arc, - pub bar: Arc, - scroll: Arc, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum ScrollTo { - Same, - Top, - Bottom, - Percent(f32), - Amount(f32), - Set(f32), -} - -impl ScrollBar { - /// # Notes - /// - Panics if parent bin is not associated to the window provided. - pub fn new( - window: Arc, - style: Option, - parent: Option>, - scroll: Arc, - ) -> Arc { - if let Some(parent) = parent.as_ref() { - match parent.window() { - Some(parent_window) => { - if window != parent_window { - panic!("parent bin is not associated to the window provided"); - } - }, - None => { - panic!("parent bin is not associated to a window"); - }, - } - } - - let style = style.unwrap_or_default(); - let mut bins = window.new_bins(4); - let back = bins.pop().unwrap(); - let up = bins.pop().unwrap(); - let down = bins.pop().unwrap(); - let bar = bins.pop().unwrap(); - - back.add_child(up.clone()); - back.add_child(down.clone()); - back.add_child(bar.clone()); - - back.style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(0.0), - pos_from_b: Pixels(0.0), - pos_from_r: Pixels(0.0), - width: Pixels(15.0), - back_color: style.back_color, - border_size_l: Pixels(1.0), - border_color_l: style.border_color, - ..BinStyle::default() - }) - .expect_valid(); - - up.style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(0.0), - pos_from_l: Pixels(0.0), - pos_from_r: Pixels(0.0), - height: Pixels(13.0), - user_vertexes: vec![( - ImageKey::INVALID, - vec![ - BinVertex { - x: Pixels(7.5), - y: Pixels(4.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - BinVertex { - x: Pixels(4.0), - y: Pixels(9.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - BinVertex { - x: Pixels(11.0), - y: Pixels(9.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - ], - )], - ..BinStyle::default() - }) - .expect_valid(); - - down.style_update(BinStyle { - position: Position::Relative, - pos_from_b: Pixels(0.0), - pos_from_l: Pixels(0.0), - pos_from_r: Pixels(0.0), - height: Pixels(13.0), - user_vertexes: vec![( - ImageKey::INVALID, - vec![ - BinVertex { - x: Pixels(11.0), - y: Pixels(4.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - BinVertex { - x: Pixels(4.0), - y: Pixels(4.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - BinVertex { - x: Pixels(7.5), - y: Pixels(9.0), - z: 0, - color: style.arrow_color, - coords: [0.0; 2], - }, - ], - )], - ..BinStyle::default() - }) - .expect_valid(); - - bar.style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(15.0), - pos_from_b: Pixels(15.0), - pos_from_l: Pixels(2.0), - pos_from_r: Pixels(2.0), - back_color: style.bar_color, - ..BinStyle::default() - }) - .expect_valid(); - - let sb = Arc::new(ScrollBar { - back, - up, - down, - bar, - scroll, - }); - - let sb_wk = Arc::downgrade(&sb); - let drag_data: Arc>> = Arc::new(Mutex::new(None)); - let drag_data_cp = drag_data.clone(); - - sb.bar.on_press(MouseButton::Left, move |_, window, _| { - let sb = match sb_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - let [_, mouse_y] = window.cursor_pos(); - let scroll_y = sb.scroll.style_copy().scroll_y; - *drag_data_cp.lock() = Some((mouse_y, scroll_y)); - Default::default() - }); - - let drag_data_cp = drag_data.clone(); - - sb.bar.on_release(MouseButton::Left, move |_, _, _| { - *drag_data_cp.lock() = None; - Default::default() - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.bar.attach_input_hook( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_cursor() - .call(move |_, window, _| { - let sb = match sb_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - let [_, mouse_y] = window.cursor_pos(); - let drag_data_op = drag_data.lock(); - - let drag_data = match drag_data_op.as_ref() { - Some(some) => some, - None => return Default::default(), - }; - - let overflow = sb.scroll.calc_vert_overflow(); - let up_post = sb.up.post_update(); - let down_post = sb.down.post_update(); - let max_bar_h = down_post.tlo[1] - up_post.blo[1]; - let mut bar_sp = overflow / 10.0; - let mut bar_h = max_bar_h - bar_sp; - - if bar_h < 3.0 { - bar_h = 3.0; - bar_sp = max_bar_h - bar_h; - } - - let bar_inc = overflow / bar_sp; - sb.update(ScrollTo::Set( - drag_data.1 + ((mouse_y - drag_data.0) * bar_inc), - )); - Default::default() - }) - .finish() - .unwrap(), - ); - - let sb_wk = Arc::downgrade(&sb); - - sb.scroll.on_update(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.back.trigger_update(); - let sb_wk = Arc::downgrade(&sb); - - sb.back.on_update_once(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.update(ScrollTo::Same); - } - }); - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.scroll.on_children_added(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.back.trigger_update(); - let sb_wk = Arc::downgrade(&sb); - - sb.back.on_update_once(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.update(ScrollTo::Same); - } - }); - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.scroll.on_children_removed(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.back.trigger_update(); - let sb_wk = Arc::downgrade(&sb); - - sb.back.on_update_once(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.update(ScrollTo::Same); - } - }); - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.back.on_update(move |_, _| { - if let Some(sb) = sb_wk.upgrade() { - sb.update(ScrollTo::Same); - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.up.on_press(MouseButton::Left, move |_, _, _| { - match sb_wk.upgrade() { - Some(sb) => { - sb.update(ScrollTo::Amount(-10.0)); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.down.on_press(MouseButton::Left, move |_, _, _| { - match sb_wk.upgrade() { - Some(sb) => { - sb.update(ScrollTo::Amount(10.0)); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }); - - let sb_wk = Arc::downgrade(&sb); - - sb.back.attach_input_hook( - window - .basalt_ref() - .input_ref() - .hook() - .bin(&sb.back) - .on_scroll() - .enable_smooth(true) - .call(move |_, _, mut amt, _| { - amt = amt.round(); - - if amt == 0.0 { - return Default::default(); - } - - match sb_wk.upgrade() { - Some(sb) => { - sb.update(ScrollTo::Amount(amt)); - Default::default() - }, - None => InputHookCtrl::Remove, - } - }) - .finish() - .unwrap(), - ); - - let sb_wk = Arc::downgrade(&sb); - - sb.scroll.attach_input_hook( - window - .basalt_ref() - .input_ref() - .hook() - .bin(&sb.scroll) - .on_scroll() - .enable_smooth(true) - .upper_blocks(true) - .call(move |_, _, mut amt, _| { - amt = amt.round(); - - if amt == 0.0 { - return Default::default(); - } - - match sb_wk.upgrade() { - Some(sb) => { - sb.update(ScrollTo::Amount(amt)); - Default::default() - }, - None => crate::input::InputHookCtrl::Remove, - } - }) - .finish() - .unwrap(), - ); - - sb - } - - pub fn update(&self, amount: ScrollTo) { - let mut scroll_y = self.scroll.style_copy().scroll_y; - let overflow = self.scroll.calc_vert_overflow(); - - if match amount { - ScrollTo::Same => { - if scroll_y > overflow { - scroll_y = overflow; - true - } else { - false - } - }, - ScrollTo::Top => { - if scroll_y == 0.0 { - false - } else { - scroll_y = 0.0; - true - } - }, - ScrollTo::Bottom => { - if scroll_y == overflow { - false - } else { - scroll_y = overflow; - true - } - }, - ScrollTo::Percent(p) => { - if p.is_sign_positive() { - if scroll_y == overflow { - false - } else { - let amt = overflow * p; - - if scroll_y + amt > overflow { - scroll_y = overflow; - } else { - scroll_y += amt; - } - - true - } - } else if scroll_y == 0.0 { - false - } else { - let amt = overflow * p; - - if scroll_y + amt < 0.0 { - scroll_y = 0.0; - } else { - scroll_y += amt; - } - - true - } - }, - ScrollTo::Amount(amt) => { - if amt.is_sign_positive() { - if scroll_y == overflow { - false - } else { - if scroll_y + amt > overflow { - scroll_y = overflow; - } else { - scroll_y += amt; - } - - true - } - } else if scroll_y == 0.0 { - false - } else { - if scroll_y + amt < 0.0 { - scroll_y = 0.0; - } else { - scroll_y += amt; - } - - true - } - }, - ScrollTo::Set(to) => { - if to < 0.0 { - if scroll_y == 0.0 { - false - } else { - scroll_y = 0.0; - true - } - } else if to > overflow { - if scroll_y == overflow { - false - } else { - scroll_y = overflow; - true - } - } else { - scroll_y = to; - true - } - }, - } { - self.scroll - .style_update(BinStyle { - scroll_y, - ..self.scroll.style_copy() - }) - .expect_valid(); - } - - let up_post = self.up.post_update(); - let down_post = self.down.post_update(); - let max_bar_h = down_post.tlo[1] - up_post.blo[1]; - - if max_bar_h < 3.0 { - // println!("Scroll bar less than minimum height."); - } - - let mut bar_sp = overflow / 10.0; - let mut bar_h = max_bar_h - bar_sp; - - if bar_h < 3.0 { - bar_h = 3.0; - bar_sp = max_bar_h - bar_h; - } - - let bar_inc = overflow / bar_sp; - let bar_pos = scroll_y / bar_inc; - - self.bar - .style_update(BinStyle { - pos_from_t: Pixels(bar_pos + up_post.blo[1] - up_post.tlo[1]), - pos_from_b: Undefined, - height: Pixels(bar_h), - ..self.bar.style_copy() - }) - .expect_valid(); - } -} diff --git a/src/interface/slider.rs b/src/interface/slider.rs deleted file mode 100644 index a72d48af..00000000 --- a/src/interface/slider.rs +++ /dev/null @@ -1,520 +0,0 @@ -use std::sync::Arc; -use std::sync::atomic::{self, AtomicBool}; -use std::time::Duration; - -use parking_lot::Mutex; - -use crate::input::{InputHookCtrl, InputHookID, MouseButton, Qwerty}; -use crate::interface::UnitValue::Pixels; -use crate::interface::{Bin, BinStyle, Color, Position, TextAttrs, TextBody, TextWrap, ZIndex}; -use crate::window::Window; - -/// ***Obsolete:** This is retained in a semi-working/untested state until widgets are implemented.* -pub struct Slider { - pub window: Arc, - pub container: Arc, - pub slidy_bit: Arc, - pub input_box: Arc, - pub slide_back: Arc, - data: Mutex, - on_change: Mutex>>, - hooks: Mutex>, -} - -struct Data { - min: f32, - max: f32, - at: f32, - step: f32, - method: Method, -} - -impl Data { - fn apply_method(&mut self) { - match self.method { - Method::Float => return, - Method::RoundToStep => { - self.at -= self.min; - self.at /= self.step; - self.at = f32::round(self.at); - self.at *= self.step; - self.at += self.min; - }, - Method::RoundToInt => { - self.at = f32::round(self.at); - }, - } - if self.at > self.max { - self.at = self.max; - } else if self.at < self.min { - self.at = self.min; - } - } -} - -pub enum Method { - Float, - RoundToStep, - RoundToInt, -} - -impl Drop for Slider { - fn drop(&mut self) { - let mut hooks = self.hooks.lock(); - - for id in hooks.split_off(0) { - self.window.basalt_ref().input_ref().remove_hook(id); - } - } -} - -impl Slider { - pub fn set_min_max(&self, min: f32, max: f32) { - let mut data = self.data.lock(); - data.min = min; - data.max = max; - } - - pub fn min_max(&self) -> (f32, f32) { - let data = self.data.lock(); - (data.min, data.max) - } - - pub fn at(&self) -> f32 { - self.data.lock().at - } - - pub fn set_step_size(&self, size: f32) { - self.data.lock().step = size; - } - - pub fn on_change(&self, func: F) { - self.on_change.lock().push(Box::new(func)); - } - - pub fn set_method(&self, method: Method) { - self.data.lock().method = method; - } - - /// # Notes - /// - Panics if parent bin is not associated to the window provided. - pub fn new(window: Arc, parent_op: Option>) -> Arc { - if let Some(parent) = parent_op.as_ref() { - match parent.window() { - Some(parent_window) => { - if window != parent_window { - panic!("parent bin is not associated to the window provided"); - } - }, - None => { - panic!("parent bin is not associated to a window"); - }, - } - } - - let mut bins = window.new_bins(4); - - let slider = Arc::new(Slider { - window: window.clone(), - container: bins.pop().unwrap(), - slide_back: bins.pop().unwrap(), - slidy_bit: bins.pop().unwrap(), - input_box: bins.pop().unwrap(), - data: Mutex::new(Data { - min: 0.0, - max: 100.0, - at: 0.0, - step: 10.0, - method: Method::Float, - }), - on_change: Mutex::new(Vec::new()), - hooks: Mutex::new(Vec::new()), - }); - - if let Some(parent) = parent_op { - parent.add_child(slider.container.clone()); - } - - slider.slide_back.add_child(slider.slidy_bit.clone()); - slider.container.add_child(slider.input_box.clone()); - slider.container.add_child(slider.slide_back.clone()); - - slider - .container - .style_update(BinStyle { - position: Position::Relative, - ..BinStyle::default() - }) - .debug(); // TODO: - - slider - .slidy_bit - .style_update(BinStyle { - position: Position::Relative, - z_index: ZIndex::Offset(100), - pos_from_l: Pixels(30.0), - pos_from_t: Pixels(-3.0), - pos_from_b: Pixels(-3.0), - width: Pixels(10.0), - border_size_t: Pixels(1.0), - border_size_b: Pixels(1.0), - border_size_l: Pixels(1.0), - border_size_r: Pixels(1.0), - border_color_t: Color::hex("808080"), - border_color_b: Color::hex("808080"), - border_color_l: Color::hex("808080"), - border_color_r: Color::hex("808080"), - back_color: Color::hex("f8f8f8"), - ..BinStyle::default() - }) - .expect_valid(); - - slider - .input_box - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(1.0), - pos_from_b: Pixels(1.0), - pos_from_r: Pixels(0.0), - padding_l: Pixels(5.0), - width: Pixels(60.0), - border_size_t: Pixels(1.0), - border_size_b: Pixels(1.0), - border_size_l: Pixels(1.0), - border_size_r: Pixels(1.0), - border_color_t: Color::hex("808080"), - border_color_b: Color::hex("808080"), - border_color_l: Color::hex("808080"), - border_color_r: Color::hex("808080"), - back_color: Color::hex("f8f8f8"), - text_body: TextBody { - spans: vec!["".into()], - text_wrap: TextWrap::None, - base_attrs: TextAttrs { - height: Pixels(14.0), - ..Default::default() - }, - ..Default::default() - }, - ..BinStyle::default() - }) - .expect_valid(); - - slider - .slide_back - .style_update(BinStyle { - position: Position::Relative, - pos_from_t: Pixels(13.0), - pos_from_b: Pixels(13.0), - pos_from_l: Pixels(0.0), - pos_from_r: Pixels(70.0), - border_size_t: Pixels(1.0), - border_size_b: Pixels(1.0), - border_size_l: Pixels(1.0), - border_size_r: Pixels(1.0), - border_color_t: Color::hex("f8f8f8"), - border_color_b: Color::hex("f8f8f8"), - border_color_l: Color::hex("f8f8f8"), - border_color_r: Color::hex("f8f8f8"), - back_color: Color::hex("808080"), - overflow_y: true, - overflow_x: true, - ..BinStyle::default() - }) - .expect_valid(); - - let slider_cp = Arc::downgrade(&slider); - - slider.slide_back.on_update(move |_, _| { - let slider_cp = match slider_cp.upgrade() { - Some(some) => some, - None => return, - }; - - slider_cp.force_update(None); - }); - - let mut hooks = slider.hooks.lock(); - let sliding = Arc::new(AtomicBool::new(false)); - let focused = Arc::new(AtomicBool::new(false)); - let slider_wk = Arc::downgrade(&slider); - let sliding_cp = sliding.clone(); - let focused_cp = focused.clone(); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_press() - .keys(MouseButton::Left) - .call(move |_, window, _| { - let slider = match slider_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - let [mouse_x, mouse_y] = window.cursor_pos(); - - if slider.slidy_bit.mouse_inside(mouse_x, mouse_y) { - sliding_cp.store(true, atomic::Ordering::SeqCst); - } - - if slider.container.mouse_inside(mouse_x, mouse_y) { - focused_cp.store(true, atomic::Ordering::SeqCst); - } else { - focused_cp.store(false, atomic::Ordering::SeqCst); - } - - Default::default() - }) - .finish() - .unwrap(), - ); - - let sliding_cp = sliding.clone(); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_release() - .keys(MouseButton::Left) - .call(move |_, _, _| { - sliding_cp.store(false, atomic::Ordering::SeqCst); - Default::default() - }) - .finish() - .unwrap(), - ); - - let slider_wk = Arc::downgrade(&slider); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_scroll() - .call(move |_, window, scroll_amt, _| { - let slider = match slider_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - let [mouse_x, mouse_y] = window.cursor_pos(); - - if slider.container.mouse_inside(mouse_x, mouse_y) { - if scroll_amt > 0.0 { - slider.increment(); - } else { - slider.decrement(); - } - } - - Default::default() - }) - .finish() - .unwrap(), - ); - - let focused_cp = focused.clone(); - let slider_wk = Arc::downgrade(&slider); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_hold() - .keys(Qwerty::ArrowRight) - .interval(Duration::from_millis(150)) - .call(move |_, _, _| { - let slider = match slider_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - if focused_cp.load(atomic::Ordering::SeqCst) { - slider.increment(); - } - - Default::default() - }) - .finish() - .unwrap(), - ); - - let slider_wk = Arc::downgrade(&slider); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_hold() - .keys(Qwerty::ArrowLeft) - .interval(Duration::from_millis(150)) - .call(move |_, _, _| { - let slider = match slider_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - if focused.load(atomic::Ordering::SeqCst) { - slider.decrement(); - } - - Default::default() - }) - .finish() - .unwrap(), - ); - - let slider_wk = Arc::downgrade(&slider); - - hooks.push( - window - .basalt_ref() - .input_ref() - .hook() - .window(&window) - .on_cursor() - .call(move |_, window, _| { - let slider = match slider_wk.upgrade() { - Some(some) => some, - None => return InputHookCtrl::Remove, - }; - - if sliding.load(atomic::Ordering::SeqCst) { - let [mouse_x, _] = window.cursor_pos(); - let back_bps = slider.slide_back.post_update(); - let back_width = back_bps.tro[0] - back_bps.tlo[0]; - let sbit_style = slider.slidy_bit.style_copy(); - let sbit_width = sbit_style.width.px_width([0.0; 2]).unwrap_or(0.0); - let sbit_bordl = sbit_style.border_size_l.px_width([0.0; 2]).unwrap_or(0.0); - let sbit_bordr = sbit_style.border_size_r.px_width([0.0; 2]).unwrap_or(0.0); - let mut from_l = mouse_x - back_bps.tlo[0] - (sbit_width / 2.0); - let max_from_l = back_width - sbit_width - sbit_bordl - sbit_bordr; - - if from_l < 0.0 { - from_l = 0.0; - } else if from_l > max_from_l { - from_l = max_from_l; - } - - let mut percent = from_l / max_from_l; - let mut data = slider.data.lock(); - data.at = ((data.max - data.min) * percent) + data.min; - data.apply_method(); - percent = (data.at - data.min) / (data.max - data.min); - from_l = max_from_l * percent; - - slider - .slidy_bit - .style_update(BinStyle { - pos_from_l: Pixels(from_l), - ..sbit_style - }) - .expect_valid(); - - let mut input_box_style = slider.input_box.style_copy(); - input_box_style.text_body.spans.last_mut().unwrap().text = - format!("{}", data.at); - slider - .input_box - .style_update(input_box_style) - .expect_valid(); - - for func in slider.on_change.lock().iter_mut() { - func(data.at); - } - } - - Default::default() - }) - .finish() - .unwrap(), - ); - - drop(hooks); - slider - } - - pub fn set(&self, val: f32) { - let mut data = self.data.lock(); - data.at = val; - - if data.at > data.max { - data.at = data.max; - } else if data.at < data.min { - data.at = data.min; - } - - self.force_update(Some(&mut *data)); - } - - pub fn increment(&self) { - let mut data = self.data.lock(); - data.at += data.step; - - if data.at > data.max { - data.at = data.max; - } - - self.force_update(Some(&mut *data)); - } - - pub fn decrement(&self) { - let mut data = self.data.lock(); - data.at -= data.step; - - if data.at < data.min { - data.at = data.min; - } - - self.force_update(Some(&mut *data)); - } - - fn force_update(&self, data: Option<&mut Data>) { - let (percent, at, changed) = match data { - Some(data) => ((data.at - data.min) / (data.max - data.min), data.at, true), - None => { - let data = self.data.lock(); - ((data.at - data.min) / (data.max - data.min), data.at, false) - }, - }; - - let back_bps = self.slide_back.post_update(); - let back_width = back_bps.tro[0] - back_bps.tlo[0]; - let sbit_style = self.slidy_bit.style_copy(); - let sbit_width = sbit_style.width.px_width([0.0; 2]).unwrap_or(0.0); - let sbit_bordl = sbit_style.border_size_l.px_width([0.0; 2]).unwrap_or(0.0); - let sbit_bordr = sbit_style.border_size_r.px_width([0.0; 2]).unwrap_or(0.0); - let max_from_l = back_width - sbit_bordl - sbit_bordr - sbit_width; - let set_from_l = max_from_l * percent; - - self.slidy_bit - .style_update(BinStyle { - pos_from_l: Pixels(set_from_l), - ..sbit_style - }) - .expect_valid(); - - let mut input_box_style = self.input_box.style_copy(); - input_box_style.text_body.spans.last_mut().unwrap().text = format!("{}", at); - self.input_box.style_update(input_box_style).expect_valid(); - - if changed { - for func in self.on_change.lock().iter_mut() { - func(at); - } - } - } -}