@ -1,3 +1,6 @@
use std ::collections ::VecDeque ;
use std ::iter ;
use skulpin ::skia_safe ::canvas ::{ SaveLayerRec , SrcRectConstraint } ;
use skulpin ::skia_safe ::gpu ::SurfaceOrigin ;
use skulpin ::skia_safe ::{
@ -11,14 +14,10 @@ use crate::redraw_scheduler::REDRAW_SCHEDULER;
fn build_window_surface (
parent_canvas : & mut Canvas ,
renderer : & Renderer ,
grid_width : u64 ,
grid_height : u64 ,
pixel_width : i32 ,
pixel_height : i32 ,
) -> Surface {
let dimensions = (
( grid_width as f32 * renderer . font_width ) as i32 ,
( grid_height as f32 * renderer . font_height ) as i32 ,
) ;
let dimensions = ( pixel_width , pixel_height ) ;
let mut context = parent_canvas . gpu_context ( ) . unwrap ( ) ;
let budgeted = Budgeted ::Yes ;
let parent_image_info = parent_canvas . image_info ( ) ;
@ -41,29 +40,84 @@ fn build_window_surface(
. expect ( "Could not create surface" )
}
fn build_window_surface_with_grid_size (
parent_canvas : & mut Canvas ,
renderer : & Renderer ,
grid_width : u64 ,
grid_height : u64 ,
) -> Surface {
let pixel_width = ( grid_width as f32 * renderer . font_width ) as i32 ;
let pixel_height = ( grid_height as f32 * renderer . font_height ) as i32 ;
build_window_surface ( parent_canvas , pixel_width , pixel_height )
}
fn build_background_window_surface (
parent_canvas : & mut Canvas ,
renderer : & Renderer ,
grid_width : u64 ,
grid_height : u64 ,
) -> Surface {
let mut surface = build_window_surface ( parent_canvas , renderer , grid_width , grid_height ) ;
let mut surface =
build_window_surface_with_grid_size ( parent_canvas , renderer , grid_width , grid_height ) ;
let canvas = surface . canvas ( ) ;
canvas . clear (
renderer
. default_style
. colors
. background
. clone ( )
. unwrap ( )
. to_color ( ) ,
) ;
canvas . clear ( renderer . get_default_background ( ) ) ;
surface
}
fn clone_window_surface ( surface : & mut Surface ) -> Surface {
let snapshot = surface . image_snapshot ( ) ;
let mut canvas = surface . canvas ( ) ;
let mut new_surface = build_window_surface ( & mut canvas , snapshot . width ( ) , snapshot . height ( ) ) ;
let new_canvas = new_surface . canvas ( ) ;
new_canvas . draw_image ( snapshot , ( 0.0 , 0.0 ) , None ) ;
new_surface
}
pub struct SurfacePair {
background : Surface ,
foreground : Surface ,
pub top_line : f32 ,
bottom_line : f32 ,
}
impl SurfacePair {
fn new (
parent_canvas : & mut Canvas ,
renderer : & Renderer ,
grid_width : u64 ,
grid_height : u64 ,
top_line : f32 ,
bottom_line : f32 ,
) -> SurfacePair {
let background =
build_background_window_surface ( parent_canvas , renderer , grid_width , grid_height ) ;
let foreground =
build_window_surface_with_grid_size ( parent_canvas , renderer , grid_width , grid_height ) ;
SurfacePair {
background ,
foreground ,
top_line ,
bottom_line ,
}
}
fn clone ( & mut self ) -> SurfacePair {
let new_background = clone_window_surface ( & mut self . background ) ;
let new_foreground = clone_window_surface ( & mut self . foreground ) ;
SurfacePair {
background : new_background ,
foreground : new_foreground ,
top_line : self . top_line ,
bottom_line : self . bottom_line ,
}
}
}
pub struct RenderedWindow {
background_surface : Surface ,
foreground_surface : Surface ,
old_surfaces : VecDeque < SurfacePair > ,
pub current_surfaces : SurfacePair ,
pub id : u64 ,
pub hidden : bool ,
pub floating : bool ,
@ -72,9 +126,14 @@ pub struct RenderedWindow {
grid_height : u64 ,
grid_start_position : Point ,
grid_current_position : Point ,
pub grid_current_position : Point ,
grid_destination : Point ,
t : f32 ,
position_t : f32 ,
start_scroll : f32 ,
pub current_scroll : f32 ,
scroll_destination : f32 ,
scroll_t : f32 ,
}
pub struct WindowDrawDetails {
@ -92,14 +151,12 @@ impl RenderedWindow {
grid_width : u64 ,
grid_height : u64 ,
) -> RenderedWindow {
let background_surface =
build_background_window_surface ( parent_canvas , renderer , grid_width , grid_height ) ;
let foreground_surface =
build_window_surface ( parent_canvas , renderer , grid_width , grid_height ) ;
let current_surfaces =
SurfacePair ::new ( parent_canvas , renderer , grid_width , grid_height , 0.0 , 0.0 ) ;
RenderedWindow {
background_surface ,
foreground_surface ,
old_surfaces: VecDeque ::new ( ) ,
current_surfaces ,
id ,
hidden : false ,
floating : false ,
@ -110,7 +167,12 @@ impl RenderedWindow {
grid_start_position : grid_position ,
grid_current_position : grid_position ,
grid_destination : grid_position ,
t : 2.0 , // 2.0 is out of the 0.0 to 1.0 range and stops animation
position_t : 2.0 , // 2.0 is out of the 0.0 to 1.0 range and stops animation
start_scroll : 0.0 ,
current_scroll : 0.0 ,
scroll_destination : 0.0 ,
scroll_t : 2.0 , // 2.0 is out of the 0.0 to 1.0 range and stops animation
}
}
@ -127,31 +189,52 @@ impl RenderedWindow {
}
pub fn update ( & mut self , settings : & RendererSettings , dt : f32 ) -> bool {
if ( self . t - 1.0 ) . abs ( ) < std ::f32 ::EPSILON {
return false ;
}
let mut animating = false ;
if ( self . t - 1.0 ) . abs ( ) < std ::f32 ::EPSILON {
{
if ( self . position_t - 1.0 ) . abs ( ) < std ::f32 ::EPSILON {
// We are at destination, move t out of 0-1 range to stop the animation
self . t = 2.0 ;
self . position_ t = 2.0 ;
} else {
self . t = ( self . t + dt / settings . animation_length ) . min ( 1.0 ) ;
animating = true ;
self . position_t =
( self . position_t + dt / settings . position_animation_length ) . min ( 1.0 ) ;
}
self . grid_current_position = ease_point (
ease_out_expo ,
self . grid_start_position ,
self . grid_destination ,
self . t ,
self . position_t ,
) ;
}
{
if ( self . scroll_t - 1.0 ) . abs ( ) < std ::f32 ::EPSILON {
// We are at destination, move t out of 0-1 range to stop the animation
self . scroll_t = 2.0 ;
self . old_surfaces . clear ( ) ;
} else {
animating = true ;
self . scroll_t = ( self . scroll_t + dt / settings . scroll_animation_length ) . min ( 1.0 ) ;
}
self . current_scroll = ease (
ease_out_expo ,
self . start_scroll ,
self . scroll_destination ,
self . scroll_t ,
) ;
}
true
animating
}
pub fn draw (
& mut self ,
root_canvas : & mut Canvas ,
settings : & RendererSettings ,
default_background : Color ,
font_width : f32 ,
font_height : f32 ,
dt : f32 ,
@ -163,7 +246,6 @@ impl RenderedWindow {
let pixel_region = self . pixel_region ( font_width , font_height ) ;
root_canvas . save ( ) ;
root_canvas . clip_rect ( & pixel_region , None , Some ( false ) ) ;
if self . floating & & settings . floating_blur {
@ -176,26 +258,55 @@ impl RenderedWindow {
}
let mut paint = Paint ::default ( ) ;
// We want each surface to overwrite the one underneath and will use layers to ensure
// only lower priority surfaces will get clobbered and not the underlying windows
paint . set_blend_mode ( BlendMode ::Src ) ;
{
// Save layer so that setting the blend mode doesn't effect the blur
root_canvas . save_layer ( & SaveLayerRec ::default ( ) ) ;
let mut a = 255 ;
if self . floating {
let a = ( settings . floating_opacity . min ( 1.0 ) . max ( 0.0 ) * 255.0 ) as u8 ;
paint . set_color ( Color ::from_argb ( a , 255 , 255 , 255 ) ) ;
a = ( settings . floating_opacity . min ( 1.0 ) . max ( 0.0 ) * 255.0 ) as u8 ;
}
self . background_surface . draw (
paint . set_color ( default_background . with_a ( a ) ) ;
root_canvas . draw_rect ( pixel_region , & paint ) ;
paint . set_color ( Color ::from_argb ( a , 255 , 255 , 255 ) ) ;
for surface_pair in iter ::once ( & mut self . current_surfaces )
. chain ( self . old_surfaces . iter_mut ( ) )
. rev ( )
{
let scroll_offset =
surface_pair . top_line * font_height - self . current_scroll * font_height ;
surface_pair . background . draw (
root_canvas . as_mut ( ) ,
( pixel_region . left ( ) , pixel_region . top ( ) ) ,
( pixel_region . left ( ) , pixel_region . top ( ) + scroll_offset ) ,
Some ( & paint ) ,
) ;
}
root_canvas . restore ( ) ;
}
let mut paint = Paint ::default ( ) ;
paint . set_blend_mode ( BlendMode ::SrcOver ) ;
self . foreground_surface . draw (
{
// Save layer so that text may safely overwrite images underneath
root_canvas . save_layer ( & SaveLayerRec ::default ( ) ) ;
for surface_pair in iter ::once ( & mut self . current_surfaces )
. chain ( self . old_surfaces . iter_mut ( ) )
. rev ( )
{
let scroll_offset =
surface_pair . top_line * font_height - self . current_scroll * font_height ;
surface_pair . foreground . draw (
root_canvas . as_mut ( ) ,
( pixel_region . left ( ) , pixel_region . top ( ) ) ,
( pixel_region . left ( ) , pixel_region . top ( ) + scroll_offset ) ,
Some ( & paint ) ,
) ;
}
root_canvas . restore ( ) ;
}
if self . floating {
root_canvas . restore ( ) ;
@ -229,13 +340,13 @@ impl RenderedWindow {
if self . grid_start_position . x . abs ( ) > f32 ::EPSILON
| | self . grid_start_position . y . abs ( ) > f32 ::EPSILON
{
self . t = 0.0 ; // Reset animation as we have a new destination.
self . position_ t = 0.0 ; // Reset animation as we have a new destination.
self . grid_start_position = self . grid_current_position ;
self . grid_destination = new_destination ;
} else {
// We don't want to animate since the window is animating out of the start location,
// so we set t to 2.0 to stop animations.
self . t = 2.0 ;
self . position_ t = 2.0 ;
self . grid_start_position = new_destination ;
self . grid_destination = new_destination ;
}
@ -243,25 +354,33 @@ impl RenderedWindow {
if grid_width ! = self . grid_width | | grid_height ! = self . grid_height {
{
let mut old_background = self . background_surface ;
self . background_surface = build_background_window_surface (
let mut old_background = self . current_surfaces. background ;
self . current_surfaces. background = build_background_window_surface (
old_background . canvas ( ) ,
& renderer ,
grid_width ,
grid_height ,
) ;
old_background . draw ( self . background_surface . canvas ( ) , ( 0.0 , 0.0 ) , None ) ;
old_background . draw (
self . current_surfaces . background . canvas ( ) ,
( 0.0 , 0.0 ) ,
None ,
) ;
}
{
let mut old_foreground = self . foreground_surface ;
self . foreground_surface = build_window_surfac e(
let mut old_foreground = self . current_surfaces. foreground ;
self . current_surfaces. foreground = build_window_surfac e_with_grid_siz e(
old_foreground . canvas ( ) ,
& renderer ,
grid_width ,
grid_height ,
) ;
old_foreground . draw ( self . foreground_surface . canvas ( ) , ( 0.0 , 0.0 ) , None ) ;
old_foreground . draw (
self . current_surfaces . foreground . canvas ( ) ,
( 0.0 , 0.0 ) ,
None ,
) ;
}
self . grid_width = grid_width ;
@ -272,7 +391,7 @@ impl RenderedWindow {
if self . hidden {
self . hidden = false ;
self . t = 2.0 ; // We don't want to animate since the window is becoming visible, so we set t to 2.0 to stop animations.
self . position_ t = 2.0 ; // We don't want to animate since the window is becoming visible, so we set t to 2.0 to stop animations.
self . grid_start_position = new_destination ;
self . grid_destination = new_destination ;
}
@ -287,7 +406,7 @@ impl RenderedWindow {
let grid_position = ( window_left , window_top ) ;
{
let mut background_canvas = self . background_surface . canvas ( ) ;
let mut background_canvas = self . current_surfaces. background . canvas ( ) ;
renderer . draw_background (
& mut background_canvas ,
grid_position ,
@ -297,7 +416,7 @@ impl RenderedWindow {
}
{
let mut foreground_canvas = self . foreground_surface . canvas ( ) ;
let mut foreground_canvas = self . current_surfaces. foreground . canvas ( ) ;
renderer . draw_foreground (
& mut foreground_canvas ,
& text ,
@ -323,8 +442,8 @@ impl RenderedWindow {
) ;
{
let background_snapshot = self . background_surface . image_snapshot ( ) ;
let background_canvas = self . background_surface . canvas ( ) ;
let background_snapshot = self . current_surfaces. background . image_snapshot ( ) ;
let background_canvas = self . current_surfaces. background . canvas ( ) ;
background_canvas . save ( ) ;
background_canvas . clip_rect ( scrolled_region , None , Some ( false ) ) ;
@ -346,8 +465,8 @@ impl RenderedWindow {
}
{
let foreground_snapshot = self . foreground_surface . image_snapshot ( ) ;
let foreground_canvas = self . foreground_surface . canvas ( ) ;
let foreground_snapshot = self . current_surfaces. foreground . image_snapshot ( ) ;
let foreground_canvas = self . current_surfaces. foreground . canvas ( ) ;
foreground_canvas . save ( ) ;
foreground_canvas . clip_rect ( scrolled_region , None , Some ( false ) ) ;
@ -369,16 +488,16 @@ impl RenderedWindow {
}
}
WindowDrawCommand ::Clear = > {
let background_canvas = self . background_surface . canvas ( ) ;
self . background_surface = build_background_window_surface (
let background_canvas = self . current_surfaces. background . canvas ( ) ;
self . current_surfaces. background = build_background_window_surface (
background_canvas ,
& renderer ,
self . grid_width ,
self . grid_height ,
) ;
let foreground_canvas = self . foreground_surface . canvas ( ) ;
self . foreground_surface = build_window_surfac e(
let foreground_canvas = self . current_surfaces. foreground . canvas ( ) ;
self . current_surfaces. foreground = build_window_surfac e_with_grid_siz e(
foreground_canvas ,
& renderer ,
self . grid_width ,
@ -388,11 +507,34 @@ impl RenderedWindow {
WindowDrawCommand ::Show = > {
if self . hidden {
self . hidden = false ;
self . t = 2.0 ; // We don't want to animate since the window is becoming visible, so we set t to 2.0 to stop animations.
self . position_ t = 2.0 ; // We don't want to animate since the window is becoming visible, so we set t to 2.0 to stop animations.
self . grid_start_position = self . grid_destination ;
}
}
WindowDrawCommand ::Hide = > self . hidden = true ,
WindowDrawCommand ::Viewport {
top_line ,
bottom_line ,
} = > {
if ( self . current_surfaces . top_line - top_line as f32 ) . abs ( ) > std ::f32 ::EPSILON {
let mut new_surfaces = self . current_surfaces . clone ( ) ;
new_surfaces . top_line = top_line as f32 ;
new_surfaces . bottom_line = bottom_line as f32 ;
// Set new target viewport position and initialize animation timer
self . start_scroll = self . current_scroll ;
self . scroll_destination = top_line as f32 ;
self . scroll_t = 0.0 ;
let current_surfaces = self . current_surfaces ;
self . current_surfaces = new_surfaces ;
self . old_surfaces . push_back ( current_surfaces ) ;
if self . old_surfaces . len ( ) > 5 {
self . old_surfaces . pop_front ( ) ;
}
}
}
_ = > { }
} ;