From 29327831431b9dcc05086db344e768276be6f97e Mon Sep 17 00:00:00 2001 From: mixeme Date: Mon, 15 Jun 2026 20:36:53 +0300 Subject: [PATCH] Stabilize Jobs pane layout Replace the resizable HSplit on the Jobs tab with a border layout that keeps the job list pane at a stable minimum width. The left pane now uses a small custom layout that asks Fyne for the content minimum size and applies at least 480 logical pixels. This prevents the divider from moving when the selected job changes while still allowing the toolbar buttons, including Delete, to fit when their calculated minimum width is larger. Only the Jobs tab layout is changed; settings, storage, scheduler behavior, and documentation are intentionally left untouched. --- src/gui/app.go | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/gui/app.go b/src/gui/app.go index 1f57ae1..4baea6a 100644 --- a/src/gui/app.go +++ b/src/gui/app.go @@ -22,6 +22,7 @@ import ( const appID = "io.github.pysentry.desktop" const allFolders = "All" const noFolder = "No folder" +const minJobsSidebarWidth float32 = 480 // The GUI package aliases core types to keep widget callbacks short. The actual // durable model still lives in src/core, so GUI code does not define a second @@ -396,8 +397,10 @@ func newMainView(w fyne.Window) fyne.CanvasObject { }) scheduler.Start() + fixedSidebar := container.New(minWidthLayout{width: minJobsSidebarWidth}, sidebar) + jobsView := container.NewBorder(nil, nil, fixedSidebar, nil, container.NewPadded(details)) tabs := container.NewAppTabs( - container.NewTabItemWithIcon("Jobs", theme.ListIcon(), container.NewHSplit(sidebar, container.NewPadded(details))), + container.NewTabItemWithIcon("Jobs", theme.ListIcon(), jobsView), container.NewTabItemWithIcon("History", theme.HistoryIcon(), history), container.NewTabItemWithIcon("Settings", theme.SettingsIcon(), settingsView(w, store, &jobs)), ) @@ -406,6 +409,38 @@ func newMainView(w fyne.Window) fyne.CanvasObject { return tabs } +type minWidthLayout struct { + width float32 +} + +func (layout minWidthLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { + width := layout.width + var height float32 + for _, object := range objects { + if !object.Visible() { + continue + } + min := object.MinSize() + if min.Width > width { + width = min.Width + } + if min.Height > height { + height = min.Height + } + } + return fyne.NewSize(width, height) +} + +func (layout minWidthLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { + for _, object := range objects { + if !object.Visible() { + continue + } + object.Move(fyne.NewPos(0, 0)) + object.Resize(size) + } +} + func statusText(j job) string { if !j.Enabled { return "Paused"