<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
                                        If you care for it, go ahead and merge it. Yet, notice the extra complexity in the form of two new instVars etc. That was one of the reasons I did not do it. :-)<div><br></div><div>You should also mention that you also decided on some visual updates in the form of border etc. I did not use that by intention as well ;-)</div><div><br></div><div>Best,</div><div>Marcel</div><div class="mb_sig"></div><blockquote class='history_container' type='cite' style='border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;'>
                        <p style='color: #AAAAAA; margin-top: 10px;'>Am 19.11.2022 20:36:17 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style='font-family:Arial,Helvetica,sans-serif'>Christoph Thiede uploaded a new version of Morphic to project The Inbox:<br>http://source.squeak.org/inbox/Morphic-ct.2051.mcz<br><br>==================== Summary ====================<br><br>Name: Morphic-ct.2051<br>Author: ct<br>Time: 19 November 2022, 8:35:59.299387 pm<br>UUID: 6d037f4d-9ad4-8f48-8a0b-b40df261c00c<br>Ancestors: Morphic-mt.2049<br><br>Makes keyboard exerciser scale-factor-aware. Fixes layout of instruction text, which was previously not wrapped within the morph, overlapped the check buttons, and caused invalidations when moving or closing the exerciser. For this, uses a classical row-based tabel layout.<br><br>=============== Diff against Morphic-mt.2049 ===============<br><br>Item was changed:<br>  Morph subclass: #KeyboardExerciser<br>+  instanceVariableNames: 'checkButtons eventPane'<br>-      instanceVariableNames: ''<br>     classVariableNames: ''<br>        poolDictionaries: ''<br>          category: 'Morphic-Demo'!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>addCheckButtons (in category 'initialization') -----<br>+ addCheckButtons<br>+ <br>+   | buttonPane |<br>+       buttonPane := Morph new<br>+              beTransparent;<br>+               changeTableLayout;<br>+           hResizing: #spaceFill;<br>+               vResizing: #shrinkWrap;<br>+              listDirection: #leftToRight;<br>+                 wrapDirection: #topToBottom;<br>+                 cellGap: 10 px;<br>+              yourself.<br>+    <br>+     checkButtons := OrderedCollection new.<br>+       #(processKeyStroke 'Test key stroke'<br>+         processKeyDown 'Test key down'<br>+       processKeyUp 'Test key up')<br>+          groupsDo: [:selector :label |<br>+                        | button |<br>+                   button := ThreePhaseButtonMorph checkBox<br>+                             target: self;<br>+                                actionSelector: selector;<br>+                            label: label;<br>+                                yourself.<br>+                    checkButtons addLast: button.<br>+                        buttonPane addMorphBack: button].<br>+    <br>+     self addMorphBack: buttonPane.<br>+       ^ buttonPane!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>addEventPane (in category 'initialization') -----<br>+ addEventPane<br>+ <br>+     eventPane := Morph new<br>+               beTransparent;<br>+               changeTableLayout;<br>+           listDirection: #leftToRight;<br>+                 wrapDirection: #topToBottom;<br>+                 hResizing: #spaceFill;<br>+               vResizing: #shrinkWrap;<br>+              cellGap: 10 px;<br>+              height: 0;<br>+           yourself.<br>+    <br>+     self addMorphBack: eventPane.<br>+        ^ eventPane!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>addTitle (in category 'initialization') -----<br>+ addTitle<br>+ <br>+      | title |<br>+    title := TextMorph new<br>+               contents: 'Move your mouse cursor to here and start typing. Try modifiers, too.' translated;<br>+                 font: Preferences standardButtonFont;<br>+                color: Color gray;<br>+           hResizing: #spaceFill;<br>+               lock;<br>+                yourself.<br>+    <br>+     self addMorphBack: title.<br>+    ^ title!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>checkButton: (in category 'initialization') -----<br>  checkButton: checkIndex<br>  <br>+     self checkButtons do: [:button |<br>+             button state: #off].<br>-         1 to: 3 do: [:index |<br>-                (self submorphs at: index)<br>-                   state: #off].<br>         <br>+     (self checkButtons at: checkIndex) state: #on.!<br>-      (self submorphs at: checkIndex) state: #on.!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>checkButtons (in category 'accessing') -----<br>+ checkButtons<br>+ <br>+   ^ checkButtons!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>clear (in category 'initialization') -----<br>  clear<br>  <br>+       eventPane removeAllMorphs.<br>+   eventPane height: 0.!<br>-        (self submorphs allButFirst: 3) do: [:m | m delete].!<br><br>Item was removed:<br>- ----- Method: KeyboardExerciser>>drawOn: (in category 'drawing') -----<br>- drawOn: aCanvas<br>- <br>-    super drawOn: aCanvas.<br>-       <br>-     aCanvas<br>-              drawString: 'Move your mouse cursor to here and start typing. Try modifiers, too.' translated<br>-                at: self topLeft<br>-             font: Preferences standardButtonFont<br>-                 color: Color gray.!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>eventMorphs (in category 'accessing') -----<br>+ eventMorphs<br>+ <br>+      ^ eventPane submorphs!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>handleEvent:inspect: (in category 'actions') -----<br>  handleEvent: mouseEvent inspect: morph<br>  <br>+       mouseEvent shiftPressed<br>-      mouseEvent       shiftPressed<br>                 ifTrue: [(morph valueOfProperty: #event) explore]<br>             ifFalse: [(morph valueOfProperty: #event) inspect].!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>initialize (in category 'initialization') -----<br>  initialize<br>  <br>         super initialize.<br>     <br>      self<br>+                 color: ((self userInterfaceTheme get: #color for: #ScrollPane) ifNil: [Color white]);<br>+                borderStyle: ((self userInterfaceTheme get: #borderStyle for: #ScrollPane) ifNil: [BorderStyle simple]) copy;<br>+                borderColor: ((self userInterfaceTheme get: #borderColor for: #ScrollPane) ifNil: [Color gray: 0.6]);<br>+                borderWidth: (((self userInterfaceTheme get: #borderWidth for: #ScrollPane) ifNil: [1]) * RealEstateAgent scaleFactor) truncated;<br>+            extent: 300 px @ 50 px;<br>-              color: (self userInterfaceTheme get: #color for: #ScrollPane);<br>-               extent: 300@50;<br>               layoutPolicy: TableLayout new;<br>+               listDirection: #topToBottom;<br>-                 listDirection: #leftToRight;<br>-                 wrapDirection: #topToBottom;<br>                  hResizing: #rigid;<br>            vResizing: #shrinkWrap;<br>+              cellGap: 10 px;<br>+              layoutInset: 20 px;<br>-          cellGap: 10;<br>-                 layoutInset: 20;<br>              yourself.<br>     <br>+     self addTitle.<br>+       self addCheckButtons.<br>+        self addEventPane.<br>-   #(processKeyStroke 'Test key stroke'<br>-         processKeyDown 'Test key down'<br>-       processKeyUp 'Test key up')<br>-          groupsDo: [:selector :label |<br>-                        self addMorphBack: (ThreePhaseButtonMorph checkBox<br>-                           target: self;<br>-                                actionSelector: selector;<br>-                            label: label;<br>-                                yourself)].<br>   <br>      self processKeyStroke.!<br><br>Item was added:<br>+ ----- Method: KeyboardExerciser>>instructionMorph (in category 'accessing') -----<br>+ instructionMorph<br>+ <br>+        ^ self hasSubmorphs ifTrue: [self firstSubmorph]!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>lastEvent (in category 'accessing') -----<br>  lastEvent<br>  <br>   | view event |<br>+       view := (self eventMorphs ifEmpty: [^ nil]) last.<br>-    view := self submorphs last.<br>          (view hasProperty: #event) ifFalse: [^ nil].    <br>      event := view valueOfProperty: #event.<br>        event isCollection ifTrue: [event := event last].<br>     ^ event!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>logEvent: (in category 'event handling') -----<br>  logEvent: evt<br>  <br>   | eventMorph |<br>        evt = self lastEvent<br>                  ifTrue: [^ self logEventRepetition: evt].<br>  <br>         eventMorph := evt asMorph.<br>    eventMorph<br>            setProperty: #event toValue: evt copy;<br>                balloonText: ('Click to inspect. Shift+click to explore.\\Virtual key: {8}\Virtual modifiers: {5}\\Physical key: {9}\Physical modifiers: {6}\\Key value: 0x{1} ({2}) \Key character: {3}\Key string: {4}\\{7}' translated withCRs format: {<br>                   evt keyValue printPaddedWith: $0 to: 2 base: 16.<br>                      evt keyValue.<br>                         evt isKeystroke ifTrue: [evt keyCharacter printString] ifFalse: ['-'].<br>                        evt isKeystroke ifTrue: [evt keyString printString] ifFalse: ['-'].<br>                   (evt virtualModifiers joinSeparatedBy: ' ') asUppercase.<br>                      (evt physicalModifiers joinSeparatedBy: ' ') asUppercase.<br>                     evt printString.<br>                      evt virtualKey printString.<br>                   evt physicalKey asString printString}).<br>                       <br>      eventMorph<br>            on: #mouseEnter send: #handleEvent:emphasize: to: self;<br>               on: #mouseLeave send: #handleEvent:deemphasize: to: self;<br>             on: #mouseDown send: #handleEvent:inspect: to: self.<br>  <br>+     eventPane addMorphBack: eventMorph.!<br>-         self addMorphBack: eventMorph.!<br><br>Item was changed:<br>  ----- Method: KeyboardExerciser>>logEventRepetition: (in category 'event handling') -----<br>  logEventRepetition: evt<br>  <br>        | label lastEvents box |<br>+     (self eventMorphs last hasProperty: #repetition)<br>+             ifTrue: [box := self eventMorphs last. label := box submorphs first]<br>-         (self submorphs last hasProperty: #repetition)<br>-               ifTrue: [box := self submorphs last. label := box submorphs first]<br>            ifFalse: [<br>                    box := Morph new<br>                              setProperty: #repetition toValue: true;<br>                               color: Color transparent;<br>                             layoutPolicy: TableLayout new;<br>                                hResizing: #shrinkWrap;<br>                               vResizing:#shrinkWrap;<br>                                yourself.<br>                     label := '' asText asMorph lock.<br>                      box addMorph: label.<br>                          box setProperty: #event toValue: (OrderedCollection with: self lastEvent).<br>+                   eventPane addMorphBack: box].<br>-                        self addMorphBack: box].<br>  <br>          lastEvents := box valueOfProperty: #event.<br>    lastEvents add: evt copy.<br>     box setProperty: #event toValue: lastEvents.<br>  <br>      label newContents: (('x ', (lastEvents size)) asText<br>                  addAttribute: (TextFontReference toFont: Preferences standardButtonFont);<br>             yourself).<br>    box balloonText: ('{1}{2}'  format: {<br>                 lastEvents size > 10 ifTrue: ['... {1} older events and:\' translated withCRs format: {lastEvents size - 10}] ifFalse: [''].<br>               (lastEvents last: (10 min: lastEvents size)) joinSeparatedBy: String cr.<br>              }).<br>                   <br>      box<br>           on: #mouseEnter send: #handleEvent:emphasize: to: self;<br>               on: #mouseLeave send: #handleEvent:deemphasize: to: self;<br>             on: #mouseDown send: #handleEvent:inspect: to: self.!<br><br><br></div></blockquote>
                                        </div></body>