11use crate :: {
22 components:: {
3- dialog_paragraph, utils:: time_to_string, CommandBlocking ,
4- CommandInfo , Component , DrawableComponent , EventState ,
5- ScrollType ,
3+ dialog_paragraph,
4+ utils:: { scroll_vertical:: VerticalScroll , time_to_string} ,
5+ CommandBlocking , CommandInfo , Component , DrawableComponent ,
6+ EventState , ScrollType ,
67 } ,
78 keys:: SharedKeyConfig ,
89 strings:: { self , order} ,
9- ui:: { self , style:: SharedTheme } ,
10+ ui:: style:: SharedTheme ,
1011} ;
1112use anyhow:: Result ;
1213use asyncgit:: {
@@ -37,10 +38,9 @@ pub struct DetailsComponent {
3738 tags : Vec < String > ,
3839 theme : SharedTheme ,
3940 focused : bool ,
40- current_size : Cell < ( u16 , u16 ) > ,
41- scroll_top : Cell < usize > ,
41+ current_width : Cell < u16 > ,
42+ scroll : VerticalScroll ,
4243 key_config : SharedKeyConfig ,
43- scroll_to_bottom_on_redraw : Cell < bool > ,
4444}
4545
4646type WrappedCommitMessage < ' a > =
@@ -58,9 +58,8 @@ impl DetailsComponent {
5858 tags : Vec :: new ( ) ,
5959 theme,
6060 focused,
61- current_size : Cell :: new ( ( 0 , 0 ) ) ,
62- scroll_top : Cell :: new ( 0 ) ,
63- scroll_to_bottom_on_redraw : Cell :: new ( false ) ,
61+ current_width : Cell :: new ( 0 ) ,
62+ scroll : VerticalScroll :: new ( ) ,
6463 key_config,
6564 }
6665 }
@@ -75,7 +74,7 @@ impl DetailsComponent {
7574 self . data =
7675 id. and_then ( |id| sync:: get_commit_details ( CWD , id) . ok ( ) ) ;
7776
78- self . scroll_top . set ( 0 ) ;
77+ self . scroll . reset ( ) ;
7978
8079 if let Some ( tags) = tags {
8180 self . tags . extend ( tags) ;
@@ -141,7 +140,7 @@ impl DetailsComponent {
141140 . concat ( )
142141 . iter ( )
143142 . enumerate ( )
144- . skip ( self . scroll_top . get ( ) )
143+ . skip ( self . scroll . get ( ) )
145144 . take ( height)
146145 . map ( |( i, line) | {
147146 Spans :: from ( vec ! [ Span :: styled(
@@ -275,34 +274,10 @@ impl DetailsComponent {
275274
276275 fn move_scroll_top ( & mut self , move_type : ScrollType ) -> bool {
277276 if self . data . is_some ( ) {
278- let old = self . scroll_top . get ( ) ;
279- let width = self . current_size . get ( ) . 0 as usize ;
280- let height = self . current_size . get ( ) . 1 as usize ;
281-
282- let number_of_lines =
283- Self :: get_number_of_lines ( & self . data , width) ;
284-
285- let max = number_of_lines. saturating_sub ( height) as usize ;
286-
287- let new_scroll_top = match move_type {
288- ScrollType :: Down => old. saturating_add ( 1 ) ,
289- ScrollType :: Up => old. saturating_sub ( 1 ) ,
290- ScrollType :: Home => 0 ,
291- ScrollType :: End => max,
292- _ => old,
293- } ;
294-
295- let new_scroll_top = new_scroll_top. clamp ( 0 , max) ;
296-
297- if new_scroll_top == old {
298- return false ;
299- }
300-
301- self . scroll_top . set ( new_scroll_top) ;
302-
303- return true ;
277+ self . scroll . move_top ( move_type)
278+ } else {
279+ false
304280 }
305- false
306281 }
307282}
308283
@@ -312,6 +287,9 @@ impl DrawableComponent for DetailsComponent {
312287 f : & mut Frame < B > ,
313288 rect : Rect ,
314289 ) -> Result < ( ) > {
290+ const CANSCROLL_STRING : & str = "[\u{2026} ]" ;
291+ const EMPTY_STRING : & str = "" ;
292+
315293 let chunks = Layout :: default ( )
316294 . direction ( Direction :: Vertical )
317295 . constraints (
@@ -338,28 +316,35 @@ impl DrawableComponent for DetailsComponent {
338316 let width = chunks[ 1 ] . width . saturating_sub ( border_width) ;
339317 let height = chunks[ 1 ] . height . saturating_sub ( border_width) ;
340318
341- self . current_size . set ( ( width, height) ) ;
342-
343- if self . scroll_to_bottom_on_redraw . get ( ) {
344- self . scroll_top . set (
345- Self :: get_number_of_lines (
346- & self . data ,
347- usize:: from ( width) ,
348- )
349- . saturating_sub ( usize:: from ( height) ) ,
350- ) ;
351- self . scroll_to_bottom_on_redraw . set ( false ) ;
352- }
319+ self . current_width . set ( width) ;
353320
354321 let wrapped_lines = self . get_wrapped_text_message (
355322 width as usize ,
356323 height as usize ,
357324 ) ;
358325
326+ let number_of_lines =
327+ Self :: get_number_of_lines ( & self . data , usize:: from ( width) ) ;
328+
329+ self . scroll . update_no_selection (
330+ number_of_lines,
331+ usize:: from ( height) ,
332+ ) ;
333+
334+ let can_scroll = usize:: from ( height) < number_of_lines;
335+
359336 f. render_widget (
360337 dialog_paragraph (
361- & strings:: commit:: details_message_title (
362- & self . key_config ,
338+ & format ! (
339+ "{} {}" ,
340+ strings:: commit:: details_message_title(
341+ & self . key_config,
342+ ) ,
343+ if !self . focused && can_scroll {
344+ CANSCROLL_STRING
345+ } else {
346+ EMPTY_STRING
347+ }
363348 ) ,
364349 Text :: from ( wrapped_lines) ,
365350 & self . theme ,
@@ -369,13 +354,7 @@ impl DrawableComponent for DetailsComponent {
369354 ) ;
370355
371356 if self . focused {
372- ui:: draw_scrollbar (
373- f,
374- chunks[ 1 ] ,
375- & self . theme ,
376- Self :: get_number_of_lines ( & self . data , width as usize ) ,
377- self . scroll_top . get ( ) ,
378- ) ;
357+ self . scroll . draw ( f, chunks[ 1 ] , & self . theme ) ;
379358 }
380359
381360 Ok ( ( ) )
@@ -388,9 +367,7 @@ impl Component for DetailsComponent {
388367 out : & mut Vec < CommandInfo > ,
389368 force_all : bool ,
390369 ) -> CommandBlocking {
391- // visibility_blocking(self)
392-
393- let width = self . current_size . get ( ) . 0 as usize ;
370+ let width = usize:: from ( self . current_width . get ( ) ) ;
394371 let number_of_lines =
395372 Self :: get_number_of_lines ( & self . data , width) ;
396373
@@ -437,10 +414,6 @@ impl Component for DetailsComponent {
437414 }
438415
439416 fn focus ( & mut self , focus : bool ) {
440- if focus {
441- self . scroll_to_bottom_on_redraw . set ( true ) ;
442- }
443-
444417 self . focused = focus;
445418 }
446419}
0 commit comments