'From Cuis 2.6 of 10 August 2010 [latest update: #540] on 23 August 2010 at 10:47:08 pm'!

!Morph methodsFor: 'geometry' stamp: 'jmv 8/23/2010 18:09'!
bounds: newBounds
	| oldExtent newExtent |
	oldExtent _ bounds extent.
	newExtent _ newBounds extent.
	"Moving stuff around is most likely the most common operation.
	Optimize it"
	oldExtent = newExtent ifTrue: [
		^self position: newBounds topLeft ].
	(oldExtent dotProduct: oldExtent) <= (newExtent dotProduct: newExtent) ifTrue:[
		"We're growing. First move then resize."
		self position: newBounds topLeft; extent: newExtent.
	] ifFalse:[
		"We're shrinking. First resize then move."
		self extent: newExtent; position: newBounds topLeft.
	].! !

!Morph methodsFor: 'layout' stamp: 'jmv 8/23/2010 18:44'!
applyLayoutFrameIn: ownerLayoutBounds
	"Layout specific. Apply the given bounds to the receiver.
	newBounds is the bounds of the owner (or its #layoutBounds). 
	This means that we need to compute and apply our own bounds from it
	using our layoutFrame."
	| newBounds myLayoutFrame |
	myLayoutFrame _ self layoutFrame ifNil: [ ^self ].

	"compute the cell size the receiver has given its layout frame"
	newBounds _ myLayoutFrame layout: bounds in: ownerLayoutBounds.
	^self bounds: newBounds! !

!Morph methodsFor: 'layout' stamp: 'jmv 8/23/2010 18:39'!
doLayoutIfNeeded
	"Return self. Recompute the layout if necessary."
	fullBounds ifNotNil: [ ^self ].

	"Errors at this point can be critical so make sure we catch 'em all right"
	[self layoutSubmorphsIn: self layoutBounds] on: Error do: [ :ex |
		"This should do it unless you don't screw up the bounds"
		fullBounds _ bounds.
		ex pass ]! !

!Morph methodsFor: 'layout' stamp: 'jmv 8/23/2010 22:47'!
layoutSubmorphsIn: layoutBounds
	"Compute a new layout of submorphs based on the given layout bounds."

	submorphs isEmpty ifTrue: [
		^fullBounds _ bounds].

	self submorphsDo: [ :m | 
		m doesLayout ifTrue: [
			m applyLayoutFrameIn: layoutBounds ]].
	fullBounds _ self computeFullBounds! !

!Morph methodsFor: 'submorphs-add/remove' stamp: 'jmv 8/23/2010 18:32'!
removeAllMorphsIn: aCollection
	"greatly speeds up the removal of *lots* of submorphs"
	| set myWorld |
	aCollection isEmpty ifTrue: [ ^self ].
	set _ IdentitySet new: aCollection size * 4 // 3.
	aCollection do: [ :each | each owner == self ifTrue: [ set add: each]].
	myWorld _ self world.
	(fullBounds notNil or:[ myWorld notNil ]) ifTrue:[ self invalidRect: self fullBounds ].
	set do: [:m | m privateOwner: nil].
	submorphs _ submorphs reject: [ :each | set includes: each].
	set do: [ :m | self removedMorph: m ].
	self layoutChanged.
! !

!Morph methodsFor: 'private' stamp: 'jmv 8/23/2010 18:39'!
privateBounds: boundsRect
	"Private!! Use position: and/or extent: instead."

	fullBounds _ nil.
	bounds _ boundsRect! !

!Morph methodsFor: 'private' stamp: 'jmv 8/23/2010 18:41'!
privateMoveBy: delta
	"Private!! Use 'position:' instead."
	bounds _ bounds translateBy: delta.
	fullBounds ifNotNil: [ fullBounds _ fullBounds translateBy: delta ].! !


!IndentingListItemMorph methodsFor: 'private-container protocol' stamp: 'jmv 8/23/2010 18:33'!
toggleExpandedState
	| newChildren toDelete c |
	isExpanded _ isExpanded not.
	toDelete _ OrderedCollection new.
	firstChild ifNotNil: [
		firstChild withSiblingsDo: [ :aNode |
			aNode recursiveAddTo: toDelete ]].
	container noteRemovalOfAll: toDelete.
	(isExpanded and: [ complexContents hasContents ]) ifFalse: [ ^ self changed ].
	(c _ complexContents contents) isEmpty ifTrue: [ ^ self changed ].
	newChildren _ container
		addSubmorphsAfter: self
		fromCollection: c
		allowSorting: true.
	firstChild _ newChildren first.! !


!PasteUpMorph methodsFor: 'project state' stamp: 'jmv 8/23/2010 18:41'!
viewBox: newViewBox
	self isWorldMorph ifTrue: [
		(self viewBox isNil or: [ self viewBox extent ~= newViewBox extent ])
			ifTrue: [ worldState canvas: nil ].
		worldState viewBox: newViewBox ].
	super position: newViewBox topLeft.
	fullBounds _ bounds _ newViewBox.! !


!Text methodsFor: 'accessing' stamp: 'jmv 8/23/2010 18:28'!
embeddedMorphs
	"return the list of morphs embedded in me"
	| morphs |
	morphs _ IdentitySet new.
	runs withStartStopAndValueDo: [ :start :stop :attribs |
		attribs do: [ :attrib |
			attrib anchoredMorph ifNotNil: [ morphs add: attrib anchoredMorph ]]].
	^ morphs select: [ :m |
		m is: #Morph ]! !


!TextMorph methodsFor: 'accessing' stamp: 'jmv 8/23/2010 18:33'!
newContents: stringOrText
	"Accept new text contents."
	"If my text is all the same font, use the font for my new contents"
	| newText oldEmbeddedMorphs |
	newText _ stringOrText isString
		ifTrue: [ | textSize |
			(text notNil and: [
				(textSize _ text size) > 0 and: [ (text runLengthFor: 1) = textSize ]])
				ifTrue: [ | attribs |
					attribs _ text attributesAt: 1.
					Text
						initialStyle: text initialStyleOrNil
						string: stringOrText copy
						attributes: attribs ]
				ifFalse: [ Text fromString: stringOrText copy ]]
		ifFalse: [ stringOrText copy asText ].	"should be veryDeepCopy?"
	(text = newText and: [ text runs = newText runs ]) ifTrue: [ ^ self ].
	text ifNotNil: [
		oldEmbeddedMorphs _ text embeddedMorphs.
		self removeAllMorphsIn: oldEmbeddedMorphs.
		oldEmbeddedMorphs do: [ :m |
			m delete ]].
	text _ newText.
	"add all morphs off the visible region; they'll be moved into the right 
	place when they become visible. (this can make the scrollable area too 
	large, though)"
	newText embeddedMorphs do: [ :m |
		self addMorph: m.
		m position: -1000 @ 0 ].
	self releaseParagraph.
	"update the paragraph cache"
	self paragraph.
	"re-instantiate to set bounds"
	self world ifNotNil: [ self world startSteppingSubmorphsOf: self ].! !

Morph removeSelector: #doLayoutIn:!
Morph removeSelector: #layoutInBounds:!
Morph removeSelector: #layoutProportionallyIn:!
LightWidget removeSelector: #layoutProportionallyIn:!
