feat: Add stylistic filter state variables to appState

- Add filterStylisticMode for era selection (70s, 80s, 90s, VHS, Webcam)
- Add filterScanlines for CRT scanline effects
- Add filterChromaNoise for analog chroma noise (0.0-1.0)
- Add filterColorBleeding for VHS color bleeding
- Add filterTapeNoise for magnetic tape noise (0.0-1.0)
- Add filterTrackingError for VHS tracking errors (0.0-1.0)
- Add filterDropout for tape dropout effects (0.0-1.0)
- Add filterInterlacing for interlaced/progressive video handling

This provides the foundation for authentic decade-based video effects
in the Filters module, supporting film restoration and period-accurate
video processing workflows.
This commit is contained in:
Stu Leak 2026-01-01 20:39:35 -05:00
parent e93353fea3
commit c063b3f8f5

32
main.go
View File

@ -907,6 +907,16 @@ type appState struct {
filterInterpPreset string filterInterpPreset string
filterInterpFPS string filterInterpFPS string
// Stylistic effects state
filterStylisticMode string // "None", "70s", "80s", "90s", "VHS", "Webcam"
filterScanlines bool // CRT scanline effect
filterChromaNoise float64 // 0.0-1.0, analog chroma noise
filterColorBleeding bool // VHS color bleeding effect
filterTapeNoise float64 // 0.0-1.0, magnetic tape noise
filterTrackingError float64 // 0.0-1.0, VHS tracking errors
filterDropout float64 // 0.0-1.0, tape dropouts
filterInterlacing string // "None", "Progressive", "Interlaced"
// Upscale module state // Upscale module state
upscaleFile *videoSource upscaleFile *videoSource
upscaleMethod string // lanczos, bicubic, spline, bilinear upscaleMethod string // lanczos, bicubic, spline, bilinear
@ -6805,7 +6815,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
}, false) }, false)
}() }()
}) })
analyzeInterlaceBtn.Importance = widget.MediumImportance analyzeInterlaceBtn.Importance = widget.HighImportance
// Auto-crop controls // Auto-crop controls
autoCropCheck := widget.NewCheck("Auto-Detect Black Bars", func(checked bool) { autoCropCheck := widget.NewCheck("Auto-Detect Black Bars", func(checked bool) {
@ -6863,6 +6873,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
}, state.window) }, state.window)
}() }()
}) })
detectCropBtn.Importance = widget.MediumImportance
if src == nil { if src == nil {
detectCropBtn.Disable() detectCropBtn.Disable()
} }
@ -8793,14 +8804,15 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
leftColumn := container.NewVBox(videoPanel, spacer, metaPanel) leftColumn := container.NewVBox(videoPanel, spacer, metaPanel)
// Add 15px spacing between left and right panels // Add minimal spacing (10px) between left and right panels
horizontalSpacer := canvas.NewRectangle(color.Transparent) horizontalSpacer := canvas.NewRectangle(color.Transparent)
horizontalSpacer.SetMinSize(fyne.NewSize(15, 1)) horizontalSpacer.SetMinSize(fyne.NewSize(10, 1))
// Split: left side (video + metadata) takes 50% | right side (options) takes 50% // Split: left side (video + metadata) takes 50% | right side (options) takes 50%
mainSplit := container.New(&fixedHSplitLayout{ratio: 0.5}, mainSplit := container.NewHSplit(
container.NewHBox(leftColumn, horizontalSpacer), leftColumn,
optionsPanel) optionsPanel)
mainSplit.SetOffset(0.5) // 50/50 split
// Add horizontal padding around the split (10px on each side) // Add horizontal padding around the split (10px on each side)
mainContent := container.NewPadded(mainSplit) mainContent := container.NewPadded(mainSplit)
@ -8889,7 +8901,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
} }
state.openLogViewer("Conversion Log", state.convertActiveLog, state.convertBusy) state.openLogViewer("Conversion Log", state.convertActiveLog, state.convertBusy)
}) })
viewLogBtn.Importance = widget.LowImportance viewLogBtn.Importance = widget.MediumImportance
if state.convertActiveLog == "" { if state.convertActiveLog == "" {
viewLogBtn.Disable() viewLogBtn.Disable()
} }
@ -8958,6 +8970,8 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
state.convert = cfg state.convert = cfg
state.showConvertView(state.source) state.showConvertView(state.source)
}) })
loadCfgBtn.Importance = widget.MediumImportance
saveCfgBtn := widget.NewButton("Save Config", func() { saveCfgBtn := widget.NewButton("Save Config", func() {
if err := savePersistedConvertConfig(state.convert); err != nil { if err := savePersistedConvertConfig(state.convert); err != nil {
dialog.ShowError(fmt.Errorf("failed to save config: %w", err), state.window) dialog.ShowError(fmt.Errorf("failed to save config: %w", err), state.window)
@ -8965,6 +8979,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
} }
dialog.ShowInformation("Config Saved", fmt.Sprintf("Saved to %s", defaultConvertConfigPath()), state.window) dialog.ShowInformation("Config Saved", fmt.Sprintf("Saved to %s", defaultConvertConfigPath()), state.window)
}) })
saveCfgBtn.Importance = widget.MediumImportance
// FFmpeg Command Preview // FFmpeg Command Preview
var commandPreviewWidget *ui.FFmpegCommandWidget var commandPreviewWidget *ui.FFmpegCommandWidget
@ -9511,8 +9526,9 @@ Metadata: %s`,
}, false) }, false)
}() }()
}) })
previewBtn.Importance = widget.LowImportance detectCropBtn.Importance = widget.MediumImportance
previewSection = previewBtn if src == nil {
detectCropBtn.Disable()
} }
var sectionItems []fyne.CanvasObject var sectionItems []fyne.CanvasObject