[Pkg] The Trunk: Morphic-mt.1378.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Dec 20 15:03:06 UTC 2017


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

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

Name: Morphic-mt.1378
Author: mt
Time: 20 December 2017, 4:02:40.532079 pm
UUID: 94c3d2cd-41b5-9742-a30e-7281fec08fd6
Ancestors: Morphic-mt.1377

Makes use of the text cursor in text morphs. If you want, you can drap/drop text selections, too, which has to be enabled via preference "Draggable Text Selection". Fixes cursor appearance when invoking halo, too.

Note that Shout was a little bit annoying here. See TextMorphForEditView >> #acceptDroppingMorph:event:.

Also note that due to the role of TextEditor, dragging is prepared in TextEditor >> #mouseDown: but started in TextMorph >> #startDrag:.

Finally, note that I decided to put the current (rudimentary) version of text dropping into TextMorphForEditView, which makes text-drop only work in PluggableTextMorphs (i.e. ToolBulder-tools) and not pure TextMorphs.

=============== Diff against Morphic-mt.1377 ===============

Item was added:
+ ----- Method: Editor>>destructiveBackWord (in category 'typing/selecting keys') -----
+ destructiveBackWord
+ 	"If the selection is not a caret, delete it and leave it in the backspace buffer.
+ 	 Else if there is typeahead, delete it.
+ 	 Else, delete the word before the caret."
+ 
+ 	| startIndex |
+ 	self hasCaret
+ 		ifTrue: "a caret, delete at least one character"
+ 			[startIndex := 1 max: self markIndex - 1.
+ 			[startIndex > 1 and:
+ 				[(self string at: startIndex - 1) tokenish]]
+ 				whileTrue:
+ 					[startIndex := startIndex - 1]]
+ 		ifFalse: "a non-caret, just delete it"
+ 			[startIndex := self markIndex].
+ 	self backTo: startIndex.
+ 	^ false!

Item was changed:
  ----- Method: Editor>>destructiveBackWord: (in category 'typing/selecting keys') -----
  destructiveBackWord: aKeyboardEvent 
+ 	
+ 	^ self destructiveBackWord!
- 	"If the selection is not a caret, delete it and leave it in the backspace buffer.
- 	 Else if there is typeahead, delete it.
- 	 Else, delete the word before the caret."
- 
- 	| startIndex |
- 	self hasCaret
- 		ifTrue: "a caret, delete at least one character"
- 			[startIndex := 1 max: self markIndex - 1.
- 			[startIndex > 1 and:
- 				[(self string at: startIndex - 1) tokenish]]
- 				whileTrue:
- 					[startIndex := startIndex - 1]]
- 		ifFalse: "a non-caret, just delete it"
- 			[startIndex := self markIndex].
- 	self backTo: startIndex.
- 	^false!

