ButtonController.st
changeset 76 81e3409404d2
child 87 2c6ab478466a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ButtonController.st	Mon Feb 06 01:52:01 1995 +0100
@@ -0,0 +1,427 @@
+"
+ COPYRIGHT (c) 1995 by Claus Gittinger
+	      All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+
+Controller subclass:#ButtonController
+	 instanceVariableNames:'enabled pressed active entered triggerOnDown autoRepeat
+		repeatBlock initialDelay repeatDelay
+		pressActionBlock releaseActionBlock'
+	 classVariableNames:''
+	 poolDictionaries:''
+	 category:'Interface-Support'
+!
+
+!ButtonController class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1995 by Claus Gittinger
+	      All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+version
+"
+$Header: /cvs/stx/stx/libwidg/ButtonController.st,v 1.1 1995-02-06 00:51:58 claus Exp $
+"
+!
+
+documentation
+"
+    ButtonControllers are used with buttons and handle all user interaction.
+    These are automatically created when a Button is created, therefore no manual
+    action is required for creation.
+
+    Instance variables:
+
+      enabled                 <Boolean>       pressing is allowed (default: true)
+      pressed                 <Boolean>       true if currently pressed (read-only)
+      entered                 <Boolean>       true if the cursor is currently in this view
+      triggerOnDown           <Boolean>       controls if the action should be executed on
+					      press or on release (default: on release).
+      pressActionBlock        <Block>         block to evaluate when pressed (default: noop)
+      releaseActionBlock      <Block>         block to evaluate when released (default: noop)
+      autoRepeat              <Boolean>       auto-repeats when pressed long enough (default: false)
+      initialDelay            <Number>        seconds till first auto-repeat (default: 0.2)
+      repeatDelay             <Number>        seconds of repeat intervall (default: 0.025)
+      repeatBlock             <Block>         block evaluated for auto-repeat (internal)
+      active                  <Boolean>       true during action evaluation (internal)
+"
+!
+
+examples
+"
+    |top b|
+
+    top := StandardSystemView new.
+    top extent:100@100.
+
+    b := Button label:'hello' in:top.
+    b action:[Transcript flash].
+    top open.
+
+
+    |top b|
+
+    top := StandardSystemView new.
+    top extent:100@100.
+
+    b := Button label:'hello' in:top.
+    b controller beTriggerOnUp.
+    top open.
+"
+! !
+
+!ButtonController class methodsFor:'defaults'!
+
+defaultRepeatDelay
+    "when autorepeat is enabled, and button is not released,
+     repeat every repeatDelay seconds"
+
+    ^ 0.025
+
+!
+
+defaultInitialDelay
+    "when autorepeat is enabled, and button is not released,
+     start repeating after initialDelay seconds"
+
+    ^ 0.2
+
+
+! !
+
+!ButtonController methodsFor:'initialization'!
+
+initialize
+    super initialize.
+
+    enabled := true.
+    active := false.
+    pressed := false.
+    entered := false.
+    autoRepeat := false.
+    initialDelay := self class defaultInitialDelay.
+    repeatDelay := self class defaultRepeatDelay.
+    triggerOnDown := false.
+! !
+
+!ButtonController methodsFor:'accessing'!
+
+beTriggerOnUp
+    "make the receiver act on button release"
+
+    triggerOnDown := false
+!
+
+beTriggerOnDown
+    "make the receiver act on button press"
+
+    triggerOnDown := true
+!
+
+triggerOnDown:aBoolean
+    "set/clear the flag which controls if the action block is to be evaluated
+     on press or on release. 
+     (see also ST-80 compatibility methods beTriggerOn*)"
+
+    triggerOnDown := aBoolean
+!
+
+isTriggerOnDown
+    ^ triggerOnDown
+!
+
+pressAction
+    "return the pressAction; thats the block which gets evaluated
+     when the button is pressed (if non-nil)"
+
+    ^ pressActionBlock
+!
+
+pressAction:aBlock
+    "define the action to be performed on press"
+
+    pressActionBlock := aBlock
+!
+
+releaseAction
+    "return the releaseAction; thats the block which gets evaluated
+     when the button is relreased (if non-nil)"
+
+    ^ releaseActionBlock
+!
+
+releaseAction:aBlock
+    "define the action to be performed on release"
+
+    releaseActionBlock := aBlock
+!
+
+action:aBlock
+    "convenient method: depending on the setting the triggerOnDown flag,
+     either set the press-action clear any release-action or
+     vice versa, set the release-action and clear the press-action."
+
+    triggerOnDown ifTrue:[
+	releaseActionBlock := nil.
+	pressActionBlock := aBlock
+    ] ifFalse:[
+	releaseActionBlock := aBlock.
+	pressActionBlock := nil
+    ]
+!
+
+autoRepeat
+    "turn on autorepeat"
+
+    autoRepeat := true.
+    repeatBlock := [self repeat]
+!
+
+disable
+    "disable the button"
+
+    enabled ifTrue:[
+	enabled := false.
+	view redraw
+    ]
+!
+
+enable
+    "enable the button"
+
+    enabled ifFalse:[
+	enabled := true.
+	view redraw
+    ]
+!
+
+enabled
+    ^ enabled
+!
+
+active
+    ^ active
+!
+
+pressed
+    ^ pressed
+!
+
+entered
+    ^ entered
+!
+
+entered:aBoolean
+    entered := aBoolean
+!
+
+pressed:aBoolean
+    pressed := aBoolean
+!
+
+active:aBoolean
+    active := aBoolean
+! !
+
+!ButtonController methodsFor:'event handling'!
+
+buttonPress:button x:x y:y
+    |sym|
+
+    (button == 1 or:[button == #select]) ifFalse:[
+	^ super buttonPress:button x:x y:y
+    ].
+
+    pressed ifFalse:[
+	enabled ifTrue:[
+	    pressed := true.
+	    view showActive.
+
+	    (pressActionBlock notNil or:[model notNil]) ifTrue:[
+		"
+		 force output - so that button is drawn correctly in case
+		 of any long-computation (at high priority)
+		"
+		view device synchronizeOutput.
+	    ].
+
+	    active := true.
+
+	    pressActionBlock notNil ifTrue:[
+		pressActionBlock value
+	    ].
+
+	    triggerOnDown ifTrue:[
+		"the ST-80 way of doing things"
+		(model notNil and:[(sym := view changeSymbol) notNil]) ifTrue:[
+		    model perform:sym
+		].
+	    ].
+
+	    active := false.
+
+	    autoRepeat ifTrue:[
+		Processor addTimedBlock:repeatBlock afterSeconds:initialDelay
+	    ]
+	]
+    ]
+!
+
+buttonRelease:button x:x y:y
+    "button was released - if enabled, perform releaseaction"
+
+    |sym|
+
+    (button == 1 or:[button == #select]) ifFalse:[
+	^ super buttonRelease:button x:x y:y
+    ].
+    pressed ifTrue:[
+	autoRepeat ifTrue:[
+	    Processor removeTimedBlock:repeatBlock
+	].
+	pressed := false.
+	view showPassive.
+
+	enabled ifTrue:[
+	    "
+	     only perform action if released within myself
+	    "
+	    ((x >= 0) 
+	    and:[x <= view width
+	    and:[y >= 0
+	    and:[y <= view height]]]) ifTrue:[
+		(releaseActionBlock notNil or:[model notNil]) ifTrue:[
+		    "
+		     force output - so that button is drawn correctly in case
+		     of any long-computation (at high priority)
+		    "
+		    view device synchronizeOutput.
+		].
+
+		active := true.
+
+		releaseActionBlock notNil ifTrue:[
+		    releaseActionBlock value
+		].
+		triggerOnDown ifFalse:[
+		    "the ST-80 way of doing things"
+		    (model notNil and:[(sym := view changeSymbol) notNil]) ifTrue:[
+			model perform:sym 
+		    ].
+		].
+
+		active := false.
+
+		view redraw.
+	    ]
+	]
+    ]
+!
+
+pointerEnter:state x:x y:y
+    "redraw with enteredColors if they differ from the normal colors"
+
+    entered := true.
+    pressed ifTrue:[
+	"
+	 reentered after a leave with mouse-button down;
+	 restart autorepeating and/or if I am a button with
+	 triggerOnDown, show active again.
+	"
+	enabled ifTrue:[
+	    autoRepeat ifTrue:[
+		Processor addTimedBlock:repeatBlock afterSeconds:initialDelay
+	    ].
+	    triggerOnDown ifFalse:[
+		view showActive.
+	    ]
+	]
+    ] ifFalse:[
+	enabled ifTrue:[
+	    view redraw
+	]
+    ]
+!
+
+repeat
+    "this is sent from the autorepeat-block, when the button has been pressed long
+     enough; it simulates a release-press, by evaluating both release
+     and press actions."
+
+    pressed ifTrue:[
+	enabled ifTrue:[
+	    active ifFalse:[
+		active := true.
+		releaseActionBlock notNil ifTrue:[releaseActionBlock value].
+		pressActionBlock notNil ifTrue:[pressActionBlock value].
+		active := false.
+
+		autoRepeat ifTrue:[
+		    Processor addTimedBlock:repeatBlock afterSeconds:repeatDelay
+		]
+	    ]
+	]
+    ]
+!
+
+buttonMultiPress:button x:x y:y
+    ^ self buttonPress:button x:x y:y
+!
+
+keyPress:key x:x y:y
+    "only trigger, if I am the focusView of my group"
+
+    |group|
+
+    ((group := view windowGroup) notNil 
+    and:[group focusView == view]) ifTrue:[
+	(key == #Return or:[key == Character space]) ifTrue:[
+	    "just simulate a buttonPress/release here."
+	    self buttonPress:1 x:0 y:0.
+	    self buttonRelease:1 x:0 y:0.
+	    ^ self.
+	]
+    ].
+    view keyPress:key x:x y:y
+!
+
+pointerLeave:state
+    "redraw with normal colors if they differ from enteredColors"
+
+    entered := false.
+    pressed ifTrue:[
+	"
+	 leave with mouse-button down;
+	 stop autorepeating and/or if I am a button with
+	 action on release, show passive
+	"
+	autoRepeat ifTrue:[
+	    Processor removeTimedBlock:repeatBlock
+	].
+	triggerOnDown ifFalse:[
+	    view showPassive.
+	]
+    ] ifFalse:[
+	enabled ifTrue:[
+	    view redraw
+	]
+    ]
+! !
+