Working on buffer stuff...

Trying to figure out how/if it fits...
This commit is contained in:
2025-10-17 16:36:29 -05:00
parent 6aaaa68228
commit 25777066cd
4 changed files with 147 additions and 74 deletions

View File

@@ -27,7 +27,6 @@ import (
)
type Buffer struct {
// cells [][]Cell
cells map[Coord]Cell
maxX, maxY int
minX, minY int
@@ -46,6 +45,22 @@ func (b *Buffer) Draw(x, y int, screen tcell.Screen) {
}
}
// MoveTo moves the minimum x and y of the buffer to x, y
// All cell coordinates are updated accordingly
func (b *Buffer) MoveTo(x, y int) {
diffX := b.minX - x
diffY := b.minY - y
cells := make(map[Coord]Cell)
for k, v := range b.cells {
cells[Coord{X: k.X - diffX, Y: k.Y - diffY}] = v
}
}
func (b *Buffer) Clear() {
b.cells = make(map[Coord]Cell)
b.maxX, b.maxY, b.minX, b.minY = 0, 0, 0, 0
}
func (b *Buffer) SetCell(x, y int, c Cell) {
b.cells[Coord{X: x, Y: y}] = c
b.maxX, b.maxY = h.Max(b.maxX, x), h.Max(b.maxY, y)
@@ -60,6 +75,13 @@ func (b *Buffer) SetCells(x, y int, c [][]Cell) {
}
}
func (b *Buffer) Merge(atX, atY int, b2 *Buffer) {
b2.MoveTo(atX, atY)
for k, v := range b2.cells {
b.cells[k] = v
}
}
// Buffer Helpers
func (b *Buffer) FillText(x, y int, txt string, style tcell.Style) {
for i := range txt {

View File

@@ -50,7 +50,7 @@ type AbsoluteLayout struct {
cursor int
disableTab bool
logger func(string)
logger func(string, ...any)
}
var _ Widget = (*AbsoluteLayout)(nil)
@@ -209,10 +209,10 @@ func (w *AbsoluteLayout) Clear() {
func (w *AbsoluteLayout) SetDefaultAnchor(d LayoutFlag) { w.defAnchor = d }
func (w *AbsoluteLayout) SetLogger(l func(string)) { w.logger = l }
func (w *AbsoluteLayout) Log(txt string) {
func (w *AbsoluteLayout) SetLogger(l func(string, ...any)) { w.logger = l }
func (w *AbsoluteLayout) Log(txt string, args ...any) {
if w.logger != nil {
w.logger(txt)
w.logger(txt, args...)
}
}
@@ -229,21 +229,39 @@ func (w *AbsoluteLayout) updateWidgetLayouts() {
for _, wd := range w.widgets {
w.updateWidgetPos(wd)
}
var updated []Widget
for wd := range w.wManualSizes {
w.updateWidgetSize(wd)
updated = append(updated, wd)
}
for wd := range w.wDynamicSizes {
w.updateWidgetSize(wd)
updated = append(updated, wd)
}
for i := range w.widgets {
var next bool
for j := range updated {
if updated[j] == w.widgets[i] {
next = true
}
}
if next {
continue
}
w.updateWidgetSize(w.widgets[i])
}
}
// Set a widgets position relative to the layout
func (w *AbsoluteLayout) updateWidgetPos(wd Widget) {
wd.SetPos(w.getRelPos(wd))
p := w.getRelPos(wd)
w.Log("%s: Setting Pos: %s (%d,%d)", w.Id(), wd.Id(), p.X, p.Y)
wd.SetPos(p)
}
func (w *AbsoluteLayout) updateWidgetSize(wd Widget) {
if sz, ok := w.wManualSizes[wd]; ok {
w.Log("%s: Updating Size: %s (%d,%d)", w.Id(), wd.Id(), sz.X, sz.Y)
wd.SetW(sz.X)
wd.SetH(sz.Y)
return
@@ -252,19 +270,17 @@ func (w *AbsoluteLayout) updateWidgetSize(wd Widget) {
// X: Layout Width - Widget X
// Y: Layout Height - Widget Y
available := Coord{X: w.GetW() - wd.GetX(), Y: w.GetH() - wd.GetY()}
ww := wd.WantW()
if ww < available.X {
wd.SetW(ww)
} else if wd.MinW() < available.X {
if wd.WantW() < available.X {
wd.SetW(wd.WantW())
} else if wd.MinW() > available.X {
wd.SetW(available.X)
} else {
wd.SetW(wd.MinW())
}
wh := wd.WantH()
if wh < available.Y {
wd.SetH(wh)
} else if wd.MinH() < available.Y {
if wd.WantH() < available.Y {
wd.SetH(wd.WantH())
} else if wd.MinH() > available.Y {
wd.SetH(available.Y)
} else {
wd.SetH(wd.MinH())
@@ -272,8 +288,13 @@ func (w *AbsoluteLayout) updateWidgetSize(wd Widget) {
}
// Manually set the size of a widget, the Layout won't override it
func (w *AbsoluteLayout) SetWidgetSize(wd Widget, sz Coord) { w.wManualSizes[wd] = sz }
func (w *AbsoluteLayout) SetDynamicWidgetSize(wd Widget, flg LayoutFlag) { w.wDynamicSizes[wd] = flg }
func (w *AbsoluteLayout) SetWidgetSize(wd Widget, sz Coord) {
w.wManualSizes[wd] = sz
}
func (w *AbsoluteLayout) SetDynamicWidgetSize(wd Widget, flg LayoutFlag) {
w.wDynamicSizes[wd] = flg
}
func (w *AbsoluteLayout) getRelPos(wd Widget) Coord {
var p Coord
@@ -339,6 +360,7 @@ func (w *AbsoluteLayout) DeleteIndex(idx int) {
delete(w.wAnchor, p)
}
}
func (w *AbsoluteLayout) Delete(n Widget) {
for i := 0; i < len(w.widgets); i++ {
if w.widgets[i] == n {
@@ -347,6 +369,7 @@ func (w *AbsoluteLayout) Delete(n Widget) {
}
}
}
func (w *AbsoluteLayout) IndexOf(n Widget) int {
for i := range w.widgets {
if w.widgets[i] == n {

View File

@@ -32,9 +32,11 @@ import (
// ArtWidget displays it's text as ascii art.
type ArtWidget struct {
id string
style tcell.Style
x, y int
w, h int
style tcell.Style
buffer Buffer
active bool
visible bool
@@ -60,6 +62,7 @@ func NewArtWidget(id string, st tcell.Style) *ArtWidget {
func (w *ArtWidget) Init(id string, st tcell.Style) {
w.id = id
w.visible = true
w.style = st
w.keyMap = BlankKeyMap()
w.initFonts()
@@ -79,34 +82,10 @@ func (w *ArtWidget) RemoveFromKeyMap(km KeyMap) {
func (w *ArtWidget) HandleKey(ev *tcell.EventKey) bool { return false }
func (w *ArtWidget) HandleTime(ev *tcell.EventTime) {}
func (w *ArtWidget) Draw(screen tcell.Screen) {
x, y := w.x, w.y
for _, ch := range w.text {
w.drawRune(ch, x, y, screen)
x += w.getRuneWidth(ch)
if !w.visible {
return
}
}
func (w *ArtWidget) drawRune(r rune, x, y int, screen tcell.Screen) {
wx, wy := x, y
rs := w.getRune(r)
for _, ln := range rs {
wx = x
for _, d := range ln {
screen.SetContent(wx, wy, d, nil, w.style)
wx++
}
wy++
}
}
func (w *ArtWidget) getRune(r rune) [][]rune { return w.currFont.GetRune(r) }
func (w *ArtWidget) getRuneHeight(r rune) int { return len(w.getRune(r)) }
func (w *ArtWidget) getRuneWidth(r rune) int {
rn := w.getRune(r)
if len(rn) > 0 {
return len(rn[0])
}
return 0
w.buffer.Draw(w.x, w.y, screen)
}
func (w *ArtWidget) Active() bool { return w.active }
@@ -127,31 +106,47 @@ func (w *ArtWidget) SetH(h int) { w.h = h }
func (w *ArtWidget) GetW() int { return w.w }
func (w *ArtWidget) GetH() int { return w.h }
func (w *ArtWidget) WantW() int {
var wd int
for _, ch := range w.text {
r := w.getRune(ch)
if len(r) > 0 {
wd += len(r[0])
}
}
w.Log("%s: Want Width: %d", w.Id(), wd)
return wd
}
func (w *ArtWidget) WantW() int { return w.buffer.Width() }
func (w *ArtWidget) WantH() int { return w.buffer.Height() }
func (w *ArtWidget) MinW() int { return w.buffer.Width() }
func (w *ArtWidget) MinH() int { return w.buffer.Height() }
func (w *ArtWidget) WantH() int {
h := len(w.getRune('Q'))
w.Log("%s: Want Height: %d", w.Id(), h)
return h
func (w *ArtWidget) SetText(txt string) {
w.text = txt
w.buildBuffer()
}
func (w *ArtWidget) MinW() int { return w.WantW() }
func (w *ArtWidget) MinH() int { return w.WantH() }
func (w *ArtWidget) SetText(txt string) { w.text = txt }
func (w *ArtWidget) GetText() string { return w.text }
func (w *ArtWidget) SetFont(fnt string) { w.font = fnt }
func (w *ArtWidget) SetFont(fnt string) {
w.font = fnt
w.buildBuffer()
}
func (w *ArtWidget) GetFont() string { return w.font }
func (w *ArtWidget) buildBuffer() {
b := NewBuffer()
x, y := w.x, w.y
chX := x
for _, ch := range w.text {
if ch == '\n' {
x = w.x
y = b.Height() + 1
continue
}
rs := w.getRune(ch)
var maxX int
for rY, ln := range rs {
for rX, bt := range ln {
b.SetCell(chX+rX, y+rY, *NewCell(bt, w.style))
if chX+rX > maxX {
maxX = chX + rX
}
}
}
chX = maxX + 1
}
w.buffer = b
}
func (w *ArtWidget) getRune(r rune) [][]rune { return w.currFont.GetRune(r) }
func (w *ArtWidget) initFonts() {
f := NewArtWidgetFont("miniwi")

View File

@@ -35,6 +35,8 @@ type Searcher struct {
x, y int
w, h int
buffer Buffer
active bool
visible bool
focusable bool
@@ -94,6 +96,7 @@ func (w *Searcher) HandleResize(ev *tcell.EventResize) {
}
w.search.SetPos(Coord{X: 1, Y: 1})
w.search.HandleResize(Coord{X: aW, Y: aH}.ResizeEvent())
// w.buildBuffer()
}
func (w *Searcher) SetKeyMap(km KeyMap, def bool) {
@@ -126,7 +129,11 @@ func (w *Searcher) HandleKey(ev *tcell.EventKey) bool {
if w.cursor != sel && w.onChange != nil {
w.onChange(w.cursor, w.filteredData[w.cursor])
}
return b1 || b2 || ret
if b1 || b2 || ret {
// w.buildBuffer()
return true
}
return false
}
func (w *Searcher) handleKeyUp(ev *tcell.EventKey) bool {
@@ -134,6 +141,7 @@ func (w *Searcher) handleKeyUp(ev *tcell.EventKey) bool {
return false
}
w.cursor = ((w.cursor - 1) + len(w.filteredData)) % len(w.filteredData)
// w.buildBuffer()
return true
}
@@ -142,6 +150,7 @@ func (w *Searcher) handleKeyDown(ev *tcell.EventKey) bool {
return false
}
w.cursor = ((w.cursor + 1) + len(w.filteredData)) % len(w.filteredData)
// w.buildBuffer()
return true
}
@@ -150,6 +159,7 @@ func (w *Searcher) handleKeyHome(ev *tcell.EventKey) bool {
return false
}
w.cursor = 0
// w.buildBuffer()
return true
}
@@ -158,6 +168,7 @@ func (w *Searcher) handleKeyEnd(ev *tcell.EventKey) bool {
return false
}
w.cursor = len(w.filteredData) - 1
// w.buildBuffer()
return true
}
@@ -169,8 +180,8 @@ func (w *Searcher) handleKeyPgUp(ev *tcell.EventKey) bool {
if w.cursor < 0 {
w.cursor = 0
}
return false
// w.buildBuffer()
return true
}
func (w *Searcher) handleKeyPgDn(ev *tcell.EventKey) bool {
@@ -182,7 +193,8 @@ func (w *Searcher) handleKeyPgDn(ev *tcell.EventKey) bool {
if w.cursor > mx {
w.cursor = mx
}
return false
// w.buildBuffer()
return true
}
func (w *Searcher) handleKeyEnter(ev *tcell.EventKey) bool {
@@ -200,7 +212,9 @@ func (w *Searcher) handleKeyEnter(ev *tcell.EventKey) bool {
idx = i
}
}
return w.selectFunc(idx, selV)
res := w.selectFunc(idx, selV)
// w.buildBuffer()
return res
}
func (w *Searcher) HandleTime(ev *tcell.EventTime) { w.search.HandleTime(ev) }
@@ -208,6 +222,11 @@ func (w *Searcher) Draw(screen tcell.Screen) {
if !w.visible {
return
}
w.oldDraw(screen)
// w.buffer.Draw(w.x, w.y, screen)
}
func (w *Searcher) oldDraw(screen tcell.Screen) {
dStyle := w.style.Dim(!w.active)
if !w.disableBorder {
if len(w.title) > 0 {
@@ -216,7 +235,7 @@ func (w *Searcher) Draw(screen tcell.Screen) {
wh.BorderFilled(w.x, w.y, w.x+w.w, w.y+w.h, wh.BRD_CSIMPLE, dStyle, screen)
}
}
//w.GetPos().DrawOffset(w.search, screen)
// w.GetPos().DrawOffset(w.search, screen)
x, y := w.x+1, w.y+2
w.search.SetPos(Coord{X: w.x + 1, Y: w.y + 1})
w.search.Draw(screen)
@@ -242,6 +261,20 @@ func (w *Searcher) Draw(screen tcell.Screen) {
}
}
func (w *Searcher) buildBuffer() {
b := NewBuffer()
dStyle := w.style.Dim(!w.active)
if !w.disableBorder {
if len(w.title) > 0 {
w.buffer.TitledBorderFilled(0, 0, w.w, w.y, w.title, wh.BRD_CSIMPLE, dStyle)
} else {
w.buffer.BorderFilled(0, 0, w.w, w.y, wh.BRD_CSIMPLE, dStyle)
}
}
// x, y := 1, 1
w.buffer = b
}
func (w *Searcher) Active() bool { return w.active }
func (w *Searcher) SetActive(a bool) {
w.active = a