[squeak-dev] The Inbox: MorphicExtras-eem.322.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Jul 14 14:14:51 UTC 2022


A new version of MorphicExtras was added to project The Inbox:
http://source.squeak.org/inbox/MorphicExtras-eem.322.mcz

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

Name: MorphicExtras-eem.322
Author: eem
Time: 13 July 2022, 4:43:20.802912 pm
UUID: 69a2e55e-f910-4b9d-94c4-4823da5ed28b
Ancestors: MorphicExtras-eem.321

Much nicer display of the WebCamMorph when it is off; Transparent light grey rather than invisible.

=============== Diff against MorphicExtras-eem.321 ===============

Item was removed:
- SystemOrganization addCategory: #'MorphicExtras-AdditionalMorphs'!
- SystemOrganization addCategory: #'MorphicExtras-AdditionalSupport'!
- SystemOrganization addCategory: #'MorphicExtras-AdditionalWidgets'!
- SystemOrganization addCategory: #'MorphicExtras-Books'!
- SystemOrganization addCategory: #'MorphicExtras-Demo'!
- SystemOrganization addCategory: #'MorphicExtras-EToy-Download'!
- SystemOrganization addCategory: #'MorphicExtras-Exceptions'!
- SystemOrganization addCategory: #'MorphicExtras-Flaps'!
- SystemOrganization addCategory: #'MorphicExtras-GeeMail'!
- SystemOrganization addCategory: #'MorphicExtras-Leds'!
- SystemOrganization addCategory: #'MorphicExtras-Navigators'!
- SystemOrganization addCategory: #'MorphicExtras-Obsolete'!
- SystemOrganization addCategory: #'MorphicExtras-Palettes'!
- SystemOrganization addCategory: #'MorphicExtras-PartsBin'!
- SystemOrganization addCategory: #'MorphicExtras-Postscript Canvases'!
- SystemOrganization addCategory: #'MorphicExtras-Postscript Filters'!
- SystemOrganization addCategory: #'MorphicExtras-SoundInterface'!
- SystemOrganization addCategory: #'MorphicExtras-SqueakPage'!
- SystemOrganization addCategory: #'MorphicExtras-Support'!
- SystemOrganization addCategory: #'MorphicExtras-Text Support'!
- SystemOrganization addCategory: #'MorphicExtras-Undo'!
- SystemOrganization addCategory: #'MorphicExtras-WebCam'!
- SystemOrganization addCategory: #'MorphicExtras-Widgets'!

Item was removed:
- ----- Method: AIFFFileReader>>edit (in category '*MorphicExtras-Sound') -----
- edit
- 
- 	| ed |
- 	ed := WaveEditor new.
- 	ed data: channelData first.
- 	ed loopEnd: markers last last.
- 	ed loopLength: (markers last last - markers first last) + 1.
- 	ed openInWorld.
- !

Item was removed:
- RectangleMorph subclass: #AbstractMediaEventMorph
- 	instanceVariableNames: 'startTimeInScore endTimeInScore'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !AbstractMediaEventMorph commentStamp: '<historical>' prior: 0!
- An abstract representation of media events to be placed in a PianoRollScoreMorph (or others as they are developed)!

Item was removed:
- ----- Method: AbstractMediaEventMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: AbstractMediaEventMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color paleYellow!

Item was removed:
- ----- Method: AbstractMediaEventMorph>>endTime (in category 'accessing') -----
- endTime
- 
- 	^endTimeInScore ifNil: [startTimeInScore + 100]!

Item was removed:
- ----- Method: AbstractMediaEventMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self layoutPolicy: TableLayout new;
- 	  listDirection: #leftToRight;
- 	  wrapCentering: #topLeft;
- 	  hResizing: #shrinkWrap;
- 	  vResizing: #shrinkWrap;
- 	  layoutInset: 2;
- 	  rubberBandCells: true!

Item was removed:
- ----- Method: AbstractMediaEventMorph>>justDroppedIntoPianoRoll:event: (in category 'piano rolls') -----
- justDroppedIntoPianoRoll: pianoRoll event: evt
- 	
- 	| ambientEvent |
- 	startTimeInScore := pianoRoll timeForX: self left.
- 
- 	ambientEvent := AmbientEvent new 
- 		morph: self;
- 		time: startTimeInScore.
- 
- 	pianoRoll score addAmbientEvent: ambientEvent.
- 
- 	"self endTime > pianoRoll scorePlayer durationInTicks ifTrue:
- 		[pianoRoll scorePlayer updateDuration]"
- !

Item was removed:
- ----- Method: AbstractSound>>viewSamples (in category '*MorphicExtras-Sound') -----
- viewSamples
- 	"Open a WaveEditor on my samples."
- 
- 	WaveEditor openOn: self samples.
- !

Item was removed:
- ----- Method: AlignmentMorph class>>supplementaryPartsDescriptions (in category '*MorphicExtras-parts bin') -----
- supplementaryPartsDescriptions
- 	"Extra items for parts bins"
- 
- 	^ {DescriptionForPartsBin
- 		formalName: 'Column' translatedNoop
- 		categoryList: #()
- 		documentation: 'An object that presents the things within it in a column' translatedNoop
- 		globalReceiverSymbol: #AlignmentMorph
- 		nativitySelector: #columnPrototype.
- 	DescriptionForPartsBin
- 		formalName: 'Row' translatedNoop
- 		categoryList: #()
- 		documentation: 'An object that presents the things within it in a row' translatedNoop
- 		globalReceiverSymbol: #AlignmentMorph
- 		nativitySelector: #rowPrototype}!

Item was removed:
- ----- Method: AlignmentMorph>>basicInitialize (in category '*MorphicExtras-initialization') -----
- basicInitialize
- 	"Do basic generic initialization of the instance variables"
- 	super basicInitialize.
- 	""
- 	self layoutPolicy: TableLayout new;
- 	  listDirection: #leftToRight;
- 	  wrapCentering: #topLeft;
- 	  hResizing: #spaceFill;
- 	  vResizing: #spaceFill;
- 	  layoutInset: 2;
- 	  rubberBandCells: true!

Item was removed:
- AlignmentMorph subclass: #AlignmentMorphBob1
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalSupport'!
- 
- !AlignmentMorphBob1 commentStamp: 'sm 8/12/2009 22:34' prior: 0!
- A quick and easy way to space things vertically in absolute or proportional amounts.!

Item was removed:
- ----- Method: AlignmentMorphBob1>>acceptDroppingMorph:event: (in category 'dropping/grabbing') -----
- acceptDroppingMorph: aMorph event: evt
- 
- 	| handlerForDrops |
- 
- 	handlerForDrops := self valueOfProperty: #handlerForDrops ifAbsent: [
- 		^super acceptDroppingMorph: aMorph event: evt
- 	].
- 	(handlerForDrops acceptDroppingMorph: aMorph event: evt inMorph: self) ifFalse: [
- 		aMorph rejectDropMorphEvent: evt.		"send it back where it came from"
- 	].!

Item was removed:
- ----- Method: AlignmentMorphBob1>>addAColumn: (in category 'ui construction') -----
- addAColumn: aCollectionOfMorphs
- 
- 	| col |
- 	col := self inAColumn: aCollectionOfMorphs.
- 	self addMorphBack: col.
- 	^col!

Item was removed:
- ----- Method: AlignmentMorphBob1>>addARow: (in category 'ui construction') -----
- addARow: aCollectionOfMorphs
- 
- 	| row |
- 	row := self inARow: aCollectionOfMorphs.
- 	self addMorphBack: row.
- 	^row!

Item was removed:
- ----- Method: AlignmentMorphBob1>>addARowCentered: (in category 'ui construction') -----
- addARowCentered: aCollectionOfMorphs
- 
- 	^(self addARow: aCollectionOfMorphs)
- 		hResizing: #shrinkWrap;
- 		wrapCentering: #center;
- 		cellPositioning: #leftCenter!

Item was removed:
- ----- Method: AlignmentMorphBob1>>addARowCentered:cellInset: (in category 'ui construction') -----
- addARowCentered: aCollectionOfMorphs cellInset: cellInsetInteger
- 
- 	^(self addARow: aCollectionOfMorphs)
- 		hResizing: #shrinkWrap;
- 		wrapCentering: #center;
- 		cellPositioning: #leftCenter;
- 		cellInset: cellInsetInteger!

Item was removed:
- ----- Method: AlignmentMorphBob1>>fancyText:font:color: (in category 'ui construction') -----
- fancyText: aString font: aFont color: aColor 
- 	| answer tm col |
- 	col := Preferences menuAppearance3d
- 				ifTrue: [aColor]
- 				ifFalse: [aColor negated].
- 	tm := TextMorph new.
- 	tm beAllFont: aFont;
- 		 color: col;
- 		 contents: aString.
- 	answer := self inAColumn: {tm}.
- 	Preferences menuAppearance3d
- 		ifTrue: [""
- 			tm addDropShadow.
- 			tm shadowPoint: 5 @ 5 + tm bounds center].
- 	tm lock.
- 	^ answer!

Item was removed:
- ----- Method: AlignmentMorphBob1>>fullDrawOn: (in category 'drawing') -----
- fullDrawOn: aCanvas
- 
- 	| mask |
- 	(aCanvas isVisible: self fullBounds) ifFalse:[^self].
- 	super fullDrawOn: aCanvas.
- 	mask := self valueOfProperty: #disabledMaskColor ifAbsent: [^self].
- 	aCanvas fillRectangle: bounds color: mask.
- !

Item was removed:
- ----- Method: AlignmentMorphBob1>>inAColumn: (in category 'ui construction') -----
- inAColumn: aCollectionOfMorphs
- 
- 	| col |
- 	col := AlignmentMorph newColumn
- 		color: Color transparent;
- 		vResizing: #shrinkWrap;
- 		layoutInset: 1;
- 		wrapCentering: #center;
- 		cellPositioning: #topCenter.
- 	aCollectionOfMorphs do: [ :each | col addMorphBack: each].
- 	^col!

Item was removed:
- ----- Method: AlignmentMorphBob1>>inARightColumn: (in category 'ui construction') -----
- inARightColumn: aCollectionOfMorphs 
- 	| col |
- 	col := AlignmentMorph newColumn color: Color transparent;
- 				 vResizing: #shrinkWrap;
- 				 layoutInset: 1;
- 				 wrapCentering: #bottomRight;
- 				 cellPositioning: #topCenter.
- 	aCollectionOfMorphs
- 		do: [:each | col addMorphBack: each].
- 	^ col!

Item was removed:
- ----- Method: AlignmentMorphBob1>>inARow: (in category 'ui construction') -----
- inARow: aCollectionOfMorphs 
- 	| row |
- 	row := AlignmentMorph newRow color: Color transparent;
- 				 vResizing: #shrinkWrap;
- 				 layoutInset: 2;
- 				 wrapCentering: #center;
- 				 cellPositioning: #leftCenter.
- 	aCollectionOfMorphs
- 		do: [:each | each ifNotNil: [row addMorphBack: each]].
- 	^ row!

Item was removed:
- ----- Method: AlignmentMorphBob1>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	self listDirection: #topToBottom.
- 	self layoutInset: 0.
- 	self hResizing: #rigid. "... this is very unlikely..."
- 	self vResizing: #rigid!

Item was removed:
- ----- Method: AlignmentMorphBob1>>simpleToggleButtonFor:attribute:help: (in category 'ui construction') -----
- simpleToggleButtonFor: target attribute: attribute help: helpText
- 
- 	^(Smalltalk at: #EtoyUpdatingThreePhaseButtonMorph ifAbsent:[^Morph new])
- 		checkBox
- 		target: target;
- 		actionSelector: #toggleChoice:;
- 		arguments: {attribute};
- 		getSelector: #getChoice:;
- 		setBalloonText: helpText;
- 		step
- 
- !

Item was removed:
- ----- Method: AlignmentMorphBob1>>wantsDroppedMorph:event: (in category 'dropping/grabbing') -----
- wantsDroppedMorph: aMorph event: evt
- 
- 	| handlerForDrops |
- 
- 	handlerForDrops := self valueOfProperty: #handlerForDrops ifAbsent: [
- 		^super wantsDroppedMorph: aMorph event: evt
- 	].
- 	^handlerForDrops wantsDroppedMorph: aMorph event: evt inMorph: self!

Item was removed:
- EllipseMorph subclass: #AtomMorph
- 	instanceVariableNames: 'velocity'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !AtomMorph commentStamp: 'tbn 11/25/2004 09:06' prior: 0!
- AtomMorph represents an atom used in the simulation of
- an ideal gas. It's container is typically a BouncingAtomsMorph.
- 
- Try:
- 
- 	BouncingAtomsMorph  new openInWorld
- 
- to open the gas simulation or:
- 
- 	AtomMorph example
- 
- to open an instance in the current world!

Item was removed:
- ----- Method: AtomMorph class>>example (in category 'examples') -----
- example
- 	"
- 	AtomMorph example
- 	"
- 	|a world|
- 	world := Project current world.
- 	a := AtomMorph new openInWorld. 
- 	a color: Color random.
-  	[1000 timesRepeat:  [a bounceIn: world bounds.  (Delay forMilliseconds: 50) wait]. 
- 	 a delete] fork.!

Item was removed:
- ----- Method: AtomMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 	"Not to be instantiated from the menu"
- 	^ false!

Item was removed:
- ----- Method: AtomMorph>>bounceIn: (in category 'private') -----
- bounceIn: aRect
- 	"Move this atom one step along its velocity vector and make it bounce if it goes outside the given rectangle. Return true if it is bounced."
- 
- 	| p vx vy px py bounced |
- 	p := self position.
- 	vx := velocity x.		vy := velocity y.
- 	px := p x + vx.		py := p y + vy.
- 	bounced := false.
- 	px > aRect right ifTrue: [
- 		px := aRect right - (px - aRect right).
- 		vx := velocity x negated.
- 		bounced := true].
- 	py > aRect bottom ifTrue: [
- 		py :=  aRect bottom - (py - aRect bottom).
- 		vy := velocity y negated.
- 		bounced := true].
- 	px < aRect left ifTrue: [
- 		px := aRect left - (px - aRect left).
- 		vx := velocity x negated.
- 		bounced := true].
- 	py < aRect top ifTrue: [
- 		py :=  aRect top - (py - aRect top).
- 		vy := velocity y negated.
- 		bounced := true].
- 	self position: px @ py.
- 	bounced ifTrue: [self velocity: vx @ vy].
- 	^ bounced
- !

Item was removed:
- ----- Method: AtomMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- "answer the default border width for the receiver"
- 	^ 0!

Item was removed:
- ----- Method: AtomMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color blue!

Item was removed:
- ----- Method: AtomMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	"Note: Set 'drawAsRect' to true to make the atoms draw faster. When testing the speed of other aspects of Morphic, such as its damage handling efficiency for large numbers of atoms, it is useful to make drawing faster."
- 
- 	| drawAsRect |
- 	drawAsRect := false.  "rectangles are faster to draw"
- 	drawAsRect
- 		ifTrue: [aCanvas fillRectangle: self bounds color: color]
- 		ifFalse: [super drawOn: aCanvas].!

Item was removed:
- ----- Method: AtomMorph>>infected (in category 'accessing') -----
- infected
- 
- 	^ color = Color red!

Item was removed:
- ----- Method: AtomMorph>>infected: (in category 'accessing') -----
- infected: aBoolean
- 
- 	aBoolean
- 		ifTrue: [self color: Color red]
- 		ifFalse: [self color: Color blue].!

Item was removed:
- ----- Method: AtomMorph>>initialize (in category 'initialization') -----
- initialize
- 	"Make a new atom with a random position and velocity."
- 	super initialize.
- ""
- 	self extent: 8 @ 7.
- 	
- 	self
- 		randomPositionIn: (0 @ 0 corner: 300 @ 300)
- 		maxVelocity: 10!

Item was removed:
- ----- Method: AtomMorph>>randomPositionIn:maxVelocity: (in category 'initialization') -----
- randomPositionIn: aRectangle maxVelocity: maxVelocity
- 	"Give this atom a random position and velocity."
- 
- 	| origin extent |
- 	origin := aRectangle origin.
- 	extent := (aRectangle extent - self bounds extent) rounded.
- 	self position:
- 		(origin x + extent x atRandom) @
- 		(origin y + extent y atRandom).
- 	velocity :=
- 		(maxVelocity - (2 * maxVelocity) atRandom) @
- 		(maxVelocity - (2 * maxVelocity) atRandom).
- !

Item was removed:
- ----- Method: AtomMorph>>velocity (in category 'accessing') -----
- velocity
- 
- 	^ velocity!

Item was removed:
- ----- Method: AtomMorph>>velocity: (in category 'accessing') -----
- velocity: newVelocity
- 
- 	velocity := newVelocity.!

Item was removed:
- TransformationMorph subclass: #BOBTransformationMorph
- 	instanceVariableNames: 'worldBoundsToShow useRegularWarpBlt'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalSupport'!

Item was removed:
- ----- Method: BOBTransformationMorph>>adjustAfter: (in category 'private') -----
- adjustAfter: changeBlock 
- 	"Cause this morph to remain cetered where it was before, and
- 	choose appropriate smoothing, after a change of scale or rotation."
- 	| |
- 
- 		"oldRefPos := self referencePosition."
- 	changeBlock value.
- 	self chooseSmoothing.
- 		"self penUpWhile: [self position: self position + (oldRefPos - self referencePosition)]."
- 	self layoutChanged.
- 	owner ifNotNil: [owner invalidRect: bounds]
- !

Item was removed:
- ----- Method: BOBTransformationMorph>>changeWorldBoundsToShow: (in category 'geometry') -----
- changeWorldBoundsToShow: aRectangle
- 
- 	aRectangle area = 0 ifTrue: [^self].
- 	worldBoundsToShow := aRectangle.
- 	owner myWorldChanged.!

Item was removed:
- ----- Method: BOBTransformationMorph>>drawSubmorphsOn: (in category 'drawing') -----
- drawSubmorphsOn: aCanvas
- 
- 	| t | 
- 	t := [
- 		self drawSubmorphsOnREAL: aCanvas
- 	] timeToRun.
- "Q1 at: 3 put: t."
- !

Item was removed:
- ----- Method: BOBTransformationMorph>>drawSubmorphsOnREAL: (in category 'drawing') -----
- drawSubmorphsOnREAL: aCanvas 
- 
- 	| newClip |
- 
- 	(self innerBounds intersects: aCanvas clipRect) ifFalse: [^self].
- 	newClip := ((self innerBounds intersect: aCanvas clipRect) expandBy: 1) truncated.
- 	useRegularWarpBlt == true ifTrue: [
- 		transform scale asFloat = 1.0 ifFalse: [
- 			newClip := self innerBounds.		"avoids gribblies"
- 		].
- 		^aCanvas 
- 			transformBy: transform
- 			clippingTo: newClip
- 			during: [:myCanvas |
- 				submorphs reverseDo:[:m | myCanvas fullDrawMorph: m]
- 			]
- 			smoothing: smoothing
- 	].
- 	aCanvas 
- 		transform2By: transform		"#transformBy: for pure WarpBlt"
- 		clippingTo: newClip
- 		during: [:myCanvas |
- 			submorphs reverseDo:[:m | myCanvas fullDrawMorph: m]
- 		]
- 		smoothing: smoothing
- !

Item was removed:
- ----- Method: BOBTransformationMorph>>extent: (in category 'geometry') -----
- extent: aPoint
- 
- 	| newExtent |
- 
- 	newExtent := aPoint truncated.
- 	bounds extent = newExtent ifTrue: [^self].
- 	bounds := bounds topLeft extent: newExtent.
- 	self recomputeExtent.
- 
- !

Item was removed:
- ----- Method: BOBTransformationMorph>>extentFromParent: (in category 'geometry') -----
- extentFromParent: aPoint
- 
- 	| newExtent |
- 
- 	submorphs isEmpty ifTrue: [^self extent: aPoint].
- 	newExtent := aPoint truncated.
- 	bounds := bounds topLeft extent: newExtent.
- 	newExtent := self recomputeExtent.
- 	newExtent ifNil: [^self].
- 	bounds := bounds topLeft extent: newExtent.
- 
- !

Item was removed:
- ----- Method: BOBTransformationMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 	"use the version from Morph"
- 
- 	| myGuy |
- 	fullBounds := nil.
- 	owner ifNotNil: [owner layoutChanged].
- 	submorphs notEmpty 
- 		ifTrue: 
- 			[(myGuy := self firstSubmorph) isWorldMorph 
- 				ifFalse: 
- 					[worldBoundsToShow = myGuy bounds 
- 						ifFalse: [self changeWorldBoundsToShow: (worldBoundsToShow := myGuy bounds)]]
- 
- 			"submorphs do: [:m | m ownerChanged]"	"<< I don't see any reason for this"]!

Item was removed:
- ----- Method: BOBTransformationMorph>>recomputeExtent (in category 'private') -----
- recomputeExtent
- 
- 	| scalePt newScale theGreenThingie greenIBE myNewExtent |
- 
- 	submorphs isEmpty ifTrue: [^self extent].
- 	worldBoundsToShow ifNil: [worldBoundsToShow := self firstSubmorph bounds].
- 	worldBoundsToShow area = 0 ifTrue: [^self extent].
- 	scalePt := owner innerBounds extent / worldBoundsToShow extent.
- 	newScale := scalePt x min: scalePt y.
- 	theGreenThingie := owner.
- 	greenIBE := theGreenThingie innerBounds extent.
- 	myNewExtent := (greenIBE min: worldBoundsToShow extent * newScale) truncated.
- 	self
- 		scale: newScale;
- 		offset: worldBoundsToShow origin * newScale.
- 	smoothing := (newScale < 1.0) ifTrue: [2] ifFalse: [1].
- 	^myNewExtent!

Item was removed:
- ----- Method: BOBTransformationMorph>>useRegularWarpBlt: (in category 'accessing') -----
- useRegularWarpBlt: aBoolean
- 
- 	useRegularWarpBlt := aBoolean!

Item was removed:
- Morph subclass: #BackgroundMorph
- 	instanceVariableNames: 'image offset delta running'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !BackgroundMorph commentStamp: '<historical>' prior: 0!
- This morph incorporates tiling and regular motion with the intent of supporting, eg, panning of endless (toroidal) backgrounds.
- 
- The idea is that embedded morphs get displayed at a moving offset relative to my position.  Moreover this display is tiled according to the bounding box of the submorphs (subBounds), as much as necesary to fill the rest of my bounds.!

Item was removed:
- ----- Method: BackgroundMorph class>>test (in category 'test') -----
- test
- 	"BackgroundMorph test"
- 	^(BackgroundMorph new addMorph: (ImageMorph new image: Form fromUser))openInWorld.!

Item was removed:
- ----- Method: BackgroundMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	running
- 		ifTrue: [aCustomMenu add: 'stop' translated action: #stopRunning]
- 		ifFalse: [aCustomMenu add: 'start' translated action: #startRunning]!

Item was removed:
- ----- Method: BackgroundMorph>>delta (in category 'accessing') -----
- delta
- 	^delta!

Item was removed:
- ----- Method: BackgroundMorph>>delta: (in category 'accessing') -----
- delta: aPoint
- 
- 	delta := aPoint.!

Item was removed:
- ----- Method: BackgroundMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	"The tiling is solely determined by bounds, subBounds and offset.
- 	The extent of display is determined by bounds and the clipRect of the canvas."
- 	| start d subBnds |
- 	submorphs isEmpty ifTrue: [^ super drawOn: aCanvas].
- 	subBnds := self subBounds.
- 	running ifFalse:
- 		[super drawOn: aCanvas.
- 		^ aCanvas fillRectangle: subBnds color: Color lightBlue].
- 	start := subBnds topLeft + offset - bounds topLeft - (1 at 1) \\ subBnds extent - subBnds extent + (1 at 1).
- 	d := subBnds topLeft - bounds topLeft.
- "Sensor redButtonPressed ifTrue: [self halt]."
- 	start x to: bounds width - 1 by: subBnds width do:
- 		[:x |
- 		start y to: bounds height - 1 by: subBnds height do:
- 			[:y | aCanvas translateBy: (x at y) - d clippingTo: bounds
- 				during:[:tileCanvas| self drawSubmorphsOn: tileCanvas]]].!

Item was removed:
- ----- Method: BackgroundMorph>>fullBounds (in category 'layout') -----
- fullBounds
- 	^ self bounds!

Item was removed:
- ----- Method: BackgroundMorph>>fullDrawOn: (in category 'drawing') -----
- fullDrawOn: aCanvas
- 	(aCanvas isVisible: self fullBounds) ifFalse:[^self].
- 	running ifFalse: [
- 		^aCanvas clipBy: (bounds translateBy: aCanvas origin)
- 				during:[:clippedCanvas| super fullDrawOn: clippedCanvas]].
- 	(aCanvas isVisible: self bounds) ifTrue:[aCanvas drawMorph: self].
- !

Item was removed:
- ----- Method: BackgroundMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- ""
- 	offset := 0 @ 0.
- 	delta := 1 @ 0.
- 	running := true!

Item was removed:
- ----- Method: BackgroundMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 	"Do nothing, since I clip my submorphs"!

Item was removed:
- ----- Method: BackgroundMorph>>offset (in category 'accessing') -----
- offset
- 	^offset!

Item was removed:
- ----- Method: BackgroundMorph>>offset: (in category 'accessing') -----
- offset: aPoint
- 	offset := aPoint!

Item was removed:
- ----- Method: BackgroundMorph>>slideBy: (in category 'accessing') -----
- slideBy: inc
- 	submorphs isEmpty ifTrue: [^ self].
- 	offset := offset + inc \\ self subBounds extent.
- 	self changed!

Item was removed:
- ----- Method: BackgroundMorph>>startRunning (in category 'accessing') -----
- startRunning
- 	running := true.
- 	self changed!

Item was removed:
- ----- Method: BackgroundMorph>>step (in category 'stepping and presenter') -----
- step
- 	
- 	running ifTrue: [self slideBy: delta]!

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

Item was removed:
- ----- Method: BackgroundMorph>>stopRunning (in category 'accessing') -----
- stopRunning
- 	running := false.
- 	self changed!

Item was removed:
- ----- Method: BackgroundMorph>>subBounds (in category 'accessing') -----
- subBounds
- 	"calculate the submorph bounds"
- 
- 	| subBounds |
- 	subBounds := (submorphs ifEmpty: [^nil]) anyOne fullBounds copy.
- 	self submorphsDo: 	[:m | subBounds swallow: m fullBounds].
- 	^subBounds!

Item was removed:
- ----- Method: Bag>>asMorph (in category '*MorphicExtras-converting') -----
- asMorph
- 	"
- 	(Bag new in: [:bag | Smalltalk allClasses do: [:cls | bag add: cls name first]. bag])
- 		asMorph openInHand.
- 	"
- 	^ HistogramMorph on: self!

Item was removed:
- ----- Method: BalloonMorph>>isBalloonHelp (in category '*MorphicExtras-classification') -----
- isBalloonHelp
- 	^true!

Item was removed:
- EllipseMorph subclass: #BannerMorph
- 	instanceVariableNames: 'header contents'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !BannerMorph commentStamp: 'ct 9/7/2019 10:43' prior: 0!
- I display a header and a contents text, arranged in an EllipseMorph in a flamboyant way. I use a ScreeningMorph and a BackgroundMorph to hinder the user to avert his gaze from me.!

Item was removed:
- ----- Method: BannerMorph class>>example (in category 'examples') -----
- example
- 	"BannerMorph example openInWorld"
- 
- 	^ self
- 		header: 'Yes, <u>you</u> are ...' withCRs asTextFromHtml
- 		contents: 'Live in Morphic' asUppercase asText!

Item was removed:
- ----- Method: BannerMorph class>>header:contents: (in category 'instance creation') -----
- header: aStringOrText contents: anotherStringOrText
- 
- 	^ self basicNew
- 		header: aStringOrText contents: anotherStringOrText;
- 		initialize;
- 		yourself!

Item was removed:
- ----- Method: BannerMorph>>contents (in category 'accessing') -----
- contents
- 
- 	^ contents!

Item was removed:
- ----- Method: BannerMorph>>createBackground (in category 'initialize-release') -----
- createBackground
- 
- 	| fillMorph fillStyle |
- 	fillStyle := GradientFillStyle colors:
- 		({Color red. Color green. Color blue}
- 			in: [:colors | colors, colors reverse]).
- 	fillStyle
- 		origin: 0 @ 0;
- 		direction: 150 @ 50.
- 	fillMorph := (Morph new
- 		fillStyle: fillStyle;
- 		yourself).
- 	^ BackgroundMorph new
- 		extent: 300 @ 130;
- 		addMorph: fillMorph;
- 		yourself!

Item was removed:
- ----- Method: BannerMorph>>createContents (in category 'initialize-release') -----
- createContents
- 
- 	| text |
- 	text := self contents asText
- 		addAttribute: TextEmphasis bold;
- 		addAttribute: (TextFontReference toFont:
- 			(StrikeFont familyName: #ComicPlain size: 39));
- 		asMorph.
- 	text readOnly: true; flag: #ct. "We're no *that* life, yet :("
- 	^ ScreeningMorph new
- 		addMorph: (self createBackground
- 			extent: text extent;
- 			yourself);
- 		addMorph: text;
- 		showScreened;
- 		cellPositioning: #center;
- 		yourself!

Item was removed:
- ----- Method: BannerMorph>>createHeader (in category 'initialize-release') -----
- createHeader
- 
- 	| text |
- 	text := (self header copyWithFirst: Character cr) asText
- 		addAttribute: TextEmphasis bold;
- 		addAttribute: (TextFontReference toFont:
- 			(StrikeFont familyName: #Accula size: 29));
- 		yourself.
- 	 ^ text asMorph
- 		centered;
- 		fillsOwner: true;
- 		yourself!

Item was removed:
- ----- Method: BannerMorph>>header (in category 'accessing') -----
- header
- 
- 	^ header!

Item was removed:
- ----- Method: BannerMorph>>header:contents: (in category 'accessing') -----
- header: aStringOrText contents: anotherStringOrText
- 
- 	header := aStringOrText.
- 	contents := anotherStringOrText.!

Item was removed:
- ----- Method: BannerMorph>>initialize (in category 'initialize-release') -----
- initialize
- 
- 	super initialize.
- 	self extent: 300 @ 200.
- 	self
- 		changeProportionalLayout;
- 		addMorph: (Morph new
- 			color: Color transparent;
- 			changeTableLayout;
- 			listCentering: #center; wrapCentering: #center;
- 			addMorph: self createContents;
- 			yourself)
- 				fullFrame: LayoutFrame fullFrame;
- 		addMorph: self createHeader.!

Item was removed:
- ----- Method: BannerMorph>>initializeToStandAlone (in category 'initialize-release') -----
- initializeToStandAlone
- 
- 	self header: 'Introducing' contents: self class name.
- 	super initializeToStandAlone.!

Item was removed:
- RotaryDialMorph subclass: #BarometerMorph
- 	instanceVariableNames: 'priorPressureIndicator'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !BarometerMorph commentStamp: 'tpr 4/13/2017 16:48' prior: 0!
- I am a model of a moderately visually ornate barometer, complete with curly tailed needle and the adjustable 'last pressure' needle used to help display the recent changes in pressure. In this case a d-click makes the 'last pressure' needle move to the current pressure position.
- 
- !

Item was removed:
- ----- Method: BarometerMorph>>buildDial (in category 'dial drawing') -----
- buildDial
- 	"start by making a damn big Form, twice the size we want to end up with"
- 	|outerRadius destForm canvas tickLabel tickLength beginAngle endAngle tickAngle tickLabelSize maxTicks |
- 	outerRadius := self height  - 1.
- 	destForm := Form extent: self extent * 2 depth: 32.
- 	(canvas := destForm getCanvas) fillOval: (0 at 0 extent: self extent * 2) color: Color white.
- 	"outer ring"
- 	self drawArcAt: destForm center radius: outerRadius thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	"inner ring"
- 	self drawArcAt: destForm center radius: outerRadius * 0.97 thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	
- 	"outer scale for inches of HG"
- 	beginAngle := startAngle -360. "needs cleaning up about this"
- 	endAngle := stopAngle.
- 	
- 	self drawArcAt: destForm center radius: outerRadius * 0.8 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	self drawArcAt: destForm center radius: outerRadius * 0.73 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	"since we're going from 28in. to 31in. of Hg for the outer scale and want alternating full and half ticks as we go round we need 31-28 * 10 * 2 -> 60 ticks"
- 	maxTicks := 31 - 28 * 10 * 2.
- 	tickAngle := endAngle - beginAngle / maxTicks.
- 	0 to: maxTicks do: [:tick|
- 		tickLabel := nil.
- 		tickLength := {outerRadius * 0.07. outerRadius * 0.14} atWrap: tick+1.
- 		tick \\ 20 = 0 ifTrue: [
- 			tickLabel := #( '28' '29' '30' '31') at: tick // 20 + 1.
- 			tickLabelSize := 24.
- 		] ifFalse: [
- 			tick \\ 2 = 0 ifTrue: [
- 				tickLabel :=  (tick // 2 \\ 10) asString.
- 				tickLabelSize := 18.
- 			].
- 		].
- 		self drawTickRadius: outerRadius * 0.73 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick * tickAngle) onCanvas: canvas.
- 		self tickLabel: tickLabel fontSize: tickLabelSize color: Color black centeredAt: dialCenter radius: (outerRadius * 0.73) + tickLength angle: beginAngle + (tick * tickAngle) onCanvas: canvas.
- 	].
- 
- 	self tickInnerLabel: 'mB' fontSize: 36 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.73) angle: 180 onCanvas: canvas.
- 
- 	"inner scale for mB"
- 	beginAngle := startAngle -360. "needs cleaning up about this"
- 	endAngle := stopAngle.
- 	
- 	self drawArcAt: destForm center radius: outerRadius * 0.71 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	self drawArcAt: destForm center radius: outerRadius * 0.63 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	"since we're going from 948mB to 1050 for this inner scale and want thick ticks at each 10mB interval with narrow ones elsewhere we have (1050 - 948) total ticks "
- 	maxTicks := stopValue - startValue.
- 	tickAngle := endAngle - beginAngle / maxTicks.
- 	tickLength := outerRadius * 0.07.
- 	startValue to: stopValue do: [ :tick ||tickThickness|
- 		tickLabel := nil.
- 		tick \\ 10 = 0 ifTrue: [
- 			tickLabelSize := 20.
- 			tickThickness := 3.
- 			tickLabel :=  tick asString.
- 		] ifFalse: [
- 			tickThickness := 2.
- 		].
- 		self drawTickRadius: outerRadius * 0.63 length: tickLength thickness: tickThickness color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		self tickInnerLabel: tickLabel fontSize: tickLabelSize color: Color black centeredAt: dialCenter radius: (outerRadius * 0.63) angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		tickLabel := nil.
- 		tick = 970 ifTrue:[tickLabel := 'Rain'].
- 		tick = 1000 ifTrue:[tickLabel := 'Change'].
- 		tick = 1030 ifTrue:[tickLabel := 'Fair'].
- 		self tickInnerLabel: tickLabel fontSize: 24 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.5) angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		
- 	].
- 	self tickLabel: '"Hg'  fontSize: 36 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.73) angle: 180 onCanvas: canvas.
- 	
- 	self addMorph: (destForm magnify: destForm boundingBox by: 0.5 smoothing: 2) asMorph!

Item was removed:
- ----- Method: BarometerMorph>>doubleClick: (in category 'initialize-release') -----
- doubleClick: evt
- 	"the user has just tapped on the glass of the barometer, so move the priorPressureIndicator to match the current value"
- 	priorPressureIndicator rotationDegrees: needleMorph rotationDegrees!

Item was removed:
- ----- Method: BarometerMorph>>handlesMouseDown: (in category 'initialize-release') -----
- handlesMouseDown: evt
- 	^true!

Item was removed:
- ----- Method: BarometerMorph>>initialize (in category 'initialize-release') -----
- initialize
- 	"assemble a nice barometer morph. The background is an ImageMorph with scale/dial drawn with code adapted from a generous donation of time and effort by Bob Arning; similarly for the needle"
- 	| pointerMorph |
- 
- 	super initialize.
- 	"set up as a barometer type display; running clockwise with increasing values.
- 	A decent range for a barometer is 950mB to 1050mB; it covers most plausible weather and matches decently with an additional inches-of-Hg scale going from 28 to 31.
- 	28in. -> 948mB and 31in. -> 1050 (to enough accuracy for a screen based widget) so we need a small tweak at the lower end of the dial. If we aim initially for 150deg each side of north we have 3deg per milliBar; to accomodate the extra 2mB we can add 6deg at the low end, which makes 1000mB sit nicely at due north.
- 	So we will use angles of -156 to 150 and values of 948 to 1050 as our limits."
- 
- 	self startAngle: -156 stopAngle: 150;
- 			startValue: 948 stopValue: 1050.
- 	self extent: self initialExtent; color: Color transparent; borderWidth: 0.
- 	dialCenter := self center.
- 
- 	"build the dial background. This is amazingly complex to think about programmatically; this example is fairly hard-coded by hand but somebody out there almost certainly has ideas about parameterizing this to amke a nice general utility"
- 	self buildDial.
- 
- 	"build our fancy needle as an ImageMorph, set the position to horizontal centre and about 2/3 down so that it rotates about that point when inside the TransformationMorph"
- 	pointerMorph := self fancyNeedleOfLength: (self height * 0.65) rounded.
-  	pointerMorph 
- 		position: pointerMorph extent * ( -0.5@ -0.65);
- 		rotationCenter: 0.5 @ 0.65.
- 
- 	"we keep track of the TransformationMorph since that is what we have to rotate as the incoming pressure values change"
- 	needleMorph := TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: needleMorph.
- 	
- 	"Add the simpler needle used to indicate the prior 'remembered' reading; we will make a click update it to the current value"
- 	pointerMorph := self simpleNeedleOfLength: (self height * 0.35) rounded color: (Color r: 16rFF g: 16rD7 b: 16r0 range: 512).
-  	pointerMorph
- 		position: pointerMorph extent * ( -0.5@ -1);
- 		rotationCenter: 0.5 @ 1.
- 	priorPressureIndicator :=  TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: priorPressureIndicator.
- 	
- 	"add a central near-to-gold colored dot. Because we just do."
- 	self addMorph: (CircleMorph new extent: 20 at 20; color: (Color r: 16rFF g: 16rD7 b: 16r0 range: 256); center: dialCenter)
- 	!

Item was removed:
- ----- Method: BarometerMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt 
- 	"Do nothing upon mouse-down except inform the hand to watch for a  
- 	double-click; wait until an ensuing click:, doubleClick:, or drag:  
- 	message gets dispatched"
- 	evt hand
- 		waitForClicksOrDrag: self
- 		event: evt
- 		selectors: #( #click: #doubleClick: #doubleClickTimeout: #startDrag:)
- 		threshold: HandMorph dragThreshold!

Item was removed:
- RectangleMorph subclass: #BasicButton
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !BasicButton commentStamp: '<historical>' prior: 0!
- A minimalist button-like object intended for use with the tile-scripting system.!

Item was removed:
- ----- Method: BasicButton class>>defaultNameStemForInstances (in category 'printing') -----
- defaultNameStemForInstances
- 	^ 'button' translatedNoop!

Item was removed:
- ----- Method: BasicButton>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'change label...' translated action: #setLabel!

Item was removed:
- ----- Method: BasicButton>>defaultBorderColor (in category 'initialization') -----
- defaultBorderColor
- 	"answer the default border color/fill style for the receiver"
- 	^ Color yellow darker!

Item was removed:
- ----- Method: BasicButton>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: BasicButton>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color yellow!

Item was removed:
- ----- Method: BasicButton>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self label: 'Button'; useRoundedCorners!

Item was removed:
- ----- Method: BasicButton>>label (in category 'label') -----
- label
- 	| s |
- 	s := ''.
- 	self allMorphsDo: [:m | (m isKindOf: StringMorph) ifTrue: [s := m contents]].
- 	^ s!

Item was removed:
- ----- Method: BasicButton>>label: (in category 'label') -----
- label: aString
- 
- 	| oldLabel m |
- 	(oldLabel := self findA: StringMorph)
- 		ifNotNil: [oldLabel delete].
- 	m := StringMorph contents: aString font: TextStyle defaultFont.
- 	self extent: m extent + (self borderWidth + 6).
- 	m position: self center - (m extent // 2).
- 	self addMorph: m.
- 	m lock!

Item was removed:
- ----- Method: BasicButton>>label:font: (in category 'label') -----
- label: aString font: aFontOrNil
- 
- 	| oldLabel m aFont |
- 	(oldLabel := self findA: StringMorph)
- 		ifNotNil: [oldLabel delete].
- 	aFont := aFontOrNil ifNil: [Preferences standardButtonFont].
- 	m := StringMorph contents: aString font: aFont.
- 	self extent: (m width + 6) @ (m height + 6).
- 	m position: self center - (m extent // 2).
- 	self addMorph: m.
- 	m lock
- !

Item was removed:
- ----- Method: BasicButton>>setLabel (in category 'label') -----
- setLabel
- 	| newLabel |
- 	newLabel := UIManager default
- 		request:
- 'Enter a new label for this button'
- 		initialAnswer: self label.
- 	newLabel isEmpty ifFalse: [self label: newLabel font: nil].
- !

Item was removed:
- ----- Method: BitBlt class>>previewAllBitBltRules (in category '*MorphicExtras') -----
- previewAllBitBltRules
- 
- 	(self previewBitBltRules: (0 to: 41)
- 		on: ToolIcons flag
- 		and: ToolIcons collection
- 		fallback: ToolIcons exception
- 		scaledTo: 32) openInHand.!

Item was removed:
- ----- Method: BitBlt class>>previewAllBitBltRulesWithAlpha (in category '*MorphicExtras') -----
- previewAllBitBltRulesWithAlpha
- 
- 	(self previewBitBltRules: (0 to: 41)
- 		on: ToolIcons flag
- 		and: ((Color red alpha: 0.4) iconOrThumbnailOfSize: 12)
- 		fallback: ToolIcons exception
- 		scaledTo: 32) openInHand.!

Item was removed:
- ----- Method: BitBlt class>>previewBitBltRules:on:and:fallback:scaledTo: (in category '*MorphicExtras') -----
- previewBitBltRules: rules on: aForm1 and: aForm2 fallback: fallbackForm scaledTo: aNumberOrPoint
- 	"Returns a combined morph of the result of each rule applied on aForm1 combined with 
- 	aForm2 scaled to aNumberOrPoint. If the combination faild with a rule, fallbackForm is 
- 	shown instead. The number of each rule is appended at the bottom of each result."
- 
- 	| resultMorph tileExtent |
- 	tileExtent := aNumberOrPoint asPoint.
- 	resultMorph := Morph new
- 		color: Color transparent;
- 		extent: (rules size * tileExtent x)@tileExtent y;
- 		yourself.
- 
- 	rules withIndexDo: [ :rule :index | | form formMorph numberLabel |
- 		form := aForm1 copy.
- 		[aForm2 copy displayOn: form at: 0 at 0 rule: rule]
- 			on: Exception 
- 			do: [form := fallbackForm].
- 		formMorph := (form scaledToSize: tileExtent) asMorph
- 			position: (index*tileExtent x)@0;
- 			yourself.
- 		resultMorph addMorph: formMorph.
- 	
- 		numberLabel := rule asString asMorph
- 	      	center: ((index+0.5)*tileExtent x)@tileExtent y;
- 			yourself.
- 		resultMorph addMorph: numberLabel].
- 
- 	^ resultMorph!

Item was removed:
- BooklikeMorph subclass: #BookMorph
- 	instanceVariableNames: 'pages currentPage'
- 	classVariableNames: 'MethodHolders VersionNames VersionTimes'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Books'!
- 
- !BookMorph commentStamp: '<historical>' prior: 0!
- A collection of pages, each of which is a place to put morphs.  Allows one or another page to show; orchestrates the page transitions; offers control panel for navigating among pages and for adding and deleting pages.
- 
- To write a book out to the disk or to a file server, decide what folder it goes in.  Construct a url to a typical page:
- 	file://myDisk/folder/myBook1.sp
- or
- 	ftp://aServer/folder/myBook1.sp
- 
- Choose "send all pages to server" from the book's menu (press the <> part of the controls).  Choose "use page numbers".  Paste in the url.
- 
- To load an existing book, find its ".bo" file in the file list browser.  Choose "load as book".
- 
- To load an existing book from its url, execute:
- ¦(URLMorph grabURL: 'ftp://aServer/folder/myBook1.sp') book: true.
- 
- Multiple people may modify a book.  If other people may have changed a book you have on your screen, choose "reload all from server".
- 
- Add or modify a page, and choose "send this page to server".
- 
- The polite thing to do is to reload before changing a book.  Then write one or all pages soon after making your changes.  If you store a stale book, it will wipe out changes that other people made in the mean time.
- 
- Pages may be linked to each other.  To create a named link to a new page, type the name of the page in a text area in a page.  Select it and do Cmd-6.  Choose 'link to'.  A new page of that name will be added at the back of the book.  Clicking on the blue text flips to that page.  
- 	To create a link to an existing page, first name the page.  Go to that page and Cmd-click on it.  The name of the page is below the page.  Click in it and backspace and type.  Return to the page you are linking from.  Type the name. Cmd-6, 'link to'.  
- 
- Text search:  Search for a set of fragments.  allStrings collects text of fields.  Turn to page with all fragments on it and highlight the first one.  Save the container and offset in properties: #searchContainer, #searchOffset, #searchKey.  Search again from there.  Clear those at each page turn, or change of search key.  
- 
- [rules about book indexes and pages:  Index and pages must live in the same directory. They have the same file prefix, followed by .bo for the index or 4.sp for a page (or x4.sp).  When a book is moved to a new directory, the load routine gets the new urls for all pages and saves those in the index.  Book stores index url in property #url.  
-     Allow mulitple indexes (books) on the same shared set of pages.  If book has a url in same directory as pages, allow them to have different prefixes.
- 	save all pages first time, save one page first time, fromRemoteStream: (first time)
- 	save all pages normal , save one page normal, reload
- 	where I check if same dir]
- URLMorph holds url of both page and book.!

Item was removed:
- ----- Method: BookMorph class>>alreadyInFromUrl: (in category 'url') -----
- alreadyInFromUrl: aUrl
- 	"Does a bookMorph living in some world in this image represent the same set of server pages? If so, don't create another one.  It will steal pages from the existing one.  Go delete the first one."
- 	
- 	self withAllSubclassesDo: [:cls |
- 		cls allInstancesDo: [:aBook | 
- 			 (aBook valueOfProperty: #url) = aUrl ifTrue: [
- 				aBook world ifNotNil: [
- 					self inform: 'This book is already open in some project' translated.
- 					^ true]]]].
- 	^ false!

Item was removed:
- ----- Method: BookMorph class>>authoringPrototype (in category 'scripting') -----
- authoringPrototype
- 	"Answer an instance of the receiver suitable for placing in a parts bin for authors"
- 	
- 	| book |
- 	book := self new initializeToStandAlone.
- 	book markAsPartsDonor.
- 	^ book!

Item was removed:
- ----- Method: BookMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'Book' translatedNoop
- 		categories:		{'Multimedia' translatedNoop}
- 		documentation:	'Multi-page structures' translatedNoop
- 		sampleImageForm: (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: 'iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAYAAABJ/yOpAAAABHNCSVQFBQUBSsjp7wAABMtJ
- REFUeF7l3S2S4kAAgFEkEonkCEiOgEQikUgkEolEcgSOgEQiOcYcAZfdniqmpnaBkE43JHni
- 7dZuzWR7m3z5ISHT6/X6hc/ne+TvL9fr1efz/cMPxOfzA/H5/EB8Pj8Qn88PxOfzA/H5OhLI
- 19eXz9dZfiA+nx+Iz+cH4vN1K5Dz+fxUEyaoCWP0xwAF8ntSy94l+NQL0IQx+mMAA3llop+9
- AO+K49Nj9MeABfLqVujVrVTOvcYnx+iPAQwkxWTn3kI1YYz+GMBAckx4kw4lUo3RH4MfiB9I
- hTHU/ZSbH0gLAsk54akmvuoYY+5LKxvjvTGkDCR2DKnnoq2RZAkkNo4cK2DKOGJv3Hw0xkdj
- SB1IzBhyzEedSC6XS7Hf74vFYlGMx+Nit9uVfs9yufz++jrLaFwg75r0KmMsW/nkQKrMSexr
- dTgc/vs/rlar0u/r9/vfkdRZRiMDecekvzrGV1Y+PZBX5yX2tTqdTsVmsymOx+PPir5er0uj
- CoGE74ldRpZA6px7xK6Mud7OrLtSPhvjszHkCKTqGHLMQYpzkdvKXbb1D3uO0WhUaxmNDyTX
- pKdeMXIFkvoQNXcgMfMQG0jZ1n84HP4cXsUuoxWB5Jj0sjGm3GprgZSN+x17kHA4Fb4mfG3n
- 9yA5Jj3H4Y1/iBU3hhx7kHCuMRgMau+F/ED8QFobyLOt/2QyKebzee3zGP8Qyz/Eau0h1qOt
- f7jWEd69Ctc7iD2If5Lun6RX2fqHi3/PDq86tQfx3+b13+atuvUPh1az2SzJO2H+hUL/QmEr
- LhTermuELX5Y+cO/F84zwp/D34d3rX5fPd9ut7WW4d9q0pJbTVLOX5tvNbmdeIf7p+79frta
- ftszhPOQ2GX4Nyu26GbFNgTSpDt6w02I0+nUv93dv93dv9390Qn6o4uD/gem/A9M+R+Y8j9R
- 6H/k1v/Irf/QBv+hDf5DG/zH/viP/fHH4AfiPzjOH4MfiP/oUf/Ro/6jR/2HV/sPr/YfXu3/
- +AOfzw/E5/MD8fn8QHy+pgfi8/k/BtqfDJ/PD8Tn8wPx+fxAfD4/EJ/PD8Tn8wPx+fxAfD4/
- EJ/PD8Tn8/mB+Hx+ID6fH4jP5wfi8/mB+Hx+ID6fH4jP5wfi8/mB+Hx+ID6fzw/E5/MD8fn8
- QHw+PxCfzw/E5/MD8fn8QHw+PxCfzw/E5/MD8QPx+fxAfD4/EJ/PD8Tn8wPx+fxAfL47ro3i
- B+Lz+YH4fH4gPp8fiM/nB+Lz+YH4fH4gPp8fiM/nB+Lz+YH4fD4/EJ/PD8Tn8wPx+fxAfD4/
- EJ/PD8Tn8wPx+fxAfD4/EJ/PD8QPxOfzA/H5/EB8Pj8Qn88PxOfzA/H5/EB8Pj8Qn88PxOfz
- A/H5fH4gPp8fiM/nB+Lz+YH4fH4gPp8fiM/nB+Lz+YH4fH4gPp8fiB+Iz+cH4vP5gfg+o6P8
- QHw+PxCfzw/E5/MD8fn8QHw+PxCfzw/E5/MD8fn8QHw+PxCfz+cH4vP5gfh8fiA+nx+Iz+cH
- 4vP5gfh8fiA+nx+Iz+cH4vP5gfiB+Hx+ID6fH4jP5wfi8/mB+Hx+ID6fH4jP5wfi8/mB+Hx+
- ID6fzw/E5/MD8fn8QHw+PxCfzw/E5/MD8fn8QHy+jgXi8/nu+wM79mpMjbRBXAAAAABJRU5E
- rkJggg==' readStream) readStream) nextImage!

Item was removed:
- ----- Method: BookMorph class>>fileReaderServicesForFile:suffix: (in category 'fileIn/Out') -----
- fileReaderServicesForFile: fullName suffix: suffix
- 
- 	^(suffix = 'bo') | (suffix = '*') 
- 		ifTrue: [ Array with: self serviceLoadAsBook]
- 		ifFalse: [#()]
- !

Item was removed:
- ----- Method: BookMorph class>>grabURL: (in category 'url') -----
- grabURL: aURLString
- 	"Create a BookMorph for this url and put it in the hand."
- 
- 	| book |
- 	book := self new fromURL: aURLString.
- 	"If this book is already in, we will steal the pages out of it!!!!!!!!"
- 	book goToPage: 1.	"install it"
- 	HandMorph attach: book!

Item was removed:
- ----- Method: BookMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: BookMorph class>>isInWorld:withUrl: (in category 'url') -----
- isInWorld: aWorld withUrl: aUrl
- 	| urls bks short |
- 	"If a book with this url is in the that (current) world, return it.  Say if it is out or in another world."
- 
- 	urls := OrderedCollection new.
- 	bks := OrderedCollection new.
- 	aWorld allMorphsDo: [:aBook | (aBook isKindOf: BookMorph) ifTrue: [
- 			bks add: aBook.
- 			 (urls add: (aBook valueOfProperty: #url)) = aUrl ifTrue: [
- 				aBook world == aWorld 
- 					ifTrue: [^ aBook]]]]. 	"shortcut"
- 		
- 	self withAllSubclassesDo: [:cls |
- 		cls allInstancesDo: [:aBook | 
- 			 (aBook valueOfProperty: #url) = aUrl ifTrue: [
- 				aBook world == aWorld 
- 					ifTrue: [^ aBook]
- 					ifFalse: [
- 						self inform: 'Book may be open in some other project' translated.
- 						^ aBook]]]].
- 
- 	"if same book name, use it"
- 	short := (aUrl findTokens: '/') last.
- 	urls withIndexDo: [:kk :ind | (kk findTokens: '/') last = short ifTrue: [
- 			^ bks at: ind]].
- 	^ #out!

Item was removed:
- ----- Method: BookMorph class>>makeBookOfProjects:named: (in category 'booksAsProjects') -----
- makeBookOfProjects: aListOfProjects named: aString
- "
- BookMorph makeBookOfProjects: (Project allProjects select: [ :each | each world isMorph])
- "
- 	| book |
- 
- 	book := self new.
- 	book setProperty: #transitionSpec toValue: {'silence'. #none. #none}.
- 	aListOfProjects do: [ :each | | pvm page |
- 		pvm := ProjectViewMorph on: each.
- 		page := PasteUpMorph new addMorph: pvm; extent: pvm extent.
- 		book insertPage: page pageSize: page extent
- 	].
- 	book goToPage: 1.
- 	book deletePageBasic.
- 	book setProperty: #nameOfThreadOfProjects toValue: aString.
- 	book removeProperty: #transitionSpec.
- 	book openInWorld!

Item was removed:
- ----- Method: BookMorph class>>nextPageButton (in category 'scripting') -----
- nextPageButton
- 	"Answer a button that will take the user to the next page of its
- 	enclosing book"
- 	| aButton |
- 	aButton := ThreePhaseButtonMorph labelSymbol: #NextPage.
- 	aButton target: aButton.
- 	aButton actionSelector: #nextOwnerPage.
- 	aButton arguments: #().
- 	aButton setNameTo: 'previous'.
- 	^ aButton!

Item was removed:
- ----- Method: BookMorph class>>openFromFile: (in category 'fileIn/Out') -----
- openFromFile: fullName
- 	"Reconstitute a Morph from the selected file, presumed to be represent
- 	a Morph saved via the SmartRefStream mechanism, and open it in an
- 	appropriate Morphic world"
- 
- 	| book aFileStream |
- 	Smalltalk verifyMorphicAvailability ifFalse: [^ self].
- 
- 	aFileStream := FileStream readOnlyFileNamed: fullName.
- 	book := BookMorph new.
- 	book setProperty: #url toValue: aFileStream url.
- 	book fromRemoteStream: aFileStream.
- 	aFileStream close.
- 
- 	Smalltalk isMorphic 
- 		ifTrue: [self currentWorld addMorphsAndModel: book]
- 		ifFalse: [book isMorph ifFalse: [^self inform: 'Can only load a single morph\into an mvc project via this mechanism.' translated withCRs].
- 			book openInWorld].
- 	book goToPage: 1!

Item was removed:
- ----- Method: BookMorph class>>previousPageButton (in category 'scripting') -----
- previousPageButton
- 	"Answer a button that will take the user to the previous page of its
- 	enclosing book"
- 	| aButton |
- 	aButton := ThreePhaseButtonMorph labelSymbol: #PrevPage.
- 	aButton target: aButton.
- 	aButton actionSelector: #previousOwnerPage.
- 	aButton arguments: #().
- 	aButton setNameTo: 'previous'.
- 	^ aButton!

Item was removed:
- ----- Method: BookMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#BookMorph	. #nextPageButton. 'NextPage' translatedNoop. 'A button that takes you to the next page' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#BookMorph. #previousPageButton. 'PreviousPage' translatedNoop. 'A button that takes you to the previous page' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#BookMorph. #authoringPrototype. 'Book' translatedNoop. 'A multi-paged structure' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#BookMorph. #nextPageButton. 'NextPage' translatedNoop. 'A button that takes you to the next page' translatedNoop}
- 						forFlapNamed: 'Supplies'.
- 						cl registerQuad: {#BookMorph. #previousPageButton. 'PreviousPage' translatedNoop. 'A button that takes you to the previous page' translatedNoop}
- 						forFlapNamed: 'Supplies'.
- 						cl registerQuad: {#BookMorph. #authoringPrototype. 'Book' translatedNoop. 'A multi-paged structure' translatedNoop}
- 						forFlapNamed: 'Supplies']!

Item was removed:
- ----- Method: BookMorph class>>serviceLoadAsBook (in category 'fileIn/Out') -----
- serviceLoadAsBook
- 
- 	^ SimpleServiceEntry 
- 			provider: self 
- 			label: 'load as book' translatedNoop
- 			selector: #openFromFile:
- 			description: 'open as bookmorph' translatedNoop!

Item was removed:
- ----- Method: BookMorph class>>services (in category 'fileIn/Out') -----
- services
- 
- 	^ Array with: self serviceLoadAsBook!

Item was removed:
- ----- Method: BookMorph class>>unload (in category 'initialize-release') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment
- 		at: #FileServices
- 		ifPresent: [:cl | cl unregisterFileReader: self].
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl unregisterQuadsWithReceiver: self]!

Item was removed:
- ----- Method: BookMorph>>abandon (in category 'submorphs - add/remove') -----
- abandon
- 	"Like delete, but we really intend not to use this morph again.  Make the page cache release the page object."
- 
- 	
- 	self delete.
- 	pages do: [:aPage | | pg |
- 		(pg := aPage sqkPage) ifNotNil: [
- 			pg contentsMorph == aPage ifTrue: [
- 					pg contentsMorph: nil]]].!

Item was removed:
- ----- Method: BookMorph>>acceptDroppingMorph:event: (in category 'layout') -----
- acceptDroppingMorph: aMorph event: evt
- 	"Allow the user to add submorphs just by dropping them on this morph."
- 
- 	(currentPage allMorphs includes: aMorph)
- 		ifFalse: [currentPage addMorph: aMorph]!

Item was removed:
- ----- Method: BookMorph>>acceptSortedContentsFrom: (in category 'sorting') -----
- acceptSortedContentsFrom: aHolder 
- 	"Update my page list from the given page sorter."
- 
- 	| goodPages rejects |
- 	goodPages := OrderedCollection new.
- 	rejects := OrderedCollection new.
- 	aHolder submorphs withIndexDo: 
- 			[:m :i | | toAdd sqPage | 
- 			toAdd := nil.
- 			(m isKindOf: PasteUpMorph) ifTrue: [toAdd := m].
- 			(m isKindOf: BookPageThumbnailMorph) 
- 				ifTrue: 
- 					[toAdd := m page.
- 					m bookMorph == self 
- 						ifFalse: 
- 							["borrowed from another book. preserve the original"
- 
- 							toAdd := toAdd veryDeepCopy.
- 
- 							"since we came from elsewhere, cached strings are wrong"
- 							self removeProperty: #allTextUrls.
- 							self removeProperty: #allText]].
- 			toAdd isString 
- 				ifTrue: 
- 					["a url"
- 
- 					toAdd := pages detect: [:aPage | aPage url = toAdd] ifNone: [toAdd]].
- 			toAdd isString 
- 				ifTrue: 
- 					[sqPage := SqueakPageCache atURL: toAdd.
- 					toAdd := sqPage contentsMorph 
- 								ifNil: [sqPage copyForSaving	"a MorphObjectOut"]
- 								ifNotNil: [sqPage contentsMorph]].
- 			toAdd ifNil: [rejects add: m] ifNotNil: [goodPages add: toAdd]].
- 	self newPages: goodPages.
- 	goodPages isEmpty ifTrue: [self insertPage].
- 	rejects notEmpty 
- 		ifTrue: 
- 			[self 
- 				inform: rejects size printString , ' objects vanished in this process.']!

Item was removed:
- ----- Method: BookMorph>>addBookMenuItemsTo:hand: (in category 'menu') -----
- addBookMenuItemsTo: aMenu hand: aHandMorph
- 	| controlsShowing subMenu |
- 	subMenu := MenuMorph new defaultTarget: self.
- 	subMenu add: 'previous page' translated action: #previousPage.
- 	subMenu add: 'next page' translated action: #nextPage.
- 	subMenu add: 'goto page' translated action: #goToPage.
- 	subMenu add: 'insert a page' translated action: #insertPage.
- 	subMenu add: 'delete this page' translated action: #deletePage.
- 
- 	controlsShowing := self hasSubmorphWithProperty: #pageControl.
- 	controlsShowing
- 		ifTrue:
- 			[subMenu add: 'hide page controls' translated action: #hidePageControls.
- 			subMenu add: 'fewer page controls' translated action: #fewerPageControls]
- 		ifFalse:
- 			[subMenu add: 'show page controls' translated action: #showPageControls].
- 	self isInFullScreenMode ifTrue: [
- 		subMenu add: 'exit full screen' translated action: #exitFullScreen.
- 	] ifFalse: [
- 		subMenu add: 'show full screen' translated action: #goFullScreen.
- 	].
- 	subMenu addLine.
- 	subMenu add: 'sound effect for all pages' translated action: #menuPageSoundForAll:.
- 	subMenu add: 'sound effect this page only' translated action: #menuPageSoundForThisPage:.
- 	subMenu add: 'visual effect for all pages' translated action: #menuPageVisualForAll:.
- 	subMenu add: 'visual effect this page only' translated action: #menuPageVisualForThisPage:.
- 
- 	subMenu addLine.
- 	subMenu add: 'sort pages' translated action: #sortPages:.
- 	subMenu add: 'uncache page sorter' translated action: #uncachePageSorter.
- 	(self hasProperty: #dontWrapAtEnd)
- 		ifTrue: [subMenu add: 'wrap after last page' translated selector: #setWrapPages: argument: true]
- 		ifFalse: [subMenu add: 'stop at last page' translated selector: #setWrapPages: argument: false].
- 
- 	subMenu addLine.
- 	subMenu add: 'search for text' translated action: #textSearch.
- 	(aHandMorph pasteBuffer class isKindOf: PasteUpMorph class) ifTrue:
- 		[subMenu add: 'paste book page' translated	action: #pasteBookPage].
- 
- 	subMenu add: 'send all pages to server' translated action: #savePagesOnURL.
- 	subMenu add: 'send this page to server' translated action: #saveOneOnURL.
- 	subMenu add: 'reload all from server' translated action: #reload.
- 	subMenu add: 'copy page url to clipboard' translated action: #copyUrl.
- 	subMenu add: 'keep in one file' translated action: #keepTogether.
- 	subMenu add: 'save as new-page prototype' translated action: #setNewPagePrototype.
- 	newPagePrototype ifNotNil:
- 		[subMenu add: 'clear new-page prototype' translated action: #clearNewPagePrototype].
- 
- 	aMenu add: 'book...' translated subMenu: subMenu
- !

Item was removed:
- ----- Method: BookMorph>>adjustCurrentPageForFullScreen (in category 'other') -----
- adjustCurrentPageForFullScreen
- 	"Adjust current page to conform to whether or not I am in full-screen mode.  Also, enforce uniform page size constraint if appropriate"
- 
- 	self isInFullScreenMode
- 		ifTrue:
- 			[(currentPage hasProperty: #sizeWhenNotFullScreen) ifFalse:
- 				[currentPage setProperty: #sizeWhenNotFullScreen toValue: currentPage extent].
- 			currentPage extent: Display extent]
- 		ifFalse:
- 			[(currentPage hasProperty: #sizeWhenNotFullScreen) ifTrue:
- 				[currentPage extent: (currentPage valueOfProperty: #sizeWhenNotFullScreen).
- 				currentPage removeProperty: #sizeWhenNotFullScreen].
- 			self uniformPageSize ifNotNil:
- 				[:anExtent | currentPage extent: anExtent]].
- 	(self valueOfProperty: #floatingPageControls) ifNotNil:
- 		[:pc | pc isInWorld ifFalse: [pc openInWorld]]!

Item was removed:
- ----- Method: BookMorph>>allNonSubmorphMorphs (in category 'submorphs - accessing') -----
- allNonSubmorphMorphs
- 	"Return a collection containing all morphs in this morph which are not currently in the submorph containment hierarchy.  Especially the non-showing pages in BookMorphs.    (As needed, make a variant of this that brings in all pages that are not in memory.)"
- 
- 	| coll |
- 	coll := OrderedCollection new.
- 	pages do: [:pg |
- 		pg isInMemory ifTrue: [
- 			pg == currentPage ifFalse: [coll add: pg]]].
- 	^ coll!

Item was removed:
- ----- Method: BookMorph>>allowSubmorphExtraction (in category 'dropping/grabbing') -----
- allowSubmorphExtraction
- 
- 	^ false!

Item was removed:
- ----- Method: BookMorph>>asPostscript (in category 'Postscript Canvases') -----
- asPostscript
- 	^self asPostscriptPrintJob.
- !

Item was removed:
- ----- Method: BookMorph>>bookmarkForThisPage (in category 'menu') -----
- bookmarkForThisPage
- 	"If this book exists on a server, make the reference via a URL"
- 	| bb url um |
- 	(url := self url) ifNil: [
- 		bb := SimpleButtonMorph new target: self.
- 		bb actionSelector: #goToPageMorph:fromBookmark:.
- 		bb label: 'Bookmark' translated.
- 		bb arguments: (Array with: currentPage with: bb).
- 		self primaryHand attachMorph: bb.
- 		^ bb].
- 	currentPage url ifNil: [currentPage saveOnURLbasic].
- 	um := URLMorph newForURL: currentPage url.
- 	um setURL: currentPage url page: currentPage sqkPage.
- 	(SqueakPage stemUrl: url) = (SqueakPage stemUrl: currentPage url) 
- 		ifTrue: [um book: true]
- 		ifFalse: [um book: url].  	"remember which book"
- 	um isBookmark: true; label: 'Bookmark' translated.
- 	um borderStyle: (BorderStyle raised width: 1).
- 	um color: (Color r: 0.4 g: 0.8 b: 0.6).
- 	self primaryHand attachMorph: um.
- 	^ um!

Item was removed:
- ----- Method: BookMorph>>buildFloatingPageControls (in category 'navigation') -----
- buildFloatingPageControls
- 
- 	| pageControls |
- 	pageControls := self makePageControlsFrom: self fullControlSpecs.
- 	pageControls borderWidth: 0; layoutInset: 4.
- 	pageControls  setProperty: #pageControl toValue: true.
- 	pageControls setNameTo: 'Page Controls'.
- 	pageControls color: Color yellow.
- 	^FloatingBookControlsMorph new addMorph: pageControls.
- !

Item was removed:
- ----- Method: BookMorph>>buildThreadOfProjects (in category 'menu') -----
- buildThreadOfProjects
- 
- 	| projectNames threadName |
- 
- 	projectNames := pages collect: [ :each | | thisPVM |
- 		(thisPVM := each findA: ProjectViewMorph) ifNil: [
- 			nil
- 		] ifNotNil: [
- 			{thisPVM project name}.
- 		].
- 	].
- 	projectNames := projectNames reject: [ :each | each isNil].
- 	threadName := UIManager default 
- 		request: 'Please name this thread.' translated 
- 		initialAnswer: (
- 			self valueOfProperty: #nameOfThreadOfProjects ifAbsent: ['Projects on Parade' translated]
- 		).
- 	threadName isEmptyOrNil ifTrue: [^self].
- 	InternalThreadNavigationMorph 
- 		know: projectNames as: threadName;
- 		openThreadNamed: threadName atIndex: nil.
- !

Item was removed:
- ----- Method: BookMorph>>cardsOrPages (in category 'accessing') -----
- cardsOrPages
- 	"The turnable and printable entities"
- 
- 	^ pages!

Item was removed:
- ----- Method: BookMorph>>copyUrl (in category 'menu') -----
- copyUrl
- 	"Copy this page's url to the clipboard"
- 	| str |
- 	str := currentPage url ifNil: [str := 'Page does not have a url.  Send page to server first.' translated].
- 	Clipboard clipboardText: str asText.
- !

Item was removed:
- ----- Method: BookMorph>>currentPage (in category 'accessing') -----
- currentPage
- 	(submorphs includes: currentPage) ifFalse: [currentPage := nil].
- 	^ currentPage!

Item was removed:
- ----- Method: BookMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color white!

Item was removed:
- ----- Method: BookMorph>>defaultNameStemForNewPages (in category 'insert and delete') -----
- defaultNameStemForNewPages
- 	"Answer a stem onto which to build default names for fresh pages"
- 
- 	^ 'page'
- !

Item was removed:
- ----- Method: BookMorph>>defersHaloOnClickTo: (in category 'halos and balloon help') -----
- defersHaloOnClickTo: aSubMorph
- 	"If a cmd-click on aSubMorph would make it a preferred recipient of the halo, answer true"
- 	^ currentPage notNil and:
- 		[aSubMorph hasOwner: currentPage]
- 	!

Item was removed:
- ----- Method: BookMorph>>deletePage (in category 'insert and delete') -----
- deletePage
- 
- 	| message |
- 	message := 
- 'Are you certain that you
- want to delete this page and
- everything that is on it? ' translated.
- 	(self confirm: message) ifTrue: 
- 			[self deletePageBasic].
- 	!

Item was removed:
- ----- Method: BookMorph>>deletePageBasic (in category 'insert and delete') -----
- deletePageBasic
- 	| thisPage |
- 	thisPage := self pageNumberOf: currentPage.
- 	pages remove: currentPage.
- 	currentPage delete.
- 	currentPage := nil.
- 	pages isEmpty ifTrue: [^ self insertPage].
- 	self goToPage: (thisPage min: pages size)
- !

Item was removed:
- ----- Method: BookMorph>>exitFullScreen (in category 'other') -----
- exitFullScreen
- 	| floater |
- 	self isInFullScreenMode ifFalse: [ ^ self ].
- 	self
- 		setProperty: #fullScreenMode
- 		toValue: false.
- 	(self hasProperty: #showWorldMainDockingBarWhenNotFullScreen) ifTrue:
- 		[ MorphicProject current showWorldMainDockingBar: (self valueOfProperty: #showWorldMainDockingBarWhenNotFullScreen).
- 		self removeProperty: #showWorldMainDockingBarWhenNotFullScreen ].
- 	floater := self
- 		valueOfProperty: #floatingPageControls
- 		ifAbsent: [  ].
- 	floater ifNotNil:
- 		[ floater delete.
- 		self removeProperty: #floatingPageControls ].
- 	self position: 0 @ 0.
- 	self adjustCurrentPageForFullScreen!

Item was removed:
- ----- Method: BookMorph>>findText: (in category 'menu') -----
- findText: wants
- 	"Turn to the next page that has all of the strings mentioned on it.  Highlight where it is found.  allText and allTextUrls have been set.  Case insensitive search.
- 	Resuming a search.  If container's text is still in the list and secondary keys are still in the page, (1) search rest of that container.  (2) search rest of containers on that page (3) pages till end of book, (4) from page 1 to this page again."
- 
- 	"Later sort wants so longest key is first"
- 	| allText here fromHereOn startToHere oldContainer oldIndex otherKeys strings good |
- 	allText := self valueOfProperty: #allText ifAbsent: [#()].
- 	here := pages identityIndexOf: currentPage ifAbsent: [1].
- 	fromHereOn := here+1 to: pages size.
- 	startToHere := 1 to: here.		"repeat this page"
- 	(self valueOfProperty: #searchKey ifAbsent: [#()]) = wants ifTrue: [
- 		"does page have all the other keys?  No highlight if found!!"
- 		otherKeys := wants allButFirst.
- 		strings := allText at: here.
- 		good := true.
- 		otherKeys do: [:searchString | | thisWord | "each key"
- 			good ifTrue: [thisWord := false.
- 				strings do: [:longString |
- 					(longString findString: searchString startingAt: 1 
- 						caseSensitive: false) > 0 ifTrue: [
- 							thisWord := true]].
- 				good := thisWord]].
- 		good ifTrue: ["all are on this page.  Look in rest for string again."
- 			oldContainer := self valueOfProperty: #searchContainer.
- 			oldIndex := self valueOfProperty: #searchOffset.
- 			(self findText: (OrderedCollection with: wants first) inStrings: strings	
- 				startAt: oldIndex+1 container: oldContainer 
- 				pageNum: here) ifTrue: [
- 					self setProperty: #searchKey toValue: wants.
- 					^ true]]]
- 		ifFalse: [fromHereOn := here to: pages size].	"do search this page"
- 	"other pages"
- 	allText ifNotEmpty: [
- 		fromHereOn do: [:pageNum |
- 			(self findText: wants inStrings: (allText at: pageNum) startAt: 1 container: nil 
- 					pageNum: pageNum) 
- 					ifTrue: [^ true]].
- 		startToHere do: [:pageNum |
- 			(self findText: wants inStrings: (allText at: pageNum) startAt: 1 container: nil 
- 					pageNum: pageNum) 
- 						ifTrue: [^ true]]].
- 	"if fail"
- 	self setProperty: #searchContainer toValue: nil.
- 	self setProperty: #searchOffset toValue: nil.
- 	self setProperty: #searchKey toValue: nil.
- 	^ false!

Item was removed:
- ----- Method: BookMorph>>findText:inStrings:startAt:container:pageNum: (in category 'menu') -----
- findText: keys inStrings: rawStrings startAt: startIndex container: oldContainer pageNum: pageNum 
- 	"Call once to search a page of the book.  Return true if found and highlight the text.  oldContainer should be NIL.  
- 	(oldContainer is only non-nil when (1) doing a 'search again' and (2) the page is in memory and (3) keys has just one element.  oldContainer is a TextMorph.)"
- 
- 	| container wasIn strings old good insideOf place start |
- 	good := true.
- 	start := startIndex.
- 	strings := oldContainer ifNil: 
- 					["normal case"
- 
- 					rawStrings]
- 				ifNotNil: 
- 					[(pages at: pageNum) isInMemory 
- 						ifFalse: [rawStrings]
- 						ifTrue: [(pages at: pageNum) allStringsAfter: oldContainer]].
- 	keys do: 
- 			[:searchString | | thisWord | 
- 			"each key"
- 
- 			good 
- 				ifTrue: 
- 					[thisWord := false.
- 					strings do: 
- 							[:longString | | index | 
- 							(index := longString 
- 										findString: searchString
- 										startingAt: start
- 										caseSensitive: false) > 0 
- 								ifTrue: 
- 									[thisWord not & (searchString == keys first) 
- 										ifTrue: 
- 											[insideOf := longString.
- 											place := index].
- 									thisWord := true].
- 							start := 1].	"only first key on first container"
- 					good := thisWord]].
- 	good 
- 		ifTrue: 
- 			["all are on this page"
- 
- 			wasIn := (pages at: pageNum) isInMemory.
- 			self goToPage: pageNum.
- 			wasIn 
- 				ifFalse: 
- 					["search again, on the real current text.  Know page is in."
- 
- 					^self 
- 						findText: keys
- 						inStrings: ((pages at: pageNum) allStringsAfter: nil)
- 						startAt: startIndex
- 						container: oldContainer
- 						pageNum: pageNum	"recompute"]].
- 	(old := self valueOfProperty: #searchContainer) ifNotNil: 
- 			[(old respondsTo: #editor) 
- 				ifTrue: 
- 					[old editor selectFrom: 1 to: 0.	"trying to remove the previous selection!!"
- 					old changed]].
- 	good 
- 		ifTrue: 
- 			["have the exact string object"
- 
- 			(container := oldContainer) ifNil: 
- 					[container := self 
- 								highlightText: keys first
- 								at: place
- 								in: insideOf]
- 				ifNotNil: 
- 					[container userString == insideOf 
- 						ifFalse: 
- 							[container := self 
- 										highlightText: keys first
- 										at: place
- 										in: insideOf]
- 						ifTrue: 
- 							[(container isTextMorph) 
- 								ifTrue: 
- 									[container editor selectFrom: place to: keys first size - 1 + place.
- 									container changed]]].
- 			self setProperty: #searchContainer toValue: container.
- 			self setProperty: #searchOffset toValue: place.
- 			self setProperty: #searchKey toValue: keys.	"override later"
- 			self currentHand newKeyboardFocus: container.
- 			^true].
- 	^false!

Item was removed:
- ----- Method: BookMorph>>forgetURLs (in category 'menu') -----
- forgetURLs
- 	"About to save these objects in a new place.  Forget where stored now.  Must bring in all pages we don't have."
- 
- 
- pages do: [:aPage | | pg |
- 	aPage yourself.	"bring it into memory"
- 	(pg := aPage valueOfProperty: #SqueakPage) ifNotNil: [
- 		SqueakPageCache removeURL: pg url.
- 		pg contentsMorph setProperty: #SqueakPage toValue: nil]].
- self setProperty: #url toValue: nil.!

Item was removed:
- ----- Method: BookMorph>>fromRemoteStream: (in category 'initialization') -----
- fromRemoteStream: strm 
- 	"Make a book from an index and a bunch of pages on a server.  NOT showing any page!!  Index and pages must live in the same directory.  If the book has moved, save the current correct urls for each of the pages.  Self must already have a url stored in property #url."
- 
- 	| remote dict bookUrl oldStem stem oldUrl endPart |
- 	remote := strm fileInObjectAndCode.
- 	bookUrl := (SqueakPage new)
- 				url: (self valueOfProperty: #url);
- 				url.
- 	"expand a relative url"
- 	oldStem := SqueakPage stemUrl: (remote second) url.
- 	oldStem := oldStem copyUpToLast: $/.
- 	stem := SqueakPage stemUrl: bookUrl.
- 	stem := stem copyUpToLast: $/.
- 	oldStem = stem 
- 		ifFalse: 
- 			["Book is in new directory, fix page urls"
- 
- 			2 to: remote size
- 				do: 
- 					[:ii | 
- 					oldUrl := (remote at: ii) url.
- 					endPart := oldUrl copyFrom: oldStem size + 1 to: oldUrl size.
- 					(remote at: ii) url: stem , endPart]].
- 	self initialize.
- 	pages := OrderedCollection new.
- 	2 to: remote size do: [:ii | pages add: (remote at: ii)].
- 	currentPage
- 		fullReleaseCachedState;
- 		delete.	"the blank one"
- 	currentPage := remote second.
- 	dict := remote first.
- 	self setProperty: #modTime toValue: (dict at: #modTime).
- 	dict at: #allText
- 		ifPresent: [:val | self setProperty: #allText toValue: val].
- 	dict at: #allTextUrls
- 		ifPresent: [:val | self setProperty: #allTextUrls toValue: val].
- 	#(#color #borderWidth #borderColor #pageSize) 
- 		with: #(#color: #borderWidth: #borderColor: #pageSize:)
- 		do: [:key :sel | dict at: key ifPresent: [:val | self perform: sel with: val]].
- 	^self!

Item was removed:
- ----- Method: BookMorph>>fromURL: (in category 'initialization') -----
- fromURL: url
- 	"Make a book from an index and a bunch of pages on a server.  NOT showing any page!!"
- 
- 	| strm |
- 	strm := Cursor wait showWhile: [
- 		(ServerFile new fullPath: url) asStream].
- 	strm isString ifTrue: [self inform: 'Sorry, ',strm. ^ nil].
- 	self setProperty: #url toValue: url.
- 	self fromRemoteStream: strm.
- 	^ self!

Item was removed:
- ----- Method: BookMorph>>fullDrawPostscriptOn: (in category 'Postscript Canvases') -----
- fullDrawPostscriptOn:aCanvas
- 	^aCanvas fullDrawBookMorph:self.
- !

Item was removed:
- ----- Method: BookMorph>>getAllText (in category 'menu') -----
- getAllText
- 	"Collect the text for each page.  Just point at strings so don't have to recopy them.  Parallel array of urls for ID of pages.
- 	allText = Array (pages size) of arrays (fields in it) of strings of text.
- 	allTextUrls = Array (pages size) of urls or page numbers.
- 	For any page that is out, text data came from .bo file on server.  
- 	Is rewritten when one or all pages are stored."
- 
- 	| oldUrls oldStringLists allText allTextUrls |
- 	oldUrls := self valueOfProperty: #allTextUrls ifAbsent: [#()].
- 	oldStringLists := self valueOfProperty: #allText ifAbsent: [#()].
- 	allText := pages collect: [:pg | OrderedCollection new].
- 	allTextUrls := Array new: pages size.
- 	pages withIndexDo: [:aPage :ind | | which aUrl |
- 		aUrl := aPage url.  aPage isInMemory 
- 			ifTrue: [(allText at: ind) addAll: (aPage allStringsAfter: nil).
- 				aUrl ifNil: [aUrl := ind].
- 				allTextUrls at: ind put: aUrl]
- 			ifFalse: ["Order of pages on server may be different.  (later keep up to date?)"
- 				which := oldUrls indexOf: aUrl.
- 				allTextUrls at: ind put: aUrl.
- 				which = 0 ifFalse: [allText at: ind put: (oldStringLists at: which)]]].
- 	self setProperty: #allText toValue: allText.
- 	self setProperty: #allTextUrls toValue: allTextUrls.
- 	^ allText!

Item was removed:
- ----- Method: BookMorph>>getStemUrl (in category 'menu') -----
- getStemUrl
- 	"Try to find the old place where this book was stored. Confirm with the 
- 	user. Else ask for new place."
- 	| initial pg url knownURL |
- 
- 	knownURL := false.
- 	initial := ''.
- 	(pg := currentPage valueOfProperty: #SqueakPage)
- 		ifNotNil: [pg contentsMorph == currentPage
- 				ifTrue: [initial := pg url.
- 					knownURL := true]].
- 	"If this page has a url"
- 	pages
- 		withIndexDo: [:aPage :ind | initial isEmpty
- 				ifTrue: [aPage isInMemory
- 						ifTrue: [(pg := aPage valueOfProperty: #SqueakPage)
- 								ifNotNil: [initial := pg url]]]].
- 	"any page with a url"
- 	initial isEmpty
- 		ifTrue: [initial := ServerDirectory defaultStemUrl , '1.sp'].
- 	"A new legal place"
- 	url := knownURL
- 		ifTrue: [initial]
- 		ifFalse: [UIManager default request: 'url of the place to store a typical page in this book.
- Must begin with file:// or ftp://' translated initialAnswer: initial].
- 	^ SqueakPage stemUrl: url!

Item was removed:
- ----- Method: BookMorph>>goFullScreen (in category 'other') -----
- goFullScreen
- 	| floater |
- 	self isInFullScreenMode ifTrue: [ ^ self ].
- 	self
- 		setProperty: #fullScreenMode
- 		toValue: true.
- 	self
- 		setProperty: #showWorldMainDockingBarWhenNotFullScreen
- 		toValue: Project current showWorldMainDockingBar.
- 	Project current showWorldMainDockingBar: false.
- 	self position: (currentPage topLeft - self topLeft) negated.
- 	self adjustCurrentPageForFullScreen.
- 	floater := self buildFloatingPageControls.
- 	self
- 		setProperty: #floatingPageControls
- 		toValue: floater.
- 	floater openInWorld!

Item was removed:
- ----- Method: BookMorph>>goToPage (in category 'menu') -----
- goToPage
- 	| pageNum |
- 	pageNum := UIManager default request: 'Page?' translated initialAnswer: '0'.
- 	pageNum isEmptyOrNil ifTrue: [^true].
- 	self goToPage: pageNum asNumber.
- !

Item was removed:
- ----- Method: BookMorph>>goToPage: (in category 'navigation') -----
- goToPage: pageNumber
- 
- 	^ self goToPage: pageNumber transitionSpec: nil!

Item was removed:
- ----- Method: BookMorph>>goToPage:transitionSpec: (in category 'navigation') -----
- goToPage: pageNumber transitionSpec: transitionSpec
- 
- 	| pageMorph |
- 	pages isEmpty ifTrue: [^ self].
- 	pageMorph := (self hasProperty: #dontWrapAtEnd)
- 		ifTrue: [pages atPin: pageNumber]
- 		ifFalse: [pages atWrap: pageNumber].
- 	^ self goToPageMorph: pageMorph transitionSpec: transitionSpec!

Item was removed:
- ----- Method: BookMorph>>goToPage:transitionSpec:runTransitionScripts: (in category 'navigation') -----
- goToPage: pageNumber transitionSpec: transitionSpec runTransitionScripts: aBoolean
- 	"Go the the given page number; use the transitionSpec supplied, and if the boolean parameter is true, run opening and closing scripts as appropriate"
- 
- 	| pageMorph |
- 	pages isEmpty ifTrue: [^ self].
- 	pageMorph := (self hasProperty: #dontWrapAtEnd)
- 		ifTrue: [pages atPin: pageNumber]
- 		ifFalse: [pages atWrap: pageNumber].
- 	^ self goToPageMorph: pageMorph transitionSpec: transitionSpec runTransitionScripts: aBoolean!

Item was removed:
- ----- Method: BookMorph>>goToPageMorph: (in category 'navigation') -----
- goToPageMorph: aMorph
- 	"Set the given morph as the current page; run closing and opening scripts as appropriate"
- 
- 	self goToPageMorph: aMorph runTransitionScripts: true!

Item was removed:
- ----- Method: BookMorph>>goToPageMorph:fromBookmark: (in category 'navigation') -----
- goToPageMorph: aMorph fromBookmark: aBookmark
- 	"This protocol enables sensitivity to a transitionSpec on the bookmark"
- 	
- 	self goToPageMorph: aMorph
- 		transitionSpec: (aBookmark valueOfProperty: #transitionSpec).
- !

Item was removed:
- ----- Method: BookMorph>>goToPageMorph:runTransitionScripts: (in category 'navigation') -----
- goToPageMorph: aMorph runTransitionScripts: aBoolean
- 	"Set the given morph as the current page.  If the boolean parameter is true, then opening and closing scripts will be run"
- 
- 	self goToPage: (pages identityIndexOf: aMorph ifAbsent: [^ self "abort"]) transitionSpec: nil runTransitionScripts: aBoolean
- !

Item was removed:
- ----- Method: BookMorph>>goToPageMorph:transitionSpec: (in category 'navigation') -----
- goToPageMorph: newPage transitionSpec: transitionSpec 
- 	"Go to a page, which is assumed to be an element of my pages array (if it is not, this method returns quickly.  Apply the transitionSpec provided."
- 
- 	| pageIndex aWorld oldPageIndex ascending tSpec readIn |
- 	pages isEmpty ifTrue: [^self].
- 	self setProperty: #searchContainer toValue: nil.	"forget previous search"
- 	self setProperty: #searchOffset toValue: nil.
- 	self setProperty: #searchKey toValue: nil.
- 	pageIndex := pages identityIndexOf: newPage ifAbsent: [^self	"abort"].
- 	readIn := newPage isInMemory not.
- 	oldPageIndex := pages identityIndexOf: currentPage ifAbsent: [nil].
- 	ascending := (oldPageIndex isNil or: [newPage == currentPage]) 
- 				ifTrue: [nil]
- 				ifFalse: [oldPageIndex < pageIndex].
- 	tSpec := transitionSpec ifNil: 
- 					["If transition not specified by requestor..."
- 
- 					newPage valueOfProperty: #transitionSpec
- 						ifAbsent: 
- 							[" ... then consult new page"
- 
- 							self transitionSpecFor: self	" ... otherwise this is the default"]].
- 	self flag: #arNote.	"Probably unnecessary"
- 	(aWorld := self world) ifNotNil: [self primaryHand releaseKeyboardFocus].
- 	currentPage ifNotNil: [currentPage updateCachedThumbnail].
- 	self currentPage notNil 
- 		ifTrue: 
- 			[(((pages at: pageIndex) owner isKindOf: TransitionMorph) 
- 				and: [(pages at: pageIndex) isInWorld]) 
- 					ifTrue: [^self	"In the process of a prior pageTurn"].
- 			self currentPlayerDo: [:aPlayer | aPlayer runAllClosingScripts].
- 			self removeViewersOnSubsIn: self currentWorld presenter.
- 			ascending ifNotNil: 
- 					["Show appropriate page transition and start new page when done"
- 
- 					currentPage stopStepping.
- 					(pages at: pageIndex) position: currentPage position.
- 					^(TransitionMorph 
- 						effect: tSpec second
- 						direction: tSpec third
- 						inverse: (ascending or: [transitionSpec notNil]) not) 
- 							showTransitionFrom: currentPage
- 							to: (pages at: pageIndex)
- 							in: self
- 							whenStart: [self playPageFlipSound: tSpec first]
- 							whenDone: 
- 								[currentPage
- 									delete;
- 									fullReleaseCachedState.
- 								self insertPageMorphInCorrectSpot: (pages at: pageIndex).
- 								self adjustCurrentPageForFullScreen.
- 								self snapToEdgeIfAppropriate.
- 								aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage].
- 								self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts].
- 								(aWorld := self world) ifNotNil: 
- 										["WHY??"
- 
- 										aWorld displayWorld].
- 								readIn 
- 									ifTrue: 
- 										[currentPage updateThumbnailUrlInBook: self url.
- 										currentPage sqkPage computeThumbnail	"just store it"]]].
- 
- 			"No transition, but at least decommission current page"
- 			currentPage
- 				delete;
- 				fullReleaseCachedState].
- 	self insertPageMorphInCorrectSpot: (pages at: pageIndex). 	"sets currentPage"
- 	self adjustCurrentPageForFullScreen.
- 	self snapToEdgeIfAppropriate.
- 	aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage].
- 	self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts].
- 	(aWorld := self world) ifNotNil: 
- 			["WHY??"
- 			aWorld displayWorld].
- 	readIn 
- 		ifTrue: 
- 			[currentPage updateThumbnailUrl.
- 			currentPage sqkPage computeThumbnail	"just store it"].
- 	self currentWorld presenter flushPlayerListCache.!

Item was removed:
- ----- Method: BookMorph>>goToPageMorph:transitionSpec:runTransitionScripts: (in category 'navigation') -----
- goToPageMorph: newPage transitionSpec: transitionSpec runTransitionScripts: aBoolean 
- 	"Install the given page as the new current page; use the given transition spec, and if the boolean parameter is true, run closing and opening scripts on the outgoing and incoming players"
- 
- 	| pageIndex aWorld oldPageIndex ascending tSpec readIn |
- 	pages isEmpty ifTrue: [^self].
- 	self setProperty: #searchContainer toValue: nil.	"forget previous search"
- 	self setProperty: #searchOffset toValue: nil.
- 	self setProperty: #searchKey toValue: nil.
- 	pageIndex := pages identityIndexOf: newPage ifAbsent: [^self	"abort"].
- 	readIn := newPage isInMemory not.
- 	oldPageIndex := pages identityIndexOf: currentPage ifAbsent: [nil].
- 	ascending := (oldPageIndex isNil or: [newPage == currentPage]) 
- 				ifTrue: [nil]
- 				ifFalse: [oldPageIndex < pageIndex].
- 	tSpec := transitionSpec ifNil: 
- 					["If transition not specified by requestor..."
- 
- 					newPage valueOfProperty: #transitionSpec
- 						ifAbsent: 
- 							[" ... then consult new page"
- 
- 							self transitionSpecFor: self	" ... otherwise this is the default"]].
- 	self flag: #arNote.	"Probably unnecessary"
- 	(aWorld := self world) ifNotNil: [self primaryHand releaseKeyboardFocus].
- 	currentPage ifNotNil: [currentPage updateCachedThumbnail].
- 	self currentPage notNil 
- 		ifTrue: 
- 			[(((pages at: pageIndex) owner isKindOf: TransitionMorph) 
- 				and: [(pages at: pageIndex) isInWorld]) 
- 					ifTrue: [^self	"In the process of a prior pageTurn"].
- 			aBoolean 
- 				ifTrue: [self currentPlayerDo: [:aPlayer | aPlayer runAllClosingScripts]].
- 			ascending ifNotNil: 
- 					["Show appropriate page transition and start new page when done"
- 
- 					currentPage stopStepping.
- 					(pages at: pageIndex) position: currentPage position.
- 					^(TransitionMorph 
- 						effect: tSpec second
- 						direction: tSpec third
- 						inverse: (ascending or: [transitionSpec notNil]) not) 
- 							showTransitionFrom: currentPage
- 							to: (pages at: pageIndex)
- 							in: self
- 							whenStart: [self playPageFlipSound: tSpec first]
- 							whenDone: 
- 								[currentPage
- 									delete;
- 									fullReleaseCachedState.
- 								self insertPageMorphInCorrectSpot: (pages at: pageIndex).
- 								self adjustCurrentPageForFullScreen.
- 								self snapToEdgeIfAppropriate.
- 								aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage].
- 								aBoolean 
- 									ifTrue: [self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts]].
- 								(aWorld := self world) ifNotNil: 
- 										["WHY??"
- 
- 										aWorld displayWorld].
- 								readIn 
- 									ifTrue: 
- 										[currentPage updateThumbnailUrlInBook: self url.
- 										currentPage sqkPage computeThumbnail	"just store it"]]].
- 
- 			"No transition, but at least decommission current page"
- 			currentPage
- 				delete;
- 				fullReleaseCachedState].
- 	self insertPageMorphInCorrectSpot: (pages at: pageIndex).
- 	self adjustCurrentPageForFullScreen.
- 	self snapToEdgeIfAppropriate.
- 	aWorld ifNotNil: [self world startSteppingSubmorphsOf: currentPage].
- 	self currentPlayerDo: [:aPlayer | aPlayer runAllOpeningScripts].
- 	(aWorld := self world) ifNotNil: 
- 			["WHY??"
- 
- 			aWorld displayWorld].
- 	readIn 
- 		ifTrue: 
- 			[currentPage updateThumbnailUrl.
- 			currentPage sqkPage computeThumbnail	"just store it"]!

Item was removed:
- ----- Method: BookMorph>>goToPageUrl: (in category 'navigation') -----
- goToPageUrl: aUrl 
- 	| pp short |
- 	pp := pages detect: [:pg | pg url = aUrl] ifNone: [nil].
- 	pp ifNil: 
- 			[short := (aUrl findTokens: '/') last.
- 			pp := pages detect: 
- 							[:pg | 
- 							pg url ifNil: [false] ifNotNil: [(pg url findTokens: '/') last = short]	"it moved"]
- 						ifNone: [pages first]].
- 	self goToPageMorph: pp!

Item was removed:
- ----- Method: BookMorph>>goto: (in category 'navigation') -----
- goto: aPlayer
- 	self goToPageMorph: aPlayer costume!

Item was removed:
- ----- Method: BookMorph>>highlightText:at:in: (in category 'menu') -----
- highlightText: stringToHilite at: index in: insideOf 
- 	"Find the container with this text and highlight it.  May not be able to do it for stringMorphs."
- 
- 	"Find the container with that text"
- 
- 	| container |
- 	self 
- 		allMorphsDo: [:sub | insideOf == sub userString ifTrue: [container := sub]].
- 	container ifNil: 
- 			[self 
- 				allMorphsDo: [:sub | insideOf = sub userString ifTrue: [container := sub]]].	"any match"
- 	container ifNil: [^nil].
- 
- 	"Order it highlighted"
- 	(container isTextMorph) 
- 		ifTrue: 
- 			[container editor selectFrom: index to: stringToHilite size - 1 + index].
- 	container changed.
- 	^container!

Item was removed:
- ----- Method: BookMorph>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- ""
- 	self setInitialState.
- 	pages := OrderedCollection new.
- 	self showPageControls.
- 	self class
- 		turnOffSoundWhile: [self insertPage]!

Item was removed:
- ----- Method: BookMorph>>initializeToStandAlone (in category 'parts bin') -----
- initializeToStandAlone
- 	super initializeToStandAlone.
- 	self removeEverything; pageSize: 360 at 228; color: Color white.
- 	self borderWidth: 1; borderColor: Color black.
- 	self beSticky.
- 	self showPageControls; insertPage.
- 	^ self!

Item was removed:
- ----- Method: BookMorph>>insertPage:pageSize: (in category 'insert and delete') -----
- insertPage: aPage pageSize: aPageSize
- 	^ self insertPage: aPage pageSize: aPageSize atIndex: (pages size + 1)!

Item was removed:
- ----- Method: BookMorph>>insertPage:pageSize:atIndex: (in category 'insert and delete') -----
- insertPage: aPage pageSize: aPageSize atIndex: anIndex 
- 	| sz predecessor |
- 	sz := aPageSize 
- 				ifNil: [currentPage isNil ifTrue: [pageSize] ifFalse: [currentPage extent]]
- 				ifNotNil: [aPageSize].
- 	aPage extent: sz.
- 	(pages isEmpty | anIndex isNil or: [anIndex > pages size]) 
- 		ifTrue: [pages add: aPage]
- 		ifFalse: 
- 			[anIndex <= 1 
- 				ifTrue: [pages addFirst: aPage]
- 				ifFalse: 
- 					[predecessor := anIndex isNil 
- 								ifTrue: [currentPage]
- 								ifFalse: [pages at: anIndex].
- 					self pages add: aPage after: predecessor]].
- 	self goToPageMorph: aPage!

Item was removed:
- ----- Method: BookMorph>>insertPageColored: (in category 'insert and delete') -----
- insertPageColored: aColor 
- 	"Insert a new page for the receiver, using the given color as its background color"
- 
- 	| pageExtent newPage borderWidth backgroundColor |
- 	backgroundColor := currentPage isNil 
- 				ifTrue: 
- 					[pageExtent := pageSize.
- 					borderWidth := 0.
- 					Color blue muchLighter]
- 				ifFalse: 
- 					[pageExtent := currentPage extent.
- 					borderWidth := currentPage borderWidth.
- 					currentPage borderColor].
- 	newPagePrototype ifNil: 
- 			[newPage := (PasteUpMorph new)
- 						extent: pageExtent;
- 						color: aColor.
- 			newPage
- 				borderWidth: borderWidth;
- 				borderColor: backgroundColor]
- 		ifNotNil: [newPage := Cursor wait showWhile: [newPagePrototype veryDeepCopy]].
- 	newPage setNameTo: self defaultNameStemForNewPages.
- 	newPage vResizeToFit: false.
- 	pages isEmpty 
- 		ifTrue: [pages add: (currentPage := newPage)]
- 		ifFalse: [pages add: newPage after: currentPage].
- 	self nextPage!

Item was removed:
- ----- Method: BookMorph>>insertPageLabel:morphs: (in category 'insert and delete') -----
- insertPageLabel: labelString morphs: morphList
- 
- 	| m c labelAllowance |
- 	self insertPage.
- 	labelString ifNotNil:
- 			[m := labelString asMorph.
- 		m lock.
- 		m position: currentPage position + (((currentPage width - m width) // 2) @ 5).
- 		currentPage addMorph: m.
- 		labelAllowance := 40]
- 		ifNil:
- 			[labelAllowance := 0].
- 
- 	"use a column to align the given morphs, then add them to the page"
- 	c := AlignmentMorph newColumn wrapCentering: #center; cellPositioning: #topCenter.
- 	c addAllMorphs: morphList.
- 	c position: currentPage position + (0 @ labelAllowance).
- 	currentPage addAllMorphs: morphList.
- 	^ currentPage
- !

Item was removed:
- ----- Method: BookMorph>>insertPageMorphInCorrectSpot: (in category 'navigation') -----
- insertPageMorphInCorrectSpot: aPageMorph
- 
- 	self addMorphBack: (currentPage := aPageMorph).
- !

Item was removed:
- ----- Method: BookMorph>>insertPageSilentlyAtEnd (in category 'insert and delete') -----
- insertPageSilentlyAtEnd
- 	"Create a new page at the end of the book.  Do not turn to it."
- 
- 	| sz newPage bw bc cc |
- 	cc := currentPage isNil 
- 				ifTrue: 
- 					[sz := pageSize.
- 					bw := 0.
- 					bc := Color blue muchLighter.
- 					color]
- 				ifFalse: 
- 					[sz := currentPage extent.
- 					bw := currentPage borderWidth.
- 					bc := currentPage borderColor.
- 					currentPage color].
- 	newPagePrototype ifNil: 
- 			[newPage := (PasteUpMorph new)
- 						extent: sz;
- 						color: cc.
- 			newPage
- 				borderWidth: bw;
- 				borderColor: bc]
- 		ifNotNil: [newPage := Cursor wait showWhile: [newPagePrototype veryDeepCopy]].
- 	newPage setNameTo: self defaultNameStemForNewPages.
- 	newPage vResizeToFit: false.
- 	pages isEmpty 
- 		ifTrue: [pages add: (currentPage := newPage)	"had been none"]
- 		ifFalse: [pages add: newPage after: pages last].
- 	^newPage!

Item was removed:
- ----- Method: BookMorph>>invokeBookMenu (in category 'menu') -----
- invokeBookMenu
- 	"Invoke the book's control panel menu."
- 	| aMenu |
- 	aMenu := MenuMorph new defaultTarget: self.
- 	aMenu addTitle: 'Book' translated.
- 	Preferences noviceMode
- 		ifFalse:[aMenu addStayUpItem].
- 	aMenu add: 'find...' translated action: #textSearch.
- 	aMenu add: 'go to page...' translated action: #goToPage.
- 	aMenu addLine.
- 
- 	aMenu addList: {
- 		{'sort pages' translated.		#sortPages}.
- 		{'uncache page sorter' translated.	#uncachePageSorter}}.
- 	(self hasProperty: #dontWrapAtEnd)
- 		ifTrue: [aMenu add: 'wrap after last page' translated selector: #setWrapPages: argument: true]
- 		ifFalse: [aMenu add: 'stop at last page' translated selector: #setWrapPages: argument: false].
- 	aMenu addList: {
- 		{'make bookmark' translated.		#bookmarkForThisPage}.
- 		{'make thumbnail' translated.		#thumbnailForThisPage}}.
- 	aMenu addUpdating: #showingPageControlsString action: #toggleShowingOfPageControls.
- 	aMenu addUpdating: #showingFullScreenString action: #toggleFullScreen.
- 
- 	aMenu addLine.
- 	aMenu add: 'sound effect for all pages' translated action: #menuPageSoundForAll:.
- 	aMenu add: 'sound effect this page only' translated action: #menuPageSoundForThisPage:.
- 	aMenu add: 'visual effect for all pages' translated action: #menuPageVisualForAll:.
- 	aMenu add: 'visual effect this page only' translated action: #menuPageVisualForThisPage:.
- 
- 	aMenu addLine.
- 	(self primaryHand pasteBuffer class isKindOf: PasteUpMorph class) ifTrue:
- 		[aMenu add: 'paste book page' translated   action: #pasteBookPage].
- 
- 	aMenu add: 'save as new-page prototype' translated action: #setNewPagePrototype.
- 	newPagePrototype ifNotNil: [
- 		aMenu add: 'clear new-page prototype' translated action: #clearNewPagePrototype].
- 
- 	aMenu add: (self dragNDropEnabled ifTrue: ['close dragNdrop'] ifFalse: ['open dragNdrop']) translated
- 			action: #changeDragAndDrop.
- 	aMenu add: 'make all pages this size' translated action: #makeUniformPageSize.
- 	
- 	aMenu
- 		addUpdating: #keepingUniformPageSizeString
- 		target: self
- 		action: #toggleMaintainUniformPageSize.
- 	aMenu addLine.
- 
- 	aMenu add: 'send all pages to server' translated action: #savePagesOnURL.
- 	aMenu add: 'send this page to server' translated action: #saveOneOnURL.
- 	aMenu add: 'reload all from server' translated action: #reload.
- 	aMenu add: 'copy page url to clipboard' translated action: #copyUrl.
- 	aMenu add: 'keep in one file' translated action: #keepTogether.
- 
- 	aMenu addLine.
- 	aMenu add: 'load PPT images from slide #1' translated action: #loadImagesIntoBook.
- 	aMenu add: 'background color for all pages...' translated action: #setPageColor.
- 	aMenu add: 'make a thread of projects in this book' translated action: #buildThreadOfProjects.
- 
- 	aMenu popUpEvent: self world activeHand lastEvent in: self world
- !

Item was removed:
- ----- Method: BookMorph>>isInFullScreenMode (in category 'other') -----
- isInFullScreenMode
- 
- 	^self valueOfProperty: #fullScreenMode ifAbsent: [false]!

Item was removed:
- ----- Method: BookMorph>>keepTogether (in category 'menu') -----
- keepTogether
- 	"Mark this book so that each page will not go into a separate file.  Do this when pages share referenes to a common Player.  Don't want many copies of that Player when bring in.  Do not write pages of book out.  Write the PasteUpMorph that the entire book lives in."
- 
- 	self setProperty: #keepTogether toValue: true.!

Item was removed:
- ----- Method: BookMorph>>keepingUniformPageSizeString (in category 'uniform page size') -----
- keepingUniformPageSizeString
- 	"Answer a string characterizing whether I am currently maintaining uniform page size"
- 
- 	^ (self maintainsUniformPageSize
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>']), 'keep all pages the same size' translated!

Item was removed:
- ----- Method: BookMorph>>lastPage (in category 'navigation') -----
- lastPage
- 	self goToPage: pages size
- !

Item was removed:
- ----- Method: BookMorph>>loadImagesIntoBook (in category 'menu') -----
- loadImagesIntoBook
- 	"PowerPoint stores GIF presentations as individual slides named Slide1, Slide2, etc.
- 	Load these into the book.  mjg 9/99"
- 
- 	| directory filenumber form newpage |
- 	directory :=DirectoryChooserDialog openOn: FileDirectory default label: 'Select the directory to load pages from'.
- 	directory ifNil: [^ self].
- 
- 	"Start loading 'em up!!"
- 	filenumber := 1.
- 	[directory fileExists: 'Slide' , filenumber asString] whileTrue: 
- 			[Transcript
- 				show: 'Slide' , filenumber asString;
- 				cr.
- 			Smalltalk bytesLeft < 1000000 
- 				ifTrue: 
- 					["Make some room"
- 
- 					(self valueOfProperty: #url) isNil 
- 						ifTrue: [self savePagesOnURL]
- 						ifFalse: [self saveAsNumberedURLs]].
- 			form := Form 
- 						fromFileNamed: (directory fullNameFor: 'Slide' , filenumber asString).
- 			newpage := PasteUpMorph new extent: form extent.
- 			newpage addMorph: (self world drawingClass withForm: form).
- 			self pages addLast: newpage.
- 			filenumber := filenumber + 1].
- 
- 	"After adding all, delete the first page."
- 	self goToPage: 1.
- 	self deletePageBasic.
- 
- 	"Save the book"
- 	(self valueOfProperty: #url) isNil 
- 		ifTrue: [self savePagesOnURL]
- 		ifFalse: [self saveAsNumberedURLs]!

Item was removed:
- ----- Method: BookMorph>>maintainsUniformPageSize (in category 'uniform page size') -----
- maintainsUniformPageSize
- 	"Answer whether I am currently set up to maintain uniform page size"
- 
- 	^ self uniformPageSize notNil!

Item was removed:
- ----- Method: BookMorph>>maintainsUniformPageSize: (in category 'uniform page size') -----
- maintainsUniformPageSize: aBoolean
- 	"Set the property governing whether I maintain uniform page size"
- 
- 	aBoolean
- 		ifFalse:
- 			[self removeProperty: #uniformPageSize]
- 		ifTrue:
- 			[self setProperty: #uniformPageSize toValue: currentPage extent]!

Item was removed:
- ----- Method: BookMorph>>makeMinimalControlsWithColor:title: (in category 'other') -----
- makeMinimalControlsWithColor: aColor title: aString
- 
- 	| aButton aColumn aRow but |
- 	aButton := SimpleButtonMorph new target: self; borderColor: Color black; 
- 				color: aColor; borderWidth: 0.
- 	aColumn := AlignmentMorph newColumn.
- 	aColumn color: aButton color; borderWidth: 0; layoutInset: 0.
- 	aColumn hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 
- 	aRow := AlignmentMorph newRow.
- 	aRow color: aButton color; borderWidth: 0; layoutInset: 0.
- 	aRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	aRow addTransparentSpacerOfSize: 40 at 0.
- 	aRow addMorphBack: (but := aButton label: ' < ' ; actionSelector: #previousPage).
- 		"copy is OK, since we just made it and it can't own any Players"
- 	but setBalloonText: 'Go to previous page'.
- 	aRow addTransparentSpacerOfSize: 82 at 0.
- 	aRow addMorphBack: (StringMorph contents: aString) lock.
- 	aRow addTransparentSpacerOfSize: 82 at 0.
- 	aButton := SimpleButtonMorph new target: self; borderColor: Color black; 
- 				color: aColor; borderWidth: 0.
- 	aRow addMorphBack: (but := aButton label: ' > ' ; actionSelector: #nextPage).
- 	but setBalloonText: 'Go to next page'.
- 	aRow addTransparentSpacerOfSize: 40 at 0.
- 
- 	aColumn addMorphBack: aRow.
- 
- 	aColumn setNameTo: 'Page Controls'.
- 	
- 	^ aColumn!

Item was removed:
- ----- Method: BookMorph>>makeUniformPageSize (in category 'menu') -----
- makeUniformPageSize
- 	"Make all pages be of the same size as the current page."
- 	currentPage ifNil: [^ Beeper beep].
- 	self resizePagesTo: currentPage extent.
- 	newPagePrototype ifNotNil:
- 		[newPagePrototype extent: currentPage extent]!

Item was removed:
- ----- Method: BookMorph>>menuPageSoundFor:event: (in category 'menu') -----
- menuPageSoundFor: target event: evt
- 	| tSpec menu |
- 	tSpec := self transitionSpecFor: target.
- 	menu := (MenuMorph entitled: 'Choose a sound
- (it is now ' translated, tSpec first translated, ')') defaultTarget: target.
- 	SoundService default sampledSoundChoices do:
- 		[:soundName |
- 		menu add: soundName translated target: target
- 			selector: #setProperty:toValue:
- 			argumentList: (Array with: #transitionSpec
- 								with: (tSpec copy at: 1 put: soundName; yourself))].
- 
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: BookMorph>>menuPageSoundForAll: (in category 'menu') -----
- menuPageSoundForAll: evt
- 
- 	^ self menuPageSoundFor: self event: evt!

Item was removed:
- ----- Method: BookMorph>>menuPageSoundForThisPage: (in category 'menu') -----
- menuPageSoundForThisPage: evt
- 
- 	currentPage ifNotNil:
- 		[^ self menuPageSoundFor: currentPage event: evt]!

Item was removed:
- ----- Method: BookMorph>>menuPageVisualFor:event: (in category 'menu') -----
- menuPageVisualFor: target event: evt
- 	| tSpec menu |
- 	tSpec := self transitionSpecFor: target.
- 	menu := (MenuMorph entitled: ('Choose an effect
- (it is now {1})' translated format:{tSpec second asString translated})) defaultTarget: target.
- 	TransitionMorph allEffects do:
- 		[:effect | | subMenu directionChoices |
- 		directionChoices := TransitionMorph directionsForEffect: effect.
- 		directionChoices isEmpty
- 		ifTrue: [menu add: effect asString translated target: target
- 					selector: #setProperty:toValue:
- 					argumentList: (Array with: #transitionSpec
- 									with: (Array with: tSpec first with: effect with: #none))]
- 		ifFalse: [subMenu := MenuMorph new.
- 				directionChoices do:
- 					[:dir |
- 					subMenu add: dir asString translated target: target
- 						selector: #setProperty:toValue:
- 						argumentList: (Array with: #transitionSpec
- 									with: (Array with: tSpec first with: effect with: dir))].
- 				menu add: effect asString translated subMenu: subMenu]].
- 
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: BookMorph>>menuPageVisualForAll: (in category 'menu') -----
- menuPageVisualForAll: evt
- 
- 	^ self menuPageVisualFor: self event: evt!

Item was removed:
- ----- Method: BookMorph>>menuPageVisualForThisPage: (in category 'menu') -----
- menuPageVisualForThisPage: evt
- 
- 	currentPage ifNotNil:
- 		[^ self menuPageVisualFor: currentPage event: evt]!

Item was removed:
- ----- Method: BookMorph>>methodHolderVersions (in category 'scripting') -----
- methodHolderVersions
- 	| arrayOfVersions vTimes |
- 	"Create lists of times of older versions of all code in MethodMorphs in this book."
- 
- 	arrayOfVersions := MethodHolders collect: [:mh | 
- 		mh versions].	"equality, hash for MethodHolders?"
- 	vTimes := OrderedCollection new.
- 	arrayOfVersions do: [:versionBrowser |  
- 		versionBrowser changeList do: [:cr | | strings | 
- 			(strings := cr stamp findTokens: ' ') size > 2 ifTrue: [
- 				vTimes add: strings second asDate asSeconds + 
- 						strings third asTime asSeconds]]].
- 	VersionTimes := Time condenseBunches: vTimes.
- 	VersionNames := Time namesForTimes: VersionTimes.
- !

Item was removed:
- ----- Method: BookMorph>>morphsForPageSorter (in category 'sorting') -----
- morphsForPageSorter
- 	| thumbnails |
- 	'Assembling thumbnail images...'
- 		displayProgressFrom: 0 to: pages size
- 		during:
- 			[:bar | | i |
- 			i := 0.
- 			thumbnails := pages collect:
- 				[:p | bar value: (i:= i+1).
- 				pages size > 40 
- 					ifTrue: [p smallThumbnailForPageSorter inBook: self]
- 					ifFalse: [p thumbnailForPageSorter inBook: self]]].
- 	^ thumbnails!

Item was removed:
- ----- Method: BookMorph>>newPages: (in category 'initialization') -----
- newPages: pageList
- 	"Replace all my pages with the given list of BookPageMorphs.  After this call, currentPage may be invalid."
- 
- 	pages := pages species new.
- 	pages addAll: pageList!

Item was removed:
- ----- Method: BookMorph>>newPages:currentIndex: (in category 'initialization') -----
- newPages: pageList currentIndex: index
- 	"Replace all my pages with the given list of BookPageMorphs. Make the current page be the page with the given index."
- 
- 	pages := pages species new.
- 	pages addAll: pageList.
- 	pages isEmpty ifTrue: [^ self insertPage].
- 	self goToPage: index.
- !

Item was removed:
- ----- Method: BookMorph>>nextPage (in category 'navigation') -----
- nextPage
- 	currentPage isNil ifTrue: [^self goToPage: 1].
- 	self goToPage: (self pageNumberOf: currentPage) + 1!

Item was removed:
- ----- Method: BookMorph>>pageControlsVisible (in category 'menu') -----
- pageControlsVisible
- 	^ self hasSubmorphWithProperty: #pageControl!

Item was removed:
- ----- Method: BookMorph>>pageNamed: (in category 'accessing') -----
- pageNamed: aName
- 	^ pages detect: [:p | p knownName = aName] ifNone: [nil]!

Item was removed:
- ----- Method: BookMorph>>pageNumber (in category 'navigation') -----
- pageNumber
- 
- 	^ self pageNumberOf: currentPage!

Item was removed:
- ----- Method: BookMorph>>pageNumberOf: (in category 'accessing') -----
- pageNumberOf: aMorph
- 	"Modified so that if the page IS in memory, other pages don't have to be brought in.  (This method may wrongly say a page is not here if pages has a tombstone (MorphObjectOut) and that tombstone would resolve to an object already in this image.  This is an unlikely case, and callers just have to tolerate it.)"
- 
- 	^ pages identityIndexOf: aMorph
- !

Item was removed:
- ----- Method: BookMorph>>pages (in category 'accessing') -----
- pages
- 
- 	^ pages
- !

Item was removed:
- ----- Method: BookMorph>>pages: (in category 'accessing') -----
- pages: aMorphList
- 
- 	pages := aMorphList asOrderedCollection.
- 
- 	"It is tempting to force the first page to be the current page.  But then, two pages might be shown at once!!  Just trust the copying mechanism and let currentPage be copied correctly. --Ted."!

Item was removed:
- ----- Method: BookMorph>>pagesHandledAutomatically (in category 'printing') -----
- pagesHandledAutomatically
- 
- 	^true!

Item was removed:
- ----- Method: BookMorph>>pasteBookPage (in category 'menu') -----
- pasteBookPage
- 	"If the paste buffer has something to paste, paste it as a book page."
- 
- 	| aPage |
- 	aPage := self primaryHand objectToPaste.
- 	aPage removeProperty: #revertKey.
- 
- 	self insertPage: aPage pageSize: aPage extent atIndex: ((pages indexOf: currentPage) - 1).
- 	"self goToPageMorph: aPage"!

Item was removed:
- ----- Method: BookMorph>>previousPage (in category 'navigation') -----
- previousPage
- 	currentPage isNil ifTrue: [^self goToPage: 1].
- 	self goToPage: (self pageNumberOf: currentPage) - 1!

Item was removed:
- ----- Method: BookMorph>>printPSToFile (in category 'menus') -----
- printPSToFile
- 	"Ask the user for a filename and print this morph as postscript."
- 
- 	| fileName rotateFlag |
- 	fileName := 'MyBook' translated asFileName.
- 	fileName := Project uiManager
- 					saveFilenameRequest: 'Filename to save BookMorph' translated 
- 					initialAnswer: fileName.
- 	fileName isEmptyOrNil ifTrue: [^ Beeper beep].
- 	(fileName endsWith: '.ps') ifFalse:
- 		[fileName := fileName,'.ps'].
- 	rotateFlag := (Project uiManager
- 					chooseOptionFrom: {'portrait (tall)' translated. 'landscape (wide)' translated}
- 					title: 'Choose orientation...' translated) = 2.
- 	FileStream
- 		newFileNamed: fileName
- 		do:
- 			[:file|
- 			file nextPutAll: (DSCPostscriptCanvas morphAsPostscript: self rotated: rotateFlag)]!

Item was removed:
- ----- Method: BookMorph>>releaseCachedState (in category 'caching') -----
- releaseCachedState
- 	"Release the cached state of all my pages."
- 
- 	super releaseCachedState.
- 	self removeProperty: #allText.	"the cache for text search"
- 	pages do: [:page | 
- 		page == currentPage ifFalse: [page fullReleaseCachedState].
- 		page removeProperty: #cachedThumbnail].!

Item was removed:
- ----- Method: BookMorph>>reload (in category 'menu') -----
- reload
- 	"Fetch the pages of this book from the server again.  For all pages that have not been modified, keep current ones.  Use new pages.  For each, look up in cache, if time there is equal to time of new, and its in, use the current morph.
- 	Later do fancy things when a page has changed here, and also on the server."
- 
- 	| url onServer onPgs which |
- 	(url := self valueOfProperty: #url) ifNil: ["for .bo index file"
- 	url := UIManager default 
- 		request: 'url of the place where this book''s index is stored.
- Must begin with file:// or ftp://' translated
- 		initialAnswer: (self getStemUrl, '.bo').
- 	url notEmpty ifTrue: [self setProperty: #url toValue: url]
- 				ifFalse: [^ self]].
- 	onServer := self class new fromURL: url.
- 	"Later: test book times?"
- 	onPgs := onServer pages collect: [:out | | sq |
- 		sq := SqueakPageCache pageCache at: out url ifAbsent: [nil].
- 		(sq notNil and: [sq contentsMorph isInMemory])
- 			ifTrue: [((out sqkPage lastChangeTime > sq lastChangeTime) or: 
- 					  [sq contentsMorph isNil]) 
- 						ifTrue: [SqueakPageCache atURL: out url put: out sqkPage.
- 							out]
- 						ifFalse: [sq contentsMorph]]
- 			ifFalse: [SqueakPageCache atURL: out url put: out sqkPage.
- 				out]].
- 	which := (onPgs findFirst: [:pg | pg url = currentPage url]) max: 1.
- 	self newPages: onPgs currentIndex: which.
- 		"later stay at current page"
- 	self setProperty: #modTime toValue: (onServer valueOfProperty: #modTime).
- 	self setProperty: #allText toValue: (onServer valueOfProperty: #allText).
- 	self setProperty: #allTextUrls toValue: (onServer valueOfProperty: #allTextUrls).
- !

Item was removed:
- ----- Method: BookMorph>>removeEverything (in category 'initialization') -----
- removeEverything
- 	currentPage := nil.
- 	pages := OrderedCollection new.
- 	self removeAllMorphs!

Item was removed:
- ----- Method: BookMorph>>reserveUrls (in category 'menu') -----
- reserveUrls
- 	"Save a dummy version of the book first, assign all pages URLs, write dummy files to reserve the url, and write the index.  Good when I have pages with interpointing bookmarks."
- 
- 	| stem |
- 	(stem := self getStemUrl) isEmpty ifTrue: [^self].
- 	pages withIndexDo: 
- 			[:pg :ind | 
- 			"does write the current page too"
- 
- 			pg url ifNil: [pg reserveUrl: stem , ind printString , '.sp']]
- 
- 	"self saveIndexOnURL."!

Item was removed:
- ----- Method: BookMorph>>reserveUrlsIfNeeded (in category 'menu') -----
- reserveUrlsIfNeeded
- 	"See if this book needs to pre-allocate urls.  Harmless if have urls already.  Actually writes dummy files to reserve names."
- 
- | baddies bad2 |
- pages size > 25 ifTrue: [^ self reserveUrls].
- baddies := BookPageThumbnailMorph withAllSubclasses.
- bad2 := FlexMorph withAllSubclasses.
- pages do: [:aPage |
- 	aPage allMorphsDo: [:mm | 
- 		(baddies includes: mm class) ifTrue: [^ self reserveUrls].
- 		(bad2 includes: mm class) ifTrue: [
- 			mm originalMorph class == aPage class ifTrue: [
- 				^ self reserveUrls]]]].
- 		
- !

Item was removed:
- ----- Method: BookMorph>>resizePagesTo: (in category 'other') -----
- resizePagesTo: anExtent
- 	pages do:
- 		[:aPage | aPage extent: anExtent]!

Item was removed:
- ----- Method: BookMorph>>revertToCheckpoint: (in category 'scripting') -----
- revertToCheckpoint: secsSince1901
- 	
- 	"Put all scripts (that appear in MethodPanes) back to the way they were at an earlier time."
- 
- 	MethodHolders do: [:mh | | cngRecord | 
- 		cngRecord := mh versions versionFrom: secsSince1901.
- 		cngRecord ifNotNil: [
- 			(cngRecord stamp: Utilities changeStamp) fileIn]].
- 		"does not delete method if no earlier version"
- 
- !

Item was removed:
- ----- Method: BookMorph>>saveAsNumberedURLs (in category 'menu') -----
- saveAsNumberedURLs
- 	"Write out all pages in this book that are not showing, onto a server.  The local disk could be the server.  For any page that does not have a SqueakPage and a url already, name that page file by its page number.  Any pages that are already totally out will stay that way."
- 
- 	| stem list firstTime |
- 	firstTime := (self valueOfProperty: #url) isNil.
- 	stem := self getStemUrl.	"user must approve"
- 	stem isEmpty ifTrue: [^self].
- 	firstTime ifTrue: [self setProperty: #futureUrl toValue: stem , '.bo'].
- 	self reserveUrlsIfNeeded.
- 	pages withIndexDo: 
- 			[:aPage :ind | 
- 			"does write the current page too"
- 
- 			aPage isInMemory 
- 				ifTrue: 
- 					["not out now"
- 
- 					aPage presenter ifNotNil: [aPage presenter flushPlayerListCache].
- 					aPage saveOnURL: stem , ind printString , '.sp']].
- 	list := pages collect: [:aPage | aPage sqkPage prePurge].
- 	"knows not to purge the current page"
- 	list := (list select: [:each | each notNil]) asArray.
- 	"do bulk become:"
- 	(list collect: [:each | each contentsMorph]) 
- 		elementsExchangeIdentityWith: (list 
- 				collect: [:spg | MorphObjectOut new xxxSetUrl: spg url page: spg]).
- 	self saveIndexOnURL.
- 	self presenter ifNotNil: [self presenter flushPlayerListCache].
- 	firstTime 
- 		ifTrue: 
- 			["Put a thumbnail into the hand"
- 
- 			URLMorph grabForBook: self.
- 			self setProperty: #futureUrl toValue: nil	"clean up"]!

Item was removed:
- ----- Method: BookMorph>>saveIndexOfOnly: (in category 'menu') -----
- saveIndexOfOnly: aPage
- 	"Modify the index of this book on a server.  Read the index, modify the entry for just this page, and write back.  See saveIndexOnURL. (page file names must be unique even if they live in different directories.)"
- 
- 	| mine sf remote pageURL num pre index after dict allText allTextUrls fName strm |
- 	mine := self valueOfProperty: #url.
- 	mine ifNil: [^ self saveIndexOnURL].
- 	strm := Cursor wait showWhile: [ServerFile new fullPath: mine].
- 	strm ifNil: [^ self saveIndexOnURL].
- 	strm isString ifTrue: [^ self saveIndexOnURL].
- 	strm exists ifFalse: [^ self saveIndexOnURL].	"write whole thing if missing"
- 	strm := strm asStream.
- 	strm isString ifTrue: [^ self saveIndexOnURL].
- 	remote := strm fileInObjectAndCode.
- 	dict := remote first.
- 	allText := dict at: #allText ifAbsent: [nil].	"remote, not local"
- 	allTextUrls := dict at: #allTextUrls ifAbsent: [nil].
- 	allText size + 1 ~= remote size ifTrue: [self error: '.bo size mismatch.  Please tell Ted what you just did to this book.' translated].
- 
- 
- 	(pageURL := aPage url) ifNil: [self error: 'just had one!!' translated].
- 	fName := pageURL copyAfterLast: $/.
- 	2 to: remote size do: [:ii | 
- 		((remote at: ii) url findString: fName startingAt: 1 
- 						caseSensitive: false) > 0 ifTrue: [index := ii].	"fast"
- 		(remote at: ii) xxxReset].
- 	index ifNil: ["new page, what existing page does it follow?"
- 		num := self pageNumberOf: aPage.
- 		1 to: num-1 do: [:ii | (pages at: ii) url ifNotNil: [pre := (pages at: ii) url]].
- 		pre ifNil: [after := remote size+1]
- 			ifNotNil: ["look for it on disk, put me after"
- 				pre := pre copyAfterLast: $/.
- 				2 to: remote size do: [:ii | 
- 					((remote at: ii) url findString: pre startingAt: 1 
- 								caseSensitive: false) > 0 ifTrue: [after := ii+1]].
- 				after ifNil: [after := remote size+1]].
- 		remote := remote copyReplaceFrom: after to: after-1 with: #(1).
- 		allText ifNotNil: [
- 			dict at: #allText put: (allText copyReplaceFrom: after-1 to: after-2 with: #(())).
- 			dict at: #allTextUrls put: (allTextUrls copyReplaceFrom: after-1 to: after-2 with: #(()))].
- 		index := after].
- 
- 	remote at: index put: (aPage sqkPage copyForSaving).
- 
- 	(dict at: #modTime ifAbsent: [0]) < Time totalSeconds ifTrue:
- 		[dict at: #modTime put: Time totalSeconds].
- 	allText ifNotNil: [
- 		(dict at: #allText) at: index-1 put: (aPage allStringsAfter: nil).
- 		(dict at: #allTextUrls) at: index-1 put: pageURL].
- 
- 	sf := ServerDirectory new fullPath: mine.
- 	Cursor wait showWhile: [ | remoteFile |
- 		remoteFile := sf fileNamed: mine.
- 		remoteFile fileOutClass: nil andObject: remote.
- 		"remoteFile close"].
- !

Item was removed:
- ----- Method: BookMorph>>saveIndexOnURL (in category 'menu') -----
- saveIndexOnURL
- 	"Make up an index to the pages of this book, with thumbnails, and store it on the server.  (aDictionary, aMorphObjectOut, aMorphObjectOut, aMorphObjectOut).  The last part corresponds exactly to what pages looks like when they are all out.  Each holds onto a SqueakPage, which holds a url and a thumbnail."
- 
- 	| dict mine sf urlList list |
- 	pages isEmpty ifTrue: [^self].
- 	dict := Dictionary new.
- 	dict at: #modTime put: Time totalSeconds.
- 	"self getAllText MUST have been called at start of this operation."
- 	dict at: #allText put: (self valueOfProperty: #allText).
- 	#(#color #borderWidth #borderColor #pageSize) 
- 		do: [:sel | dict at: sel put: (self perform: sel)].
- 	self reserveUrlsIfNeeded.	"should already be done"
- 	list := pages copy.	"paste dict on front below"
- 	"Fix up the entries, should already be done"
- 	list withIndexDo: 
- 			[:out :ind | 
- 			out isInMemory 
- 				ifTrue: 
- 					[(out valueOfProperty: #SqueakPage) ifNil: [out saveOnURLbasic].
- 					list at: ind put: out sqkPage copyForSaving]].
- 	urlList := list collect: [:ppg | ppg url].
- 	self setProperty: #allTextUrls toValue: urlList.
- 	dict at: #allTextUrls put: urlList.
- 	list := (Array with: dict) , list.
- 	mine := self valueOfProperty: #url.
- 	mine ifNil: 
- 			[mine := self getStemUrl , '.bo'.
- 			self setProperty: #url toValue: mine].
- 	sf := ServerDirectory new fullPath: mine.
- 	Cursor wait showWhile: 
- 			[ | remoteFile |
- 			remoteFile := sf fileNamed: mine.
- 			remoteFile dataIsValid.
- 			remoteFile fileOutClass: nil andObject: list
- 			"remoteFile close"]!

Item was removed:
- ----- Method: BookMorph>>saveOnUrlPage: (in category 'menu') -----
- saveOnUrlPage: pageMorph
- 	"Write out this single page in this book onto a server.  See savePagesOnURL.  (Don't compute the texts, only this page's is written.)"
- 	| stem ind response rand newPlace dir |
- 	(self valueOfProperty: #keepTogether) ifNotNil:
- 		[self inform: 'This book is marked ''keep in one file''. 
- Several pages use a common Player.
- Save the owner of the book instead.' translated.
- 		^ self].
- 	"Don't give the chance to put in a different place.  Assume named by number"
- 	((self valueOfProperty: #url) isNil and: [pages first url notNil]) ifTrue:
- 		[response := Project uiManager
- 						chooseOptionFrom: {'Old book' translated. 'New book sharing old pages' translated}
- 						title: 'Modify the old book, or make a new
- 			book sharing its pages?' translated.
- 		response = 2 ifTrue:
- 			["Make up new url for .bo file and confirm with user."  "Mark as shared"
- 			[rand := String new: 4.
- 			1 to: rand size do:
- 				[:ii |
- 				rand at: ii put: ('bdfghklmnpqrstvwz' at: 17 atRandom)].
- 			(newPlace := self getStemUrl) ifEmpty: [^ self].
- 			newPlace := (newPlace copyUpToLast: $/), '/BK', rand, '.bo'.
- 			dir := ServerFile new fullPath: newPlace.
- 			(dir includesKey: dir fileName)] whileTrue.	"keep doing until a new file"
- 			self setProperty: #url toValue: newPlace].
- 		response = 0 ifTrue: [^ self]].
- 
- 	stem := self getStemUrl.	"user must approve"
- 	stem ifEmpty: [^ self].
- 	ind := pages identityIndexOf: pageMorph ifAbsent: [self error: 'where is the page?' translated].
- 	pageMorph isInMemory ifTrue: "not out now"
- 		[pageMorph saveOnURL: stem,(ind printString),'.sp'].
- 	self saveIndexOfOnly: pageMorph.!

Item was removed:
- ----- Method: BookMorph>>saveOneOnURL (in category 'menu') -----
- saveOneOnURL
- 	"Write out this single page onto a server.  See savePagesOnURL.  (Don't compute the texts, only this page's is written.)"
- 
- 	^ self saveOnUrlPage: currentPage!

Item was removed:
- ----- Method: BookMorph>>savePagesOnURL (in category 'menu') -----
- savePagesOnURL
- 	"Write out all pages in this book onto a server.  For any page that does not have a SqueakPage and a url already, ask the user for one.  Give the option of naming all page files by page number.  Any pages that are not in memory will stay that way.  The local disk could be the server."
- 
- 	| response list firstTime newPlace rand dir bookUrl |
- 	(self valueOfProperty: #keepTogether) ifNotNil:
- 		[self inform: 'This book is marked ''keep in one file''. 
- Several pages use a common Player.
- Save the owner of the book instead.' translated.
- 		^ self].
- 	self getAllText.	"stored with index later"
- 	response := Project uiManager
- 					chooseOptionFrom:
- 						{'Use page numbers' translated.
- 						'Type in file names' translated.
- 						'Save in a new place (using page numbers)' translated.
- 						'Save in a new place (typing names)' translated.
- 						'Save new book sharing old pages' translated. }
- 					title:  'Each page will be a file on the server.  
- Do you want to page numbers be the names of the files? 
- or name each one yourself?' translated.
- 	response = 1 ifTrue: [self saveAsNumberedURLs. ^ self].
- 	response = 3 ifTrue: [self forgetURLs; saveAsNumberedURLs. ^ self].
- 	response = 4 ifTrue: [self forgetURLs].
- 	response = 5 ifTrue:
- 		["Make up new url for .bo file and confirm with user."  "Mark as shared"
- 		[rand := String new: 4.
- 		1 to: rand size do: [:ii |
- 			rand at: ii put: ('bdfghklmnpqrstvwz' at: 17 atRandom)].
- 		(newPlace := self getStemUrl) isEmpty ifTrue: [^ self].
- 		newPlace := (newPlace copyUpToLast: $/), '/BK', rand, '.bo'.
- 		dir := ServerFile new fullPath: newPlace.
- 		(dir includesKey: dir fileName)] whileTrue.	"keep doing until a new file"
- 
- 		self setProperty: #url toValue: newPlace.
- 		self saveAsNumberedURLs. 
- 		bookUrl := self valueOfProperty: #url.
- 		(SqueakPage stemUrl: bookUrl) =  (SqueakPage stemUrl: currentPage url) ifTrue:
- 			[bookUrl := true].		"not a shared book"
- 		(URLMorph grabURL: currentPage url) book: bookUrl.
- 		^ self].
- 	response = 0 ifTrue: [^ self].
- 
- 	"self reserveUrlsIfNeeded.	Need two passes here -- name on one, write on second"
- 	pages do:
- 		[:aPage |	"does write the current page too"
- 		aPage isInMemory ifTrue: "not out now"
- 			[aPage presenter ifNotNil:
- 				[aPage presenter flushPlayerListCache].
- 			aPage saveOnURLbasic]].	"ask user if no url"
- 
- 	list := pages collect:
- 			[:aPage |
- 			aPage sqkPage prePurge]. "knows not to purge the current page"
- 	list := (list select: [:each | each notNil]) asArray.
- 	"do bulk become:"
- 	(list collect:
- 		[:each |
- 		each contentsMorph])
- 		elementsExchangeIdentityWith: (list collect:
- 						[:spg |
- 						MorphObjectOut new xxxSetUrl: spg url page: spg]).
- 
- 	firstTime := (self valueOfProperty: #url) isNil.
- 	self saveIndexOnURL.
- 	self presenter ifNotNil:
- 		[self presenter flushPlayerListCache].
- 	firstTime ifTrue: "Put a thumbnail into the hand"
- 		[URLMorph grabForBook: self.
- 		self setProperty: #futureUrl toValue: nil].	"clean up"
- !

Item was removed:
- ----- Method: BookMorph>>setAllPagesColor: (in category 'accessing') -----
- setAllPagesColor: aColor
- 	"Set the color of all the pages to a new color"
- 
- 	self pages do: [:page | page color: aColor].!

Item was removed:
- ----- Method: BookMorph>>setExtentFromHalo: (in category 'other') -----
- setExtentFromHalo: anExtent
- 	"The user has dragged the grow box such that the receiver's extent would be anExtent.  Do what's needed.  For a BookMorph, we assume any resizing attempt is a request that the book-page currently being viewed be resized accoringly; this will typically not affect unseen book pages, though there is a command that can be issued to harmonize all book-page sizes, and also an option to set that will maintain all pages at the same size no matter what."
- 
- 	currentPage isInWorld
- 		ifFalse: "doubtful case mostly"
- 			[super setExtentFromHalo: anExtent]
- 		ifTrue:
- 			[currentPage width: anExtent x.
- 			currentPage height: (anExtent y - (self innerBounds height - currentPage height)).
- 			self maintainsUniformPageSize ifTrue:
- 				[self setProperty: #uniformPageSize toValue: currentPage extent]]!

Item was removed:
- ----- Method: BookMorph>>setInitialState (in category 'initialization') -----
- setInitialState
- 	self listDirection: #topToBottom;
- 	  wrapCentering: #topLeft;
- 	  hResizing: #shrinkWrap;
- 	  vResizing: #shrinkWrap;
- 	  layoutInset: 5.
- 	pageSize := 160 @ 300.
- 	self enableDragNDrop!

Item was removed:
- ----- Method: BookMorph>>setNewPagePrototype (in category 'menu') -----
- setNewPagePrototype
- 	"Record the current page as the prototype to be copied when inserting new pages."
- 
- 	currentPage ifNotNil:
- 		[newPagePrototype := currentPage veryDeepCopy.
- 		 newPagePrototype removeProperty: #revertKey].
- 		"When a new page is inserted, it will not have any original page to revert to.  After author improves the new page, he can save it for later revert."
- !

Item was removed:
- ----- Method: BookMorph>>setPageColor (in category 'menu') -----
- setPageColor
- 	"Get a color from the user, then set all the pages to that color"
- 	self currentPage ifNil: [ ^ self ].
- 	NewColorPickerMorph useIt
- 		ifTrue:
- 			[ (NewColorPickerMorph
- 				on: self
- 				originalColor: self currentPage color
- 				setColorSelector: #setAllPagesColor:) openNear: self fullBoundsInWorld ]
- 		ifFalse:
- 			[ ColorPickerMorph new
- 				 choseModalityFromPreference ;
- 				 sourceHand: self activeHand ;
- 				 target: self ;
- 				 selector: #setAllPagesColor: ;
- 				 originalColor: self currentPage color ;
- 				
- 				putUpFor: self
- 				near: self fullBoundsInWorld ]!

Item was removed:
- ----- Method: BookMorph>>setWrapPages: (in category 'navigation') -----
- setWrapPages: doWrap
- 	doWrap
- 		ifTrue: [self removeProperty: #dontWrapAtEnd]
- 		ifFalse: [self setProperty: #dontWrapAtEnd toValue: true].
- !

Item was removed:
- ----- Method: BookMorph>>showMoreControls (in category 'navigation') -----
- showMoreControls
- 	self currentEvent shiftPressed
- 		ifTrue:
- 			[self hidePageControls]
- 		ifFalse:
- 			[self showPageControls: self fullControlSpecs]!

Item was removed:
- ----- Method: BookMorph>>sortPages (in category 'menu commands') -----
- sortPages
- 
- 	currentPage ifNotNil: [currentPage updateCachedThumbnail].
- 	^ super sortPages!

Item was removed:
- ----- Method: BookMorph>>sortPages: (in category 'sorting') -----
- sortPages: evt
- 
- 	^ self sortPages!

Item was removed:
- ----- Method: BookMorph>>textSearch (in category 'menu') -----
- textSearch
- 	"search the text on all pages of this book"
- 
- 	| wanted wants list str |
- 	list := self valueOfProperty: #searchKey ifAbsent: [#()].
- 	str := String streamContents: [:strm | 
- 			list do: [:each | strm nextPutAll: each; space]].
- 	wanted := UIManager default request: 'words to search for.  Order is not important.
- Beginnings of words are OK.' translated
- 		initialAnswer: str.
- 	wants := wanted findTokens: Character separators.
- 	wants isEmpty ifTrue: [^ self].
- 	self getAllText.		"save in allText, allTextUrls"
- 	^ self findText: wants	"goes to the page and highlights the text"!

Item was removed:
- ----- Method: BookMorph>>textSearch: (in category 'menu') -----
- textSearch: stringWithKeys 
- 	"search the text on all pages of this book"
- 
- 	| wants |
- 	wants := stringWithKeys findTokens: Character separators.
- 	wants isEmpty ifTrue: [^self].
- 	self getAllText.	"save in allText, allTextUrls"
- 	^self findText: wants	"goes to the page and highlights the text"!

Item was removed:
- ----- Method: BookMorph>>thumbnailForThisPage (in category 'menu') -----
- thumbnailForThisPage
- 	self primaryHand attachMorph:
- 		(currentPage thumbnailForPageSorter pageMorph: currentPage inBook: self)
- !

Item was removed:
- ----- Method: BookMorph>>toggleFullScreen (in category 'menu') -----
- toggleFullScreen
- 	self isInFullScreenMode
- 		ifTrue:	[self exitFullScreen]
- 		ifFalse:	[self goFullScreen]!

Item was removed:
- ----- Method: BookMorph>>toggleMaintainUniformPageSize (in category 'uniform page size') -----
- toggleMaintainUniformPageSize
- 	"Toggle whether or not the receiver should maintain uniform page size"
- 
- 	self maintainsUniformPageSize: self maintainsUniformPageSize not!

Item was removed:
- ----- Method: BookMorph>>toggleShowingOfPageControls (in category 'menu') -----
- toggleShowingOfPageControls
- 	self pageControlsVisible
- 		ifTrue:	[self hidePageControls]
- 		ifFalse:	[self showPageControls]!

Item was removed:
- ----- Method: BookMorph>>transitionSpecFor: (in category 'navigation') -----
- transitionSpecFor: aMorph
- 	^ aMorph valueOfProperty: #transitionSpec  " check for special propety"
- 		ifAbsent: [Array with: 'camera'  " ... otherwise this is the default"
- 						with: #none
- 						with: #none]!

Item was removed:
- ----- Method: BookMorph>>uncachePageSorter (in category 'menu') -----
- uncachePageSorter
- 	pages do: [:aPage | aPage removeProperty: #cachedThumbnail].!

Item was removed:
- ----- Method: BookMorph>>uniformPageSize (in category 'uniform page size') -----
- uniformPageSize
- 	"Answer the uniform page size to maintain, or nil if the option is not set"
- 
- 	^ self valueOfProperty: #uniformPageSize ifAbsent: [nil]!

Item was removed:
- ----- Method: BookMorph>>updateReferencesUsing: (in category 'copying') -----
- updateReferencesUsing: aDictionary
- 
- 	super updateReferencesUsing: aDictionary.
- 	pages do: [:page |
- 		page allMorphsDo: [:m | m updateReferencesUsing: aDictionary]].
- !

Item was removed:
- ----- Method: BookMorph>>userString (in category 'accessing') -----
- userString
- 	"Do I have a text string to be searched on?"
- 
- 	| list |
- 	self getAllText.
- 	list := OrderedCollection new.
- 	(self valueOfProperty: #allText ifAbsent: #()) do: [:aList |
- 		list addAll: aList].
- 	^ list!

Item was removed:
- ----- Method: BookMorph>>wantsDroppedMorph:event: (in category 'dropping/grabbing') -----
- wantsDroppedMorph: aMorph event: evt
- 	(currentPage bounds containsPoint: (self pointFromWorld: evt cursorPoint)) ifFalse: [^ false].
- 	^ super wantsDroppedMorph: aMorph event: evt!

Item was removed:
- AlignmentMorph subclass: #BookPageSorterMorph
- 	instanceVariableNames: 'book pageHolder'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Books'!

Item was removed:
- ----- Method: BookPageSorterMorph>>acceptSort (in category 'buttons') -----
- acceptSort
- 
- 	book acceptSortedContentsFrom: pageHolder.
- 	self delete.
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>addControls (in category 'initialization') -----
- addControls
- 	"Add the control bar at the top of the tool."
- 
- 	| bb r str aCheckbox aWrapper |
- 	r := AlignmentMorph newRow color: Color transparent; borderWidth: 0; layoutInset: 0.
- 	r wrapCentering: #center; cellPositioning: #leftCenter; 
- 			hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	bb := SimpleButtonMorph new target: self; borderColor: Color black.
- 	r addMorphBack: (self wrapperFor: (bb label: 'Okay' translated font: ScriptingSystem fontForEToyButtons;	actionSelector: #acceptSort)).
- 	bb setBalloonText: 'Accept the changes made here as the new page-order for this book' translated.
- 	r addTransparentSpacerOfSize: 12.
- 	bb := SimpleButtonMorph new target: self; borderColor: Color black.
- 	r addMorphBack: (self wrapperFor: (bb label: 'Cancel' translated font: ScriptingSystem fontForEToyButtons;	actionSelector: #delete)).
- 	bb setBalloonText: 'Forgot any changes made here, and dismiss this sorter' translated.
- 
- 	"eliminate the parts-bin button on the book-page sorters...
- 	r addTransparentSpacerOfSize: 24 @ 0.
- 
- 	aCheckbox :=  UpdatingThreePhaseButtonMorph checkBox.
- 	aCheckbox 
- 		target: self;
- 		actionSelector: #togglePartsBinStatus;
- 		arguments: #();
- 		getSelector: #getPartsBinStatus.
- 	str := StringMorph contents: 'Parts bin' translated font: ScriptingSystem fontForEToyButtons.
- 	aWrapper := AlignmentMorph newRow beTransparent.
- 	aWrapper cellInset: 0; layoutInset: 0; borderWidth: 0.
- 	aWrapper
- 		addMorphBack: (self wrapperFor: aCheckbox);
- 		addMorphBack: (self wrapperFor: str lock).
- 	r addMorphBack: aWrapper."
- 
- 	self addMorphFront: r
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>book:morphsToSort: (in category 'initialization') -----
- book: aBookMorph morphsToSort: morphList
- 
- 	| innerBounds scrollPane newHeight |
- 	book := aBookMorph.
- 	newHeight := self currentWorld height.
- 	pageHolder removeAllMorphs.
- 	pageHolder addAllMorphs: morphList.
- 	pageHolder extent: pageHolder width at pageHolder fullBounds height.
- 	innerBounds := Rectangle merging: (morphList collect: [:m | m bounds]).
- 	pageHolder extent: innerBounds extent + pageHolder borderWidth + 6.
- 	(pageHolder height > newHeight) ifTrue: [
- 		scrollPane := ScrollPane new.
- 
- 		self height: newHeight.
- 		scrollPane model: pageHolder.
- 		scrollPane extent: pageHolder width@(newHeight - aBookMorph submorphs first height - 28).
- 		self addMorph: scrollPane inFrontOf: pageHolder.
- 		scrollPane scroller addMorph: pageHolder.
- 		scrollPane scrollBarOnLeft: false.
- 		scrollPane retractable: false.
- 		scrollPane hScrollBarPolicy: #never.
- 		scrollPane borderWidth: 1; borderColor: Color gray.
- 	].
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>changeExtent: (in category 'private') -----
- changeExtent: aPoint 
- 	self extent: aPoint.
- 	pageHolder extent: self extent - self borderWidth!

Item was removed:
- ----- Method: BookPageSorterMorph>>closeButtonOnly (in category 'private') -----
- closeButtonOnly
- 	"Replace my default control panel with one that has only a close button."
- 
- 	| b r |
- 	self firstSubmorph delete.  "remove old control panel"
- 	b := SimpleButtonMorph new target: self; borderColor: Color black.
- 	r := AlignmentMorph newRow.
- 	r color: b color; borderWidth: 0; layoutInset: 0.
- 	r hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	r wrapCentering: #topLeft.
- 	r addMorphBack: (b label: 'Close' translated; actionSelector: #delete).
- 	self addMorphFront: r.
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>columnWith: (in category 'private') -----
- columnWith: aMorph
- 
- 	^AlignmentMorph newColumn
- 		color: Color transparent;
- 		hResizing: #shrinkWrap;
- 		vResizing: #shrinkWrap;
- 		wrapCentering: #center;
- 		cellPositioning: #topCenter;
- 		layoutInset: 1;
- 		addMorph: aMorph
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- "answer the default border width for the receiver"
- 	^ 2!

Item was removed:
- ----- Method: BookPageSorterMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color lightGray!

Item was removed:
- ----- Method: BookPageSorterMorph>>getPartsBinStatus (in category 'buttons') -----
- getPartsBinStatus
- 
- 	^pageHolder isPartsBin!

Item was removed:
- ----- Method: BookPageSorterMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self extent: Display extent - 100;
- 		 listDirection: #topToBottom;
- 		 wrapCentering: #topLeft;
- 		 hResizing: #shrinkWrap;
- 		 vResizing: #shrinkWrap;
- 		 layoutInset: 3.
- 	pageHolder := PasteUpMorph new behaveLikeHolder extent: self extent -self borderWidth.
- 	pageHolder hResizing: #shrinkWrap.
- 	pageHolder wantsMouseOverHalos: false.
- 	"pageHolder cursor: 0."
- 	"causes a walkback as of 5/25/2000"
- 	self addControls.
- 	self addMorphBack: pageHolder!

Item was removed:
- ----- Method: BookPageSorterMorph>>pageHolder (in category 'accessing') -----
- pageHolder
- 
- 	^ pageHolder
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>rowWith: (in category 'private') -----
- rowWith: aMorph
- 
- 	^AlignmentMorph newColumn
- 		color: Color transparent;
- 		hResizing: #shrinkWrap;
- 		vResizing: #shrinkWrap;
- 		wrapCentering: #center;
- 		cellPositioning: #topCenter;
- 		layoutInset: 1;
- 		addMorph: aMorph
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>togglePartsBinStatus (in category 'buttons') -----
- togglePartsBinStatus
- 
- 	pageHolder isPartsBin: pageHolder isPartsBin not!

Item was removed:
- ----- Method: BookPageSorterMorph>>veryDeepFixupWith: (in category 'copying') -----
- veryDeepFixupWith: deepCopier
- 	"If fields were weakly copied, fix them here.  If they were in the tree being copied, fix them up, otherwise point to the originals."
- 
- super veryDeepFixupWith: deepCopier.
- book := deepCopier references at: book ifAbsent: [book].
- !

Item was removed:
- ----- Method: BookPageSorterMorph>>veryDeepInner: (in category 'copying') -----
- veryDeepInner: deepCopier
- 	"Copy all of my instance variables.  Some need to be not copied at all, but shared.  	Warning!!!!  Every instance variable defined in this class must be handled.  We must also implement veryDeepFixupWith:.  See DeepCopier class comment."
- 
- super veryDeepInner: deepCopier.
- "book := book.		Weakly copied"
- pageHolder := pageHolder veryDeepCopyWith: deepCopier.!

Item was removed:
- ----- Method: BookPageSorterMorph>>wantsToBeDroppedInto: (in category 'dropping/grabbing') -----
- wantsToBeDroppedInto: aMorph
- 	"Return true if it's okay to drop the receiver into aMorph"
- 	^aMorph isWorldMorph "only into worlds"!

Item was removed:
- ----- Method: BookPageSorterMorph>>wrapperFor: (in category 'private') -----
- wrapperFor: aMorph
- 
- 	^self columnWith: (self rowWith: aMorph)
- !

Item was removed:
- SketchMorph subclass: #BookPageThumbnailMorph
- 	instanceVariableNames: 'page pageNumber bookMorph flipOnClick'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Books'!
- 
- !BookPageThumbnailMorph commentStamp: '<historical>' prior: 0!
- A small picture representing a page of a BookMorph here or somewhere else.  When clicked, make that book turn to the page and do a visual effect and a noise.
- 
- page			either the morph of the page, or a url
- pageNumber
- bookMorph		either the book, or a url
- flipOnClick!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu addLine.
- 	aCustomMenu add: 'make a flex morph' translated selector: #makeFlexMorphFor: argument: aHandMorph.
- 	flipOnClick
- 		ifTrue: [aCustomMenu add: 'disable bookmark action' translated action: #toggleBookmark]
- 		ifFalse: [aCustomMenu add: 'enable bookmark action' translated action: #toggleBookmark].
- 	(bookMorph isKindOf: BookMorph)
- 		ifTrue:
- 			[aCustomMenu add: 'set page sound' translated action: #setPageSound:.
- 			aCustomMenu add: 'set page visual' translated action: #setPageVisual:]
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>bookMorph (in category 'accessing') -----
- bookMorph
- 
- 	^bookMorph!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>computeThumbnail (in category 'private') -----
- computeThumbnail
- 	| f scale |
- 	self objectsInMemory.
- 	f := page imageForm.
- 	scale := (self height / f height).  "keep height invariant"
- "(Sensor shiftPressed) ifTrue: [scale := scale * 1.4]."
- 	self form: (f magnify: f boundingBox by: scale at scale smoothing: 2).
- 
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color lightGray!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>doPageFlip (in category 'private') -----
- doPageFlip
- 	"Flip to this page"
- 
- 	self objectsInMemory.
- 	bookMorph ifNil: [^ self].
- 	bookMorph goToPageMorph: page
- 			transitionSpec: (self valueOfProperty: #transitionSpec).
- 	(owner isKindOf: PasteUpMorph) ifTrue:
- 		[owner cursor: (owner submorphs indexOf: self ifAbsent: [1])]!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>encounteredAtTime:inScorePlayer:atIndex:inEventTrack:secsPerTick: (in category 'piano rolls') -----
- encounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick
- 	"Flip to this page with no extra sound"
- 	BookMorph turnOffSoundWhile: [self doPageFlip]!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: event
- 
- 	^ event shiftPressed or: [flipOnClick and: [event controlKeyPressed not]]!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>inBook: (in category 'accessing') -----
- inBook: book
- 	bookMorph := book!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 
- 	| f |
- 	super initialize.
- 	flipOnClick := false.
- 	
- 	f := Form extent: 160 at 120 depth: Display depth.
- 	f fill: f boundingBox fillColor: color.
- 	self form: f!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>makeFlexMorphFor: (in category 'private') -----
- makeFlexMorphFor: aHand
- 
- 	aHand grabMorph: (FlexMorph new originalMorph: page)!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: event
- 	"turn the book to that page"
- 
- 	"May need to lie to it so mouseUp won't go to menu that may come up during fetch of a page in doPageFlip.  (Is this really true? --tk)"
- 
- 	self doPageFlip.
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>objectForDataStream: (in category 'fileIn/Out') -----
- objectForDataStream: refStrm
- 	"I am about to be written on an object file.  It would be bad to write a whole BookMorph out.  Store a string that is the url of the book or page in my inst var."
- 
- 	| clone bookUrl bb stem ind |
- 	(bookMorph isString) & (page isString) ifTrue: [
- 		^ super objectForDataStream: refStrm].
- 	(bookMorph isNil) & (page isString) ifTrue: [
- 		^ super objectForDataStream: refStrm].
- 	(bookMorph isNil) & (page url notNil) ifTrue: [
- 		^ super objectForDataStream: refStrm].
- 	(bookMorph isNil) & (page url isNil) ifTrue: [
- 		self error: 'page should already have a url' translated.
- 		"find page's book, and remember it"
- 		"bookMorph := "].
- 	
- 	clone := self shallowCopy.
- 	(bookUrl := bookMorph url)
- 		ifNil: [bookUrl := self valueOfProperty: #futureUrl].
- 	bookUrl 
- 		ifNil: [	bb := RectangleMorph new.	"write out a dummy"
- 			bb bounds: bounds.
- 			refStrm replace: self with: bb.
- 			^ bb]
- 		ifNotNil: [clone instVarNamed: 'bookMorph' put: bookUrl].
- 
- 	page url ifNil: [
- 			"Need to assign a url to a page that will be written later.
- 			It might have bookmarks too.  Don't want to recurse deeply.  
- 			Have that page write out a dummy morph to save its url on the server."
- 		stem := SqueakPage stemUrl: bookUrl.
- 		ind := bookMorph pages identityIndexOf: page.
- 		page reserveUrl: stem,(ind printString),'.sp'].
- 	clone instVarNamed: 'page' put: page url.
- 	refStrm replace: self with: clone.
- 	^ clone!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>objectsInMemory (in category 'fileIn/Out') -----
- objectsInMemory
- 	"See if page or bookMorph need to be brought in from a server."
- 	| bookUrl bk wld try |
- 	bookMorph ifNil: ["fetch the page"
- 		page isString ifFalse: [^ self].	"a morph"
- 		try := (SqueakPageCache atURL: page) fetchContents.
- 		try ifNotNil: [page := try].
- 		^ self].
- 	bookMorph isString ifTrue: [
- 		bookUrl := bookMorph.
- 		(wld := self world) ifNil: [wld := Smalltalk currentWorld].
- 		bk := BookMorph isInWorld: wld withUrl: bookUrl.
- 		bk == #conflict ifTrue: [
- 			^ self inform: 'This book is already open in some other project' translated].
- 		bk == #out ifTrue: [
- 			(bk := BookMorph new fromURL: bookUrl) ifNil: [^ self]].
- 		bookMorph := bk].
- 	page isString ifTrue: [
- 		page := (bookMorph pages detect: [:pg | pg url = page] 
- 					ifNone: [bookMorph pages first])].
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>page (in category 'accessing') -----
- page
- 
- 	^ page
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>page: (in category 'accessing') -----
- page: aMorph
- 
- 	page := aMorph.
- 	self computeThumbnail.
- 	self setNameTo: aMorph externalName.
- 	page fullReleaseCachedState.
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>pageMorph:inBook: (in category 'accessing') -----
- pageMorph: pageMorph inBook: book
- 	page := pageMorph.
- 	bookMorph := book!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>pageNumber:inBook: (in category 'accessing') -----
- pageNumber: n inBook: b
- 	pageNumber := n.
- 	bookMorph := b!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>setPageSound: (in category 'menus') -----
- setPageSound: event
- 
- 	^ bookMorph menuPageSoundFor: self event: event!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>setPageVisual: (in category 'menus') -----
- setPageVisual: event
- 
- 	^ bookMorph menuPageVisualFor: self event: event!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>smaller (in category 'initialization') -----
- smaller
- 	self form: (self form copy: (0 at 0 extent: self form extent//2)).
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>toggleBookmark (in category 'menus') -----
- toggleBookmark
- 	"Enable or disable sensitivity as a bookmark
- 		enabled means that a normal click will cause a pageFlip
- 		disabled means this morph can be picked up normally by the hand."
- 
- 	flipOnClick := flipOnClick not!

Item was removed:
- ----- Method: BookPageThumbnailMorph>>veryDeepFixupWith: (in category 'copying') -----
- veryDeepFixupWith: deepCopier
- 	"If target and arguments fields were weakly copied, fix them here.  If they were in the tree being copied, fix them up, otherwise point to the originals!!!!"
- 
- super veryDeepFixupWith: deepCopier.
- page := deepCopier references at: page ifAbsent: [page].
- bookMorph := deepCopier references at: bookMorph ifAbsent: [bookMorph].
- !

Item was removed:
- ----- Method: BookPageThumbnailMorph>>veryDeepInner: (in category 'copying') -----
- veryDeepInner: deepCopier
- 	"Copy all of my instance variables.  Some need to be not copied at all, but shared.  	Warning!!!!  Every instance variable defined in this class must be handled.  We must also implement veryDeepFixupWith:.  See DeepCopier class comment."
- 
- super veryDeepInner: deepCopier.
- "page := page.		Weakly copied"
- pageNumber := pageNumber veryDeepCopyWith: deepCopier.
- "bookMorph := bookMorph.		All weakly copied"
- flipOnClick := flipOnClick veryDeepCopyWith: deepCopier. !

Item was removed:
- AlignmentMorph subclass: #BooklikeMorph
- 	instanceVariableNames: 'pageSize newPagePrototype'
- 	classVariableNames: 'PageFlipSoundOn'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Books'!
- 
- !BooklikeMorph commentStamp: '<historical>' prior: 0!
- A common superclass for BookMorph and WebBookMorph!

Item was removed:
- ----- Method: BooklikeMorph class>>initialize (in category 'class initialization') -----
- initialize
- 	"BooklikeMorph initialize"
- 	PageFlipSoundOn := true
- !

Item was removed:
- ----- Method: BooklikeMorph class>>turnOffSoundWhile: (in category 'as yet unclassified') -----
- turnOffSoundWhile: aBlock
- 	"Turn off page flip sound during the given block."
- 	| old |
- 	old := PageFlipSoundOn.
- 	PageFlipSoundOn := false.
- 	aBlock value.
- 	PageFlipSoundOn := old!

Item was removed:
- ----- Method: BooklikeMorph>>addBookMenuItemsTo:hand: (in category 'misc') -----
- addBookMenuItemsTo: aCustomMenu hand: aHandMorph
- 	(self hasSubmorphWithProperty: #pageControl)
- 		ifTrue: [aCustomMenu add: 'hide page controls' translated action: #hidePageControls]
- 		ifFalse: [aCustomMenu add: 'show page controls' translated action: #showPageControls]!

Item was removed:
- ----- Method: BooklikeMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 	"This factoring allows subclasses to have different menu yet still use the super call for the rest of the metamenu."
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'book...' translated target: self action: #invokeBookMenu.
- 	
- 	"self addBookMenuItemsTo: aCustomMenu hand: aHandMorph"!

Item was removed:
- ----- Method: BooklikeMorph>>addPageControlMorph: (in category 'page controls') -----
- addPageControlMorph: aMorph
- 	"Add the morph provided as a page control, at the appropriate place"
- 
- 	aMorph setProperty: #pageControl toValue: true.
- 	self addMorph: aMorph asElementNumber: self indexForPageControls!

Item was removed:
- ----- Method: BooklikeMorph>>clearNewPagePrototype (in category 'menu commands') -----
- clearNewPagePrototype
- 	newPagePrototype := nil
- !

Item was removed:
- ----- Method: BooklikeMorph>>currentPlayerDo: (in category 'e-toy support') -----
- currentPlayerDo: aBlock
- 	| aPlayer aPage |
- 	(aPage := self currentPage) ifNil: [^ self].
- 	aPage allMorphsDo:[ :m|
- 	(aPlayer := m player) ifNotNil:
- 		[aBlock value: aPlayer]]!

Item was removed:
- ----- Method: BooklikeMorph>>fewerPageControls (in category 'page controls') -----
- fewerPageControls
- 	self currentEvent shiftPressed
- 		ifTrue:
- 			[self hidePageControls]
- 		ifFalse:
- 			[self showPageControls: self shortControlSpecs]!

Item was removed:
- ----- Method: BooklikeMorph>>firstPage (in category 'menu commands') -----
- firstPage
- 	self goToPage: 1!

Item was removed:
- ----- Method: BooklikeMorph>>fullControlSpecs (in category 'page controls') -----
- fullControlSpecs
- 
- 	^ {
- 		#spacer.
- 		#variableSpacer.
- 		{'-'.		#deletePage.				'Delete this page' translated}.
- 		#spacer.
- 		{'«'.		#firstPage.				'First page' translated}.
- 		#spacer.
- 		{'<'. 		#previousPage.			'Previous page' translated}.
- 		#spacer.
- 		{'·'.		#invokeBookMenu. 		'Click here to get a menu of options for this book.' translated}.
- 		#spacer.
- 		{'>'.		#nextPage.				'Next page' translated}.
- 		#spacer.
- 		{ '»'.		#lastPage.				'Final page' translated}.
- 		#spacer.
- 		{'+'.		#insertPage.				'Add a new page after this one' translated}.
- 		#variableSpacer.
- 		{'o'.		#fewerPageControls.	'Fewer controls' translated}
- }
- !

Item was removed:
- ----- Method: BooklikeMorph>>hidePageControls (in category 'page controls') -----
- hidePageControls
- 	"Delete all submorphs answering to the property #pageControl"
- 	self deleteSubmorphsWithProperty: #pageControl!

Item was removed:
- ----- Method: BooklikeMorph>>indexForPageControls (in category 'page controls') -----
- indexForPageControls
- 	"Answer which submorph should hold the page controls"
- 
- 	^ (submorphs size > 0 and: [submorphs first hasProperty: #header])
- 		ifTrue:	[2]
- 		ifFalse:	[1]!

Item was removed:
- ----- Method: BooklikeMorph>>insertPage (in category 'menu commands') -----
- insertPage
- 	self insertPageColored: self color!

Item was removed:
- ----- Method: BooklikeMorph>>makePageControlsFrom: (in category 'page controls') -----
- makePageControlsFrom: controlSpecs
- 	"From the controlSpecs, create a set of page control and return them -- this method does *not* add the controls to the receiver."
- 
- 	| c col row |
- 	c := (color saturation > 0.4) ifTrue: [color slightlyLighter] ifFalse: [color slightlyDarker].
- 	col := AlignmentMorph newColumn.
- 	col color: c; borderWidth: 0; layoutInset: 0.
- 	col hResizing: #spaceFill; vResizing: #shrinkWrap; extent: 5 at 5.
- 
- 	row := AlignmentMorph newRow.
- 	row color: c; borderWidth: 0; layoutInset: 0.
- 	row hResizing: #spaceFill; vResizing: #shrinkWrap; extent: 5 at 5.
- 	controlSpecs do: [:spec | | lastGuy b |
- 		spec == #showDescription ifTrue: [row addMorphBack: self makeDescriptionViewer].
- 		spec == #pageNumber ifTrue: [row addMorphBack: self makePageNumberItem].
- 		spec == #spacer ifTrue: [row addTransparentSpacerOfSize: (10 @ 0)].
- 		spec == #variableSpacer ifTrue: [
- 			row addMorphBack: AlignmentMorph newVariableTransparentSpacer].
- 		spec class == Array ifTrue: [
- 			spec first isSymbol
- 				ifTrue: [b := ThreePhaseButtonMorph labelSymbol: spec first]
- 				ifFalse: [b := SimpleButtonMorph new borderWidth: 2; 
- 							borderColor: Color black; color: Color white.
- 							b label: spec first font: Preferences standardMenuFont].
- 				b target: self;  actionSelector: spec second;  setBalloonText: spec third.
- 				(spec atPin: 4) = #border 
- 					ifTrue: [b actWhen: #buttonDown]
- 					ifFalse: [b borderWidth: 0].	"default is none"
- 				row addMorphBack: b.
- 				(((lastGuy := spec last asLowercase) includesSubstring: 'menu') or:
- 						[lastGuy includesSubstring: 'designations'])
- 					ifTrue: [b actWhen: #buttonDown]]].  "pop up menu on mouseDown"
- 		col addMorphBack: row.
- 	^ col!

Item was removed:
- ----- Method: BooklikeMorph>>move (in category 'misc') -----
- move
- 	(owner isWorldMorph and:[self isSticky not]) ifTrue: [self activeHand grabMorph: self]!

Item was removed:
- ----- Method: BooklikeMorph>>pageSize (in category 'misc') -----
- pageSize
- 	^ pageSize
- !

Item was removed:
- ----- Method: BooklikeMorph>>pageSize: (in category 'misc') -----
- pageSize: aPoint
- 	pageSize := aPoint!

Item was removed:
- ----- Method: BooklikeMorph>>playPageFlipSound: (in category 'misc') -----
- playPageFlipSound: soundName
- 	self presenter ifNil: [^ self].  "Avoid failures when called too early"
- 	PageFlipSoundOn  "mechanism to suppress sounds at init time"
- 			ifTrue: [self playSoundNamed: soundName].
- !

Item was removed:
- ----- Method: BooklikeMorph>>setEventHandlerForPageControls: (in category 'page controls') -----
- setEventHandlerForPageControls: controls
- 	"Set the controls' event handler if appropriate.  Default is to let the tool be dragged by the controls"
- 
- 	controls eventHandler: (EventHandler new on: #mouseDown send: #move to: self)!

Item was removed:
- ----- Method: BooklikeMorph>>shortControlSpecs (in category 'page controls') -----
- shortControlSpecs
- 	"Answer  specs defining the widgets in the short form of the control panel."
- 
- ^ {
- 		{#MenuIcon.		#invokeShortBookMenu. 		'Click here to get a menu of options for this book.' translated}.
- 		#variableSpacer.
- 		{#PrevPage. 		#previousPage.			'Previous page' translated}.
- 		#spacer.
- 		#pageNumber.
- 		#spacer.
- 		{#NextPage.		#nextPage.				'Next page' translated}.
- 		#spacer.
- 		#variableSpacer.
- 		{'...'.		#showMoreControls.		'More controls' translated}
- }
- !

Item was removed:
- ----- Method: BooklikeMorph>>showPageControls (in category 'page controls') -----
- showPageControls
- 	self showPageControls: self shortControlSpecs!

Item was removed:
- ----- Method: BooklikeMorph>>showPageControls: (in category 'page controls') -----
- showPageControls: controlSpecs  
- 	"Remove any existing page controls, and add fresh controls at the top of the receiver (or in position 2 if the receiver's first submorph is one with property #header).  Add a single column of controls."
- 
- 	| pageControls column |
- 	self hidePageControls.
- 	column := AlignmentMorph newColumn beTransparent.
- 	pageControls := self makePageControlsFrom: controlSpecs.
- 	pageControls borderWidth: 0; layoutInset: 4.
- 	pageControls beSticky.
- 	pageControls setNameTo: 'Page Controls'.
- 	self setEventHandlerForPageControls: pageControls.
- 	column addMorphBack: pageControls.
- 	self addPageControlMorph: column!

Item was removed:
- ----- Method: BooklikeMorph>>showingFullScreenString (in category 'misc') -----
- showingFullScreenString
- 	"Answer a string characterizing whether the receiver is operating in full-screen mode."
- 
- 	^ (self isInFullScreenMode ifTrue: ['<yes>'] ifFalse: ['<no>']), 'view pages full-screen' translated!

Item was removed:
- ----- Method: BooklikeMorph>>showingPageControlsString (in category 'misc') -----
- showingPageControlsString
- 	"Answer a string characterizing whether page controls are currently showing."
- 
- 	^ (self pageControlsVisible ifTrue: ['<yes>'] ifFalse: ['<no>']),
- 		'page controls visible' translated!

Item was removed:
- ----- Method: BooklikeMorph>>sortPages (in category 'menu commands') -----
- sortPages
- 	| sorter |
- 	sorter := BookPageSorterMorph new
- 		book: self morphsToSort: self morphsForPageSorter.
- 	sorter pageHolder cursor: self pageNumber.
- 	"Align at bottom right of screen, but leave 20-pix margin."
- 	self bottom + sorter height < Display height ifTrue: "Place it below if it fits"
- 		[^ self world addMorphFront: (sorter align: sorter topLeft with: self bottomLeft)].
- 	self right + sorter width < Display width ifTrue: "Place it below if it fits"
- 		[^ self world addMorphFront: (sorter align: sorter bottomLeft with: self bottomRight)].
- 	"Otherwise, place it at lower right of screen"
- 	self world addMorphFront: (sorter position: Display extent - (20 at 20) - sorter extent).
- !

Item was removed:
- ----- Method: BorderedMorph>>basicInitialize (in category '*MorphicExtras-initialization') -----
- basicInitialize
- 	"Do basic generic initialization of the instance variables"
- 	
- 	super basicInitialize.
- 	self borderInitialize!

Item was removed:
- Morph subclass: #BouncingAtomsMorph
- 	instanceVariableNames: 'damageReported infectionHistory transmitInfection recentTemperatures temperature'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !BouncingAtomsMorph commentStamp: '<historical>' prior: 0!
- This morph shows how an ideal gas simulation might work. When it gets step messages, it makes all its atom submorphs move along their velocity vectors, bouncing when they hit a wall. It also exercises the Morphic damage reporting and display architecture. Here are some things to try:
- 
-   1. Resize this morph as the atoms bounce around.
-   2. In an inspector on this morph, evaluate "self addAtoms: 10."
-   3. Try setting quickRedraw to false in invalidRect:. This gives the
-      default damage reporting and incremental redraw. Try it for
-      100 atoms.
-   4. In the drawOn: method of AtomMorph, change drawAsRect to true.
-   5. Create a HeaterCoolerMorph and embed it in the simulation. Extract
- 	it and use an inspector on it to evaluate "self velocityDelta: -5", then
-      re-embed it. Note the effect on atoms passing over it.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'BouncingAtoms' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop}
- 		documentation:	'The original, intensively-optimized bouncing-atoms simulation by John Maloney' translatedNoop!

Item was removed:
- ----- Method: BouncingAtomsMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: BouncingAtomsMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#BouncingAtomsMorph, #new. 'Bouncing Atoms' translatedNoop. 'Atoms, mate' translatedNoop}
- 						forFlapNamed: 'Widgets']!

Item was removed:
- ----- Method: BouncingAtomsMorph class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: BouncingAtomsMorph>>addAtoms: (in category 'other') -----
- addAtoms: n
- 	"Add a bunch of new atoms."
- 
- 	n timesRepeat: [
- 		| a |
- 		a := AtomMorph new.
- 		a randomPositionIn: bounds maxVelocity: 10.
- 		self addMorph: a].
- 	self stopStepping.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'start bouncing' translated action: #startStepping.
- 	aCustomMenu add: 'start infection' translated action: #startInfection.
- 	aCustomMenu add: 'set atom count' translated action: #setAtomCount.
- 	aCustomMenu add: 'show infection history' translated action: #showInfectionHistory:.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>addMorphFront: (in category 'submorphs - add/remove') -----
- addMorphFront: aMorph
- 	"Called by the 'embed' meta action. We want non-atoms to go to the back."
- 	"Note: A user would not be expected to write this method. However, a sufficiently advanced user (e.g, an e-toy author) might do something equivalent by overridding the drag-n-drop messages when they are implemented."
- 
- 	(aMorph isMemberOf: AtomMorph)
- 		ifTrue: [super addMorphFront: aMorph]
- 		ifFalse: [super addMorphBack: aMorph].!

Item was removed:
- ----- Method: BouncingAtomsMorph>>areasRemainingToFill: (in category 'drawing') -----
- areasRemainingToFill: aRectangle
- 	color isTranslucent
- 		ifTrue: [^ Array with: aRectangle]
- 		ifFalse: [^ aRectangle areasOutside: self bounds]!

Item was removed:
- ----- Method: BouncingAtomsMorph>>collisionPairs (in category 'other') -----
- collisionPairs
- 	"Return a list of pairs of colliding atoms, which are assumed to be
- circles of known radius. This version uses the morph's positions--i.e.
- the top-left of their bounds rectangles--rather than their centers."
- 
- 	| count sortedAtoms radius twoRadii radiiSquared collisions p1 continue j p2 distSquared m1 m2 |
- 	count := submorphs size.
- 	sortedAtoms := submorphs 
- 				sorted: [:mt1 :mt2 | mt1 position x < mt2 position x].
- 	radius := 8.
- 	twoRadii := 2 * radius.
- 	radiiSquared := radius squared * 2.
- 	collisions := OrderedCollection new.
- 	1 to: count - 1
- 		do: 
- 			[:i | 
- 			m1 := sortedAtoms at: i.
- 			p1 := m1 position.
- 			continue := (j := i + 1) <= count.
- 			[continue] whileTrue: 
- 					[m2 := sortedAtoms at: j.
- 					p2 := m2 position.
- 					continue := p2 x - p1 x <= twoRadii  
- 								ifTrue: 
- 									[distSquared := (p1 x - p2 x) squared + (p1 y - p2 y) squared.
- 									distSquared < radiiSquared 
- 										ifTrue: [collisions add: (Array with: m1 with: m2)].
- 									(j := j + 1) <= count]
- 								ifFalse: [false]]].
- 	^collisions!

Item was removed:
- ----- Method: BouncingAtomsMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0.8
- 		g: 1.0
- 		b: 0.8!

Item was removed:
- ----- Method: BouncingAtomsMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	"Clear the damageReported flag when redrawn."
- 
- 	super drawOn: aCanvas.
- 	damageReported := false.!

Item was removed:
- ----- Method: BouncingAtomsMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	damageReported := false.
- 	self extent: 400 @ 250.
- 
- 	infectionHistory := OrderedCollection new.
- 	transmitInfection := false.
- 	self addAtoms: 30!

Item was removed:
- ----- Method: BouncingAtomsMorph>>intoWorld: (in category 'initialization') -----
- intoWorld: newOwner
- "Make sure report damage at least once"
- 	damageReported := false.
- 	super intoWorld: newOwner.
- 	!

Item was removed:
- ----- Method: BouncingAtomsMorph>>invalidRect:from: (in category 'change reporting') -----
- invalidRect: damageRect from: aMorph
- 	"Try setting 'quickRedraw' to true. This invalidates the entire morph, whose bounds typically subsume all it's submorphs. (However, this code checks that assumption and passes through any damage reports for out-of-bounds submorphs. Note that atoms with super-high velocities do occaisionally shoot through the walls!!) An additional optimization is to only submit only damage report per display cycle by using the damageReported flag, which is reset to false when the morph is drawn."
- 
- 	| quickRedraw |
- 	quickRedraw := true.  "false gives the original invalidRect: behavior"
- 	(quickRedraw and:
- 	 [(bounds origin <= damageRect topLeft) and:
- 	 [damageRect bottomRight <= bounds corner]]) ifTrue: [
- 		"can use quick redraw if damage is within my bounds"
- 		damageReported ifFalse: [super invalidRect: bounds from: self].  "just report once"
- 		damageReported := true.
- 	] ifFalse: [super invalidRect: damageRect from: aMorph].  "ordinary damage report"!

Item was removed:
- ----- Method: BouncingAtomsMorph>>justDroppedInto:event: (in category 'initialization') -----
- justDroppedInto: aWorld event: evt
- 
- 	damageReported := false.
- 	self changed
- 	
- 	!

Item was removed:
- ----- Method: BouncingAtomsMorph>>setAtomCount (in category 'menu') -----
- setAtomCount
- 
- 	| countString count |
- 	countString := UIManager default
- 		request: 'Number of atoms?'
- 		initialAnswer: self submorphCount printString.
- 	countString isEmpty ifTrue: [^ self].
- 	count := Integer readFrom: (ReadStream on: countString).
- 	self removeAllMorphs.
- 	self addAtoms: count.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>showInfectionHistory: (in category 'other') -----
- showInfectionHistory: evt
- 	"Place a graph of the infection history in the world."
- 
- 	| graph |
- 	infectionHistory isEmpty ifTrue: [^ self].
- 	graph := GraphMorph new data: infectionHistory.
- 	graph extent: ((infectionHistory size + (2 * graph borderWidth) + 5)@(infectionHistory last max: 50)).
- 	evt hand attachMorph: graph.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>startInfection (in category 'menu') -----
- startInfection
- 
- 	self submorphsDo: [:m | m infected: false].
- 	self firstSubmorph infected: true.
- 	infectionHistory := OrderedCollection new: 500.
- 	transmitInfection := true.
- 	self startStepping.
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>step (in category 'stepping and presenter') -----
- step
- 	"Bounce those atoms!!"
- 
- 	| r bounces |
- 	super step.
- 	bounces := 0.
- 	r := bounds origin corner: (bounds corner - (8 at 8)).
- 	self submorphsDo: [ :m |
- 		(m isMemberOf: AtomMorph) ifTrue: [
- 			(m bounceIn: r) ifTrue: [bounces := bounces + 1]]].
- 	"compute a 'temperature' that is proportional to the number of bounces
- 	 divided by the circumference of the enclosing rectangle"
- 	self updateTemperature: (10000.0 * bounces) / (r width + r height).
- 	transmitInfection ifTrue: [self transmitInfection].
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 	"As fast as possible."
- 
- 	^ 0
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>transmitInfection (in category 'other') -----
- transmitInfection
- 
- 	| count |
- 	self collisionPairs do: [:pair | | infected |
- 		infected := false.
- 		pair do: [:atom | atom infected ifTrue: [infected := true]].
- 		infected
- 			ifTrue: [pair do: [:atom | atom infected: true]]].
- 
- 	count := 0.
- 	self submorphsDo: [:m | m infected ifTrue: [count := count + 1]].
- 	infectionHistory addLast: count.
- 	count = submorphs size ifTrue: [
- 		transmitInfection := false.
- 		self stopStepping].
- !

Item was removed:
- ----- Method: BouncingAtomsMorph>>updateTemperature: (in category 'other') -----
- updateTemperature: currentTemperature 
- 	"Record the current temperature, which is taken to be the number of atoms that have bounced in the last cycle. To avoid too much jitter in the reading, the last several readings are averaged."
- 
- 	recentTemperatures isNil 
- 		ifTrue: 
- 			[recentTemperatures := OrderedCollection new.
- 			20 timesRepeat: [recentTemperatures add: 0]].
- 	recentTemperatures removeLast.
- 	recentTemperatures addFirst: currentTemperature.
- 	temperature := recentTemperatures sum asFloat / recentTemperatures size!

Item was removed:
- FlattenEncoder subclass: #ByteEncoder
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Postscript Filters'!

Item was removed:
- ----- Method: ByteEncoder class>>defaultTarget (in category 'configuring') -----
- defaultTarget
- 	^WriteStream on:(String new: 40000).!

Item was removed:
- ----- Method: ByteEncoder class>>filterSelector (in category 'configuring') -----
- filterSelector
- 	^#byteEncode:.!

Item was removed:
- ----- Method: ByteEncoder class>>numberDefaultBase (in category 'configuring') -----
- numberDefaultBase
- 	^10.
- !

Item was removed:
- ----- Method: ByteEncoder>>cr (in category 'writing') -----
- cr
- 	^target cr.
- !

Item was removed:
- ----- Method: ByteEncoder>>elementSeparator (in category 'filter streaming') -----
- elementSeparator
- 	^' '.!

Item was removed:
- ----- Method: ByteEncoder>>nextPut: (in category 'writing') -----
- nextPut: encodedObject
- 	"pass through for stream compatibility"
- 	^target nextPut: encodedObject.
- !

Item was removed:
- ----- Method: ByteEncoder>>nextPutAll: (in category 'writing') -----
- nextPutAll: encodedObject
- 	"pass through for stream compatibility"
- 	^target nextPutAll: encodedObject.
- !

Item was removed:
- ----- Method: ByteEncoder>>numberDefaultBase (in category 'accessing') -----
- numberDefaultBase
- 	^self class numberDefaultBase.
- !

Item was removed:
- ----- Method: ByteEncoder>>print: (in category 'writing') -----
- print:encodedObject
- 	^target write:encodedObject.
- !

Item was removed:
- ----- Method: ByteEncoder>>space (in category 'writing') -----
- space
- 	^target space.
- !

Item was removed:
- ----- Method: ByteEncoder>>tab (in category 'writing') -----
- tab
- 	^target tab.
- !

Item was removed:
- ----- Method: ByteEncoder>>writeArray: (in category 'writing') -----
- writeArray:aCollection
- 	^self writeArrayedCollection:aCollection.
- 
- !

Item was removed:
- ----- Method: ByteEncoder>>writeAssocation: (in category 'writing') -----
- writeAssocation:anAssociation
- 	^self write:anAssociation key; print:'->'; write:anAssociation value.
- 
- !

Item was removed:
- ----- Method: ByteEncoder>>writeCollection: (in category 'writing') -----
- writeCollection:aCollection
- 	^self print:aCollection class name; 
- 		writeCollectionContents:aCollection.
- 
- !

Item was removed:
- ----- Method: ByteEncoder>>writeCollectionContents: (in category 'writing') -----
- writeCollectionContents:aCollection
- 	self print:'( '.
- 		super writeCollectionContents:aCollection.
- 		self print:')'.
- 	^self.
- !

Item was removed:
- ----- Method: ByteEncoder>>writeNumber: (in category 'writing') -----
- writeNumber:aNumber
- 	^self writeNumber:aNumber base:self numberDefaultBase.
- 
- !

Item was removed:
- ----- Method: ByteEncoder>>writeNumber:base: (in category 'writing') -----
- writeNumber:aNumber base:aBase
- 	^aNumber byteEncode:self base:aBase.
- 
- !

Item was removed:
- ----- Method: ByteEncoder>>writeObject: (in category 'writing') -----
- writeObject:anObject
- 	^self print:anObject stringRepresentation.
- !

Item was removed:
- ----- Method: ByteEncoder>>writeString: (in category 'writing') -----
- writeString:aString
- 	^aString encodeDoublingQuoteOn:self.!

Item was removed:
- PluggableCanvas subclass: #CachingCanvas
- 	instanceVariableNames: 'cacheCanvas mainCanvas'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Support'!
- 
- !CachingCanvas commentStamp: '<historical>' prior: 0!
- A canvas which has a hidden form caching the events.  contentsOfArea:into: uses the cache, instead of the main canvas.  This is typically used with remote canvases, where querying the bits would involve a network transaction.
- !

Item was removed:
- ----- Method: CachingCanvas class>>on: (in category 'instance creation') -----
- on: aCanvas
- 	^super new mainCanvas: aCanvas!

Item was removed:
- ----- Method: CachingCanvas>>allocateForm: (in category 'canvas methods') -----
- allocateForm: extentPoint
- 
- 	^cacheCanvas form allocateForm: extentPoint!

Item was removed:
- ----- Method: CachingCanvas>>apply: (in category 'private') -----
- apply: aBlock
- 	aBlock value: cacheCanvas.
- 	aBlock value: mainCanvas.!

Item was removed:
- ----- Method: CachingCanvas>>contentsOfArea:into: (in category 'accessing') -----
- contentsOfArea: area  into: aForm
- 	^cacheCanvas contentsOfArea: area  into: aForm!

Item was removed:
- ----- Method: CachingCanvas>>form (in category 'accessing') -----
- form
- 	^cacheCanvas form!

Item was removed:
- ----- Method: CachingCanvas>>mainCanvas: (in category 'initialization') -----
- mainCanvas: mainCanvas0
- 	mainCanvas := mainCanvas0.
- 	cacheCanvas := FormCanvas extent: mainCanvas extent depth: mainCanvas depth.!

Item was removed:
- ----- Method: CachingCanvas>>showAt:invalidRects: (in category 'canvas methods') -----
- showAt: pt  invalidRects: rects
- 
- 	mainCanvas showAt: pt  invalidRects: rects!

Item was removed:
- Object subclass: #CameraInterface
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: '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>>bufferedInterruptDrivenVideoTest: (in category 'test') -----
- bufferedInterruptDrivenVideoTest: 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 bufferedInterruptDrivenVideoTest: 1"
- 	"self bufferedInterruptDrivenVideoTest: 2"
- 	"[self bufferedInterruptDrivenVideoTest: 2] fork.
- 	  self bufferedInterruptDrivenVideoTest: 1"
- 
- 	| semaphore height frameExtent frameBuffer |
- 	height := 16.
- 	1 to: camNum - 1 do:
- 		[:camIndex| "N.B. the extent of an unopened camera is 0 at 0"
- 		height := height + (self frameExtent: camIndex) y + 16].
- 	(self cameraIsOpen: camNum) ifFalse:
- 		[(self openCamera: camNum width: 352 height: 288) ifNil:
- 			[self inform: 'no camera'.
- 			 ^nil]].
- 	frameExtent := self frameExtent: camNum.
- 	frameBuffer := Form extent: frameExtent depth: 32.
- 	frameBuffer bits pin.
- 	self camera: camNum setFrameBuffer: frameBuffer bits.
- 		 
- 	semaphore := Semaphore new.
- 	[self camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)]
- 		on: Error
- 		do: [:err|
- 			Smalltalk unregisterExternalObject: semaphore.
- 			self inform: 'interrupt-driven camera interface unavailable: ', err messageText.
- 			^nil].
- 	[| n startTime frameCount msecs fps |
- 	 [semaphore wait.
- 	  startTime ifNil:
- 		[frameCount := 0.
- 		 frameExtent := self frameExtent: camNum.
- 		"N.B. the actual frame size may not be determined until delivery of the first frame.
- 		 So resize the form if necessary."
- 		 frameExtent ~= frameBuffer extent ifTrue:
- 			[frameBuffer := Form extent: frameExtent depth: 32 bits: frameBuffer bits].
- 		 startTime := Time millisecondClockValue].
- 	  Sensor anyButtonPressed] whileFalse:
- 		[n := self getFrameForCamera: camNum into: frameBuffer bits.
- 		n > 0 ifTrue:
- 			[frameCount := frameCount + 1.
- 			 frameBuffer displayAt: 16 @ height]].
- 	 msecs := Time millisecondClockValue - startTime.
- 	 fps := (frameCount * 1000) // msecs.
- 	 ^(self cameraName: camNum), ': ', frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec']
- 		ensure:
- 			[self closeCamera: camNum.
- 			 Smalltalk unregisterExternalObject: semaphore.
- 			 Sensor waitNoButton]!

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 the number of 16ms delays per second if polling is used, plus indications of which schemes
- 	 were used. Be destructive; use only one bitmap, overwriting its contents with each successive frame.
- 	 Use the buffered interface if possible. It is the sender's responsibility to open and close the camera."
- 	| form bitmap schemes delay start duration frameCount delayCount semaphore  |
- 	form := Form
- 				extent: (self frameExtent: cameraNum)
- 				depth: 32.
- 	bitmap := form bits.
- 	bitmap pin.
- 	schemes := Array new writeStream.
- 	[self camera: cameraNum setFrameBuffer: bitmap.
- 	 schemes nextPut: 'buffered']
- 		on: Error
- 		do: [:err|
- 			bitmap unpin.
- 			schemes nextPut: 'copied'].
- 	semaphore := Semaphore new.
- 	[self camera: cameraNum setSemaphore: (Smalltalk registerExternalObject: semaphore).
- 	 schemes nextPut: 'interrupt driven']
- 		on: Error
- 		do: [:err|
- 			Smalltalk unregisterExternalObject: semaphore.
- 			semaphore := nil.
- 			schemes nextPut: 'polling'].
- 	delay := Delay forMilliseconds: (1000 / 60) asInteger. "60 fps is fast"
- 
- 	start := Time utcMicrosecondClock.
- 	frameCount := delayCount := 0.
- 	[semaphore ifNotNil:
- 		[semaphore wait].
- 	[(self getFrameForCamera: cameraNum into: bitmap) <= 0] whileTrue:
- 		[delay wait. delayCount := delayCount + 1].
- 	 frameCount := frameCount + 1.
- 	 aBlock value: form.
- 	 whileBlock value] whileTrue.
- 	^{ frameCount * 1.0e6 / (duration := Time utcMicrosecondClock - start).
- 		delayCount * 1.0e6 / duration },
- 	 schemes contents
- 
- 	"| 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:setFrameBuffer: (in category 'camera ops') -----
- camera: cameraNum setFrameBuffer: frameBuffer
- 	"Set a pinned non-pointer object as the frame buffer for the camera.
- 	 Fail if cameraNum does not reference an open camera, or if the buffer is not large enough."
- 	<primitive: 'primSetCameraBuffers' module: 'CameraPlugin' error: ec>
- 	^self primitiveFailed!

Item was removed:
- ----- Method: CameraInterface class>>camera:setFrameBufferA:B: (in category 'camera ops') -----
- camera: cameraNum setFrameBufferA: frameBufferA B: frameBufferBOrNil
- 	"Set a pair of pinned non-pointer objects as the frame buffers for the camera.
- 	 If both are non-nil the plugin will fill them alternating between first frameBufferA and second frameBufferBOrNil.
- 	 Fail if frameBufferBOrNil is not nil and a different size from frameBufferA.
- 	 Fail if cameraNum does not reference an open camera, or if the buffers are not large enough."
- 	<primitive: 'primSetCameraBuffers' module: 'CameraPlugin' error: ec>
- 	^self primitiveFailed!

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 frameExtent |
- 	height := 16.
- 	1 to: camNum - 1 do:
- 		[:camIndex| "N.B. the extent of an unopened camera is 0 at 0"
- 		height := height + (self frameExtent: camIndex) y + 16].
- 	(self cameraIsOpen: camNum) ifFalse:
- 		[(self openCamera: camNum width: 352 height: 288) ifNil:
- 			[self inform: 'no camera'.
- 			 ^nil]].
- 	semaphore := Semaphore new.
- 	[self 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:
- 		[(frameExtent := self frameExtent: camNum) x = 0 ifTrue: [self inform: 'no camera'. ^nil].
- 		 f := Form extent: (self frameExtent: camNum) depth: 32.
- 		 frameCount := 0.
- 		 startTime := Time millisecondClockValue].
- 	  Sensor anyButtonPressed] whileFalse:
- 		[n := self getFrameForCamera: camNum into: f bits.
- 		n > 0 ifTrue:
- 			[frameCount := frameCount + 1.
- 			 f displayAt: 16 @ height]].
- 	 msecs := Time millisecondClockValue - startTime.
- 	 fps := (frameCount * 1000) // msecs.
- 	 ^(self cameraName: camNum), ': ', frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec']
- 		ensure:
- 			[self 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"
- 
- 	| frameExtent f n startTime frameCount msecs fps |
- 	(self cameraIsOpen: camNum) ifFalse:
- 		[(self openCamera: camNum width: 320 height: 240) ifNil:
- 			[self inform: 'no camera'.
- 			 ^nil]].
- 	self waitForCameraStart: camNum.
- 	(frameExtent := self frameExtent: camNum) x = 0 ifTrue: [^ self inform: 'no camera'].
- 	f := Form extent: (self frameExtent: camNum) depth: 32.
- 	frameCount := 0.
- 	startTime := nil.
- 	[Sensor anyButtonPressed] whileFalse:
- 		[n := self getFrameForCamera: camNum into: f bits.
- 		n > 0 ifTrue:
- 			[startTime ifNil: [startTime := Time millisecondClockValue].
- 			frameCount := frameCount + 1.
- 			f display]].
- 	Sensor waitNoButton.
- 	msecs := Time millisecondClockValue - startTime.
- 	self closeCamera: camNum.
- 	fps := frameCount * 1000 // msecs.
- 	^(self cameraName: camNum), ': ', frameExtent printString, ' ', 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 removed:
- ----- Method: Canvas>>paragraph2:bounds:color: (in category '*MorphicExtras-drawing') -----
- paragraph2: para bounds: bounds color: c
- 
- 	| scanner |
- 	scanner := CanvasCharacterScanner new.
- 	scanner
- 		 canvas: self;
- 		text: para text textStyle: para textStyle;
- 		textColor: c.
- 
- 	para displayOn: self using: scanner at: bounds topLeft.
- !

Item was removed:
- DisplayScanner subclass: #CanvasCharacterScanner
- 	instanceVariableNames: 'canvas'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Support'!
- 
- !CanvasCharacterScanner commentStamp: 'nice 10/12/2013 01:37' prior: 0!
- A CanvasCharacterScanner is displaying characters onto a Morphic canvas.
- 
- Instance Variables
- 	canvas:		<Canvas>
- 
- canvas
- 	- the canvas on which characters are displayed
- 
- !

Item was removed:
- ----- Method: CanvasCharacterScanner>>canvas: (in category 'accessing') -----
- canvas: aCanvas
- 	"set the canvas to draw on"
- 	canvas ifNotNil: [ self inform: 'initializing twice!!' ].
- 	canvas := aCanvas!

Item was removed:
- ----- Method: CanvasCharacterScanner>>convertToCurrentVersion:refStream: (in category 'object fileIn') -----
- convertToCurrentVersion: varDict refStream: smartRefStrm
- 
- 	"From Squeak3.5 [latest update: #5180] on 17 June 2003"
- 	varDict  at: 'defaultTextColor' put: Color black.
- 	^ super convertToCurrentVersion: varDict refStream: smartRefStrm!

Item was removed:
- ----- Method: CanvasCharacterScanner>>displayEmbeddedForm: (in category 'displaying') -----
- displayEmbeddedForm: aForm
- 	canvas
- 		drawImage: aForm
- 		at: destX @ (lineY + line baseline - aForm height)!

Item was removed:
- ----- Method: CanvasCharacterScanner>>displayString:from:to:at: (in category 'displaying') -----
- displayString: string from: startIndex  to: stopIndex at: aPoint
- 	canvas 
- 		drawString: string
- 		from: startIndex
- 		to: stopIndex
- 		at: aPoint
- 		font: font
- 		color: foregroundColor.!

Item was removed:
- ----- Method: CanvasCharacterScanner>>fillTextBackground (in category 'displaying') -----
- fillTextBackground
- 	"do nothing"!

Item was removed:
- RotaryDialMorph subclass: #ClockDialMorph
- 	instanceVariableNames: 'hourHandMorph'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !ClockDialMorph commentStamp: 'tpr 6/29/2017 13:26' prior: 0!
- A ClockDialMorph is a clock implemented as a rotary dial morph. The intersting part of this is having two needles that continuously rotate as opposed to the normal rule of having a single needle limited in range.
- 
- Instance Variables
- 	hourHandMorph:		<Morph, typically wrapped ina a TransformationMorph>!

Item was removed:
- ----- Method: ClockDialMorph>>buildDial (in category 'dial drawing') -----
- buildDial
- 	"start by making a damn big Form, twice the size we want to end up with"
- 	|outerRadius destForm canvas tickLabel tickLength beginAngle endAngle tickAngle maxTicks |
- 	outerRadius := self height  - 1.
- 	destForm := Form extent: self extent * 2 depth: 32.
- 	(canvas := destForm getCanvas) fillOval: (0 at 0 extent: self extent * 2) color: Color white.
- 	"outer ring"
- 	self drawArcAt: destForm center radius: outerRadius thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	"inner ring"
- 	self drawArcAt: destForm center radius: outerRadius * 0.97 thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	
- 	"outer scale for degrees"
- 	beginAngle := startAngle . 
- 	endAngle := stopAngle.
- 	
- 	maxTicks := stopValue - startValue .
- 	tickAngle := endAngle - beginAngle / maxTicks.
- 	startValue to: stopValue do: [:tick|
- 	tickLength := outerRadius * 0.07.
- 		tickLabel := nil.
- 		tick \\ 6 = 0 ifTrue:["tick every 6 degrees on the outer ring"
- 			self drawTickRadius: outerRadius * 0.9 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		].
- 		tick \\ 30 = 0 ifTrue: ["tick every 30 degrees on the inner ring"
- 			self drawTickRadius: outerRadius * 0.83 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 			(tick \\ 30 = 0 and: [tick < 360]) ifTrue:["numbered ticks every 30 degrees, don't overwrite 0 with 360"
- 				self tickInnerLabel: (tick // 30)  asString fontSize: 24 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.75) + tickLength angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas
- 				]
- 		]
- 	].
- 
- 	self addMorph: (destForm magnify: destForm boundingBox by: 0.5 smoothing: 2) asMorph!

Item was removed:
- ----- Method: ClockDialMorph>>initialize (in category 'initialization') -----
- initialize
- 	"assemble a nice clock morph. The background is an ImageMorph with scale/dial drawn with code adapted from a generous donation of time and effort by Bob Arning; the minute needle is the inherited needleMorph and we added a new hourHandMorph. Both are simple rectangleMorphs"
- 	| pointerMorph |
- 
- 	super initialize.
- 
- 	self startAngle: 0 stopAngle: 360;
- 			startValue: 0 stopValue: 360.
- 	self extent: self initialExtent; color: Color transparent; borderWidth: 0.
- 	dialCenter := self center.
- 
- 	"build the dial background; basic clock with miute ticks and hour long-ticks + arabic numerals"
- 	self buildDial.
- 
- 	pointerMorph := self basicNeedleOfLength: (self height * 0.45) rounded width: 4 color: Color red.
-  	pointerMorph
- 		position: pointerMorph extent * ( -0.5@ -1);
- 		rotationCenter: 0.5 @ 1.
- 
- 	"we keep track of the TransformationMorph since that is what we have to rotate"
- 	needleMorph := TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: needleMorph.
- 
- 	"additional neelde for the hours"
- 	pointerMorph := self basicNeedleOfLength: (self height * 0.35) rounded width: 6 color: Color black.
-  	pointerMorph
- 		position: pointerMorph extent * ( -0.5@ -1);
- 		rotationCenter: 0.5 @ 1.
- 
- 	"we keep track of the TransformationMorph since that is what we have to rotate"
- 	hourHandMorph := TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: hourHandMorph.
- 		
- 	"add a central colored dot. Because we just do."
- 	self addMorph: (CircleMorph new extent: 8 at 8; color: Color red twiceDarker; center: dialCenter)
- 	!

Item was removed:
- ----- Method: ClockDialMorph>>setTime: (in category 'updating') -----
- setTime: aTime
- 
- 	needleMorph rotationDegrees: aTime minutes * 6 + (aTime seconds / 10).
- 	hourHandMorph rotationDegrees: (aTime hours * 30) + (aTime minutes / 2)!

Item was removed:
- ----- Method: ClockDialMorph>>step (in category 'stepping and presenter') -----
- step
- 	self setTime: Time now!

Item was removed:
- ----- Method: ClockDialMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 	^5000!

Item was removed:
- StringMorph subclass: #ClockMorph
- 	instanceVariableNames: 'showSeconds show24hr'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!

Item was removed:
- ----- Method: ClockMorph class>>authoringPrototype (in category 'scripting') -----
- authoringPrototype
- 	^ super authoringPrototype contents: Time now printString!

Item was removed:
- ----- Method: ClockMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	"Answer a description for use in parts bins."
- 
- 	^ self partName:	'Digital Clock' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop}
- 		documentation:	'A digital clock' translatedNoop!

Item was removed:
- ----- Method: ClockMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: ClockMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#ClockMorph,	#authoringPrototype.	'Clock' translatedNoop.			'A simple digital clock' translatedNoop}
- 						forFlapNamed: 'Supplies'.
- 						cl registerQuad: {#ClockMorph.	#authoringPrototype.	'Clock' translatedNoop. 'A simple digital clock' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.]!

Item was removed:
- ----- Method: ClockMorph class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: ClockMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 	"Add toggles for showing-seconds and display-24-hrs to the halo menu"
- 
- 	"NB:  intentionallyi no super call here!!"
- 
- 	aCustomMenu add: 'change font' translated action: #changeFont.
- 
- 	aCustomMenu addUpdating: #showingSecondsString action: #toggleShowingSeconds.
- 	aCustomMenu addUpdating: #displaying24HourString action: #toggleShowing24hr!

Item was removed:
- ----- Method: ClockMorph>>balloonText (in category 'accessing') -----
- balloonText
- 
- 	^ Date current weekday, ', ', Date current printString!

Item was removed:
- ----- Method: ClockMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 
- 	super initialize.
- 
- 	showSeconds := true.
- 	show24hr := false.
- 	self font: Preferences standardMenuFont emphasis: 1.
- 	self step!

Item was removed:
- ----- Method: ClockMorph>>initializeToStandAlone (in category 'parts bin') -----
- initializeToStandAlone
- 	super initializeToStandAlone.
- 	showSeconds := false.
- 	self font: (Preferences standardMenuFont emphasized: 1).
- 	self step!

Item was removed:
- ----- Method: ClockMorph>>show24hr: (in category '24hr') -----
- show24hr: aBoolean
- 	show24hr := aBoolean!

Item was removed:
- ----- Method: ClockMorph>>showSeconds: (in category 'seconds') -----
- showSeconds: aBoolean
- 	showSeconds := aBoolean!

Item was removed:
- ----- Method: ClockMorph>>step (in category 'stepping and presenter') -----
- step
- 
- 	| time |
- 	super step.
- 	time := String streamContents: [ :stream |
- 		| t |
- 		t := Time now.
- 		t seconds: t asSeconds. "ignore nanoSeconds"
- 		t 
- 			print24: (show24hr == true)
- 			showSeconds: (showSeconds == true)
- 			on: stream].
- 	self contents: time!

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

Item was removed:
- ----- Method: ClockMorph>>toggleShowing24hr (in category '24hr') -----
- toggleShowing24hr
- 	show24hr := (show24hr == true) not
- !

Item was removed:
- ----- Method: ClockMorph>>toggleShowingSeconds (in category 'seconds') -----
- toggleShowingSeconds
- 	showSeconds := (showSeconds == true) not
- !

Item was removed:
- ----- Method: Color>>encodePostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- encodePostscriptOn: aStream
- 
- 	aStream setrgbcolor:self.
- 
- !

Item was removed:
- ----- Method: ColorForm>>encodePostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- encodePostscriptOn: aStream 
- 	self unhibernate.
- 	aStream print: '% form contains ';
- 	 write: (colors select: [:c | c = Color transparent]) size;
- 	 print: ' transparent colors';
- 	 cr.
- 	^ self asFormWithSingleTransparentColors 
- 		printPostscript: aStream operator: (self depth = 1
- 			ifTrue: ['imagemask']
- 			ifFalse: [(self indexOfColor: Color transparent) printString , ' transparentimage'])!

Item was removed:
- ----- Method: ColorForm>>printPostscript: (in category '*MorphicExtras-Postscript Canvases') -----
- printPostscript:aStream
- 	aStream nextPutAll:'% form contains '; 
- 			print:((colors select:[:c| c=Color transparent]) size); 
- 			nextPutAll:' transparent colors'; cr.
- 	^self asFormWithSingleTransparentColors printPostscript:aStream operator:(self depth=1 ifTrue:['imagemask'] 
- 	ifFalse:[ (self indexOfColor:Color transparent) printString ,' transparentimage']) .
- !

Item was removed:
- Object subclass: #Command
- 	instanceVariableNames: 'phase cmdWording undoTarget undoSelector undoArguments redoTarget redoSelector redoArguments parameters'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Undo'!
- 
- !Command commentStamp: 'nice 3/25/2010 22:59' prior: 0!
- An object representing an undoable command to be done in the environment.
- 
- Structure:
- 	phase			indicates whether the cmd is current in undone or redone mode
-  	cmdWording		The wording of the command (used in arming the "undo"/"redo" menu items
-  	parameters		an IdentityDictionary /NOT USED/
- 	undoTarget		Receiver, selector and arguments to accomplish undo
- 	undoSelector
- 	undoArguments
- 	redoTarget		Receiver, selector and arguments to accomplish redo
- 	redoSelector
- 	redoArguments
- 
- To use this, for any command you wish to use, you
- 	*	Create an instance of Command, as follows...
- 			cmd := Command new cmdWording: 'resizing'.
- 	*	Give the the command undo state and redo state, as follows...
- 			cmd undoTarget: target selector: #extent: argument: oldExtent.
- 			cmd redoTarget: target selector: #extent: argument: newExtent.
- 	*	Send a message of the form
- 			Command rememberCommand: cmd
- 
- LastCommand is the last command that was actually done or undone.
- 
- CommandHistory, applicable only when infiniteUndo is set, holds a 'tape' of the complete history of commands, as far back as it's possible to go.
- 
- CommandExcursions, also applicable only in the infiniteUndo case, and rather at the fringe even then, holds segments of former CommandHistory that have been lopped off because of variant paths taken.!

Item was removed:
- ----- Method: Command class>>cleanUp (in category 'initialize-release') -----
- cleanUp
- 
- 	MorphExtension allInstancesDo: [ :each | each removeUndoCommands ]!

Item was removed:
- ----- Method: Command class>>redoEnabled (in category 'dog simple ui') -----
- redoEnabled
- 	| w |
- 	^(w := self currentWorld) == nil ifTrue:[false] ifFalse:[w commandHistory redoEnabled]!

Item was removed:
- ----- Method: Command class>>redoNextCommand (in category 'dog simple ui') -----
- redoNextCommand
- 	| w |
- 	^(w := self currentWorld) == nil ifFalse:[w commandHistory redoNextCommand]!

Item was removed:
- ----- Method: Command class>>undoEnabled (in category 'dog simple ui') -----
- undoEnabled
- 	| w |
- 	^(w := self currentWorld) == nil ifTrue:[false] ifFalse:[w commandHistory undoEnabled]!

Item was removed:
- ----- Method: Command class>>undoLastCommand (in category 'dog simple ui') -----
- undoLastCommand
- 	| w |
- 	^(w := self currentWorld) == nil ifFalse:[w commandHistory undoLastCommand]!

Item was removed:
- ----- Method: Command class>>undoRedoButtons (in category 'dog simple ui') -----
- undoRedoButtons
- 	"Answer a morph that offers undo and redo buttons"
- 
- 	| wrapper |
- 	"self currentHand attachMorph: Command undoRedoButtons"
- 	wrapper := AlignmentMorph newColumn.
- 	wrapper color: Color veryVeryLightGray lighter;
- 		borderWidth: 0;
- 		layoutInset: 0;
- 		vResizing: #shrinkWrap;
- 		hResizing: #shrinkWrap.
- 	#((CrudeUndo undoLastCommand 'undo last command done' undoEnabled CrudeUndoDisabled CrudeUndoDisabled) 
- 	(CrudeRedo redoNextCommand 'redo last undone command' redoEnabled CrudeRedoDisabled CrudeRedoDisabled)) do:
- 		[:tuple |
- 			| aButton |
- 			wrapper addTransparentSpacerOfSize: (8 at 0).
- 			aButton := UpdatingThreePhaseButtonMorph new.
- 			aButton
- 				onImage: (ScriptingSystem formAtKey: tuple first);
- 				offImage: (ScriptingSystem formAtKey: tuple fifth);
- 				pressedImage: (ScriptingSystem formAtKey: tuple sixth);
- 				getSelector: tuple fourth;
- 				color: Color transparent; 
- 				target: self;
- 				actionSelector: tuple second;
- 				setNameTo: tuple second;
- 				setBalloonText: tuple third;
- 				extent: aButton onImage extent.
- 			wrapper addMorphBack: aButton.
- 			wrapper addTransparentSpacerOfSize: (8 at 0)].
- 	^ wrapper!

Item was removed:
- ----- Method: Command class>>zapObsolete (in category 'class initialization') -----
- zapObsolete
- "Command zapObsolete"
- 	"kill some obsolete stuff still retained by the CompiledMethods in change records"
- 
- 	| before after histories lastCmd histCount lastCount |
- 	Smalltalk garbageCollect.
- 	before := Command allInstances size.
- 	histories := Association allInstances select: [ :each | 
- 		each key == #CommandHistory and: [
- 			(each value isKindOf: OrderedCollection) and: [
- 				each value isEmpty not and: [
- 					each value first isKindOf: Command]]]
- 	].
- 	histCount := histories size.
- 	lastCmd := Association allInstances select: [ :each | 
- 		each key == #LastCommand and: [each value isKindOf: Command]
- 	].
- 	lastCount := lastCmd size.
- 	histories do: [ :each | each value: OrderedCollection new].
- 	lastCmd do: [ :each | each value: Command new].
- 	Smalltalk garbageCollect.
- 	Smalltalk garbageCollect.
- 	after := Command allInstances size.
- 	Transcript show: {before. after. histCount. histories. lastCount. lastCmd} printString; cr; cr.
- 	!

Item was removed:
- ----- Method: Command>>assuredParameterDictionary (in category 'private') -----
- assuredParameterDictionary
- 	"Private!!  Answer the parameters dictionary, creating it if necessary"
- 
- 	^ parameters ifNil: [parameters := IdentityDictionary new]!

Item was removed:
- ----- Method: Command>>cmdWording (in category 'private') -----
- cmdWording
- 	"Answer the wording to be used to refer to the command in a menu"
- 
- 	^ cmdWording ifNil: ['last command' translated]!

Item was removed:
- ----- Method: Command>>cmdWording: (in category 'initialization') -----
- cmdWording: wrd
- 	"Set the wording to be used in a menu item referring to the receiver"
- 
- 	cmdWording := wrd!

Item was removed:
- ----- Method: Command>>doCommand (in category 'command execution') -----
- doCommand
- 	"Do the command represented by the receiver.  Not actually called by active current code, but reachable by the not-yet-unsealed promoteToCurrent: action."
- 
- 	redoTarget ifNotNil: [redoTarget perform: redoSelector withArguments: redoArguments]!

Item was removed:
- ----- Method: Command>>parameterAt: (in category 'parameters') -----
- parameterAt: aSymbol
- 	"Answer the parameter stored at the given symbol, or nil if none"
- 
- 	^ self parameterAt: aSymbol ifAbsent: [nil]!

Item was removed:
- ----- Method: Command>>parameterAt:ifAbsent: (in category 'parameters') -----
- parameterAt: aSymbol ifAbsent: aBlock
- 	"Answer the parameter stored at the aSymbol, but if none, return the result of evaluating aBlock"
- 
- 	^ self assuredParameterDictionary at: aSymbol ifAbsent: aBlock!

Item was removed:
- ----- Method: Command>>parameterAt:put: (in category 'parameters') -----
- parameterAt: aSymbol put: aValue
- 	"Place aValue in the parameters dictionary using aSymbol as key"
- 
- 	^ self assuredParameterDictionary at: aSymbol put: aValue!

Item was removed:
- ----- Method: Command>>phase (in category 'private') -----
- phase
- 	"Answer the phase of the command"
- 
- 	^ phase!

Item was removed:
- ----- Method: Command>>phase: (in category 'initialization') -----
- phase: aPhase
- 	"Set the phase of the command to the supplied symbol"
- 
- 	phase := aPhase!

Item was removed:
- ----- Method: Command>>printOn: (in category 'printing') -----
- printOn: aStream
- 	"Provide more detailed info about the receiver, put in for debugging, maybe should be removed"
- 
- 	super printOn: aStream.
- 	aStream nextPutAll: ' phase: ', phase printString.
- 	cmdWording ifNotNil: [aStream nextPutAll: '; ', cmdWording asString].
- 	parameters ifNotNil:
- 		[parameters associationsDo:
- 			[:assoc | aStream nextPutAll: ': ', assoc printString]]!

Item was removed:
- ----- Method: Command>>redoCommand (in category 'command execution') -----
- redoCommand
- 	"Perform the 'redo' operation"
- 
- 	redoTarget ifNotNil: [redoTarget perform: redoSelector withArguments: redoArguments]!

Item was removed:
- ----- Method: Command>>redoTarget:selector:argument: (in category 'initialization') -----
- redoTarget: target selector: aSymbol argument: argument
- 
- 	^ self redoTarget: target selector: aSymbol arguments: {argument}!

Item was removed:
- ----- Method: Command>>redoTarget:selector:arguments: (in category 'initialization') -----
- redoTarget: target selector: selector arguments: arguments
- 	"Give target morph a chance to refine its undo operation"
- 
- 	target refineRedoTarget: target selector: selector arguments: arguments in:
- 		[:rTarget :rSelector :rArguments |
- 		redoTarget := rTarget.
- 		redoSelector := rSelector.
- 		redoArguments := rArguments]!

Item was removed:
- ----- Method: Command>>stillValid (in category 'command execution') -----
- stillValid
- 	"Answer whether the receiver is still valid."
- 
- 	^ (undoTarget isMorph and: [undoTarget isInWorld]) or: [redoTarget isMorph and:  [redoTarget isInWorld]]!

Item was removed:
- ----- Method: Command>>undoCommand (in category 'command execution') -----
- undoCommand
- 	"Perform the 'undo' operation"
- 
- 	undoTarget ifNotNil: [undoTarget perform: undoSelector withArguments: undoArguments]!

Item was removed:
- ----- Method: Command>>undoTarget (in category 'private') -----
- undoTarget
- 	^ undoTarget!

Item was removed:
- ----- Method: Command>>undoTarget:selector:argument: (in category 'initialization') -----
- undoTarget: target selector: aSymbol argument: argument
- 
- 	^ self undoTarget: target selector: aSymbol arguments: {argument}!

Item was removed:
- ----- Method: Command>>undoTarget:selector:arguments: (in category 'initialization') -----
- undoTarget: target selector: selector arguments: arguments
- 	"Give target morph a chance to refine its undo operation"
- 
- 	target refineUndoTarget: target selector: selector arguments: arguments in:
- 		[:rTarget :rSelector :rArguments |
- 		undoTarget := rTarget.
- 		undoSelector := rSelector.
- 		undoArguments := rArguments]!

Item was removed:
- ----- Method: Command>>veryDeepFixupWith: (in category 'copying') -----
- veryDeepFixupWith: deepCopier
- 	"ALL inst vars were weakly copied.  If they were in the tree being copied, fix them up, otherwise point to the originals!!!!"
- 	super veryDeepFixupWith: deepCopier.
- 	1 to: self class instSize do:
- 		[:ii |
- 		| old  |
- 		old := self instVarAt: ii.
- 		self instVarAt: ii put: (deepCopier references at: old ifAbsent: [old])].!

Item was removed:
- ----- Method: Command>>veryDeepInner: (in category 'copying') -----
- veryDeepInner: deepCopier
- 	"ALL fields are weakly copied!!  Can't duplicate an object by duplicating a Command that involves it.  See DeepCopier."
- 
- 	super veryDeepInner: deepCopier.
- 	"just keep old pointers to all fields"
- 	parameters := parameters.!

Item was removed:
- Object subclass: #CommandHistory
- 	instanceVariableNames: 'lastCommand history excursions'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Undo'!

Item was removed:
- ----- Method: CommandHistory class>>cleanUp (in category 'class initialization') -----
- cleanUp
- 	"Dump command histories"
- 
- 	self resetAllHistory
- !

Item was removed:
- ----- Method: CommandHistory class>>initialize (in category 'class initialization') -----
- initialize
- 	"CommandHistory initialize"
- 
- 	Smalltalk addToStartUpList: self.
- 	Smalltalk addToShutDownList: self.!

Item was removed:
- ----- Method: CommandHistory class>>resetAllHistory (in category 'system startup') -----
- resetAllHistory
- 	"Reset all command histories, and make all morphs that might be holding on to undo-grab-commands forget them"
- 
- 	self allInstancesDo: [:c | c resetCommandHistory].
- 	MorphExtension withAllSubclassesDo:
- 		[:morphExtensionClass|
- 		 morphExtensionClass allInstancesDo:
- 			[:object| object removeProperty: #undoGrabCommand]]
- 
- 	"CommandHistory resetAllHistory"
- !

Item was removed:
- ----- Method: CommandHistory class>>shutDown: (in category 'system startup') -----
- shutDown: aboutToQuit 
- 	Preferences purgeUndoOnQuit ifTrue: [
- 		aboutToQuit ifTrue: [self resetAllHistory].
- 	].
- !

Item was removed:
- ----- Method: CommandHistory class>>startUp: (in category 'system startup') -----
- startUp: aboutToQuit 
- 	Preferences purgeUndoOnQuit
- 		ifTrue: [
- 			aboutToQuit ifTrue: [self resetAllHistory].
- 		].
-  
- 	!

Item was removed:
- ----- Method: CommandHistory>>assureLastCommandStillValid (in category 'called by programmer') -----
- assureLastCommandStillValid
- 	"If the lastCommand is not valid, set it to nil; answer the lastCommand."
- 
- 	lastCommand ifNotNil:
- 		[lastCommand stillValid ifFalse:
- 			[self cantUndo]].
- 	^ lastCommand!

Item was removed:
- ----- Method: CommandHistory>>cantUndo (in category 'called by programmer') -----
- cantUndo
- 	"Called by client to indicate that the prior undoable command is no longer undoable"
- 
- 	lastCommand := nil.
- 	history := OrderedCollection new.!

Item was removed:
- ----- Method: CommandHistory>>commandToUndo (in category 'called from the ui') -----
- commandToUndo
- 	"Undo the last command, i.e. move backward in the recent-commands tape, if possible."
- 
- 	| anIndex |
- 	lastCommand ifNil: [^ nil].
- 	lastCommand phase == #done ifTrue: [^ lastCommand].
- 	(lastCommand phase == #undone and:
- 		[(anIndex := history indexOf: lastCommand) > 1])
- 		ifTrue: [^ history at: anIndex - 1]
- 		ifFalse: [^ nil]
- !

Item was removed:
- ----- Method: CommandHistory>>historyIndexOfLastCommand (in category 'command history') -----
- historyIndexOfLastCommand
- 	"Answer which position of the CommandHistory list is occupied by the LastCommand"
- 
- 	^ history indexOf: lastCommand!

Item was removed:
- ----- Method: CommandHistory>>initialize (in category 'initialize') -----
- initialize
- 	lastCommand := nil.
- 	history := OrderedCollection new.
- 	excursions := OrderedCollection new.!

Item was removed:
- ----- Method: CommandHistory>>lastCommand (in category 'command history') -----
- lastCommand
- 	"Answer the last command done or undone"
- 
- 	^ lastCommand!

Item was removed:
- ----- Method: CommandHistory>>nextCommand (in category 'command history') -----
- nextCommand
- 	"Answer the command object that would be sent the #redoCommand message if the user were to request Redo, or nil if none"
- 
- 	| anIndex |
- 	lastCommand ifNil: [^ nil].
- 	lastCommand phase == #undone ifTrue: [^ lastCommand].
- 	anIndex := history indexOf: lastCommand ifAbsent: [^ nil].
- 	^ anIndex = history size ifTrue: [nil] ifFalse: [history at: (anIndex + 1)]!

Item was removed:
- ----- Method: CommandHistory>>nextCommandToUndo (in category 'menu') -----
- nextCommandToUndo
- 	| anIndex |
- 	lastCommand ifNil: [^ nil].
- 	lastCommand phase == #done ifTrue: [^ lastCommand].
- 	(lastCommand phase == #undone and:
- 		[(anIndex := history indexOf: lastCommand) > 1])
- 		ifTrue: [^ history at: anIndex - 1]
- 		ifFalse: [^ nil]!

Item was removed:
- ----- Method: CommandHistory>>promoteToCurrent: (in category 'called by programmer') -----
- promoteToCurrent: aCommand
- 	"Very unusual and speculative and unfinished!!.  Not currently reachable.  For the real thing, we presumably march forward or backward from the current command pointer to the target command in an orderly fashion, doing or undoing each command in turn."
- 
- 	| itsIndex |
- 	Preferences useUndo ifFalse: [^ self].
- 	itsIndex := history indexOf: aCommand ifAbsent: [nil].
- 	itsIndex ifNotNil:
- 		[history remove: aCommand ifAbsent: []].
- 	history add: (lastCommand := aCommand).
- 	itsIndex < history size ifTrue:
- 		[excursions add: (history copyFrom: (itsIndex to: history size))].
- 	history := (history copyFrom: 1 to: itsIndex) copyWith: aCommand.
- 
- 	lastCommand := aCommand.
- 	aCommand doCommand.
- 	lastCommand phase: #done.!

Item was removed:
- ----- Method: CommandHistory>>purgeAllCommandsSuchThat: (in category 'called by programmer') -----
- purgeAllCommandsSuchThat: cmdBlock 
- 	"Remove a bunch of commands, as in [:cmd | cmd undoTarget == zort]"
- 
- 	Preferences useUndo ifFalse: [^self].
- 	history := history reject: cmdBlock.
- 	lastCommand := history isEmpty ifTrue: [nil] ifFalse: [history last] !

Item was removed:
- ----- Method: CommandHistory>>redoEnabled (in category 'menu') -----
- redoEnabled
- 	"Answer whether the redo command is currently available"
- 
- 	^ self nextCommand notNil!

Item was removed:
- ----- Method: CommandHistory>>redoMenuWording (in category 'menu') -----
- redoMenuWording
- 	"Answer the wording to be used in a menu offering the current 
- 	Redo command"
- 	| nextCommand |
- 
- 	((nextCommand := self nextCommand) isNil
- 			or: [Preferences useUndo not])
- 		ifTrue: [^ 'can''t redo' translated].
- 
- 	^ String
- 		streamContents: [:aStream | 
- 			aStream nextPutAll: 'redo' translated.
- 			aStream nextPutAll: ' "'.
- 			aStream nextPutAll: (nextCommand cmdWording truncateWithElipsisTo: 20).
- 			aStream nextPut: $".
- 			lastCommand phase == #done
- 				ifFalse: [aStream nextPutAll: ' (z)']]!

Item was removed:
- ----- Method: CommandHistory>>redoNextCommand (in category 'called from the ui') -----
- redoNextCommand
- 	"If there is a way to 'redo' (move FORWARD) in the undo/redo history tape, do it."
- 
- 	| anIndex |
- 	lastCommand ifNil: [^ Beeper beep].
- 	lastCommand phase == #undone
- 		ifFalse:
- 			[anIndex := history indexOf: lastCommand.
- 			(anIndex < history size)
- 				ifTrue:
- 					[lastCommand := history at: anIndex + 1]
- 				ifFalse:
- 					[^ Beeper beep]].
- 
- 	lastCommand redoCommand.
- 	lastCommand phase: #done
- !

Item was removed:
- ----- Method: CommandHistory>>rememberCommand: (in category 'undo') -----
- rememberCommand: aCommand
- 	"Make the supplied command be the 'LastCommand', and mark it 'done'"
- 
- 	| currentCommandIndex |
- 	Preferences useUndo ifFalse: [^ self].  "Command initialize"
- 
- 	Preferences infiniteUndo ifTrue:
- 		[currentCommandIndex := history indexOf: lastCommand.
- 		((currentCommandIndex < history size) and: [Preferences preserveCommandExcursions]) ifTrue:
- 			[excursions add: (history copyFrom: (currentCommandIndex to: history size)).
- 			history := history copyFrom: 1 to: currentCommandIndex].
- 		history addLast: aCommand].
- 
- 	lastCommand := aCommand.
- 	lastCommand phase: #done.!

Item was removed:
- ----- Method: CommandHistory>>resetCommandHistory (in category 'command history') -----
- resetCommandHistory    "CommandHistory allInstancesDo: [:ch | ch resetCommandHistory]"
- 	"Clear out the command history so that no commands are held"
- 
- 	lastCommand := nil.
- 	history := OrderedCollection new.!

Item was removed:
- ----- Method: CommandHistory>>undoEnabled (in category 'menu') -----
- undoEnabled
- 	"Answer whether there is an undoable command at the ready"
- 
- 	^ lastCommand notNil!

Item was removed:
- ----- Method: CommandHistory>>undoLastCommand (in category 'called from the ui') -----
- undoLastCommand
- 	"Undo the last command, i.e. move backward in the recent-commands tape, if possible."
- 
- 	| aPhase anIndex |
- 	lastCommand ifNil: [^ Beeper beep].
- 
- 	(aPhase := lastCommand phase) == #done
- 		ifFalse:
- 			[aPhase == #undone
- 				ifTrue:
- 					[anIndex := history indexOf: lastCommand.
- 					anIndex > 1 ifTrue:
- 						[lastCommand := history at: anIndex - 1]]].
- 
- 	lastCommand undoCommand.
- 	lastCommand phase: #undone
- 
- 	"Command undoLastCommand"
- !

Item was removed:
- ----- Method: CommandHistory>>undoMenuWording (in category 'menu') -----
- undoMenuWording
- 	"Answer the wording to be used in an 'undo' menu item"
- 
- 	(lastCommand isNil
- 			or: [Preferences useUndo not
- 			or: [(Preferences infiniteUndo not and: [lastCommand phase == #undone])
- 			or: [self nextCommandToUndo isNil]]])
- 		ifTrue: [^ 'can''t undo' translated].
- 
- 	^ String
- 		streamContents: [:aStream | 
- 			aStream nextPutAll: 'undo' translated.
- 			aStream nextPutAll: ' "'.
- 			aStream nextPutAll: (self nextCommandToUndo cmdWording truncateWithElipsisTo: 20).
- 			aStream nextPut: $".
- 			lastCommand phase == #done
- 				ifTrue: [aStream nextPutAll: ' (z)']].!

Item was removed:
- ----- Method: CommandHistory>>undoOrRedoCommand (in category 'called from the ui') -----
- undoOrRedoCommand
- 	"This gives a feature comparable to standard Mac undo/redo.  If the undo/redo action taken was a simple do or a redo, then undo it.  But if the last undo/redo action taken was an undo, then redo it."
- 
- 	"Command undoOrRedoCommand"
- 	| aPhase |
- 	lastCommand ifNil: [^ Beeper beep].
- 
- 	(aPhase := lastCommand phase) == #done
- 		ifTrue:
- 			[lastCommand undoCommand.
- 			lastCommand phase: #undone]
- 		ifFalse:
- 			[aPhase == #undone
- 				ifTrue:
- 					[lastCommand redoCommand.
- 					lastCommand phase: #done]]!

Item was removed:
- ----- Method: CommandHistory>>undoOrRedoMenuWording (in category 'menu') -----
- undoOrRedoMenuWording
- 	"Answer the wording to be used in a menu item offering undo/redo (i.e., the form used when the #infiniteUndo preference is false)"
- 
- 	| pre |
- 	self assureLastCommandStillValid. 
- 	lastCommand ifNil: [^ 'can''t undo' translated].
- 	pre := lastCommand phase == #done
- 		ifTrue: ['undo' translated]
- 		ifFalse: ['redo' translated].
- 	^ pre, ' "', (lastCommand cmdWording truncateWithElipsisTo: 20), '" (z)'!

Item was removed:
- ----- Method: CommandHistory>>undoTo (in category 'called from the ui') -----
- undoTo
- 	"Not yet functional, and not yet sent.  Allow the user to choose a point somewhere in the undo/redo tape, and undo his way to there.   Applicable only if infiniteUndo is set. "
- 
- 	| anIndex commandList reply |
- 	(anIndex := self historyIndexOfLastCommand) = 0 ifTrue: [^ Beeper beep].
- 	commandList := history
- 		copyFrom:	((anIndex - 10) max: 1)
- 		to:			((anIndex + 10) min: history size).
- 	reply := UIManager default chooseFrom: (commandList collect: [:cmd | cmd cmdWording truncateWithElipsisTo: 20]) values: commandList title: 'undo or redo to...'.
- 	reply ifNotNil: [self inform: #deferred]
- 
- 	"ActiveWorld commandHistory undoTo"
- !

Item was removed:
- RotaryDialMorph subclass: #CompassDialMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !CompassDialMorph commentStamp: 'tpr 4/14/2017 13:21' prior: 0!
- A CompassDialMorph shows a navigation compass. Unusually for most dials it has a full 360 degree span.!

Item was removed:
- ----- Method: CompassDialMorph>>basicNeedleOfLength:width:color: (in category 'needle graphics') -----
- basicNeedleOfLength: nLength width: nWidth color: aColor
- 	"make a really trivial needle as a colored rhombus"
- 	| fancy |
-     
- 	fancy := Form extent: nWidth at nLength depth: 32.
- 	fancy fillColor: Color transparent.
- 	fancy getCanvas asBalloonCanvas
- 		aaLevel: 4;
- 		drawPolygon: (Array with: (nWidth/ 2)@0 with: (nWidth)@( nLength / 2)  with:0@(nLength / 2) with: (nWidth/ 2)@0) fillStyle: aColor borderWidth: 1 borderColor: Color black;
- 		drawPolygon: (Array with: (nWidth)@( nLength / 2) with: (nWidth/ 2)@(nLength) with:0@(nLength / 2)  with: (nWidth)@( nLength / 2)) fillStyle: Color black borderWidth: 0 borderColor: Color black.
- 
- 	^fancy asMorph.
- !

Item was removed:
- ----- Method: CompassDialMorph>>buildDial (in category 'dial drawing') -----
- buildDial
- 	"start by making a damn big Form, twice the size we want to end up with"
- 	|outerRadius destForm canvas tickLabel tickLength beginAngle endAngle tickAngle maxTicks |
- 	outerRadius := self height  - 1.
- 	destForm := Form extent: self extent * 2 depth: 32.
- 	(canvas := destForm getCanvas) fillOval: (0 at 0 extent: self extent * 2) color: Color white.
- 	"outer ring"
- 	self drawArcAt: destForm center radius: outerRadius thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	"inner ring"
- 	self drawArcAt: destForm center radius: outerRadius * 0.97 thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	
- 	"outer scale for degrees"
- 	beginAngle := startAngle . 
- 	endAngle := stopAngle.
- 	
- 	self drawArcAt: destForm center radius: outerRadius * 0.9 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	self drawArcAt: destForm center radius: outerRadius * 0.83 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	self drawArcAt: destForm center radius: outerRadius * 0.55 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	"We use a simple % range, just one scale"
- 	maxTicks := stopValue - startValue .
- 	tickAngle := endAngle - beginAngle / maxTicks.
- 	startValue to: stopValue do: [:tick|
- 	tickLength := outerRadius * 0.07.
- 		tickLabel := nil.
- 		tick \\ 2 = 0 ifTrue:["tick every 2 degrees on the outer ring"
- 			self drawTickRadius: outerRadius * 0.9 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		].
- 		tick \\ 10 = 0 ifTrue: ["tick every 10 degrees on the inner ring"
- 			self drawTickRadius: outerRadius * 0.83 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 			(tick \\ 30 = 0 and: [tick < 360]) ifTrue:["numbered ticks every 30 degrees, don't overwrite 0 with 360"
- 				self tickInnerLabel: tick asString fontSize: 24 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.75) + tickLength angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas
- 			]
- 		].
- 		(tick \\ 90 = 0 and: [tick < 360]) ifTrue:["Major cardianl at the full points"
- 			tickLabel := { 'N'. 'E'. 'S'. 'W'. nil.} atWrap: tick // 90 +1.
- 			self tickInnerLabel: tickLabel fontSize: 36 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.65) + tickLength angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas
- 		].
- 		(tick \\ 90 = 45 and: [tick < 360]) ifTrue:["minor cardinal at the half-points"
- 			tickLabel := { 'NE'. 'SE'. 'SW'. 'NW'. nil.} atWrap: tick // 90 +1.
- 			self tickInnerLabel: tickLabel fontSize: 30 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.48) + tickLength angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas
- 		]		
- 	].
- 
- 	self addMorph: (destForm magnify: destForm boundingBox by: 0.5 smoothing: 2) asMorph!

Item was removed:
- ----- Method: CompassDialMorph>>initialize (in category 'initialize-release') -----
- initialize
- 	"assemble a nice compass morph. The background is an ImageMorph with scale/dial drawn with code adapted from a generous donation of time and effort by Bob Arning; similarly for the needle"
- 	| pointerMorph |
- 
- 	super initialize.
- 	"A compass runs from 0 deg to 360, clockwise. Traditional compass roses can be very ornate."
- 
- 	self startAngle: 0 stopAngle: 360;
- 			startValue: 0 stopValue: 360.
- 	self extent: self initialExtent; color: Color transparent; borderWidth: 0.
- 	dialCenter := self center.
- 
- 	"build the dial background. This is amazingly complex to think about programmatically; this example is fairly hard-coded by hand but somebody out there almost certainly has ideas about parameterizing this to amke a nice general utility"
- 	self buildDial.
- 
- 	"build our fancy needle as an ImageMorph, set the position to horizontal centre and about 2/3 down so that it rotates about that point when inside the TransformationMorph"
- 	pointerMorph := self basicNeedleOfLength: (self height * 0.65) rounded width: 10 color: Color red.
-  	pointerMorph
- 		position: pointerMorph extent * ( -0.5@ -0.5);
- 		rotationCenter: 0.5 @ 0.5.
- 
- 	"we keep track of the TransformationMorph since that is what we have to rotate as the incoming pressure values change"
- 	needleMorph := TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: needleMorph.
- 		
- 	"add a central colored dot. Because we just do."
- 	self addMorph: (CircleMorph new extent: 20 at 20; color: Color red twiceDarker; center: dialCenter)
- 	!

Item was removed:
- ----- Method: CurveMorph class>>extraExampleArrow (in category '*MorphicExtras-examples') -----
- extraExampleArrow
- 	"CurveMorph extraExampleArrow openInHand"
- 
- 	| arrow |
- 	arrow := CurveMorph
- 		vertices: {200 @ 75. 35 @ 0. 40 @ 55. -55 @ 30}
- 		color: Color veryDarkGray
- 		borderWidth: 5
- 		borderColor: Color veryDarkGray.
- 	arrow makeOpen; makeForwardArrow; beSmoothCurve.
- 	arrow addHandles.
- 	^ arrow!

Item was removed:
- ----- Method: CurveMorph class>>extraExampleTextFlow (in category '*MorphicExtras-examples') -----
- extraExampleTextFlow
- 	"CurveMorph extraExampleTextFlow openInHand"
- 
- 	| curve text |
- 	curve := CurveMorph
- 		vertices: {135 @ 270. 75 @ 200. 50 @ 150. 100 @ 100. 125 @ 150. 175 @ 100. 200 @ 150. 175 @ 200 . 115 @ 340} * RealEstateAgent scaleFactor
- 		color: Color cyan
- 		borderWidth: 25 * RealEstateAgent scaleFactor
- 		borderColor: Color salmon.
- 	curve makeOpen; beSmoothCurve.
- 	text := ('Texts can also follow ........................................ an open curve. ' asText
- 		, ('So morphic!!' asText
- 			addAttribute: TextEmphasis italic;
- 			addAttribute: (TextColor color: Color blue);
- 			yourself))
- 		addAttribute: (TextFontChange fontNumber: (3.4 * RealEstateAgent scaleFactor) rounded);
- 		asMorph.
- 	text textColor: Color yellow.
- 	curve addMorph: text.
- 	text followCurve.
- 	^ curve!

Item was removed:
- ----- Method: CurveMorph class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: CurveMorph class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#CurveMorph, #authoringPrototype. 'Curve'	translatedNoop, 'A curve' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#CurveMorph. #authoringPrototype. 'Curve'	 translatedNoop. 'A curve' translatedNoop}
- 						forFlapNamed: 'Supplies'.]!

Item was removed:
- ----- Method: CurveMorph class>>supplementaryPartsDescriptions (in category '*MorphicExtras-parts bin') -----
- supplementaryPartsDescriptions
- 	^ {DescriptionForPartsBin
- 		formalName: 'Curvy Arrow' translatedNoop
- 		categoryList: {'Graphics' translatedNoop}
- 		documentation: 'A curved line with an arrowhead.  Shift-click to get handles and move the points.' translatedNoop
- 		globalReceiverSymbol: #CurveMorph
- 		nativitySelector: #arrowPrototype}
- !

Item was removed:
- ----- Method: CurveMorph class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- PostscriptCanvas subclass: #DSCPostscriptCanvas
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Postscript Canvases'!
- 
- !DSCPostscriptCanvas commentStamp: '<historical>' prior: 0!
- I generate multi-page Postscript files, for example of Book morphs.  The goal is to crete Adobe Document Structuring Conventions compliant, but this is currently not the case.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvas>>defaultImageableArea (in category 'page geometry') -----
- defaultImageableArea
- 	^ self defaultPageSize insetBy:self defaultMargin.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvas>>defaultMargin (in category 'page geometry') -----
- defaultMargin  "In Points"
- 	^ (0.25 * 72) asInteger.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvas>>defaultPageSize (in category 'page geometry') -----
- defaultPageSize
- 	" This is Letter size in points.  European A4 is 595 @ 842 "
- 	^ 0 @ 0 extent: ((8.5 @ 11.0) * 72) asIntegerPoint.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvas>>endGStateForMorph: (in category 'morph drawing') -----
- endGStateForMorph: aMorph 
- 	"position the morph on the page "
- 	morphLevel
- 			== (topLevelMorph pagesHandledAutomatically
- 					ifTrue: [2]
- 					ifFalse: [1])
- 		ifTrue:  [ target showpage; print: 'grestore'; cr  ]!

Item was removed:
- ----- Method: DSCPostscriptCanvas>>fullDraw: (in category 'drawing-general') -----
- fullDraw: aMorph 
- 	(morphLevel = 0 and: [aMorph pagesHandledAutomatically not]) 
- 		ifTrue: 
- 			[pages := pages + 1.
- 			target
- 				print: '%%Page: 1 1';
- 				cr].
- 	super fullDraw: aMorph.
- 	morphLevel = 0 
- 		ifTrue: 
- 			[ self writeTrailer: pages. ]!

Item was removed:
- ----- Method: DSCPostscriptCanvas>>pageBBox (in category 'page geometry') -----
- pageBBox
- 	| pageSize offset bbox trueExtent |
- 	trueExtent := savedMorphExtent * initialScale.
- 	"this one has been rotated"
- 	pageSize := self defaultPageSize.
- 	offset := pageSize extent - trueExtent / 2 max: 0 @ 0.
- 	bbox := offset extent: trueExtent.
- 	^ bbox!

Item was removed:
- ----- Method: DSCPostscriptCanvas>>pageOffset (in category 'page geometry') -----
- pageOffset
- 	^self pageBBox origin.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvas>>setupGStateForMorph: (in category 'morph drawing') -----
- setupGStateForMorph: aMorph 
- 	"position the morph on the page "
- 	morphLevel
- 			== (topLevelMorph pagesHandledAutomatically
- 					ifTrue: [2]
- 					ifFalse: [1])
- 		ifTrue:  [ self writePageSetupFor: aMorph ]!

Item was removed:
- ----- Method: DSCPostscriptCanvas>>writePSIdentifierRotated: (in category 'initialization') -----
- writePSIdentifierRotated: rotateFlag 
- 	| morphExtent pageExtent |
- 	target print: '%!!PS-Adobe-2.0'; cr;
- 		 print: '%%Pages: (atend)'; cr;
- 		 print: '%%DocumentFonts: (atend)'; cr.
- 	"Define initialScale so that the morph will fit the page rotated or not"
- 	savedMorphExtent := morphExtent := rotateFlag
- 						ifTrue: [psBounds extent transposed]
- 						ifFalse: [psBounds extent].
- 	pageExtent := self defaultImageableArea extent asFloatPoint.
- 	initialScale := (printSpecs isNil
- 					or: [printSpecs scaleToFitPage])
- 				ifTrue: [pageExtent x / morphExtent x min: pageExtent y / morphExtent y]
- 				ifFalse: [1.0].
- 	target print: '%%BoundingBox: ';
- 		 write: self defaultImageableArea; cr.
- 	target print: '%%Title: '; print: self topLevelMorph externalName; cr.
- 	target print: '%%Creator: '; print: Utilities authorName; cr.
- 	target print: '%%CreationDate: '; print: Date today asString; space; print: Time now asString; cr.
- 
- 	target print: '%%Orientation: ';
- 		
- 		print: (rotateFlag
- 				ifTrue: ['Landscape']
- 				ifFalse: ['Portrait']); cr.
- 	target print: '%%EndComments'; cr.
- !

Item was removed:
- DSCPostscriptCanvas subclass: #DSCPostscriptCanvasToDisk
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Postscript Canvases'!

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk class>>defaultTarget (in category 'configuring') -----
- defaultTarget
- 
- 	^PostscriptEncoderToDisk stream.
- !

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk class>>morphAsPostscript:rotated:offsetBy: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset
- 
- 	^self morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset specs: nil
- !

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk class>>morphAsPostscript:rotated:offsetBy:specs: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset specs: specsOrNil
- 
- 
- 	^[
- 		(self new morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset) close
- 	]
- 		on: PickAFileToWriteNotification
- 		do: [ :ex |
- 			| newFileName stream |
- 			newFileName := UIManager default
- 				saveFilenameRequest: 'Name of file to write:' translated
- 				initialAnswer: 'xxx',Time millisecondClockValue printString, self defaultExtension. 
- 			newFileName isEmptyOrNil ifFalse: [
- 				stream := FileStream fileNamed: newFileName.
- 				stream ifNotNil: [ex resume: stream].
- 			].
- 		].
- 
- !

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk class>>morphAsPostscript:rotated:specs: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag specs: specsOrNil
- 
- 	^ self morphAsPostscript: aMorph rotated: rotateFlag offsetBy: self baseOffset specs: specsOrNil
- !

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk>>morphAsPostscript:rotated:offsetBy: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset
- 
- 	^self morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset specs: nil
- !

Item was removed:
- ----- Method: DSCPostscriptCanvasToDisk>>morphAsPostscript:rotated:offsetBy:specs: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag offsetBy: offset specs: specsOrNil 
- 	self reset.
- 	psBounds := offset extent: aMorph bounds extent.
- 	topLevelMorph := aMorph.
- 	self writeHeaderRotated: rotateFlag.
- 	self fullDrawMorph: aMorph.
- 	^ self close!

Item was removed:
- Object subclass: #DescriptionForPartsBin
- 	instanceVariableNames: 'formalName categoryList documentation globalReceiverSymbol nativitySelector sampleImageForm'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-PartsBin'!
- 
- !DescriptionForPartsBin commentStamp: '<historical>' prior: 0!
- An object description, for use with the ObjectsTool and other parts-bin-like repositories.
- 
- formalName				The formal name by which the object is to be known 
- categoryList				A list of category symbols, by way of attribute tags
- documentation			For use in balloon help, etc.
- globalReceiverSymbol	A symbol representing the global to whom to send nativitySelector 
- nativitySelector 		The selector to send to the global receiver to obtain a new instance!

Item was removed:
- ----- Method: DescriptionForPartsBin class>>formalName:categoryList:documentation:globalReceiverSymbol:nativitySelector: (in category 'instance creation') -----
- formalName: aName categoryList: aList documentation: aDoc globalReceiverSymbol: aSym nativitySelector: aSel
- 	"Answer a new instance of the receiver with the given traits"
- 
- 	^ self new formalName: aName categoryList: aList documentation: aDoc globalReceiverSymbol: aSym nativitySelector: aSel!

Item was removed:
- ----- Method: DescriptionForPartsBin class>>fromQuad:categoryList: (in category 'instance creation') -----
- fromQuad: aQuad categoryList: aList
- 	"Answer an instance of DescriptionForPartsBin from the part-defining quad provided"
- 
- 	^ self formalName: aQuad third categoryList: aList documentation: aQuad fourth globalReceiverSymbol: aQuad first nativitySelector: aQuad second!

Item was removed:
- ----- Method: DescriptionForPartsBin>>categories (in category 'accessing') -----
- categories
- 	"Answer the categoryList of the receiver"
- 
- 	^ categoryList!

Item was removed:
- ----- Method: DescriptionForPartsBin>>documentation (in category 'accessing') -----
- documentation
- 	"Answer the documentation of the receiver"
- 
- 	^ documentation!

Item was removed:
- ----- Method: DescriptionForPartsBin>>formalName (in category 'accessing') -----
- formalName
- 	"Answer the formalName of the receiver"
- 
- 	^ formalName!

Item was removed:
- ----- Method: DescriptionForPartsBin>>formalName:categoryList:documentation:globalReceiverSymbol:nativitySelector: (in category 'initialization') -----
- formalName: aName categoryList: aList documentation: aDoc globalReceiverSymbol: aSym nativitySelector: aSel
- 	"Set all of the receiver's instance variables from the parameters provided"
- 
- 	formalName := aName.
- 	categoryList := aList.
- 	documentation := aDoc.
- 	globalReceiverSymbol := aSym.
- 	nativitySelector  := aSel!

Item was removed:
- ----- Method: DescriptionForPartsBin>>globalReceiverSymbol (in category 'accessing') -----
- globalReceiverSymbol
- 	"Answer the globalReceiverSymbol of the receiver"
- 
- 	^ globalReceiverSymbol!

Item was removed:
- ----- Method: DescriptionForPartsBin>>nativitySelector (in category 'accessing') -----
- nativitySelector
- 	"Answer the nativitySelector of the receiver"
- 
- 	^ nativitySelector!

Item was removed:
- ----- Method: DescriptionForPartsBin>>printOn: (in category 'printing') -----
- printOn: aStream
- 	aStream nextPutAll: 'a DescriptionForPartsBin, with categoryList=', categoryList asString, ' docmentation=', documentation asString,  ' globalReceiverSymbol=', globalReceiverSymbol asString, ' nativitySelector=', nativitySelector asString !

Item was removed:
- ----- Method: DescriptionForPartsBin>>sampleImageForm (in category 'initialization') -----
- sampleImageForm
- 	"If I have a sample image form override stored, answer it, else answer one obtained by launching an actual instance"
- 
- 	^ sampleImageForm ifNil:
- 		[((Smalltalk at: globalReceiverSymbol) perform: nativitySelector) imageFormDepth: 32]!

Item was removed:
- ----- Method: DescriptionForPartsBin>>sampleImageForm: (in category 'initialization') -----
- sampleImageForm: aForm
- 	"Set the sample image form"
- 
- 	sampleImageForm := aForm!

Item was removed:
- ----- Method: DescriptionForPartsBin>>sampleImageFormOrNil (in category 'initialization') -----
- sampleImageFormOrNil
- 	"If I have a sample image form override stored, answer it, dlse answer nil"
- 
- 	^ sampleImageForm !

Item was removed:
- ----- Method: DescriptionForPartsBin>>translatedCategories (in category 'accessing') -----
- translatedCategories
- 	"Answer translated the categoryList of the receiver"
- 	^ self categories
- 		collect: [:each | each translated]!

Item was removed:
- PopUpChoiceMorph subclass: #DropDownChoiceMorph
- 	instanceVariableNames: 'items border'
- 	classVariableNames: 'SubMenuMarker'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!

Item was removed:
- ----- Method: DropDownChoiceMorph class>>initialize (in category 'class initialization') -----
- initialize
- 	"DropDownChoiceMorph initialize"
- 
- 	| f |
- 	f := Form
- 		extent: 5 at 9
- 		fromArray: #(2147483648 3221225472 3758096384 4026531840 4160749568 4026531840 3758096384 3221225472 2147483648)
- 		offset: 0 at 0.
- 	SubMenuMarker := ColorForm mappingWhiteToTransparentFrom: f.
- !

Item was removed:
- ----- Method: DropDownChoiceMorph>>border (in category 'accessing') -----
- border
- 	^border!

Item was removed:
- ----- Method: DropDownChoiceMorph>>border: (in category 'accessing') -----
- border: newBorder
- 	border := newBorder!

Item was removed:
- ----- Method: DropDownChoiceMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	aCanvas drawString: contents in: (bounds insetBy: 2)  font: self fontToUse color: color.
- 
- 	border ifNotNil: [aCanvas frameAndFillRectangle: bounds
- 		fillColor: Color transparent
- 		borderWidth: 1
- 		borderColor: Color black].
- 
- 	aCanvas
- 			paintImage: SubMenuMarker
- 			at: (self right - 8 @ ((self top + self bottom - SubMenuMarker height) // 2))!

Item was removed:
- ----- Method: DropDownChoiceMorph>>getCurrentSelectionIndex (in category 'list access') -----
- getCurrentSelectionIndex
- 	^self items indexOf: contents!

Item was removed:
- ----- Method: DropDownChoiceMorph>>items (in category 'accessing') -----
- items
- 	(target notNil and: [getItemsSelector notNil])
- 		ifTrue: [items := target perform: getItemsSelector withArguments: getItemsArgs].
- 	items ifNil: [items := #()].
- 	^items!

Item was removed:
- ----- Method: DropDownChoiceMorph>>items: (in category 'accessing') -----
- items: someItems
- 	items := someItems!

Item was removed:
- ----- Method: DropDownChoiceMorph>>maxExtent: (in category 'drawing') -----
- maxExtent: listOfStrings
- 
- 	| h maxW |
- 	maxW := 0.
- 	listOfStrings do: [:str | | f w |
- 		f := self fontToUse.
- 		w := f widthOfString: str.
- 		h := f height.
- 		maxW := maxW max: w].
- 	self extent: (maxW + 4 + h) @ (h + 4).
- 	self changed!

Item was removed:
- ----- Method: DropDownChoiceMorph>>mouseUp: (in category 'event handling') -----
- mouseUp: evt
- 
- 	| selectedItem |
- 	self items isEmpty ifTrue: [^ self].
- 	selectedItem := UIManager default chooseFrom: self items values: self items.
- 	selectedItem ifNil: [^ self].
- 	self contentsClipped: selectedItem.  "Client can override this if necess"
- 	actionSelector ifNotNil: [
- 		target
- 			perform: actionSelector
- 			withArguments: (arguments copyWith: selectedItem)].
- !

Item was removed:
- ----- Method: DropDownChoiceMorph>>selection: (in category 'list access') -----
- selection: val
- 	self contentsClipped: val!

Item was removed:
- ----- Method: DropDownChoiceMorph>>veryDeepInner: (in category 'copying') -----
- veryDeepInner: deepCopier
- 	super veryDeepInner: deepCopier.
- 	items := items veryDeepCopyWith: deepCopier.
- 	border := border veryDeepCopyWith: deepCopier!

Item was removed:
- PostscriptCanvas subclass: #EPSCanvas
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Postscript Canvases'!
- 
- !EPSCanvas commentStamp: '<historical>' prior: 0!
- I am a canvas for generating Encapsulates PostScript (EPS) files from single morphs, for example for screen-dumps.
- 
- I make sure that the bounding box of the EPS surrounds exactly the morph, and am not capable of generating multiple pages.  I do not generate an on-screen Preview for the EPS file, though that should be possible.
- !

Item was removed:
- ----- Method: EPSCanvas class>>baseOffset (in category 'configuring') -----
- baseOffset
- 	^0 at 0.!

Item was removed:
- ----- Method: EPSCanvas class>>defaultExtension (in category 'configuring') -----
- defaultExtension
- 	^'.eps'!

Item was removed:
- ----- Method: EPSCanvas>>fullDraw: (in category 'drawing-general') -----
- fullDraw: aMorph
- 	super fullDraw: aMorph.
- 	morphLevel = 0 ifTrue: [
- 		self writeTrailer: 1.
- 	]!

Item was removed:
- ----- Method: EPSCanvas>>pageBBox (in category 'page geometry') -----
- pageBBox
- 	^psBounds!

Item was removed:
- ----- Method: EPSCanvas>>pageOffset (in category 'page geometry') -----
- pageOffset
- 	^0 at 0!

Item was removed:
- ----- Method: EPSCanvas>>writeEPSPreviewImageFor: (in category 'private') -----
- writeEPSPreviewImageFor: aMorph
- 	| form stream string newExtent |
- 	newExtent := (aMorph width roundUpTo: 8) @ aMorph height.
- 	form := aMorph imageForm: 1 forRectangle: (aMorph bounds origin extent: newExtent).
- 	stream := WriteStream on: (String new: (form bits byteSize * 2.04) asInteger).
- 	form storePostscriptHexOn: stream.
- 	string := stream contents.
- 
- 	"%%BeginPreview: 80 24 1 24"
- 	"width height depth "
- 	target print: '%%BeginPreview: '; write:  newExtent; space; write: form depth; space; write: string lineCount; cr.
- 
- 	string linesDo: [:e | target nextPut: $%; nextPutAll: e; cr.].
- 
- 	target print: '%%EndPreview'; cr.
- 
- !

Item was removed:
- ----- Method: EPSCanvas>>writePSIdentifierRotated: (in category 'private') -----
- writePSIdentifierRotated: rotateFlag 
- 	target
- 		print: '%!!PS-Adobe-2.0 EPSF-2.0';
- 		cr.
- 	rotateFlag 
- 		ifTrue: 
- 			[target
- 				print: '%%BoundingBox: ';
- 				write: (0 @ 0 corner: psBounds corner transposed) rounded;
- 				cr]
- 		ifFalse: 
- 			[target
- 				print: '%%BoundingBox: ';
- 				write: psBounds rounded;
- 				cr].
- 	target
- 		print: '%%Title: ';
- 		print: self topLevelMorph externalName;
- 		cr.
- 	target
- 		print: '%%Creator: ';
- 		print: Utilities authorName;
- 		cr.
- 	target
- 		print: '%%CreationDate: ';
- 		print: Date today asString;
- 		space;
- 		print: Time now asString;
- 		cr.
- 		
- 	"is this relevant?"
- 	target print: '%%Orientation: ';
- 		 print: (rotateFlag ifTrue: [ 'Landscape' ] ifFalse: [ 'Portrait' ]);
- 		cr.
- 	target print: '%%DocumentFonts: (atend)'; cr.
- 	target
- 		print: '%%EndComments';
- 		cr
- 
- 	"	self writeEPSPreviewImageFor: topLevelMorph."
- 
- 	"	target print: '%%EndProlog'; cr."!

Item was removed:
- ----- Method: EllipseMorph class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: EllipseMorph class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#EllipseMorph. #authoringPrototype. 'Ellipse'	 translatedNoop. 'An ellipse or circle' translatedNoop}
- 						forFlapNamed: 'Supplies'.
- 						cl registerQuad: {#EllipseMorph. #authoringPrototype. 'Ellipse' translatedNoop. 'An ellipse or circle' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.]!

Item was removed:
- ----- Method: EllipseMorph class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- AlignmentMorph subclass: #EmbeddedWorldBorderMorph
- 	instanceVariableNames: 'heights minWidth minHeight'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalSupport'!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: menu hand: aHandMorph
- 
- 	super addCustomMenuItems: menu hand: aHandMorph.
- 
- 	self worldIEnclose
- 		addScalingMenuItems: menu 
- 		hand: aHandMorph
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>appViewBoxArea (in category 'boxes') -----
- appViewBoxArea
- 
- 	^self genericBoxArea: 1
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>boxesAndColorsAndSelectors (in category 'boxes') -----
- boxesAndColorsAndSelectors
- 
- 	^{
- 		{self zoomBoxArea. Color blue. #toggleZoom}.
- 		{self appViewBoxArea. Color yellow. #goAppView}.
- 		{self factoryViewBoxArea. Color red. #goFactoryView}.
- 		{self fullViewBoxArea. Color cyan. #goFullView}.
- 		{self normalEntryBoxArea. Color white. #goNormalProjectEntry}.
- 	}!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	super drawOn: aCanvas.
- 	self boxesAndColorsAndSelectors do: [ :each |
- 		aCanvas fillRectangle: each first fillStyle: each second
- 	].
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>extent: (in category 'geometry') -----
- extent: aPoint
- 
- 	bounds extent = aPoint ifFalse: [
- 		self changed.
- 		bounds := bounds topLeft extent: aPoint.
- 		self myWorldChanged.
- 	].
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>factoryViewBoxArea (in category 'boxes') -----
- factoryViewBoxArea
- 
- 	^self genericBoxArea: 2
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>fullViewBoxArea (in category 'boxes') -----
- fullViewBoxArea
- 
- 	^self genericBoxArea: 3
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>genericBoxArea: (in category 'boxes') -----
- genericBoxArea: countDownFromTop
- 
- 	^self innerBounds right @ (self top + (countDownFromTop * 2 * self borderWidth)) 
- 		extent: self borderWidth asPoint
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>goAppView (in category 'navigation') -----
- goAppView
- 
- 	self worldIEnclose showApplicationView
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>goFactoryView (in category 'navigation') -----
- goFactoryView
- 
- 	self worldIEnclose showFactoryView
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>goFullView (in category 'navigation') -----
- goFullView
- 
- 	self worldIEnclose showFullView
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>goNormalProjectEntry (in category 'navigation') -----
- goNormalProjectEntry
- 
- 	| w |
- 	w := self worldIEnclose.
- 	self delete.
- 	w project enter.
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	self boxesAndColorsAndSelectors do: [ :each |
- 		(each first containsPoint: evt cursorPoint) ifTrue: [^true]
- 	].
- 	^false
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>initialize (in category 'initialization') -----
- initialize
- 
- 	super initialize.
- 	self setBalloonText: 'This is the frame of an embedded project. Click on the colored boxes:
- blue - expand or reduce
- yellow - app view
- red - factory view
- cyan - full view
- white - enter the project completely' translated!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>minHeight: (in category 'layout') -----
- minHeight: anInteger
- 
- 	super minHeight: anInteger.
- 	minHeight := anInteger.!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>minWidth: (in category 'layout') -----
- minWidth: anInteger
- 
- 	super minWidth: anInteger.
- 	minWidth := anInteger.!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>morphicLayerNumber (in category 'submorphs - layers') -----
- morphicLayerNumber
- 	"Embedded worlds come in front of other worlds' Project navigation morphs"
- 
- 	^ self valueOfProperty: #morphicLayerNumber ifAbsent: [self class navigatorLayer - 1]	
- 	!

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 
- 	self boxesAndColorsAndSelectors do: [ :each |
- 		(each first containsPoint: evt cursorPoint) ifTrue: [
- 			^self perform: each third
- 		].
- 	].
- 
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>myTransformation (in category 'accessing') -----
- myTransformation
- 
- 	^submorphs detect: [ :x | x isKindOf: TransformationMorph] ifNone: [nil]
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>myWorldChanged (in category 'layout') -----
- myWorldChanged
- 	| trans |
- 	trans := self myTransformation.
- 	self changed.
- 	self layoutChanged.
- 	trans ifNotNil:[
- 		trans extentFromParent: self innerBounds extent.
- 		bounds := self bounds topLeft extent: trans extent + (self borderWidth * 2).
- 	].
- 	self changed.
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>normalEntryBoxArea (in category 'boxes') -----
- normalEntryBoxArea
- 
- 	^self genericBoxArea: 4
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>toggleZoom (in category 'accessing') -----
- toggleZoom
- 
- 	self bounds: (
- 		bounds area > (Display boundingBox area * 0.9) ifTrue: [
- 			Display extent // 4 extent: Display extent // 2.
- 		] ifFalse: [
- 			Display boundingBox
- 		]
- 	)
- 
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>worldIEnclose (in category 'accessing') -----
- worldIEnclose
- 
- 	^self myTransformation firstSubmorph	
- 					"quick hack since this is the only usage pattern at the moment"
- !

Item was removed:
- ----- Method: EmbeddedWorldBorderMorph>>zoomBoxArea (in category 'boxes') -----
- zoomBoxArea
- 
- 	^self genericBoxArea: 0
- !

Item was removed:
- RectangleMorph subclass: #EnvelopeEditorMorph
- 	instanceVariableNames: 'sound soundName envelope hScale vScale graphArea pixPerTick limits limitXs limitHandles line prevMouseDown sampleDuration showAllEnvelopes denominator keyboard'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!

Item was removed:
- ----- Method: EnvelopeEditorMorph class>>openOn:title: (in category 'opening') -----
- openOn: aSound title: aString
- 	"EnvelopeEditorMorph openOn: (AbstractSound soundNamed: 'brass1') copy title: 'brass1'"
- 	(self basicNew initOnSound: aSound title: aString) openInWorld!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>acceptGraphPoint:at: (in category 'editing') -----
- acceptGraphPoint: p at: index 
- 	| ms val points whichLim linePoint other boundedP |
- 	boundedP := p adhereTo: graphArea bounds.
- 	ms := self msFromX: boundedP x.
- 	points := envelope points.
- 	ms := self 
- 				constrain: ms
- 				adjacentTo: index
- 				in: points.
- 	(index = 1 or: [(whichLim := limits indexOf: index) > 0]) 
- 		ifTrue: 
- 			["Limit points must not move laterally"
- 
- 			ms := (points at: index) x].
- 	val := self valueFromY: boundedP y.
- 	points at: index put: ms @ val.
- 	linePoint := (self xFromMs: ms) @ (self yFromValue: val).
- 	(whichLim notNil and: [whichLim between: 1 and: 2]) 
- 		ifTrue: 
- 			["Loop start and loop end must be tied together"
- 
- 			other := limits at: 3 - whichLim.	" 1 <--> 2 "
- 			points at: other put: (points at: other) x @ val.
- 			line verticesAt: other put: (line vertices at: other) x @ linePoint y].
- 	"Make sure envelope feels the change in points array..."
- 	envelope 
- 		setPoints: points
- 		loopStart: limits first
- 		loopEnd: (limits second).
- 	^linePoint!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>addCurves (in category 'construction') -----
- addCurves
- 	"Add the polyLine corresponding to the currently selected envelope,
- 	and possibly all the others, too."
- 	
- 	sound envelopes do:
- 		[:env | | aLine verts | 
- 		(showAllEnvelopes or: [env == envelope]) ifTrue:
- 			[verts := env points collect:
- 				[:p | (self xFromMs: p x) @ (self yFromValue: p y)].
- 			aLine := EnvelopeLineMorph basicNew
- 						vertices: verts borderWidth: 1
- 						borderColor: (self colorForEnvelope: env).
- 			env == envelope
- 				ifTrue: [aLine borderWidth: 2.  line := aLine]
- 				ifFalse: [aLine on: #mouseUp send: #clickOn:evt:from:
- 							to: self withValue: env.
- 						self addMorph: aLine]]].
- 	self addMorph: line  "add the active one last (in front)"!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>addEnvelopeNamed: (in category 'editing') -----
- addEnvelopeNamed: envName
- 	| points env |
- 	points := OrderedCollection new.
- 	points add: 0 at 0.0;
- 		add: (envelope points at: envelope loopStartIndex) x at 1.0;
- 		add: (envelope points at: envelope loopEndIndex) x at 1.0;
- 		add: (envelope points last) x at 0.0.
- 	envName = 'volume' ifTrue:
- 		[env := VolumeEnvelope points: points loopStart: 2 loopEnd: 3.
- 		env target: sound; scale: 0.7].
- 	envName = 'modulation' ifTrue:
- 		[env := Envelope points: (points collect: [:p | p x @ 0.5])
- 						loopStart: 2 loopEnd: 3.
- 		env target: sound; updateSelector: #modulation:;
- 			scale: sound modulation*2.0].
- 	envName = 'pitch' ifTrue:
- 		[env := PitchEnvelope points: (points collect: [:p | p x @ 0.5])
- 						loopStart: 2 loopEnd: 3.
- 		env target: sound; updateSelector: #pitch:; scale: 0.5].
- 	envName = 'random pitch:' ifTrue:
- 		[env := RandomEnvelope for: #pitch:.
- 		points := OrderedCollection new.
- 		points add: 0@(env delta * 5 + 0.5);
- 			add: (envelope points at: envelope loopStartIndex) x@(env highLimit - 1 * 5 + 0.5);
- 			add: (envelope points at: envelope loopEndIndex) x@(env highLimit - 1 * 5 + 0.5);
- 			add: (envelope points last) x@(env lowLimit - 1 * 5 + 0.5).
- 		env setPoints: points loopStart: 2 loopEnd: 3.
- 		env target: sound. ].
- 	envName = 'ratio' ifTrue:
- 		[denominator := 9999.  "No gridding"
- 		env := Envelope points: (points collect: [:p | p x @ 0.5])
- 						loopStart: 2 loopEnd: 3.
- 		env target: sound; updateSelector: #ratio:;
- 			scale: sound ratio*2.0].
- 	env ifNotNil:
- 		[sound addEnvelope: env.
- 		self editEnvelope: env]!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>addHandlesIn: (in category 'construction') -----
- addHandlesIn: frame
- 	| handle |
- 	handle := PolygonMorph
- 		vertices: (Array with: 0 at 0 with: 8 at 0 with: 4 at 8)
- 		color: Color orange borderWidth: 1 borderColor: Color black.
- 	handle addMorph: ((RectangleMorph
- 			newBounds: ((self handleOffset: handle)-(2 at 0) extent: 1@(graphArea height-2))
- 			color: Color orange) borderWidth: 0).
- 
- 	limitHandles := Array with: handle with: handle veryDeepCopy with: handle veryDeepCopy.
- 	1 to: limitHandles size do:
- 		[:i | handle := limitHandles at: i.
- 		handle on: #mouseDown
- 				send: #limitHandleMove:event:from:
- 				to: self withValue: i.
- 		handle on: #mouseMove
- 				send: #limitHandleMove:event:from:
- 				to: self withValue: i.
- 		self addMorph: handle.
- 		handle position: ((self xFromMs: 
- 			(envelope points at: (limits at: i)) x) @ 
- 				(graphArea top)) - (self handleOffset: handle)]!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>addKeyboard (in category 'construction') -----
- addKeyboard
- 	keyboard := PianoKeyboardMorph new soundPrototype: sound.
- 	keyboard align: keyboard bounds bottomCenter with: bounds bottomCenter - (0 at 4).
- 	self addMorph: keyboard!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>adjustScale: (in category 'menu') -----
- adjustScale: evt 
- 	| scaleString oldScale baseValue |
- 	oldScale := envelope scale.
- 	scaleString := UIManager default request: 'Enter the new full-scale value...'
- 				initialAnswer: oldScale printString.
- 	scaleString isEmpty ifTrue: [^self].
- 	envelope scale: (Number readFrom: scaleString) asFloat.
- 	baseValue := envelope updateSelector = #pitch: ifTrue: [0.5] ifFalse: [0.0].
- 	envelope 
- 		setPoints: (envelope points collect: 
- 					[:p | 
- 					p x @ ((p y - baseValue) * oldScale / envelope scale + baseValue min: 1.0
- 								max: 0.0)])
- 		loopStart: (limits first)
- 		loopEnd: (limits second).
- 	self buildView!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>buildGraphAreaIn: (in category 'construction') -----
- buildGraphAreaIn: frame
- 	| r y |
- 	graphArea := RectangleMorph
- 		newBounds: ((frame left + 15) @ (frame top + 15)
- 		corner: (frame right+1) @ (frame bottom - 70))
- 		color: Color lightGreen lighter lighter.
- 	graphArea borderWidth: 1.
- 	self addMorph: graphArea.
- 	(envelope updateSelector = #pitch: and: [envelope scale <= 2.0]) ifTrue:
- 		["Show half-steps"
- 		r := graphArea innerBounds.
- 		0.0 to: 1.0 by: 1.0/12.0/envelope scale do:
- 			[:val |
- 			y := self yFromValue: val.
- 			graphArea addMorph: ((RectangleMorph
- 					newBounds: (r left at y extent: r width at 1)
- 					color: Color veryLightGray)
- 						borderWidth: 0)]].
- 	(envelope updateSelector = #ratio: and: [denominator ~= 9999]) ifTrue:
- 		["Show denominator gridding"
- 		r := graphArea innerBounds.
- 		(0.0 to: 1.0 by: 1.0/denominator/envelope scale) do:
- 			[:v |
- 			y := self yFromValue: v.
- 			graphArea addMorph: ((RectangleMorph
- 					newBounds: (r left at y extent: r width at 1)
- 					color: Color veryLightGray)
- 						borderWidth: 0)]].
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>buildScalesIn: (in category 'editing') -----
- buildScalesIn: frame
- 	| env |
- 	env := envelope.
- 	pixPerTick := graphArea width // (self maxTime//10) max: 1.
- 	"hminortick := ( 1 + ( self maxTime // 800 ) ) * 10.
- 	hmajortick := ( 1 + ( self maxTime // 800 ) ) * 100."
- 	hScale := (Morph newBounds: ((graphArea left)@(frame top) corner: (self xFromMs: self maxTime)@(graphArea top - 1))) color: Color lightGreen.
- "	hScale := (ScaleMorph newBounds: ((graphArea left)@(frame top) corner: (self xFromMs: self maxTime)@(graphArea top - 1)))
- 		start: 0 stop: self maxTime
- 		minorTick: hminortick minorTickLength: 3
- 		majorTick: hmajortick majorTickLength: 10
- 		caption: 'milliseconds' tickPrintBlock: [:v | v printString].
- "
- 	self addMorph: hScale.
- 	vScale := (Morph newBounds: (0 at 0 extent: (graphArea height)@(graphArea left - frame left))) color: Color lightGreen.
- 	"vScale := ScaleMorph newBounds: (0 at 0 extent: (graphArea height)@(graphArea left - frame left))."
- 	"env name = 'pitch'
- 		ifTrue:
- 		[env scale >= 2.0
- 			ifTrue:
- 			[vScale start: 0 stop: env scale
- 				minorTick: env scale / 24 minorTickLength: 3
- 				majorTick: env scale / 2.0 majorTickLength: 10
- 				caption: 'pitch (octaves)'
- 				tickPrintBlock: [:v | (v-(env scale/2)) asInteger printString]]
- 			ifFalse:
- 			[vScale start: 0 stop: env scale
- 				minorTick: 1.0/48.0 minorTickLength: 3
- 				majorTick: 1.0/12.0 majorTickLength: 10
- 				caption: 'pitch (half-steps)'
- 				tickPrintBlock: [:v | (v-(env scale/2)*12) rounded printString]]]
- 		ifFalse: [
- 			env name = 'random pitch:'
- 				ifTrue: [
- 					vScale start: 0.9 stop: 1.1
- 						minorTick: 0.2 / 50.0 minorTickLength: 3
- 						majorTick: 0.2 / 5.0 majorTickLength: 10
- 						caption: env name
- 						tickPrintBlock: [:v | v printString]]
- 				ifFalse: [
- 					vScale start: 0 stop: env scale
- 						minorTick: env scale / 50.0 minorTickLength: 3
- 						majorTick: env scale / 5.0 majorTickLength: 10
- 						caption: env name
- 						tickPrintBlock: [:v | v printString]].
- 		]."
- 	vScale := TransformationMorph new asFlexOf: vScale.
- 	vScale angle: Float pi / 2.0.
- 	self addMorph: vScale.
- 	vScale position: (frame left + 1)@(graphArea top-1) - (3 at 1).
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>buildView (in category 'construction') -----
- buildView
- 	| frame |
- 	self color: Color lightGreen.
- 	self removeAllMorphs.
- 	frame := self innerBounds.
- 	self buildGraphAreaIn: frame.
- 	self buildScalesIn: frame.
- 	self addHandlesIn: frame.
- 	self addCurves.
- 	line addHandles.
- 	self addMorph: self makeControls.
- 	self addKeyboard!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>chooseDenominator: (in category 'menu') -----
- chooseDenominator: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	(Integer primesUpTo: 30) do:
- 		[:i |
- 		menu add: i printString
- 			target: self selector: #setDenominator:
- 			argument: i].
- 	menu addLine.
- 	menu add: 'none' target: self selector: #setDenominator: argument: 9999.
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>chooseEnvelope: (in category 'menu') -----
- chooseEnvelope: choice
- 	| name |
- 	(choice beginsWith: 'edit ') ifTrue:
- 		[name := choice copyFrom: 'edit ' size+1 to: choice size.
- 		^ self editEnvelope: (sound envelopes detect:
- 				[:env | env name = name])].
- 	(choice beginsWith: 'add ') ifTrue:
- 		[name := choice copyFrom: 'add ' size+1 to: choice size.
- 		^ self addEnvelopeNamed: name].
- 	(choice beginsWith: 'remove ') ifTrue:
- 		[^ self removeEnvelope  "the current one"].
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>chooseFrom:envelopeItem: (in category 'menu') -----
- chooseFrom: chooserMorph envelopeItem: item
- 	| name |
- 	(item beginsWith: 'edit ') ifTrue:
- 		[name := item copyFrom: 'edit ' size+1 to: item size.
- 		self editEnvelope: (sound envelopes detect:
- 				[:env | env name = name])].
- 	(item beginsWith: 'add ') ifTrue:
- 		[name := item copyFrom: 'add ' size+1 to: item size.
- 		self addEnvelopeNamed: name].
- 	(item beginsWith: 'remove ') ifTrue:
- 		[self removeEnvelope  "the current one"].
- 	chooserMorph contentsClipped: envelope name!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>chooseFrom:soundItem: (in category 'menu') -----
- chooseFrom: chooserMorph soundItem: item
- 	self editSoundNamed: item.
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>chooseSound: (in category 'menu') -----
- chooseSound: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	menu add: 'new...' target: self selector: #editNewSound.
- 	menu addLine.
- 	AbstractSound soundNames do:
- 		[:name |
- 		menu add: name
- 			target: self selector: #editSoundNamed:
- 			argument: name].
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>clickOn:evt:from: (in category 'editing') -----
- clickOn: env evt: anEvent from: aLine
- 	self editEnvelope: env!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>clickOnLine:evt:envelope: (in category 'editing') -----
- clickOnLine: arg1 evt: arg2 envelope: arg3
- 	"Reorder the arguments for existing event handlers"
- 	(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].
- 	^self clickOn: arg1 evt: arg2 from: arg3!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>colorForEnvelope: (in category 'construction') -----
- colorForEnvelope: env
- 	| name index |
- 	name := env name.
- 	index := #('volume' 'modulation' 'pitch' 'ratio') indexOf: name
- 				ifAbsent: [5].
- 	^ Color perform: (#(red green blue magenta black) at: index)!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>constrain:adjacentTo:in: (in category 'editing') -----
- constrain: xVal adjacentTo: ix in: points
- 	"Return xVal, restricted between points adjacent to vertX"
- 	| newVal |
- 	newVal := xVal.
- 	ix > 1 ifTrue: [newVal := newVal max: (points at: ix-1) x].
- 	ix < points size ifTrue: [newVal := newVal min: (points at: ix+1) x].
- 	^ newVal!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>curveChoices (in category 'construction') -----
- curveChoices
- 	| extant others |
- 	extant := sound envelopes collect: [:env | env name].
- 	others := #('volume' 'modulation' 'pitch' 'random pitch:' 'ratio')
- 		reject: [:x | (extant includes: x) | ((x = 'pitch') & (extant includes: 'random pitch:')) | ((x = 'random pitch:') & (extant includes: 'pitch')) ].
- 	^ (extant collect: [:name | 'edit ' , name])
- 	, (others collect: [:name | 'add ' , name])
- 	, (sound envelopes size > 1
- 		ifTrue: [Array with: 'remove ' , envelope name]
- 		ifFalse: [Array new])!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>deletePoint: (in category 'editing') -----
- deletePoint: ix 
- 	"If the point is a limit point, return false,
- 	otherwise, delete the point at ix, and return true."
- 
- 	(limits includes: ix) ifTrue: [^false].
- 	1 to: limits size
- 		do: 
- 			[:i | 
- 			"Decrease limit indices beyond the deletion"
- 
- 			(limits at: i) > ix ifTrue: [limits at: i put: (limits at: i) - 1]].
- 	envelope 
- 		setPoints: (envelope points 
- 				copyReplaceFrom: ix
- 				to: ix
- 				with: Array new)
- 		loopStart: (limits first)
- 		loopEnd: (limits second).
- 	^true!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>editEnvelope: (in category 'initialization') -----
- editEnvelope: env
- 	envelope := env.
- 	limits := Array with: envelope loopStartIndex
- 				with: envelope loopEndIndex
- 				with: envelope points size.
- 	limitXs := limits collect: [:i | (envelope points at: i) x].
- 	self buildView!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>editNewSound (in category 'menu') -----
- editNewSound
- 	| known i |
- 	known := AbstractSound soundNames.
- 	i := 0.
- 	[soundName := 'unnamed' , i printString.
- 	known includes: soundName]
- 		whileTrue: [i := 1+1].
- 	soundName := soundName.
- 	self editSound: FMSound default copy!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>editSound: (in category 'initialization') -----
- editSound: aSound
- 
- 	| p |
- 	(aSound respondsTo: #envelopes)
- 		ifFalse: [
- 			UIManager default inform: 'You selected a ', aSound class name, '.', String cr,
- 				'I can''t handle these kinds of sounds.'.
- 			^self ].
- 	sound := aSound.
- 	sound envelopes isEmpty ifTrue: [
- 		"provide a default volume envelope"
- 		p := OrderedCollection new.
- 		p add: 0 at 0.0; add: 10 at 1.0; add: 100 at 1.0; add: 120 at 0.0.
- 		sound addEnvelope: (VolumeEnvelope points: p loopStart: 2 loopEnd: 3)].
- 
- 	self editEnvelope: sound envelopes first.
- 	keyboard soundPrototype: sound.
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>editSoundNamed: (in category 'menu') -----
- editSoundNamed: name
- 
- 	name = 'new...' ifTrue: [^ self editNewSound].
- 	soundName := name.
- 	self editSound: (AbstractSound soundNamed: soundName) copy!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>extent: (in category 'geometry') -----
- extent: newExtent
- 	super extent: (newExtent max: (self maxTime//10*3+50 max: 355) @ 284).
- 	self buildView!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>handleOffset: (in category 'construction') -----
- handleOffset: handle
- 	"This is the offset from position to the bottom vertex"
- 	^ (handle width//2+1) @ handle height
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>initOnSound:title: (in category 'initialization') -----
- initOnSound: aSound title: title
- 	sound := aSound.
- 	soundName := title.
- 	self initialize.
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	prevMouseDown := false.
- 	showAllEnvelopes := true.
- 	soundName ifNil: [soundName := 'test'].
- 	self editSound: (sound ifNil: [FMSound brass1 copy]).
- 	sound duration: 0.25.
- 	denominator := 7.
- 	self extent: 10 at 10.  "ie the minimum"
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>insertPointAfter: (in category 'editing') -----
- insertPointAfter: ix 
- 	"If there is not enough roon (in x) then return false.
- 	Otherwise insert a point between ix and ix+1 and return true."
- 
- 	| points pt |
- 	points := envelope points.
- 	(points at: ix + 1) x - (points at: ix) x < 20 ifTrue: [^false].
- 	pt := ((points at: ix + 1) + (points at: ix)) // 2.
- 	1 to: limits size
- 		do: 
- 			[:i | 
- 			"Increase limit indices beyond the insertion"
- 
- 			(limits at: i) > ix ifTrue: [limits at: i put: (limits at: i) + 1]].
- 	envelope 
- 		setPoints: (points 
- 				copyReplaceFrom: ix + 1
- 				to: ix
- 				with: (Array with: pt))
- 		loopStart: (limits first)
- 		loopEnd: (limits second).
- 	^true!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>invokeMenu (in category 'menu') -----
- invokeMenu
- 	"Invoke a menu of additonal functions for this ScorePlayer."
- 	| menu |
- 	menu := MenuMorph new defaultTarget: self.
- 	
- 	envelope updateSelector = #ratio: ifTrue:
- 		[menu add: 'choose denominator...' translated action: #chooseDenominator:].
- 	menu add: 'adjust scale...' translated action: #adjustScale:.
- 	SoundPlayer isReverbOn
- 		ifTrue: [menu add: 'turn reverb off' translated target: SoundPlayer selector: #stopReverb]
- 		ifFalse: [menu add: 'turn reverb on' translated target: SoundPlayer selector: #startReverb].
- 	menu addLine.
- 	menu add: 'get sound from lib' translated action: #chooseSound:.
- 	menu add: 'put sound in lib' translated action: #saveSound:.
- 	menu add: 'read sound from disk...' translated action: #readFromDisk:.
- 	menu add: 'save sound on disk...' translated action: #saveToDisk:.
- 	menu add: 'save library on disk...' translated action: #saveLibToDisk:.
- 	menu popUpInWorld: self world!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>limitHandleMove:event:from: (in category 'editing') -----
- limitHandleMove: index event: evt from: handle
- 	"index is the handle index = 1, 2 or 3"
- 	| ix p x ms limIx |
- 	ix := limits at: index.  "index of corresponding vertex"
- 	p := evt cursorPoint adhereTo: graphArea bounds.
- 	ms := self msFromX: p x + (self handleOffset: handle) x.
- 
- 	"Constrain move to adjacent points on ALL envelopes"
- 	sound envelopes do:
- 		[:env |
- 		limIx := env perform:
- 			(#(loopStartIndex loopEndIndex decayEndIndex) at: index).
- 		ms := self constrain: ms adjacentTo: limIx in: env points].
- 
- 	"Update the handle, the vertex and the line being edited"
- 	x := self xFromMs: ms.
- 	handle position: (x @ graphArea top) - (self handleOffset: handle).
- 	line verticesAt: ix put: x @ (line vertices at: ix) y.
- 
- 	sound envelopes do:
- 		[:env | | points |
- 		limIx := env perform:
- 			(#(loopStartIndex loopEndIndex decayEndIndex) at: index).
- 		points := env points.
- 		points at: limIx put: ms @ (points at: limIx) y.
- 		env setPoints: points loopStart: env loopStartIndex loopEnd: env loopEndIndex].!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>limitHandleMoveEvent:from:index: (in category 'editing') -----
- limitHandleMoveEvent: arg1 from: arg2 index: arg3
- 	"Reorder the arguments for existing event handlers"
- 	(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].
- 	^self limitHandleMove: arg1 event: arg2 from: arg3!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>makeControls (in category 'construction') -----
- makeControls
- 	| chooser button row |
- 	row := AlignmentMorph newRow color: color; borderWidth: 0.
- 	row align: row bounds topLeft with: graphArea bounds bottomLeft + (0 at 5).
- 	button := SimpleButtonMorph new target: self; borderColor: Color black;
- 			borderWidth: 2; color: color.
- 	row addMorphBack: (button label: 'Menu' translated; actWhen: #buttonDown;
- 												actionSelector: #invokeMenu).
- 	row addMorphBack: (Morph new extent:10 at 1; color: Color transparent).
- 	chooser := PopUpChoiceMorph new extent: 120 at 14;
- 		contentsClipped: 'Editing: ' , envelope name;
- 		target: self;
- 		actionSelector: #chooseFrom:envelopeItem:;
- 		getItemsSelector: #curveChoices.
- 	chooser arguments: (Array with: chooser).
- 	row addMorphBack: chooser.
- 	
- 	chooser := PopUpChoiceMorph new extent: 130 at 14;
- 		contentsClipped: 'Timbre: ' , soundName;
- 		target: self;
- 		actionSelector: #chooseFrom:soundItem:;
- 		getItemsSelector: #soundChoices.
- 	chooser arguments: (Array with: chooser).
- 	row addMorphBack: chooser.
- 	
- 	^row!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>maxTime (in category 'scaling') -----
- maxTime
- 	^ (envelope points at: limits last) x + 100!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>msFromX: (in category 'scaling') -----
- msFromX: x
- 	^ (x - graphArea left)//pixPerTick*10!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>playNothing (in category 'playing') -----
- playNothing
- !

Item was removed:
- ----- Method: EnvelopeEditorMorph>>readFileNamed: (in category 'menu') -----
- readFileNamed: fileName
- 	| snd |
- 	snd := Compiler evaluate:
- 		(FileStream readOnlyFileNamed: fileName) contentsOfEntireFile.
- 	soundName := fileName copyFrom: 1 to: fileName size-4. "---.fmp"
- 	self editSound: snd!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>readFromDisk: (in category 'menu') -----
- readFromDisk: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	(FileDirectory default fileNamesMatching: '*.fmp') do:
- 		[:fileName |
- 		menu add: fileName
- 			target: self selector: #readFileNamed:
- 			argument: fileName].
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>removeEnvelope (in category 'menu') -----
- removeEnvelope
- 	(UIManager default confirm: 'Really remove ' , envelope name , '?')
- 		ifFalse: [^ self].
- 	sound removeEnvelope: envelope.
- 	self editEnvelope: sound envelopes first.!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>saveLibToDisk: (in category 'menu') -----
- saveLibToDisk: evt 
- 	"Save the library to disk"
- 	| newName |
- 	newName := UIManager default saveFilenameRequest: 'Please confirm name for library...' initialAnswer: 'MySounds.fml'.
- 	newName ifNil: [^ self].
- 
- 	FileStream newFileNamed: newName
- 		do: [:f | AbstractSound soundNames
- 				do: [:name | | snd |
- 					snd := AbstractSound soundNamed: name.
- 					f nextChunkPut: 'AbstractSound soundNamed: ' , name , ' put: ' , snd storeString;
- 						cr;
- 						cr]]!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>saveSound: (in category 'menu') -----
- saveSound: evt
- 	| newName |
- 	newName := UIManager default request: 'Please confirm name for save...'
- 						initialAnswer: soundName.
- 	newName isEmpty ifTrue: [^ self].
- 	AbstractSound soundNamed: newName put: sound.
- 	soundName := newName.!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>saveToDisk: (in category 'menu') -----
- saveToDisk: evt
- 	| newName |
- 	newName := UIManager default saveFilenameRequest: 'Please confirm name for save...'
- 						initialAnswer: soundName, '.fmp'.
- 	newName isEmptyOrNil ifTrue: [^ self].
- 	FileStream newFileNamed: newName
- 		do:[:f| sound storeOn: f]!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>setDenominator: (in category 'menu') -----
- setDenominator: denom
- 	denominator := denom.
- 	self buildView!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>soundBeingEdited (in category 'initialization') -----
- soundBeingEdited
- 
- 	^ sound!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>soundChoices (in category 'construction') -----
- soundChoices
- 	^ #('new...') , AbstractSound soundNames!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>step (in category 'stepping and presenter') -----
- step
- 	| mouseDown hand |
- 	hand := self world firstHand.
- 	(bounds containsPoint: hand position) ifFalse: [^ self].
- 
- 	mouseDown := hand lastEvent redButtonPressed.
- 	mouseDown not & prevMouseDown ifTrue:
- 		["Mouse just went up"
- 		limitXs = (limits collect: [:i | (envelope points at: i) x]) ifFalse:
- 			["Redisplay after changing limits"
- 			self editEnvelope: envelope]].
- 	prevMouseDown := mouseDown!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 	^ 100!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>valueFromY: (in category 'scaling') -----
- valueFromY: y
- 	"The convention is that envelope values are between 0.0 and 1.0"
- 	| value |
- 	value := (graphArea bottom - y) asFloat / (graphArea height).
- 	envelope updateSelector = #ratio: ifTrue:
- 		["Ratio gets gridded by denominator"
- 		^ (value * envelope scale * denominator) rounded asFloat / denominator / envelope scale].
- 	^ value!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>wantsRoundedCorners (in category 'rounding') -----
- wantsRoundedCorners
- 	^ SystemWindow roundedWindowCorners or: [super wantsRoundedCorners]!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>xFromMs: (in category 'scaling') -----
- xFromMs: ms
- 	^ graphArea left + (ms//10*pixPerTick)!

Item was removed:
- ----- Method: EnvelopeEditorMorph>>yFromValue: (in category 'scaling') -----
- yFromValue: val
- 	"The convention is that envelope values are between 0.0 and 1.0"
- 	^ graphArea bottom - (val* (graphArea height))!

Item was removed:
- PolygonMorph subclass: #EnvelopeLineMorph
- 	instanceVariableNames: 'editor'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!

Item was removed:
- ----- Method: EnvelopeLineMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color transparent!

Item was removed:
- ----- Method: EnvelopeLineMorph>>dragVertex:event:fromHandle: (in category 'editing') -----
- dragVertex: ix event: evt fromHandle: handle
- 	| p |
- 	super dragVertex: ix event: evt fromHandle: handle.
- 	p := owner acceptGraphPoint: evt cursorPoint at: ix.
- 	self verticesAt: ix put: p.
- !

Item was removed:
- ----- Method: EnvelopeLineMorph>>dropVertex:event:fromHandle: (in category 'editing') -----
- dropVertex: ix event: evt fromHandle: handle
- 	| oldVerts |
- 	oldVerts := vertices.
- 	super dropVertex: ix event: evt fromHandle: handle.
- 	vertices = oldVerts ifFalse: [owner deletePoint: ix "deleted a vertex"]!

Item was removed:
- ----- Method: EnvelopeLineMorph>>newVertex:event:fromHandle: (in category 'editing') -----
- newVertex: ix event: evt fromHandle: handle
- 	"Install a new vertex if there is room."
- 	(owner insertPointAfter: ix) ifFalse: [^ self "not enough room"].
- 	super newVertex: ix event: evt fromHandle: handle.
- 	self verticesAt: ix+1 put: (owner acceptGraphPoint: evt cursorPoint at: ix+1).
- !

Item was removed:
- ----- Method: EnvelopeLineMorph>>vertices:borderWidth:borderColor: (in category 'initialization') -----
- vertices: verts borderWidth: bw borderColor: bc 
- 	super initialize.
- 	vertices := verts.
- 	
- 	self borderWidth: bw.
- 	self borderColor: bc.
- 	
- 	closed := false.
- 	arrows := #none.
- 	self computeBounds!

Item was removed:
- ----- Method: EventHandler>>adaptToWorld: (in category '*MorphicExtras-initialization') -----
- adaptToWorld: aWorld
- 	"If any of my recipients refer to a world or a hand, make them now refer
- 	to the corresponding items in the new world.  (instVarNamed: is slow, later
- 	use perform of two selectors.)"
- 
- 	
- 	#(mouseDownRecipient mouseStillDownRecipient mouseUpRecipient
- 	mouseEnterRecipient mouseLeaveRecipient mouseEnterDraggingRecipient
- 	mouseLeaveDraggingRecipient clickRecipient doubleClickRecipient startDragRecipient keyStrokeRecipient valueParameter) do:
- 		[:aName | | value newValue |
- 		(value := self instVarNamed: aName asString) ifNotNil:[
- 			newValue := value adaptedToWorld: aWorld.
- 			(newValue notNil and: [newValue ~~ value])
- 				ifTrue:
- 					[self instVarNamed: aName asString put: newValue]]]!

Item was removed:
- AlignmentMorph subclass: #EventRecorderMorph
- 	instanceVariableNames: 'tape state time deltaTime recHand playHand lastEvent lastDelta tapeStream saved statusLight voiceRecorder startSoundEvent recordMeter caption journalFile'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalSupport'!
- 
- !EventRecorderMorph commentStamp: '<historical>' prior: 0!
- During recording, the EventRecorder subscribes to all events of the normal morphic hand, and saves them as they occur.
- 
- For replay, a second playback hand is created that reads events from the recorder and plays them back in the world.
- 
- The EventRecorder began with the work of Ted Kaehler and John Malone.  This was then signifcantly expanded by Leandro Caniglia and Valeria Murgia as a tutorial aid for the Morphic Wrapper project.
- 
- Since that time, I have...
- Changed to a simple inboard array for the tape (event storage).
- Provided the ability to condense linear mouse movement with interpolation at replay.
- Made simple provisions for wrap-around of the millisecond clock.
- Eliminated step methods in favor of using the processEvents cycle in the playback hand.
- Provided a pause/resume mechanism that is capable of surviving project changes.
- Added the ability to spawn a simple 'play me' button that can be saved as a morph.
- Caused the playback hand to display its cursor double size for visibility.
- Integrated a voice recorder with on-the-fly compression.
- 	This currently does NOT survive project changes, not is its data stored on the tape.
- 	Right now it can only be saved by saving the entire recorder as a morph.
- 	This will be fixed by adding a startSound event at each project change.
- 	We will also convert read/write file to use saveOnFile.
- Added a journal file facility for recording sequences that end in a crash.
- The above two features can be engaged via the ER's morph menu.
- 	- Dan Ingalls 3/6/99!

Item was removed:
- ----- Method: EventRecorderMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	"Answer  a description for use in a parts bin"
- 
- 	^ self partName: 'Event Recorder'
- 		categories: #(Presentation Tools)
- 		documentation: 'Lets you record and play back interactions'!

Item was removed:
- ----- Method: EventRecorderMorph class>>fileReaderServicesForFile:suffix: (in category 'fileIn/Out') -----
- fileReaderServicesForFile: fullName suffix: suffix
- 
- 	^(suffix = 'tape') | (suffix = '*') 
- 		ifTrue: [ self services]
- 		ifFalse: [#()]
- 
- !

Item was removed:
- ----- Method: EventRecorderMorph class>>fromFileNamed: (in category 'instance creation') -----
- fromFileNamed: aFileName
- 	| file answer |
- 	file := FileStream readOnlyFileNamed: aFileName.
- 	answer := self readFrom: file setConverterForCode.
- 	file close.
- 	^ answer!

Item was removed:
- ----- Method: EventRecorderMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	FileServices registerFileReader: self!

Item was removed:
- ----- Method: EventRecorderMorph class>>openTapeFromFile: (in category 'instance creation') -----
- openTapeFromFile: fullName
- 	"Open an eventRecorder tape for playback."
-  
- 	(self new) readTape: fullName; openInWorld!

Item was removed:
- ----- Method: EventRecorderMorph class>>readFrom: (in category 'instance creation') -----
- readFrom: aStream
- 	^ self new readFrom: aStream!

Item was removed:
- ----- Method: EventRecorderMorph class>>services (in category 'fileIn/Out') -----
- services
- 
- 	^{SimpleServiceEntry 
- 			provider: self 
- 			label: 'open for playback'
- 			selector: #openTapeFromFile:.}
- !

Item was removed:
- ----- Method: EventRecorderMorph class>>unload (in category 'initialize-release') -----
- unload
- 
- 	FileServices unregisterFileReader: self !

Item was removed:
- ----- Method: EventRecorderMorph>>addButtons (in category 'initialization') -----
- addButtons
- 	| r b w |
- 
- 	caption ifNotNil: ["Special setup for play-only interface"
- 		(r := self makeARowForButtons)
- 			addMorphBack: (SimpleButtonMorph new target: self;
- 	 							label: caption font: Preferences standardButtonFont; actionSelector: #play);
- 			addMorphBack: self makeASpacer.
- 		w := r fullBounds height * 0.5.
- 		r addMorphBack: (self makeStatusLightIn: (w at w));
- 			addMorphBack: self makeASpacer.
- 		^ self addMorphBack: r
- 	].
- 
- 	(r := self makeARowForButtons)
- 		addMorphBack: (b := self buttonFor: {#record. nil. 'Begin recording'});
- 		addMorphBack: self makeASpacer;
- 		addMorphBack: (self buttonFor: {#stop. b width. 'Stop recording - you can also use the ESC key to stop it'});
- 		addMorphBack: self makeASpacer;
- 		addMorphBack: (self buttonFor: {#play. b width. 'Play current recording'}).
- 	self addMorphBack: r.
- 
- 	(r := self makeARowForButtons)
- 		addMorphBack: (b := self buttonFor: {#writeTape. nil. 'Save current recording on disk'});
- 		addMorphBack: self makeASpacer;
- 		addMorphBack: (self buttonFor: {#readTape. b width. 'Get a new recording from disk'}).
- 	self addMorphBack: r.
- 
- 	(r := self makeARowForButtons)
- 		addMorphBack: (b := self buttonFor: {#shrink. nil. 'Make recording shorter by removing unneeded events'});
- 		addMorphBack: self makeASpacer.
- 	w := r fullBounds height * 0.5.
- 	r addMorphBack: (self makeStatusLightIn: (w at w));
- 		addMorphBack: self makeASpacer;
- 		addMorphBack: (self buttonFor: {#createPlayButton. b width. 'Make a simple button to play this recording'}).
- 	self addMorph: r.
- 	self setStatusLight: #ready.!

Item was removed:
- ----- Method: EventRecorderMorph>>addCustomMenuItems:hand: (in category 'initialization') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'add voice controls' translated action: #addVoiceControls.
- 	aCustomMenu add: 'add journal file' translated action: #addJournalFile.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>addJournalFile (in category 'initialization') -----
- addJournalFile
- 	"In case there is a chance of not regaining control to stop recording and save a file, the EventRecorder can write directly to file as it is recording.  This is useful for capturing a sequence that results in a nasty crash."
- 
- 	journalFile ifNotNil: [journalFile close].
- 	journalFile := FileStream newFileNamed: 'EventRecorder.tape'.
- 	journalFile nextPutAll:'Event Tape v1 ASCII'; cr.!

Item was removed:
- ----- Method: EventRecorderMorph>>addMorphsTo:pianoRoll:eventTime:betweenTime:and: (in category 'sound-piano rolls') -----
- addMorphsTo: morphList pianoRoll: pianoRoll eventTime: t betweenTime: leftTime and: rightTime
- 
- 	| startX myDurationInTicks endX |
- 
- 	startX := pianoRoll xForTime: t.
- 	myDurationInTicks := pianoRoll scorePlayer ticksForMSecs: self myDurationInMS.
- 	t > rightTime ifTrue: [^ self].  
- 	(t + myDurationInTicks) < leftTime ifTrue: [^ self].
- 	endX := pianoRoll xForTime: t + myDurationInTicks.
- 
- 	morphList add: 
- 		(self hResizing: #spaceFill; left: startX; width: endX - startX).
- 
- !

Item was removed:
- ----- Method: EventRecorderMorph>>addVoiceControls (in category 'sound') -----
- addVoiceControls 
- 
- 	| levelSlider r meterBox |
- 	voiceRecorder := SoundRecorder new
- 		desiredSampleRate: 11025.0;		"<==try real hard to get the low rate"
- 		codec: (GSMCodec new).		"<--this should compress better than ADPCM.. is it too slow?"
- 		"codec: (ADPCMCodec new initializeForBitsPerSample: 4 samplesPerFrame: 0)."
- 
- 	levelSlider := SimpleSliderMorph new
- 		color: color;
- 		extent: 100 at 2;
- 		target: voiceRecorder;
- 		actionSelector: #recordLevel:;
- 		adjustToValue: voiceRecorder recordLevel.
- 	r := AlignmentMorph newRow
- 		color: color;
- 		layoutInset: 0;
- 		wrapCentering: #center; cellPositioning: #leftCenter;
- 		hResizing: #shrinkWrap;
- 		vResizing: #rigid;
- 		height: 24.
- 	r addMorphBack: (StringMorph contents: '0 ').
- 	r addMorphBack: levelSlider.
- 	r addMorphBack: (StringMorph contents: ' 10').
- 	self addMorphBack: r.
- 
- 	meterBox := Morph new extent: 102 at 18; color: Color gray.
- 	recordMeter := Morph new extent: 1 at 16; color: Color yellow.
- 	recordMeter position: meterBox topLeft + (1 at 1).
- 	meterBox addMorph: recordMeter.
- 
- 	r := AlignmentMorph newRow vResizing: #shrinkWrap.
- 	r addMorphBack: meterBox.
- 	self addMorphBack: r.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>button (in category 'commands') -----
- button
- 	"Make a simple button interface for replay only"
- 	| butnCaption erm |
- 	butnCaption := UIManager default request: 'Caption for this butn?' translated initialAnswer: 'play' translated.
- 	butnCaption isEmpty ifTrue: [^ self].
- 	erm := (EventRecorderMorph basicNew
- 				caption: butnCaption
- 				voiceRecorder: voiceRecorder copy
- 				tape: tape) initialize.
- 	self world primaryHand attachMorph: erm!

Item was removed:
- ----- Method: EventRecorderMorph>>button: (in category 'accessing') -----
- button: label 
- 	^ self allMorphs
- 		detect: [:one | (one isKindOf: SimpleButtonMorph)
- 				and: [one label = label]]
- 		ifNone: []!

Item was removed:
- ----- Method: EventRecorderMorph>>buttonFor: (in category 'initialization') -----
- buttonFor: data 
- 
- 	| b |
- 	b := SimpleButtonMorph new 
- 		target: self;
- 		label: data first asString translated;
- 		actionSelector: data first.
- 	data second ifNotNil: [b width < data second ifTrue: [b width: data second]].
- 	data third ifNotNil: [b setBalloonText: data third translated].
- 	^b!

Item was removed:
- ----- Method: EventRecorderMorph>>caption:voiceRecorder:tape: (in category 'initialization') -----
- caption: butnCaption voiceRecorder: butnRecorder tape: butnTape
- 	caption := butnCaption.
- 	voiceRecorder := butnRecorder.
- 	tape := butnTape!

Item was removed:
- ----- Method: EventRecorderMorph>>checkTape (in category 'fileIn/Out') -----
- checkTape
- 	"See if this tape was already converted to the new format"
- 
- 	tape ifNil: [^self].
- 	tape isEmpty ifTrue: [^self].
- 	(tape first isKindOf: Association) 
- 		ifTrue: [tape := self convertV0Tape: tape]!

Item was removed:
- ----- Method: EventRecorderMorph>>condense (in category 'commands') -----
- condense
- 	"Shorten the tape by deleting mouseMove events that can just as well be
- 	interpolated later at playback time."
- 
- 	"e1, e2, and e3 are three consecutive events on the tape.
- 	t1, t2, and t3 are the associated time steps for each of them."
- 
- 	
- 	tape := Array streamContents: 
- 					[:tStream | | e1 t1 t2 e2 t3 e3 | 
- 					e1 := e2 := e3 := nil.
- 					t1 := t2 := t3 := nil.
- 					1 to: tape size
- 						do: 
- 							[:i | 
- 							e1 := e2.
- 							t1 := t2.
- 							e2 := e3.
- 							t2 := t3.
- 							e3 := tape at: i.
- 							t3 := e3 timeStamp.
- 							((e1 notNil and: 
- 									[e2 type == #mouseMove 
- 										& (e1 type == #mouseMove or: [e3 type == #mouseMove])]) 
- 								and: 
- 									["Middle point within 3 pixels of mean of outer two"
- 
- 									e2 position 
- 										onLineFrom: e1 position
- 										to: e3 position
- 										within: 2.5]) 
- 									ifTrue: 
- 										["Delete middle mouse move event.  Absorb its time into e3"
- 
- 										e2 := e1.
- 										t2 := t1]
- 									ifFalse: [e1 ifNotNil: [tStream nextPut: (e1 copy setTimeStamp: t1)]]].
- 					e2 ifNotNil: [tStream nextPut: (e2 copy setTimeStamp: t2)].
- 					e3 ifNotNil: [tStream nextPut: (e3 copy setTimeStamp: t3)]]!

Item was removed:
- ----- Method: EventRecorderMorph>>convertV0Tape: (in category 'fileIn/Out') -----
- convertV0Tape: anArray
- 	"Convert the tape into the new format"
- 	| lastKey |
- 	lastKey := 0.
- 	^anArray collect:[:assn| | evt | 
- 		evt := assn value.
- 		evt setTimeStamp: (lastKey := lastKey + assn key).
- 		evt]!

Item was removed:
- ----- Method: EventRecorderMorph>>defaultBorderColor (in category 'initialization') -----
- defaultBorderColor
- 	^ Color transparent!

Item was removed:
- ----- Method: EventRecorderMorph>>defaultBorderStyle (in category 'initialization') -----
- defaultBorderStyle
- 	^ BorderStyle raised!

Item was removed:
- ----- Method: EventRecorderMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 2!

Item was removed:
- ----- Method: EventRecorderMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color red!

Item was removed:
- ----- Method: EventRecorderMorph>>encounteredAtTime:inScorePlayer:atIndex:inEventTrack:secsPerTick: (in category 'sound-piano rolls') -----
- encounteredAtTime: ticks inScorePlayer: scorePlayer atIndex: index inEventTrack: track secsPerTick: secsPerTick
- 
- 	self play.!

Item was removed:
- ----- Method: EventRecorderMorph>>handleListenEvent: (in category 'events-processing') -----
- handleListenEvent: anEvent
- 	"Record the given event"
- 	anEvent hand == recHand ifFalse: [^ self].	"not for me"
- 	state == #record ifFalse: [
- 		"If user got an error while recording and deleted recorder, will still be listening"
- 		recHand ifNotNil: [recHand removeEventListener: self].
- 		^self].
- 	anEvent = lastEvent ifTrue: [^ self].
- 	(anEvent isKeyboard and:[anEvent keyValue = 27 "esc"])
- 		ifTrue: [^ self stop].
- 	time := anEvent timeStamp.
- 	tapeStream nextPut: (anEvent copy setHand: nil).
- 	journalFile ifNotNil:
- 		[journalFile store: anEvent; cr; flush].
- 	lastEvent := anEvent.!

Item was removed:
- ----- Method: EventRecorderMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	saved := true.
- 	self listDirection: #topToBottom;
- 		 wrapCentering: #center;
- 		 cellPositioning: #topCenter;
- 		 hResizing: #shrinkWrap;
- 		 vResizing: #shrinkWrap;
- 		 layoutInset: 2;
- 		 minCellSize: 4;
- 		 addButtons!

Item was removed:
- ----- Method: EventRecorderMorph>>justDroppedIntoPianoRoll:event: (in category 'sound-piano rolls') -----
- justDroppedIntoPianoRoll: newOwner event: evt
- 	
- 	| startX lengthInTicks endX startTimeInScore endTimeInScore |
- 
- 	super justDroppedIntoPianoRoll: newOwner event: evt.
- 
- 	startTimeInScore := newOwner timeForX: self left.
- 	lengthInTicks := newOwner scorePlayer ticksForMSecs: self myDurationInMS.
- 	endTimeInScore := startTimeInScore + lengthInTicks.
- 
- 	endTimeInScore > newOwner scorePlayer durationInTicks ifTrue:
- 		[newOwner scorePlayer updateDuration].
- 
- 	startX := newOwner xForTime: startTimeInScore.
- 	endX := newOwner xForTime: endTimeInScore.
- 	self width: endX - startX.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>makeARowForButtons (in category 'initialization') -----
- makeARowForButtons
- 
- 	^AlignmentMorph newRow
- 		vResizing: #shrinkWrap;
- 		wrapCentering: #center;
- 		cellPositioning: #leftCenter;
- 		minCellSize: 4;
- 		color: Color blue!

Item was removed:
- ----- Method: EventRecorderMorph>>makeASpacer (in category 'initialization') -----
- makeASpacer
- 
- 	^AlignmentMorph newSpacer: Color transparent!

Item was removed:
- ----- Method: EventRecorderMorph>>makeStatusLight (in category 'initialization') -----
- makeStatusLight
- 
- 	^statusLight := EllipseMorph new 
- 		extent: 11 @ 11;
- 		color: Color green;
- 		borderWidth: 0!

Item was removed:
- ----- Method: EventRecorderMorph>>myDurationInMS (in category 'sound-piano rolls') -----
- myDurationInMS
- 
- 	^tape isEmptyOrNil ifTrue: [
- 		10
- 	] ifFalse: [
- 		tape last timeStamp - tape first timeStamp
- 	]
- !

Item was removed:
- ----- Method: EventRecorderMorph>>nextEventToPlay (in category 'event handling') -----
- nextEventToPlay
- 	"Return the next event when it is time to be replayed.
- 	If it is not yet time, then return an interpolated mouseMove.
- 	Return nil if nothing has happened.
- 	Return an EOF event if there are no more events to be played."
- 	| nextEvent now nextTime lastP delta |
- 	(tapeStream isNil or:[tapeStream atEnd]) 
- 		ifTrue:[^MorphicUnknownEvent new setType: #EOF argument: nil].
- 	now := Time millisecondClockValue.
- 	nextEvent := tapeStream next.
- 	"nextEvent isKeyboard ifTrue: [ nextEvent setPosition: self position ]."
- 	deltaTime ifNil:[deltaTime := now - nextEvent timeStamp].
- 	nextTime := nextEvent timeStamp + deltaTime.
- 	now < time ifTrue:["clock rollover"
- 		time := now.
- 		deltaTime := nil.
- 		^nil "continue it on next cycle"].
- 	time := now.
- 	(now >= nextTime) ifTrue:[
- 		nextEvent := nextEvent copy setTimeStamp: nextTime.
- 		nextEvent isMouse ifTrue:[lastEvent := nextEvent] ifFalse:[lastEvent := nil].
- 		^nextEvent].
- 	tapeStream skip: -1.
- 	"Not time for the next event yet, but interpolate the mouse.
- 	This allows tapes to be compressed when velocity is fairly constant."
- 	lastEvent ifNil: [^ nil].
- 	lastP := lastEvent position.
- 	delta := (nextEvent position - lastP) * (now - lastEvent timeStamp) // (nextTime - lastEvent timeStamp).
- 	delta = lastDelta ifTrue: [^ nil]. "No movement"
- 	lastDelta := delta.
- 	^MouseMoveEvent new
- 		setType: #mouseMove 
- 		startPoint: lastEvent position endPoint: lastP + delta
- 		trail: #() buttons: lastEvent buttons hand: nil stamp: now.!

Item was removed:
- ----- Method: EventRecorderMorph>>pauseIn: (in category 'pause/resume') -----
- pauseIn: aWorld
- 	"Suspend playing or recording, either as part of a stop command,
- 	or as part of a project switch, after which it will be resumed."
- 
- 	self setStatusLight: #ready.
- 	state = #play ifTrue:
- 		[state := #suspendedPlay.
- 		playHand halo ifNotNil: [playHand halo delete].
- 		playHand delete.
- 		aWorld removeHand: playHand.
- 		aWorld firstHand showHardwareCursor: true.
- 		playHand := nil].
- 	state = #record ifTrue:
- 		[state := #suspendedRecord.
- 		recHand removeEventListener: self.
- 		recHand := nil].
- 
- 	voiceRecorder ifNotNil:
- 		[voiceRecorder pause.
- 		startSoundEvent ifNotNil:
- 			[startSoundEvent argument: voiceRecorder recordedSound.
- 			voiceRecorder clearRecordedSound.
- 			startSoundEvent := nil]].
- !

Item was removed:
- ----- Method: EventRecorderMorph>>play (in category 'commands') -----
- play
- 
- 	self isInWorld ifFalse: [^ self].
- 	self stop.
- 	tape ifNil: [^ self].
- 	tapeStream := ReadStream on: tape.
- 	self resumePlayIn: self world.
- 	self setStatusLight: #nowPlaying.
- 
- !

Item was removed:
- ----- Method: EventRecorderMorph>>readFrom: (in category 'fileIn/Out') -----
- readFrom: aStream
- 	"Private"
- 	| header |
- 	header := aStream nextLine.
- 	(header = 'Event Tape v1 BINARY') ifTrue:[^aStream fileInObjectAndCode].
- 	(header = 'Event Tape v1 ASCII') ifTrue:[^self readFromV1: aStream].
- 	"V0 had no header so guess"
- 	aStream reset.
- 	header first isDigit ifFalse:[^self convertV0Tape: (aStream fileInObjectAndCode)].
- 	^self convertV0Tape: (self readFromV0: aStream).
- !

Item was removed:
- ----- Method: EventRecorderMorph>>readFromV0: (in category 'fileIn/Out') -----
- readFromV0: aStream
- 	^Array streamContents:[:tStream | | evt line t lineStream |
- 		[aStream atEnd] whileFalse:
- 			[line := aStream nextLine.
- 			line isEmpty "Some MW tapes have an empty record at the end"
- 				ifFalse: [lineStream := ReadStream on: line.
- 						t := Integer readFrom: lineStream.
- 						[lineStream peek isLetter] whileFalse: [lineStream next].
- 						evt := MorphicEvent readFromObsolete: lineStream.
- 						tStream nextPut: t -> evt]]].!

Item was removed:
- ----- Method: EventRecorderMorph>>readFromV1: (in category 'fileIn/Out') -----
- readFromV1: aStream
- 	^Array streamContents:[:tStream |
- 		[aStream atEnd] whileFalse:[
- 			tStream nextPut: (MorphicEvent readFromString: aStream nextLine)]]!

Item was removed:
- ----- Method: EventRecorderMorph>>readTape (in category 'fileIn/Out') -----
- readTape
- 	^ self readTape: (UIManager default
- 							request: 'Tape to read' translated
- 							initialAnswer: 'tapeName.tape').!

Item was removed:
- ----- Method: EventRecorderMorph>>readTape: (in category 'fileIn/Out') -----
- readTape: fileName 
- 	| file |
- 	self writeCheck.
- 	(FileStream isAFileNamed: fileName) ifFalse: [^ nil].
- 	file := FileStream oldFileNamed: fileName.
- 	tape := self readFrom: file.
- 	file close.
- 	saved := true  "Still exists on file"!

Item was removed:
- ----- Method: EventRecorderMorph>>record (in category 'commands') -----
- record
- 
- 	self isInWorld ifFalse: [^ self].
- 	self stop.
- 	self writeCheck.
- 	self addJournalFile.
- 	tapeStream := WriteStream on: (Array new: 10000).
- 	self resumeRecordIn: self world.
- 	self setStatusLight: #nowRecording.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>resumeIn: (in category 'pause/resume') -----
- resumeIn: aWorld
- 	"Resume playing or recording after a project switch."
- 
- 	self state = #suspendedPlay ifTrue:
- 		[self resumePlayIn: aWorld].
- 	self state = #suspendedRecord ifTrue:
- 		[self resumeRecordIn: aWorld].
- !

Item was removed:
- ----- Method: EventRecorderMorph>>resumePlayIn: (in category 'pause/resume') -----
- resumePlayIn: aWorld
- 
- 	playHand := HandMorphForReplay new recorder: self.
- 	playHand position: tapeStream peek position.
- 	aWorld addHand: playHand.
- 	playHand newKeyboardFocus: aWorld.
- 	playHand userInitials: 'play' andPicture: nil.
- 
- 	lastEvent := nil.
- 	lastDelta := 0 at 0.
- 	state := #play.
- 
- 	self synchronize.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>resumeRecordIn: (in category 'pause/resume') -----
- resumeRecordIn: aWorld
- 
- 	recHand := aWorld activeHand ifNil: [aWorld primaryHand].
- 	recHand newKeyboardFocus: aWorld.
- 	recHand addEventListener: self.
- 
- 	lastEvent := nil.
- 	state := #record.
- 
- 	voiceRecorder ifNotNil:
- 		[voiceRecorder clearRecordedSound.
- 		voiceRecorder resumeRecording.
- 		startSoundEvent := MorphicUnknownEvent new setType: #startSound argument: nil hand: nil stamp: Time millisecondClockValue.
- 		tapeStream nextPut: startSoundEvent].
- 
- 	self synchronize.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>setStatusLight: (in category 'commands') -----
- setStatusLight: aSymbol
- 
- 	aSymbol == #ready ifTrue: [
- 		statusLight color: Color green.
- 		tape ifNil: [
- 			statusLight setBalloonText: 'Ready to record'.
- 		] ifNotNil: [
- 			statusLight setBalloonText: 'Ready to record or play'.
- 		].
- 		^self
- 	].
- 	aSymbol == #nowRecording ifTrue: [
- 		statusLight 
- 			color: Color red;
- 			setBalloonText: 'Recording is active'.
- 		^self
- 	].
- 	aSymbol == #nowPlaying ifTrue: [
- 		statusLight 
- 			color: Color yellow;
- 			setBalloonText: 'Now playing'.
- 		^self
- 	].
- !

Item was removed:
- ----- Method: EventRecorderMorph>>shrink (in category 'commands') -----
- shrink
- 	"Shorten the tape by deleting mouseMove events that can just as well be
- 	interpolated later at playback time."
- 
- 	| oldSize priorSize |
- 	self writeCheck.
- 	oldSize := priorSize := tape size.
- 	[self condense.  tape size < priorSize] whileTrue: [priorSize := tape size].
- 	self inform: ('{1} events reduced to {2}' translated format:{oldSize. tape size}).
- 	voiceRecorder ifNotNil: [voiceRecorder suppressSilence].
- 	saved := false.
- !

Item was removed:
- ----- Method: EventRecorderMorph>>step (in category 'stepping and presenter') -----
- step
- 
- 	(state == #record and: [voiceRecorder notNil]) ifTrue: [
- 		recordMeter width: (voiceRecorder meterLevel + 1).
- 	].
- !

Item was removed:
- ----- Method: EventRecorderMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 
- 	^500
- !

Item was removed:
- ----- Method: EventRecorderMorph>>stop (in category 'stepping and presenter') -----
- stop
- 
- 	state = #record ifTrue:
- 		[tape := tapeStream contents.
- 		saved := false].
- 	journalFile ifNotNil:
- 		[journalFile close].
- 	self pauseIn: self world.
- 	tapeStream := nil.
- 	state := nil.
- 	self setStatusLight: #ready.
- 	recordMeter ifNotNil: [recordMeter width: 1].
- 
- 	self checkTape.!

Item was removed:
- ----- Method: EventRecorderMorph>>synchronize (in category 'event handling') -----
- synchronize
- 
- 	time := Time millisecondClockValue.
- 	deltaTime := nil.!

Item was removed:
- ----- Method: EventRecorderMorph>>wantsSteps (in category 'stepping and presenter') -----
- wantsSteps
- 
- 	^true
- !

Item was removed:
- ----- Method: EventRecorderMorph>>writeCheck (in category 'fileIn/Out') -----
- writeCheck
- 	(saved not and: [self confirm: 'The current tape has not been saved.
- Would you like to do so now?']) ifTrue:
- 		[self writeTape].
- !

Item was removed:
- ----- Method: EventRecorderMorph>>writeFileNamed: (in category 'fileIn/Out') -----
- writeFileNamed: fileName
- 	| file noVoice delta |
- 	file := FileStream newFileNamed: fileName.
- 	noVoice := true.
- 	tape do:[:evt | evt type = #startSound ifTrue: [noVoice := false]].
- 	noVoice
- 		ifTrue: ["Simple format (reads fast) for no voice"
- 				file nextPutAll:'Event Tape v1 ASCII'; cr.
- 				delta := tape first timeStamp.
- 				tape do: [:evt | file store: (evt copy setTimeStamp: evt timeStamp-delta); cr].
- 				file close]
- 		ifFalse: ["Inclusion of voice events requires general object storage"
- 				file nextPutAll:'Event Tape v1 BINARY'; cr.
- 				file fileOutClass: nil andObject: tape].
- 	saved := true.
- 	^ file name!

Item was removed:
- ----- Method: EventRecorderMorph>>writeTape (in category 'fileIn/Out') -----
- writeTape
- 	| args b fileName |
- 	args := (b := self button: 'writeTape') isNil
- 				ifTrue: [#()]
- 				ifFalse: [b arguments].
- 	(args notEmpty
- 			and: [args first notEmpty])
- 		ifTrue: [args first.
- 			self writeTape: args first]
- 		ifFalse: [fileName := UIManager default saveFilenameRequest: 'Tape to write' initialAnswer: 'tapeName.tape'.
- 			fileName ifNil: [^ self].
- 			^ self writeTape: fileName]!

Item was removed:
- ----- Method: EventRecorderMorph>>writeTape: (in category 'fileIn/Out') -----
- writeTape: fileName 
- 	| name bb |
- 	name := self writeFileNamed: fileName.
- 	bb := self findDeepSubmorphThat: [:mm | (mm isKindOf: SimpleButtonMorph)
- 				and: [mm label = 'writeTape']] 
- 			ifAbsent: [^ self].
- 	bb actionSelector: #writeTape:.
- 	bb arguments: (Array with: name).
- !

Item was removed:
- Model subclass: #FancyMailComposition
- 	instanceVariableNames: 'messageText theLinkToInclude to subject'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-EToy-Download'!

Item was removed:
- ----- Method: FancyMailComposition>>addAttachment (in category 'actions') -----
- addAttachment
- 
- 	self changed: #acceptChanges.
- 
- 	(FileChooserDialog openOn: FileDirectory default pattern: nil label: 'Choose attachment') ifNotNil: 
- 		[:fileName |
- 		FileStream readOnlyFileNamed: fileName do:
- 			[:file | 
- 			file binary.
- 			self messageText:
- 				((MailMessage from: self messageText asString)
- 					addAttachmentFrom: file withName: (FileDirectory localNameFor: fileName);  
- 				text)]]!

Item was removed:
- ----- Method: FancyMailComposition>>breakLines:atWidth: (in category 'private') -----
- breakLines: aString  atWidth: width
- 	"break lines in the given string into shorter lines"
- 	| result atAttachment |
- 
- 	result := WriteStream on: (String new: (aString size * 50 // 49)).
- 
- 	atAttachment := false.
- 	aString asString linesDo: [ :line | | start end | 
- 		(line beginsWith: '====') ifTrue: [ atAttachment := true ].
- 		atAttachment ifTrue: [
- 			"at or after an attachment line; no more wrapping for the rest of the message"
- 			result nextPutAll: line.  result cr ]
- 		ifFalse: [
- 			(line beginsWith: '>') ifTrue: [
- 				"it's quoted text; don't wrap it"
- 				result nextPutAll: line. result cr. ]
- 			ifFalse: [
- 				"regular old line.  Wrap it to multiple lines"
- 				start := 1.
- 					"output one shorter line each time through this loop"
- 				[ start + width <= line size ] whileTrue: [
- 	
- 					"find the end of the line"
- 					end := start + width - 1.
- 					[end >= start and: [ (line at: (end+1)) isSeparator not ]] whileTrue: [
- 						end := end - 1 ].
- 					end < start ifTrue: [
- 						"a word spans the entire width!!"
- 						end := start + width - 1 ].
- 
- 					"copy the line to the output"
- 					result nextPutAll: (line copyFrom: start to: end).
- 					result cr.
- 
- 					"get ready for next iteration"
- 					start := end+1.
- 					(line at: start) isSeparator ifTrue: [ start := start + 1 ].
- 				].
- 
- 				"write out the final part of the line"
- 				result nextPutAll: (line copyFrom: start to: line size).
- 				result cr.
- 			].
- 		].
- 	].
- 
- 	^result contents!

Item was removed:
- ----- Method: FancyMailComposition>>buildButtonsWith: (in category 'toolbuilder') -----
- buildButtonsWith: builder
- 
- 	| panel |
- 	panel := builder pluggablePanelSpec new.
- 	panel
- 		layout: #horizontal;
- 		children: OrderedCollection new.
- 	
- 	panel children addLast: (builder pluggableButtonSpec new
- 		model: self;
- 		label: 'send later';
- 		help: 'add this to the queue of messages to be sent';
- 		action: #submit;
- 		color: Color white;
- 		yourself).
- 		
- 	panel children addLast: (builder pluggableButtonSpec new
- 		model: self;
- 		label: 'send now';
- 		help: 'send this message immediately';
- 		action: #sendNow;
- 		color: Color white;
- 		yourself).
- 
- 	panel children addLast: (builder pluggableButtonSpec new
- 		model: self;
- 		label: 'add attachment';
- 		help: 'send a file with the message';
- 		action: #addAttachment;
- 		color: Color white;
- 		yourself).
- 
- 	^ panel!

Item was removed:
- ----- Method: FancyMailComposition>>buildMessageTextWith: (in category 'toolbuilder') -----
- buildMessageTextWith: builder
- 
- 	^ builder pluggableTextSpec new
- 		model: self;
- 		getText: #messageText;
- 		setText: #messageText:;
- 		menu: #menuGet:shifted:;
- 		yourself!

Item was removed:
- ----- Method: FancyMailComposition>>buildTextFieldsWith: (in category 'toolbuilder') -----
- buildTextFieldsWith: builder
- 
- 	| panel |
- 	panel := builder pluggablePanelSpec new.
- 	panel
- 		layout: #vertical;
- 		children: OrderedCollection new.
- 	
- 	panel children addLast: (builder pluggableInputFieldSpec new
- 		model: self;
- 		help: 'To';
- 		getText: #to;
- 		setText: #to:;
- 		yourself).
- 
- 	panel children addLast: (builder pluggableInputFieldSpec new
- 		model: self;
- 		help: 'Subject';
- 		getText: #subject;
- 		setText: #subject:;
- 		yourself).
- 
- 	^ panel!

Item was removed:
- ----- Method: FancyMailComposition>>buildWith: (in category 'toolbuilder') -----
- buildWith: builder
- 
- 	^ builder build: (self buildWindowWith: builder specs: {
- 		(0 @ 0 corner: 1 @ 0.1) -> [self buildButtonsWith: builder].
- 		(0 @ 0.1 corner: 1 @ 0.3) -> [self buildTextFieldsWith: builder].
- 		(0 @ 0.3 corner: 1 @ 1) -> [self buildMessageTextWith: builder]. })!

Item was removed:
- ----- Method: FancyMailComposition>>celeste:to:subject:initialText:theLinkToInclude: (in category 'initialization') -----
- celeste: aCeleste to: argTo subject: argSubject initialText: aText theLinkToInclude: linkText 
-  "self new celeste: Celeste current to: 'danielv at netvision.net.il' subject: 'Mysubj' initialText: 'atext' theLinkToInclude: 'linkText'"
- 
- 	to := argTo.
- 	subject := argSubject.
- 	messageText := aText.
- 	theLinkToInclude := linkText.!

Item was removed:
- ----- Method: FancyMailComposition>>completeTheMessage (in category 'actions') -----
- completeTheMessage
- 
- 	| newText strm |
- 	self changed: #acceptChanges.
- 
- 	newText := String new: 200.
- 	strm := WriteStream on: newText.
- 	strm 
- 		nextPutAll: 'Content-Type: text/html'; cr;
- 		nextPutAll: 'From: ', MailSender userName; cr;
- 		nextPutAll: 'To: ',to; cr;
- 		nextPutAll: 'Subject: ',subject; cr;
- 
- 		cr;
- 		nextPutAll: '<HTML><BODY><BR>';
- 		nextPutAll: messageText asStringToHtml;
- 		nextPutAll: '<BR><BR>',theLinkToInclude,'<BR></BODY></HTML>'.
- 	^strm contents!

Item was removed:
- ----- Method: FancyMailComposition>>defaultWindowColor (in category 'user interface') -----
- defaultWindowColor
- 
- 	^ Color veryLightGray!

Item was removed:
- ----- Method: FancyMailComposition>>forgetIt (in category 'user interface') -----
- forgetIt
- 
- 	self changed: #close.!

Item was removed:
- ----- Method: FancyMailComposition>>menuGet:shifted: (in category 'interface') -----
- menuGet: aMenu shifted: shifted
- 	
- 	aMenu addList: {
- 		{'find...(f)' translated.		#find}.
- 		{'find selection again (g)' translated.		#findAgain}.
- 			#-.
- 		{'accept (s)' translated. #accept}.
- 		{'send message' translated.  #submit}}.
- 
- 	^aMenu.!

Item was removed:
- ----- Method: FancyMailComposition>>messageText (in category 'accessing') -----
- messageText
- 	"return the current text"
- 	^messageText.
- !

Item was removed:
- ----- Method: FancyMailComposition>>messageText: (in category 'accessing') -----
- messageText: aText
- 	"change the current text"
- 	messageText := aText.
- 	self changed: #messageText.
- 	^true!

Item was removed:
- ----- Method: FancyMailComposition>>open (in category 'user interface') -----
- open
- 	
- 	self flag: #refactor. "FancyMailComposition should probably be removed in favour of MailComposition."
- 	^ ToolBuilder open: self!

Item was removed:
- ----- Method: FancyMailComposition>>sendMailMessage: (in category 'MailSender interface') -----
- sendMailMessage: aMailMessage
- 	self messageText: aMailMessage text!

Item was removed:
- ----- Method: FancyMailComposition>>sendNow (in category 'actions') -----
- sendNow
- 
- 	self submit: true
- !

Item was removed:
- ----- Method: FancyMailComposition>>smtpServer (in category 'MailSender interface') -----
- smtpServer
- 	^MailSender smtpServer!

Item was removed:
- ----- Method: FancyMailComposition>>subject (in category 'accessing') -----
- subject
- 
- 	^ subject
- 
- 	!

Item was removed:
- ----- Method: FancyMailComposition>>subject: (in category 'accessing') -----
- subject: x
- 
- 	subject := x.
- 	self changed: #subject.
- 	^true!

Item was removed:
- ----- Method: FancyMailComposition>>submit (in category 'actions') -----
- submit
- 
- 	self submit: false!

Item was removed:
- ----- Method: FancyMailComposition>>submit: (in category 'actions') -----
- submit: sendNow
- 
- 	| message |
- 
- 	messageText := self breakLines: self completeTheMessage atWidth: 999.
- 	message := MailMessage from: messageText.
- 	SMTPClient
- 			deliverMailFrom: message from 
- 			to: (Array with: message to) 
- 			text: message text 
- 			usingServer: self smtpServer.
- 	self forgetIt.
- !

Item was removed:
- ----- Method: FancyMailComposition>>to (in category 'accessing') -----
- to
- 
- 	^to!

Item was removed:
- ----- Method: FancyMailComposition>>to: (in category 'accessing') -----
- to: x
- 
- 	to := x.	
- 	self changed: #to.
- 	^true
- 	!

Item was removed:
- ----- Method: FancyMailComposition>>windowTitle (in category 'user interface') -----
- windowTitle
- 
- 	^ 'Mister Postman'!

Item was removed:
- SketchMorph subclass: #FatBitsPaint
- 	instanceVariableNames: 'formToEdit magnification brush brushSize brushColor lastMouse currentTools currentSelectionMorph selectionAnchor backgroundColor'
- 	classVariableNames: 'FormClipboard'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalWidgets'!
- 
- !FatBitsPaint commentStamp: '<historical>' prior: 0!
- Extensions to FatBitsPaint
- 
- With the goal of making FatBitsPaint a fairly nifty Form fixer-upper in the Squeak/morphic environment, I have started this set of extensions. It will probably be updated as the mood strikes, so keep an eye out for new versions.
- 
- First, some basic operating instructions:
- 
- Get a Form and send it the message #morphEdit. To get started, you can try:
- 
-         (Form fromUser) morphEdit
- 
- And there is the form in all its glory. Control click on the form to get theFatBitsPaint menu and choose the "keep this menu up" item. This will be your main tool/command palette. With it you can:
- ¥ Change the magnification
- ¥ Change the brush size (in original scale pixels)
- ¥ Change the brush color (via a ColorPickerMorph)
- 
- Now to some of the enhancements:
- 
- (25 September 1999 2:38:25 pm )
- 
- ¥ ColorPickerMorphs now have a label below that indicates their use (you might have more than one open)
- ¥ A quirk that could get the brush size out of alignment with the pixel size is fixed.
- ¥ A background has been added so that you can see the full extent of the Form and so that you can observe the effect of translucent pixels in the form.
- ¥ A menu item has been added to change the background color so that you can simulate the real environment the form will be displayed in.
- ¥ The magnification and brush size menus now highlight their current value.
- ¥ An inspect option has been added to the menu so that you can do arbitrary things to the form.
- ¥ A file out option has been added to write the form to a file.
- 
- (25 September 1999 10:02:13 pm ) 
- 
- ¥ New menu item: Tools allows you to choose between (for now) Paint Brush (all there was before) and Selections. Selections allows you to select rectangular regions of the form where the next menu takes over.
- ¥ New menu item: Selections gives you choices:
-         ¥ edit separately - opens a new editor on the selected rectangle. Useful for cropping.
-         ¥ copy - copies the selection rectangle to a clipboard. Can be pasted to this or another FatBitsPaint.
-         ¥ cut - does a copy and clears the selection to transparent.
-         ¥ paste - paints the contents of the clipboard over the current selection. Only the starting point of the selection matters - the extent is controlled by the clipboard.
- 
- !

Item was removed:
- ----- Method: FatBitsPaint>>accept (in category 'menu') -----
- accept
- 	| f |
- 	f := self unmagnifiedForm.
- 	f boundingBox = formToEdit boundingBox
- 		ifFalse: [^ self error: 'implementation error; form dimensions should match'].
- 	f displayOn: formToEdit.  "modify formToEdit in place"!

Item was removed:
- ----- Method: FatBitsPaint>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	^ aCustomMenu add: 'fat bits paint ..' translated action: #openFatBitsPaintMenu!

Item was removed:
- ----- Method: FatBitsPaint>>backgroundColor: (in category 'menu') -----
- backgroundColor: aColor
- 
-         backgroundColor := aColor.
-         self changed!

Item was removed:
- ----- Method: FatBitsPaint>>brushColor: (in category 'menu') -----
- brushColor: aColor
- 
- 	brushColor := aColor.
- 	brush color: aColor.
- !

Item was removed:
- ----- Method: FatBitsPaint>>containsPoint: (in category 'geometry testing') -----
- containsPoint: aPoint
- 
-         ^ self bounds containsPoint: aPoint     "even if we are transparent"
- !

Item was removed:
- ----- Method: FatBitsPaint>>copySelection (in category 'menu') -----
- copySelection
- 
-         | relativeBounds scaledBounds |
-         currentSelectionMorph ifNil: [^ nil].
-         relativeBounds := currentSelectionMorph bounds translateBy: self position negated.
-         scaledBounds := relativeBounds scaleBy: 1 / magnification.
-         FormClipboard := (self unmagnifiedForm copy: scaledBounds).
-         ^ relativeBounds!

Item was removed:
- ----- Method: FatBitsPaint>>cutSelection (in category 'menu') -----
- cutSelection
- 
-         | relativeBounds |
-         relativeBounds := self copySelection ifNil: [^ nil].
-         originalForm fill: relativeBounds rule: Form over fillColor: Color transparent.
-         self revealPenStrokes!

Item was removed:
- ----- Method: FatBitsPaint>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color veryVeryLightGray!

Item was removed:
- ----- Method: FatBitsPaint>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	| f |
- 	f := self rotatedForm.
- 	backgroundColor ifNotNil: [aCanvas fillRectangle: bounds fillStyle: backgroundColor].
- 	aCanvas translucentImage: f at: bounds origin.!

Item was removed:
- ----- Method: FatBitsPaint>>editForm: (in category 'initialization') -----
- editForm: aForm
- 
-         formToEdit := aForm.
-         brushSize := magnification := 64 // (aForm height min: aForm width) max: 4.
-         self revert!

Item was removed:
- ----- Method: FatBitsPaint>>editSelection (in category 'menu') -----
- editSelection
- 
-        FatBitsPaint new openWith: (self selectionAsForm ifNil: [^ nil])!

Item was removed:
- ----- Method: FatBitsPaint>>fileOut (in category 'menu') -----
- fileOut
- 
-         | fileName |
- 
- 	fileName := FileSaverDialog openOn: FileDirectory default.
- 	fileName ifNil: [^Beeper beep].
- 	
-  	Cursor normal showWhile:  [self unmagnifiedForm writeOnFileNamed: fileName]!

Item was removed:
- ----- Method: FatBitsPaint>>fill (in category 'menu') -----
- fill
- 
- 	| fillPt |
- 	Cursor blank show.
- 	fillPt := Cursor crossHair showWhile:
- 		[Sensor waitButton - self position].
- 	originalForm shapeFill: brushColor interiorPoint: fillPt.
- 	self changed.
- !

Item was removed:
- ----- Method: FatBitsPaint>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	^ true
- !

Item was removed:
- ----- Method: FatBitsPaint>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self setCurrentToolTo: self toolsForPaintBrush.
- 	formToEdit := Form extent: 50 @ 40 depth: 8.
- 	formToEdit fill: formToEdit boundingBox fillColor: Color veryVeryLightGray.
- 	brushSize := magnification := 4.
- 	
- 	brushColor := Color red.
- 	backgroundColor := Color white.
- 	self revert!

Item was removed:
- ----- Method: FatBitsPaint>>inspectForm (in category 'menu') -----
- inspectForm
- 
-         self unmagnifiedForm inspect!

Item was removed:
- ----- Method: FatBitsPaint>>magnification: (in category 'menu') -----
- magnification: aNumber
- 
-         | oldPenSize oldForm |
-         oldPenSize := brushSize / magnification.
-         oldForm := self unmagnifiedForm.
-         magnification := aNumber asInteger max: 1.
-         self form: (oldForm magnify: oldForm boundingBox by: magnification).
-         brush := Pen newOnForm: originalForm.
-         self penSize: oldPenSize.
-         brush color: brushColor!

Item was removed:
- ----- Method: FatBitsPaint>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 
-         ^ self
-                 perform: (currentTools at: #mouseDown: ifAbsent: [^nil])
-                 with: evt!

Item was removed:
- ----- Method: FatBitsPaint>>mouseDownDefault: (in category 'events') -----
- mouseDownDefault: evt
- 	lastMouse := nil.
- 	formToEdit depth = 1 ifTrue:
- 		[self brushColor: (originalForm colorAt: (self pointGriddedFromEvent: evt)) negated]!

Item was removed:
- ----- Method: FatBitsPaint>>mouseDownSelection: (in category 'events') -----
- mouseDownSelection: evt
- 
-         lastMouse := nil.
-         currentSelectionMorph ifNotNil: [currentSelectionMorph delete. currentSelectionMorph := nil].
-         selectionAnchor := self pointGriddedFromEvent: evt!

Item was removed:
- ----- Method: FatBitsPaint>>mouseMove: (in category 'event handling') -----
- mouseMove: evt
- 
-         ^ self
-                 perform: (currentTools at: #mouseMove: ifAbsent: [^nil])
-                 with: evt!

Item was removed:
- ----- Method: FatBitsPaint>>mouseMovePaintBrushMode: (in category 'events') -----
- mouseMovePaintBrushMode: evt
- 
-         | p p2 |
-         p := self pointGriddedFromEvent: evt.
-         lastMouse = p ifTrue: [^ self].
-         lastMouse ifNil: [lastMouse := p].  "first point in a stroke"
-         "draw etch-a-sketch style-first horizontal, then vertical"
-         p2 := p x at lastMouse y.
-         brush drawFrom: lastMouse to: p2.
-         brush drawFrom: p2 to: p.
-                         
-         self revealPenStrokes.
-         lastMouse := p!

Item was removed:
- ----- Method: FatBitsPaint>>mouseMoveSelectionMode: (in category 'menu') -----
- mouseMoveSelectionMode: evt
- 
-         | p |
-         p := self pointGriddedFromEvent: evt.
-         lastMouse = p ifTrue: [^ self].
- 
-         currentSelectionMorph ifNil:
-                 [currentSelectionMorph := MarqueeMorph new 
-                         color: Color transparent;
-                         borderWidth: 2;
-                         lock.
-                 self addMorphFront: currentSelectionMorph.
-                 currentSelectionMorph startStepping].
-         currentSelectionMorph 
-                 bounds: ((Rectangle encompassing: {p. selectionAnchor}) translateBy: self position).
- 
-         lastMouse := p!

Item was removed:
- ----- Method: FatBitsPaint>>openFatBitsPaintMenu (in category 'menu') -----
- openFatBitsPaintMenu
- 	| menu |
- 	(menu := MenuMorph entitled: 'FatBitsPaint' translated) defaultTarget: self;
- 		 addStayUpItem;
- 		 commandKeyHandler: self.
- 	menu add: 'background color' translated action: #setBackgroundColor:;
- 		 add: 'pen color' translated action: #setPenColor:;
- 		 add: 'pen size' translated action: #setPenSize:;
- 		 add: 'fill' translated action: #fill;
- 		 add: 'magnification' translated action: #setMagnification:;
- 		 add: 'accept' translated action: #accept;
- 		 add: 'revert' translated action: #revert;
- 		 add: 'inspect' translated action: #inspectForm;
- 		 add: 'file out' translated action: #fileOut;
- 		 add: 'selection...' translated action: #selectionMenu:;
- 		 add: 'tools...' translated action: #toolMenu:.
- 	^ menu popUpInWorld!

Item was removed:
- ----- Method: FatBitsPaint>>openWith: (in category 'initialization') -----
- openWith: aForm
- 
-         self editForm: aForm; openInWorld!

Item was removed:
- ----- Method: FatBitsPaint>>pasteSelection (in category 'menu') -----
- pasteSelection
- 
-         | relativeBounds tempForm |
-         currentSelectionMorph ifNil: [^ nil].
-         FormClipboard ifNil: [^nil].
-         relativeBounds := currentSelectionMorph bounds translateBy: self position negated.
-         tempForm := (FormClipboard magnify: FormClipboard boundingBox by: magnification).
-         self form
-                 copy: (relativeBounds origin extent: tempForm boundingBox extent)
-                 from: 0 at 0
-                 in: tempForm
-                 rule: Form over. 
-         self revealPenStrokes!

Item was removed:
- ----- Method: FatBitsPaint>>penSize: (in category 'menu') -----
- penSize: aNumber
- 
- 	brushSize := (aNumber * magnification) asInteger.
- 	brush squareNib: brushSize.
- !

Item was removed:
- ----- Method: FatBitsPaint>>pointGriddedFromEvent: (in category 'events') -----
- pointGriddedFromEvent: evt
- 
- 	| relativePt |
- 	relativePt := evt cursorPoint - self position.
- 	^ (relativePt x truncateTo: magnification)@(relativePt y truncateTo: magnification)
- !

Item was removed:
- ----- Method: FatBitsPaint>>revert (in category 'menu') -----
- revert
- "since WarpBits may mangle an 8-bit ColorForm, make it 32 first"
-         self form: ((formToEdit asFormOfDepth: 32) 
-                 magnify: formToEdit boundingBox 
-                 by: magnification 
-                 smoothing: 1).
-         brush := Pen newOnForm: originalForm.
-         brush squareNib: brushSize.
-         brush color: brushColor!

Item was removed:
- ----- Method: FatBitsPaint>>selectionAsForm (in category 'menu') -----
- selectionAsForm
- 
-         | relativeBounds scaledBounds |
-         currentSelectionMorph ifNil: [^nil].
-         relativeBounds := currentSelectionMorph bounds translateBy: self position negated.
-         scaledBounds := relativeBounds scaleBy: 1 / magnification.
-         ^ self unmagnifiedForm copy: scaledBounds!

Item was removed:
- ----- Method: FatBitsPaint>>selectionMenu: (in category 'menu') -----
- selectionMenu: evt
- 
-         | menu |
-  
-         (menu := MenuMorph new)
-                 addTitle: 'Edit';
-                 addStayUpItem.
- 
-         {
-                 {'edit separately'. #editSelection}.
-                 {'copy'. #copySelection}.
-                 {'cut'. #cutSelection}.
-                 {'paste'. #pasteSelection}
-         } do: [:each |
-                 menu add: each first
-                         target: self
-                         selector: each second
-                         argumentList: #()].
-         menu toggleStayUp: evt.
-         menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: FatBitsPaint>>setBackgroundColor: (in category 'menu') -----
- setBackgroundColor: evt
- 
- 	self
- 		changeColorTarget: self 
- 		selector: #backgroundColor: 
- 		originalColor: backgroundColor
- 		hand: evt hand!

Item was removed:
- ----- Method: FatBitsPaint>>setCurrentToolTo: (in category 'initialization') -----
- setCurrentToolTo: aDictionary
- 
-         currentTools := aDictionary.
-         currentSelectionMorph ifNotNil: [currentSelectionMorph delete. currentSelectionMorph := nil]!

Item was removed:
- ----- Method: FatBitsPaint>>setMagnification: (in category 'menu') -----
- setMagnification: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	((1 to: 8), #(16 24 32)) do: [:w |
- 		menu add: w printString
- 			target: self
- 			selector: #magnification:
- 			argumentList: (Array with: w).
- 		magnification = w ifTrue: [menu lastSubmorph color: Color red]].
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: FatBitsPaint>>setPenColor: (in category 'menu') -----
- setPenColor: evt
- 
- 	self changeColorTarget: self selector: #brushColor: originalColor: brushColor hand: evt hand.!

Item was removed:
- ----- Method: FatBitsPaint>>setPenSize: (in category 'menu') -----
- setPenSize: evt
- 	| menu sizes |
-  
- 	menu := MenuMorph new.
- 	sizes := (1 to: 5), (6 to: 12 by: 2), (15 to: 40 by: 5).
- 	sizes do: [:w |
- 		menu add: w printString
- 			target: self
- 			selector: #penSize:
- 			argumentList: (Array with: w).
- 		(brushSize // magnification) = w ifTrue: [menu lastSubmorph color: Color red]].
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: FatBitsPaint>>toolMenu: (in category 'events') -----
- toolMenu: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	menu
- 		addTitle: 'Tools';
- 		addStayUpItem.
- 	{
- 		{'paint brush'. self toolsForPaintBrush}.
- 		{'selections'. self toolsForSelection}
- 	} do: [:each |
- 		menu add: each first
- 			target: self
- 			selector: #setCurrentToolTo:
- 			argumentList: {each second}].
- 	menu toggleStayUp: evt.
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: FatBitsPaint>>toolsForPaintBrush (in category 'initialization') -----
- toolsForPaintBrush
- 
-         ^Dictionary new
-                 at: #mouseMove: put: #mouseMovePaintBrushMode:;
-                 at: #mouseDown: put: #mouseDownDefault:;
-                 yourself!

Item was removed:
- ----- Method: FatBitsPaint>>toolsForSelection (in category 'initialization') -----
- toolsForSelection
- 
-         ^ Dictionary new
-                 at: #mouseMove: put: #mouseMoveSelectionMode:;
-                 at: #mouseDown: put: #mouseDownSelection:;
-                 yourself!

Item was removed:
- ----- Method: FatBitsPaint>>unmagnifiedForm (in category 'menu') -----
- unmagnifiedForm
- 
-         ^ self form shrink: self form boundingBox by: magnification!

Item was removed:
- ----- Method: FileDirectory>>url (in category '*MorphicExtras-file name utilities') -----
- url
- 	"Convert my path into a file:// type url String."
- 	
- 	^self asUrl asString.!

Item was removed:
- ----- Method: FileStream>>url (in category '*MorphicExtras-file accessing') -----
- url
- 	"Convert my path into a file:// type url String."
- 	
- 	^self asUrl asString!

Item was removed:
- ReferenceMorph subclass: #FlapTab
- 	instanceVariableNames: 'flapShowing edgeToAdhereTo slidesOtherObjects popOutOnDragOver popOutOnMouseOver inboard dragged lastReferentThickness edgeFraction labelString'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Flaps'!
- 
- !FlapTab commentStamp: '<historical>' prior: 0!
- The tab associated with a flap.
- 
- nb: slidesOtherObjects and inboard are instance variables relating to disused features.  The feature implementations still exist in the system, but the UI to them has been sealed off.!

Item was removed:
- ----- Method: FlapTab class>>defaultNameStemForInstances (in category 'printing') -----
- defaultNameStemForInstances
- 	^ 'flap tab' translatedNoop!

Item was removed:
- ----- Method: FlapTab class>>givenID:matches: (in category 'testing') -----
- givenID: aFlapID matches: pureID
- 	"eg, FlapTab givenID: 'Stack Tools2' matches: 'Stack Tools' "
- 
- 	^ aFlapID = pureID or:
- 		[(aFlapID beginsWith: pureID)
- 			and: [(aFlapID copyFrom: pureID size+1 to: aFlapID size)
- 					allSatisfy: [:c | c isDigit]]]!

Item was removed:
- ----- Method: FlapTab class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 	"Not to be instantiated from the menu"
- 	^ false!

Item was removed:
- ----- Method: FlapTab>>acquirePlausibleFlapID (in category 'access') -----
- acquirePlausibleFlapID
- 	"Give the receiver a flapID that is globally unique; try to hit the mark vis a vis the standard system flap id's, for the case when this method is invoked as part of the one-time transition"
- 
- 	| wording |
- 	wording := self wording.
- 	(wording isEmpty or: [wording = '---']) ifTrue: [wording := 'Flap' translated].
- 	
- 	^ self provideDefaultFlapIDBasedOn: wording!

Item was removed:
- ----- Method: FlapTab>>adaptToWorld (in category 'initialization') -----
- adaptToWorld
- 	| wasShowing new |
- 	(wasShowing := self flapShowing) ifTrue:
- 					[self hideFlap].
- 	(self respondsTo: #unhibernate) ifTrue: [
- 		(new := self unhibernate) == self ifFalse: [
- 			^ new adaptToWorld]].
- 	wasShowing ifTrue:
- 		[self spanWorld.
- 		self positionObject: self.
- 		self showFlap]!

Item was removed:
- ----- Method: FlapTab>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aMenu hand: aHandMorph
- 	"Add further items to the menu as appropriate"
- 
- 	aMenu add: 'tab color...' translated target: self action: #changeColor.
- 	aMenu add: 'flap color...' translated target: self action: #changeFlapColor.
- 	aMenu addLine.
- 	aMenu addUpdating: #edgeString action: #setEdgeToAdhereTo.
- 	aMenu addLine.
- 	aMenu addUpdating: #textualTabString action: #textualTab.
- 	aMenu addUpdating: #graphicalTabString action: #graphicalTab.
- 	aMenu addUpdating: #solidTabString enablement: #notSolid action: #solidTab.
- 	aMenu addLine.
- 
- 	(referent isKindOf: PasteUpMorph) ifTrue: 
- 		[aMenu addUpdating: #partsBinString action: #togglePartsBinMode].
- 	aMenu addUpdating: #dragoverString action: #toggleDragOverBehavior.
- 	aMenu addUpdating: #mouseoverString action: #toggleMouseOverBehavior.
- 	aMenu addLine.
- 	aMenu addUpdating: #isGlobalFlapString enablement: #sharedFlapsAllowed action: #toggleIsGlobalFlap.
- 	aMenu balloonTextForLastItem: 'If checked, this flap will be available in all morphic projects; if not, it will be private to this project.' translated.
- 
- 	aMenu addLine.
- 	aMenu addUpdating: #compactFlapString target: self action: #changeCompactFlap.
- 	aMenu add: 'destroy this flap' translated action: #destroyFlap.
- 
- 	"aMenu addUpdating: #slideString action: #toggleSlideBehavior.
- 	aMenu addUpdating: #inboardString action: #toggleInboardness.
- 	aMenu addUpdating: #thicknessString ('thickness... (current: ', self thickness printString, ')') action: #setThickness."
- 
- !

Item was removed:
- ----- Method: FlapTab>>addGestureMenuItems:hand: (in category 'menus') -----
- addGestureMenuItems: aMenu hand: aHandMorph
- 	"If the receiver wishes the Genie menu items, add a line to the menu and then those Genie items, else do nothing"!

Item was removed:
- ----- Method: FlapTab>>addTitleForHaloMenu: (in category 'menus') -----
- addTitleForHaloMenu: aMenu
- 	aMenu addTitle: self externalName updatingSelector: #flapMenuTitle updateTarget: self!

Item was removed:
- ----- Method: FlapTab>>adjustPositionAfterHidingFlap (in category 'show & hide') -----
- adjustPositionAfterHidingFlap
- 	self positionObject: self!

Item was removed:
- ----- Method: FlapTab>>adjustPositionVisAVisFlap (in category 'positioning') -----
- adjustPositionVisAVisFlap
- 	| sideToAlignTo opposite |
- 	opposite := Utilities oppositeSideTo: edgeToAdhereTo.
- 	sideToAlignTo := inboard
- 		ifTrue:	[opposite]
- 		ifFalse:	[edgeToAdhereTo].
- 	self perform: sideToAlignTo asSimpleSetter with: (referent perform: opposite)!

Item was removed:
- ----- Method: FlapTab>>applyEdgeFractionWithin: (in category 'edge') -----
- applyEdgeFractionWithin: aBoundsRectangle
- 	"Make the receiver reflect remembered edgeFraction"
- 
- 	| newPosition |
- 	edgeFraction ifNil: [^ self].
- 	self isCurrentlySolid ifTrue: [^ self].
- 	newPosition := self
- 		ifVertical:
- 			[self left @  (self edgeFraction * (aBoundsRectangle height - self height))]
- 		ifHorizontal:
- 			[(self edgeFraction * (aBoundsRectangle width - self width) @ self top)].
- 
- 	self position: (aBoundsRectangle origin + newPosition)
- 	!

Item was removed:
- ----- Method: FlapTab>>applyTabThickness: (in category 'solid tabs') -----
- applyTabThickness: newThickness
- 	(self orientation == #vertical)
- 			ifTrue:
- 				[submorphs first width: newThickness asNumber]
- 			ifFalse:
- 				[submorphs first height: newThickness asNumber].
- 	self fitContents.
- 	self positionReferent. 
- 	self adjustPositionVisAVisFlap!

Item was removed:
- ----- Method: FlapTab>>applyThickness: (in category 'menu') -----
- applyThickness: newThickness
- 	| toUse |
- 	toUse := newThickness asNumber max: 0.
- 	(self orientation == #vertical)
- 			ifTrue:
- 				[referent width: toUse]
- 			ifFalse:
- 				[referent height: toUse].
- 	self positionReferent. 
- 	self adjustPositionVisAVisFlap!

Item was removed:
- ----- Method: FlapTab>>arrangeToPopOutOnDragOver: (in category 'mouseover & dragover') -----
- arrangeToPopOutOnDragOver: aBoolean
- 	aBoolean
- 		ifTrue:
- 			[self on: #mouseEnterDragging send: #showFlapIfHandLaden: to: self.
- 			referent on: #mouseLeaveDragging send: #maybeHideFlapOnMouseLeaveDragging to: self.
- 			self on: #mouseLeaveDragging send: #maybeHideFlapOnMouseLeaveDragging to: self]
- 		ifFalse:
- 			[self on: #mouseEnterDragging send: nil to: nil.
- 			referent on: #mouseLeaveDragging send: nil to: nil.
- 			self on: #mouseLeaveDragging send: nil to: nil]!

Item was removed:
- ----- Method: FlapTab>>arrangeToPopOutOnMouseOver: (in category 'mouseover & dragover') -----
- arrangeToPopOutOnMouseOver: aBoolean
- 	aBoolean
- 		ifTrue:
- 			[self on: #mouseEnter send: #showFlap to: self.
- 			referent on: #mouseLeave send: #hideFlapUnlessBearingHalo to: self.
- 			self on: #mouseLeave send: #maybeHideFlapOnMouseLeave to: self]
- 		ifFalse:
- 			[self on: #mouseEnter send: nil to: nil.
- 			self on: #mouseLeave send: nil to: nil.
- 			referent on: #mouseLeave send: nil to: nil]!

Item was removed:
- ----- Method: FlapTab>>assumeString:font:orientation:color: (in category 'textual tabs') -----
- assumeString: aString font: aFont orientation: orientationSymbol color: aColor 
- 	| aTextMorph workString tabStyle |
- 	labelString := aString asString.
- 	workString := orientationSymbol == #vertical 
- 				ifTrue: 
- 					[String streamContents: 
- 							[:s | 
- 							labelString do: [:c | s nextPut: c] separatedBy: [s nextPut: Character cr]]]
- 				ifFalse: [labelString]. 
- 	tabStyle := TextStyle new
- 				newFontArray: (Array with: aFont).
- 	aTextMorph := (TextMorph new setTextStyle: tabStyle) 
- 				contents: (workString asText addAttribute: (TextKern kern: 3)).
- 	aTextMorph wrapFlag: true.
- 	self removeAllMorphs.
- 	self borderStyle: (BorderStyle raised width: 2).
- 	aColor ifNotNil: [self color: aColor. aTextMorph color: aColor makeForegroundColor].
- 	self addMorph: aTextMorph centered.
- 	aTextMorph lock
- 	"
- FlapTab allSubInstancesDo: [:ft | ft reformatTextualTab]
- "!

Item was removed:
- ----- Method: FlapTab>>balloonTextForFlapsMenu (in category 'miscellaneous') -----
- balloonTextForFlapsMenu
- 	"Answer the balloon text to show on a menu item in the flaps menu that governs the visibility of the receiver in the current project"
- 
- 	| id |
- 	id := self flapID.
- 	#(
- 	('Squeak'		'Has a few generally-useful controls; it is also a place where you can "park" objects' translatedNoop)
- 	('Tools'			'A quick way to get browsers, change sorters, file lists, etc.' translatedNoop)
- 	('Widgets'		'A variety of controls and media tools' translatedNoop)
- 	('Supplies' 		'Supplies' translatedNoop)
- 	('Help'			'A flap providing documentation, tutorials, and other help' translatedNoop)
- 	('Stack Tools' 	'Tools for building stacks.  Caution!!  Powerful but young and underdocumented' translatedNoop)
- 	('Scripting'		'Tools useful when doing tile scripting' translatedNoop)
- 	('Navigator'		'Project navigator:  includes controls for navigating through linked projects.  Also supports finding, loading and publishing projects in a shared environment' translatedNoop)
- 	('Painting'		'A flap housing the paint palette.  Click on the closed tab to make make a new painting' translatedNoop)) do:
- 		[:pair | (FlapTab givenID: id matches: pair first translated) ifTrue: [^ pair second translated]].
- 
- 	^ self balloonText!

Item was removed:
- ----- Method: FlapTab>>changeColor (in category 'menu') -----
- changeColor
- 	self isCurrentlyGraphical
- 		ifTrue:
- 			[^ self inform: 'Color only pertains to a flap tab when the 
- tab is textual or "solid".  This tab is
- currently graphical, so color-choice
- does not apply.' translated].
- 	super changeColor
- 	
- !

Item was removed:
- ----- Method: FlapTab>>changeFlapColor (in category 'menu') -----
- changeFlapColor
- 	(self flapShowing)
- 		ifTrue:
- 			[referent changeColor]
- 		ifFalse:
- 			[self inform: 'The flap itself needs to be open
- before you can change its
- color.' translated]!

Item was removed:
- ----- Method: FlapTab>>changeTabSolidity (in category 'solid tabs') -----
- changeTabSolidity
- 	"Presently no actual options associated with this menu item if the flap is currently alreadly solid, so entertain the user with an anuran sound.  However, in latest scheme, the corresponding menu item is disabled in this circumstance, so this method is effectively unreachable."
- 
- 	self playSoundNamed: 'croak'!

Item was removed:
- ----- Method: FlapTab>>changeTabText (in category 'menu') -----
- changeTabText
- 	"Allow the user to change the text on the tab"
- 
- 	| reply |
- 	reply := UIManager default
- 		request: 'new wording for this tab:' translated
- 		initialAnswer: self existingWording.
- 	reply isEmptyOrNil ifTrue: [^ self].
- 	self changeTabText: reply.
- !

Item was removed:
- ----- Method: FlapTab>>changeTabText: (in category 'textual tabs') -----
- changeTabText: aString 
- 
- 	| label |
- 	aString isEmptyOrNil ifTrue: [^ self].
- 	label := Locale current languageEnvironment class flapTabTextFor: aString in: self.
- 	label isEmptyOrNil ifTrue: [^ self].
- 	self useStringTab: label.
- 	submorphs first delete.
- 	self assumeString: label
- 		font: Preferences standardFlapFont
- 		orientation: (Flaps orientationForEdge: self edgeToAdhereTo)
- 		color: nil.
- !

Item was removed:
- ----- Method: FlapTab>>changeTabThickness (in category 'solid tabs') -----
- changeTabThickness
- 	| newThickness |
- 	newThickness := UIManager default request: 'New thickness:'
- 				initialAnswer: self tabThickness printString.
- 	newThickness notEmpty ifTrue: [self applyTabThickness: newThickness]!

Item was removed:
- ----- Method: FlapTab>>computeEdgeFraction (in category 'edge') -----
- computeEdgeFraction
- 	"Compute and remember the edge fraction"
- 
- 	| aBox aFraction |
- 	self isCurrentlySolid ifTrue: [^ edgeFraction ifNil: [self edgeFraction: 0.5]].
- 
- 	aBox := ((self pasteUpMorph ifNil: [self currentWorld]) bounds) insetBy: (self extent // 2).
- 	aFraction := self
- 		ifVertical: 
- 			[(self center y - aBox top) / (aBox height max: 1)]
- 		ifHorizontal:
- 			[(self center x - aBox left) / (aBox width max: 1)].
- 	^ self edgeFraction: aFraction!

Item was removed:
- ----- Method: FlapTab>>destroyFlap (in category 'menu') -----
- destroyFlap
- 	"Destroy the receiver"
- 
- 	| reply request |
- 	request := self isGlobalFlap
- 		ifTrue:
- 			['Caution -- this would permanently
- remove this flap, so it would no longer be
- available in this or any other project.
- Do you really want to this? ' translated]
- 		ifFalse:
- 			['Caution -- this is permanent!!  Do
- you really want to do this? ' translated].
- 	reply := self confirm: request translated orCancel: [^ self].
- 	reply ifTrue:
- 		[self isGlobalFlap
- 			ifTrue:
- 				[Flaps removeFlapTab: self keepInList: false.
- 				self currentWorld reformulateUpdatingMenus]
- 			ifFalse:
- 				[referent isInWorld ifTrue: [referent delete].
- 				self delete]]!

Item was removed:
- ----- Method: FlapTab>>dismissViaHalo (in category 'submorphs - add/remove') -----
- dismissViaHalo
- 	"Dismiss the receiver (and its referent), unless it resists"
- 
- 	self resistsRemoval ifTrue:
- 		[(Project uiManager
- 			chooseOptionFrom: #( 'Yes' 'Um, no, let me reconsider') 
- 			title: 'Really throw this flap away?') = 2 ifFalse: [^ self]].
- 	referent delete.
- 	self delete!

Item was removed:
- ----- Method: FlapTab>>dragoverString (in category 'mouseover & dragover') -----
- dragoverString
- 	"Answer the string to be shown in a menu to represent the 
- 	dragover status"
- 	^ (popOutOnDragOver
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>']), 'pop out on dragover' translated!

Item was removed:
- ----- Method: FlapTab>>edgeFraction (in category 'edge') -----
- edgeFraction
- 	^ edgeFraction ifNil: [self computeEdgeFraction]!

Item was removed:
- ----- Method: FlapTab>>edgeFraction: (in category 'edge') -----
- edgeFraction: aNumber
- 	"Set my edgeFraction to the given number, without side effects"
- 
- 	edgeFraction := aNumber asFloat!

Item was removed:
- ----- Method: FlapTab>>edgeString (in category 'edge') -----
- edgeString
- 	^ 'cling to edge... (current: {1})' translated format: {edgeToAdhereTo translated}!

Item was removed:
- ----- Method: FlapTab>>edgeToAdhereTo (in category 'edge') -----
- edgeToAdhereTo
- 	^ edgeToAdhereTo!

Item was removed:
- ----- Method: FlapTab>>edgeToAdhereTo: (in category 'edge') -----
- edgeToAdhereTo: e
- 	edgeToAdhereTo := e asSymbol!

Item was removed:
- ----- Method: FlapTab>>existingWording (in category 'menu') -----
- existingWording
- 	^ labelString!

Item was removed:
- ----- Method: FlapTab>>fitContents (in category 'layout') -----
- fitContents
- 	self isCurrentlyTextual ifFalse: [^ super fitContents].
- 	self ifVertical:
- 		[self extent: submorphs first extent + (2 * self borderWidth) + (0 @ 4).
- 		submorphs first position: self position + self borderWidth + (1 @ 4)]
- 	ifHorizontal:
- 		[self extent: submorphs first extent + (2 * self borderWidth) + (8 @ -1).
- 		submorphs first position: self position + self borderWidth + (5 @ 1)]!

Item was removed:
- ----- Method: FlapTab>>fitOnScreen (in category 'positioning') -----
- fitOnScreen
- 	"19 sept 2000 - allow flaps in any paste up"
- 	| constrainer t l |
- 	constrainer := (owner ifNil: [self]) clearArea.
- 	self flapShowing "otherwise no point in doing this"
- 		ifTrue:[self spanWorld].
- 	self orientation == #vertical ifTrue: [
- 		t := ((self top min: (constrainer bottom- self height)) max: constrainer top).
- 		t = self top ifFalse: [self top: t].
- 	] ifFalse: [
- 		l := ((self left min: (constrainer right - self width)) max: constrainer left).
- 		l = self left ifFalse: [self left: l].
- 	].
- 	self flapShowing ifFalse: [self positionObject: self atEdgeOf: constrainer].
- !

Item was removed:
- ----- Method: FlapTab>>flapID (in category 'access') -----
- flapID
- 	"Answer the receiver's flapID, creating it if necessary"
- 
- 	^ self knownName ifNil: [self acquirePlausibleFlapID]!

Item was removed:
- ----- Method: FlapTab>>flapID: (in category 'access') -----
- flapID: anID
- 	"Set the receiver's flapID"
- 
- 	self setNameTo: anID!

Item was removed:
- ----- Method: FlapTab>>flapIDOrNil (in category 'access') -----
- flapIDOrNil
- 	"If the receiver has a flapID, answer it, else answer nil"
- 
- 	^ self knownName!

Item was removed:
- ----- Method: FlapTab>>flapMenuTitle (in category 'menu') -----
- flapMenuTitle
- 	^ 'flap: ' translated , self wording!

Item was removed:
- ----- Method: FlapTab>>flapShowing (in category 'access') -----
- flapShowing
- 	^ flapShowing == true!

Item was removed:
- ----- Method: FlapTab>>graphicalTab (in category 'graphical tabs') -----
- graphicalTab
- 	self isCurrentlyGraphical
- 		ifTrue:
- 			[self changeTabGraphic]
- 		ifFalse:
- 			[self useGraphicalTab]!

Item was removed:
- ----- Method: FlapTab>>graphicalTabString (in category 'graphical tabs') -----
- graphicalTabString
- 	^ (self isCurrentlyGraphical
- 		ifTrue: ['choose new graphic...' translated]
- 		ifFalse: ['use graphical tab' translated]) !

Item was removed:
- ----- Method: FlapTab>>hideFlap (in category 'show & hide') -----
- hideFlap
- 	| aWorld |
- 	aWorld := self world ifNil: [self currentWorld].
- 	referent privateDelete.
- 	aWorld removeAccommodationForFlap: self.
- 	flapShowing := false.
- 	self isInWorld ifFalse: [aWorld addMorphFront: self].
- 	self adjustPositionAfterHidingFlap.
- 	aWorld haloMorphs do:
- 		[:m | m target isInWorld ifFalse: [m delete]]!

Item was removed:
- ----- Method: FlapTab>>hideFlapUnlessBearingHalo (in category 'show & hide') -----
- hideFlapUnlessBearingHalo
- 	self hasHalo ifFalse: [self hideFlapUnlessOverReferent]!

Item was removed:
- ----- Method: FlapTab>>hideFlapUnlessOverReferent (in category 'show & hide') -----
- hideFlapUnlessOverReferent
- 	"Hide the flap unless the mouse is over my referent."
- 
- 	| aWorld where |
- 	(referent isInWorld and: 
- 		[where := self outermostWorldMorph activeHand lastEvent cursorPoint.
- 			referent bounds containsPoint: (referent globalPointToLocal: where)])
- 				ifTrue: [^ self].
- 	(aWorld := self world) ifNil: [^ self].  "In case flap tabs just got hidden"
- 	self referent delete.
- 	aWorld removeAccommodationForFlap: self.
- 	flapShowing := false.
- 	self isInWorld ifFalse:
- 		[self inboard ifTrue: [aWorld addMorphFront: self]].
- 	self adjustPositionAfterHidingFlap!

Item was removed:
- ----- Method: FlapTab>>ifVertical:ifHorizontal: (in category 'edge') -----
- ifVertical: block1 ifHorizontal: block2
- 	"Evaluate and return the value of either the first or the second block, depending whether I am vertically or horizontally oriented"
- 
- 	^ self orientation == #vertical
- 		ifTrue:
- 			[block1 value]
- 		ifFalse:
- 			[block2 value]
- 	!

Item was removed:
- ----- Method: FlapTab>>inboard (in category 'disused options') -----
- inboard
- 	^ inboard == true!

Item was removed:
- ----- Method: FlapTab>>inboard: (in category 'disused options') -----
- inboard: aBoolean
- 	inboard := aBoolean!

Item was removed:
- ----- Method: FlapTab>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- 	self disableLayout: true.
- ""
- 	edgeToAdhereTo := #left.
- 	flapShowing := false.
- 	slidesOtherObjects := false.
- 	popOutOnDragOver := false.
- 	popOutOnMouseOver := false.
- 	inboard := false.
- 	dragged := false!

Item was removed:
- ----- Method: FlapTab>>isCurrentlySolid (in category 'solid tabs') -----
- isCurrentlySolid
- 	"Don't never use double negatives"
- 
- 	^ self notSolid not!

Item was removed:
- ----- Method: FlapTab>>isCurrentlyTextual (in category 'menu') -----
- isCurrentlyTextual
- 	| first |
- 	^submorphs notEmpty and: 
- 			[((first := submorphs first) isKindOf: StringMorph) 
- 				or: [first isTextMorph]]!

Item was removed:
- ----- Method: FlapTab>>isFlapTab (in category 'classification') -----
- isFlapTab
- 	^true!

Item was removed:
- ----- Method: FlapTab>>isGlobalFlap (in category 'globalness') -----
- isGlobalFlap
- 	"Answer whether the receiver is currently a shared flap"
- 
- 	^ Flaps globalFlapTabsIfAny includes: self!

Item was removed:
- ----- Method: FlapTab>>isGlobalFlapString (in category 'globalness') -----
- isGlobalFlapString
- 	"Answer a string to construct a menu item representing control 
- 	over whether the receiver is or is not a shared flap"
- 	^ (self isGlobalFlap
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>'])
- 		, 'shared by all projects' translated!

Item was removed:
- ----- Method: FlapTab>>labelString (in category 'accessing') -----
- labelString
- 	^labelString!

Item was removed:
- ----- Method: FlapTab>>lastReferentThickness: (in category 'show & hide') -----
- lastReferentThickness: anInteger
- 	"Set the last remembered referent thickness to the given integer"
- 
- 	lastReferentThickness := anInteger!

Item was removed:
- ----- Method: FlapTab>>layoutChanged (in category 'layout') -----
- layoutChanged
- 	self fitOnScreen.
- 	^super layoutChanged!

Item was removed:
- ----- Method: FlapTab>>makeNewDrawing: (in category 'mouseover & dragover') -----
- makeNewDrawing: evt
- 	self flapShowing ifTrue:[
- 		self world makeNewDrawing: evt.
- 	] ifFalse:[
- 		self world assureNotPaintingEvent: evt.
- 	].!

Item was removed:
- ----- Method: FlapTab>>maybeHideFlapOnMouseLeave (in category 'show & hide') -----
- maybeHideFlapOnMouseLeave
- 	self hasHalo ifTrue: [^ self].
- 	referent isInWorld ifFalse: [^ self].
- 	self hideFlapUnlessOverReferent.
- !

Item was removed:
- ----- Method: FlapTab>>maybeHideFlapOnMouseLeaveDragging (in category 'show & hide') -----
- maybeHideFlapOnMouseLeaveDragging
- 	| aWorld |
- 	self hasHalo ifTrue: [^ self].
- 	referent isInWorld ifFalse: [^ self].
- 	(dragged or: [referent bounds containsPoint: self cursorPoint])
- 		ifTrue:	[^ self].
- 	aWorld := self world.
- 	referent privateDelete.  "could make me worldless if I'm inboard"
- 	aWorld ifNotNil: [aWorld removeAccommodationForFlap: self].
- 	flapShowing := false.
- 	self isInWorld ifFalse: [aWorld addMorphFront: self].
- 	self adjustPositionAfterHidingFlap!

Item was removed:
- ----- Method: FlapTab>>morphicLayerNumber (in category 'submorphs - layers') -----
- morphicLayerNumber
- 
- 	^ self valueOfProperty: #morphicLayerNumber ifAbsent: [self class navigatorLayer]!

Item was removed:
- ----- Method: FlapTab>>mouseMove: (in category 'event handling') -----
- mouseMove: evt
- 	"Handle a mouse-move event.   The event, a MorphicEvent, is passed in."
- 
- 	| aPosition newReferentThickness adjustedPosition thick |
- 
- 	dragged ifFalse: [(thick := self referentThickness) > 0
- 			ifTrue: [lastReferentThickness := thick]].
- 	((self containsPoint: (aPosition := evt cursorPoint)) and: [dragged not])
- 		ifFalse:
- 			[flapShowing ifFalse: [self showFlap].
- 			adjustedPosition := aPosition - evt hand targetOffset.
- 			(edgeToAdhereTo == #bottom)
- 				ifTrue:
- 					[newReferentThickness := inboard
- 						ifTrue:
- 							[self world height - adjustedPosition y]
- 						ifFalse:
- 							[self world height - adjustedPosition y - self height]].
- 
- 			(edgeToAdhereTo == #left)
- 					ifTrue:
- 						[newReferentThickness :=
- 							inboard
- 								ifTrue:
- 									[adjustedPosition x + self width]
- 								ifFalse:
- 									[adjustedPosition x]].
- 
- 			(edgeToAdhereTo == #right)
- 					ifTrue:
- 						[newReferentThickness :=
- 							inboard
- 								ifTrue:
- 									[self world width - adjustedPosition x]
- 								ifFalse:
- 									[self world width - adjustedPosition x - self width]].
- 
- 			(edgeToAdhereTo == #top)
- 					ifTrue:
- 						[newReferentThickness :=
- 							inboard
- 								ifTrue:
- 									[adjustedPosition y + self height]
- 								ifFalse:
- 									[adjustedPosition y]].
- 		
- 			self isCurrentlySolid ifFalse:
- 				[(#(left right) includes: edgeToAdhereTo)
- 					ifFalse:
- 						[self left: adjustedPosition x]
- 					ifTrue:
- 						[self top: adjustedPosition y]].
- 
- 			((edgeToAdhereTo == #left) and: [(self  valueOfProperty: #rigidThickness) notNil]) ifTrue:
- 				[newReferentThickness := referent width].
- 
- 			self applyThickness: newReferentThickness.
- 			dragged := true.
- 			self fitOnScreen.
- 			self computeEdgeFraction]!

Item was removed:
- ----- Method: FlapTab>>mouseUp: (in category 'event handling') -----
- mouseUp: evt
- 	"The mouse came back up, presumably after having dragged the tab.  Caution: if not operating full-screen, this notification can easily be *missed*, which is why the edge-fraction-computation is also being done on mouseMove."
- 
- 	super mouseUp: evt.
- 	(self referentThickness <= 0 or:
- 		[(referent isInWorld and: [(referent boundsInWorld intersects: referent owner boundsInWorld) not])]) ifTrue:
- 			[self hideFlap.
- 			flapShowing := false].
- 	self fitOnScreen.
- 	dragged ifTrue:
- 		[self computeEdgeFraction.
- 		dragged := false].
- 	Flaps doAutomaticLayoutOfFlapsIfAppropriate!

Item was removed:
- ----- Method: FlapTab>>mouseoverString (in category 'mouseover & dragover') -----
- mouseoverString
- 	"Answer the string to be shown in a menu to represent the  
- 	mouseover status"
- 	^ (popOutOnMouseOver
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>'])
- 		, 'pop out on mouseover' translated !

Item was removed:
- ----- Method: FlapTab>>notSolid (in category 'solid tabs') -----
- notSolid
- 	"Answer whether the receiver is currenty not solid.  Used for determining whether the #solidTab menu item should be enabled"
- 
- 	^ self isCurrentlyTextual or: [self isCurrentlyGraphical]!

Item was removed:
- ----- Method: FlapTab>>objectForDataStream: (in category 'objects from disk') -----
- objectForDataStream: refStrm
- 	"I am about to be written on an object file.  If I am a global flap, write a proxy instead."
- 
- 	| dp |
- 	self isGlobalFlap ifTrue:
- 		[dp := DiskProxy global: #Flaps selector: #globalFlapTabOrDummy: 
- 					args: {self flapID}.
- 		refStrm replace: self with: dp.
- 		^ dp].
- 
- 	^ super objectForDataStream: refStrm!

Item was removed:
- ----- Method: FlapTab>>openFully (in category 'show & hide') -----
- openFully
- 	"Make an educated guess at how wide or tall we are to be, and open to that thickness"
- 
- 	| thickness amt |
- 	thickness := referent boundingBoxOfSubmorphs extent max: (100 @ 100).
- 	self applyThickness: (amt := self orientation == #horizontal
- 			ifTrue:
- 				[thickness y]
- 			ifFalse:
- 				[thickness x]).
- 	self lastReferentThickness: amt.
- 	self showFlap!

Item was removed:
- ----- Method: FlapTab>>orientation (in category 'access') -----
- orientation
- 	^ (#left == edgeToAdhereTo or: [#right == edgeToAdhereTo])
- 		ifTrue:		[#vertical]
- 		ifFalse:		[#horizontal]!

Item was removed:
- ----- Method: FlapTab>>ownerChanged (in category 'change reporting') -----
- ownerChanged
- 	self fitOnScreen.
- 	^super ownerChanged.!

Item was removed:
- ----- Method: FlapTab>>partsBinString (in category 'parts bin') -----
- partsBinString
- 	"Answer the string to be shown in a menu to represent the 
- 	parts-bin status"
- 	^ (referent isPartsBin
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>']), 'parts-bin' translated!

Item was removed:
- ----- Method: FlapTab>>permitsThumbnailing (in category 'thumbnail') -----
- permitsThumbnailing
- 	^ false!

Item was removed:
- ----- Method: FlapTab>>positionObject: (in category 'positioning') -----
- positionObject: anObject
-         "anObject could be myself or my referent"
- 
- 	| pum clearArea |
- 	pum := self pasteUpMorph ifNil: [^ self].
- 
- 	clearArea := Morph newBounds: pum clearArea.
- 	^self 
- 		positionObject: anObject 
- 		atEdgeOf: clearArea!

Item was removed:
- ----- Method: FlapTab>>positionObject:atEdgeOf: (in category 'positioning') -----
- positionObject: anObject atEdgeOf: container
-         "anObject could be myself or my referent"
- 
-         edgeToAdhereTo == #left ifTrue: [^ anObject left: container left].
-         edgeToAdhereTo == #right ifTrue: [^ anObject right: container right].
-         edgeToAdhereTo == #top ifTrue: [^ anObject top: container top].
-         edgeToAdhereTo == #bottom ifTrue: [^ anObject bottom: container bottom]!

Item was removed:
- ----- Method: FlapTab>>positionReferent (in category 'positioning') -----
- positionReferent
- 	self positionObject: referent!

Item was removed:
- ----- Method: FlapTab>>preserveDetails (in category 'menu') -----
- preserveDetails
- 	"The receiver is being switched to use a different format.  Preserve the existing details (e.g. wording if textual, grapheme if graphical) so that if the user reverts back to the current format, the details will be right"
- 
- 	| thickness |
- 	color = Color transparent ifFalse: [self setProperty: #priorColor toValue: color].
- 	self isCurrentlyTextual
- 		ifTrue:
- 			[self setProperty: #priorWording toValue: self existingWording]
- 		ifFalse:
- 			[self isCurrentlyGraphical
- 				ifTrue:
- 					[self setProperty: #priorGraphic toValue: submorphs first form]
- 				ifFalse:
- 					[thickness := (self orientation == #vertical)
- 						ifTrue:	[self width]
- 						ifFalse:	[self height].
- 					self setProperty: #priorThickness toValue: thickness]]!

Item was removed:
- ----- Method: FlapTab>>printOn: (in category 'printing') -----
- printOn: aStream
- 	"Append a textual representation of the receiver to aStream"
- 
- 	super printOn: aStream.
- 	aStream nextPutAll: ' "', self wording, '"'!

Item was removed:
- ----- Method: FlapTab>>provideDefaultFlapIDBasedOn: (in category 'initialization') -----
- provideDefaultFlapIDBasedOn: aStem
- 	"Provide the receiver with a default flap id"
- 
- 	| aNumber usedIDs anID  |
- 	aNumber := 0.
- 	usedIDs := FlapTab allSubInstances select: [:f | f ~~ self] thenCollect: [:f | f flapIDOrNil].
- 	anID := aStem.
- 	[usedIDs includes: anID] whileTrue:
- 		[aNumber := aNumber + 1.
- 		anID := aStem, (aNumber asString)].
- 	self flapID: anID.
- 	^ anID!

Item was removed:
- ----- Method: FlapTab>>referentThickness (in category 'access') -----
- referentThickness
- 	referent ifNil: [^ 32].
- 	^ (self orientation == #horizontal)
- 		ifTrue:
- 			[referent height]
- 		ifFalse:
- 			[referent width]!

Item was removed:
- ----- Method: FlapTab>>reformatTextualTab (in category 'textual tabs') -----
- reformatTextualTab
- 	"The font choice possibly having changed, reformulate the receiver"
- 
- 	self isCurrentlyTextual ifFalse: [^ self].
- 	self assumeString: self existingWording font: Preferences standardFlapFont orientation: self orientation color: self color!

Item was removed:
- ----- Method: FlapTab>>roundedCorners (in category 'rounding') -----
- roundedCorners
- 	edgeToAdhereTo == #bottom ifTrue: [^ #(1 4)].
- 	edgeToAdhereTo == #right ifTrue: [^ #(1 2)].
- 	edgeToAdhereTo == #left ifTrue: [^ #(3 4)].
- 	^ #(2 3)  "#top and undefined"
- !

Item was removed:
- ----- Method: FlapTab>>setEdge: (in category 'edge') -----
- setEdge: anEdge
- 	"Set the edge as indicated, if possible"
- 
- 	| newOrientation e |
- 	e := anEdge asSymbol.
- 	self edgeToAdhereTo = anEdge ifTrue: [^ self].
- 	newOrientation := nil.
- 	self orientation == #vertical
- 		ifTrue: [(#top == e or: [#bottom == e]) ifTrue:
- 					[newOrientation := #horizontal]]
- 		ifFalse: [(#top == e or: [#bottom == e]) ifFalse:
- 					[newOrientation := #vertical]].
- 	self edgeToAdhereTo: e.
- 	newOrientation ifNotNil: [self transposeParts].
- 	referent isInWorld ifTrue: [self positionReferent].
- 	self adjustPositionVisAVisFlap!

Item was removed:
- ----- Method: FlapTab>>setEdgeToAdhereTo (in category 'edge') -----
- setEdgeToAdhereTo
- 	| aMenu |
- 	aMenu := MenuMorph new defaultTarget: self.
- 	#(left top right bottom) do:
- 		[:sym | aMenu add: sym asString translated target: self selector:  #setEdge: argument: sym].
- 	aMenu popUpEvent: self currentEvent in: self world!

Item was removed:
- ----- Method: FlapTab>>setName:edge:color: (in category 'initialization') -----
- setName: nameString edge: edgeSymbol color: flapColor
- 	"Set me up with the usual..."
- 
- 	self setNameTo: nameString.
- 	self edgeToAdhereTo: edgeSymbol; inboard: false.
- 	self assumeString: nameString font: Preferences standardFlapFont
- 		orientation: self orientation color: flapColor.
- 	self setToPopOutOnDragOver: true.
- 	self setToPopOutOnMouseOver: false.
- !

Item was removed:
- ----- Method: FlapTab>>setToPopOutOnDragOver: (in category 'mouseover & dragover') -----
- setToPopOutOnDragOver: aBoolean
- 	self arrangeToPopOutOnDragOver:  (popOutOnDragOver := aBoolean)!

Item was removed:
- ----- Method: FlapTab>>setToPopOutOnMouseOver: (in category 'mouseover & dragover') -----
- setToPopOutOnMouseOver: aBoolean
- 	self arrangeToPopOutOnMouseOver:  (popOutOnMouseOver := aBoolean)!

Item was removed:
- ----- Method: FlapTab>>sharedFlapsAllowed (in category 'menu') -----
- sharedFlapsAllowed
- 	"Answer (for the benefit of a menu item for which I am the target) whether the system presently allows shared flaps"
- 
- 	^ Flaps sharedFlapsAllowed!

Item was removed:
- ----- Method: FlapTab>>showFlap (in category 'show & hide') -----
- showFlap
- 	"Open the flap up"
- 
- 	| thicknessToUse flapOwner |
- 
- 	"19 sept 2000 - going for all paste ups <- raa note"
- 	flapOwner := self pasteUpMorph.
- 	self referentThickness <= 0
- 		ifTrue:
- 			[thicknessToUse := lastReferentThickness ifNil: [100].
- 			self orientation == #horizontal
- 				ifTrue:
- 					[referent height: thicknessToUse]
- 				ifFalse:
- 					[referent width: thicknessToUse]].
- 	inboard ifTrue:
- 		[self stickOntoReferent].  "makes referent my owner, and positions me accordingly"
- 	referent pasteUpMorph == flapOwner
- 		ifFalse:
- 			[flapOwner accommodateFlap: self.  "Make room if needed"
- 			flapOwner addMorphFront: referent.
- 			flapOwner startSteppingSubmorphsOf: referent.
- 			self positionReferent.
- 			referent adaptToWorld: flapOwner].
- 	inboard  ifFalse:
- 		[self adjustPositionVisAVisFlap].
- 	flapShowing := true.
- 	
- 	self pasteUpMorph hideFlapsOtherThan: self ifClingingTo: edgeToAdhereTo.
- 
- 	flapOwner bringTopmostsToFront!

Item was removed:
- ----- Method: FlapTab>>showFlapIfHandLaden: (in category 'show & hide') -----
- showFlapIfHandLaden: evt
- 	"The hand has drifted over the receiver with the button down.  If the hand is carrying anything, show the flap.  If the hand is empty, the likely cause is that it's manipulating a scrollbar or some such, so in that case don't pop the flap out."
- 
- 	evt hand hasSubmorphs ifTrue: [self showFlap]!

Item was removed:
- ----- Method: FlapTab>>slidesOtherObjects (in category 'disused options') -----
- slidesOtherObjects
- 	^ slidesOtherObjects!

Item was removed:
- ----- Method: FlapTab>>solidTab (in category 'solid tabs') -----
- solidTab
- 	self isCurrentlySolid
- 		ifFalse:
- 			[self useSolidTab]
- 		ifTrue:
- 			[self changeTabSolidity]!

Item was removed:
- ----- Method: FlapTab>>solidTabString (in category 'solid tabs') -----
- solidTabString
- 	^ (self isCurrentlySolid
- 		ifTrue: ['currently using solid tab' translated]
- 		ifFalse: ['use solid tab' translated]) !

Item was removed:
- ----- Method: FlapTab>>spanWorld (in category 'positioning') -----
- spanWorld
- 	| container area |
- 	
- 	container := self pasteUpMorph
- 				ifNil: [self currentWorld].
- 
- 	area := container clearArea.
- 
- 	self orientation == #vertical ifTrue: [
- 		referent vResizing == #rigid
- 			ifTrue: [referent height: area height].
- 		referent hResizing == #rigid
- 			ifTrue: [referent width: (referent width min: area width - self width)].
- 		referent top: area top.
- 		referent bottom: (area bottom min: referent bottom)
- 	]
- 	ifFalse: [
- 		referent hResizing == #rigid
- 			ifTrue: [referent width: area width].
- 		referent vResizing == #rigid
- 			ifTrue: [referent height: (referent height min: area height - self height)].
- 		referent left: area left.
- 		referent right: (area right min: referent right)
- 	].
- !

Item was removed:
- ----- Method: FlapTab>>startOrFinishDrawing: (in category 'mouseover & dragover') -----
- startOrFinishDrawing: evt
- 	| w |
- 	self flapShowing ifTrue:[
- 		(w := self world) makeNewDrawing: evt at:  w center.
- 	] ifFalse:[
- 		self world endDrawing: evt.
- 	].!

Item was removed:
- ----- Method: FlapTab>>stickOntoReferent (in category 'positioning') -----
- stickOntoReferent
- 	"Place the receiver directly onto the referent -- for use when the referent is being shown as a flap"
- 	| newPosition |
- 	referent addMorph: self.
- 	edgeToAdhereTo == #left
- 		ifTrue:
- 			[newPosition := (referent width - self width) @ self top].
- 	edgeToAdhereTo == #right
- 		ifTrue:
- 			[newPosition := (referent left @ self top)].
- 	edgeToAdhereTo == #top
- 		ifTrue:
- 			[newPosition := self left @ (referent height - self height)].
- 	edgeToAdhereTo == #bottom
- 		ifTrue:
- 			[newPosition := self left @ referent top].
- 	self position: newPosition!

Item was removed:
- ----- Method: FlapTab>>tabSelected (in category 'events') -----
- tabSelected
- 	"The user clicked on the tab.  Show or hide the flap.  Try to be a little smart about a click on a tab whose flap is open but only just barely."
- 
- 	dragged == true ifTrue:
- 		[^ dragged := false].
- 	self flapShowing
- 		ifTrue:
- 			[self referentThickness < 23  "an attractive number"
- 				ifTrue:
- 					[self openFully]
- 				ifFalse:
- 					[self hideFlap]]
- 		ifFalse:
- 			[self showFlap]!

Item was removed:
- ----- Method: FlapTab>>tabThickness (in category 'access') -----
- tabThickness
- 	^ (self orientation == #vertical)
- 		ifTrue:
- 			[self width]
- 		ifFalse:
- 			[self height]!

Item was removed:
- ----- Method: FlapTab>>textualTab (in category 'textual tabs') -----
- textualTab
- 	self isCurrentlyTextual
- 		ifTrue:
- 			[self changeTabText]
- 		ifFalse:
- 			[self useTextualTab]!

Item was removed:
- ----- Method: FlapTab>>textualTabString (in category 'textual tabs') -----
- textualTabString
- 	^ (self isCurrentlyTextual
- 		ifTrue: ['change tab wording...' translated]
- 		ifFalse: ['use textual tab' translated]) !

Item was removed:
- ----- Method: FlapTab>>thicknessString (in category 'menu') -----
- thicknessString
- 	^ 'thickness... (currently ', self thickness printString, ')'!

Item was removed:
- ----- Method: FlapTab>>toggleDragOverBehavior (in category 'mouseover & dragover') -----
- toggleDragOverBehavior
- 	self arrangeToPopOutOnDragOver:  (popOutOnDragOver := popOutOnDragOver not)!

Item was removed:
- ----- Method: FlapTab>>toggleIsGlobalFlap (in category 'globalness') -----
- toggleIsGlobalFlap
- 	"Toggle whether the receiver is currently a global flap or not"
- 
- 	| oldWorld |
- 	self hideFlap.
- 	oldWorld := self currentWorld.
- 	self isGlobalFlap
- 		ifTrue:
- 			[Flaps removeFromGlobalFlapTabList: self.
- 			oldWorld addMorphFront: self]
- 		ifFalse:
- 			[self delete.
- 			Flaps addGlobalFlap: self.
- 			self currentWorld addGlobalFlaps].
- 	self currentWorld reformulateUpdatingMenus.!

Item was removed:
- ----- Method: FlapTab>>toggleMouseOverBehavior (in category 'mouseover & dragover') -----
- toggleMouseOverBehavior
- 	self arrangeToPopOutOnMouseOver:  (popOutOnMouseOver := popOutOnMouseOver not)!

Item was removed:
- ----- Method: FlapTab>>togglePartsBinMode (in category 'parts bin') -----
- togglePartsBinMode
- 	referent setPartsBinStatusTo: referent isPartsBin not!

Item was removed:
- ----- Method: FlapTab>>transposeParts (in category 'positioning') -----
- transposeParts
- 	"The receiver's orientation has just been changed from vertical to horizontal or vice-versa."
- 	"First expand the flap to screen size, letting the submorphs lay out to fit,
- 	and then shrink the minor dimension back to the last row."
- 
- 	self isCurrentlyTextual ifTrue:  "First recreate the tab with proper orientation"
- 		[self assumeString: self existingWording font: Preferences standardFlapFont
- 			orientation: self orientation color: self color].
- 	self orientation == #vertical
- 		ifTrue:	"changed from horizontal"
- 			[referent listDirection: #topToBottom; wrapDirection: #leftToRight.
- 			referent hasSubmorphs ifTrue:
- 				[referent extent: self currentWorld extent.
- 				referent fullBounds.  "Needed to trigger layout"
- 				referent width: (referent submorphs collect: [:m | m right]) max
- 									- referent left + self width]]
- 		ifFalse:
- 			[referent listDirection: #leftToRight; wrapDirection: #topToBottom.
- 			referent hasSubmorphs ifTrue:
- 				[referent extent: self currentWorld extent.
- 				referent fullBounds.  "Needed to trigger layout"
- 				referent height: (referent submorphs collect: [:m | m bottom]) max
- 									- referent top + self height]].
- 	referent hasSubmorphs ifFalse: [referent extent: 100 at 100].
- 
- 	self spanWorld.
- 	flapShowing ifTrue: [self showFlap]!

Item was removed:
- ----- Method: FlapTab>>useSolidTab (in category 'solid tabs') -----
- useSolidTab
- 	| thickness colorToUse |
- 	self preserveDetails.
- 
- 	thickness := self valueOfProperty: #priorThickness ifAbsent: [20].
- 	colorToUse := self valueOfProperty: #priorColor ifAbsent: [Color red muchLighter].
- 	self color: colorToUse.
- 	self removeAllMorphs.
- 	
- 	(self orientation == #vertical)
- 		ifTrue:
- 			[self width: thickness.
- 			self height: self currentWorld height.
- 			self position: (self position x @ 0)]
- 		ifFalse:
- 			[self height: thickness.
- 			self width: self currentWorld width.
- 			self position: (0 @ self position y)].
- 
- 	self borderWidth: 0.
- 	self layoutChanged.!

Item was removed:
- ----- Method: FlapTab>>useStringTab: (in category 'textual tabs') -----
- useStringTab: aString
- 	| aLabel |
- 	labelString := aString asString.
- 	aLabel := StringMorph  new contents: labelString.
- 	self addMorph: aLabel.
- 	aLabel position: self position.
- 	aLabel highlightColor: self highlightColor; regularColor: self regularColor.
- 	aLabel lock.
- 	self fitContents.
- 	self layoutChanged!

Item was removed:
- ----- Method: FlapTab>>useTextualTab (in category 'textual tabs') -----
- useTextualTab
- 	| stringToUse colorToUse |
- 	self preserveDetails.
- 	colorToUse := self valueOfProperty: #priorColor ifAbsent: [Color green muchLighter].
- 	submorphs notEmpty ifTrue: [self removeAllMorphs].
- 	stringToUse := self valueOfProperty: #priorWording ifAbsent: ['Unnamed Flap' translated].
- 	self assumeString: stringToUse font:  Preferences standardFlapFont orientation: self orientation color: colorToUse!

Item was removed:
- ----- Method: FlapTab>>wantsRoundedCorners (in category 'rounding') -----
- wantsRoundedCorners
- 	^self isCurrentlyTextual or:[super wantsRoundedCorners]!

Item was removed:
- ----- Method: FlapTab>>wording (in category 'menu') -----
- wording
- 	^ self isCurrentlyTextual
- 		ifTrue:
- 			[self existingWording]
- 		ifFalse:
- 			[self valueOfProperty: #priorWording ifAbsent: ['---']]!

Item was removed:
- Object subclass: #Flaps
- 	instanceVariableNames: ''
- 	classVariableNames: 'FlapsQuads SharedFlapTabs SharedFlapsAllowed'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Flaps'!
- 
- !Flaps commentStamp: 'asm 3/13/2003 12:46' prior: 0!
- ClassVariables
- 
- FlapsQuads               quads defining predefined flaps
- 			default flaps are: 'PlugIn Supplies', 'Stack Tools', 'Supplies', 'Tools', 'Widgets' and 'Scripting'
- 
- SharedFlapTabs          an  array of flaps shared between squeak projects
- SharedFlapsAllowed     boolean
- 
- !

Item was removed:
- ----- Method: Flaps class>>addAndEnableEToyFlaps (in category 'predefined flaps') -----
- addAndEnableEToyFlaps
- 	"Initialize the standard default out-of-box set of global flaps.  This method creates them and places them in my class variable #SharedFlapTabs, but does not itself get them displayed."
- 
- 	| aSuppliesFlap |
- 	SharedFlapTabs
- 		ifNotNil: [^ self].
- 	SharedFlapTabs := OrderedCollection new.
- 
- 	aSuppliesFlap := self newSuppliesFlapFromQuads: self quadsDefiningPlugInSuppliesFlap positioning: #right.
- 	aSuppliesFlap referent setNameTo: 'Supplies Flap' translated.  "Per request from Kim Rose, 7/19/02"
- 	SharedFlapTabs add: aSuppliesFlap.  "The #center designation doesn't quite work at the moment"
- 
- 	(Smalltalk globals at: #SugarNavigatorBar ifPresent: [:c | c showSugarNavigator] ifAbsent: [false])
- 		ifTrue: [SharedFlapTabs add: self newSugarNavigatorFlap]
- 		ifFalse: [Preferences showProjectNavigator
- 			ifTrue:[ SharedFlapTabs add: self newNavigatorFlap]].
- 
- 	self enableGlobalFlapWithID: 'Supplies' translated.
- 
- 	(Smalltalk globals at: #SugarNavigatorBar ifPresent: [:c | c showSugarNavigator] ifAbsent: [false])
- 		ifTrue:
- 			[self enableGlobalFlapWithID: 'Sugar Navigator Flap' translated.
- 			(self globalFlapTabWithID: 'Sugar Navigator Flap' translated) ifNotNil:
- 				[:navTab | aSuppliesFlap sugarNavTab: navTab]]
- 		ifFalse: [
- 			Preferences showProjectNavigator
- 				ifTrue:[ self enableGlobalFlapWithID: 'Navigator' translated]].
- 
- 	SharedFlapsAllowed := true.
- 	Project current flapsSuppressed: false.
- 	^ SharedFlapTabs
- 
- "Flaps addAndEnableEToyFlaps"!

Item was removed:
- ----- Method: Flaps class>>addGlobalFlap: (in category 'shared flaps') -----
- addGlobalFlap: aFlapTab
- 	"Add the given flap tab to the list of shared flaps"
- 
- 	SharedFlapTabs ifNil: [SharedFlapTabs := OrderedCollection new].
- 	SharedFlapTabs add: aFlapTab!

Item was removed:
- ----- Method: Flaps class>>addIndividualGlobalFlapItemsTo: (in category 'menu support') -----
- addIndividualGlobalFlapItemsTo: aMenu
- 	"Add items governing the enablement of specific global flaps to aMenu"
- 
- 	self globalFlapTabsIfAny do:
- 		[:aFlapTab |
- 			|  anItem |
- 			anItem := aMenu addUpdating: #globalFlapWithIDEnabledString: enablementSelector: #showSharedFlaps target: self selector: #enableDisableGlobalFlapWithID: argumentList: {aFlapTab flapID}.
- 			anItem wordingArgument: aFlapTab flapID.
- 			anItem setBalloonText: aFlapTab balloonTextForFlapsMenu].!

Item was removed:
- ----- Method: Flaps class>>addLocalFlap (in category 'new flap') -----
- addLocalFlap
- 
- 	^ self addLocalFlap: self currentEvent!

Item was removed:
- ----- Method: Flaps class>>addLocalFlap: (in category 'new flap') -----
- addLocalFlap: anEvent
- 	"Menu command -- let the user add a new project-local flap.  Once the new flap is born, the user can tell it to become a shared flap.  Obtain an initial name and edge for the flap, launch the flap, and also launch a menu governing the flap, so that the user can get started right away with customizing it."
- 
- 	| title edge |
- 	edge := self askForEdgeOfNewFlap.
- 	edge ifNil: [^ self].
- 	
- 	title := UIManager default request: 'Wording for this flap:' translated initialAnswer: 'Flap' translated.
- 	title isEmptyOrNil ifTrue: [^ self].
- 	
- 	^ self addLocalFlap: anEvent titled: title onEdge: edge!

Item was removed:
- ----- Method: Flaps class>>addLocalFlap:titled:onEdge: (in category 'new flap') -----
- addLocalFlap: anEvent titled: title onEdge: edge
- 
- 	| flapTab menu world |
- 	flapTab := self newFlapTitled: title onEdge: edge.
- 	(world := anEvent hand world) addMorphFront: flapTab.
- 	flapTab adaptToWorld: world.
- 	menu := flapTab buildHandleMenu: anEvent hand.
- 	flapTab addTitleForHaloMenu: menu.
- 	flapTab computeEdgeFraction.
- 	menu popUpEvent: anEvent in: world.!

Item was removed:
- ----- Method: Flaps class>>addMorph:asElementNumber:inGlobalFlapSatisfying: (in category 'construction support') -----
- addMorph: aMorph asElementNumber: aNumber inGlobalFlapSatisfying: flapBlock
- 	"If any global flap satisfies flapBlock, add aMorph to it at the given position.  Applies to flaps that are parts bins and that like thumbnailing"
- 
- 	| aFlapTab flapPasteUp |
- 	aFlapTab := self globalFlapTabsIfAny detect: flapBlock ifNone: [^ self].
- 	flapPasteUp := aFlapTab referent.
- 	flapPasteUp addMorph: aMorph asElementNumber: aNumber.
- 	flapPasteUp replaceTallSubmorphsByThumbnails; setPartsBinStatusTo: true!

Item was removed:
- ----- Method: Flaps class>>addMorph:asElementNumber:inGlobalFlapWithID: (in category 'construction support') -----
- addMorph: aMorph asElementNumber: aNumber inGlobalFlapWithID: anID
- 	"If any global flap satisfies flapBlock, add aMorph to it at the given position.  No senders in the image -- intended to be invoked by doits in code updates only, and applies to flaps that are parts bins and that like thumbnailing"
- 
- 	^ self addMorph: aMorph asElementNumber: aNumber inGlobalFlapSatisfying: [:aFlap | aFlap flapID = anID]!

Item was removed:
- ----- Method: Flaps class>>addNewDefaultSharedFlaps (in category 'predefined flaps') -----
- addNewDefaultSharedFlaps
- 	"Add the stack tools flap and the navigator flap to the global list, but do not have them showing initially.  Transitional, called by the postscript of the FlapsOnBottom update; probably dispensable afterwards."
- 
- 	SharedFlapTabs ifNotNil:
- 		[(self globalFlapTabWithID: 'Stack Tools' translated) ifNil:
- 			[SharedFlapTabs add: self newStackToolsFlap delete].
- 		self enableGlobalFlapWithID: 'Stack Tools' translated.
- 		(self globalFlapTabWithID: 'Navigator' translated) ifNil:
- 			[SharedFlapTabs add: self newNavigatorFlap delete].
- 		self enableGlobalFlapWithID: 'Navigator' translated.
- 		self currentWorld addGlobalFlaps]!

Item was removed:
- ----- Method: Flaps class>>addStandardFlaps (in category 'predefined flaps') -----
- addStandardFlaps
- 	"Initialize the standard default out-of-box set of global flaps. 
- 	This method creates them and places them in my class 
- 	variable #SharedFlapTabs, but does not itself get them 
- 	displayed. "
- 	SharedFlapTabs
- 		ifNil: [SharedFlapTabs := OrderedCollection new].
- 	SharedFlapTabs add: self newSqueakFlap.
- 	SharedFlapTabs add: self newSuppliesFlap.
- 	SharedFlapTabs add: self newToolsFlap.
- 	SharedFlapTabs add: self newWidgetsFlap.
- 	SharedFlapTabs add: self newStackToolsFlap.
- 
- 	Preferences showProjectNavigator
- 		ifTrue:[SharedFlapTabs add: self newNavigatorFlap].
- 
- 	SharedFlapTabs add: self newPaintingFlap.
- 	SharedFlapTabs add: self newObjectsFlap.
- 	self disableGlobalFlapWithID: 'Stack Tools' translated.
- 	self disableGlobalFlapWithID: 'Painting' translated.
- 
- 	Preferences showProjectNavigator
- 		ifTrue:[self disableGlobalFlapWithID: 'Navigator' translated].
- 
- 	^ SharedFlapTabs!

Item was removed:
- ----- Method: Flaps class>>addToSuppliesFlap:asElementNumber: (in category 'construction support') -----
- addToSuppliesFlap: aMorph asElementNumber: aNumber
- 	"Add the given morph to the supplies flap.  To be called by doits in updates, so don't be alarmed by its lack of senders."
- 
- 	self addMorph: aMorph asElementNumber: aNumber inGlobalFlapWithID: 'Supplies'!

Item was removed:
- ----- Method: Flaps class>>anyFlapsVisibleIn: (in category 'testing') -----
- anyFlapsVisibleIn: aWorld
- 
- 	aWorld submorphsDo: [:m |
- 		(m isKindOf: FlapTab) ifTrue: [^ true]].
- 	
- 	^ false!

Item was removed:
- ----- Method: Flaps class>>askForEdgeOfNewFlap (in category 'new flap') -----
- askForEdgeOfNewFlap
- 
- 	
- 	^MenuMorph 
- 		chooseFrom: (#('left' 'right' 'top' 'bottom') collect: [ :each | each translated ])
- 		values: #(left right top bottom)
- 		lines: #()
- 		title: 'Where should the new flap cling?' translated.
- !

Item was removed:
- ----- Method: Flaps class>>automaticFlapLayoutChanged (in category 'miscellaneous') -----
- automaticFlapLayoutChanged
- 	"Sent when the automaticFlapLayout preference changes.  No senders in easily traceable in the image, but this is really sent by a Preference object!!"
- 
- 	Preferences automaticFlapLayout ifTrue:
- 		[self positionNavigatorAndOtherFlapsAccordingToPreference]!

Item was removed:
- ----- Method: Flaps class>>clobberFlapTabList (in category 'flap mechanics') -----
- clobberFlapTabList
- 	"Flaps clobberFlapTabList"
- 
- 	SharedFlapTabs := nil!

Item was removed:
- ----- Method: Flaps class>>defaultColorForFlapBackgrounds (in category 'new flap') -----
- defaultColorForFlapBackgrounds
- 	"Answer the color to use, by default, in new flap backgrounds"
- 
- 	^ (Color blue mixed: 0.8 with: Color white) alpha: 0.6!

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningPlugInSuppliesFlap (in category 'predefined flaps') -----
- defaultsQuadsDefiningPlugInSuppliesFlap
- 	"Answer a list of quads which define the objects to appear in the default Supplies flap used in the Plug-in image"
- 
- 	"PartsBin reconstructAllPartsIcons"
- 
- 	^  #(
- 	(ObjectsTool				newStandAlone				'Object Catalog'		'A tool that lets you browse the catalog of available objects')
- 	(AllScriptsTool			allScriptsToolForActiveWorld	'All Scripts' 		'Stop, Step, and Go buttons for controlling all your scripts at once.  The tool can also be "opened up" to control each script in your project individually.')
- 	(TrashCanMorph			new						'Trash'				'A tool for discarding objects')
- 	(GrabPatchMorph		new						'Grab Patch'		'Allows you to create a new Sketch by grabbing a rectangular patch from the screen')
- 	(LassoPatchMorph		new						'Lasso'		'Allows you to create a new Sketch by lassoing an area from the screen')
- 
- 	(StickyPadMorph		newStandAlone			'Sticky Pad'			'Each time you obtain one of these pastel, translucent, borderless rectangles, it will be a different color from the previous time.')
- 	"(PaintInvokingMorph	new						'Paint'				'Drop this into an area to start making a fresh painting there')"
- 	(TextMorph				boldAuthoringPrototype			'Text'				'Text that you can edit into anything you desire.')
- 	(RecordingControlsMorph	authoringPrototype		'Sound'				'A device for making sound recordings.')
- 	(RectangleMorph 		authoringPrototype		'Rectangle' 		'A rectangle')
- 	(RectangleMorph		roundRectPrototype		'RoundRect'		'A rectangle with rounded corners')
- 	(EllipseMorph			authoringPrototype		'Ellipse'			'An ellipse or circle')
- 	(StarMorph				authoringPrototype		'Star'			'A star')
- 	(CurveMorph			authoringPrototype		'Curve'			'A curve')
- 	(PolygonMorph			authoringPrototype		'Polygon'		'A straight-sided figure with any number of sides')
- 	(ScriptableButton		authoringPrototype		'Button'			'A Scriptable button')
- 	"(BookMorph				nextPageButton			'NextPage'		'A button that takes you to the next page')
- 	(BookMorph				previousPageButton 		'PreviousPage'	'A button that takes you to the previous page')"
- 	"(ScriptingSystem		prototypicalHolder 		'Holder'			'A place for storing alternative pictures in an animation, etc.')"
- 	(PasteUpMorph			authoringPrototype		'Playfield'		'A place for assembling parts or for staging animations')
- 	(SimpleSliderMorph		authoringPrototype		'Slider'			'A slider for showing and setting numeric values.')
- 	(JoystickMorph			authoringPrototype		'Joystick'		'A joystick-like control')
- 	(BookMorph				authoringPrototype		'Book'			'A multi-paged structure')
- 	"(ClockMorph				authoringPrototype		'Clock'			'A simple digital clock')"
- 	(KedamaMorph			 newSet 		'Particles'	'A Kedama World with pre-made components')
- 	"(RandomNumberTile		new					'Random'		'A random-number tile for use with tile scripting')") asOrderedCollection!

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningScriptingFlap (in category 'flaps registry') -----
- defaultsQuadsDefiningScriptingFlap
- 	"Answer a structure defining the default items in the Scripting flap.
- 	previously in quadsDeiningScriptingFlap"
- 
- 	^ {
- 	{#TrashCanMorph.		#new.							'Trash' translatedNoop. 	'A tool for discarding objects' translatedNoop}.	
- 	{#ScriptingSystem.		#scriptControlButtons.			'Status' translatedNoop.	'Buttons to run, stop, or single-step scripts' translatedNoop}.
- 	{#AllScriptsTool.			#allScriptsToolForActiveWorld.	'All Scripts' translatedNoop.	'A tool that lets you control all the running scripts in your world' translatedNoop}.
- 	{#ScriptingSystem.		#newScriptingSpace.		'Scripting' translatedNoop. 	'A confined place for drawing and scripting, with its own private stop/step/go buttons.' translatedNoop}.
- 
- 	{#PaintInvokingMorph.	#new.		'Paint' translatedNoop.	'Drop this into an area to start making a fresh painting there' translatedNoop}.
- 	{#ScriptableButton.		#authoringPrototype.	'Button' translatedNoop.		'A Scriptable button' translatedNoop}.
- 	{#ScriptingSystem.		#prototypicalHolder.		'Holder' translatedNoop.		'A place for storing alternative pictures in an animation, etc.' translatedNoop}.
- 	{#FunctionTile.			#randomNumberTile.	'Random' translatedNoop.	'A tile that will produce a random number in a given range' translatedNoop}.
- 	{#ScriptingSystem.		#anyButtonPressedTiles.	'ButtonDown?' translatedNoop.	'Tiles for querying whether the mouse button is down' translatedNoop}.
- 	{#ScriptingSystem.		#noButtonPressedTiles.	'ButtonUp?' translatedNoop.		'Tiles for querying whether the mouse button is up' translatedNoop}.
- 
- 	{#SimpleSliderMorph.	#authoringPrototype.	'Slider' translatedNoop.		'A slider for showing and setting numeric values.' translatedNoop}.
- 	{#JoystickMorph	.		#authoringPrototype.	'Joystick' translatedNoop.	'A joystick-like control' translatedNoop}.
- 	{#TextFieldMorph.		#exampleBackgroundField.	'Scrolling Field'	translatedNoop. 'A scrolling data field which will have a different value on every card of the background' translatedNoop}.
- 
- 	{#PasteUpMorph.	#authoringPrototype.		'Playfield' translatedNoop.	'A place for assembling parts or for staging animations' translatedNoop}.
- 
- 
- 	{#StackMorph. 		#authoringPrototype.		'Stack' translatedNoop. 		'A multi-card data base'	translatedNoop}.
- 	{#TextMorph.		#exampleBackgroundLabel.	'Background Label' translatedNoop. 'A piece of text that will occur on every card of the background' translatedNoop}.
- 	{#TextMorph	.		#exampleBackgroundField.	'Background Field' translatedNoop. 'A data field which will have a different value on every card of the background' translatedNoop}
- } asOrderedCollection!

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningStackToolsFlap (in category 'flaps registry') -----
- defaultsQuadsDefiningStackToolsFlap
- 	"Answer a structure defining the items on the default system Stack Tools flap.
- 	previously in quadsDefiningStackToolsFlap"
- 
- 	^ {
- 	{#StackMorph. 		#authoringPrototype.	'Stack' translatedNoop. 				'A multi-card data base'	translatedNoop}.
- 	{#StackMorph.		#stackHelpWindow.		'Stack Help'	translatedNoop.		'Some hints about how to use Stacks' translatedNoop}.
- 	{#TextMorph	.		#authoringPrototype.	'Simple Text' translatedNoop.		'Text that you can edit into anything you wish' translatedNoop}.
- 	{#TextMorph	.		#fancyPrototype.		'Fancy Text' translatedNoop. 		'A text field with a rounded shadowed border, with a fancy font.' translatedNoop}.
- 	{#ScrollableField.	#newStandAlone.		'Scrolling Text' translatedNoop.		'Holds any amount of text; has a scroll bar' translatedNoop}.
- 	{#ScriptableButton.	#authoringPrototype.	'Scriptable Button' translatedNoop.	'A button whose script will be a method of the background Player' translatedNoop}.
- 	{#StackMorph.		#previousCardButton. 	'Previous Card' translatedNoop. 		'A button that takes the user to the previous card in the stack' translatedNoop}.
- 	{#StackMorph.		#nextCardButton.		'Next Card' translatedNoop.			'A button that takes the user to the next card in the stack' translatedNoop} } asOrderedCollection
- !

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningSuppliesFlap (in category 'flaps registry') -----
- defaultsQuadsDefiningSuppliesFlap
- 	"Answer a list of quads which define the objects to appear in the default Supplies flap.
- 	previously in quadsDefiningSuppliesFlap"
- 
- 	^ {
- 	{#RectangleMorph. 	#authoringPrototype.		'Rectangle' 	translatedNoop.	'A rectangle' translatedNoop}.
- 	{#RectangleMorph.	#roundRectPrototype.		'RoundRect' translatedNoop.		'A rectangle with rounded corners' translatedNoop}.
- 	{#EllipseMorph.		#authoringPrototype.		'Ellipse' translatedNoop.			'An ellipse or circle' translatedNoop}.
- 	{#StarMorph.		#authoringPrototype.		'Star' translatedNoop.			'A star' translatedNoop}.
- 	{#PolygonMorph.		#curvePrototype.		'Curve' translatedNoop.			'A curve' translatedNoop}.
- 	{#PolygonMorph.	#authoringPrototype.		'Polygon' translatedNoop.		'A straight-sided figure with any number of sides' translatedNoop}.
- 	{#TextMorph	.		#authoringPrototype.	'Text' translatedNoop.			'Text that you can edit into anything you desire.' translatedNoop}.
- 	{#ScriptingSystem.	#prototypicalHolder. 		'Holder' translatedNoop.			'A place for storing alternative pictures in an animation, etc.' translatedNoop}.
- 	{#ImageMorph.		#authoringPrototype.		'Picture' translatedNoop.		'A non-editable picture of something' translatedNoop}.
- 	{#ScriptableButton.	#authoringPrototype.		'Button' translatedNoop.			'A Scriptable button' translatedNoop}.
- 	{#SimpleSliderMorph.	#authoringPrototype.	'Slider' translatedNoop.			'A slider for showing and setting numeric values.' translatedNoop}.
- 	{#PasteUpMorph.	#authoringPrototype.		'Playfield' translatedNoop.		'A place for assembling parts or for staging animations' translatedNoop}.
- 	{#BookMorph.		#authoringPrototype.		'Book' translatedNoop.			'A multi-paged structure' translatedNoop}.
- 	{#TabbedPalette.		#authoringPrototype.		'TabbedPalette' translatedNoop.	'A structure with tabs' translatedNoop}.
- 	{#JoystickMorph	.	#authoringPrototype.		'Joystick' translatedNoop.		'A joystick-like control' translatedNoop}.
- 	{#ClockMorph.		#authoringPrototype.		'Clock' translatedNoop.			'A simple digital clock' translatedNoop}.
- 	{#BookMorph.		#previousPageButton. 		'PreviousPage' translatedNoop.	'A button that takes you to the previous page' translatedNoop}.
- 	{#BookMorph.		#nextPageButton.			'NextPage' translatedNoop.		'A button that takes you to the next page' translatedNoop}
- } asOrderedCollection!

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningToolsFlap (in category 'flaps registry') -----
- defaultsQuadsDefiningToolsFlap
- 	"Answer a structure defining the default Tools flap.
- 	previously in quadsDefiningToolsFlap"
- 
- 	^ OrderedCollection new
- 	addAll: #(
- 	(Browser 				prototypicalToolWindow		'Browser'			'A Browser is a tool that allows you to view all the code of all the classes in the system')
- 	(TranscriptStream		openMorphicTranscript				'Transcript'			'A Transcript is a window usable for logging and debugging; browse references to #Transcript for examples of how to write to it.')
- 	(Workspace			prototypicalToolWindow		'Workspace'			'A Workspace is a simple window for editing text.  You can later save the contents to a file if you desire.'));
- 		add: {   FileList2 .
- 				#prototypicalToolWindow.
- 				'File List'.
- 				'A File List is a tool for browsing folders and files on disks and FTP servers.' };
- 	addAll: #(
- 	(DualChangeSorter		prototypicalToolWindow		'Change Sorter'		'Shows two change sets side by side')
- 	(SelectorBrowser		prototypicalToolWindow		'Method Finder'		'A tool for discovering methods by providing sample values for arguments and results')
- 	(MessageNames		prototypicalToolWindow		'Message Names'		'A tool for finding, viewing, and editing all methods whose names contain a given character sequence.')
- 	(PreferencesBrowser	prototypicalToolWindow	'Preferences'			'Allows you to control numerous options')
- 	(Utilities				recentSubmissionsWindow	'Recent'				'A message browser that tracks the most recently-submitted methods')
- 	(ProcessBrowser		prototypicalToolWindow		'Processes'			'A Process Browser shows you all the running processes')
- 	(Preferences			annotationEditingWindow	'Annotations'		'Allows you to specify the annotations to be shown in the annotation panes of browsers, etc.')
- 		(PackagePaneBrowser	prototypicalToolWindow		'Packages'			'Package Browser:  like a System Browser, except that if has extra level of categorization in the top-left pane, such that class-categories are further organized into groups called "packages"')
- 	(ChangeSorter			prototypicalToolWindow		'Change Set'			'A tool that allows you to view and manipulate all the code changes in a single change set'));
- 		yourself!

Item was removed:
- ----- Method: Flaps class>>defaultsQuadsDefiningWidgetsFlap (in category 'flaps registry') -----
- defaultsQuadsDefiningWidgetsFlap
- 	"Answer a structure defining the default Widgets flap.
-      previously in quadsDefiningWidgetsFlap"
- 
- 	^ #(
- 	(TrashCanMorph			new						'Trash'		
- 		'A tool for discarding objects')
- 	"(AllScriptsTool			allScriptsToolForActiveWorld	'All
- Scripts' 		'A tool that lets you see and control all the running
- scripts in your project')"
- 	(PaintInvokingMorph	new						'Paint'		
- 		'Drop this into an area to start making a fresh painting there')
- 	(GeeMailMorph			new						'Gee-Mail'	
- 		'A place to present annotated content')
- 	(RecordingControlsMorph	authoringPrototype		'Sound'		
- 		'A device for making sound recordings.')
- 	"(MPEGMoviePlayerMorph	authoringPrototype		'Movie
- Player'		'A Player for MPEG movies')"
- 	(FrameRateMorph		authoringPrototype			'Frame
- Rate'		'An indicator of how fast your system is running')
- 	(MagnifierMorph		newRound					'Magnifier'	
- 		'A magnifying glass')
- 	"(ScriptingSystem		newScriptingSpace			'Scripting'	
- 		'A confined place for drawing and scripting, with its own
- private stop/step/go buttons.')
- 	(ScriptingSystem		holderWithAlphabet			'Alphabet'	
- 		'A source for single-letter objects')
- 	(BouncingAtomsMorph	new						'Bouncing
- Atoms'	'Atoms, mate')"
- 	(ObjectsTool				newStandAlone				'Object
- Catalog'		'A tool that lets you browse the catalog of objects')
- 	) asOrderedCollection!

Item was removed:
- ----- Method: Flaps class>>deleteMorphsSatisfying:fromGlobalFlapSatisfying: (in category 'construction support') -----
- deleteMorphsSatisfying: deleteBlock fromGlobalFlapSatisfying: flapBlock
- 	"If any global flap satisfies flapBlock, then delete objects satisfying from deleteBlock from it.  Occasionally called from do-its in updates or other fileouts."
- 
- 	| aFlapTab flapPasteUp |
- 	aFlapTab := self globalFlapTabsIfAny detect: flapBlock ifNone: [^ self].
- 	flapPasteUp := aFlapTab referent.
- 	flapPasteUp submorphs do:
- 		[:aMorph | (deleteBlock value: aMorph) ifTrue: [aMorph delete]]!

Item was removed:
- ----- Method: Flaps class>>disableGlobalFlapWithID: (in category 'menu commands') -----
- disableGlobalFlapWithID: aFlapID
- 	"Mark this project as having the given flapID disabled"
- 
- 	| disabledFlapIDs  aFlapTab currentProject |
- 	(currentProject := Project current) assureFlapIntegrity.
- 	Smalltalk isMorphic ifFalse: [^ self].
- 	disabledFlapIDs := currentProject parameterAt: #disabledGlobalFlapIDs.
- 	(aFlapTab := self globalFlapTabWithID: aFlapID) ifNotNil:
- 		[aFlapTab hideFlap].
- 	(disabledFlapIDs includes: aFlapID)
- 		ifFalse:
- 			[disabledFlapIDs add: aFlapID].
- 	aFlapTab ifNotNil: [aFlapTab delete]
- 
- 	!

Item was removed:
- ----- Method: Flaps class>>disableGlobalFlaps (in category 'menu commands') -----
- disableGlobalFlaps
- 	"Clobber all the shared flaps structures.  First read the user her Miranda rights."
- 
- 	self disableGlobalFlaps: true!

Item was removed:
- ----- Method: Flaps class>>disableGlobalFlaps: (in category 'menu commands') -----
- disableGlobalFlaps: interactive
- 	"Clobber all the shared flaps structures.  First read the user her Miranda rights."
- 
- 	interactive
- 		ifTrue: [(self confirm: 
- 'CAUTION!! This will destroy all the shared
- flaps, so that they will not be present in 
- *any* project.  If, later, you want them
- back, you will have to reenable them, from
- this same menu, whereupon the standard
- default set of shared flaps will be created.
- Do you really want to go ahead and clobber
- all shared flaps at this time?' translated) ifFalse: [^ self]].
- 
- 	self globalFlapTabsIfAny do:
- 		[:aFlapTab | self removeFlapTab: aFlapTab keepInList: false.
- 		aFlapTab isInWorld ifTrue: [self error: 'Flap problem' translated]].
- 	self clobberFlapTabList.
- 	self initializeFlapsQuads.
- 	SharedFlapsAllowed := false.
- 	Smalltalk isMorphic ifTrue: [
- 		Project current world
- 			restoreMorphicDisplay;
- 			reformulateUpdatingMenus].
- 	
- 	"The following reduces the risk that flaps will be created with variant IDs
- 		such as 'Stack Tools2', potentially causing some shared flap logic to fail."
- 		"Smalltalk garbageCollect."  "-- see if we are OK without this"!

Item was removed:
- ----- Method: Flaps class>>doAutomaticLayoutOfFlapsIfAppropriate (in category 'miscellaneous') -----
- doAutomaticLayoutOfFlapsIfAppropriate
- 	"Do automatic layout of flaps if appropriate"
- 
- 	Preferences automaticFlapLayout ifTrue:
- 		[self positionNavigatorAndOtherFlapsAccordingToPreference]!

Item was removed:
- ----- Method: Flaps class>>enableClassicNavigatorChanged (in category 'miscellaneous') -----
- enableClassicNavigatorChanged
- 	"The #classicNavigatorEnabled preference has changed.   No senders in easily traceable in the image, but this is really sent by a Preference object!!"
- 
- 	Preferences classicNavigatorEnabled
- 		ifTrue:
- 			[Flaps disableGlobalFlapWithID: 'Navigator' translated.
- 			Preferences enable: #showProjectNavigator.
- 			self disableGlobalFlapWithID: 'Navigator' translated.]
- 		ifFalse:
- 			[self enableGlobalFlapWithID: 'Navigator' translated.
- 			Project current world addGlobalFlaps].
- 
- 	self doAutomaticLayoutOfFlapsIfAppropriate.
- 	Project current assureNavigatorPresenceMatchesPreference.
- 	Project current world reformulateUpdatingMenus.!

Item was removed:
- ----- Method: Flaps class>>enableDisableGlobalFlapWithID: (in category 'menu commands') -----
- enableDisableGlobalFlapWithID: aFlapID
- 	"Toggle the enable/disable status of the given global flap"
- 
- 	| disabledFlapIDs  aFlapTab currentProject |
- 	(currentProject := Project current) assureFlapIntegrity.
- 	Smalltalk isMorphic ifFalse: [^ self].
- 	disabledFlapIDs := currentProject parameterAt: #disabledGlobalFlapIDs.
- 	(aFlapTab := self globalFlapTabWithID: aFlapID) ifNotNil:
- 		[aFlapTab hideFlap].
- 	(disabledFlapIDs includes: aFlapID)
- 		ifTrue:
- 			[disabledFlapIDs remove: aFlapID.
- 			self currentWorld addGlobalFlaps]
- 		ifFalse:
- 			[disabledFlapIDs add: aFlapID.
- 			aFlapTab ifNotNil: [aFlapTab delete]].
- 	self doAutomaticLayoutOfFlapsIfAppropriate!

Item was removed:
- ----- Method: Flaps class>>enableEToyFlaps (in category 'menu support') -----
- enableEToyFlaps
- 	"Start using global flaps, plug-in version, given that they were not present."
- 
- 	Cursor wait showWhile:
- 		[self addAndEnableEToyFlaps.
- 		self enableGlobalFlaps]!

Item was removed:
- ----- Method: Flaps class>>enableGlobalFlapWithID: (in category 'menu commands') -----
- enableGlobalFlapWithID: aFlapID
- 	"Remove any memory of this flap being disabled in this project"
- 
- 	| disabledFlapIDs  currentProject |
- 	(currentProject := Project current) assureFlapIntegrity.
- 	Smalltalk isMorphic ifFalse: [^ self].
- 	disabledFlapIDs := currentProject parameterAt: #disabledGlobalFlapIDs ifAbsent: [^ self].
- 	disabledFlapIDs remove: aFlapID ifAbsent: []
- 	!

Item was removed:
- ----- Method: Flaps class>>enableGlobalFlaps (in category 'menu support') -----
- enableGlobalFlaps
- 	"Start using global flaps, given that they were not present."
- 
- 	Cursor wait showWhile: [
- 		SharedFlapsAllowed := true.
- 		self globalFlapTabs. "This will create them"
- 		Smalltalk isMorphic ifTrue: [
- 			Project current world addGlobalFlaps.
- 			self doAutomaticLayoutOfFlapsIfAppropriate.
- 			FlapTab allInstancesDo: [:tab | tab computeEdgeFraction].
- 			Project current world reformulateUpdatingMenus]]!

Item was removed:
- ----- Method: Flaps class>>enableOnlyGlobalFlapsWithIDs: (in category 'shared flaps') -----
- enableOnlyGlobalFlapsWithIDs: survivorList
- 	"In the current project, suppress all global flaps other than those with ids in the survivorList"
- 
- 	self globalFlapTabsIfAny do: [:flapTab |
- 		(survivorList includes: flapTab flapID)
- 			ifTrue: [self enableGlobalFlapWithID: flapTab flapID]
- 			ifFalse: [self disableGlobalFlapWithID: flapTab flapID]].
- 	Project current world addGlobalFlaps 
- 
- 	"Flaps enableOnlyGlobalFlapsWithIDs: #('Supplies')"!

Item was removed:
- ----- Method: Flaps class>>explainFlaps (in category 'menu commands') -----
- explainFlaps
- 	"Open a window giving flap help."
- 
- 	(StringHolder new contents: self explainFlapsText translated)
- 		openLabel: 'Flaps' translated
- 
- "Flaps explainFlaps"
- 
- 
- 
- 
- 	!

Item was removed:
- ----- Method: Flaps class>>explainFlapsText (in category 'menu commands') -----
- explainFlapsText
- 	"Answer the text, in English, to show in a help-window about Flaps."
- 
- 	^'Flaps are like drawers on the edge of the screen, which can be opened so that you can use what is inside them, and closed when you do not need them.  They have many possible uses, a few of which are illustrated by the default set of flaps you can get as described below.
- 
-  ''Shared flaps'' are available in every morphic project.  As you move from project to project, you will see these same shared flaps in each, though there are also options, on a project-by-project basis, to choose which of the shared flaps should be shown, and also momentarily to suppress the showing of all shared flaps.   
- 
-  To get started using flaps, bring up the desktop menu and choose ''flaps...'', and make the menu stay up by choosing ''keep this menu up''.  If you see, in this flaps menu,  a list of flap names such as ''Squeak'', ''Tools'', etc., it means that shared flaps are already set up in your image.  If you do not see the list, you will instead see a menu item that invites you to ''install default shared flaps''; choose that, and new flaps will be created, and the flaps menu will change to reflect their presence.
- 
-  ''Project flaps'' are flaps that belong to a single morphic project.  You will see them when you are in that project, but not when you are in any other morphic project.
- 
-  If a flap is set up as a parts bin (such as the default Tools and Supplies flaps), you can use it to create new objects -- just open the flap, then find the object you want, and drag it out; when the cursor leaves the flap, the flap itself will snap closed, and you''ll be left holding the new object -- just click to place it exactly where you want it.
- 
-  If a flap is *not* set up as a parts bin (such as the default ''Squeak'' flap at the left edge of the screen) you can park objects there (this is an easy way to move objects from project to project) and you can place your own private controls there, etc.  Everything in the default ''Squeak'' flap (and all the other default flaps, for that matter) is there only for illustrative purposes -- every user will want to fine-tune the flaps to suit his/her own style and needs.
- 
-  Each flap may be set up to appear on mouseover, dragover, both, or neither.  See the menu items described below for more about these and other options.
- 
-  You can open a closed flap by clicking on its tab, or by dragging the tab toward the center of the screen
- 
-  You can close an open flap by clicking on its tab or by dragging the tab back off the edge of the screen.
- 
-  Drag the tab of a flap to reposition the tab and to resize the flap itself.  Repositioning starts when you drag the cursor out of the original tab area.
- 
-  If flaps or their tabs seem wrongly positioned or lost, try issuing a restoreDisplay from the screen menu.
- 
-  The red-halo menu on a flap allows you to change the flap''s properties.   For greatest ease of use, request ''keep this menu up'' here -- that way, you can easily explore all the options in the menu.
- 
-  tab color...				Lets you change the color of the flap''s tab.
-  flap color...				Lets you change the color of the flap itself.
- 
-  use textual tab...		If the tab is not textual, makes it become textual.
-  change tab wording...	If the tab is already textual, allows you to edit
- 							its wording.
- 
-  use graphical tab...		If the tab is not graphical, makes it become
- 							graphical.
-  choose tab graphic...	If the tab is already graphical, allows you
- 							to change the picture.
- 
-  use solid tab...			If the tab is not solid, makes it become solid, i.e.
- 							appear as a solid band of color along the
- 							entire length or width of the screen.
- 
-  parts-bin behavior		If set, then dragging an object from the flap
- 							tears off a new copy of the object.
- 
-  dragover				If set, the flap opens on dragover and closes
- 							again on drag-leave.
- 
- 
-  mouseover				If set, the flap opens on mouseover and closes
- 							again on mouse-leave. 
- 
-  cling to edge...			Governs which edge (left, right, top, bottom)
- 							the flap adheres to.
- 
-  shared					If set, the same flap will be available in all projects; if not, the
- 							flap will will occur only in one project.
- 
-  destroy this flap		Deletes the flap.
- 
-  To define a new flap, use ''make a new flap'', found in the ''flaps'' menu.
- 
-  To reinstate the default system flaps, you can use ''destroy all shared flaps'' from the ''flaps'' menu, and once they are destroyed, choose ''install default shared flaps''.
- 
-  To add, delete, or edit things on a given flap, it is often wise first to suspend the flap''s mouse-over and drag-over sensitivity, so it won''t keep disappearing on you while you''re trying to work with it.
- 
-  Besides the three standard flaps delivered with the default system, there are two other flaps readily available on demand from the ''flaps'' menu -- one is called ''Stack Tools'', which provides some tools useful for building stack-like content, the other is called ''Painting'', which provides a quick way to make a new painting.  Simply clicking on the appropriate checkbox in the ''flaps'' menu will toggle the corresponding flap between being visible and not being visible in the project.' translated!

Item was removed:
- ----- Method: Flaps class>>fileOutChanges (in category 'miscellaneous') -----
- fileOutChanges
- 	"Bug workaround for squeak-flap 'fileOutChanges' buttons which for a while were mistakenly sending their requests here..."
- 
- 	^ ChangeSet current verboseFileOut. !

Item was removed:
- ----- Method: Flaps class>>freshFlapsStart (in category 'flap mechanics') -----
- freshFlapsStart
- 	"To be called manually only, as a drastic measure.  Delete all flap artifacts and establish fresh default global flaps
- 	Flaps freshFlapsStart
- 	"
- 	self currentWorld deleteAllFlapArtifacts.
- 	self clobberFlapTabList.
- 	self addStandardFlaps
- !

Item was removed:
- ----- Method: Flaps class>>globalFlapTab: (in category 'shared flaps') -----
- globalFlapTab: aName
- 	"Answer the global flap tab in the current system whose flapID is the same as aName, or nil if none found."
- 
- 	| idToMatch |
- 	idToMatch := (aName beginsWith: 'flap: ')
- 		ifTrue:  "Ted's old scheme; this convention may still be found
- 				in pre-existing content that has been externalized"
- 			[aName copyFrom: 7 to: aName size]
- 		ifFalse:
- 			[aName].
- 
- 	^ self globalFlapTabsIfAny detect: [:ft | ft flapID = idToMatch] ifNone: [nil]!

Item was removed:
- ----- Method: Flaps class>>globalFlapTabOrDummy: (in category 'shared flaps') -----
- globalFlapTabOrDummy: aName
- 	"Answer a global flap tab in the current image with the given name.  If none is found, answer a dummy StringMorph for some reason (check with tk about the use of this)"
- 
- 	| gg |
- 	(gg := self globalFlapTab: aName) ifNil:
- 		[^ StringMorph contents: aName, ' can''t be found'].
- 	^ gg!

Item was removed:
- ----- Method: Flaps class>>globalFlapTabWithID: (in category 'shared flaps') -----
- globalFlapTabWithID: aFlapID
- 	"answer the global flap tab with the given id, or nil if none"
- 
- 	^ self globalFlapTabsIfAny detect: [:aFlapTab | aFlapTab flapID = aFlapID]
- 		ifNone:
- 		["Second try allows sequence numbers"
- 		self globalFlapTabsIfAny detect: [:aFlapTab | FlapTab givenID: aFlapTab flapID matches: aFlapID]
- 			ifNone: [nil]]!

Item was removed:
- ----- Method: Flaps class>>globalFlapTabs (in category 'shared flaps') -----
- globalFlapTabs
- 	"Answer the list of shared flap tabs, creating it if necessary.  Much less aggressive is #globalFlapTabsIfAny"
- 
- 	SharedFlapTabs ifNil: [self initializeStandardFlaps].
- 	^ SharedFlapTabs copy!

Item was removed:
- ----- Method: Flaps class>>globalFlapTabsIfAny (in category 'shared flaps') -----
- globalFlapTabsIfAny
- 	"Answer a list of the global flap tabs, but it they don't exist, just answer an empty list"
- 
- 	^ SharedFlapTabs copy ifNil: [Array new]!

Item was removed:
- ----- Method: Flaps class>>globalFlapTabsWithID: (in category 'shared flaps') -----
- globalFlapTabsWithID: aFlapID
- 	"Answer all flap tabs whose ids start with the given id"
- 
- 	^ self globalFlapTabsIfAny select:
- 		[:aFlapTab |
- 			(aFlapTab flapID = aFlapID) or: [FlapTab givenID: aFlapTab flapID matches: aFlapID]]
- 
- "Flaps globalFlapTabsWithID: 'Stack Tools'"!

Item was removed:
- ----- Method: Flaps class>>globalFlapWithIDEnabledString: (in category 'menu support') -----
- globalFlapWithIDEnabledString: aFlapID
- 	"Answer the string to be shown in a menu to represent the status of the givne flap regarding whether it it should be shown in this project."
- 
- 	| aFlapTab wording |
- 	aFlapTab := self globalFlapTabWithID: aFlapID.
- 	wording := aFlapTab ifNotNil: [aFlapTab wording] ifNil: ['(',  aFlapID, ')'].
- 	^ (Project current isFlapIDEnabled: aFlapID)
- 		ifTrue:
- 			['<on>', wording]
- 		ifFalse:
- 			['<off>', wording]!

Item was removed:
- ----- Method: Flaps class>>initialize (in category 'class initialization') -----
- initialize
- 	self initializeFlapsQuads!

Item was removed:
- ----- Method: Flaps class>>initializeFlapsQuads (in category 'flaps registry') -----
- initializeFlapsQuads
- 	"initialize the list of dynamic flaps quads.
- 	self initializeFlapsQuads"
- 	FlapsQuads := nil. 
- 	self registeredFlapsQuads at: 'PlugIn Supplies' put: self defaultsQuadsDefiningPlugInSuppliesFlap;
- 		 at: 'Stack Tools' put: self defaultsQuadsDefiningStackToolsFlap;
- 		 at: 'Supplies' put: self defaultsQuadsDefiningSuppliesFlap;
- 		 at: 'Tools' put: self defaultsQuadsDefiningToolsFlap;
- 		 at: 'Widgets' put: self defaultsQuadsDefiningWidgetsFlap..
- 	^ self registeredFlapsQuads!

Item was removed:
- ----- Method: Flaps class>>initializeStandardFlaps (in category 'predefined flaps') -----
- initializeStandardFlaps
- 	"Initialize the standard default out-of-box set of global flaps. This method creates them and places them in my class variable #SharedFlapTabs, but does not itself get them displayed."
- 
- 	SharedFlapTabs := nil.
- 	self addStandardFlaps!

Item was removed:
- ----- Method: Flaps class>>makeNavigatorFlapResembleGoldenBar (in category 'miscellaneous') -----
- makeNavigatorFlapResembleGoldenBar
- 	"At explicit request, make the flap-based navigator resemble the golden bar.  No senders in the image, but sendable from a doit"
- 
- 	"Flaps makeNavigatorFlapResembleGoldenBar"
- 
- 	Preferences setPreference: #classicNavigatorEnabled toValue: false.
- 	Preferences setPreference: #showProjectNavigator toValue: false.
- 	(self globalFlapTabWithID: 'Navigator' translated) ifNil:
- 		[SharedFlapTabs add: self newNavigatorFlap delete].
- 	self enableGlobalFlapWithID: 'Navigator' translated.
- 	Preferences setPreference: #navigatorOnLeftEdge toValue: true.
- 	(self globalFlapTabWithID: 'Navigator' translated) arrangeToPopOutOnMouseOver: true.
- 	Project current world addGlobalFlaps.
- 	self doAutomaticLayoutOfFlapsIfAppropriate.
- 	Project current assureNavigatorPresenceMatchesPreference.	!

Item was removed:
- ----- Method: Flaps class>>newFlapTitled:onEdge: (in category 'new flap') -----
- newFlapTitled: aString onEdge: anEdge
- 	"Create a new flap with the given title and place it on the given edge"
- 
- 	^ self newFlapTitled: aString onEdge: anEdge inPasteUp: self currentWorld
- !

Item was removed:
- ----- Method: Flaps class>>newFlapTitled:onEdge:inPasteUp: (in category 'new flap') -----
- newFlapTitled: aString onEdge: anEdge inPasteUp: aPasteUpMorph
- 	"Add a flap with the given title, placing it on the given edge, in the given pasteup"
- 
- 	| aFlapBody aFlapTab  |
- 	aFlapBody := PasteUpMorph newSticky.
- 	aFlapTab := FlapTab new referent: aFlapBody.
- 	aFlapTab setName: aString edge: anEdge color: (Color r: 0.516 g: 0.452 b: 1.0).
- 
- 	anEdge == #left ifTrue:
- 		[aFlapTab position: (aPasteUpMorph left @ aPasteUpMorph top).
- 		aFlapBody extent: (200 @ aPasteUpMorph height)].
- 	anEdge == #right ifTrue:
- 		[aFlapTab position: ((aPasteUpMorph right - aFlapTab width) @ aPasteUpMorph top).
- 		aFlapBody extent: (200 @ aPasteUpMorph height)].
- 	anEdge == #top ifTrue:
- 		[aFlapTab position: ((aPasteUpMorph left + 50) @ aPasteUpMorph top).
- 		aFlapBody extent: (aPasteUpMorph width @ 200)].
- 	anEdge == #bottom ifTrue:
- 		[aFlapTab position: ((aPasteUpMorph left + 50) @ (aPasteUpMorph bottom - aFlapTab height)).
- 		aFlapBody extent: (aPasteUpMorph width @ 200)].
- 
- 	aFlapBody
- 		beFlap: true;
- 		color: self defaultColorForFlapBackgrounds;
- 		changeTableLayout.
- 	^ aFlapTab!

Item was removed:
- ----- Method: Flaps class>>newLoneSuppliesFlap (in category 'predefined flaps') -----
- newLoneSuppliesFlap
- 	"Answer a fully-instantiated flap named 'Supplies' to be placed at the bottom of the screen, for use when it is the only flap shown upon web launch.  We're still evidently nurturing this method along, but it is a disused branch, whose lone sender has no senders..."
- 
- 	|  aFlapTab aStrip leftEdge |  "Flaps setUpSuppliesFlapOnly"
- 	aStrip := PartsBin newPartsBinWithOrientation: #leftToRight andColor: Color red muchLighter from:	 {
- 
- 	{#TrashCanMorph. #new	. 'Trash' translatedNoop. 'A tool for discarding objects' translatedNoop}.	
- 	{#ScriptingSystem. #scriptControlButtons. 'Status'	translatedNoop. 'Buttons to run, stop, or single-step scripts' translatedNoop}.
- 	{#AllScriptsTool.    #allScriptsToolForActiveWorld. 'All Scripts' translatedNoop. 'A tool that lets you control all the running scripts in your world' translatedNoop}.
- 
- 	{#PaintInvokingMorph. #new. 'Paint' translatedNoop.	'Drop this into an area to start making a fresh painting there' translatedNoop}.
- 	{#RectangleMorph. #authoringPrototype. 'Rectangle' translatedNoop. 'A rectangle' translatedNoop}.
- 	{#RectangleMorph. #roundRectPrototype. 'RoundRect'	 translatedNoop. 'A rectangle with rounded corners' translatedNoop}.
- 	{#EllipseMorph.	#authoringPrototype.	'Ellipse' translatedNoop. 'An ellipse or circle' translatedNoop}.
- 	{#StarMorph. 	#authoringPrototype.	'Star' translatedNoop. 	'A star' translatedNoop}.
- 	{#PolygonMorph.	#curvePrototype.	'Curve'	translatedNoop. 'A curve' translatedNoop}.
- 	{#PolygonMorph	. #authoringPrototype.	'Polygon' translatedNoop. 'A straight-sided figure with any number of sides' translatedNoop}.
- 	{#TextMorph	.	#authoringPrototype. 	'Text' translatedNoop.	'Text that you can edit into anything you desire.' translatedNoop}.
- 	{#SimpleSliderMorph	.	#authoringPrototype.	'Slider' translatedNoop.	'A slider for showing and setting numeric values.' translatedNoop}.
- 	{#JoystickMorph	.	#authoringPrototype.	'Joystick' translatedNoop. 	'A joystick-like control' translatedNoop}.
- 	{#ScriptingSystem.	#prototypicalHolder.		'Holder'	translatedNoop.		'A place for storing alternative pictures in an animation, etc.' translatedNoop}.
- "	{#ScriptableButton.	#authoringPrototype.	'Button'	 translatedNoop.		'A Scriptable button' translatedNoop}."
- 	{#PasteUpMorph.	#authoringPrototype.	'Playfield' translatedNoop.	'A place for assembling parts or for staging animations' translatedNoop}.
- 	{#BookMorph.		#authoringPrototype.	'Book' translatedNoop.		'A multi-paged structure' translatedNoop}.
- 	{#TabbedPalette.		#authoringPrototype.	'Tabs' translatedNoop.		'A structure with tabs' translatedNoop}.
- 
- 	{#RecordingControls.	#authoringPrototype.	'Sound Recorder' translatedNoop. 'A device for making sound recordings.' translatedNoop}.
- 	{#MagnifierMorph.	#newRound	.			'Magnifier' translatedNoop.		'A magnifying glass' translatedNoop}.
- 
- 	{#ImageMorph.		#authoringPrototype.	'Picture' translatedNoop. 	'A non-editable picture of something' translatedNoop}.
- 	{#ClockMorph.		#authoringPrototype,	'Clock' translatedNoop, 	'A simple digital clock' translatedNoop}.
- 	{#BookMorph,		#previousPageButton,	'Previous' translatedNoop, 'A button that takes you to the previous page' translatedNoop}.
- 	{#BookMorph,		#nextPageButton,		'Next' translatedNoop,	'A button that takes you to the next page' translatedNoop}.
- }.
- 
- 	aFlapTab := FlapTab new referent: aStrip beSticky.
- 	aFlapTab setName: 'Supplies' translated edge: #bottom color: Color red lighter.
- 
- 	aStrip extent: self currentWorld width @ 78.
- 	leftEdge := ((Display width - (16  + aFlapTab width)) + 556) // 2.
- 
- 	aFlapTab position: (leftEdge @ (self currentWorld height - aFlapTab height)).
- 
- 	aStrip beFlap: true.
- 	aStrip autoLineLayout: true.
- 	
- 	^ aFlapTab!

Item was removed:
- ----- Method: Flaps class>>newNavigatorFlap (in category 'predefined flaps') -----
- newNavigatorFlap
- 	"Answer a newly-created flap which adheres to the bottom edge of the screen and which holds the project navigator controls. "
- 
- 	|  aFlapTab navBar aFlap |
- 	navBar := ProjectNavigationMorph preferredNavigator new addButtons.
- 	aFlap := PasteUpMorph newSticky borderWidth: 0;
- 			extent: navBar extent + (0 at 20);
- 			color: (Color orange alpha: 0.8);
- 			beFlap: true;
- 			addMorph: navBar beSticky.
- 	aFlap hResizing: #shrinkWrap; vResizing: #shrinkWrap.
- 	aFlap useRoundedCorners.
- 	aFlap setNameTo: 'Navigator Flap' translated.
- 	navBar fullBounds.  "to establish width"
- 	
- 	aFlapTab := FlapTab new referent: aFlap.
- 	aFlapTab setName: 'Navigator' translated edge: #bottom color: Color orange.
- 	aFlapTab position: ((navBar width // 2) - (aFlapTab width // 2))
- 					@ (self currentWorld height - aFlapTab height).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Navigator' translated "
- !

Item was removed:
- ----- Method: Flaps class>>newObjectsFlap (in category 'predefined flaps') -----
- newObjectsFlap
- 	"Answer a fully-instantiated flap named 'Objects' to be placed at the top of the screen."
- 
- 	|  aFlapTab anObjectsTool |
- 	anObjectsTool := ObjectsTool new.
- 	anObjectsTool initializeForFlap.
- 
- 	aFlapTab := FlapTab new referent: anObjectsTool beSticky.
- 	aFlapTab setName: 'Objects' translated edge: #top color: Color red lighter.
- 	aFlapTab position: ((Display width - (aFlapTab width + 22)) @ 0).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	anObjectsTool extent: self currentWorld width @ 200.
- 	anObjectsTool beFlap: true.
- 	anObjectsTool color: Color red muchLighter.
- 	anObjectsTool clipSubmorphs: true.
- 
- 	anObjectsTool showCategories.
- 
- 	^ aFlapTab!

Item was removed:
- ----- Method: Flaps class>>newPaintingFlap (in category 'predefined flaps') -----
- newPaintingFlap
- 	"Add a flap with the paint palette in it"
- 
- 	| aFlap aFlapTab  |
- 	"Flaps reinstateDefaultFlaps. Flaps newPaintingFlap"
- 
- 	aFlap := PasteUpMorph new borderWidth: 0.
- 	aFlap color: Color transparent.
- 	aFlap layoutPolicy: TableLayout new.
- 	aFlap hResizing: #shrinkWrap.
- 	aFlap vResizing: #shrinkWrap.
- 	aFlap cellPositioning: #topLeft.
- 	aFlap clipSubmorphs: false.
- 
- 	aFlap beSticky. "really?!!"
- 	aFlap addMorphFront: PaintBoxMorph new.
- 	aFlap beFlap: true.
- 	aFlap fullBounds. "force layout"
- 
- 	aFlapTab := FlapTab new referent: aFlap.
- 	aFlapTab setNameTo: 'Painting' translated.
- 	aFlapTab setProperty: #priorWording toValue: 'Paint' translated.
- 	aFlapTab useGraphicalTab.
- 	aFlapTab removeAllMorphs.
- 	aFlapTab setProperty: #paintingFlap toValue: true.
- 	aFlapTab addMorphFront: 
- 		"(SketchMorph withForm: (ScriptingSystem formAtKey: #PaintingFlapPic))"
- 		self paintFlapButton.
- 	aFlapTab cornerStyle: #rounded.
- 	aFlapTab edgeToAdhereTo: #right.
- 	aFlapTab setToPopOutOnDragOver: false.
- 	aFlapTab setToPopOutOnMouseOver: false.
- 	aFlapTab on: #mouseUp send: #startOrFinishDrawing: to: aFlapTab.
- 	aFlapTab setBalloonText:'Click here to start or finish painting.' translated.
- 
- 	aFlapTab fullBounds. "force layout"
- 	aFlapTab position: (0 at 6).
- 	self currentWorld addMorphFront: aFlapTab.  
- 	^ aFlapTab!

Item was removed:
- ----- Method: Flaps class>>newSqueakFlap (in category 'predefined flaps') -----
- newSqueakFlap
- 	"Answer a new default 'Squeak' flap for the left edge of the screen"
- 
- 	| aFlap aFlapTab aButton aClock buttonColor anOffset bb aFont |
- 	aFlap := PasteUpMorph newSticky borderWidth: 0.
- 	aFlapTab := FlapTab new referent: aFlap.
- 	aFlapTab setName: 'Squeak' translated edge: #left color: Color brown lighter lighter.
- 	aFlapTab position: (0 @ ((Display height - aFlapTab height) // 2)).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	aFlap cellInset: 14 at 14.
- 	aFlap beFlap: true.
- 	aFlap color: (Color brown muchLighter lighter "alpha: 0.3").
- 	aFlap extent: 150 @ self currentWorld height.
- 	aFlap layoutPolicy: TableLayout new.
- 	aFlap wrapCentering: #topLeft.
- 	aFlap layoutInset: 2.
- 	aFlap listDirection: #topToBottom.
- 	aFlap wrapDirection: #leftToRight.
- 
- 	"self addProjectNavigationButtonsTo: aFlap."
- 	anOffset := 16.
- 
- 	aClock := ClockMorph newSticky.
- 	aClock color: Color red.
- 	aClock showSeconds: false.
- 	aClock font: (TextStyle default fontAt: 3).
- 	aClock step.
- 	aClock setBalloonText: 'The time of day.  If you prefer to see seconds, check out my menu.' translated.
- 	aFlap addCenteredAtBottom: aClock offset: anOffset.
- 
- 	buttonColor :=  Color cyan muchLighter.
- 	bb := SimpleButtonMorph new target: Smalltalk.
- 	bb color: buttonColor.
- 	aButton := bb copy.
- 	aButton actionSelector: #saveSession.
- 	aButton setBalloonText: 'Make a complete snapshot of the current state of the image onto disk.' translated.
- 	aButton label: 'save' translated font: (aFont := ScriptingSystem fontForTiles).
- 	aFlap addCenteredAtBottom: aButton offset: anOffset.
- 
- 	aButton := bb copy target: MCMcmUpdater.
- 	aButton actionSelector: #updateFromServer.
- 	aButton label: 'load code updates' translated font: aFont.
- 	aButton color: buttonColor.
- 	aButton setBalloonText: 'Check the Squeak server for any new code updates, and load any that are found.' translated.
- 	aFlap addCenteredAtBottom: aButton offset: anOffset.
- 
- 	aButton := SimpleButtonMorph new target: Smalltalk; actionSelector: #aboutThisSystem;
- 		label: 'about this system' translated font: aFont.
- 	aButton color: buttonColor.
- 	aButton setBalloonText: 'click here to find out version information' translated.
- 	aFlap addCenteredAtBottom: aButton offset: anOffset.
- 
- 	aFlap addCenteredAtBottom: (Preferences themeChoiceButtonOfColor: buttonColor font: aFont) offset: anOffset.
- 
- 	aButton := TrashCanMorph newSticky.
- 	aFlap addCenteredAtBottom: aButton offset: anOffset.
- 	aButton startStepping.
- 
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Squeak' translated "!

Item was removed:
- ----- Method: Flaps class>>newStackToolsFlap (in category 'predefined flaps') -----
- newStackToolsFlap
- 	"Add a flap with stack tools in it"
- 
- 	| aFlapTab aStrip |
- 	aStrip := PartsBin newPartsBinWithOrientation: #leftToRight
- 		andColor: (Color red muchLighter "alpha: 0.2") from: self quadsDefiningStackToolsFlap.
- 
- 	aFlapTab := FlapTab new referent: aStrip beSticky.
- 	aFlapTab setName: 'Stack Tools' translated edge: #bottom color: Color brown lighter lighter.
- 	aFlapTab position: ((Display width - (aFlapTab width + 226)) @ (self currentWorld height - aFlapTab height)).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	aStrip extent: self currentWorld width @ 78.
- 	aStrip beFlap: true.
- 	aStrip autoLineLayout: true.
- 	aStrip extent: self currentWorld width @ 70.
- 
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Stack Tools' translated"!

Item was removed:
- ----- Method: Flaps class>>newSuppliesFlap (in category 'predefined flaps') -----
- newSuppliesFlap
- 	"Answer a fully-instantiated flap named 'Supplies' to be placed at the bottom of the screen; this is for the non-plug-in-version"
- 
- 	^ self newSuppliesFlapFromQuads: self quadsDefiningSuppliesFlap positioning: #right!

Item was removed:
- ----- Method: Flaps class>>newSuppliesFlapFromQuads:positioning: (in category 'predefined flaps') -----
- newSuppliesFlapFromQuads: quads positioning: positionSymbol
- 	"Answer a fully-instantiated flap named 'Supplies' to be placed at the bottom of the screen.  Use #center as the positionSymbol to have it centered at the bottom of the screen, or #right to have it placed off near the right edge."
- 
- 	|  aFlapTab aStrip hPosition |
- 	(Smalltalk classNamed: 'SugarNavigatorBar') ifNotNil: [:c |
- 		c showSugarNavigator ifTrue: [
- 			^ self newSuppliesFlapFromQuads: quads positioning: positionSymbol withPreviousEntries: nil]].
- 	aStrip := PartsBin newPartsBinWithOrientation: #leftToRight andColor: Color red muchLighter from:	 quads.
- 	"self twiddleSuppliesButtonsIn: aStrip."
- 	aFlapTab := FlapTab new referent: aStrip beSticky.
- 	aFlapTab setName: 'Supplies' translated edge: #bottom color: Color red lighter.
- 	hPosition := positionSymbol == #center
- 		ifTrue:
- 			[(Display width // 2) - (aFlapTab width // 2)]
- 		ifFalse:
- 			[Display width - (aFlapTab width + 22)].
- 	aFlapTab position: (hPosition @ (self currentWorld height - aFlapTab height)).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	aStrip extent: self currentWorld width @ 136.
- 	aStrip beFlap: true.
- 	aStrip autoLineLayout: true.
- 	
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Supplies' translated"!

Item was removed:
- ----- Method: Flaps class>>newToolsFlap (in category 'predefined flaps') -----
- newToolsFlap
- 	"Answer a newly-created flap which adheres to the right edge of the screen and which holds prototypes of standard tools."
- 
- 	|  aFlapTab aStrip |
- 	aStrip := PartsBin newPartsBinWithOrientation: #topToBottom andColor: (Color orange muchLighter alpha: 0.8) from: self quadsDefiningToolsFlap.
-  
- 	aFlapTab := FlapTab new referent: aStrip beSticky.
- 	aFlapTab setName: 'Tools' translated edge: #right color: Color orange lighter.
- 	aFlapTab position: (self currentWorld width - aFlapTab width) @ ((Display height - aFlapTab height) // 2).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	aStrip extent: (90 @ self currentWorld height).
- 	aStrip beFlap: true.
- 	
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Tools' translated "
- !

Item was removed:
- ----- Method: Flaps class>>newWidgetsFlap (in category 'predefined flaps') -----
- newWidgetsFlap
- 	"Answer a newly-created flap which adheres to the bottom edge of the screen and which holds prototypes of standard widgets. "
- 
- 	|  aFlapTab aStrip |
- 	aStrip := PartsBin newPartsBinWithOrientation: #leftToRight andColor: (Color blue muchLighter alpha: 0.8)
- 		from:	 self quadsDefiningWidgetsFlap.
- 
- 	aFlapTab := FlapTab new referent: aStrip beSticky.
- 	aFlapTab setName: 'Widgets' translated edge: #bottom color: Color blue lighter lighter.
- 	aFlapTab position: ((Display width - (aFlapTab width + 122)) @ (self currentWorld height - aFlapTab height)).
- 	aFlapTab setBalloonText: aFlapTab balloonTextForFlapsMenu.
- 
- 	aStrip extent: self currentWorld width @ 78.
- 	aStrip beFlap: true.
- 	aStrip autoLineLayout: true.
- 	
- 	^ aFlapTab
- 
- "Flaps replaceGlobalFlapwithID: 'Widgets' translated "
- !

Item was removed:
- ----- Method: Flaps class>>orientationForEdge: (in category 'miscellaneous') -----
- orientationForEdge: anEdge
- 	"Answer the orientation -- #horizontal or #vertical -- that corresponds to the edge symbol"
- 
- 	^ (#(left right) includes: anEdge)
- 		ifTrue:	[#vertical]
- 		ifFalse:	[#horizontal]!

Item was removed:
- ----- Method: Flaps class>>paintFlapButton (in category 'miscellaneous') -----
- paintFlapButton
- 	"Answer a button to serve as the paint flap"
- 
- 	| pb oldArgs brush myButton m |
- 	pb := PaintBoxMorph new submorphNamed: #paint:.
- 	pb
- 		ifNil:
- 			[(brush := Form extent: 16 at 16 depth: 16) fillColor: Color red]
- 		ifNotNil:
- 			[oldArgs := pb arguments.
- 			brush := oldArgs third.
- 			brush := brush copy: (2 at 0 extent: 42 at 38).
- 			brush := brush scaledToSize: brush extent // 2].
- 	myButton := BorderedMorph new.
- 	myButton color: (Color r: 0.833 g: 0.5 b: 0.0); borderStyle: (BorderStyle raised width: 2).
- 	myButton addMorph: (m := brush asMorph lock).
- 	myButton extent: m extent + (myButton borderWidth + 6).
- 	m position: myButton center - (m extent // 2).
- 	^ myButton
- 
- !

Item was removed:
- ----- Method: Flaps class>>positionNavigatorAndOtherFlapsAccordingToPreference (in category 'shared flaps') -----
- positionNavigatorAndOtherFlapsAccordingToPreference
- 	"Lay out flaps along the designated edge right-to-left, possibly positioning the navigator flap, exceptionally, on the left."
- 
- 	| ids |
- 	ids := Preferences navigatorOnLeftEdge ifTrue: [{'Navigator' translated}] ifFalse: [#()].
- 
- 	Flaps positionVisibleFlapsRightToLeftOnEdge: #bottom butPlaceAtLeftFlapsWithIDs: ids
- 
- "Flaps positionNavigatorAndOtherFlapsAccordingToPreference"!

Item was removed:
- ----- Method: Flaps class>>positionVisibleFlapsRightToLeftOnEdge:butPlaceAtLeftFlapsWithIDs: (in category 'shared flaps') -----
- positionVisibleFlapsRightToLeftOnEdge: edgeSymbol butPlaceAtLeftFlapsWithIDs: idList
- 	"Lay out flaps along the designated edge right-to-left, while laying left-to-right any flaps found in the exception list
- 
- 	Flaps positionVisibleFlapsRightToLeftOnEdge: #bottom butPlaceAtLeftFlapWithIDs: {'Navigator' translated. 'Supplies' translated}
- 	Flaps sharedFlapsAlongBottom"
- 
- 	| leftX flapList flapsOnRight flapsOnLeft |
- 	flapList := self globalFlapTabsIfAny select:
- 		[:aFlapTab | aFlapTab isInWorld and: [aFlapTab edgeToAdhereTo == edgeSymbol]].
- 	flapsOnLeft := OrderedCollection new.
- 	flapsOnRight := OrderedCollection new.
- 	
- 	flapList do: [:fl | 
- 		(idList includes: fl flapID)
- 			ifTrue: [ flapsOnLeft addLast: fl ]
- 			ifFalse: [ flapsOnRight addLast: fl ] ].
- 
- 	leftX := Project current world width - 15.
- 
- 	flapsOnRight 
- 		sort: [:f1 :f2 | f1 left > f2 left];
- 		do: [:aFlapTab |
- 			aFlapTab right: leftX - 3.
- 			leftX := aFlapTab left].
- 
- 	leftX := Project current world left.
- 
- 	flapsOnLeft
- 		sort: [:f1 :f2 | f1 left > f2 left];
- 		do: [:aFlapTab |
- 			aFlapTab left: leftX + 3.
- 			leftX := aFlapTab right].
- 
- 	flapList do:
- 		[:ft | ft computeEdgeFraction.
- 		ft flapID = 'Navigator' translated ifTrue:
- 			[ft referent left: (ft center x - (ft referent width//2) max: 0)]]!

Item was removed:
- ----- Method: Flaps class>>possiblyReplaceEToyFlaps (in category 'construction support') -----
- possiblyReplaceEToyFlaps
- 	"If in eToyFriendly mode, and if it's ok to reinitialize flaps, replace the existing flaps with up-too-date etoy flaps.  Caution:  this is destructive of existing flaps.  If preserving the contents of existing flaps is important, set the preference 'okToReinitializeFlaps' to true"
- 
- 	PartsBin thumbnailForPartsDescription: StickyPadMorph descriptionForPartsBin.  "Puts StickyPadMorph's custom icon back in the cache which typically will have been called"
- 	(Preferences eToyFriendly and: [Preferences okToReinitializeFlaps]) ifTrue:
- 		[Flaps disableGlobalFlaps: false.
- 		Flaps addAndEnableEToyFlaps.
- 		Smalltalk isMorphic ifTrue: [Project current world enableGlobalFlaps]].
- 	"PartsBin clearThumbnailCache"
- 
- "Flaps possiblyReplaceEToyFlaps"!

Item was removed:
- ----- Method: Flaps class>>quadsDefiningPlugInSuppliesFlap (in category 'predefined flaps') -----
- quadsDefiningPlugInSuppliesFlap
- 	"Answer a list of quads which define the objects to appear in the default Supplies flap used in the Plug-in image"
- 
- 	^ self registeredFlapsQuadsAt: 'PlugIn Supplies'!

Item was removed:
- ----- Method: Flaps class>>quadsDefiningStackToolsFlap (in category 'predefined flaps') -----
- quadsDefiningStackToolsFlap
- 	"Answer a structure defining the items on the default system Stack Tools flap"
- 
- 	^ self registeredFlapsQuadsAt: 'Stack Tools'
- 
- 	"Flaps replaceGlobalFlapwithID: 'Stack Tools'"!

Item was removed:
- ----- Method: Flaps class>>quadsDefiningSuppliesFlap (in category 'predefined flaps') -----
- quadsDefiningSuppliesFlap
- 	"Answer a list of quads which define the objects to appear in the default Supplies flap"
- 
- 	^ self registeredFlapsQuadsAt: 'Supplies'!

Item was removed:
- ----- Method: Flaps class>>quadsDefiningToolsFlap (in category 'predefined flaps') -----
- quadsDefiningToolsFlap
- 	"Answer a structure defining the default Tools flap"
- 
- 	^ self registeredFlapsQuadsAt: 'Tools'!

Item was removed:
- ----- Method: Flaps class>>quadsDefiningWidgetsFlap (in category 'predefined flaps') -----
- quadsDefiningWidgetsFlap
- 	"Answer a structure defining the default Widgets flap"
- 
- 	^ self registeredFlapsQuadsAt: 'Widgets'!

Item was removed:
- ----- Method: Flaps class>>quadsDeiningScriptingFlap (in category 'predefined flaps') -----
- quadsDeiningScriptingFlap
- 	"Answer a structure defining the default items in the Scripting flap"
- 
- 	^ self registeredFlapsQuadsAt: 'Scripting'!

Item was removed:
- ----- Method: Flaps class>>registerQuad:forFlapNamed: (in category 'flaps registry') -----
- registerQuad: aQuad forFlapNamed: aLabel
- 	"If any previous registration of the same label string is already known, delete the old one."
- 
- 	"aQuad received must be an array of the form {TargetObject. #command label  'A Help String'} 
- 
- Flaps registerQuad: #(FileList2 openMorphicViewInWorld	'Enhanced File List'	'A nicer File List.')
- 	forFlapNamed: 'Tools' "
- 
- 	self unregisterQuad: aQuad forFlapNamed: aLabel.
- 	(self registeredFlapsQuads at: aLabel ifAbsent:[^self]) add: aQuad!

Item was removed:
- ----- Method: Flaps class>>registeredFlapsQuads (in category 'flaps registry') -----
- registeredFlapsQuads
- 	"Answer the list of dynamic flaps quads"
- 	
- 	FlapsQuads ifNil: [FlapsQuads := Dictionary new].
- 	^ FlapsQuads
- 
- " FlapsQuads := nil. "!

Item was removed:
- ----- Method: Flaps class>>registeredFlapsQuadsAt: (in category 'flaps registry') -----
- registeredFlapsQuadsAt: aLabel
- 	"Answer the list of dynamic flaps quads at aLabel"
- 
- 	^ (self registeredFlapsQuads at: aLabel ifAbsent:[^#()])
- 		removeAllSuchThat: [:q | (self environment includesKey: q first) not or: [(self environment at: q first) isNil]]
- !

Item was removed:
- ----- Method: Flaps class>>reinstateDefaultFlaps (in category 'flap mechanics') -----
- reinstateDefaultFlaps
- 	"Remove all existing 'standard' global flaps clear the global list, and and add fresh ones.  To be called by doits in updates etc.  This is a radical step, but it does *not* clobber non-standard global flaps or local flaps.  To get the effect of the *former* version of this method, call Flaps freshFlapsStart"
- 
- 	"Flaps reinstateDefaultFlaps"
- 	self globalFlapTabsIfAny do:
- 		[:aFlapTab |
- 			({
- 				
- 				'Squeak' translated.
- 				'Menu' translated.
- 				'Widgets' translated.
- 				'Tools' translated.
- 				'Supplies' translated.
- 				
- 				'Objects' translated.
- 				'Navigator' translated
- 			  } includes: aFlapTab flapID) ifTrue:
- 				[self removeFlapTab: aFlapTab keepInList: false]].
- 
- 	"The following reduces the risk that flaps will be created with variant IDs
- 		such as 'Stack Tools2', potentially causing some shared flap logic to fail."
- 		"Smalltalk garbageCollect."  "-- see if we are OK without this"
- 
- 	self addStandardFlaps.
- 	"self disableGlobalFlapWithID: 'Scripting'.
- 	self disableGlobalFlapWithID: 'Objects'."
- 	self currentWorld addGlobalFlaps.
- 	self currentWorld reformulateUpdatingMenus.
- !

Item was removed:
- ----- Method: Flaps class>>removeDuplicateFlapTabs (in category 'shared flaps') -----
- removeDuplicateFlapTabs
- 	"Remove flaps that were accidentally added multiple times"
- 	"Flaps removeDuplicateFlapTabs"
- 	| tabs duplicates |
- 	SharedFlapTabs copy ifNil: [^self].
- 	tabs := SharedFlapTabs copy.
- 	duplicates := Set new.
- 	tabs do: [:tab | | same |
- 		same := tabs select: [:each | each wording = tab wording].
- 		same isEmpty not
- 			ifTrue: [
- 				same removeFirst.
- 				duplicates addAll: same]].
- 	SharedFlapTabs removeAll: duplicates!

Item was removed:
- ----- Method: Flaps class>>removeFlapTab:keepInList: (in category 'flap mechanics') -----
- removeFlapTab: aFlapTab keepInList: aBoolean
- 	"Remove the given flap tab from the screen, and, if aBoolean is true, also from the global list"
- 
- 	(SharedFlapTabs ~~ nil and: [SharedFlapTabs includes: aFlapTab])
- 		ifTrue:
- 			[aBoolean ifFalse: [self removeFromGlobalFlapTabList: aFlapTab]].
- 	aFlapTab ifNotNil:
- 		[aFlapTab referent delete.
- 		aFlapTab delete]!

Item was removed:
- ----- Method: Flaps class>>removeFromGlobalFlapTabList: (in category 'miscellaneous') -----
- removeFromGlobalFlapTabList: aFlapTab
- 	"If the flap tab is in the global list, remove it"
- 
- 	SharedFlapTabs remove: aFlapTab ifAbsent: []!

Item was removed:
- ----- Method: Flaps class>>replaceGlobalFlapwithID: (in category 'replacement') -----
- replaceGlobalFlapwithID: flapID
- 	"If there is a global flap with flapID, replace it with an updated one."
- 
- 	| replacement tabs |
- 	(tabs := self globalFlapTabsWithID: flapID) size = 0 ifTrue: [^ self].
- 	tabs do: [:tab |
- 		self removeFlapTab: tab keepInList: false].
- 	flapID = 'Stack Tools' translated ifTrue: [replacement := self newStackToolsFlap].
- 	flapID = 'Supplies' translated ifTrue: [replacement := self newSuppliesFlapFromQuads: 
- 		(Preferences eToyFriendly
- 			ifFalse: [self quadsDefiningSuppliesFlap]
- 			ifTrue: [self quadsDefiningPlugInSuppliesFlap]) positioning: #right].
- 	flapID = 'Tools' translated ifTrue: [replacement := self newToolsFlap].
- 	flapID = 'Widgets' translated ifTrue: [replacement := self newWidgetsFlap].
- 	flapID = 'Navigator' translated ifTrue: [replacement := self newNavigatorFlap].
- 	flapID = 'Squeak' translated ifTrue: [replacement := self newSqueakFlap].
- 	replacement ifNil: [^ self].
- 	self addGlobalFlap: replacement.
- 	self currentWorld ifNotNil: [self currentWorld addGlobalFlaps]
- 
- "Flaps replaceFlapwithID: 'Widgets' translated "!

Item was removed:
- ----- Method: Flaps class>>replacePartSatisfying:inGlobalFlapSatisfying:with: (in category 'replacement') -----
- replacePartSatisfying: elementBlock inGlobalFlapSatisfying: flapBlock with: replacement
- 	"If any global flap satisfies flapBlock, look in it for a part satisfying elementBlock; if such a part is found, replace it with the replacement morph, make sure the flap's layout is made right, etc."
- 
- 	| aFlapTab flapPasteUp anElement |
- 	aFlapTab := self globalFlapTabsIfAny detect: flapBlock ifNone: [^ self].
- 	flapPasteUp := aFlapTab referent.
- 	anElement := flapPasteUp submorphs detect: elementBlock ifNone: [^ self].
- 	flapPasteUp replaceSubmorph: anElement by: replacement.
- 	flapPasteUp replaceTallSubmorphsByThumbnails; setPartsBinStatusTo: true.
- 
- "Flaps replacePartSatisfying: [:el |  (el isKindOf: MorphThumbnail) and: [(el morphRepresented isKindOf: SystemWindow) and: [el morphRepresented label = 'scripting area']]]
- inGlobalFlapSatisfying: [:fl | (fl submorphs size > 0) and:  [(fl submorphs first isKindOf: TextMorph) and: [(fl submorphs first contents string copyWithout: Character cr) = 'Tools']]] with: ScriptingSystem newScriptingSpace"!

Item was removed:
- ----- Method: Flaps class>>replacePartSatisfying:inGlobalFlapWithID:with: (in category 'replacement') -----
- replacePartSatisfying: elementBlock inGlobalFlapWithID: aFlapID with: replacement
- 	"If a global flapl exists with the given flapID, look in it for a part satisfying elementBlock; if such a part is found, replace it with the replacement morph, make sure the flap's layout is made right, etc."
- 
- 	^ self replacePartSatisfying: elementBlock inGlobalFlapSatisfying: [:fl | fl flapID = aFlapID] with: replacement!

Item was removed:
- ----- Method: Flaps class>>replaceToolsFlap (in category 'replacement') -----
- replaceToolsFlap
- 	"if there is a global tools flap, replace it with an updated one."
- 
- 	self replaceGlobalFlapwithID: 'Tools' translated
- 
- "Flaps replaceToolsFlap"!

Item was removed:
- ----- Method: Flaps class>>setUpSuppliesFlapOnly (in category 'menu support') -----
- setUpSuppliesFlapOnly
- 	"Set up the Supplies flap as the only shared flap.  A special version formulated for this stand-alone use is used, defined in #newLoneSuppliesFlap"
- 
- 	| supplies |
- 	SharedFlapTabs isEmptyOrNil ifFalse:  "get rid of pre-existing guys if any"
- 		[SharedFlapTabs do:
- 			[:t | t referent delete.  t delete]].
- 
- 	SharedFlapsAllowed := true.
- 	SharedFlapTabs := OrderedCollection new.
- 	SharedFlapTabs add: (supplies := self newLoneSuppliesFlap).
- 	self enableGlobalFlapWithID: 'Supplies' translated.
- 	supplies setToPopOutOnMouseOver: false.
- 
- 	Smalltalk isMorphic ifTrue: [
- 		Project current world
- 			addGlobalFlaps;
- 			reformulateUpdatingMenus].!

Item was removed:
- ----- Method: Flaps class>>sharedFlapsAllowed (in category 'shared flaps') -----
- sharedFlapsAllowed
- 	"Answer whether the shared flaps feature is allowed in this system"
- 
- 	^ SharedFlapsAllowed ifNil: [SharedFlapsAllowed := SharedFlapTabs isEmptyOrNil not]!

Item was removed:
- ----- Method: Flaps class>>sharedFlapsAlongBottom (in category 'shared flaps') -----
- sharedFlapsAlongBottom
- 	"Put all shared flaps (except Painting which can't be moved) along the bottom"
- 	"Flaps sharedFlapsAlongBottom"
- 
- 	| leftX unordered ordered |
- 	unordered := self globalFlapTabsIfAny asIdentitySet.
- 	ordered := Array streamContents:
- 		[:s | {
- 				'Squeak' translated.
- 				'Navigator' translated.
- 				'Supplies' translated.
- 				'Widgets' translated.
- 				'Stack Tools' translated.
- 				'Tools' translated.
- 				'Painting' translated.
- 			} do:
- 			[:id | (self globalFlapTabWithID: id) ifNotNil:
- 				[:ft | unordered remove: ft.
- 				id = 'Painting' translated ifFalse: [s nextPut: ft]]]].
- 
- 	"Pace off in order from right to left, setting positions"
- 	leftX := Display width-15.
- 	ordered , unordered asArray reverseDo:
- 		[:ft | ft setEdge: #bottom.
- 		ft right: leftX - 3.  leftX := ft left].
- 
- 	"Put Nav Bar centered under tab if possible"
- 	(self globalFlapTabWithID: 'Navigator' translated) ifNotNil:
- 		[:ft | ft referent left: (ft center x - (ft referent width//2) max: 0)].
- 	self positionNavigatorAndOtherFlapsAccordingToPreference.
- !

Item was removed:
- ----- Method: Flaps class>>showSharedFlaps (in category 'menu support') -----
- showSharedFlaps
- 	"Answer whether shared flaps are currently showing.  Presumably it is in service of Alan's wishes to have flaps show sometimes on interior subprojects and sometomes on outer projects that Bob's CurrentProjectRefactoring is threaded into the logic here."
- 
- 	^ Project current showSharedFlaps!

Item was removed:
- ----- Method: Flaps class>>suppressFlapsString (in category 'menu support') -----
- suppressFlapsString
- 	"Answer the string to be shown in a menu to represent the suppress-flaps-in-this-project status"
- 
- 	^ Project current suppressFlapsString!

Item was removed:
- ----- Method: Flaps class>>twiddleSuppliesButtonsIn: (in category 'predefined flaps') -----
- twiddleSuppliesButtonsIn: aStrip
- 	"Munge item(s) in the strip whose names as seen in the parts bin should be different from the names to be given to resulting torn-off instances"
- 
- 	(aStrip submorphs detect: [:m | m target == StickyPadMorph] ifNone: [nil])
- 		ifNotNil:
- 			[:aButton | aButton arguments: {#newStandAlone.  'tear off'}]!

Item was removed:
- ----- Method: Flaps class>>unregisterQuad:forFlapNamed: (in category 'flaps registry') -----
- unregisterQuad: aQuad forFlapNamed: aLabel 
- 	"If any previous registration at the same label string has the same receiver-command,
- 	delete the old one."
- 	(self registeredFlapsQuadsAt: aLabel)
- 		removeAllSuchThat: [:q | q first = aQuad first
- 				and: [q second = aQuad second]]!

Item was removed:
- ----- Method: Flaps class>>unregisterQuadsWithReceiver: (in category 'flaps registry') -----
- unregisterQuadsWithReceiver: aReceiver 
- 	"delete all quads with receiver aReceiver."
- 	self registeredFlapsQuads
- 		do: [:assoc | assoc value
- 				removeAllSuchThat: [:q | (self environment at: (q first) ifAbsent:[nil]) = aReceiver ]]!

Item was removed:
- ----- Method: Flaps class>>unregisterQuadsWithReceiver:fromFlapNamed: (in category 'flaps registry') -----
- unregisterQuadsWithReceiver: aReceiver fromFlapNamed: aLabel
- 	"delete all quads with receiver aReceiver."
- 	(self registeredFlapsQuads at: aLabel) removeAllSuchThat: [:q | q first = aReceiver name]!

Item was removed:
- EllipseMorph subclass: #Flasher
- 	instanceVariableNames: 'onColor'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !Flasher commentStamp: '<historical>' prior: 0!
- A simple example - a circle that flashes.
- 
- The "onColor" instance variable indicates the color to use when "on",  A darker color is used to represent "off".
- 
- The #step method, called every 500ms. by default, alternatively makes the flasher show its "on" and its "off" color.!

Item was removed:
- ----- Method: Flasher class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	"Answer a description of the receiver for use in a parts bin"
- 
- 	^ self partName:	'Flasher' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop}
- 		documentation:	'A circle that flashes' translatedNoop!

Item was removed:
- ----- Method: Flasher>>initializeToStandAlone (in category 'parts bin') -----
- initializeToStandAlone
- 	"Initialize the flasher."
- 
- 	super initializeToStandAlone.
- 	self color: Color red.
- 	self onColor: Color red. 
- 	self borderWidth: 2.
- 	self extent: 25 at 25!

Item was removed:
- ----- Method: Flasher>>onColor (in category 'operations') -----
- onColor
- 	"Answer my onColor"
- 
- 	^ onColor ifNil: [onColor := Color red]!

Item was removed:
- ----- Method: Flasher>>onColor: (in category 'operations') -----
- onColor: aColor
- 	"Change my on color to be aColor"
- 
- 	onColor := aColor.
- 	self color: aColor!

Item was removed:
- ----- Method: Flasher>>step (in category 'stepping and presenter') -----
- step
- 	"Perform my standard periodic action"
- 
- 	super step.
- 	self color = self onColor
- 		ifTrue: [self color: (onColor alphaMixed: 0.5 with: Color black)]
- 		ifFalse: [self color: onColor]!

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

Item was removed:
- SketchMorph subclass: #FlexMorph
- 	instanceVariableNames: 'originalMorph borderWidth borderColor'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalMorphs'!

Item was removed:
- ----- Method: FlexMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	"super addCustomMenuItems: aCustomMenu hand: aHandMorph."
- 	aCustomMenu addLine.
- 	aCustomMenu add: 'update from original' translated action: #updateFromOriginal.
- 	aCustomMenu addList: {
- 						{'border color...' translated. #changeBorderColor:}.
- 						{'border width...' translated. #changeBorderWidth:}.
- 						}.
- 	aCustomMenu addLine.
- !

Item was removed:
- ----- Method: FlexMorph>>borderColor: (in category 'accessing') -----
- borderColor: aColor
- 	borderColor := aColor.
- 	self updateFromOriginal!

Item was removed:
- ----- Method: FlexMorph>>borderWidth: (in category 'accessing') -----
- borderWidth: width
- 	borderWidth := width asPoint.
- 	self updateFromOriginal!

Item was removed:
- ----- Method: FlexMorph>>changeBorderColor: (in category 'menus') -----
- changeBorderColor: evt
- 	| aHand |
- 	aHand := evt ifNotNil: [evt hand] ifNil: [self primaryHand].
- 	self changeColorTarget: self selector: #borderColor: originalColor: self borderColor hand: aHand.!

Item was removed:
- ----- Method: FlexMorph>>changeBorderWidth: (in category 'menus') -----
- changeBorderWidth: evt
- 	| handle origin aHand |
- 	aHand := evt ifNil: [self primaryHand] ifNotNil: [evt hand].
- 	origin := aHand position.
- 	handle := HandleMorph new forEachPointDo:
- 		[:newPoint | handle removeAllMorphs.
- 		handle addMorph:
- 			(LineMorph from: origin to: newPoint color: Color black width: 1).
- 		self borderWidth: (newPoint - origin) r asInteger // 5].
- 	aHand attachMorph: handle.
- 	handle startStepping!

Item was removed:
- ----- Method: FlexMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	originalForm := nil.  "Aggressively uncache the originalForm"
- 	^ super drawOn: aCanvas!

Item was removed:
- ----- Method: FlexMorph>>extent: (in category 'geometry') -----
- extent: newExtent
- 
- 	self loadOriginalForm.  "make sure it's not nil"
- 	^ super extent: newExtent!

Item was removed:
- ----- Method: FlexMorph>>form (in category 'accessing') -----
- form
- 
- 	self loadOriginalForm.  "make sure it's not nil"
- 	^ super form!

Item was removed:
- ----- Method: FlexMorph>>generateRotatedForm (in category 'drawing') -----
- generateRotatedForm
- 
- 	self loadOriginalForm.  "make sure it's not nil"
- 	^ super generateRotatedForm!

Item was removed:
- ----- Method: FlexMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	borderWidth := 2 at 2.
- 	borderColor := Color black.!

Item was removed:
- ----- Method: FlexMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 
- 	self loadOriginalForm.  "make sure it's not nil"
- 	^ super layoutChanged!

Item was removed:
- ----- Method: FlexMorph>>loadOriginalForm (in category 'private') -----
- loadOriginalForm
- 
- 	originalForm ifNil: [self updateFromOriginal].
- !

Item was removed:
- ----- Method: FlexMorph>>originalMorph (in category 'accessing') -----
- originalMorph
- 
- 	^ originalMorph!

Item was removed:
- ----- Method: FlexMorph>>originalMorph: (in category 'accessing') -----
- originalMorph: aMorph
- 
- 	originalMorph := aMorph.
- 	scalePoint := 0.25 at 0.25.
- 	self updateFromOriginal.!

Item was removed:
- ----- Method: FlexMorph>>releaseCachedState (in category 'caching') -----
- releaseCachedState
- 	"Clear cache of rotated, scaled Form."
- 
- 	originalForm := Form extent: 10 at 10.  "So super hibernate won't have to work hard
- 												but won't crash either."
- 	super releaseCachedState.
- 	rotatedForm := nil.
- 	originalForm := nil.!

Item was removed:
- ----- Method: FlexMorph>>updateFromOriginal (in category 'private') -----
- updateFromOriginal
- 
- 	| intermediateForm |
- 	intermediateForm := originalMorph imageForm offset: 0 at 0.
- 	intermediateForm border: intermediateForm boundingBox
- 		widthRectangle: (borderWidth corner: borderWidth+1)
- 		rule: Form over fillColor: borderColor.
- 	self form: intermediateForm.
- 	originalMorph fullReleaseCachedState!

Item was removed:
- AlignmentMorph subclass: #FloatingBookControlsMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Navigators'!

Item was removed:
- ----- Method: FloatingBookControlsMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: FloatingBookControlsMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self layoutInset: 0;
- 		 hResizing: #shrinkWrap;
- 		 vResizing: #shrinkWrap !

Item was removed:
- ----- Method: FloatingBookControlsMorph>>morphicLayerNumber (in category 'submorphs - layers') -----
- morphicLayerNumber
- 	"page controls are behind menus and balloons, but in front of most other stuff"
- 	
- 	^ self valueOfProperty: #morphicLayerNumber ifAbsent: [self class navigatorLayer]!

Item was removed:
- ----- Method: FloatingBookControlsMorph>>step (in category 'stepping and presenter') -----
- step
- 
- 	owner == self world ifFalse: [^ self].
- 	owner addMorphInLayer: self.
- 	self position: (owner bottomCenter) - ((self width//2)@self height)
- !

Item was removed:
- ----- Method: FloatingBookControlsMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 
- 	^1000!

Item was removed:
- ----- Method: FloatingBookControlsMorph>>wantsSteps (in category 'stepping and presenter') -----
- wantsSteps
- 
- 	^true!

Item was removed:
- ----- Method: Form class>>exampleColorSees (in category '*MorphicExtras-examples') -----
- exampleColorSees
- 	"Form exampleColorSees"
- 	"First column as above shows the sneaky red/yellow pirate sneaking up on the blue/peach galleon.
- 	Second column shows the 1bpp made from the red/yellow/transparent - white -> ignore this, black -> test this
- 	Third shows the hit area - where red touches blue - superimposed on the original scene.
- 	Fourth column is the tally of hits via the old algorithm
- 	Last column shows the tally of hits via the new prim"	
- 		
- 	| formA formB maskA  offset tally map intersection left top dCanvas sensitiveColor soughtColor index |
- 	formA := formB := maskA := offset := tally := map := intersection :=  nil. "just to shut up the compiler when testing"
- 	Project current world restoreMorphicDisplay; doOneCycle.
- 	
- 	sensitiveColor := Color red.
- 	soughtColor := Color blue.
- 
- 	top := 50.
- 	dCanvas := FormCanvas on: Display.
- 	-50 to: 80 by: 10 do:[:p|
- 		offset:= p at 0. "vary this to check different states"
- 		left := 10.
- 
- 		formA := (Form extent: 100 at 50 depth: 32) asFormOfDepth: 16 "so we can try original forms of other depths".
- 		formB := Form extent: 100 at 50 depth: 32.
- 
- 		"make a red square in the middle of the form"
- 		(FormCanvas on: formA) fillRectangle: (25 at 25 extent: 50 at 5) fillStyle: sensitiveColor.
- 		(FormCanvas on: formA) fillRectangle: (25 at 30 extent: 50 at 5) fillStyle: Color transparent.
- 		(FormCanvas on: formA) fillRectangle: (25 at 35 extent: 50 at 50) fillStyle: Color yellow.
- 		"formA displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		"make a blue block on the right half of the form"
- 		(FormCanvas on: formB) fillRectangle: (50 at 0 extent: 50 at 100) fillStyle: soughtColor.
- 		(FormCanvas on: formB) fillRectangle: (60 at 0 extent: 10 at 100) fillStyle: Color palePeach.
- 		"formB displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		intersection := (formA boundingBox translateBy: offset) intersect: (formB boundingBox).
- 
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150.
- 	
- 		maskA := Form extent: intersection extent depth: 1.
- 
- 		map := Bitmap new: (1 bitShift: (formA depth min: 15)).
- 		map at: (index := sensitiveColor indexInMap: map) put: 1.
- 
- 		maskA copyBits: (intersection translateBy:  offset negated) from: formA at: 0 at 0 colorMap: map.
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.	left := left + 150.
- 
- 		"intersect world pixels of the color we're looking for with sensitive pixels mask"
- 		map at: index put: 0.  "clear map and reuse it"
- 		map at: (soughtColor indexInMap: map) put: 1.
- 
- 		maskA
- 	 		copyBits: intersection
- 			from: formB at: 0 at 0 clippingBox: formB boundingBox
- 			rule: Form and
- 			fillColor: nil
- 			map: map.
- 
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 170.
- 		
- 		(maskA tallyPixelValues at: 2) asString asDisplayText displayOn: Display at: left@(top +20).
- 		left := left + 70.
- 		
- 		"now try using the new primitive"
- 		tally := (BitBlt
- 			destForm: formB
- 			sourceForm: formA
- 			fillColor: nil
- 			combinationRule: 3 "really ought to work with nil but prim code checks"
- 			destOrigin: intersection origin
- 			sourceOrigin: (offset negated max: 0 at 0)
- 			extent: intersection extent 
- 			clipRect: intersection)
- 				primCompareColor: ((sensitiveColor pixelValueForDepth: formA depth) ) to: ((soughtColor pixelValueForDepth: formB depth) ) test: (Form compareMatchColor bitOr: Form compareTallyFlag).
- 		tally  asString asDisplayText displayOn: Display at: left@(top +20).
- 		top:= top + 60]!

Item was removed:
- ----- Method: Form class>>exampleTouchTest (in category '*MorphicExtras-examples') -----
- exampleTouchTest
- 	"Form exampleTouchTest"
- 	"Demonstrate the algorithm used in Scratch code to determine if a sprite's non-transparent pixels touch a 
- 	non-transparent pixel of the background upon which it is displayed.
- 	First column shows a form with a red block in the midst of transparent area sneaking up on a form with a transparent LHS and blue RHS. 	The green frame shows the intersection area.
- 	Second column shows in grey the part of the red that is within the intersection.
- 	Third column shows in black the blue that is within the intersection.
- 	Fourth column shows just the A touching B area.
- 	Fifth column is the tally of hits via the old algorithm
- 	Last column shows the tally of hits via the new prim"
- 	|formA formB maskA maskB offset tally map intersection left top dCanvas|
- 	formA := formB := maskA := maskB := offset := tally := map := intersection :=  nil. "just to shut up the compiler when testing"
- 
- 	Project current world restoreMorphicDisplay; doOneCycle.
- 
- 	top := 50.
- 	dCanvas := FormCanvas on: Display.
- 	-50 to: 80 by: 10 do:[:p|
- 		offset:= p at 0. "vary this to check different states"
- 		left := 10.
- 
- 		formA := Form extent: 100 at 50 depth: 32.
- 		formB := Form extent: 100 at 50 depth: 16.
- 
- 		"make a red square in the middle of the form"
- 		(FormCanvas on: formA) fillRectangle: (25 at 25 extent: 50 at 5) fillStyle: Color yellow.
- 		(FormCanvas on: formA) fillRectangle: (25 at 30 extent: 50 at 5) fillStyle: Color transparent.
- 		(FormCanvas on: formA) fillRectangle: (25 at 35 extent: 50 at 50) fillStyle: Color red.
- 		"formA displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		"make a blue block on the right half of the form"
- 		(FormCanvas on: formB) fillRectangle: (50 at 0 extent: 50 at 100) fillStyle: Color blue.
- 		(FormCanvas on: formB) fillRectangle: (60 at 0 extent: 10 at 100) fillStyle: Color palePeach.
- 		"formB displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		intersection := (formA boundingBox translateBy: offset) intersect: (formB boundingBox).
- 
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150.
- 
- 		maskA := Form extent: intersection extent depth: 2.
- 		formA displayOn: maskA at: offset  - intersection origin rule: Form paint.
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150.
- 
- 		maskB := Form extent: intersection extent depth: 2.
- 		formB displayOn: maskB at: intersection origin negated rule: Form paint.
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskB displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150.
- 
- 		map := Bitmap new: 4 withAll: 1.
- 		map at: 1 put: 0.  "transparent"
- 
- 		maskA copyBits: maskA boundingBox from: maskA at: 0 at 0 colorMap: map.
- 		"maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150."
- 
- 		maskB copyBits: maskB boundingBox from: maskB at: 0 at 0 colorMap: map.
- 		"maskB displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150."
- 
- 		maskB displayOn: maskA at: 0 at 0 rule: Form and.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 170.
- 		
- 		(maskA boundingBox area -( maskA tallyPixelValues at: 1)) asString asDisplayText displayOn: Display at: left@(top +20).
- 		left := left + 70.
- 		
- 		"now try using the new primitive"
- 		tally := (BitBlt
- 			destForm: formB
- 			sourceForm: formA
- 			fillColor: nil
- 			combinationRule: 3 "really ought to work with nil but prim code checks"
- 			destOrigin: intersection origin
- 			sourceOrigin: (offset negated max: 0 at 0)
- 			extent: intersection extent 
- 			clipRect: intersection)
- 				primCompareColor: ((Color transparent pixelValueForDepth: formA depth) bitAnd: 16rFFFFFF) to: ((Color transparent pixelValueForDepth: formB depth) bitAnd: 16rFFFFFF) test: (Form compareNotColorANotColorB bitOr: Form compareTallyFlag).
- 		tally  asString asDisplayText displayOn: Display at: left@(top +20).
- 		top:= top + 60]!

Item was removed:
- ----- Method: Form class>>exampleTouchingColor (in category '*MorphicExtras-examples') -----
- exampleTouchingColor
- 	"Form exampleTouchingColor"
- 	"Demonstrate the algorithm used in Scratch code to determine if a sprite's non-transparent pixels touch a
- 	particular color pixel of the background upon which it is displayed.
- 	First column as above shows the sneaky red/yellow pirate sneaking up on the blue/peach galleon.
- 	Second column shows the 1bpp made from the red/yellow/transparent - white -> ignore this, black -> test this
- 	Third shows the hit area (black) superimposed on the original scene
- 	Fourth column is the tally of hits via the old algorithm
- 	Last column shows the tally of hits via the new prim"	
- 	|formA formB maskA  offset tally map intersection left top dCanvas ignoreColor soughtColor|
- 	formA := formB := maskA := offset := tally := map := intersection :=  nil. "just to shut up the compiler when testing"
- 	Project current world restoreMorphicDisplay; doOneCycle.
- 
- 	ignoreColor := Color transparent.
- 	soughtColor := Color blue.
- 
- 	top := 50.
- 	dCanvas := FormCanvas on: Display.
- 	-50 to: 80 by: 10 do:[:p|
- 		offset:= p at 0. "vary this to check different states"
- 		left := 10.
- 
- 		formA := (Form extent: 100 at 50 depth: 32) asFormOfDepth: 16 "so we can try original forms of other depths".
- 		formB := Form extent: 100 at 50 depth: 32.
- 
- 		"make a red square in the middle of the form"
- 		(FormCanvas on: formA) fillRectangle: (25 at 25 extent: 50 at 5) fillStyle: Color red.
- 		(FormCanvas on: formA) fillRectangle: (25 at 30 extent: 50 at 5) fillStyle: Color transparent.
- 		(FormCanvas on: formA) fillRectangle: (25 at 35 extent: 50 at 50) fillStyle: Color yellow.
- 		"formA displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		"make a blue block on the right half of the form"
- 		(FormCanvas on: formB) fillRectangle: (50 at 0 extent: 50 at 100) fillStyle: soughtColor.
- 		(FormCanvas on: formB) fillRectangle: (60 at 0 extent: 10 at 100) fillStyle: Color palePeach.
- 		"formB displayOn: Display at: left at top rule: Form paint.
- 		dCanvas frameRectangle: (left at top extent: formA extent) width:2 color: Color green.
- 		left := left + 150."
- 
- 		intersection := (formA boundingBox translateBy: offset) intersect: (formB boundingBox).
- 
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 150.
- 	
- 		maskA := Form extent: intersection extent depth: 1.
- 
- 		map := Bitmap new: (1 bitShift: (formA depth min: 15)).
- 		map atAllPut: 1.
- 		map at: ( ignoreColor indexInMap: map) put: 0.
- 
- 		maskA copyBits: (intersection translateBy:  offset negated) from: formA at: 0 at 0 colorMap: map.
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.	left := left + 150.
- 
- 		"intersect world pixels of the color we're looking for with sensitive pixels mask"
- 		map atAllPut: 0.  "clear map and reuse it"
- 		map at: (soughtColor indexInMap: map) put: 1.
- 
- 		maskA
- 	 		copyBits: intersection
- 			from: formB at: 0 at 0 clippingBox: formB boundingBox
- 			rule: Form and
- 			fillColor: nil
- 			map: map.
- 
- 		formB displayOn: Display at: left at top rule: Form paint.
- 		formA displayOn: Display at: (left at top) + offset rule: Form paint.
- 		maskA displayOn: Display at: (left at top) + intersection origin rule: Form paint.
- 		dCanvas frameRectangle: (intersection translateBy: left at top) width:2 color: Color green.
- 		left := left + 170.
- 		
- 		(maskA tallyPixelValues at: 2) asString asDisplayText displayOn: Display at: left@(top +20).
- 		left := left + 70.
- 		
- 		"now try using the new primitive"
- 		tally := (BitBlt
- 			destForm: formB
- 			sourceForm: formA
- 			fillColor: nil
- 			combinationRule: 3 "really ought to work with nil but prim code checks"
- 			destOrigin: intersection origin
- 			sourceOrigin: (offset negated max: 0 at 0)
- 			extent: intersection extent 
- 			clipRect: intersection)
- 				primCompareColor: ((ignoreColor pixelValueForDepth: formA depth) bitAnd: 16rFFFFFF) to: ((soughtColor pixelValueForDepth: formB depth) bitAnd: 16rFFFFFF) test: (Form compareNotColorAMatchColorB bitOr: Form compareTallyFlag).
- 		tally  asString asDisplayText displayOn: Display at: left@(top +20).
- 		top:= top + 60]!

Item was removed:
- ----- Method: Form class>>extraCook (in category '*MorphicExtras-sprites') -----
- extraCook
- 
- 	^ Imports default imports
- 		at: #extraCook
- 		ifAbsentPut: [ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self extraCookContents readStream) ]!

Item was removed:
- ----- Method: Form class>>extraCookContents (in category '*MorphicExtras-sprites') -----
(excessive size, no diff calculated)

Item was removed:
- ----- Method: Form class>>extraWizard (in category '*MorphicExtras-sprites') -----
- extraWizard
- 
- 	^ Imports default imports
- 		at: #extraWizard
- 		ifAbsentPut: [ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self extraWizardContents readStream) ]!

Item was removed:
- ----- Method: Form class>>extraWizardContents (in category '*MorphicExtras-sprites') -----
- extraWizardContents
- 
- 	^ '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
- QmCC'!

Item was removed:
- ----- Method: Form class>>squeakLogo (in category '*MorphicExtras-sprites') -----
- squeakLogo
- 
- 	^ Imports default imports
- 		at: #squeakLogo
- 		ifAbsentPut: [ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self squeakLogoContents readStream) ]!

Item was removed:
- ----- Method: Form class>>squeakLogoContents (in category '*MorphicExtras-sprites') -----
(excessive size, no diff calculated)

Item was removed:
- ----- Method: Form>>encodePostscriptOn: (in category '*MorphicExtras-postscript generation') -----
- encodePostscriptOn: aStream 
- 	self unhibernate.
- 
- 	"since current Postscript support treats 8-bit forms as 0 to 255 gray scale, convert
- 	to 16 first so we get more faithful results"
- 
- 	self depth <= 8 ifTrue: [^(self asFormOfDepth: 16) encodePostscriptOn: aStream].
- 
- 	^ self printPostscript: aStream operator: (self depth = 1
- 			ifTrue: ['imagemask']
- 			ifFalse: ['image'])!

Item was removed:
- ----- Method: Form>>graphicForViewerTab (in category '*MorphicExtras-other') -----
- graphicForViewerTab
- 	"Answer the graphic to be used in the tab of a viewer open on me"
- 
- 	^ self!

Item was removed:
- StringMorph subclass: #FrameRateMorph
- 	instanceVariableNames: 'updateInterval lastDisplayTime framesSinceLastDisplay mSecsPerFrame framesPerSec'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!

Item was removed:
- ----- Method: FrameRateMorph class>>authoringPrototype (in category 'scripting') -----
- authoringPrototype
- 	"Answer a morph representing a prototypical instance of the receiver"
- 
- 	| aMorph |
- 	aMorph := self new.
- 	aMorph color: Color blue.
- 	aMorph step.
- 	^ aMorph!

Item was removed:
- ----- Method: FrameRateMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'FrameRate' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop. 'Tools' translatedNoop}
- 		documentation:	'A readout that allows you to monitor the frame rate of your system' translatedNoop!

Item was removed:
- ----- Method: FrameRateMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: FrameRateMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl |
- 			cl registerQuad: {
- 					#FrameRateMorph. #authoringPrototype. 'Frame Rate' translatedNoop.
- 					'An indicator of how fast your system is running' translatedNoop}
- 				forFlapNamed: 'Widgets'.
- 			cl registerQuad: {
- 					#FrameRateMorph. #authoringPrototype. 'Frame Rate' translatedNoop.
- 					'An indicator of how fast your system is running' translatedNoop}
- 				forFlapNamed: 'Supplies']!

Item was removed:
- ----- Method: FrameRateMorph class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: FrameRateMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aMenu hand: aHandMorph.
- 	
- 	aMenu add: 'set update interval...' translated action: #editUpdateInterval.!

Item was removed:
- ----- Method: FrameRateMorph>>editUpdateInterval (in category 'menu') -----
- editUpdateInterval
- 
- 	| old new |
- 	old := self updateInterval.
- 	new := Project uiManager request: 'edit update interval' translated initialAnswer: old asString.
- 	new isEmptyOrNil ifTrue: [^ false].
- 	
- 	self updateInterval: (old class readFromString: new).
- 	^ true!

Item was removed:
- ----- Method: FrameRateMorph>>framesPerSec (in category 'accessing') -----
- framesPerSec
- 
- 	^ framesPerSec!

Item was removed:
- ----- Method: FrameRateMorph>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- ""
- 	lastDisplayTime := TimeStamp new.
- 	framesSinceLastDisplay := 0.
- 	self updateInterval: 500 milliSeconds.
- 	self font: (Preferences standardMenuFont emphasized: 1).
- !

Item was removed:
- ----- Method: FrameRateMorph>>initializeToStandAlone (in category 'parts bin') -----
- initializeToStandAlone
- 	"Initialize the receiver as a stand-alone entity"
- 
- 	super initializeToStandAlone.
- 	self color: Color blue.
- 	self font: (Preferences standardMenuFont emphasized: 1).
- 	self step.
- !

Item was removed:
- ----- Method: FrameRateMorph>>mSecsPerFrame (in category 'accessing') -----
- mSecsPerFrame
- 
- 	^ mSecsPerFrame!

Item was removed:
- ----- Method: FrameRateMorph>>step (in category 'stepping and presenter') -----
- step
- 	"Compute and display (every half second or so) the current framerate"
- 
- 	| now timePassed newContents |
- 	framesSinceLastDisplay := framesSinceLastDisplay + 1.
- 	now := TimeStamp now.
- 	timePassed := now - lastDisplayTime.
- 	(timePassed > self updateInterval) ifTrue: 
- 		[| mSecs |
- 		mSecs := timePassed asMilliSeconds.
- 		mSecsPerFrame := mSecs // framesSinceLastDisplay.
- 		framesPerSec := (framesSinceLastDisplay * 1000) // mSecs.
- 		newContents := mSecsPerFrame printString, ' mSecs (', framesPerSec printString, ' frame', (framesPerSec = 1 ifTrue: [''] ifFalse: ['s']), '/sec)'.
- 		self contents: newContents.
- 		lastDisplayTime := now.
- 		framesSinceLastDisplay := 0]
- 	ifFalse:
- 		["Ensure at least one pixel is drawn per frame"
- 		Preferences higherPerformance ifTrue: [self invalidRect: (self position extent: 1 at 1)]]!

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

Item was removed:
- ----- Method: FrameRateMorph>>updateInterval (in category 'accessing') -----
- updateInterval
- 
- 	^ updateInterval!

Item was removed:
- ----- Method: FrameRateMorph>>updateInterval: (in category 'accessing') -----
- updateInterval: aDuration
- 
- 	updateInterval := aDuration!

Item was removed:
- BookMorph subclass: #GeeBookMorph
- 	instanceVariableNames: 'geeMail'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!

Item was removed:
- ----- Method: GeeBookMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^ false!

Item was removed:
- ----- Method: GeeBookMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0.909
- 		g: 0.819
- 		b: 0.09!

Item was removed:
- ----- Method: GeeBookMorph>>geeMail: (in category 'accessing') -----
- geeMail: aGeeMail
- 
- 	geeMail := aGeeMail.!

Item was removed:
- ----- Method: GeeBookMorph>>geePageRectangles (in category 'ui') -----
- geePageRectangles
- 
- 	| pageBounds allPageRects |
- 
- 	pageBounds := geeMail topLeft 
- 			extent: geeMail width @ (geeMail height min: Display height - 50).
- 	allPageRects := OrderedCollection new.
- 	[pageBounds top <= geeMail bottom] whileTrue: [
- 		allPageRects add: pageBounds.
- 		pageBounds := pageBounds translateBy: 0 @ pageBounds height.
- 	].
- 	^allPageRects
- !

Item was removed:
- ----- Method: GeeBookMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	newPagePrototype := GeeBookPageMorph new extent: Display extent // 3 !

Item was removed:
- ----- Method: GeeBookMorph>>rebuildPages (in category 'ui') -----
- rebuildPages
- 
- 	pages := self geePageRectangles collect: [ :each |
- 		GeeBookPageMorph new 
- 			disableDragNDrop;
- 			geeMail: geeMail geeMailRectangle: each.
- 	].
- 	currentPage delete.
- 	currentPage := nil.
- 	pages isEmpty ifTrue: [^ self insertPage].
- 	self goToPage: 1.
- 
- !

Item was removed:
- PasteUpMorph subclass: #GeeBookPageMorph
- 	instanceVariableNames: 'geeMail geeMailRectangle'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!

Item was removed:
- ----- Method: GeeBookPageMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^ false!

Item was removed:
- ----- Method: GeeBookPageMorph>>fullDrawOn: (in category 'drawing') -----
- fullDrawOn: aCanvas
- 
- 	aCanvas 
- 		translateTo: self topLeft + aCanvas origin - geeMailRectangle origin 
- 		clippingTo: (bounds translateBy: aCanvas origin) 
- 		during: [ :c |
- 			geeMail disablePageBreaksWhile: [geeMail fullDrawOn: c].
- 		].
- !

Item was removed:
- ----- Method: GeeBookPageMorph>>geeMail:geeMailRectangle: (in category 'initialization') -----
- geeMail: aGeeMail geeMailRectangle: aRectangle
- 
- 	geeMail := aGeeMail.
- 	geeMailRectangle := aRectangle.
- 	self extent: aRectangle extent.!

Item was removed:
- ----- Method: GeeBookPageMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 	"Handle a mouse down event."
- 
- 	
- 	"{evt. self recipientForMouseDown: evt. self} explore."
- !

Item was removed:
- ScrollPane subclass: #GeeMailMorph
- 	instanceVariableNames: 'theTextMorph thePasteUp'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!
- 
- !GeeMailMorph commentStamp: '<historical>' prior: 0!
- GeeMail is a scrolling playfield with a text morph (typically on the left) and room on the right for other morphs to be placed. The morphs on the right can be linked to text selections on the left so that they remain positioned beside the pertinent text as the text is reflowed. Probably the best thing is and example and Alan will be making some available soon.!

Item was removed:
- ----- Method: GeeMailMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^ false		"to encourage the use of GeeMail instead"!

Item was removed:
- ----- Method: GeeMailMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	self addGeeMailMenuItemsTo: aCustomMenu.!

Item was removed:
- ----- Method: GeeMailMorph>>addGeeMailMenuItemsTo: (in category 'menus') -----
- addGeeMailMenuItemsTo: menu
- 
- 	menu 
- 		addUpdating: #showPageBreaksString action: #togglePageBreaks;
- 		addUpdating: #keepScrollbarString action: #toggleKeepScrollbar;
- 		addLine;
- 		add: 'Print...' translated action: #printPSToFile;
- 		addLine.
- 	thePasteUp allTextPlusMorphs size = 1 ifTrue: [
- 		menu add: 'make 1-column book' translated selector: #makeBookStyle: argument: 1.
- 		menu add: 'make 2-column book' translated selector: #makeBookStyle: argument: 2.
- 		menu add: 'make 3-column book' translated selector: #makeBookStyle: argument: 3.
- 		menu add: 'make 4-column book' translated selector: #makeBookStyle: argument: 4.
- 	] ifFalse: [
- 		menu add: 'make a galley of me' translated action: #makeGalleyStyle.
- 	].
- 	^menu!

Item was removed:
- ----- Method: GeeMailMorph>>adjustPasteUpSize (in category 'private') -----
- adjustPasteUpSize
- 
- 	| newBottom |
- 
- 	thePasteUp ifNil: [^self].
- 	newBottom := thePasteUp bottom max: thePasteUp boundingBoxOfSubmorphs bottom + 20.
- 	thePasteUp height: (newBottom - thePasteUp top max: self height).
- 	thePasteUp width: (thePasteUp width max: scroller innerBounds width - 5).!

Item was removed:
- ----- Method: GeeMailMorph>>allTextPlusMorphs (in category 'accessing') -----
- allTextPlusMorphs
- 
- 	^thePasteUp allTextPlusMorphs!

Item was removed:
- ----- Method: GeeMailMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color white!

Item was removed:
- ----- Method: GeeMailMorph>>doLayoutIn: (in category 'layout') -----
- doLayoutIn: layoutBounds
- 	"layout has changed. update scroll deltas or whatever else"
- 
- 	self adjustPasteUpSize.
- 	scroller ifNotNil: [self setScrollDeltas].
- 	super doLayoutIn: layoutBounds.
- !

Item was removed:
- ----- Method: GeeMailMorph>>extraScrollRange (in category 'geometry') -----
- extraScrollRange
- 	^ bounds height
- !

Item was removed:
- ----- Method: GeeMailMorph>>getMenu: (in category 'menus') -----
- getMenu: shiftKeyState
- 
- 	| menu |
- 	menu := MenuMorph new defaultTarget: self.
- 	self addGeeMailMenuItemsTo: menu.
- 	^menu!

Item was removed:
- ----- Method: GeeMailMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	^evt yellowButtonPressed !

Item was removed:
- ----- Method: GeeMailMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self initializeThePasteUp.
- 	self position: 100 at 100.
- 	self extent: Display extent // 3.
- 	self useRoundedCorners.
- 	!

Item was removed:
- ----- Method: GeeMailMorph>>initializeThePasteUp (in category 'initialization') -----
- initializeThePasteUp
- "initialize the receiver's thePasteUp"
- 	thePasteUp := TextPlusPasteUpMorph new borderWidth: 0;
- 				 color: color.
- 	scroller addMorph: thePasteUp!

Item was removed:
- ----- Method: GeeMailMorph>>keepScrollBarAlways (in category 'menus') -----
- keepScrollBarAlways
- 
- 	^self valueOfProperty: #keepScrollBarAlways ifAbsent: [false]!

Item was removed:
- ----- Method: GeeMailMorph>>keepScrollbarString (in category 'menus') -----
- keepScrollbarString
- 
- 	^self keepScrollBarAlways ifTrue: ['<on>scrollbar stays up'] ifFalse: ['<off>scrollbar stays up']!

Item was removed:
- ----- Method: GeeMailMorph>>makeBookStyle: (in category 'menus') -----
- makeBookStyle: nColumns
- 
- 	| all totalWidth second columnWidth currY prev columnHeight currX currColumn pageBreakRectangles r rm columnGap pageGap starter |
- 
- 	pageBreakRectangles := OrderedCollection new.
- 	all := thePasteUp allTextPlusMorphs.
- 	all size = 1 ifFalse: [^self].
- 	Cursor wait show.
- 	starter := prev := all first.
- 	totalWidth := self width - 16.
- 	columnGap := 32.
- 	pageGap := 16.
- 	columnWidth := totalWidth - (columnGap * (nColumns - 1)) // nColumns.
- 	columnHeight := self height - 12.
- 	currY := 4.
- 	currX := 4.
- 	currColumn := 1.
- 	prev
- 		position: currX at currY;
- 		width: columnWidth.
- 	[
- 		second := prev makeSuccessorMorph.
- 		thePasteUp addMorphBack: second.
- 		prev 
- 			setProperty: #autoFitContents toValue: false;
- 			height: columnHeight.
- 		(currColumn := currColumn + 1) <= nColumns ifTrue: [
- 			currX := currX + columnWidth + columnGap.
- 		] ifFalse: [
- 			r := 4@(prev bottom + 4) corner: (self right - 4 @ (prev bottom + pageGap - 4)).
- 			rm := RectangleMorph new bounds: r; color: (Color gray alpha: 0.3); borderWidth: 0.
- 			pageBreakRectangles add: rm beSticky.
- 			thePasteUp addMorphBack: rm.
- 			currColumn := 1.
- 			currX := 4.
- 			currY := prev bottom + pageGap.
- 		].
- 		second 
- 			autoFit: true;
- 			position: currX at currY;
- 			width: columnWidth.
- 		prev recomposeChain.		"was commented"
- 		prev := second.
- 		prev height > columnHeight
- 	] whileTrue.
- 	prev autoFit: true.
- 	thePasteUp height: (prev bottom + 20 - self top).
- 	self layoutChanged.
- 	self setProperty: #pageBreakRectangles toValue: pageBreakRectangles.
- 	thePasteUp allTextPlusMorphs do: [ :each |
- 		each repositionAnchoredMorphs
- 	].
- 	Cursor normal show.
- !

Item was removed:
- ----- Method: GeeMailMorph>>makeGalleyStyle (in category 'menus') -----
- makeGalleyStyle
- 
- 	| all first theRest |
- 
- 	(self valueOfProperty: #pageBreakRectangles ifAbsent: [#()]) do: [ :each |
- 		each delete
- 	].
- 	self removeProperty: #pageBreakRectangles.
- 	all := thePasteUp allTextPlusMorphs.
- 	first := all select: [ :x | x predecessor isNil].
- 	first size = 1 ifFalse: [^self].
- 	Cursor wait show.
- 	first := first first.
- 	theRest := all reject: [ :x | x predecessor isNil].
- 	theRest do: [ :each | each delete].
- 	first autoFit: true.
- 	first width: self width - 8.
- 	first recomposeChain.
- 	first repositionAnchoredMorphs.
- 	Cursor normal show.
- !

Item was removed:
- ----- Method: GeeMailMorph>>mouseUp:inMorph: (in category 'event handling') -----
- mouseUp: evt inMorph: aMorph
- 
- 	evt hand grabMorph: aMorph	"old instances may have a handler we no longer use"!

Item was removed:
- ----- Method: GeeMailMorph>>pageRectanglesForPrinting (in category 'printing') -----
- pageRectanglesForPrinting
- 
- 	| pageBreaks pageRects prevBottom |
- 
- 	pageBreaks := self valueOfProperty: #pageBreakRectangles ifAbsent: [^nil].
- 	prevBottom := 0.
- 	pageRects := pageBreaks collect: [ :each | | r |
- 		r := 0 at prevBottom corner: self width @ each top.
- 		prevBottom := each bottom.
- 		r
- 	].
- 	pageRects add: (0 at prevBottom corner: self width @ thePasteUp bottom).
- 	^pageRects!

Item was removed:
- ----- Method: GeeMailMorph>>printPSToFile (in category 'Postscript Canvases') -----
- printPSToFile
- 
- 	thePasteUp printer
- 		geeMail: self;
- 		doPages!

Item was removed:
- ----- Method: GeeMailMorph>>scrollBarValue: (in category 'scroll bar events') -----
- scrollBarValue: scrollValue
- 
- 	| newPt pageBreaks topOfPage |
- 
- 	scroller hasSubmorphs ifFalse: [^ self].
- 	newPt := -3 @ (self vLeftoverScrollRange * scrollValue).
- 
- 	pageBreaks := self valueOfProperty: #pageBreakRectangles ifAbsent: [#()].
- 	pageBreaks isEmpty ifTrue: [
- 		^scroller offset: newPt.
- 	].
- 	topOfPage := pageBreaks inject: (0 at 0 corner: 0 at 0) into: [ :closest :each |
- 		(each bottom - newPt y) abs < (closest bottom - newPt y) abs ifTrue: [
- 			each 
- 		] ifFalse: [
- 			closest 
- 		].
- 	].
- 	topOfPage ifNotNil: [
- 		newPt := newPt x @ topOfPage bottom.
- 		scrollBar value: newPt y / self vLeftoverScrollRange.
- 	].
- 	scroller offset: newPt.!

Item was removed:
- ----- Method: GeeMailMorph>>scrollSelectionIntoView:alignTop:inTextMorph: (in category 'scrolling') -----
- scrollSelectionIntoView: event alignTop: alignTop inTextMorph: tm
- 	"Scroll my text into view if necessary and return true, else return false"
- 
- 	| selRects delta selRect rectToTest transform cpHere |
- 
- 	selRects := tm paragraph selectionRects.
- 	selRects isEmpty ifTrue: [^ false].
- 	rectToTest := selRects first merge: selRects last.
- 	transform := scroller transformFrom: self.
- 	(event notNil and: [event isMouse and: [event anyButtonPressed]]) ifTrue:  "Check for autoscroll"
- 		[cpHere := transform localPointToGlobal: event cursorPoint.
- 		cpHere y <= self top
- 			ifTrue: [rectToTest := selRects first topLeft extent: 2 at 2]
- 			ifFalse: [cpHere y >= self bottom
- 					ifTrue: [rectToTest := selRects last bottomRight extent: 2 at 2]
- 					ifFalse: [^ false]]].
- 	selRect := transform localBoundsToGlobal: rectToTest.
- 	selRect height > bounds height
- 		ifTrue: [^ false].  "Would not fit, even if we tried to scroll"
- 	alignTop ifTrue: [
- 		self scrollBy: 0@(bounds top - selRect top).
- 		^ true
- 	].
- 	selRect bottom > bounds bottom ifTrue: [
- 		self scrollBy: 0@(bounds bottom - selRect bottom - 30).
- 		^ true
- 	].
- 	(delta := selRect amountToTranslateWithin: self bounds) y ~= 0 ifTrue: [
- 		"Scroll end of selection into view if necessary"
- 		self scrollBy: 0 at delta y.
- 		^ true].
- 	^ false!

Item was removed:
- ----- Method: GeeMailMorph>>scrollToPage: (in category 'scrolling') -----
- scrollToPage: pageNumber
- 
- 	| rects oneRect |
- 
- 	rects := self valueOfProperty: #pageBreakRectangles ifAbsent: [#()].
- 	oneRect := rects at: pageNumber - 1 ifAbsent: [0 at 0 extent: 0 at 0].
- 	self scrollToYAbsolute: oneRect bottom.
- !

Item was removed:
- ----- Method: GeeMailMorph>>scrollToYAbsolute: (in category 'scrolling') -----
- scrollToYAbsolute: yValue
- 
- 	| transform transformedPoint |
- 
- 	transform := scroller transformFrom: self.
- 	transformedPoint := transform localPointToGlobal: 0 at yValue.
- 
- 	self scrollBy: 0@(bounds top - transformedPoint y).
- !

Item was removed:
- ----- Method: GeeMailMorph>>showPageBreaksString (in category 'menus') -----
- showPageBreaksString
- 
- 	^(thePasteUp ifNil: [^'???']) showPageBreaksString!

Item was removed:
- ----- Method: GeeMailMorph>>toggleKeepScrollbar (in category 'menus') -----
- toggleKeepScrollbar
- 
- 	self setProperty: #keepScrollBarAlways toValue: self keepScrollBarAlways not!

Item was removed:
- ----- Method: GeeMailMorph>>togglePageBreaks (in category 'menus') -----
- togglePageBreaks
- 
- 	(thePasteUp ifNil: [^self]) togglePageBreaks!

Item was removed:
- ----- Method: GeeMailMorph>>vHideScrollBar (in category 'scrolling') -----
- vHideScrollBar
- 
- 	self keepScrollBarAlways ifTrue: [^self].
- 	^super vHideScrollBar!

Item was removed:
- ----- Method: GeeMailMorph>>wantsDroppedMorph:event: (in category 'dropping/grabbing') -----
- wantsDroppedMorph: aMorph event: evt
- 	"Return true if the receiver wishes to accept the given morph, which is being dropped by a hand in response to the given event. The default implementation returns false.
- NOTE: the event is assumed to be in global (world) coordinates."
- 
- 	^false!

Item was removed:
- ----- Method: GeeMailMorph>>wantsSlot (in category 'accessing') -----
- wantsSlot
- 
- 	^false!

Item was removed:
- Object subclass: #GeePrinter
- 	instanceVariableNames: 'pasteUp printSpecs geeMail computedBounds'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!

Item was removed:
- ----- Method: GeePrinter>>allPages (in category 'private - postscript canvases') -----
- allPages
- 
- 	| pageNumber allPages maxPages |
- 
- 	maxPages := 9999.
- 	pageNumber := 0.
- 	allPages := self pageRectangles collect: [ :rect |
- 		pageNumber := pageNumber + 1.
- 		(self as: GeePrinterPage) pageNumber: pageNumber bounds: rect
- 	].
- 	allPages size > maxPages ifTrue: [allPages := allPages first: maxPages].
- 	allPages do: [ :each | each totalPages: allPages size].
- 	^allPages
- 
- !

Item was removed:
- ----- Method: GeePrinter>>bounds (in category 'geometry') -----
- bounds
- 
- 	^computedBounds ifNil: [computedBounds := self computeBounds]!

Item was removed:
- ----- Method: GeePrinter>>computeBounds (in category 'geometry') -----
- computeBounds
- 
- 	| w ratio |
- 
- 	w := pasteUp width.
- 	self printSpecs scaleToFitPage ifTrue: [
- 		^0 at 0 extent: w@(w * self hOverW) rounded.
- 	].
- 	ratio := 8.5 @ 11.
- 	self printSpecs landscapeFlag ifTrue: [
- 		ratio := ratio transposed
- 	].
- 	^0 at 0 extent: (ratio * 72) rounded!

Item was removed:
- ----- Method: GeePrinter>>doPages (in category 'postscript canvases') -----
- doPages
- 
- 	| dialog |
- 	(dialog := GeePrinterDialogMorph new) 
- 		printSpecs: self printSpecs 
- 		printBlock: [ :preview :specs |
- 			preview ifTrue: [self doPrintPreview] ifFalse: [self doPrintToPrinter]
- 		];
- 		fullBounds;
- 		position: Display extent - dialog extent // 2;
- 		openInWorld
- 
- !

Item was removed:
- ----- Method: GeePrinter>>doPrintPreview (in category 'private - postscript canvases') -----
- doPrintPreview
- 
- 	| pageDisplay sz |
- 
- 	sz := (85 @ 110) * 3.
- 	self printSpecs landscapeFlag ifTrue: [
- 		sz := sz transposed
- 	].
- 	pageDisplay := BookMorph new
- 		color: Color paleYellow;
- 		borderWidth: 1.
- 	self allPages withIndexDo: [ :each :index | | pic align newPage subBounds |
- 		pic := ImageMorph new image: (each pageThumbnailOfSize: sz).
- 		align := AlignmentMorph newColumn
- 			addMorph: pic;
- 			borderWidth: 1;
- 			layoutInset: 0;
- 			borderColor: Color blue.
- 		newPage := pageDisplay 
- 			insertPageLabel: 'Page ',index printString
- 			morphs: {align}.
- 		subBounds := newPage boundingBoxOfSubmorphs.
- 		newPage extent: subBounds corner - newPage topLeft + ((subBounds left - newPage left)@0).
- 	].
- 	pageDisplay 
- 		goToPage: 1;
- 		deletePageBasic;
- 		position: Display extent - pageDisplay extent // 2;
- 		openInWorld.
- !

Item was removed:
- ----- Method: GeePrinter>>doPrintToPrinter (in category 'postscript canvases') -----
- doPrintToPrinter
- 
- 	"fileName := ('gee.',Time millisecondClockValue printString,'.eps') asFileName."
- 	self pageRectangles.	"ensure bounds computed"
- 	DSCPostscriptCanvasToDisk 
- 		morphAsPostscript: self 
- 		rotated: self printSpecs landscapeFlag
- 		specs: self printSpecs
- !

Item was removed:
- ----- Method: GeePrinter>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	pasteUp drawOn: aCanvas
- 
- !

Item was removed:
- ----- Method: GeePrinter>>fullBounds (in category 'layout') -----
- fullBounds
- 
- 	^self bounds!

Item was removed:
- ----- Method: GeePrinter>>fullDrawOn: (in category 'drawing') -----
- fullDrawOn: aCanvas
- 
- 	pasteUp fullDrawOn: aCanvas
- 
- !

Item was removed:
- ----- Method: GeePrinter>>fullDrawPostscriptOn: (in category 'postscript canvases') -----
- fullDrawPostscriptOn: aCanvas
- 
- 	aCanvas drawPages: self allPages.
- 
- !

Item was removed:
- ----- Method: GeePrinter>>geeMail: (in category 'accessing') -----
- geeMail: aGeeMail
- 
- 	geeMail := aGeeMail!

Item was removed:
- ----- Method: GeePrinter>>hOverW (in category 'private - postscript canvases') -----
- hOverW
- 
- 	^self printSpecs landscapeFlag ifTrue: [
- 		8.5 /  11.0
- 	] ifFalse: [
- 		11.0 / 8.5
- 	].
- !

Item was removed:
- ----- Method: GeePrinter>>pageRectangles (in category 'private - postscript canvases') -----
- pageRectangles
- 
- 	| pageBounds allPageRects maxExtent |
- 
- 	geeMail ifNotNil: [
- 		allPageRects := geeMail pageRectanglesForPrinting.
- 		allPageRects ifNotNil: [
- 			maxExtent := allPageRects inject: 0 at 0 into: [ :max :each |
- 				max max: each extent
- 			].
- 			computedBounds := 0 at 0 extent: maxExtent.
- 			^allPageRects
- 		].
- 	].
- 	pageBounds := self bounds.
- 	allPageRects := OrderedCollection new.
- 	[pageBounds top <= pasteUp bottom] whileTrue: [
- 		allPageRects add: pageBounds.
- 		pageBounds := pageBounds translateBy: 0 @ pageBounds height.
- 	].
- 	^allPageRects
- !

Item was removed:
- ----- Method: GeePrinter>>pagesHandledAutomatically (in category 'printing') -----
- pagesHandledAutomatically
- 
- 	^true!

Item was removed:
- ----- Method: GeePrinter>>pasteUp: (in category 'accessing') -----
- pasteUp: x
- 
- 	pasteUp := x.!

Item was removed:
- ----- Method: GeePrinter>>printSpecs (in category 'accessing') -----
- printSpecs
- 
- 	^printSpecs ifNil: [printSpecs := PrintSpecifications defaultSpecs].
- !

Item was removed:
- ----- Method: GeePrinter>>printSpecs: (in category 'accessing') -----
- printSpecs: aPrintSpecification
- 
- 	printSpecs := aPrintSpecification!

Item was removed:
- ----- Method: GeePrinter>>wantsRoundedCorners (in category 'rounding') -----
- wantsRoundedCorners
- 
- 	^false!

Item was removed:
- AlignmentMorphBob1 subclass: #GeePrinterDialogMorph
- 	instanceVariableNames: 'printSpecs printBlock'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!

Item was removed:
- ----- Method: GeePrinterDialogMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^ false!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>buttonColor (in category 'user interface - constants') -----
- buttonColor
- 
- 	^color darker!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>buttonNamed:action:color:help: (in category 'private') -----
- buttonNamed: aString action: aSymbol color: aColor help: helpString 
- 	| f col |
- 	f := SimpleButtonMorph new target: self;
- 				 label: aString;
- 				 color: aColor;
- 				 borderColor: aColor muchDarker;
- 				 actionSelector: aSymbol;
- 				 setBalloonText: helpString.
- 	col := self inAColumn: {f}.
- 	col hResizing: #shrinkWrap.
- 	^ col!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>cancelButton (in category 'user interface') -----
- cancelButton
- 	^ self
- 		buttonNamed: 'Cancel'
- 		action: #doCancel
- 		color: Color lightRed
- 		help: 'Cancel this printing operation.'!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>defaultBorderColor (in category 'initialization') -----
- defaultBorderColor
- 	"answer the default border color/fill style for the receiver"
- 	^ self color darker!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 8!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color paleYellow!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>doCancel (in category 'user interface') -----
- doCancel
- 
- 	self delete!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>doPreview (in category 'user interface') -----
- doPreview
- 
- 	self delete.
- 	printBlock value: true value: printSpecs.!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>doPrint (in category 'user interface') -----
- doPrint
- 
- 	self delete.
- 	printBlock value: false value: printSpecs.!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>getChoice: (in category 'user interface') -----
- getChoice: aSymbol
- 
- 	aSymbol == #landscapeFlag ifTrue: [^printSpecs landscapeFlag].
- 	aSymbol == #drawAsBitmapFlag ifTrue: [^printSpecs drawAsBitmapFlag].
- 	aSymbol == #scaleToFitPage ifTrue: [^printSpecs scaleToFitPage].
- !

Item was removed:
- ----- Method: GeePrinterDialogMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self vResizing: #shrinkWrap;
- 		 hResizing: #shrinkWrap;
- 		 layoutInset: 4;
- 		 useRoundedCorners.
- 	printSpecs
- 		ifNil: [printSpecs := PrintSpecifications defaultSpecs].
- 	self rebuild !

Item was removed:
- ----- Method: GeePrinterDialogMorph>>previewButton (in category 'user interface') -----
- previewButton
- 
- 	^self
- 		buttonNamed: 'Preview' 
- 		action: #doPreview 
- 		color: self buttonColor 
- 		help: 'Show a preview of the pages that will be printed on the screen.'!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>printButton (in category 'user interface') -----
- printButton
- 
- 	^self
- 		buttonNamed: 'Print' 
- 		action: #doPrint 
- 		color: self buttonColor 
- 		help: 'Print me (a PostScript file will be created)'!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>printSpecs:printBlock: (in category 'accessing') -----
- printSpecs: aPrintSpecification printBlock: aTwoArgBlock
- 
- 	printSpecs := aPrintSpecification.
- 	printBlock := aTwoArgBlock.!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>rebuild (in category 'private') -----
- rebuild
- 
- 	self removeAllMorphs.
- 	self addARow: {
- 		(StringMorph contents: 'PostScript Printing Options') lock.
- 	}.
- 	self addARow: {
- 		self
- 			simpleToggleButtonFor: self
- 			attribute: #landscapeFlag
- 			help: 'Print in landscape mode'.
- 		(StringMorph contents: ' Landscape') lock.
- 	}.
- 	self addARow: {
- 		self
- 			simpleToggleButtonFor: self
- 			attribute: #drawAsBitmapFlag
- 			help: 'Print as a bitmap'.
- 		(StringMorph contents: ' Bitmap') lock.
- 	}.
- 	self addARow: {
- 		self
- 			simpleToggleButtonFor: self
- 			attribute: #scaleToFitPage
- 			help: 'Scale printing to fill page'.
- 		(StringMorph contents: ' Scale to fit') lock.
- 	}.
- 
- 
- 	self addARow: {
- 		self printButton.
- 		self previewButton.
- 		self cancelButton.
- 	}.!

Item was removed:
- ----- Method: GeePrinterDialogMorph>>toggleChoice: (in category 'user interface') -----
- toggleChoice: aSymbol
- 
- 	aSymbol == #landscapeFlag ifTrue: [
- 		printSpecs landscapeFlag: printSpecs landscapeFlag not
- 	].
- 	aSymbol == #drawAsBitmapFlag ifTrue: [
- 		printSpecs drawAsBitmapFlag: printSpecs drawAsBitmapFlag not
- 	].
- 	aSymbol == #scaleToFitPage ifTrue: [
- 		printSpecs scaleToFitPage: printSpecs scaleToFitPage not
- 	].
- !

Item was removed:
- GeePrinter subclass: #GeePrinterPage
- 	instanceVariableNames: 'pageNumber bounds totalPages'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-GeeMail'!

Item was removed:
- ----- Method: GeePrinterPage>>fullDrawPostscriptOn: (in category 'postscript canvases') -----
- fullDrawPostscriptOn: aCanvas
- 
- 	| s |
- 	s := TextMorph new 
- 		beAllFont: (TextStyle default fontOfSize: 30);
- 		contentsAsIs: '   Drawing page ',pageNumber printString,' of ',totalPages printString,'     '.
- 	s layoutChanged; fullBounds.
- 	s := AlignmentMorph newRow
- 		hResizing: #shrinkWrap;
- 		vResizing: #shrinkWrap;
- 		addMorph: s;
- 		color: Color yellow.
- 	s position: Display center - (s width // 2 @ 0).
- 	Project current world addMorphFront: s;
- 		displayWorld.
- 	printSpecs drawAsBitmapFlag ifTrue: [
- 		aCanvas paintImage: self pageAsForm at: 0 at 0
- 	] ifFalse: [
- 		aCanvas 
- 			translateTo: bounds origin negated 
- 			clippingTo: (0 at 0 extent: bounds extent) 
- 			during: [ :c |
- 				pasteUp fullDrawForPrintingOn: c
- 			].
- 	].
- 	s delete.
- 
- !

Item was removed:
- ----- Method: GeePrinterPage>>pageAsForm (in category 'private - postscript canvases') -----
- pageAsForm
- 
- 	| f canvas |
- 	f := Form extent: bounds extent depth: 16.
- 	canvas := f getCanvas.
- 	canvas fillColor: pasteUp color.
- 	canvas translateTo: bounds origin negated clippingTo: f boundingBox during: [ :c |
- 		pasteUp fullDrawForPrintingOn: c
- 	].
- 	^f
- 
- !

Item was removed:
- ----- Method: GeePrinterPage>>pageNumber:bounds: (in category 'private - accessing') -----
- pageNumber: anInteger bounds: aRect
- 
- 	pageNumber := anInteger.
- 	bounds := aRect.!

Item was removed:
- ----- Method: GeePrinterPage>>pageThumbnailOfSize: (in category 'private - postscript canvases') -----
- pageThumbnailOfSize: aPoint
- 
- 	^self pageAsForm scaledToSize: aPoint
- 
- !

Item was removed:
- ----- Method: GeePrinterPage>>totalPages: (in category 'private - accessing') -----
- totalPages: x
- 
- 	totalPages := x!

Item was removed:
- ImageMorph subclass: #GrabPatchMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !GrabPatchMorph commentStamp: 'sw 8/1/2004 13:27' prior: 0!
- When an instance of GrabPatchMorph is dropped by the user, it signals a desire to do a screen-grab of a rectangular area.!

Item was removed:
- ----- Method: GrabPatchMorph class>>authoringPrototype (in category 'instance creation') -----
- authoringPrototype
- 	"Answer a prototype for use in a parts bin"
- 
- 	^ self new image: (ScriptingSystem formAtKey: 'GrabPatch'); markAsPartsDonor; setBalloonText: 'Use this to grab a rectangular patch from the screen'; yourself!

Item was removed:
- ----- Method: GrabPatchMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	"Answer a description of the receiver's instances for a parts bin"
- 
- 	^ self partName:	'Grab Patch' translatedNoop
- 		categories:		{'Graphics' translatedNoop}
- 		documentation:	'Use this to grab a rectangular patch from the screen' translatedNoop!

Item was removed:
- ----- Method: GrabPatchMorph>>initialize (in category 'initialization') -----
- initialize
- 	"Initialize the receiver.  Emblazon the GrabPatch icon on its face"
- 
- 	super initialize.
- 	self image: (ScriptingSystem formAtKey: 'GrabPatch').
- 	self setProperty: #ignorePartsBinDrop toValue: true!

Item was removed:
- ----- Method: GrabPatchMorph>>initializeToStandAlone (in category 'initialization') -----
- initializeToStandAlone
- 	"Initialize the receiver.  Emblazon the GrabPatch icon on its face"
- 
- 	super initializeToStandAlone.
- 	self image: (ScriptingSystem formAtKey: 'GrabPatch')!

Item was removed:
- ----- Method: GrabPatchMorph>>justDroppedInto:event: (in category 'dropping') -----
- justDroppedInto: aPasteUpMorph event: anEvent
- 	"This message is sent to a dropped morph after it has been dropped on--and been accepted by--a drop-sensitive morph"
- 
- 	super justDroppedInto: aPasteUpMorph event: anEvent.
- 	
- 	aPasteUpMorph isPartsBin ifFalse: [
- 		"Do not show this morph in the screenshot."
- 		self hide.
- 		anEvent hand hide.
- 		self refreshWorld.
- 
- 		[aPasteUpMorph grabDrawingFromScreen: anEvent]
- 			ensure: [anEvent hand show]].
- 
- 	"Just needed for this operation. Remove."	
- 	self delete.!

Item was removed:
- ----- Method: GrabPatchMorph>>wantsToBeDroppedInto: (in category 'dropping') -----
- wantsToBeDroppedInto: aMorph
- 	"Only into PasteUps that are not part bins"
- 
- 	^ aMorph isPlayfieldLike!

Item was removed:
- RectangleMorph subclass: #GradientFillMorph
- 	instanceVariableNames: 'fillColor2 gradientDirection colorArray colorDepth'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !GradientFillMorph commentStamp: 'dtl 11/11/2017 22:32' prior: 0!
- Class GradientFillMorph is obsolete. For getting gradient fills use a BorderedMorph with an appropriate fill style, e.g.,
- 
- 	| morph fs |
- 	morph := BorderedMorph new.
- 	fs := GradientFillStyle ramp: {0.0 -> Color red. 1.0 -> Color green}.
- 	fs origin: morph bounds center.
- 	fs direction: (morph bounds width // 2) @ 0.
- 	fs radial: true.
- 	morph fillStyle: fs.
- 	Project current world primaryHand attachMorph: morph.
- 
- Here's the old (obsolete) comment:
- GradientFills cache an array of bitpatterns for the colors across their rectangle.  It costs a bit of space, but makes display fast enough to eschew the use of a bitmap.  The array must be recomputed whenever the colors, dimensions or display depth change.!

Item was removed:
- ----- Method: GradientFillMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'gradient color' translated action: #setGradientColor:.
- 	gradientDirection == #vertical
- 		ifTrue: [aCustomMenu add: 'horizontal pan' translated action: #beHorizontal]
- 		ifFalse: [aCustomMenu add: 'vertical pan' translated action: #beVertical].
- !

Item was removed:
- ----- Method: GradientFillMorph>>beHorizontal (in category 'menu') -----
- beHorizontal
- 	gradientDirection := #horizontal.
- 	self changed!

Item was removed:
- ----- Method: GradientFillMorph>>beVertical (in category 'menu') -----
- beVertical
- 	gradientDirection := #vertical.
- 	self changed!

Item was removed:
- ----- Method: GradientFillMorph>>changed (in category 'updating') -----
- changed
- 	super changed.
- 	self releaseCachedState!

Item was removed:
- ----- Method: GradientFillMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas 
- 	"Note that this could run about 4 times faster if we got hold of
- 	the canvas's port and just sent it copyBits with new coords and color"
- 
- 	| style |
- 	super drawOn: aCanvas.
- 	(color isColor) ifFalse: [^self].	"An InfiniteForm, for example"
- 	color = Color transparent ifTrue: [^self].	"Skip the gradient attempts, which will drop into debugger"
- 	color = fillColor2 ifTrue: [^self].	"same color; no gradient"
- 	"Check if we can use the cached gradient fill"
- 	((self valueOfProperty: #cachedGradientColor1) = color 
- 		and: [(self valueOfProperty: #cachedGradientColor2) = fillColor2]) 
- 			ifTrue: [style := self valueOfProperty: #cachedGradientFill].
- 	style ifNil: 
- 			[style := GradientFillStyle ramp: { 
- 								0.0 -> color.
- 								1.0 -> fillColor2}.
- 			self setProperty: #cachedGradientColor1 toValue: color.
- 			self setProperty: #cachedGradientColor2 toValue: fillColor2.
- 			self setProperty: #cachedGradientFill toValue: style].
- 	style origin: self position.
- 	style direction: (gradientDirection == #vertical 
- 				ifTrue: [0 @ self height]
- 				ifFalse: [self width @ 0]).
- 	aCanvas fillRectangle: self innerBounds fillStyle: style!

Item was removed:
- ----- Method: GradientFillMorph>>gradientFillColor: (in category 'accessing') -----
- gradientFillColor: aColor
- 
- 	fillColor2 := aColor.
- 	self changed.
- !

Item was removed:
- ----- Method: GradientFillMorph>>hasTranslucentColor (in category 'accessing') -----
- hasTranslucentColor
- 	"Answer true if this any of this morph is translucent but not transparent."
- 
- 	(color isColor and: [color isTranslucentColor]) ifTrue: [^ true].
- 	(fillColor2 isColor and: [fillColor2 isTranslucentColor]) ifTrue: [^ true].
- 	^ false
- !

Item was removed:
- ----- Method: GradientFillMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	self borderWidth: 0.
- 	fillColor2 := Color black.
- 	gradientDirection := #vertical!

Item was removed:
- ----- Method: GradientFillMorph>>setGradientColor: (in category 'menu') -----
- setGradientColor: evt
- 
- 	self changeColorTarget: self selector: #gradientFillColor: originalColor: fillColor2 hand: evt hand!

Item was removed:
- RectangleMorph subclass: #GraphMorph
- 	instanceVariableNames: 'data dataColor cursor cursorColor cursorColorAtZeroCrossings startIndex minVal maxVal cachedForm hasChanged'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !GraphMorph commentStamp: '<historical>' prior: 0!
- I display a graph of numbers, normalized so the full range of values just fits my height. I support a movable cursor that can be dragged with the mouse.
- 
- Implementation notes: Some operations on me may be done at sound sampling rates (e.g. 11-44 thousand times/second). To allow such high bandwidth application, certain operations that change my appearance do not immediately report a damage rectangle. Instead, a flag is set indicating that my display needs to refreshed and a step method reports the damage rectangle if that flag is set. Also, I cache a bitmap of my graph to allow the cursor to be moved without redrawing the graph.
- !

Item was removed:
- ----- Method: GraphMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'Graph' translatedNoop
- 		categories:		#()
- 		documentation:	'A graph of numbers, normalized so the full range of values just fits my height.  I support a movable cursor that can be dragged with the mouse.' translatedNoop!

Item was removed:
- ----- Method: GraphMorph>>addCustomMenuItems:hand: (in category 'sound') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'open wave editor' translated action: #openWaveEditor.
- 	aCustomMenu add: 'read file' translated action: #readDataFromFile.
- !

Item was removed:
- ----- Method: GraphMorph>>appendValue: (in category 'commands') -----
- appendValue: aPointOrNumber
- 
- 	| newVal |
- 	(data isKindOf: OrderedCollection) ifFalse: [data := data asOrderedCollection].
- 	newVal := self asNumber: aPointOrNumber.
- 	data addLast: newVal.
- 	newVal < minVal ifTrue: [minVal := newVal].
- 	newVal > maxVal ifTrue: [maxVal := newVal].
- 	self cursor: data size.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>centerCursor (in category 'commands') -----
- centerCursor
- 	"Scroll so that the cursor is as close as possible to the center of my window."
- 
- 	| w |
- 	w := self width - (2 * self borderWidth).
- 	self startIndex: ((cursor - (w // 2)) max: 1).
- !

Item was removed:
- ----- Method: GraphMorph>>clear (in category 'commands') -----
- clear
- 
- 	self startIndex: 1.
- 	self cursor: 1.
- 	self data: OrderedCollection new.
- !

Item was removed:
- ----- Method: GraphMorph>>color: (in category 'accessing') -----
- color: aColor
- 
- 	super color: aColor.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>convertToCurrentVersion:refStream: (in category 'objects from disk') -----
- convertToCurrentVersion: varDict refStream: smartRefStrm
- 	
- 	hasChanged ifNil: [hasChanged := false].
- 	^super convertToCurrentVersion: varDict refStream: smartRefStrm.
- 
- !

Item was removed:
- ----- Method: GraphMorph>>cursor (in category 'e-toy support') -----
- cursor
- 
- 	^ cursor
- !

Item was removed:
- ----- Method: GraphMorph>>cursor: (in category 'e-toy support') -----
- cursor: aNumber
- 
- 	| truncP |
- 	cursor ~= aNumber ifTrue:  [
- 		cursor := aNumber.
- 		truncP := aNumber truncated.
- 		truncP > data size ifTrue: [cursor := data size].
- 		truncP < 0 ifTrue: [cursor := 1].
- 		self keepIndexInView: truncP.
- 		hasChanged := true].
- !

Item was removed:
- ----- Method: GraphMorph>>cursorAtEnd (in category 'accessing') -----
- cursorAtEnd
- 
- 	^ cursor truncated >= data size
- !

Item was removed:
- ----- Method: GraphMorph>>cursorColor (in category 'accessing') -----
- cursorColor
- 
- 	^ cursorColor
- !

Item was removed:
- ----- Method: GraphMorph>>cursorColor: (in category 'accessing') -----
- cursorColor: aColor
- 
- 	cursorColor := aColor.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>cursorColorAtZeroCrossing (in category 'accessing') -----
- cursorColorAtZeroCrossing
- 
- 	^ cursorColorAtZeroCrossings
- !

Item was removed:
- ----- Method: GraphMorph>>cursorColorAtZeroCrossings: (in category 'accessing') -----
- cursorColorAtZeroCrossings: aColor
- 
- 	cursorColorAtZeroCrossings := aColor.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>cursorWrapped: (in category 'accessing') -----
- cursorWrapped: aNumber
- 
- 	| sz |
- 	cursor ~= aNumber ifTrue: [
- 		cursor := aNumber.
- 		sz := data size.
- 		sz = 0
- 			ifTrue: [cursor := 1]
- 			ifFalse: [
- 				((cursor >= (sz + 1)) or: [cursor < 0]) ifTrue: [
- 					cursor := cursor - ((cursor // sz) * sz)].
- 				cursor < 1 ifTrue: [cursor := sz + cursor]].
- 		"assert: 1 <= cursor < data size + 1"
- 		hasChanged := true].
- !

Item was removed:
- ----- Method: GraphMorph>>data (in category 'accessing') -----
- data
- 
- 	^ data
- !

Item was removed:
- ----- Method: GraphMorph>>data: (in category 'accessing') -----
- data: aCollection
- 
- 	data := aCollection.
- 	maxVal := minVal := 0.
- 	data do: [:x |
- 		x < minVal ifTrue: [minVal := x].
- 		x > maxVal ifTrue: [maxVal := x]].
- 
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>dataColor (in category 'accessing') -----
- dataColor
- 
- 	^ dataColor
- !

Item was removed:
- ----- Method: GraphMorph>>dataColor: (in category 'accessing') -----
- dataColor: aColor
- 
- 	dataColor := aColor.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0.8
- 		g: 0.8
- 		b: 0.6!

Item was removed:
- ----- Method: GraphMorph>>drawCursorOn: (in category 'private') -----
- drawCursorOn: aCanvas
- 
- 	| ptr x r c |
- 	ptr := (cursor asInteger max: 1) min: data size.
- 	c := cursorColor.
- 	((ptr > 1) and: [ptr < data size]) ifTrue: [
- 		(data at: ptr) sign ~= (data at: ptr + 1) sign
- 			ifTrue: [c := cursorColorAtZeroCrossings]].
- 	r := self innerBounds.
- 	x := r left + ptr - startIndex.
- 	((x >= r left) and: [x <= r right]) ifTrue: [
- 		aCanvas fillRectangle: (x at r top corner: x + 1 at r bottom) color: c].
- !

Item was removed:
- ----- Method: GraphMorph>>drawDataOn: (in category 'private') -----
- drawDataOn: aCanvas
- 
- 	| yScale baseLine x start end value left top bottom right |
- 	super drawOn: aCanvas.
- 
- 	data isEmpty ifTrue: [^ self].
- 	maxVal = minVal ifTrue: [
- 		yScale := 1.
- 	] ifFalse: [
- 		yScale := (self bounds height - (2 * self borderWidth)) asFloat / (maxVal - minVal)].
- 	baseLine := self bounds bottom - self borderWidth + (minVal * yScale) truncated.
- 	left := top := 0. right := 10. bottom := 0.
- 	x := self bounds left + self borderWidth.
- 	start := (startIndex asInteger max: 1) min: data size.
- 	end := (start + self bounds width) min: data size.
- 	start to: end do: [:i |
- 		left := x truncated. right := x + 1.
- 		right > (self bounds right - self borderWidth) ifTrue: [^ self].
- 		value := (data at: i) asFloat.
- 		value >= 0.0 ifTrue: [
- 			top := baseLine - (yScale * value) truncated.
- 			bottom := baseLine.
- 		] ifFalse: [
- 			top := baseLine.
- 			bottom := baseLine - (yScale * value) truncated].
- 		aCanvas fillRectangle: (left at top corner: right at bottom) color: dataColor.
- 		x := x + 1].
- !

Item was removed:
- ----- Method: GraphMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas 
- 	| c |
- 	cachedForm isNil 
- 		ifTrue: 
- 			[c := Display defaultCanvasClass extent: bounds extent.
- 			c translateBy: bounds origin negated
- 				during: [:tempCanvas | self drawDataOn: tempCanvas].
- 			cachedForm := c form].
- 	aCanvas 
- 		cache: bounds
- 		using: cachedForm
- 		during: [:cachingCanvas | self drawDataOn: cachingCanvas].
- 	self drawCursorOn: aCanvas!

Item was removed:
- ----- Method: GraphMorph>>flushCachedForm (in category 'private') -----
- flushCachedForm
- 
- 	cachedForm := nil.
- 	hasChanged := true.
- !

Item was removed:
- ----- Method: GraphMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	evt shiftPressed
- 		ifTrue: [^ super handlesMouseDown: evt]
- 		ifFalse: [^ true].
- !

Item was removed:
- ----- Method: GraphMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	self extent: 365 @ 80.
- 
- 	dataColor := Color darkGray.
- 	cursor := 1.0.
- 	"may be fractional"
- 	cursorColor := Color red.
- 	cursorColorAtZeroCrossings := Color red.
- 	startIndex := 1.
- 	hasChanged := false.
- 	self
- 		data: ((0 to: 360 - 1)
- 				collect: [:x | (100.0 * x degreesToRadians sin) asInteger])!

Item was removed:
- ----- Method: GraphMorph>>interpolatedValueAtCursor (in category 'accessing') -----
- interpolatedValueAtCursor
- 	| sz prev frac next |
- 	data isEmpty ifTrue: [^0].
- 	sz := data size.
- 	cursor < 0 ifTrue: [^data first].	"just to be safe, though cursor shouldn't be negative"
- 	prev := cursor truncated.
- 	frac := cursor - prev.
- 	prev < 1 ifTrue: [prev := sz].
- 	prev > sz ifTrue: [prev := 1].
- 	"assert: 1 <= prev <= sz"
- 	frac = 0 ifTrue: [^data at: prev].	"no interpolation needed"
- 
- 	"interpolate"
- 	next := prev = sz ifTrue: [1] ifFalse: [prev + 1].
- 	^(1.0 - frac) * (data at: prev) + (frac * (data at: next))!

Item was removed:
- ----- Method: GraphMorph>>keepIndexInView: (in category 'private') -----
- keepIndexInView: index
- 
- 	| w newStart |
- 	w := self bounds width - (2 * self borderWidth).
- 	index < startIndex ifTrue: [
- 		newStart := index - w + 1.
- 		^ self startIndex: (newStart max: 1)].
- 	index > (startIndex + w) ifTrue: [
- 		^ self startIndex: (index min: data size)].
- !

Item was removed:
- ----- Method: GraphMorph>>lastValue (in category 'accessing') -----
- lastValue
- 	data isEmpty ifTrue: [^0].
- 	^data last!

Item was removed:
- ----- Method: GraphMorph>>lastValue: (in category 'accessing') -----
- lastValue: aNumber
- 
- 	self appendValue: aNumber.
- !

Item was removed:
- ----- Method: GraphMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 
- 	super layoutChanged.
- 	cachedForm := nil.
- !

Item was removed:
- ----- Method: GraphMorph>>loadSineWave (in category 'commands') -----
- loadSineWave
- 
- 	self loadSoundData: SoundBuffer sineTable.
- !

Item was removed:
- ----- Method: GraphMorph>>loadSound: (in category 'commands') -----
- loadSound: aSound
- 
- 	self loadSoundData: aSound samples.
- !

Item was removed:
- ----- Method: GraphMorph>>loadSoundData: (in category 'commands') -----
- loadSoundData: aCollection
- 
- 	| newData scale |
- 	scale := 0.
- 	aCollection do: [:v |
- 		| absV |
- 		(absV := v abs) > scale ifTrue: [scale := absV]].
- 	scale := 100.0 / scale.
- 	newData := OrderedCollection new: aCollection size.
- 	1 to: aCollection size do: [:i | newData addLast: (scale * (aCollection at: i))].
- 
- 	self data: newData.
- 	self startIndex: 1.
- 	self cursor: 1.
- !

Item was removed:
- ----- Method: GraphMorph>>mouseMove: (in category 'event handling') -----
- mouseMove: evt
- 
- 	| x w |
- 	x := evt cursorPoint x - (self bounds left + self borderWidth).
- 	w := self width - (2 * self borderWidth).
- 
- 	self changed.
- 	x < 0 ifTrue: [
- 		cursor := startIndex + (3 * x).
- 		cursor := (cursor max: 1) min: data size.
- 		^ self startIndex: cursor].
- 	x > w ifTrue: [
- 		cursor := startIndex + w + (3 * (x - w)).
- 		cursor := (cursor max: 1) min: data size.
- 		^ self startIndex: cursor - w].
- 
- 	cursor := ((startIndex + x) max: 1) min: data size.
- !

Item was removed:
- ----- Method: GraphMorph>>openWaveEditor (in category 'sound') -----
- openWaveEditor
- 
- 	| scaleFactor scaledData editor |
- 	self data: data.  "make sure maxVal and minVal are current"
- 	scaleFactor := 32767 // ((minVal abs max: maxVal abs) max: 1).
- 	scaledData := SoundBuffer newMonoSampleCount: data size.
- 	1 to: data size do: [:i | scaledData at: i put: (scaleFactor * (data at: i)) truncated].
- 	editor := WaveEditor new
- 		data: scaledData;
- 		samplingRate: 11025;
- 		perceivedFrequency: 220.0.
- 	editor openInWorld.
- !

Item was removed:
- ----- Method: GraphMorph>>playOnce (in category 'commands') -----
- playOnce
- 
- 	| scaledData scale |
- 	data isEmpty ifTrue: [^ self].  "nothing to play"
- 	scale := 1.
- 	data do: [:v |
- 		| absV |
- 		(absV := v abs) > scale ifTrue: [scale := absV]].
- 	scale := 32767.0 / scale.
- 	scaledData := SoundBuffer newMonoSampleCount: data size.
- 	1 to: data size do: [:i | scaledData at: i put: (scale * (data at: i)) truncated].
- 	SoundService default playSampledSound: scaledData rate: 11025.
- !

Item was removed:
- ----- Method: GraphMorph>>readDataFromFile (in category 'sound') -----
- readDataFromFile
- "This makes very little sense; it appears to be inteded as a general load data method but explicitly handles only AIFF files; very odd"
- 	| fileName |
- 	fileName := UIManager default
- 		chooseFileMatchingSuffixes: #('aif')
- 		label: 'File name?' translated.
- 	fileName isEmpty ifTrue: [^ self].
- 	(StandardFileStream isAFileNamed: fileName) ifFalse: [
- 		^ self inform: 'Sorry, I cannot find that file' translated].
- 	self data: (SampledSound fromAIFFfileNamed: fileName) samples.
- 
- !

Item was removed:
- ----- Method: GraphMorph>>reverse (in category 'commands') -----
- reverse
- 
- 	data := data reversed.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: GraphMorph>>startIndex (in category 'accessing') -----
- startIndex
- 
- 	^ startIndex
- !

Item was removed:
- ----- Method: GraphMorph>>startIndex: (in category 'accessing') -----
- startIndex: aNumber
- 
- 	startIndex ~= aNumber ifTrue:  [
- 		startIndex := aNumber asInteger.
- 		self flushCachedForm].
- !

Item was removed:
- ----- Method: GraphMorph>>step (in category 'stepping and presenter') -----
- step
- 	"Make a deferred damage rectangle if I've changed. This allows applications to call methods that invalidate my display at high-bandwidth without paying the cost of doing the damage reporting on ever call; they can merely set hasChanged to true."
- 
- 	super step.
- 	hasChanged isNil ifTrue: [hasChanged := false].
- 	hasChanged 
- 		ifTrue: 
- 			[self changed.
- 			hasChanged := false]!

Item was removed:
- ----- Method: GraphMorph>>valueAtCursor (in category 'accessing') -----
- valueAtCursor
- 
- 	data isEmpty ifTrue: [^ 0].
- 	^ data at: ((cursor truncated max: 1) min: data size)
- !

Item was removed:
- ----- Method: GraphMorph>>valueAtCursor: (in category 'accessing') -----
- valueAtCursor: aPointOrNumber
- 
- 	data isEmpty ifTrue: [^ 0].
- 	data
- 		at: ((cursor truncated max: 1) min: data size)
- 		put: (self asNumber: aPointOrNumber).
- 	self flushCachedForm.
- !

Item was removed:
- GraphicalMenu subclass: #GraphicalDictionaryMenu
- 	instanceVariableNames: 'baseDictionary entryNames lastSearchString'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalWidgets'!
- 
- !GraphicalDictionaryMenu commentStamp: '<historical>' prior: 0!
- A morph that allows you to view, rename, and remove elements from a dictionary whose keys are strings and whose values are forms.!

Item was removed:
- ----- Method: GraphicalDictionaryMenu class>>example (in category 'example') -----
- example
- 	"GraphicalDictionaryMenu example"
- 	| aDict |
- 	aDict := Dictionary new.
- 	#('ColorTilesOff' 'ColorTilesOn' 'Controls') do:
- 		[:aString | aDict at: aString put: (ScriptingSystem formAtKey: aString)].
- 	self openOn: aDict withLabel: 'Testing One Two Three'!

Item was removed:
- ----- Method: GraphicalDictionaryMenu class>>example2 (in category 'example') -----
- example2
- 	"GraphicalDictionaryMenu example2"
- 	| aDict |
- 	aDict := Dictionary new.
- 	self openOn: aDict withLabel: 'Testing Zero'!

Item was removed:
- ----- Method: GraphicalDictionaryMenu class>>openOn:withLabel: (in category 'instance creation') -----
- openOn: aFormDictionary withLabel: aLabel
- 	"open a graphical dictionary in a window having the label aLabel. 
-      aFormDictionary should be a dictionary containing as value a form."
- 
- 	| inst aWindow |
- 	aFormDictionary size isZero ifTrue: [^ self inform: 'Empty!!' translated].	
- 	inst := self new initializeFor: nil fromDictionary: aFormDictionary.
- 
- 	aWindow := (SystemWindow labelled: aLabel) model: inst.
- 	aWindow addMorph: inst frame: (0 at 0 extent: 1 at 1).
- 	aWindow extent: inst fullBounds extent + (3 @ aWindow labelHeight + 3);
- 		minimumExtent: inst minimumExtent + (3 @ aWindow labelHeight + 3).
- 	
-      HandMorph attach: aWindow.
- 
- 	^ inst!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>baseDictionary: (in category 'initialization') -----
- baseDictionary: aDictionary
- 	baseDictionary := aDictionary.
- 	entryNames := aDictionary keys asArray sort.
- 	formChoices := entryNames collect: [:n | aDictionary at: n].
- 	currentIndex := 1!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>browseIconReferences (in category 'menu commands') -----
- browseIconReferences
- 	"Browse all calls on the symbol by which the currently-seen graphic is keyed"
- 
- 	self systemNavigation browseAllCallsOn: self nameOfGraphic!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>browseStringIconReferences (in category 'menu commands') -----
- browseStringIconReferences
- 	"Browse string references to the selected entry's key"
- 
- 	self systemNavigation browseMethodsWithString: self nameOfGraphic asString matchCase: true!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>copyName (in category 'menu commands') -----
- copyName
- 	"Copy the name of the current selection to the clipboard"
- 
- 	Clipboard clipboardText: self nameOfGraphic asText!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>encodeToWorkspace (in category 'menu commands') -----
- encodeToWorkspace
- 	| stream encodedStream pict text |
- 	pict := formChoices at: currentIndex.
- 	stream := ByteArray new writeStream.
- 	PNGReadWriter putForm: pict onStream: stream.
- 	encodedStream := stream contents base64Encoded.
- 	text := Workspace open model.
- 	text contents: 'Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: ''', encodedStream,''' readStream)'!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>findAgain (in category 'menu commands') -----
- findAgain
- 	"Look for the next occurrence of the search string"
- 
- 	| toFind searchIndex |
- 	lastSearchString ifNil: [lastSearchString := 'controls'].
- 	searchIndex := currentIndex + 1.
- 	searchIndex > entryNames size ifTrue:
- 		[currentIndex := 0.
- 		self inform: 'not found' translated.
- 		^ self].
- 	toFind := '*', lastSearchString, '*'.
- 	[toFind match: (entryNames at: searchIndex) asString]
- 		whileFalse:
- 			[searchIndex := (searchIndex \\ entryNames size) + 1.
- 			searchIndex == currentIndex ifTrue:
- 				[^ (toFind match: (entryNames at: searchIndex) asString)
- 					ifFalse:
- 						[self inform: 'not found' translated]
- 					ifTrue:
- 						[self flash]]].
- 
- 	currentIndex := searchIndex.
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>findEntry (in category 'menu commands') -----
- findEntry
- 	"Prompt the user for a search string and find the next match for it"
- 
- 	| toFind searchIndex |
- 	lastSearchString ifNil: [lastSearchString := 'controls'].
- 	toFind := UIManager default request: 'Type name or fragment: ' initialAnswer: lastSearchString.
- 	toFind isEmptyOrNil ifTrue: [^ self].
- 	lastSearchString := toFind asLowercase.
- 	searchIndex := currentIndex + 1.
- 	toFind := '*', lastSearchString, '*'.
- 	[toFind match: (entryNames at: searchIndex) asString]
- 		whileFalse:
- 			[searchIndex := (searchIndex \\ entryNames size) + 1.
- 			searchIndex == currentIndex ifTrue: [^ self inform: 'not found']].
- 
- 	currentIndex := searchIndex.
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>handMeOne (in category 'menu commands') -----
- handMeOne
- 	self currentHand attachMorph: (self world drawingClass new form: (formChoices at: currentIndex))!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>initializeFor:fromDictionary: (in category 'initialization') -----
- initializeFor: aTarget fromDictionary: aDictionary 
- 	"Initialize me for a target and a dictionary."
- 
- 	| anIndex aButton |
- 	self baseDictionary: aDictionary.
- 	target := aTarget.
- 	coexistWithOriginal := true.
- 	self extent: 210 @ 210.
- 	self clipSubmorphs: true.
- 	self layoutPolicy: ProportionalLayout new.
- 	aButton := (IconicButton new)
- 				borderWidth: 0;
- 				labelGraphic: (ScriptingSystem formAtKey: 'TinyMenu');
- 				color: Color transparent;
- 				actWhen: #buttonDown;
- 				actionSelector: #showMenu;
- 				target: self;
- 				setBalloonText: 'menu'.
- 	self addMorph: aButton
- 		fullFrame: (LayoutFrame fractions: (0.5 @ 0 extent: 0 @ 0)
- 				offsets: (-50 @ 6 extent: aButton extent)).
- 	aButton := (SimpleButtonMorph new)
- 				target: self;
- 				borderColor: Color black;
- 				label: 'Prev';
- 				actionSelector: #downArrowHit;
- 				actWhen: #whilePressed;
- 				setBalloonText: 'show previous picture';
- 				yourself.
- 	self addMorph: aButton
- 		fullFrame: (LayoutFrame fractions: (0.5 @ 0 extent: 0 @ 0)
- 				offsets: (-24 @ 4 extent: aButton extent)).
- 	aButton := (SimpleButtonMorph new)
- 				target: self;
- 				borderColor: Color black;
- 				label: 'Next';
- 				actionSelector: #upArrowHit;
- 				actWhen: #whilePressed;
- 				setBalloonText: 'show next pictutre'.
- 	self addMorph: aButton
- 		fullFrame: (LayoutFrame fractions: (0.5 @ 0 extent: 0 @ 0)
- 				offsets: (24 @ 4 extent: aButton extent)).
- 	self addMorph: ((UpdatingStringMorph new)
- 				contents: ' ';
- 				target: self;
- 				putSelector: #renameGraphicTo:;
- 				getSelector: #truncatedNameOfGraphic;
- 				useStringFormat;
- 				setBalloonText: 'The name of the current graphic';
- 				yourself)
- 		fullFrame: (LayoutFrame fractions: (0 @ 0 extent: 1 @ 0)
- 				offsets: (10 @ 40 corner: -10 @ 60)).
- 	self addMorph: ((Morph new)
- 				extent: 100 @ 4;
- 				color: Color black)
- 		fullFrame: (LayoutFrame fractions: (0 @ 0 extent: 1 @ 0)
- 				offsets: (0 @ 60 corner: 0 @ 64)).
- 	formDisplayMorph := (Thumbnail new)
- 				extent: 100 @ 100;
- 				useInterpolation: true;
- 				maxWidth: 300 minHeight: 100;
- 				yourself.
- 	formDisplayMorph layoutFrame: 
- 		(LayoutFrame fractions: (0 @ 0 extent: 0 at 0)
- 				offsets: (8 @ 72 corner:  108 @ 172)).				
- 	self addMorph: formDisplayMorph.
- 	self minimumExtent: 116 at 180.
- 	target ifNotNil: 
- 			[(anIndex := formChoices indexOf: target form ifAbsent: []) 
- 				ifNotNil: [currentIndex := anIndex]].
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>nameOfGraphic (in category 'private') -----
- nameOfGraphic
- 	^ entryNames at: currentIndex!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>removeEntry (in category 'menu commands') -----
- removeEntry
- 	baseDictionary removeKey: (entryNames at: currentIndex).
- 	self baseDictionary: baseDictionary.
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>renameEntry (in category 'menu commands') -----
- renameEntry
- 	| reply curr |
- 	reply := UIManager default
- 		request: 'New key? '
- 		initialAnswer: (curr := entryNames at: currentIndex).
- 	(reply isEmptyOrNil or: [reply = curr]) ifTrue: [^ Beeper beep].
- 	(baseDictionary includesKey: reply) ifTrue:
- 		[^ self inform: 'sorry that conflicts with
- the name of another
- entry in this dictionary'].
- 	baseDictionary at: reply put: (baseDictionary at: curr).
- 	baseDictionary removeKey: curr.
- 	self baseDictionary: baseDictionary.
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>renameGraphicTo: (in category 'menu commands') -----
- renameGraphicTo: newName
- 	| curr |
- 	curr := entryNames at: currentIndex.
- 	(newName isEmptyOrNil or: [newName = curr]) ifTrue: [^ Beeper beep].
- 	(baseDictionary includesKey: newName) ifTrue:
- 		[^ self inform: 'sorry that conflicts with
- the name of another
- entry in this dictionary' translated].
- 	baseDictionary at: newName put: (baseDictionary at: curr).
- 	baseDictionary removeKey: curr.
- 	self baseDictionary: baseDictionary.
- 	currentIndex := entryNames indexOf: newName.
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>repaintEntry (in category 'menu commands') -----
- repaintEntry
- 	"Let the user enter into painting mode to repaint the item and save it back."
- 
- 	| aWorld bnds sketchEditor aPaintBox formToEdit |
- 	
- 	(aWorld := self world) assureNotPaintingElse: [^ self].
- 
- 	aWorld prepareToPaint.
- 	aWorld displayWorld.
- 	formToEdit := formChoices at: currentIndex.
- 	bnds := (submorphs second boundsInWorld origin extent: formToEdit extent) intersect: aWorld bounds.
- 	bnds := (aWorld paintingBoundsAround: bnds center) merge: bnds.
- 	sketchEditor := SketchEditorMorph new.
- 	aWorld addMorphFront: sketchEditor.
- 	sketchEditor initializeFor: ((aWorld drawingClass withForm: formToEdit) position: submorphs second positionInWorld)  inBounds: bnds pasteUpMorph: aWorld paintBoxPosition: bnds topRight.
- 	sketchEditor
- 		afterNewPicDo: [:aForm :aRect |
- 			formChoices at: currentIndex put: aForm.
- 			baseDictionary at: (entryNames at: currentIndex) put: aForm.
- 			self updateThumbnail.
- 			(aPaintBox := aWorld paintBoxOrNil) ifNotNil: [aPaintBox delete]] 
- 		ifNoBits:
- 			[(aPaintBox := aWorld paintBoxOrNil) ifNotNil: [aPaintBox delete]].
- 	
- !

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>showMenu (in category 'menu commands') -----
- showMenu
- 	"Show the receiver's menu"
- 
- 	| aMenu |
- 	aMenu := MenuMorph new defaultTarget: self.
- 	aMenu title: 'Graphics Library'.
- 	aMenu addStayUpItem.
- 	aMenu addList: #(
- 		('remove'			removeEntry			'Remove this entry from the dictionary')
- 		('rename'			renameEntry			'Rename this entry')
- 		('repaint'			repaintEntry			'Edit the actual graphic for this entry' )
- 		-
- 		('hand me one'		handMeOne				'Hand me a morph with this picture as its form')
- 		('encode to Workspace'	encodeToWorkspace		'Open a Workspace with the grapics encoded to be added to code')
- 		('browse symbol references'
- 							browseIconReferences	'Browse methods that refer to this icon''s name')
- 		('browse string references'
- 							browseStringIconReferences 'Browse methods that refer to string constants that contain this icon''s name')
- 		('copy name'		copyName				'Copy the name of this graphic to the clipboard')
- 		-
- 		('find...'			findEntry				'Find an entry by name')
- 		('find again'		findAgain				'Find the next match for the keyword previously searched for')).
- 	aMenu popUpInWorld
- !

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>truncatedNameOfGraphic (in category 'menu commands') -----
- truncatedNameOfGraphic
- 	^ self nameOfGraphic truncateTo: 30!

Item was removed:
- ----- Method: GraphicalDictionaryMenu>>updateThumbnail (in category 'private') -----
- updateThumbnail
- 	super updateThumbnail.
- 	(self findA: UpdatingStringMorph)
- 		doneWithEdits;
- 		contents: (entryNames at: currentIndex)
- !

Item was removed:
- AlignmentMorph subclass: #GraphicalMenu
- 	instanceVariableNames: 'target selector argument currentIndex formChoices formDisplayMorph coexistWithOriginal'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalWidgets'!

Item was removed:
- ----- Method: GraphicalMenu>>argument (in category 'accessing') -----
- argument
- 	^argument!

Item was removed:
- ----- Method: GraphicalMenu>>argument: (in category 'accessing') -----
- argument: anObject
- 	argument := anObject!

Item was removed:
- ----- Method: GraphicalMenu>>cancel (in category 'event handling') -----
- cancel
- 	coexistWithOriginal
- 		ifTrue:
- 			[self delete]
- 		ifFalse:
- 			[owner replaceSubmorph: self topRendererOrSelf by: target]!

Item was removed:
- ----- Method: GraphicalMenu>>defaultBorderColor (in category 'initialization') -----
- defaultBorderColor
- 	"answer the default border color/fill style for the receiver"
- 	^ Color blue darker!

Item was removed:
- ----- Method: GraphicalMenu>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: GraphicalMenu>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color white!

Item was removed:
- ----- Method: GraphicalMenu>>downArrowHit (in category 'event handling') -----
- downArrowHit
- 	currentIndex := currentIndex - 1.
- 	(currentIndex < 1) ifTrue:  [currentIndex := formChoices size].
- 	self updateThumbnail
- 	
- !

Item was removed:
- ----- Method: GraphicalMenu>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	selector := #newForm:.!

Item was removed:
- ----- Method: GraphicalMenu>>initializeFor:withForms:coexist: (in category 'initialization') -----
- initializeFor: aTarget withForms: formList coexist: aBoolean 
- 	"World primaryHand attachMorph:
- 		(GraphicalMenu new initializeFor: nil  
- 		withForms: Form allInstances coexist: true)"
- 	| buttons bb anIndex buttonCage |
- 	target := aTarget.
- 	coexistWithOriginal := aBoolean.
- 	formChoices := formList.
- 	currentIndex := 1.
- 	self borderWidth: 1;
- 		 cellPositioning: #center;
- 		 color: Color white;
- 		 hResizing: #shrinkWrap;
- 		 vResizing: #shrinkWrap.
- 	buttons := AlignmentMorph newRow.
- 	buttons borderWidth: 0;
- 		 layoutInset: 0.
- 	buttons hResizing: #shrinkWrap;
- 		 vResizing: #shrinkWrap;
- 		 extent: 5 @ 5.
- 	buttons wrapCentering: #topLeft.
- 	buttonCage := AlignmentMorph newColumn.
- 	buttonCage hResizing: #shrinkWrap;
- 		 vResizing: #spaceFill.
- 	buttonCage addTransparentSpacerOfSize: 0 @ 10.
- 	bb := SimpleButtonMorph new target: self;
- 				 borderColor: Color black.
- 	buttons addMorphBack: (bb label: 'Prev' translated;
- 			 actionSelector: #downArrowHit;
- 			 actWhen: #whilePressed).
- 	buttons addTransparentSpacerOfSize: 9 @ 0.
- 	bb := SimpleButtonMorph new target: self;
- 				 borderColor: Color black.
- 	buttons addMorphBack: (bb label: 'Next' translated;
- 			 actionSelector: #upArrowHit;
- 			 actWhen: #whilePressed).
- 	buttons addTransparentSpacerOfSize: 5 @ 0.
- 	buttons submorphs last color: Color white.
- 	buttonCage addMorphBack: buttons.
- 	buttonCage addTransparentSpacerOfSize: 0 @ 12.
- 	buttons := AlignmentMorph newRow.
- 	bb := SimpleButtonMorph new target: self;
- 				 borderColor: Color black.
- 	buttons addMorphBack: (bb label: 'OK' translated;
- 			 actionSelector: #okay).
- 	buttons addTransparentSpacerOfSize: 5 @ 0.
- 	bb := SimpleButtonMorph new target: self;
- 				 borderColor: Color black.
- 	buttons addMorphBack: (bb label: 'Cancel' translated;
- 			 actionSelector: #cancel).
- 	buttonCage addMorphBack: buttons.
- 	buttonCage addTransparentSpacerOfSize: 0 @ 10.
- 	self addMorphFront: buttonCage.
- 	formDisplayMorph := Thumbnail new extent: 100 @ 100;
- 				 maxWidth: 100 minHeight: 30;
- 				 yourself.
- 	self addMorphBack: (Morph new color: Color white;
- 			 layoutPolicy: TableLayout new;
- 			 layoutInset: 4 @ 4;
- 			 hResizing: #spaceFill;
- 			 vResizing: #spaceFill;
- 			 listCentering: #center;
- 			 addMorphBack: formDisplayMorph;
- 			 yourself).
- 	target
- 		ifNotNil: [(anIndex := formList
- 						indexOf: target form
- 						ifAbsent: [])
- 				ifNotNil: [currentIndex := anIndex]].
- 	self updateThumbnail!

Item was removed:
- ----- Method: GraphicalMenu>>okay (in category 'event handling') -----
- okay
- 	| nArgs |
- 	target ifNotNil:[
- 		nArgs := selector numArgs.
- 		nArgs = 1 ifTrue:[target perform: selector with: (formChoices at: currentIndex)].
- 		nArgs = 2 ifTrue:[target perform: selector with: (formChoices at: currentIndex) with: argument]].
- 	coexistWithOriginal
- 		ifTrue:
- 			[self delete]
- 		ifFalse:
- 			[owner replaceSubmorph: self topRendererOrSelf by: target]!

Item was removed:
- ----- Method: GraphicalMenu>>selector (in category 'accessing') -----
- selector
- 	^selector!

Item was removed:
- ----- Method: GraphicalMenu>>selector: (in category 'accessing') -----
- selector: aSymbol
- 	selector := aSymbol!

Item was removed:
- ----- Method: GraphicalMenu>>upArrowHit (in category 'event handling') -----
- upArrowHit
- 	currentIndex := currentIndex + 1.
- 	(currentIndex > formChoices size) ifTrue: [currentIndex := 1].
- 	self updateThumbnail
- 	
- !

Item was removed:
- ----- Method: GraphicalMenu>>updateThumbnail (in category 'event handling') -----
- updateThumbnail
- 	| f |
- 	f := formChoices at: currentIndex.
- 	formDisplayMorph 
- 		makeThumbnailFromForm: f.
- !

Item was removed:
- ----- Method: HTTPDownloadRequest>>url (in category '*MorphicExtras-accessing') -----
- url
- 	^url!

Item was removed:
- ----- Method: HandMorph>>pauseEventRecorderIn: (in category '*MorphicExtras-event handling') -----
- pauseEventRecorderIn: aWorld
- 	"Suspend any recorder prior to a project change, and return it.
- 	It will be resumed after starting the new project."
- 	eventListeners ifNil:[^nil].
- 	eventListeners do:
- 		[:er | (er isKindOf: EventRecorderMorph) ifTrue: [^ er pauseIn: aWorld]].
- 	^ nil!

Item was removed:
- HandMorph subclass: #HandMorphForReplay
- 	instanceVariableNames: 'recorder suspended'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalSupport'!
- 
- !HandMorphForReplay commentStamp: '<historical>' prior: 0!
- I am a hand for replaying events stored in an EventRecorderMorph.  When there are no more events, I delete myself.!

Item was removed:
- ----- Method: HandMorphForReplay>>initialize (in category 'initialization') -----
- initialize
- 	"Initialize the receiver."
- 
- 	super initialize.
- 	suspended := false.
- 	self showTemporaryCursor: Cursor normal
- !

Item was removed:
- ----- Method: HandMorphForReplay>>needsToBeDrawn (in category 'drawing') -----
- needsToBeDrawn
- 
- 	^true!

Item was removed:
- ----- Method: HandMorphForReplay>>pauseEventRecorderIn: (in category 'event handling') -----
- pauseEventRecorderIn: aWorld
- 	"Suspend my recorder prior to a project change, and return it.
- 	It will be resumed after starting the new project."
- 
- 	^ recorder pauseIn: aWorld!

Item was removed:
- ----- Method: HandMorphForReplay>>processEvents (in category 'event handling') -----
- processEvents
- 	"Play back the next event"
- 
- 	| evt hadMouse hadAny tracker  |
- 	suspended == true ifTrue: [^ self].
- 	hadMouse := hadAny := false.
- 	tracker := recorder objectTrackingEvents.
- 	[(evt := recorder nextEventToPlay) isNil] whileFalse: 
- 			[
- 			((evt isMemberOf: MouseMoveEvent) and: [evt trail isNil]) ifTrue: [^ self].
- 			tracker ifNotNil: [tracker currentEventTimeStamp: evt timeStamp].
- 			evt type == #EOF 
- 				ifTrue: 
- 					[recorder pauseIn: self currentWorld.
- 					^ self].
- 			evt type == #startSound 
- 				ifTrue: 
- 					[recorder perhapsPlaySound: evt argument.
- 					recorder synchronize.
- 					^ self].
- 			evt type == #startEventPlayback 
- 				ifTrue: 
- 					[evt argument launchPlayback.
- 					recorder synchronize.
- 					^ self].
- 
- 			evt type == #noteTheatreBounds 
- 				ifTrue: 
- 					["The argument holds the content rect --for now we don't make any use of that info in this form."
- 					^ self].
- 
- 			evt isMouse ifTrue: [hadMouse := true].
- 			(evt isMouse or: [evt isKeyboard]) 
- 				ifTrue: 
- 					[self handleEvent: (evt setHand: self) resetHandlerFields.
- 					hadAny := true]].
- 	(mouseClickState notNil and: [hadMouse not]) 
- 		ifTrue: 
- 			["No mouse events during this cycle. Make sure click states time out accordingly"
- 
- 			mouseClickState handleEvent: lastMouseEvent asMouseMove from: self].
- 	hadAny 
- 		ifFalse: 
- 			["No pending events. Make sure z-order is up to date"
- 
- 			self mouseOverHandler processMouseOver: lastMouseEvent]!

Item was removed:
- ----- Method: HandMorphForReplay>>recorder: (in category 'initialization') -----
- recorder: anEventRecorder
- 	recorder := anEventRecorder!

Item was removed:
- ----- Method: HandMorphForReplay>>showTemporaryCursor:hotSpotOffset: (in category 'cursor') -----
- showTemporaryCursor: cursorOrNil hotSpotOffset: hotSpotOffset
- 	"When I show my cursor, it appears double size,
- 	unless it is a form such as a paint brush."
- 
- 	cursorOrNil
- 	ifNil: ["Setting cursor to nil cannot revert to hardware cursor -- just show normal."
- 			^ self showTemporaryCursor: Cursor normal hotSpotOffset: Cursor normal offset]
- 	ifNotNil:
- 		[(cursorOrNil isKindOf: Cursor)
- 			ifTrue: ["Show cursors magnified for visibility"
- 					^ super showTemporaryCursor: (cursorOrNil asCursorForm magnifyBy: 2)
- 				 				hotSpotOffset: (cursorOrNil offset negated*2) + hotSpotOffset]
- 			ifFalse: [^ super showTemporaryCursor: cursorOrNil
- 				 				hotSpotOffset: hotSpotOffset]]!

Item was removed:
- ----- Method: HandMorphForReplay>>veryDeepCopyWith: (in category 'copying') -----
- veryDeepCopyWith: deepCopier
- 	"Handmorph blocks deep copy.  Go up to Morph"
- 
- 	^ self perform: #veryDeepCopyWith: withArguments: {deepCopier} inSuperclass: Morph!

Item was removed:
- RectangleMorph subclass: #HistogramMorph
- 	instanceVariableNames: 'bag cachedForm values counts max sum limit labelBlock countLabelBlock'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !HistogramMorph commentStamp: 'topa 6/14/2016 11:27' prior: 0!
- I display bags as a histogram, that is a bar chart of the counts in the bag.
- 
- Example:
- 	HistogramMorph openOn: (Smalltalk allClasses gather: 
- 		[:class | class selectors collect: [:selector | class ]])
- 
- 
- Instance Variables
- 	bag:		<Bag>
- 	cachedForm:		<Form>
- 	countLabelBlock:		<BlockClosure>
- 	counts:		<SequencableCollection>
- 	labelBlock:		<BlockClosure>
- 	limit:		<Number>
- 	max:		<Number>
- 	sum:		<Number>
- 	values:		<SequencableCollection>
- 
- bag
- 	- The bag that forms the data basis for the histogram display
- 
- cachedForm
- 	- A form used to cache the historgram rendering.
- 
- countLabelBlock
- 	- Optional. Block that receives the count for the current bar and should return a String.
- 	  Leaving this nil is equivalent to [:count | count asString].
- 
- counts
- 	- Cached collection of all counts in (value-)frequency-sorted order for rendering speed.
- 	See values.
- 
- labelBlock
- 	- Optional. Block that receives the value for the current bar and should return a 
- 	String for the label. Leaving this nil is equivalent to [:value | value asString].
- 
- limit
- 	- Maximum number of elements from values to consider. Defaults to 25.
- 
- max
- 	- Cached maximum value from values. 
- 
- sum
- 	- Cached sum of all elements in values. Determines overall histogram height.
- 
- values
- 	- Cached collection of all values in frequency-sorted order for rendering speed.
- 	See counts.!

Item was removed:
- ----- Method: HistogramMorph class>>on: (in category 'instance creation') -----
- on: aCollection
- 
- 	^ self new
- 		bag: aCollection asBag;
- 		yourself!

Item was removed:
- ----- Method: HistogramMorph class>>openOn: (in category 'instance creation') -----
- openOn: aCollection
- 
- 	^ (self on: aCollection)
- 		openInHand!

Item was removed:
- ----- Method: HistogramMorph>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aMenu hand: aHandMorph.
- 	
- 	aMenu add: 'set limit...' translated action: #editLimit.!

Item was removed:
- ----- Method: HistogramMorph>>bag (in category 'accessing') -----
- bag
- 
- 	^ bag!

Item was removed:
- ----- Method: HistogramMorph>>bag: (in category 'accessing') -----
- bag: anObject
- 
- 	self basicBag: anObject.
- 	self flush.
- 	self changed.
- !

Item was removed:
- ----- Method: HistogramMorph>>basicBag: (in category 'accessing') -----
- basicBag: anObject
- 
- 	bag := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>basicLimit: (in category 'accessing') -----
- basicLimit: anObject
- 
- 	limit := anObject.
- !

Item was removed:
- ----- Method: HistogramMorph>>cachedForm (in category 'accessing') -----
- cachedForm
- 
- 	^ cachedForm!

Item was removed:
- ----- Method: HistogramMorph>>cachedForm: (in category 'accessing') -----
- cachedForm: anObject
- 
- 	cachedForm := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>color: (in category 'accessing') -----
- color: aColor
- 
- 	super color: aColor.
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: HistogramMorph>>countLabelBlock (in category 'accessing') -----
- countLabelBlock
- 
- 	^ countLabelBlock!

Item was removed:
- ----- Method: HistogramMorph>>countLabelBlock: (in category 'accessing') -----
- countLabelBlock: anObject
- 
- 	countLabelBlock := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>countLabelFor: (in category 'drawing') -----
- countLabelFor: aNumber
- 
- 	^ self countLabelBlock 
- 		ifNotNil: [:block | block value: aNumber]
- 		ifNil: [aNumber asString]
- !

Item was removed:
- ----- Method: HistogramMorph>>counts (in category 'accessing') -----
- counts
- 
- 	^ counts!

Item was removed:
- ----- Method: HistogramMorph>>counts: (in category 'accessing') -----
- counts: anObject
- 
- 	counts := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	^ Color veryVeryLightGray!

Item was removed:
- ----- Method: HistogramMorph>>drawBar:value:count:chartHeight:font:on: (in category 'drawing') -----
- drawBar: aRectangle value: anObject count: anInteger chartHeight: chartHeight font: aFont on: aCanvas
- 
- 	| label countLabel labelWidth countWidth midX  |
- 	label := self labelFor: anObject.
- 	countLabel := self countLabelFor: anInteger.
- 	labelWidth := aFont widthOfString: label.
- 	countWidth := aFont widthOfString: countLabel.
- 	midX := aRectangle origin x + (aRectangle width // 2).
- 	
- 	aCanvas fillRectangle: aRectangle color: Color blue.
- 	self drawLabel: label width: labelWidth at: (midX - (labelWidth // 2) @ chartHeight) barWidth: aRectangle width font: aFont on: aCanvas.
- 	countWidth < aRectangle width
- 		ifTrue: [aCanvas drawString: countLabel at: (midX - (countWidth // 2) @ (chartHeight - (3/2 * aFont height))) font: aFont color: Color lightGray].
- !

Item was removed:
- ----- Method: HistogramMorph>>drawDataOn: (in category 'drawing') -----
- drawDataOn: aCanvas
- 
- 	| numX elementWidth offsetX font fontHeight offsetY maxY barWidth barRadius chartHeight |
- 	font := TextStyle defaultFont.
- 	fontHeight := font height.
- 	numX := self limit.
- 	maxY := self sum.
- 	elementWidth := self width / (numX + 1).
- 	barWidth := 2 max: (elementWidth * 0.9) floor.
- 	barRadius := barWidth / 2.
- 	offsetX := elementWidth / 2.
- 	offsetY := fontHeight * 1.2
- 		max: (self values collect: [:value | font widthOfString: (self labelFor: value)]) max.
- 	chartHeight := self height - offsetY.
- 
- 	0 to: (self height - offsetY) by: 20 do: [:i |
- 	aCanvas
- 		line: 0 at i to: aCanvas clipRect width at i width: 1 color: (Color lightGray lighter alpha: 0.5)].
- 	
- 	self valuesAndCountsWithIndexDo: 
- 		[:value :count :barIndex | | barMidX origin end  |
- 		barIndex <= self limit ifTrue: [
- 			barMidX := barIndex * elementWidth.
- 			origin := barMidX - barRadius @ ((maxY - count) / maxY * chartHeight).
- 			end := barMidX + barRadius @ chartHeight.
- 
- 			self
- 				drawBar: (origin corner: end)  
- 				value: value
- 				count: count
- 				chartHeight: chartHeight
- 				font: font
- 				on: aCanvas]].
- !

Item was removed:
- ----- Method: HistogramMorph>>drawLabel:width:at:barWidth:font:on: (in category 'drawing') -----
- drawLabel: aString width: aNumber at: aPoint barWidth: barWidth font: aFont on: aCanvas
- 
- 	aNumber <= barWidth
- 		ifTrue: [aCanvas drawString: aString at: aPoint font: aFont color: Color black]
- 		ifFalse: [
- 			| c  |
- 			c := Display defaultCanvasClass extent: aNumber @ aFont height.
- 			c drawString: aString at: 0 @ 0  font: aFont color: Color black.
- 			aCanvas paintImage: (c form rotateBy: -90 smoothing: 3) at: aPoint].!

Item was removed:
- ----- Method: HistogramMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas 
- 	| c |
- 	self cachedForm 
- 		ifNil:
- 			[c := Display defaultCanvasClass extent: self bounds extent.
- 			c translateBy: self bounds origin negated
- 				during: [:tempCanvas | super drawOn: tempCanvas].
- 			self drawDataOn: c.
- 			self cachedForm: c form].
- 	aCanvas 
- 		cache: self bounds
- 		using: self cachedForm
- 		during: [:cachingCanvas | self drawDataOn: cachingCanvas].
- !

Item was removed:
- ----- Method: HistogramMorph>>editLimit (in category 'menus') -----
- editLimit
- 
- 	| newLimit |
- 	newLimit := Project uiManager request: 'limit for histogram' translated initialAnswer: self limit asString.
- 	newLimit isEmptyOrNil ifTrue: [^ false].
- 	
- 	self limit: newLimit asInteger.
- 	^ true!

Item was removed:
- ----- Method: HistogramMorph>>flush (in category 'initialization') -----
- flush
- 
- 	| valuesAndCounts |
- 	self bag ifNil: [^self]. "nothing to do yet"
- 	valuesAndCounts := self bag sortedCounts.
- 	valuesAndCounts size < self limit
- 		ifTrue: [self basicLimit: valuesAndCounts size].
- 	self values: ((valuesAndCounts collect: [:ea | ea value]) first: self limit).
- 	self counts: ((valuesAndCounts collect: [:ea | ea key]) first: self limit).
- 	self max: self counts max.
- 	self sum: self counts sum.
- 
- 	self flushCachedForm.
- !

Item was removed:
- ----- Method: HistogramMorph>>flushCachedForm (in category 'initialization') -----
- flushCachedForm
- 
- 	cachedForm := nil.
- !

Item was removed:
- ----- Method: HistogramMorph>>initialize (in category 'initialization') -----
- initialize
- 
- 	super initialize.
- 	self
- 		extent:  700 @ 400;
- 		basicLimit: 25;
- 		yourself.!

Item was removed:
- ----- Method: HistogramMorph>>labelBlock (in category 'accessing') -----
- labelBlock
- 
- 	^ labelBlock!

Item was removed:
- ----- Method: HistogramMorph>>labelBlock: (in category 'accessing') -----
- labelBlock: anObject
- 
- 	labelBlock := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>labelFor: (in category 'drawing') -----
- labelFor: aValue
- 
- 	^ self labelBlock 
- 		ifNotNil: [:block | block value: aValue]
- 		ifNil: [aValue asString]
- !

Item was removed:
- ----- Method: HistogramMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 
- 	super layoutChanged.
- 	cachedForm := nil.
- !

Item was removed:
- ----- Method: HistogramMorph>>limit (in category 'accessing') -----
- limit
- 
- 	^ limit!

Item was removed:
- ----- Method: HistogramMorph>>limit: (in category 'accessing') -----
- limit: anObject
- 
- 	self basicLimit: anObject.
- 	self flush.
- 	self changed!

Item was removed:
- ----- Method: HistogramMorph>>max (in category 'accessing') -----
- max
- 
- 	^ max!

Item was removed:
- ----- Method: HistogramMorph>>max: (in category 'accessing') -----
- max: anObject
- 
- 	max := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>sum (in category 'accessing') -----
- sum
- 
- 	^ sum!

Item was removed:
- ----- Method: HistogramMorph>>sum: (in category 'accessing') -----
- sum: anObject
- 
- 	sum := anObject!

Item was removed:
- ----- Method: HistogramMorph>>values (in category 'accessing') -----
- values
- 
- 	^ values!

Item was removed:
- ----- Method: HistogramMorph>>values: (in category 'accessing') -----
- values: anObject
- 
- 	values := anObject.!

Item was removed:
- ----- Method: HistogramMorph>>valuesAndCountsWithIndexDo: (in category 'enumeration') -----
- valuesAndCountsWithIndexDo: aBlock
- 
- 	1 to: self values size do: [:index |
- 		aBlock
- 			value: (self values at: index)
- 			value: (self counts at: index)
- 			value: index].	!

Item was removed:
- RotaryDialMorph subclass: #HygrometerDialMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !HygrometerDialMorph commentStamp: 'tpr 4/14/2017 10:13' prior: 0!
- A Hygrometer measures the relative humidity of the air; a HygrometerDialMorph provides a way to display the value of R.H.!

Item was removed:
- ----- Method: HygrometerDialMorph>>buildDial (in category 'dial drawing') -----
- buildDial
- 	"start by making a damn big Form, twice the size we want to end up with"
- 	|outerRadius destForm canvas tickLabel tickLength beginAngle endAngle tickAngle tickLabelSize maxTicks |
- 	outerRadius := self height  - 1.
- 	destForm := Form extent: self extent * 2 depth: 32.
- 	(canvas := destForm getCanvas) fillOval: (0 at 0 extent: self extent * 2) color: Color white.
- 	"outer ring"
- 	self drawArcAt: destForm center radius: outerRadius thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	"inner ring"
- 	self drawArcAt: destForm center radius: outerRadius * 0.97 thickness: 1 color: Color black beginAngle: 0 endAngle: 360 onForm: destForm.
- 	
- 	"just one scale for a hygrometer"
- 	beginAngle := startAngle -360. "needs cleaning up about this"
- 	endAngle := stopAngle.
- 	
- 	self drawArcAt: destForm center radius: outerRadius * 0.8 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	self drawArcAt: destForm center radius: outerRadius * 0.73 thickness: 1 color: Color black beginAngle:beginAngle endAngle: stopAngle onForm: destForm.
- 	"We use a simple % range, just one scale"
- 	maxTicks := stopValue - startValue .
- 	tickAngle := endAngle - beginAngle / maxTicks.
- 	startValue to: stopValue do: [:tick|
- 	tickLength := outerRadius * 0.07.
- 		tickLabel := nil.
- 		tick \\ 10 = 0 ifTrue: [
- 			tickLabel := tick asString.
- 			tickLabelSize := 24
- 		] ifFalse: [
- 			tick \\ 2 = 0 ifTrue:[
- 				tickLabel := (tick \\ 10) asString.
- 				tickLabelSize := 18
- 			] ifFalse: [
- 				tickLength := tickLength * 2
- 			]
- 		].
- 		self drawTickRadius: outerRadius * 0.73 length: tickLength thickness: 2 color: Color black angle:  beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 		self tickLabel: tickLabel fontSize: tickLabelSize color: Color black centeredAt: dialCenter radius: (outerRadius * 0.73) + tickLength angle: beginAngle + (tick - startValue * tickAngle) onCanvas: canvas.
- 	].
- 
- 	self tickLabel: '% R.H.'  fontSize: 36 color: Color black centeredAt: dialCenter radius: (outerRadius * 0.53) angle: 180 onCanvas: canvas.
- 	
- 	self addMorph: (destForm magnify: destForm boundingBox by: 0.5 smoothing: 2) asMorph!

Item was removed:
- ----- Method: HygrometerDialMorph>>initialize (in category 'initialize-release') -----
- initialize
- 	"Build a hygrometer. The background is an ImageMorph showing a dial derived from the same general principles as the BarometerMorph. "
- 	| pointerMorph |
- 	super initialize.
- 	
- 	self startAngle: -140 stopAngle: 140;
- 		startValue: 0 stopValue: 100.
- 	self extent: self initialExtent; color: Color transparent; borderWidth: 0.
- 	dialCenter := self center.
- 	
- 	self buildDial.
- 
- 	"build our fancy needle as an ImageMorph, set the position to horizontal centre and about 2/3 down so that it rotates about that point when inside the TransformationMorph"
- 	pointerMorph := self fancyNeedleOfLength: (self height * 0.65) rounded.
-  	pointerMorph
- 		position: pointerMorph extent * ( -0.5@ -0.65);
- 		rotationCenter: 0.5 @ 0.65.
- 
- 	"we keep track of the TransformationMorph since that is what we have to rotate as the incoming pressure values change"
- 	needleMorph := TransformationMorph new position: dialCenter; addMorph: pointerMorph.
- 	self addMorph: needleMorph.
- 
- 	"add a central colored dot. Because we just do."
- 	self addMorph: (CircleMorph new extent: 20 at 20; color: Color black; center: dialCenter)
- !

Item was removed:
- ----- Method: IconicButton>>initializeToShow:withLabel:andSend:to: (in category '*MorphicExtras-initialization') -----
- initializeToShow: aMorph withLabel: aLabel andSend: aSelector to: aReceiver 	
- 	"Initialize the receiver to show the current appearance of aMorph on its face, giving it the label supplied and arranging for it, when the button goes down on it, to obtain a new morph by sending the specified selector to the specified receiver"
- 
- 	| aThumbnail |
- 	aThumbnail := Thumbnail new.
- 	aThumbnail makeThumbnailFromForm: (aMorph imageFormDepth: 32).
- 	^ self initializeWithThumbnail: aThumbnail withLabel: aLabel andColor: self color andSend: aSelector to: aReceiver 	!

Item was removed:
- ----- Method: ImageMorph>>drawPostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- drawPostscriptOn: aCanvas
- 
- 	| top f2 c2 clrs |
- 
- 	clrs := image colorsUsed.
- 	(clrs includes: Color transparent) 
- 		ifFalse: [^super drawPostscriptOn: aCanvas].		"no need for this, then"
- 
- 	top := aCanvas topLevelMorph.
- 	f2 := Form extent: self extent depth: image depth.
- 	c2 := f2 getCanvas.
- 	c2 fillColor: Color white.
- 	c2 translateBy: bounds origin negated clippingTo: f2 boundingBox during: [ :c |
- 		top fullDrawOn: c
- 	].
- 	aCanvas paintImage: f2 at: bounds origin
- 
- !

Item was removed:
- PasteUpMorph subclass: #IndexTabs
- 	instanceVariableNames: 'highlightColor regularColor basicHeight basicWidth verticalPadding fixedWidth'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Palettes'!
- 
- !IndexTabs commentStamp: '<historical>' prior: 0!
- Used in conjunction wi[th a TabbedPalette -- each TabbedPalette has one.  Each submorph of an IndexTabs is a TabMorph.  When you click on one of the tabs, a corresponding action is taken -- sometimes, the existing palette gets replaced by the new one, other times, the tab results in some selector being invoked; in any case, tab highlighting takes place accordingly.!

Item was removed:
- ----- Method: IndexTabs class>>defaultNameStemForInstances (in category 'printing') -----
- defaultNameStemForInstances
- 	"Answer a basis for names of default instances of the receiver"
- 	^ 'tabs' translatedNoop!

Item was removed:
- ----- Method: IndexTabs>>addTab: (in category 'tabs') -----
- addTab: aTab
- 	self addMorphBack: aTab.
- 	self laySubpartsOutInOneRow!

Item was removed:
- ----- Method: IndexTabs>>addTabFor:font: (in category 'tabs') -----
- addTabFor: aReferent font: aFont
- 	|  aTab |
- 	aTab := ReferenceMorph forMorph: aReferent font: aFont.
- 	self addMorphBack: aTab.
- 	aTab highlightColor: self highlightColor; regularColor: self regularColor.
- 	aTab unHighlight.
- 	self laySubpartsOutInOneRow; layoutChanged.
- 	^ aTab!

Item was removed:
- ----- Method: IndexTabs>>addTabForBook: (in category 'tabs') -----
- addTabForBook: aBook
- 	|  aTab |
- 	aTab := ReferenceMorph forMorph: aBook.
- 	self addMorphBack: aTab.
- 	aTab highlightColor: self highlightColor; regularColor: self regularColor.
- 	aTab unHighlight.
- 	self laySubpartsOutInOneRow; layoutChanged.
- 	^ aTab!

Item was removed:
- ----- Method: IndexTabs>>basicHeight (in category 'layout') -----
- basicHeight
- 	^ basicHeight!

Item was removed:
- ----- Method: IndexTabs>>basicWidth (in category 'layout') -----
- basicWidth
- 	basicWidth ifNil: [basicWidth := owner ifNotNil: [owner width] ifNil: [100]].
- 	^ basicWidth!

Item was removed:
- ----- Method: IndexTabs>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 0!

Item was removed:
- ----- Method: IndexTabs>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0.0
- 		g: 0.6
- 		b: 0.6!

Item was removed:
- ----- Method: IndexTabs>>fixedWidth: (in category 'layout') -----
- fixedWidth: aWidth
- 	fixedWidth := aWidth!

Item was removed:
- ----- Method: IndexTabs>>highlightColor (in category 'accessing') -----
- highlightColor
- 	^ highlightColor ifNil: [Color yellow]!

Item was removed:
- ----- Method: IndexTabs>>highlightColor: (in category 'accessing') -----
- highlightColor: aColor
- 	highlightColor := aColor!

Item was removed:
- ----- Method: IndexTabs>>highlightColor:regularColor: (in category 'highlighting') -----
- highlightColor: color1 regularColor: color2
- 	"Apply these colors to all of the receiver's tabs"
- 	highlightColor := color1.
- 	regularColor := color2.
- 	self tabMorphs do:
- 		[:m | m highlightColor: color1.  m regularColor: color2]!

Item was removed:
- ----- Method: IndexTabs>>highlightTab: (in category 'highlighting') -----
- highlightTab: aTab
- 	self tabMorphs do:
- 		[:m | m == aTab
- 			ifTrue: [m highlight]
- 			ifFalse: [m unHighlight]]!

Item was removed:
- ----- Method: IndexTabs>>highlightTabFor: (in category 'highlighting') -----
- highlightTabFor: aBook
- 	| theOne |
- 	self tabMorphs do: [:m |
- 		(m morphToInstall == aBook)
- 				ifTrue: [m highlight.  theOne := m]
- 				ifFalse: [m unHighlight]].
- 	^ theOne
- !

Item was removed:
- ----- Method: IndexTabs>>highlightedTab (in category 'highlighting') -----
- highlightedTab
- 	^ self tabMorphs detect: [:m | m isHighlighted] ifNone: [nil]!

Item was removed:
- ----- Method: IndexTabs>>initialize (in category 'initialization') -----
- initialize
- 	"Initialize the receiver. Make sure it is not open to drag and  
- 	drop"
- 	super initialize.
- 	""
- 	padding := 10.
- 	verticalPadding := 4.
- 	basicHeight := 14.
- 	basicWidth := 200.
- 	
- 	self enableDragNDrop: false!

Item was removed:
- ----- Method: IndexTabs>>laySubpartsOutInOneRow (in category 'layout') -----
- laySubpartsOutInOneRow
- 	| aPosition neededHeight widthToUse mid |
- 	fixedWidth ifNotNil: [self error: 'incompatibility in IndexTabs'].
- 	verticalPadding ifNil: [verticalPadding := 4].  "for benefit of old structures"
- 	aPosition := self topLeft.
- 	neededHeight := self basicHeight.
- 	submorphs do:
- 		[:aMorph |
- 			aMorph position: (aPosition + (padding @ 0)).
- 			aPosition := aMorph topRight.
- 			neededHeight := neededHeight max: aMorph height].
- 	neededHeight := neededHeight + (verticalPadding * 2).
- 	mid := self top + (neededHeight // 2).
- 	submorphs do:
- 		[:aMorph |
- 			aMorph top: (mid - (aMorph height // 2))].
- 	widthToUse := self widthImposedByOwner max: self requiredWidth.
- 	self extent: (((aPosition x + padding - self left) max: widthToUse) @ neededHeight)!

Item was removed:
- ----- Method: IndexTabs>>ownerChanged (in category 'change reporting') -----
- ownerChanged
- 	fixedWidth ifNil: [self laySubpartsOutInOneRow]!

Item was removed:
- ----- Method: IndexTabs>>regularColor (in category 'accessing') -----
- regularColor
- 	^ regularColor ifNil: [Color r: 0.4 g: 0.2 b: 0.6]!

Item was removed:
- ----- Method: IndexTabs>>regularColor: (in category 'accessing') -----
- regularColor: aColor
- 	regularColor := aColor!

Item was removed:
- ----- Method: IndexTabs>>repelsMorph:event: (in category 'dropping/grabbing') -----
- repelsMorph: aMorph event: evt
- 	^ false!

Item was removed:
- ----- Method: IndexTabs>>requiredWidth (in category 'layout') -----
- requiredWidth
- 	submorphs isEmpty ifTrue: [^self basicWidth].
- 	^(submorphs detectSum: [:m | m width]) + (submorphs size * padding)!

Item was removed:
- ----- Method: IndexTabs>>rowsNoWiderThan: (in category 'layout') -----
- rowsNoWiderThan: maxWidth
- 	| aPosition neededHeight |
- 	self fixedWidth: maxWidth.
- 	verticalPadding ifNil: [verticalPadding := 4].  "for benefit of old structures"
- 	aPosition := self topLeft.
- 	neededHeight := self basicHeight.
- 	submorphs do:
- 		[:aMorph |
- 			aMorph position: (aPosition + (padding @ 0)).
- 			(aMorph right > (self left + maxWidth)) ifTrue:
- 				[aPosition := self left @ (aPosition y + neededHeight).
- 				aMorph position: aPosition + (padding @ 0).
- 				neededHeight := self basicHeight].
- 			aPosition := aMorph topRight.
- 			neededHeight := neededHeight max: aMorph height].
- 	self extent: (maxWidth @ ((aPosition y + neededHeight) - self top))!

Item was removed:
- ----- Method: IndexTabs>>selectTab: (in category 'selection') -----
- selectTab: aTab
- 	| aWorld |
- 	(aWorld := self world) ifNotNil: [aWorld abandonAllHalos].  "nil can happen at init time"
- 	self highlightTab: aTab.
- !

Item was removed:
- ----- Method: IndexTabs>>tabMorphs (in category 'tabs') -----
- tabMorphs
- 	"Presently all the submorphs are ReferenceMorphs, but this still supports an earlier design where spacers are interleaved, and where the old TabMorph class was used"
- 
- 	^ submorphs select: [:m | (m isKindOf: TabMorph) or: [m isKindOf: ReferenceMorph]]!

Item was removed:
- ----- Method: IndexTabs>>widthImposedByOwner (in category 'layout') -----
- widthImposedByOwner
- 	((owner isNil or: [owner isWorldOrHandMorph]) 
- 		or: [owner submorphs size < 2]) ifTrue: [^self basicWidth].
- 	^owner submorphs second width!

Item was removed:
- RectangleMorph subclass: #InterimSoundMorph
- 	instanceVariableNames: 'graphic sound'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!

Item was removed:
- ----- Method: InterimSoundMorph>>addGraphic (in category 'initialization') -----
- addGraphic
- 
- 	graphic := SketchMorph withForm: self speakerGraphic.
- 	graphic position: bounds center - (graphic extent // 2).
- 	self addMorph: graphic.
- !

Item was removed:
- ----- Method: InterimSoundMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: InterimSoundMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0
- 		g: 0.8
- 		b: 0.6!

Item was removed:
- ----- Method: InterimSoundMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	(graphic containsPoint: evt cursorPoint)
- 		ifTrue: [^ true]
- 		ifFalse: [^ super handlesMouseDown: evt].
- !

Item was removed:
- ----- Method: InterimSoundMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	
- 	self extent: 30 @ 30.
- 	self addGraphic.
- 	sound := PluckedSound
- 				pitch: 880.0
- 				dur: 2.0
- 				loudness: 0.5!

Item was removed:
- ----- Method: InterimSoundMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 
- 	(graphic containsPoint: evt cursorPoint)
- 		ifTrue: [sound copy play]
- 		ifFalse: [super mouseDown: evt].
- !

Item was removed:
- ----- Method: InterimSoundMorph>>sound (in category 'accessing') -----
- sound
- 
- 	^ sound
- !

Item was removed:
- ----- Method: InterimSoundMorph>>sound: (in category 'accessing') -----
- sound: aSound
- 
- 	sound := aSound.
- !

Item was removed:
- ----- Method: InterimSoundMorph>>speakerGraphic (in category 'initialization') -----
- speakerGraphic
- 
- 	^ Form
- 		extent: 19 at 18
- 		depth: 8
- 		fromArray: #(0 0 1493172224 2816 0 0 0 1493172224 11 0 0 138 1493172224 184549376 184549376 0 35509 2315255808 720896 720896 0 9090522 2315255808 2816 720896 0 2327173887 2315255819 2816 720896 138 3051028442 2315255819 2816 2816 1505080590 4294957786 2315255808 184549387 2816 3053453311 4292532917 1493172224 184549387 2816 1505080714 3048584629 1493172224 184549387 2816 9079434 3048584629 1493172224 184549387 2816 138 2327164341 1493172235 2816 2816 0 2324346293 1493172235 2816 720896 0 9079477 1493172224 2816 720896 0 35466 1493172224 720896 720896 0 138 0 184549376 184549376 0 0 0 11 0 0 0 0 2816 0)
- 		offset: 0 at 0
- !

Item was removed:
- ThreadNavigationMorph subclass: #InternalThreadNavigationMorph
- 	instanceVariableNames: 'threadName preferredIndex'
- 	classVariableNames: 'CachedThumbnails KnownThreads'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Navigators'!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>cacheThumbnailFor: (in category 'thumbnails') -----
- cacheThumbnailFor: aProject
- 	"Save a thumbnail  of the given project in my thumbnail cache."
- 
- 	| form |
- 	CachedThumbnails ifNil: [CachedThumbnails := Dictionary new].
- 	CachedThumbnails
- 		at: aProject name
- 		put: (form := self sorterFormForProject: aProject sized: 160 @ 120).
- 	^ form
- 	!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>clearKnownThreads (in category 'known threads') -----
- clearKnownThreads
- 
- 	KnownThreads := nil!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>clearThumbnailCache (in category 'thumbnails') -----
- clearThumbnailCache
- 
- 	CachedThumbnails := nil!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName: 	'ThreadNavigator' translatedNoop
- 		categories:		{'Multimedia' translatedNoop}
- 		documentation:	'A tool that lets you navigate through a thread of projects.' translatedNoop!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>getThumbnailFor: (in category 'thumbnails') -----
- getThumbnailFor: aProject
- 	"Answer a thumbnail for the given project, retrieving it from a cache of such objects if possible, else creating a fresh thumbnail, storing it in the cache, and answering it."
- 
- 	CachedThumbnails ifNil: [CachedThumbnails := Dictionary new].
- 	^CachedThumbnails
- 		at: aProject name
- 		ifAbsentPut: [self sorterFormForProject: aProject sized: 160 at 120]!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>know:as: (in category 'known threads') -----
- know: listOfPages as: nameOfThread
- 
- 	self knownThreads at: nameOfThread put: listOfPages.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>knownThreads (in category 'known threads') -----
- knownThreads
- 
- 	^KnownThreads ifNil: [KnownThreads := Dictionary new].
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>openThreadNamed:atIndex: (in category 'known threads') -----
- openThreadNamed: nameOfThread atIndex: anInteger
- 
- 	| coll nav |
- 
- 	coll := self knownThreads at: nameOfThread ifAbsent: [^self].
- 	nav := Project current world 
- 		submorphThat: [ :each | (each isKindOf: self) and: [each threadName = nameOfThread]]
- 		ifNone: [
- 			nav := self basicNew.
- 			nav
- 				listOfPages: coll;
- 				threadName: nameOfThread index: anInteger;
- 				initialize;
- 				openInWorld;
- 				positionAppropriately.
- 			^self
- 		].
- 	nav
- 		listOfPages: coll;
- 		threadName: nameOfThread index: anInteger;
- 		removeAllMorphs;
- 		addButtons.
- 
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>openThreadNamed:atIndex:beKeyboardHandler: (in category 'known threads') -----
- openThreadNamed: nameOfThread atIndex: anInteger beKeyboardHandler: aBoolean
- 	"Activate the thread of the given name, from the given index; set it up to be navigated via desktop keys if indicated"
- 
- 	| coll nav |
- 
- 	coll := self knownThreads at: nameOfThread ifAbsent: [^self].
- 	nav := Project current world 
- 		submorphThat: [ :each | (each isKindOf: self) and: [each threadName = nameOfThread]]
- 		ifNone:
- 			[nav := self basicNew.
- 			nav
- 				listOfPages: coll;
- 				threadName: nameOfThread index: anInteger;
- 				initialize;
- 				openInWorld;
- 				positionAppropriately.
- 			aBoolean ifTrue: [Project current world keyboardNavigationHandler: nav].
- 			^ self].
- 	nav
- 		listOfPages: coll;
- 		threadName: nameOfThread index: anInteger;
- 		removeAllMorphs;
- 		addButtons.
- 	aBoolean ifTrue: [Project current world keyboardNavigationHandler: nav].!

Item was removed:
- ----- Method: InternalThreadNavigationMorph class>>sorterFormForProject:sized: (in category 'sorter') -----
- sorterFormForProject: aProject sized: aSize
- 	"Answer a form to use in a project-sorter to represent the project."
- 
- 	^ (ProjectViewMorph on: aProject) imageForm scaledToSize: aSize
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>acceptSortedContentsFrom: (in category 'sorting') -----
- acceptSortedContentsFrom: aHolder
- 	"Update my page list from the given page sorter."
- 
- 	
- 
- 	threadName isEmpty ifTrue: [threadName := 'I need a name' translated].
- 	threadName := UIManager default 
- 		request: 'Name this thread.' translated 
- 		initialAnswer: threadName.
- 	threadName isEmptyOrNil ifTrue: [^self].
- 	listOfPages := OrderedCollection new.
- 	aHolder submorphs withIndexDo: [:m :i | | cachedData proj nameOfThisProject |
- 		(nameOfThisProject := m valueOfProperty: #nameOfThisProject) ifNotNil: [
- 			cachedData := {nameOfThisProject}.
- 			proj := Project named: nameOfThisProject.
- 			(proj isNil or: [proj thumbnail isNil]) ifFalse: [
- 				cachedData := cachedData, {proj thumbnail scaledToSize: self myThumbnailSize}.
- 			].
- 			listOfPages add: cachedData.
- 		].
- 	].
- 	self class know: listOfPages as: threadName.
- 	self removeAllMorphs; addButtons.
- 	self world ifNil: [
- 		self openInWorld; positionAppropriately.
- 	].
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>addButtons (in category 'initialization') -----
- addButtons
- 
- 	| marginPt i sz data images b1 b2 dot arrowWidth arrowHeight nameMorph sizeRatio controlsColor |
- 
- 	sizeRatio := self sizeRatio.
- 	controlsColor := Color orange lighter.
- 
- 	self changeNoLayout.
- 	self hResizing: #rigid.
- 	self vResizing: #rigid.
- 	marginPt := (4 @ 4 * sizeRatio) rounded..
- 	i := self currentIndex.
- 	sz := self myThumbnailSize.
- 	arrowWidth := (14 * sizeRatio) rounded.
- 	arrowHeight := (14 * sizeRatio) rounded.
- 	data := {
- 		{i - 1. 'Previous:'. #previousPage. #leftCenter. arrowWidth. 'Prev'}.
- 		{i + 1. 'Next:'. #nextPage. #rightCenter. arrowWidth negated. 'Next'}
- 	}.
- 	images := data collect: [ :tuple | | pageNumber f vertices m arrowCenter |
- 		pageNumber := tuple first.
- 		(pageNumber between: 1 and: listOfPages size) ifTrue: [
- 			f := self 
- 				makeThumbnailForPageNumber: pageNumber 
- 				scaledToSize: sz 
- 				default: tuple sixth.
- 			f := f deepCopy.		"we're going to mess it up"
- 			arrowCenter := f boundingBox perform: tuple fourth.
- 			vertices := {
- 				arrowCenter + (tuple fifth @ arrowHeight negated).
- 				arrowCenter + (tuple fifth @ arrowHeight).
- 				arrowCenter.
- 			}.
- 			f getCanvas
- 				drawPolygon: vertices 
- 				color: controlsColor
- 				borderWidth: 0 
- 				borderColor: Color transparent.
- 			m := ImageMorph new image: f.
- 			m setBalloonText: tuple second translated,' ',(listOfPages at: pageNumber) first.
- 			m addMouseUpActionWith: (
- 				MessageSend receiver: self selector: tuple third
- 			).
- 		] ifFalse: [
- 			f := (Form extent: sz depth: 16) fillColor: Color lightGray.
- 			m := ImageMorph new image: f.
- 		].
- 		m
- 	].
- 	b1 := images first.
- 	b2 := images second.
- 	dot := EllipseMorph new extent: (18 at 18 * sizeRatio) rounded; color: controlsColor; borderWidth: 0.
- 
- 	self addMorph: (b1 position: self position + marginPt).
- 	self addMorph: (b2 position: b1 topRight + (marginPt x @ 0)).
- 
- 	self extent: (b1 bottomRight max: b2 bottomRight) - self position + marginPt.
- 	self addMorph: dot.
- 	dot align: dot center with: b1 bounds rightCenter + ((marginPt x @ 0) // 2).
- 	dot setBalloonText: threadName,'
- more commands'.
- 	dot on: #mouseDown send: #moreCommands to: self.
- 	self fullBounds.
- 	self addMorph: (nameMorph := SquishedNameMorph new).
- 	nameMorph
- 		target: self getSelector: #threadName setSelector: nil;
- 		color: Color transparent;
- 		width: self width;
- 		height: (15 * sizeRatio) rounded;
- 		align: nameMorph bottomLeft with: self bottomLeft.
- 
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>buttonForMenu (in category 'navigation') -----
- buttonForMenu
- 
- 	^self makeButton: '?' balloonText: 'More commands' translated for: #moreCommands.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>currentIndex (in category 'private') -----
- currentIndex
- 
- 	| currentName |
- 
- 	currentName := Project current name.
- 	listOfPages withIndexDo: [ :each :index |
- 		(each first = currentName and: [preferredIndex = index]) ifTrue: [^currentIndex := index]
- 	].
- 	listOfPages withIndexDo: [ :each :index |
- 		each first = currentName ifTrue: [^currentIndex := index]
- 	].
- 	
- 	currentIndex isNil
- 		ifTrue: [^ 1].
- 
- 	^ currentIndex min: listOfPages size
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^(Color r: 0.27 g: 0.634 b: 0.365) alpha: 0.5!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>deleteCurrentPage (in category 'navigation') -----
- deleteCurrentPage
- 
- 	"no-op here"!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>destroyThread (in category 'navigation') -----
- destroyThread
- 	"Manually destroy the thread"
- 
- 	(self confirm: ('Destroy thread <{1}> ?' translated format:{threadName})) ifFalse: [^ self].
- 	self class knownThreads removeKey: threadName ifAbsent: [].
- 	self setProperty: #moribund toValue: true.  "In case pointed to in some other project"
- 	self currentWorld keyboardNavigationHandler == self ifTrue:
- 		[self stopKeyboardNavigation]. 
- 	self delete.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>editThisThread (in category 'navigation') -----
- editThisThread
- 
- 	| sorter |
- 
- 	sorter := ProjectSorterMorph new.
- 	sorter navigator: self listOfPages: listOfPages.
- 	self currentWorld addMorphFront: sorter.
- 	sorter align: sorter topCenter with: self currentWorld topCenter.
- 	self delete.
- 
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>ensureSuitableDefaults (in category 'initialization') -----
- ensureSuitableDefaults
- 
- 	listOfPages ifNil: [
- 		listOfPages := Project allMorphicProjects collect: [ :each | {each name}].
- 		threadName := 'all (default)' translated.
- 		self class know: listOfPages as: threadName.
- 	].
- 	currentIndex ifNil: [currentIndex := 0].
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>getRecentThread (in category 'navigation') -----
- getRecentThread
- 
- 	self switchToThread: (
- 		ProjectHistory currentHistory mostRecentThread ifNil: [^self]
- 	)
- 
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>insertNewProject (in category 'navigation') -----
- insertNewProject
- 
- 	| newProj |
- 
- 	[newProj := MorphicProject openViewOn: nil.]
- 		on: ProjectViewOpenNotification
- 		do: [ :ex | ex resume: false].	
- 
- 	Smalltalk at: #EToyProjectDetailsMorph ifPresent:[:aClass|
- 		aClass
- 			getFullInfoFor: newProj
- 			ifValid: [self insertNewProjectActionFor: newProj]
- 			expandedFormat: false.
- 	].
- 
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>insertNewProjectActionFor: (in category 'navigation') -----
- insertNewProjectActionFor: newProj
- 
- 	| me |
- 
- 	me := Project current name.
- 	listOfPages withIndexDo: [ :each :index |
- 		each first = me ifTrue: [
- 			listOfPages add: {newProj name} afterIndex: index.
- 			^self switchToThread: threadName.
- 		].
- 	].
- 	listOfPages add: {newProj name} afterIndex: listOfPages size.
- 	^self switchToThread: threadName
- 		
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>jumpToIndex: (in category 'navigation') -----
- jumpToIndex: anInteger
- 
- 	currentIndex := anInteger.
- 	self loadPageWithProgress.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>jumpWithinThread (in category 'navigation') -----
- jumpWithinThread
- 
- 	| aMenu me weHaveOthers myIndex |
- 
- 	me := Project current name.
- 	aMenu := MenuMorph new defaultTarget: self.
- 	weHaveOthers := false.
- 	myIndex := self currentIndex.
- 	listOfPages withIndexDo: [ :each :index |
- 		index = myIndex ifTrue: [
- 			aMenu add: 'you are here' translated action: #yourself.
- 			aMenu lastSubmorph color: Color red.
- 		] ifFalse: [
- 			weHaveOthers := true.
- 			aMenu add: ('jump to <{1}>' translated format:{each first}) selector: #jumpToIndex: argument: index.
- 			myIndex = (index - 1) ifTrue: [
- 				aMenu lastSubmorph color: Color blue
- 			].
- 			myIndex = (index + 1) ifTrue: [
- 				aMenu lastSubmorph color: Color orange
- 			].
- 		].
- 	].
- 	weHaveOthers ifFalse: [^self inform: 'This is the only project in this thread' translated].
- 	aMenu popUpEvent: self world primaryHand lastEvent in: self world!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>listOfPages: (in category 'private') -----
- listOfPages: aCollection
- 
- 	listOfPages := aCollection.
- 	currentIndex := nil.
- 	self currentIndex
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>loadPageWithProgress (in category 'private') -----
- loadPageWithProgress
- 	"Load the desired page, showing a progress indicator as we go"
- 	
- 	| projectInfo projectName beSpaceHandler |
- 	projectInfo := listOfPages at: currentIndex.
- 	projectName := projectInfo first.
- 	loadedProject := Project named: projectName.
- 	self class know: listOfPages as: threadName.
- 	beSpaceHandler := (Project current world keyboardNavigationHandler == self).
- 	self currentWorld addDeferredUIMessage:
- 		[InternalThreadNavigationMorph openThreadNamed: threadName atIndex: currentIndex beKeyboardHandler: beSpaceHandler].
- 
- 	loadedProject ifNil: [
- 		ComplexProgressIndicator new 
- 			targetMorph: self;
- 			historyCategory: 'project loading' translated;
- 			withProgressDo: [
- 				[
- 					loadedProject := Project current 
- 							fromMyServerLoad: projectName
- 				] 
- 					on: ProjectViewOpenNotification
- 					do: [ :ex | ex resume: false]		
- 						"we probably don't want a project view morph in this case"
- 			].
- 	].
- 	loadedProject ifNil: [
- 		^self inform: 'I cannot find that project' translated
- 	].
- 	self delete.
- 
- 	loadedProject enter.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>makeThumbnailForPageNumber:scaledToSize:default: (in category 'sorting') -----
- makeThumbnailForPageNumber: pageNumber scaledToSize: sz default: aString
- 
- 	| cachedData proj tn label |
- 	cachedData := listOfPages at: pageNumber.
- 	proj := Project named: cachedData first.
- 	(proj isNil or: [proj thumbnail isNil]) ifTrue: [
- 		cachedData size >= 2 ifTrue: [^cachedData second].
- 		tn := Form extent: sz depth: 8.
- 		tn fillColor: Color veryLightGray.
- 		label := (StringMorph contents: aString) imageForm.
- 		label displayOn: tn at: tn center - (label extent // 2) rule: Form paint.
- 		^tn
- 	].
- 	tn := proj thumbnail  scaledToSize: sz.
- 	cachedData size < 2 ifTrue: [
- 		cachedData := cachedData,#(0).
- 		listOfPages at: pageNumber put: cachedData.
- 	].
- 	cachedData at: 2 put: tn.
- 	^tn
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>moreCommands (in category 'navigation') -----
- moreCommands
- 	"Put up a menu of options"
- 
- 	| allThreads aMenu others target |
- 	allThreads := self class knownThreads.
- 	aMenu := MenuMorph new defaultTarget: self.
- 	aMenu addTitle: 'navigation' translated.
- 
- 	Preferences noviceMode ifFalse:[
- 		self flag: #deferred.  "Probably don't want that stay-up item, not least because the navigation-keystroke stuff is not dynamically handled"
- 		aMenu addStayUpItem
- 	].
- 	
- 	others := (allThreads keys reject: [ :each | each = threadName]) asArray sort.
- 	others do: [ :each |
- 		aMenu add: ('switch to <{1}>' translated format:{each}) selector: #switchToThread: argument: each
- 	].
- 
- 	aMenu addList: {
- 		{'switch to recent projects' translated.  #getRecentThread}.
- 		#-.
- 		{'create a new thread' translated.  #threadOfNoProjects}.
- 		{'edit this thread' translated.  #editThisThread}.
- 		{'create thread of all projects' translated.  #threadOfAllProjects}.
- 		#-.
- 		{'First project in thread' translated.  #firstPage}.
- 		{'Last project in thread' translated.  #lastPage}
- 	}.
- 
- 	(target := self currentIndex + 2) > listOfPages size ifFalse: [
- 		aMenu 
- 			add: ('skip over next project ({1})' translated format:{(listOfPages at: target - 1) first})
- 			action: #skipOverNext
- 	].
- 
- 	aMenu addList: {
- 		{'jump within this thread' translated.  #jumpWithinThread}.
- 		{'insert new project' translated.  #insertNewProject}.
- 		#-.
- 		{'simply close this navigator' translated.  #delete}.
- 		{'destroy this thread' translated. #destroyThread}.
- 		#-
- 	}.
- 
- 	(self currentWorld keyboardNavigationHandler == self) ifFalse:[
- 		aMenu add: 'start keyboard navigation with this thread' translated action: #startKeyboardNavigation
- 	]
- 	ifTrue: [
- 		aMenu add: 'stop keyboard navigation with this thread' translated action: #stopKeyboardNavigation
- 	].
- 
- 	aMenu popUpInWorld.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>myThumbnailSize (in category 'navigation') -----
- myThumbnailSize
- 	^ (52 @ 39 * self sizeRatio) rounded!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>positionAppropriately (in category 'navigation') -----
- positionAppropriately
- 
- 	| others world otherRects overlaps bottomRight |
- 	(self ownerThatIsA: HandMorph) ifNotNil: [^self].
- 	others := (world := Project currentWorld) submorphs select: [ :each | each ~~ self and: [each isKindOf: self class]].
- 	otherRects := others collect: [ :each | each bounds].
- 	bottomRight := (world hasProperty: #threadNavigatorPosition)
- 		ifTrue: [world valueOfProperty: #threadNavigatorPosition]
- 		ifFalse: [world bottomRight].
- 	self align: self fullBounds bottomRight with: bottomRight.
- 	self setProperty: #previousWorldBounds toValue: self world bounds.
- 
- 	[
- 		overlaps := false.
- 		otherRects do: [ :r |
- 			(r intersects: bounds) ifTrue: [overlaps := true. self bottom: r top].
- 		].
- 		self top < self world top ifTrue: [
- 			self bottom: bottomRight y.
- 			self right: self left - 1.
- 		].
- 		overlaps
- 	] whileTrue.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>showMenuFor:event: (in category 'menu') -----
- showMenuFor: actionSelector event: evt
- 
- 	self perform: actionSelector
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>sizeRatio (in category 'accessing') -----
- sizeRatio
- 	"answer the size ratio for the receiver"
- 	
- 	^ 1.0
- 
- 	"^ Preferences standardMenuFont height / 12"    "Good grief!!"!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>skipOverNext (in category 'navigation') -----
- skipOverNext
- 	
- 	| target |
- 
- 	(target := self currentIndex + 2) > listOfPages size ifTrue: [^Beeper beep].
- 	currentIndex := target.
- 	self loadPageWithProgress.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>startKeyboardNavigation (in category 'navigation') -----
- startKeyboardNavigation
- 	"Tell the active world to starting navigating via desktop keyboard navigation via me"
- 
- 	self currentWorld keyboardNavigationHandler: self!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>step (in category 'stepping') -----
- step
- 
- 	super step.
- 	(self valueOfProperty: #previousWorldBounds) = self world bounds ifFalse: [
- 		self positionAppropriately.
- 	].
- 	self class knownThreads
- 		at: threadName
- 		ifPresent: [ :known |
- 			known == listOfPages ifFalse: [
- 				listOfPages := known.
- 				self removeAllMorphs.
- 				self addButtons.
- 			].
- 		].
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>stopKeyboardNavigation (in category 'navigation') -----
- stopKeyboardNavigation
- 	"Cease navigating via the receiver in response to desktop keystrokes"
- 
- 	self currentWorld removeProperty: #keyboardNavigationHandler!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>switchToThread: (in category 'navigation') -----
- switchToThread: newName
- 
- 	threadName := newName.
- 	listOfPages := self class knownThreads at: threadName.
- 	self removeAllMorphs.
- 	self addButtons.
- 	self currentIndex.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>threadName (in category 'navigation') -----
- threadName
- 
- 	^threadName!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>threadName:index: (in category 'navigation') -----
- threadName: aString index: anInteger
- 
- 	threadName := aString.
- 	preferredIndex := anInteger.
- 	self currentIndex.!

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>threadOfAllProjects (in category 'navigation') -----
- threadOfAllProjects
- 
- 	| nameList nav |
- 
- 	nameList := Project allMorphicProjects collect: [ :each | {each name}].
- 	nav := self class basicNew.
- 	nav
- 		listOfPages: nameList;
- 		threadName: '' index: nil;
- 		initialize.
- 	nav editThisThread.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>threadOfNoProjects (in category 'navigation') -----
- threadOfNoProjects
- 
- 	| nameList nav |
- 
- 	nameList := { {Project current name} }.
- 	nav := self class basicNew.
- 	nav
- 		listOfPages: nameList;
- 		threadName: '' index: nil;
- 		initialize.
- 	nav editThisThread.
- !

Item was removed:
- ----- Method: InternalThreadNavigationMorph>>triggerActionFromPianoRoll (in category 'piano rolls') -----
- triggerActionFromPianoRoll
- 	
- 	WorldState addDeferredUIMessage: 
- 			[ | proj |
- 			self currentIndex >= listOfPages size 
- 				ifTrue: [Beeper beep]
- 				ifFalse: 
- 					[currentIndex := self currentIndex + 1.
- 					proj := Project named: ((listOfPages at: currentIndex) first).
- 					proj world setProperty: #letTheMusicPlay toValue: true.
- 					proj enter]]!

Item was removed:
- PianoKeyboardMorph subclass: #KeyboardMorphForInput
- 	instanceVariableNames: 'pianoRoll duration durationModifier articulation buildingChord insertMode prevSelection startOfNextNote chordSemitones chordDictionary'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!
- 
- !KeyboardMorphForInput commentStamp: 'nice 3/24/2010 07:37' prior: 0!
- This class adds state and controls to the basic PianoKeyboardMorph so that notes of reliable duration can be keyed into a score without the need for a real keyboard.
- 
- To try this out, execute...
- 
- 	| n score | n := 3.
- 	score := (MIDIScore new tracks: ((1 to: n) collect: [:i | Array new]);
- 		trackInfo: ((1 to: n) collect: [:i | 'Instrument' , i printString]);
- 		tempoMap: nil; ticksPerQuarterNote: 96).
- 	ScorePlayerMorph openOn: score title: 'empty score'
- 
- Then open a pianoRoll and, from that, open a keyboard.  The rule is that the keyboard will append after the current selection.  If the current selection is muted or nil, then input will go to the end of the first non-muted track.!

Item was removed:
- ----- Method: KeyboardMorphForInput>>addChordControls (in category 'initialization') -----
- addChordControls
- 	| switch chordRow |
-       chordRow := AlignmentMorph newRow.
-       chordRow color: color; borderWidth: 0; layoutInset: 0.
- 	chordRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'maj' translated;
- 				actionSelector: #chords:onOff:; arguments: #(maj)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'min' translated;
- 				actionSelector: #chords:onOff:; arguments: #(min)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'dim' translated;
- 				actionSelector: #chords:onOff:; arguments: #(dim)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'maj7' translated;
- 				actionSelector: #chords:onOff:; arguments: #(maj7)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'min7' translated;
- 				actionSelector: #chords:onOff:; arguments: #(min7)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'dom7' translated;
- 				actionSelector: #chords:onOff:; arguments: #(dom7)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'sus2' translated;
- 				actionSelector: #chords:onOff:; arguments: #(sus2)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'sus4' translated;
- 				actionSelector: #chords:onOff:; arguments: #(sus4)). 
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	chordRow addMorphBack: (switch label: 'aug' translated;
- 				actionSelector: #chords:onOff:; arguments: #(aug)). 
- 	^chordRow
- !

Item was removed:
- ----- Method: KeyboardMorphForInput>>addNoteEventAt:rootNote: (in category 'simple keyboard') -----
- addNoteEventAt: eventTime rootNote: rootNote
-    | noteEvent noteEvents semitones |
-    semitones := chordSemitones.
-    buildingChord ifFalse:[ semitones := #(0)].
-    noteEvents := OrderedCollection new.
-    semitones do:
-    [: semitone | noteEvent := NoteEvent new time: eventTime; duration: self noteDuration;
- 			key: rootNote + semitone velocity: self velocity channel: 1.
- 			pianoRoll appendEvent: noteEvent fullDuration: self fullDuration.
- 			noteEvents add: noteEvent].
-   ^noteEvents!

Item was removed:
- ----- Method: KeyboardMorphForInput>>addRecordingControls (in category 'initialization') -----
- addRecordingControls
- 	| button switch playRow durRow articRow modRow chordRow |
- 
- 	"Add chord, rest and delete buttons"
- 	playRow := AlignmentMorph newRow.
- 	playRow color: color; borderWidth: 0; layoutInset: 0.
- 	playRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	playRow addMorphBack: (switch label: 'chord' translated; actionSelector: #buildChord:).
- 	button := SimpleButtonMorph new target: self;
- 		borderStyle: (BorderStyle raised width: 2); color: color.
- 	playRow addMorphBack: (button label: '          rest          ' translated; actionSelector: #emitRest).
- 	button := SimpleButtonMorph new target: self;
- 		borderStyle: (BorderStyle raised width: 2); color: color.
- 	playRow addMorphBack: (button label: 'del' translated; actionSelector: #deleteNotes).
- 	self addMorph: playRow.
- 	playRow align: playRow fullBounds topCenter
- 			with: self fullBounds bottomCenter.
-       
-       chordRow := self addChordControls.
-       self addMorph: chordRow.
- 	chordRow align: chordRow fullBounds topCenter
- 			with: playRow fullBounds bottomCenter.
- 
- 	"Add note duration buttons"
- 	durRow := AlignmentMorph newRow.
- 	durRow color: color; borderWidth: 0; layoutInset: 0.
- 	durRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	durRow addMorphBack: (switch label: 'whole' translated;
- 				actionSelector: #duration:onOff:; arguments: #(1)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	durRow addMorphBack: (switch label: 'half' translated;
- 				actionSelector: #duration:onOff:; arguments: #(2)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	durRow addMorphBack: (switch label: 'quarter' translated;
- 				actionSelector: #duration:onOff:; arguments: #(4)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	durRow addMorphBack: (switch label: 'eighth' translated;
- 				actionSelector: #duration:onOff:; arguments: #(8)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	durRow addMorphBack: (switch label: 'sixteenth' translated;
- 				actionSelector: #duration:onOff:; arguments: #(16)).
- 	self addMorph: durRow.
- 	durRow align: durRow fullBounds topCenter
- 			with: chordRow fullBounds bottomCenter.
- 
- 	"Add note duration modifier buttons"
- 	modRow := AlignmentMorph newRow.
- 	modRow color: color; borderWidth: 0; layoutInset: 0.
- 	modRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	modRow addMorphBack: (switch label: 'dotted' translated;
- 				actionSelector: #durMod:onOff:; arguments: #(dotted)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	modRow addMorphBack: (switch label: 'normal' translated;
- 				actionSelector: #durMod:onOff:; arguments: #(normal)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	modRow addMorphBack: (switch label: 'triplets' translated;
- 				actionSelector: #durMod:onOff:; arguments: #(triplets)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	modRow addMorphBack: (switch label: 'quints' translated;
- 				actionSelector: #durMod:onOff:; arguments: #(quints)).
- 	self addMorph: modRow.
- 	modRow align: modRow fullBounds topCenter
- 			with: durRow fullBounds bottomCenter.
- 
- 	"Add articulation buttons"
- 	articRow := AlignmentMorph newRow.
- 	articRow color: color; borderWidth: 0; layoutInset: 0.
- 	articRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; extent: 5 at 5.
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	articRow addMorphBack: (switch label: 'legato' translated;
- 				actionSelector: #articulation:onOff:; arguments: #(legato)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	articRow addMorphBack: (switch label: 'normal' translated;
- 				actionSelector: #articulation:onOff:; arguments: #(normal)).
- 	switch := SimpleSwitchMorph new target: self; borderWidth: 2;
- 		offColor: color; onColor: (Color r: 1.0 g: 0.6 b: 0.6); setSwitchState: false.
- 	articRow addMorphBack: (switch label: 'staccato' translated;
- 				actionSelector: #articulation:onOff:; arguments: #(staccato)).
- 	self addMorph: articRow.
- 	articRow align: articRow fullBounds topCenter
- 			with: modRow fullBounds bottomCenter.
- 
- 	self bounds: (self fullBounds expandBy: (0 at 0 extent: 0 @ self borderWidth))
- !

Item was removed:
- ----- Method: KeyboardMorphForInput>>articulation:onOff: (in category 'note controls') -----
- articulation: artic onOff: ignored    "artic = eg, #legato, #normal, #staccato."
- 	"Set the articulation of notes to be emitted when a key is pressed."
- 
- 	self allMorphsDo:
- 		[:m | ((m isMemberOf: SimpleSwitchMorph)
- 				and: [m actionSelector == #articulation:onOff:])
- 				ifTrue: [m setSwitchState: m arguments first == artic]].
- 	articulation := artic!

Item was removed:
- ----- Method: KeyboardMorphForInput>>backspaceNote (in category 'note controls') -----
- backspaceNote
- 
- 	self deleteNotes!

Item was removed:
- ----- Method: KeyboardMorphForInput>>buildChord: (in category 'note controls') -----
- buildChord: onOff
- 	buildingChord := buildingChord not.!

Item was removed:
- ----- Method: KeyboardMorphForInput>>chords:onOff: (in category 'note controls') -----
- chords: chord onOff: ignored   
- 	"Select the semi tones of the chord from the chordDictonary."
- 
- 	self allMorphsDo:
- 		[:m | ((m isMemberOf: SimpleSwitchMorph)
- 				and: [m actionSelector == #chords:onOff:])
- 				ifTrue: [m setSwitchState: m arguments first = chord]].
- 	chordSemitones := chordDictionary at: chord.
- 	!

Item was removed:
- ----- Method: KeyboardMorphForInput>>deleteNotes (in category 'note controls') -----
- deleteNotes
- 
- 	pianoRoll deleteSelection!

Item was removed:
- ----- Method: KeyboardMorphForInput>>durMod:onOff: (in category 'note controls') -----
- durMod: durMod onOff: ignored    "durMod = eg, #dotted, #normal, #triplets, #quints"
- 	"Set the duration of notes to be emitted when a key is pressed."
- 
- 	self allMorphsDo:
- 		[:m | ((m isMemberOf: SimpleSwitchMorph)
- 				and: [m actionSelector == #durMod:onOff:])
- 				ifTrue: [m setSwitchState: m arguments first = durMod]].
- 	durationModifier := durMod!

Item was removed:
- ----- Method: KeyboardMorphForInput>>duration:onOff: (in category 'note controls') -----
- duration: denom onOff: ignored    "denom = eg, 1, 2, 4, 8, 16"
- 	"Set the duration of notes to be emitted when a key is pressed."
- 
- 	self allMorphsDo:
- 		[:m | ((m isMemberOf: SimpleSwitchMorph)
- 				and: [m actionSelector == #duration:onOff:])
- 				ifTrue: [m setSwitchState: m arguments first = denom]].
- 	duration := denom.
- 	self durMod: #normal onOff: true!

Item was removed:
- ----- Method: KeyboardMorphForInput>>emitRest (in category 'note controls') -----
- emitRest
- 
- 	| sel noteEvent |
- 
- 	"All this selection logic should be shared with mouseDown..."
- 	(sel := pianoRoll selection) ifNil: [^ self].
- 	insertMode ifTrue:
- 		[sel := pianoRoll selectionForInsertion.
- 		insertMode := false].
- 	sel = prevSelection ifFalse:
- 		["This is a new selection -- need to determine start time"
- 		sel third = 0
- 			ifTrue: [startOfNextNote := 0]
- 			ifFalse: [startOfNextNote := ((pianoRoll score tracks at: sel first)
- 										at: sel third) endTime.
- 					startOfNextNote := startOfNextNote + self fullDuration - 1
- 										truncateTo: self fullDuration]].
- 	noteEvent := NoteEvent new time: startOfNextNote; duration: self noteDuration;
- 			key: -1 "my flag for rest" velocity: self velocity channel: 1.
- 	pianoRoll appendEvent: noteEvent fullDuration: self fullDuration.
- 	soundPlaying ifNotNil: [soundPlaying stopGracefully].
- 	prevSelection := pianoRoll selection.
- 	startOfNextNote := startOfNextNote + self fullDuration.!

Item was removed:
- ----- Method: KeyboardMorphForInput>>fullDuration (in category 'note controls') -----
- fullDuration
- 
- 	| num denom |
- 	num := denom := 1.
- 	durationModifier == #dotted ifTrue: [num := 3.  denom := 2].
- 	durationModifier == #triplets ifTrue: [num := 2.  denom := 3].
- 	durationModifier == #quints ifTrue: [num := 2.  denom := 5].
- 	^ pianoRoll score ticksPerQuarterNote * 4 * num // duration // denom!

Item was removed:
- ----- Method: KeyboardMorphForInput>>initChordDictionary (in category 'initialization') -----
- initChordDictionary
-    
- chordDictionary :=
-       {'maj' -> #(0 4  7).
-         'min' -> #(0 3 7).
-         'dim' -> #(0 3 6).
-         'maj7' -> #(0 4 7 11).
-         'min7' -> #(0 3 7 10).
-         'dom7' -> #(0 4 7 10).
-         'sus2' -> #(0 2 7).
-         'sus4' -> #(0 5 7).
-         'aug' -> #(0 4 8)} as: Dictionary!

Item was removed:
- ----- Method: KeyboardMorphForInput>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- ""
- 	buildingChord := false.
- 	self addRecordingControls.
- 	self duration: 4 onOff: true.
- 	self durMod: #normal onOff: true.
- 	self articulation: #normal onOff: true.
- 	insertMode := false.
- 	self initChordDictionary!

Item was removed:
- ----- Method: KeyboardMorphForInput>>mouseDownPitch:event:noteMorph: (in category 'simple keyboard') -----
- mouseDownPitch: midiKey event: event noteMorph: keyMorph
- 
- 	| sel noteEvents |
- 	event hand hasSubmorphs ifTrue: [^ self  "no response if drag something over me"].
- 	keyMorph color: playingKeyColor.
- 	(sel := pianoRoll selection) ifNil: [^ self].
- 	insertMode ifTrue:
- 		[sel := pianoRoll selectionForInsertion.
- 		insertMode := false].
- 	sel = prevSelection ifFalse:
- 		["This is a new selection -- need to determine start time"
- 		sel third = 0
- 			ifTrue: [startOfNextNote := 0]
- 			ifFalse: [startOfNextNote := ((pianoRoll score tracks at: sel first)
- 										at: sel third) endTime.
- 					startOfNextNote := startOfNextNote + self fullDuration - 1
- 										truncateTo: self fullDuration]].
- 	noteEvents := self addNoteEventAt:startOfNextNote  rootNote: midiKey +23.
- 	soundPlaying ifNotNil: [soundPlaying stopGracefully].
- 	(soundPlaying := self soundForEvent: noteEvents inTrack: sel first) play.
- 	prevSelection := pianoRoll selection.
- 	startOfNextNote := startOfNextNote + self fullDuration.!

Item was removed:
- ----- Method: KeyboardMorphForInput>>mouseUpPitch:event:noteMorph: (in category 'simple keyboard') -----
- mouseUpPitch: pitch event: event noteMorph: noteMorph
- 	noteMorph color: ((#(0 1 3 5 6 8 10) includes: pitch\\12)
- 					ifTrue: [whiteKeyColor]
- 					ifFalse: [blackKeyColor]).
- !

Item was removed:
- ----- Method: KeyboardMorphForInput>>noteDuration (in category 'note controls') -----
- noteDuration
- 
- 	articulation == #staccato ifTrue: [^ (self fullDuration * 0.65) asInteger].
- 	articulation == #normal ifTrue: [^ (self fullDuration * 0.8) asInteger].
- 	articulation == #legato ifTrue: [^ (self fullDuration * 0.95) asInteger].
- !

Item was removed:
- ----- Method: KeyboardMorphForInput>>pianoRoll: (in category 'initialization') -----
- pianoRoll: prMorph
- 
- 	pianoRoll := prMorph!

Item was removed:
- ----- Method: KeyboardMorphForInput>>soundForEvent:inTrack: (in category 'events') -----
- soundForEvent: noteEvents inTrack: trackIndex
- 
- 	| sound player |
- 	player := pianoRoll scorePlayer.
- 	sound := MixedSound new.
- 	noteEvents do:[: noteEvent|
- 	sound add: ((player instrumentForTrack: trackIndex)
- 					soundForMidiKey: noteEvent midiKey
- 					dur: noteEvent duration / (pianoRoll scorePlayer ticksForMSecs: 1000)
- 					loudness: (noteEvent velocity asFloat / 127.0))
- 			pan: (player panForTrack: trackIndex)
- 			volume: player overallVolume *
- 						(player volumeForTrack: trackIndex)].
- 	^ sound
- !

Item was removed:
- ----- Method: KeyboardMorphForInput>>velocity (in category 'note controls') -----
- velocity
- 
- 	^ 80  "Later put a slider on the keyboard control"!

Item was removed:
- ImageMorph subclass: #LassoPatchMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !LassoPatchMorph commentStamp: 'sw 8/1/2004 13:27' prior: 0!
- When dropped by the user, a cursor is presented, allowing the user to grab a rectangular patch from the screen.!

Item was removed:
- ----- Method: LassoPatchMorph class>>authoringPrototype (in category 'instance creation') -----
- authoringPrototype
- 	"Answer a prototype  for use in a parts bin"
- 
- 	^ self new image: (ScriptingSystem formAtKey: 'Lasso'); markAsPartsDonor; setBalloonText: 'Drop this on the desktop and you can then grab a patch from the screen with a lasso.'; yourself!

Item was removed:
- ----- Method: LassoPatchMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	"Answer a description of the receiver to be used in a parts bin"
- 
- 	^ self partName:	'Lasso' translatedNoop
- 		categories:		{'Graphics' translatedNoop}
- 		documentation:	'Drop this icon to grab a patch from the screen with a lasso.' translatedNoop!

Item was removed:
- ----- Method: LassoPatchMorph>>initialize (in category 'initialization') -----
- initialize
- 	"Initialize the receiver.  Sets its image to the lasso picture"
- 
- 	super initialize.
- 	self image: (ScriptingSystem formAtKey: 'Lasso')!

Item was removed:
- ----- Method: LassoPatchMorph>>initializeToStandAlone (in category 'initialization') -----
- initializeToStandAlone
- 	"Initialize the receiver such that it can live on its own.  Sets its image to the lasso picture"
- 
- 	super initializeToStandAlone.
- 	self image: (ScriptingSystem formAtKey: 'Lasso')!

Item was removed:
- ----- Method: LassoPatchMorph>>justDroppedInto:event: (in category 'dropping') -----
- justDroppedInto: aPasteUpMorph event: anEvent
- 	"This message is sent to a dropped morph after it has been dropped on--and been accepted by--a drop-sensitive morph"
- 
- 	super justDroppedInto: aPasteUpMorph event: anEvent.
- 	
- 	aPasteUpMorph isPartsBin ifFalse: [
- 		"Do not show this morph in the screenshot."
- 		self hide.
- 		anEvent hand hide.
- 		self refreshWorld.
- 
- 		[aPasteUpMorph grabLassoFromScreen: anEvent]
- 			ensure: [anEvent hand show]].
- 
- 	"Just needed for this operation. Remove."	
- 	self delete.!

Item was removed:
- ----- Method: LassoPatchMorph>>wantsToBeDroppedInto: (in category 'dropping') -----
- wantsToBeDroppedInto: aMorph
- 	"Only wanted by the world"
- 
- 	^ aMorph isWorldMorph!

Item was removed:
- Morph subclass: #LedCharacterMorph
- 	instanceVariableNames: 'char highlighted'
- 	classVariableNames: 'BSegments CHSegmentOrigins CHSegments CVSegmentOrigins CVSegments DSegments TSegments'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Leds'!
- 
- !LedCharacterMorph commentStamp: 'cbr 7/27/2010 18:47' prior: 0!
- I represent a character to be displayed on an LedMorph; I am a peer to LedDigitMorph. The char 36 is SPACE.
- 
- I can live outside of LedMorphs, however. If you'd like to play with me, evaluate the following line:
- 
- 
- LedCharacterMorph new char: $e; openInWorld!

Item was removed:
- ----- Method: LedCharacterMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^false!

Item was removed:
- ----- Method: LedCharacterMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	CHSegmentOrigins := {0.2 at 0.1. 0.2 at 0.45. 0.2 at 0.8}.
- 	CVSegmentOrigins := {0.1 at 0.2. 0.1 at 0.55. 0.8 at 0.2. 0.8 at 0.55}.
- 	TSegments := { 0.25 at 0.25. 0.45 at 0.25. 0.55 at 0.25. 0.75 at 0.25. 0.25 at 0.6. 0.45 at 0.6. 0.55 at 0.6. 0.75 at 0.6. }.
- 	BSegments := { 0.45 at 0.4. 0.25 at 0.4. 0.75 at 0.4. 0.55 at 0.4. 0.45 at 0.76. 0.25 at 0.76. 0.75 at 0.76. 0.55 at 0.76. }.
- 
- 	DSegments  := {
- 	{false. false. false. false. false. false. false. false. }."0"
- 	{false. false. false. false. false. false. false. false. }."1"
- 	{false. false. false. false. false. false. false. false. }."2"
- 	{false. false. false. false. false. false. false. false. }."3"
- 	{false. false. false. false. false. false. false. false. }."4"
- 	{false. false. false. false. false. false. false. false. }."5"
- 	{false. false. false. false. false. false. false. false. }."6"
- 	{false. false. false. false. false. false. false. false. }."7"
- 	{false. false. false. false. false. false. false. false. }."8"
- 	{false. false. false. false. false. false. false. false. }."9"
- 	{false. false. false. false. false. false. false. false. }."A"
- 	{false. false. false. false. false. false. false. false. }."B"
- 	{false. false. false. false. false. false. false. false. }."C"
- 	{false. false. false. false. false. false. false. false. }."D"
- 	{false. false. false. false. false. false. false. false. }."E"
- 	{false. false. false. false. false. false. false. false. }."F"
- 	{false. false. false. false. false. false. false. false. }."G"
- 	{false. false. false. false. false. false. false. false. }."H"
- 	{false. false. false. false. false. false. false. false. }."I"
- 	{false. false. false. false. false. false. false. false. }."J"
- 	{false. false. false. true. false. false. false. false. }."K"
- 	{false. false. false. false. false. false. false. false. }."L"
- 	{true. false. false. true. false. false. false. false. }."M"
- 	{true. false. false. false. false. false. true. false. }."N"
- 	{false. true. true. false. true. false. false. true.  }."O"
- 	{false. false. false. false. false. false. false. false. }."P"
- 	{false. false. false. false. false. false. true. false. }."Q"
- 	{false. false. false. false. false. false. true. false. }."R"
- 	{false. false. false. false. false. false. false. false. }."S"
- 	{false. false. false. false. false. false. false. false. }."T"
- 	{false. false. false. false. false. false. false. false. }."U"
- 	{false. false. false. false. true. false. false. true. }."V"
- 	{false. false. false. false. false. true. true. false. }."W"
- 	{true. false. false. true. false. true. true. false. }."X"
- 	{false. false. false. false. false. false. false. false. }."Y"
- 	{false. false. false. true. false. true. false. false. }."Z"
- 	{false. false. false. false. false. false. false. false. }}."SPACE"
- 
- 	CHSegments := {
- 		{true. false. true}."0"
- 		{false. false. false}."1"
- 		{true. true. true}."2"
- 		{true. true. true}."3"
- 		{false. true. false}."4"
- 		{true. true. true}."5"
- 		{true. true. true}."6"
- 		{true. false. false}."7"
- 		{true. true. true}."8"
- 		{true. true. true}."9"
- 		{true. true. false}."A"
- 		{true. true. true}."B"
- 		{true. false. true}."C"
- 		{true. false. true}."D"
- 		{true. true. true}."E"
- 		{true. true. false}."F"
- 		{true. true. true}."G"
- 		{false. true. false}."H"
- 		{false. false. false}."I"
- 		{false. false. true}."J"
- 		{false. true. false}."K"
- 		{false. false. true}."L"
- 		{false. false. false}."M"
- 		{false. false. false}."N"
- 		{false. false. false}."O"
- 		{true. true. false}."P"
- 		{true. false. true}."Q"
- 		{true. true. false}."R"
- 		{true. true. true}."S"
- 		{false. true. true}."t"
- 		{false. false. true}."U"
- 		{false. false. false}."V"
- 		{false. false. false}."W"
- 		{false. false. false}."X"
- 		{false. true. true}."Y"
- 		{true. false. true}."Z"
- 		{false. false. false.}}."SPACE"
- 	CVSegments := {
- 		{true. true.  true. true}."0"
- 		{false. false. true. true}."1"
- 		{false. true. true. false}."2"
- 		{false. false. true. true}."3"
- 		{true. false. true. true}."4"
- 		{true. false. false. true}."5"
- 		{true. true. false. true}."6"
- 		{false. false. true. true}."7"
- 		{true. true. true. true}."8"
- 		{true. false. true. true}."9"
- 		{true. true. true. true}."A"
- 		{true. true. true. true}."B"
- 		{true. true. false. false}."C"
- 		{true. true. true. true}."D"
- 		{true. true. false. false}."E"
- 		{true. true. false. false}."F"
- 		{true. true. false. true}."G"
- 		{true. true. true. true}."H"
- 		{true. true. false. false}."I"
- 		{false. true. true. true}."J"
- 		{true. true. false. true}."K"
- 		{true. true. false. false}."L"
- 		{true. true.  true. true}."N"
- 		{true. true. true. true}."N"
- 		{false. false. false. false}."O"
- 		{true. true. true. false}."P"
- 		{true. true.  true. true}."q"
- 		{true. true. true. false}."R"
- 		{true. false. false. true}."S"
- 		{true. true. false. false}."t"
- 		{true. true. true. true}."U"
- 		{true. false. true. false}."V"
- 		{true. true.  true. true}."w"
- 		{false. false. false. false}."x"
- 		{true. false. true. true}."y"
- 		{false. false. false. false}."z"
- 		{false. false. false. false}}."SPACE"!

Item was removed:
- ----- Method: LedCharacterMorph>>char (in category 'accessing') -----
- char
- 
- 	 ^ char !

Item was removed:
- ----- Method: LedCharacterMorph>>char: (in category 'accessing') -----
- char: aCharacter 
- 	char := aCharacter digitValue.
- 	char >= 0 & (char <= 35) ifFalse: [char := 36]!

Item was removed:
- ----- Method: LedCharacterMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color green!

Item was removed:
- ----- Method: LedCharacterMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas 
- 	| foregroundColor backgroundColor thickness hThickness vThickness hOffset vOffset i |
- 	i := 0.
- 	foregroundColor := highlighted
- 				ifTrue: [Color white]
- 				ifFalse: [color].
- 	backgroundColor := color darker darker darker.
- 	hThickness := self height * 0.1.
- 	vThickness := self width * 0.1.
- 	thickness := hThickness min: vThickness.
- 	vOffset := hThickness - thickness // 2 max: 0.
- 	hOffset := vThickness - thickness // 2 max: 0.
- 	aCanvas fillRectangle: self bounds color: backgroundColor.
- 	CHSegmentOrigins with: (CHSegments at: char + 1)
- 		do: [:o :isLit | aCanvas fillRectangle: (Rectangle origin: (self position + (0 @ vOffset) + (o * self extent)) rounded extent: (self width * 0.6 @ thickness) rounded)
- 				color: (isLit
- 						ifTrue: [foregroundColor]
- 						ifFalse: [backgroundColor])].
- 	CVSegmentOrigins with: (CVSegments at: char + 1)
- 		do: [:o :isLit | aCanvas fillRectangle: (Rectangle origin: (self position + (hOffset @ 0) + (o * self extent)) rounded extent: (thickness @ (self height * 0.25)) rounded)
- 				color: (isLit
- 						ifTrue: [foregroundColor]
- 						ifFalse: [backgroundColor])].
- 	TSegments with: (DSegments at: char + 1)
- 		do: 
- 			[:tOrigin :isLit | | bOrigin | 
- 			i := i + 1.
- 			bOrigin := BSegments at: i.
- 			aCanvas
- 				line: self position x - hOffset + (self width * tOrigin x) @ (self position y - vOffset + (self height * tOrigin y))
- 				to: self position x + hOffset + (self width * bOrigin x) @ (self position y + vOffset + (self height * bOrigin y))
- 				width: thickness + 1 // 1.25
- 				color: (isLit
- 						ifTrue: [foregroundColor]
- 						ifFalse: [Color transparent])]!

Item was removed:
- ----- Method: LedCharacterMorph>>drawOnFills: (in category 'drawing') -----
- drawOnFills: aRectangle
- 
- 	^ true!

Item was removed:
- ----- Method: LedCharacterMorph>>highlighted (in category 'accessing') -----
- highlighted
- 
- 	^ highlighted!

Item was removed:
- ----- Method: LedCharacterMorph>>highlighted: (in category 'accessing') -----
- highlighted: aBoolean
- 
- 	highlighted := aBoolean.
- 	self changed.!

Item was removed:
- ----- Method: LedCharacterMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	
- 	highlighted := false.
- 	char := 0!

Item was removed:
- Morph subclass: #LedDigitMorph
- 	instanceVariableNames: 'digit highlighted'
- 	classVariableNames: 'HSegmentOrigins HSegments VSegmentOrigins VSegments'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Leds'!
- 
- !LedDigitMorph commentStamp: '<historical>' prior: 0!
- I am a 7-segment LED that can display a decimal digit!

Item was removed:
- ----- Method: LedDigitMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^false!

Item was removed:
- ----- Method: LedDigitMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	HSegmentOrigins := {0.2 at 0.1. 0.2 at 0.45. 0.2 at 0.8}.
- 	VSegmentOrigins := {0.1 at 0.2. 0.1 at 0.55. 0.8 at 0.2. 0.8 at 0.55}.
- 	HSegments := {
- 		{true. false. true}.
- 		{false. false. false}.
- 		{true. true. true}.
- 		{true. true. true}.
- 		{false. true. false}.
- 		{true. true. true}.
- 		{true. true. true}.
- 		{true. false. false}.
- 		{true. true. true}.
- 		{true. true. true}.
- 		{false. true. false}}.
- 	VSegments := {
- 		{true. true. true. true}.
- 		{false. false. true. true}.
- 		{false. true. true. false}.
- 		{false. false. true. true}.
- 		{true. false. true. true}.
- 		{true. false. false. true}.
- 		{true. true. false. true}.
- 		{false. false. true. true}.
- 		{true. true. true. true}.
- 		{true. false. true. true}.
- 		{false. false. false. false}}.!

Item was removed:
- ----- Method: LedDigitMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color green!

Item was removed:
- ----- Method: LedDigitMorph>>digit (in category 'accessing') -----
- digit
- 
- 	^ digit!

Item was removed:
- ----- Method: LedDigitMorph>>digit: (in category 'accessing') -----
- digit: anInteger
- 
- 	digit := anInteger \\ 10	"make sure it stays between 0 and 9"!

Item was removed:
- ----- Method: LedDigitMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	| foregroundColor backgroundColor thickness hThickness vThickness hOffset vOffset |
- 	foregroundColor := highlighted ifTrue: [Color white] ifFalse: [color].
- 	backgroundColor := color muchDarker.
- 	hThickness := self height * 0.1.
- 	vThickness := self width * 0.1.
- 	thickness := hThickness min: vThickness.
- 	vOffset := ((hThickness - thickness) // 2) max: 0.
- 	hOffset := ((vThickness - thickness) // 2) max: 0.
- 	aCanvas fillRectangle: self bounds color: backgroundColor.
- 	"added to show the minus sign"
- 	(digit asString = '-') ifTrue: [digit := 10].
- 	HSegmentOrigins with: (HSegments at: digit+1) do:
- 		[:o :isLit |
- 		aCanvas
- 			fillRectangle: (Rectangle
- 				origin: (self position + (0 at vOffset) + (o * self extent)) rounded
- 				extent: ((self width * 0.6) @ thickness) rounded)
- 			color: (isLit ifTrue: [foregroundColor] ifFalse: [backgroundColor])].
- 	VSegmentOrigins with: (VSegments at: digit+1) do:
- 		[:o :isLit |
- 		aCanvas
- 			fillRectangle: (Rectangle
- 				origin: (self position + (hOffset at 0) + (o * self extent)) rounded
- 				extent: (thickness @ (self height * 0.25)) rounded)
- 			color: (isLit ifTrue: [foregroundColor] ifFalse: [backgroundColor])].
- !

Item was removed:
- ----- Method: LedDigitMorph>>drawOnFills: (in category 'drawing') -----
- drawOnFills: aRectangle
- 
- 	^ true!

Item was removed:
- ----- Method: LedDigitMorph>>highlighted (in category 'accessing') -----
- highlighted
- 
- 	^ highlighted!

Item was removed:
- ----- Method: LedDigitMorph>>highlighted: (in category 'accessing') -----
- highlighted: aBoolean
- 
- 	highlighted := aBoolean.
- 	self changed.!

Item was removed:
- ----- Method: LedDigitMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	highlighted := false.
- 	digit := 0 !

Item was removed:
- Morph subclass: #LedMorph
- 	instanceVariableNames: 'digits chars value flashing flash string scroller scrollLoop'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Leds'!
- 
- !LedMorph commentStamp: '<historical>' prior: 0!
- I am a collection of LED digits that can display a decimal value.  The display can be set to flash by sending flash: true.
- 
- LedMorph can now display characters:
- 
- LedMorph new  string:'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; openInWorld
- 
- Lowercase letters will be converted to Uppercase. Carachters not in the examle
- above will be shown as SPACE which is char 36 in LedCharacterMorph.
- 
- LedMorph new  chars: 10; string:'           I must get a life';flash:true;scrollLoop:true; openInWorld
- 
- The number of letters is set by chars. 
- If chars is not specified it will be set to the string size. 
- When the string size is bigger than chars
- the string will scroll across the led. WOW!!
- scrollLoop let's you set the scrolling to start over once its finished.
- 
- Enjoy.
- 
- !

Item was removed:
- ----- Method: LedMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^false!

Item was removed:
- ----- Method: LedMorph>>chars (in category 'accessing') -----
- chars
- 
- 	 ^ chars!

Item was removed:
- ----- Method: LedMorph>>chars: (in category 'accessing') -----
- chars: aNumber 
- 	chars := aNumber.
- 	self removeAllMorphs.
- 	1 to: chars do: [:i | self addMorph: (LedCharacterMorph new color: color)].
- 	self layoutChanged.
- 	self changed!

Item was removed:
- ----- Method: LedMorph>>color: (in category 'accessing') -----
- color: aColor 
- 	"set the receiver's color and the submorphs color"
- 	super color: aColor.
- 	self
- 		submorphsDo: [:m | m color: aColor]!

Item was removed:
- ----- Method: LedMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color green!

Item was removed:
- ----- Method: LedMorph>>digits (in category 'accessing') -----
- digits
- 
- 	^ digits!

Item was removed:
- ----- Method: LedMorph>>digits: (in category 'accessing') -----
- digits: aNumber
- 
- 	digits := aNumber.
- 	self removeAllMorphs.
- 	1 to: digits do: [:i | self addMorph: (LedDigitMorph new color: color)].
- 	self layoutChanged.
- 	self changed.!

Item was removed:
- ----- Method: LedMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	aCanvas fillRectangle: self bounds color: color darker darker.
- !

Item was removed:
- ----- Method: LedMorph>>flash (in category 'macpal') -----
- flash
- 
- 	^ flash!

Item was removed:
- ----- Method: LedMorph>>flash: (in category 'accessing') -----
- flash: aBoolean
- 
- 	flash := aBoolean.!

Item was removed:
- ----- Method: LedMorph>>highlighted: (in category 'accessing') -----
- highlighted: aBoolean
- 
- 	self submorphsDo: [:m | m highlighted: aBoolean]!

Item was removed:
- ----- Method: LedMorph>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- ""
- 	flashing := false.
- 	flash := false.
- 	self scrollInit.
- 	self digits: 2.
- 	self value: 0!

Item was removed:
- ----- Method: LedMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 
- 	super layoutChanged.
- 	submorphs withIndexDo:
- 		[:m :i |
- 		m
- 			position: self position + (((i-1) * self width / digits) rounded @ 0);
- 			extent: (self width / digits) rounded @ self height]!

Item was removed:
- ----- Method: LedMorph>>scrollInit (in category 'initialization') -----
- scrollInit
- 
- 	chars := 0.
- 	scroller := 1.
- 	string := ''.
- 	scrollLoop := false.
- !

Item was removed:
- ----- Method: LedMorph>>scrollLoop (in category 'accessing') -----
- scrollLoop	
- 
- 	^ scrollLoop!

Item was removed:
- ----- Method: LedMorph>>scrollLoop: (in category 'accessing') -----
- scrollLoop: aBoolean
- 
- 	scrollLoop := aBoolean.!

Item was removed:
- ----- Method: LedMorph>>step (in category 'stepping and presenter') -----
- step
- 	(flash or: [flashing])
- 		ifTrue: 
- 			[flashing := flashing not.
- 			self highlighted: flashing].
- 	scroller ifNil: [scroller := 1].
- 	chars ifNil: [^ self].
- 	scroller + chars < (string size + 1)
- 		ifTrue: 
- 			[scroller := scroller + 1.
- 			self stringToLed]
- 		ifFalse: [scrollLoop ifTrue: [scroller := 1]]!

Item was removed:
- ----- Method: LedMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 
- 	^ 500!

Item was removed:
- ----- Method: LedMorph>>string (in category 'accessing') -----
- string
- 
- 	^ string!

Item was removed:
- ----- Method: LedMorph>>string: (in category 'accessing') -----
- string: aString 
- 	string := aString.
- 	chars = 0
- 		ifTrue: 
- 			[chars := string size.
- 			self chars: chars].
- 	self stringToLed!

Item was removed:
- ----- Method: LedMorph>>stringToLed (in category 'accessing') -----
- stringToLed
- 	| i k actualString |
- 	i := scroller ifNil: [1].
- 	k := 1.
- 	actualString := String new: chars.
- 	actualString do: 
- 		[:m | 
- 		i > string size ifFalse: [actualString at: k put: (string at: i) asUppercase asCharacter].
- 		i := i + 1.
- 		k := k + 1].
- 	i := 1.
- 	submorphs do: 
- 		[:m | 
- 		m char: (actualString at: i).
- 		i := i + 1].
- 	self changed!

Item was removed:
- ----- Method: LedMorph>>value (in category 'accessing') -----
- value
- 
- 	^ value!

Item was removed:
- ----- Method: LedMorph>>value: (in category 'accessing') -----
- value: aNumber
- 
- 	| val |
- 	value := aNumber.
- 	val := value.
- 	submorphs reverseDo:
- 		[:m |
- 		m digit: val \\ 10.
- 		val := val // 10].
- 	self changed.!

Item was removed:
- LedMorph subclass: #LedTimerMorph
- 	instanceVariableNames: 'counting startSeconds'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Leds'!

Item was removed:
- ----- Method: LedTimerMorph class>>includeInNewMorphMenu (in category 'new-morph participation') -----
- includeInNewMorphMenu
- 
- 	^false!

Item was removed:
- ----- Method: LedTimerMorph>>continue (in category 'accessing') -----
- continue
- 
- 	counting := true!

Item was removed:
- ----- Method: LedTimerMorph>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	super initialize.
- ""
- 	counting := false.
- 	startSeconds := Time totalSeconds!

Item was removed:
- ----- Method: LedTimerMorph>>pause (in category 'accessing') -----
- pause
- 
- 	counting ifTrue: [self updateTime].
- 	counting := false!

Item was removed:
- ----- Method: LedTimerMorph>>reset (in category 'accessing') -----
- reset
- 
- 	startSeconds := Time totalSeconds.
- 	self value: 0.!

Item was removed:
- ----- Method: LedTimerMorph>>resume (in category 'accessing') -----
- resume
- 
- 	counting ifFalse: [
- 		counting := true.
- 		startSeconds :=  (Time totalSeconds) - self value]!

Item was removed:
- ----- Method: LedTimerMorph>>start (in category 'stepping and presenter') -----
- start
- 
- 	counting := true!

Item was removed:
- ----- Method: LedTimerMorph>>step (in category 'stepping and presenter') -----
- step
- 
- 	flash
- 		ifTrue: [super step]
- 		ifFalse: [
- 			counting ifTrue: [self updateTime]]!

Item was removed:
- ----- Method: LedTimerMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 
- 	^ 1000!

Item was removed:
- ----- Method: LedTimerMorph>>stop (in category 'stepping and presenter') -----
- stop
- 
- 	counting ifTrue: [self updateTime].
- 	counting := false.!

Item was removed:
- ----- Method: LedTimerMorph>>updateTime (in category 'stepping and presenter') -----
- updateTime
- 
- 	self value:  Time totalSeconds - startSeconds.
- 	self changed!

Item was removed:
- ----- Method: LineMorph class>>exampleBackArrow (in category '*MorphicExtras-examples') -----
- exampleBackArrow
- 	"LineMorph exampleBackArrow openInHand"
- 
- 	^ (LineMorph from: 12 @ 0 to: 0 @ 0 color: Color black width: 1)
- 		makeForwardArrow;
- 		yourself!

Item was removed:
- ----- Method: LoopedSampledSound>>edit (in category '*MorphicExtras-Sound') -----
- edit
- 	"Open a WaveEditor on this sound."
- 
- 	| loopLen ed |
- 	loopLen := scaledLoopLength asFloat / LoopIndexScaleFactor.
- 	ed := WaveEditor new
- 		data: leftSamples;
- 		samplingRate: originalSamplingRate;
- 		loopEnd: loopEnd;
- 		loopLength: loopLen;
- 		loopCycles: (loopLen / (originalSamplingRate asFloat / perceivedPitch)) rounded.
- 	ed openInWorld.
- !

Item was removed:
- AlignmentMorph subclass: #MIDIControllerMorph
- 	instanceVariableNames: 'channel controller midiPort lastValue'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!

Item was removed:
- ----- Method: MIDIControllerMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'set channel' translated action: #setChannel:.
- 	aCustomMenu add: 'set controller' translated action: #setController:.
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>channel (in category 'accessing') -----
- channel
- 
- 	^ channel
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>channel: (in category 'accessing') -----
- channel: anInteger
- 
- 	channel := anInteger.
- 	lastValue := nil.
- 	self updateLabel.
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>controller (in category 'accessing') -----
- controller
- 
- 	^ controller
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>controller: (in category 'accessing') -----
- controller: anInteger
- 
- 	controller := anInteger.
- 	lastValue := nil.
- 	self updateLabel.
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>controllerList (in category 'menu') -----
- controllerList
- 	"Answer a list of controller name, number pairs to be used in the menu."
- 
- 	^ #((1 modulation)
- 		(2 'breath control')
- 		(7 volume)
- 		(10 pan)
- 		(11 expression)
- 		(92 'tremolo depth')
- 		(93 'chorus depth')
- 		(94 'celeste depth')
- 		(95 'phaser depth'))
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>controllerName: (in category 'menu') -----
- controllerName: controllerNumber
- 	"Answer a name for the given controller. If no name is available, use the form 'CC5' (CC is short for 'continuous controller')."
- 
- 	self controllerList do: [:pair |
- 		pair first = controllerNumber ifTrue: [^ pair last]].
- 	^ 'CC', controllerNumber asString
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- "answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: MIDIControllerMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color
- 		r: 0.484
- 		g: 0.613
- 		b: 0.0!

Item was removed:
- ----- Method: MIDIControllerMorph>>initialize (in category 'initialization') -----
- initialize
- "initialize the state of the receiver"
- 	| slider |
- 	super initialize.
- ""
- 	self listDirection: #topToBottom.
- 	self wrapCentering: #center;
- 		 cellPositioning: #topCenter.
- 	self hResizing: #shrinkWrap.
- 	self vResizing: #shrinkWrap.
- 	channel := 0.
- 	controller := 7.
- 	"channel volume"
- 	slider := SimpleSliderMorph new target: self;
- 				 actionSelector: #newSliderValue:;
- 				 minVal: 0;
- 				 maxVal: 127;
- 				 extent: 128 @ 10.
- 	self addMorphBack: slider.
- 	self
- 		addMorphBack: (StringMorph contents: 'Midi Controller').
- 	self updateLabel!

Item was removed:
- ----- Method: MIDIControllerMorph>>midiPort (in category 'accessing') -----
- midiPort
- 
- 	^ midiPort
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>midiPort: (in category 'accessing') -----
- midiPort: anInteger
- 
- 	midiPort := anInteger.
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>newSliderValue: (in category 'other') -----
- newSliderValue: newValue
- 	"Send a control command out the MIDI port."
- 
- 	| val |
- 	midiPort ifNil: [^ self].
- 	val := newValue asInteger.
- 	lastValue = val ifTrue: [^ self].
- 	lastValue := val.
- 	midiPort midiCmd: 16rB0 channel: channel byte: controller byte: val.
- !

Item was removed:
- ----- Method: MIDIControllerMorph>>setChannel: (in category 'menu') -----
- setChannel: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	1 to: 16 do: [:chan |
- 		menu add: chan printString
- 			target: self
- 			selector: #channel:
- 			argumentList: (Array with: chan - 1)].
- 
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: MIDIControllerMorph>>setController: (in category 'menu') -----
- setController: evt
- 	| menu |
- 	menu := MenuMorph new.
- 	self controllerList do: [:pair |
- 		menu add: (pair last)
- 			target: self
- 			selector: #controller:
- 			argumentList: (Array with: pair first)].
- 
- 	menu popUpEvent: evt in: self world!

Item was removed:
- ----- Method: MIDIControllerMorph>>updateLabel (in category 'other') -----
- updateLabel
- 
- 	| label |
- 	(label := self findA: StringMorph) ifNil: [^ self].
- 	label contents: (self controllerName: controller), ', ch: ', (channel + 1) printString.
- !

Item was removed:
- ----- Method: MIDIScore class>>extraExample (in category '*MorphicExtras-examples') -----
- extraExample
- 	"(ScorePlayerMorph on: MIDIScore extraExample) openInWorld"
- 
- 	| tracks |
- 	tracks := self extraExampleTrackData collect: [:track | (ReferenceStream on:
- 		(Base64MimeConverter mimeDecodeToBytes: track readStream)) next].
- 	^ self new
- 		tracks: tracks values trackInfo: tracks keys;
- 		ticksPerQuarterNote: 96;
- 		tempoMap: self extraExampleTempoMap;
- 		yourself!

Item was removed:
- ----- Method: MIDIScore class>>extraExampleTempoMap (in category '*MorphicExtras-examples') -----
- extraExampleTempoMap
- 
- 	^ {0->750000 . 26496->769230 . 26592->789473 . 26688->810810 . 26784->833333 . 26880->857142 . 26976->882352 . 27072->909090}
- 		collect: [:tempoData | TempoEvent time: tempoData key tempo: tempoData value]!

Item was removed:
- ----- Method: MIDIScore class>>extraExampleTrackData (in category '*MorphicExtras-examples') -----
(excessive size, no diff calculated)

Item was removed:
- BorderedMorph subclass: #MagnifierMorph
- 	instanceVariableNames: 'magnification trackPointer srcExtent showPointer'
- 	classVariableNames: 'RecursionLock'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!
- 
- !MagnifierMorph commentStamp: '<historical>' prior: 0!
- MagnifierMorph instances are magnifying lenses that magnify the morphs below them (if grabbed or if trackPointer is false) or the area around the mouse pointer.
- 
- Instance variables:
- 
- magnification	<Number> The magnification to use. If non-integer, smooths the magnified form.
- 
- trackPointer		<Boolean> If set, magnifies the area around the Hand. If not, magnfies the area underneath the magnifier center.
- 
- showPointer		<Boolean> If set, display a small reversed rectangle in the center of the lens. Also enables the display of Morphs in the Hand itself.
- 
- srcExtent		<Rectangle> The extent of the source rectangle.
- 		
- Class variables:
- 
- RecursionLock	<MagnifierMorph|nil> Used to avoid infinite recursion when getting the source patch to display.!

Item was removed:
- ----- Method: MagnifierMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'Magnifier' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop}
- 		documentation:	'A magnifying glass' translatedNoop!

Item was removed:
- ----- Method: MagnifierMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.!

Item was removed:
- ----- Method: MagnifierMorph class>>newRound (in category 'instance creation') -----
- newRound
- 	"Answer a round Magnifier"
- 
- 	| aMagnifier sm |
- 	aMagnifier := self new.
- 	sm := ScreeningMorph new position: aMagnifier position.
- 	sm addMorph: aMagnifier.
- 	sm addMorph: (EllipseMorph newBounds: aMagnifier bounds).
- 	sm setNameTo: 'Magnifier'.
- 	^ sm!

Item was removed:
- ----- Method: MagnifierMorph class>>newShowingPointer (in category 'instance creation') -----
- newShowingPointer
- 	"Answer a Magnifier that also displays Morphs in the Hand and the Hand position"
- 
- 	^(self new)
- 		showPointer: true;
- 		setNameTo: 'HandMagnifier';
- 		yourself!

Item was removed:
- ----- Method: MagnifierMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#MagnifierMorph. #newRound. 'Magnifier' translatedNoop.	'A magnifying glass' translatedNoop}
- 						forFlapNamed: 'Widgets']!

Item was removed:
- ----- Method: MagnifierMorph class>>supplementaryPartsDescriptions (in category 'parts bin') -----
- supplementaryPartsDescriptions
- 	^ {DescriptionForPartsBin
- 		formalName: 'RoundGlass' translatedNoop
- 		categoryList: {'Just for Fun' translatedNoop}
- 		documentation: 'A round magnifying glass' translatedNoop
- 		globalReceiverSymbol: #MagnifierMorph
- 		nativitySelector: #newRound.
- 		
- 	DescriptionForPartsBin
- 		formalName: 'Hand Magnifier' translatedNoop
- 		categoryList: #()
- 		documentation: 'A magnifying glass that also shows Morphs in the Hand and displays the Hand position.' translatedNoop
- 		globalReceiverSymbol: #MagnifierMorph
- 		nativitySelector: #newShowingPointer }!

Item was removed:
- ----- Method: MagnifierMorph class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: MagnifierMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu
- 		addLine;
- 		add: 'magnification...' translated action: #chooseMagnification;
- 		addUpdating: #trackingPointerString action: #toggleTrackingPointer;
- 		addUpdating: #showingPointerString action: #toggleShowingPointer.!

Item was removed:
- ----- Method: MagnifierMorph>>borderWidth: (in category 'accessing') -----
- borderWidth: anInteger
- 	"Grow outwards preserving innerBounds"
- 	| c |  
- 	c := self center.
- 	super borderWidth: anInteger.
- 	super extent: self defaultExtent.
- 	self center: c.!

Item was removed:
- ----- Method: MagnifierMorph>>chooseMagnification (in category 'menu') -----
- chooseMagnification
- 	| result |
- 	result := UIManager default chooseFrom: #(1.5 2 4 8) values: #(1.5 2 4 8) 
- 		title:  ('Choose magnification
- (currently {1})' translated format:{magnification}).
- 	(result isNil or: [result = magnification]) ifTrue: [^ self].
- 	magnification := result.
- 	self extent: self extent. "round to new magnification"
- 	self changed. "redraw even if extent wasn't changed"!

Item was removed:
- ----- Method: MagnifierMorph>>chooseMagnification: (in category 'menu') -----
- chooseMagnification: evt
- 	| handle origin aHand currentMag |
- 	currentMag := magnification.
- 	aHand := evt ifNil: [self currentHand] ifNotNil: [evt hand].
- 	origin := aHand position y.
- 	handle := HandleMorph new forEachPointDo:
- 		[:newPoint | self magnification: (newPoint y - origin) / 8.0 + currentMag].
- 	aHand attachMorph: handle.
- 	handle startStepping.
- 	self changed. "Magnify handle"!

Item was removed:
- ----- Method: MagnifierMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: MagnifierMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color black!

Item was removed:
- ----- Method: MagnifierMorph>>defaultExtent (in category 'geometry') -----
- defaultExtent
- 	^(srcExtent * magnification) truncated + (2 * self borderWidth)!

Item was removed:
- ----- Method: MagnifierMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	super drawOn: aCanvas.		"border and fill"
- 	aCanvas isShadowDrawing ifFalse: [
- 		"Optimize because #magnifiedForm is expensive"
- 		aCanvas paintImage: self magnifiedForm at: self innerBounds origin]!

Item was removed:
- ----- Method: MagnifierMorph>>extent: (in category 'geometry') -----
- extent: aPoint
- 	"Round to multiples of magnification"
- 	srcExtent := (aPoint - (2 * self borderWidth)) // magnification.
- 	^super extent: self defaultExtent!

Item was removed:
- ----- Method: MagnifierMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 	^evt yellowButtonPressed
- 		or: [super handlesMouseDown: evt]!

Item was removed:
- ----- Method: MagnifierMorph>>hasTranslucentColor (in category 'accessing') -----
- hasTranslucentColor
- 	"I may show what's behind me, so tell the hand to don't cache"
- 	^self sourceRect intersects: self bounds!

Item was removed:
- ----- Method: MagnifierMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 
- 	trackPointer := true.
- 	showPointer := false.
- 	magnification := 2.
- 
- 	self extent: 128 @ 128!

Item was removed:
- ----- Method: MagnifierMorph>>magnification: (in category 'magnifying') -----
- magnification: aNumber
- 	| c |  
- 	magnification := aNumber min: 8 max: 0.5.
- 	magnification := magnification roundTo:
- 		(magnification < 3 ifTrue: [0.5] ifFalse: [1]).
- 	srcExtent := srcExtent min: (512 at 512) // magnification. "to prevent accidents"
- 	c := self center.
- 	super extent: self defaultExtent.
- 	self center: c.!

Item was removed:
- ----- Method: MagnifierMorph>>magnifiedForm (in category 'magnifying') -----
- magnifiedForm
- 	"Answer the magnified form"
- 	| srcRect form exclusion magnified |
- 	srcRect := self sourceRectFrom: self sourcePoint.
- 	(RecursionLock isNil and: [ self showPointer or: [ srcRect intersects: self bounds ]])
- 		ifTrue: [RecursionLock := self.
- 			exclusion := self.
- 			form := self currentWorld
- 						patchAt: srcRect
- 						without: exclusion
- 						andNothingAbove: false.
- 			RecursionLock := nil]
- 		ifFalse: ["cheaper method if the source is not occluded"
- 			form := Display copy: srcRect].
- 	"smooth if non-integer scale"
- 	magnified := form
- 				magnify: form boundingBox
- 				by: magnification
- 				smoothing: (magnification isInteger
- 						ifTrue: [1]
- 						ifFalse: [2]).
- 	"display the pointer rectangle if desired"
- 	self showPointer
- 		ifTrue: [magnified
- 				reverse: (magnified center - (2 @ 2) extent: 4 @ 4)
- 				fillColor: Color white].
- 	^ magnified!

Item was removed:
- ----- Method: MagnifierMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 	evt yellowButtonPressed
- 		ifTrue: [self chooseMagnification: evt]
- 		ifFalse: [super mouseDown: evt]!

Item was removed:
- ----- Method: MagnifierMorph>>showPointer (in category 'menu') -----
- showPointer
- 	^showPointer ifNil: [ showPointer := false ].!

Item was removed:
- ----- Method: MagnifierMorph>>showPointer: (in category 'accessing') -----
- showPointer: aBoolean
- 	"If aBoolean is true, display the current pointer position as a small square in the center of the lens."
- 
- 	showPointer == aBoolean ifTrue: [ ^self ].
- 	showPointer := aBoolean.
- 	self changed.!

Item was removed:
- ----- Method: MagnifierMorph>>showingPointerString (in category 'menu') -----
- showingPointerString
- 	"Answer a string characterizing whether or not I'm showing the pointer."
- 
- 	^ (self showPointer 
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>']), 'show pointer' translated!

Item was removed:
- ----- Method: MagnifierMorph>>sourcePoint (in category 'magnifying') -----
- sourcePoint
- 	"If we are being dragged use our center, otherwise use pointer position"
- 	^(trackPointer not or: [owner notNil and: [owner isHandMorph]])
- 		ifTrue: [self isFlexed ifTrue:[owner center] ifFalse:[self center]]
- 		ifFalse: [self currentHand position]!

Item was removed:
- ----- Method: MagnifierMorph>>sourceRect (in category 'magnifying') -----
- sourceRect
- 	^self sourceRectFrom: self sourcePoint
- !

Item was removed:
- ----- Method: MagnifierMorph>>sourceRectFrom: (in category 'magnifying') -----
- sourceRectFrom: aPoint
- 	^ (aPoint extent: srcExtent) translateBy: (srcExtent // -2) + 1.
- !

Item was removed:
- ----- Method: MagnifierMorph>>step (in category 'stepping and presenter') -----
- step
- 	self changed!

Item was removed:
- ----- Method: MagnifierMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 	^ 33 "ms = 30 frames-per-second"!

Item was removed:
- ----- Method: MagnifierMorph>>toggleShowingPointer (in category 'menu') -----
- toggleShowingPointer
- 	self showPointer: self showPointer not!

Item was removed:
- ----- Method: MagnifierMorph>>toggleTrackingPointer (in category 'menu') -----
- toggleTrackingPointer
- 	trackPointer := trackPointer not!

Item was removed:
- ----- Method: MagnifierMorph>>trackingPointerString (in category 'menu') -----
- trackingPointerString
- 	"Answer a string describing whether or not I'm currently tracking the pointer."
- 
- 	^ (trackPointer
- 		ifTrue: ['<yes>']
- 		ifFalse: ['<no>']), 'track pointer' translated!

Item was removed:
- BorderedMorph subclass: #MarqueeMorph
- 	instanceVariableNames: 'colors count'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-AdditionalWidgets'!
- 
- !MarqueeMorph commentStamp: '<historical>' prior: 0!
- The MarqueeMorph is a subclass of the BorderedMorph which quickly cycles its border color.
- 
- The implementation could be simplified and generalized.  The color values and cycle speed are hard-coded for example.!

Item was removed:
- ----- Method: MarqueeMorph>>initialize (in category 'initialization') -----
- initialize
- 
-         super initialize.
-         colors := {Color red. Color white. Color blue}.
-         count := 0!

Item was removed:
- ----- Method: MarqueeMorph>>step (in category 'stepping and presenter') -----
- step
- 
-         count := count + 1.
-         count > colors size ifTrue: [count := 1].
-         self borderColor: (colors at: count)!

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

Item was removed:
- ----- Method: MarqueeMorph>>wantsSteps (in category 'stepping and presenter') -----
- wantsSteps
- 
-         ^ true!

Item was removed:
- ----- Method: MatrixTransform2x3>>encodePostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- encodePostscriptOn: aStream
- 	aStream writeMatrix:self.
- !

Item was removed:
- ----- Method: MenuIcons class>>backIcon (in category '*MorphicExtras-accessing - icons') -----
- backIcon
- 	"Private - Generated method"
- 	^ Icons
- 			at: #'back'
- 			ifAbsentPut:[ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self backIconContents readStream) ].!

Item was removed:
- ----- Method: MenuIcons class>>backIconContents (in category '*MorphicExtras-private - icons') -----
- backIconContents
- 	"Private - Method generated with the content of the file /home/dgd/back.png"
- 	^ 'iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAABHNCSVQICAgIfAhkiAAAABF0
- RVh0U29mdHdhcmUAU29kaXBvZGmU4xfQAAADRElEQVRIie3WW4hVVRgH8N/e+5y56aCizpnR
- jJzUCNFqLhqEWGlQDz0mGEJBCSL1Ur1YZA9BSIZGZg9dVBoo0B5D6qGwOzVaairZiJiKZ0hs
- 1NE5c2bm7N3DmXF2zQyO5lv+YbFZa/2/77+/y9prcxNpNFnoHi3/xUU4LtYiszX5WGC/ULsW
- m69XMLgqo8UzEhtRlVpNJJb62Tc3TnCxnH7bBR65sra0nt8vkC9Ah9Ay7U5d2Z+jUrUaoRqx
- Hr/qGp9gk0cFPsB0UFfFugUsybH1N7YfS7O7UTE4/u2vgDze02ijXUrRCLFmzwtswwRhwGO3
- Wb55tcWNzQ75g7+KfNmZtqhEZoyXz2IKlutSIe+LNCnQ7A08NxRVuKHVywvXWG+lDXZ5SRs9
- A7Qd53g3pSQlG1GboTY7PKojNh/hXBFK+s0oC85XocoOrASzJ6p9+wE7c69I8K7PfKrdgBK4
- XYNWc+VMFgwGlkgU9Svo06OooOiksw7u3MPrhwySVmVAlTasAAummPzWg16oXWGdD+13fESe
- ulxSZ5I7zTJHg1tNVxIr6FNQ1KlLuw7fOkJ9dTqHDwWarBJoA7lqPlqiflJO58gGuz78cJZn
- fxya/ZQRutdQKZY1MKlifGJJzEA/A32UUs+4NDhispVcjtMRdmeU7BBag8iJM5yOmDmPYIwj
- 2pXn5MGy2LhQl3pJF0O/2CuwBXzfS0cnR7+j9/IoUSWcPnINYuhNcRN/DnXpRFUOoFFNwKYa
- wgJ1s2mYS1TuLedOceLAsIMwIsoSZEhC4oCBgD70xpzB9ktcGExr4PHhvLVqFPsaM02NeC2L
- XjKVTJtVdp7vKNfufB1bznO2RLE03lhj5P5ZqBZ3SHyFnFsyrM+SFEaabqrm6CjrY6Mf79tn
- 7cjOaDVfbA+mmRzyajUVqXpGE3g6NQ88IXZYKFISCUVioUAfetDjolOOKZbpo6HV3WK70SCL
- F2uZ0V3eOzCFd64cm8/t8/C1hDr29dSqXuwT3AfuyjIvy66etPVT9tp2YwShWRZvYu0ouydd
- MG8oVePFyOspjbxY3m4znMD9hm/90xJPOuzYmLZj4Oq/GENYZKqS1QKxPlsdNMqX4Sb+D/gb
- LOgMCUjhiw4AAAAASUVORK5CYII='!

Item was removed:
- ----- Method: MenuIcons class>>forwardIcon (in category '*MorphicExtras-accessing - icons') -----
- forwardIcon
- 	"Private - Generated method"
- 	^ Icons
- 			at: #'forward'
- 			ifAbsentPut:[ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self forwardIconContents readStream) ].!

Item was removed:
- ----- Method: MenuIcons class>>forwardIconContents (in category '*MorphicExtras-private - icons') -----
- forwardIconContents
- 	"Private - Method generated with the content of the file /home/dgd/forward.png"
- 	^ 'iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAABHNCSVQICAgIfAhkiAAAABF0
- RVh0U29mdHdhcmUAU29kaXBvZGmU4xfQAAADXUlEQVRIie3WX2iVZRwH8M97znv2f1o2Fy4r
- hxMvhhCeTewmJcuEbiLLP0GECoJWEIlYUBoR3QTVhRRIXffvJupiBF4oRCZukq5Na4LhlKnT
- 6XE7c/P8ebs4O8fNlh3nVdEPHnif5/d8f9/3+33e53le/usRvyv0UknzzDXgQrmQ2IzJkt4V
- 6BT4xVJfWKa5HFgwI7J27fIOmerQmMBOnfbeGWGrChXmoVZeSlZKjzQisEyznA4s1lhFWwMd
- Z4tZIh0SNjk8vc03CZO2Yzcap32R6WLLIrYt5sgl3jvOudFiZlBki6O+vxVSsKTNK9iLurLJ
- 4PkFLKy38YE1Wp5b7uT1P+hJEakV2KDJiAGHpipMSmAIdeoT7GwlGzGaJT2pjeUK49l8Aflw
- HZtaqI57xwv22OhD33qj+2OZXYe5OFaYF/nIUTtMmB5ot0LeAbB5kSXbn9LqIRXCUksIBZOE
- Dxl2RJ8T+ktjKy2x1RpN5lh7aY/Lr+6n71qR9EvjXtLjRijnyVKt+TVOOqtNiyc84kENQnGJ
- Cef7XXLKgGtG9Ruc4u4B3Q7o1mKelxue9ennCYOv76fzMoENqmXxYiDpK6wD7y9ldVPZS3i7
- mKPe0PAQ6w/etDfwTIjh0qx0mounuXEdAUFAECMekqgkrCCsJFFReA7+/twYMkx9guVz+W7C
- +rwVIVKlWUGK/vPlSQgC5rfSuGD6fD7H6V76SvXGBPbFBJM2aCpTHhlEEQO/E+X/mhu+TO9B
- jl3lxETNyG5dTsbdb1xgK+gaY3YdFdXkagiqCWuIVxFWEYbEYhMkUUFFWEntPYWimXHOdHO2
- l5Fa3koVyQ5aaJteUYCYpAtoKFtdTYwd9zF/sGBtY3OBfOgcuSz5Wbw2zHgEXVilq7B0cUSa
- jKEdNWURZiL6MqyMCkrTVxhNFZTnZ7MrzWgeesSt0ulKETr1GFviXjUqkJAVE8rLysnIqZKT
- 0SzmR1SCfXVEIzfxV+t5e4QbEZzCY7oMTKa48+sp6TNsAetn8fi1wvY4Vssnw8Vb41c8rcuZ
- W+EzIVyNH0r99gT9Oc6XvtavZWx2XHo6+Mwu4DY/iTx6y2hO5E1HfXA76Ex/MTbh50n930RW
- /xMZM1VYxLZZK2/MQh2+kbuLWv/Hvyj+BJaPHpqZ0oo8AAAAAElFTkSuQmCC'!

Item was removed:
- ----- Method: MenuIcons class>>helpIcon (in category '*MorphicExtras-accessing - icons') -----
- helpIcon
- 	"Private - Generated method"
- 	^ Icons
- 			at: #'help'
- 			ifAbsentPut:[ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self helpIconContents readStream) ].!

Item was removed:
- ----- Method: MenuIcons class>>helpIconContents (in category '*MorphicExtras-private - icons') -----
- helpIconContents
- 	"Private - Method generated with the content of the file /home/dgd/help.png"
- 	^ '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
- W2tds0/6AAAAAElFTkSuQmCC'!

Item was removed:
- ----- Method: MenuIcons class>>openIcon (in category '*MorphicExtras-accessing - icons') -----
- openIcon
- 	"Private - Generated method"
- 	^ Icons
- 			at: #'open'
- 			ifAbsentPut:[ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: self openIconContents readStream) ].!

Item was removed:
- ----- Method: MenuIcons class>>openIconContents (in category '*MorphicExtras-private - icons') -----
- openIconContents
- 	"Private - Method generated with the content of the file /home/dgd/open.png"
- 	^ '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
- 0/8ClPo3sCGCJrEAAAAASUVORK5CYII='!

Item was removed:
- ----- Method: MenuMorph>>allWordings (in category '*MorphicExtras-accessing') -----
- allWordings
- 	"Answer a collection of the wordings of all items and subitems, omitting the window-list in the embed... branch and (unless a certain hard-coded preference is set) also omitting items from the debug menu"
- 
- 	| verboten |
- 	verboten := OrderedCollection with: 'embed into'.
- 	Preferences debugMenuItemsInvokableFromScripts 
- 		ifFalse:	[verboten add: 'debug...' translated].
- 	^ self allWordingsNotInSubMenus: verboten!

Item was removed:
- ----- Method: MenuMorph>>allWordingsNotInSubMenus: (in category '*MorphicExtras-accessing') -----
- allWordingsNotInSubMenus: verbotenSubmenuContentsList
- 	"Answer a collection of the wordings of all items and subitems, but omit the stay-up item, and also any items in any submenu whose tag is in verbotenSubmenuContents"
- 
- 	| aList |
- 	aList := OrderedCollection new.
- 	self items do: [:anItem | aList addAll: (anItem allWordingsNotInSubMenus: verbotenSubmenuContentsList)].
- 	^ aList!

Item was removed:
- ----- Method: MessageNames class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: MessageNames class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#MessageNames.		#prototypicalToolWindow.	'Message Names' translatedNoop.		'A tool for finding, viewing, and editing all methods whose names contain a given character sequence.' translatedNoop}
- 						forFlapNamed: 'Tools']!

Item was removed:
- ----- Method: MessageNames class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #FileServices ifPresent: [:cl |
- 		cl unregisterFileReader: self].
- 	self environment at: #Flaps ifPresent: [:cl |
- 		cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: Morph class>>addPartsDescriptorQuadsTo:if: (in category '*MorphicExtras-new-morph participation') -----
- addPartsDescriptorQuadsTo: aList if: aBlock
- 	"For each of the standard objects to be put into parts bins based on declarations in this class, add a parts-launching quintuplet to aList, provided that the boolean-valued-block-with-one-argument supplied evaluates to true when provided the DescriptionForPartsBin"
- 
- 	| info more |
- 	(self class includesSelector: #descriptionForPartsBin) ifTrue:
- 		[info := self descriptionForPartsBin.
- 		(aBlock value: info) ifTrue:
- 			[aList add:
- 				{info globalReceiverSymbol.
- 				info nativitySelector.
- 				info formalName.
- 				info documentation.
- 				info sampleImageFormOrNil}]].
- 
- 	(self class includesSelector: #supplementaryPartsDescriptions)
- 		ifTrue:
- 			[more := self supplementaryPartsDescriptions.
- 			(more isKindOf: DescriptionForPartsBin) ifTrue: [more := Array with: more].
- 				"The above being a mild bit of forgiveness, so that in the usual only-one
- 				case, the user need not return a collection"
- 			more do:
- 				[:aPartsDescription |  (aBlock value: aPartsDescription) ifTrue:
- 					[aList add:
- 						{aPartsDescription globalReceiverSymbol.
- 						aPartsDescription nativitySelector.
- 						aPartsDescription formalName.
- 						aPartsDescription documentation.
- 						aPartsDescription sampleImageFormOrNil}]]]!

Item was removed:
- ----- Method: Morph class>>defaultArrowheadSize (in category '*MorphicExtras-arrow head size') -----
- defaultArrowheadSize
- 	
- 	^ 5 @ 4!

Item was removed:
- ----- Method: Morph class>>obtainArrowheadFor:defaultValue: (in category '*MorphicExtras-arrow head size') -----
- obtainArrowheadFor: aPrompt defaultValue: defaultPoint
- 	"Allow the user to supply a point to serve as an arrowhead size.  Answer nil if we fail to get a good point"
- 
- 	| result  |
- 	result := UIManager default request: aPrompt initialAnswer: defaultPoint asString.
- 	result isEmptyOrNil ifTrue: [^ nil].
- 	^ [(Point readFrom: (ReadStream on: result))]
- 		on: Error do: [:ex |  nil].!

Item was removed:
- ----- Method: Morph class>>supplementaryPartsDescriptions (in category '*MorphicExtras-parts bin') -----
- supplementaryPartsDescriptions
- 	"Answer a list of DescriptionForPartsBin objects that characterize objects that this class wishes to contribute to Stationery bins *other* than by the standard default #newStandAlone protocol"
- 
- 	^ {	DescriptionForPartsBin
- 			formalName: 'Status' translatedNoop
- 			categoryList: #()
- 			documentation: 'Buttons to run, stop, or single-step scripts' translatedNoop
- 			globalReceiverSymbol: #ScriptingSystem
- 			nativitySelector: #scriptControlButtons.
- 		DescriptionForPartsBin
- 			formalName: 'Scripting' translatedNoop
- 			categoryList: {'Scripting' translatedNoop}
- 			documentation: 'A confined place for drawing and scripting, with its own private stop/step/go buttons.' translatedNoop
- 			globalReceiverSymbol: #ScriptingSystem
- 			nativitySelector: #newScriptingSpace.
- 		DescriptionForPartsBin
- 			formalName: 'Random' translatedNoop
- 			categoryList: {'Scripting' translatedNoop}
- 			documentation: 'A tile that will produce a random number in a given range' translatedNoop
- 			globalReceiverSymbol: #FunctionTile
- 			nativitySelector: #randomNumberTile.
- 		DescriptionForPartsBin
- 			formalName: 'ButtonDown?' translatedNoop
- 			categoryList: {'Scripting' translatedNoop}
- 			documentation: 'Tiles for querying whether the mouse button is down' translatedNoop
- 			globalReceiverSymbol: #ScriptingSystem
- 			nativitySelector: #anyButtonPressedTiles.
- 		DescriptionForPartsBin
- 			formalName: 'ButtonUp?' translatedNoop
- 			categoryList: {'Scripting' translatedNoop}
- 			documentation: 'Tiles for querying whether the mouse button is up' translatedNoop
- 			globalReceiverSymbol: #ScriptingSystem
- 			nativitySelector: #noButtonPressedTiles.
- 		DescriptionForPartsBin
- 			formalName: 'NextPage' translatedNoop
- 			categoryList: {'Multimedia' translatedNoop}
- 			documentation: 'A button which, when clicked, takes the reader to the next page of a book' translatedNoop
- 			globalReceiverSymbol: #BookMorph
- 			nativitySelector: #nextPageButton.
- 		DescriptionForPartsBin
- 			formalName: 'PreviousPage' translatedNoop
- 			categoryList: {'Multimedia'}
- 			documentation: 'A button which, when clicked, takes the reader to the previous page of a book' translatedNoop
- 			globalReceiverSymbol: #BookMorph
- 			nativitySelector: #previousPageButton.},
- 
- 	self partsDescriptionsFromToolsFlap!

Item was removed:
- ----- Method: Morph>>asEPS (in category '*MorphicExtras-postscript') -----
- asEPS
- 
- 	^ EPSCanvas morphAsPostscript: self rotated: false.
- !

Item was removed:
- ----- Method: Morph>>asPostscriptPrintJob (in category '*MorphicExtras-postscript') -----
- asPostscriptPrintJob
- 
- 	^ DSCPostscriptCanvas morphAsPostscript: self rotated: false.
- !

Item was removed:
- ----- Method: Morph>>dismissButton (in category '*MorphicExtras-menus') -----
- dismissButton
- 	"Answer a button whose action would be to dismiss the receiver, and whose action is to send #delete to the receiver"
- 
- 	| aButton |
- 	aButton := SimpleButtonMorph new.
- 	aButton
- 		target: self topRendererOrSelf;
- 		color: Color lightRed;
- 		borderColor: Color lightRed muchDarker;
- 		borderWidth: 1;
- 		label: 'X' font: Preferences standardButtonFont;
- 		actionSelector: #delete;
- 		setBalloonText: 'dismiss' translated.
- 	^ aButton!

Item was removed:
- ----- Method: Morph>>exportAsEPS (in category '*MorphicExtras-postscript') -----
- exportAsEPS
- 
- 	| fName |
- 	fName := UIManager default saveFilenameRequest:'Please enter the name' translated initialAnswer: self externalName,'.eps'.
- 	fName ifNil:[^self].
- 	self exportAsEPSNamed: fName
- !

Item was removed:
- ----- Method: Morph>>exportAsEPSNamed: (in category '*MorphicExtras-postscript') -----
- exportAsEPSNamed: aString
- 
- 	FileStream fileNamed: aString do: [:stream |
- 		stream nextPutAll: self asEPS]
- !

Item was removed:
- ----- Method: Morph>>nextOwnerPage (in category '*MorphicExtras') -----
- nextOwnerPage
- 	"Tell my container to advance to the next page"
- 	| targ |
- 	targ := self ownerThatIsA: BookMorph.
- 	targ ifNotNil: [targ nextPage]!

Item was removed:
- ----- Method: Morph>>previousOwnerPage (in category '*MorphicExtras') -----
- previousOwnerPage
- 	"Tell my container to advance to the previous page"
- 	| targ |
- 	targ := self ownerThatIsA: BookMorph.
- 	targ ifNotNil: [targ previousPage]!

Item was removed:
- ----- Method: Morph>>printPSToFileNamed: (in category '*MorphicExtras-menus') -----
- printPSToFileNamed: aString 
- 	"Ask the user for a filename and print this morph as postscript."
- 	| fileName rotateFlag psCanvasType psExtension |
- 
- 	psCanvasType := PostscriptCanvas defaultCanvasType.
- 	psExtension := psCanvasType defaultExtension.
- 	fileName := UIManager default saveFilenameRequest: 'File name? '
- 			initialAnswer: (aString, psExtension) asFileName.
- 	fileName ifNil: [^ Beeper beep].
- 
- 	rotateFlag := (UIManager default chooseOptionFrom: {
- 		'portrait (tall)' translated.
- 		'landscape (wide)' translated.
- 	} title: 'Choose orientation...' translated) = 2.
- 	(FileStream newFileNamed: fileName)
- 		nextPutAll: (psCanvasType morphAsPostscript: self rotated: rotateFlag);
- 		 close!

Item was removed:
- ----- Method: Morph>>shiftSubmorphsBy: (in category '*MorphicExtras-geometry') -----
- shiftSubmorphsBy: delta
- 	self shiftSubmorphsOtherThan: (submorphs select: [:m | m wantsToBeTopmost]) by: delta!

Item was removed:
- ----- Method: MorphExtension>>removeUndoCommands (in category '*MorphicExtras-Undo') -----
- removeUndoCommands
- 
- 	| keysToBeRemoved |
- 	otherProperties ifNil: [ ^self ].
- 	otherProperties keysAndValuesDo: [ :key :value |
- 		value class == Command ifTrue: [
- 			(keysToBeRemoved ifNil: [
- 				keysToBeRemoved := OrderedCollection new ]) add: key ] ].
- 	keysToBeRemoved ifNil: [ ^self ].
- 	keysToBeRemoved do: [ :each |
- 		self removeProperty: each ]
- 	!

Item was removed:
- ----- Method: MorphExtension>>updateReferencesUsing: (in category '*MorphicExtras-copying') -----
- updateReferencesUsing: aDictionary 
- 	"Update intra-morph references within a composite morph that  
- 	has been copied. For example, if a button refers to morph X in  
- 	the orginal  
- 	composite then the copy of that button in the new composite  
- 	should refer to  
- 	the copy of X in new composite, not the original X. This default  
- 	implementation updates the contents of any morph-bearing slot."
- 
- 	| old |
- 	eventHandler isNil 
- 		ifFalse: 
- 			[self eventHandler: self eventHandler copy.
- 			1 to: self eventHandler class instSize
- 				do: 
- 					[:i | 
- 					old := eventHandler instVarAt: i.
- 					old isMorph 
- 						ifTrue: [eventHandler instVarAt: i put: (aDictionary at: old ifAbsent: [old])]]].
- 	otherProperties ifNotNil: [otherProperties associationsDo:  [:assn | 
- 					assn value: (aDictionary at: assn value ifAbsent: [assn value])]]!

Item was removed:
- ObjectOut subclass: #MorphObjectOut
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SqueakPage'!

Item was removed:
- ----- Method: MorphObjectOut>>doesNotUnderstand: (in category 'error handling') -----
- doesNotUnderstand: aMessage 
- 	"Bring in the object, install, then resend aMessage"
- 	| aMorph myUrl oldFlag response |
- 	"Transcript show: thisContext sender selector; cr." "useful for debugging"
- 	oldFlag := recursionFlag.
- 	recursionFlag := true.
- 	myUrl := url.	"can't use inst vars after become"
- 	"fetch the object"
- 	aMorph := self xxxFetch.		"watch out for the become!!"
- 	"Now we ARE a MORPH"
- 	oldFlag == true ifTrue:
- 		[response := Project uiManager
- 						chooseOptionFrom: #('proceed normally' 'debug')
- 						title: 'Object being fetched for a second time.
- Should not happen, and needs to be fixed later.'.
- 		response = 2 ifTrue: [self halt]].	"We are already the new object"
- 
- 	aMorph setProperty: #SqueakPage toValue: (SqueakPageCache pageCache at: myUrl).
- 	"Can't be a super message, since this is the first message sent to this object"
- 	^ aMorph perform: aMessage selector withArguments: aMessage arguments
- !

Item was removed:
- ----- Method: MorphObjectOut>>fullReleaseCachedState (in category 'caching') -----
- fullReleaseCachedState
- 	"do nothing, especially don't bring in my object!!"!

Item was removed:
- ----- Method: MorphObjectOut>>smallThumbnailForPageSorter (in category 'misc') -----
- smallThumbnailForPageSorter
- 
- 	^ self sqkPage thumbnail!

Item was removed:
- ----- Method: MorphObjectOut>>thumbnailForPageSorter (in category 'misc') -----
- thumbnailForPageSorter
- 
- 	^ self sqkPage thumbnail!

Item was removed:
- SketchMorph subclass: #MorphThumbnail
- 	instanceVariableNames: 'morphRepresented'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Books'!
- 
- !MorphThumbnail commentStamp: '<historical>' prior: 0!
- A morph whose appearance is a thumbnail of some other morph.!

Item was removed:
- ----- Method: MorphThumbnail>>addCustomMenuItems:hand: (in category 'menus') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 	super addCustomMenuItems: aCustomMenu hand: aHandMorph.
- 	aCustomMenu add: 'reveal original morph' translated action: #revealOriginal.
- 	aCustomMenu add: 'grab original morph' translated action: #grabOriginal.
- !

Item was removed:
- ----- Method: MorphThumbnail>>computeThumbnail (in category 'private') -----
- computeThumbnail
- 	"Assumption on entry:
-        The receiver's width represents the maximum width allowable.
-        The receiver's height represents the exact height desired."
- 
- 	| f scaleX scaleY |
- 	f := morphRepresented imageForm.
- 	morphRepresented fullReleaseCachedState.
- 	scaleY := self height / f height.  "keep height invariant"
- 	scaleX := ((morphRepresented width * scaleY) <= self width)
- 		ifTrue:
- 			[scaleY]  "the usual case; same scale factor, to preserve aspect ratio"
- 		ifFalse:
- 			[self width / f width].
- 	self form: (f magnify: f boundingBox by: (scaleX @ scaleY) smoothing: 2).
- 	self extent: originalForm extent!

Item was removed:
- ----- Method: MorphThumbnail>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color lightGray!

Item was removed:
- ----- Method: MorphThumbnail>>grabOriginal (in category 'menus') -----
- grabOriginal
- 	self primaryHand attachMorph: morphRepresented!

Item was removed:
- ----- Method: MorphThumbnail>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	| f |
- 	super initialize.
- 	""
- 
- 	f := Form extent: 60 @ 80 depth: Display depth.
- 	f fill: f boundingBox fillColor: color.
- 	self form: f!

Item was removed:
- ----- Method: MorphThumbnail>>innocuousName (in category 'naming') -----
- innocuousName
- 	^ morphRepresented isNil
- 		ifTrue: [super innocuousName]
- 		ifFalse: [morphRepresented innocuousName]!

Item was removed:
- ----- Method: MorphThumbnail>>isPartsDonor (in category 'parts bin') -----
- isPartsDonor
- 	"answer whether the receiver is PartsDonor"
- 	^ self partRepresented isPartsDonor!

Item was removed:
- ----- Method: MorphThumbnail>>isPartsDonor: (in category 'parts bin') -----
- isPartsDonor: aBoolean
- 	"change the receiver's isPartDonor property"
- 	self partRepresented isPartsDonor: aBoolean!

Item was removed:
- ----- Method: MorphThumbnail>>morphRepresented (in category 'thumbnail') -----
- morphRepresented
- 
- 	^ morphRepresented
- !

Item was removed:
- ----- Method: MorphThumbnail>>morphRepresented: (in category 'accessing') -----
- morphRepresented: aMorph
- 
- 	morphRepresented := aMorph.
- 	self computeThumbnail.
- !

Item was removed:
- ----- Method: MorphThumbnail>>partRepresented (in category 'parts bin') -----
- partRepresented
- 	^self morphRepresented!

Item was removed:
- ----- Method: MorphThumbnail>>representativeNoTallerThan:norWiderThan:thumbnailHeight: (in category 'thumbnail') -----
- representativeNoTallerThan: maxHeight norWiderThan: maxWidth thumbnailHeight: thumbnailHeight
- 
- 	"Return a morph representing the receiver but which is no taller than aHeight.  If the receiver is already small enough, just return it, else return a MorphThumbnail companioned to the receiver, enforcing the maxWidth"
- 
- 	(self height <= maxHeight and: [self width <= maxWidth]) ifTrue: [^ self].
- 
- 	^ MorphThumbnail new
- 		extent: maxWidth @ (thumbnailHeight min: self height);
- 		morphRepresented: morphRepresented!

Item was removed:
- ----- Method: MorphThumbnail>>revealOriginal (in category 'menus') -----
- revealOriginal
- 	((owner isKindOf: PasteUpMorph) and: [owner alwaysShowThumbnail]) 
- 		ifTrue: [^Beeper beep].
- 	morphRepresented owner isNil 
- 		ifTrue: [^owner replaceSubmorph: self by: morphRepresented].
- 	Beeper beep!

Item was removed:
- ----- Method: MorphThumbnail>>smaller (in category 'initialization') -----
- smaller
- 	self form: (self form copy: (0 at 0 extent: self form extent // 2))!

Item was removed:
- ----- Method: MorphThumbnail>>veryDeepFixupWith: (in category 'copying') -----
- veryDeepFixupWith: deepCopier
- 	"If target and arguments fields were weakly copied, fix them here.  If they were in the tree being copied, fix them up, otherwise point to the originals!!!!"
- 
- super veryDeepFixupWith: deepCopier.
- morphRepresented := deepCopier references at: morphRepresented 
- 		ifAbsent: [morphRepresented].!

Item was removed:
- ----- Method: MorphThumbnail>>veryDeepInner: (in category 'copying') -----
- veryDeepInner: deepCopier
- 	"Copy all of my instance variables.  Some need to be not copied at all, but shared.  	Warning!!!!  Every instance variable defined in this class must be handled.  We must also implement veryDeepFixupWith:.  See DeepCopier class comment."
- 
- super veryDeepInner: deepCopier.
- morphRepresented := morphRepresented.		"Weakly copied"!

Item was removed:
- ----- Method: MorphicModel>>compileInitMethods (in category '*MorphicExtras-compilation') -----
- compileInitMethods
- 	| s nodeDict varNames |
- 	nodeDict := IdentityDictionary new.
- 	s := WriteStream on: (String new: 2000).
- 	varNames := self class allInstVarNames.
- 	s nextPutAll: 'initMorph'.
- 	3 to: self class instSize do:
- 		[:i | (self instVarAt: i) isMorph ifTrue:
- 			[s cr; tab; nextPutAll: (varNames at: i) , ' := '.
- 			s nextPutAll: (self instVarAt: i) initString; nextPutAll: '.'.
- 			nodeDict at: (self instVarAt: i) put: (varNames at: i)]].
- 	submorphs do: 
- 		[:m | s cr; tab; nextPutAll: 'self addMorph: '.
- 		m printConstructorOn: s indent: 1 nodeDict: nodeDict.
- 		s nextPutAll: '.'].
- 	self class
- 		compile: s contents
- 		classified: 'initialization'
- 		notifying: nil.!

Item was removed:
- EllipseMorph subclass: #MovingEyeMorph
- 	instanceVariableNames: 'inner iris'
- 	classVariableNames: 'IrisSize'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Demo'!

Item was removed:
- ----- Method: MovingEyeMorph class>>color:irisColor: (in category 'instance creation') -----
- color: aColor irisColor: anotherColor
- 
- 	^ self new color: aColor irisColor: anotherColor!

Item was removed:
- ----- Method: MovingEyeMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'MovingEye' translatedNoop
- 		categories:		{'Just for Fun' translatedNoop}
- 		documentation:	'An eye which follows the cursor' translatedNoop!

Item was removed:
- ----- Method: MovingEyeMorph class>>extraExampleSqueakGhostIsWatchingYou (in category 'examples') -----
- extraExampleSqueakGhostIsWatchingYou
- 	"MovingEyeMorph extraExampleSqueakGhostIsWatchingYou openInHand"
- 
- 	| logoMorph leftEye rightEye |
- 	logoMorph := (Form squeakLogo collectColors: #negated) asMorph.
- 	leftEye := (self color: Color white irisColor: Color black)
- 		extent: logoMorph extent * (0.1 @ 0.15);
- 		center: (logoMorph pointAtFraction: 0.39 @ 0.55);
- 		yourself.
- 	rightEye := (self color: Color white irisColor: Color black)
- 		extent: logoMorph extent * (0.1 @ 0.15);
- 		center: (logoMorph pointAtFraction: 0.59 @ 0.56);
- 		yourself.
- 	logoMorph addAllMorphs: {leftEye. rightEye}.
- 	^ logoMorph.!

Item was removed:
- ----- Method: MovingEyeMorph class>>extraExampleSqueakIsWatchingYou (in category 'examples') -----
- extraExampleSqueakIsWatchingYou
- 	"MovingEyeMorph extraExampleSqueakIsWatchingYou openInHand"
- 
- 	| logoMorph leftEye rightEye |
- 	logoMorph := Form squeakLogo asMorph.
- 	leftEye := self new
- 		extent: logoMorph extent * (0.1 @ 0.15);
- 		center: (logoMorph pointAtFraction: 0.39 @ 0.55);
- 		yourself.
- 	rightEye := self new
- 		extent: logoMorph extent * (0.1 @ 0.15);
- 		center: (logoMorph pointAtFraction: 0.59 @ 0.56);
- 		yourself.
- 	logoMorph addAllMorphs: {leftEye. rightEye}.
- 	^ logoMorph.!

Item was removed:
- ----- Method: MovingEyeMorph class>>initialize (in category 'class initialization') -----
- initialize
- "
- 	MovingEyeMorph initialize
- "
- 	IrisSize := (0.42 at 0.50).!

Item was removed:
- ----- Method: MovingEyeMorph>>color: (in category 'accessing') -----
- color: aColor
- 
- 	super color: aColor.
- 	
- 	"Migrate old instances."
- 	inner color: Color transparent.
- 	
- 	self keepIrisVisible.!

Item was removed:
- ----- Method: MovingEyeMorph>>color:irisColor: (in category 'accessing') -----
- color: aColor irisColor: anotherColor
- 
- 	self color: aColor.
- 	self irisColor: anotherColor.!

Item was removed:
- ----- Method: MovingEyeMorph>>defaultBorderWidth (in category 'accessing') -----
- defaultBorderWidth
- 
- 	^ 0!

Item was removed:
- ----- Method: MovingEyeMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- "answer the default color/fill style for the receiver"
- 	^ Color black!

Item was removed:
- ----- Method: MovingEyeMorph>>extent: (in category 'geometry') -----
- extent: aPoint
- 
- 	super extent: aPoint.
- 	inner extent: (self extent * ((1.0 at 1.0)-IrisSize)) asIntegerPoint.
- 	iris extent: (self extent * IrisSize) asIntegerPoint.
- 	inner position: (self center - (inner extent // 2)) asIntegerPoint.
- !

Item was removed:
- ----- Method: MovingEyeMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	inner := EllipseMorph new.
- 	inner color: Color transparent.
- 	inner extent: (self extent * (1.0 @ 1.0 - IrisSize)) asIntegerPoint.
- 	inner borderWidth: 0.
- ""
- 	iris := EllipseMorph new.
- 	iris color: Color white.
- 	iris extent: (self extent * IrisSize) asIntegerPoint.
- ""
- 	self addMorphCentered: inner.
- 	inner addMorphCentered: iris.
- ""
- 	self extent: 26 @ 33!

Item was removed:
- ----- Method: MovingEyeMorph>>irisColor (in category 'accessing') -----
- irisColor
- 
- 	^ iris color!

Item was removed:
- ----- Method: MovingEyeMorph>>irisColor: (in category 'accessing') -----
- irisColor: aColor
- 
- 	iris color: aColor.
- 	
- 	self keepIrisVisible.!

Item was removed:
- ----- Method: MovingEyeMorph>>irisPos (in category 'accessing') -----
- irisPos
- 
- 	^ iris position!

Item was removed:
- ----- Method: MovingEyeMorph>>irisPos: (in category 'accessing') -----
- irisPos: cp
- 
- 	| a b theta x y |
- 	theta := (cp - self center) theta.
- 	a := inner width // 2.
- 	b := inner height // 2.
- 	x := a * (theta cos).
- 	y := b * (theta sin).
- 	iris position: ((x at y) asIntegerPoint) + self center - (iris extent // 2).!

Item was removed:
- ----- Method: MovingEyeMorph>>keepIrisVisible (in category 'private') -----
- keepIrisVisible
- 
- 	self color = self irisColor
- 		ifTrue: [
- 			iris borderWidth: 1;
- 			borderColor: self color makeForegroundColor]
- 		ifFalse: [
- 			iris borderWidth: 0].!

Item was removed:
- ----- Method: MovingEyeMorph>>step (in category 'stepping and presenter') -----
- step
- 	| cp |
- 	cp := self globalPointToLocal: self world primaryHand position.
- 	(inner containsPoint: cp)
- 		ifTrue: [iris position: (cp - (iris extent // 2))]
- 		ifFalse: [self irisPos: cp].!

Item was removed:
- ----- Method: MovingEyeMorph>>stepTime (in category 'testing') -----
- stepTime
- 
- 	^ 100.!

Item was removed:
- FormCanvas subclass: #MultiResolutionCanvas
- 	instanceVariableNames: 'deferredMorphs'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Support'!

Item was removed:
- ----- Method: MultiResolutionCanvas>>deferredMorphs (in category 'accessing') -----
- deferredMorphs
- 
- 	^deferredMorphs!

Item was removed:
- ----- Method: MultiResolutionCanvas>>deferredMorphs: (in category 'accessing') -----
- deferredMorphs: aCollection
- 
- 	deferredMorphs := aCollection!

Item was removed:
- ----- Method: MultiResolutionCanvas>>fullDraw: (in category 'drawing-general') -----
- fullDraw: aMorph
- 
- 	aMorph canDrawAtHigherResolution ifTrue: [
- 		deferredMorphs ifNil: [deferredMorphs := OrderedCollection new].
- 		deferredMorphs add: aMorph.
- 	] ifFalse: [
- 		super fullDraw: aMorph
- 	].!

Item was removed:
- ----- Method: MultiResolutionCanvas>>initializeFrom: (in category 'initialize-release') -----
- initializeFrom: aFormCanvas
- 
- 	origin := aFormCanvas origin.
- 	clipRect := aFormCanvas privateClipRect.
- 	form := aFormCanvas form.
- 	port := aFormCanvas privatePort.
- 	shadowColor := aFormCanvas shadowColor.
- !

Item was removed:
- ----- Method: NewBalloonMorph>>isBalloonHelp (in category '*MorphicExtras-classification') -----
- isBalloonHelp
- 	^ true!

Item was removed:
- ----- Method: Object>>capturedState (in category '*MorphicExtras-Undo') -----
- capturedState
- 	"May be overridden in subclasses."
- 
- 	^ self shallowCopy
- !

Item was removed:
- ----- Method: Object>>commandHistory (in category '*MorphicExtras-Undo') -----
- commandHistory
- 	"Return the command history for the receiver"
- 	| w |
- 	(w := self currentWorld) ifNotNil: [^ w commandHistory].
- 	^ CommandHistory new. "won't really record anything but prevent breaking things"!

Item was removed:
- ----- Method: Object>>descriptionForPartsBin (in category '*MorphicExtras-PartsBin') -----
- descriptionForPartsBin
- 	"If the receiver is a member of a class that would like to be represented in a parts bin, answer the name by which it should be known, and a documentation string to be provided, for example, as balloon help.  When the 'nativitySelector' is sent to the 'globalReceiver', it is expected that some kind of Morph will result.  The parameters used in the implementation below are for documentation purposes only!!"
- 
- 	^ DescriptionForPartsBin
- 		formalName: 'PutFormalNameHere'
- 		categoryList: #(PutACategoryHere MaybePutAnotherCategoryHere)
- 		documentation: 'Put the balloon help here'
- 		globalReceiverSymbol: #PutAGlobalHere
- 		nativitySelector: #PutASelectorHere!

Item was removed:
- ----- Method: Object>>purgeAllCommands (in category '*MorphicExtras-Undo') -----
- purgeAllCommands
- 	"Purge all commands for this object"
- 	Preferences useUndo ifFalse: [^ self]. "get out quickly"
- 	self commandHistory purgeAllCommandsSuchThat: [:cmd | cmd undoTarget == self].
- !

Item was removed:
- ----- Method: Object>>redoFromCapturedState: (in category '*MorphicExtras-Undo') -----
- redoFromCapturedState: st 
- 	"May be overridden in subclasses.  See also capturedState"
- 
- 	self undoFromCapturedState: st  "Simple cases are symmetric"
- !

Item was removed:
- ----- Method: Object>>refineRedoTarget:selector:arguments:in: (in category '*MorphicExtras-Undo') -----
- refineRedoTarget: target selector: aSymbol arguments: arguments in: refineBlock 
- 	"Any object can override this method to refine its redo specification"
- 
- 	^ refineBlock
- 		value: target
- 		value: aSymbol
- 		value: arguments!

Item was removed:
- ----- Method: Object>>refineUndoTarget:selector:arguments:in: (in category '*MorphicExtras-Undo') -----
- refineUndoTarget: target selector: aSymbol arguments: arguments in: refineBlock 
- 	"Any object can override this method to refine its undo specification"
- 
- 	^ refineBlock
- 		value: target
- 		value: aSymbol
- 		value: arguments!

Item was removed:
- ----- Method: Object>>rememberCommand: (in category '*MorphicExtras-Undo') -----
- rememberCommand: aCommand
- 	"Remember the given command for undo"
- 	Preferences useUndo ifFalse: [^ self]. "get out quickly"
- 	^ self commandHistory rememberCommand: aCommand!

Item was removed:
- ----- Method: Object>>rememberUndoableAction:named: (in category '*MorphicExtras-Undo') -----
- rememberUndoableAction: actionBlock named: caption
- 	| cmd result |
- 	cmd := Command new cmdWording: caption.
- 	cmd undoTarget: self selector: #undoFromCapturedState: argument: self capturedState.
- 	result := actionBlock value.
- 	cmd redoTarget: self selector: #redoFromCapturedState: argument: self capturedState.
- 	self rememberCommand: cmd.
- 	^ result!

Item was removed:
- ----- Method: Object>>undoFromCapturedState: (in category '*MorphicExtras-Undo') -----
- undoFromCapturedState: st 
- 	"May be overridden in subclasses.  See also capturedState"
- 
- 	self copyFrom: st
- !

Item was removed:
- ProtoObject subclass: #ObjectOut
- 	instanceVariableNames: 'url page recursionFlag'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SqueakPage'!
- 
- !ObjectOut commentStamp: '<historical>' prior: 0!
- I am a stand-in for an object that is out on the disk.  The object that is out on the disk is the head of a tree of objects that are out.  See SqueakPage.
- 
- When any message is sent to me, I don't understand it, and bring in my true object.  I become myself with the objects and resend the message.  
- 
- I may not represent the object nil.  
- The file is represented as a url, and that url may point at any file on the net.  
- 
- page is a SqueakPage.
- If the cache already has an object, widely in use, that claims to be the object for my url, what do I do?  I can't become him, since others believe that he is the true object.  Run through memory and replace refs to me with refs to him.  Be careful not to trigger a fault.  Become me to a string, then find pointers and replace?
- 
- [[[They don't want to end up holding an ObjectOut.  (would oscillate back and forth)  This is a problem.  A user could bring in two trees that both refer to a 3rd url.  (check with cache before installing any new ObjectOut) Two trees could be written to the same url.
- Or, I remain an ObjectOut, and keep getting notUnderstood, and keep returning the other guy.
- Or I smash the cache, and install MY page and object.  Other guy is a copy -- still in, but with no place in the cache.  When we both write to the same url, there will be trouble.]  No -- search and replace.]]]
- !

Item was removed:
- ----- Method: ObjectOut>>comeFullyUpOnReload: (in category 'object storage') -----
- comeFullyUpOnReload: smartRefStream
- 	"Normally this read-in object is exactly what we want to store.  Try to dock first.  If it is here already, use that one."
- 
- 	| sp |
- 	"Transcript show: 'has ref to: ', url; cr."
- 	(sp := SqueakPageCache pageCache at: page ifAbsent: [nil]) ifNotNil: [
- 		sp isContentsInMemory ifTrue: [^ sp contentsMorph]].
- 	^ self!

Item was removed:
- ----- Method: ObjectOut>>doesNotUnderstand: (in category 'error handling') -----
- doesNotUnderstand: aMessage 
- 	"Bring in the object, install, then resend aMessage"
- 	| realObject oldFlag response |
- 	oldFlag := recursionFlag.
- 	recursionFlag := true.
- 	"fetch the object"
- 	realObject := self xxxFetch.		"watch out for the become!!"
- 	"Now we ARE the realObject"
- 	oldFlag == true ifTrue: 
- 		[response := (Project uiManager
- 						chooseOptionFrom: #('proceed normally' 'debug')
- 						title: 'Object being fetched for a second time.
- Should not happen, and needs to be fixed later.').
- 		response = 2 ifTrue: [self halt]].	"We are already the new object"
- 
- 	"Can't be a super message, since this is the first message sent to this object"
- 	^ realObject perform: aMessage selector withArguments: aMessage arguments!

Item was removed:
- ----- Method: ObjectOut>>isInMemory (in category 'basics') -----
- isInMemory
- 	"We are a place holder for an object that is out."
- 	^ false!

Item was removed:
- ----- Method: ObjectOut>>objectForDataStream: (in category 'object storage') -----
- objectForDataStream: refStrm
-     "Return an object to store on a data stream (externalize myself)."
- 
-     ^ self!

Item was removed:
- ----- Method: ObjectOut>>readDataFrom:size: (in category 'object storage') -----
- readDataFrom: aDataStream size: varsOnDisk
- 	"Make self be an object based on the contents of aDataStream, which was generated by the object's storeDataOn: method. Return self."
- 	| cntInstVars |
- 	cntInstVars := self xxxClass instSize.
- 	self xxxClass isVariable
- 		ifTrue: [self xxxClass error: 'needs updating']	"assume no variable subclasses"
- 		ifFalse: [cntInstVars := varsOnDisk].
- 
- 	aDataStream beginReference: self.
- 	1 to: cntInstVars do:
- 		[:i | self xxxInstVarAt: i put: aDataStream next].
- "	1 to: cntIndexedVars do:
- 		[:i | self basicAt: i put: aDataStream next].
- "
- 	^ self!

Item was removed:
- ----- Method: ObjectOut>>sqkPage (in category 'access') -----
- sqkPage
- 	^ page!

Item was removed:
- ----- Method: ObjectOut>>storeDataOn: (in category 'object storage') -----
- storeDataOn: aDataStream
- 	"Store myself on a DataStream. See also objectToStoreOnDataStream.
- 	must send 'aDataStream beginInstance:size:'"
- 	| cntInstVars |
- 
- 	cntInstVars := self class instSize.
- 	"cntIndexedVars := self basicSize."
- 	aDataStream
- 		beginInstance: self xxxClass
- 		size: cntInstVars "+ cntIndexedVars".
- 	1 to: cntInstVars do:
- 		[:i | aDataStream nextPut: (self xxxInstVarAt: i)].
- "	1 to: cntIndexedVars do:
- 		[:i | aDataStream nextPut: (self basicAt: i)]
- "!

Item was removed:
- ----- Method: ObjectOut>>url (in category 'access') -----
- url
- 	^ url!

Item was removed:
- ----- Method: ObjectOut>>url: (in category 'access') -----
- url: aString
- 
- 	url := aString!

Item was removed:
- ----- Method: ObjectOut>>veryDeepCopyWith: (in category 'object storage') -----
- veryDeepCopyWith: deepCopier
- 	"Copy me and the entire tree of objects I point to.  An object in the tree twice is copied once, and both references point to him.  deepCopier holds a dictionary of objects we have seen.  Some classes refuse to be copied.  Some classes are picky about which fields get deep copied."
- 	| class index sub subAss new absent |
- 	new := deepCopier references at: self ifAbsent: [absent := true].
- 	absent ifNil: [^ new].	"already done"
- 	class := self xxxClass.
- 	class isMeta ifTrue: [^ self].		"a class"
- 	new := self xxxClone.
- 	"not a uniClass"
- 	deepCopier references at: self put: new.	"remember"
- 	"class is not variable"
- 	index := class instSize.
- 	[index > 0] whileTrue: 
- 		[sub := self xxxInstVarAt: index.
- 		(subAss := deepCopier references associationAt: sub ifAbsent: [nil])
- 			ifNil: [new xxxInstVarAt: index put: (sub veryDeepCopyWith: deepCopier)]
- 			ifNotNil: [new xxxInstVarAt: index put: subAss value].
- 		index := index - 1].
- 	new rehash.	"force Sets and Dictionaries to rehash"
- 	^ new
- !

Item was removed:
- ----- Method: ObjectOut>>xxxClass (in category 'basics') -----
- xxxClass
- 	"Primitive. Answer the object which is the receiver's class. Essential. See 
- 	Object documentation whatIsAPrimitive."
- 
- 	<primitive: 111>
- 	self primitiveFailed!

Item was removed:
- ----- Method: ObjectOut>>xxxClone (in category 'basics') -----
- xxxClone
- 
- 	<primitive: 148>
- 	self primitiveFailed!

Item was removed:
- ----- Method: ObjectOut>>xxxFetch (in category 'fetch from disk') -----
- xxxFetch
- 	"Bring in my object and replace all references to me with references to him.  First try looking up my url in the pageCache.  Then try the page (and install it, under its url).  Then start from scratch with the url."
- 
- 	| truePage object existing |
- 	existing := SqueakPageCache pageCache at: url ifAbsent: [nil].
- 	existing ifNotNil: [existing isContentsInMemory
- 		ifTrue: [page := truePage := existing]].	"This url already has an object in this image"
- 	truePage ifNil: [
- 		truePage := SqueakPageCache atURL: url oldPage: page].
- 	object := truePage isContentsInMemory 
- 		ifTrue: [truePage contentsMorph]
- 		ifFalse: [truePage fetchInformIfError].	"contents, not the page"
- 			"Later, collect pointers to object and fix them up.  Not scan memory"
- 	object ifNil: [^ 'Object could not be fetched.'].
- 	"recursionFlag := false."  	"while I still have a pointer to myself"
- 	truePage contentsMorph: object.
- 	page := truePage.
- 	self xxxFixup.
- 	^ object	"the final object!!"
-  !

Item was removed:
- ----- Method: ObjectOut>>xxxFixup (in category 'fetch from disk') -----
- xxxFixup
- 	"There is already an object in memory for my url.  All pointers to me need to be pointers to him.  Can't use become, because other pointers to him must stay valid."
- 
- 	| real temp list |
- 	real := page contentsMorph.
- 	real == self ifTrue: [page error: 'should be converted by now'].
- 	temp := self.
- 	list := (PointerFinder pointersTo: temp) asOrderedCollection.
- 	list add: thisContext.  list add: thisContext sender.
- 	list do: [:holder |
- 		1 to: holder class instSize do:
- 			[:i | (holder instVarAt: i) == temp ifTrue: [holder instVarAt: i put: real]].
- 		1 to: holder basicSize do:
- 			[:i | (holder basicAt: i) == temp ifTrue: [holder basicAt: i put: real]].
- 		].
- 	^ real!

Item was removed:
- ----- Method: ObjectOut>>xxxInstVarAt: (in category 'basics') -----
- xxxInstVarAt: index 
- 	"Primitive. Answer a fixed variable in an object. The numbering of the 
- 	variables corresponds to the named instance variables. Fail if the index 
- 	is not an Integer or is not the index of a fixed variable. Essential. See 
- 	Object documentation whatIsAPrimitive."
- 
- 	<primitive: 73>
- 	self primitiveFailed !

Item was removed:
- ----- Method: ObjectOut>>xxxInstVarAt:put: (in category 'basics') -----
- xxxInstVarAt: anInteger put: anObject 
- 	"Primitive. Store a value into a fixed variable in the receiver. The 
- 	numbering of the variables corresponds to the named instance variables. 
- 	Fail if the index is not an Integer or is not the index of a fixed variable. 
- 	Answer the value stored as the result. Using this message violates the 
- 	principle that each object has sovereign control over the storing of 
- 	values into its instance variables. Essential. See Object documentation 
- 	whatIsAPrimitive."
- 
- 	<primitive: 74>
- 	self primitiveFailed !

Item was removed:
- ----- Method: ObjectOut>>xxxReset (in category 'access') -----
- xxxReset
- 	"mark as never brought in"
- 	recursionFlag := nil!

Item was removed:
- ----- Method: ObjectOut>>xxxSetUrl:page: (in category 'fetch from disk') -----
- xxxSetUrl: aString page: aSqkPage
- 
- 	url := aString.
- 	page := aSqkPage.!

Item was removed:
- AlignmentMorph subclass: #ObjectsTool
- 	instanceVariableNames: 'searchString modeSymbol'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-PartsBin'!
- 
- !ObjectsTool commentStamp: '<historical>' prior: 0!
- I am a Master Parts Bin that allows the user to drag out a new Morph from a voluminous iconic list.
- 
- Choose "objects" from the world menu, or type Alt-o (Cmd-o on the Mac).
- 
- To add a new kinds of Morphs:
- In the class of the Morph, implement the message:
- 
- descriptionForPartsBin
- 	^ self partName:	'Rectangle'
- 		categories:		#('Graphics' ' Basic 1 ')
- 		documentation:	'A rectangular shape, with border and fill style'
- 
- The partName is the title that will show in the lower pane of the Object Tool.
- When is categories mode, an object can be seen in more than one category.  The list above tells which ones.
- Documentation is what will show in the balloon help for each object thumbnail.
- The message #initializeToStandAlone creates the actual instance.
- 
- To make a second variant object prototype coming from the same class, implement #supplementaryPartsDescriptions.  In it, you get to specify the nativitySelector.  It is sent to the class to get the variant objects.  Often it is #authoringPrototype.  (A class may supply supplementaryPartsDescriptions without implementing descriptionForPartsBin.  This gives you better control.)
- 
- !

Item was removed:
- ----- Method: ObjectsTool class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'Objects' translatedNoop
- 		categories:		#()
- 		documentation:	'A place to obtain many kinds of objects' translatedNoop!

Item was removed:
- ----- Method: ObjectsTool class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: ObjectsTool class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#ObjectsTool.	 #newStandAlone. 'Object Catalog' translatedNoop. 'A tool that lets you browse the catalog of objects' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#ObjectsTool	. #newStandAlone. 'Object Catalog' translatedNoop.'A tool that lets you browse the catalog of objects' translatedNoop}
- 						forFlapNamed: 'Widgets'.]!

Item was removed:
- ----- Method: ObjectsTool class>>themeProperties (in category 'preferences') -----
- themeProperties
- 
- 	^ super themeProperties, {
- 		{ #borderColor. 'Colors'. 'Color of the tools'' border.' }.
- 		{ #borderWidth. 'Borders'. 'Width of the tools'' border.' }.
- 		{ #borderStyle. 'Borders'. 'Whether to use a plain border, inset, or outset.' }.
- 		{ #color. 'Colors'. 'Background color of the tool.' }.
- 		{ #textColor. 'Colors'. 'Color for the category button labels.' }.
- 		{ #selectionTextColor. 'Colors'. 'Color used for the button of the selected category.' }.
- 	}!

Item was removed:
- ----- Method: ObjectsTool class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: ObjectsTool>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aMenu hand: aHand
- 	"Add items to the given halo-menu, given a hand"
- 
- 	super addCustomMenuItems: aMenu hand: aHand.
- 	aMenu addLine.
- 	aMenu add: 'alphabetic' translated target: self selector: #showAlphabeticTabs.
- 	aMenu add: 'find' translated target: self selector: #showSearchPane.
- 	aMenu add: 'categories' translated target: self selector: #showCategories.
- 	aMenu addLine.
- 	aMenu add: 'reset thumbnails' translated target: self selector: #resetThumbnails.!

Item was removed:
- ----- Method: ObjectsTool>>alphabeticTabs (in category 'alphabetic') -----
- alphabeticTabs
- 	"Answer a list of buttons which, when hit, will trigger the choice of a morphic category"
- 
- 	| buttonList tabLabels |
- 
- 	self flag: #todo. "includes non-english characters"
- 	tabLabels := (($a to: $z) asOrderedCollection collect: [:ch | ch asString]) .
- 
- 	buttonList := tabLabels collect:
- 		[:catName |
- 			| aButton |
- 			aButton := SimpleButtonMorph new label: catName.
- 			aButton actWhen: #buttonDown.
- 			aButton target: self; actionSelector: #showAlphabeticCategory:fromButton:; arguments: {catName. aButton}].
- 	^ buttonList
- 
- "ObjectsTool new tabsForMorphicCategories"!

Item was removed:
- ----- Method: ObjectsTool>>applyUserInterfaceTheme (in category 'updating') -----
- applyUserInterfaceTheme
- 
- 	super applyUserInterfaceTheme.
- 	self setDefaultParameters.!

Item was removed:
- ----- Method: ObjectsTool>>baseBackgroundColor (in category 'constants') -----
- baseBackgroundColor
- 
- 	^ self userInterfaceTheme borderColor ifNil: [Color veryLightGray] !

Item was removed:
- ----- Method: ObjectsTool>>baseBorderColor (in category 'constants') -----
- baseBorderColor
- 
- 	^ self userInterfaceTheme borderColor ifNil: [Color veryLightGray] !

Item was removed:
- ----- Method: ObjectsTool>>buttonActiveColor (in category 'constants') -----
- buttonActiveColor
- 
- 	^ self userInterfaceTheme selectionTextColor ifNil: [Color white]!

Item was removed:
- ----- Method: ObjectsTool>>buttonColor (in category 'constants') -----
- buttonColor
- 
- 	^ self userInterfaceTheme textColor ifNil: [Color black]!

Item was removed:
- ----- Method: ObjectsTool>>buttonPane (in category 'submorph access') -----
- buttonPane
- 	"Answer the receiver's button pane, nil if none"
- 
- 	^ self submorphNamed: 'ButtonPane' ifNone: [].!

Item was removed:
- ----- Method: ObjectsTool>>extent: (in category 'layout') -----
- extent: anExtent
- 	"The user has dragged the grow box such that the receiver's extent would be anExtent.  Do what's needed"
- 	super extent: anExtent.
- 	self submorphsDo: [:m |
- 		m width: anExtent x]!

Item was removed:
- ----- Method: ObjectsTool>>fixLayoutFrames (in category 'layout') -----
- fixLayoutFrames
- 	"Adjust the boundary between the tabs or search pane and the parts bin, giving preference to the tabs."
- 
- 	| oldY newY aTabsPane aTabsPaneHeight |
- 	oldY := ((aTabsPane := self tabsPane
- 						ifNil: [self searchPane])
- 				ifNil: [^ self]) layoutFrame bottomOffset.
- 	aTabsPaneHeight := aTabsPane hasSubmorphs
- 				ifTrue: [(aTabsPane submorphBounds outsetBy: aTabsPane layoutInset) height]
- 				ifFalse: [aTabsPane height].
- 	newY := (self buttonPane ifNil: [^ self]) height + aTabsPaneHeight.
- 	oldY = newY ifTrue: [^ self].
- 	aTabsPane layoutFrame bottomOffset: newY.
- 	(self partsBin ifNil: [^ self]) layoutFrame topOffset: newY.
- 	submorphs	do: [:m | m layoutChanged]!

Item was removed:
- ----- Method: ObjectsTool>>highlightOnlySubmorph:in: (in category 'tabs') -----
- highlightOnlySubmorph: aMorph in: anotherMorph
- 	"Distinguish only aMorph with border highlighting (2-pixel wide red); make all my other submorphs have one-pixel-black highlighting.  This is a rather special-purpose and hard-coded highlighting regime, of course.  Later, if someone cared to do it, we could parameterize the widths and colors via properties, or some such."
- 
- 	anotherMorph submorphs do: [:m | | color |
- 	 	color := m == aMorph ifTrue: [self buttonActiveColor] ifFalse: [self buttonColor].
- 		m 
- 			borderWidth: 1;
- 			borderColor: color. 
- 		m firstSubmorph color: color]
- !

Item was removed:
- ----- Method: ObjectsTool>>icon (in category 'thumbnail') -----
- icon
- 	"Answer a form with an icon to represent the receiver"
- 	^ MenuIcons objectCatalogIcon!

Item was removed:
- ----- Method: ObjectsTool>>initializeForFlap (in category 'initialization') -----
- initializeForFlap
- 	"Initialize the receiver to operate in a flap at the top of the screen."
- 
- 	"
- 	Flaps newObjectsFlap openInWorld
- 	"
- 
- 	| buttonPane aBin aColor heights tabsPane |
- 	self basicInitialize.
- 
- 	self layoutInset: 0;
- 		layoutPolicy: ProportionalLayout new;
- 		hResizing: #shrinkWrap;
- 		vResizing: #rigid;
- 		borderWidth: 2; borderColor: Color darkGray;
- 		extent: (self minimumWidth @ self minimumHeight).
- 
- 	"mode buttons"
- 	buttonPane := self paneForTabs: self modeTabs.
- 	buttonPane
- 		vResizing: #shrinkWrap;
- 		setNameTo: 'ButtonPane';
- 		color: (aColor := buttonPane color) darker;
- 		layoutInset: 6;
- 		wrapDirection: nil;
- 		width: self width;
- 		layoutChanged; fullBounds.
- 
- 	"Place holder for a tabs or text pane"
- 	tabsPane := Morph new
- 		setNameTo: 'TabPane';
- 		hResizing: #spaceFill;
- 		yourself.
- 
- 	heights := { buttonPane height. 40 }.
- 
- 	buttonPane vResizing: #spaceFill.
- 	self
- 		addMorph: buttonPane
- 		fullFrame: (LayoutFrame
- 				fractions: (0 @ 0 corner: 1 @ 0)
- 				offsets: (0 @ 0 corner: 0 @ heights first)).
- 
- 	self
- 		addMorph: tabsPane
- 		fullFrame: (LayoutFrame
- 				fractions: (0 @ 0 corner: 1 @ 0)
- 				offsets: (0 @ heights first corner: 0 @ (heights first + heights second))).
- 
- 	aBin := (PartsBin newPartsBinWithOrientation: #leftToRight from: #())
- 		listDirection: #leftToRight;
- 		wrapDirection: #topToBottom;
- 		color: aColor lighter lighter;
- 		setNameTo: 'Parts';
- 		dropEnabled: false;
- 		vResizing: #spaceFill;
- 		yourself.
- 
- 	self
- 		addMorph: aBin
- 		fullFrame: (LayoutFrame
- 				fractions: (0 @ 0 corner: 1 @ 1)
- 				offsets: (0 @ (heights first + heights second) corner: 0 @ 0)).
- 
- 	aBin color: (Color orange muchLighter);
- 		setNameTo: 'Objects' translated.
- 
- 	self color: (Color orange muchLighter);
- 		setNameTo: 'Objects' translated.
- !

Item was removed:
- ----- Method: ObjectsTool>>initializeToStandAlone (in category 'initialization') -----
- initializeToStandAlone
- 	"Initialize the receiver so that it can live as a stand-alone morph"
- 
- 	| buttonPane aBin aColor tabsPane |
- 	self basicInitialize.
- 	
- 	self
- 		layoutInset: 0;
- 		useRoundedCorners;
- 		hResizing: #rigid;
- 		vResizing: #shrinkWrap;
- 		extent: RealEstateAgent standardSize;
- 		listDirection: #topToBottom;
- 		wrapDirection: #none.
- 
- 	"mode buttons"
- 	buttonPane := self paneForTabs: self modeTabs.
- 	buttonPane color: self baseBackgroundColor.
- 	buttonPane
- 		vResizing: #shrinkWrap;
- 		setNameTo: 'ButtonPane';
- 		addMorphFront: self dismissButton;
- 		addMorphBack: self helpButton;
- 		color: (aColor := buttonPane color) darker;
- 		layoutInset: 5;
- 		width: self width;
- 		layoutChanged; fullBounds.
- 
- 	"Place holder for a tabs or text pane"
- 	tabsPane := Morph new.
- 	tabsPane
- 		color: self baseBackgroundColor;
- 		setNameTo: 'TabPane';
- 		hResizing: #spaceFill;
- 		vResizing: #shrinkWrap.
- 
- 	aBin := (PartsBin newPartsBinWithOrientation: #leftToRight from: #())
- 		changeTableLayout;
- 		listDirection: #leftToRight;
- 		wrapDirection: #topToBottom;
- 		vResizing: #shrinkWrap;
- 		color: aColor lighter lighter;
- 		borderColor: aColor lighter lighter;
- 		setNameTo: 'Parts';
- 		dropEnabled: false;
- 		yourself.
- 		
- 	self addMorphBack: buttonPane.
- 	self addMorphBack: tabsPane.
- 	self addMorphBack: aBin.
- 	
- 	self
- 		borderWidth: 1;
- 		borderColor: self baseBorderColor;
- 		color: self baseBackgroundColor;
- 		setNameTo: 'Objects' translated;
- 		showCategories.!

Item was removed:
- ----- Method: ObjectsTool>>initializeWithTabs: (in category 'tabs') -----
- initializeWithTabs: tabList
- 	"Initialize the receiver to have the given tabs"
- 
- 	| oldPane newPane |
- 	oldPane := self tabsPane ifNil: [ self searchPane ].
- 	newPane := (self paneForTabs: tabList)
- 		setNameTo: 'TabPane';
- 		yourself.
- 	self replaceSubmorph: oldPane by: newPane.
- 
- !

Item was removed:
- ----- Method: ObjectsTool>>installQuads:fromButton: (in category 'alphabetic') -----
- installQuads: quads fromButton: aButton
- 	"Install items in the bottom pane that correspond to the given set of quads, as triggered from the given button"
- 
- 	| aPartsBin sortedQuads oldResizing |
- 	aPartsBin := self partsBin.
- 	oldResizing := aPartsBin vResizing.
- 	aPartsBin removeAllMorphs.
- 	sortedQuads := ((PartsBin translatedQuads: quads)
- 		select: [ :each | Smalltalk hasClassNamed: each first ])
- 		sort: [ :a :b | a third < b third ].
- 	aPartsBin listDirection: #leftToRight quadList: sortedQuads.
- 	aButton ifNotNil: [self highlightOnlySubmorph: aButton in: self tabsPane].
- 	aPartsBin vResizing: oldResizing.
- 	aPartsBin layoutChanged; fullBounds.!

Item was removed:
- ----- Method: ObjectsTool>>minHeight (in category 'layout') -----
- minHeight
- 	^(self minimumBottom - self top) max: 280!

Item was removed:
- ----- Method: ObjectsTool>>minWidth (in category 'layout') -----
- minWidth
- 	"Answer a width that assures that the alphabet fits in two rows.  For olpc, this is increased in order to make the Connectors category not too absurdly tall."
- 
- 	^ 400!

Item was removed:
- ----- Method: ObjectsTool>>minimizePartsBinSize (in category 'layout') -----
- minimizePartsBinSize
- 	self layoutChanged; fullBounds.
- 	self fixLayoutFrames.
- 	self setExtentFromHalo: (self minimumWidth @ self minimumHeight) !

Item was removed:
- ----- Method: ObjectsTool>>minimumBottom (in category 'layout') -----
- minimumBottom
- 	| iconsBottom partsBin |
- 	partsBin := self partsBin ifNil: [ ^self bottom ].
- 	iconsBottom := partsBin submorphs isEmpty
- 		ifTrue: [ partsBin top + 60 ]
- 		ifFalse: [ partsBin submorphBounds bottom + partsBin layoutInset ].
- 
- 	^iconsBottom + self layoutInset + self borderWidth!

Item was removed:
- ----- Method: ObjectsTool>>modeSymbol (in category 'major modes') -----
- modeSymbol
- 	"Answer the modeSymbol"
- 
- 	^ modeSymbol!

Item was removed:
- ----- Method: ObjectsTool>>modeSymbol: (in category 'major modes') -----
- modeSymbol: aSymbol
- 	"Set the receiver's modeSymbol as indicated"
- 
- 	modeSymbol := aSymbol.
- 	self tweakAppearanceAfterModeShift.
- !

Item was removed:
- ----- Method: ObjectsTool>>modeTabs (in category 'major modes') -----
- modeTabs
- 	"Answer a list of buttons which, when hit, will trigger the choice of mode of the receiver"
- 
- 	| buttonList tupleList |
- 	tupleList :=  #(
- 		('alphabetic'		alphabetic	showAlphabeticTabs	'A separate tab for each letter of the alphabet')
- 		('find'				search			showSearchPane			'Provides a type-in pane allowing you to match')
- 		('categories'		categories	showCategories			'Grouped by category')
- 
- 		"('standard'		standard		showStandardPane		'Standard Squeak tools supplies for building')"
- 	).
- 				
- 	buttonList := tupleList collect:
- 		[:tuple |
- 			| aButton |
- 			aButton := SimpleButtonMorph new label: tuple first translated.
- 			aButton actWhen: #buttonUp.
- 			aButton setProperty: #modeSymbol toValue: tuple second.
- 			aButton target: self; actionSelector: tuple third.
- 			aButton setBalloonText: tuple fourth translated.
- 			aButton borderWidth: 0.
- 			aButton].
- 	^ buttonList
- 
- "ObjectsTool new modeTabs"!

Item was removed:
- ----- Method: ObjectsTool>>newSearchPane (in category 'search') -----
- newSearchPane
- 	"Answer a type-in pane for searches"
- 
- 	| aTextMorph |
- 	aTextMorph := TextMorph new
- 		setProperty: #defaultContents toValue: ('' asText allBold addAttribute: (TextFontChange font3));
- 		setTextStyle: (TextStyle fontArray: { Preferences standardEToysFont });
- 		setDefaultContentsIfNil;
- 		on: #keyStroke send: #searchPaneCharacter: to: self;
- 		setNameTo: 'SearchPane';
- 		setBalloonText: 'Type here and all entries that match will be shown.' translated;
- 		vResizing: #shrinkWrap;
- 		hResizing: #spaceFill;
- 		margins: 4 at 6;
- 		backgroundColor: Color white.
- 	^ aTextMorph!

Item was removed:
- ----- Method: ObjectsTool>>paneForTabs: (in category 'tabs') -----
- paneForTabs: tabList 
- 	"Answer a pane bearing tabs for the given list"
- 	| aPane |
- 	tabList do: [:t |
- 			t color: Color transparent.
- 			t borderWidth: 1;
- 				borderColor: Color black].
- 
- 	aPane := Morph new
- 				changeTableLayout;
- 				color: self baseBackgroundColor;
- 				listDirection: #leftToRight;
- 				wrapDirection: #topToBottom;
- 				vResizing: #spaceFill;
- 				hResizing: #spaceFill;
- 				cellGap: 6;
- 				layoutInset: 4;
- 				listCentering: #center;
- 				addAllMorphs: tabList;
- 				yourself.
- 
- 	aPane width: self layoutBounds width.
- 
- 	^ aPane!

Item was removed:
- ----- Method: ObjectsTool>>partsBin (in category 'submorph access') -----
- partsBin
- 	^self findDeeplyA: PartsBin.!

Item was removed:
- ----- Method: ObjectsTool>>presentHelp (in category 'tabs') -----
- presentHelp
- 	"Sent when a Help button is hit; provide the user with some form of help for the tool at hand"
- 
- 	StringHolder new contents: 'The Objects tool allows you to browse through, and obtain copies of, many kinds of objects.  
- 
- You can obtain an Objects tool by choosing "Objects" from the world menu, or by the shortcut of typing alt-o (cmd-o) any time the cursor is over the desktop.
- 
- There are three ways to use Objects, corresponding to the three tabs seen at the top:
- 
- alphabetic - gives you separate tabs for a, b, c, etc.  Click any tab, and you will see the icons of all the objects whose names begin with that letter
- 
- search - gives you a type-in pane for a search string.  Type any letters there, and icons of all the objects whose names match what you have typed will appear in the bottom pane.
- 
- categories - provides tabs representing categories of related items.  Click on any tab to see the icons of all the objects in the category.
- 
- When the cursor lingers over the icon of any object, you will get balloon help for the item.
- 
- When you drag an icon from Objects, it will result in a new copy of it in your hand; the new object will be deposited wherever you next click.' translated; 
- 	openLabel: 'About Objects' translated!

Item was removed:
- ----- Method: ObjectsTool>>resetThumbnails (in category 'menu') -----
- resetThumbnails
- 	"Reset the thumbnail cache"
- 
- 	PartsBin clearThumbnailCache.
- 	modeSymbol == #categories ifTrue: [self showCategories] ifFalse: [self showAlphabeticTabs]!

Item was removed:
- ----- Method: ObjectsTool>>searchPane (in category 'submorph access') -----
- searchPane
- 	"Answer the receiver's search pane, nil if none"
- 
- 	^ self submorphNamed: 'SearchPane' ifNone: [].!

Item was removed:
- ----- Method: ObjectsTool>>searchPaneCharacter: (in category 'search') -----
- searchPaneCharacter: evt
- 	"A character represented by the event handed in was typed in the search pane by the user"
- 
- 	^ self showMorphsMatchingSearchString
- 
- "	| char |  *** The variant below only does a new search if RETURN or ENTER is hit ***
- 	char := evt keyCharacter.
- 	(char == Character enter or: [char == Character cr]) ifTrue:
- 		[self showMorphsMatchingSearchString]"!

Item was removed:
- ----- Method: ObjectsTool>>setDefaultParameters (in category 'initialization') -----
- setDefaultParameters
- 	
- 	self
- 		borderColor: self baseBorderColor;
- 		color: self baseBackgroundColor!

Item was removed:
- ----- Method: ObjectsTool>>setExtentFromHalo: (in category 'layout') -----
- setExtentFromHalo: anExtent
- 	"The user has dragged the grow box such that the receiver's extent would be anExtent.  Do what's needed"
- 	super setExtentFromHalo: ((anExtent x max: self minimumWidth) @ (anExtent y max: self minimumHeight)).
- !

Item was removed:
- ----- Method: ObjectsTool>>setSearchStringFromSearchPane (in category 'search') -----
- setSearchStringFromSearchPane
- 	"Set the search string by obtaining its contents from the search pane, and doing a certain amount of munging"
- 
- 	searchString := self searchPane text string asLowercase withBlanksTrimmed.
- 	searchString := searchString copyWithoutAll: {Character enter. Character cr}!

Item was removed:
- ----- Method: ObjectsTool>>showAll (in category 'search') -----
- showAll
- 	"Put items matching the search string into my lower pane.
- 	showAll is for testing that all bin parts can be displayed.
- 	Currently it has no callers of use other than the test."
- 	| quads |
- 	self partsBin removeAllMorphs.
- 	self modeSymbol: nil .
- 	Cursor wait
- 		showWhile: [quads := OrderedCollection new.
- 			Morph withAllSubclasses
- 				do: [:aClass | aClass
- 						addPartsDescriptorQuadsTo: quads
- 						if: [:info | true ]].
- 			self installQuads: quads fromButton: nil]!

Item was removed:
- ----- Method: ObjectsTool>>showAlphabeticCategory:fromButton: (in category 'submorph access') -----
- showAlphabeticCategory: aString fromButton: aButton 
- 	"Blast items beginning with a given letter into my lower pane"
- 	self partsBin removeAllMorphs.
- 	Cursor wait
- 		showWhile: [
- 			| eligibleClasses quads uc |
- 			uc := aString asUppercase asCharacter.
- 			eligibleClasses := Morph withAllSubclasses.
- 			quads := OrderedCollection new.
- 			eligibleClasses
- 				do: [:aClass | aClass theNonMetaClass
- 						addPartsDescriptorQuadsTo: quads
- 						if: [:info | info formalName translated asUppercase first = uc]].
- 			self installQuads: quads fromButton: aButton]!

Item was removed:
- ----- Method: ObjectsTool>>showAlphabeticTabs (in category 'alphabetic') -----
- showAlphabeticTabs
- 	"Switch to the mode of showing alphabetic tabs"
- 
- 	modeSymbol == #alphabetic ifTrue: [ ^self ].
- 	self partsBin removeAllMorphs.
- 	self initializeWithTabs: self alphabeticTabs.
- 	self modeSymbol: #alphabetic.
- 	self tabsPane submorphs first doButtonAction!

Item was removed:
- ----- Method: ObjectsTool>>showCategories (in category 'categories') -----
- showCategories
- 	"Set the receiver up so that it shows tabs for each of the standard categories"
- 
- 	modeSymbol == #categories ifTrue: [ ^self ].
- 
- 	self partsBin removeAllMorphs.
- 	self initializeWithTabs: self tabsForCategories.
- 	self modeSymbol: #categories.
- 	self tabsPane submorphs first doButtonAction.
- !

Item was removed:
- ----- Method: ObjectsTool>>showCategory:fromButton: (in category 'categories') -----
- showCategory: aCategoryName fromButton: aButton 
- 	"Project items from the given category into my lower pane"
- 
- 	"self partsBin removeAllMorphs. IMHO is redundant, "
- 	Cursor wait
- 		showWhile: [
- 			| quads |
- 			quads := OrderedCollection new.
- 			Morph withAllSubclasses
- 				do: [:aClass | aClass theNonMetaClass
- 						addPartsDescriptorQuadsTo: quads
- 						if: [:aDescription | aDescription translatedCategories includes: aCategoryName]].
- 			quads sort: [:q1 :q2 | q1 third <= q2 third].
- 			self installQuads: quads fromButton: aButton]!

Item was removed:
- ----- Method: ObjectsTool>>showMorphsMatchingSearchString (in category 'search') -----
- showMorphsMatchingSearchString
- 	"Put items matching the search string into my lower pane"
- 	self setSearchStringFromSearchPane.
- 	self partsBin removeAllMorphs.
- 	Cursor wait
- 		showWhile: [
- 			| quads |
- 			quads := OrderedCollection new.
- 			Morph withAllSubclasses
- 				do: [:aClass | aClass
- 						addPartsDescriptorQuadsTo: quads
- 						if: [:info | info formalName translated includesSubstring: searchString caseSensitive: false]].
- 			self installQuads: quads fromButton: nil]!

Item was removed:
- ----- Method: ObjectsTool>>showSearchPane (in category 'search') -----
- showSearchPane
- 	"Set the receiver up so that it shows the search pane"
- 
- 	| tabsPane aPane |
- 	modeSymbol == #search ifTrue: [ ^self ].
- 
- 	self partsBin removeAllMorphs.
- 
- 	tabsPane := self tabsPane.
- 	aPane := self newSearchPane.
- 	self replaceSubmorph: tabsPane by: aPane.
- 
- 	self modeSymbol: #search.
- 	self showMorphsMatchingSearchString.
- 	self currentHand newKeyboardFocus: aPane!

Item was removed:
- ----- Method: ObjectsTool>>tabsForCategories (in category 'categories') -----
- tabsForCategories
- 	"Answer a list of buttons which, when hit, will trigger the choice of a category"
- 
- 	| buttonList classes categoryList basic |
- 	classes := Morph withAllSubclasses.
- 	categoryList := Set new.
- 	classes do: [:aClass |
- 		(aClass class includesSelector: #descriptionForPartsBin) ifTrue:
- 			[categoryList addAll: aClass descriptionForPartsBin translatedCategories].
- 		(aClass class includesSelector: #supplementaryPartsDescriptions) ifTrue:
- 			[aClass supplementaryPartsDescriptions do:
- 				[:aDescription | categoryList addAll: aDescription translatedCategories]]].
- 
- 	categoryList := categoryList asOrderedCollection sort.
- 	
- 	basic := categoryList remove: ' Basic' translated ifAbsent: [ ].
- 	basic ifNotNil: [ categoryList addFirst: basic ].
- 
- 	basic := categoryList remove: 'Basic' translated ifAbsent: [ ].
- 	basic ifNotNil: [ categoryList addFirst: basic ].
- 
- 	buttonList := categoryList collect:
- 		[:catName |
- 			| aButton |
- 			aButton := SimpleButtonMorph new label: catName.
- 			aButton actWhen: #buttonDown.
- 			aButton target: self; actionSelector: #showCategory:fromButton:; arguments: {catName. aButton}].
- 	^ buttonList
- 
- "ObjectsTool new tabsForCategories"!

Item was removed:
- ----- Method: ObjectsTool>>tabsPane (in category 'submorph access') -----
- tabsPane
- 	"Answer the receiver's tabs pane, nil if none"
- 
- 	^ self submorphNamed: 'TabPane' ifNone: [].!

Item was removed:
- ----- Method: ObjectsTool>>tweakAppearanceAfterModeShift (in category 'initialization') -----
- tweakAppearanceAfterModeShift
- 	"After the receiver has been put into a given mode, make an initial selection of category, if appropriate, and highlight the mode button."
- 	
- 	self buttonPane submorphs do:
- 		[:aButton | 
- 			| aColor |
- 			"aButton borderWidth: 1."
- 			aColor := (aButton valueOfProperty: #modeSymbol) = modeSymbol
- 				ifTrue: [self buttonActiveColor]
- 				ifFalse: [self buttonColor].
- 
- 			aButton firstSubmorph color: aColor.
- 			aButton borderColor: aColor].!

Item was removed:
- ----- Method: PackagePaneBrowser class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry;
- 		registerInAppRegistry.!

Item was removed:
- ----- Method: PackagePaneBrowser class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#PackagePaneBrowser. #prototypicalToolWindow	.	'Packages' translatedNoop.		'Package Browser:  like a System Browser, except that if has extra level of categorization in the top-left pane, such that class-categories are further organized into groups called "packages"' translatedNoop}
- 						forFlapNamed: 'Tools']!

Item was removed:
- ----- Method: PackagePaneBrowser class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self].
- 	SystemBrowser unregister: self.!

Item was removed:
- ImageMorph subclass: #PaintBoxColorPicker
- 	instanceVariableNames: 'currentColor locOfCurrent'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Support'!
- 
- !PaintBoxColorPicker commentStamp: 'JMM 9/13/2004 07:37' prior: 0!
- A pop-up, 32-bit color palette used as part of a PaintBoxMorph.
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>beStatic (in category 'initialization') -----
- beStatic
- 
- 	"an aid for Nebraska: make the color chart a static image to reduce traffic"
- 	image isStatic ifFalse: [
- 		image := image as: StaticForm
- 	].!

Item was removed:
- ----- Method: PaintBoxColorPicker>>currentColor (in category 'accessing') -----
- currentColor
- 
- 	^ currentColor
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>currentColor: (in category 'accessing') -----
- currentColor: aColor
- 	"Force me to select the given color."
- 
- 	currentColor := aColor.
- 	locOfCurrent := nil.  "remove the marker"
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 	"Image plus circles for currently selected color."
- 
- 	| c |
- 	super drawOn: aCanvas.
- 	locOfCurrent ifNotNil: [
- 		c := self ringColor.
- 		aCanvas
- 			fillOval: (Rectangle center: locOfCurrent + self topLeft extent: 9 at 9)
- 			color: Color transparent
- 			borderWidth: 1
- 			borderColor: c].
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>endColorSelection: (in category 'event handling') -----
- endColorSelection: evt
- 	"Update current color and report it to paint box."
- 
- 	self selectColor: evt.
- 	"restore mouseLeave handling"
- 	self on: #mouseLeave send: #delete to: self.
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>initMouseHandlers (in category 'event handling') -----
- initMouseHandlers
- 
- 	self on: #mouseDown send: #startColorSelection: to: self.
- 	self on: #mouseMove send: #selectColor: to: self.
- 	self on: #mouseUp send: #endColorSelection: to: self.
- 	self on: #mouseLeave send: #delete to: self.
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>initialize (in category 'initialization') -----
- initialize
- 
- 	super initialize.
- 	currentColor := Color black.
- 	locOfCurrent := nil.
- 	self initMouseHandlers.
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>ringColor (in category 'drawing') -----
- ringColor
- 	"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green"
- 
- 	currentColor isTransparent ifTrue: [^ Color red].
- 	currentColor red < 0.5 ifTrue: [^ Color red].
- 	currentColor red > (currentColor green + (currentColor blue * 0.5))
- 		ifTrue: [^ Color green]
- 		ifFalse: [^ Color red].
- !

Item was removed:
- ----- Method: PaintBoxColorPicker>>selectColor: (in category 'event handling') -----
- selectColor: evt 
- 	"Update the receiver from the given event. Constrain locOfCurrent's center to lie within the color selection area. If it is partially in the transparent area, snap it entirely into it vertically."
- 
- 	| r |
- 
- 	locOfCurrent := evt cursorPoint - self topLeft.
- 	r := Rectangle center: locOfCurrent extent: 9 @ 9.
- 	locOfCurrent := locOfCurrent 
- 				+ (r amountToTranslateWithin: (8 @ 11 corner: (self image width-6) @ (self image height-6))).
- 	locOfCurrent x > (self image width-(12+7))  ifTrue: [locOfCurrent := (self image width - 12) @ locOfCurrent y].	"snap into grayscale"
- 	currentColor := locOfCurrent y < 19
- 				ifTrue:  
- 					[locOfCurrent := locOfCurrent x @ 11.	"snap into transparent"
- 					Color transparent]
- 				ifFalse: [image colorAt: locOfCurrent].
- 	(owner isKindOf: PaintBoxMorph) 
- 		ifTrue: [owner takeColorEvt: evt from: self].
- 	self changed!

Item was removed:
- ----- Method: PaintBoxColorPicker>>startColorSelection: (in category 'event handling') -----
- startColorSelection: evt
- 	"Start color selection. Make me stay up as long as the mouse is down."
- 
- 	self on: #mouseLeave send: nil to: nil.
- 	self selectColor: evt.
- !

Item was removed:
- ImageMorph subclass: #PaintBoxMorph
- 	instanceVariableNames: 'action tool currentCursor thumbnail currentColor currentBrush colorMemory stampHolder rotationTabForm scaleTabForm colorMemoryThin brushes focusMorph weakDependents recentColors'
- 	classVariableNames: 'ColorChart ImageLibrary Prototype RecentColors UseLargeColorPicker'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Support'!

Item was removed:
- ----- Method: PaintBoxMorph class>>cleanUp (in category 'class initialization') -----
- cleanUp
- 	"Flush caches"
- 
- 	ColorChart := nil.
- !

Item was removed:
- ----- Method: PaintBoxMorph class>>colorChart (in category 'resources') -----
- colorChart
- 	^ColorChart ifNil:
- 		[ColorChart := self useLargeColorPicker
- 			ifTrue: [ColorPickerMorph colorPaletteForDepth: 32 extent: (360+10)@(180+10)]
- 			ifFalse: [ColorPickerMorph colorPaletteForDepth: 16 extent: 120 @ 89]]!

Item was removed:
- ----- Method: PaintBoxMorph class>>colorMemoryImage (in category 'resources') -----
- colorMemoryImage
- 	^self imageLibrary at: #colorMemoryImage ifAbsentPut:
- 		[| offset chart spec fillStyle colorMemoryImage |
- 		offset := 7 at 6.
- 		chart := self colorChart.
- 		colorMemoryImage := Form extent: chart extent+(offset*2) depth: chart depth.
- 		spec := #(
- 			(1.00 #(0.4 0.6 0.8))
- 			(0.67 #(0.6 0.6 0.8))
- 			(0.33 #(0.6 0.8 0.8))
- 			(0.00 #(0.6 0.8 0.9))).
- 		fillStyle := GradientFillStyle ramp: (spec collect: [:e | e first -> (Color fromRgbTriplet: e second)]).
- 		fillStyle origin: 0@(colorMemoryImage extent y //2); direction: colorMemoryImage extent x @0.
- 
- 		(colorMemoryImage getCanvas copyOrigin: 0 at 0 clipRect: (0 at 0 extent: colorMemoryImage extent))
- 			fillRectangle: (0 at 0 extent: colorMemoryImage extent) fillStyle: fillStyle;
- 			frameAndFillRectangle: (0 at 0 extent: colorMemoryImage extent) fillColor: Color transparent borderWidth: 1 borderColor: Color black.
- 		colorMemoryImage copy: (0 at 0 extent: chart extent) from: chart to: offset rule: Form over.
- 		colorMemoryImage]!

Item was removed:
- ----- Method: PaintBoxMorph class>>colorMemoryThinImage (in category 'resources') -----
- colorMemoryThinImage
- 	^self imageLibrary at: #colorMemoryThinImage ifAbsentPut:
- 		[| offset chart spec fillStyle thinImage |
- 		offset := 7 at 6.
- 		chart := self colorChart.
- 		thinImage := Form extent: 42 at 101 depth: chart depth.
- 		spec := #(
- 			(1.00 #(0.4 0.6 0.8))
- 			(0.67 #(0.6 0.6 0.8))
- 			(0.33 #(0.6 0.8 0.8))
- 			(0.00 #(0.6 0.8 0.9))).
- 		fillStyle := GradientFillStyle ramp: (spec collect: [:e | e first -> (Color fromRgbTriplet: e second)]).
- 		fillStyle origin: 0@(thinImage extent y //2); direction: thinImage extent x @0.
- 		(thinImage getCanvas copyOrigin: 0 at 0 clipRect: (0 at 0 extent: thinImage extent))
- 			fillRectangle: (0 at 0 extent: thinImage extent) fillStyle: fillStyle;
- 			frameAndFillRectangle: (0 at 0 extent: thinImage extent) fillColor: Color transparent borderWidth: 1 borderColor: Color black.
- 		thinImage copy: (chart extent x - thinImage extent x + (2*offset x)@0 corner: chart extent x @ (chart extent y min: thinImage extent y - (2 * offset y))) from: chart to: offset rule: Form over.
- 		thinImage]!

Item was removed:
- ----- Method: PaintBoxMorph class>>ellipseIcon (in category 'resources') -----
- ellipseIcon
- 	^self imageLibrary at: #ellipseIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABsAAAAVCAMAAACAAGUXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAALJJREFUeF6N0U0OgyAQBWDfFm0ygGLk73rteTzurCpIBIxN+lYTvpmEgYE5ZeeHDPyXRWeFlHLeWttz3g5QWhMgXD8XPcGEVFoN8p15KgdH1oLFPrFSQtGYh2lvqGGrLYitTRgvi1L0q5G+zMqxt9x7mqPl5xyT6g11jkV/F4u12oS5NYFQ7aVyZ0k8ty3G6TlLGQJU+54ZpbEc3AZo7o3jAoCOL6KV73boNOrZbPd/f8wXgWSq2Ol/ETUAAAAASUVORK5CYII=' readStream)) offset: -5@ -4; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>ellipseIconImage (in category 'resources') -----
- ellipseIconImage
- 	^self imageLibrary at: #ellipseIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABsAAAAVCAMAAACAAGUXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAALJJREFUeF6N0U0OgyAQBWDfFm0ygGLk73rteTzurCpIBIxN+lYTvpmEgYE5ZeeHDPyXRWeFlHLeWttz3g5QWhMgXD8XPcGEVFoN8p15KgdH1oLFPrFSQtGYh2lvqGGrLYitTRgvi1L0q5G+zMqxt9x7mqPl5xyT6g11jkV/F4u12oS5NYFQ7aVyZ0k8ty3G6TlLGQJU+54ZpbEc3AZo7o3jAoCOL6KV73boNOrZbPd/f8wXgWSq2Ol/ETUAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>eraseIcon (in category 'resources') -----
- eraseIcon
- 	^self imageLibrary at: #eraseIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAAC8AAAAjCAMAAAAzO6PlAAADAFBMVEUAAAAAAAD//+V/f3//AAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y////+Vs9r+lAAABAHRSTlMA////////////////////////////////////////////////////AP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2hiZ4AAAATlJREFUeF7l1DFuhDAQBVA0bST7AFmJzsfci9Cl4xSWVgodVHsDJJBWWMJ2AW4yGRsWJYWxt0qRoaF4Y/4YQ/GXBY7qRZ7f8eTuNW5NNgevjcnmShnTXanN5PFRdcaV750FOB8CNz4aAwjXt9TQTz5auqFIiV1CpMiej5TIACR2tUYSgfsOa1Nv4YFw8L3FWqViXGuEn3wcqG5DNLxe0f3iN6opPqtff5dT4HTZGBfeC7QbVyqsPkRnFd73GnHbTRV0dFLiwfd3EHaPPsSzeE6e99QguAtZhsmdcf610gOklC1jrOsmc3ZsiK/LwgX4BvlxuZQcz04ZcfLUIFgjZVVV9fmZ96svi9Z3zlhZt0wkvhG+8Xlua58l/Q16TbxpPhudwQt+8DXvF8L1/CA989w/GtfEl+L/11Hf/SVoHyShmoYAAAAASUVORK5CYII=' readStream)) offset: -16@ -34; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>eraseIconImage (in category 'resources') -----
- eraseIconImage
- 	^self imageLibrary at: #eraseIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAAC8AAAAjCAMAAAAzO6PlAAADAFBMVEUAAAAAAAD//+V/f3//AAAA/wAAAP8A/////wD/AP8fHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8v/AP//Mv//Zf//mP//y////+Vs9r+lAAABAHRSTlMA////////////////////////////////////////////////////AP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2hiZ4AAAATlJREFUeF7l1DFuhDAQBVA0bST7AFmJzsfci9Cl4xSWVgodVHsDJJBWWMJ2AW4yGRsWJYWxt0qRoaF4Y/4YQ/GXBY7qRZ7f8eTuNW5NNgevjcnmShnTXanN5PFRdcaV750FOB8CNz4aAwjXt9TQTz5auqFIiV1CpMiej5TIACR2tUYSgfsOa1Nv4YFw8L3FWqViXGuEn3wcqG5DNLxe0f3iN6opPqtff5dT4HTZGBfeC7QbVyqsPkRnFd73GnHbTRV0dFLiwfd3EHaPPsSzeE6e99QguAtZhsmdcf610gOklC1jrOsmc3ZsiK/LwgX4BvlxuZQcz04ZcfLUIFgjZVVV9fmZ96svi9Z3zlhZt0wkvhG+8Xlua58l/Q16TbxpPhudwQt+8DXvF8L1/CA989w/GtfEl+L/11Hf/SVoHyShmoYAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>eyedropperIcon (in category 'resources') -----
- eyedropperIcon
- 	^self imageLibrary at: #eyedropperIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACYAAAAkCAMAAADSK7iXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAR5JREFUeF6t1DGygjAQBmCHVkYroplhFBjzwmHouAidF8ALZOzSeYF4g1Smeu8CtlRJR5vqJejTV0CWwq2/2QnL/ruwdk4t7CfYj5IXmKnOaMkhdjO+5DHMlDF93xvZ4BD71oNyrAmx7ql4VQbYSzXlFFNK6f9qgslOaq/0U02wi2tjetPJYzWoqbdxZaQcWpWBn7Vfcfeqtxpn2ToquB/Enxpl2VdED7g5Vy81xpwi91Od1m81wnLqVJtYe64DLKeUXFsErKXvdcU1sL2riBKxXQJLnrtPFNsYyELhFUJAZJy6CxQDySr8uBAGAph7lcRATjM/riQF4rxfExEvUyD1rCACbcDjwA4t2sE3hKUYPDXsUTMuEpt3uD7LoPoFh1uzvVTXHQoAAAAASUVORK5CYII=' readStream)) offset: -12@ -35; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>eyedropperIconImage (in category 'resources') -----
- eyedropperIconImage
- 	^self imageLibrary at: #eyedropperIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACYAAAAkCAMAAADSK7iXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAR5JREFUeF6t1DGygjAQBmCHVkYroplhFBjzwmHouAidF8ALZOzSeYF4g1Smeu8CtlRJR5vqJejTV0CWwq2/2QnL/ruwdk4t7CfYj5IXmKnOaMkhdjO+5DHMlDF93xvZ4BD71oNyrAmx7ql4VQbYSzXlFFNK6f9qgslOaq/0U02wi2tjetPJYzWoqbdxZaQcWpWBn7Vfcfeqtxpn2ToquB/Enxpl2VdED7g5Vy81xpwi91Od1m81wnLqVJtYe64DLKeUXFsErKXvdcU1sL2riBKxXQJLnrtPFNsYyELhFUJAZJy6CxQDySr8uBAGAph7lcRATjM/riQF4rxfExEvUyD1rCACbcDjwA4t2sE3hKUYPDXsUTMuEpt3uD7LoPoFh1uzvVTXHQoAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>fillIcon (in category 'resources') -----
- fillIcon
- 	^self imageLibrary at: #fillIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACEAAAAxCAMAAABj7DDGAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAglJREFUeF6tlN2aoyAMhsfTitIZJSugCX/67PXO5Xq0AdpOZ7a2J8ORJC/Jlwh52/cX623/VcL5mDwdE9R7RB+3SAeE87jsO2InpXtIkFuuFimJyNEPouvxZiFGUgrOfSPcV2QDuPnY9zH13R1xLYFYbM9SMMgUg/siuksB5IOUqwwbmhBD6N2NcKH6OXTis1zyZBjw5K6Ej9XPzhiTTFJqsAwQ3hHE/j4E9ksm1nmCmQGkSnQx9DF4HyKrWNcU49YJAMTZ2kowizkJu7dVphDc1llQwhotukIgHwDtt7UECD15mYlWazHZQkytUuPQIheaYhEoOyOUAjGByAQqBhgZZ8lqKAuUi5nYCqAgE2JUAzOM1ArRznIWkI3qQvDnULbKUi4AaTEChjFbShY7jGWj2uHEgDFhMQZUiayK0mWsG1BN085Ga88U1KBT7cckBKsGdW6as8gVcgx1BQphtck9+2h4jZp7IzSUvPr2b23uqckABwHuTlHZ2q/7gUQ+QiGaFmoCBXh3C/nmpDRU4lQTtAK/3VPPDX
 +vxN/czLbVP+46pTWem4sQBsD+/15iuBDNxL9jefjmrjE0TPj43V6IDy0OXjZW4iTwcDqcMgBIx/Mj90PTk/mRY0D3dAaNTWOfT6k/jXoxx+bHIe4n3Vnsr7KMLwj1Wsf7cx2fdT1X+vlyav8GcbD+Ab0bxRv8puClAAAAAElFTkSuQmCC' readStream)) offset: -10@ -44; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>fillIconImage (in category 'resources') -----
- fillIconImage
- 	^self imageLibrary at: #fillIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACEAAAAxCAMAAABj7DDGAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAglJREFUeF6tlN2aoyAMhsfTitIZJSugCX/67PXO5Xq0AdpOZ7a2J8ORJC/Jlwh52/cX623/VcL5mDwdE9R7RB+3SAeE87jsO2InpXtIkFuuFimJyNEPouvxZiFGUgrOfSPcV2QDuPnY9zH13R1xLYFYbM9SMMgUg/siuksB5IOUqwwbmhBD6N2NcKH6OXTis1zyZBjw5K6Ej9XPzhiTTFJqsAwQ3hHE/j4E9ksm1nmCmQGkSnQx9DF4HyKrWNcU49YJAMTZ2kowizkJu7dVphDc1llQwhotukIgHwDtt7UECD15mYlWazHZQkytUuPQIheaYhEoOyOUAjGByAQqBhgZZ8lqKAuUi5nYCqAgE2JUAzOM1ArRznIWkI3qQvDnULbKUi4AaTEChjFbShY7jGWj2uHEgDFhMQZUiayK0mWsG1BN085Ga88U1KBT7cckBKsGdW6as8gVcgx1BQphtck9+2h4jZp7IzSUvPr2b23uqckABwHuTlHZ2q/7gUQ+QiGaFmoCBXh3C/nmpDRU4lQTtAK/3VPPDX
 +vxN/czLbVP+46pTWem4sQBsD+/15iuBDNxL9jefjmrjE0TPj43V6IDy0OXjZW4iTwcDqcMgBIx/Mj90PTk/mRY0D3dAaNTWOfT6k/jXoxx+bHIe4n3Vnsr7KMLwj1Wsf7cx2fdT1X+vlyav8GcbD+Ab0bxRv8puClAAAAAElFTkSuQmCC' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>imageLibrary (in category 'resources') -----
- imageLibrary
- 	^ImageLibrary ifNil: [ImageLibrary := IdentityDictionary new]!

Item was removed:
- ----- Method: PaintBoxMorph class>>initialize (in category 'class initialization') -----
- initialize
- 	"PaintBoxMorph initialize"
- 
- 	Prototype := ColorChart := ImageLibrary := nil.
- 
- !

Item was removed:
- ----- Method: PaintBoxMorph class>>lineIcon (in category 'resources') -----
- lineIcon
- 	^self imageLibrary at: #lineIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABYAAAAVCAMAAAB1/u6nAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAF5JREFUeF6V0LEOgDAIBNB2dmmiSRPhq/ncTlbRSuEGvfGFELjUGkpqn3mviGktgLty5EsD03aqZ531zFnV8aMz50LgnTE7sdGbpd9gdXB991rmhV2DogHFCu77H4cc4R6SttzoBIUAAAAASUVORK5CYII=' readStream)) offset: -5@ -17; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>lineIconImage (in category 'resources') -----
- lineIconImage
- 	^self imageLibrary at: #lineIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABYAAAAVCAMAAAB1/u6nAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAF5JREFUeF6V0LEOgDAIBNB2dmmiSRPhq/ncTlbRSuEGvfGFELjUGkpqn3mviGktgLty5EsD03aqZ531zFnV8aMz50LgnTE7sdGbpd9gdXB991rmhV2DogHFCu77H4cc4R6SttzoBIUAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>localeChanged (in category 'notification') -----
- localeChanged
- 	| caption |
- 	caption := ColorPickerMorph noColorCaption.
- 	ColorChart ifNotNil: [
- 		caption displayOn: ColorChart at: ColorChart boundingBox topCenter - (caption width // 2 @ 0)].!

Item was removed:
- ----- Method: PaintBoxMorph class>>new (in category 'instance creation') -----
- new
- 
- 	| pb |
- 	pb := self prototype veryDeepCopy.
- 		"Assume that the PaintBox does not contain any scripted Players!!"
- 	pb stampHolder normalize.	"Get the stamps to show"
- 	"Get my own copies of the brushes so I can modify them"
- 	#(brush1: brush2: brush3: brush4: brush5: brush6:) do: [:sel | | dualUse button |
- 		button := pb submorphNamed: sel.
- 		button offImage: button offImage deepCopy.
- 		dualUse := button onImage == button pressedImage.	"sometimes shared"
- 		button onImage: button onImage deepCopy.
- 		dualUse
- 			ifTrue: [button pressedImage: button onImage]
- 			ifFalse: [button pressedImage: button pressedImage deepCopy].
- 		].
- 	pb showColor.
- 	pb fixUpRecentColors.
- 	pb addLabels.
- 	^ pb!

Item was removed:
- ----- Method: PaintBoxMorph class>>newPrototype (in category 'instance creation') -----
- newPrototype
- 	^self basicNew buildAPrototype!

Item was removed:
- ----- Method: PaintBoxMorph class>>paintIcon (in category 'resources') -----
- paintIcon
- 	^self imageLibrary at: #paintIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACwAAAAnCAMAAABDnVrwAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAATNJREFUeF7d1KFywzAMBuCN9griLLnF7Rxs5DcJcZDZYKmRQ8pSVBZsFFS2ZwgK6mMUJU9QNMXLunV3sTwwMuHvdDrZ+h8er+H1f7EpaTA2WhcmEFfaWl2UQXiyXWeKKgC3YG03jDYAb7WBvv04Xs44Bmu7EWyPz1xN9vJhMWy+WwS7RdysH7duaTBwH/Dczg7QOMex/hz4jH8kZ4fbwF5czQMPPf5Ft7P96ruMmXvle7uEaVTcLc2H11FEyp99F/AKLOGge/wGnY1jzlvsYPPNc+osIQly3XmmklSCJYI85X68kUpJKMEJT5g/N/I4AalUTWW8ZkjIpEKArU9vJ8X8idRcM07EbCkSXw3jHKza13uZYVl3EICnMaR68Qdj0+wOx+NrpqA3DUjR5jeR+3c4oN4B/GzJ0c+GFaAAAAAASUVORK5CYII=' readStream)) offset: 0 at 0; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>paintIconImage (in category 'resources') -----
- paintIconImage
- 	^self imageLibrary at: #paintIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACwAAAAnCAMAAABDnVrwAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAATNJREFUeF7d1KFywzAMBuCN9griLLnF7Rxs5DcJcZDZYKmRQ8pSVBZsFFS2ZwgK6mMUJU9QNMXLunV3sTwwMuHvdDrZ+h8er+H1f7EpaTA2WhcmEFfaWl2UQXiyXWeKKgC3YG03jDYAb7WBvv04Xs44Bmu7EWyPz1xN9vJhMWy+WwS7RdysH7duaTBwH/Dczg7QOMex/hz4jH8kZ4fbwF5czQMPPf5Ft7P96ruMmXvle7uEaVTcLc2H11FEyp99F/AKLOGge/wGnY1jzlvsYPPNc+osIQly3XmmklSCJYI85X68kUpJKMEJT5g/N/I4AalUTWW8ZkjIpEKArU9vJ8X8idRcM07EbCkSXw3jHKza13uZYVl3EICnMaR68Qdj0+wOx+NrpqA3DUjR5jeR+3c4oN4B/GzJ0c+GFaAAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>paletteImage (in category 'resources') -----
- paletteImage
- 	^self imageLibrary at: #paletteImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'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' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>paletteOnImage (in category 'resources') -----
(excessive size, no diff calculated)

Item was removed:
- ----- Method: PaintBoxMorph class>>polygonIcon (in category 'resources') -----
- polygonIcon
- 	^self imageLibrary at: #polygonIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABsAAAAVCAMAAACAAGUXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAI9JREFUeF6dkU0OhCAMhWXrOAmo0IxM5lIeQs/jcbvyp7appOPCBwuSj34vgQpxz4JGKnzOFsq/ufkNsad0sWATeCf5FqxOfBvc68qGIAxdKJgHYT1LT5YVa1hqOEXKc5qx1OgTqdEnUqsPR5LyXKvZh6Q8V8c8ZAlJpW97Rx8o7XZW7JfgWLQBkmJ48+9mVvybrBthz+e6AAAAAElFTkSuQmCC' readStream)) offset: -5@ -4; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>polygonIconImage (in category 'resources') -----
- polygonIconImage
- 	^self imageLibrary at: #polygonIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABsAAAAVCAMAAACAAGUXAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAI9JREFUeF6dkU0OhCAMhWXrOAmo0IxM5lIeQs/jcbvyp7appOPCBwuSj34vgQpxz4JGKnzOFsq/ufkNsad0sWATeCf5FqxOfBvc68qGIAxdKJgHYT1LT5YVa1hqOEXKc5qx1OgTqdEnUqsPR5LyXKvZh6Q8V8c8ZAlJpW97Rx8o7XZW7JfgWLQBkmJ48+9mVvybrBthz+e6AAAAAElFTkSuQmCC' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>prototype (in category 'instance creation') -----
- prototype
- 	"Later we will be a subclass of Model, and it will have a general version of this"
- 	^ Prototype ifNil: [Prototype := self newPrototype]!

Item was removed:
- ----- Method: PaintBoxMorph class>>rectIcon (in category 'resources') -----
- rectIcon
- 	^self imageLibrary at: #rectIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABUAAAAUCAMAAABVlYYBAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAG5JREFUeF6VkNEKgCAMRfV1L7mMRhZ9tJ+7p+ZyZCCIRxhyuNyH65gL99mQTqeSlwMwoLLG4KslpL08PWgWIn9Eswg9G8bZbZCNE9lub7+hm80IKdk4F5j1gq0j32pJVtFtdB4Sm1+aYq5Z/jNjH9oIHun4V1LxAAAAAElFTkSuQmCC' readStream)) offset: -6@ -17; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>rectIconImage (in category 'resources') -----
- rectIconImage
- 	^self imageLibrary at: #rectIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABUAAAAUCAMAAABVlYYBAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAG5JREFUeF6VkNEKgCAMRfV1L7mMRhZ9tJ+7p+ZyZCCIRxhyuNyH65gL99mQTqeSlwMwoLLG4KslpL08PWgWIn9Eswg9G8bZbZCNE9lub7+hm80IKdk4F5j1gq0j32pJVtFtdB4Sm1+aYq5Z/jNjH9oIHun4V1LxAAAAAElFTkSuQmCC' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>rotationTabImage (in category 'resources') -----
- rotationTabImage
- 	^self imageLibrary at: #rotationTabImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAABHNCSVQFBQUBSsjp7wAAAwZJREFUeF6VlS2UpDAQhCORSCQSiUQikUgkEolEIpFIJBKJRCKRSOTIkchxfVX5Ydnd2b27vNdvZjbJ19WVTlb9Np7rKkfbypplskSRTEEgUxjKlCSy1JXs8yzqf8e577IXuWxhIFtgYkUsiJkJECOiD3wZkOifkzynSXao3AHWEZhwCVySjwSBtEgyNc3vCR59r4HH17gl2L5UMCA635cG0Zel/KiYoIeOUAdBNTZFnicRqonjWEL8TvGbwNmpx/cWUTFBXcs3j4840uAnAGdRyJSmElERyt0xf56njsfjITM8TuA1kwwEBgZOIYXvyTyOHwmOPDdgqD2rUuau00q3bZPX6/VjMHGklIZ3Fl4iclRDEercVu2zhkewAxsytN5xHBeECwkqUFEJX0coc3P8nVubGgvPWBEEqkfbXF4TPqCKu+IVvR5Z70co7K3nFECbns+neFDfXMo9Da/BUTtVXnC0FZTcS8/g/dbUOvFh25P9T7U1Dk+vAYNeOzjnctiqNrvJeI6TRzkOzApaHPSZJXrewdeQrejrzuG6FreY1dQAO+UJ5tRqN7gEXOjgPfqeXt7Bs+2MKTAtSmu4LsH3CuDCwmOEWqB8u12YlK2IDYQPwyAlFl122K7w8Deq9vHJdVVVaWBp4awipvIlTXSZLgEXsY+5iYcVoT0HQDm/Br5WzgPmQbuDZ7LUwnP7PcU+teF1W+xmBkG8IM4aqo89dYFpR3IT4OzjfQnQNdpvRIFGUAcWcQMTrCGTmD5lX7tOaHnrLJjtSG/Z37SPyXnhCI6tan527iGbklhvnG2SWatTkiI7VTsoq+JtbACn37QstGpph1MdYX6HZeb6L7PeOFp1Luhhh3BgHqa5iQZW3Hy+wHfVbiy4qb2F3KPXt9IkoT2Nb/pZW2MTOHDsvH43RvhIQ
 HcDvoXalss/gWEP2lg/WD+NCVe6trDmBv0E9r6Diyz9HezGilevxmGVFuaU3tWmFhr7bzz+6/9SqJjwzrR43Uq0WhaY1zDh9WZiKCX06oo34w9N0ZSkQD6ZeQAAAABJRU5ErkJggg==' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>scaleTabImage (in category 'resources') -----
- scaleTabImage
- 	^self imageLibrary at: #scaleTabImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAABHNCSVQFBQUBSsjp7wAAAr9JREFUeF6VlSGUo0AQRJHISCQSiUQikUgkEolEIpHISCQSGYlEIpFIJBLXVzVpcvOyZHPHe7UDZPOrp6e74/x27eMoS13LnCQyBoEMnie970sfRfIoC5mHQZz/vfZ5liVLZfa9p7ynRsgYQB3Ueje5w+ifTba+lzUMZAV0Ua0ALdCkBg81MQa3m9RQX1W/G2xta6AbtJvVN/cr1kWjtw3MDgCmQeW60mbZtcHOiC3wAeCuosl6ATcpUngNeOE40haF/MgxU2HAgS9HFMoRhsbgNDFpuooe4DvUAF4CnkLD/f7XYE1TBSPiOJKjLKEC97Hk+GKGSslgFgMW4ZkKKQADyAcwhypdE3y2rqs4+zSaQyP8YNSokqPrnsIWE0Bn7gz/vCyLubfFdymCSy14zPQ0jThrXb1y/YLjg6Op5UgTqfJc9n2X4zg+qkAQNjzhit5wFvxZ9RBNWpjvJJYd4n2DJvoGzxHAOzzGOTkTol2sKqEBD/VUi/r9Bs9Qgu9wnoczno1iGTzQeT1XHGSOfA7oQKpHuW7b9gPOnBPIask05wHkjIhutgwoVgLz2KKpGuS/Rmr4HOJw+fwJXig8esFRepPOkLPdWXJX26dZhTRdwWNNSarwEAxnQj0zDTQ4FeGDq+2fu7jKeaRRJxp1ih5xFuYScBqMPoT1N3iML9GgRKMxVVw9NpcVNZuqxnvToT1KjgaDmoTQFZxpCTXCVBUrMNH7UOHzND3hy2OQO4Adq8R7tjY7kiVoi5ET2DAyrY7cMjnBzfv4feBFe3MxhDArXOQNZcjqsMXtn/VcfACn+PG4HLtdnmHwu9Lc4O5a0kgrK9rsAhwjIDOwPl0dDqlQyLsKC5pY9expdawYYl9/6h6Yx2bUKswGngd4RuujzetvP3HvF6PocIAlBluKIRRxdjNSr
 CxVRkrodFbFxfUHM1HXoyHv+TYAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>shapeTabImage (in category 'resources') -----
- shapeTabImage
- 	^self imageLibrary at: #shapeTabImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAACUAAAAXCAYAAACMLIalAAAABHNCSVQFBQUBSsjp7wAAAmFJREFUeF7FlCGQpDAQRZHIkStPjkSuHHlyJRKJRCKRSCQSiYyMRCKRSGQkclxf/w4ZAlu3M2zVsqn6RRFI5/XvTgKtChqHlqaxJTMpuhstmkZFfVdT2xbU1Dm1TUFBEFJWdw/lTS8q2sETz9Wa0rJ9zGHd0DeicWi+3MuYiQ5DORCBcVpg3HucFhS9/2W4jt+7X4JalDNAkld0eXujK0NllRLXToVa1QlAnOYCdItThqulhJg/Hwq9xQLQNXpnh24Us1sWqvkFKAHSlBWlfAMQYJIFKmOn8uqM8i3OWClKMjt/+0gozsrVpaI5safclcAOAOjPNeKy3SxQVgmUAMElBjrl9Nk7SlNZN7Zkke0hAcosUFoq+QfXRHnGPZWwAzhdm5ItDiWFPXFwCD0HoFKNPw8V88bR7UPuIQeDpwVa+mi5t0p1EhR6KeWN4QhArJrHneRueOdSdTaU9I8HZBt7KdujdBg/DHUJLxuFYfhUWKdV9TrUMGgvC/vzjJ9nLU8swLyfqS/Vllaq5I1X4d19QwwIsffx8Y64+A/JG2MomGezs3ZdhCwcGLID3F5u7VcyO6Bt0i11eq3IPM+25NPUi33/c8tlBCHIUfkws9kmiz3hLNpjmlwP8gAdoByYH+juBfHhjsgH8uMMXJlOVw+XpHT+MGbcgPmO+Rl+R3sY5xCA0EufXPLHNA1S3xVscW1Un5w7CuVgbB/WrwH5jmEBtHVude+o3IHoBaaW60FOJZvwFMjvMSzAYr0AOshXTtteXWed2cIMhJMfHB33+8zWG852tIFGqP+GLATizOY5yD+ABou9MdPjbQAAAABJRU5ErkJggg==' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>shapesImage (in category 'resources') -----
- shapesImage
- 	^self imageLibrary at: #shapesImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'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' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>shapesOnImage (in category 'resources') -----
- shapesOnImage
- 	^self imageLibrary at: #shapesOnImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'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' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>stampTabImage (in category 'resources') -----
- stampTabImage
- 	^self imageLibrary at: #stampTabImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAADMAAAAWCAYAAABtwKSvAAAABHNCSVQFBQUBSsjp7wAAA6tJREFUeF69ViuwqzAURFYikUgkEhkZiUQiI5FIJLISWYlEIisrkUhkJLLuvLNJU0J75777PoWZnbTAJmd3T9IG49DQPPW0zD3pZaC7Hg2WeaDbtaO+b+jS1dRfGgqCExVVYVEXVNblDrjnYO41JSmgVTtU54rBn8/q7ZkPrDfdLgbzdPm2Rq0X+jsxLwVjbHjszznVSvA7uX3uCUHxVoQF7p353tAVdK4llRXm2zh45/Ni6pdUHmJ0J+k+KhqrjPIspryUT0G+CIe2LWk9C8OZGkkqi54c1ZZHi9mSQVpKRNTIxIxpdKJMpJSr/CFGvQuCCWlItYwNRHyiJLGCnAGHiFEQ4vYOI+e2UqUgyQXFYUDhKWAxGUlXGLdNDUHP/VAaM5TieTgRcCLmxHFEspDGJBjwcTEVF7HUKS2t4PYQNHCLFEVGV/5cipjiBIh2yXRtQbrJDOfWSurRViz+xmPDqaRpYjgpc+SRyZScQhOHNGQhTVVKMxeJtkKbpFxQnMaUZAmJQtj2w2bmsY0CusqIZjbiUqbMCUgmoUkFYt44h7QZ2ordy+OYFBdScVECe4TFZCwm4cIyuTnsTrOSUyq4jSrmlMzJnpzQiDFJeqkck0xt9wiKFZL3RRRSwf2ehyiQwakJrzD12Pz4vSlYkMSzkE3h94vIcThZTmY7MFhMd4SYxm5el5DIM8rY2fwhSqJt0HZpZIrffiQhSBme5HYSHudphDnNxHFtZsQ4GFGPlCAKG5j3TM7pSEbORTun60tNNc+Dz7iHFHBygSeRCgsBB8nZ0+wAMXDX/8vhhJmkXIEsAu4/24ZbpmF+01tAmPsXYLm5SRmm+JyPiwlP4Q6n0+kPERqEPwDWG4fzz8VM0+ipty+veHkdzQgC7vsO+Rj61mJoeeEN+P585j2/jmdTALCfr
 7emPoy1GAxQ02td+A4+5obZWmsK1lW/RLmRoN4JwuRuQR+O+z26By5fmLKfzxeiX4TsTe7ZmK1z1nXlJPlalpvn1Hs6zglgW+wT2Cfhi1j13lzUiqTR/ssyWyG4oMqP3vWmm+Cu30X9f/D8y7gr/iuY9uJE0a4uFdNi/qX1/NLL/ZfOfBzrhlcRLhEIwV55S8W/lmUyfehvTpPSPLwl9b/xXRLbIdT9TIifEAhfnzr9B9tseBbuHzhY+2ZEdOaYhhCY/lsh/h4CAeTxIcyJ+9np9W9wJl6vNom9iIlwAgd/et3vK0et2bHZTjQDtwNhi8f6q/69gF+MUOdTGgYgKwAAAABJRU5ErkJggg==' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>stampsImage (in category 'resources') -----
- stampsImage
- 	^self imageLibrary at: #stampsImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'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' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>stampsOnImage (in category 'resources') -----
- stampsOnImage
- 	^self imageLibrary at: #stampsOnImage ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'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' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>starIcon (in category 'resources') -----
- starIcon
- 	^self imageLibrary at: #starIcon ifAbsentPut: [(Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABgAAAAUCAMAAACgaw2xAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAKlJREFUeF51kTsSwyAMRNkWU8gQrOEzuV5yHh+XKsIEE2aIqkVPQlpQpaxDTSc3g7MfGHEJIsEtAdiNFnW2EGmpxNFydaQU2QMs00Fu45AaeJWyA/YhMjlRBDTw1kR5LBoA331Y2Dufj5rvBv1NMtdZw7nH1kSCmZ4k4OgVzwkYhCaOr0d1P1NOrGmTCi7zDA1UE+7aaQBISu4wFU2A9u8MQ3rxUX9/8Cc+919bKkV5meQAAAAASUVORK5CYII=' readStream)) offset: -2@ -5; yourself]!

Item was removed:
- ----- Method: PaintBoxMorph class>>starIconImage (in category 'resources') -----
- starIconImage
- 	^self imageLibrary at: #starIcon ifAbsentPut: [Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes:
- 		'iVBORw0KGgoAAAANSUhEUgAAABgAAAAUCAMAAACgaw2xAAADAFBMVEX///8AAAD///9/f3//AAAA/wAAAP8A/////wAAAAAfHx8/Pz9fX1+enp6+vr7e3t4HBwcPDw8XFxcnJycvLy83NzdHR0dPT09XV1dnZ2dvb293d3eGhoaOjo6Wlpampqaurq62trbGxsbOzs7W1tbm5ubu7u729vYAAAAAMgAAZQAAmAAAywAA/wAAADIAMjIAZTIAmDIAyzIA/zIAAGUAMmUAZWUAmGUAy2UA/2UAAJgAMpgAZZgAmJgAy5gA/5gAAMsAMssAZcsAmMsAy8sA/8sAAP8AMv8AZf8AmP8Ay/8A//8yAAAyMgAyZQAymAAyywAy/wAyADIyMjIyZTIymDIyyzIy/zIyAGUyMmUyZWUymGUyy2Uy/2UyAJgyMpgyZZgymJgyy5gy/5gyAMsyMssyZcsymMsyy8sy/8syAP8yMv8yZf8ymP8yy/8y//9lAABlMgBlZQBlmABlywBl/wBlADJlMjJlZTJlmDJlyzJl/zJlAGVlMmVlZWVlmGVly2Vl/2VlAJhlMphlZZhlmJhly5hl/5hlAMtlMstlZctlmMtly8tl/8tlAP9lMv9lZf9lmP9ly/9l//+YAACYMgCYZQCYmACYywCY/wCYADKYMjKYZTKYmDKYyzKY/zKYAGWYMmWYZWWYmGWYy2WY/2WYAJiYMpiYZZiYmJiYy5iY/5iYAMuYMsuYZcuYmMuYy8uY/8uYAP+YMv+YZf+YmP+Yy/+Y///LAADLMgDLZQDLmADLywDL/wDLADLLMjLLZTLLmDLLyzLL/zLLAGXLMmXLZWXLmGXLy2XL/2XLAJjLMpjLZZjLmJjLy5jL/5jLAMvLMsvLZcvLmMvLy8vL/8vLAP/LMv/LZf/LmP/Ly//L////AAD/MgD/ZQD/mAD/ywD//wD/ADL/MjL/ZTL/mDL/yzL//zL/AGX/MmX/Z
 WX/mGX/y2X//2X/AJj/Mpj/ZZj/mJj/y5j//5j/AMv/Msv/Zcv/mMv/y8v//8sAAAD/Mv//Zf//mP//y//////eTOgfAAABAHRSTlP///////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AP//////OE00OwAAAKlJREFUeF51kTsSwyAMRNkWU8gQrOEzuV5yHh+XKsIEE2aIqkVPQlpQpaxDTSc3g7MfGHEJIsEtAdiNFnW2EGmpxNFydaQU2QMs00Fu45AaeJWyA/YhMjlRBDTw1kR5LBoA331Y2Dufj5rvBv1NMtdZw7nH1kSCmZ4k4OgVzwkYhCaOr0d1P1NOrGmTCi7zDA1UE+7aaQBISu4wFU2A9u8MQ3rxUX9/8Cc+919bKkV5meQAAAAASUVORK5CYII=' readStream)]!

Item was removed:
- ----- Method: PaintBoxMorph class>>useLargeColorPicker (in category 'preferences') -----
- useLargeColorPicker
- 	<preference: 'Use large color picker'
- 	category: 'Morphic'
- 	description: 'If true, then the color picker of the paint box will be large and 32bits deep.'
- 	type: #Boolean>
- 	^UseLargeColorPicker ifNil: [ false ]!

Item was removed:
- ----- Method: PaintBoxMorph class>>useLargeColorPicker: (in category 'preferences') -----
- useLargeColorPicker: aBoolean
- 	UseLargeColorPicker = aBoolean
- 		ifFalse:
- 			[ColorChart := nil.
- 			ImageLibrary ifNotNil: [ImageLibrary
- 				removeKey: #colorMemoryImage ifAbsent: [];
- 				removeKey: #colorMemoryThinImage ifAbsent: []]].
- 	UseLargeColorPicker := aBoolean!

Item was removed:
- ----- Method: PaintBoxMorph>>action (in category 'actions') -----
- action
- 	^ action	!

Item was removed:
- ----- Method: PaintBoxMorph>>actionCursor (in category 'actions') -----
- actionCursor
- 	"Return the cursor to use with this painting action/tool. Offset of the form must be set."
- 
- 	^self
- 		cursorFor: action
- 		oldCursor: currentCursor
- 		currentNib: self getNib
- 		color: currentColor
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addActionsOffImage:onImage: (in category 'initialization') -----
- addActionsOffImage: offImage onImage: onImage
- 	| posSpec actionSpec |
- 	posSpec := #(
- 		(53 53 53 53) "offset X"
- 		(154 178 202 226) "offset Y"
- 		(39 39 39 39) "width"
- 		(23 23 23 23) "height").
- 	actionSpec := #(undo:with:evt: keep:with:evt: clear:with:evt: toss:with:evt:).
- 	#(undo: keep: clear: toss:) keysAndValuesDo: [:index :name |
- 		| button rect |
- 		(self submorphNamed: name) ifNil:
- 			[rect := ((posSpec at: 1) at: index) @ ((posSpec at: 2) at: index)
- 					extent: ((posSpec at: 3) at: index) @ ((posSpec at: 4) at: index).
- 			(button := ThreePhaseButtonMorph new)
- 				onImage: (onImage copy: rect);
- 				offImage: (offImage copy: rect);
- 				pressedImage: (onImage copy: rect);
- 				bounds: (rect translateBy: self position);
- 				setNamePropertyTo: name;
- 				actionSelector: (actionSpec at: index); 
- 					arguments: (Array with: button with: name);
- 				actWhen: #buttonUp; target: self.
- 			self addMorph: button.]].!

Item was removed:
- ----- Method: PaintBoxMorph>>addBrushesOffImage: (in category 'initialization') -----
- addBrushesOffImage: offImage
- 	| posSpec |
- 	posSpec := #(
- 		(13 37 64 13 37 64) "offset X"
- 		(107 107 107 124 124 124) "offset Y"
- 		(21 24 27 21 24 27) "width"
- 		(18 18 18 25 25 25) "height").
- 	#(brush1: brush2: brush3: brush4: brush5: brush6: ) keysAndValuesDo: [:index :name |
- 		| button nib rect on off |
- 		(self submorphNamed: name) ifNil:
- 			[nib := Form dotOfSize: (#(1 2 3 6 11 26) at: index).
- 			rect := ((posSpec at: 1) at: index) @ ((posSpec at: 2) at: index)
- 					extent: ((posSpec at: 3) at: index) @ ((posSpec at: 4) at: index).
- 			off := (offImage copy: rect) as8BitColorForm.
- 			"highlight a frame"
- 			on := off deepCopy.
- 			(on getCanvas copyOrigin: 0 at 0 clipRect: (0 at 0 extent: rect extent))
- 				frameAndFillRectangle: (0 at 0 extent: rect extent) fillColor: Color transparent
- 				borderWidth: 2 borderColor: (Color r: 0.6 g: 0.8 b: 1.0).
- 			(button := ThreePhaseButtonMorph new)
- 				onImage: on;
- 				offImage: off;
- 				pressedImage: on;
- 				bounds: (rect translateBy: self position);
- 				setNamePropertyTo: name;
- 				actionSelector: #brush:action:nib:evt:; 
- 					arguments: (Array with: button with: name with: nib);
- 				actWhen: #buttonUp; target: self.
- 			self addMorph: button.]].
- 	brushes := #(brush1: brush2: brush3: brush4: brush5: brush6: ) collect: [:name | self submorphNamed: name].
- 	currentBrush := brushes at: 3.
- 	currentBrush state: #on.
- 
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addCustomMenuItems:hand: (in category 'other') -----
- addCustomMenuItems: aCustomMenu hand: aHandMorph
- 
- 	"super addCustomMenuItems: aCustomMenu hand: aHandMorph."
- 		"don't want the ones from ImageMorph"
- 	aCustomMenu add: 'grab stamp from screen' translated action: #grabFromScreen:.
- 
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addGraphicLabels (in category 'initialization') -----
- addGraphicLabels
- 	"translate button labels"
- 
- 	| formTranslator |
- 	formTranslator := NaturalLanguageFormTranslator localeID: (Locale current localeID).
- 
- 	#('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:label |
- 		(formTranslator translate: label, '-off') ifNil: [^ false].
- 		(formTranslator translate: label, '-pressed') ifNil: [^ false].
- 	].
- 	
- 	#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |
- 		| button newForm ext pos |
- 		button := submorphs detect: [:m | m externalName = extName] ifNone: [nil].
- 		button ifNotNil: [
- 			button removeAllMorphs.
- 			ext := button extent.
- 			pos := button position.
- 			(newForm := formTranslator translate: label, '-off') ifNotNil: [
- 				button offImage: newForm.
- 
- 			].
- 			(newForm := formTranslator translate: label, '-pressed') ifNotNil: [
- 				button pressedImage: newForm.
- 			].
- 			button extent: ext.
- 			button position: pos.
- 		].
- 	].
- 
- 	^ true.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addLabels (in category 'initialization') -----
- addLabels
- 
- 	Preferences useFormsInPaintBox ifFalse: [
- 		self addTextualLabels.
- 	] ifTrue: [
- 		self addGraphicLabels ifFalse: [self addTextualLabels].
- 	].
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addShapeButtonsOffImage:onImage: (in category 'initialization') -----
- addShapeButtonsOffImage: offImage onImage: onImage
- 	| shapes posSpec iconSpec |
- 	posSpec := #(
- 		(17 17 17 17 17) "offset X"
- 		(0 22 44 66 88) "offset Y"
- 		(30 30 30 30 30) "width"
- 		(21 21 21 21 21) "height").
- 	shapes := self submorphNamed: 'shapes'.
- 	iconSpec := #(lineIcon rectIcon ellipseIcon polygonIcon starIcon).
- 	#(line: rect: ellipse: polygon: star:) keysAndValuesDo: [:index :name |
- 		| button rect |
- 		(self submorphNamed: name) ifNil:
- 			[rect := ((posSpec at: 1) at: index) @ ((posSpec at: 2) at: index)
- 					extent: ((posSpec at: 3) at: index) @ ((posSpec at: 4) at: index).
- 			(button := ThreePhaseButtonMorph new)
- 				onImage: (onImage copy: rect);
- 				offImage: (offImage copy: rect);
- 				pressedImage: (onImage copy: rect);
- 				bounds: (rect translateBy: shapes position);
- 				setNamePropertyTo: name;
- 				actionSelector: #tool:action:cursor:evt:; 
- 					arguments: (Array with: button with: name with: (self class perform: (iconSpec at: index)));
- 				actWhen: #buttonUp; target: self.
- 			shapes addMorph: button.]].!

Item was removed:
- ----- Method: PaintBoxMorph>>addStampButtonsOffImage:onImage: (in category 'initialization') -----
- addStampButtonsOffImage: offImage onImage: onImage
- 	| stamps posSpec actionSpec argSpec names |
- 	posSpec := #(
- 		(13 38 63 13 38 63 37 55) "offset X"
- 		(0 0 0 25 25 25 51 51) "offset Y"
- 		(25 25 25 25 25 25 15 15) "width"
- 		(25 25 25 25 25 25 15 15) "height").
- 	actionSpec := #(
- 		pickup:action:cursor:evt: pickup:action:cursor:evt: pickup:action:cursor:evt:
- 		pickup:action:cursor:evt: pickup:action:cursor:evt: pickup:action:cursor:evt:
- 		scrollStamps:action:evt: scrollStamps:action:evt:).
- 	argSpec := #(
- 		stamp: stamp: stamp:
- 		stamp: stamp: stamp:
- 		prevStamp: nextStamp:).
- 	names := #(
- 		pickup: pickup: pickup:
- 		stamp: stamp: stamp:
- 		prevStamp: nextStamp:).
- 	stamps := self submorphNamed: 'stamps'.
- 	names keysAndValuesDo: [:index :name |
- 		| button rect |
- 		(self submorphNamed: name) ifNil:
- 			[rect := ((posSpec at: 1) at: index) @ ((posSpec at: 2) at: index)
- 					extent: ((posSpec at: 3) at: index) @ ((posSpec at: 4) at: index).
- 			(button := ThreePhaseButtonMorph new)
- 				onImage: (onImage copy: rect);
- 				offImage: (offImage copy: rect);
- 				pressedImage: (onImage copy: rect);
- 				bounds: (rect translateBy: stamps position);
- 				setNamePropertyTo: name;
- 				actionSelector: (actionSpec at: index); 
- 					arguments: ((Array with: button with: (argSpec at: index) with: Cursor origin) first: (actionSpec at: index) numArgs - 1);
- 				actWhen: #buttonUp; target: self.
- 			stamps addMorph: button.]].!

Item was removed:
- ----- Method: PaintBoxMorph>>addStampsAndShapes (in category 'initialization') -----
- addStampsAndShapes
- 	| shapeTab shapes stampTab stamps |
- 	(stampTab := ThreePhaseButtonMorph new)
- 		onImage: self class stampTabImage;
- 		offImage: self class stampTabImage;
- 		pressedImage: self class stampTabImage;
- 		setNamePropertyTo: 'stampTab';
- 		actionSelector: #toggleStamps; target: self;
- 		position: self position + (9 at image height);
- 		bounds: (stampTab position extent: stampTab onImage extent).
- 	self addMorph: stampTab.
- 	
- 	(shapeTab := ThreePhaseButtonMorph new)
- 		onImage: self class shapeTabImage;
- 		offImage: self class shapeTabImage;
- 		pressedImage: self class shapeTabImage;
- 		setNamePropertyTo: 'shapeTab';
- 		actionSelector: #toggleShapes; target: self;
- 		position: self position + (image width - shapeTab onImage width-9 at image height);
- 		bounds: (shapeTab position extent: shapeTab onImage extent).
- 	self addMorph: shapeTab.
- 	
- 	self layoutChanged.
- 	
- 	(stamps := self class stampsImage asMorph)
- 		setNamePropertyTo: 'stamps';
- 		visible: false;
- 		position: self position + (0@(image height - stamps image height)).
- 	self addMorph: stamps.
- 	
- 	(shapes := self class shapesImage asMorph)
- 		setNamePropertyTo: 'shapes';
- 		visible: false;
- 		position: self position + (image width - shapes image width at image height).
- 	self addMorph: shapes.!

Item was removed:
- ----- Method: PaintBoxMorph>>addTextualLabels (in category 'initialization') -----
- addTextualLabels
- 	"Translate button labels. Use unscaled font because of #beSupersized."
- 
- 	#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |
- 		| button |
- 		button := submorphs detect: [:m | m externalName = extName] ifNone: [nil].
- 		button ifNotNil: [
- 			button removeAllMorphs.
- 			button addMorph: (TextMorph new 
- 				contentsWrapped: (Text string: label translated
- 					attributes: {
- 						TextAlignment centered. 
- 						TextEmphasis bold.
- 						TextFontReference toFont: (StrikeFont familyName: 'Bitmap DejaVu Sans' size: 12)
- 							});
- 				bounds: (button bounds translateBy: 0 at 3);
- 				lock)]]!

Item was removed:
- ----- Method: PaintBoxMorph>>addToolsOffImage:onImage: (in category 'initialization') -----
- addToolsOffImage: offImage onImage: onImage
- 	| posSpec actionSpec iconSpec |
- 	posSpec := #(
- 		(13 53 13 53) "offset X"
- 		(13 13 61 61) "offset Y"
- 		(40 40 40 40) "width"
- 		(48 48 44 44) "height").
- 	actionSpec := #(tool:action:cursor:evt: tool:action:cursor:evt: eyedropper:action:cursor:evt: tool:action:cursor:evt:).
- 	iconSpec := #(paintIcon fillIcon eyedropperIcon eraseIcon).
- 	#(paint: fill: eyedropper: erase:) keysAndValuesDo: [:index :name |
- 		| button rect |
- 		(self submorphNamed: name) ifNil:
- 			[rect := ((posSpec at: 1) at: index) @ ((posSpec at: 2) at: index)
- 					extent: ((posSpec at: 3) at: index) @ ((posSpec at: 4) at: index).
- 			(button := ThreePhaseButtonMorph new)
- 				onImage: (onImage copy: rect);
- 				offImage: (offImage copy: rect);
- 				pressedImage: (onImage copy: rect);
- 				bounds: (rect translateBy: self position);
- 				setNamePropertyTo: name;
- 				actionSelector: (actionSpec at: index); 
- 					arguments: (Array with: button with: name with: (self class perform: (iconSpec at: index)));
- 				actWhen: #buttonUp; target: self.
- 			index = 1
- 				ifTrue:
- 					[action := name.
- 					tool := button.
- 					currentCursor := button arguments at: 3].
- 			self addMorph: button.]].
- 
- !

Item was removed:
- ----- Method: PaintBoxMorph>>addWeakDependent: (in category 'initialization') -----
- addWeakDependent: anObject
- 
- 	weakDependents ifNil: [^weakDependents := WeakArray with: anObject].
- 	weakDependents := weakDependents,{anObject} reject: [ :each | each isNil].!

Item was removed:
- ----- Method: PaintBoxMorph>>beStatic (in category 'initialization') -----
- beStatic
- 
- 	colorMemory ifNotNil: [colorMemory beStatic].!

Item was removed:
- ----- Method: PaintBoxMorph>>beSupersized (in category 'initialization') -----
- beSupersized
- 	| scaleFactor |
- 	scaleFactor := RealEstateAgent scaleFactor.
- 	self isFlexed
- 		ifFalse: [self scaleFactor: scaleFactor.
- 			self position: self position / scaleFactor.
- 			self changed]!

Item was removed:
- ----- Method: PaintBoxMorph>>brush:action:nib:evt: (in category 'actions') -----
- brush: brushButton action: aSelector nib: aMask evt: evt 
- 	"Set the current tool and action for the paintBox.  "
- 
- 	currentBrush 
- 		ifNotNil: [currentBrush == brushButton ifFalse: [currentBrush state: #off]].
- 	currentBrush := brushButton.	"A ThreePhaseButtonMorph"
- 
- 	"currentBrush state: #on.	already done"
- 	"aSelector is like brush3:.  Don't save it.  Can always say (currentBrush arguments at: 2)
- 	aMask is the brush shape.  Don't save it.  Can always say (currentBrush arguments at: 3)"
- 	self notifyWeakDependentsWith: { 
- 				#currentNib.
- 				evt.
- 				currentBrush arguments third}.
- 	self brushable ifFalse: [self setAction: #paint: evt: evt]	"User now thinking of painting"!

Item was removed:
- ----- Method: PaintBoxMorph>>brushable (in category 'actions') -----
- brushable
- 	"Return true if the current tool uses a brush."
- 	^ (#("non-brushable" eyedropper: fill: pickup: stamp:) indexOf: action) = 0!

Item was removed:
- ----- Method: PaintBoxMorph>>buildAPrototype (in category 'initialization') -----
- buildAPrototype
- 	| onImage |
- 	self initialize.
- 	self image: self class paletteImage.
- 	rotationTabForm := self class rotationTabImage.
- 	scaleTabForm := self class scaleTabImage.
- 	(colorMemoryThin := self class colorMemoryThinImage asMorph)
- 		setNamePropertyTo: 'ColorPickerClosed';
- 		position: self position + (11 at 150);
- 		on: #mouseEnter send: #showColorPalette: to: self.
- 	self addMorph: colorMemoryThin.
- 	(colorMemory := PaintBoxColorPicker new image: self class colorMemoryImage)
- 		setNamePropertyTo: 'ColorPickerOpened';
- 		on: #mouseDown send: #takeColorEvt:from: to: self.
- 	currentColor := Color black.
- 	
- 	onImage := self class paletteOnImage.
- 	self
- 		addToolsOffImage: image onImage: onImage;
- 		addBrushesOffImage: image;
- 		addActionsOffImage: image onImage: onImage;
- 		addStampsAndShapes;
- 		addShapeButtonsOffImage: self class shapesImage onImage: self class shapesOnImage;
- 		addStampButtonsOffImage: self class stampsImage onImage: self class stampsOnImage.
- 	stampHolder := ScrollingToolHolder newPrototypeFor: self.!

Item was removed:
- ----- Method: PaintBoxMorph>>clear:with:evt: (in category 'actions') -----
- clear: clearButton with: clearSelector evt: evt
- 
- 	| ss |
- 	(ss := self focusMorph) 
- 		ifNotNil: [ss clearPainting: self]
- 		ifNil: [self notCurrentlyPainting].
- 	clearButton state: #off.!

Item was removed:
- ----- Method: PaintBoxMorph>>colorMemory (in category 'other') -----
- colorMemory
- 
- 	^ colorMemory!

Item was removed:
- ----- Method: PaintBoxMorph>>colorMemory: (in category 'other') -----
- colorMemory: aMorph
- 
- 	colorMemory := aMorph!

Item was removed:
- ----- Method: PaintBoxMorph>>colorable (in category 'actions') -----
- colorable
- 	"Return true if the current tool uses a color."
- 	^ (#("These use no color" erase: eyedropper: "fill: does" pickup: stamp:) indexOf: action) = 0!

Item was removed:
- ----- Method: PaintBoxMorph>>currentColor:evt: (in category 'actions') -----
- currentColor: aColor evt: evt
- 	"Accept a color from the outside.  (my colorMemoryMorph must call takeColorEvt: evt from: colorPicker instead)"
- 
- 	currentColor := aColor.
- 	colorMemory currentColor: aColor.
- 	self notifyWeakDependentsWith: {#currentColor. evt. currentColor}.
- 	self showColor.
- 	self colorable ifFalse: [self setAction: #paint: evt: evt].	"User now thinking of painting"!

Item was removed:
- ----- Method: PaintBoxMorph>>cursorFor:oldCursor:currentNib:color: (in category 'actions') -----
- cursorFor: anAction oldCursor: oldCursor currentNib: aNibForm color: aColor 
- 	"Return the cursor to use with this painting action/tool. Offset of the 
- 	form must be set."
- 
- 	| ff width co larger c box |
- 
- 	anAction == #paint:
- 		ifTrue: ["Make a cursor from the brush and the color"
- 			width := aNibForm width.
- 			c := self ringColorFor: aColor.
- 			co := oldCursor offset - (width // 4 @ 34 - (width // 6)) min: 0 @ 0.
- 			larger := width negated + 10 @ 0 extent: oldCursor extent + (width @ width).
- 			ff := oldCursor copy: larger.
- 			ff colors at: 1 put: Color transparent.
- 			ff colors at: 2 put: Color transparent.
- 			ff offset: co - (width @ width // 2).
- 			ff getCanvas
- 				fillOval: (Rectangle center: ff offset negated extent: width @ width)
- 				color: Color transparent
- 				borderWidth: 1
- 				borderColor: c.
- 			^ ff].
- 	anAction == #erase:
- 		ifTrue: ["Make a cursor from the cursor and the color"
- 			width := aNibForm width.
- 			co := oldCursor offset + (width // 2 @ 4) min: 0 @ 0.
- 			larger := 0 @ 0 extent: oldCursor extent + (width @ width).
- 			ff := oldCursor copy: larger.
- 			ff offset: co - (width @ width // 2).
- 			ff
- 				fill: (box := co negated extent: width @ width)
- 				fillColor: (Color r: 0.5 g: 0.5 b: 1.0).
- 			ff
- 				fill: (box insetBy: 1 @ 1)
- 				fillColor: Color transparent.
- 			^ ff].
- 	^ oldCursor!

Item was removed:
- ----- Method: PaintBoxMorph>>delete (in category 'actions') -----
- delete
- 			
- 	^ self isSupersized
- 		ifTrue: [self owner delete]
- 		ifFalse: [super delete]!

Item was removed:
- ----- Method: PaintBoxMorph>>deleteCurrentStamp: (in category 'actions') -----
- deleteCurrentStamp: evt 
- 	"The trash is telling us to delete the currently selected stamp"
- 
- 	(tool arguments second) == #stamp: 
- 		ifTrue: 
- 			[stampHolder remove: tool.
- 			self setAction: #paint: evt: evt]	"no use stamping with a blank stamp"!

Item was removed:
- ----- Method: PaintBoxMorph>>eyedropper:action:cursor:evt: (in category 'actions') -----
- eyedropper: aButton action: aSelector cursor: aCursor evt: evt 
- 	"Take total control and pick up a color!!!!"
- 
- 	| pt feedbackColor delay |
- 	delay := Delay forMilliseconds: 10.
- 	aButton state: #on.
- 	tool ifNotNil: [tool state: #off].
- 	currentCursor := aCursor.
- 	evt hand showTemporaryCursor: currentCursor
- 		hotSpotOffset: 6 negated @ 4 negated.
- 	"<<<< the form was changed a bit??"
- 	feedbackColor := Display colorAt: Sensor cursorPoint.
- 	colorMemory align: colorMemory bounds topRight
- 		with: colorMemoryThin bounds topRight.
- 	self addMorphFront: colorMemory.
- 
- 	"Full color picker"
- 	[Sensor anyButtonPressed] whileFalse: 
- 			[pt := Sensor cursorPoint.
- 			"deal with the fact that 32 bit displays may have garbage in the 
- 			alpha bits"
- 			feedbackColor := Display depth = 32 
- 						ifTrue: 
- 							[Color colorFromPixelValue: ((Display pixelValueAt: pt) bitOr: 16rFF000000)
- 								depth: 32]
- 						ifFalse: [Display colorAt: pt].
- 			"the hand needs to be drawn"
- 			evt hand position: pt.
- 			currentColor ~= feedbackColor ifTrue: [
- 				currentColor := feedbackColor.
- 				self showColor ].
- 			self refreshWorld.
- 			delay wait].
- 
- 	"Now wait for the button to be released."
- 	[Sensor anyButtonPressed] whileTrue:
- 		[ pt := Sensor cursorPoint.
- 		"the hand needs to be drawn"
- 		evt hand position: pt.
- 		self refreshWorld.
- 		delay wait].
- 
- 	evt hand showTemporaryCursor: nil hotSpotOffset: 0 @ 0.
- 	self currentColor: feedbackColor evt: evt.
- 	colorMemory delete.
- 	tool ifNotNil: 
- 			[tool state: #on.
- 			currentCursor := tool arguments third].
- 	aButton state: #off
- !

Item was removed:
- ----- Method: PaintBoxMorph>>fixUpColorPicker (in category 'recent colors') -----
- fixUpColorPicker
- 	| chart picker |
- 	chart := self class colorChart.
- 	chart getCanvas frameRectangle: chart boundingBox color: Color black.
- 	picker := Form extent: (chart extent + (14 @ 12)) depth: 16.
- 	picker fillWhite.
- 	"top"
- 	picker copy: (0 @ 0 extent: picker width @ 6)
- 			from: (colorMemory image width - picker width) @ 0 
- 			in: colorMemory image rule: Form over.
- 	"bottom"
- 	picker copy: (0 @  (picker height - 6) extent: picker width @ 6) 
- 			from: (colorMemory image width - picker width) @ (colorMemory image height - 7)
- 			in: colorMemory image rule: Form over.
- 	"left"
- 	picker copy: (0 @ 6 corner: 8 @ (picker height - 6))
- 			from: (colorMemory image boundingBox topLeft + (0 @ 6)) 
- 			in: colorMemory image rule: Form over.
- 	"right"
- 	picker copy: (picker width-6 @ 6 corner: picker width @ (picker height - 6))
- 			from: (colorMemory image boundingBox topRight - (6 @ -6)) 
- 			in: colorMemory image rule: Form over.
- 	chart displayOn: picker at: 8 @ 6.
- 	picker getCanvas frameRectangle: picker boundingBox color: Color black.
- 	colorMemory image: picker.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>fixUpRecentColors (in category 'recent colors') -----
- fixUpRecentColors
- 	| inner outer border box form newImage canvas morph |
- 	self fixUpColorPicker.
- 	recentColors := WriteStream on: Array new.
- 	form := image.
- 	newImage := Form extent: form extent + (0 @ 41) depth: form depth.
- 	form displayOn: newImage.
- 	newImage 
- 		copy: (0 @ (form height - 10) 
- 				extent: form width @ (newImage height - form height + 10))
- 		from: 0 @ (form height - (newImage height - form height + 10))
- 		in: form
- 		rule: Form over.
- 	canvas := newImage getCanvas.
- 	canvas 
- 		line: 12 @ (form height - 10)
- 		to: 92 @ (form height - 10)
- 		width: 1
- 		color: Color black.
- 	canvas := canvas copyOffset: 12 @ (form height - 9).
- 	inner := Color 
- 				r: 0.677
- 				g: 0.71
- 				b: 0.968.
- 	outer := inner darker darker.
- 	border := Color 
- 				r: 0.194
- 				g: 0.258
- 				b: 0.194.
- 	0 to: 1
- 		do: 
- 			[:y | 
- 			0 to: 3
- 				do: 
- 					[:x | 
- 					box := (x * 20) @ (y * 20) extent: 20 @ 20.
- 					morph := BorderedMorph new 
- 								bounds: ((box insetBy: 1) translateBy: canvas origin + bounds origin).
- 					morph
- 						borderWidth: 1;
- 						borderColor: border.
- 					morph color: Color white.
- 					morph 
- 						on: #mouseDown
- 						send: #mouseDownRecent:with:
- 						to: self.
- 					morph 
- 						on: #mouseMove
- 						send: #mouseStillDownRecent:with:
- 						to: self.
- 					morph 
- 						on: #mouseUp
- 						send: #mouseUpRecent:with:
- 						to: self.
- 					self addMorphFront: morph.
- 					recentColors nextPut: morph.
- 					canvas fillRectangle: box color: Color white.
- 					canvas frameRectangle: (box insetBy: 1) color: border.
- 					canvas frameRectangle: box color: inner.
- 					box := box insetBy: 1.
- 					canvas 
- 						line: box topRight
- 						to: box bottomRight
- 						width: 1
- 						color: outer.
- 					canvas 
- 						line: box bottomLeft
- 						to: box bottomRight
- 						width: 1
- 						color: outer]].
- 	recentColors := recentColors contents.
- 	(RecentColors isNil or: [RecentColors size ~= recentColors size]) 
- 		ifTrue: [RecentColors := recentColors collect: [:each | each color]]
- 		ifFalse: 
- 			[RecentColors 
- 				keysAndValuesDo: [:idx :aColor | (recentColors at: idx) color: aColor]].
- 	self image: newImage.
- 	self toggleStamps.
- 	self toggleStamps!

Item was removed:
- ----- Method: PaintBoxMorph>>focusMorph (in category 'other') -----
- focusMorph
- 	"Note: For backward compatibility we search the world for a SketchEditorMorph if the current focus morph is nil"
- 	^focusMorph ifNil:[focusMorph := self world findA: SketchEditorMorph]!

Item was removed:
- ----- Method: PaintBoxMorph>>focusMorph: (in category 'other') -----
- focusMorph: newFocus
- 	"Set the new focus morph"
- 	focusMorph ifNotNil:[focusMorph paletteDetached: self]. "In case the morph is interested"
- 	focusMorph := newFocus.
- 	focusMorph ifNotNil:[focusMorph paletteAttached: self]. "In case the morph is interested"!

Item was removed:
- ----- Method: PaintBoxMorph>>getColor (in category 'actions') -----
- getColor
- 	^ currentColor!

Item was removed:
- ----- Method: PaintBoxMorph>>getNib (in category 'actions') -----
- getNib
- 	^currentBrush arguments third!

Item was removed:
- ----- Method: PaintBoxMorph>>getSpecial (in category 'actions') -----
- getSpecial
- 	^ action		"a selector like #paint:"!

Item was removed:
- ----- Method: PaintBoxMorph>>grabFromScreen: (in category 'actions') -----
- grabFromScreen: evt 
- 	"Allow the user to grab a picture from the screen OUTSIDE THE PAINTING AREA and install it in a blank stamp.  To get a stamp in the painting area, click on the stamp tool in a blank stamp."
- 
- 	"scroll to blank stamp"
- 
- 	| stampButton form |
- 	stampButton := stampHolder stampButtons first.
- 	[(stampHolder stampFormFor: stampButton) isNil] 
- 		whileFalse: [stampHolder scroll: 1].
- 	form := Form fromUser.
- 	tool state: #off.
- 	tool := stampHolder otherButtonFor: stampButton.
- 	stampHolder stampForm: form for: tool.	"install it"
- 	stampButton state: #on.
- 	stampButton doButtonAction: evt.
- 	evt hand showTemporaryCursor: (focusMorph getCursorFor: evt)!

Item was removed:
- ----- Method: PaintBoxMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	colorMemory ifNotNil: [colorMemory on: #mouseDown send: #takeColorEvt:from: to: self].!

Item was removed:
- ----- Method: PaintBoxMorph>>isSupersized (in category 'initialization') -----
- isSupersized
- 	
- 	^ self isFlexed!

Item was removed:
- ----- Method: PaintBoxMorph>>keep:with:evt: (in category 'actions') -----
- keep: keepButton with: keepSelector evt: evt
- 	"Showing of the corrent palette (viewer or noPalette) is done by the block submitted to the SketchMorphEditor, see (EToyHand makeNewDrawing) and (SketchMorph editDrawingInWorld:forBackground:)."
- 	| ss |
- 	owner ifNil: [^ self].
- 	keepButton ifNotNil: [keepButton state: #off].
- 	(ss := self focusMorph) 
- 		ifNotNil: [ss savePainting: self evt: evt]
- 		ifNil:
- 		[keepSelector == #silent ifTrue: [^ self].
- 		self notCurrentlyPainting].!

Item was removed:
- ----- Method: PaintBoxMorph>>loadJapanesePaintBoxBitmaps (in category 'initialization') -----
- loadJapanesePaintBoxBitmaps
- "
- 	PaintBoxMorph new loadJapanesePaintBoxBitmaps.
- "
- 
- 	| formTranslator form bb |
- 	self position: 0 at 0.
- 	formTranslator := NaturalLanguageFormTranslator localeID: (LocaleID isoString: 'ja').
- 	form := Form fromFileNamed: 'offPaletteJapanese(children).form'.
- 
- 	#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |
- 		bb := (self submorphs detect: [:e | e externalName = extName]) bounds.
- 		formTranslator name: label, '-off' form: (form copy: bb)
- 	].
- 
- 
- 	form := Form fromFileNamed: 'pressedPaletteJapanese(children).form'.
- 	#('keep:' 'undo:' 'clear:' 'toss:') with: #('KEEP' 'UNDO' 'CLEAR' 'TOSS') do: [:extName :label |
- 		bb := (self submorphs detect: [:e | e externalName = extName]) bounds.
- 		formTranslator name: label, '-pressed' form: (form copy: bb)
- 	].
- !

Item was removed:
- ----- Method: PaintBoxMorph>>maxBounds (in category 'other') -----
- maxBounds
- 	| rr |
- 	"fullBounds if all flop-out parts of the paintBox were showing."
- 
- 	rr := bounds merge: colorMemory bounds.
- 	rr := rr merge: (self submorphNamed: 'stamps') bounds.
- 	rr := rr origin corner: rr corner + (0@ (self submorphNamed: 'shapes') height 
- 				+ 10 "what is showing of (self submorphNamed: #toggleShapes) height").
- 	^ rr!

Item was removed:
- ----- Method: PaintBoxMorph>>mouseDownRecent:with: (in category 'recent colors') -----
- mouseDownRecent: evt with: aMorph
- 	aMorph borderColor: Color white.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>mouseStillDownRecent:with: (in category 'recent colors') -----
- mouseStillDownRecent: evt with: aMorph
- 	(aMorph containsPoint: evt cursorPoint)
- 		ifTrue:[aMorph borderColor: Color white]
- 		ifFalse:[aMorph borderColor: (Color r: 0.194 g: 0.258 b: 0.194)]
- !

Item was removed:
- ----- Method: PaintBoxMorph>>mouseUpBalk: (in category 'user interface') -----
- mouseUpBalk: evt
- 	"A button I own got a mouseDown, but the user moved out before letting up.  Prevent this for the current tool.  Some tool must stay selected."
- 
- 	tool state: #on.	"keep current one, even if user balked on it"
- 	currentBrush ifNotNil: [currentBrush state: #on].!

Item was removed:
- ----- Method: PaintBoxMorph>>mouseUpRecent:with: (in category 'recent colors') -----
- mouseUpRecent: evt with: aMorph
- 	aMorph borderColor: (Color r: 0.194 g: 0.258 b: 0.194).
- 	(aMorph containsPoint: evt cursorPoint) ifTrue:[
- 		self takeColor: aMorph color event: evt.
- 	].!

Item was removed:
- ----- Method: PaintBoxMorph>>notCurrentlyPainting (in category 'actions') -----
- notCurrentlyPainting
- 	self inform: 'You are not currently painting'!

Item was removed:
- ----- Method: PaintBoxMorph>>notifyWeakDependentsWith: (in category 'actions') -----
- notifyWeakDependentsWith: arguments
- 
- 	weakDependents ifNil: [^self].
- 	weakDependents do: [ :each |
- 		each ifNotNil: [
- 			each paintBoxChanged: arguments.
- 			each paintBoxChanged: {#changed. arguments second. true}.
- 		].
- 	].!

Item was removed:
- ----- Method: PaintBoxMorph>>offsetFromMaxBounds (in category 'other') -----
- offsetFromMaxBounds
- 	"location of normal PaintBox within maxBounds."
- 	| left |
- 	left := self left.
- 	((Preferences canUnderstand: #useBiggerPaintingBox) and: [ Preferences useBiggerPaintingBox ]) ifTrue: [left := left  - (( self width * 1.5)- self width)].
- 	^ left - colorMemory left @ 0!

Item was removed:
- ----- Method: PaintBoxMorph>>pickup:action:cursor:evt: (in category 'actions') -----
- pickup: actionButton action: aSelector cursor: aCursor evt: evt 
- 	"Special version for pickup: and stamp:, because of these tests"
- 
- 	| ss picker old map stamper |
- 	self 
- 		tool: actionButton
- 		action: aSelector
- 		cursor: aCursor
- 		evt: evt.
- 	aSelector == #stamp: 
- 		ifTrue: 
- 			[(stampHolder pickupButtons includes: actionButton) 
- 				ifTrue: 
- 					[stamper := stampHolder otherButtonFor: actionButton.
- 					^self 
- 						pickup: stamper
- 						action: #stamp:
- 						cursor: (stamper arguments third)
- 						evt: evt].
- 			(stampHolder stampFormFor: actionButton) ifNil: 
- 					["If not stamp there, go to pickup mode"
- 
- 					picker := stampHolder otherButtonFor: actionButton.
- 					picker state: #on.
- 					^self 
- 						pickup: picker
- 						action: #pickup:
- 						cursor: (picker arguments third)
- 						evt: evt]
- 				ifNotNil: 
- 					[old := stampHolder stampFormFor: actionButton.
- 					currentCursor := ColorForm extent: old extent depth: 8.
- 					old displayOn: currentCursor.
- 					map := Color indexedColors copy.
- 					map at: 1 put: Color transparent.
- 					currentCursor colors: map.
- 					currentCursor offset: currentCursor extent // -2.
- 					"Emphisize the stamp button"
- 					actionButton owner borderColor: (Color 
- 								r: 0.65
- 								g: 0.599
- 								b: 0.8)	"layoutMorph"	"color: (Color r: 1.0 g: 0.645 b: 0.419);"]].
- 	aSelector == #pickup: 
- 		ifTrue: 
- 			[ss := self focusMorph.
- 			ss ifNotNil: [currentCursor := aCursor]
- 				ifNil: 
- 					[self notCurrentlyPainting.
- 					self setAction: #paint: evt: evt]]!

Item was removed:
- ----- Method: PaintBoxMorph>>pickupForm: (in category 'actions') -----
- pickupForm: stampForm
- 	"Install the new picture in this stamp"
- 
- 	| stampButton |
- 	stampHolder stampForm: stampForm for: tool.
- 	stampButton := action == #pickup: 
- 		ifTrue: [stampHolder otherButtonFor: tool]
- 		ifFalse: [tool].	"was a nil stampForm"
- 	stampButton state: #on.
- 	stampButton doButtonAction.!

Item was removed:
- ----- Method: PaintBoxMorph>>pickupForm:evt: (in category 'actions') -----
- pickupForm: stampForm evt: evt
- 	"Install the new picture in this stamp"
- 
- 	| stampButton |
- 	stampHolder stampForm: stampForm for: tool.
- 	stampButton := action == #pickup: 
- 		ifTrue: [stampHolder otherButtonFor: tool]
- 		ifFalse: [tool].	"was a nil stampForm"
- 	stampButton state: #on.
- 	stampButton doButtonAction: evt.!

Item was removed:
- ----- Method: PaintBoxMorph>>plainCursor (in category 'actions') -----
- plainCursor
- 	"Return the cursor to use with this painting action/tool. Offset of the form must be set."
- 
- 	^currentCursor
- !

Item was removed:
- ----- Method: PaintBoxMorph>>plainCursor:event: (in category 'actions') -----
- plainCursor: aCursor event: anEvent
- 	"Set the cursor to use with this painting action/tool. Offset of the form must be set."
- 
- 	currentCursor := aCursor.
- 	anEvent hand showTemporaryCursor: aCursor.
- 	self notifyWeakDependentsWith: {#currentCursor. anEvent. currentCursor}.!

Item was removed:
- ----- Method: PaintBoxMorph>>recentColor: (in category 'recent colors') -----
- recentColor: aColor 
- 	"Remember the color as one of our recent colors"
- 	Prototype currentColor: aColor.
- 	(recentColors anySatisfy: [:any | any color = aColor])
- 		ifTrue: [^self].	"already remembered"
- 	RecentColors := {aColor}, RecentColors allButLast.
- 	RecentColors keysAndValuesDo: [:i :each |
- 		(recentColors at: i) color: each]!

Item was removed:
- ----- Method: PaintBoxMorph>>ringColor (in category 'actions') -----
- ringColor
- 	"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green"
- 
- 	^self ringColorFor: currentColor
- !

Item was removed:
- ----- Method: PaintBoxMorph>>ringColorFor: (in category 'actions') -----
- ringColorFor: aColor
- 	"Choose a color that contrasts with my current color. If that color isn't redish, return red. Otherwise, return green"
- 
- 	aColor isTransparent ifTrue: [^ Color red].
- 	aColor red < 0.5 ifTrue: [^ Color red].
- 	aColor red > (aColor green + (aColor blue * 0.5))
- 		ifTrue: [^ Color green]
- 		ifFalse: [^ Color red].
- !

Item was removed:
- ----- Method: PaintBoxMorph>>rotationTabForm (in category 'other') -----
- rotationTabForm
- 	^ rotationTabForm!

Item was removed:
- ----- Method: PaintBoxMorph>>scaleTabForm (in category 'other') -----
- scaleTabForm
- 	^ scaleTabForm!

Item was removed:
- ----- Method: PaintBoxMorph>>scrollStamps:action:evt: (in category 'actions') -----
- scrollStamps: actionButton action: aSelector evt: evt
- 	"Move the stamps over"
- 
- 	aSelector == #prevStamp:
- 		ifTrue: [stampHolder scroll: -1]
- 		ifFalse: [stampHolder scroll: 1].
- 	actionButton state: #off.
- 	action == #stamp: ifTrue: ["reselect the stamp and compute the cursor"
- 		self stampForm 
- 			ifNil: [self setAction: #paint: evt: evt]
- 			ifNotNil: [tool doButtonAction: evt]].
- 		!

Item was removed:
- ----- Method: PaintBoxMorph>>setAction:evt: (in category 'actions') -----
- setAction: aSelector evt: evt
- 	"Find this button and turn it on.  Does not work for stamps or pickups"
- 
- 	| button |
- 	button := self submorphNamed: aSelector.
-  
- 	button ifNotNil: [
- 		button state: #on.
- 		button doButtonAction: evt].	"select it!!"!

Item was removed:
- ----- Method: PaintBoxMorph>>showColor (in category 'actions') -----
- showColor
- 	"Display the current color in all brushes, both on and off."
- 
- 	| offIndex onIndex center |
- 	currentColor ifNil: [^self].
- 	"colorPatch color: currentColor.	May delete later"
- 	(brushes isNil or: [brushes first owner ~~ self]) 
- 		ifTrue: 
- 			[brushes := OrderedCollection new.
- 			#(#brush1: #brush2: #brush3: #brush4: #brush5: #brush6:) 
- 				do: [:sel | brushes addLast: (self submorphNamed: sel)]].
- 	brushes last offImage unhibernate.
- 	brushes last onImage unhibernate.
- 	brushes last pressedImage unhibernate.
- 	center := brushes last offImage extent // 2.
- 	offIndex := brushes last offImage pixelValueAt: center.
- 	onIndex := brushes last onImage pixelValueAt: center.
- 	brushes do: 
- 			[:bb | 
- 			bb offImage colors at: offIndex + 1 put: currentColor.
- 			bb offImage clearColormapCache.
- 			bb onImage colors at: onIndex + 1 put: currentColor.
- 			bb onImage clearColormapCache.
- 			bb invalidRect: bb bounds].
- 	self invalidRect: (brushes first topLeft rect: brushes last bottomRight)!

Item was removed:
- ----- Method: PaintBoxMorph>>showColorPalette: (in category 'actions') -----
- showColorPalette: evt
- 
- 	| w box |
- 	self comeToFront.
- 	colorMemory align: colorMemory bounds topRight 
- 			with: colorMemoryThin bounds topRight.
- 	"make sure color memory fits or else align with left"
- 	w := self world.
- 	box := self bounds: colorMemory fullBounds in: w.
- 	box left < 0 ifTrue:[
- 		colorMemory align: colorMemory bounds topLeft
- 			with: colorMemoryThin bounds topLeft].
- 	self addMorphFront: colorMemory.
- 	self changed!

Item was removed:
- ----- Method: PaintBoxMorph>>stampCursorBeCursorFor: (in category 'actions') -----
- stampCursorBeCursorFor: anAction
- 	"User just chose a stamp.  Take that stamp picture and make it be the cursor for the tool named."
- 	"self stampCursorBeCursorFor: #star:.
- 	currentCursor offset: -9 at -3.			Has side effect on the saved cursor."
- 
- 	(self submorphNamed: anAction) arguments at: 3 put: currentCursor.
- 		"Already converted to 8 bits and in the right form"!

Item was removed:
- ----- Method: PaintBoxMorph>>stampDeEmphasize (in category 'actions') -----
- stampDeEmphasize
- 	"Turn off an emphasized stamp.  Was turned on in pickup:action:cursor:"
- 
- 	tool owner class == AlignmentMorph ifTrue: [
- 		tool "actionButton" owner "layoutMorph" color: Color transparent; 
- 					borderColor: Color transparent].!

Item was removed:
- ----- Method: PaintBoxMorph>>stampForm (in category 'actions') -----
- stampForm
- 	"Return the selected stamp"
- 
- 	^ stampHolder stampFormFor: tool.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>stampHolder (in category 'actions') -----
- stampHolder
- 
- 	^ stampHolder!

Item was removed:
- ----- Method: PaintBoxMorph>>stampHolder: (in category 'actions') -----
- stampHolder: newOne
- 
- 	stampHolder := newOne!

Item was removed:
- ----- Method: PaintBoxMorph>>takeColor:event: (in category 'actions') -----
- takeColor: aColor event: evt
- 	"Accept the given color programmatically"
- 	currentColor := aColor.
- 	self notifyWeakDependentsWith: {#currentColor. evt. currentColor}.
- 	self showColor.
- 	self colorable ifFalse: [self setAction: #paint: evt: evt].	"User now thinking of painting"!

Item was removed:
- ----- Method: PaintBoxMorph>>takeColorEvt:from: (in category 'actions') -----
- takeColorEvt: evt from: colorPicker
- 	"Accept a new color from the colorMemory.  Programs use currentColor: instead.  Do not do this before the picker has a chance to set its own color!!"
- 	^self takeColor: colorPicker currentColor event: evt!

Item was removed:
- ----- Method: PaintBoxMorph>>toggleShapes (in category 'actions') -----
- toggleShapes
- 	| tab sh stamps |
- 	"The sub panel that has the shape tools on it.  Rect, line..."
- 	stamps := self submorphNamed: 'stamps'.
- 	tab := self submorphNamed: 'shapeTab'.
- 	(sh := self submorphNamed: 'shapes') visible
- 		ifTrue: [sh hide.  tab top: stamps bottom-1]
- 		ifFalse: [sh comeToFront.  sh top: stamps bottom-9.  
- 				sh show.  tab top: sh bottom - tab height + 10].
- 	self layoutChanged.
- 	self changed
- !

Item was removed:
- ----- Method: PaintBoxMorph>>toggleStamps (in category 'actions') -----
- toggleStamps
- 	| tab otherTab st shapes |
- 	"The sub panel that has the stamps in it.  For saving and moving parts of an image."
- 	shapes := self submorphNamed: 'shapes'.
- 	otherTab := self submorphNamed: 'shapeTab'.
- 	tab := self submorphNamed: 'stampTab'.
- 	(st := self submorphNamed: 'stamps') visible
- 		ifTrue: [st hide.  st bottom: self bottom.  tab top: self bottom-1.
- 				shapes top: self bottom-9.
- 				otherTab top: (shapes visible ifTrue: [shapes bottom - otherTab height + 10] 
- 									ifFalse: [self bottom-1])]
- 		ifFalse: [st top: self bottom-10.  st show.  tab top: st bottom-0.
- 				shapes top: st bottom-9.
- 				otherTab top: (shapes visible ifTrue: [shapes bottom - otherTab height + 10] 
- 									ifFalse: [st bottom-0])].
- 	self layoutChanged.
- 	self changed!

Item was removed:
- ----- Method: PaintBoxMorph>>tool (in category 'actions') -----
- tool
- 	^ tool!

Item was removed:
- ----- Method: PaintBoxMorph>>tool:action:cursor:evt: (in category 'actions') -----
- tool: actionButton action: aSelector cursor: aCursor evt: evt
- 	"Set the current tool and action for the paintBox.  "
- 
- 	tool ifNotNil: [
- 		tool == actionButton ifFalse: [
- 			tool state: #off.
- 			action == #stamp: ifTrue: [self stampDeEmphasize]]].
- 	tool := actionButton.		"A ThreePhaseButtonMorph"
- 	"tool state: #on.	already done"
- 	action := aSelector.		"paint:"
- 	currentCursor := aCursor.
- 	self notifyWeakDependentsWith: {#action. evt. action}.
- 	self notifyWeakDependentsWith: {#currentCursor. evt. currentCursor}.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>toss:with:evt: (in category 'actions') -----
- toss: cancelButton with: cancelSelector evt: evt
- 	"Reject the painting.  Showing noPalette is done by the block submitted to the SketchEditorMorph"
- 
- 	| focus |
- 	owner ifNil: ["it happens"  ^ self].
- 	(focus := self focusMorph) 
- 		ifNotNil: [focus cancelPainting: self evt: evt]
- 		ifNil:
- 			[self delete].
- 	cancelButton state: #off.
- !

Item was removed:
- ----- Method: PaintBoxMorph>>undo:with:evt: (in category 'actions') -----
- undo: undoButton with: undoSelector evt: evt
- 	| ss |
- 	(ss := self focusMorph) 
- 		ifNotNil: [ss undoPainting: self evt: evt]
- 		ifNil: [self notCurrentlyPainting].
- 	undoButton state: #off.!

Item was removed:
- ----- Method: PaintBoxMorph>>updateReferencesUsing: (in category 'copying') -----
- updateReferencesUsing: aDictionary
- 	"Fix up stampHolder which is a ScrollingToolHolder, which is not a Morph"
- 
- 	super updateReferencesUsing: aDictionary.
- 	stampHolder updateReferencesUsing: aDictionary.
- 	colorMemory updateReferencesUsing: aDictionary.!

Item was removed:
- ImageMorph subclass: #PaintInvokingMorph
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Widgets'!
- 
- !PaintInvokingMorph commentStamp: '<historical>' prior: 0!
- When this is dropped inside some appropriate place, then painting is invoked for that place.!

Item was removed:
- ----- Method: PaintInvokingMorph class>>authoringPrototype (in category 'scripting') -----
- authoringPrototype
- 	^ self new image: (ScriptingSystem formAtKey: 'Painting'); markAsPartsDonor; setBalloonText: 'drop this into any playfield or book page to make a new painting there'; yourself!

Item was removed:
- ----- Method: PaintInvokingMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'Paint' translatedNoop
- 		categories:		{'Graphics' translatedNoop}
- 		documentation:	'Drop this icon to start painting a new object.' translatedNoop!

Item was removed:
- ----- Method: PaintInvokingMorph class>>initialize (in category 'class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.!

Item was removed:
- ----- Method: PaintInvokingMorph class>>registerInFlapsRegistry (in category 'class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#PaintInvokingMorph. #new	. 'Paint' translatedNoop. 'Drop this into an area to start making a fresh painting there' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#PaintInvokingMorph. #new. 'Paint' translatedNoop. 'Drop this into an area to start making a fresh painting there' translatedNoop}
- 						forFlapNamed: 'Widgets'.
- 						cl registerQuad: {#PaintInvokingMorph. #new. 'Paint' translatedNoop. 'Drop this into an area to start making a fresh painting there' translatedNoop}
- 						forFlapNamed: 'Scripting']!

Item was removed:
- ----- Method: PaintInvokingMorph class>>unload (in category 'class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: PaintInvokingMorph>>initialize (in category 'initialization') -----
- initialize
- 	super initialize.
- 	self image: (ScriptingSystem formAtKey: 'Painting')!

Item was removed:
- ----- Method: PaintInvokingMorph>>initializeToStandAlone (in category 'parts bin') -----
- initializeToStandAlone
- 	super initializeToStandAlone.
- 	self image: (ScriptingSystem formAtKey: 'Painting')!

Item was removed:
- ----- Method: PaintInvokingMorph>>justDroppedInto:event: (in category 'dropping/grabbing') -----
- justDroppedInto: aPasteUpMorph event: anEvent
- 	"This message is sent to a dropped morph after it has been dropped on--and been accepted by--a drop-sensitive morph"
- 	aPasteUpMorph isPartsBin ifFalse:[
- 		self removeHalo.
- 		self delete.
- 		^aPasteUpMorph makeNewDrawing: anEvent].
- 	^super justDroppedInto: aPasteUpMorph event: anEvent!

Item was removed:
- ----- Method: PaintInvokingMorph>>wantsToBeDroppedInto: (in category 'dropping/grabbing') -----
- wantsToBeDroppedInto: aMorph
- 	"Only into PasteUps that are not part bins"
- 	^aMorph isPlayfieldLike!

Item was removed:
- PasteUpMorph subclass: #PartsBin
- 	instanceVariableNames: ''
- 	classVariableNames: 'Thumbnails'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-PartsBin'!

Item was removed:
- ----- Method: PartsBin class>>cacheAllThumbnails (in category 'thumbnail cache') -----
- cacheAllThumbnails
- 	"In one monster operation, cache all the thumbnails of parts.  Intended to be called from do-its in update postscripts, for example, or manually."
- 
- 	Cursor wait showWhile:
- 		[Morph withAllSubclasses do: [:aClass |
- 			(aClass class includesSelector: #descriptionForPartsBin) ifTrue:
- 				[self thumbnailForPartsDescription: aClass descriptionForPartsBin].
- 			(aClass class includesSelector: #supplementaryPartsDescriptions) ifTrue:
- 				[aClass supplementaryPartsDescriptions do:
- 					[:aDescription | self thumbnailForPartsDescription: aDescription]]]]
- 
- "Time millisecondsToRun: [PartsBin initialize. PartsBin cacheAllThumbnails]"
- !

Item was removed:
- ----- Method: PartsBin class>>cacheThumbnail:forSymbol: (in category 'thumbnail cache') -----
- cacheThumbnail: aThumbnail forSymbol: aSymbol
- 	"Cache the thumbnail provided as the graphic representing a parts-bin denizen whose name is the given symbol"
- 
- 	Thumbnails at: aSymbol put: aThumbnail!

Item was removed:
- ----- Method: PartsBin class>>cleanUp (in category 'class initialization') -----
- cleanUp
- 	"Flush caches"
- 
- 	self clearThumbnailCache!

Item was removed:
- ----- Method: PartsBin class>>clearThumbnailCache (in category 'thumbnail cache') -----
- clearThumbnailCache
- 	"Clear the cache of thumbnails:
- 		PartsBin clearThumbnailCache
- "
- 
- 	Thumbnails := Dictionary new!

Item was removed:
- ----- Method: PartsBin class>>initialize (in category 'class initialization') -----
- initialize
- 	"Initialize the PartsBin class, by starting it out with an empty Thumbnails dictionary"
- 
- 	Thumbnails := Dictionary new
- 	"PartsBin initialize"!

Item was removed:
- ----- Method: PartsBin class>>localeChanged (in category 'class initialization') -----
- localeChanged
- 	self initialize!

Item was removed:
- ----- Method: PartsBin class>>newPartsBinWithOrientation:andColor:from: (in category 'instance creation') -----
- newPartsBinWithOrientation: aListDirection andColor: aColor from: quadList 
- 	"Answer a new PartBin object, to run horizontally or vertically,  
- 	obtaining its elements from the list of tuples of the form:  
- 	(<receiver> <selector> <label> <balloonHelp>)"
- 	^ (self new)
- 		color: aColor;
- 		listDirection: aListDirection quadList: (self translatedQuads: quadList).!

Item was removed:
- ----- Method: PartsBin class>>newPartsBinWithOrientation:from: (in category 'instance creation') -----
- newPartsBinWithOrientation: aListDirection from: quadList 
- 	"Answer a new PartBin object, to run horizontally or vertically,  
- 	obtaining its elements from the list of tuples of the form:  
- 	(<receiver> <selector> <label> <balloonHelp>)"
- 	^ self new
- 		listDirection: aListDirection
- 		quadList: (self translatedQuads: quadList) !

Item was removed:
- ----- Method: PartsBin class>>thumbnailForInstanceOf: (in category 'thumbnail cache') -----
- thumbnailForInstanceOf: aMorphClass
- 	"Answer a thumbnail for a stand-alone instance of the given class, creating it if necessary.  If it is created afresh, it will also be cached at this time"
- 
- 	^ Thumbnails at: aMorphClass name ifAbsent:
- 		[| aThumbnail |
- 		aThumbnail := Thumbnail new makeThumbnailFromForm: aMorphClass newStandAlone imageForm.
- 		self cacheThumbnail: aThumbnail forSymbol: aMorphClass name.
- 		^ aThumbnail]
- 
- "PartsBin initialize"!

Item was removed:
- ----- Method: PartsBin class>>thumbnailForPartsDescription: (in category 'thumbnail cache') -----
- thumbnailForPartsDescription: aPartsDescription
- 	"Answer a thumbnail for the given parts description creating it if necessary.  If it is created afresh, it will also be cached at this time"
- 
- 	| aSymbol |
- 	aSymbol := aPartsDescription formalName asSymbol.
- 	^ Thumbnails at: aSymbol ifAbsent:
- 		[| aThumbnail |
- 		aThumbnail := Thumbnail new makeThumbnailFromForm: aPartsDescription sampleImageForm.
- 		self cacheThumbnail: aThumbnail forSymbol: aSymbol.
- 		^ aThumbnail]
- 
- "PartsBin initialize"!

Item was removed:
- ----- Method: PartsBin class>>thumbnailForQuad: (in category 'thumbnail cache') -----
- thumbnailForQuad: aQuint
- 	"Answer a thumbnail for a morph obtaining as per the quintuplet provided, creating the thumbnail if necessary.  If it is created afresh, it will also be cached at this time"
- 	^self thumbnailForQuad: aQuint color: Color transparent.!

Item was removed:
- ----- Method: PartsBin class>>thumbnailForQuad:color: (in category 'thumbnail cache') -----
- thumbnailForQuad: aQuint color: aColor
- 	"Answer a thumbnail for a morph obtaining as per the quintuplet provided, creating the thumbnail if necessary.  If it is created afresh, it will also be cached at this time"
- 
- 	| aThumbnail aSymbol formToThumbnail labeledItem |
- 	aSymbol := aQuint third.
- 	Thumbnails at: aSymbol ifPresent: [ :thumb | ^thumb ].
- 	formToThumbnail := aQuint at: 5 ifAbsent: [].
- 	formToThumbnail ifNil: [
- 		labeledItem := (Smalltalk at: aQuint first) perform: aQuint second.
- 		formToThumbnail := labeledItem imageForm: 32 backgroundColor: aColor forRectangle: labeledItem fullBounds.
- 		formToThumbnail replaceColor: aColor withColor: Color transparent.
- 		labeledItem delete.
- 	].
- 
- 	aThumbnail := Thumbnail new makeThumbnailFromForm: formToThumbnail.
- 	self cacheThumbnail: aThumbnail forSymbol: aSymbol.
- 	^ aThumbnail
- 
- "PartsBin initialize"!

Item was removed:
- ----- Method: PartsBin class>>translatedQuads: (in category 'private') -----
- translatedQuads: quads
- 	"private - convert the given quads to a translated one"
- 	
- 	| translatedQuads |
- 
- 	translatedQuads := quads collect: [:each |
- 		| element |
- 		element := each copy. 
- 		element at: 3 put: each third translated.
- 		element at: 4 put: each fourth translated.
- 		element.
- 	].
- 
- 	^ translatedQuads
- !

Item was removed:
- ----- Method: PartsBin>>innocuousName (in category 'properties') -----
- innocuousName
- 	"Answer a harmless name for an unnamed instance"
- 
- 	^ 'parts bin' translated!

Item was removed:
- ----- Method: PartsBin>>listDirection:quadList: (in category 'initialization') -----
- listDirection: aListDirection quadList: quadList
- 	"Initialize the receiver to run horizontally or vertically, obtaining its elements from the list of tuples of the form:
- 		(<receiver> <selector> <label> <balloonHelp>)"
- 
- 	^self listDirection: aListDirection quadList: quadList buttonClass: IconicButton!

Item was removed:
- ----- Method: PartsBin>>listDirection:quadList:buttonClass: (in category 'initialization') -----
- listDirection: aListDirection quadList: quadList buttonClass: buttonClass
- 	"Initialize the receiver to run horizontally or vertically, obtaining its elements from the list of tuples of the form:
- 		(<receiver> <selector> <label> <balloonHelp>)
- 	Used by external package Connectors."
- 
- 	self layoutPolicy: TableLayout new.
- 	self listDirection: aListDirection.
- 	self wrapCentering: #topLeft.
- 	self layoutInset: 2.
- 	self cellPositioning: #bottomCenter.
- 
- 	aListDirection == #leftToRight
- 		ifTrue:
- 			[self vResizing: #rigid.
- 			self hResizing: #spaceFill.
- 			self wrapDirection: #topToBottom]
- 		ifFalse:
- 			[self hResizing: #rigid.
- 			self vResizing: #spaceFill.
- 			self wrapDirection: #leftToRight].
- 	quadList do:
- 		[:tuple |
- 			| aButton aClass |
- 			aClass := Smalltalk at: tuple first.
- 			aButton := buttonClass new 
- 				initializeWithThumbnail: (self class thumbnailForQuad: tuple color: self color) 				withLabel: tuple third 
- 				andColor: self color 
- 				andSend: tuple second 
- 				to: aClass.
- 			(tuple size > 3 and: [tuple fourth isEmptyOrNil not]) ifTrue:
- 				[aButton setBalloonText: tuple fourth].
-  			self addMorphBack: aButton]!

Item was removed:
- ----- Method: PartsBin>>morphToDropFrom: (in category 'dropping/grabbing') -----
- morphToDropFrom: aMorph
- 	"Answer the morph to drop if the user attempts to drop aMorph"
- 
- 	| aButton |
- 	((aMorph isKindOf: IconicButton) and: [aMorph actionSelector == #launchPartVia:label:])
- 		ifTrue: [^ aMorph].  
- 	"The above handles the unusual case of a button that's already set up in a manner suitable for living in PartsBin; the archetypal example is the attempt to reposition an object within a partsflap by dragging it via the black halo handle."
- 
- 	aButton := IconicButton new.
- 	aButton color: self color;
- 		initializeToShow: aMorph withLabel: aMorph externalName andSend: #veryDeepCopy to: aMorph veryDeepCopy.
- 	^ aButton!

Item was removed:
- ----- Method: PartsBin>>wantsDroppedMorph:event: (in category 'dropping/grabbing') -----
- wantsDroppedMorph: aMorph event: evt
- 	"Answer whether the receiver would like to accept the given morph.  For a Parts bin, we accept just about anything except something that just originated from ourselves"
- 
- 	(aMorph hasProperty: #beFullyVisibleAfterDrop) ifTrue:
- 		[^ true].
- 
- 	^ super wantsDroppedMorph: aMorph event: evt!

Item was removed:
- ----- Method: PartsBin>>wantsEasySelection (in category 'event handling') -----
- wantsEasySelection
- 	"Answer if the receiver want easy selection mode"
- 	^ false!

Item was removed:
- ----- Method: PasteUpMorph class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 	"Initialize the class"
- 
- 	#('keyStroke') translatedNoop.
- 
- 	self registerInFlapsRegistry.	
- 	ScriptingSystem addCustomEventFor: self named: #keyStroke help: 'when a keystroke happens and nobody heard it' translatedNoop targetMorphClass: PasteUpMorph.!

Item was removed:
- ----- Method: PasteUpMorph class>>newWorldTesting (in category '*MorphicExtras-project') -----
- newWorldTesting
- 
- 	| world ex |
- 
- 	ex := 500 at 500.
- 	world := PasteUpMorph newWorldForProject: nil.
- 	world extent: ex; color: Color orange.
- 	world openInWorld.
- 	BouncingAtomsMorph new openInWorld: world.
- 
- "-----
- 
- 	| world window |
- 	world := PasteUpMorph newWorldForProject: nil.
- 	world extent: 300 at 300; color: Color orange.
- 	world viewBox: (0 at 0 extent: 300 at 300).
- 	window := (SystemWindow labelled: 'the new world') model: world.
- 	window color: Color orange.
- 	window addMorph: world frame: (0 at 0 extent: 1.0 at 1.0).
- 	window openInWorld.
- 
- ---"
- !

Item was removed:
- ----- Method: PasteUpMorph class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#PasteUpMorph. #authoringPrototype. 'Playfield'	 translatedNoop. 'A place for assembling parts or for staging animations' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#PasteUpMorph. #authoringPrototype. 'Playfield' translatedNoop. 'A place for assembling parts or for staging animations' translatedNoop}
- 						forFlapNamed: 'Supplies'.
- 						cl registerQuad: {#PasteUpMorph. #authoringPrototype. 'Playfield' translatedNoop. 'A place for assembling parts or for staging animations' translatedNoop}
- 						forFlapNamed: 'Scripting']!

Item was removed:
- ----- Method: PasteUpMorph class>>supplementaryPartsDescriptions (in category '*MorphicExtras-parts bin') -----
- supplementaryPartsDescriptions
- 	^ {DescriptionForPartsBin
- 		formalName: 'Holder' translatedNoop
- 		categoryList: {'Scripting' translatedNoop}
- 		documentation: 'A place for storing alternative pictures in an animation, ec.' translatedNoop
- 		globalReceiverSymbol: #ScriptingSystem
- 		nativitySelector: #prototypicalHolder}!

Item was removed:
- ----- Method: PasteUpMorph class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: PasteUpMorph>>deleteAllFlapArtifacts (in category '*MorphicExtras-flaps') -----
- deleteAllFlapArtifacts
- 	"self currentWorld deleteAllFlapArtifacts"
- 
- 	self submorphs do:[:m | m wantsToBeTopmost ifTrue:[m delete]].!

Item was removed:
- ----- Method: PasteUpMorph>>roundUpStrays (in category '*MorphicExtras-misc') -----
- roundUpStrays
- 	self submorphs
- 		reject: [:each | each wantsToBeTopmost]
- 		thenDo: [:each | each goHome].
- 	super roundUpStrays!

Item was removed:
- RectangleMorph subclass: #PianoKeyboardMorph
- 	instanceVariableNames: 'whiteKeyColor blackKeyColor playingKeyColor nOctaves target noteOnSelector noteOffSelector soundPrototype soundPlaying'
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!

Item was removed:
- ----- Method: PianoKeyboardMorph class>>descriptionForPartsBin (in category 'parts bin') -----
- descriptionForPartsBin
- 	^ self partName:	'PianoKeyboard' translatedNoop
- 		categories:		{'Multimedia' translatedNoop}
- 		documentation:	'A piano keyboard' translatedNoop!

Item was removed:
- ----- Method: PianoKeyboardMorph>>basicMouseDownPitch: (in category 'simple keyboard') -----
- basicMouseDownPitch: midiKey
- 
- 	| pitch |
- 	pitch := AbstractSound pitchForMIDIKey: midiKey + 23.
- 	soundPlaying ifNotNil: [soundPlaying stopGracefully].
- 	soundPlaying := soundPrototype soundForPitch: pitch dur: 100.0 loudness: 0.3.
- 	SoundPlayer resumePlaying: soundPlaying quickStart: true.!

Item was removed:
- ----- Method: PianoKeyboardMorph>>basicMouseUpPitch: (in category 'simple keyboard') -----
- basicMouseUpPitch: pitch
- 
- 	soundPlaying ifNotNil: [soundPlaying stopGracefully].!

Item was removed:
- ----- Method: PianoKeyboardMorph>>buildKeyboard (in category 'simple keyboard') -----
- buildKeyboard
- 	| wtWid bkWid keyRect octavePt nWhite nBlack |
- 	self removeAllMorphs.
- 	wtWid := 8. bkWid := 5.
- 	self extent: 10 @ 10.
- 	1 to: nOctaves + 1 do:
- 		[:i | i <= nOctaves ifTrue: [nWhite := 7.  nBlack := 5]
- 						ifFalse: [nWhite := 1.  nBlack := 0 "High C"].
- 		octavePt := self innerBounds topLeft + ((7 * wtWid * (i - 1) - 1) @ -1).
- 		1 to: nWhite do:
- 			[:j | keyRect := octavePt + (j - 1 * wtWid @ 0) extent: (wtWid + 1) @ 36.
- 			self addMorph: ((RectangleMorph newBounds: keyRect color: whiteKeyColor)
- 								borderWidth: 1;
- 				on: #mouseDown send: #mouseDownPitch:event:noteMorph: to: self
- 								withValue: i - 1 * 12 + (#(1 3 5 6 8 10 12) at: j))].
- 		1 to: nBlack do:
- 			[:j | keyRect := octavePt + ((#(6 15 29 38 47) at: j) @ 1) extent: bkWid @ 21.
- 			self addMorph: ((Morph newBounds: keyRect color: blackKeyColor)
- 				on: #mouseDown send: #mouseDownPitch:event:noteMorph: to: self
- 								withValue: i - 1 * 12 + (#(2 4 7 9 11) at: j))]].
- 	self submorphsDo:
- 		[:m | m on: #mouseMove send: #mouseMovePitch:event:noteMorph: to: self;
- 				on: #mouseUp send: #mouseUpPitch:event:noteMorph: to: self;
- 				on: #mouseEnterDragging send: #mouseDownPitch:event:noteMorph: to: self;
- 				on: #mouseLeaveDragging send: #mouseUpPitch:event:noteMorph: to: self].
- 	self extent: (self fullBounds extent + self borderWidth - 1)!

Item was removed:
- ----- Method: PianoKeyboardMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color veryLightGray!

Item was removed:
- ----- Method: PianoKeyboardMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 
- 	whiteKeyColor := Color gray: 0.95.
- 	blackKeyColor := Color black.
- 	playingKeyColor := Color red.
- 	nOctaves := 6.
- 	self buildKeyboard.
- 	soundPrototype := FMSound new.!

Item was removed:
- ----- Method: PianoKeyboardMorph>>initializeToStandAlone (in category 'initialization') -----
- initializeToStandAlone
- 
- 	super initializeToStandAlone.
- 	soundPrototype := FMSound brass1 duration: 9.9.!

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseDownEvent:noteMorph:pitch: (in category 'simple keyboard') -----
- mouseDownEvent: arg1 noteMorph: arg2 pitch: arg3
- 	"Reorder the arguments for existing event handlers"
- 	(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].
- 	^self mouseDownPitch: arg1 event: arg2 noteMorph: arg3!

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseDownPitch:event:noteMorph: (in category 'simple keyboard') -----
- mouseDownPitch: midiKey event: event noteMorph: noteMorph
- 
- 	event redButtonPressed ifFalse: [^ self].
- 	event hand hasSubmorphs ifTrue: [^ self  "no response if drag something over me"].
- 	event hand mouseFocus ifNil:
- 		["If dragged into me, then establish focus so I'll see moves"
- 		event hand newMouseFocus: noteMorph event: event].
- 	
- 	noteMorph color: playingKeyColor.
- 	
- 	self basicMouseDownPitch: midiKey.!

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseMoveEvent:noteMorph:pitch: (in category 'simple keyboard') -----
- mouseMoveEvent: arg1 noteMorph: arg2 pitch: arg3
- 	"Reorder the arguments for existing event handlers"
- 	(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].
- 	^self mouseMovePitch: arg1 event: arg2 noteMorph: arg3!

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseMovePitch:event:noteMorph: (in category 'simple keyboard') -----
- mouseMovePitch: pitch event: event noteMorph: noteMorph
- 
- 	(noteMorph containsPoint: event cursorPoint) ifFalse:
- 		["If drag out of me, zap focus so other morphs can see drag in."
- 		event hand releaseMouseFocus: noteMorph]
- !

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseUpEvent:noteMorph:pitch: (in category 'simple keyboard') -----
- mouseUpEvent: arg1 noteMorph: arg2 pitch: arg3
- 	"Reorder the arguments for existing event handlers"
- 	(arg3 isMorph and:[arg3 eventHandler notNil]) ifTrue:[arg3 eventHandler fixReversedValueMessages].
- 	^self mouseUpPitch: arg1 event: arg2 noteMorph: arg3!

Item was removed:
- ----- Method: PianoKeyboardMorph>>mouseUpPitch:event:noteMorph: (in category 'simple keyboard') -----
- mouseUpPitch: pitch event: event noteMorph: noteMorph
- 
- 	noteMorph color: ((#(0 1 3 5 6 8 10) includes: pitch \\ 12)
- 		ifTrue: [whiteKeyColor]
- 		ifFalse: [blackKeyColor]).
- 	
- 	self basicMouseUpPitch: pitch.!

Item was removed:
- ----- Method: PianoKeyboardMorph>>soundPrototype: (in category 'simple keyboard') -----
- soundPrototype: aSound
- 	soundPrototype := aSound!

Item was removed:
- Morph subclass: #PianoRollNoteMorph
- 	instanceVariableNames: 'trackIndex indexInTrack hitLoc editMode selected notePlaying'
- 	classVariableNames: 'SoundPlaying'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!
- 
- !PianoRollNoteMorph commentStamp: '<historical>' prior: 0!
- A PianoRollNoteMorph is drawn as a simple mroph, but it carries the necessary state to locate its source sound event via its owner (a PianorRollScoreMorph) and the score therein.  Simple editing of pitch and time placement is provided here.!

Item was removed:
- ----- Method: PianoRollNoteMorph>>deselect (in category 'selecting') -----
- deselect
- 
- 	selected ifFalse: [^ self].
- 	self changed.
- 	selected := false.
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	selected
- 		ifTrue: [aCanvas frameAndFillRectangle: self fullBounds fillColor: color borderWidth: 1 borderColor: Color black]
- 		ifFalse: [aCanvas fillRectangle: self bounds color: color].
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>editPitch: (in category 'editing') -----
- editPitch: evt
- 
- 	| mk note |
- 	mk := owner midiKeyForY: evt cursorPoint y.
- 	note := (owner score tracks at: trackIndex) at: indexInTrack.
- 	note midiKey = mk ifTrue: [^ self].
- 	note midiKey: mk.
- 	self playSound: (self soundOfDuration: 999.0).
- 	self position: self position x @ ((owner yForMidiKey: mk) - 1)
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>fullBounds (in category 'layout') -----
- fullBounds
- 
- 	selected
- 		ifTrue: [^ bounds expandBy: 1]
- 		ifFalse: [^ bounds]!

Item was removed:
- ----- Method: PianoRollNoteMorph>>gridToNextQuarter (in category 'editing') -----
- gridToNextQuarter
- 
- 	owner score gridTrack: trackIndex toQuarter: 1 at: indexInTrack.
- 	owner rebuildFromScore!

Item was removed:
- ----- Method: PianoRollNoteMorph>>gridToPrevQuarter (in category 'editing') -----
- gridToPrevQuarter
- 
- 	owner score gridTrack: trackIndex toQuarter: -1 at: indexInTrack.
- 	owner rebuildFromScore!

Item was removed:
- ----- Method: PianoRollNoteMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	^ owner scorePlayer isPlaying not!

Item was removed:
- ----- Method: PianoRollNoteMorph>>indexInTrack (in category 'accessing') -----
- indexInTrack
- 
- 	^ indexInTrack!

Item was removed:
- ----- Method: PianoRollNoteMorph>>invokeNoteMenu: (in category 'menu') -----
- invokeNoteMenu: evt
- 	"Invoke the note's edit menu."
- 
- 	| menu |
- 	menu := MenuMorph new defaultTarget: self.
- 	menu addList:
- 		#(('grid to next quarter'		gridToNextQuarter)
- 		('grid to prev quarter'		gridToPrevQuarter)).
- 
- 	menu popUpEvent: evt in: self world.
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 
- 	hitLoc := evt cursorPoint.
- 	editMode := nil.
- 	owner submorphsDo:
- 		[:m | (m isKindOf: PianoRollNoteMorph) ifTrue: [m deselect]].
- 	selected := true.
- 	self changed. 
- 	owner changed.
- 	owner selection: (Array with: trackIndex with: indexInTrack with: indexInTrack).
- 	self playSound!

Item was removed:
- ----- Method: PianoRollNoteMorph>>mouseMove: (in category 'event handling') -----
- mouseMove: evt 
- 	| delta offsetEvt |
- 	editMode isNil 
- 		ifTrue: 
- 			["First movement determines edit mode"
- 
- 			((delta := evt cursorPoint - hitLoc) dist: 0 @ 0) <= 2 
- 				ifTrue: [^self	"No significant movement yet."].
- 			delta x abs > delta y abs 
- 				ifTrue: 
- 					[delta x > 0 
- 						ifTrue: 
- 							["Horizontal drag"
- 
- 							editMode := #selectNotes]
- 						ifFalse: 
- 							[self playSound: nil.
- 							offsetEvt := evt copy translateBy:(20 @ 0).
- 							self invokeNoteMenu: offsetEvt]]
- 				ifFalse: [editMode := #editPitch	"Vertical drag"]].
- 	editMode == #editPitch ifTrue: [self editPitch: evt].
- 	editMode == #selectNotes ifTrue: [self selectNotes: evt]!

Item was removed:
- ----- Method: PianoRollNoteMorph>>mouseUp: (in category 'event handling') -----
- mouseUp: evt
- 
- 	self playSound: nil!

Item was removed:
- ----- Method: PianoRollNoteMorph>>noteInScore (in category 'note playing') -----
- noteInScore
- 
- 	^ (owner score tracks at: trackIndex) at: indexInTrack
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>noteOfDuration: (in category 'note playing') -----
- noteOfDuration: duration
- 
- 	| note |
- 	note := self noteInScore.
- 	^ (owner scorePlayer instrumentForTrack: trackIndex)
- 			soundForMidiKey: note midiKey
- 			dur: duration
- 			loudness: (note velocity asFloat / 127.0)
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>playSound (in category 'note playing') -----
- playSound
- 	"This STARTS a single long sound.  It must be stopped by playing another or nil."
- 
- 	^ self playSound: (self soundOfDuration: 999.0)!

Item was removed:
- ----- Method: PianoRollNoteMorph>>playSound: (in category 'note playing') -----
- playSound: aSoundOrNil
- 
- 	SoundPlaying ifNotNil: [SoundPlaying stopGracefully].
- 	SoundPlaying := aSoundOrNil.
- 	SoundPlaying ifNotNil: [SoundPlaying play].!

Item was removed:
- ----- Method: PianoRollNoteMorph>>select (in category 'selecting') -----
- select
- 
- 	selected ifTrue: [^ self].
- 	selected := true.
- 	self changed!

Item was removed:
- ----- Method: PianoRollNoteMorph>>selectFrom: (in category 'selecting') -----
- selectFrom: selection 
- 	(trackIndex = selection first and: 
- 			[indexInTrack >= (selection second) and: [indexInTrack <= (selection third)]]) 
- 		ifTrue: [selected ifFalse: [self select]]
- 		ifFalse: [selected ifTrue: [self deselect]]!

Item was removed:
- ----- Method: PianoRollNoteMorph>>selectNotes: (in category 'selecting') -----
- selectNotes: evt
- 
- 	| lastMorph oldEnd saveOwner |
- 	
- 	saveOwner := owner.
- 	(owner autoScrollForX: evt cursorPoint x) ifTrue:
- 		["If scroll talkes place I will be deleted and my x-pos will become invalid."
- 		owner := saveOwner.
- 		bounds := bounds withLeft: (owner xForTime: self noteInScore time)].
- 	oldEnd := owner selection last.
- 	(owner notesInRect: (evt cursorPoint x @ owner top corner: owner bottomRight))
- 		do: [:m | m trackIndex = trackIndex ifTrue: [m deselect]].
- 	self select.  
- 	lastMorph := self.
- 	(owner notesInRect: (self left @ owner top corner: evt cursorPoint x @ owner bottom))
- 		do: [:m | m trackIndex = trackIndex ifTrue: [m select.  lastMorph := m]].
- 	owner selection: (Array with: trackIndex with: indexInTrack with: lastMorph indexInTrack).
- 	lastMorph indexInTrack ~= oldEnd ifTrue:
- 		["Play last note as selection grows or shrinks"
- 		owner ifNotNil: [lastMorph playSound]].
- 	owner changed.
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>selected (in category 'selecting') -----
- selected
- 
- 	^ selected!

Item was removed:
- ----- Method: PianoRollNoteMorph>>soundOfDuration: (in category 'note playing') -----
- soundOfDuration: duration
- 
- 	| sound |
- 	sound := MixedSound new.
- 	sound add: (self noteOfDuration: duration)
- 		pan: (owner scorePlayer panForTrack: trackIndex)
- 		volume: owner scorePlayer overallVolume *
- 				(owner scorePlayer volumeForTrack: trackIndex).
- 	^ sound reset
- !

Item was removed:
- ----- Method: PianoRollNoteMorph>>trackIndex (in category 'accessing') -----
- trackIndex
- 
- 	^ trackIndex!

Item was removed:
- ----- Method: PianoRollNoteMorph>>trackIndex:indexInTrack: (in category 'initialization') -----
- trackIndex: ti indexInTrack: i
- 
- 	trackIndex := ti.
- 	indexInTrack := i.
- 	selected := false!

Item was removed:
- RectangleMorph subclass: #PianoRollScoreMorph
- 	instanceVariableNames: 'scorePlayer score colorForTrack lowestNote leftEdgeTime timeScale indexInTrack lastUpdateTick lastMutedState cursor selection timeSignature beatsPerMeasure notePerBeat showMeasureLines showBeatLines soundsPlaying soundsPlayingMorph movieClipPlayer'
- 	classVariableNames: 'NotePasteBuffer'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-SoundInterface'!
- 
- !PianoRollScoreMorph commentStamp: '<historical>' prior: 0!
- A PianoRollScoreMorph displays a score such as a MIDIScore, and will scroll through it tracking the progress of a ScorePlayerMorph (from which it is usually spawned).
- 
- timeScale is in pixels per score tick.
- 
- Currently the ambient track (for synchronizing thumbnails, eg) is treated specially here and in the score.  This should be cleaned up by adding a trackType or something like it in the score.!

Item was removed:
- ----- Method: PianoRollScoreMorph>>acceptDroppingMorph:event: (in category 'layout') -----
- acceptDroppingMorph: aMorph event: evt
- 	"In addition to placing this morph in the pianoRoll, add a corresponding
- 	event to the score so that it will always appear when played, in addition
- 	to possibly triggering other actions"
- 
- 	aMorph justDroppedIntoPianoRoll: self event: evt.
- 	super acceptDroppingMorph: aMorph event: evt.
- 
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>addCustomMenuItems:hand: (in category 'menu') -----
- addCustomMenuItems: aMenu hand: aHandMorph
- 
- 	super addCustomMenuItems: aMenu hand: aHandMorph.
- 	aMenu add: 'expand time' translated action: #expandTime.
- 	aMenu add: 'contract time' translated action: #contractTime.
- 	aMenu addLine.
- 	aMenu add: 'add movie clip player' translated action: #addMovieClipPlayer.
- 	(self valueOfProperty: #dragNDropEnabled) == true
- 		ifTrue: [aMenu add: 'close drag and drop' translated action: #disableDragNDrop]
- 		ifFalse: [aMenu add: 'open drag and drop' translated action: #enableDragNDrop].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>addKeyboard (in category 'menu') -----
- addKeyboard
- 
- 	(KeyboardMorphForInput new pianoRoll: self) openInWorld!

Item was removed:
- ----- Method: PianoRollScoreMorph>>addNotes (in category 'drawing') -----
- addNotes
- 	"Recompute the set of morphs that should be visible at the current scroll position."
- 
- 	| visibleMorphs rightEdge topEdge rightEdgeTime |
- 	visibleMorphs := OrderedCollection new: 500.
- 	rightEdge := self right - self borderWidth.
- 	rightEdgeTime := self timeForX: rightEdge.
- 	topEdge := self top + self borderWidth + 1.
- 
- 	"Add ambient morphs first (they will be front-most)"
- 	score eventMorphsWithTimeDo:
- 		[:m :t | m addMorphsTo: visibleMorphs pianoRoll: self eventTime: t
- 					betweenTime: leftEdgeTime and: rightEdgeTime].
- 
- 	"Then add note morphs"
- 	score tracks withIndexDo:
- 		[:track :trackIndex | | done n i nRight nTop nLeft trackColor |
- 		trackColor := colorForTrack at: trackIndex.
- 		i := indexInTrack at: trackIndex.
- 		done := scorePlayer mutedForTrack: trackIndex.
- 		[done | (i > track size)] whileFalse: [
- 			n := track at: i.
- 			(n isNoteEvent and: [n midiKey >= lowestNote]) ifTrue: [
- 				n time > rightEdgeTime
- 					ifTrue: [done := true]
- 					ifFalse: [
- 						nLeft := self xForTime: n time.
- 						nTop := (self yForMidiKey: n midiKey) - 1.
- 						nTop > topEdge ifTrue: [
- 							nRight := nLeft + (n duration * timeScale) truncated - 1.
- 							visibleMorphs add:
- 								((PianoRollNoteMorph
- 									newBounds: (nLeft at nTop corner: nRight@(nTop + 3))
- 									color: trackColor)
- 									trackIndex: trackIndex indexInTrack: i)]]].
- 			i := i + 1].
- 			(selection notNil
- 				and: [trackIndex = selection first
- 				and: [i >= selection second and: [(indexInTrack at: trackIndex) <= selection third]]])
- 				ifTrue: [visibleMorphs do:
- 						[:vm | (vm isKindOf: PianoRollNoteMorph) ifTrue: [vm selectFrom: selection]]]].
- 
- 	"Add the cursor morph in front of all notes; height and position are set later."
- 	cursor ifNil: [cursor := Morph newBounds: (self topLeft extent: 1 at 1) color: Color red].
- 	visibleMorphs addFirst: cursor.
- 
- 	self changed.
- 	self removeAllMorphs.
- 	self addAllMorphs: visibleMorphs.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>appendEvent:fullDuration: (in category 'editing') -----
- appendEvent: noteEvent fullDuration: fullDuration 
- 
- 	| sel x |
- 	score appendEvent: noteEvent fullDuration: fullDuration at: (sel := self selection).
- 	noteEvent midiKey = -1 ifFalse:  "Unless it is a rest..."
- 		["Advance the selection to the note just entered"
- 		selection := Array with: sel first with: sel third + 1 with: sel third + 1].
- 
- 	"This is all horribly inefficient..."
- 	scorePlayer updateDuration.
- 	(x := self xForTime: noteEvent endTime) > (self right - 30) ifTrue:
- 		[self autoScrollForX: x + (30 + self width // 4)].
- 	self updateLowestNote.
- 	self rebuildFromScore!

Item was removed:
- ----- Method: PianoRollScoreMorph>>autoScrollForX: (in category 'scrolling') -----
- autoScrollForX: x
- 	"Scroll by the amount x lies outside of my innerBounds.  Return true if this happens."
- 
- 	| d ticks |
- 	((d := x - self innerBounds right) > 0
- 		or: [(d := x - self innerBounds left) < 0])
- 		ifTrue: [ticks := (self timeForX: self bounds center x + d+1)
- 						min: score durationInTicks max: 0.
- 				self moveCursorToTime: ticks.
- 				scorePlayer ticksSinceStart: ticks.
- 				^ true].
- 	^ false
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>beatLinesOnOff (in category 'menu') -----
- beatLinesOnOff
- 
- 	showBeatLines := showBeatLines not.
- 	self changed!

Item was removed:
- ----- Method: PianoRollScoreMorph>>beatsPerMeasure: (in category 'accessing') -----
- beatsPerMeasure: n
- 
- 	^ self timeSignature: n over: notePerBeat!

Item was removed:
- ----- Method: PianoRollScoreMorph>>contractTime (in category 'geometry') -----
- contractTime
- 
- 	timeScale := timeScale / 1.5.
- 	self rebuildFromScore.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>copySelection (in category 'editing') -----
- copySelection
- 	selection isNil ifTrue: [^self].
- 	NotePasteBuffer := (score tracks at: selection first) 
- 				copyFrom: selection second
- 				to: selection third!

Item was removed:
- ----- Method: PianoRollScoreMorph>>cutSelection (in category 'editing') -----
- cutSelection
- 	selection isNil ifTrue: [^self].
- 	self copySelection.
- 	self deleteSelection!

Item was removed:
- ----- Method: PianoRollScoreMorph>>defaultBorderWidth (in category 'initialization') -----
- defaultBorderWidth
- 	"answer the default border width for the receiver"
- 	^ 1!

Item was removed:
- ----- Method: PianoRollScoreMorph>>defaultColor (in category 'initialization') -----
- defaultColor
- 	"answer the default color/fill style for the receiver"
- 	^ Color white!

Item was removed:
- ----- Method: PianoRollScoreMorph>>deleteSelection (in category 'editing') -----
- deleteSelection
- 	| selMorphs priorEvent x |
- 	(selection isNil or: [selection second = 0]) ifTrue: [^self].
- 	score cutSelection: selection.
- 	selection second > 1 
- 		ifTrue: 
- 			[selection at: 2 put: selection second - 1.
- 			selection at: 3 put: selection second.
- 			priorEvent := (score tracks at: selection first) at: selection second.
- 			(x := self xForTime: priorEvent time) < (self left + 30) 
- 				ifTrue: [self autoScrollForX: x - ((30 + self width) // 4)]]
- 		ifFalse: [selection := nil].
- 	scorePlayer updateDuration.
- 	self rebuildFromScore.
- 	selMorphs := self 
- 				submorphsSatisfying: [:m | (m isKindOf: PianoRollNoteMorph) and: [m selected]].
- 	selMorphs isEmpty ifFalse: [(selMorphs last soundOfDuration: 0.3) play]!

Item was removed:
- ----- Method: PianoRollScoreMorph>>drawMeasureLinesOn: (in category 'drawing') -----
- drawMeasureLinesOn: aCanvas
- 
- 	| ticksPerMeas x measureLineColor inner |
- 	showBeatLines ifNil: [showBeatLines := false].
- 	showMeasureLines ifNil: [showMeasureLines := true].
- 	notePerBeat ifNil: [self timeSignature: 4 over: 4].
- 	showBeatLines ifTrue:
- 		[measureLineColor := Color gray: 0.8.
- 		ticksPerMeas := score ticksPerQuarterNote.
- 		inner := self innerBounds.
- 		(leftEdgeTime + ticksPerMeas truncateTo: ticksPerMeas)
- 			to: ((self timeForX: self right - self borderWidth) truncateTo: ticksPerMeas)
- 			by: ticksPerMeas
- 			do: [:tickTime | x := self xForTime: tickTime.
- 				aCanvas fillRectangle: (x @ inner top extent: 1 @ inner height)
- 					color: measureLineColor]].
- 
- 	showMeasureLines ifTrue:
- 		[measureLineColor := Color gray: 0.7.
- 		ticksPerMeas := beatsPerMeasure*score ticksPerQuarterNote*4//notePerBeat.
- 		inner := self innerBounds.
- 		(leftEdgeTime + ticksPerMeas truncateTo: ticksPerMeas)
- 			to: ((self timeForX: self right - self borderWidth) truncateTo: ticksPerMeas)
- 			by: ticksPerMeas
- 			do: [:tickTime | x := self xForTime: tickTime.
- 				aCanvas fillRectangle: (x @ inner top extent: 1 @ inner height)
- 						color: (tickTime = 0 ifTrue: [Color black] ifFalse: [measureLineColor])]].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>drawOn: (in category 'drawing') -----
- drawOn: aCanvas
- 
- 	super drawOn: aCanvas.
- 	self drawStaffOn: aCanvas.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>drawStaffOn: (in category 'drawing') -----
- drawStaffOn: aCanvas
- 
- 	| blackKeyColor l r topEdge y |
- 	self drawMeasureLinesOn: aCanvas.
- 
- 	blackKeyColor := Color gray: 0.5.
- 	l := self left + self borderWidth.
- 	r := self right - self borderWidth.
- 	topEdge := self top + self borderWidth + 3.
- 	lowestNote to: 127 do: [:k |
- 		y := self yForMidiKey: k.
- 		y <= topEdge ifTrue: [^ self].  "over the top!!"
- 		(self isBlackKey: k) ifTrue: [
- 			aCanvas
- 				fillRectangle: (l at y corner: r@(y + 1))
- 				color: blackKeyColor]].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>expandTime (in category 'geometry') -----
- expandTime
- 
- 	timeScale := timeScale * 1.5.
- 	self rebuildFromScore.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>extent: (in category 'geometry') -----
- extent: aPoint
- 	"Force rebuild when re-sized."
- 
- 	super extent: aPoint. 
- 	score ifNotNil: [self updateLowestNote].
- 	self rebuildFromScore.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>fullBounds (in category 'layout') -----
- fullBounds
- 	"Overridden to clip submorph hit detection to my bounds."
- 
- 	fullBounds ifNil: [fullBounds := bounds].
- 	^ bounds
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>goToTime: (in category 'scrolling') -----
- goToTime: scoreTime
- 
- 	| track trackSize index newLeftEdgeTime |
- 	newLeftEdgeTime := scoreTime asInteger.
- 	newLeftEdgeTime < leftEdgeTime
- 		ifTrue: [indexInTrack := Array new: score tracks size+1 withAll: 1].
- 	leftEdgeTime := newLeftEdgeTime.
- 	1 to: score tracks size do: [:trackIndex |
- 		track := score tracks at: trackIndex.
- 		index := indexInTrack at: trackIndex.
- 		trackSize := track size.
- 		[(index < trackSize) and:
- 		 [(track at: index) endTime < leftEdgeTime]]
- 			whileTrue: [index := index + 1].
- 		indexInTrack at: trackIndex put: index].
- 	self addNotes.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>handlesMouseDown: (in category 'event handling') -----
- handlesMouseDown: evt
- 
- 	^ true!

Item was removed:
- ----- Method: PianoRollScoreMorph>>initialize (in category 'initialization') -----
- initialize
- 	"initialize the state of the receiver"
- 	super initialize.
- 	""
- 	
- 	self extent: 400 @ 300.
- 	showMeasureLines := true.
- 	showBeatLines := false.
- 	self timeSignature: 4 over: 4.
- 	self clipSubmorphs: true!

Item was removed:
- ----- Method: PianoRollScoreMorph>>insertSelection (in category 'editing') -----
- insertSelection
- 	self selection isNil ifTrue: [^self].
- 	score insertEvents: NotePasteBuffer at: self selection.
- 	scorePlayer updateDuration.
- 	self rebuildFromScore!

Item was removed:
- ----- Method: PianoRollScoreMorph>>insertTransposed (in category 'editing') -----
- insertTransposed
- 	| delta transposedNotes |
- 	(delta := UIManager default 
- 		chooseFrom: ((12 to: -12 by: -1) collect: [:i | i printString])
- 		values: ((12 to: -12 by: -1) collect: [:i | i printString])
- 		title: 'offset...') ifNil: [^self].
- 	transposedNotes := NotePasteBuffer 
- 				collect: [:note | note copy midiKey: note midiKey + delta].
- 	selection isNil ifTrue: [^self].
- 	score insertEvents: transposedNotes at: self selection.
- 	scorePlayer updateDuration.
- 	self rebuildFromScore!

Item was removed:
- ----- Method: PianoRollScoreMorph>>invokeScoreMenu: (in category 'menu') -----
- invokeScoreMenu: evt
- 	"Invoke the score's edit menu."
- 
- 	| menu subMenu |
- 	menu := MenuMorph new defaultTarget: self.
- 	menu addList:
- 		{{'cut' translated.		#cutSelection}.
- 		{'copy' translated.		#copySelection}.
- 		{'paste' translated.		#insertSelection}.
- 		{'paste...' translated.		#insertTransposed}}.
- 	menu addLine.
- 	menu addList:
- 		{{'legato' translated.		#selectionBeLegato}.
- 		{'staccato' translated.	#selectionBeStaccato}.
- 		{'normal' translated.		#selectionBeNormal}}.
- 	menu addLine.
- 	menu addList:
- 		{{'expand time' translated.		#expandTime}.
- 		{'contract time' translated.		#contractTime}}.
- 	menu addLine.
- 	subMenu := MenuMorph new defaultTarget: self.
- 		(2 to: 12) do: [:i | subMenu add: i printString selector: #beatsPerMeasure: argument: i].
- 		menu add: 'time   ' translated, beatsPerMeasure printString subMenu: subMenu.
- 	subMenu := MenuMorph new defaultTarget: self.
- 		#(2 4 8) do: [:i | subMenu add: i printString selector: #notePerBeat: argument: i].
- 		menu add: 'sig     ' translated, notePerBeat printString subMenu: subMenu.
- 	menu addLine.
- 	showMeasureLines
- 		ifTrue: [menu add: 'hide measure lines' translated action: #measureLinesOnOff]
- 		ifFalse: [menu add: 'show measure lines' translated action: #measureLinesOnOff].
- 	showBeatLines
- 		ifTrue: [menu add: 'hide beat lines' translated action: #beatLinesOnOff]
- 		ifFalse: [menu add: 'show beat lines' translated action: #beatLinesOnOff].
- 
- 	menu addLine.
- 	menu add: 'add keyboard' translated action: #addKeyboard.
- 
- 	menu popUpEvent: evt in: self world.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>isBlackKey: (in category 'drawing') -----
- isBlackKey: midiKey
- 	"Answer true if the given MIDI key corresponds to a black key on the piano keyboard."
- 
- 	| note |
- 	note := midiKey \\ 12.
- 	note = 1 ifTrue: [^ true].
- 	note = 3 ifTrue: [^ true].
- 	note = 6 ifTrue: [^ true].
- 	note = 8 ifTrue: [^ true].
- 	note = 10 ifTrue: [^ true].
- 	^ false
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>layoutChanged (in category 'layout') -----
- layoutChanged
- 	"Override this to avoid propagating 'layoutChanged' when just adding/removing note objects."
- 
- 	fullBounds = bounds ifTrue: [^ self].
- 	super layoutChanged.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>measureLinesOnOff (in category 'menu') -----
- measureLinesOnOff
- 
- 	showMeasureLines := showMeasureLines not.
- 	self changed!

Item was removed:
- ----- Method: PianoRollScoreMorph>>midiKeyForY: (in category 'geometry') -----
- midiKeyForY: y
- 
- 	^ lowestNote - ((y - (bounds bottom - self borderWidth - 4)) // 3)
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>mouseDown: (in category 'event handling') -----
- mouseDown: evt
- 
- 	| noteMorphs chordRect |
- 	(self notesInRect: ((evt cursorPoint extent: 1 at 0) expandBy: 2 at 30)) isEmpty
- 		ifTrue: ["If not near a note, then put up score edit menu"
- 				^ self invokeScoreMenu: evt].
- 
- 	"Clicked near (but not on) a note, so play all notes at the cursor time"
- 	noteMorphs := self notesInRect: ((evt cursorPoint extent: 1 at 0) expandBy: 0 at self height).
- 	chordRect := (self innerBounds withLeft: evt cursorPoint x) withWidth: 1.
- 	soundsPlayingMorph := Morph newBounds: chordRect color: Color green.
- 	self addMorphBack: soundsPlayingMorph.
- 	
- 	soundsPlaying := IdentityDictionary new.
- 	noteMorphs do:
- 		[:m | | sound | sound := m soundOfDuration: 999.0.
- 		soundsPlaying at: m put: sound.
- 		SoundPlayer resumePlaying: sound quickStart: false].
- 
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>mouseMove: (in category 'event handling') -----
- mouseMove: evt
- 
- 	| noteMorphs chordRect |
- 	soundsPlaying ifNil: [^ self].
- 	self autoScrollForX: evt cursorPoint x.
- 
- 	"Play all notes at the cursor time"
- 	noteMorphs := self notesInRect: ((evt cursorPoint extent: 1 at 0) expandBy: 0 at self height).
- 	chordRect := (self innerBounds withLeft: evt cursorPoint x) withWidth: 1.
- 	soundsPlayingMorph delete.
- 	soundsPlayingMorph := Morph newBounds: chordRect color: Color green.
- 	self addMorphBack: soundsPlayingMorph.
- 	
- 	noteMorphs do:
- 		[:m | | sound |  "Add any new sounds"
- 		(soundsPlaying includesKey: m)
- 			ifFalse: [sound := m soundOfDuration: 999.0.
- 					soundsPlaying at: m put: sound.
- 					SoundPlayer resumePlaying: sound quickStart: false]].
- 	soundsPlaying keys do:
- 		[:m |  "Remove any sounds no longer in selection."
- 		(noteMorphs includes: m)
- 			ifFalse: [(soundsPlaying at: m) stopGracefully.
- 					soundsPlaying removeKey: m]].
- 
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>mouseUp: (in category 'event handling') -----
- mouseUp: evt
- 
- 	soundsPlayingMorph ifNotNil: [soundsPlayingMorph delete].
- 	soundsPlaying ifNotNil: [soundsPlaying do: [:s | s stopGracefully]].
- 	soundsPlayingMorph := soundsPlaying := nil
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>moveCursorToTime: (in category 'scrolling') -----
- moveCursorToTime: scoreTime
- 
- 	| cursorOffset desiredCursorHeight |
- 	scorePlayer isPlaying
- 		ifTrue:
- 			[cursorOffset := ((scoreTime - leftEdgeTime) asFloat * timeScale) asInteger.
- 			(cursorOffset < 0
- 				or: [cursorOffset > (self width-20)])
- 				ifTrue:
- 				[self goToTime: scoreTime - (20/timeScale).
- 				cursorOffset := ((scoreTime - leftEdgeTime) asFloat * timeScale) asInteger]]
- 		ifFalse:
- 			[self goToTime: (scoreTime - (self width//2 / timeScale)
- 							max: (self width//10 / timeScale) negated).
- 			cursorOffset := ((scoreTime - leftEdgeTime) asFloat * timeScale) asInteger].
- 
- 	cursor position: (self left + self borderWidth + cursorOffset)@(self top + self borderWidth).
- 	desiredCursorHeight := self height.
- 	cursor height ~= desiredCursorHeight ifTrue: [cursor extent: 1 at desiredCursorHeight].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>movieClipPlayer (in category 'accessing') -----
- movieClipPlayer
- 
- 	^ movieClipPlayer!

Item was removed:
- ----- Method: PianoRollScoreMorph>>movieClipPlayer: (in category 'accessing') -----
- movieClipPlayer: moviePlayer
- 
- 	movieClipPlayer := moviePlayer
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>notePerBeat: (in category 'accessing') -----
- notePerBeat: n
- 
- 	^ self timeSignature: beatsPerMeasure over: n!

Item was removed:
- ----- Method: PianoRollScoreMorph>>notesInRect: (in category 'scrolling') -----
- notesInRect: timeSlice
- 
- 	^ self submorphsSatisfying:
- 		[:m | (timeSlice intersects: m bounds)
- 				and: [m isKindOf: PianoRollNoteMorph]]!

Item was removed:
- ----- Method: PianoRollScoreMorph>>on: (in category 'initialization') -----
- on: aScorePlayer
- 
- 	scorePlayer := aScorePlayer.
- 	score := aScorePlayer score.
- 	colorForTrack := Color wheel: score tracks size.
- 	leftEdgeTime := 0.
- 	timeScale := 0.1.
- 	indexInTrack := Array new: score tracks size withAll: 1.
- 	lastUpdateTick := -1.
- 
- 	self updateLowestNote
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>rebuildFromScore (in category 'drawing') -----
- rebuildFromScore
- 	"Rebuild my submorphs from the score. This method should be invoked after changing the time scale, the color or visibility of a track, the extent of this morph, etc."
- 
- 	score ifNil: [^ self].
- 	self addNotes.
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>removedMorph: (in category 'private') -----
- removedMorph: aMorph
- 	| trackSize |
- 	trackSize := score ambientTrack size.
- 	score removeAmbientEventWithMorph: aMorph.
- 	trackSize = score ambientTrack size ifFalse:
- 		["Update duration if we removed an event"
- 		scorePlayer updateDuration].
- 	^super removedMorph: aMorph!

Item was removed:
- ----- Method: PianoRollScoreMorph>>score (in category 'accessing') -----
- score
- 
- 	^ score!

Item was removed:
- ----- Method: PianoRollScoreMorph>>scorePlayer (in category 'accessing') -----
- scorePlayer
- 
- 	^ scorePlayer!

Item was removed:
- ----- Method: PianoRollScoreMorph>>selection (in category 'accessing') -----
- selection
- 	"Returns an array of 3 elements:
- 		trackIndex
- 		indexInTrack of first note
- 		indexInTrack of last note"
- 
- 	| trackIndex track |
- 	selection ifNil:  "If no selection, return last event of 1st non-muted track (or nil)"
- 		[trackIndex := (1 to: score tracks size)
- 			detect: [:i | (scorePlayer mutedForTrack: i) not] ifNone: [^ nil].
- 		track := score tracks at: trackIndex.
- 		^ Array with: trackIndex with: track size with: track size].
- 	(scorePlayer mutedForTrack: selection first)
- 		ifTrue: [selection := nil.  ^ self selection].
- 	^ selection!

Item was removed:
- ----- Method: PianoRollScoreMorph>>selection: (in category 'accessing') -----
- selection: anArray
- 
- 	selection := anArray!

Item was removed:
- ----- Method: PianoRollScoreMorph>>step (in category 'stepping and presenter') -----
- step
- 
- 	| t |
- 	score ifNil: [^ self].
- 
- 	lastMutedState ~= scorePlayer mutedState ifTrue: [
- 		self rebuildFromScore.
- 		lastMutedState := scorePlayer mutedState copy].
- 
- 	t := scorePlayer ticksSinceStart.
- 	t = lastUpdateTick ifFalse: [
- 		self moveCursorToTime: t.
- 		lastUpdateTick := t].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>stepTime (in category 'stepping and presenter') -----
- stepTime
- 
- 	^ 0
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>tickTimeAtCursor (in category 'geometry') -----
- tickTimeAtCursor
- 	cursor ifNil: [^ 0].
- 	^ self timeForX: cursor left!

Item was removed:
- ----- Method: PianoRollScoreMorph>>timeForX: (in category 'geometry') -----
- timeForX: aNumber
- 
- 	^ ((aNumber - self left - self borderWidth) asFloat / timeScale + leftEdgeTime) asInteger!

Item was removed:
- ----- Method: PianoRollScoreMorph>>timeScale (in category 'accessing') -----
- timeScale
- 
- 	^ timeScale  "in pixels per tick"!

Item was removed:
- ----- Method: PianoRollScoreMorph>>timeSignature:over: (in category 'accessing') -----
- timeSignature: num over: denom
- 
- 	beatsPerMeasure := num.
- 	notePerBeat := denom.  "a number like 2, 4, 8"
- 	self changed!

Item was removed:
- ----- Method: PianoRollScoreMorph>>updateLowestNote (in category 'initialization') -----
- updateLowestNote
- 	"find the actual lowest note in the score"
- 
- 	
- 	lowestNote := 128 - (self innerBounds height // 3).
- 	score tracks do: [:track | | n |
- 		1 to: track size do: [:i |
- 			n := track at: i.
- 			(n isNoteEvent and: [n midiKey < lowestNote])
- 				ifTrue: [lowestNote := n midiKey - 4]]].
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>xForTime: (in category 'geometry') -----
- xForTime: aNumber
- 
- 	^ ((aNumber - leftEdgeTime) asFloat * timeScale) asInteger + self left + self borderWidth
- !

Item was removed:
- ----- Method: PianoRollScoreMorph>>yForMidiKey: (in category 'geometry') -----
- yForMidiKey: midiKey
- 
- 	^ (self bottom - self borderWidth - 4) - (3 * (midiKey - lowestNote))
- !

Item was removed:
- Notification subclass: #PickAFileToWriteNotification
- 	instanceVariableNames: ''
- 	classVariableNames: ''
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Exceptions'!

Item was removed:
- ----- Method: Point>>encodePostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- encodePostscriptOn:aStream 
- 	aStream writePoint:self.!

Item was removed:
- ----- Method: PolygonMorph class>>curvePrototype (in category '*MorphicExtras-instance creation') -----
- curvePrototype
- 	"Answer an instance of the receiver that will serve as a prototypical curve"
- 
- 	| aa |
- 	aa := self new. 
- 	aa vertices: (Array with: 0 at 80 with: 70 at 90 with: 60 at 0) 
- 		color: Color orange lighter 
- 		borderWidth: 4 
- 		borderColor: Color black.
- 	aa beSmoothCurve.
- 	aa setNameTo: 'Curve'.
- 	aa makeForwardArrow.		"is already open"
- 	aa computeBounds.
- 	^ aa
- 
- "
- PolygonMorph curvePrototype openInHand
- "!

Item was removed:
- ----- Method: PolygonMorph class>>extraCircularVertices (in category '*MorphicExtras-examples') -----
- extraCircularVertices
- 
- 	self flag: #note. "Cannot use Circle because it is in the ST80 package."
- 	 ^ {400 at 100. 477 at 115. 541 at 159. 585 at 223. 600 at 300. 600 at 300. 585 at 377. 541 at 441. 477 at 485. 400 at 500. 400 at 500. 438 at 492. 471 at 471. 492 at 438. 500 at 400. 500 at 400. 492 at 362. 471 at 329. 438 at 308. 400 at 300. 400 at 300. 362 at 292. 329 at 271. 308 at 238. 300 at 200. 300 at 200. 308 at 162. 329 at 129. 362 at 108. 400 at 100}
- 
- "	^ ((Circle center: 400 @ 300 radius: 200 quadrant: 1) computeVertices: 5) reverse
- 		, ((Circle center: 400 @ 300 radius: 200 quadrant: 4) computeVertices: 5) reverse
- 		, ((Circle center: 400 @ 400 radius: 100 quadrant: 4) computeVertices: 5)
- 		, ((Circle center: 400 @ 400 radius: 100 quadrant: 1) computeVertices: 5)
- 		, ((Circle center: 400 @ 200 radius: 100 quadrant: 3) computeVertices: 5) reverse
- 		, ((Circle center: 400 @ 200 radius: 100 quadrant: 2) computeVertices: 5) reverse"!

Item was removed:
- ----- Method: PolygonMorph class>>extraExampleTextFlow (in category '*MorphicExtras-examples') -----
- extraExampleTextFlow
- 	"PolygonMorph extraExampleTextFlow openInHand"
- 
- 	| polygon text obstacle |
- 	polygon := self new.
- 	polygon
- 		setVertices: self extraCircularVertices;
- 		extent: 309 asPoint;
- 		beSmoothCurve;
- 		color: Color lightGray;
- 		addHandles.
- 	
- 	text := (TextMorph
- 		string: 'TextMorphs can be chained together, causing their contents to flow between containers as either the contents or the containers change. If a TextMorph is embedded in another Morph, you can ask it to have fill the shape of that Morph. Moreover, you can ask it to avoid occlusions, in which case it will do its best to avoid collisions with siblings being in front of it. If a TextMorph is embedded in a CurveMorph, you can ask it to have the text follow the curve, as illustrated here.' asTextMorph
- 		fontName: #BitstreamVeraSans
- 		size: 14)
- 			textColor: Color white;
- 			fillsOwner: true;
- 			yourself.
- 	obstacle := StarMorph new
- 		center: polygon center - (50 @ 25);
- 		extent: 81 asPoint;
- 		color: Color orchid;
- 		yourself.
- 	
- 	polygon
- 		addMorph: text;
- 		addMorph: obstacle.
- 	text centered.
- 	text container avoidsOcclusions: true.
- 	^ polygon!

Item was removed:
- ----- Method: PolygonMorph class>>extraExampleTrapeze (in category '*MorphicExtras-examples') -----
- extraExampleTrapeze
- 	"PolygonMorph extraExampleTrapeze openInHand"
- 
- 	| polygon text |
- 	polygon := self new.
- 	polygon
- 		setVertices: {0 @ 100. 275 @ 100. 200 @ 0. 75 @ 0};
- 		addHandles	;
- 		balloonText: 'Click and drag the handles to change my shape'.
- 	text := '<b>Polygons</b> can be closed or open, filled or empty as well as lined or convex and can have directed arrows, bevelled borders and last but not least adapted handles.' asTextFromHtml asMorph
- 		beAllFont: (TextStyle default fontOfSize: 14);
- 		fillsOwner: true;
- 		yourself.
- 	polygon addMorph: text.
- 	text centered.
- 	^ polygon!

Item was removed:
- ----- Method: PolygonMorph class>>extraExampleTrapezePlus (in category '*MorphicExtras-examples') -----
- extraExampleTrapezePlus
- 	"PolygonMorph extraExampleTrapezePlus openInHand"
- 	"Some additional decoration"
- 
- 	^ self extraExampleTrapeze
- 		fillStyle: ((GradientFillStyle
- 			ramp: { 0.0 -> Color orange. 0.7 -> Color magenta twiceLighter. 1.0 -> Color red muchLighter })
- 			origin: 0 @ 0; direction: 275 @ 100;
- 			yourself);
- 		borderWidth: 2;
- 		borderColor: Color blue;
- 		dashedBorder: {35. 20. Color yellow};
- 		yourself!

Item was removed:
- ----- Method: PolygonMorph class>>initialize (in category '*MorphicExtras-class initialization') -----
- initialize
- 
- 	self registerInFlapsRegistry.	!

Item was removed:
- ----- Method: PolygonMorph class>>registerInFlapsRegistry (in category '*MorphicExtras-class initialization') -----
- registerInFlapsRegistry
- 	"Register the receiver in the system's flaps registry"
- 	self environment
- 		at: #Flaps
- 		ifPresent: [:cl | cl registerQuad: {#PolygonMorph. #authoringPrototype. 'Polygon'	translatedNoop. 'A straight-sided figure with any number of sides' translatedNoop}
- 						forFlapNamed: 'PlugIn Supplies'.
- 						cl registerQuad: {#PolygonMorph. #authoringPrototype. 'Polygon'	translatedNoop. 'A straight-sided figure with any number of sides' translatedNoop}
- 						forFlapNamed: 'Supplies'.]!

Item was removed:
- ----- Method: PolygonMorph class>>supplementaryPartsDescriptions (in category '*MorphicExtras-instance creation') -----
- supplementaryPartsDescriptions
- 	"Answer a list of DescriptionForPartsBin objects that characterize objects that this class wishes to contribute to Stationery bins *other* than by the standard default #newStandAlone protocol"
- 
- 	^ {DescriptionForPartsBin
- 		formalName: 'Arrow' translatedNoop
- 		categoryList: {'Graphics' translatedNoop}
- 		documentation: 'A line with an arrowhead.  Shift-click to get handles and move the ends.' translatedNoop
- 		globalReceiverSymbol: #PolygonMorph
- 		nativitySelector: #arrowPrototype.
- 	DescriptionForPartsBin
- 		formalName: 'Triangle' translatedNoop
- 		categoryList: {'Graphics' translatedNoop}
- 		documentation: 'A three-sided polygon.' translatedNoop
- 		globalReceiverSymbol: #PolygonMorph
- 		nativitySelector: #trianglePrototype.
- 
- 		DescriptionForPartsBin
- 		formalName: 'Curve' translatedNoop
- 		categoryList: {'Graphics' translatedNoop.  'Basic' translatedNoop}
- 		documentation: 'A smooth wiggly curve, or a curved solid.  Shift-click to get handles and move the points.  Using the halo menu, can be coverted into a polygon, and can be made "open" rather than closed.' translatedNoop
- 		globalReceiverSymbol: #PolygonMorph
- 		nativitySelector: #curvePrototype.
-  }
- 
- 	
- !

Item was removed:
- ----- Method: PolygonMorph class>>trianglePrototype (in category '*MorphicExtras-instance creation') -----
- trianglePrototype
- 	"Answer an instance of the receiver that will serve as a prototypical triangle"
- 
- 	| aa |
- 	aa := self new. 
- 	aa vertices: {0.0 at 0.0. 138.0 at 0.0. -37.0@ -74.0}
- 		color:  (TranslucentColor r: 0.387 g: 1.0 b: 0.548 alpha: 0.463)
- 		borderWidth: 3 
- 		borderColor: Color black.
- 	aa setProperty: #noNewVertices toValue: true.
- 	aa setNameTo: 'Triangle'.
- 	aa makeForwardArrow.		"is already open"
- 	aa computeBounds.
- 	aa addHandles.
- 	^ aa
- 
- "
- PolygonMorph trianglePrototype openInHand
- "!

Item was removed:
- ----- Method: PolygonMorph class>>unload (in category '*MorphicExtras-class initialization') -----
- unload
- 	"Unload the receiver from global registries"
- 
- 	self environment at: #Flaps ifPresent: [:cl |
- 	cl unregisterQuadsWithReceiver: self] !

Item was removed:
- ----- Method: PolygonMorph>>drawPostscriptOn: (in category '*MorphicExtras-Postscript Canvases') -----
- drawPostscriptOn: aCanvas 
- 	"Display the receiver, a spline curve, approximated by straight 
- 	line segments."
- 	| array |
- 	vertices size < 1
- 		ifTrue: [self error: 'a polygon must have at least one point'].
- 	array := self drawArrowsOn: aCanvas.
- 	closed
- 		ifTrue: [aCanvas
- 				drawPolygon: self getVertices
- 				color: self color
- 				borderWidth: self borderWidth
- 				borderColor: self borderColor]
- 		ifFalse: [self drawClippedBorderOn: aCanvas usingEnds: array].
- !

Item was removed:
- ----- Method: PolygonMorph>>scale: (in category '*MorphicExtras-geometry eToy') -----
- scale: scaleFactor 
- 	| flex center ratio |
- 	ratio := self scaleFactor / scaleFactor.
- 	self borderWidth: ((self borderWidth / ratio) rounded max: 0).
- 	center := self referencePosition.
- 	flex := (MorphicTransform offset: center negated)
- 				withScale: ratio.
- 	self
- 		setVertices: (vertices
- 				collect: [:v | (flex transform: v)
- 						- flex offset]).
- 	super scale: scaleFactor.!

Item was removed:
- Canvas subclass: #PostscriptCanvas
- 	instanceVariableNames: 'origin clipRect currentColor shadowColor currentFont morphLevel gstateStack fontMap usedFonts psBounds topLevelMorph initialScale savedMorphExtent currentTransformation printSpecs pages'
- 	classVariableNames: 'FontMap'
- 	poolDictionaries: ''
- 	category: 'MorphicExtras-Postscript Canvases'!
- 
- !PostscriptCanvas commentStamp: '<historical>' prior: 0!
- I am a canvas that converts Morphic drawing messages into Postscript.  The canvas itself does not actually generate the Postscript code, but rather sends messages corresponding 1:1 to the Postscript imaging model to its target (default: PostscriptEncoder), which has the job of generating actual drawing commands.
- 
- PostscriptCharacterScanner and PostscriptDummyWarp are helper classes that simulate effects currently implemented via BitBlt-specific mechanisms during Postscript generation.  They should be going away as Morphic becomes fully device independent.
- 
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>baseOffset (in category 'configuring') -----
- baseOffset
- 	^0 at 0.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>convertFontName: (in category 'font mapping') -----
- convertFontName: aName
- 	"Break apart aName on case boundaries, inserting hyphens as needed."
- 	| lastCase |
- 	lastCase := aName first isUppercase.
- 	^ String streamContents: [ :s |
- 		aName do: [ :c | | thisCase |
- 			thisCase := c isUppercase.
- 			(thisCase and: [ lastCase not ]) ifTrue: [ s nextPut: $- ].
- 			lastCase := thisCase.
- 			s nextPut: c ]]!

Item was removed:
- ----- Method: PostscriptCanvas class>>defaultCanvasType (in category 'configuring') -----
- defaultCanvasType
- 
- 	^Preferences postscriptStoredAsEPS ifTrue: [EPSCanvas] ifFalse: [DSCPostscriptCanvas]!

Item was removed:
- ----- Method: PostscriptCanvas class>>defaultExtension (in category 'configuring') -----
- defaultExtension
- 	^ '.ps'!

Item was removed:
- ----- Method: PostscriptCanvas class>>defaultTarget (in category 'configuring') -----
- defaultTarget
- 	^PostscriptEncoder stream.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>filterSelector (in category 'configuring') -----
- filterSelector
- 	^#fullDrawPostscriptOn:.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>fontMap (in category 'font mapping') -----
- fontMap
- 	"Answer the font mapping dictionary. Made into a class var so that it can be edited."
- 	^FontMap ifNil: [ self initializeFontMap. FontMap ].!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontSampler (in category 'font mapping') -----
- fontSampler
- 	"Produces a Postscript .eps file on disk, returns a Morph."
- 	"PostscriptCanvas fontSampler"
- 	"PostscriptCanvas fontSampler openInWorld"
- 	| morph file |
- 	morph := Morph new
- 		layoutPolicy: TableLayout new;
- 		listDirection: #topToBottom;
- 		wrapDirection: #leftToRight;
- 		hResizing: #shrinkWrap;
- 		vResizing: #shrinkWrap;
- 		color: Color white.
- 	TextStyle actualTextStyles keysAndValuesDo: [ :styleName :style |
- 		{ style fontArray first. style fontArray last } do: [ :baseFont | | info |
- 			0 to: 2 do: [ :i | | font string string2 textMorph row |
- 				font := baseFont emphasized: i.
- 				(i isZero or: [ font ~~ baseFont ]) ifTrue: [
- 					string := font fontNameWithPointSize.
- 					row := Morph new
- 						layoutPolicy: TableLayout new;
- 						listDirection: #topToBottom;
- 						hResizing: #shrinkWrap;
- 						vResizing: #shrinkWrap;
- 						cellGap: 20 at 0;
- 						color: Color white.
- 		
- 					textMorph := TextMorph new hResizing: #spaceFill; backgroundColor: Color white; beAllFont: font; contentsAsIs: string.
- 					row addMorphBack: (textMorph imageForm asMorph).
- 
- 					info := self postscriptFontInfoForFont: font.
- 					string2 := String streamContents: [ :stream |
- 						stream nextPutAll: info first; space; print: (font pixelSize * info second) rounded.
- 					].
- 					textMorph := TextMorph new hResizing: #spaceFill; backgroundColor: Color white; beAllFont: font; contentsAsIs: string2.
- 					row addMorphBack: textMorph.
- 					
- 					morph addMorphBack: row.
- 				]
- 			]
- 		]
- 	].
- 	morph bounds: Project current world bounds.
- 	morph layoutChanged; fullBounds.
- 	file := (FileDirectory default newFileNamed: 'PSFontSampler.eps').
- 	Cursor wait showWhile: [ 
- 		file nextPutAll: (EPSCanvas morphAsPostscript: morph) ].
- 	^morph!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForAccuAt (in category 'font mapping') -----
- fontsForAccuAt
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Helvetica-Bold' 1.0);
- 		at: 1 put: #('Helvetica-Bold' 1.0);
- 		at: 2 put: #('Helvetica-BoldOblique' 1.0);
- 		at: 3 put: #('Helvetica-BoldOblique' 1.0).
- 	^d!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForComicBold (in category 'font mapping') -----
- fontsForComicBold
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Helvetica-Narrow-Bold' 0.9);
- 		at: 1 put: #('Helvetica-Narrow-Bold' 0.9);
- 		at: 2 put: #('Helvetica-Narrow-BoldOblique' 0.9);
- 		at: 3 put: #('Helvetica-Narrow-BoldOblique' 0.9).
- 	^d!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForComicPlain (in category 'font mapping') -----
- fontsForComicPlain
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 
- "how do we do underlined??"
- 
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Helvetica-Narrow' 0.9);
- 		at: 1 put: #('Helvetica-Narrow-Bold' 0.9);
- 		at: 2 put: #('Helvetica-Narrow-Oblique' 0.9);
- 		at: 3 put: #('Helvetica-Narrow-BoldOblique' 0.9).
- 	^d
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForDejaVuSans (in category 'font mapping') -----
- fontsForDejaVuSans
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Helvetica-Bold' 1.0);
- 		at: 1 put: #('Helvetica-Bold' 1.0);
- 		at: 2 put: #('Helvetica-Oblique' 1.0);
- 		at: 3 put: #('Helvetica-BoldOblique' 1.0).
- 	^d!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForHelvetica (in category 'font mapping') -----
- fontsForHelvetica
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Helvetica' 1.0);
- 		at: 1 put: #('Helvetica-Bold' 1.0);
- 		at: 2 put: #('Helvetica-Oblique' 1.0);
- 		at: 3 put: #('Helvetica-BoldOblique' 1.0);
- 		at: 8 put: #('Helvetica-Narrow' 1.0);
- 		at: 9 put: #('Helvetica-Narrow-Bold' 1.0);
- 		at: 10 put: #('Helvetica-Narrow-Oblique' 1.0);
- 		at: 11 put: #('Helvetica-Narrow-BoldOblique' 1.0).
- 	^d!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForNewYork (in category 'font mapping') -----
- fontsForNewYork
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Times-Roman' 1.0);
- 		at: 1 put: #('Times-Bold' 1.0);
- 		at: 2 put: #('Times-Italic' 1.0);
- 		at: 3 put: #('Times-BoldItalic' 1.0);
- 		at: 8 put: #('Helvetica-Narrow' 1.0);
- 		at: 9 put: #('Helvetica-Narrow-Bold' 1.0);
- 		at: 10 put: #('Helvetica-Narrow-Oblique' 1.0);
- 		at: 11 put: #('Helvetica-Narrow-BoldOblique' 1.0).
- 	^d!

Item was removed:
- ----- Method: PostscriptCanvas class>>fontsForPalatino (in category 'font mapping') -----
- fontsForPalatino
- 
- 	| d |
- 
- 	"Bold = 1, Ital = 2, Under = 4, Narrow = 8, Struckout = 16"
- 	d := Dictionary new.
- 	d
- 		at: 0 put: #('Palatino-Roman' 1.0);
- 		at: 1 put: #('Palatino-Bold' 1.0);
- 		at: 2 put: #('Palatino-Italic' 1.0);
- 		at: 3 put: #('Palatino-BoldItalic' 1.0).
- 	^d
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>initializeFontMap (in category 'font mapping') -----
- initializeFontMap
- 	"Initialize the dictionary mapping font names to substitutions for Postscript code generation."
- 	"PostscriptCanvas initializeFontMap"
- 	| f |
- 	FontMap := Dictionary new.
- 	FontMap
- 		at: 'NewYork' put: (f := self fontsForNewYork);
- 		at: 'Accuny' put: f;
- 
- 		at: 'Helvetica' put: (f := self fontsForHelvetica);
- 		at: 'Accujen' put: f;
- 				
- 		at: 'Palatino' put: self fontsForPalatino;
- 		
- 		at: 'ComicBold' put: (f := self fontsForComicBold);
- 		at: 'Accuat' put: self fontsForAccuAt;
- 		
- 		at: 'Bitmap DejaVu Sans' put: self fontsForDejaVuSans;
- 		
- 		at: 'ComicPlain' put: self fontsForComicPlain!

Item was removed:
- ----- Method: PostscriptCanvas class>>morphAsPostscript: (in category 'drawing') -----
- morphAsPostscript:aMorph
- 	^self morphAsPostscript:aMorph rotated:false offsetBy:self baseOffset.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>morphAsPostscript:rotated: (in category 'drawing') -----
- morphAsPostscript: aMorph rotated: rotateFlag
- 
- 	^ self morphAsPostscript: aMorph rotated: rotateFlag offsetBy: self baseOffset.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>morphAsPostscript:rotated:offsetBy: (in category 'drawing') -----
- morphAsPostscript:aMorph rotated:rotateFlag offsetBy:offset
-  | psCanvas |
-   psCanvas := self new.
-   psCanvas reset.
-   psCanvas bounds: (0 at 0 extent: (aMorph bounds extent + (2 * offset))).
-   psCanvas topLevelMorph:aMorph.
-   psCanvas resetContentRotated: rotateFlag.
-   psCanvas fullDrawMorph: aMorph .
-   ^psCanvas contents.
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>postscriptFontInfoForFont: (in category 'font mapping') -----
- postscriptFontInfoForFont: font
- 
- 	| decoded decodedName keys match fontName |
- 
- 	fontName := font textStyleName asString.
- 	decoded := TextStyle decodeStyleName: fontName.
- 	decodedName := decoded second.
- 	keys := self fontMap keys asArray sort: [ :a :b | a size > b size ].
- 	match := keys select: [ :k | decoded first = k or: [ fontName = k ] ].
- 	match do: [ :key | | subD desired mask |
- 		subD := self fontMap at: key.
- 		desired := font emphasis.
- 		mask := 31.
- 		[
- 			desired := desired bitAnd: mask.
- 			subD at: desired ifPresent: [ :answer | ^answer].
- 			mask := mask bitShift: -1.
- 			desired > 0
- 		] whileTrue.
- 	].
- 
- 	"No explicit lookup found; try to convert the style name into the canonical Postscript name.
- 	This name will probably still be wrong."
- 
- 	fontName := String streamContents: [ :s |
- 		s nextPutAll: decodedName.
- 		decoded third do: [ :nm | s nextPut: $-; nextPutAll: nm ].
- 
- 		(font emphasis = 0 and: [ (decoded last includes: 0) not ])
- 			ifTrue: [ s nextPutAll:  '-Regular' ].
- 
- 		(font emphasis = 1 and: [ (decoded first anyMask: 1) not ])
- 			ifTrue: [ s nextPutAll:  '-Bold' ].
- 
- 		(font emphasis = 2 and: [ (decoded first anyMask: 2) not ])
- 			ifTrue: [ s nextPutAll:  '-Italic' ].
- 
- 		(font emphasis = 3 and: [ (decoded first anyMask: 3) not ])
- 			ifTrue: [ s nextPutAll:  '-BoldItalic' ].
- 	].
- 
- 	^ {'(', fontName, ') cvn'. 1.0}
- !

Item was removed:
- ----- Method: PostscriptCanvas class>>postscriptFontMappingSummary (in category 'font mapping') -----
- postscriptFontMappingSummary
- 	"
- 	Transcript nextPutAll: 
- 	PostscriptCanvas postscriptFontMappingSummary
- 	; endEntry
- 	"
- 	| stream |
- 	stream := WriteStream on: (String new: 1000).
- 	TextStyle actualTextStyles keysAndValuesDo: [ :styleName :style |
- 		stream nextPutAll: styleName; cr.
- 		style fontArray do: [ :baseFont | | info |
- 			0 to: 3 do: [ :i | | font |
- 				font := baseFont emphasized: i.
- 				font emphasis = i ifTrue: [
- 					stream tab; nextPutAll: font fontNameWithPointSize; tab.
- 					info := self postscriptFontInfoForFont: font.
- 					stream nextPutAll: info first; space; print: (font pixelSize * info second) rounded.
- 					stream cr.
- 				]
- 			]
- 		]
- 	].
- 	^stream contents!

Item was removed:
- ----- Method: PostscriptCanvas>>aaLevel: (in category 'balloon compatibility') -----
- aaLevel:newLevel
- 	"ignore "!

Item was removed:
- ----- Method: PostscriptCanvas>>asBalloonCanvas (in category 'balloon compatibility') -----
- asBalloonCanvas
-      ^self.!

Item was removed:
- ----- Method: PostscriptCanvas>>bounds: (in category 'private') -----
- bounds:newBounds
- 	psBounds := newBounds.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>canBlendAlpha (in category 'testing') -----
- canBlendAlpha
- 	^false!

Item was removed:
- ----- Method: PostscriptCanvas>>clip (in category 'private') -----
- clip	
- 	^target clip.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>clipBy:during: (in category 'drawing-support') -----
- clipBy: aRectangle during: aBlock
- 	^self translateBy: 0 at 0 clippingTo: aRectangle during: aBlock.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>clipRect (in category 'accessing') -----
- clipRect
- 	^clipRect.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>closepath (in category 'private') -----
- closepath
- 	^target closepath.
- 
- 
-               !

Item was removed:
- ----- Method: PostscriptCanvas>>comment: (in category 'private') -----
- comment:aString
- 	target comment:aString.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>comment:with: (in category 'private') -----
- comment: aString with: anObject 
- 	target comment:aString with:anObject.
- 	!

Item was removed:
- ----- Method: PostscriptCanvas>>contentsOfArea:into: (in category 'accessing') -----
- contentsOfArea: aRectangle into: aForm
- 	"not supported for PS canvas"
- !

Item was removed:
- ----- Method: PostscriptCanvas>>defaultFont (in category 'private') -----
- defaultFont
- 	^ TextStyle defaultFont!

Item was removed:
- ----- Method: PostscriptCanvas>>deferred: (in category 'balloon compatibility') -----
- deferred: ignored!

Item was removed:
- ----- Method: PostscriptCanvas>>defineFont: (in category 'private') -----
- defineFont: aFont
- 
- 	| psNameFor alreadyRemapped |
- 
- 	(usedFonts includesKey: aFont) ifFalse:[
- 		psNameFor := self postscriptFontNameForFont: aFont.
- 		alreadyRemapped := usedFonts includes: psNameFor.
- 		usedFonts at: aFont put: psNameFor.
- 		" here: define as Type-3 unless we think its available "
- 		" or, just remap"
- 
- 		" I had some problems if same font remapped twice"
- 		alreadyRemapped ifFalse: [target remapFontForSqueak: psNameFor].
- 	].!

Item was removed:
- ----- Method: PostscriptCanvas>>definePathProcIn:during: (in category 'drawing-support') -----
- definePathProcIn: pathBlock during: duringBlock 
- 	"Bracket the output of pathBlock (which is passed the receiver) in 
- 	gsave 
- 		newpath 
- 			<pathBlock> 
- 		closepath 
- 		<duringBlock> 
- 	grestore 
- 	"
- 	^self
- 		preserveStateDuring: [:tgt | 
- 			| retval |
- 			self comment: 'begin pathProc path block'.
- 			target newpath.
- 			pathBlock value: tgt.
- 			target closepath.
- 			self comment: 'begin pathProc during block'.
- 			retval := duringBlock value: tgt.
- 			self comment: 'end pathProc'.
- 			retval].!

Item was removed:
- ----- Method: PostscriptCanvas>>doesRoundedCorners (in category 'testing') -----
- doesRoundedCorners 
- 
- 	^ false!

Item was removed:
- ----- Method: PostscriptCanvas>>draw: (in category 'drawing-general') -----
- draw: anObject
- 	^anObject drawPostscriptOn: self!

Item was removed:
- ----- Method: PostscriptCanvas>>drawGeneralBezierShape:color:borderWidth:borderColor: (in category 'balloon compatibility') -----
- drawGeneralBezierShape: shapeArray color: color borderWidth: borderWidth borderColor: borderColor 
- 	"shapeArray is an array of: 
- 	arrays of points, each of which must have 
- 	a multiple of 3 points in it. 
- 	This method tries to sort the provided triplets so that curves that 
- 	start and end at the same point are together."
- 	| groups fillC where triplets |
- 	fillC := self shadowColor
- 				ifNil: [color].
- 	shapeArray isEmpty
- 		ifTrue: [^ self].
- 	where := nil.
- 	groups := OrderedCollection new.
- 	triplets := OrderedCollection new.
- 	shapeArray
- 		do: [:arr | arr
- 				groupsOf: 3
- 				atATimeDo: [:bez | 
- 					| rounded | 
- 					rounded := bez roundTo: 0.001.
- 					(where isNil
- 							or: [where = rounded first])
- 						ifFalse: [groups addLast: triplets.
- 							triplets := OrderedCollection new].
- 					triplets addLast: rounded.
- 					where := rounded last]].
- 	groups addLast: triplets.
- 	triplets := OrderedCollection new.
- 	"now try to merge stray groups"
- 	groups copy
- 		do: [:g1 | | g2 |
- 			g1 first first = g1 last last
- 				ifFalse: ["not closed"
- 					g2 := groups
- 								detect: [:g | g ~~ g1
- 										and: [g1 last last = g first first]]
- 								ifNone: [].
- 					g2
- 						ifNotNil: [groups remove: g2.
- 							groups add: g2 after: g1]]].
- 	groups
- 		do: [:g | triplets addAll: g].
- 	where := nil.
- 	self
- 		definePathProcIn: [ :cvs |
- 			triplets do: [:shape | 
- 					where ~= shape first
- 						ifTrue: [where
- 								ifNotNil: [cvs closepath].
- 							cvs moveto: shape first].
- 					where := cvs outlineQuadraticBezierShape: shape]]
- 		during: [ :cvs |
- 			cvs clip.
- 			cvs setLinewidth: borderWidth "*2";
- 				 fill: fillC andStroke: borderColor]!

Item was removed:
- ----- Method: PostscriptCanvas>>drawGradient: (in category 'private') -----
- drawGradient: fillColor 
- 	self comment: 'not-solid fill ' with: fillColor.
- 	self comment: ' origin ' with: fillColor origin.
- 	self comment: ' direction ' with: fillColor direction.
- 	self fill: fillColor asColor!

Item was removed:
- ----- Method: PostscriptCanvas>>drawOval:color:borderWidth:borderColor: (in category 'balloon compatibility') -----
- drawOval: r color: c borderWidth: borderWidth borderColor: borderColor
- 	| fillC |
- 	fillC := self shadowColor ifNil:[c].
- 	^ self fillOval: r color: fillC borderWidth: borderWidth borderColor: borderColor
- 	
- 
- 		
- !

Item was removed:
- ----- Method: PostscriptCanvas>>drawPage: (in category 'private') -----
- drawPage:aMorph
- 	self fullDrawMorph:aMorph.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>drawPages: (in category 'private') -----
- drawPages:collectionOfPages
- 	collectionOfPages do:[ :page |
- 		pages := pages + 1.
- 		target print:'%%Page: '; write:pages; space; write:pages; cr.
- 		self drawPage:page.
- 	].
- 	morphLevel = 0 ifTrue: [ self writeTrailer: pages ].!

Item was removed:
- ----- Method: PostscriptCanvas>>drawPolygon:color:borderWidth:borderColor: (in category 'drawing-polygons') -----
- drawPolygon: vertices color: aColor borderWidth: bw borderColor: bc 
- 	| fillC |
- 	fillC := self shadowColor ifNil:[aColor].
- 	self
- 		preserveStateDuring: [:pc | pc
- 			 outlinePolygon: vertices;
- 				 setLinewidth: bw;
- 				
- 				fill: fillC
- 				andStroke: (bc isSymbol
- 						ifTrue: [Color gray]
- 						ifFalse: [bc])]!

Item was removed:
- ----- Method: PostscriptCanvas>>drawPostscriptContext: (in category 'private') -----
- drawPostscriptContext: subCanvas
- 	| contents |
- 	(contents := subCanvas contents) ifNil: [^ self].
- 	^ target comment: ' sub-canvas start';
- 		preserveStateDuring: [:inner | inner print: contents];
- 		comment: ' sub-canvas stop'.	
- 
- !

Item was removed:
- ----- Method: PostscriptCanvas>>drawRectangle:color:borderWidth:borderColor: (in category 'balloon compatibility') -----
- drawRectangle: r color: color borderWidth: borderWidth borderColor: borderColor
- 
- 	| fillC |
- 	fillC := self shadowColor
- 				ifNil: [color].
- 	^ self
- 		frameAndFillRectangle: r
- 		fillColor: fillC
- 		borderWidth: borderWidth
- 		borderColor: borderColor!

Item was removed:
- ----- Method: PostscriptCanvas>>drawString:from:to:in:font:color: (in category 'drawing-text') -----
- drawString: s from: firstIndex to: lastIndex in: boundsRect font: fontOrNil color: c 
- 	| fillC oldC |
- 	fillC := self shadowColor
- 		ifNil: [c].
- 	self setFont: (fontOrNil
- 				ifNil: [self defaultFont]).
- 	self comment: ' text color: ' , c printString.
- 	oldC := currentColor.
- 	self setColor: fillC.
- 	self comment: ' boundsrect origin ' , boundsRect origin printString.
- 	self comment: '  origin ' , origin printString.
- 	self moveto: boundsRect origin.
- 	target print: ' (';
- 		 print: (s asString copyFrom: firstIndex to: lastIndex) asPostscript;
- 		 print: ') show';
- 		 cr.
- 	self setColor: oldC.!

Item was removed:
- ----- Method: PostscriptCanvas>>drawString:from:to:in:font:color:background: (in category 'drawing-text') -----
- drawString: s from: firstIndex to: lastIndex in: boundsRect font: fontOrNil color: c background: b
- 	target preserveStateDuring: [ :t | self fillRectangle: boundsRect color: b ].
- 	self drawString: s from: firstIndex to: lastIndex in: boundsRect font: fontOrNil color: c !

Item was removed:
- ----- Method: PostscriptCanvas>>endGStateForMorph: (in category 'private') -----
- endGStateForMorph: aMorph 
- 
- 	morphLevel = 1
- 		ifTrue: [ target showpage; print: 'grestore'; cr ]!

Item was removed:
- ----- Method: PostscriptCanvas>>fill: (in category 'private') -----
- fill: fillColor
- 	fillColor isSolidFill
- 		ifTrue: [self paint: fillColor asColor operation: #eofill]
- 		ifFalse: [self preserveStateDuring: [:inner | inner clip; drawGradient: fillColor]]!

Item was removed:
- ----- Method: PostscriptCanvas>>fill:andStroke: (in category 'private') -----
- fill: fillColor andStroke: strokeColor
- 	self preserveStateDuring: [:inner | inner fill: fillColor];
- 		stroke: strokeColor.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>fillColor: (in category 'drawing') -----
- fillColor:aColor
- 	self rect:clipRect; fill:aColor.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>fillOval:color:borderWidth:borderColor: (in category 'drawing-ovals') -----
- fillOval: r color: c borderWidth: borderWidth borderColor: borderColor 
- 	self preserveStateDuring:
- 		[:inner |
- 		inner oval: r;
- 		setLinewidth: borderWidth;
- 		fill: c andStroke: borderColor].
- 
- 	
- 
- 		
- !

Item was removed:
- ----- Method: PostscriptCanvas>>fillRectangle:color: (in category 'drawing-rectangles') -----
- fillRectangle: r color: c
- 	self rect:r; fill:c.!

Item was removed:
- ----- Method: PostscriptCanvas>>fillRectangle:fillStyle: (in category 'drawing-rectangles') -----
- fillRectangle: aRectangle fillStyle: aFillStyle
- 	"Fill the given rectangle."
- 	| pattern |
- 
- 	(aFillStyle isKindOf: InfiniteForm) ifTrue: [
- 		^self infiniteFillRectangle: aRectangle fillStyle: aFillStyle
- 	].
- 
- 	aFillStyle isSolidFill ifTrue:[^self fillRectangle: aRectangle color: aFillStyle asColor].
- 
- 	"We have a very special case for filling with infinite forms"
- 	(aFillStyle isBitmapFill and:[aFillStyle origin = (0 at 0)]) ifTrue:[
- 		pattern := aFillStyle form.
- 		(aFillStyle direction = (pattern width @ 0) 
- 			and:[aFillStyle normal = (0 at pattern height)]) ifTrue:[
- 				"Can use an InfiniteForm"
- 				^self fillRectangle: aRectangle color: (InfiniteForm with: pattern)].
- 	].
- 
- 	"Use a BalloonCanvas instead PROBABLY won't work here"
- 	"self balloonFillRectangle: aRectangle fillStyle: aFillStyle."
- 
- 	^self fillRectangle: aRectangle color: aFillStyle asColor!

Item was removed:
- ----- Method: PostscriptCanvas>>frameAndFillRectangle:fillColor:borderWidth:borderColor: (in category 'drawing-rectangles') -----
- frameAndFillRectangle: r fillColor: fillColor borderWidth: borderWidth borderColor: borderColor 
- 	"since postscript strokes on the line and squeak strokes inside, we need 
- 	to adjust inwards"
- 	self
- 		preserveStateDuring: [:pc | pc
- 				
- 				rect: (r insetBy: borderWidth / 2);
- 				 setLinewidth: borderWidth;
- 				 fill: fillColor andStroke: borderColor]!

Item was removed:
- ----- Method: PostscriptCanvas>>frameAndFillRectangle:fillColor:borderWidth:topLeftColor:bottomRightColor: (in category 'drawing-rectangles') -----
- frameAndFillRectangle: r fillColor: fillColor borderWidth: borderWidth topLeftColor: topLeftColor bottomRightColor: bottomRightColor 
- 	self
- 		preserveStateDuring: [:pc | 
- 			target newpath.
- 			pc setLinewidth: 0.
- 			pc outlinePolygon: {r origin. r topRight. r topRight + (borderWidth negated @ borderWidth). r origin + (borderWidth @ borderWidth). r bottomLeft + (borderWidth @ borderWidth negated). r bottomLeft. r origin};
- 				 fill: topLeftColor andStroke: topLeftColor.
- 			target newpath.
- 			pc outlinePolygon: {r topRight. r bottomRight. r bottomLeft. r bottomLeft + (borderWidth @ borderWidth negated). r bottomRight - (borderWidth @ borderWidth). r topRight + (borderWidth negated @ borderWidth). r topRight};
- 				 fill: bottomRightColor andStroke: bottomRightColor]!

Item was removed:
- ----- Method: PostscriptCanvas>>frameRectangle:width:color: (in category 'drawing-rectangles') -----
- frameRectangle: r width: w color: c 
- 	self rect:r; stroke:c.
- 
- !

Item was removed:
- ----- Method: PostscriptCanvas>>fullDraw: (in category 'drawing-general') -----
- fullDraw: aMorph 
- 	self comment: 'start morph: ' with: aMorph.
- 	self comment: 'level: ' with: morphLevel.
- 	self comment: 'bounds: ' with: aMorph bounds.
- 	self comment: 'corner: ' with: aMorph bounds corner.
- 	morphLevel := morphLevel + 1.
- 	self setupGStateForMorph: aMorph.
- 	aMorph fullDrawPostscriptOn: self.
- 	self endGStateForMorph: aMorph.
- 	morphLevel := morphLevel - 1.
- 	self comment: 'end morph: ' with: aMorph.
- 	self comment: 'level: ' with: morphLevel.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>fullDrawBookMorph: (in category 'drawing-general') -----
- fullDrawBookMorph:aBookMorph
- 	^aBookMorph fullDrawOn:self.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>image:at:sourceRect:rule: (in category 'private') -----
- image: form at: aPoint sourceRect: sourceRect rule: rule 
- 	| aForm |
- 	self preserveStateDuring:
- 		[:inner | inner translate: aPoint + self origin.
- 		aForm := form depth <= 8 ifTrue: [form asFormOfDepth: 32] ifFalse: [form].
- 		target write: ((aForm colorsUsed includes: Color transparent)
- 			ifTrue: [| top f2 c2 offset |
- 				"tfel: This was taken from SketchMorph, but is actually needed for all 
- 				forms that use transparency"
- 				offset := currentTransformation ifNil: [0 at 0] ifNotNil: [:t | t offset].
- 				top := self topLevelMorph.
- 				f2 := Form extent: aForm extent depth: self depth.
- 				c2 := f2 getCanvas.
- 				c2 fillColor: Color white.
- 				c2
- 					translateBy: offset - self origin - aPoint
- 					clippingTo: f2 boundingBox
- 					during: [:c | top fullDrawOn: c].
- 				f2]
- 			ifFalse: [aForm])].
- !

Item was removed:
- ----- Method: PostscriptCanvas>>infiniteFillRectangle:fillStyle: (in category 'balloon compatibility') -----
- infiniteFillRectangle: aRectangle fillStyle: aFillStyle
- 
- 	self flag: #bob.		"need to fix this"
- 
- 	"^aFillStyle 
- 		displayOnPort: (port clippedBy: aRectangle) 
- 		at: aRectangle origin - origin"
- !

Item was removed:
- ----- Method: PostscriptCanvas>>isPostscriptCanvas (in category 'testing') -----
- isPostscriptCanvas
- 	^true!

Item was removed:
- ----- Method: PostscriptCanvas>>isShadowDrawing (in category 'accessing') -----
- isShadowDrawing
- 	^shadowColor notNil!

Item was removed:
- ----- Method: PostscriptCanvas>>line:to:brushForm: (in category 'drawing') -----
- line: pt1 to: pt2 brushForm: brush 
- 	" to do: set brushform "
- 	self moveto:pt1; lineto:pt2; stroke:currentColor.
-  
- !

Item was removed:
- ----- Method: PostscriptCanvas>>line:to:width:color: (in category 'drawing') -----
- line: pt1 to: pt2 width: w color: c 
- 	self setLinewidth:w; moveto:pt1; lineto:pt2; stroke:c. 	
- !

Item was removed:
- ----- Method: PostscriptCanvas>>lineto: (in category 'private') -----
- lineto:aPoint
- 	^target lineto:aPoint.
- 
- 
-               !

Item was removed:
- ----- Method: PostscriptCanvas>>moveto: (in category 'private') -----
- moveto:aPoint
- 	^target moveto:aPoint.
- 
- 
-               !

Item was removed:
- ----- Method: PostscriptCanvas>>origin (in category 'accessing') -----
- origin
- 	^origin.
- !

Item was removed:
- ----- Method: PostscriptCanvas>>outlinePolygon: (in category 'private') -----
- outlinePolygon: vertices 
- 	target moveto: (vertices first).
- 	2 to