# HG changeset patch # User Claus Gittinger # Date 1582306316 -3600 # Node ID 11efde58092f6385027c69f02761f3fcf7c56c0a # Parent c1824d0bfeb5d8d34384a212d10fa6e5a6ba8030 #FEATURE by exept class: ShowMeHowItWorks class definition added: #fastMoveAbsolute: #fastMovePointerToComponent: #fastMovePointerToComponent:at: #fastMoveTo:at: #goto: #movePointerToComponent:at: #movePointerToComponent:at:speed: #useApplication: comment/format in: #click:inComponent: #clickIn: #fastMoveTo: #findApplication:ifMultiple: #movePointerToComponent: #movePointerToComponent:offset: #movePointerToComponent:rightBottomOffset: #movePointerToComponent:rightOffset: #movePointerToComponent:speed: #movePointerToScreenPosition: changed: #click:inComponent:clickTime: #doShowFile: #doStream:from: #findApplication: #movePointerToScreenPosition:speed: #where:inComponent: category of: #closeApplication #findApplication: #open: #popApplication #pushApplication: class: ShowMeHowItWorks class added: #example3 diff -r c1824d0bfeb5 -r 11efde58092f ShowMeHowItWorks.st --- a/ShowMeHowItWorks.st Thu Feb 20 15:49:39 2020 +0100 +++ b/ShowMeHowItWorks.st Fri Feb 21 18:31:56 2020 +0100 @@ -104,6 +104,11 @@ ) ! +example3 + ShowMeHowItWorks new + doShowFile:'../../../exept/expecco/resources/shows/Browser_overview_en' asFilename +! + scriptFormat " @@ -289,12 +294,6 @@ !ShowMeHowItWorks methodsFor:'commands'! -closeApplication - - - application closeRequest. -! - freezePin:pinName ofStep:stepName with:freezeString @@ -318,6 +317,32 @@ self key:#Return. ! +goto:nameOfLabel + + + "/ leaves opStream positioned after label: nameOfLabel + |savedPosition found| + + savedPosition := opStream position. + opStream position:0. + + "/ skip for that label + found := false. + [ found ] whileFalse:[ + |cmd| + + cmd := opStream nextOrNil. + cmd isNil ifTrue:[ + opStream position:savedPosition. + self proceedableError:'label not found: ',nameOfLabel. + ^ self. + ]. + (cmd = 'label:') ifTrue:[ + found := (opStream next = nameOfLabel) + ]. + ]. +! + intro @@ -354,22 +379,6 @@ "Created: / 23-07-2019 / 10:27:02 / Claus Gittinger" ! -open:applicationClassName - - - |appClass| - - (appClass := Smalltalk classNamed:applicationClassName) isNil ifTrue:[ - self error:'no such application class' - ]. - verifying ifFalse:[ - application := appClass new openAndWaitUntilVisible. - closeApplicationWhenFinished := true. - ]. - - "Created: / 19-07-2019 / 15:09:45 / Claus Gittinger" -! - pause @@ -380,14 +389,6 @@ "Modified: / 19-07-2019 / 16:13:33 / Claus Gittinger" ! -popApplication - - - "go back to the previous app" - - application := applicationStack removeLast. -! - pronounce:word as:pronunciation @@ -397,27 +398,6 @@ pronunciations at:word put:pronunciation ! -pushApplication:newApplicationOrName - - - "goto another app, remembering where we were before" - - |newApplication| - - (newApplication := newApplicationOrName) isString ifTrue:[ - newApplication := self findApplication:newApplicationOrName ifMultiple:nil. - newApplication isNil ifTrue:[ - self error:('Could not find an application named "%1" (to switch to)' bindWith:newApplicationOrName). - ]. - "/ self assert: newApplication notNil. - ]. - - applicationStack isNil ifTrue:[applicationStack := OrderedCollection new]. - - applicationStack add:application. - self application:newApplication. -! - raise:what @@ -656,6 +636,73 @@ ] loop ! ! +!ShowMeHowItWorks methodsFor:'commands - application'! + +closeApplication + + + application closeRequest. +! + +open:applicationClassName + + + |appClass| + + (appClass := Smalltalk classNamed:applicationClassName) isNil ifTrue:[ + self error:'no such application class' + ]. + verifying ifFalse:[ + application := appClass new openAndWaitUntilVisible. + closeApplicationWhenFinished := true. + ]. + + "Created: / 19-07-2019 / 15:09:45 / Claus Gittinger" +! + +popApplication + + + "go back to the previous app" + + application := applicationStack removeLast. +! + +pushApplication:newApplicationOrName + + + "goto another app, remembering where we were before" + + |newApplication| + + (newApplication := newApplicationOrName) isString ifTrue:[ + newApplication := self findApplication:newApplicationOrName ifMultiple:nil. + newApplication isNil ifTrue:[ + self error:('Could not find an application named "%1" (to switch to)' bindWith:newApplicationOrName). + ]. + "/ self assert: newApplication notNil. + ]. + + applicationStack isNil ifTrue:[applicationStack := OrderedCollection new]. + + applicationStack add:application. + self application:newApplication. +! + +useApplication:classNameOrWindowTitle + + + "find an application by name and return it (useful as arg to application)" + + application := + self + findApplication:classNameOrWindowTitle + ifMultiple:[ + self error:('multiple applications named "%1"' bindWith:classNameOrWindowTitle). + nil + ] +! ! + !ShowMeHowItWorks methodsFor:'commands - checking'! isEmpty:componentName @@ -738,6 +785,10 @@ + (self componentNamed:componentName) == lastComponent ifFalse:[ + self fastMoveTo:componentName. + self wait:0.25. + ]. ^ self click:1 inComponent:(self componentNamed:componentName) "Created: / 19-07-2019 / 16:09:58 / Claus Gittinger" @@ -874,6 +925,21 @@ "Modified (format): / 19-07-2019 / 14:55:34 / Claus Gittinger" ! +fastMoveAbsolute:pos + "move the mouse to a new position within the current component" + + + + |screen newPos currentPos| + + verifying ifTrue:[^ self]. + + screen := Screen current. + currentPos := screen pointerPosition. + newPos := currentPos + pos. + self fastMovePointerToScreenPosition:newPos +! + fastMoveRelativeX:dX y:dY "move the mouse to a new relative position" @@ -890,7 +956,7 @@ ! fastMoveTo:componentName - "move the mouse to componentName without circling. + "move the mouse to the center of componentName without circling. Leaves component in lastComponent" @@ -910,6 +976,20 @@ "Modified (comment): / 23-07-2019 / 09:33:31 / Claus Gittinger" ! +fastMoveTo:componentName at:positionOrSymbol + "move the mouse to a new position within the current component" + + + + |newPos component| + + component := self componentNamed:componentName. + (newPos := positionOrSymbol) isSymbol ifTrue:[ + newPos := self where:positionOrSymbol inComponent:component. + ]. + self fastMovePointerToComponent:component at:newPos +! + key:aKeySymbol "press/release a key in last component" @@ -1490,7 +1570,7 @@ ! findApplication:classNameOrWindowTitle ifMultiple:exceptionalValue - "find an application by name" + "find an application by name and return it (useful as arg to application)" |candidates| @@ -1927,9 +2007,11 @@ |t| t := self shortClickTime. + + "/ longer click time for Buttons and Menus, to allow redraw to be seen ((component isKindOf:Button) or:[(component askFor:#isMenuItem)] - )ifTrue:[ + ) ifTrue:[ t := self longClickTime ]. self click:buttonNr inComponent:component clickTime:t @@ -1944,12 +2026,15 @@ self withViewAndPositionFor:viewOrMenuItem do:[:viewToClick :clickPos | |clickDone| + Transcript showCR:'click pos is %1' with:clickPos. + clickDone := false. Display activePointerGrab == Display rootView ifTrue:[ |pos| pos := Display translatePoint:clickPos fromView:viewToClick toView:nil. Error handle:[:ex | + Transcript showCR:'failed to click (unupported in OS?)' ] do:[ OperatingSystem isOSXlike ifTrue:[ OperatingSystem @@ -1964,12 +2049,16 @@ yourself. ^ self. ]. + ]. + Display ungrabPointer. + false ifFalse:[ Display rootView simulateButtonPress:buttonNr at:pos sendDisplayEvent:true. Delay waitForSeconds:clickTime. Display rootView simulateButtonRelease:buttonNr at:pos sendDisplayEvent:true. clickDone := true. ]. ]. + clickDone ifFalse:[ viewToClick simulateButtonPress:buttonNr at:clickPos sendDisplayEvent:false. Delay waitForSeconds:clickTime. @@ -2073,6 +2162,27 @@ "Created: / 23-07-2019 / 09:37:46 / Claus Gittinger" ! +fastMovePointerToComponent:aWidgetOrMenuItem + "move the mouse to a widget's center" + + |bounds| + + bounds := self screenBoundsOfComponent:aWidgetOrMenuItem. + self fastMovePointerToScreenPosition:(bounds center rounded). + + "Created: / 19-07-2019 / 13:11:33 / Claus Gittinger" + "Modified: / 23-07-2019 / 09:37:01 / Claus Gittinger" +! + +fastMovePointerToComponent:aWidgetOrMenuItem at:offset + "move the mouse to a widget's center" + + |bounds| + + bounds := self screenBoundsOfComponent:aWidgetOrMenuItem. + self fastMovePointerToScreenPosition:(bounds origin + offset). +! + fastMovePointerToScreenPosition:position self movePointerToScreenPosition:position speed:(self pointerMoveSpeedFast). @@ -2080,7 +2190,7 @@ ! movePointerToComponent:aWidgetOrMenuItem - "move the mouse to aWidget's center" + "move the mouse to a widget's center" |bounds| @@ -2091,8 +2201,33 @@ "Modified: / 23-07-2019 / 09:37:01 / Claus Gittinger" ! +movePointerToComponent:aWidgetOrMenuItem at:offset + "move the mouse to a widget's center" + + |bounds| + + bounds := self screenBoundsOfComponent:aWidgetOrMenuItem. + self movePointerToScreenPosition:(bounds origin + offset). +! + +movePointerToComponent:aWidgetOrMenuItemOrTab at:offset speed:pixelsPerSecond + "move the mouse to a position within a widget" + + |bounds position| + + bounds := self screenBoundsOfComponent:aWidgetOrMenuItemOrTab. + bounds isNil ifTrue:[ + self error:('no bounds found for: %1 (%2)' bindWith:lastComponentName with:aWidgetOrMenuItemOrTab printString). + ]. + position := bounds origin + offset. + self movePointerToScreenPosition:position speed:pixelsPerSecond. + + "Created: / 20-07-2019 / 08:12:49 / Claus Gittinger" + "Modified: / 23-07-2019 / 09:37:27 / Claus Gittinger" +! + movePointerToComponent:aWidgetOrMenuItem offset:offset - "move the mouse to position inside aWidget's" + "move the mouse to position inside a widget" |bounds| @@ -2104,7 +2239,7 @@ ! movePointerToComponent:aWidgetOrMenuItem rightBottomOffset:offset - "move the mouse to position inside aWidget's. + "move the mouse to position inside a widget. Offset is from the rightBottom" |bounds| @@ -2117,7 +2252,7 @@ ! movePointerToComponent:aWidgetOrMenuItem rightOffset:offset - "move the mouse to position inside aWidget's. + "move the mouse to position inside a widget. Offset is from the rightTop (i.e. x is subtracted, y is added)" |bounds pos| @@ -2131,7 +2266,7 @@ ! movePointerToComponent:aWidgetOrMenuItemOrTab speed:pixelsPerSecond - "move the mouse to aWidget's center" + "move the mouse to a widget's center" |bounds position| @@ -2147,7 +2282,7 @@ ! movePointerToScreenPosition:newPosition - "move the mouse to newPosition" + "move the mouse to a new screenPosition" self movePointerToScreenPosition:newPosition speed:(self pointerMoveSpeed) @@ -2165,7 +2300,7 @@ start := screen pointerPosition. distance := start dist:newPosition. - distance = 0 ifTrue:[ + distance < 10 ifTrue:[ "/ already there screen setPointerPosition:newPosition. "/ do it anyway, in case of rounding errors ^ self @@ -2196,32 +2331,35 @@ ! where:where inComponent:aComponent + |bounds| + + bounds := aComponent bounds. where == #center ifTrue:[ - ^ aComponent center + ^ bounds center rounded ]. where == #leftCenter ifTrue:[ - ^ aComponent leftCenter + (5@0). + ^ bounds leftCenter rounded + (5@0). ]. where == #rightCenter ifTrue:[ - ^ aComponent rightCenter - (5@0). + ^ bounds rightCenter rounded - (5@0). ]. where == #topLeft ifTrue:[ - ^ aComponent topLeft + (5@5). + ^ bounds topLeft + (5@5). ]. where == #topCenter ifTrue:[ - ^ aComponent topCenter + (0@5). + ^ bounds topCenter rounded + (0@5). ]. where == #topRight ifTrue:[ - ^ aComponent topRight - (5@5). + ^ bounds topRight - (5@5). ]. where == #bottomCenter ifTrue:[ - ^ aComponent bottomCenter - (0 @ 5) + ^ bounds bottomCenter rounded - (0 @ 5) ]. where == #bottomLeft ifTrue:[ - ^ aComponent bottomLeft + (5 @ -5) + ^ bounds bottomLeft + (5 @ -5) ]. where == #bottomRight ifTrue:[ - ^ aComponent bottomLeft - (5 @ 5) + ^ bounds bottomLeft - (5 @ 5) ]. self error:'where is this' ! ! @@ -2323,18 +2461,27 @@ "Modified: / 25-07-2019 / 11:48:53 / Claus Gittinger" ! -doShowFile:aFilename - "the file from which the show was loaded" - - |spec| - - theShowFile := aFilename. - aFilename readingFileWithEncoding:#utf8 do:[:s | +doShowFile:aFilenameOrDirectory + "the file from which the show was loaded. + aFilenameOrDirectory must be either a show file, + or a folder containing start.show" + + |spec startFile| + + aFilenameOrDirectory isDirectory ifTrue:[ + "/ look for a start.show in there + (startFile := aFilenameOrDirectory / 'start.show') exists ifTrue:[ + self doShowFile:startFile. + ^ self. + ]. + self error:'no "startFile" in show''s folder'. + ]. + + theShowFile := aFilenameOrDirectory. + aFilenameOrDirectory readingFileWithEncoding:#utf8 do:[:s | spec := Array readFrom:s. ]. self do:spec. - - ! prepare @@ -2525,22 +2672,7 @@ opStream := specStream. startLabelOrNil notNil ifTrue:[ - |found| - - "/ skip for that label - found := false. - [ found ] whileFalse:[ - |cmd| - - cmd := opStream nextOrNil. - cmd isNil ifTrue:[ - self proceedableError:'label not found: ',startLabelOrNil. - ^ self. - ]. - (cmd = 'label:') ifTrue:[ - found := (opStream next = startLabelOrNil) - ]. - ]. + self goto:startLabelOrNil ]. [opStream atEnd] whileFalse:[