okami.mom/ultraviolet

git clone https://git.nkp.pet/okami.mom/ultraviolet

Ayman Bagabasrefactor(terminal): rename NewScreen to NewWindow356d603

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