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 (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(true, "textResize() changed") } return changed } func (w *guiWidget) hideView() { w.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 (w *guiWidget) showView() { var err error if w.cuiName == "" { log.Log(ERROR, "showView() w.cuiName was not set for widget", w) w.cuiName = string(w.node.WidgetId) } log.Log(ERROR, "showView() labelN =", w.labelN) // if the gocui element doesn't exist, create it if w.v == nil { w.recreateView() } x0, y0, x1, y1, err := me.baseGui.ViewPosition(w.cuiName) log.Log(INFO, "showView() w.v already defined for widget", w.String(), err) // n.smartGocuiSize() changed := w.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, w.labelN) w.SetVisible(false) w.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 { 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(ERROR, "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(ERROR, "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 if w.String() == "CLOUDFLARE_EMAIL" { w.showWidgetPlacement(true, "n.String()="+w.String()+" n.tk.label="+w.labelN+" "+w.cuiName) // w.dumpWidget("jwc") w.textResize() w.showWidgetPlacement(true, "n.String()="+w.String()+" n.tk.label="+w.labelN+" "+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 { w.showWidgetPlacement(true, "recreateView()") log.Log(ERROR, "recreateView() internal plugin error err = nil") return } if !errors.Is(err, gocui.ErrUnknownView) { w.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, w.labelN) // n.showWidgetPlacement(true, "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 } if w.String() == "CLOUDFLARE_EMAIL" { w.showWidgetPlacement(true, "w.String()="+w.String()+" w.label="+w.labelN+" "+w.cuiName) w.dumpTree(true) } log.Log(ERROR, "recreateView() END") } func (w *guiWidget) hideWidgets() { 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 (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(true, "showFake:") } for _, child := range w.children { child.showFake() } } func (w *guiWidget) showWidgets() { if w.isFake { // don't display by default } else { w.showWidgetPlacement(true, "current:") w.showView() } for _, child := range w.children { child.showWidgets() } }