[squeak-dev] The Trunk: EToys-mt.435.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Mar 17 14:15:10 UTC 2021


Marcel Taeumel uploaded a new version of EToys to project The Trunk:
http://source.squeak.org/trunk/EToys-mt.435.mcz

==================== Summary ====================

Name: EToys-mt.435
Author: mt
Time: 17 March 2021, 3:15:04.484151 pm
UUID: 4951443f-e7ab-6c45-9901-0509281a39ac
Ancestors: EToys-mt.434

Further untangles Etoys from other packages:
- Moves webcam stuff to MorphicExtras
- Moves PointType to Protocols (i.e. vocabularies)
- Clean up vocabularies when unloading Etoys

=============== Diff against EToys-mt.434 ===============

Item was changed:
  SystemOrganization addCategory: #'Etoys-Buttons'!
  SystemOrganization addCategory: #'Etoys-CustomEvents'!
  SystemOrganization addCategory: #'Etoys-Experimental'!
  SystemOrganization addCategory: #'Etoys-OLPC-Display'!
  SystemOrganization addCategory: #'Etoys-Outliner'!
  SystemOrganization addCategory: #'Etoys-Protocols'!
  SystemOrganization addCategory: #'Etoys-Protocols-Type Vocabularies'!
  SystemOrganization addCategory: #'Etoys-ReleaseBuilder'!
  SystemOrganization addCategory: #'Etoys-Scripting'!
  SystemOrganization addCategory: #'Etoys-Scripting Support'!
  SystemOrganization addCategory: #'Etoys-Scripting Tiles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Base'!
  SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Connectors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-EToys-Kedama'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Buttons'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Calendar'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Debugger'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Help'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Input'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Tiles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-SpeechBubbles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Tile Scriptors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Text'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Intersection'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Simplification'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Triangulation'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Basic'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Books'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Components'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Demo'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Experimental'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess960'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-GeeMail'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Kernel'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Mentoring'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Navigators'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PDA'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PartsBin'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Widgets'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Windows'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Worlds'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-AdditionalMorphs'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Charts'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Postscript Filters'!
- SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-WebCam'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Widgets'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-Languages'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-TextConversion'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Formatter'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Forms'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser Entities'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Tokenizer'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-MIME'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-TelNet WordNet'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-UI'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-Url'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Protocols-Type Vocabularies'!
  SystemOrganization addCategory: #'Etoys-Squeakland-SISS-Serialization'!
  SystemOrganization addCategory: #'Etoys-Squeakland-ST80-Morphic'!
  SystemOrganization addCategory: #'Etoys-Squeakland-SUnit'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Interface'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Ogg'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Scores'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sugar'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Clipboard-Extended'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Compiler'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Exceptions Kernel'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Changes'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Explorer'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Process Browser'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ObjectVectors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTree-AttributeDefinition'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTreeTransformer'!
  SystemOrganization addCategory: #'Etoys-Stacks'!
  SystemOrganization addCategory: #'Etoys-StarSqueak'!
  SystemOrganization addCategory: #'Etoys-Support'!
  SystemOrganization addCategory: #'Etoys-Tests'!
  SystemOrganization addCategory: #'Etoys-Tile Scriptors'!
  SystemOrganization addCategory: #'Etoys-UserInterfaceTheme'!
  SystemOrganization addCategory: #'Etoys-Widgets'!

Item was removed:
- Object subclass: #CameraInterface
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'Etoys-Squeakland-MorphicExtras-WebCam'!
- 
- !CameraInterface commentStamp: 'eem 10/16/2020 10:53' prior: 0!
- CameraInterface: Simple cross-platform webcam access interface adapted from MIT Scratch. Changes made so that different cameras can be tested when more than one is connected, and so that the interface is simpler and may be interrupt-driven.
- 
- [| form |
- form := Form extent: 352 @ 288 depth: 32.
- CameraInterface
- 	openCamera: 1 width: form width height: form height;
- 	trySetSemaphoreForCamera: 1.
- [Sensor noButtonPressed] whileTrue:
- 	[CameraInterface
- 		waitForNextFrame: 1 timeout: 2000;
- 		getFrameForCamera: 1 into: form bits.
- 	 form displayAt: Sensor cursorPoint]] ensure: [CameraInterface closeCamera: 1]
- 
- Copyright (c) 2009 Massachusetts Institute of Technology
- 
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- 
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.!

Item was removed:
- ----- Method: CameraInterface class>>camera:framesDo:while: (in category 'utilities') -----
- camera: cameraNum framesDo: aBlock while: whileBlock
- 	"Evaluate aBlock every time a frame becomes available.  Answer a tuple of frames per second and number of 16ms delays per second.
- 	 Be destructive; use only one bitmap, overwriting its contents with each successive frame.
- 	 It is the sender's responsibility to open and close the camera."
- 	| form bitmap delay start duration frameCount delayCount |
- 	form := Form
- 				extent: (self frameExtent: cameraNum)
- 				depth: 32.
- 	bitmap := form bits.
- 	delay := Delay forMilliseconds: (1000 / 60) asInteger. "60 fps is fast"
- 	start := Time utcMicrosecondClock.
- 	frameCount := delayCount := 0.
- 	[[(self camera: cameraNum getParam: 1) <= 0] whileTrue:
- 		[delay wait. delayCount := delayCount + 1].
- 	 self getFrameForCamera: cameraNum into: bitmap.
- 	 frameCount := frameCount + 1.
- 	 aBlock value: form.
- 	 whileBlock value] whileTrue.
- 	^{ frameCount * 1.0e6 / (duration := Time utcMicrosecondClock - start).
- 		delayCount * 1.0e6 / duration }
- 
- 	"| cameraNum |
- 	 self openCamera: (cameraNum := 1) width: 640 height: 480.
- 	 self waitForCameraStart: cameraNum.
- 	 [self camera: cameraNum framesDo: [:bitmap| bitmap display] while: [Sensor noButtonPressed]] ensure:
- 		[self closeCamera: cameraNum]"!

Item was removed:
- ----- Method: CameraInterface class>>camera:getParam: (in category 'camera ops') -----
- camera: cameraNum getParam: paramNum
- 	"Answer the given parameter for the given camera.
- 		param 1 is the frame count, the number of frames grabbed since the last send of getFrameForCamera:into:
- 		param 2 is the size of the bitmap in bytes required for an image"
- 
- 	<primitive: 'primGetParam' module: 'CameraPlugin' error: ec>
- 	^nil
- !

