280 lines
7.9 KiB
Markdown
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. |