Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented mouse release handling #110

Merged
merged 6 commits into from Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 85 additions & 10 deletions _examples/mouse.go
Expand Up @@ -33,12 +33,24 @@ func main() {
}
}

var initialMouseX, initialMouseY, xOffset, yOffset int
var globalMouseDown, msgMouseDown, movingMsg bool

func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
if _, err := g.View("msg"); msgMouseDown && err == nil {
moveMsg(g)
}
if v, err := g.SetView("global", -1, -1, maxX, maxY, 0); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
v.Frame = false
}
if v, err := g.SetView("but1", 2, 2, 22, 7, 0); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
v.Highlight = true
v.SelBgColor = gocui.ColorGreen
v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, "Button 1 - line 1")
Expand All @@ -53,11 +65,11 @@ func layout(g *gocui.Gui) error {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
v.Highlight = true
v.SelBgColor = gocui.ColorGreen
v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, "Button 2 - line 1")
}
updateHighlightedView(g)
return nil
}

Expand All @@ -70,13 +82,13 @@ func keybindings(g *gocui.Gui) error {
return err
}
}
if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, delMsg); err != nil {
if err := g.SetKeybinding("", gocui.MouseRelease, gocui.ModNone, mouseUp); err != nil {
return err
}
if err := g.SetKeybinding("", gocui.MouseRight, gocui.ModNone, delMsg); err != nil {
if err := g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, globalDown); err != nil {
return err
}
if err := g.SetKeybinding("", gocui.MouseMiddle, gocui.ModNone, delMsg); err != nil {
if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, msgDown); err != nil {
return err
}
return nil
Expand All @@ -100,17 +112,80 @@ func showMsg(g *gocui.Gui, v *gocui.View) error {
}

maxX, maxY := g.Size()
if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err != nil {
if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2, 0); err == nil || errors.Is(err, gocui.ErrUnknownView) {
v.Clear()
v.SelBgColor = gocui.ColorCyan
v.SelFgColor = gocui.ColorBlack
fmt.Fprintln(v, l)
}
return nil
}

func updateHighlightedView(g *gocui.Gui) {
mx, my := g.MousePosition()
for _, view := range g.Views() {
view.Highlight = false
}
if v, err := g.ViewByPosition(mx, my); err == nil {
v.Highlight = true
}
}

func moveMsg(g *gocui.Gui) {
mx, my := g.MousePosition()
if !movingMsg && (mx != initialMouseX || my != initialMouseY) {
movingMsg = true
}
g.SetView("msg", mx-xOffset, my-yOffset, mx-xOffset+20, my-yOffset+2, 0)
}

func msgDown(g *gocui.Gui, v *gocui.View) error {
initialMouseX, initialMouseY = g.MousePosition()
if vx, vy, _, _, err := g.ViewPosition("msg"); err == nil {
xOffset = initialMouseX - vx
yOffset = initialMouseY - vy
msgMouseDown = true
}
return nil
}

func globalDown(g *gocui.Gui, v *gocui.View) error {
mx, my := g.MousePosition()
if vx0, vy0, vx1, vy1, err := g.ViewPosition("msg"); err == nil {
if mx >= vx0 && mx <= vx1 && my >= vy0 && my <= vy1 {
return msgDown(g, v)
}
}
globalMouseDown = true
maxX, _ := g.Size()
msg := fmt.Sprintf("Mouse down at: %d,%d", mx, my)
x := mx - len(msg)/2
if x < 0 {
x = 0
} else if x+len(msg)+1 > maxX-1 {
x = maxX - 1 - len(msg) - 1
}
if v, err := g.SetView("globalDown", x, my-1, x+len(msg)+1, my+1, 0); err != nil {
if !errors.Is(err, gocui.ErrUnknownView) {
return err
}
fmt.Fprintln(v, l)
v.WriteString(msg)
}
return nil
}

func delMsg(g *gocui.Gui, v *gocui.View) error {
// Error check removed, because delete could be called multiple times with the above keybindings
g.DeleteView("msg")
func mouseUp(g *gocui.Gui, v *gocui.View) error {
if msgMouseDown {
msgMouseDown = false
if movingMsg {
movingMsg = false
return nil
} else {
g.DeleteView("msg")
}
} else if globalMouseDown {
globalMouseDown = false
g.DeleteView("globalDown")
}
return nil
}
10 changes: 10 additions & 0 deletions gui.go
Expand Up @@ -76,6 +76,9 @@ type Gui struct {
testCounter int // used for testing synchronization
testNotify chan struct{}

// The position of the mouse
mouseX, mouseY int
Kavantix marked this conversation as resolved.
Show resolved Hide resolved

// BgColor and FgColor allow to configure the background and foreground
// colors of the GUI.
BgColor, FgColor, FrameColor Attribute
Expand Down Expand Up @@ -141,6 +144,7 @@ func NewGui(mode OutputMode, supportOverlaps bool) (*Gui, error) {
g.maxX, g.maxY = screen.Size()
}

g.mouseX, g.mouseY = -1, -1
g.BgColor, g.FgColor, g.FrameColor = ColorDefault, ColorDefault, ColorDefault
g.SelBgColor, g.SelFgColor, g.SelFrameColor = ColorDefault, ColorDefault, ColorDefault

Expand All @@ -165,6 +169,10 @@ func (g *Gui) Size() (x, y int) {
return g.maxX, g.maxY
}

func (g *Gui) MousePosition() (x, y int) {
Kavantix marked this conversation as resolved.
Show resolved Hide resolved
return g.mouseX, g.mouseY
}

// SetRune writes a rune at the given point, relative to the top-left
// corner of the terminal. It checks if the position is valid and applies
// the given colors.
Expand Down Expand Up @@ -881,6 +889,8 @@ func (g *Gui) onKey(ev *gocuiEvent) error {
}
case eventMouse:
mx, my := ev.MouseX, ev.MouseY
g.mouseX = mx
g.mouseY = my
v, err := g.ViewByPosition(mx, my)
if err != nil {
break
Expand Down
20 changes: 11 additions & 9 deletions tcell_driver.go
Expand Up @@ -174,7 +174,7 @@ func pollEvent() gocuiEvent {
case *tcell.EventMouse:
x, y := tev.Position()
button := tev.Buttons()
mouseKey := MouseRelease
mouseKey := Key(0)
mouseMod := ModNone
// process mouse wheel
if button&tcell.WheelUp != 0 {
Expand All @@ -199,19 +199,21 @@ func pollEvent() gocuiEvent {
if button != tcell.ButtonNone && lastMouseKey == tcell.ButtonNone {
lastMouseKey = button
lastMouseMod = tev.Modifiers()
switch tev.Buttons() {
case tcell.ButtonPrimary:
mouseKey = MouseLeft
case tcell.ButtonSecondary:
mouseKey = MouseRight
case tcell.ButtonMiddle:
mouseKey = MouseMiddle
}
mouseMod = Modifier(lastMouseMod)
}

switch tev.Buttons() {
case tcell.ButtonNone:
if lastMouseKey != tcell.ButtonNone {
switch lastMouseKey {
case tcell.ButtonPrimary:
mouseKey = MouseLeft
case tcell.ButtonSecondary:
mouseKey = MouseRight
case tcell.ButtonMiddle:
mouseKey = MouseMiddle
}
mouseKey = MouseRelease
mouseMod = Modifier(lastMouseMod)
lastMouseMod = tcell.ModNone
lastMouseKey = tcell.ButtonNone
Expand Down