ShowMeHowItWorks.st
changeset 3700 34af8cf33242
child 3711 a472042fd298
equal deleted inserted replaced
3699:1070017213b7 3700:34af8cf33242
       
     1 "{ Package: 'stx:libtool2' }"
       
     2 
       
     3 "{ NameSpace: Smalltalk }"
       
     4 
       
     5 Object subclass:#ShowMeHowItWorks
       
     6 	instanceVariableNames:'opStream lastComponentName lastComponent'
       
     7 	classVariableNames:''
       
     8 	poolDictionaries:''
       
     9 	category:'Interface-Help'
       
    10 !
       
    11 
       
    12 !ShowMeHowItWorks class methodsFor:'documentation'!
       
    13 
       
    14 documentation
       
    15 "
       
    16     documentation to be added.
       
    17 
       
    18     class:
       
    19         <a short class summary here, describing what instances represent>
       
    20 
       
    21     responsibilities:    
       
    22         <describing what my main role is>
       
    23 
       
    24     collaborators:    
       
    25         <describing with whom and how I talk to>
       
    26 
       
    27     API:
       
    28         <public api and main messages>
       
    29         
       
    30     example:
       
    31         <a one-line examples on how to use - can also be in a separate example method>
       
    32 
       
    33     implementation:
       
    34         <implementation points>
       
    35 
       
    36     [author:]
       
    37         Claus Gittinger
       
    38 
       
    39     [instance variables:]
       
    40 
       
    41     [class variables:]
       
    42 
       
    43     [see also:]
       
    44 
       
    45 "
       
    46 !
       
    47 
       
    48 example
       
    49     ShowMeHowItWorks do:#(
       
    50         ( showing: 'Choose the number of arguments' do:(
       
    51             moveTo: NumberOfArguments
       
    52             select: '1' 
       
    53         ))  
       
    54         (showing: 'Click into the "receiver" field' do:(
       
    55             moveTo: ReceiverEditor
       
    56             click: ReceiverEditor 
       
    57         ))
       
    58         (showing: 'Enter a value (or expression) into "receiver" field' do:(
       
    59             enter: '100'
       
    60         ))
       
    61         (showing: 'Click into the "first argument" field' do:(
       
    62             moveTo: Arg1Editor
       
    63             click: ReceiverEditor
       
    64         ))
       
    65         (showing: 'Enter a value (or expression) into "receiver" field' do:(
       
    66             enter: '100'
       
    67         ))
       
    68 
       
    69     )
       
    70 ! !
       
    71 
       
    72 !ShowMeHowItWorks class methodsFor:'running'!
       
    73 
       
    74 do:specArray
       
    75     self doStream:specArray readStream
       
    76 
       
    77     "Created: / 19-07-2019 / 10:52:59 / Claus Gittinger"
       
    78     "Modified: / 19-07-2019 / 14:30:43 / Claus Gittinger"
       
    79 !
       
    80 
       
    81 doStream:specStream
       
    82     "must run as a separate process;
       
    83      otherwise - if started by the app itself -
       
    84      no events will be processed while running"
       
    85      
       
    86     [
       
    87         self new doStream:specStream
       
    88     ] fork.
       
    89 
       
    90     "Created: / 19-07-2019 / 10:53:07 / Claus Gittinger"
       
    91     "Modified (comment): / 19-07-2019 / 14:30:29 / Claus Gittinger"
       
    92 ! !
       
    93 
       
    94 !ShowMeHowItWorks methodsFor:'commands'!
       
    95 
       
    96 pause
       
    97     <action>
       
    98     
       
    99     Dialog information:'Show Paused.\Click on "OK" to proceed'
       
   100 
       
   101     "Created: / 19-07-2019 / 15:03:17 / Claus Gittinger"
       
   102 !
       
   103 
       
   104 showing:message do:operations
       
   105     "execute operations while showing (and speaking) some message."
       
   106 
       
   107     <action>
       
   108     
       
   109     |messageView talkDone|
       
   110 
       
   111     self assert:operations isSequenceable.
       
   112 
       
   113     messageView := ActiveHelpView for:message.
       
   114     "/ messageView shapeStyle:#cartoon.
       
   115     [
       
   116         messageView realize.
       
   117 
       
   118         self talking ifTrue:[
       
   119             talkDone := Semaphore new.
       
   120             [
       
   121                 self tell:message.
       
   122                 talkDone signal
       
   123             ] fork.
       
   124             
       
   125             "/
       
   126             "/ allow speaker some headoff
       
   127             Delay waitForSeconds:(message size / 20).
       
   128         ].
       
   129 
       
   130         self doStream:(operations readStream).
       
   131     ] ensure:[
       
   132         messageView destroy
       
   133     ].
       
   134     self talking ifTrue:[
       
   135         talkDone wait.
       
   136     ].
       
   137 
       
   138     "Created: / 19-07-2019 / 11:19:27 / Claus Gittinger"
       
   139     "Modified (format): / 19-07-2019 / 15:02:12 / Claus Gittinger"
       
   140 !
       
   141 
       
   142 wait:seconds
       
   143     <action>
       
   144     
       
   145     Delay waitForSeconds:seconds
       
   146 
       
   147     "Created: / 19-07-2019 / 15:09:45 / Claus Gittinger"
       
   148 ! !
       
   149 
       
   150 !ShowMeHowItWorks methodsFor:'commands - mouse'!
       
   151 
       
   152 click:buttonNr
       
   153     "press-release"
       
   154     
       
   155     <action>
       
   156 
       
   157     self click:buttonNr inComponent:lastComponent
       
   158 
       
   159     "Created: / 19-07-2019 / 13:21:20 / Claus Gittinger"
       
   160     "Modified: / 19-07-2019 / 14:55:18 / Claus Gittinger"
       
   161 !
       
   162 
       
   163 enter:aString
       
   164     "enter text into the last component"
       
   165 
       
   166     <action>
       
   167 
       
   168     lastComponent simulateTextInput:aString at:(lastComponent extent // 2) sendDisplayEvent:false
       
   169 
       
   170     "Created: / 19-07-2019 / 14:29:27 / Claus Gittinger"
       
   171 !
       
   172 
       
   173 moveTo:componentName
       
   174     "move the mouse to componentName,
       
   175      then circle around it a few times"
       
   176 
       
   177     <action>
       
   178 
       
   179     |component|
       
   180 
       
   181     lastComponentName := componentName.
       
   182     
       
   183     component := self findComponent:componentName.
       
   184     component isNil ifTrue:[
       
   185         self error:'no component found for: ',componentName.
       
   186     ].
       
   187     lastComponent := component.
       
   188 
       
   189     self movePointerToComponent:component.
       
   190     self circlePointerAroundComponent:component.
       
   191 
       
   192     "Created: / 19-07-2019 / 11:20:42 / Claus Gittinger"
       
   193     "Modified (format): / 19-07-2019 / 14:55:27 / Claus Gittinger"
       
   194 !
       
   195 
       
   196 select:itemsLabel
       
   197     "select an item by label,
       
   198      allowed after moving to:
       
   199         aComboBox
       
   200         aSelectionInListView
       
   201     "    
       
   202 
       
   203     <action>
       
   204 
       
   205     |idx|
       
   206     
       
   207     (lastComponent isKindOf:ComboView) ifTrue:[
       
   208         "/ click on the menubutton
       
   209         self movePointerToComponent:lastComponent menuButton.
       
   210         self click:1 inComponent:lastComponent menuButton.
       
   211         Delay waitForSeconds:0.3.
       
   212         (idx := lastComponent list indexOf:itemsLabel ifAbsent:[nil]) isNil ifTrue:[
       
   213             self error:'no such item in comboList: ',itemsLabel
       
   214         ].
       
   215         lastComponent select:idx.
       
   216         Delay waitForSeconds:0.3.
       
   217         lastComponent shownMenu notNil ifTrue:[
       
   218             lastComponent shownMenu hide.
       
   219         ].    
       
   220         ^ self
       
   221     ].    
       
   222     self error:'cannot select this component'
       
   223 
       
   224     "Created: / 19-07-2019 / 12:34:25 / Claus Gittinger"
       
   225     "Modified (format): / 19-07-2019 / 14:55:34 / Claus Gittinger"
       
   226 !
       
   227 
       
   228 selectIndex:itemsIndex
       
   229     "select an item by index,
       
   230      allowed after moving to:
       
   231         aComboBox
       
   232         aSelectionInListView
       
   233     "    
       
   234 
       
   235     <action>
       
   236 
       
   237     (lastComponent isKindOf:ComboView) ifTrue:[
       
   238         "/ click on the menubutton
       
   239         self movePointerToComponent:lastComponent menuButton.
       
   240         self click:1 inComponent:lastComponent menuButton.
       
   241         Delay waitForSeconds:0.5.
       
   242         lastComponent select:itemsIndex.
       
   243         Delay waitForSeconds:0.5.
       
   244 self halt.
       
   245         ^ self
       
   246     ].    
       
   247     self error:'cannot select this component'
       
   248 
       
   249     "Created: / 19-07-2019 / 14:20:11 / Claus Gittinger"
       
   250 ! !
       
   251 
       
   252 !ShowMeHowItWorks methodsFor:'defaults'!
       
   253 
       
   254 circlingCount
       
   255     "circle around move-end position that many times"
       
   256 
       
   257     ^ 3
       
   258 
       
   259     "Created: / 19-07-2019 / 13:03:45 / Claus Gittinger"
       
   260 !
       
   261 
       
   262 circlingRadius 
       
   263     "radius when circling"
       
   264     
       
   265     ^ 30 "/ pixels
       
   266 
       
   267     "Created: / 19-07-2019 / 13:07:59 / Claus Gittinger"
       
   268 !
       
   269 
       
   270 circlingSpeed 
       
   271     "time per round when circling"
       
   272     
       
   273     ^ 0.3 seconds.       "/ time per round
       
   274 
       
   275     "Created: / 19-07-2019 / 13:02:34 / Claus Gittinger"
       
   276 !
       
   277 
       
   278 clickTime
       
   279     "when clicking"
       
   280 
       
   281     ^ 100 milliseconds
       
   282 
       
   283     "Created: / 19-07-2019 / 13:17:20 / Claus Gittinger"
       
   284 !
       
   285 
       
   286 pointerAnimationDelay
       
   287     ^ 50 milliseconds.   "/ 20 updates per second
       
   288 
       
   289     "Created: / 19-07-2019 / 13:04:45 / Claus Gittinger"
       
   290 !
       
   291 
       
   292 pointerMoveSpeed
       
   293     ^ 400.   "/ pixels per second
       
   294 
       
   295     "Created: / 19-07-2019 / 13:05:40 / Claus Gittinger"
       
   296 !
       
   297 
       
   298 talking
       
   299     ^ true
       
   300 
       
   301     "Created: / 19-07-2019 / 14:31:14 / Claus Gittinger"
       
   302 ! !
       
   303 
       
   304 !ShowMeHowItWorks methodsFor:'helper'!
       
   305 
       
   306 findComponent:componentName
       
   307     "find a component by name - in the active and possibly in any app"
       
   308     
       
   309     |app component candidates|
       
   310 
       
   311     app := WindowGroup activeMainApplication.
       
   312     app notNil ifTrue:[ 
       
   313         component := self findComponent:componentName in:app.
       
   314     ].
       
   315     
       
   316     component isNil ifTrue:[
       
   317         "/ search through all current applications
       
   318         candidates := OrderedCollection new.
       
   319         WindowGroup scheduledWindowGroups do:[:eachWG |
       
   320             |eachApp|
       
   321 
       
   322             (eachApp := eachWG application) notNil ifTrue:[
       
   323                 component := self findComponent:componentName in:eachApp.
       
   324                 component notNil ifTrue:[ 
       
   325                     candidates add:component
       
   326                 ].
       
   327             ].
       
   328         ].
       
   329         
       
   330         candidates size == 1 ifTrue:[
       
   331             component := candidates first
       
   332         ] ifFalse:[    
       
   333             candidates notEmpty ifTrue:[
       
   334                 self error:'multiple components found by name: ',componentName.
       
   335             ]    
       
   336         ].    
       
   337     ].    
       
   338     ^ component
       
   339 
       
   340     "Created: / 19-07-2019 / 12:02:30 / Claus Gittinger"
       
   341 !
       
   342 
       
   343 findComponent:componentName in:anApplication
       
   344     |component componentNameSymbol foundByName foundByTitle foundByLabel|
       
   345 
       
   346     (component := anApplication componentAt:componentName) notNil ifTrue:[^ component].
       
   347     (componentNameSymbol := componentName asSymbolIfInterned) notNil ifTrue:[
       
   348         (component := anApplication componentAt:componentNameSymbol) notNil ifTrue:[^ component].
       
   349     ].
       
   350     
       
   351     "/ mhmh - search through all widgets of anApplication; 
       
   352     "/ maybe it was not created via the builder/spec,
       
   353     "/ or it has changed its name.
       
   354     "/ look for: widget's name, widget's title, widget's label
       
   355     foundByName := OrderedCollection new. 
       
   356     foundByTitle := OrderedCollection new. 
       
   357     foundByLabel := OrderedCollection new.
       
   358     
       
   359     anApplication window allSubViewsDo:[:each |
       
   360         [
       
   361             each name = componentName ifTrue:[ foundByName add:each ].
       
   362         ] on:MessageNotUnderstood do:[:ex | ].
       
   363         [
       
   364             each title = componentName ifTrue:[ foundByTitle add:each ].
       
   365         ] on:MessageNotUnderstood do:[:ex | ].
       
   366         [
       
   367             each label = componentName ifTrue:[ foundByLabel add:each ].
       
   368         ] on:MessageNotUnderstood do:[:ex | ].
       
   369     ].
       
   370     foundByName notEmpty ifTrue:[
       
   371         self assert:(foundByName size == 1) message:'multiple components found by name'.
       
   372         ^ foundByName first.
       
   373     ].
       
   374     foundByTitle notEmpty ifTrue:[
       
   375         self assert:(foundByTitle size == 1) message:'multiple components found by title'.
       
   376         ^ foundByTitle first.
       
   377     ].
       
   378     foundByLabel notEmpty ifTrue:[
       
   379         self assert:(foundByLabel size == 1) message:'multiple components found by label'.
       
   380         ^ foundByLabel first.
       
   381     ].
       
   382     ^ component
       
   383 
       
   384     "Created: / 19-07-2019 / 11:36:21 / Claus Gittinger"
       
   385 !
       
   386 
       
   387 tell:message
       
   388     self talking ifTrue:[
       
   389         OperatingSystem speak:message.
       
   390     ].
       
   391 
       
   392     "Created: / 19-07-2019 / 14:57:50 / Claus Gittinger"
       
   393 ! !
       
   394 
       
   395 !ShowMeHowItWorks methodsFor:'helpers - broken'!
       
   396 
       
   397 click:buttonNr atPosition:position
       
   398     "press-release at position"
       
   399     
       
   400     |screen|
       
   401 
       
   402     screen := Screen current.
       
   403     
       
   404     screen setPointerPosition:position.    
       
   405     screen flush.
       
   406     self click:buttonNr
       
   407 
       
   408     "Created: / 19-07-2019 / 13:14:51 / Claus Gittinger"
       
   409 ! !
       
   410 
       
   411 !ShowMeHowItWorks methodsFor:'helpers - mouse movement'!
       
   412 
       
   413 circlePointerAroundComponent:component
       
   414     "circle around it a few times"
       
   415     
       
   416     self circlePointerAroundPosition:(component screenBounds center rounded)
       
   417 
       
   418     "Created: / 19-07-2019 / 13:12:35 / Claus Gittinger"
       
   419 !
       
   420 
       
   421 circlePointerAroundPosition:position
       
   422     "circle around it a few times"
       
   423     
       
   424     |screen stepDelayTime numCircles circlingSpeed radius|
       
   425 
       
   426     screen := Screen current.
       
   427     
       
   428     circlingSpeed := self circlingSpeed.    "/ time per round
       
   429     numCircles := self circlingCount.
       
   430     stepDelayTime := self pointerAnimationDelay.   "/ update interval
       
   431     
       
   432     radius := self circlingRadius.
       
   433 
       
   434     "/ move it around a few times
       
   435     1 to:numCircles do:[:round |
       
   436         |n angle|
       
   437 
       
   438         n := circlingSpeed / stepDelayTime. "/ nr of steps per circle
       
   439         angle := 360 / n.                   "/ angle-delta per step
       
   440         1 to:n do:[:step |
       
   441             |a x y|
       
   442             
       
   443             a := angle * step.
       
   444             "/ clockwise starting above the center
       
   445             x := position x + (radius * a degreesToRadians sin).
       
   446             y := position y + (radius * a degreesToRadians cos).
       
   447 "/ Transcript showCR:(x@y).
       
   448             screen setPointerPosition:(x@y) rounded.
       
   449             screen flush.
       
   450             Delay waitFor:stepDelayTime.
       
   451         ].    
       
   452         "/ and back
       
   453         screen setPointerPosition:position rounded.
       
   454         screen flush.
       
   455         Delay waitFor:stepDelayTime.
       
   456     ].
       
   457 
       
   458     "Created: / 19-07-2019 / 13:12:40 / Claus Gittinger"
       
   459 !
       
   460 
       
   461 click:buttonNr inComponent:component
       
   462     "press-release in a component"
       
   463 
       
   464     component simulateButtonPress:buttonNr at:(component extent // 2) sendDisplayEvent:false.
       
   465     Delay waitForSeconds:(self clickTime).
       
   466     component simulateButtonRelease:buttonNr at:(component extent // 2) sendDisplayEvent:false.
       
   467 
       
   468 "/    self click:buttonNr atPosition:(component extent // 2)
       
   469 
       
   470     "Created: / 19-07-2019 / 13:18:27 / Claus Gittinger"
       
   471 !
       
   472 
       
   473 movePointerToComponent:aWidget
       
   474     "move the mouse to aWidget's center"
       
   475     
       
   476     self movePointerToPosition:(aWidget screenBounds center rounded).
       
   477 
       
   478     "Created: / 19-07-2019 / 13:11:33 / Claus Gittinger"
       
   479 !
       
   480 
       
   481 movePointerToPosition:newPosition
       
   482     "move the mouse to newPosition"
       
   483     
       
   484     |screen distance start numSteps moveTime stepDelayTime delta|
       
   485 
       
   486     screen := Screen current.
       
   487     start := screen pointerPosition.   
       
   488 
       
   489     distance := start dist:newPosition.
       
   490     moveTime := (distance / self pointerMoveSpeed) seconds. "/ time to move
       
   491     stepDelayTime := self pointerAnimationDelay.            "/ update every 50ms
       
   492     
       
   493     numSteps := moveTime / stepDelayTime.
       
   494     numSteps = 0 ifTrue:[
       
   495         "/ already there
       
   496         ^ self
       
   497     ].
       
   498     
       
   499     delta := (newPosition - start) / numSteps.
       
   500     1 to:numSteps do:[:step |
       
   501         |p|
       
   502         
       
   503         p := (start + (delta * step)) rounded.
       
   504 "/ Transcript showCR:p.
       
   505         screen setPointerPosition:p.
       
   506         screen flush.
       
   507         Delay waitFor:stepDelayTime.
       
   508     ].
       
   509 
       
   510     "Created: / 19-07-2019 / 12:57:30 / Claus Gittinger"
       
   511 !
       
   512 
       
   513 press:buttonNr
       
   514     "press at the current position"
       
   515     
       
   516     |position screen x y|
       
   517 
       
   518     screen := Screen current.
       
   519     position := screen pointerPosition.
       
   520     x := position x.
       
   521     y := position y.
       
   522     
       
   523     self movePointerToPosition:position.
       
   524 
       
   525     false "OperatingSystem isOSXlike" ifTrue:[
       
   526         |osxPos|
       
   527 
       
   528         osxPos := OperatingSystem getMousePosition.
       
   529         x := osxPos x rounded.
       
   530         y := osxPos y rounded.
       
   531         OperatingSystem generateButtonEvent:buttonNr down:true x:x y:y.
       
   532         ^ self.
       
   533     ].
       
   534 
       
   535     screen sendKeyOrButtonEvent:#buttonPress x:x y:y keyOrButton:buttonNr state:0 toViewId:(screen rootWindowId).
       
   536     screen flush.
       
   537 
       
   538     "Created: / 19-07-2019 / 13:52:38 / Claus Gittinger"
       
   539 !
       
   540 
       
   541 release:buttonNr
       
   542     "press-release at the current position"
       
   543     
       
   544     |position screen x y|
       
   545 
       
   546     screen := Screen current.
       
   547     position := screen pointerPosition.
       
   548     x := position x.
       
   549     y := position y.
       
   550     
       
   551     self movePointerToPosition:position.
       
   552 
       
   553     false "OperatingSystem isOSXlike" ifTrue:[
       
   554         |osxPos|
       
   555 
       
   556         osxPos := OperatingSystem getMousePosition.
       
   557         x := osxPos x rounded.
       
   558         y := osxPos y rounded.
       
   559         OperatingSystem generateButtonEvent:buttonNr down:false x:x y:y.
       
   560         ^ self.
       
   561     ].
       
   562 
       
   563     screen sendKeyOrButtonEvent:#buttonRelease x:x y:y keyOrButton:buttonNr state:0 toViewId:(screen rootWindowId).
       
   564     screen flush.
       
   565 
       
   566     "Created: / 19-07-2019 / 13:53:05 / Claus Gittinger"
       
   567 ! !
       
   568 
       
   569 !ShowMeHowItWorks methodsFor:'running'!
       
   570 
       
   571 doStream:specStream
       
   572     |previousStream|
       
   573 
       
   574     previousStream := opStream.
       
   575     [
       
   576         opStream := specStream.
       
   577         [opStream atEnd] whileFalse:[
       
   578             self nextCommand.
       
   579             Display shiftDown ifTrue:[
       
   580                 self tell:'Shou stopped by shiftkee'.
       
   581                 ^ AbortOperationRequest raise
       
   582             ].    
       
   583         ].    
       
   584     ] ensure:[
       
   585         opStream := previousStream
       
   586     ].
       
   587     
       
   588 "<<END
       
   589      ShowMeHowItWorks do:#(
       
   590         showing: 'Choose the number of arguments'
       
   591         do: (
       
   592             moveTo: NumberOfArguments
       
   593             select: '1'
       
   594         )    
       
   595         showing: 'Click into the "receiver" field'
       
   596         do: (
       
   597             moveTo: ReceiverEditor
       
   598             click: ReceiverEditor
       
   599         )
       
   600         showing: 'Enter a value (or expression) into "receiver" field'
       
   601         do: (
       
   602             enter: '100'
       
   603         )
       
   604         showing: 'Click into the "first argument" field'
       
   605         do: (
       
   606             moveTo: Arg1Editor
       
   607             click: ReceiverEditor
       
   608         )
       
   609         showing: 'Enter a value (or expression) into "receiver" field'
       
   610         do: (
       
   611             enter: '100'
       
   612         )
       
   613      )
       
   614 END"
       
   615 
       
   616     "Created: / 19-07-2019 / 10:52:24 / Claus Gittinger"
       
   617     "Modified: / 19-07-2019 / 15:00:44 / Claus Gittinger"
       
   618 !
       
   619 
       
   620 nextCommand
       
   621     |op numArgs sel args method|
       
   622 
       
   623     op := opStream next.
       
   624     op isArray ifTrue:[
       
   625         "/ construct a selector from keyword parts at odd indices
       
   626         sel := ((op with:(1 to:op size) select:[:el :idx | idx odd]) asStringWith:'') asSymbol.
       
   627         "/ construct arg vector from parts at even indices
       
   628         args := op with:(1 to:op size) select:[:el :idx | idx even].
       
   629     ] ifFalse:[
       
   630         sel := op.
       
   631         numArgs := sel argumentCount.
       
   632         args := opStream next:numArgs.
       
   633     ].
       
   634     
       
   635     (self respondsTo:sel) ifFalse:[
       
   636         self error:'bad operation: ',sel
       
   637     ].
       
   638     method := self class lookupMethodFor:sel.
       
   639     (method hasAnnotation:#action) ifFalse:[self halt].
       
   640     
       
   641     self perform:sel withArguments:args.
       
   642 
       
   643 "<<END
       
   644      ShowMeHowItWorks do:#(
       
   645         showing: 'Choose the number of arguments'
       
   646         do: (
       
   647             moveTo: NumberOfArguments
       
   648             select: '1'
       
   649         )    
       
   650         showing: 'Click into the "receiver" field'
       
   651         do: (
       
   652             moveTo: ReceiverEditor
       
   653             click: ReceiverEditor
       
   654         )
       
   655         showing: 'Enter a value (or expression) into "receiver" field'
       
   656         do: (
       
   657             enter: '100'
       
   658         )
       
   659         showing: 'Click into the "first argument" field'
       
   660         do: (
       
   661             moveTo: Arg1Editor
       
   662             click: ReceiverEditor
       
   663         )
       
   664         showing: 'Enter a value (or expression) into "receiver" field'
       
   665         do: (
       
   666             enter: '100'
       
   667         )
       
   668      )
       
   669 END"
       
   670 
       
   671     "Created: / 19-07-2019 / 10:54:04 / Claus Gittinger"
       
   672     "Modified: / 19-07-2019 / 14:53:15 / Claus Gittinger"
       
   673 ! !
       
   674 
       
   675 !ShowMeHowItWorks class methodsFor:'documentation'!
       
   676 
       
   677 version_CVS
       
   678     ^ '$Header$'
       
   679 ! !
       
   680