Hi Marcel,<br>
<br>
> If you care for it, go ahead and merge it.<br>
<br>
I really think that the invalidated instruction text provides a poor experience ...<br>
<br>
> You should also mention that you also decided on some visual updates in the form of border etc.<br>
<br>
I'm sorry, I forgot that. My goal was to align the look with regular pluggable text morphs & Co.<br>
<br>
> Yet, notice the extra complexity in the form of two new instVars etc. That was one of the reasons I did not do it. :-)<br>
<br>
Hm ... that touches on our common conflict between "minimal implementation" and "convenient UI" again, I think. Would there be frameworks in a perfect world where these two aspects would not contradict each other at all? In some previous discussions, I opted for prioritizing "convenient UI" because the main usage of any tool or widget still is to be *use* it, not to study its implementation. If we want to have simple exemplary implementations for teaching and documentation purposes, maybe we should maintain them separately from "production code"?<br>
Apart from that, the most interesting documentational aspect of the KeyboardExerciser seems to me to be its event handling implementation, which I did not touch.<br>
<br>
Best,<br>
Christoph<br>
<br>
<font color="#808080">---<br>
</font><font color="#808080"><i>Sent from </i></font><font color="#808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk"><u><font color="#808080">Squeak Inbox Talk</font></u></a></i></font><br>
<br>
On 2022-11-21T11:04:24+01:00, marcel.taeumel@hpi.de wrote:<br>
<br>
> 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. :-)<br>
> <br>
> 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 ;-)<br>
> <br>
> Best,<br>
> Marcel<br>
> Am 19.11.2022 20:36:17 schrieb commits at source.squeak.org <commits at source.squeak.org>:<br>
> 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 at 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>
> -------------- next part --------------<br>
> An HTML attachment was scrubbed...<br>
> URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20221121/782a6911/attachment.html><br>
> <br>