// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "fmt" "github.com/awesome-gocui/gocui" "go.wit.com/widget" ) /* gocui defines the offset like this: width -> increases to the right ---------------------------------- hieght | H = 1 | increases | | | | W = 1 W = 18 | | | | v | H = 5 | downwards ------------------------------------- */ // change over to this name // returns all the widgets under (X,H) that are visible func findByXY(w int, h int) []*guiWidget { rootW := me.treeRoot.TK.(*guiWidget) // this searches the binary tree recursively (function is right below) return rootW.findByXYreal(w, h) } // this checks a widget to see if it is under (W,H), then checks the widget's children // anything that matches is passed back as an array of widgets func (tk *guiWidget) findByXYreal(w int, h int) []*guiWidget { var widgets []*guiWidget if !tk.Visible() { // ignore widgets that are not visible } else { // check the location to see if this is under (W,H) // if it is, return this widget if (tk.gocuiSize.w0 <= w) && (w <= tk.gocuiSize.w1) && (tk.gocuiSize.h0 <= h) && (h <= tk.gocuiSize.h1) { widgets = append(widgets, tk) // log.Log(GOCUI, "findByXY() found", widget.node.WidgetType, w, h) } } // tk.verifyRect() // search through the children widgets in the binary tree for _, child := range tk.children { widgets = append(widgets, child.findByXYreal(w, h)...) } return widgets } // returns all the windows from the root of the binary tree func findWindows() []*guiWidget { rootW := me.treeRoot.TK.(*guiWidget) return rootW.findWindows() } // walk the binary tree looking for WidgetType == Window func (tk *guiWidget) findWindows() []*guiWidget { var found []*guiWidget if tk.node.WidgetType == widget.Window { found = append(found, tk) } for _, child := range tk.children { found = append(found, child.findWindows()...) } return found } func (tk *guiWidget) setFullSize() bool { r := tk.getFullSize() var changed bool if tk.full.w0 != r.w0 { tk.full.w0 = r.w0 changed = true } if tk.full.w1 != r.w1 { tk.full.w1 = r.w1 changed = true } if tk.full.h0 != r.h0 { tk.full.h0 = r.h0 changed = true } if tk.full.h1 != r.h1 { tk.full.h1 = r.h1 changed = true } if changed { tk.dumpWidget(fmt.Sprintf("setFullSize(changed)")) } return changed } func (tk *guiWidget) gridFullSize() rectType { var r rectType var first bool = true for _, child := range tk.children { cr := child.getFullSize() if cr.Width() == 0 && cr.Height() == 0 { // ignore widgets of zero size? continue } if first { // use the lowest width and hight from children widgets r.w0 = cr.w0 r.h0 = cr.h0 r.w1 = cr.w1 r.h1 = cr.h1 first = false child.dumpWidget(fmt.Sprintf("grid(f)")) continue } child.dumpWidget(fmt.Sprintf("grid()")) // use the lowest width and hight from children widgets if r.w0 > cr.w0 { r.w0 = cr.w0 } if r.h0 > cr.h0 { r.h0 = cr.h0 } // use the highest width and hight from children widgets if r.w1 < cr.w1 { r.w1 = cr.w1 } if r.h1 < cr.h1 { r.h1 = cr.h1 } } tk.full.w0 = r.w0 tk.full.w1 = r.w1 tk.full.h0 = r.h0 tk.full.h1 = r.h1 return r } func (tk *guiWidget) buttonFullSize() rectType { var r rectType r.w0 = tk.gocuiSize.w0 r.w1 = tk.gocuiSize.w1 r.h0 = tk.gocuiSize.h0 r.h1 = tk.gocuiSize.h1 // try setting the full values here ? is this right? tk.full.w0 = r.w0 tk.full.w1 = r.w1 tk.full.h0 = r.h0 tk.full.h1 = r.h1 return r } // this checks a widget to see if it is under (W,H), then checks the widget's children // anything that matches is passed back as an array of widgets func (tk *guiWidget) getFullSize() rectType { var r rectType if tk.node.WidgetType == widget.Grid { return tk.gridFullSize() } // these are 'simple' widgets // the full size is exactly what gocui uses switch tk.node.WidgetType { case widget.Label: return tk.buttonFullSize() case widget.Button: return tk.buttonFullSize() case widget.Checkbox: return tk.buttonFullSize() case widget.Dropdown: return tk.buttonFullSize() default: } if tk.v == nil { r.w0 = tk.full.w0 r.w1 = tk.full.w1 r.h0 = tk.full.h0 r.h1 = tk.full.h1 } else { r.w0 = tk.gocuiSize.w0 r.w1 = tk.gocuiSize.w1 r.h0 = tk.gocuiSize.h0 r.h1 = tk.gocuiSize.h1 } // search through the children widgets in the binary tree for _, child := range tk.children { cr := child.getFullSize() /* this didn't make things work either if child.v == nil { continue } */ // use the lowest width and hight from children widgets if r.w0 > cr.w0 { r.w0 = cr.w0 } if r.h0 > cr.h0 { r.h0 = cr.h0 } // use the highest width and hight from children widgets if r.w1 < cr.w1 { r.w1 = cr.w1 } if r.h1 < cr.h1 { r.h1 = cr.h1 } } // try setting the full values here ? is this right? tk.full.w0 = r.w0 tk.full.w1 = r.w1 tk.full.h0 = r.h0 tk.full.h1 = r.h1 return r } // returns the "highest priority widget under the mouse func findUnderMouse() *guiWidget { w, h := me.baseGui.MousePosition() widgets := findByXY(w, h) // search through all the widgets that were below the mouse click var found *guiWidget for _, w := range widgets { // prioritize window buttons. This means if some code covers // up the window widgets, then it will ignore everything else // and allow the user (hopefully) to redraw or switch windows // TODO: display the window widgets on top if w.node.WidgetType == widget.Window { return w } } // return anything else that is interactive for _, w := range widgets { if w.node.WidgetType == widget.Button { return w } if w.node.WidgetType == widget.Combobox { return w } if w.node.WidgetType == widget.Checkbox { return w } w.dumpWidget("findUnderMouse() found something unknown") found = w } // maybe something else was found return found } // panics. todo: fix ctrl-mouse click? // find the widget under the mouse click func ctrlDown(g *gocui.Gui, v *gocui.View) error { var found *guiWidget // var widgets []*node // var f func (n *node) found = findUnderMouse() if me.ctrlDown == nil { setupCtrlDownWidget() var tk *guiWidget tk = me.ctrlDown.TK.(*guiWidget) tk.labelN = found.String() tk.cuiName = "ctrlDown" // me.ctrlDown.parent = me.rootNode } var tk *guiWidget tk = me.ctrlDown.TK.(*guiWidget) if found == nil { found = me.treeRoot.TK.(*guiWidget) } tk.labelN = found.String() newR := found.realGocuiSize() tk.gocuiSize.w0 = newR.w0 tk.gocuiSize.h0 = newR.h0 tk.gocuiSize.w1 = newR.w1 tk.gocuiSize.h1 = newR.h1 return nil }