[squeak-dev] The Trunk: Morphic-mt.1925.mcz

commits at source.squeak.org commits at source.squeak.org
Fri Mar 4 11:07:00 UTC 2022

Marcel Taeumel uploaded a new version of Morphic to project The Trunk:

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

Name: Morphic-mt.1925
Author: mt
Time: 4 March 2022, 12:06:55.474297 pm
UUID: c1de3832-5419-5840-b5d6-86794370c969
Ancestors: Morphic-mt.1924

Avoid superfluous re-compositions of paragraphs in shrink-wrapping text morphs.

This also fixes the issue where composition "exploded downwards" for too-small containers. For shrink-wrapping, the paragraph will now always use the unadjusted container, for which partial re-composition was never built, and recompose everything. See #compose:style:from:in:.

Note that this means that input/composition in (multi-line) text morphs with #hResizing = #shrinkWrap remains more expensive than the ones with #rigid or #spaceFill. For our one-line input fields, it input might now even be a little bit faster than before.

Nukes unused #fixLastWithHeight:.

=============== Diff against Morphic-mt.1924 ===============

Item was changed:
  Object subclass: #NewParagraph
+ 	instanceVariableNames: 'text textStyle firstCharacterIndex container containerUnadjusted lines positionWhenComposed offsetToEnd maxRightX selectionStart selectionStop wantsColumnBreaks focused caretRect showCaret caretColor selectionColor unfocusedSelectionColor'
- 	instanceVariableNames: 'text textStyle firstCharacterIndex container lines positionWhenComposed offsetToEnd maxRightX selectionStart selectionStop wantsColumnBreaks focused caretRect showCaret caretColor selectionColor unfocusedSelectionColor'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Morphic-Text Support'!
  !NewParagraph commentStamp: '<historical>' prior: 0!
  A Paragraph represents text that has been laid out, or composed, in some container.
  	text 		A Text with encoded per-character emphasis.
  	textStyle	A TextStyle with font set, line height and horizontal alignment.
  	firstCharacterIndex    The starting index in text for this paragraph, allowing
  				composition of a long text into a number of containers.
  	container	A Rectangle or TextContainer that determines where text can go.
  	lines		An Array of TextLines comprising the final layout of the text
  				after it has been composed within its container.
  	positionWhenComposed   As its name implies.  Allows display at new locations
  				without the need to recompose the text.
  Lines are ordered vertically.  However, for a given y, there may be several lines in left to right order.  Lines must never be empty, even if text is empty.
  Notes on yet another hack - 5 Feb 2001
  We really need to clean up #composeLinesFrom:to:delta:into:priorLines:atY:!!!!!!
  I added one more habdful of code to correct:
  This is an annoying bug that's been around for a couple of years, but I finally figured out how to duplicate the problem, so I figured I'd just report it now.  (It doesn't necessarily have to be fixed for 3.0 if it looks messy, but if it's a simple fix, it would be worth it.)
  In Morphic, if you have the following text in a workspace:
  This is line 1
  This is line 2
  **and** you have a return character after line 2, you will normally be able to click the mouse two times below line 2 in order to select all the text.  If you edit line 2 (e.g. so that it reads "line number 2"), you can still select all the text by clicking below the second line.  However, if you edit line 1, you will not be able to select all the text from the bottom in the same way.  Things get messed up such that the last return character seems to be gone.  In this state, if you position the cursor immediately after the 2, and press the right arrow, the cursor jumps to the beginning of line 2... oof. (report by Doug Way)
  While I don't have a very deep understanding of the above mentioned method, I was able to determine that text ending in a CR worked better in the editor when the last entry in <lines> had a start of text size + 1 and a stop of text size. I have accordingly added code near the end to ensure this. It seems to have fixed the problem, but we do need to clean this baby up some day. - Bob

Item was changed:
  ----- Method: NewParagraph>>adjustRightXDownTo: (in category 'private') -----
  adjustRightXDownTo: minWidth
+ 	| shrink minRight |
+ 	minRight := container left + minWidth.
+ 	shrink := container right - (maxRightX max: minRight).
- 	| shrink |
- 	shrink := container right - maxRightX.
  	lines do: [:line | line paddingWidth: (line paddingWidth - shrink)].
+ 	containerUnadjusted := container.
+ 	container := container withRight: (maxRightX + self caretWidth max: minRight).!
- 	container := container withRight: (maxRightX + self caretWidth max: minWidth).!

Item was changed:
  ----- Method: NewParagraph>>compose:style:from:in: (in category 'composition') -----
  compose: t style: ts from: startingIndex in: textContainer
  	text := t.
  	textStyle := ts.
  	firstCharacterIndex := startingIndex.
  	offsetToEnd := text size - firstCharacterIndex.
  	container := textContainer.
+ 	containerUnadjusted := nil.
  	self composeAll!

Item was removed:
- ----- Method: NewParagraph>>fixLastWithHeight: (in category 'composition') -----
- fixLastWithHeight: lineHeightGuess
- "This awful bit is to ensure that if we have scanned all the text and the last character is a CR that there is a null line at the end of lines. Sometimes this was not happening which caused anomalous selections when selecting all the text. This is implemented as a post-composition fixup because I coul;dn't figure out where to put it in the main logic."
- 	| oldLastLine newRectangle line |
- 	(text size > 1 and: [text last = Character cr]) ifFalse: [^self].
- 	oldLastLine := lines last.
- 	oldLastLine last - oldLastLine first >= 0 ifFalse: [^self].
- 	oldLastLine last = text size ifFalse: [^self].
- 	newRectangle := oldLastLine left @ oldLastLine bottom 
- 				extent: 0@(oldLastLine bottom - oldLastLine top).
- 	"Even though we may be below the bottom of the container,
- 	it is still necessary to compose the last line for consistency..."
- 	line := TextLine start: text size+1 stop: text size internalSpaces: 0 paddingWidth: 0.
- 	line rectangle: newRectangle.
- 	line lineHeight: lineHeightGuess baseline: textStyle baseline.
- 	lines := lines, (Array with: line).
- !

