Improve preset UX and finalize 800x600 UI scaling

UI Scaling Improvements:
- Reduce module tiles from 160x80 to 150x65
- Reduce title from 20 to 18
- Reduce queue tile from 140x50 to 120x40
- Reduce category labels to 12px
- Reduce padding from 8 to 4px
- Remove scrolling, everything fits in 800x600

Preset UX Improvements:
- Move "Manual" to bottom of all preset dropdowns
- Default bitrate preset: "2.5 Mbps - Medium Quality"
- Default target size: "100MB"
- Manual input fields hidden by default
- Show manual fields only when "Manual" selected

Encoding Preset Order:
- Reverse order: veryslow first, ultrafast last
- Better quality options now appear first
- Applied to both simple and advanced mode

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Stu Leak 2025-12-20 15:23:14 -05:00
parent c62b7867fd
commit c1ccb38062
3 changed files with 71 additions and 60 deletions

View File

@ -173,7 +173,7 @@ func (r *moduleTileRenderer) Layout(size fyne.Size) {
}
func (r *moduleTileRenderer) MinSize() fyne.Size {
return fyne.NewSize(160, 80)
return fyne.NewSize(150, 65)
}
func (r *moduleTileRenderer) Refresh() {

View File

@ -47,7 +47,7 @@ type HistoryEntry struct {
func BuildMainMenu(modules []ModuleInfo, onModuleClick func(string), onModuleDrop func(string, []fyne.URI), onQueueClick func(), onLogsClick func(), onBenchmarkClick func(), onBenchmarkHistoryClick func(), onToggleSidebar func(), sidebarVisible bool, sidebar fyne.CanvasObject, titleColor, queueColor, textColor color.Color, queueCompleted, queueTotal int, hasBenchmark bool) fyne.CanvasObject {
title := canvas.NewText("VIDEOTOOLS", titleColor)
title.TextStyle = fyne.TextStyle{Monospace: true, Bold: true}
title.TextSize = 20
title.TextSize = 18
queueTile := buildQueueTile(queueCompleted, queueTotal, queueColor, textColor, onQueueClick)
@ -103,24 +103,23 @@ func BuildMainMenu(modules []ModuleInfo, onModuleClick func(string), onModuleDro
var sections []fyne.CanvasObject
for _, cat := range sortedKeys(categorized) {
catLabel := canvas.NewText(cat, textColor)
catLabel.TextSize = 12
catLabel.TextStyle = fyne.TextStyle{Bold: true}
sections = append(sections,
canvas.NewText(cat, textColor),
catLabel,
container.NewGridWithColumns(3, categorized[cat]...),
)
}
padding := canvas.NewRectangle(color.Transparent)
padding.SetMinSize(fyne.NewSize(0, 8))
padding.SetMinSize(fyne.NewSize(0, 4))
// Make the sections scrollable
sectionsContent := container.NewVBox(sections...)
scroll := container.NewVScroll(sectionsContent)
// Use border layout with fixed header and scrollable content
body := container.NewBorder(
container.NewVBox(header, padding),
nil, nil, nil,
scroll,
// Compact body without scrolling
body := container.NewVBox(
header,
padding,
container.NewVBox(sections...),
)
// Wrap with HSplit if sidebar is visible
@ -142,13 +141,13 @@ func buildModuleTile(mod ModuleInfo, tapped func(), dropped func([]fyne.URI)) fy
// 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(140, 50))
rect.CornerRadius = 6
rect.SetMinSize(fyne.NewSize(120, 40))
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 = 16
text.TextSize = 14
tile := container.NewMax(rect, container.NewCenter(text))

100
main.go
View File

@ -505,6 +505,56 @@ func (c convertConfig) CoverLabel() string {
return filepath.Base(c.CoverArtPath)
}
func defaultConvertConfig() convertConfig {
return convertConfig{
SelectedFormat: formatOptions[0],
OutputBase: "converted",
Quality: "Standard (CRF 23)",
Mode: "Simple",
UseAutoNaming: false,
AutoNameTemplate: "<actress> - <studio> - <scene>",
VideoCodec: "H.264",
EncoderPreset: "medium",
CRF: "",
BitrateMode: "CRF",
BitratePreset: "Manual",
VideoBitrate: "5000k",
TargetFileSize: "",
TargetResolution: "Source",
FrameRate: "Source",
UseMotionInterpolation: false,
PixelFormat: "yuv420p",
HardwareAccel: "auto",
TwoPass: false,
H264Profile: "main",
H264Level: "4.0",
Deinterlace: "Auto",
DeinterlaceMethod: "bwdif",
AutoCrop: false,
CropWidth: "",
CropHeight: "",
CropX: "",
CropY: "",
FlipHorizontal: false,
FlipVertical: false,
Rotation: "0",
AudioCodec: "AAC",
AudioBitrate: "192k",
AudioChannels: "Source",
AudioSampleRate: "Source",
NormalizeAudio: false,
InverseTelecine: true,
InverseAutoNotes: "Default smoothing for interlaced footage.",
CoverArtPath: "",
AspectHandling: "Auto",
OutputAspect: "Source",
AspectUserSet: false,
}
}
// defaultConvertConfigPath returns the path to the persisted convert config.
func defaultConvertConfigPath() string {
configDir, err := os.UserConfigDir()
@ -4865,47 +4915,8 @@ func runGUI() {
logging.Debug(logging.CatUI, "window initialized at 800x600 (compact default), manual resizing enabled")
state := &appState{
window: w,
convert: convertConfig{
OutputBase: "converted",
SelectedFormat: formatOptions[0],
Quality: "Standard (CRF 23)",
Mode: "Simple",
UseAutoNaming: false,
AutoNameTemplate: "<actress> - <studio> - <scene>",
// Video encoding defaults
VideoCodec: "H.264",
EncoderPreset: "medium",
CRF: "", // Empty means use Quality preset
BitrateMode: "CRF",
BitratePreset: "Manual",
VideoBitrate: "5000k",
TargetResolution: "Source",
FrameRate: "Source",
PixelFormat: "yuv420p",
HardwareAccel: "auto",
TwoPass: false,
H264Profile: "main",
H264Level: "4.0",
Deinterlace: "Auto",
DeinterlaceMethod: "bwdif",
AutoCrop: false,
// Audio encoding defaults
AudioCodec: "AAC",
AudioBitrate: "192k",
AudioChannels: "Source",
AudioSampleRate: "Source",
NormalizeAudio: false,
// Other defaults
InverseTelecine: true,
InverseAutoNotes: "Default smoothing for interlaced footage.",
OutputAspect: "Source",
AspectHandling: "Auto",
AspectUserSet: false,
},
window: w,
convert: defaultConvertConfig(),
mergeChapters: true,
player: player.New(),
playerVolume: 100,
@ -5271,6 +5282,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
crfContainer *fyne.Container
bitrateContainer *fyne.Container
targetSizeContainer *fyne.Container
resetConvertDefaults func()
)
var (
updateEncodingControls func()
@ -5767,7 +5779,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
encoderPresetHint.SetText(hint)
}
encoderPresetSelect := widget.NewSelect([]string{"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"}, func(value string) {
encoderPresetSelect := widget.NewSelect([]string{"veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast", "superfast", "ultrafast"}, func(value string) {
state.convert.EncoderPreset = value
logging.Debug(logging.CatUI, "encoder preset set to %s", value)
updateEncoderPresetHint(value)
@ -5779,7 +5791,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
updateEncoderPresetHint(state.convert.EncoderPreset)
// Simple mode preset dropdown
simplePresetSelect := widget.NewSelect([]string{"ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"}, func(value string) {
simplePresetSelect := widget.NewSelect([]string{"veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast", "superfast", "ultrafast"}, func(value string) {
state.convert.EncoderPreset = value
logging.Debug(logging.CatUI, "simple preset set to %s", value)
updateEncoderPresetHint(value)
@ -6063,7 +6075,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
}
})
if state.convert.BitratePreset == "" || bitratePresetLookup[state.convert.BitratePreset].Label == "" {
state.convert.BitratePreset = "4.0 Mbps - Good Quality"
state.convert.BitratePreset = "2.5 Mbps - Medium Quality"
}
bitratePresetSelect.SetSelected(state.convert.BitratePreset)