feat: improve UI readability and flexibility

- Increase text and padding sizes in MonoTheme for better readability
  - Text: 14px → 15px
  - Headings: 18px → 20px
  - Padding: 6px → 8px, 8px → 10px
- Make horizontal splitter more flexible (10-90% → 5-95% drag range)
- Add comprehensive color mapping functions for dropdowns:
  - BuildGenericColorMap: rainbow palette for any options
  - BuildQualityColorMap: gradient based on quality level
  - BuildPixelFormatColorMap: semantic colors for pixel formats
- Fix settings_module.go build errors:
  - Remove duplicate buildBenchmarkTab function
  - Fix missing imports (runtime, exec, color)
  - Fix runBenchmarkFromSettings → showBenchmark
  - Remove unused variable i in loop
This commit is contained in:
Stu Leak 2026-01-02 12:02:51 -05:00
parent 86227d805a
commit eb8c553c71
7 changed files with 139 additions and 12 deletions

View File

@ -176,7 +176,7 @@ func (v *BenchmarkProgressView) AddResult(result benchmark.Result) {
// Status indicator
statusRect := canvas.NewRectangle(statusColor)
statusRect.SetMinSize(fyne.NewSize(6, 0))
// statusRect.SetMinSize(fyne.NewSize(6, 0)) // Removed for flexible sizing
// Encoder label
encoderLabel := widget.NewLabel(fmt.Sprintf("%s (%s)", result.Encoder, result.Preset))
@ -354,7 +354,7 @@ func BuildBenchmarkResultsView(
resultsBox := container.NewVBox(resultItems...)
resultsScroll := container.NewVScroll(resultsBox)
resultsScroll.SetMinSize(fyne.NewSize(0, 300))
// resultsScroll.SetMinSize(fyne.NewSize(0, 300)) // Removed for flexible sizing
resultsSection := container.NewBorder(
topResultsTitle,
@ -436,7 +436,7 @@ func BuildBenchmarkHistoryView(
runsList := container.NewVBox(runItems...)
runsScroll := container.NewVScroll(runsList)
runsScroll.SetMinSize(fyne.NewSize(0, 400))
// runsScroll.SetMinSize(fyne.NewSize(0, 400)) // Removed for flexible sizing
infoLabel := widget.NewLabel("Click on a benchmark run to view detailed results")
infoLabel.Alignment = fyne.TextAlignCenter

View File

@ -199,3 +199,68 @@ func BuildAudioCodecColorMap(codecs []string) map[string]color.Color {
}
return colorMap
}
// BuildGenericColorMap creates a rainbow color map for any list of options
// Uses distinct, vibrant colors to make navigation faster
func BuildGenericColorMap(options []string) map[string]color.Color {
colorMap := make(map[string]color.Color)
// Rainbow palette - vibrant and distinct colors
rainbowColors := []color.Color{
utils.MustHex("#EF4444"), // Red
utils.MustHex("#F97316"), // Orange
utils.MustHex("#F59E0B"), // Amber
utils.MustHex("#EAB308"), // Yellow
utils.MustHex("#84CC16"), // Lime
utils.MustHex("#22C55E"), // Green
utils.MustHex("#10B981"), // Emerald
utils.MustHex("#14B8A6"), // Teal
utils.MustHex("#06B6D4"), // Cyan
utils.MustHex("#0EA5E9"), // Sky
utils.MustHex("#3B82F6"), // Blue
utils.MustHex("#6366F1"), // Indigo
utils.MustHex("#8B5CF6"), // Violet
utils.MustHex("#A855F7"), // Purple
utils.MustHex("#D946EF"), // Fuchsia
utils.MustHex("#EC4899"), // Pink
}
for i, opt := range options {
colorMap[opt] = rainbowColors[i%len(rainbowColors)]
}
return colorMap
}
// BuildQualityColorMap creates a gradient-based color map for quality/preset options
// Higher quality = cooler colors (blue), lower quality = warmer colors (red/orange)
func BuildQualityColorMap(options []string) map[string]color.Color {
colorMap := make(map[string]color.Color)
// Quality gradient: red (fast/low) -> yellow -> green -> blue (slow/high)
qualityColors := []color.Color{
utils.MustHex("#EF4444"), // Red - ultrafast/lowest
utils.MustHex("#F97316"), // Orange - superfast
utils.MustHex("#F59E0B"), // Amber - veryfast
utils.MustHex("#EAB308"), // Yellow - faster
utils.MustHex("#84CC16"), // Lime - fast
utils.MustHex("#22C55E"), // Green - medium
utils.MustHex("#10B981"), // Emerald - slow
utils.MustHex("#14B8A6"), // Teal - slower
utils.MustHex("#06B6D4"), // Cyan - veryslow
utils.MustHex("#3B82F6"), // Blue - highest quality
}
for i, opt := range options {
colorMap[opt] = qualityColors[i%len(qualityColors)]
}
return colorMap
}
// BuildPixelFormatColorMap creates a color map for pixel format options
func BuildPixelFormatColorMap(formats []string) map[string]color.Color {
colorMap := make(map[string]color.Color)
for _, format := range formats {
colorMap[format] = GetPixelFormatColor(format)
}
return colorMap
}

View File

@ -75,6 +75,21 @@ func (m *MonoTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
}
func (m *MonoTheme) Size(name fyne.ThemeSizeName) float32 {
// Make UI elements larger and more readable
switch name {
case theme.SizeNamePadding:
return 8 // Increased from default 6
case theme.SizeNameInnerPadding:
return 10 // Increased from default 8
case theme.SizeNameText:
return 15 // Increased from default 14
case theme.SizeNameHeadingText:
return 20 // Increased from default 18
case theme.SizeNameSubHeadingText:
return 17 // Increased from default 16
case theme.SizeNameInputBorder:
return 2 // Keep default
}
return theme.DefaultTheme().Size(name)
}
@ -1125,7 +1140,7 @@ func (cs *ColoredSelect) showPopup() {
// Create scrollable list
list := container.NewVBox(items...)
scroll := container.NewVScroll(list)
scroll.SetMinSize(fyne.NewSize(300, 200))
// scroll.SetMinSize(fyne.NewSize(300, 200)) // Removed for flexible sizing
// Create popup
cs.popup = widget.NewPopUp(scroll, cs.window.Canvas())

View File

@ -149,7 +149,7 @@ func BuildMainMenu(modules []ModuleInfo, onModuleClick func(string), onModuleDro
gridBox := container.NewVBox(rows...)
scroll := container.NewVScroll(gridBox)
scroll.SetMinSize(fyne.NewSize(0, 0))
// scroll.SetMinSize(fyne.NewSize(0, 0)) // Removed for flexible sizing
body := container.NewBorder(
header,
@ -177,7 +177,7 @@ func buildModuleTile(mod ModuleInfo, tapped func(), dropped func([]fyne.URI)) fy
func buildQueueTile(completed, total int, queueColor, textColor color.Color, onClick func()) fyne.CanvasObject {
rect := canvas.NewRectangle(queueColor)
rect.CornerRadius = 6
rect.SetMinSize(fyne.NewSize(120, 40))
// rect.SetMinSize(fyne.NewSize(120, 40)) // Removed for flexible sizing
text := canvas.NewText(fmt.Sprintf("QUEUE: %d/%d", completed, total), textColor)
text.Alignment = fyne.TextAlignCenter

View File

@ -273,7 +273,7 @@ func BuildQueueView(
jobList := container.NewVBox(jobItems...)
// Use a scroll container anchored to the top to avoid jumpy scroll-to-content behavior.
scrollable := container.NewScroll(jobList)
scrollable.SetMinSize(fyne.NewSize(0, 0))
// scrollable.SetMinSize(fyne.NewSize(0, 0)) // Removed for flexible sizing
scrollable.Offset = fyne.NewPos(0, 0)
body := container.NewBorder(
@ -409,7 +409,7 @@ func buildJobItem(
// Card background
card := canvas.NewRectangle(bgColor)
card.CornerRadius = 4
card.SetMinSize(fyne.NewSize(0, 140)) // Fixed minimum height to prevent jumping
// card.SetMinSize(fyne.NewSize(0, 140)) // Removed for flexible sizing
item := container.NewPadded(
container.NewMax(card, content),

View File

@ -156,10 +156,11 @@ func (l *fixedHSplitLayout) Layout(objects []fyne.CanvasObject, size fyne.Size)
if ratio <= 0 {
ratio = 0.6
}
if ratio < 0.1 {
ratio = 0.1
} else if ratio > 0.9 {
ratio = 0.9
// Much more flexible split - allow dragging from 5% to 95%
if ratio < 0.05 {
ratio = 0.05
} else if ratio > 0.95 {
ratio = 0.95
}
leadWidth := float32(total * ratio)

View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"image/color"
"os/exec"
"runtime"
@ -161,6 +162,7 @@ func buildSettingsView(state *appState) fyne.CanvasObject {
tabs := container.NewAppTabs(
container.NewTabItem("Dependencies", buildDependenciesTab(state)),
container.NewTabItem("Benchmark", buildBenchmarkTab(state)),
container.NewTabItem("Preferences", buildPreferencesTab(state)),
)
tabs.SetTabLocation(container.TabLocationTop)
@ -272,6 +274,50 @@ func buildDependenciesTab(state *appState) fyne.CanvasObject {
return content
}
func buildBenchmarkTab(state *appState) fyne.CanvasObject {
content := container.NewVBox()
// Header
header := widget.NewLabel("Hardware Benchmark")
header.TextStyle = fyne.TextStyle{Bold: true}
content.Add(header)
desc := widget.NewLabel("Test your system's video encoding performance to get optimal encoder recommendations.")
desc.Wrapping = fyne.TextWrapWord
content.Add(desc)
content.Add(widget.NewSeparator())
// Run benchmark button
runBtn := widget.NewButton("Run Hardware Benchmark", func() {
state.showBenchmark()
})
runBtn.Importance = widget.MediumImportance
content.Add(container.NewCenter(runBtn))
// Show recent results if available
cfg, err := loadBenchmarkConfig()
if err == nil && len(cfg.History) > 0 {
content.Add(widget.NewSeparator())
recentHeader := widget.NewLabel("Recent Benchmarks")
recentHeader.TextStyle = fyne.TextStyle{Bold: true}
content.Add(recentHeader)
for _, run := range cfg.History[:min(3, len(cfg.History))] {
timestamp := run.Timestamp.Format("Jan 2, 2006 at 3:04 PM")
summary := fmt.Sprintf("%s - Recommended: %s (%s)",
timestamp, run.RecommendedEncoder, run.RecommendedPreset)
runLabel := widget.NewLabel(summary)
runLabel.TextStyle = fyne.TextStyle{Italic: true}
content.Add(runLabel)
}
}
return content
}
func buildPreferencesTab(state *appState) fyne.CanvasObject {
content := container.NewVBox()