turbo-editors/turbo-corepublic Fork 0
v1.0.1
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

rect.go · 86 lines · 2.9 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 18h ago1// Package ui is the widget framework the editor is built from: a desktop
2// holding movable windows, a menu bar with drop-down menus, modal dialogs,
3// buttons, input lines and list boxes — the Turbo Vision furniture, drawn on
4// tcell.
5//
6// Nothing here knows about Go source, buffers or language servers. Widgets
7// draw through a clipping Painter and answer key and mouse events; what they
8// mean is decided by the package above.
9package ui
10
11// Rect is a rectangle of terminal cells: its top-left corner and its size.
12//
13// A rectangle with a zero or negative width or height is empty and covers no
14// cell at all, which is what an off-screen or fully clipped widget reduces to.
15type Rect struct {
16 X, Y, W, H int
17}
18
19// Right returns the column just past the rectangle's right edge.
20func (r Rect) Right() int { return r.X + r.W }
21
22// Bottom returns the row just past the rectangle's bottom edge.
23func (r Rect) Bottom() int { return r.Y + r.H }
24
25// IsEmpty reports whether the rectangle covers no cell.
26func (r Rect) IsEmpty() bool { return r.W <= 0 || r.H <= 0 }
27
28// Contains reports whether the cell at (x, y) is inside the rectangle.
29func (r Rect) Contains(x, y int) bool {
30 return x >= r.X && x < r.Right() && y >= r.Y && y < r.Bottom()
31}
32
33// Intersect returns the rectangle covered by both r and other, which is empty
34// when they do not overlap.
35func (r Rect) Intersect(other Rect) Rect {
36 x := max(r.X, other.X)
37 y := max(r.Y, other.Y)
38 right := min(r.Right(), other.Right())
39 bottom := min(r.Bottom(), other.Bottom())
40
41 if right <= x || bottom <= y {
42 return Rect{X: x, Y: y}
43 }
44 return Rect{X: x, Y: y, W: right - x, H: bottom - y}
45}
46
47// Inset returns the rectangle shrunk by dx on the left and right and by dy on
48// the top and bottom. It is how a widget moves inside its own frame.
49//
50// body := window.Bounds().Inset(1, 1)
51func (r Rect) Inset(dx, dy int) Rect {
52 return Rect{X: r.X + dx, Y: r.Y + dy, W: r.W - 2*dx, H: r.H - 2*dy}
53}
54
55// Move returns the rectangle shifted by (dx, dy), keeping its size.
56func (r Rect) Move(dx, dy int) Rect {
57 return Rect{X: r.X + dx, Y: r.Y + dy, W: r.W, H: r.H}
58}
59
60// WithSize returns the rectangle with a different size and the same corner.
61func (r Rect) WithSize(w, h int) Rect {
62 return Rect{X: r.X, Y: r.Y, W: w, H: h}
63}
64
65// CenteredIn returns a rectangle of the same size placed in the middle of
66// outer, which is where a dialog opens.
67func (r Rect) CenteredIn(outer Rect) Rect {
68 return Rect{
69 X: outer.X + (outer.W-r.W)/2,
70 Y: outer.Y + (outer.H-r.H)/2,
71 W: r.W,
72 H: r.H,
73 }
74}
75
76// ClampInto returns the rectangle moved — never resized — so that it lies
77// inside outer, as far as its size allows. A window dragged past the edge of
78// the screen comes back this way.
79func (r Rect) ClampInto(outer Rect) Rect {
80 out := r
81 out.X = min(out.X, outer.Right()-out.W)
82 out.Y = min(out.Y, outer.Bottom()-out.H)
83 out.X = max(out.X, outer.X)
84 out.Y = max(out.Y, outer.Y)
85 return out
86}