Item was changed:
  ----- Method: NewParagraph>>recomposeFrom:to:delta: (in category 'composition') -----
  recomposeFrom: start to: stop delta: delta
  	"Recompose this paragraph.  The altered portion is between start and stop.
  	Recomposition may continue to the end of the text, due to a ripple effect.
  	Delta is the amount by which the current text is longer than it was
  	when its current lines were composed."
  	| startLine newLines |
+ 	containerUnadjusted ifNotNil: [
+ 		"Somebody called #adjustRightX. We must recompose everything to avoid strange line breaks and clipping."
+ 		container := containerUnadjusted. self composeAll; adjustRightX. ^ self].
  	"Have to recompose line above in case a word-break was affected."
  	startLine := (self lineIndexOfCharacterIndex: start) - 1 max: 1.
  	[startLine > 1 and: [(lines at: startLine-1) top = (lines at: startLine) top]]
  		whileTrue: [startLine := startLine - 1].  "Find leftmost of line pieces"
  	newLines := OrderedCollection new: lines size + 1.
  	1 to: startLine-1 do: [:i | newLines addLast: (lines at: i)].
  	self composeLinesFrom: (lines at: startLine) first to: stop delta: delta
  			into: newLines priorLines: lines
  			atY: (lines at: startLine) top!

Item was changed:
  ----- Method: TextMorph>>handleInteraction:fromEvent: (in category 'editing') -----
  handleInteraction: interactionBlock fromEvent: evt
  	"Perform the changes in interactionBlock, noting any change in selection
  	and possibly a change in the size of the paragraph (ar 9/22/2001 - added for TextPrintIts)"
  	| oldEditor oldParagraph oldText oldSelection |
  	oldEditor := editor.
  	oldParagraph := paragraph.
  	oldText := oldParagraph text copy.
  	oldSelection := oldParagraph selectionRects. "already copy"
  	"Note old selection."
  	self selectionChanged: oldSelection.
  	interactionBlock value.
  	(oldParagraph == paragraph) ifTrue:[
  		"this will not work if the paragraph changed"
  		editor := oldEditor.     "since it may have been changed while in block"
  	"Note new selection."
  	paragraph selectionRects in: [:newSelection |
  		newSelection ~= oldSelection ifTrue: [
  			self selectionChanged: newSelection]].
  	(oldText = paragraph text and: [ oldText runs = paragraph text runs ])
+ 		ifFalse: [ self updateFromParagraph ].
- 		ifFalse:[ 
- 			self paragraph composeAll.
- 			self updateFromParagraph ].
  	self flag: #ImmPlugin.
  	"self setCompositionWindow."!

Item was changed:
  ----- Method: TextMorph>>updateFromParagraph (in category 'private') -----
  	"A change has taken place in my paragraph, as a result of editing and I must be updated.  If a line break causes recomposition of the current paragraph, or it the selection has entered a different paragraph, then the current editor will be released, and must be reinstalled with the resulting new paragraph, while retaining any editor state, such as selection, undo state, and current typing emphasis."
  	| newStyle sel oldLast oldEditor back |
  	paragraph ifNil: [^self].
  	wrapFlag ifNil: [wrapFlag := true].
  	editor ifNotNil: 
  			[oldEditor := editor.
  			sel := editor selectionInterval.
  			editor storeSelectionInParagraph].
  	text := paragraph text.
  	paragraph textStyle = textStyle 
  		ifTrue: [self fit]
  			["Broadcast style changes to all morphs"
  			newStyle := paragraph textStyle.
  			(self firstInChain text: text textStyle: newStyle) recomposeChain.
  			editor ifNotNil: [self installEditorToReplace: editor]].
+ 	self layoutChanged.
- 	(self isAutoFit and: [self isWrapped not])
- 		ifTrue: [self extent: self paragraph extent; composeToBounds]
- 		ifFalse: [self layoutChanged].
  	sel ifNil: [^self].
  	"If selection is in top line, then recompose predecessor for possible ripple-back"
  	predecessor ifNotNil: 
  			[sel first <= (self paragraph lines first last + 1) 
  					[oldLast := predecessor lastCharacterIndex.
  					predecessor paragraph 
  						recomposeFrom: oldLast
  						to: text size
  						delta: 0.
  					oldLast = predecessor lastCharacterIndex 
  							[predecessor changed.	"really only last line"
  							self predecessorChanged]]].
  	((back := predecessor notNil 
  				and: [sel first <= self paragraph firstCharacterIndex]) or: 
  				[successor notNil 
  					and: [sel first > (self paragraph lastCharacterIndex + 1)]]) 
  			["The selection is no longer inside this paragraph.
  		Pass focus to the paragraph that should be in control."
  			back ifTrue: [predecessor recomposeChain] ifFalse: [self recomposeChain].
  			self firstInChain withSuccessorsDo: 
  					[:m | 
  					(sel first between: m firstCharacterIndex and: m lastCharacterIndex + 1) 
  							[m installEditorToReplace: oldEditor.
  							^self passKeyboardFocusTo: m]].
  			self error: 'Inconsistency in text editor'	"Must be somewhere in the successor chain"].
  	editor ifNil: 
  			["Reinstate selection after, eg, style change"
  			self installEditorToReplace: oldEditor].
  	self flag: #ImmPlugin.
  	"self setCompositionWindow."

More information about the Squeak-dev mailing list