making lots of progress!
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
// Package renderer provides screen rendering implementations for hdmistat
|
||||
//
|
||||
//nolint:mnd
|
||||
package renderer
|
||||
|
||||
import (
|
||||
@@ -25,7 +27,10 @@ func (s *OverviewScreen) Name() string {
|
||||
}
|
||||
|
||||
// Render draws the overview screen to the provided canvas
|
||||
func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.SystemInfo) error {
|
||||
func (s *OverviewScreen) Render(
|
||||
canvas *layout.Canvas,
|
||||
info *statcollector.SystemInfo,
|
||||
) error {
|
||||
_, _ = canvas.Size()
|
||||
|
||||
// Colors
|
||||
@@ -47,11 +52,15 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
|
||||
// Title - left aligned at consistent position
|
||||
titleText := fmt.Sprintf("%s: status", shortHostname)
|
||||
_ = canvas.DrawText(titleText, layout.Point{X: 50, Y: y}, layout.TextStyle{
|
||||
Size: 36, // Smaller than before
|
||||
Color: titleStyle.Color,
|
||||
Alignment: layout.AlignLeft,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
titleText,
|
||||
layout.Point{X: 50, Y: y},
|
||||
layout.TextStyle{
|
||||
Size: 36, // Smaller than before
|
||||
Color: titleStyle.Color,
|
||||
Alignment: layout.AlignLeft,
|
||||
},
|
||||
)
|
||||
y += 60
|
||||
|
||||
// Standard bar dimensions
|
||||
@@ -74,8 +83,12 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
cpuBar := &layout.ProgressBar{
|
||||
X: 50, Y: y,
|
||||
Width: barWidth, Height: barHeight,
|
||||
Value: avgCPU / 100.0,
|
||||
Label: fmt.Sprintf("%.1f%% average across %d cores", avgCPU, len(info.CPUPercent)),
|
||||
Value: avgCPU / 100.0,
|
||||
Label: fmt.Sprintf(
|
||||
"%.1f%% average across %d cores",
|
||||
avgCPU,
|
||||
len(info.CPUPercent),
|
||||
),
|
||||
LeftLabel: "0%",
|
||||
RightLabel: "100%",
|
||||
BarColor: color.RGBA{255, 100, 100, 255},
|
||||
@@ -91,8 +104,12 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
memoryBar := &layout.ProgressBar{
|
||||
X: 50, Y: y,
|
||||
Width: barWidth, Height: barHeight,
|
||||
Value: memUsedPercent,
|
||||
Label: fmt.Sprintf("%s of %s", layout.FormatBytes(info.MemoryUsed), layout.FormatBytes(info.MemoryTotal)),
|
||||
Value: memUsedPercent,
|
||||
Label: fmt.Sprintf(
|
||||
"%s of %s",
|
||||
layout.FormatBytes(info.MemoryUsed),
|
||||
layout.FormatBytes(info.MemoryTotal),
|
||||
),
|
||||
LeftLabel: "0B",
|
||||
RightLabel: layout.FormatBytes(info.MemoryTotal),
|
||||
BarColor: color.RGBA{100, 200, 100, 255},
|
||||
@@ -102,7 +119,11 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
|
||||
// Temperature section
|
||||
if len(info.Temperature) > 0 {
|
||||
_ = canvas.DrawText("TEMPERATURE", layout.Point{X: 50, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText(
|
||||
"TEMPERATURE",
|
||||
layout.Point{X: 50, Y: y},
|
||||
headerStyle,
|
||||
)
|
||||
y += 30
|
||||
|
||||
// Find the highest temperature
|
||||
@@ -150,8 +171,13 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
diskBar := &layout.ProgressBar{
|
||||
X: 50, Y: y,
|
||||
Width: barWidth, Height: barHeight,
|
||||
Value: disk.UsedPercent / 100.0,
|
||||
Label: fmt.Sprintf("%s: %s of %s", disk.Path, layout.FormatBytes(disk.Used), layout.FormatBytes(disk.Total)),
|
||||
Value: disk.UsedPercent / 100.0,
|
||||
Label: fmt.Sprintf(
|
||||
"%s: %s of %s",
|
||||
disk.Path,
|
||||
layout.FormatBytes(disk.Used),
|
||||
layout.FormatBytes(disk.Total),
|
||||
),
|
||||
LeftLabel: "0B",
|
||||
RightLabel: layout.FormatBytes(disk.Total),
|
||||
BarColor: color.RGBA{200, 200, 100, 255},
|
||||
@@ -168,16 +194,28 @@ func (s *OverviewScreen) Render(canvas *layout.Canvas, info *statcollector.Syste
|
||||
|
||||
// Network section
|
||||
if len(info.Network) > 0 {
|
||||
_ = canvas.DrawText("NETWORK", layout.Point{X: 50, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText(
|
||||
"NETWORK",
|
||||
layout.Point{X: 50, Y: y},
|
||||
headerStyle,
|
||||
)
|
||||
y += 30
|
||||
|
||||
for _, net := range info.Network {
|
||||
// Network interface info
|
||||
interfaceText := net.Name
|
||||
if len(net.IPAddresses) > 0 {
|
||||
interfaceText = fmt.Sprintf("%s (%s)", net.Name, net.IPAddresses[0])
|
||||
interfaceText = fmt.Sprintf(
|
||||
"%s (%s)",
|
||||
net.Name,
|
||||
net.IPAddresses[0],
|
||||
)
|
||||
}
|
||||
_ = canvas.DrawText(interfaceText, layout.Point{X: 50, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
interfaceText,
|
||||
layout.Point{X: 50, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
// Get link speed for scaling (default to 1 Gbps if unknown)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:mnd
|
||||
package renderer
|
||||
|
||||
import (
|
||||
@@ -45,7 +46,10 @@ func (s *ProcessScreen) Name() string {
|
||||
}
|
||||
|
||||
// Render draws the process screen to the provided canvas
|
||||
func (s *ProcessScreen) Render(canvas *layout.Canvas, info *statcollector.SystemInfo) error {
|
||||
func (s *ProcessScreen) Render(
|
||||
canvas *layout.Canvas,
|
||||
info *statcollector.SystemInfo,
|
||||
) error {
|
||||
width, _ := canvas.Size()
|
||||
|
||||
// Colors
|
||||
@@ -74,11 +78,15 @@ func (s *ProcessScreen) Render(canvas *layout.Canvas, info *statcollector.System
|
||||
} else {
|
||||
titleText = fmt.Sprintf("%s: memory", shortHostname)
|
||||
}
|
||||
_ = canvas.DrawText(titleText, layout.Point{X: 50, Y: y}, layout.TextStyle{
|
||||
Size: 36, // Same size as overview
|
||||
Color: titleStyle.Color,
|
||||
Alignment: layout.AlignLeft,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
titleText,
|
||||
layout.Point{X: 50, Y: y},
|
||||
layout.TextStyle{
|
||||
Size: 36, // Same size as overview
|
||||
Color: titleStyle.Color,
|
||||
Alignment: layout.AlignLeft,
|
||||
},
|
||||
)
|
||||
y += 60
|
||||
|
||||
// Sort processes
|
||||
@@ -99,9 +107,17 @@ func (s *ProcessScreen) Render(canvas *layout.Canvas, info *statcollector.System
|
||||
x := 50
|
||||
_ = canvas.DrawText("PID", layout.Point{X: x, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText("USER", layout.Point{X: x + 100, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText("PROCESS", layout.Point{X: x + 250, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText(
|
||||
"PROCESS",
|
||||
layout.Point{X: x + 250, Y: y},
|
||||
headerStyle,
|
||||
)
|
||||
_ = canvas.DrawText("CPU %", layout.Point{X: x + 600, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText("MEMORY", layout.Point{X: x + 700, Y: y}, headerStyle)
|
||||
_ = canvas.DrawText(
|
||||
"MEMORY",
|
||||
layout.Point{X: x + 700, Y: y},
|
||||
headerStyle,
|
||||
)
|
||||
|
||||
y += 30
|
||||
canvas.DrawHLine(x, y, width-100, color.RGBA{100, 100, 100, 255})
|
||||
@@ -126,16 +142,42 @@ func (s *ProcessScreen) Render(canvas *layout.Canvas, info *statcollector.System
|
||||
|
||||
// Highlight bar for high usage (draw BEFORE text)
|
||||
if s.SortBy == "cpu" && proc.CPUPercent > cpuHighThreshold {
|
||||
canvas.DrawBox(x-5, y-15, width-90, 20, color.RGBA{100, 50, 50, 100})
|
||||
canvas.DrawBox(
|
||||
x-5,
|
||||
y-15,
|
||||
width-90,
|
||||
20,
|
||||
color.RGBA{100, 50, 50, 100},
|
||||
)
|
||||
} else if s.SortBy == "memory" && float64(proc.MemoryRSS)/float64(info.MemoryTotal) > memoryHighRatio {
|
||||
canvas.DrawBox(x-5, y-15, width-90, 20, color.RGBA{50, 50, 100, 100})
|
||||
}
|
||||
|
||||
_ = canvas.DrawText(fmt.Sprintf("%d", proc.PID), layout.Point{X: x, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(user, layout.Point{X: x + 100, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(name, layout.Point{X: x + 250, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(fmt.Sprintf("%.1f", proc.CPUPercent), layout.Point{X: x + 600, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(layout.FormatBytes(proc.MemoryRSS), layout.Point{X: x + 700, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
fmt.Sprintf("%d", proc.PID),
|
||||
layout.Point{X: x, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
user,
|
||||
layout.Point{X: x + 100, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
name,
|
||||
layout.Point{X: x + 250, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
fmt.Sprintf("%.1f", proc.CPUPercent),
|
||||
layout.Point{X: x + 600, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
layout.FormatBytes(proc.MemoryRSS),
|
||||
layout.Point{X: x + 700, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
|
||||
y += 25
|
||||
}
|
||||
@@ -151,17 +193,23 @@ func (s *ProcessScreen) Render(canvas *layout.Canvas, info *statcollector.System
|
||||
}
|
||||
avgCPU := totalCPU / float64(len(info.CPUPercent))
|
||||
|
||||
footerText := fmt.Sprintf("System: CPU %.1f%% | Memory: %s / %s (%.1f%%)",
|
||||
footerText := fmt.Sprintf(
|
||||
"System: CPU %.1f%% | Memory: %s / %s (%.1f%%)",
|
||||
avgCPU,
|
||||
layout.FormatBytes(info.MemoryUsed),
|
||||
layout.FormatBytes(info.MemoryTotal),
|
||||
float64(info.MemoryUsed)/float64(info.MemoryTotal)*percentMultiplier)
|
||||
float64(info.MemoryUsed)/float64(info.MemoryTotal)*percentMultiplier,
|
||||
)
|
||||
|
||||
_ = canvas.DrawText(footerText, layout.Point{X: width / halfDivisor, Y: y}, layout.TextStyle{
|
||||
Size: smallStyle.Size,
|
||||
Color: smallStyle.Color,
|
||||
Alignment: layout.AlignCenter,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
footerText,
|
||||
layout.Point{X: width / halfDivisor, Y: y},
|
||||
layout.TextStyle{
|
||||
Size: smallStyle.Size,
|
||||
Color: smallStyle.Color,
|
||||
Alignment: layout.AlignCenter,
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:mnd
|
||||
package renderer
|
||||
|
||||
import (
|
||||
@@ -44,7 +45,10 @@ func (r *Renderer) SetResolution(width, height int) {
|
||||
}
|
||||
|
||||
// RenderScreen renders a screen to an image
|
||||
func (r *Renderer) RenderScreen(screen Screen, info *statcollector.SystemInfo) (*image.RGBA, error) {
|
||||
func (r *Renderer) RenderScreen(
|
||||
screen Screen,
|
||||
info *statcollector.SystemInfo,
|
||||
) (*image.RGBA, error) {
|
||||
canvas := layout.NewCanvas(r.width, r.height, r.font, r.logger)
|
||||
|
||||
// Draw common header
|
||||
@@ -58,7 +62,10 @@ func (r *Renderer) RenderScreen(screen Screen, info *statcollector.SystemInfo) (
|
||||
}
|
||||
|
||||
// drawHeader draws the common header with system info
|
||||
func (r *Renderer) drawHeader(canvas *layout.Canvas, _ *statcollector.SystemInfo) {
|
||||
func (r *Renderer) drawHeader(
|
||||
canvas *layout.Canvas,
|
||||
_ *statcollector.SystemInfo,
|
||||
) {
|
||||
width, _ := canvas.Size()
|
||||
headerColor := color.RGBA{150, 150, 150, 255}
|
||||
headerStyle := layout.TextStyle{Size: 14, Color: headerColor, Bold: true}
|
||||
@@ -97,42 +104,66 @@ func (r *Renderer) drawHeader(canvas *layout.Canvas, _ *statcollector.SystemInfo
|
||||
// For simplicity, we'll use a fixed position approach
|
||||
|
||||
// Draw UTC time
|
||||
_ = canvas.DrawText(utcTime, layout.Point{X: width - 40, Y: 20}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: color.RGBA{255, 255, 255, 255}, // White
|
||||
Alignment: layout.AlignRight,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
utcTime,
|
||||
layout.Point{X: width - 40, Y: 20},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: color.RGBA{255, 255, 255, 255}, // White
|
||||
Alignment: layout.AlignRight,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
// UTC sync indicators
|
||||
_ = canvas.DrawText(syncIndicator, layout.Point{X: width - 280, Y: 20}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(syncIndicator, layout.Point{X: width - 20, Y: 20}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
syncIndicator,
|
||||
layout.Point{X: width - 280, Y: 20},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
syncIndicator,
|
||||
layout.Point{X: width - 20, Y: 20},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
|
||||
// Draw local time
|
||||
_ = canvas.DrawText(localTime, layout.Point{X: width - 40, Y: 35}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: color.RGBA{255, 255, 255, 255}, // White
|
||||
Alignment: layout.AlignRight,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
localTime,
|
||||
layout.Point{X: width - 40, Y: 35},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: color.RGBA{255, 255, 255, 255}, // White
|
||||
Alignment: layout.AlignRight,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
// Local sync indicators
|
||||
_ = canvas.DrawText(syncIndicator, layout.Point{X: width - 280, Y: 35}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(syncIndicator, layout.Point{X: width - 20, Y: 35}, layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
})
|
||||
_ = canvas.DrawText(
|
||||
syncIndicator,
|
||||
layout.Point{X: width - 280, Y: 35},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
syncIndicator,
|
||||
layout.Point{X: width - 20, Y: 35},
|
||||
layout.TextStyle{
|
||||
Size: headerStyle.Size,
|
||||
Color: syncColor,
|
||||
Bold: true,
|
||||
},
|
||||
)
|
||||
|
||||
// Get uptime command output
|
||||
uptimeStr := "uptime unavailable"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:mnd
|
||||
package renderer
|
||||
|
||||
import (
|
||||
@@ -24,7 +25,10 @@ func (s *StatusScreen) Name() string {
|
||||
}
|
||||
|
||||
// Render renders the status screen
|
||||
func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemInfo) error {
|
||||
func (s *StatusScreen) Render(
|
||||
canvas *layout.Canvas,
|
||||
info *statcollector.SystemInfo,
|
||||
) error {
|
||||
// Use consistent font size for entire screen
|
||||
const fontSize = 16
|
||||
|
||||
@@ -51,37 +55,70 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
y += 40
|
||||
|
||||
// CPU section
|
||||
cpuLabel := fmt.Sprintf("CPU: %.1f%% average across %d cores",
|
||||
getAverageCPU(info.CPUPercent), len(info.CPUPercent))
|
||||
cpuLabel := fmt.Sprintf(
|
||||
"CPU: %.1f%% average across %d cores",
|
||||
getAverageCPU(info.CPUPercent),
|
||||
len(info.CPUPercent),
|
||||
)
|
||||
_ = canvas.DrawText(cpuLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
y += 25
|
||||
|
||||
// CPU progress bar
|
||||
_ = canvas.DrawText("0%", layout.Point{X: 100, Y: y}, dimStyle)
|
||||
drawProgressBar(canvas, 130, y-10, getAverageCPU(info.CPUPercent)/100.0, textColor)
|
||||
drawProgressBar(
|
||||
canvas,
|
||||
130,
|
||||
y-10,
|
||||
getAverageCPU(info.CPUPercent)/100.0,
|
||||
textColor,
|
||||
)
|
||||
_ = canvas.DrawText("100%", layout.Point{X: 985, Y: y}, dimStyle)
|
||||
y += 40
|
||||
|
||||
// Memory section
|
||||
memUsedPercent := float64(info.MemoryUsed) / float64(info.MemoryTotal) * 100.0
|
||||
memLabel := fmt.Sprintf("MEMORY: %s of %s (%.1f%%)",
|
||||
memUsedPercent := float64(
|
||||
info.MemoryUsed,
|
||||
) / float64(
|
||||
info.MemoryTotal,
|
||||
) * 100.0
|
||||
memLabel := fmt.Sprintf(
|
||||
"MEMORY: %s of %s (%.1f%%)",
|
||||
layout.FormatBytes(info.MemoryUsed),
|
||||
layout.FormatBytes(info.MemoryTotal),
|
||||
memUsedPercent)
|
||||
memUsedPercent,
|
||||
)
|
||||
_ = canvas.DrawText(memLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
y += 25
|
||||
|
||||
// Memory progress bar
|
||||
_ = canvas.DrawText("0B", layout.Point{X: 100, Y: y}, dimStyle)
|
||||
drawProgressBar(canvas, 130, y-10, float64(info.MemoryUsed)/float64(info.MemoryTotal), textColor)
|
||||
_ = canvas.DrawText(layout.FormatBytes(info.MemoryTotal), layout.Point{X: 985, Y: y}, dimStyle)
|
||||
drawProgressBar(
|
||||
canvas,
|
||||
130,
|
||||
y-10,
|
||||
float64(info.MemoryUsed)/float64(info.MemoryTotal),
|
||||
textColor,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
layout.FormatBytes(info.MemoryTotal),
|
||||
layout.Point{X: 985, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
y += 40
|
||||
|
||||
// Temperature section
|
||||
if len(info.Temperature) > 0 {
|
||||
maxTemp, maxSensor := getMaxTemperature(info.Temperature)
|
||||
tempLabel := fmt.Sprintf("TEMPERATURE: %.1f°C (%s)", maxTemp, maxSensor)
|
||||
_ = canvas.DrawText(tempLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
tempLabel := fmt.Sprintf(
|
||||
"TEMPERATURE: %.1f°C (%s)",
|
||||
maxTemp,
|
||||
maxSensor,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
tempLabel,
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
// Temperature progress bar (30-99°C scale)
|
||||
@@ -99,7 +136,11 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
}
|
||||
|
||||
// Disk usage section
|
||||
_ = canvas.DrawText("DISK USAGE:", layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
"DISK USAGE:",
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
for _, disk := range info.DiskUsage {
|
||||
@@ -113,12 +154,26 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
layout.FormatBytes(disk.Used),
|
||||
layout.FormatBytes(disk.Total),
|
||||
disk.UsedPercent)
|
||||
_ = canvas.DrawText(diskLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
diskLabel,
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
|
||||
// Disk progress bar
|
||||
_ = canvas.DrawText("0B", layout.Point{X: 470, Y: y}, dimStyle)
|
||||
drawDiskProgressBar(canvas, 500, y-10, disk.UsedPercent/100.0, textColor)
|
||||
_ = canvas.DrawText(layout.FormatBytes(disk.Total), layout.Point{X: 985, Y: y}, dimStyle)
|
||||
drawDiskProgressBar(
|
||||
canvas,
|
||||
500,
|
||||
y-10,
|
||||
disk.UsedPercent/100.0,
|
||||
textColor,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
layout.FormatBytes(disk.Total),
|
||||
layout.Point{X: 985, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
y += 30
|
||||
|
||||
if y > 700 {
|
||||
@@ -129,16 +184,28 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
// Network section
|
||||
if len(info.Network) > 0 {
|
||||
y += 15
|
||||
_ = canvas.DrawText("NETWORK:", layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
"NETWORK:",
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
for _, net := range info.Network {
|
||||
// Interface header
|
||||
interfaceText := fmt.Sprintf(" * %s", net.Name)
|
||||
if len(net.IPAddresses) > 0 {
|
||||
interfaceText = fmt.Sprintf(" * %s (%s):", net.Name, net.IPAddresses[0])
|
||||
interfaceText = fmt.Sprintf(
|
||||
" * %s (%s):",
|
||||
net.Name,
|
||||
net.IPAddresses[0],
|
||||
)
|
||||
}
|
||||
_ = canvas.DrawText(interfaceText, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText(
|
||||
interfaceText,
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
// Get link speed for scaling (default to 1 Gbps if unknown)
|
||||
@@ -152,19 +219,59 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
}
|
||||
|
||||
// Upload rate
|
||||
upLabel := fmt.Sprintf(" ↑ %7s (%s)", net.FormatSentRate(), linkSpeedText)
|
||||
_ = canvas.DrawText(upLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText("0 bit/s", layout.Point{X: 400, Y: y}, dimStyle)
|
||||
drawNetworkProgressBar(canvas, 500, y-10, float64(net.BitsSentRate)/float64(linkSpeed), textColor)
|
||||
_ = canvas.DrawText(humanize.SI(float64(linkSpeed), "bit/s"), layout.Point{X: 960, Y: y}, dimStyle)
|
||||
upLabel := fmt.Sprintf(
|
||||
" ↑ %7s (%s)",
|
||||
net.FormatSentRate(),
|
||||
linkSpeedText,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
upLabel,
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
"0 bit/s",
|
||||
layout.Point{X: 400, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
drawNetworkProgressBar(
|
||||
canvas,
|
||||
500,
|
||||
y-10,
|
||||
float64(net.BitsSentRate)/float64(linkSpeed),
|
||||
textColor,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
humanize.SI(float64(linkSpeed), "bit/s"),
|
||||
layout.Point{X: 960, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
y += 25
|
||||
|
||||
// Download rate
|
||||
downLabel := fmt.Sprintf(" ↓ %7s", net.FormatRecvRate())
|
||||
_ = canvas.DrawText(downLabel, layout.Point{X: 16, Y: y}, normalStyle)
|
||||
_ = canvas.DrawText("0 bit/s", layout.Point{X: 400, Y: y}, dimStyle)
|
||||
drawNetworkProgressBar(canvas, 500, y-10, float64(net.BitsRecvRate)/float64(linkSpeed), textColor)
|
||||
_ = canvas.DrawText(humanize.SI(float64(linkSpeed), "bit/s"), layout.Point{X: 960, Y: y}, dimStyle)
|
||||
_ = canvas.DrawText(
|
||||
downLabel,
|
||||
layout.Point{X: 16, Y: y},
|
||||
normalStyle,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
"0 bit/s",
|
||||
layout.Point{X: 400, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
drawNetworkProgressBar(
|
||||
canvas,
|
||||
500,
|
||||
y-10,
|
||||
float64(net.BitsRecvRate)/float64(linkSpeed),
|
||||
textColor,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
humanize.SI(float64(linkSpeed), "bit/s"),
|
||||
layout.Point{X: 960, Y: y},
|
||||
dimStyle,
|
||||
)
|
||||
y += 35
|
||||
|
||||
if y > 900 {
|
||||
@@ -177,45 +284,96 @@ func (s *StatusScreen) Render(canvas *layout.Canvas, info *statcollector.SystemI
|
||||
}
|
||||
|
||||
// drawProgressBar draws a progress bar matching the mockup style
|
||||
func drawProgressBar(canvas *layout.Canvas, x, y int, value float64, color color.Color) {
|
||||
func drawProgressBar(
|
||||
canvas *layout.Canvas,
|
||||
x, y int,
|
||||
value float64,
|
||||
color color.Color,
|
||||
) {
|
||||
const barWidth = 850
|
||||
|
||||
// Draw opening bracket
|
||||
_ = canvas.DrawText("[", layout.Point{X: x, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
_ = canvas.DrawText(
|
||||
"[",
|
||||
layout.Point{X: x, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
|
||||
// Calculate fill
|
||||
fillChars := int(value * 80)
|
||||
emptyChars := 80 - fillChars
|
||||
|
||||
// Draw bar content
|
||||
barContent := strings.Repeat("█", fillChars) + strings.Repeat("▒", emptyChars)
|
||||
_ = canvas.DrawText(barContent, layout.Point{X: x + 10, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
barContent := strings.Repeat(
|
||||
"█",
|
||||
fillChars,
|
||||
) + strings.Repeat(
|
||||
"▒",
|
||||
emptyChars,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
barContent,
|
||||
layout.Point{X: x + 10, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
|
||||
// Draw closing bracket
|
||||
_ = canvas.DrawText("]", layout.Point{X: x + barWidth - 10, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
_ = canvas.DrawText(
|
||||
"]",
|
||||
layout.Point{X: x + barWidth - 10, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
}
|
||||
|
||||
// drawDiskProgressBar draws a smaller progress bar for disk usage
|
||||
func drawDiskProgressBar(canvas *layout.Canvas, x, y int, value float64, color color.Color) {
|
||||
func drawDiskProgressBar(
|
||||
canvas *layout.Canvas,
|
||||
x, y int,
|
||||
value float64,
|
||||
color color.Color,
|
||||
) {
|
||||
const barWidth = 480
|
||||
|
||||
// Draw opening bracket
|
||||
_ = canvas.DrawText("[", layout.Point{X: x, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
_ = canvas.DrawText(
|
||||
"[",
|
||||
layout.Point{X: x, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
|
||||
// Calculate fill (50 chars total)
|
||||
fillChars := int(value * 50)
|
||||
emptyChars := 50 - fillChars
|
||||
|
||||
// Draw bar content
|
||||
barContent := strings.Repeat("█", fillChars) + strings.Repeat("▒", emptyChars)
|
||||
_ = canvas.DrawText(barContent, layout.Point{X: x + 10, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
barContent := strings.Repeat(
|
||||
"█",
|
||||
fillChars,
|
||||
) + strings.Repeat(
|
||||
"▒",
|
||||
emptyChars,
|
||||
)
|
||||
_ = canvas.DrawText(
|
||||
barContent,
|
||||
layout.Point{X: x + 10, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
|
||||
// Draw closing bracket
|
||||
_ = canvas.DrawText("]", layout.Point{X: x + barWidth - 10, Y: y + 15}, layout.TextStyle{Size: 16, Color: color})
|
||||
_ = canvas.DrawText(
|
||||
"]",
|
||||
layout.Point{X: x + barWidth - 10, Y: y + 15},
|
||||
layout.TextStyle{Size: 16, Color: color},
|
||||
)
|
||||
}
|
||||
|
||||
// drawNetworkProgressBar draws a progress bar for network rates
|
||||
func drawNetworkProgressBar(canvas *layout.Canvas, x, y int, value float64, color color.Color) {
|
||||
func drawNetworkProgressBar(
|
||||
canvas *layout.Canvas,
|
||||
x, y int,
|
||||
value float64,
|
||||
color color.Color,
|
||||
) {
|
||||
// Same as disk progress bar
|
||||
drawDiskProgressBar(canvas, x, y, value, color)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user