Separate action events

pull/363/head
Chris Miller 4 years ago
parent 0daf286122
commit 1fb9862c00

@ -77,7 +77,6 @@ type Application struct {
lastMouseX, lastMouseY int // track last mouse pos
mouseDownX, mouseDownY int // track last mouse down pos
lastMouseAct MouseAction
lastClickTime time.Time
lastMouseBtn tcell.ButtonMask
}
@ -292,51 +291,47 @@ EventLoop:
screen.Clear()
a.draw()
case *tcell.EventMouse:
atX, atY := event.Position()
btn := event.Buttons()
// Calculate mouse actions.
var action MouseAction
if atX != int(a.lastMouseX) || atY != int(a.lastMouseY) {
action |= MouseMove
a.lastMouseX = atX
a.lastMouseY = atY
}
action = action.getMouseButtonAction(a.lastMouseBtn, btn)
if atX == int(a.mouseDownX) && atY == int(a.mouseDownY) {
action = action.getMouseClickAction(a.lastMouseAct, &a.lastClickTime)
}
a.lastMouseAct = action
a.lastMouseBtn = btn
if action&(MouseLeftDown|MouseMiddleDown|MouseRightDown) != 0 {
a.mouseDownX = atX
a.mouseDownY = atY
}
isMouseDownAct := false
// Fire a mouse action.
mouseEv := func(action MouseAction) {
switch action {
case MouseLeftDown, MouseMiddleDown, MouseRightDown:
isMouseDownAct = true
}
// Intercept event.
if mouseCapture != nil {
event, action = mouseCapture(event, action)
if event == nil {
a.draw()
continue // Don't forward event.
// Intercept event.
if mouseCapture != nil {
event, action = mouseCapture(event, action)
if event == nil {
a.draw()
return // Don't forward event.
}
}
}
var newHandlerCapture Primitive = nil // Clear it by default.
if a.mouseHandlerCapture != nil { // Check if already captured.
if handler := a.mouseHandlerCapture.MouseHandler(); handler != nil {
var newHandlerCapture Primitive = nil // Clear it by default.
if a.mouseHandlerCapture != nil { // Check if already captured.
if handler := a.mouseHandlerCapture.MouseHandler(); handler != nil {
_, newHandlerCapture = handler(action, event, func(p Primitive) {
a.SetFocus(p)
})
a.draw()
}
} else if handler := root.MouseHandler(); handler != nil {
_, newHandlerCapture = handler(action, event, func(p Primitive) {
a.SetFocus(p)
})
a.draw()
}
} else if handler := root.MouseHandler(); handler != nil {
_, newHandlerCapture = handler(action, event, func(p Primitive) {
a.SetFocus(p)
})
a.draw()
a.mouseHandlerCapture = newHandlerCapture
}
a.fireMouseActions(event, mouseEv)
// Keep state:
a.lastMouseBtn = event.Buttons()
if isMouseDownAct {
a.mouseDownX, a.mouseDownY = event.Position()
}
a.mouseHandlerCapture = newHandlerCapture
}
// If we have updates, now is the time to execute them.
@ -352,6 +347,83 @@ EventLoop:
return nil
}
func (a *Application) fireMouseActions(event *tcell.EventMouse, mouseEv func(MouseAction)) {
atX, atY := event.Position()
btn := event.Buttons()
clickMoved := atX != int(a.mouseDownX) || atY != int(a.mouseDownY)
btnDiff := btn ^ a.lastMouseBtn
if atX != int(a.lastMouseX) || atY != int(a.lastMouseY) {
mouseEv(MouseMove)
a.lastMouseX = atX
a.lastMouseY = atY
}
if btnDiff&tcell.Button1 != 0 {
if btn&tcell.Button1 != 0 {
mouseEv(MouseLeftDown)
} else {
mouseEv(MouseLeftUp)
if !clickMoved {
if a.lastClickTime.Add(DoubleClickInterval).Before(time.Now()) {
mouseEv(MouseLeftClick)
a.lastClickTime = time.Now()
} else {
mouseEv(MouseLeftDoubleClick)
a.lastClickTime = time.Time{} // reset
}
}
}
}
if btnDiff&tcell.Button2 != 0 {
if btn&tcell.Button2 != 0 {
mouseEv(MouseMiddleDown)
} else {
mouseEv(MouseMiddleUp)
if !clickMoved {
if a.lastClickTime.Add(DoubleClickInterval).Before(time.Now()) {
mouseEv(MouseMiddleClick)
a.lastClickTime = time.Now()
} else {
mouseEv(MouseMiddleDoubleClick)
a.lastClickTime = time.Time{} // reset
}
}
}
}
if btnDiff&tcell.Button3 != 0 {
if btn&tcell.Button3 != 0 {
mouseEv(MouseRightDown)
} else {
mouseEv(MouseRightUp)
if !clickMoved {
if a.lastClickTime.Add(DoubleClickInterval).Before(time.Now()) {
mouseEv(MouseRightClick)
a.lastClickTime = time.Now()
} else {
mouseEv(MouseRightDoubleClick)
a.lastClickTime = time.Time{} // reset
}
}
}
}
if btn&tcell.WheelUp != 0 {
mouseEv(WheelUp)
}
if btn&tcell.WheelDown != 0 {
mouseEv(WheelDown)
}
if btn&tcell.WheelLeft != 0 {
mouseEv(WheelLeft)
}
if btn&tcell.WheelRight != 0 {
mouseEv(WheelRight)
}
}
// Stop stops the application, causing Run() to return.
func (a *Application) Stop() {
a.Lock()

@ -143,7 +143,7 @@ func (b *Button) MouseHandler() func(action MouseAction, event *tcell.EventMouse
return false, nil
}
// Process mouse event.
if action&MouseLeftClick != 0 {
if action == MouseLeftClick {
if b.selected != nil {
b.selected()
}

@ -209,7 +209,7 @@ func (c *Checkbox) MouseHandler() func(action MouseAction, event *tcell.EventMou
return false, nil
}
// Process mouse event.
if action&MouseLeftClick != 0 {
if action == MouseLeftClick {
c.checked = !c.checked
if c.changed != nil {
c.changed(c.checked)

@ -493,50 +493,39 @@ func (d *DropDown) HasFocus() bool {
return d.hasFocus
}
func (d *DropDown) listClick(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
if d.list.InRect(event.Position()) {
// Mouse is within the list.
if handler := d.list.MouseHandler(); handler != nil {
// Treat mouse up as click here.
// This allows you to expand and select in one go.
handler(MouseLeftUp|MouseLeftClick, event, setFocus)
}
return true, d // capture
func (d *DropDown) listClick(event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool) {
if !d.list.InRect(event.Position()) {
return false
}
// Mouse is within the list.
if handler := d.list.MouseHandler(); handler != nil {
consumed, _ := handler(MouseLeftClick, event, setFocus)
return consumed
}
return false, nil
return false
}
// MouseHandler returns the mouse handler for this primitive.
func (d *DropDown) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
return d.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) {
inRect := d.InRect(event.Position())
inRect := d.InRect(event.Position()) // mouse in the dropdown box itself, not the list.
if !d.open && !inRect {
return false, nil
}
// Process mouse event.
if d.open && action&(MouseLeftDown|MouseLeftUp) != 0 { // Close it:
consumed, capture = d.listClick(action, event, setFocus)
if consumed {
// The list click was processed.
d.closeList(setFocus)
return consumed, capture
}
if inRect && action&MouseLeftClick == 0 {
// Close the list if mouse down/up is not a click.
d.closeList(setFocus)
} else if !inRect && action&MouseLeftDown != 0 {
// Close the list if not in the list and mouse is down.
if action == MouseLeftClick {
if !d.open { // not open
d.openList(setFocus)
} else { // if d.open
if !inRect {
d.listClick(event, setFocus)
}
d.closeList(setFocus)
}
} else if !d.open && inRect && action&MouseLeftDown != 0 { // Open it:
d.openList(setFocus)
return true, d // capture
} else if d.open { // Non-click while list is open:
if handler := d.list.MouseHandler(); handler != nil {
handler(action, event, setFocus)
}
}
if d.open {
return true, d // capture
}
return true, nil
return inRect, nil
})
}

@ -599,7 +599,7 @@ func (i *InputField) MouseHandler() func(action MouseAction, event *tcell.EventM
return false, nil
}
// Process mouse event.
if action&MouseLeftDown != 0 {
if action == MouseLeftDown {
setFocus(i)
}
return true, nil

@ -553,7 +553,7 @@ func (l *List) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
return false, nil
}
// Process mouse event.
if action&MouseLeftClick != 0 {
if action == MouseLeftClick {
atX, atY := event.Position()
index := l.indexAtPoint(atX, atY)
if index != -1 {

@ -2,15 +2,13 @@ package tview
import (
"time"
"github.com/gdamore/tcell"
)
// MouseAction are bit flags indicating what the mouse is logically doing.
type MouseAction int32
// MouseAction indicates one of the actions the mouse is logically doing.
type MouseAction int16
const (
MouseMove MouseAction = 1 << iota
MouseMove MouseAction = iota
MouseLeftDown
MouseLeftUp
MouseLeftClick
@ -30,83 +28,3 @@ const (
)
var DoubleClickInterval = 500 * time.Millisecond
// Does not set MouseMove or *Click actions.
func (action MouseAction) getMouseButtonAction(lastBtn, btn tcell.ButtonMask) MouseAction {
btnDiff := btn ^ lastBtn
if btnDiff&tcell.Button1 != 0 {
if btn&tcell.Button1 != 0 {
action |= MouseLeftDown
} else {
action |= MouseLeftUp
}
}
if btnDiff&tcell.Button2 != 0 {
if btn&tcell.Button2 != 0 {
action |= MouseMiddleDown
} else {
action |= MouseMiddleUp
}
}
if btnDiff&tcell.Button3 != 0 {
if btn&tcell.Button3 != 0 {
action |= MouseRightDown
} else {
action |= MouseRightUp
}
}
if btn&tcell.WheelUp != 0 {
action |= WheelUp
}
if btn&tcell.WheelDown != 0 {
action |= WheelDown
}
if btn&tcell.WheelLeft != 0 {
action |= WheelLeft
}
if btn&tcell.WheelRight != 0 {
action |= WheelRight
}
return action
}
// Do not call if the mouse moved.
// Sets the *Click, including *DoubleClick.
// This should be called last, after setting all the other flags.
func (action MouseAction) getMouseClickAction(lastAct MouseAction, lastClickTime *time.Time) MouseAction {
if action&MouseMove == 0 {
if action&MouseLeftUp != 0 {
if (*lastClickTime).Add(DoubleClickInterval).Before(time.Now()) {
action |= MouseLeftClick
*lastClickTime = time.Now()
} else {
action |= MouseLeftDoubleClick
*lastClickTime = time.Time{} // reset
}
}
if action&MouseMiddleUp != 0 {
if (*lastClickTime).Add(DoubleClickInterval).Before(time.Now()) {
action |= MouseMiddleClick
*lastClickTime = time.Now()
} else {
action |= MouseMiddleDoubleClick
*lastClickTime = time.Time{} // reset
}
}
if action&MouseRightUp != 0 {
if (*lastClickTime).Add(DoubleClickInterval).Before(time.Now()) {
action |= MouseRightClick
*lastClickTime = time.Now()
} else {
action |= MouseRightDoubleClick
*lastClickTime = time.Time{} // reset
}
}
}
return action
}

Loading…
Cancel
Save