Skip to content

Commit

Permalink
Merge pull request #110 from Kavantix/mouse-release
Browse files Browse the repository at this point in the history
Implemented mouse release handling
  • Loading branch information
mjarkk committed Jan 8, 2022
2 parents 1b2209a + c4c1d5f commit df3d389
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 19 deletions.
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
}
12 changes: 12 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

// 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,12 @@ func (g *Gui) Size() (x, y int) {
return g.maxX, g.maxY
}

// MousePosition returns the last position of the mouse.
// If no mouse event was triggered yet MousePosition will return -1, -1.
func (g *Gui) MousePosition() (x, y int) {
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 +891,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

0 comments on commit df3d389

Please sign in to comment.