<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le lun. 6 janv. 2020 à 14:37, Marcel Taeumel <<a href="mailto:marcel.taeumel@hpi.de">marcel.taeumel@hpi.de</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div id="gmail-m_5382389470770557352__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:rgb(0,0,0)">
Hi Nicolas.<div><br></div><div>> <span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">IMO, global mouse wheel state serves just complexifies things uselessly.</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Not global. Local to a hand. There can be multiple hands in an image.</span></div><div><br></div><div>> <span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">So -1 for a Preferences, this is not a Preferences, this is a must, or we will never switch to sendMouseWheelEvents</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Agreed. :-)</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Also, smooth wheel scrolling is related to some magic numbers in PluggableTextMorph and ScrollPane (or ScrollBar). In any case an issue for after the 5.3 release. I suppose.</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Best,</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Marcel</span></div></div></blockquote><div><br></div><div>Indeed, magic numbers just show how experimental (young) the code is.</div><div>This can wait a few more weeks, the important thing is that we get the updated VM.</div><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div id="gmail-m_5382389470770557352__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:rgb(0,0,0)"><div></div>
<blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-top:20px;margin-left:0px;padding-left:10px;min-width:500px">
<p style="color:rgb(170,170,170);margin-top:10px">Am 06.01.2020 14:10:54 schrieb Nicolas Cellier <<a href="mailto:nicolas.cellier.aka.nice@gmail.com" target="_blank">nicolas.cellier.aka.nice@gmail.com</a>>:</p><div style="font-family:Arial,Helvetica,sans-serif">
<div dir="ltr"><div>Hi Marcel,</div><div>this is the pragmatical result of experimentation.</div><div>Please try such a configuration:</div><div>- a VM that sends mouse wheel events<br></div><div>- Smalltalk sendMouseWheelEvents: true</div><div>- a computer with a trackpad (preferably a MacBook which sends many many such events)</div><div><br></div><div>So -1 for a Preferences, this is not a Preferences, this is a must, or we will never switch to
sendMouseWheelEvents
</div><div><br></div><div>Concerning peekEvent, sorry, I don't understand the problem.</div><div>I used the exact same solution than HandMorph>>mouseTrailFrom: (from #generateMouseEvent:)</div><div>If we send #peekEvent at every #mouseMove we can also send it at every mouse wheel.</div><div><br></div><div>IMO, global mouse wheel state serves just complexifies things uselessly.</div><div>We don't want a global state (Or is it for MVC?)<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Le lun. 6 janv. 2020 à 13:46, Marcel Taeumel <<a href="mailto:marcel.taeumel@hpi.de" target="_blank">marcel.taeumel@hpi.de</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex;min-width:500px"><div id="gmail-m_5382389470770557352gmail-m_4029910953160414098__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:rgb(0,0,0)">
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.<div><br></div><div>Considering cross-platform VM issues in the past, I would rather not remove the delta aggregation (or delta mapping) from the image. <span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">MouseWheelState took inspiration from MouseClickState and MouseOverHandler.</span><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">So, I vote for:</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">- make delta aggregation (or mapping) optional in the image via a preference</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">- add that time-out to MouseWheelState</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">- no calls to "Sensor peekEvent" in HandMorph under any circumstances ... please :-)</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Best,</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px">Marcel</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px"><br></span></div></div><div></div>
<blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-top:20px;margin-left:0px;padding-left:10px;min-width:500px">
<p style="color:rgb(170,170,170);margin-top:10px">Am 27.12.2019 22:58:16 schrieb <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> <<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>>:</p><div style="font-family:Arial,Helvetica,sans-serif">Nicolas Cellier uploaded a new version of Morphic to project The Inbox:<br><a href="http://source.squeak.org/inbox/Morphic-nice.1613.mcz" target="_blank">http://source.squeak.org/inbox/Morphic-nice.1613.mcz</a><br><br>==================== Summary ====================<br><br>Name: Morphic-nice.1613<br>Author: nice<br>Time: 27 December 2019, 10:57:36.813907 pm<br>UUID: 07043442-aa16-4af4-9123-601cd503346a<br>Ancestors: Morphic-mt.1612<br><br>Provide smoother scrolling in response to mouse wheel events<br><br>Instead of delivering the events when delta reaches 120, make this threshold a Preference (minimumWheelDelta)<br><br>Reminder: 120 represents a single notch for traditional mouse wheel with notches, but trackpads can deliver much smaller deltas<br><br>Rather than accumulating the deltas into MouseWheelState, do it when we #generateMouseWheelEvent:<br>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...<br><br>Also MouseWheelState did ignore time outs (long delays between deltas) and other state changes (buttons/modifiers), which was not ideal.<br><br>Directly get those states from the raw eventBuffer, like any other mouse event. This requires integration of tose 2 PR:<br><a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/461" target="_blank">https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/461</a> for Windows<br><a href="https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/462" target="_blank">https://github.com/OpenSmalltalk/opensmalltalk-vm/pull/462</a> for OSX and linux<br><br>Honour larger deltas too in ScrollPane>>#mouseWheel: event handling<br>Honour horizontal mouse wheels too in ScrollPane<br><br>With patched VM, and following settings, I get a reasonnable scrolling experience on OSX:<br><br> HandMorph minimumWheelDelta: 20.<br> Smalltalk sendMouseWheelEvents: true.<br><br>=============== Diff against Morphic-mt.1612 ===============<br><br>Item was changed:<br> Morph subclass: #HandMorph<br> 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'<br>+ classVariableNames: 'CompositionWindowManager DoubleClickTime DragThreshold EventStats MinimalWheelDelta NewEventRules NormalCursor PasteBuffer SendMouseWheelToKeyboardFocus ShowEvents SynthesizeMouseWheelEvents'<br>- classVariableNames: 'CompositionWindowManager DoubleClickTime DragThreshold EventStats NewEventRules NormalCursor PasteBuffer SendMouseWheelToKeyboardFocus ShowEvents SynthesizeMouseWheelEvents'<br> poolDictionaries: 'EventSensorConstants'<br> category: 'Morphic-Kernel'!<br> <br> !HandMorph commentStamp: '<u></u>' prior: 0!<br> The cursor may be thought of as the HandMorph. The hand's submorphs hold anything being carried by dragging. <br> <br> There is some minimal support for multiple hands in the same world.!<br><br>Item was added:<br>+ ----- Method: HandMorph class>>minimumWheelDelta (in category 'preferences') -----<br>+ minimumWheelDelta<br>+ <u></u><u></u><br>+ categoryList: #(Morphic mouse)<br>+ description: 'Answer the minimal scroll increment taken into account<br>+ Defaults to 120, corresponding to a single mouse wheel notch.<br>+ Use a lower value (20) if wanting smoother scrolling with trackpads.'<br>+ type: #Number><br>+ ^MinimalWheelDelta ifNil: [120].!<br><br>Item was added:<br>+ ----- Method: HandMorph class>>minimumWheelDelta: (in category 'preferences') -----<br>+ minimumWheelDelta: anInteger<br>+ MinimalWheelDelta := anInteger ifNotNil: [anInteger clampLow: 20 high: 120]!<br><br>Item was changed:<br> ----- Method: HandMorph>>generateMouseWheelEvent: (in category 'private events') -----<br> generateMouseWheelEvent: evtBuf<br> "Generate the appropriate mouse wheel event for the given raw event buffer"<br> <br>+ | buttons modifiers deltaX deltaY stamp nextEvent |<br>- | buttons modifiers deltaX deltaY stamp |<br> stamp := evtBuf second.<br> stamp = 0 ifTrue: [stamp := Time eventMillisecondClock].<br> deltaX := evtBuf third.<br> deltaY := evtBuf fourth.<br>+ buttons := evtBuf fifth.<br>+ modifiers := evtBuf sixth.<br>+ [(deltaX abs + deltaY abs < self="" class=""><br>+ and: [(nextEvent := Sensor peekEvent) notNil<br>+ and: [nextEvent first = evtBuf first<br>+ and: [nextEvent fifth = evtBuf fifth <br>+ and: [nextEvent sixth = evtBuf sixth]<br>+ and: [nextEvent third isZero = evtBuf third isZero "both horizontal or vertical"]]]]]<br>+ whileTrue:<br>+ ["nextEvent is similar. Remove it from the queue, and check the next."<br>+ nextEvent := Sensor nextEvent.<br>+ deltaX := deltaX + nextEvent third.<br>+ deltaY := deltaY + nextEvent fourth].<br>- modifiers := evtBuf fifth.<br>- buttons := (modifiers bitShift: 3) bitOr: (lastMouseEvent buttons bitAnd: 7).<br> ^ MouseWheelEvent new<br> setType: #mouseWheel<br> position: self position<br> delta: deltaX@deltaY<br>- direction: 2r0000<br> buttons: buttons <br> hand: self<br> stamp: stamp!<br><br>Item was changed:<br> ----- Method: HandMorph>>handleEvent: (in category 'events-processing') -----<br> handleEvent: unfilteredEvent<br> <br> | filteredEvent |<br> owner ifNil: [^ unfilteredEvent "not necessary but good style -- see Morph >> #handleEvent:"].<br> <br> self logEvent: unfilteredEvent.<br> <br> "Mouse-over events occur really, really, really often. They are kind of the heart beat of the Morphic UI process."<br> unfilteredEvent isMouseOver ifTrue: [^ self sendMouseEvent: unfilteredEvent].<br> <br> self showEvent: unfilteredEvent.<br> self sendListenEvents: unfilteredEvent.<br> <br> filteredEvent := self sendFilterEventCapture: unfilteredEvent for: nil.<br> "filteredEvent := unfilteredEvent" " <-- use="" this="" to="" disable="" global="" capture=""><br> <br> filteredEvent wasIgnored ifTrue: [<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> filteredEvent isWindowEvent ifTrue: [<br> self sendEvent: filteredEvent focus: nil.<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> filteredEvent isKeyboard ifTrue:[<br> self sendKeyboardEvent: filteredEvent.<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> filteredEvent isDropEvent ifTrue:[<br> self sendEvent: filteredEvent focus: nil.<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> filteredEvent isMouse ifFalse: [<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> " ********** MOUSE EVENT *********** "<br> <br> lastMouseEvent := filteredEvent.<br> <br> "Check for pending drag or double click operations."<br> mouseClickState ifNotNil:[<br> (mouseClickState handleEvent: filteredEvent from: self) ifFalse:[<br> "Possibly dispatched #click: or something and will not re-establish otherwise"<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent]].<br> <br> filteredEvent isMouseWheel ifTrue: [<br>+ self class sendMouseWheelToKeyboardFocus<br>+ ifFalse: [self sendMouseEvent: filteredEvent]<br>+ ifTrue: [self sendEvent: filteredEvent focus: self keyboardFocus clear: [self keyboardFocus: nil]].<br>- mouseWheelState ifNil: [mouseWheelState := MouseWheelState new].<br>- mouseWheelState handleEvent: filteredEvent from: self.<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> filteredEvent isMove ifTrue:[<br> self position: filteredEvent position.<br> self sendMouseEvent: filteredEvent.<br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent].<br> <br> "Issue a synthetic move event if we're not at the position of the event"<br> filteredEvent position = self position<br> ifFalse: [self moveToEvent: filteredEvent].<br> <br> "Drop submorphs on button events"<br> self hasSubmorphs<br> ifTrue:[self dropMorphs: filteredEvent]<br> ifFalse:[self sendMouseEvent: filteredEvent].<br> <br> self mouseOverHandler processMouseOver: lastMouseEvent.<br> ^ filteredEvent "not necessary but good style -- see Morph >> #handleEvent:" !<br><br>Item was added:<br>+ ----- Method: MouseWheelEvent>>setDirection (in category 'initialization') -----<br>+ setDirection<br>+ delta x > 0 ifTrue: [self setWheelRight].<br>+ delta x < 0="" iftrue:="" [self=""><br>+ <br>+ delta y > 0 ifTrue: [self setWheelUp].<br>+ delta y < 0="" iftrue:="" [self=""><br><br>Item was added:<br>+ ----- Method: MouseWheelEvent>>setType:position:delta:buttons:hand:stamp: (in category 'private') -----<br>+ setType: evtType position: evtPos delta: evtDelta buttons: evtButtons hand: evtHand stamp: stamp<br>+ type := evtType.<br>+ position := evtPos.<br>+ buttons := evtButtons.<br>+ source := evtHand.<br>+ wasHandled := false.<br>+ direction := 2r0000.<br>+ delta := evtDelta.<br>+ timeStamp := stamp.<br>+ self setDirection!<br><br>Item was removed:<br>- Object subclass: #MouseWheelState<br>- instanceVariableNames: 'currentDelta'<br>- classVariableNames: ''<br>- poolDictionaries: ''<br>- category: 'Morphic-Events'!<br><br>Item was removed:<br>- ----- Method: MouseWheelState>>handleEvent:from: (in category 'event processing') -----<br>- handleEvent: aMouseWheelEvent from: aHand<br>- "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."<br>- <br>- | sign |<br>- currentDelta := currentDelta + aMouseWheelEvent wheelDelta.<br>- <br>- sign := currentDelta sign.<br>- currentDelta := currentDelta abs.<br>- <br>- (currentDelta x // 120) > 0 ifTrue: [<br>- sign x = 1<br>- ifTrue: [aMouseWheelEvent setWheelRight]<br>- ifFalse: [aMouseWheelEvent setWheelLeft]].<br>- <br>- (currentDelta y // 120) > 0 ifTrue: [<br>- sign y = 1<br>- ifTrue: [aMouseWheelEvent setWheelUp]<br>- ifFalse: [aMouseWheelEvent setWheelDown]].<br>- <br>- currentDelta := currentDelta \\ 120.<br>- currentDelta := currentDelta * sign.<br>- <br>- "Finally, send the event."<br>- HandMorph sendMouseWheelToKeyboardFocus<br>- ifFalse: [aHand sendMouseEvent: aMouseWheelEvent]<br>- ifTrue: [aHand sendEvent: aMouseWheelEvent focus: aHand keyboardFocus clear: [aHand keyboardFocus: nil]].<br>- !<br><br>Item was removed:<br>- ----- Method: MouseWheelState>>initialize (in category 'initialize-release') -----<br>- initialize<br>- <br>- super initialize.<br>- currentDelta := 0@0.!<br><br>Item was changed:<br> ----- Method: ScrollPane>>mouseWheel: (in category 'event handling') -----<br> mouseWheel: evt<br> <br>+ evt isWheelUp ifTrue: [scrollBar scrollUp: (3 * evt wheelDelta y abs // 120 max: 1)].<br>+ evt isWheelDown ifTrue: [scrollBar scrollDown: (3 * evt wheelDelta y abs // 120 max: 1)].<br>+ evt isWheelLeft ifTrue: [hScrollBar scrollUp: (3 * evt wheelDelta x abs // 120 max: 1)].<br>+ evt isWheelRight ifTrue: [hScrollBar scrollDown: (3 * evt wheelDelta x abs // 120 max: 1)].!<br>- evt isWheelUp ifTrue: [scrollBar scrollUp: 3].<br>- evt isWheelDown ifTrue: [scrollBar scrollDown: 3].!<br><br><br><u></u></div></blockquote></div><br>
</blockquote></div>
</div></blockquote></div><br>
</blockquote></div></div>