Item was removed:
- ----- Method: CameraInterface class>>camera:setSemaphore: (in category 'camera ops') -----
- camera: cameraNum setSemaphore: semaphoreIndex
- 	"Set an external semaphore index through which to signal that a frame is available.
- 	 Fail if cameraNum does not reference an open camera, or if the platform does not
- 	 support interrupt-driven frame receipt."
- 	<primitive: 'primSetCameraSemaphore' module: 'CameraPlugin' error: ec>
- 	^self primitiveFailed!

Item was removed:
- ----- Method: CameraInterface class>>cameraDevices (in category 'utilities') -----
- cameraDevices
- 	"CameraInterface cameraDevices"
- 	^Array streamContents:
- 		[:s| | i |
- 		i := 1.
- 		[(self cameraName: i)
- 			ifNotNil: [:cameraName| s nextPut: cameraName. true]
- 			ifNil: [false]] whileTrue: [i := i + 1]]!

Item was removed:
- ----- Method: CameraInterface class>>cameraGetSemaphore: (in category 'camera ops') -----
- cameraGetSemaphore: cameraNum
- 	"Answer the external semaphore index through which to signal that a frame is available.
- 	 Fail if cameraNum has not had a semaphore index set, or is otherwise invalid.
- 	 Answer nil on failure for convenience."
- 	<primitive: 'primGetCameraSemaphore' module: 'CameraPlugin' error: ec>
- 	^nil!

Item was removed:
- ----- Method: CameraInterface class>>cameraIsAvailable (in category 'camera ops') -----
- cameraIsAvailable
- 	"Answer true if at least one camera is available."
- 
- 	^(self cameraName: 1) notNil
- !

Item was removed:
- ----- Method: CameraInterface class>>cameraIsOpen: (in category 'camera ops') -----
- cameraIsOpen: cameraNum
- 	"Answer true if the camera is open."
- 
- 	^ (self packedFrameExtent: cameraNum) > 0
- !

Item was removed:
- ----- Method: CameraInterface class>>cameraName: (in category 'camera ops') -----
- cameraName: cameraNum
- 	"Answer the name of the given camera. Answer nil if there is no camera with the given number."
- 
- 	<primitive: 'primCameraName' module: 'CameraPlugin'>
- 	^ nil
- !

Item was removed:
- ----- Method: CameraInterface class>>cameraUID: (in category 'camera ops') -----
- cameraUID: cameraNum
- 	"Answer the unique ID of the given camera. Answer nil if there is no camera with the given number."
- 
- 	<primitive: 'primCameraUID' module: 'CameraPlugin'>
- 	^ nil
- 
- 	"CameraInterface cameraUID: 1"!

Item was removed:
- ----- Method: CameraInterface class>>closeCamera: (in category 'camera ops') -----
- closeCamera: cameraNum
- 	"Close the camera. Do nothing if it was not open. Unregister any associated semaphore."
- 
- 	(self cameraGetSemaphore: cameraNum) ifNotNil:
- 		[:semaphoreIndex|
- 		Smalltalk unregisterExternalObject: (Smalltalk externalObjectAt: semaphoreIndex ifAbsent: nil)].
- 	self primitiveCloseCamera: cameraNum!

Item was removed:
- ----- Method: CameraInterface class>>declareCVarsIn: (in category 'translation') -----
- declareCVarsIn: aCCodeGenerator
- 	"self translate"
- 
- 	super declareCVarsIn: aCCodeGenerator.
- 	aCCodeGenerator cExtras: '
- #include "cameraOps.h"
- #include <string.h>
- '.!

Item was removed:
- ----- Method: CameraInterface class>>frameExtent: (in category 'camera ops') -----
- frameExtent: cameraNum
- 	"Answer the frame extent of the currently open camera, or zero if the camera isn't open."
- 
- 	| packedExtent |
- 	packedExtent := self packedFrameExtent: cameraNum.
- 	^ (packedExtent bitShift: -16) @ (packedExtent bitAnd: 16rFFFF) !

Item was removed:
- ----- Method: CameraInterface class>>getFrameForCamera:into: (in category 'camera ops') -----
- getFrameForCamera: cameraNum into: aBitmap
- 	"Copy a camera frame into the given Bitmap. The Bitmap should be a Form of depth 32 that is the same width and height as the current camera frame. Fail if the camera is not open or if the bitmap is not the right size. If successful, answer the number of frames received from the camera since the last call. If this is zero, then there has been no change."
- 
- 	<primitive: 'primGetFrame' module: 'CameraPlugin'>
- 	^ 0!

Item was removed:
- ----- Method: CameraInterface class>>interruptDrivenVideoTest: (in category 'test') -----
- interruptDrivenVideoTest: camNum
- 	"A quick test of video input. Displays video on the screen until the mouse is pressed.
- 	 Answer nil if the interrupt-driven interface is unavailable."
- 	"self interruptDrivenVideoTest: 1"
- 	"self interruptDrivenVideoTest: 2"
- 	"[self interruptDrivenVideoTest: 2] fork.
- 	  self interruptDrivenVideoTest: 1"
- 
- 	| semaphore height |
- 	height := 16.
- 	1 to: camNum - 1 do:
- 		[:camIndex| "N.B. the of an unopened camera is 0 at 0"
- 		height := height + (CameraInterface frameExtent: camIndex) y + 16].
- 	(CameraInterface cameraIsOpen: camNum) ifFalse:
- 		[(CameraInterface openCamera: camNum width: 352 height: 288) ifNil:
- 			[self inform: 'no camera'.
- 			 ^nil]].
- 	semaphore := Semaphore new.
- 	[CameraInterface camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)]
- 		on: Error
- 		do: [:err|
- 			Smalltalk unregisterExternalObject: semaphore.
- 			self inform: 'interrupt-driven camera interface unavailable: ', err messageText.
- 			^nil].
- 	[| f n startTime frameCount msecs fps |
- 	 [semaphore wait.
- 	 "N.B. the frame extent may not be known until the delivery of the first frame.
- 	  So we have to delay initialization."
- 	  startTime ifNil:
- 		[(self frameExtent: camNum) x = 0 ifTrue: [self inform: 'no camera'. ^nil].
- 		 f := Form extent: (CameraInterface frameExtent: camNum) depth: 32.
- 		 frameCount := 0.
- 		 startTime := Time millisecondClockValue].
- 	  Sensor anyButtonPressed] whileFalse:
- 		[n := CameraInterface getFrameForCamera: camNum into: f bits.
- 		n > 0 ifTrue:
- 			[frameCount := frameCount + 1.
- 			 f displayAt: 16 @ height]].
- 	 msecs := Time millisecondClockValue - startTime.
- 	 fps := (frameCount * 1000) // msecs.
- 	 ^(CameraInterface cameraName: camNum), ': ', frameCount printString, ' frames at ', fps printString, ' frames/sec']
- 		ensure:
- 			[CameraInterface closeCamera: camNum.
- 			 Smalltalk unregisterExternalObject: semaphore.
- 			 Sensor waitNoButton]!

