# fbdraw Carousel Example This example demonstrates how to use the fbdraw carousel API to create a rotating display with multiple screens, each updating at its own frame rate. ```go package main import ( "fmt" "math" "math/rand" "time" "git.eeqj.de/sneak/hdmistat/internal/fbdraw" "git.eeqj.de/sneak/hdmistat/internal/font" ) // SystemStatusGenerator generates frames showing system status type SystemStatusGenerator struct { frameCount int } func (g *SystemStatusGenerator) GenerateFrame(grid *fbdraw.CharGrid) error { g.frameCount++ w := fbdraw.NewGridWriter(grid) // Clear and draw header w.Clear() w.SetColor(fbdraw.Cyan).SetWeight(font.WeightBold) w.MoveAbs(0, 0).WriteLine("=== SYSTEM STATUS ===") // Animate with frame count w.SetColor(fbdraw.White).SetWeight(font.WeightRegular) w.MoveAbs(0, 2).WriteLine("Frame: %d", g.frameCount) w.MoveAbs(0, 3).WriteLine("Time: %s", time.Now().Format("15:04:05.000")) // Animated CPU meter cpuUsage := 50 + 30*math.Sin(float64(g.frameCount)*0.1) w.MoveAbs(0, 5).Write("CPU: [") w.DrawMeter(cpuUsage, 20) w.Write("] %.1f%%", cpuUsage) return nil } func (g *SystemStatusGenerator) FramesPerSecond() float64 { return 15.0 // 15 FPS } // NetworkMonitorGenerator shows network activity type NetworkMonitorGenerator struct { packets []float64 } func (g *NetworkMonitorGenerator) GenerateFrame(grid *fbdraw.CharGrid) error { w := fbdraw.NewGridWriter(grid) // Update data if len(g.packets) > 50 { g.packets = g.packets[1:] } g.packets = append(g.packets, rand.Float64()*100) // Draw w.Clear() w.SetColor(fbdraw.Green).SetWeight(font.WeightBold) w.MoveAbs(0, 0).WriteLine("=== NETWORK MONITOR ===") // Draw graph w.SetColor(fbdraw.White).SetWeight(font.WeightRegular) for i, val := range g.packets { height := int(val / 10) // Scale to 0-10 for y := 10; y > 10-height; y-- { w.MoveAbs(i+5, y).Write("█") } } w.MoveAbs(0, 12).WriteLine("Packets/sec: %.0f", g.packets[len(g.packets)-1]) return nil } func (g *NetworkMonitorGenerator) FramesPerSecond() float64 { return 10.0 // 10 FPS } // ProcessListGenerator shows top processes type ProcessListGenerator struct { updateCount int } func (g *ProcessListGenerator) GenerateFrame(grid *fbdraw.CharGrid) error { g.updateCount++ w := fbdraw.NewGridWriter(grid) w.Clear() w.SetColor(fbdraw.Yellow).SetWeight(font.WeightBold) w.MoveAbs(0, 0).WriteLine("=== TOP PROCESSES ===") // Table header w.MoveAbs(0, 2).SetColor(fbdraw.White).SetWeight(font.WeightBold) w.WriteLine("PID CPU% PROCESS") w.WriteLine("----- ----- ----------------") // Fake process data w.SetWeight(font.WeightRegular) processes := []struct { pid int cpu float64 name string }{ {1234, 42.1 + float64(g.updateCount%10), "firefox"}, {5678, 18.7, "vscode"}, {9012, 8.3, "dockerd"}, } for i, p := range processes { if p.cpu > 30 { w.SetColor(fbdraw.Red) } else if p.cpu > 15 { w.SetColor(fbdraw.Yellow) } else { w.SetColor(fbdraw.White) } w.MoveAbs(0, 4+i) w.WriteLine("%-5d %5.1f %s", p.pid, p.cpu, p.name) } w.MoveAbs(0, 10).SetColor(fbdraw.Gray60) w.WriteLine("Update #%d", g.updateCount) return nil } func (g *ProcessListGenerator) FramesPerSecond() float64 { return 1.0 // 1 FPS - processes don't change that fast } func main() { // Initialize display (auto-detect framebuffer) display, err := fbdraw.NewFBDisplayAuto() if err != nil { // Fall back to terminal display display = fbdraw.NewTerminalDisplay(80, 25) } defer display.Close() // Create carousel with 10 second rotation carousel := fbdraw.NewCarousel(display, 10*time.Second) // Add screens with their generators carousel.AddScreen("System Status", &SystemStatusGenerator{}) carousel.AddScreen("Network Monitor", &NetworkMonitorGenerator{}) carousel.AddScreen("Process List", &ProcessListGenerator{}) // Start the carousel (blocks until interrupted) if err := carousel.Run(); err != nil { fmt.Printf("Carousel error: %v\n", err) } } ``` ## Key Features Demonstrated 1. **Multiple Display Types**: The example tries to auto-detect a framebuffer, falling back to terminal display if not available. 2. **Different Frame Rates**: Each screen updates at its own rate: - System Status: 15 FPS (smooth animations) - Network Monitor: 10 FPS (moderate updates) - Process List: 1 FPS (slow changing data) 3. **GridWriter API**: Shows various drawing operations: - `MoveAbs()` for absolute positioning - `Move()` for relative movement - `DrawMeter()` for progress bars with automatic coloring - `SetColor()`, `SetWeight()` for styling 4. **Carousel Management**: The carousel automatically: - Rotates screens every 10 seconds - Manages frame timing for each screen - Only renders the active screen 5. **Animation**: The system status screen demonstrates smooth animation using frame counting and sine waves.