<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from text --><style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
</head>
<body>
<meta content="text/html; charset=UTF-8">
<style type="text/css" style="">
<!--
p
        {margin-top:0;
        margin-bottom:0}
-->
</style>
<div dir="ltr">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size:12pt; color:#000000; font-family:Calibri,Helvetica,sans-serif">
<p>Hm, the diff looks weird again. Did I make some mistake or is this some issue with the "diff server" (unknowing any details on how this online stuff works)? Chris, could you maybe enlighten me? :)</p>
<div id="x_Signature">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size:12pt; color:rgb(0,0,0); font-family:Calibri,Helvetica,sans-serif,EmojiFont,"Apple Color Emoji","Segoe UI Emoji",NotoColorEmoji,"Segoe UI Symbol","Android Emoji",EmojiSymbols">
<div name="x_divtagdefaultwrapper" style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:; margin:0">
<div>
<div class="x__rp_T4" id="x_Item.MessagePartBody">
<div class="x__rp_U4 x_ms-font-weight-regular x_ms-font-color-neutralDark x_rpHighlightAllClass x_rpHighlightBodyClass" id="x_Item.MessageUniqueBody" style="font-family:wf_segoe-ui_normal,"Segoe UI","Segoe WP",Tahoma,Arial,sans-serif,serif,EmojiFont">
<div dir="ltr">
<div id="x_divtagdefaultwrapper"><font face="Calibri,Helvetica,sans-serif,EmojiFont,Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols">
<div id="x_Signature">
<div style="margin:0px"><font style="font-family:Calibri,Arial,Helvetica,sans-serif,serif,EmojiFont"></font></div>
</div>
</font></div>
</div>
</div>
</div>
<div class="x__rp_T4" id="x_Item.MessagePartBody"><br>
</div>
<div class="x__rp_T4" id="x_Item.MessagePartBody">Best,</div>
<div class="x__rp_T4" id="x_Item.MessagePartBody">Christoph</div>
</div>
<div><font size="2" color="#808080"></font></div>
</div>
</div>
</div>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>Von:</b> Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von commits@source.squeak.org <commits@source.squeak.org><br>
<b>Gesendet:</b> Sonntag, 12. Januar 2020 03:34:33<br>
<b>An:</b> squeak-dev@lists.squeakfoundation.org<br>
<b>Betreff:</b> [squeak-dev] The Inbox: Morphic-ct.1617.mcz</font>
<div> </div>
</div>
</div>
<font size="2"><span style="font-size:10pt;">
<div class="PlainText">Christoph Thiede uploaded a new version of Morphic to project The Inbox:<br>
<a href="http://source.squeak.org/inbox/Morphic-ct.1617.mcz">http://source.squeak.org/inbox/Morphic-ct.1617.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Morphic-ct.1617<br>
Author: ct<br>
Time: 12 January 2020, 3:34:20.453555 am<br>
UUID: d75dd5ad-8420-c443-9314-c01d96409fae<br>
Ancestors: Morphic-tpr.1616<br>
<br>
Fixes #applyUserInterfaceTheme on SystemProgressMorph really!<br>
<br>
Explanation: Resetting the ProgressMorph from the class side is definively bad, because it deletes the progress morph if currently visible. The current instance-side implementation was not reliable either, because if the UniqueInstance is not in world, it cannot
 apply the new UI theme. Thus we need to override #canApplyUserInterfaceTheme from Morph.<br>
<br>
This commit replaces Morphic-ct.1615. See also: <a href="http://forum.world.st/SystemProgressMorph-applyUserInterfaceTheme-td5108129.html">
http://forum.world.st/SystemProgressMorph-applyUserInterfaceTheme-td5108129.html</a><br>
<br>
=============== Diff against Morphic-tpr.1616 ===============<br>
<br>
Item was added:<br>
+ ----- Method: AlternatePluggableListMorphOfMany>>mouseLeaveDragging: (in category 'event handling') -----<br>
+ mouseLeaveDragging: anEvent<br>
+        "Dragging means changing the list's multi-selection state. Thus, there is no support for drag-and-drop of elements within a selection."<br>
+        <br>
+        self hoverRow: nil.<br>
+        self resetPotentialDropRow.!<br>
<br>
Item was changed:<br>
  ----- Method: FontChooserTool>>selectedPointSizeIndex: (in category 'point size') -----<br>
  selectedPointSizeIndex: anIndex<br>
  <br>
         anIndex = 0 ifTrue: [^self].<br>
         pointSize := (self pointSizeList at: anIndex) withBlanksTrimmed asNumber.<br>
+        self changed: #selectedPointSizeIndex.<br>
         self changed: #pointSizeList.<br>
         self changed: #contents.!<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 NewEventRules NormalCursor PasteBuffer SendMouseWheelToKeyboardFocus ShowEvents SynthesizeMouseWheelEvents'<br>
-        instanceVariableNames: 'mouseFocus keyboardFocus eventListeners mouseListeners keyboardListeners eventCaptureFilters mouseCaptureFilters keyboardCaptureFilters mouseClickState mouseOverHandler targetOffset lastMouseEvent 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>
         poolDictionaries: 'EventSensorConstants'<br>
         category: 'Morphic-Kernel'!<br>
  <br>
  !HandMorph commentStamp: '<historical>' 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 removed:<br>
- ----- Method: HandMorph class>>minimumWheelDelta (in category 'preferences') -----<br>
- minimumWheelDelta<br>
-        <preference: 'Minimal Mouse Wheel Scroll Delta'<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 removed:<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 |<br>
-        | buttons modifiers deltaX deltaY stamp nextEvent |<br>
         stamp := evtBuf second.<br>
         stamp = 0 ifTrue: [stamp := Time eventMillisecondClock].<br>
         deltaX := evtBuf third.<br>
         deltaY := evtBuf fourth.<br>
