Proper keyboard and mouse event propagation
This commit is contained in:
		
							parent
							
								
									e931717241
								
							
						
					
					
						commit
						4c6f1f80e7
					
				@ -42,6 +42,22 @@ func (entity *entity) unbind () {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entity *entity) propagate (callback func (*entity) bool) {
 | 
			
		||||
	for _, child := range entity.children {
 | 
			
		||||
		if callback(child) { break }
 | 
			
		||||
		child.propagate(callback)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entity *entity) childAt (point image.Point) *entity {
 | 
			
		||||
	for _, child := range entity.children {
 | 
			
		||||
		if point.In(child.bounds) {
 | 
			
		||||
			return child
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return entity
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------- Entity ----------- //
 | 
			
		||||
 | 
			
		||||
func (entity *entity) Invalidate () {
 | 
			
		||||
@ -144,11 +160,11 @@ func (entity *entity) Focus () {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entity *entity) FocusNext () {
 | 
			
		||||
	// TODO
 | 
			
		||||
	entity.window.system.focusNext()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (entity *entity) FocusPrevious () {
 | 
			
		||||
	// TODO
 | 
			
		||||
	entity.window.system.focusPrevious()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------- FlexibleEntity ----------- //
 | 
			
		||||
 | 
			
		||||
@ -20,25 +20,17 @@ func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
 | 
			
		||||
		(state & window.backend.modifierMasks.shiftLock) > 0
 | 
			
		||||
	if shift {
 | 
			
		||||
		switch button {
 | 
			
		||||
		case 4:
 | 
			
		||||
			sum.x -= scrollDistance
 | 
			
		||||
		case 5:
 | 
			
		||||
			sum.x += scrollDistance
 | 
			
		||||
		case 6:
 | 
			
		||||
			sum.y -= scrollDistance
 | 
			
		||||
		case 7:
 | 
			
		||||
			sum.y += scrollDistance
 | 
			
		||||
		case 4: sum.x -= scrollDistance
 | 
			
		||||
		case 5: sum.x += scrollDistance
 | 
			
		||||
		case 6: sum.y -= scrollDistance
 | 
			
		||||
		case 7: sum.y += scrollDistance
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		switch button {
 | 
			
		||||
		case 4:
 | 
			
		||||
			sum.y -= scrollDistance
 | 
			
		||||
		case 5:
 | 
			
		||||
			sum.y += scrollDistance
 | 
			
		||||
		case 6:
 | 
			
		||||
			sum.x -= scrollDistance
 | 
			
		||||
		case 7:
 | 
			
		||||
			sum.x += scrollDistance
 | 
			
		||||
		case 4: sum.y -= scrollDistance
 | 
			
		||||
		case 5: sum.y += scrollDistance
 | 
			
		||||
		case 6: sum.x -= scrollDistance
 | 
			
		||||
		case 7: sum.x += scrollDistance
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -129,8 +121,8 @@ func (window *window) handleKeyPress (
 | 
			
		||||
	connection *xgbutil.XUtil,
 | 
			
		||||
	event xevent.KeyPressEvent,
 | 
			
		||||
) {
 | 
			
		||||
	if window.child == nil { return }
 | 
			
		||||
	if window.hasModal     { return }
 | 
			
		||||
	if window.system.focused == nil { return }
 | 
			
		||||
	if window.hasModal              { return }
 | 
			
		||||
	
 | 
			
		||||
	keyEvent := *event.KeyPressEvent
 | 
			
		||||
	key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State)
 | 
			
		||||
@ -138,18 +130,16 @@ func (window *window) handleKeyPress (
 | 
			
		||||
	modifiers.NumberPad = numberPad
 | 
			
		||||
 | 
			
		||||
	if key == input.KeyTab && modifiers.Alt {
 | 
			
		||||
		// if child, ok := window.child.element.(tomo.Focusable); ok {
 | 
			
		||||
			// direction := input.KeynavDirectionForward
 | 
			
		||||
			// if modifiers.Shift {
 | 
			
		||||
				// direction = input.KeynavDirectionBackward
 | 
			
		||||
			// }
 | 
			
		||||
// 
 | 
			
		||||
			// // TODO
 | 
			
		||||
		// }
 | 
			
		||||
		if modifiers.Shift {
 | 
			
		||||
			window.system.focusPrevious()
 | 
			
		||||
		} else {
 | 
			
		||||
			window.system.focusNext()
 | 
			
		||||
		}
 | 
			
		||||
	} else if key == input.KeyEscape && window.shy {
 | 
			
		||||
		window.Close()
 | 
			
		||||
	} else if child, ok := window.child.element.(tomo.KeyboardTarget); ok {
 | 
			
		||||
		child.HandleKeyDown(key, modifiers)
 | 
			
		||||
	} else if window.focused != nil {
 | 
			
		||||
		focused, ok := window.focused.element.(tomo.KeyboardTarget)
 | 
			
		||||
		if ok { focused.HandleKeyDown(key, modifiers) }
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	window.system.afterEvent()
 | 
			
		||||
@ -159,8 +149,7 @@ func (window *window) handleKeyRelease (
 | 
			
		||||
	connection *xgbutil.XUtil,
 | 
			
		||||
	event xevent.KeyReleaseEvent,
 | 
			
		||||
) {
 | 
			
		||||
	if window.child == nil { return }
 | 
			
		||||
	
 | 
			
		||||
	if window.system.focused == nil { return }
 | 
			
		||||
	keyEvent := *event.KeyReleaseEvent
 | 
			
		||||
 | 
			
		||||
	// do not process this event if it was generated from a key repeat
 | 
			
		||||
@ -184,9 +173,8 @@ func (window *window) handleKeyRelease (
 | 
			
		||||
	modifiers := window.modifiersFromState(keyEvent.State)
 | 
			
		||||
	modifiers.NumberPad = numberPad
 | 
			
		||||
	
 | 
			
		||||
	if child, ok := window.child.element.(tomo.KeyboardTarget); ok {
 | 
			
		||||
		child.HandleKeyUp(key, modifiers)
 | 
			
		||||
	}
 | 
			
		||||
	focused, ok := window.focused.element.(tomo.KeyboardTarget)
 | 
			
		||||
	if ok { focused.HandleKeyUp(key, modifiers) }
 | 
			
		||||
	
 | 
			
		||||
	window.system.afterEvent()
 | 
			
		||||
}
 | 
			
		||||
@ -195,34 +183,31 @@ func (window *window) handleButtonPress (
 | 
			
		||||
	connection *xgbutil.XUtil,
 | 
			
		||||
	event xevent.ButtonPressEvent,
 | 
			
		||||
) {
 | 
			
		||||
	if window.child == nil { return }
 | 
			
		||||
	if window.hasModal     { return }
 | 
			
		||||
	if window.hasModal { return }
 | 
			
		||||
	
 | 
			
		||||
	buttonEvent := *event.ButtonPressEvent
 | 
			
		||||
	
 | 
			
		||||
	insideWindow := image.Pt (
 | 
			
		||||
		int(buttonEvent.EventX),
 | 
			
		||||
		int(buttonEvent.EventY)).In(window.canvas.Bounds())
 | 
			
		||||
	buttonEvent  := *event.ButtonPressEvent
 | 
			
		||||
	point        := image.Pt(int(buttonEvent.EventX), int(buttonEvent.EventY))
 | 
			
		||||
	insideWindow := point.In(window.canvas.Bounds())
 | 
			
		||||
	scrolling    := buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7
 | 
			
		||||
 | 
			
		||||
	scrolling := buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7
 | 
			
		||||
		
 | 
			
		||||
	underneath := window.system.childAt(point)
 | 
			
		||||
	
 | 
			
		||||
	if !insideWindow && window.shy && !scrolling {
 | 
			
		||||
		window.Close()
 | 
			
		||||
	} else if scrolling {
 | 
			
		||||
		if child, ok := window.child.element.(tomo.ScrollTarget); ok {
 | 
			
		||||
		if child, ok := underneath.element.(tomo.ScrollTarget); ok {
 | 
			
		||||
			sum := scrollSum { }
 | 
			
		||||
			sum.add(buttonEvent.Detail, window, buttonEvent.State)
 | 
			
		||||
			window.compressScrollSum(buttonEvent, &sum)
 | 
			
		||||
			child.HandleScroll (
 | 
			
		||||
				int(buttonEvent.EventX),
 | 
			
		||||
				int(buttonEvent.EventY),
 | 
			
		||||
				point.X, point.Y,
 | 
			
		||||
				float64(sum.x), float64(sum.y))
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if child, ok := window.child.element.(tomo.MouseTarget); ok {
 | 
			
		||||
		if child, ok := underneath.element.(tomo.MouseTarget); ok {
 | 
			
		||||
			window.system.drags[buttonEvent.Detail] = child
 | 
			
		||||
			child.HandleMouseDown (
 | 
			
		||||
				int(buttonEvent.EventX),
 | 
			
		||||
				int(buttonEvent.EventY),
 | 
			
		||||
				point.X, point.Y,
 | 
			
		||||
				input.Button(buttonEvent.Detail))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -234,11 +219,10 @@ func (window *window) handleButtonRelease (
 | 
			
		||||
	connection *xgbutil.XUtil,
 | 
			
		||||
	event xevent.ButtonReleaseEvent,
 | 
			
		||||
) {
 | 
			
		||||
	if window.child == nil { return }
 | 
			
		||||
	
 | 
			
		||||
	if child, ok := window.child.element.(tomo.MouseTarget); ok {
 | 
			
		||||
		buttonEvent := *event.ButtonReleaseEvent
 | 
			
		||||
		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
 | 
			
		||||
	buttonEvent := *event.ButtonReleaseEvent
 | 
			
		||||
	if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
 | 
			
		||||
	child := window.system.drags[buttonEvent.Detail]
 | 
			
		||||
	if child != nil {
 | 
			
		||||
		child.HandleMouseUp (
 | 
			
		||||
			int(buttonEvent.EventX),
 | 
			
		||||
			int(buttonEvent.EventY),
 | 
			
		||||
@ -252,13 +236,23 @@ func (window *window) handleMotionNotify (
 | 
			
		||||
	connection *xgbutil.XUtil,
 | 
			
		||||
	event xevent.MotionNotifyEvent,
 | 
			
		||||
) {
 | 
			
		||||
	if window.child == nil { return }
 | 
			
		||||
	
 | 
			
		||||
	if child, ok := window.child.element.(tomo.MotionTarget); ok {
 | 
			
		||||
		motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
 | 
			
		||||
		child.HandleMotion (
 | 
			
		||||
			int(motionEvent.EventX),
 | 
			
		||||
			int(motionEvent.EventY))
 | 
			
		||||
	motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
 | 
			
		||||
	x := int(motionEvent.EventX)
 | 
			
		||||
	y :=int(motionEvent.EventY)
 | 
			
		||||
 | 
			
		||||
	handled := false
 | 
			
		||||
	for _, child := range window.system.drags {
 | 
			
		||||
		if child, ok := child.(tomo.MotionTarget); ok {
 | 
			
		||||
			child.HandleMotion(x, y)
 | 
			
		||||
			handled = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !handled {
 | 
			
		||||
		child := window.system.childAt(image.Pt(x, y))
 | 
			
		||||
		if child, ok := child.element.(tomo.MotionTarget); ok {
 | 
			
		||||
			child.HandleMotion(x, y)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	window.system.afterEvent()
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,8 @@ type system struct {
 | 
			
		||||
	invalidateIgnore bool
 | 
			
		||||
	drawingInvalid   entitySet
 | 
			
		||||
	anyLayoutInvalid bool
 | 
			
		||||
	
 | 
			
		||||
	drags [10]tomo.MouseTarget
 | 
			
		||||
 | 
			
		||||
	pushFunc func (image.Rectangle)
 | 
			
		||||
}
 | 
			
		||||
@ -40,18 +42,40 @@ func (system *system) initialize () {
 | 
			
		||||
 | 
			
		||||
func (system *system) SetTheme (theme tomo.Theme) {
 | 
			
		||||
	system.theme = theme
 | 
			
		||||
	if system.child == nil { return }
 | 
			
		||||
	if child, ok := system.child.element.(tomo.Themeable); ok {
 | 
			
		||||
		child.SetTheme(theme)
 | 
			
		||||
	}
 | 
			
		||||
	system.propagate (func (entity *entity) bool {
 | 
			
		||||
		if child, ok := system.child.element.(tomo.Themeable); ok {
 | 
			
		||||
			child.SetTheme(theme)
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) SetConfig (config tomo.Config) {
 | 
			
		||||
	system.config = config
 | 
			
		||||
	system.propagate (func (entity *entity) bool {
 | 
			
		||||
		if child, ok := system.child.element.(tomo.Configurable); ok {
 | 
			
		||||
			child.SetConfig(config)
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) focusNext () {
 | 
			
		||||
	// TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) focusPrevious () {
 | 
			
		||||
	// TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) propagate (callback func (*entity) bool) {
 | 
			
		||||
	if system.child == nil { return }
 | 
			
		||||
	if child, ok := system.child.element.(tomo.Configurable); ok {
 | 
			
		||||
		child.SetConfig(config)
 | 
			
		||||
	}
 | 
			
		||||
	system.child.propagate(callback)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) childAt (point image.Point) *entity {
 | 
			
		||||
	if system.child == nil { return nil }
 | 
			
		||||
	return system.child.childAt(point)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (system *system) resizeChildToFit () {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user