From a0d7f4acecc8da60ba16b2389a070a99f2a00985 Mon Sep 17 00:00:00 2001 From: Adrian Wozniak Date: Sat, 21 Dec 2019 18:45:56 +0100 Subject: [PATCH] Add Widget trait, improve scrollbar --- rider-editor/src/ui/buttons/save_button.rs | 151 +++++++---------- .../src/ui/buttons/settings_button.rs | 152 +++++++----------- rider-editor/src/ui/file_editor/mod.rs | 6 +- rider-editor/src/ui/menu_bar.rs | 18 ++- rider-editor/src/ui/mod.rs | 97 ++++++++++- rider-editor/src/ui/modal/open_file.rs | 59 ++++--- rider-editor/src/ui/project_tree/mod.rs | 2 +- .../ui/scroll_bar/horizontal_scroll_bar.rs | 74 ++++----- rider-editor/src/ui/scroll_bar/mod.rs | 82 +++++++--- .../src/ui/scroll_bar/vertical_scroll_bar.rs | 71 ++++---- rider-themes/src/code_highlighting_color.rs | 1 - 11 files changed, 380 insertions(+), 333 deletions(-) diff --git a/rider-editor/src/ui/buttons/save_button.rs b/rider-editor/src/ui/buttons/save_button.rs index 395af1a..498f0b5 100644 --- a/rider-editor/src/ui/buttons/save_button.rs +++ b/rider-editor/src/ui/buttons/save_button.rs @@ -1,8 +1,5 @@ -use crate::app::{ConfigAccess, ConfigHolder, UpdateResult as UR}; -use crate::renderer::Renderer; -use crate::ui::{ - move_render_point, CanvasAccess, ClickHandler, RenderBox, RenderContext, Update, UpdateContext, -}; +use crate::app::{ConfigAccess, UpdateResult as UR}; +use crate::ui::{UpdateContext, Widget, WidgetInner}; use sdl2::rect::{Point, Rect}; const ICON_DEST_WIDTH: u32 = 16; @@ -11,97 +8,69 @@ const ICON_SRC_WIDTH: u32 = 32; const ICON_SRC_HEIGHT: u32 = 32; pub struct SaveButton { - source: Rect, - dest: Rect, - config: ConfigAccess, + inner: WidgetInner, +} + +impl std::ops::Deref for SaveButton { + type Target = WidgetInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for SaveButton { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Widget for SaveButton { + fn texture_path(&self) -> Option { + let c = self.config.read().unwrap(); + let mut themes_dir = c.directories().themes_dir.clone(); + let path = c.theme().images().save_icon(); + themes_dir.push(path); + Some(themes_dir.to_str().unwrap().to_owned()) + } + + fn dest(&self) -> &Rect { + &self.dest + } + + fn set_dest(&mut self, rect: &Rect) { + self.inner.dest = rect.clone(); + } + + fn source(&self) -> &Rect { + &self.source + } + + fn set_source(&mut self, rect: &Rect) { + self.inner.source = rect.clone(); + } + + fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR { + UR::SaveCurrentFile + } + + fn padding_width(&self) -> u32 { + ICON_DEST_WIDTH + } + + fn padding_height(&self) -> u32 { + ICON_DEST_HEIGHT + } } impl SaveButton { pub fn new(config: ConfigAccess) -> Self { Self { - dest: Rect::new(0, 0, ICON_DEST_WIDTH, ICON_DEST_HEIGHT), - source: Rect::new(0, 0, ICON_SRC_WIDTH, ICON_SRC_HEIGHT), - config, + inner: WidgetInner::new( + config, + Rect::new(0, 0, ICON_SRC_WIDTH, ICON_SRC_HEIGHT), + Rect::new(0, 0, ICON_DEST_WIDTH, ICON_DEST_HEIGHT), + ), } } - - pub fn render(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext) - where - C: CanvasAccess, - R: Renderer, - { - use std::borrow::*; - let mut dest = match context { - &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest.clone(), - }; - - let mut clipping = dest.clone(); - clipping.set_width(clipping.width() + ICON_DEST_WIDTH); - clipping.set_height(clipping.height() + ICON_DEST_HEIGHT); - canvas.set_clipping(clipping); - let save_texture_path = { - let c = self.config.read().unwrap(); - let mut themes_dir = c.directories().themes_dir.clone(); - let path = c.theme().images().save_icon(); - themes_dir.push(path); - themes_dir.to_str().unwrap().to_owned() - }; - let maybe_tex = renderer.load_image(save_texture_path.clone()); - if let Ok(texture) = maybe_tex { - dest.set_width(ICON_DEST_WIDTH); - dest.set_height(ICON_DEST_HEIGHT); - canvas - .render_image(texture, self.source.clone(), dest.clone()) - .unwrap_or_else(|_| panic!("Failed to draw directory entry texture")); - } - } - - pub fn prepare_ui<'l, T>(&mut self, _renderer: &mut T) - where - T: ConfigHolder + Renderer, - { - } - - pub fn source(&self) -> &Rect { - &self.source - } - - pub fn set_dest(&mut self, rect: &Rect) { - self.dest = rect.clone(); - } - - pub fn set_source(&mut self, rect: &Rect) { - self.source = rect.clone(); - } -} - -impl Update for SaveButton { - fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - UR::NoOp - } -} - -impl ClickHandler for SaveButton { - fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR { - UR::SaveCurrentFile - } - - fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool { - match *context { - UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest, - } - .contains_point(point.clone()) - } -} - -impl RenderBox for SaveButton { - fn render_start_point(&self) -> Point { - self.dest.top_left() - } - - fn dest(&self) -> Rect { - self.dest - } } diff --git a/rider-editor/src/ui/buttons/settings_button.rs b/rider-editor/src/ui/buttons/settings_button.rs index 8d5b578..4bd0f47 100644 --- a/rider-editor/src/ui/buttons/settings_button.rs +++ b/rider-editor/src/ui/buttons/settings_button.rs @@ -1,8 +1,6 @@ -use crate::app::{ConfigAccess, ConfigHolder, UpdateResult as UR}; -use crate::renderer::Renderer; -use crate::ui::{ - move_render_point, CanvasAccess, ClickHandler, RenderBox, RenderContext, Update, UpdateContext, -}; +use crate::app::UpdateResult as UR; +use crate::ui::{UpdateContext, Widget, WidgetInner}; +use rider_config::ConfigAccess; use sdl2::rect::{Point, Rect}; const ICON_DEST_WIDTH: u32 = 16; @@ -11,97 +9,69 @@ const ICON_SRC_WIDTH: u32 = 16; const ICON_SRC_HEIGHT: u32 = 16; pub struct SettingsButton { - source: Rect, - dest: Rect, - config: ConfigAccess, + inner: WidgetInner, +} + +impl std::ops::Deref for SettingsButton { + type Target = WidgetInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for SettingsButton { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl Widget for SettingsButton { + fn texture_path(&self) -> Option { + let c = self.config.read().unwrap(); + let mut themes_dir = c.directories().themes_dir.clone(); + let path = c.theme().images().settings_icon(); + themes_dir.push(path); + Some(themes_dir.to_str().unwrap().to_owned()) + } + + fn dest(&self) -> &Rect { + &self.dest + } + + fn set_dest(&mut self, rect: &Rect) { + self.inner.dest = rect.clone(); + } + + fn source(&self) -> &Rect { + &self.source + } + + fn set_source(&mut self, rect: &Rect) { + self.inner.source = rect.clone(); + } + + fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR { + UR::OpenSettings + } + + fn padding_width(&self) -> u32 { + ICON_DEST_WIDTH + } + + fn padding_height(&self) -> u32 { + ICON_DEST_HEIGHT + } } impl SettingsButton { pub fn new(config: ConfigAccess) -> Self { Self { - dest: Rect::new(0, 0, ICON_DEST_WIDTH, ICON_DEST_HEIGHT), - source: Rect::new(0, 0, ICON_SRC_WIDTH, ICON_SRC_HEIGHT), - config, + inner: WidgetInner::new( + config, + Rect::new(0, 0, ICON_SRC_WIDTH, ICON_SRC_HEIGHT), + Rect::new(0, 0, ICON_DEST_WIDTH, ICON_DEST_HEIGHT), + ), } } - - pub fn render(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext) - where - C: CanvasAccess, - R: Renderer, - { - use std::borrow::*; - let mut dest = match context { - &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest.clone(), - }; - - let mut clipping = dest.clone(); - clipping.set_width(clipping.width() + ICON_DEST_WIDTH); - clipping.set_height(clipping.height() + ICON_DEST_HEIGHT); - canvas.set_clipping(clipping); - let settings_texture_path = { - let c = self.config.read().unwrap(); - let mut themes_dir = c.directories().themes_dir.clone(); - let path = c.theme().images().settings_icon(); - themes_dir.push(path); - themes_dir.to_str().unwrap().to_owned() - }; - let maybe_tex = renderer.load_image(settings_texture_path.clone()); - if let Ok(texture) = maybe_tex { - dest.set_width(ICON_DEST_WIDTH); - dest.set_height(ICON_DEST_HEIGHT); - canvas - .render_image(texture, self.source.clone(), dest.clone()) - .unwrap_or_else(|_| panic!("Failed to draw directory entry texture")); - } - } - - pub fn prepare_ui<'l, T>(&mut self, _renderer: &mut T) - where - T: ConfigHolder + Renderer, - { - } - - pub fn source(&self) -> &Rect { - &self.source - } - - pub fn set_dest(&mut self, rect: &Rect) { - self.dest = rect.clone(); - } - - pub fn set_source(&mut self, rect: &Rect) { - self.source = rect.clone(); - } -} - -impl Update for SettingsButton { - fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - UR::NoOp - } -} - -impl ClickHandler for SettingsButton { - fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UR { - UR::OpenSettings - } - - fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool { - match *context { - UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest, - } - .contains_point(point.clone()) - } -} - -impl RenderBox for SettingsButton { - fn render_start_point(&self) -> Point { - self.dest.top_left() - } - - fn dest(&self) -> Rect { - self.dest - } } diff --git a/rider-editor/src/ui/file_editor/mod.rs b/rider-editor/src/ui/file_editor/mod.rs index 99784b2..c59f398 100644 --- a/rider-editor/src/ui/file_editor/mod.rs +++ b/rider-editor/src/ui/file_editor/mod.rs @@ -9,7 +9,7 @@ use crate::ui::file::TextCollection; use crate::ui::file::TextWidget; use crate::ui::scroll_bar::horizontal_scroll_bar::*; use crate::ui::scroll_bar::vertical_scroll_bar::*; -use crate::ui::scroll_bar::Scroll; +use crate::ui::scroll_bar::ScrollWidget; use crate::ui::text_character::CharacterSizeManager; use crate::ui::CanvasAccess; use crate::ui::ClickHandler; @@ -175,8 +175,8 @@ impl FileAccess for FileEditor { if let Some(f) = self.file.as_ref() { self.full_rect = f.full_rect(); } - self.vertical_scroll_bar.set_location(0); - self.horizontal_scroll_bar.set_location(0); + self.vertical_scroll_bar.reset(); + self.horizontal_scroll_bar.reset(); file } diff --git a/rider-editor/src/ui/menu_bar.rs b/rider-editor/src/ui/menu_bar.rs index ab15b0a..1184654 100644 --- a/rider-editor/src/ui/menu_bar.rs +++ b/rider-editor/src/ui/menu_bar.rs @@ -71,15 +71,21 @@ impl MenuBar { ) .unwrap_or_else(|_| panic!("Failed to draw main menu background")); - let context = RenderContext::ParentPosition( - relative_position.offset(SAVE_BUTTON_OFFSET_LEFT, SAVE_BUTTON_OFFSET_TOP), + self.save_button.render( + canvas, + renderer, + &RenderContext::ParentPosition( + relative_position.offset(SAVE_BUTTON_OFFSET_LEFT, SAVE_BUTTON_OFFSET_TOP), + ), ); - self.save_button.render(canvas, renderer, &context); - let context = RenderContext::ParentPosition( - relative_position.offset(SAVE_BUTTON_OFFSET_LEFT * 2, SAVE_BUTTON_OFFSET_TOP), + self.settings_button.render( + canvas, + renderer, + &RenderContext::ParentPosition( + relative_position.offset(SAVE_BUTTON_OFFSET_LEFT * 2, SAVE_BUTTON_OFFSET_TOP), + ), ); - self.settings_button.render(canvas, renderer, &context); } pub fn prepare_ui(&mut self) { diff --git a/rider-editor/src/ui/mod.rs b/rider-editor/src/ui/mod.rs index efc9d1d..9d536e5 100644 --- a/rider-editor/src/ui/mod.rs +++ b/rider-editor/src/ui/mod.rs @@ -4,7 +4,7 @@ use sdl2::render::Texture; use std::rc::Rc; use crate::app::application::WindowCanvas; -use crate::app::UpdateResult as UR; +use crate::app::{UpdateResult as UR, UpdateResult}; use crate::renderer::managers::*; use rider_config::*; @@ -31,6 +31,7 @@ pub use self::modal::*; pub use self::project_tree::*; pub use self::scroll_bar::*; pub use self::text_character::*; +use crate::renderer::Renderer; #[derive(Debug)] pub enum UpdateContext<'l> { @@ -140,6 +141,100 @@ pub trait RenderBox { fn dest(&self) -> Rect; } +pub struct WidgetInner { + source: Rect, + dest: Rect, + config: ConfigAccess, +} + +impl WidgetInner { + pub fn new(config: ConfigAccess, source: Rect, dest: Rect) -> Self { + Self { + dest, + source, + config, + } + } +} + +pub trait Widget { + fn texture_path(&self) -> Option; + + fn render(&self, canvas: &mut C, renderer: &mut R, context: &RenderContext) + where + C: CanvasAccess, + R: Renderer, + { + let mut dest = match context { + &RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest()), + _ => self.dest().clone(), + }; + + canvas.set_clipping(self.clipping(&dest)); + self.texture_path() + .and_then(|path| renderer.load_image(path).ok()) + .and_then(|texture| { + dest.set_width(self.dest().width()); + dest.set_height(self.dest().height()); + canvas + .render_image(texture.clone(), self.source().clone(), dest.clone()) + .unwrap_or_else(|_| panic!("Failed to draw widget texture")); + Some(()) + }); + } + + fn prepare_ui<'l, T>(&mut self, _renderer: &mut T) + where + T: ConfigHolder + Renderer, + { + } + + fn dest(&self) -> &Rect; + + fn set_dest(&mut self, rect: &Rect); + + fn source(&self) -> &Rect; + + fn set_source(&mut self, rect: &Rect); + + fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UpdateResult { + UpdateResult::NoOp + } + + fn on_left_click(&mut self, _point: &Point, _context: &UpdateContext) -> UpdateResult { + UpdateResult::NoOp + } + + fn is_left_click_target(&self, point: &Point, context: &UpdateContext) -> bool { + match *context { + UpdateContext::ParentPosition(p) => move_render_point(p.clone(), &self.dest()), + _ => self.dest().clone(), + } + .contains_point(point.clone()) + } + + fn render_start_point(&self) -> Point { + self.dest().top_left() + } + + fn clipping(&self, relative_dest: &Rect) -> Rect { + Rect::new( + relative_dest.x(), + relative_dest.y(), + relative_dest.width() + self.padding_width(), + relative_dest.height() + self.padding_height(), + ) + } + + fn padding_width(&self) -> u32 { + 0 + } + + fn padding_height(&self) -> u32 { + 0 + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rider-editor/src/ui/modal/open_file.rs b/rider-editor/src/ui/modal/open_file.rs index 4d55aa9..1481bd8 100644 --- a/rider-editor/src/ui/modal/open_file.rs +++ b/rider-editor/src/ui/modal/open_file.rs @@ -24,6 +24,30 @@ pub struct OpenFile { config: ConfigAccess, } +impl ScrollView for OpenFile { + fn mut_horizontal_scroll_handler(&mut self) -> Option<&mut HorizontalScrollBar> { + Some(&mut self.horizontal_scroll_bar) + } + + fn horizontal_scroll_handler(&self) -> Option<&HorizontalScrollBar> { + Some(&self.horizontal_scroll_bar) + } + + fn mut_vertical_scroll_handler(&mut self) -> Option<&mut VerticalScrollBar> { + Some(&mut self.vertical_scroll_bar) + } + + fn vertical_scroll_handler(&self) -> Option<&VerticalScrollBar> { + Some(&self.vertical_scroll_bar) + } +} + +impl ConfigHolder for OpenFile { + fn config(&self) -> &ConfigAccess { + &self.config + } +} + impl OpenFile { pub fn new(root_path: String, width: u32, height: u32, config: ConfigAccess) -> Self { let (window_width, window_height, background_color, border_color) = { @@ -79,35 +103,6 @@ impl OpenFile { &self.full_dest } - pub fn scroll_by(&mut self, x: i32, y: i32) { - let read_config = self.config.read().unwrap(); - - let value_x = read_config.scroll().speed() * x; - let value_y = read_config.scroll().speed() * y; - let old_x = self.horizontal_scroll_bar.scroll_value(); - let old_y = self.vertical_scroll_bar.scroll_value(); - - if value_x + old_x >= 0 { - self.horizontal_scroll_bar.scroll_to(value_x + old_x); - if self.horizontal_scroll_bar.scrolled_part() > 1.0 { - self.horizontal_scroll_bar.scroll_to(old_x); - } - } - if value_y + old_y >= 0 { - self.vertical_scroll_bar.scroll_to(value_y + old_y); - if self.vertical_scroll_bar.scrolled_part() > 1.0 { - self.vertical_scroll_bar.scroll_to(old_y); - } - } - } - - pub fn scroll(&self) -> Point { - Point::new( - -self.horizontal_scroll_bar.scroll_value(), - -self.vertical_scroll_bar.scroll_value(), - ) - } - pub fn update(&mut self, ticks: i32, context: &UC) -> UR { let (window_width, window_height, color, scroll_width, scroll_margin) = { let c = self.config.read().unwrap(); @@ -218,8 +213,8 @@ impl OpenFile { pub fn is_left_click_target(&self, point: &Point, context: &UC) -> bool { let dest = match context { - UC::ParentPosition(p) => move_render_point(p.clone(), &self.dest), - _ => self.dest.clone(), + UC::ParentPosition(p) => move_render_point(p.clone(), &self.dest()), + _ => self.dest().clone(), }; let p = dest.top_left() + Point::new(CONTENT_MARGIN_LEFT, CONTENT_MARGIN_TOP) + self.scroll(); @@ -248,7 +243,7 @@ mod tests { let config = build_config(); let mut widget = OpenFile::new("/tmp".to_owned(), 100, 100, config); widget.scroll_by(12, 13); - assert_eq!(widget.scroll(), Point::new(0, -390)); + assert_eq!(widget.scroll(), Point::new(-360, -390)); } //####################################################################### diff --git a/rider-editor/src/ui/project_tree/mod.rs b/rider-editor/src/ui/project_tree/mod.rs index 2352663..cde8b1e 100644 --- a/rider-editor/src/ui/project_tree/mod.rs +++ b/rider-editor/src/ui/project_tree/mod.rs @@ -311,7 +311,7 @@ mod tests { let mut widget = ProjectTreeSidebar::new("/tmp".to_owned(), config); widget.scroll_by(10, 10); let res = widget.scroll(); - let expected = Point::new(0, -300); + let expected = Point::new(-300, -300); assert_eq!(res, expected); } diff --git a/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs b/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs index cbd3fb7..4a2ee52 100644 --- a/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs +++ b/rider-editor/src/ui/scroll_bar/horizontal_scroll_bar.rs @@ -1,7 +1,5 @@ -use crate::app::UpdateResult as UR; use crate::ui::*; use rider_config::ConfigAccess; -use sdl2::pixels::Color; use std::ops::{Deref, DerefMut}; pub struct HorizontalScrollBar { @@ -22,6 +20,7 @@ impl DerefMut for HorizontalScrollBar { } } +#[cfg_attr(tarpaulin, skip)] impl HorizontalScrollBar { pub fn new(config: ConfigAccess) -> Self { Self { @@ -30,70 +29,55 @@ impl HorizontalScrollBar { } } -impl Update for HorizontalScrollBar { - fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - if self.full < self.viewport { - return UR::NoOp; - } - let ratio = self.full as f64 / self.viewport as f64; - let width = (self.viewport as f64 / ratio) as u32; - self.rect.set_width(width); - let x = (self.viewport - self.rect.width()) as f64 - * (self.scroll_value().abs() as f64 / (self.full - self.viewport) as f64); - self.rect.set_x(x as i32); - - UR::NoOp +impl ScrollWidget for HorizontalScrollBar { + fn update_rect(&mut self, pos: i32, max: u32) { + self.mut_rect().set_width(max); + self.mut_rect().set_x(pos); } -} -#[cfg_attr(tarpaulin, skip)] -impl HorizontalScrollBar { - pub fn render(&self, canvas: &mut T, context: &RenderContext) - where - T: CanvasAccess, - { - if self.full < self.viewport { - return; - } - - canvas - .render_rect( - match context { - RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect), - _ => self.rect.clone(), - }, - Color::RGBA(255, 255, 255, 0), - ) - .unwrap_or_else(|_| panic!("Failed to render vertical scroll back")); - } -} - -impl Scroll for HorizontalScrollBar { + #[inline] fn scroll_to(&mut self, n: i32) { self.scroll_value = n; } + #[inline] fn scroll_value(&self) -> i32 { self.scroll_value } + #[inline] fn set_viewport(&mut self, n: u32) { self.viewport = n; } + #[inline] fn set_full_size(&mut self, n: u32) { self.full = n; } + #[inline] fn set_location(&mut self, n: i32) { self.rect.set_y(n); } - fn scrolled_part(&self) -> f64 { - if self.full < self.viewport() { - return 1.0; - } - self.scroll_value().abs() as f64 / (self.full - self.viewport()) as f64 + #[inline] + fn viewport(&self) -> u32 { + self.viewport + } + + #[inline] + fn full(&self) -> u32 { + self.full + } + + #[inline] + fn rect(&self) -> &sdl2::rect::Rect { + &self.rect + } + + #[inline] + fn mut_rect(&mut self) -> &mut sdl2::rect::Rect { + &mut self.rect } } @@ -104,7 +88,7 @@ mod test_update { use std::sync::*; impl HorizontalScrollBar { - pub fn rect_mut(&mut self) -> &mut Rect { + pub fn rect_mut(&mut self) -> &mut sdl2::rect::Rect { &mut self.rect } } diff --git a/rider-editor/src/ui/scroll_bar/mod.rs b/rider-editor/src/ui/scroll_bar/mod.rs index 9f1800c..c063bd2 100644 --- a/rider-editor/src/ui/scroll_bar/mod.rs +++ b/rider-editor/src/ui/scroll_bar/mod.rs @@ -1,16 +1,19 @@ use sdl2::rect::{Point, Rect}; +use crate::app::UpdateResult; pub use crate::ui::scroll_bar::horizontal_scroll_bar::HorizontalScrollBar; pub use crate::ui::scroll_bar::vertical_scroll_bar::VerticalScrollBar; +use crate::ui::{move_render_point, CanvasAccess, RenderContext, UpdateContext}; use rider_config::{ConfigAccess, ConfigHolder}; +use sdl2::pixels::Color; pub mod horizontal_scroll_bar; pub mod vertical_scroll_bar; pub trait ScrollView: ConfigHolder where - VS: Scroll, - HS: Scroll, + VS: ScrollWidget, + HS: ScrollWidget, { fn scroll_by(&mut self, x: i32, y: i32) { let speed = self.config().read().unwrap().scroll().speed(); @@ -70,7 +73,39 @@ where fn vertical_scroll_handler(&self) -> Option<&VS>; } -pub trait Scroll { +pub trait ScrollWidget { + fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UpdateResult { + if self.full() < self.viewport() { + return UpdateResult::NoOp; + } + let max = (self.viewport() as f64 / self.ratio()) as u32; + let pos = (self.viewport() - max) as f64 * self.scrolled_part(); + self.update_rect(pos as i32, max); + + UpdateResult::NoOp + } + + fn render(&self, canvas: &mut T, context: &RenderContext) + where + T: CanvasAccess, + { + if self.full() < self.viewport() { + return; + } + + canvas + .render_border( + match context { + RenderContext::ParentPosition(p) => move_render_point(p.clone(), self.rect()), + _ => self.rect().clone(), + }, + Color::RGBA(255, 255, 255, 0), + ) + .unwrap_or_else(|_| panic!("Failed to render vertical scroll back")); + } + + fn update_rect(&mut self, pos: i32, max: u32); + fn scroll_to(&mut self, n: i32); fn scroll_value(&self) -> i32; @@ -81,7 +116,31 @@ pub trait Scroll { fn set_location(&mut self, n: i32); - fn scrolled_part(&self) -> f64; + #[inline] + fn scrolled_part(&self) -> f64 { + if self.full() <= self.viewport() { + return 1.0; + } + self.scroll_value().abs() as f64 / (self.full() - self.viewport()) as f64 + } + + fn viewport(&self) -> u32; + + fn full(&self) -> u32; + + fn rect(&self) -> &Rect; + + fn mut_rect(&mut self) -> &mut Rect; + + fn ratio(&self) -> f64 { + self.full() as f64 / self.viewport() as f64 + } + + fn reset(&mut self) { + self.update_rect(0, 0); + self.set_full_size(0); + self.scroll_to(0); + } } pub struct ScrollBar { @@ -101,19 +160,4 @@ impl ScrollBar { rect: Rect::new(0, 0, width, 0), } } - - #[inline] - pub fn viewport(&self) -> u32 { - self.viewport - } - - #[inline] - pub fn full(&self) -> u32 { - self.full - } - - #[inline] - pub fn rect(&self) -> &Rect { - &self.rect - } } diff --git a/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs b/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs index 7f0bd4b..ef1cfa5 100644 --- a/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs +++ b/rider-editor/src/ui/scroll_bar/vertical_scroll_bar.rs @@ -1,7 +1,5 @@ -use crate::app::UpdateResult as UR; use crate::ui::*; use rider_config::ConfigAccess; -use sdl2::pixels::Color; use std::ops::{Deref, DerefMut}; pub struct VerticalScrollBar { @@ -22,6 +20,7 @@ impl DerefMut for VerticalScrollBar { } } +#[cfg_attr(tarpaulin, skip)] impl VerticalScrollBar { pub fn new(config: ConfigAccess) -> Self { Self { @@ -30,69 +29,55 @@ impl VerticalScrollBar { } } -impl Update for VerticalScrollBar { - fn update(&mut self, _ticks: i32, _context: &UpdateContext) -> UR { - if self.full < self.viewport() { - return UR::NoOp; - } - let ratio = self.full as f64 / self.viewport() as f64; - let height = (self.viewport() as f64 / ratio) as u32; - self.rect.set_height(height); - let y = (self.viewport() - self.rect.height()) as f64 * self.scrolled_part(); - self.rect.set_y(y as i32); - - UR::NoOp +impl ScrollWidget for VerticalScrollBar { + fn update_rect(&mut self, pos: i32, max: u32) { + self.mut_rect().set_height(max); + self.mut_rect().set_y(pos); } -} -#[cfg_attr(tarpaulin, skip)] -impl VerticalScrollBar { - pub fn render(&self, canvas: &mut T, context: &RenderContext) - where - T: CanvasAccess, - { - if self.full < self.viewport() { - return; - } - - canvas - .render_border( - match context { - RenderContext::ParentPosition(p) => move_render_point(p.clone(), &self.rect), - _ => self.rect.clone(), - }, - Color::RGBA(255, 255, 255, 0), - ) - .unwrap_or_else(|_| panic!("Failed to render vertical scroll back")); - } -} - -impl Scroll for VerticalScrollBar { + #[inline] fn scroll_to(&mut self, n: i32) { self.scroll_value = n; } + #[inline] fn scroll_value(&self) -> i32 { self.scroll_value } + #[inline] fn set_viewport(&mut self, n: u32) { self.viewport = n; } + #[inline] fn set_full_size(&mut self, n: u32) { self.full = n; } + #[inline] fn set_location(&mut self, n: i32) { self.rect.set_x(n); } - fn scrolled_part(&self) -> f64 { - if self.full <= self.viewport() { - return 1.0; - } - self.scroll_value().abs() as f64 / (self.full - self.viewport()) as f64 + #[inline] + fn viewport(&self) -> u32 { + self.viewport + } + + #[inline] + fn full(&self) -> u32 { + self.full + } + + #[inline] + fn rect(&self) -> &sdl2::rect::Rect { + &self.rect + } + + #[inline] + fn mut_rect(&mut self) -> &mut sdl2::rect::Rect { + &mut self.rect } } diff --git a/rider-themes/src/code_highlighting_color.rs b/rider-themes/src/code_highlighting_color.rs index 2ed1761..0966353 100644 --- a/rider-themes/src/code_highlighting_color.rs +++ b/rider-themes/src/code_highlighting_color.rs @@ -269,5 +269,4 @@ mod tests { let expected = ThemeConfig::new(SerdeColor::new(0, 0, 0, 0), false, false); assert_eq!(result, expected); } - }