'From Squeak6.0alpha of 11 May 2018 [latest update: #17975] on 11 May 2018 at 4:22:15 pm'!
Object subclass: #Morph
	instanceVariableNames: 'bounds owner submorphs fullBounds color extension '
	classVariableNames: 'IndicateKeyboardFocus PreferredCornerRadius UseSoftDropShadow HaloForAll MetaMenuForAll '
	poolDictionaries: ''
	category: 'Morphic-Kernel'!

!Object methodsFor: 'graph model' stamp: 'mt 5/11/2018 16:20'!
addModelYellowButtonMenuItemsTo: aCustomMenu forMorph: aMorph hand: aHandMorph 
	"The receiver serves as the model for aMorph; a menu is being constructed for the morph, and here the receiver is able to add its own items"
	
	aCustomMenu add: 'inspect model' translated target: self action: #inspect.
	^aCustomMenu
! !

!Object methodsFor: 'graph model' stamp: 'mt 5/11/2018 16:21'!
hasModelYellowButtonMenuItems
	^ true! !


!Morph methodsFor: 'menu' stamp: 'mt 5/11/2018 16:21'!
addYellowButtonMenuItemsTo: aMenu event: evt 
	"Populate aMenu with appropriate menu items for a  
	yellow-button (context menu) click."
	aMenu defaultTarget: self.
	""
	Preferences noviceMode
		ifFalse: [aMenu addStayUpItem].
	""
	self addModelYellowButtonItemsTo: aMenu event: evt.
	""
	Preferences generalizedYellowButtonMenu
		ifFalse: [^ self].
	""
	aMenu addLine.
	aMenu add: 'inspect' translated action: #inspect.
	""
	aMenu addLine.
	self world selectedObject == self
		ifTrue: [aMenu add: 'deselect' translated action: #removeHalo]
		ifFalse: [aMenu add: 'select' translated action: #addHalo].
	""
	(self isWorldMorph
			or: [self mustBeBackmost
			or: [self wantsToBeTopmost]])
		ifFalse: [""
			aMenu addLine.
			aMenu add: 'send to back' translated action: #goBehind.
			aMenu add: 'bring to front' translated action: #comeToFront.
			self addEmbeddingMenuItemsTo: aMenu hand: evt hand].
	""
	self isWorldMorph
		ifFalse: [""
	Smalltalk
		at: #NCAAConnectorMorph
		ifPresent: [:connectorClass | 
			aMenu addLine.
			aMenu add: 'connect to' translated action: #startWiring.
			aMenu addLine].
	""

			self isFullOnScreen
				ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]].
	""
	Preferences noviceMode
		ifFalse: [""
			self addLayoutMenuItems: aMenu hand: evt hand.
			(owner notNil
					and: [owner isTextMorph])
				ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]].
	""
	self isWorldMorph
		ifFalse: [""
			aMenu addLine.
			self addToggleItemsToHaloMenu: aMenu].
	""
	aMenu addLine.
	self isWorldMorph
		ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:].
	(self allStringsAfter: nil) isEmpty
		ifFalse: [aMenu add: 'copy text' translated action: #clipText].
	""
	self addExportMenuItems: aMenu hand: evt hand.
	""
	(Preferences noviceMode not
			and: [self isWorldMorph not])
		ifTrue: [""
			aMenu addLine.
			aMenu add: 'adhere to edge...' translated action: #adhereToEdge].
	""
	self addCustomMenuItems: aMenu hand: evt hand! !


!Morph class methodsFor: 'preferences' stamp: 'mt 5/11/2018 16:19'!
haloForAll

	<preference: 'Offer Halo for All Morphs'
		categoryList: #(Morphic)
		description: 'If enabled, there will be a halo provided for any morph after a certain input gesture is detected, which is usually a BLUE (middle) mouse click.'
		type: #Boolean>
	^ HaloForAll ifNil: [true]! !

!Morph class methodsFor: 'preferences' stamp: 'mt 5/11/2018 16:16'!
haloForAll: aBoolean

	HaloForAll := aBoolean.! !

!Morph class methodsFor: 'preferences' stamp: 'mt 5/11/2018 16:19'!
metaMenuForAll

	<preference: 'Offer Meta Menu for All Morphs'
		categoryList: #(Morphic)
		description: 'If enabled, there will be a meta menu provided for any morph after a certain input gesture is detected, which is usually a CTRL+Any mouse click.'
		type: #Boolean>
	^ MetaMenuForAll ifNil: [true]! !

!Morph class methodsFor: 'preferences' stamp: 'mt 5/11/2018 16:08'!
metaMenuForAll: aBoolean

	MetaMenuForAll := aBoolean.! !


!PasteUpMorph methodsFor: 'events-processing' stamp: 'mt 5/11/2018 16:16'!
tryInvokeHalo: anEvent

	| innerMost target |
	anEvent hand halo ifNotNil: [^ self "No invocation needed. Halo will handle transfer itself."].
	Preferences noviceMode ifTrue: [^ self "No halo in novice mode."].
	Morph haloForAll ifFalse: [^ self].
	
	innerMost := (self morphsAt: anEvent position unlocked: true) first.
	
	"1) Try to use innermost morph but skip all the ones that do not want to show a halo along the owner chain."
	target := innerMost.
	[target isNil or: [target wantsHaloFromClick]]
		whileFalse: [target := target owner].
	target ifNil: [^ self].
	
	"2) Without a modifier, which is normal, find the outermost container for that inner morph."
	(innerMost == self or: [anEvent shiftPressed]) ifFalse: [
		| previousTargets |
		previousTargets := OrderedCollection new.
		[target notNil and: [target owner ~~ self]] whileTrue: [
			previousTargets add: target.
			target := target owner].
		target ifNil: [^ self].
		[previousTargets isEmpty or: [target wantsHaloFromClick]] whileFalse: [
			target := previousTargets removeLast].
		target wantsHaloFromClick ifFalse: [^ self]].
		
	"3) Now that we have the target, show the halo. Abort event dispatching, too, to avoid confusion."
	anEvent hand newMouseFocus: target event: anEvent.
	target invokeHaloOrMove: anEvent.
	anEvent ignore.! !

!PasteUpMorph methodsFor: 'events-processing' stamp: 'mt 5/11/2018 16:17'!
tryInvokeMetaMenu: anEvent

	| innerMost target |
	Morph metaMenuForAll ifFalse: [^ self].
	Preferences eToyFriendly ifTrue: [^ self].
	
	innerMost := (self morphsAt: anEvent position unlocked: true) first.
	
	"Traverse the owner chain if some morph does not want to show its meta menu."
	target := innerMost.
	[target isNil or: [target wantsMetaMenu]] whileFalse: [target := target owner].
	target ifNil: [^ self].
	
	target invokeMetaMenu: anEvent.
	anEvent ignore.! !

Object subclass: #Morph
	instanceVariableNames: 'bounds owner submorphs fullBounds color extension'
	classVariableNames: 'HaloForAll IndicateKeyboardFocus MetaMenuForAll PreferredCornerRadius UseSoftDropShadow'
	poolDictionaries: ''
	category: 'Morphic-Kernel'!
