gocui/view.go

238 lines
5.5 KiB
Go

package main
import (
"bufio"
"errors"
"fmt"
"strconv"
"strings"
"github.com/awesome-gocui/gocui"
"go.wit.com/log"
"go.wit.com/widget"
)
func splitLines(s string) []string {
var lines []string
sc := bufio.NewScanner(strings.NewReader(s))
for sc.Scan() {
lines = append(lines, sc.Text())
}
return lines
}
func (w *guiWidget) textResize() bool {
// w := n.tk
var width, height int = 0, 0
var changed bool = false
for i, s := range splitLines(w.labelN) {
log.Log(INFO, "textResize() len =", len(s), i, s)
if width < len(s) {
width = len(s)
}
height += 1
}
if w.gocuiSize.w1 != w.gocuiSize.w0+width+me.FramePadW {
w.gocuiSize.w1 = w.gocuiSize.w0 + width + me.FramePadW
changed = true
}
if w.gocuiSize.h1 != w.gocuiSize.h0+height+me.FramePadH {
w.gocuiSize.h1 = w.gocuiSize.h0 + height + me.FramePadH
changed = true
}
if changed {
// w.showWidgetPlacement("textResize() changed")
}
return changed
}
func (w *guiWidget) hideView() {
// w.SetVisible(false)
w.deleteView()
}
// display's the text of the widget in gocui
// will create a new gocui view if there isn't one or if it has been moved
func (w *guiWidget) showView() {
if w.cuiName == "" {
log.Log(ERROR, "showView() w.cuiName was not set for widget", w)
w.cuiName = strconv.Itoa(w.node.WidgetId) + " TK"
}
log.Log(INFO, "showView() labelN =", w.labelN)
if w.hidden {
w.SetVisible(false)
return
}
// if the gocui element doesn't exist, create it
if w.v == nil {
w.recreateView()
}
x0, y0, x1, y1, _ := me.baseGui.ViewPosition(w.cuiName)
// x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName)
// log.Log(INFO, "showView() w.v already defined for widget", w.String(), x0, y0, x1, y1, err)
// n.smartGocuiSize()
changed := w.textResize()
if !changed {
log.Log(INFO, "showView() Clear() and Fprint() here wId =", w.cuiName)
w.v.Clear()
fmt.Fprint(w.v, w.labelN)
w.SetVisible(false)
w.SetVisible(true)
return
}
log.Log(INFO, "showView() textResize() changed. Should recreateView here wId =", w.cuiName)
// if the gocui element has changed where it is supposed to be on the screen
// recreate it
if x0 != w.gocuiSize.w0 {
w.recreateView()
return
}
if y0 != w.gocuiSize.h0 {
log.Log(ERROR, "showView() start hight mismatch id=", w.cuiName, "gocui h vs computed h =", w.gocuiSize.h0, y0)
w.recreateView()
return
}
if x1 != w.gocuiSize.w1 {
log.Log(INFO, "showView() too wide", w.cuiName, "w,w", w.gocuiSize.w1, x1)
w.recreateView()
return
}
if y1 != w.gocuiSize.h1 {
log.Log(ERROR, "showView() too high", w.cuiName, "h,h", w.gocuiSize.h1, y1)
w.recreateView()
return
}
w.SetVisible(true)
}
// create or recreate the gocui widget visible
// deletes the old view if it exists and recreates it
func (w *guiWidget) recreateView() {
var err error
log.Log(INFO, "recreateView() START", w.WidgetType, w.String())
if me.baseGui == nil {
log.Log(ERROR, "recreateView() ERROR: me.baseGui == nil", w)
return
}
// this deletes the button from gocui
me.baseGui.DeleteView(w.cuiName)
w.v = nil
a := w.gocuiSize.w0
b := w.gocuiSize.h0
c := w.gocuiSize.w1
d := w.gocuiSize.h1
w.v, err = me.baseGui.SetView(w.cuiName, a, b, c, d, 0)
if err == nil {
w.showWidgetPlacement("recreateView()")
log.Log(ERROR, "recreateView() internal plugin error err = nil")
return
}
if !errors.Is(err, gocui.ErrUnknownView) {
w.showWidgetPlacement("recreateView()")
log.Log(ERROR, "recreateView() internal plugin error error.IS()", err)
return
}
// this sets up the keybinding for the name of the window
// does this really need to be done? I think we probably already
// know everything about where all the widgets are so we could bypass
// the gocui package and just handle all the mouse events internally here (?)
// for now, the w.v.Name is a string "1", "2", "3", etc from the widgetId
// set the binding for this gocui view now that it has been created
// gocui handles overlaps of views so it will run on the view that is clicked on
me.baseGui.SetKeybinding(w.v.Name(), gocui.MouseLeft, gocui.ModNone, click)
// this actually sends the text to display to gocui
w.v.Wrap = true
w.v.Frame = w.frame
w.v.Clear()
fmt.Fprint(w.v, w.labelN)
// n.showWidgetPlacement("n.String()=" + n.String() + " n.tk.label=" + n.tk.label + " " + w.cuiName)
// n.dumpWidget("jwc 2")
// if you don't do this here, it will be black & white only
if w.color != nil {
w.v.FrameColor = w.color.frame
w.v.FgColor = w.color.fg
w.v.BgColor = w.color.bg
w.v.SelFgColor = w.color.selFg
w.v.SelBgColor = w.color.selBg
}
log.Log(INFO, "recreateView() END")
}
func (w *guiWidget) hideWidgets() {
if w == nil {
return
}
w.isCurrent = false
switch w.node.WidgetType {
case widget.Root:
case widget.Flag:
case widget.Window:
case widget.Box:
case widget.Grid:
default:
w.hideView()
}
for _, child := range w.children {
child.hideWidgets()
}
}
func hideFake() {
var w *guiWidget
w = me.treeRoot.TK.(*guiWidget)
w.hideFake()
}
func showFake() {
var w *guiWidget
w = me.treeRoot.TK.(*guiWidget)
w.showFake()
}
func (w *guiWidget) hideFake() {
if w.isFake {
w.hideView()
}
for _, child := range w.children {
child.hideFake()
}
}
func (w *guiWidget) showFake() {
if w.isFake {
// w.setFake()
w.showView()
w.showWidgetPlacement("showFake:")
}
for _, child := range w.children {
child.showFake()
}
}
func (w *guiWidget) showWidgets() {
if w.isFake {
// don't display by default
} else {
// w.showWidgetPlacement("current:")
w.showView()
}
for _, child := range w.children {
child.showWidgets()
}
}