+        modifiers := evtBuf fifth.<br>
+        buttons := (modifiers bitShift: 3) bitOr: (lastMouseEvent buttons bitAnd: 7).<br>
-        buttons := evtBuf fifth.<br>
-        modifiers := evtBuf sixth.<br>
-        [(deltaX abs + deltaY abs < self class minimumWheelDelta)<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>
         ^ 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 filters"<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>
+                mouseWheelState ifNil: [mouseWheelState := MouseWheelState new].<br>
+                mouseWheelState handleEvent: filteredEvent from: self.<br>
-                self class sendMouseWheelToKeyboardFocus<br>
-                        ifFalse: [self sendMouseEvent: filteredEvent]<br>
-                        ifTrue: [self sendEvent: filteredEvent focus: self keyboardFocus clear: [self keyboardFocus: nil]].<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 removed:<br>
- ----- Method: MouseWheelEvent>>setDirection (in category 'initialization') -----<br>
- setDirection<br>
-        delta x > 0 ifTrue: [self setWheelRight].<br>
-        delta x < 0 ifTrue: [self setWheelLeft].<br>
- <br>
-        delta y > 0 ifTrue: [self setWheelUp].<br>
-        delta y < 0 ifTrue: [self setWheelDown].!<br>
<br>
Item was removed:<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 added:<br>
+ Object subclass: #MouseWheelState<br>
+        instanceVariableNames: 'currentDelta'<br>
+        classVariableNames: ''<br>
+        poolDictionaries: ''<br>
+        category: 'Morphic-Events'!<br>
<br>
Item was added:<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 added:<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: PluggableListMorph>>mouseUp: (in category 'event handling') -----<br>
  mouseUp: event <br>
  <br>
         | row |<br>
         model okToChange ifFalse: [^ self].<br>
+        (self containsPoint: event position) ifFalse: [^ self].<br>
  <br>
         row := self rowAtLocation: event position.<br>
         row = self selectionIndex<br>
                 ifTrue: [(autoDeselect ifNil: [true]) ifTrue: [row = 0 ifFalse: [self changeModelSelection: 0] ]]<br>
                 ifFalse: [self changeModelSelection: (self modelIndexFor: row)].<br>
                 <br>
         event hand newKeyboardFocus: self. <br>
         hasFocus := true.<br>
         Cursor normal show.!<br>
<br>
Item was changed:<br>
  ----- Method: ScrollPane>>mouseWheel: (in category 'event handling') -----<br>
  mouseWheel: evt<br>
  <br>
+        evt isWheelUp ifTrue: [scrollBar scrollUp: 3].<br>
+        evt isWheelDown ifTrue: [scrollBar scrollDown: 3].!<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>
<br>
Item was changed:<br>
  ----- Method: StringMorph>>contents: (in category 'accessing') -----<br>
  contents: newContents <br>
  <br>
         newContents isText<br>
                 ifTrue: [^ self initializeFromText: newContents].<br>
  <br>
         contents = newContents<br>
+                ifTrue: [^ self "No substantive change."].<br>
-                ifTrue: [^ self "no substantive change"].<br>
  <br>
         contents := newContents.<br>
+        self changed. "New contents need to be drawn."<br>
+                <br>
+        self fitContents. "Resize if necessary."!<br>
-        <br>
-        self fitContents.!<br>
<br>
Item was changed:<br>
  ----- Method: StringMorph>>fitContents (in category 'layout') -----<br>
  fitContents<br>
  <br>
+        self extent: self measureContents.!<br>
-        | newBounds boundsChanged |<br>
-        newBounds := self measureContents.<br>
-        boundsChanged := bounds extent ~= newBounds.<br>
-        self extent: newBounds.         "default short-circuits if bounds not changed"<br>
-        boundsChanged ifFalse: [self changed]!<br>
<br>
Item was removed:<br>
- ----- Method: SystemProgressMorph class>>applyUserInterfaceTheme (in category 'preferences') -----<br>
- applyUserInterfaceTheme<br>
- <br>
-        self reset.!<br>
<br>
Item was added:<br>
+ ----- Method: SystemProgressMorph>>canApplyUserInterfaceTheme (in category 'updating') -----<br>
+ canApplyUserInterfaceTheme<br>
+ <br>
+        ^ true!<br>
<br>
Item was changed:<br>
  ----- Method: UpdatingStringMorph>>fitContents (in category 'layout') -----<br>
  fitContents<br>
+        "Overridden to respect minimum and maximum widfth."<br>
+        <br>
- <br>
         | newExtent |<br>
+        newExtent :=  self measureContents.<br>
+        self extent: ((newExtent x max: self minimumWidth) min: self maximumWidth) @ newExtent y.!<br>
-        newExtent := self measureContents.<br>
-        newExtent := ((newExtent x max: self minimumWidth) min: self maximumWidth) @ newExtent y.<br>
-        (self extent = newExtent) ifFalse:<br>
-                [self extent: newExtent.<br>
-                self changed]<br>
- !<br>
<br>
Item was changed:<br>
  ----- Method: UpdatingStringMorph>>updateContentsFrom: (in category 'stepping') -----<br>
  updateContentsFrom: aValue<br>
         self growable<br>
                 ifTrue:<br>
+                        [self contentsFitted: aValue]<br>
-                        [self contents: aValue]<br>
                 ifFalse:<br>
                         [self contentsClipped: aValue]!<br>
<br>
<br>
</div>
</span></font>
</body>
</html>