screen.go

  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}