[squeak-dev] The Inbox: Morphic-nice.1613.mcz

Nicolas Cellier nicolas.cellier.aka.nice at gmail.com
Mon Jan 6 13:06:44 UTC 2020


Hi Marcel,
this is the pragmatical result of experimentation.
Please try such a configuration:
- a VM that sends mouse wheel events
- Smalltalk sendMouseWheelEvents: true
- a computer with a trackpad (preferably a MacBook which sends many many
such events)

So -1 for a Preferences, this is not a Preferences, this is a must, or we
will never switch to sendMouseWheelEvents

Concerning peekEvent, sorry, I don't understand the problem.
I used the exact same solution than HandMorph>>mouseTrailFrom: (from
#generateMouseEvent:)
If we send #peekEvent at every #mouseMove we can also send it at every
mouse wheel.

IMO, global mouse wheel state serves  just complexifies things uselessly.
We don't want a global state (Or is it for MVC?)

Le lun. 6 janv. 2020 à 13:46, Marcel Taeumel <marcel.taeumel at hpi.de> a
écrit :

> Hmm... so you want to move any delta aggregation into the VM but keep
> delta-to-event mapping inside the image. In a perfect world, this would be
> the way to go. But the use of "Sensor peekEvent" is really, really, really
> unfortunate! :-) I would try to remove it the next time I stumble over it.
> :-D Sorry.
>
> Considering cross-platform VM issues in the past, I would rather not
> remove the delta aggregation (or delta mapping) from the image. MouseWheelState
> took inspiration from MouseClickState and MouseOverHandler.
>
> So, I vote for:
>
> - make delta aggregation (or mapping) optional in the image via a
> preference
> - add that time-out to MouseWheelState
> - no calls to "Sensor peekEvent" in HandMorph under any circumstances ...
> please :-)
>
> Best,
> Marcel
>
> Am 27.12.2019 22:58:16 schrieb commits at source.squeak.org <
> commits at source.squeak.org>:
> Nicolas Cellier uploaded a new version of Morphic to project The Inbox:
> http://source.squeak.org/inbox/Morphic-nice.1613.mcz
>
> ==================== Summary ====================
>
> Name: Morphic-nice.1613
> Author: nice
> Time: 27 December 2019, 10:57:36.813907 pm
> UUID: 07043442-aa16-4af4-9123-601cd503346a
> Ancestors: Morphic-mt.1612
>
> Provide smoother scrolling in response to mouse wheel events
>
> Instead of delivering the events when delta reaches 120, make this
> threshold a Preference (minimumWheelDelta)
>
> Reminder: 120 represents a single notch for traditional mouse wheel with
> notches, but trackpads can deliver much smaller deltas
>
> Rather than accumulating the deltas into MouseWheelState, do it when we
> #generateMouseWheelEvent:
> Indeed, small deltas will come in packets of successive events, and it's
> more efficient to regroup then, a bit like we do with mouse trails...
>
> Also MouseWheelState did ignore time outs (long delays between deltas) and
> other state changes (buttons/modifiers), which was not ideal.
>
> Directly get those states from the raw eventBuffer, like any other mouse
> event. This requires integration of tose 2 PR:
> https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/461 for Windows
> https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/462 for OSX and
> linux
>
> Honour larger deltas too in ScrollPane>>#mouseWheel: event handling
> Honour horizontal mouse wheels too in ScrollPane
>
> With patched VM, and following settings, I get a reasonnable scrolling
> experience on OSX:
>
> HandMorph minimumWheelDelta: 20.
> Smalltalk sendMouseWheelEvents: true.
>
> =============== Diff against Morphic-mt.1612 ===============
>
> Item was changed:
> Morph subclass: #HandMorph
> instanceVariableNames: 'mouseFocus keyboardFocus eventListeners
> mouseListeners keyboardListeners eventCaptureFilters mouseCaptureFilters
> keyboardCaptureFilters mouseClickState mouseOverHandler mouseWheelState
> lastMouseEvent targetOffset damageRecorder cacheCanvas cachedCanvasHasHoles
> temporaryCursor temporaryCursorOffset hardwareCursor hasChanged savedPatch
> userInitials lastEventBuffer genieGestureProcessor keyboardInterpreter'
> + classVariableNames: 'CompositionWindowManager DoubleClickTime
> DragThreshold EventStats MinimalWheelDelta NewEventRules NormalCursor
> PasteBuffer SendMouseWheelToKeyboardFocus ShowEvents
> SynthesizeMouseWheelEvents'
> - classVariableNames: 'CompositionWindowManager DoubleClickTime
> DragThreshold EventStats NewEventRules NormalCursor PasteBuffer
> SendMouseWheelToKeyboardFocus ShowEvents SynthesizeMouseWheelEvents'
> poolDictionaries: 'EventSensorConstants'
> category: 'Morphic-Kernel'!
>
> !HandMorph commentStamp: '' prior: 0!
> The cursor may be thought of as the HandMorph. The hand's submorphs hold
> anything being carried by dragging.
>
> There is some minimal support for multiple hands in the same world.!
>
> Item was added:
> + ----- Method: HandMorph class>>minimumWheelDelta (in category
> 'preferences') -----
> + minimumWheelDelta
> +
> + categoryList: #(Morphic mouse)
> + description: 'Answer the minimal scroll increment taken into account
> + Defaults to 120, corresponding to a single mouse wheel notch.
> + Use a lower value (20) if wanting smoother scrolling with trackpads.'
> + type: #Number>
> + ^MinimalWheelDelta ifNil: [120].!
>
> Item was added:
> + ----- Method: HandMorph class>>minimumWheelDelta: (in category
> 'preferences') -----
> + minimumWheelDelta: anInteger
> + MinimalWheelDelta := anInteger ifNotNil: [anInteger clampLow: 20 high:
> 120]!
>
> Item was changed:
> ----- Method: HandMorph>>generateMouseWheelEvent: (in category 'private
> events') -----
> generateMouseWheelEvent: evtBuf
> "Generate the appropriate mouse wheel event for the given raw event buffer"
>
> + | buttons modifiers deltaX deltaY stamp nextEvent |
> - | buttons modifiers deltaX deltaY stamp |
> stamp := evtBuf second.
> stamp = 0 ifTrue: [stamp := Time eventMillisecondClock].
> deltaX := evtBuf third.
> deltaY := evtBuf fourth.
> + buttons := evtBuf fifth.
> + modifiers := evtBuf sixth.
> + [(deltaX abs + deltaY abs < self="" class="">
> + and: [(nextEvent := Sensor peekEvent) notNil
> + and: [nextEvent first = evtBuf first
> + and: [nextEvent fifth = evtBuf fifth
> + and: [nextEvent sixth = evtBuf sixth]
> + and: [nextEvent third isZero = evtBuf third isZero "both horizontal or
> vertical"]]]]]
> + whileTrue:
> + ["nextEvent is similar. Remove it from the queue, and check the next."
> + nextEvent := Sensor nextEvent.
> + deltaX := deltaX + nextEvent third.
> + deltaY := deltaY + nextEvent fourth].
> - modifiers := evtBuf fifth.
> - buttons := (modifiers bitShift: 3) bitOr: (lastMouseEvent buttons
> bitAnd: 7).
> ^ MouseWheelEvent new
> setType: #mouseWheel
> position: self position
> delta: deltaX at deltaY
> - direction: 2r0000
> buttons: buttons
> hand: self
> stamp: stamp!
>
> Item was changed:
> ----- Method: HandMorph>>handleEvent: (in category 'events-processing')
> -----
> handleEvent: unfilteredEvent
>
> | filteredEvent |
> owner ifNil: [^ unfilteredEvent "not necessary but good style -- see Morph
> >> #handleEvent:"].
>
> self logEvent: unfilteredEvent.
>
> "Mouse-over events occur really, really, really often. They are kind of
> the heart beat of the Morphic UI process."
> unfilteredEvent isMouseOver ifTrue: [^ self sendMouseEvent:
> unfilteredEvent].
>
> self showEvent: unfilteredEvent.
> self sendListenEvents: unfilteredEvent.
>
> filteredEvent := self sendFilterEventCapture: unfilteredEvent for: nil.
> "filteredEvent := unfilteredEvent" " <-- use="" this="" to="" disable=""
> global="" capture="">
>
> filteredEvent wasIgnored ifTrue: [
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> filteredEvent isWindowEvent ifTrue: [
> self sendEvent: filteredEvent focus: nil.
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> filteredEvent isKeyboard ifTrue:[
> self sendKeyboardEvent: filteredEvent.
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> filteredEvent isDropEvent ifTrue:[
> self sendEvent: filteredEvent focus: nil.
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> filteredEvent isMouse ifFalse: [
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> " ********** MOUSE EVENT *********** "
>
> lastMouseEvent := filteredEvent.
>
> "Check for pending drag or double click operations."
> mouseClickState ifNotNil:[
> (mouseClickState handleEvent: filteredEvent from: self) ifFalse:[
> "Possibly dispatched #click: or something and will not re-establish
> otherwise"
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent]].
>
> filteredEvent isMouseWheel ifTrue: [
> + self class sendMouseWheelToKeyboardFocus
> + ifFalse: [self sendMouseEvent: filteredEvent]
> + ifTrue: [self sendEvent: filteredEvent focus: self keyboardFocus clear:
> [self keyboardFocus: nil]].
> - mouseWheelState ifNil: [mouseWheelState := MouseWheelState new].
> - mouseWheelState handleEvent: filteredEvent from: self.
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> filteredEvent isMove ifTrue:[
> self position: filteredEvent position.
> self sendMouseEvent: filteredEvent.
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent].
>
> "Issue a synthetic move event if we're not at the position of the event"
> filteredEvent position = self position
> ifFalse: [self moveToEvent: filteredEvent].
>
> "Drop submorphs on button events"
> self hasSubmorphs
> ifTrue:[self dropMorphs: filteredEvent]
> ifFalse:[self sendMouseEvent: filteredEvent].
>
> self mouseOverHandler processMouseOver: lastMouseEvent.
> ^ filteredEvent "not necessary but good style -- see Morph >>
> #handleEvent:" !
>
> Item was added:
> + ----- Method: MouseWheelEvent>>setDirection (in category
> 'initialization') -----
> + setDirection
> + delta x > 0 ifTrue: [self setWheelRight].
> + delta x < 0="" iftrue:="" [self="">
> +
> + delta y > 0 ifTrue: [self setWheelUp].
> + delta y < 0="" iftrue:="" [self="">
>
> Item was added:
> + ----- Method:
> MouseWheelEvent>>setType:position:delta:buttons:hand:stamp: (in category
> 'private') -----
> + setType: evtType position: evtPos delta: evtDelta buttons: evtButtons
> hand: evtHand stamp: stamp
> + type := evtType.
> + position := evtPos.
> + buttons := evtButtons.
> + source := evtHand.
> + wasHandled := false.
> + direction := 2r0000.
> + delta := evtDelta.
> + timeStamp := stamp.
> + self setDirection!
>
> Item was removed:
> - Object subclass: #MouseWheelState
> - instanceVariableNames: 'currentDelta'
> - classVariableNames: ''
> - poolDictionaries: ''
> - category: 'Morphic-Events'!
>
> Item was removed:
> - ----- Method: MouseWheelState>>handleEvent:from: (in category 'event
> processing') -----
> - handleEvent: aMouseWheelEvent from: aHand
> - "Every 120 units, raise the wheel flags for convenient mouse wheel
> programming. We choose not to send multiple mouse-wheel events for
> multiples of 120 because applications can always react to the actual delta
> values if they want to do more scrolling or zooming."
> -
> - | sign |
> - currentDelta := currentDelta + aMouseWheelEvent wheelDelta.
> -
> - sign := currentDelta sign.
> - currentDelta := currentDelta abs.
> -
> - (currentDelta x // 120) > 0 ifTrue: [
> - sign x = 1
> - ifTrue: [aMouseWheelEvent setWheelRight]
> - ifFalse: [aMouseWheelEvent setWheelLeft]].
> -
> - (currentDelta y // 120) > 0 ifTrue: [
> - sign y = 1
> - ifTrue: [aMouseWheelEvent setWheelUp]
> - ifFalse: [aMouseWheelEvent setWheelDown]].
> -
> - currentDelta := currentDelta \\ 120.
> - currentDelta := currentDelta * sign.
> -
> - "Finally, send the event."
> - HandMorph sendMouseWheelToKeyboardFocus
> - ifFalse: [aHand sendMouseEvent: aMouseWheelEvent]
> - ifTrue: [aHand sendEvent: aMouseWheelEvent focus: aHand keyboardFocus
> clear: [aHand keyboardFocus: nil]].
> - !
>
> Item was removed:
> - ----- Method: MouseWheelState>>initialize (in category
> 'initialize-release') -----
> - initialize
> -
> - super initialize.
> - currentDelta := 0 at 0.!
>
> Item was changed:
> ----- Method: ScrollPane>>mouseWheel: (in category 'event handling') -----
> mouseWheel: evt
>
> + evt isWheelUp ifTrue: [scrollBar scrollUp: (3 * evt wheelDelta y abs //
> 120 max: 1)].
> + evt isWheelDown ifTrue: [scrollBar scrollDown: (3 * evt wheelDelta y abs
> // 120 max: 1)].
> + evt isWheelLeft ifTrue: [hScrollBar scrollUp: (3 * evt wheelDelta x abs
> // 120 max: 1)].
> + evt isWheelRight ifTrue: [hScrollBar scrollDown: (3 * evt wheelDelta x
> abs // 120 max: 1)].!
> - evt isWheelUp ifTrue: [scrollBar scrollUp: 3].
> - evt isWheelDown ifTrue: [scrollBar scrollDown: 3].!
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200106/0145cab7/attachment.html>


More information about the Squeak-dev mailing list