From 25777066cdd34497b946efd0f9a6b2b7c47391df Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 17 Oct 2025 16:36:29 -0500 Subject: [PATCH] Working on buffer stuff... Trying to figure out how/if it fits... --- buffer.go | 24 ++++++++++- wdgt_absolute_layout.go | 53 ++++++++++++++++------- wdgt_asciiarttext.go | 95 +++++++++++++++++++---------------------- wdgt_searcher.go | 49 +++++++++++++++++---- 4 files changed, 147 insertions(+), 74 deletions(-) diff --git a/buffer.go b/buffer.go index 254c11a..6be54b1 100644 --- a/buffer.go +++ b/buffer.go @@ -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 { diff --git a/wdgt_absolute_layout.go b/wdgt_absolute_layout.go index d2b0bc1..686553c 100644 --- a/wdgt_absolute_layout.go +++ b/wdgt_absolute_layout.go @@ -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 { diff --git a/wdgt_asciiarttext.go b/wdgt_asciiarttext.go index 724d0fa..1dc81eb 100644 --- a/wdgt_asciiarttext.go +++ b/wdgt_asciiarttext.go @@ -32,10 +32,12 @@ import ( // ArtWidget displays it's text as ascii art. type ArtWidget struct { id string - x, y int - w, h int style tcell.Style + x, y int + w, h int + buffer Buffer + active bool visible bool focusable 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 +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) SetText(txt string) { + w.text = txt + w.buildBuffer() +} +func (w *ArtWidget) GetText() string { return w.text } + +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 { - r := w.getRune(ch) - if len(r) > 0 { - wd += len(r[0]) + 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.Log("%s: Want Width: %d", w.Id(), wd) - return wd + w.buffer = b } - -func (w *ArtWidget) WantH() int { - h := len(w.getRune('Q')) - w.Log("%s: Want Height: %d", w.Id(), h) - return h -} -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) GetFont() string { return w.font } +func (w *ArtWidget) getRune(r rune) [][]rune { return w.currFont.GetRune(r) } func (w *ArtWidget) initFonts() { f := NewArtWidgetFont("miniwi") diff --git a/wdgt_searcher.go b/wdgt_searcher.go index 4e75f7f..a039911 100644 --- a/wdgt_searcher.go +++ b/wdgt_searcher.go @@ -33,8 +33,10 @@ type Searcher struct { id string style tcell.Style - x, y int - w, h int + 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