v0.21.0 73bf644

modal_sizing.go RawHistoryFolder

1package component
2
3import (
4	"github.com/bnema/dumber/internal/ui/layout"
5	"github.com/jwijenbergh/puregotk/v4/gtk"
6)
7
8// ModalSizeConfig holds configuration for modal sizing calculations.
9type ModalSizeConfig struct {
10	WidthPct       float64 // Percentage of parent width (e.g., 0.6)
11	MaxWidth       int     // Maximum width in pixels
12	TopMarginPct   float64 // Top margin as percentage of parent height
13	FallbackWidth  int     // Fallback when parent not allocated
14	FallbackHeight int     // Fallback height
15}
16
17// RowHeightDefaults holds default (unscaled) row heights for list-based modals.
18// These are base pixel values that should be multiplied by UI scale.
19type RowHeightDefaults struct {
20	Standard int // Standard list row (e.g., session row, history row)
21	Compact  int // Compact row (e.g., tree row, sub-item)
22	Divider  int // Divider/separator row
23}
24
25// ListDisplayDefaults holds display limits for list-based modals.
26type ListDisplayDefaults struct {
27	MaxVisibleRows int // Maximum rows visible before scrolling
28	MaxResults     int // Maximum results to fetch/display
29}
30
31// Package-level defaults for row heights.
32var DefaultRowHeights = RowHeightDefaults{
33	Standard: 50,
34	Compact:  28,
35	Divider:  30,
36}
37
38// OmniboxSizeDefaults provides default sizing for omnibox modal.
39var OmniboxSizeDefaults = ModalSizeConfig{
40	WidthPct:       0.8,
41	MaxWidth:       800,
42	TopMarginPct:   0.2,
43	FallbackWidth:  800,
44	FallbackHeight: 600,
45}
46
47// OmniboxListDefaults provides display limits for omnibox modal.
48var OmniboxListDefaults = ListDisplayDefaults{
49	MaxVisibleRows: 10,
50	MaxResults:     10,
51}
52
53// SessionManagerSizeDefaults provides default sizing for session manager modal.
54var SessionManagerSizeDefaults = ModalSizeConfig{
55	WidthPct:       0.6,
56	MaxWidth:       600,
57	TopMarginPct:   0.15,
58	FallbackWidth:  600,
59	FallbackHeight: 600,
60}
61
62// SessionManagerListDefaults provides display limits for session manager modal.
63var SessionManagerListDefaults = ListDisplayDefaults{
64	MaxVisibleRows: 6,
65	MaxResults:     50,
66}
67
68// CalculateModalDimensions computes width and top margin based on parent overlay.
69// Returns calculated width and top margin in pixels.
70func CalculateModalDimensions(parent layout.OverlayWidget, cfg ModalSizeConfig) (width, marginTop int) {
71	var parentWidth, parentHeight int
72
73	if parent != nil {
74		parentWidth = parent.GetAllocatedWidth()
75		parentHeight = parent.GetAllocatedHeight()
76	}
77
78	if parentWidth <= 0 {
79		parentWidth = cfg.FallbackWidth
80	}
81	if parentHeight <= 0 {
82		parentHeight = cfg.FallbackHeight
83	}
84
85	width = int(float64(parentWidth) * cfg.WidthPct)
86	if width > cfg.MaxWidth {
87		width = cfg.MaxWidth
88	}
89
90	marginTop = int(float64(parentHeight) * cfg.TopMarginPct)
91	return width, marginTop
92}
93
94// SetScrolledWindowHeight safely sets min/max content height on a ScrolledWindow.
95// Resets min to -1 first to avoid GTK assertion (min <= max) when shrinking.
96func SetScrolledWindowHeight(sw *gtk.ScrolledWindow, height int) {
97	if sw == nil {
98		return
99	}
100	sw.SetMinContentHeight(-1)
101	sw.SetMaxContentHeight(height)
102	sw.SetMinContentHeight(height)
103}
104
105// MeasureWidgetHeight returns the natural height of a widget for a given width.
106// Returns 0 if widget is nil or measurement fails.
107func MeasureWidgetHeight(widget *gtk.Widget, forWidth int) int {
108	if widget == nil {
109		return 0
110	}
111	var minH, natH int
112	widget.Measure(gtk.OrientationVerticalValue, forWidth, &minH, &natH, nil, nil)
113	return natH
114}
115
116// ScaleValue scales a base pixel value by UI scale factor.
117// Returns the base value if scale is <= 0.
118func ScaleValue(base int, uiScale float64) int {
119	if uiScale <= 0 {
120		uiScale = 1.0
121	}
122	return int(float64(base) * uiScale)
123}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close