Item was removed:
- ----- Method: CameraInterface class>>openCamera:width:height: (in category 'camera ops') -----
- openCamera: cameraNum width: frameWidth height: frameHeight
- 	"Open the given camera requesting the given frame dimensions. The camera number is usually 1 since you typically have only one camera plugged in. If the camera does not support the exact frame dimensions, an available frame size with width >= the requested width is selected."
- 
- 	<primitive: 'primOpenCamera' module: 'CameraPlugin'>
- 	^ nil
- !

Item was removed:
- ----- Method: CameraInterface class>>packedFrameExtent: (in category 'camera ops') -----
- packedFrameExtent: cameraNum
- 	"Answer the extent of the currently open camera packed in an integer. The top 16 bits are the width, the low 16 bits are the height. Answer zero if the camera isn't open."
- 
- 	<primitive: 'primFrameExtent' module: 'CameraPlugin'>
- 	^ 0
- !

Item was removed:
- ----- Method: CameraInterface class>>primitiveCloseCamera: (in category 'private-primitives') -----
- primitiveCloseCamera: cameraNum
- 	"Close the camera. Do nothing if it was not open except answering nil."
- 
- 	<primitive: 'primCloseCamera' module: 'CameraPlugin'>
- 	^nil!

Item was removed:
- ----- Method: CameraInterface class>>trySetSemaphoreForCamera: (in category 'utilities') -----
- trySetSemaphoreForCamera: camNum
- 	"Attempt to set a semaphore to be signalled when a frame is available.
- 	 Fail silently.  Use e.g. waitForCameraStart: or waitForNextFrame: to
- 	 access the semaphore if available."
- 	| semaphore |
- 	Smalltalk registerExternalObject: (semaphore := Semaphore new).
- 	[CameraInterface camera: camNum setSemaphore: semaphore]
- 		on: Error
- 		do: [:err|
- 			Smalltalk unregisterExternalObject: semaphore]!

Item was removed:
- ----- Method: CameraInterface class>>videoTest: (in category 'test') -----
- videoTest: camNum
- 	"A quick test of video input. Displays video on the screen until the mouse is pressed."
- 	"self videoTest: 1"
- 	"self videoTest: 2"
- 
- 	| f n startTime frameCount msecs fps |
- 	(CameraInterface openCamera: camNum width: 320 height: 240) ifNil: [^ self inform: 'no camera'].
- 	self waitForCameraStart: camNum.
- 	(self frameExtent: camNum) x = 0 ifTrue: [^ self inform: 'no camera'].
- 	f := Form extent: (CameraInterface frameExtent: camNum) depth: 32.
- 	frameCount := 0.
- 	startTime := nil.
- 	[Sensor anyButtonPressed] whileFalse: [
- 		n := CameraInterface getFrameForCamera: camNum into: f bits.
- 		n > 0 ifTrue: [
- 			startTime ifNil: [startTime := Time millisecondClockValue].
- 			frameCount := frameCount + 1.
- 			f display]].
- 	Sensor waitNoButton.
- 	msecs := Time millisecondClockValue - startTime.
- 	CameraInterface closeCamera: camNum.
- 	fps := (frameCount * 1000) // msecs.
- 	^ frameCount printString, ' frames at ', fps printString, ' frames/sec'!

Item was removed:
- ----- Method: CameraInterface class>>waitForCameraStart: (in category 'utilities') -----
- waitForCameraStart: camNum
- 	"Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds."
- 	"self waitForCameraStart: 1"
- 
- 	| startTime |
- 	(self cameraGetSemaphore: camNum) ifNotNil:
- 		[:semaphoreIndex|
- 		(Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) wait.
- 		^self].
- 	startTime := Time utcMicrosecondClock.
- 	[(self packedFrameExtent: camNum) > 0 ifTrue: [^ self].
- 	 (Time utcMicrosecondClock - startTime) < 2000000] whileTrue:
- 		[(Delay forMilliseconds: 50) wait]!

Item was removed:
- ----- Method: CameraInterface class>>waitForNextFrame:timeout: (in category 'utilities') -----
- waitForNextFrame: camNum timeout: timeoutms
- 	"Wait for the camera to get it's first frame (indicated by a non-zero frame extent. Timeout after two seconds."
- 	"self waitForNextFrame: 1 timeout: 2000"
- 
- 	| now timeoutusecs |
- 	(self cameraGetSemaphore: camNum) ifNotNil:
- 		[:semaphoreIndex|
- 		(Smalltalk externalObjectAt: semaphoreIndex ifAbsent: [self error: 'seriously?!!?!!?!!?']) waitTimeoutMSecs: timeoutms.
- 		^self].
- 	now := Time utcMicrosecondClock.
- 	timeoutusecs := timeoutms * 1000.
- 	[(self camera: camNum getParam: 1) > 0 ifTrue: [^self].
- 	 (Time utcMicrosecondClock - now) < timeoutusecs] whileTrue:
- 		[(Delay forMilliseconds: 50) wait]!

