hdmistat/internal/fbdraw/EXAMPLE.md
2025-07-24 14:32:50 +02:00

184 lines
4.8 KiB
Markdown

# 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.