4runr-os 2.1.49 → 2.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
Binary file
|
package/mk3-tui/src/ui/layout.rs
CHANGED
|
@@ -511,31 +511,53 @@ fn render_center_column(f: &mut Frame, area: Rect, state: &AppState) {
|
|
|
511
511
|
f.render_widget(Paragraph::new(lines), content_area);
|
|
512
512
|
|
|
513
513
|
// === RENDER CLEAN SCROLLBAR (only if scrollable) ===
|
|
514
|
+
// CRITICAL FIX: Only render scrollbar when actually scrollable to prevent flickering
|
|
514
515
|
if total_logs > visible_height && max_scroll > 0 {
|
|
515
516
|
// Scrollbar positioned inside the border, 1 char from right edge
|
|
516
|
-
|
|
517
|
+
// Use fixed position to prevent jitter
|
|
518
|
+
let scrollbar_x = panel_area.x + panel_area.width.saturating_sub(3);
|
|
517
519
|
let scrollbar_y = content_area.y;
|
|
518
520
|
let scrollbar_height = content_area.height;
|
|
519
521
|
|
|
520
|
-
//
|
|
521
|
-
|
|
522
|
-
let thumb_height =
|
|
522
|
+
// CRITICAL: Use integer math to prevent floating point rounding issues
|
|
523
|
+
// Calculate thumb size (minimum 1 char, proportional to visible/total)
|
|
524
|
+
let thumb_height = ((visible_height as u32 * scrollbar_height as u32) / total_logs as u32) as u16;
|
|
525
|
+
let thumb_height = thumb_height.max(1).min(scrollbar_height);
|
|
523
526
|
|
|
524
|
-
// Calculate thumb position
|
|
525
|
-
let
|
|
526
|
-
|
|
527
|
+
// Calculate thumb position using integer math for stability
|
|
528
|
+
let thumb_start = if max_scroll > 0 {
|
|
529
|
+
// Use integer division to avoid floating point jitter
|
|
530
|
+
((state.log_scroll as u32 * (scrollbar_height.saturating_sub(thumb_height) as u32)) / max_scroll as u32) as u16
|
|
531
|
+
} else {
|
|
532
|
+
0
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// Clamp thumb_start to valid range
|
|
536
|
+
let thumb_start = thumb_start.min(scrollbar_height.saturating_sub(thumb_height));
|
|
537
|
+
let thumb_end = (thumb_start + thumb_height).min(scrollbar_height);
|
|
538
|
+
|
|
539
|
+
// Render scrollbar track (entire height) as single operation to prevent flicker
|
|
540
|
+
// Build scrollbar string first, then render once
|
|
541
|
+
let mut scrollbar_chars = vec![String::from("│"); scrollbar_height as usize];
|
|
542
|
+
|
|
543
|
+
// Fill thumb portion
|
|
544
|
+
for i in thumb_start..thumb_end {
|
|
545
|
+
if i < scrollbar_height {
|
|
546
|
+
scrollbar_chars[i as usize] = String::from("█");
|
|
547
|
+
}
|
|
548
|
+
}
|
|
527
549
|
|
|
528
|
-
//
|
|
529
|
-
for i in
|
|
530
|
-
let y = scrollbar_y + i;
|
|
550
|
+
// Render entire scrollbar at once (prevents flickering from multiple renders)
|
|
551
|
+
for (i, c) in scrollbar_chars.iter().enumerate() {
|
|
552
|
+
let y = scrollbar_y + i as u16;
|
|
531
553
|
if y < scrollbar_y + scrollbar_height {
|
|
532
|
-
let
|
|
533
|
-
|
|
554
|
+
let color = if i >= thumb_start as usize && i < thumb_end as usize {
|
|
555
|
+
CYBER_CYAN
|
|
534
556
|
} else {
|
|
535
|
-
|
|
557
|
+
TEXT_MUTED
|
|
536
558
|
};
|
|
537
559
|
f.render_widget(
|
|
538
|
-
Paragraph::new(c).style(Style::default().fg(color)),
|
|
560
|
+
Paragraph::new(c.as_str()).style(Style::default().fg(color)),
|
|
539
561
|
Rect { x: scrollbar_x, y, width: 1, height: 1 }
|
|
540
562
|
);
|
|
541
563
|
}
|