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

280 lines
7.9 KiB
Markdown

# Framebuffer Display API
A high-level Go package for easily creating text-based status displays on Linux framebuffers. Perfect for system monitors, embedded displays, IoT dashboards, and more.
## API Design Concepts
Below are four different API design approaches for creating framebuffer displays. Each example shows how you might implement a system status display.
### Concept 1: Builder Pattern
```go
package main
import (
"time"
fb "github.com/example/framebufferdisplay"
)
func main() {
// Create and configure display with fluent interface
display := fb.New().
AutoDetect(). // Find first available framebuffer
WithFont("IBM Plex Mono", 14). // Default font
WithUpdateInterval(time.Second). // Auto-refresh rate
Build()
defer display.Close()
// Define the layout
display.Layout(func(canvas *fb.Canvas) {
// Header section
canvas.Section("header", fb.TopCenter).
Font("IBM Plex Mono", 24).
Color(fb.White).
Text("System Status")
// System info section
canvas.Section("info", fb.TopLeft).
Margin(20).
Rows(
fb.Row().Label("Hostname:").Value(getHostname()),
fb.Row().Label("Uptime:").Value(getUptime()),
fb.Row().Label("Load:").Value(getLoad()).Color(fb.Red),
)
// CPU meters
canvas.Section("cpu", fb.CenterLeft).
Title("CPU Usage").
Meters(getCPUMeters()...)
// Memory bar
canvas.Section("memory", fb.BottomLeft).
Title("Memory").
ProgressBar(getMemoryPercent(), fb.Green)
})
// Start the display loop
display.Run()
}
```
### Concept 2: Declarative/React-like
```go
package main
import (
fb "github.com/example/framebufferdisplay"
)
type SystemStatus struct {
fb.Component
hostname string
uptime time.Duration
}
func (s *SystemStatus) Render() fb.Element {
return fb.Screen(
fb.Header(
fb.Text("System Status").
Font("IBM Plex Mono", 48).
Color(fb.RGB(100, 200, 255)),
),
fb.Grid(fb.GridOptions{Columns: 2, Gap: 20},
// Left column
fb.Column(
fb.Card(
fb.Title("System Info"),
fb.List(
fb.ListItem("Hostname", s.hostname),
fb.ListItem("Uptime", formatDuration(s.uptime)),
fb.ListItem("OS", getOS()),
),
),
fb.Card(
fb.Title("Network"),
fb.List(getNetworkInfo()...),
),
),
// Right column
fb.Column(
fb.Card(
fb.Title("CPU Usage"),
fb.BarChart(getCPUData(), fb.ChartOptions{
Height: 200,
Color: fb.Gradient(fb.Green, fb.Red),
}),
),
fb.Card(
fb.Title("Memory"),
fb.CircularProgress(getMemoryPercent(), fb.Blue),
fb.Text(getMemoryDetails()).Size(12),
),
),
),
)
}
func main() {
fb.Run(&SystemStatus{})
}
```
### Concept 3: Immediate Mode
```go
package main
import (
fb "github.com/example/framebufferdisplay"
)
func main() {
// Auto-detect and initialize
ctx := fb.Init()
defer ctx.Close()
// Main render loop
ctx.Loop(func(d *fb.Draw) {
// Clear with background
d.Clear(fb.Black)
// Draw header
d.SetFont("IBM Plex Mono Bold", 36)
d.SetColor(fb.White)
d.TextCenter(d.Width/2, 50, "System Monitor")
// System info box
d.SetFont("IBM Plex Mono", 14)
d.Box(20, 100, 400, 200, fb.Gray)
d.SetColor(fb.Green)
d.Text(30, 120, "Hostname: %s", getHostname())
d.Text(30, 140, "Uptime: %s", getUptime())
d.Text(30, 160, "Load: %.2f %.2f %.2f", getLoad())
// CPU visualization
cpus := getCPUPercents()
for i, cpu := range cpus {
y := 320 + i*30
d.Text(30, y, "CPU%d", i)
d.ProgressBar(80, y-10, 300, 20, cpu, fb.Heat(cpu))
}
// Memory meter
mem := getMemoryPercent()
d.SetFont("IBM Plex Mono", 18)
d.Text(30, 500, "Memory: %.1f%%", mem)
d.Gauge(30, 520, 350, 40, mem, fb.Blue)
// Update display
d.Present()
})
}
```
### Concept 4: Template/Widget-based
```go
package main
import (
fb "github.com/example/framebufferdisplay"
)
func main() {
// Create display with auto-detection
display := fb.NewDisplay()
// Create a dashboard with predefined widgets
dashboard := fb.Dashboard{
Title: "System Status",
Theme: fb.Themes.Dark,
Layout: fb.GridLayout(3, 3), // 3x3 grid
Widgets: []fb.Widget{
// Row 1
fb.BigNumber{
GridPos: fb.Pos(0, 0),
Label: "CPU Temp",
Value: getCPUTemp,
Unit: "°C",
Color: fb.TempColor, // Auto-colors based on value
},
fb.LineGraph{
GridPos: fb.Pos(1, 0).Span(2, 1), // Spans 2 columns
Title: "CPU History",
Duration: 5 * time.Minute,
Source: streamCPUData,
},
// Row 2
fb.InfoTable{
GridPos: fb.Pos(0, 1),
Rows: []fb.TableRow{
{"Host", getHostname},
{"Kernel", getKernel},
{"Uptime", getUptime},
},
},
fb.MultiMeter{
GridPos: fb.Pos(1, 1),
Title: "CPU Cores",
Meters: getCPUCoreMeters,
Compact: true,
},
fb.PieChart{
GridPos: fb.Pos(2, 1),
Title: "Disk Usage",
Data: getDiskUsage,
},
// Row 3
fb.MemoryWidget{
GridPos: fb.Pos(0, 2).Span(2, 1),
ShowDetails: true,
},
fb.NetworkTraffic{
GridPos: fb.Pos(2, 2),
Interface: "eth0",
},
},
// Optional: Add alerts
Alerts: []fb.Alert{
fb.Alert{
Condition: func() bool { return getCPUTemp() > 80 },
Message: "High CPU Temperature!",
Color: fb.Red,
},
},
}
// Run the dashboard
display.RunDashboard(dashboard)
}
```
## Key Features Across All Concepts
- **Auto-detection**: Automatically finds and configures the first available framebuffer
- **Resolution independence**: Layouts adapt to the detected resolution
- **Font management**: Easy font loading and sizing
- **Color utilities**: Named colors, RGB, gradients, and conditional coloring
- **Common widgets**: Progress bars, meters, graphs, tables, etc.
- **Refresh control**: Configurable update intervals or manual control
- **Error handling**: Graceful fallbacks for missing fonts, permissions, etc.
## Design Considerations
Each approach offers different benefits:
1. **Builder Pattern**: Familiar to Go developers, good for static layouts
2. **Declarative**: Clean separation of data and presentation, easy to test
3. **Immediate Mode**: Simple and direct, good for dynamic content
4. **Widget-based**: Highest level abstraction, fastest to build common dashboards
The final API could combine elements from multiple approaches, such as using the widget system from Concept 4 with the immediate mode drawing primitives from Concept 3 for custom widgets.