Item was changed:
  ----- Method: Morph>>invokeHaloOrMove: (in category 'meta-actions') -----
  invokeHaloOrMove: anEvent
  	"Special gestures (cmd-mouse on the Macintosh; Alt-mouse on Windows and Unix) allow a mouse-sensitive morph to be moved or bring up a halo for the morph."
  	| h tfm doNotDrag |
  	h := anEvent hand halo.
  	"Prevent wrap around halo transfers originating from throwing the event back in"
  	doNotDrag := false.
  	h ifNotNil:[
  		(h innerTarget == self) ifTrue:[doNotDrag := true].
  		(h innerTarget hasOwner: self) ifTrue:[doNotDrag := true].
  		(self hasOwner: h target) ifTrue:[doNotDrag := true]].
  
  	tfm := (self transformedFrom: nil) inverseTransformation.
  
  	"cmd-drag on flexed morphs works better this way"
  	h := self addHalo: (anEvent transformedBy: tfm).
  	h ifNil: [^ self].
  	doNotDrag ifTrue:[^self].
  	"Initiate drag transition if requested"
  	anEvent hand 
  		waitForClicksOrDrag: h
  		event: (anEvent transformedBy: tfm)
  		selectors: { nil. nil. nil. #startDragTarget:. }
  		threshold: HandMorph dragThreshold.
  	"Pass focus explicitly here"
+ 	anEvent hand newMouseFocus: h.
+ 	"Reset temporary cursors to make available halo interaction visible."
+ 	anEvent hand showTemporaryCursor: nil.!
- 	anEvent hand newMouseFocus: h.!

Item was added:
+ ----- Method: Text>>asDraggableMorph (in category '*Morphic-converting') -----
+ asDraggableMorph
+ 	^ self asMorph!

Item was added:
+ ----- Method: TextEditor>>addText:event: (in category 'editing dragdrop') -----
+ addText: aText event: anEvent
+ 	"Used for dropping/inserting text."
+ 	
+ 	| index |
+ 	index := (paragraph characterBlockAtPoint: anEvent position) stringIndex.
+ 	self closeTypeIn.
+ 	
+ 	self selectInvisiblyFrom: index to: index-1.
+ 	self replaceSelectionWith: aText.!

Item was added:
+ ----- Method: TextEditor>>click: (in category 'events') -----
+ click: evt
+ 	"This is called if you click in a text selection while drag is enabled, but you did not drag. Also see #startDrag:."
+ 	
+ 	self selectAt: (paragraph characterBlockAtPoint: evt position) stringIndex.!

Item was added:
+ ----- Method: TextEditor>>isEventInSelection: (in category 'events') -----
+ isEventInSelection: evt
+ 	"Check whether the event position is within the current selection."
+ 
+ 	| pt a b |	
+ 	self hasSelection ifFalse: [^ false].
+ 
+ 	pt := evt position.
+ 	a := self startBlock.
+ 	b := self stopBlock.
+ 	
+ 	^ (pt >= a topLeft and: [pt <= b bottomLeft]) "Start and stop in same line"
+ 		or: [
+ 			a top < b top and: [ "Start and stop in different lines."
+ 				((pt y > a bottom and: [pt y < b top]) "Fully selected lines in the middle."
+ 					or: [pt x >= a left and: [pt y between: a top and: a bottom]]) "Top tail."
+ 					or: [pt x <= b left and: [pt y between: b top and: b bottom]]]]. "Bottom tail."
+ 	
+ 	
+ 	
+ 
+ 	!

Item was changed:
  ----- Method: TextEditor>>mouseDown: (in category 'events') -----
  mouseDown: evt 
+ 	"Either 1) handle text actions in the paragraph, 2) begin a text drag operation, or 3) modify the caret/selection."
+ 	
- 	"An attempt to break up the old processRedButton code into threee phases"
  	| clickPoint b |
  
  	oldInterval := self selectionInterval.
  	clickPoint := evt cursorPoint.
  	b := paragraph characterBlockAtPoint: clickPoint.
  
  	(paragraph clickAt: clickPoint for: model controller: self) ifTrue: [
  		markBlock := b.
  		pointBlock := b.
  		evt hand releaseKeyboardFocus: morph.
  		evt hand releaseMouseFocus: morph.
  		^ self ].
  	
+ 	(morph dragEnabled and: [self isEventInSelection: evt]) ifTrue: [
+ 		evt hand
+ 			waitForClicksOrDrag: morph
+ 			event: evt
+ 			selectors: {#click:. nil. nil. #startDrag:}
+ 			threshold: HandMorph dragThreshold.
+ 		morph setProperty: #waitingForTextDrag toValue: true.
+ 		^ self].
+ 	
  	evt shiftPressed
  		ifFalse: [
  			self closeTypeIn.
  			markBlock := b.
  			pointBlock := b ]
  		 ifTrue: [
  			self closeTypeIn.
  			self mouseMove: evt ].
         self storeSelectionInParagraph!

Item was changed:
  ----- Method: TextEditor>>mouseMove: (in category 'events') -----
  mouseMove: evt
+ 	"Change the selection in response to mouse-down drag. Do not change the selection if the user wants to drag the current selection."
- 	"Change the selection in response to mouse-down drag"
  
+ 	(morph hasProperty: #waitingForTextDrag) ifTrue: [^ self].
  	pointBlock := paragraph characterBlockAtPoint: evt position.
  	self storeSelectionInParagraph!

Item was changed:
  ----- Method: TextEditor>>mouseUp: (in category 'events') -----
  mouseUp: evt
  	"An attempt to break up the old processRedButton code into threee phases"
+ 
+ 	self updateCursorForEvent: evt.
+ 	morph removeProperty: #waitingForTextDrag.
+ 
  	oldInterval ifNil: [^ self].  "Patched during clickAt: repair"
  	(self hasCaret 
  		and: [oldInterval = self selectionInterval])
  		ifTrue: [self selectWord].
  	self setEmphasisHere.
  	(self isDisjointFrom: oldInterval) ifTrue:
  		[otherInterval := oldInterval].
  	self storeSelectionInParagraph!

Item was added:
+ ----- Method: TextEditor>>updateCursorForEvent: (in category 'events') -----
+ updateCursorForEvent: evt 
+ 
+ 	(((morph bounds containsPoint: evt position)
+ 		and: [morph dragEnabled not or: [(self isEventInSelection: evt) not]])
+ 		and: [evt hand temporaryCursor ~~ Cursor text])
+ 			ifTrue: [evt hand showTemporaryCursor: Cursor text]
+ 			ifFalse: [evt hand showTemporaryCursor: nil].!

Item was added:
+ ----- Method: TextMorph>>click: (in category 'event handling') -----
+ click: evt
+ 
+ 	self
+ 		handleInteraction: [self editor click: evt]
+ 		fromEvent: evt.!

Item was changed:
  ----- Method: TextMorph>>enterClickableRegion: (in category 'editing') -----
  enterClickableRegion: evt
  	| index isLink |
  	evt hand hasSubmorphs ifTrue:[^self].
- 	evt hand temporaryCursor ifNotNil:[^self].
  	paragraph ifNotNil:[
  		index := (paragraph characterBlockAtPoint: evt position) stringIndex.
  		isLink := (paragraph text attributesAt: index forStyle: paragraph textStyle) 
  					anySatisfy:[:attr| attr mayActOnClick].
+ 		isLink ifTrue:[evt hand showTemporaryCursor: Cursor webLink].
- 		isLink ifTrue:[Cursor webLink show] ifFalse:[Cursor normal show].
  	].
  !

Item was added:
+ ----- Method: TextMorph>>handlesMouseOver: (in category 'event handling') -----
+ handlesMouseOver: evt
+ 	^ self isPartsDonor not!

Item was changed:
  ----- Method: TextMorph>>mouseDown: (in category 'event handling') -----
  mouseDown: evt 
  	"Make this TextMorph be the keyboard input focus, if it isn't  
  	already, and repond to the text selection gesture."
  	
  	evt yellowButtonPressed ifTrue: [
  		"First check for option (menu) click"
  		^ self yellowButtonActivity: evt shiftPressed].
  
  	"Show the caret immediately on mouse down to give user feedback."
  	self resetBlinkCursor.
  
  	"If focus does not follow the mouse cursor and we click below everything, just grab the focus to not destroy the selection."
  	((self hasKeyboardFocus: evt hand) not and: [(self bounds containsPoint: evt position) not])
  		ifTrue: [evt hand newKeyboardFocus: self]
  		ifFalse: [
  			evt hand newKeyboardFocus: self.
  			self
+ 				handleInteraction: [self mouseEnter: evt. editor mouseDown: evt]
- 				handleInteraction: [editor mouseDown: evt]
  				fromEvent: evt].!

Item was added:
+ ----- Method: TextMorph>>mouseEnter: (in category 'event handling') -----
+ mouseEnter: evt 
+ 
+ 	self editor updateCursorForEvent: evt.!

Item was added:
+ ----- Method: TextMorph>>mouseLeave: (in category 'event handling') -----
+ mouseLeave: evt 
+ 
+ 	evt hand showTemporaryCursor: nil.!

Item was changed:
  ----- Method: TextMorph>>mouseMove: (in category 'event handling') -----
  mouseMove: evt
+ 
+ 	evt redButtonPressed ifFalse: [
+ 		self editor updateCursorForEvent: evt.
+ 		self enterClickableRegion: evt.
+ 		^ self].
+ 
+ 	self
+ 		handleInteraction: [self editor mouseMove: evt]
+ 		fromEvent: evt.!
- 	evt redButtonPressed ifFalse: [^ self enterClickableRegion: evt].
- 	self handleInteraction: [self editor mouseMove: evt] fromEvent: evt!

Item was added:
+ ----- Method: TextMorph>>startDrag: (in category 'event handling') -----
+ startDrag: evt
+ 
+ 	[evt hand grabMorph: (TransferMorph withPassenger: self selection from: self)]
+ 		ensure: [evt hand releaseMouseFocus: self].!

Item was changed:
  TextMorph subclass: #TextMorphForEditView
  	instanceVariableNames: 'editView acceptOnCR'
+ 	classVariableNames: 'DraggableTextSelection'
- 	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Morphic-Text Support'!

Item was added:
+ ----- Method: TextMorphForEditView class>>draggableTextSelection (in category 'preferences') -----
+ draggableTextSelection
+ 
+ 	<preference: 'Draggable Text Selections'
+ 		categoryList: #(editing mouse Morphic)
+ 		description: 'Whether you can drag-and-drop selections in text morphs.'
+ 		type: #Boolean>
+ 		
+ 	^ DraggableTextSelection ifNil: [false]!

Item was added:
+ ----- Method: TextMorphForEditView class>>draggableTextSelection: (in category 'preferences') -----
+ draggableTextSelection: aBoolean
+ 
+ 	DraggableTextSelection := aBoolean.
+ 	
+ 	TextMorphForEditView allInstancesDo: [:tm |
+ 		tm dragEnabled: aBoolean; dropEnabled: aBoolean].!

Item was added:
+ ----- Method: TextMorphForEditView>>acceptDroppingMorph:event: (in category 'dropping/grabbing') -----
+ acceptDroppingMorph: aTransferMorph event: evt
+ 	"Accept a text to be inserted at the event/cursor position. Either remove or keep the source text depending on the transfer morph's copy state."
+ 	
+ 	self removeProperty: #waitingForTextDrag.
+ 	
+ 	self
+ 		handleInteraction: [
+ 			aTransferMorph shouldCopy
+ 				ifFalse: [(aTransferMorph source respondsTo: #editor)
+ 					ifTrue: [aTransferMorph source editor destructiveBackWord]].
+ 			self editor addText: aTransferMorph passenger asText event: evt]
+ 		fromEvent: evt.
+ 		
+ 	self flag: #hack. "mt: Shout background styling restores the selection, which interferes here. *sigh*"
+ 	self editView instVarNamed: #selectionInterval put: nil.
+ 	(aTransferMorph source respondsTo: #editView)
+ 		ifTrue: [aTransferMorph source editView instVarNamed: #selectionInterval put: nil.]!

Item was changed:
  ----- Method: TextMorphForEditView>>initialize (in category 'initialization') -----
  initialize
+ 	
  	super initialize.
+ 	
+ 	self acceptOnCR: false.
+ 	self dragEnabled: self class draggableTextSelection.
+ 	self dropEnabled: self class draggableTextSelection.!
- 	acceptOnCR := false!

Item was added:
+ ----- Method: TextMorphForEditView>>wantsDroppedMorph:event: (in category 'dropping/grabbing') -----
+ wantsDroppedMorph: aMorph event: evt
+ 
+ 	^ ((super wantsDroppedMorph: aMorph event: evt)
+ 		and: [aMorph isKindOf: TransferMorph])
+ 		and: [aMorph passenger isString or: [aMorph passenger isText]]!



More information about the Packages mailing list