[comp.lang.smalltalk] GOODIE - DisplayIfWhile.st

pieter@prls.UUCP (Pieter van der Meulen) (07/11/90)

It has been a while since the last goodie posting, and I noticed
some discussions on the (limitations of) Smalltalk processes.
Here is a goodie which gives you an idea of what you can and should
(not) do with Smalltalk processes. You use it to show a message if
users get impatient while Smalltalk is busily computing (at fileIn maybe ? :-)

Have fun, Pieter.
 
'-----------------------------------cut here----------------------------------'!

'Suppose you are filing in your application, and you want to display a
PLEASE WAIT message only if the mouse buttons are pressed, neither
<aCursor showWhile: [...]> nor <aForm follow: [....] while: [...]>
are what you want. These sources show you how to do this, i.e.
conditionally displaying a DisplayObject.

The basic and a derivative display methods for DisplayObject are given.
Other display methods like the ones in the DisplayObject>displaying
protocol can easily be constructed using the basic display primitive.

As an example, the <fileIn> method for FileModel is included. The code works
for both Smalltalk version 2.3 and (2.4) 2.5. A <fileIn> initiated from a
FileList will display a PLEASE WAIT message if the user pressed a key or
mouse button. Note that any KEYS pressed will NOT be flushed.
Also, try the examples included in the comment of each display method.

	Copyright (C) 1990, Pieter S. van der Meulen.
	This program is placed in the public domain.
	You may use and alter this program freely
	for non-commercial purposes as long as you
	leave this message intact.  Neither I nor
	my company will recognize any responsibility
	for damages arising from use of this program.'!

!DisplayObject methodsFor: 'conditional displaying'!

displayForSeconds: secInteger if: testBlock while: evalBlock
	"This is a simple method for conditional display of objects while
	evaluating evalBlock. The value of evalBlock is returned.
	The evalBlock is expected to take some time to execute.
	If the testBlock evaluates to true during this execution, the
	receiver will be displayed. The duration of this display is
	determined by secInteger. If the latter is equal to zero, display
	will continue until evalBlock is finished.

	In the example below, the evaluation of evalBlock creates a new
	active process, which causes an abnormal termination of this method,
	but gives you a good impression how it all works."

	"' Still browsing. Please wait. ' asDisplayText form reverse
		displayForSeconds: 2
		if: [Sensor anythingPressed]
		while: [Smalltalk browseAllCallsOn: #at: and: #at:put:]"

	^self displayOn: Display
		at: [Sensor cursorPoint]
		clippingBox: Display boundingBox
		rule: Form over
		mask: nil
		forSeconds: secInteger
		if: testBlock
		while: evalBlock!

displayOn: aDisplayMedium at: pointOrBlock clippingBox: aRect rule: ruleInteger
mask: aForm forSeconds: secInteger if: testBlock while: evalBlock
	"This is the basic display primitive for conditional display of objects
	while evaluating evalBlock. The value of evalBlock is returned.
	The evalBlock is expected to take some time to execute. If the testBlock
	evaluates to true during this execution, the receiver will be displayed.
	The duration of this display is determined by secInteger. If the latter
	is equal to zero, display will continue until evalBlock is finished.
	The location for display is determined by pointOrBlock, which may be a
	Point or a block which evaluates to aPoint.
	If pointOrBlock would be [Sensor cursorPoint] and testBlock [true], this
	method will behave like a 1-second-update-<follow:while:> method.
	If the evaluation of evalBlock creates a new active process, e.g.
	opening an Inspector, the receiver may not be able to erase itself from
	aDisplayMedium. To cover ST-versions, 3 termination tricks are used.
	The process associated with displaying the receiver needs to run at
	userInterruptPriority, because the system code implemeting the <fileIn>
	never issues a <Processor yield>. (C) 1990, Pieter S. van der Meulen."

	"Cursor crossHair showWhile:
		[' Showing cursor location in top left corner.
 Hold SHIFT key for 1 second to terminate.'
			asDisplayText form reverse
				displayOn: Display
				at: [Sensor cursorPoint]
				clippingBox: Display boundingBox
				rule: Form over
				mask: nil
				forSeconds: 2
				if: [Sensor anythingPressed]
				while: [[Sensor leftShiftDown] whileFalse:
					[(Sensor cursorPoint printString,'    ')
						asDisplayText displayAt: 0@0]].
		Sensor flushKeyboard]"

	| oldP newP seconds showProcess showing value bgForm thisProcess |
	seconds _ 0.
	showing _ true.
	thisProcess _ Processor activeProcess.
	showProcess _ [
		[(Delay forMilliseconds: 1000) wait.
		(testBlock isNil or: [thisProcess suspendingList isNil])
			ifTrue: [showing _ nil]		"Unexpected termination"
			ifFalse:
				[testBlock value
					ifTrue:
						[seconds _ secInteger.
						(pointOrBlock isKindOf: Point)
							ifTrue: [oldP _ pointOrBlock]
							ifFalse:	"Trace without flashing"
								[newP _ pointOrBlock value.
								(oldP ~= newP and: [bgForm notNil])
									ifTrue: [bgForm display. bgForm _ nil].
								oldP _ newP].
						bgForm isNil
							ifTrue:
								[aDisplayMedium = Display
									ifTrue: [bgForm _ self backgroundAt:
												oldP + self offset].
								self displayOn: aDisplayMedium
									at: oldP
									clippingBox: aRect
									rule: ruleInteger
									mask: aForm]].
				seconds > 0
					ifTrue:
						[seconds _ seconds - 1.
						seconds = 0
							ifTrue:
								[bgForm display. bgForm _ nil]]].
		showing notNil] whileTrue.
		bgForm notNil ifTrue: [bgForm display]] newProcess.
	showProcess priority: Processor userInterruptPriority.
	showProcess resume.
	value _ evalBlock value.
	showing _ nil.	"Proper termination of the showProcess."
	[showProcess suspendingList isNil] whileFalse.
	bgForm notNil ifTrue: [bgForm display].
	^value! !


!InputSensor methodsFor: 'mouse'!

anythingPressed
	"Answer whether anything is being pressed."

	^self anyButtonPressed or:
	[self keyboardPressed or:
	[self leftShiftDown or:
	[self ctrlDown]]]! !


!FileModel methodsFor: 'user protocol'!

fileInFile
	"Read the entire file as Smalltalk code.
	Display a PLEASE WAIT message if the user pressed a key or mouse button.
	This methods supports both Smalltalk version 2.3 and (2.4) 2.5.
	To simplify, take out that part which does not relate to your version."
 
	| aForm |
	aForm _ ('Please wait. Still reading ',fileName) asDisplayText form.
	^((Form new extent: aForm extent + (8@8)) black
		copyBits: (0@0 extent: aForm extent)
		from: aForm
		at: (4@4)
		clippingBox: (0@0 extent: aForm extent + (8@8))
		rule: Form over
		mask: Form black)
			displayOn: Display
			at: [Sensor cursorPoint]
			clippingBox: Display boundingBox
			rule: Form over
			mask: nil
			forSeconds: 3
			if: [Sensor anythingPressed]
			while: [('*2.5*' match: Smalltalk version)
				ifTrue: [(Filename named: fileName) fileIn]
				ifFalse: [(FileStream oldFileNamed: fileName) fileIn]]! !

'-----------------------------------cut here----------------------------------'!
-- 
---------------------------------------------
P.S. van der Meulen, MS 02        prls!pieter
PRLS, Signetics div. of NAPC      -----------
811 E.Arques Avenue, Sunnyvale, CA 94088-3409