free.go RawHistoryFolder

1package core
2
3// Free floats: a tile the user floated with toggle-floating (or dragged
4// out, drag.go) floats over the columns at a size and centre core owns.
5// The centre is a fraction of the usable area, so the window keeps its
6// relative place across stash, workspace and monitor moves.
7
8// freeNudge is how far a keyboard move shifts a free float, logical px.
9const freeNudge = 50
10
11// freeMinSize is the smallest client size a free float is resized to.
12const freeMinSize = 64
13
14// ToggleFloating turns the focused tile into a free float at its current
15// size, centred; a float (free or native) returns to the columns: a free
16// one to its former place, a native one as a new column. A fullscreen or
17// stashed window is left alone.
18func (w *Workspace) ToggleFloating() {
19	id, ok := w.Focused()
20	if !ok || id == w.fullscreen || w.stashIndex(id) >= 0 {
21		return
22	}
23	if i := w.floatIndex(id); i >= 0 {
24		back := w.Floats[i].back
25		w.RemoveWindow(id)
26		w.restore(id, back)
27		return
28	}
29	r, ok := w.placed(id)
30	if !ok {
31		return
32	}
33	// Its slot is released: the slot column refills without it.
34	back := w.tilePlace(id)
35	back.slot = 0
36	w.dropSlotOf(id)
37	w.RemoveWindow(id)
38	w.Floats = append(w.Floats, Float{
39		ID: id, W: max(r.W-2*w.border, 1), H: max(r.H-2*w.border, 1),
40		free: true, cx: 0.5, cy: 0.5, back: back,
41	})
42	w.floatFocus, w.stashFocus = true, false
43}
44
45// placed is the rect of window id in the current layout.
46func (w *Workspace) placed(id WindowID) (Rect, bool) {
47	for _, p := range w.Layout() {
48		if p.ID == id && !p.Hidden {
49			return p.Rect, true
50		}
51	}
52	return Rect{}, false
53}
54
55// focusedFree returns the index of the focused free float, or -1.
56func (w *Workspace) focusedFree() int {
57	id, ok := w.Focused()
58	if !ok || !w.floatFocus {
59		return -1
60	}
61	if i := w.floatIndex(id); i >= 0 && w.Floats[i].free && id != w.fullscreen {
62		return i
63	}
64	return -1
65}
66
67// freeAction runs a move or resize action on the focused free float and
68// reports whether it did: moves shift it by freeNudge, resizes change its
69// size by a share of the usable area.
70func (w *Workspace) freeAction(a Action) bool {
71	i := w.focusedFree()
72	if i < 0 {
73		return false
74	}
75	f := &w.Floats[i]
76	u := w.Usable
77	if axis, step, ok := ResizeArg(a); ok {
78		if u.W <= 0 || u.H <= 0 {
79			return true
80		}
81		// The size is the client's: the border must fit too. A width
82		// step is in cells, a cell being Usable.W/MaxColumns.
83		if axis == ResizeWidth {
84			f.W = max(min(f.W+step*u.W/max(w.MaxColumns, 1), u.W-2*w.border), freeMinSize)
85		} else {
86			f.H = max(min(f.H+u.H*step/100, u.H-2*w.border), freeMinSize)
87		}
88		w.clampFree(f)
89		return true
90	}
91	dx, dy := 0, 0
92	switch a {
93	case ActionMoveColumnLeft:
94		dx = -freeNudge
95	case ActionMoveColumnRight:
96		dx = freeNudge
97	case ActionMoveWindowUp:
98		dy = -freeNudge
99	case ActionMoveWindowDown:
100		dy = freeNudge
101	default:
102		return false
103	}
104	if u.W <= 0 || u.H <= 0 {
105		return true
106	}
107	w.moveFree(f, w.floatRect(*f), dx, dy)
108	return true
109}
110
111// moveFree puts free float f at rect r shifted by dx, dy, kept inside
112// the usable area.
113func (w *Workspace) moveFree(f *Float, r Rect, dx, dy int) {
114	u := w.Usable
115	x := min(max(r.X+dx, u.X), u.X+u.W-r.W)
116	y := min(max(r.Y+dy, u.Y), u.Y+u.H-r.H)
117	f.cx = float64(x-u.X+r.W/2) / float64(u.W)
118	f.cy = float64(y-u.Y+r.H/2) / float64(u.H)
119}
120
121// clampFree keeps the centre of f where its rect stays inside the area.
122func (w *Workspace) clampFree(f *Float) {
123	w.moveFree(f, w.floatRect(*f), 0, 0)
124}

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 25

Tags 10

↑↓ moveenter openesc close