Implemented a full benchmark system that automatically detects available hardware encoders, tests them with different presets, measures FPS performance, and recommends optimal settings for the user's system. Features: - Automatic test video generation (30s 1080p test pattern) - Hardware encoder detection (NVENC, QSV, AMF, VideoToolbox) - Comprehensive encoder testing across multiple presets - Real-time progress UI with live results - Performance scoring based on FPS metrics - Top 10 results display with recommendation - Config persistence for benchmark results - One-click apply to use recommended settings UI Components: - Benchmark button in main menu header - Progress view showing current test and results - Final results view with ranked encoders - Apply/Close actions for recommendation Integration: - Added to main menu between "Benchmark" and "Logs" buttons - Saves results to ~/.config/VideoTools/benchmark.json - Comprehensive debug logging for troubleshooting This allows users to optimize their encoding settings based on their specific hardware capabilities rather than guessing which encoder will work best.
119 lines
3.7 KiB
Go
119 lines
3.7 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"image/color"
|
|
"sort"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/widget"
|
|
"git.leaktechnologies.dev/stu/VideoTools/internal/logging"
|
|
)
|
|
|
|
// ModuleInfo contains information about a module for display
|
|
type ModuleInfo struct {
|
|
ID string
|
|
Label string
|
|
Color color.Color
|
|
Enabled bool
|
|
Category string
|
|
}
|
|
|
|
// BuildMainMenu creates the main menu view with module tiles grouped by category
|
|
func BuildMainMenu(modules []ModuleInfo, onModuleClick func(string), onModuleDrop func(string, []fyne.URI), onQueueClick func(), onLogsClick func(), onBenchmarkClick func(), titleColor, queueColor, textColor color.Color, queueCompleted, queueTotal int) fyne.CanvasObject {
|
|
title := canvas.NewText("VIDEOTOOLS", titleColor)
|
|
title.TextStyle = fyne.TextStyle{Monospace: true, Bold: true}
|
|
title.TextSize = 28
|
|
|
|
queueTile := buildQueueTile(queueCompleted, queueTotal, queueColor, textColor, onQueueClick)
|
|
|
|
benchmarkBtn := widget.NewButton("Benchmark", onBenchmarkClick)
|
|
benchmarkBtn.Importance = widget.LowImportance
|
|
|
|
logsBtn := widget.NewButton("Logs", onLogsClick)
|
|
logsBtn.Importance = widget.LowImportance
|
|
|
|
header := container.New(layout.NewHBoxLayout(), title, layout.NewSpacer(), benchmarkBtn, logsBtn, queueTile)
|
|
|
|
categorized := map[string][]fyne.CanvasObject{}
|
|
for i := range modules {
|
|
mod := modules[i] // Create new variable for this iteration
|
|
modID := mod.ID // Capture for closure
|
|
cat := mod.Category
|
|
if cat == "" {
|
|
cat = "General"
|
|
}
|
|
var tapFunc func()
|
|
var dropFunc func([]fyne.URI)
|
|
if mod.Enabled {
|
|
// Create new closure with properly captured modID
|
|
id := modID // Explicit capture
|
|
tapFunc = func() {
|
|
onModuleClick(id)
|
|
}
|
|
dropFunc = func(items []fyne.URI) {
|
|
logging.Debug(logging.CatUI, "MainMenu dropFunc called for module=%s itemCount=%d", id, len(items))
|
|
onModuleDrop(id, items)
|
|
}
|
|
}
|
|
logging.Debug(logging.CatUI, "Creating tile for module=%s enabled=%v hasDropFunc=%v", modID, mod.Enabled, dropFunc != nil)
|
|
categorized[cat] = append(categorized[cat], buildModuleTile(mod, tapFunc, dropFunc))
|
|
}
|
|
|
|
var sections []fyne.CanvasObject
|
|
for _, cat := range sortedKeys(categorized) {
|
|
sections = append(sections,
|
|
canvas.NewText(cat, textColor),
|
|
container.NewGridWithColumns(3, categorized[cat]...),
|
|
)
|
|
}
|
|
|
|
padding := canvas.NewRectangle(color.Transparent)
|
|
padding.SetMinSize(fyne.NewSize(0, 14))
|
|
|
|
body := container.New(layout.NewVBoxLayout(),
|
|
header,
|
|
padding,
|
|
container.NewVBox(sections...),
|
|
)
|
|
|
|
return body
|
|
}
|
|
|
|
// buildModuleTile creates a single module tile
|
|
func buildModuleTile(mod ModuleInfo, tapped func(), dropped func([]fyne.URI)) fyne.CanvasObject {
|
|
logging.Debug(logging.CatUI, "building tile %s color=%v enabled=%v", mod.ID, mod.Color, mod.Enabled)
|
|
return container.NewPadded(NewModuleTile(mod.Label, mod.Color, mod.Enabled, tapped, dropped))
|
|
}
|
|
|
|
// buildQueueTile creates the queue status tile
|
|
func buildQueueTile(completed, total int, queueColor, textColor color.Color, onClick func()) fyne.CanvasObject {
|
|
rect := canvas.NewRectangle(queueColor)
|
|
rect.CornerRadius = 8
|
|
rect.SetMinSize(fyne.NewSize(160, 60))
|
|
|
|
text := canvas.NewText(fmt.Sprintf("QUEUE: %d/%d", completed, total), textColor)
|
|
text.Alignment = fyne.TextAlignCenter
|
|
text.TextStyle = fyne.TextStyle{Monospace: true, Bold: true}
|
|
text.TextSize = 18
|
|
|
|
tile := container.NewMax(rect, container.NewCenter(text))
|
|
|
|
// Make it tappable
|
|
tappable := NewTappable(tile, onClick)
|
|
return tappable
|
|
}
|
|
|
|
// sortedKeys returns sorted keys for stable category ordering
|
|
func sortedKeys(m map[string][]fyne.CanvasObject) []string {
|
|
keys := make([]string, 0, len(m))
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
return keys
|
|
}
|