# HG changeset patch # User Claus Gittinger # Date 1563546689 -7200 # Node ID a472042fd298c1318102ded7c095f96d22bda6bb # Parent 280daf8b3626fa4daf5fb355c639690d5bee80f2 #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: diff -r 280daf8b3626 -r a472042fd298 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 + + + self tell:'you can stopp the shou - by pressing - the shiftkee'. + + "Created: / 19-07-2019 / 15:49:19 / Claus Gittinger" +! + pause - 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." + + + + 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." |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 + + + |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 + + + |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" + + + + ^ self click:1 inComponent:lastComponent + + "Created: / 19-07-2019 / 16:11:03 / Claus Gittinger" +! click:buttonNr "press-release" - 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" + + + + ^ 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" - 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 @@ - (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" + + + + 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 + +"<