@@ -118,8 +118,19 @@ impl StatefulWidget for ScrollView {
118
118
fn render ( self , area : Rect , buf : & mut Buffer , state : & mut Self :: State ) {
119
119
let ( mut x, mut y) = state. offset . into ( ) ;
120
120
// ensure that we don't scroll past the end of the buffer in either direction
121
- x = x. min ( self . buf . area . width . saturating_sub ( 1 ) ) ;
122
- y = y. min ( self . buf . area . height . saturating_sub ( 1 ) ) ;
121
+ let max_x_offset = self
122
+ . buf
123
+ . area
124
+ . width
125
+ . saturating_sub ( area. width . saturating_sub ( 1 ) ) ;
126
+ let max_y_offset = self
127
+ . buf
128
+ . area
129
+ . height
130
+ . saturating_sub ( area. height . saturating_sub ( 1 ) ) ;
131
+
132
+ x = x. min ( max_x_offset) ;
133
+ y = y. min ( max_y_offset) ;
123
134
state. offset = ( x, y) . into ( ) ;
124
135
state. size = Some ( self . size ) ;
125
136
state. page_size = Some ( area. into ( ) ) ;
@@ -135,6 +146,7 @@ impl ScrollView {
135
146
/// scrollbars
136
147
fn render_scrollbars ( & self , area : Rect , buf : & mut Buffer , state : & mut ScrollViewState ) -> Rect {
137
148
let size = self . size ;
149
+
138
150
let width = size. width . saturating_sub ( area. width ) ;
139
151
let height = size. height . saturating_sub ( area. height ) ;
140
152
match ( width, height) {
@@ -147,46 +159,48 @@ impl ScrollView {
147
159
// area is taller and narrower than the scroll_view
148
160
state. offset . y = 0 ;
149
161
self . render_horizontal_scrollbar ( area, buf, state) ;
150
- Rect :: new ( state. offset . x , 0 , area. width , area. height - 1 )
162
+ Rect :: new ( state. offset . x , 0 , area. width , area. height . saturating_sub ( 1 ) )
151
163
}
152
164
( 0 , _) if area. width > size. width => {
153
165
// area is wider and shorter than the scroll_view
154
166
state. offset . x = 0 ;
155
167
self . render_vertical_scrollbar ( area, buf, state) ;
156
- Rect :: new ( 0 , state. offset . y , area. width - 1 , area. height )
168
+ Rect :: new ( 0 , state. offset . y , area. width . saturating_sub ( 1 ) , area. height )
157
169
}
158
170
( _, _) => {
159
171
// scroll_view is both wider and taller than the area
160
172
let vertical_area = Rect {
161
- height : area. height - 1 ,
173
+ height : area. height . saturating_sub ( 1 ) ,
162
174
..area
163
175
} ;
164
176
let horizontal_area = Rect {
165
- width : area. width - 1 ,
177
+ width : area. width . saturating_sub ( 1 ) ,
166
178
..area
167
179
} ;
168
180
self . render_vertical_scrollbar ( vertical_area, buf, state) ;
169
181
self . render_horizontal_scrollbar ( horizontal_area, buf, state) ;
170
182
Rect :: new (
171
183
state. offset . x ,
172
184
state. offset . y ,
173
- area. width - 1 ,
174
- area. height - 1 ,
185
+ area. width . saturating_sub ( 1 ) ,
186
+ area. height . saturating_sub ( 1 ) ,
175
187
)
176
188
}
177
189
}
178
190
}
179
191
180
192
fn render_vertical_scrollbar ( & self , area : Rect , buf : & mut Buffer , state : & ScrollViewState ) {
193
+ let scrollbar_height = self . size . height . saturating_sub ( area. height ) ;
181
194
let mut scrollbar_state =
182
- ScrollbarState :: new ( self . size . height as usize ) . position ( state. offset . y as usize ) ;
195
+ ScrollbarState :: new ( scrollbar_height as usize ) . position ( state. offset . y as usize ) ;
183
196
let scrollbar = Scrollbar :: new ( ScrollbarOrientation :: VerticalRight ) ;
184
197
scrollbar. render ( area, buf, & mut scrollbar_state) ;
185
198
}
186
199
187
200
fn render_horizontal_scrollbar ( & self , area : Rect , buf : & mut Buffer , state : & ScrollViewState ) {
201
+ let scrollbar_width = self . size . width . saturating_sub ( area. width ) ;
188
202
let mut scrollbar_state =
189
- ScrollbarState :: new ( self . size . width as usize ) . position ( state. offset . x as usize ) ;
203
+ ScrollbarState :: new ( scrollbar_width as usize ) . position ( state. offset . x as usize ) ;
190
204
let scrollbar = Scrollbar :: new ( ScrollbarOrientation :: HorizontalBottom ) ;
191
205
scrollbar. render ( area, buf, & mut scrollbar_state) ;
192
206
}
@@ -246,10 +260,10 @@ mod tests {
246
260
Buffer :: with_lines( vec![
247
261
"ABCDE▲" ,
248
262
"KLMNO█" ,
249
- "UVWXY║ " ,
263
+ "UVWXY█ " ,
250
264
"EFGHI║" ,
251
265
"OPQRS▼" ,
252
- "◄█═ ═► " ,
266
+ "◄██ ═► " ,
253
267
] )
254
268
)
255
269
}
@@ -264,10 +278,10 @@ mod tests {
264
278
Buffer :: with_lines( vec![
265
279
"DEFGH▲" ,
266
280
"NOPQR█" ,
267
- "XYZAB║ " ,
281
+ "XYZAB█ " ,
268
282
"HIJKL║" ,
269
283
"RSTUV▼" ,
270
- "◄═█═ ► " ,
284
+ "◄═██ ► " ,
271
285
] )
272
286
)
273
287
}
@@ -283,9 +297,9 @@ mod tests {
283
297
"EFGHI▲" ,
284
298
"OPQRS║" ,
285
299
"YZABC█" ,
286
- "IJKLM║ " ,
300
+ "IJKLM█ " ,
287
301
"STUVW▼" ,
288
- "◄█═ ═► " ,
302
+ "◄██ ═► " ,
289
303
] )
290
304
)
291
305
}
@@ -325,9 +339,9 @@ mod tests {
325
339
"UVWXYZABCD█" ,
326
340
"EFGHIJKLMN█" ,
327
341
"OPQRSTUVWX█" ,
328
- "YZABCDEFGH║ " ,
329
- "IJKLMNOPQR║ " ,
330
- "STUVWXYZAB║ " ,
342
+ "YZABCDEFGH█ " ,
343
+ "IJKLMNOPQR█ " ,
344
+ "STUVWXYZAB█ " ,
331
345
"CDEFGHIJKL▼" ,
332
346
] )
333
347
)
@@ -351,7 +365,7 @@ mod tests {
351
365
"STUVWXYZA" ,
352
366
"CDEFGHIJK" ,
353
367
"MNOPQRSTU" ,
354
- "◄████═══ ►" ,
368
+ "◄███████ ►" ,
355
369
] )
356
370
)
357
371
}
@@ -370,11 +384,11 @@ mod tests {
370
384
"KLMNOPQRS█" ,
371
385
"UVWXYZABC█" ,
372
386
"EFGHIJKLM█" ,
373
- "OPQRSTUVW║ " ,
374
- "YZABCDEFG║ " ,
387
+ "OPQRSTUVW█ " ,
388
+ "YZABCDEFG█ " ,
375
389
"IJKLMNOPQ║" ,
376
390
"STUVWXYZA▼" ,
377
- "◄████═══ ► " ,
391
+ "◄███████ ► " ,
378
392
] )
379
393
)
380
394
}
@@ -394,21 +408,21 @@ mod tests {
394
408
"UVWXYZAB█" ,
395
409
"EFGHIJKL█" ,
396
410
"OPQRSTUV█" ,
397
- "YZABCDEF║ " ,
398
- "IJKLMNOP║ " ,
399
- "STUVWXYZ║ " ,
411
+ "YZABCDEF█ " ,
412
+ "IJKLMNOP█ " ,
413
+ "STUVWXYZ█ " ,
400
414
"CDEFGHIJ▼" ,
401
- "◄███══ ═► " ,
415
+ "◄█████ ═► " ,
402
416
] )
403
417
)
404
418
}
405
419
406
420
/// The purpose of this test is to ensure that the buffer offset is correctly calculated when
407
- /// rendering a scroll view into a buffer (i.e. the buffer offset is not always (0, 0))
421
+ /// rendering a scroll view into a buffer (i.e. the buffer offset is not always (0, 0)).
408
422
#[ rstest]
409
423
fn ensure_buffer_offset_is_correct ( scroll_view : ScrollView ) {
410
424
let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 20 , 20 ) ) ;
411
- let mut state = ScrollViewState :: with_offset ( ( 3 , 4 ) . into ( ) ) ;
425
+ let mut state = ScrollViewState :: with_offset ( ( 2 , 3 ) . into ( ) ) ;
412
426
scroll_view. render ( Rect :: new ( 5 , 6 , 7 , 8 ) , & mut buf, & mut state) ;
413
427
assert_eq ! (
414
428
buf,
@@ -419,14 +433,14 @@ mod tests {
419
433
" " ,
420
434
" " ,
421
435
" " ,
422
- " RSTUVW ▲ " ,
423
- " BCDEFG ║ " ,
424
- " LMNOPQ █ " ,
425
- " VWXYZA █ " ,
426
- " FGHIJK║ " ,
427
- " PQRSTU║ " ,
428
- " ▼ " ,
429
- " ◄═█══ ► " ,
436
+ " GHIJKL ▲ " ,
437
+ " QRSTUV ║ " ,
438
+ " ABCDEF █ " ,
439
+ " KLMNOP █ " ,
440
+ " UVWXYZ█ " ,
441
+ " EFGHIJ█ " ,
442
+ " OPQRST ▼ " ,
443
+ " ◄═███ ► " ,
430
444
" " ,
431
445
" " ,
432
446
" " ,
@@ -436,4 +450,36 @@ mod tests {
436
450
] )
437
451
)
438
452
}
453
+ /// The purpose of this test is to ensure that the last elements are rendered.
454
+ #[ rstest]
455
+ fn ensure_buffer_last_elements ( scroll_view : ScrollView ) {
456
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 6 , 6 ) ) ;
457
+ let mut state = ScrollViewState :: with_offset ( ( 5 , 5 ) . into ( ) ) ;
458
+ scroll_view. render ( buf. area , & mut buf, & mut state) ;
459
+ assert_eq ! (
460
+ buf,
461
+ Buffer :: with_lines( vec![
462
+ "DEFGH▲" ,
463
+ "NOPQR║" ,
464
+ "XYZAB█" ,
465
+ "HIJKL█" ,
466
+ "RSTUV▼" ,
467
+ "◄═██► " ,
468
+ ] )
469
+ )
470
+ }
471
+ #[ rstest]
472
+ #[ should_panic( expected = "Scrollbar area is empty" ) ]
473
+ fn zero_width ( scroll_view : ScrollView ) {
474
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 0 , 10 ) ) ;
475
+ let mut state = ScrollViewState :: new ( ) ;
476
+ scroll_view. render ( buf. area , & mut buf, & mut state) ;
477
+ }
478
+ #[ rstest]
479
+ #[ should_panic( expected = "Scrollbar area is empty" ) ]
480
+ fn zero_height ( scroll_view : ScrollView ) {
481
+ let mut buf = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 0 ) ) ;
482
+ let mut state = ScrollViewState :: new ( ) ;
483
+ scroll_view. render ( buf. area , & mut buf, & mut state) ;
484
+ }
439
485
}
0 commit comments