okami.mom/ultraviolet
git clone https://git.nkp.pet/okami.mom/ultraviolet
356d603
main
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 11method * WidthMethod 12parent * Window 13bounds 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 { 24return 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 { 30return w .parent 31} 32 33// MoveTo moves the window to the specified x and y coordinates. 34func (w * Window )MoveTo (x ,y int ) { 35size := w .bounds .Size () 36w .bounds .Min .X = x 37w .bounds .Min .Y = y 38w .bounds .Max .X = x + size .X 39w .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 ) { 44w .bounds .Min .X += dx 45w .bounds .Min .Y += dy 46w .bounds .Max .X += dx 47w .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 { 54return 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 { 62clone := new (Window ) 63clone .Buffer = w .Buffer .CloneArea (area ) 64clone .parent = w .parent 65clone .method = w .method 66clone .bounds = area 67return 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. 73if w .parent == nil || w .Buffer != w .parent .Buffer { 74w .Buffer .Resize (width ,height ) 75 } 76w .bounds .Max .X = w .bounds .Min .X + width 77w .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 { 83return * w .method 84} 85 86// Bounds returns the bounds of the window as a rectangle. 87func (w * Window )Bounds ()Rectangle { 88return 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 { 96return 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 { 103return 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 { 123if method == nil { 124method = ansi .WcWidth 125 } 126return 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 ) { 131w .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 { 137w := new (Window ) 138if view { 139w .Buffer = parent .Buffer 140 }else { 141w .Buffer = NewBuffer (width ,height ) 142 } 143w .parent = parent 144w .method = method 145w .bounds = Rect (x ,y ,width ,height ) 146return w 147}