package main import ( "bufio" "errors" "fmt" "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 (n *node) textResize() bool { w := n.tk var width, height int = 0, 0 var changed bool = false for i, s := range splitLines(n.tk.label) { 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 { n.showWidgetPlacement(true, "textResize() changed") } return changed } func (n *node) hideView() { n.SetVisible(false) } // 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 (n *node) showView() { var err error w := n.tk if w.cuiName == "" { log.Log(ERROR, "showView() w.cuiName was not set for widget", w) w.cuiName = string(n.WidgetId) } // if the gocui element doesn't exist, create it if w.v == nil { n.recreateView() } x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName) log.Log(INFO, "showView() w.v already defined for widget", n.progname, err) // n.smartGocuiSize() changed := n.textResize() if changed { log.Log(NOW, "showView() textResize() changed. Should recreateView here wId =", w.cuiName) } else { log.Log(NOW, "showView() Clear() and Fprint() here wId =", w.cuiName) w.v.Clear() fmt.Fprint(w.v, n.tk.label) n.SetVisible(false) n.SetVisible(true) return } // if the gocui element has changed where it is supposed to be on the screen // recreate it if x0 != w.gocuiSize.w0 { n.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) n.recreateView() return } if x1 != w.gocuiSize.w1 { log.Log(ERROR, "showView() too wide", w.cuiName, "w,w", w.gocuiSize.w1, x1) n.recreateView() return } if y1 != w.gocuiSize.h1 { log.Log(ERROR, "showView() too high", w.cuiName, "h,h", w.gocuiSize.h1, y1) n.recreateView() return } n.SetVisible(true) } // create or recreate the gocui widget visible // deletes the old view if it exists and recreates it func (n *node) recreateView() { var err error w := n.tk log.Log(ERROR, "recreateView() START", n.WidgetType, n.progname) 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 if n.progname == "CLOUDFLARE_EMAIL" { n.showWidgetPlacement(true, "n.progname="+n.progname+" n.tk.label="+n.tk.label+" "+w.cuiName) n.dumpWidget("jwc") n.textResize() n.showWidgetPlacement(true, "n.progname="+n.progname+" n.tk.label="+n.tk.label+" "+w.cuiName) } 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 { n.showWidgetPlacement(true, "recreateView()") log.Log(ERROR, "recreateView() internal plugin error err = nil") return } if !errors.Is(err, gocui.ErrUnknownView) { n.showWidgetPlacement(true, "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, n.tk.label) // n.showWidgetPlacement(true, "n.progname=" + n.progname + " 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 } if n.progname == "CLOUDFLARE_EMAIL" { n.showWidgetPlacement(true, "n.progname="+n.progname+" n.tk.label="+n.tk.label+" "+w.cuiName) n.dumpTree(true) } log.Log(ERROR, "recreateView() END") } func (n *node) hideWidgets() { w := n.tk w.isCurrent = false switch n.WidgetType { case widget.Root: case widget.Flag: case widget.Window: case widget.Box: case widget.Grid: default: n.hideView() } for _, child := range n.children { child.hideWidgets() } } func (n *node) hideFake() { w := n.tk if w.isFake { n.hideView() } for _, child := range n.children { child.hideFake() } } func (n *node) showFake() { w := n.tk if w.isFake { n.setFake() n.showWidgetPlacement(true, "showFake:") n.showView() } for _, child := range n.children { child.showFake() } } func (n *node) showWidgets() { w := n.tk if w.isFake { // don't display by default } else { n.showWidgetPlacement(true, "current:") n.showView() } for _, child := range n.children { child.showWidgets() } }