1// Package screen provides functions and helpers to manipulate a [uv.Screen].
2package screen
3
4import uv "github.com/charmbracelet/ultraviolet"
5
6// Clear clears the screen with empty cells. This is equivalent to filling the
7// screen with empty cells.
8//
9// If the screen implements a [Clear] method, it will be called instead of
10// filling the screen with empty cells.
11func Clear(scr uv.Screen) {
12 if c, ok := scr.(interface {
13 Clear()
14 }); ok {
15 c.Clear()
16 return
17 }
18 Fill(scr, nil)
19}
20
21// ClearArea clears the given area of the screen with empty cells. This is
22// equivalent to filling the area with empty cells.
23//
24// If the screen implements a [ClearArea] method, it will be called instead of
25// filling the area with empty cells.
26func ClearArea(scr uv.Screen, area uv.Rectangle) {
27 if c, ok := scr.(interface {
28 ClearArea(area uv.Rectangle)
29 }); ok {
30 c.ClearArea(area)
31 return
32 }
33 FillArea(scr, nil, area)
34}
35
36// Fill fills the screen with the given cell. If the cell is nil, it fills the
37// screen with empty cells.
38//
39// If the screen implements a [Fill] method, it will be called instead of
40// filling the screen with empty cells.
41func Fill(scr uv.Screen, cell *uv.Cell) {
42 if f, ok := scr.(interface {
43 Fill(cell *uv.Cell)
44 }); ok {
45 f.Fill(cell)
46 return
47 }
48 FillArea(scr, cell, scr.Bounds())
49}
50
51// FillArea fills the given area of the screen with the given cell. If the cell
52// is nil, it fills the area with empty cells.
53//
54// If the screen implements a [FillArea] method, it will be called instead of
55// filling the area with empty cells.
56func FillArea(scr uv.Screen, cell *uv.Cell, area uv.Rectangle) {
57 if f, ok := scr.(interface {
58 FillArea(cell *uv.Cell, area uv.Rectangle)
59 }); ok {
60 f.FillArea(cell, area)
61 return
62 }
63 for y := area.Min.Y; y < area.Max.Y; y++ {
64 for x := area.Min.X; x < area.Max.X; x++ {
65 scr.SetCell(x, y, cell)
66 }
67 }
68}
69
70// CloneArea clones the given area of the screen and returns a new buffer
71// with the same size as the area. The new buffer will contain the same cells
72// as the area in the screen.
73// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again.
74//
75// If the screen implements a [CloneArea] method, it will be called instead of
76// cloning the area manually.
77func CloneArea(scr uv.Screen, area uv.Rectangle) *uv.Buffer {
78 if c, ok := scr.(interface {
79 CloneArea(area uv.Rectangle) *uv.Buffer
80 }); ok {
81 return c.CloneArea(area)
82 }
83 buf := uv.NewBuffer(area.Dx(), area.Dy())
84 for y := area.Min.Y; y < area.Max.Y; y++ {
85 for x := area.Min.X; x < area.Max.X; x++ {
86 cell := scr.CellAt(x, y)
87 if cell == nil || cell.IsZero() {
88 continue
89 }
90 buf.SetCell(x-area.Min.X, y-area.Min.Y, cell.Clone())
91 }
92 }
93 return buf
94}
95
96// Clone creates a new [uv.Buffer] clone of the given screen. The new buffer will
97// have the same size as the screen and will contain the same cells.
98// Use [uv.Buffer.Draw] to draw the cloned buffer to a screen again.
99//
100// If the screen implements a [Clone] method, it will be called instead of
101// cloning the entire screen manually.
102func Clone(scr uv.Screen) *uv.Buffer {
103 if c, ok := scr.(interface {
104 Clone() *uv.Buffer
105 }); ok {
106 return c.Clone()
107 }
108 return CloneArea(scr, scr.Bounds())
109}