-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathwindow.go
More file actions
147 lines (129 loc) Β· 4.65 KB
/
window.go
File metadata and controls
147 lines (129 loc) Β· 4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package uv
import "github.com/charmbracelet/x/ansi"
// Window represents a rectangular area on the screen. It can be a root window
// with no parent, or a sub-window with a parent window. A window can have its
// own buffer or share the buffer of its parent window (view).
type Window struct {
*Buffer
method *WidthMethod
parent *Window
bounds Rectangle
}
var (
_ Screen = (*Window)(nil)
_ Drawable = (*Window)(nil)
)
// HasParent returns whether the window has a parent window. This can be used
// to determine if the window is a root window or a sub-window.
func (w *Window) HasParent() bool {
return w.parent != nil
}
// Parent returns the parent window of the current window.
// If the window does not have a parent, it returns nil.
func (w *Window) Parent() *Window {
return w.parent
}
// MoveTo moves the window to the specified x and y coordinates.
func (w *Window) MoveTo(x, y int) {
size := w.bounds.Size()
w.bounds.Min.X = x
w.bounds.Min.Y = y
w.bounds.Max.X = x + size.X
w.bounds.Max.Y = y + size.Y
}
// MoveBy moves the window by the specified delta x and delta y.
func (w *Window) MoveBy(dx, dy int) {
w.bounds.Min.X += dx
w.bounds.Min.Y += dy
w.bounds.Max.X += dx
w.bounds.Max.Y += dy
}
// Clone creates an exact copy of the window, including its buffer and values.
// The cloned window will have the same parent and method as the original
// window.
func (w *Window) Clone() *Window {
return w.CloneArea(w.Buffer.Bounds())
}
// CloneArea creates an exact copy of the window, including its buffer and
// values, but only within the specified area. The cloned window will have the
// same parent and method as the original window, but its bounds will be
// limited to the specified area.
func (w *Window) CloneArea(area Rectangle) *Window {
clone := new(Window)
clone.Buffer = w.Buffer.CloneArea(area)
clone.parent = w.parent
clone.method = w.method
clone.bounds = area
return clone
}
// Resize resizes the window to the specified width and height.
func (w *Window) Resize(width, height int) {
// Only resize the buffer if this window owns its buffer.
if w.parent == nil || w.Buffer != w.parent.Buffer {
w.Buffer.Resize(width, height)
}
w.bounds.Max.X = w.bounds.Min.X + width
w.bounds.Max.Y = w.bounds.Min.Y + height
}
// WidthMethod returns the method used to calculate the width of characters in
// the window.
func (w *Window) WidthMethod() WidthMethod {
return *w.method
}
// Bounds returns the bounds of the window as a rectangle.
func (w *Window) Bounds() Rectangle {
return w.bounds
}
// NewWindow creates a new window with its own buffer relative to the parent
// window at the specified position and size.
//
// This will panic if width or height is negative.
func (w *Window) NewWindow(x, y, width, height int) *Window {
return newWindow(w, x, y, width, height, w.method, false)
}
// NewView creates a new view into the parent window at the specified position
// and size. Unlike [Window.NewWindow], this view shares the same buffer as the
// parent window.
func (w *Window) NewView(x, y, width, height int) *Window {
return newWindow(w, x, y, width, height, w.method, true)
}
// NewWindow creates a new root [Window] with the given size and width method.
// If the method is nil, it defaults to [ansi.WcWidth].
//
// The [WidthMethod] is used to calculate the width of characters in the
// window, which is important for correctly rendering text, especially when
// dealing with wide characters, combining characters, emojis, and other
// Unicode characters that may have varying widths.
//
// Use [ansi.WcWidth] as the default width method, which is a common
// implementation that handles a wide range of Unicode characters according to
// the Unicode Standard. Use [ansi.GraphemeWidth] if you know that your
// terminal supports grapheme clusters and proper rendering of combining
// characters and emojis, and you want to ensure that the width calculations
// are based on grapheme clusters rather than individual code points.
//
// This will panic if width or height is negative.
func NewWindow(width, height int, method WidthMethod) *Window {
if method == nil {
method = ansi.WcWidth
}
return newWindow(nil, 0, 0, width, height, &method, false)
}
// SetWidthMethod sets the width method for the window.
func (w *Window) SetWidthMethod(method WidthMethod) {
w.method = &method
}
// newWindow creates a new [Window] with the specified parent, position,
// method, and size.
func newWindow(parent *Window, x, y, width, height int, method *WidthMethod, view bool) *Window {
w := new(Window)
if view {
w.Buffer = parent.Buffer
} else {
w.Buffer = NewBuffer(width, height)
}
w.parent = parent
w.method = method
w.bounds = Rect(x, y, width, height)
return w
}