#UI_ENHANCEMENT by cg draft
authorClaus Gittinger <cg@exept.de>
Fri, 19 Jul 2019 16:31:29 +0200
changeset 3711 a472042fd298
parent 3710 280daf8b3626
child 3712 688f4186d4f2
#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:
ShowMeHowItWorks.st
--- 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'!