#UI_ENHANCEMENT by cg
class: ShowMeHowItWorks
class definition
added:
#click
#click:inComponent:clickTime:
#clickIn:
#componentNamed:
#doCommand:
#fastMoveTo:
#intro
#isEmpty:
#longClickTime
#movePointerToComponent:offset:
#shortClickTime
#show:
#type:
#unless:do:
removed: #enter:
comment/format in: #click:
changed:
#click:inComponent: (send #clickTime instead of #shortClickTime)
#clickTime
#doStream:
#moveTo:
#nextCommand
#pause
#selectIndex:
#showing:do:
category of:
#click:
#click:inComponent:
#moveTo:
#press:
#release:
#select:
#selectIndex:
--- a/ShowMeHowItWorks.st Fri Jul 19 16:28:39 2019 +0200
+++ b/ShowMeHowItWorks.st Fri Jul 19 16:31:29 2019 +0200
@@ -1,9 +1,11 @@
+"{ Encoding: utf8 }"
+
"{ Package: 'stx:libtool2' }"
"{ NameSpace: Smalltalk }"
Object subclass:#ShowMeHowItWorks
- instanceVariableNames:'opStream lastComponentName lastComponent'
+ instanceVariableNames:'opStream lastComponentName lastComponent lastResult'
classVariableNames:''
poolDictionaries:''
category:'Interface-Help'
@@ -93,22 +95,41 @@
!ShowMeHowItWorks methodsFor:'commands'!
+intro
+ <action>
+
+ self tell:'you can stopp the shou - by pressing - the shiftkee'.
+
+ "Created: / 19-07-2019 / 15:49:19 / Claus Gittinger"
+!
+
pause
<action>
- Dialog information:'Show Paused.\Click on "OK" to proceed'
+ Dialog information:(self class classResources stringWithCRs:'Show Paused.\Click on "OK" to proceed')
"Created: / 19-07-2019 / 15:03:17 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 16:13:33 / Claus Gittinger"
!
-showing:message do:operations
+show:message
+ "execute operations while showing (and speaking) some message."
+
+ <action>
+
+ self showing:message do:nil
+
+ "Created: / 19-07-2019 / 15:59:18 / Claus Gittinger"
+!
+
+showing:message do:operationsOrNothing
"execute operations while showing (and speaking) some message."
<action>
|messageView talkDone|
- self assert:operations isSequenceable.
+ self assert:(operationsOrNothing isNil or:[operationsOrNothing isSequenceable]).
messageView := ActiveHelpView for:message.
"/ messageView shapeStyle:#cartoon.
@@ -127,7 +148,9 @@
Delay waitForSeconds:(message size / 20).
].
- self doStream:(operations readStream).
+ operationsOrNothing notEmptyOrNil ifTrue:[
+ self doStream:(operationsOrNothing readStream).
+ ].
] ensure:[
messageView destroy
].
@@ -136,7 +159,7 @@
].
"Created: / 19-07-2019 / 11:19:27 / Claus Gittinger"
- "Modified (format): / 19-07-2019 / 15:02:12 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 15:59:52 / Claus Gittinger"
!
wait:seconds
@@ -147,27 +170,83 @@
"Created: / 19-07-2019 / 15:09:45 / Claus Gittinger"
! !
-!ShowMeHowItWorks methodsFor:'commands - mouse'!
+!ShowMeHowItWorks methodsFor:'commands - checking'!
+
+isEmpty:componentName
+ <action>
+
+ |component|
+
+ component := self componentNamed:componentName.
+ component isScrollWrapper ifTrue:[ component := component scrolledView ].
+ component isTextView ifTrue:[
+ ^ component contents isEmptyOrNil
+ ] ifFalse:[
+ self halt.
+ ].
+ self error:'isEmpty: unhandled component type: ',component displayString.
+
+ "Created: / 19-07-2019 / 15:33:47 / Claus Gittinger"
+!
+
+unless:query do:actions
+ <action>
+
+ |result|
+
+ result := self doCommand:query.
+ result ifFalse:[
+ self doCommand:actions
+ ].
+
+ "Created: / 19-07-2019 / 15:33:32 / Claus Gittinger"
+! !
+
+!ShowMeHowItWorks methodsFor:'commands - mouse & keyboard'!
+
+click
+ "press-release"
+
+ <action>
+
+ ^ self click:1 inComponent:lastComponent
+
+ "Created: / 19-07-2019 / 16:11:03 / Claus Gittinger"
+!
click:buttonNr
"press-release"
<action>
- self click:buttonNr inComponent:lastComponent
+ self assert:(buttonNr isInteger).
+ ^ self click:buttonNr inComponent:lastComponent
"Created: / 19-07-2019 / 13:21:20 / Claus Gittinger"
- "Modified: / 19-07-2019 / 14:55:18 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 16:10:19 / Claus Gittinger"
!
-enter:aString
- "enter text into the last component"
+clickIn:componentName
+ "press-release"
+
+ <action>
+
+ ^ self click:1 inComponent:(self componentNamed:componentName)
+
+ "Created: / 19-07-2019 / 16:09:58 / Claus Gittinger"
+!
+
+fastMoveTo:componentName
+ "move the mouse to componentName without circling"
<action>
- lastComponent simulateTextInput:aString at:(lastComponent extent // 2) sendDisplayEvent:false
+ |component|
- "Created: / 19-07-2019 / 14:29:27 / Claus Gittinger"
+ component := self componentNamed:componentName.
+ self movePointerToComponent:component.
+
+ "Created: / 19-07-2019 / 15:39:23 / Claus Gittinger"
!
moveTo:componentName
@@ -178,19 +257,12 @@
|component|
- lastComponentName := componentName.
-
- component := self findComponent:componentName.
- component isNil ifTrue:[
- self error:'no component found for: ',componentName.
- ].
- lastComponent := component.
-
+ component := self componentNamed:componentName.
self movePointerToComponent:component.
self circlePointerAroundComponent:component.
"Created: / 19-07-2019 / 11:20:42 / Claus Gittinger"
- "Modified (format): / 19-07-2019 / 14:55:27 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 15:38:11 / Claus Gittinger"
!
select:itemsLabel
@@ -234,19 +306,47 @@
<action>
- (lastComponent isKindOf:ComboView) ifTrue:[
+ |widget y offset|
+
+ (widget := lastComponent) isScrollWrapper ifTrue:[
+ widget := widget scrolledView
+ ].
+
+ (widget isKindOf:ComboView) ifTrue:[
"/ click on the menubutton
- self movePointerToComponent:lastComponent menuButton.
- self click:1 inComponent:lastComponent menuButton.
+ self movePointerToComponent:widget menuButton.
+ self click:1 inComponent:widget menuButton.
Delay waitForSeconds:0.5.
- lastComponent select:itemsIndex.
+ widget select:itemsIndex.
Delay waitForSeconds:0.5.
self halt.
^ self
].
+ (widget isKindOf:SelectionInListView) ifTrue:[
+ "/ click on the item
+ y := widget yOfLine:itemsIndex.
+ offset := (widget width // 2) @ y.
+ self movePointerToComponent:widget offset:offset.
+ widget simulateButtonPress:1 at:offset sendDisplayEvent:false.
+ Delay waitForSeconds:(self clickTime).
+ widget simulateButtonRelease:1 at:offset sendDisplayEvent:false.
+ Delay waitForSeconds:0.5.
+ ^ self
+ ].
self error:'cannot select this component'
"Created: / 19-07-2019 / 14:20:11 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 16:22:47 / Claus Gittinger"
+!
+
+type:aString
+ "enter text into the last component"
+
+ <action>
+
+ lastComponent simulateTextInput:aString at:(lastComponent extent // 2) sendDisplayEvent:false
+
+ "Created: / 19-07-2019 / 15:50:40 / Claus Gittinger"
! !
!ShowMeHowItWorks methodsFor:'defaults'!
@@ -278,9 +378,18 @@
clickTime
"when clicking"
- ^ 100 milliseconds
+ ^ self shortClickTime
"Created: / 19-07-2019 / 13:17:20 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 15:21:51 / Claus Gittinger"
+!
+
+longClickTime
+ "when clicking buttons"
+
+ ^ 500 milliseconds
+
+ "Created: / 19-07-2019 / 15:21:42 / Claus Gittinger"
!
pointerAnimationDelay
@@ -295,6 +404,14 @@
"Created: / 19-07-2019 / 13:05:40 / Claus Gittinger"
!
+shortClickTime
+ "when clicking"
+
+ ^ 100 milliseconds
+
+ "Created: / 19-07-2019 / 15:21:29 / Claus Gittinger"
+!
+
talking
^ true
@@ -303,6 +420,23 @@
!ShowMeHowItWorks methodsFor:'helper'!
+componentNamed:componentName
+ "retrieve a component by name or report an error if not found"
+
+ |component|
+
+ lastComponentName := componentName.
+
+ component := self findComponent:componentName.
+ component isNil ifTrue:[
+ self error:'no component found for: ',componentName.
+ ].
+ lastComponent := component.
+ ^ component
+
+ "Created: / 19-07-2019 / 15:37:35 / Claus Gittinger"
+!
+
findComponent:componentName
"find a component by name - in the active and possibly in any app"
@@ -458,18 +592,6 @@
"Created: / 19-07-2019 / 13:12:40 / Claus Gittinger"
!
-click:buttonNr inComponent:component
- "press-release in a component"
-
- component simulateButtonPress:buttonNr at:(component extent // 2) sendDisplayEvent:false.
- Delay waitForSeconds:(self clickTime).
- component simulateButtonRelease:buttonNr at:(component extent // 2) sendDisplayEvent:false.
-
-"/ self click:buttonNr atPosition:(component extent // 2)
-
- "Created: / 19-07-2019 / 13:18:27 / Claus Gittinger"
-!
-
movePointerToComponent:aWidget
"move the mouse to aWidget's center"
@@ -478,6 +600,14 @@
"Created: / 19-07-2019 / 13:11:33 / Claus Gittinger"
!
+movePointerToComponent:aWidget offset:offset
+ "move the mouse to position inside aWidget's"
+
+ self movePointerToPosition:(aWidget screenBounds origin + offset) rounded.
+
+ "Created: / 19-07-2019 / 16:18:58 / Claus Gittinger"
+!
+
movePointerToPosition:newPosition
"move the mouse to newPosition"
@@ -508,6 +638,35 @@
].
"Created: / 19-07-2019 / 12:57:30 / Claus Gittinger"
+! !
+
+!ShowMeHowItWorks methodsFor:'menu actions - mouse buttons'!
+
+click:buttonNr inComponent:component
+ "press-release in a component"
+
+ |t|
+
+ t := self shortClickTime.
+ (component isKindOf:Button) ifTrue:[
+ t := self longClickTime
+ ].
+ self click:buttonNr inComponent:component clickTime:t
+
+ "Created: / 19-07-2019 / 13:18:27 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 15:22:47 / Claus Gittinger"
+!
+
+click:buttonNr inComponent:component clickTime:clickTime
+ "press-release in a component"
+
+ component simulateButtonPress:buttonNr at:(component extent // 2) sendDisplayEvent:false.
+ Delay waitForSeconds:clickTime.
+ component simulateButtonRelease:buttonNr at:(component extent // 2) sendDisplayEvent:false.
+
+"/ self click:buttonNr atPosition:(component extent // 2)
+
+ "Created: / 19-07-2019 / 15:21:05 / Claus Gittinger"
!
press:buttonNr
@@ -568,6 +727,65 @@
!ShowMeHowItWorks methodsFor:'running'!
+doCommand:op
+ |numArgs sel args method|
+
+ op isArray ifTrue:[
+ op first isArray ifTrue:[
+ self doStream:op readStream.
+ ^ self.
+ ].
+
+ "/ construct a selector from keyword parts at odd indices
+ sel := ((op with:(1 to:op size) select:[:el :idx | idx odd]) asStringWith:'') asSymbol.
+ "/ construct arg vector from parts at even indices
+ args := op with:(1 to:op size) select:[:el :idx | idx even].
+ ] ifFalse:[
+ sel := op.
+ numArgs := sel argumentCount.
+ args := opStream next:numArgs.
+ ].
+
+ (self respondsTo:sel) ifFalse:[
+ self error:'bad operation: ',sel
+ ].
+ method := self class lookupMethodFor:sel.
+ (method hasAnnotation:#action) ifFalse:[self halt].
+
+ lastResult := self perform:sel withArguments:args.
+ ^ lastResult
+
+"<<END
+ ShowMeHowItWorks do:#(
+ showing: 'Choose the number of arguments'
+ do: (
+ moveTo: NumberOfArguments
+ select: '1'
+ )
+ showing: 'Click into the "receiver" field'
+ do: (
+ moveTo: ReceiverEditor
+ click: ReceiverEditor
+ )
+ showing: 'Enter a value (or expression) into "receiver" field'
+ do: (
+ enter: '100'
+ )
+ showing: 'Click into the "first argument" field'
+ do: (
+ moveTo: Arg1Editor
+ click: ReceiverEditor
+ )
+ showing: 'Enter a value (or expression) into "receiver" field'
+ do: (
+ enter: '100'
+ )
+ )
+END"
+
+ "Created: / 19-07-2019 / 15:34:55 / Claus Gittinger"
+!
+
doStream:specStream
|previousStream|
@@ -577,7 +795,7 @@
[opStream atEnd] whileFalse:[
self nextCommand.
Display shiftDown ifTrue:[
- self tell:'Shou stopped by shiftkee'.
+ self tell:'you stopped the shou, thank you, for watching'.
^ AbortOperationRequest raise
].
].
@@ -614,31 +832,11 @@
END"
"Created: / 19-07-2019 / 10:52:24 / Claus Gittinger"
- "Modified: / 19-07-2019 / 15:00:44 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 16:02:51 / Claus Gittinger"
!
nextCommand
- |op numArgs sel args method|
-
- op := opStream next.
- op isArray ifTrue:[
- "/ construct a selector from keyword parts at odd indices
- sel := ((op with:(1 to:op size) select:[:el :idx | idx odd]) asStringWith:'') asSymbol.
- "/ construct arg vector from parts at even indices
- args := op with:(1 to:op size) select:[:el :idx | idx even].
- ] ifFalse:[
- sel := op.
- numArgs := sel argumentCount.
- args := opStream next:numArgs.
- ].
-
- (self respondsTo:sel) ifFalse:[
- self error:'bad operation: ',sel
- ].
- method := self class lookupMethodFor:sel.
- (method hasAnnotation:#action) ifFalse:[self halt].
-
- self perform:sel withArguments:args.
+ self doCommand:(opStream next).
"<<END
ShowMeHowItWorks do:#(
@@ -669,7 +867,7 @@
END"
"Created: / 19-07-2019 / 10:54:04 / Claus Gittinger"
- "Modified: / 19-07-2019 / 14:53:15 / Claus Gittinger"
+ "Modified: / 19-07-2019 / 15:35:15 / Claus Gittinger"
! !
!ShowMeHowItWorks class methodsFor:'documentation'!