diff --git a/internal/ui/components.go b/internal/ui/components.go index 515df85..673a7ff 100644 --- a/internal/ui/components.go +++ b/internal/ui/components.go @@ -60,6 +60,12 @@ func (m *MonoTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) c case theme.ColorNameInputBackground: // Match dropdown background tone for input fields return utils.MustHex("#344256") + case theme.ColorNameInputBorder: + // Keep input borders visually flat against the background + return utils.MustHex("#344256") + case theme.ColorNameFocus: + // Avoid bright focus outlines on dark input fields + return utils.MustHex("#344256") case theme.ColorNameForeground: // Ensure good contrast on dark backgrounds return color.White @@ -358,11 +364,17 @@ func TintedBar(col color.Color, body fyne.CanvasObject) fyne.CanvasObject { // NewRatioRow lays out two objects with a fixed width ratio for the left item. func NewRatioRow(left, right fyne.CanvasObject, leftRatio float32) *fyne.Container { - return container.New(&ratioRowLayout{leftRatio: leftRatio}, left, right) + return NewRatioRowWithGap(left, right, leftRatio, 0) +} + +// NewRatioRowWithGap lays out two objects with a fixed width ratio and a gap between them. +func NewRatioRowWithGap(left, right fyne.CanvasObject, leftRatio float32, gap float32) *fyne.Container { + return container.New(&ratioRowLayout{leftRatio: leftRatio, gap: gap}, left, right) } type ratioRowLayout struct { leftRatio float32 + gap float32 } func (r *ratioRowLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { @@ -370,12 +382,20 @@ func (r *ratioRowLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { return } ratio := clampRatio(r.leftRatio) - leftWidth := size.Width * ratio - rightWidth := size.Width - leftWidth + gap := float32(0) + if r.gap > 0 { + gap = r.gap + } + availableWidth := size.Width - gap + if availableWidth < 0 { + availableWidth = 0 + } + leftWidth := availableWidth * ratio + rightWidth := availableWidth - leftWidth objects[0].Move(fyne.NewPos(0, 0)) objects[0].Resize(fyne.NewSize(leftWidth, size.Height)) - objects[1].Move(fyne.NewPos(leftWidth, 0)) + objects[1].Move(fyne.NewPos(leftWidth+gap, 0)) objects[1].Resize(fyne.NewSize(rightWidth, size.Height)) } @@ -1303,11 +1323,16 @@ func (cs *ColoredSelect) showPopup() { if dropWidth < 200 { dropWidth = 200 } - scroll.SetMinSize(fyne.NewSize(dropWidth, 300)) + visibleItems := min(len(cs.options), 6) + popupHeight := float32(visibleItems) * 36 + if popupHeight < 144 { + popupHeight = 144 + } + scroll.SetMinSize(fyne.NewSize(dropWidth, popupHeight)) // Create popup cs.popup = widget.NewPopUp(scroll, cs.window.Canvas()) - cs.popup.Resize(fyne.NewSize(dropWidth, 300)) + cs.popup.Resize(fyne.NewSize(dropWidth, popupHeight)) // Position popup below the select widget popupPos := fyne.CurrentApp().Driver().AbsolutePositionForObject(cs) diff --git a/main.go b/main.go index 4717be5..b83b2e7 100644 --- a/main.go +++ b/main.go @@ -7204,6 +7204,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { outputEntry := widget.NewEntry() outputEntry.SetText(state.convert.OutputBase) + outputEntry.SetMinSize(fyne.NewSize(0, 36)) var updatingOutput bool var autoNameCheck *widget.Check outputEntry.OnChanged = func(val string) { @@ -7223,6 +7224,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { outputDirEntry := widget.NewEntry() outputDirEntry.SetPlaceHolder("Output folder path") outputDirEntry.SetText(state.convert.OutputDir) + outputDirEntry.SetMinSize(fyne.NewSize(0, 36)) outputDirEntry.OnChanged = func(val string) { state.convert.OutputDir = val updateOutputHint() @@ -7652,26 +7654,30 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { } encoderPresetOptions := []string{"veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast", "superfast", "ultrafast"} - encoderPresetSelect := widget.NewSelect(encoderPresetOptions, func(value string) { + presetColorMap := make(map[string]color.Color, len(encoderPresetOptions)) + for _, opt := range encoderPresetOptions { + presetColorMap[opt] = utils.MustHex("#344256") + } + encoderPresetSelect := ui.NewColoredSelect(encoderPresetOptions, presetColorMap, func(value string) { state.convert.EncoderPreset = value logging.Debug(logging.CatUI, "encoder preset set to %s", value) updateEncoderPresetHint(value) if buildCommandPreview != nil { buildCommandPreview() } - }) + }, state.window) encoderPresetSelect.SetSelected(state.convert.EncoderPreset) updateEncoderPresetHint(state.convert.EncoderPreset) // Simple mode preset dropdown - simplePresetSelect := widget.NewSelect(encoderPresetOptions, func(value string) { + simplePresetSelect := ui.NewColoredSelect(encoderPresetOptions, presetColorMap, func(value string) { state.convert.EncoderPreset = value logging.Debug(logging.CatUI, "simple preset set to %s", value) updateEncoderPresetHint(value) if buildCommandPreview != nil { buildCommandPreview() } - }) + }, state.window) simplePresetSelect.SetSelected(state.convert.EncoderPreset) // Settings management for batch operations @@ -8950,11 +8956,12 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { // Advanced mode options - full controls with organized sections videoCodecLabel := widget.NewLabelWithStyle("Video Codec", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}) presetLabel := widget.NewLabelWithStyle("Encoder Preset (speed vs quality)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}) - videoCodecRow := ui.NewRatioRow(videoCodecLabel, presetLabel, 0.3) - videoCodecControls := ui.NewRatioRow( + videoCodecRow := ui.NewRatioRowWithGap(videoCodecLabel, presetLabel, 0.3, 10) + videoCodecControls := ui.NewRatioRowWithGap( container.NewPadded(videoCodecContainer), container.NewPadded(encoderPresetSelect), 0.3, + 10, ) advancedVideoEncodingBlock = container.NewVBox( @@ -9164,7 +9171,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject { return false } switch c.Focused().(type) { - case *widget.Entry, *widget.MultiLineEntry: + case *widget.Entry: return true default: return false