Item was changed:
+ ----- Method: EToyVocabulary class>>allPhrasesWithContextToTranslate (in category 'accessing') -----
- ----- Method: EToyVocabulary class>>allPhrasesWithContextToTranslate (in category '*Etoys-Squeakland-as yet unclassified') -----
  allPhrasesWithContextToTranslate
  	| etoyVocab results literals additions |
  
  	results := OrderedCollection new.
  	etoyVocab := Vocabulary eToyVocabulary.
  	etoyVocab initialize.		"just to make sure that it's unfiltered."
  	self morphClassesDeclaringViewerAdditions do: [:cl |
  		(cl class includesSelector: #additionsToViewerCategories)
  			ifTrue: [
  				literals := OrderedCollection new.
  				cl additionsToViewerCategories do: [:group | 
  					literals add: group first.
  					group second do: [:tuple |
  						literals add: (ScriptingSystem wordingForOperator: (tuple at: 2)).  "wording"
  						literals add: (tuple at: 3).  "help string"]].
  				literals ifNotEmpty: [
  					results add: {cl category. cl class. #additionsToViewerCategories. literals}]].
  
  		cl class selectors do: [:aSelector | ((aSelector beginsWith: 'additionsToViewerCategory')
  								and: [(aSelector at: 26 ifAbsent: []) ~= $:])
  			ifTrue: [
  				literals := OrderedCollection new.
  				additions := (cl perform: aSelector).
  				literals add: additions first.
  				additions second do: [:tuple |
  					literals add: (ScriptingSystem wordingForOperator: (tuple at: 2)).  "wording"
  					literals add: (tuple at: 3).  "help string"].
  				literals ifNotEmpty: [
  					results add: {cl category. cl class. aSelector. literals}]]]].
  
+ 	^results!
- 		literals :=( self allStandardVocabularies
- 			select: 
- 				[:aVocab | aVocab representsAType]
- 			thenCollect: 
- 				[:aVocab | aVocab vocabularyName asString ]).
- 		results add: {Vocabulary class category. Vocabulary class. #typeChoices. literals}.
- 	^results.!

Item was added:
+ ----- Method: EToyVocabulary class>>initialize (in category 'class initialization') -----
+ initialize
+ 
+ 	self addStandardVocabulary: EToyVocabulary new.
+ 	self addStandardVocabulary: EToyVectorVocabulary new.
+ 
+ 	self addStandardVocabulary: PlayerType new.
+ 	self addStandardVocabulary: ScriptNameType new.
+ 	
+ 	self addStandardVocabulary: (SymbolListType new symbols: #(lines arrows arrowheads dots); vocabularyName: #TrailStyle; yourself).
+ 	self addStandardVocabulary: (SymbolListType new symbols: #(rotate #'do not rotate' #'flip left right' #'flip up down'); vocabularyName: #RotationStyle; yourself).
+ 	
+ 	self addStandardVocabulary: (KedamaPatchType new vocabularyName: #Patch; yourself).
+ 
+ 	self addStandardVocabulary: (SymbolListType new symbols: #(wrap stick bouncing); vocabularyName: #EdgeMode; yourself).
+ 	self addStandardVocabulary: (SymbolListType new symbols: #(logScale linear color); vocabularyName: #PatchDisplayMode; yourself).
+ 	
+ 	self addStandardVocabulary: (SymbolListType new symbols: #(#top #'top right' #right #'bottom right' #bottom #'bottom left' #left #'top left' #center ); vocabularyName: #AttachmentEdge; yourself).!

Item was added:
+ ----- Method: EToyVocabulary class>>unload (in category 'class initialization') -----
+ unload
+ 
+ 	#(eToy Vector CustomEvents Patch PatchDisplayMode EdgeMode AttachmentEdge Player ScriptName RotationStyle TrailStyle Wonderland)
+ 		do: [:vocabularyName |
+ 			self allStandardVocabularies removeKey: vocabularyName ifAbsent: []].!

Item was changed:
+ ----- Method: EToyVocabulary>>systemSlotNames (in category 'initialization') -----
- ----- Method: EToyVocabulary>>systemSlotNames (in category '*Etoys-Squeakland-initialization') -----
  systemSlotNames
  	"Answer a list of the predefined system slots"
  
  	^ (methodInterfaces select: [:m | m resultType ~= #unknown] thenCollect: [:m | m selector inherentSelector]) keys
  
  "
  Vocabulary eToyVocabulary systemSlotNames
  "!

Item was removed:
- DataType subclass: #PointType
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'Etoys-Squeakland-Protocols-Type Vocabularies'!
- 
- !PointType commentStamp: 'sw 2/8/2012 17:57' prior: 0!
- A value type whose representing Point-valued variables.!

Item was changed:
+ ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category '*Etoys-defaults') -----
- ----- Method: PointType>>addExtraItemsToMenu:forSlotSymbol: (in category 'defaults') -----
  addExtraItemsToMenu: aMenu forSlotSymbol: slotSym
  	"If the receiver has extra menu items to add to the slot menu, here is its chance to do it.  The defaultTarget of the menu is the player concerned."
  
  	aMenu add: 'decimal places...' translated selector: #setPrecisionFor: argument: slotSym.
  	aMenu balloonTextForLastItem: 'Lets you choose how many decimal places should be shown in readouts for this variable' translated!

Item was changed:
+ ----- Method: PointType>>defaultArgumentTile (in category '*Etoys-defaults') -----
- ----- Method: PointType>>defaultArgumentTile (in category 'defaults') -----
  defaultArgumentTile
  	"Answer a tile to represent the type"
  
  	^ (0 at 0) newTileMorphRepresentative typeColor: self typeColor!

Item was removed:
- ----- Method: PointType>>initialValueForASlotFor: (in category 'defaults') -----
- initialValueForASlotFor: aPlayer
- 	"Answer the value to give initially to a newly created slot of the given type in the given player"
- 
- 	^  0 at 0!

Item was removed:
- ----- Method: PointType>>initialize (in category 'defaults') -----
- initialize
- 	"Initialize the receiver"
- 
- 	super initialize.
- 	self vocabularyName: #Point!

Item was changed:
+ ----- Method: PointType>>newReadoutTile (in category '*Etoys-tiles') -----
- ----- Method: PointType>>newReadoutTile (in category 'tiles') -----
  newReadoutTile
  	"Answer a tile that can serve as a readout for data of this type"
  
  	| aTile |
  	aTile := NumericReadoutTile new typeColor: Color lightGray lighter.
  	aTile setProperty: #PointValued toValue: true.
  	^ aTile!

Item was changed:
+ ----- Method: PointType>>wantsArrowsOnTiles (in category '*Etoys-defaults') -----
- ----- Method: PointType>>wantsArrowsOnTiles (in category 'defaults') -----
  wantsArrowsOnTiles
  	"Answer whether this data type wants up/down arrows on tiles representing its values"
  
  	^ false!

Item was changed:
+ ----- Method: PointType>>wantsAssignmentTileVariants (in category '*Etoys-tiles') -----
- ----- Method: PointType>>wantsAssignmentTileVariants (in category 'tiles') -----
  wantsAssignmentTileVariants
  	"Answer whether an assignment tile for a variable of this type should show variants to increase-by, decrease-by, multiply-by."
  
  	^ true!

Item was changed:
+ ----- Method: PointType>>wantsSuffixArrow (in category '*Etoys-defaults') -----
- ----- Method: PointType>>wantsSuffixArrow (in category 'defaults') -----
  wantsSuffixArrow
  	"Answer whether a tile showing data of this type would like to have a suffix arrow"
  
  	^ true!

Item was removed:
- RectangleMorph subclass: #WebCamMorph
- 	instanceVariableNames: 'camNum camIsOn frameExtent displayForm resolution useFrameSize captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps orientation'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'Etoys-Squeakland-MorphicExtras-WebCam'!
- 
- !WebCamMorph commentStamp: '<historical>' prior: 0!
- INTRODUCTION
- =========
- 
- WebCamMorph together with CameraPlugin (originally from MIT Scratch) provides an easy and cross platform way to use webcam input in Squeak and Etoys. The first version has been created specifically with Etoys in mind. To view a live feed simply drag a "WebCam" tile from the "WebCam" category in the objects tool. Open up a viewer on the morph and display the "camera settings" category to explore the following basic settings:
- 
- 	"camera is on": turn the camera on/off.
- 
- 	"camera number": usually the default of "1" is ok but if you have more than one camera connected then adjust between 1 and 9 for other instances of WebCamMorph.
- 
- 	"max fps": leave as is for now. It is unusual for webcams to capture at higher than 30fps. See later for further explanation of how fps is controlled.
- 
- 	"actual fps": read-only. Indicates the actual fps being achieved which can depend significantly on lighting conditions and capture resolution...
- 
- 	"resolution": webcams can have a range of resolutions but for simplicity three are supported: "low" (160x120), "medium" (320x240) and "high" (640x480). Adjust in good lighting to see if "actual fps" increases. 
- 
- 	"use frame size": the resolution used for capturing can differ from the resolution used for display. If this setting is true then WebCamMorph is resized to match the camera resolution. If false then you are free to resize it however you want (via the "resize" halo button, use shift to preserve aspect ratio)
- 
- 
- Beyond viewing a live feed WebCamMorph has been designed to support different uses including simple effects, time-lapse photography, stop-motion animation, character recognition, motion detection and more complex processing of every frame for feature detection. The following information is to help you understand how and why WebCamMorph operates so you can adjust it for your particular needs.
- 
- 
- "FRAMES PER SECOND", LIGHTING & CAMERA RESOLUTION
- ==================================
- 
- The maximum possible frame rate depends on many factors, some of which are outside of our control. Frame rates differ between cameras and usually depend significantly on chosen resolution and lighting conditions. To ensure a balance between capturing every available frame and keeping everything else responsive, WebCamMorph dynamically adjusts the delay between capturing one frame and the next (does not apply when in "manual capture" mode, see later). 
- 
- WebCams often include automatic compensation for lighting conditions. In low lighting it takes significantly more time for the camera to get a picture than it does in good lighting conditions. For example 30fps may be possible with good lighting compared to 7fps in low lighting. So for best capture rates ensure you have good lighting!! 
- 
- Cameras have a "native" resolution at which frame rates are usually better than for other resolutions. Note though that the native resolution might be *higher*
- than the *minimum* resolution available. It pays to experiment with different resolutions to find which one results in the highest frame rate. Use good lighting conditions when experimenting with resolutions.
- 
- 
- "MANUAL CAPTURE" MODE
- ===============
- 
- In simply usage WebCamMorph automatically captures a frame and displays it. To support Etoys scripting a "manual capture" mode is provided where you or your script determines when to capture, when to apply effects (or not) and when to update the display. In between these steps you can do anything you want. Note that frames rates will be lower than that in automatic capture mode and that "skip frames" (described next) will need adjusting at very low capture rates.
- 
- Tip: In manual mode the camera can be turned off. It will be turned on automatically when required and return to it's previous state after a frame has been captured. For capture periods of five seconds or more turning the camera off may save power, which can especially useful when running off batteries. For smaller periods leaving the camera on will avoid some delays and could help speed up webcam related scripts.
- 
- 
- "SKIP FRAMES"
- ========
- 
- Webcams and their drivers are typically designed for streaming live video and use internal buffering to help speed things up. At low capture rates the picture can appear to lag real-time because what you see is the next available buffer not the *latest* buffer. So for example if you capture a frame every ten seconds and there are three buffers being used then what you actually see may be thirty seconds old. We have little/no control over the number of buffers used and the actual number can vary between cameras and under different circumstances for the same camera. "skip frames" is provided to compensate for buffering so increase it when doing "manual" capturing until you see what you expect to see. Typically a setting of 8 is enough but I have had to use 20 with one particular camera in low lighting.
- 
- 
- "SNAPSHOTS"
- ========
- 
- Where as "capturing" is the process of getting an image from the Camera into Squeak/Etoys, a "snapshot" preserves whatever is currently displayed (which may be the captured image after effects have been applied). To store snapshots you need to designate a "holder" which at the moment can be either a "holder" morph or a "movie" morph. Create one of these before proceeding. To assign a holder open up a viewer for WebCamMorph, display the "snapshot" category and click in the box at the right of the entry called "snapshot holder". The cursor will now resemble a cross-hair and can be clicked on the target holder/movie morph. To take a single snapshot at any time click (!!) on the left of "take snapshot". In auto-capture mode WebCamMorph can also be set to take multiple consecutive snapshots . First, before turning the camera on, set a sensible limit using "snapshot limit" (to avoid using all the computers memory) then set "auto snapshot" to true. When the camera is next turned on then s
 napshots are taken for every frame until "snapshot limit" becomes zero. "snapshot limit" is automatically decremented but not reset to avoid problems (although you are free to reset it manually or via a script).
- 
- 
- "EFFECTS" - WIP
- =========
- 
- Similar to snapshots, a holder can be designated as the "effects holder". This holder is intended to be populated with "fx" morphs (coming soon) which will operate on captured frames prior to displaying. Stay tuned ;-)
- 
- 
- CLEARING SNAPSHOT & EFFECTS HOLDERS
- =========================
- 
- Keeping a link to snapshot or effects holders can tie up resources even after the target holders have been deleted and are no longer visible. To ensure this does not happen designate the WebCamMorph itself as the holder (for method see "snapshots" section above).
- 
- 
- COMING SOON!!
- =========
- 
- - Built-in basic effects such as brightness, contrast and hue.
- - Image "fx" morphs for effects such as those found in MIT Scratch and many other types of effects/ image processing.
- - More snapshot options, eg, store to file
- - Demo projects
- 
- !

Item was removed:
- ----- Method: WebCamMorph class>>additionsToViewerCategories (in category 'scripting') -----
- additionsToViewerCategories
- 	"Answer a list of (<categoryName> <list of category specs>) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories."
- 	^ #(
- 
- 	(#'camera' (
- 		(slot resolution '160x120, 320x240, 640x480 or 1280x960' 
- 			WebCamResolution readWrite Player getWebCamResolution Player setWebCamResolution:)
- 		(slot orientation 'Natural (mirrored) or navtive (as from the camera' 
- 			WebCamOrientation readWrite Player getWebCamOrientation Player setWebCamOrientation:)
- 		(slot cameraIsOn 'Whether the camera is on/off' Boolean readWrite Player getWebCamIsOn Player setWebCamIsOn:)
- 		(slot useFrameSize 'Resize the player to match the camera''s frame size' 
- 			Boolean readWrite Player getUseFrameSize Player setUseFrameSize:)
- 		(slot lastFrame 'A player with the last frame' Player readOnly	Player getLastFrame unused unused)
- 		(slot showFPS 'Whether to show the samera''s frames per second' Boolean readWrite Player getShowFPS Player setShowFPS:)
- 		))
- )
- !

Item was removed:
- ----- Method: WebCamMorph class>>allOff (in category 'accessing') -----
- allOff
- 	self allInstancesDo: [:each | each off].!

Item was removed:
- ----- Method: WebCamMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self
- 		partName: 'Camera' translatedNoop
- 		categories: {'Multimedia' translatedNoop}
- 		documentation: 'Web camera player.' translatedNoop
- 		sampleImageForm: self icon!

Item was removed:
- ----- Method: WebCamMorph class>>icon (in category 'parts bin') -----
- icon
- 	"Original file: imagecodericon.png"
- 
- 	^ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: 
- '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
- /i957VpDfrfOMwAAAABJRU5ErkJggg=='
- 	readStream) readStream) nextImage
- !

Item was removed:
- ----- Method: WebCamMorph class>>initialize (in category 'class initialization') -----
- initialize
- 	"CameraMorph initialize"
- 
- 
- 	
- !

Item was removed:
- ----- Method: WebCamMorph class>>resolutionFor: (in category 'scripting') -----
- resolutionFor: aSymbol
- 	(#(low medium high hd) includes: aSymbol) ifFalse: [^ 320 at 240].
- 
- 	^ {160 @ 120. 320 @ 240. 640 @ 480. 1280 @ 960} 
- 			at: (WebCamResolution resolutions indexOf: aSymbol)
- !

Item was removed:
- ----- Method: WebCamMorph class>>shutDown (in category 'accessing') -----
- shutDown
- 	self allOff.
- !

Item was removed:
- ----- Method: WebCamMorph class>>startUp (in category 'accessing') -----
- startUp
- 	"Try to bring up any instances that were on before shutdown"
- !

Item was removed:
- ----- Method: WebCamMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aMenu hand: aHandMorph 
- 
- 	super addCustomMenuItems: aMenu hand: aHandMorph.
- 	aMenu
- 		addUpdating: #cameraToggleString action: #toggleCameraOnOff;
- 		addLine;
- 		add: 'resolution...' translated subMenu: ([:menu |
- 			WebCamResolution resolutions do: [:res |
- 				menu
- 					add: (resolution == res ifTrue: ['<on>'] ifFalse: ['<off>']), res translated
- 					selector: #setWebCamResolution:
- 					argument: res].
- 			menu] value: (aMenu class new defaultTarget: aMenu defaultTarget));
- 		add: 'orientation...' translated subMenu: ([:menu |
- 			WebCamOrientation orientations do: [:ori |
- 				menu
- 					add: (orientation == ori ifTrue: ['<on>'] ifFalse: ['<off>']), ori translated
- 					selector: #setWebCamOrientation:
- 					argument: ori].
- 			menu] value: (aMenu class new defaultTarget: aMenu defaultTarget));
- 		addUpdating: #frameSizeToggleString action: #toggleUseFrameSize;
- 		addUpdating: #showFPSToggleString action: #toggleShowFPS;
- 		yourself
- !

Item was removed:
- ----- Method: WebCamMorph>>cameraIsOn (in category 'accessing') -----
- cameraIsOn
- 	^camIsOn!

Item was removed:
- ----- Method: WebCamMorph>>cameraNumber (in category 'accessing') -----
- cameraNumber
- 	^camNum!

Item was removed:
- ----- Method: WebCamMorph>>cameraNumber: (in category 'accessing') -----
- cameraNumber: anInteger
- 	camNum ~= anInteger ifTrue:
- 		[camNum := anInteger.
- 		 self initializeDisplayForm]!

Item was removed:
- ----- Method: WebCamMorph>>cameraToggleString (in category 'menu') -----
- cameraToggleString
- 
- 	^ camIsOn
- 		ifTrue: ['<on>', 'turn camera off' translated]
- 		ifFalse: ['<off>', 'turn camera on' translated].
- 	
- 
- 	
- !

Item was removed:
- ----- Method: WebCamMorph>>decreaseCaptureDelay (in category 'accessing') -----
- decreaseCaptureDelay
- 
- 	captureDelayMs := (captureDelayMs - 1) min: 200.!

Item was removed:
- ----- Method: WebCamMorph>>delete (in category 'submorphs - add/remove') -----
- delete
- 	self off.
- 	super delete!

Item was removed:
- ----- Method: WebCamMorph>>drawCameraImageOn: (in category 'drawing') -----
- drawCameraImageOn: aCanvas
- 	| scale offset |
- 	offset :=  0 @ 0.
- 	scale := 1 @ 1.
- 	bounds extent = displayForm extent
- 		ifFalse: [scale := bounds extent  / displayForm extent].
- 	orientation == #natural
- 		ifTrue: [
- 			scale := scale x negated @ scale y.
- 			offset := bounds width @ 0].
- 	1 @ 1 = scale
- 		ifTrue: [aCanvas drawImage: displayForm at: bounds origin + offset]
- 		ifFalse: [aCanvas
- 			warpImage: displayForm
- 			transform: (MatrixTransform2x3 withScale: scale)
- 			at: bounds origin + offset].
- !

Item was removed:
- ----- Method: WebCamMorph>>drawFPSOn: (in category 'drawing') -----
- drawFPSOn: aCanvas
- 	showFPS ifFalse: [^self].
- 	aCanvas
- 		drawString: 'FPS: ', fps asString
- 		at: bounds bottomLeft + (5 @ -20)
- 		font: Preferences windowTitleFont
- 		color: Color white!

Item was removed:
- ----- Method: WebCamMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas 
- 	camIsOn ifFalse:
- 		[self initializeDisplayForm.
- 		 self on].
- 	camIsOn ifTrue:
- 		[(CameraInterface frameExtent: camNum) ~= displayForm extent ifTrue:
- 			[self initializeDisplayForm]].
- 	displayForm ifNil:
- 		[self initializeDisplayForm].
- 	useFrameSize ifTrue: [self extent: frameExtent].
- 	self drawCameraImageOn: aCanvas.
- 	self drawFPSOn: aCanvas.
- 	self drawOverlayTextOn: aCanvas!

Item was removed:
- ----- Method: WebCamMorph>>drawOverlayTextOn: (in category 'drawing') -----
- drawOverlayTextOn: aCanvas
- 	camIsOn ifTrue: [^self].
- 	aCanvas
- 		drawString: 'Camera is off' translated
- 		at: bounds origin + (5 @ 2)
- 		font: Preferences windowTitleFont
- 		color: Color white.!

Item was removed:
- ----- Method: WebCamMorph>>frameSizeToggleString (in category 'menu') -----
- frameSizeToggleString
- 
- 	^ (useFrameSize ifTrue: ['<on>'] ifFalse: ['<off>']), 'use frame size' translated
- 
- 	
- !

Item was removed:
- ----- Method: WebCamMorph>>getLastFrame (in category 'e-toy - settings') -----
- getLastFrame
- 
- 	
- 	^ SketchMorph withForm: displayForm deepCopy!

Item was removed:
- ----- Method: WebCamMorph>>getShowFPS (in category 'e-toy - settings') -----
- getShowFPS
- 	^ showFPS
- !

Item was removed:
- ----- Method: WebCamMorph>>getUseFrameSize (in category 'e-toy - settings') -----
- getUseFrameSize
- 	^ useFrameSize
- !

Item was removed:
- ----- Method: WebCamMorph>>getWebCamIsOn (in category 'e-toy - settings') -----
- getWebCamIsOn
- 
- 	^ camIsOn!

Item was removed:
- ----- Method: WebCamMorph>>getWebCamResolution (in category 'e-toy - settings') -----
- getWebCamResolution
- 	^ resolution
- 			
- !

Item was removed:
- ----- Method: WebCamMorph>>increaseCaptureDelay (in category 'accessing') -----
- increaseCaptureDelay
- 
- 	captureDelayMs := (captureDelayMs + 1) max: 10.!

Item was removed:
- ----- Method: WebCamMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	camNum := 1.
- 	camIsOn := false.
- 	showFPS := false.
- 	captureDelayMs := 16. "stepTime"	
- 	fps := 60. "guess."
- 	lastDisplayTime := 0.
- 	framesSinceLastDisplay := 0.
- 	useFrameSize := false.
- 	resolution := #medium.
- 	orientation := #natural.
- 	frameExtent := self class resolutionFor: resolution!

Item was removed:
- ----- Method: WebCamMorph>>initializeDisplayForm (in category 'initialization') -----
- initializeDisplayForm
- 	| cameraExtent formExtent |
- 
- 	cameraExtent := CameraInterface frameExtent: camNum.
- 	cameraExtent isZero 
- 		ifTrue: [formExtent := frameExtent]
- 		ifFalse: [ | camRatio frameRatio |
- 			formExtent := cameraExtent.
- 			camRatio := cameraExtent x / cameraExtent y.
- 			frameRatio := frameExtent x / frameExtent y.
- 			camRatio ~= frameRatio ifTrue: [frameExtent := frameExtent x @ (frameExtent x * camRatio reciprocal)]].
- 	displayForm := Form extent: formExtent depth: 32.
- 	self extent: frameExtent.
- !

Item was removed:
- ----- Method: WebCamMorph>>intoWorld: (in category 'initialization') -----
- intoWorld: aWorld
- 
- 	super intoWorld: aWorld.
- 	camIsOn ifTrue: [self on]
- 					ifFalse:[self off].
- 	self removeActionsForEvent: #aboutToEnterWorld.
- 	aWorld
- 		when: #aboutToLeaveWorld
- 		send: #outOfWorld:
- 		to: self
- 		with: aWorld.!

Item was removed:
- ----- Method: WebCamMorph>>knownName (in category 'testing') -----
- knownName
- 
- 	^ CameraInterface cameraName: camNum	!

Item was removed:
- ----- Method: WebCamMorph>>nextFrame (in category 'stepping and presenter') -----
- nextFrame
- 	
- 	| frameCount |
- 	frameCount := CameraInterface getFrameForCamera: camNum into: displayForm bits.
- 	frameCount = 0 ifTrue: [self increaseCaptureDelay].
- 	frameCount > 2 ifTrue: [self decreaseCaptureDelay].
- 	framesSinceLastDisplay := framesSinceLastDisplay + frameCount!

Item was removed:
- ----- Method: WebCamMorph>>off (in category 'accessing') -----
- off
- 	self stopStepping.
- 	camIsOn := false.
- 	"Be careful not to close the camera if any other morphs are using the same camera."
- 	(self class allInstances anySatisfy: [:wcm| wcm cameraNumber = camNum and: [wcm cameraIsOn]]) ifFalse:
- 		[CameraInterface  closeCamera: camNum].
- 	self changed
- 	
- 	"self allInstances select: [:wcm| wcm cameraNumber = 1 and: [wcm cameraIsOn]]"!

Item was removed:
- ----- Method: WebCamMorph>>on (in category 'accessing') -----
- on
- 	camIsOn ifTrue: [^true].
- 	(CameraInterface cameraIsOpen: camNum) ifFalse:
- 		[(CameraInterface openCamera: camNum width: frameExtent x height: frameExtent y) ifNil:
- 			[^false]].
- 	"The plugin/camera subsystem may end up choosing a different width and height.
- 	 So use the width and height it has selected; it may not be what was asked for."
- 	self initializeDisplayForm.
- 	CameraInterface waitForCameraStart: camNum.
- 	camIsOn := true.
- 	self startStepping!

Item was removed:
- ----- Method: WebCamMorph>>outOfWorld: (in category 'initialization') -----
- outOfWorld: aWorld
- 
- 	super outOfWorld: aWorld.
- 	camIsOn ifTrue: [self off. camIsOn := true].
- 	aWorld
- 		when: #aboutToEnterWorld
- 		send: #intoWorld:
- 		to: self
- 		with: aWorld.!

Item was removed:
- ----- Method: WebCamMorph>>setShowFPS: (in category 'e-toy - settings') -----
- setShowFPS: aBoolean
- 	showFPS := aBoolean
- !

Item was removed:
- ----- Method: WebCamMorph>>setUseFrameSize: (in category 'e-toy - settings') -----
- setUseFrameSize: aBoolean
- 	useFrameSize := aBoolean!

Item was removed:
- ----- Method: WebCamMorph>>setWebCamIsOn: (in category 'e-toy - settings') -----
- setWebCamIsOn: aBoolean
- 	aBoolean ifTrue: [self on] ifFalse: [self off]
- !

Item was removed:
- ----- Method: WebCamMorph>>setWebCamOrientation: (in category 'e-toy - settings') -----
- setWebCamOrientation: aSymbol
- 
- 	((WebCamOrientation orientations) includes: aSymbol) ifFalse: [^ self].
- 	orientation := aSymbol.
- 			
- 
- !

Item was removed:
- ----- Method: WebCamMorph>>setWebCamResolution: (in category 'e-toy - settings') -----
- setWebCamResolution: aSymbol
- 	| wasOn |
- 	"Failing silently here is awful; but that's what the code did :-("
- 	(WebCamResolution resolutions includes: aSymbol) ifFalse: [^ self].
- 	resolution := aSymbol.
- 
- 	(wasOn := camIsOn) ifTrue: [self off].
- 	frameExtent := self class resolutionFor: aSymbol.
- 	displayForm ifNotNil:
- 		[displayForm := displayForm scaledToSize: frameExtent].
- 	self updateDisplay.
-      wasOn ifTrue: [self on]
- !

Item was removed:
- ----- Method: WebCamMorph>>showFPSToggleString (in category 'menu') -----
- showFPSToggleString
- 
- 	^ (showFPS ifTrue: ['<on>'] ifFalse: ['<off>']), 'show fps' translated
- 
- 	
- !

Item was removed:
- ----- Method: WebCamMorph>>step (in category 'stepping and presenter') -----
- step
- 	camIsOn ifFalse:[self stopStepping].
- 	self updateDisplay.
- 	
- 									!

Item was removed:
- ----- Method: WebCamMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 	"Answer the desired time between steps in milliseconds"
- 	^ captureDelayMs
- !

Item was removed:
- ----- Method: WebCamMorph>>toggleCameraOnOff (in category 'menu') -----
- toggleCameraOnOff
- 	camIsOn
- 			ifTrue:[self off]
- 			ifFalse:[self on]!

Item was removed:
- ----- Method: WebCamMorph>>toggleShowFPS (in category 'menu') -----
- toggleShowFPS
- 
- 	showFPS := showFPS not.
- !

Item was removed:
- ----- Method: WebCamMorph>>toggleUseFrameSize (in category 'menu') -----
- toggleUseFrameSize
- 
- 	useFrameSize := useFrameSize not.
- !

Item was removed:
- ----- Method: WebCamMorph>>updateDisplay (in category 'stepping and presenter') -----
- updateDisplay
- 	camIsOn ifTrue:[self nextFrame].
- 	self updateFPS.
- 	self changed.!

Item was removed:
- ----- Method: WebCamMorph>>updateFPS (in category 'stepping and presenter') -----
- updateFPS
- 
- 	| now mSecs |
- 	now := Time millisecondClockValue.
- 	mSecs := now - lastDisplayTime.
- 	(mSecs > 500 or: [mSecs < 0 "clock wrap-around"])
- 		ifTrue: [
- 			fps := (framesSinceLastDisplay * 1000) // mSecs.
- 			lastDisplayTime := now.
- 			framesSinceLastDisplay := 0].!

Item was removed:
- SymbolListType subclass: #WebCamOrientation
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'Etoys-Squeakland-MorphicExtras-WebCam'!

Item was removed:
- ----- Method: WebCamOrientation class>>initialize (in category 'as yet unclassified') -----
- initialize
- 	Vocabulary initialize.!

Item was removed:
- ----- Method: WebCamOrientation class>>orientations (in category 'as yet unclassified') -----
- orientations
- 	^ #( native natural )!

Item was removed:
- ----- Method: WebCamOrientation>>initialize (in category 'as yet unclassified') -----
- initialize
- 	super initialize.
- 	self vocabularyName: #WebCamOrientation.
- 	
- 	self symbols: self class orientations.!

Item was removed:
- ----- Method: WebCamOrientation>>representsAType (in category 'as yet unclassified') -----
- representsAType
- 	^true!

Item was removed:
- SymbolListType subclass: #WebCamResolution
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'Etoys-Squeakland-MorphicExtras-WebCam'!

Item was removed:
- ----- Method: WebCamResolution class>>initialize (in category 'as yet unclassified') -----
- initialize
- 	Vocabulary initialize.!

Item was removed:
- ----- Method: WebCamResolution class>>resolutions (in category 'as yet unclassified') -----
- resolutions
- 	^ #(#'low' #'medium' #'high' #'hd')
- !

Item was removed:
- ----- Method: WebCamResolution>>initialize (in category 'as yet unclassified') -----
- initialize
- 	super initialize.
- 	self vocabularyName: #WebCamResolution.
- 	
- 	self symbols: self class resolutions
- !

Item was removed:
- ----- Method: WebCamResolution>>representsAType (in category 'as yet unclassified') -----
- representsAType
- 	^true!



More information about the Squeak-dev mailing list