* Render scrollbar (Phase 2) * Shows scroll position and allows click/drag interaction * @param opacity Opacity level (0-1) for fade in/out effect
(
viewportY: number,
scrollbackLength: number,
visibleRows: number,
opacity: number = 1
)
| 838 | * @param opacity Opacity level (0-1) for fade in/out effect |
| 839 | */ |
| 840 | private renderScrollbar( |
| 841 | viewportY: number, |
| 842 | scrollbackLength: number, |
| 843 | visibleRows: number, |
| 844 | opacity: number = 1 |
| 845 | ): void { |
| 846 | const ctx = this.ctx; |
| 847 | const canvasHeight = this.canvas.height / this.devicePixelRatio; |
| 848 | const canvasWidth = this.canvas.width / this.devicePixelRatio; |
| 849 | |
| 850 | // Scrollbar dimensions |
| 851 | const scrollbarWidth = 8; |
| 852 | const scrollbarX = canvasWidth - scrollbarWidth - 4; |
| 853 | const scrollbarPadding = 4; |
| 854 | const scrollbarTrackHeight = canvasHeight - scrollbarPadding * 2; |
| 855 | |
| 856 | // Always clear the scrollbar area first (fixes ghosting when fading out) |
| 857 | ctx.fillStyle = this.theme.background; |
| 858 | ctx.fillRect(scrollbarX - 2, 0, scrollbarWidth + 6, canvasHeight); |
| 859 | |
| 860 | // Don't draw scrollbar if fully transparent or no scrollback |
| 861 | if (opacity <= 0 || scrollbackLength === 0) return; |
| 862 | |
| 863 | // Calculate scrollbar thumb size and position |
| 864 | const totalLines = scrollbackLength + visibleRows; |
| 865 | const thumbHeight = Math.max(20, (visibleRows / totalLines) * scrollbarTrackHeight); |
| 866 | |
| 867 | // Position: 0 = at bottom, scrollbackLength = at top |
| 868 | const scrollPosition = viewportY / scrollbackLength; // 0 to 1 |
| 869 | const thumbY = scrollbarPadding + (scrollbarTrackHeight - thumbHeight) * (1 - scrollPosition); |
| 870 | |
| 871 | // Draw scrollbar track (subtle background) with opacity |
| 872 | ctx.fillStyle = `rgba(128, 128, 128, ${0.1 * opacity})`; |
| 873 | ctx.fillRect(scrollbarX, scrollbarPadding, scrollbarWidth, scrollbarTrackHeight); |
| 874 | |
| 875 | // Draw scrollbar thumb with opacity |
| 876 | const isScrolled = viewportY > 0; |
| 877 | const baseOpacity = isScrolled ? 0.5 : 0.3; |
| 878 | ctx.fillStyle = `rgba(128, 128, 128, ${baseOpacity * opacity})`; |
| 879 | ctx.fillRect(scrollbarX, thumbY, scrollbarWidth, thumbHeight); |
| 880 | } |
| 881 | public getMetrics(): FontMetrics { |
| 882 | return { ...this.metrics }; |
| 883 | } |