[squeak-dev] A fix for ProportionalSplitterMorph, take 2

Stéphane Rollandin lecteur at zogotounga.net
Sat Mar 31 08:47:47 UTC 2018


Repeat:

Attached is a fix for ProportionalSplitterMorph.

Currently, moving a window splitter changes all relevant frame layout
offsets; fractions are not touched. But offsets are absolute values, in
pixels, and a frame with a large offset will be badly redimensionned
when the system window extent is reduced.

To see this, open a browser, and move the main horizontal splitter way
up. Then shrink the browser: the code pane will keep a largeish height
(because of its large vertical offsets), and eventually be moved above
the browser top.

To fix this, I propose in the attached changeset to keep track of the
overall splitter delta, then on #mouseUp to recompute the fractions and
reset the offsets to the typical small values they have.

I don't know if I am being clear, but it works... try it.

(the #balanceOffsets method may possibly be simplified I guess)


Stef
-------------- next part --------------
'From Squeak5.1 of 5 September 2016 [latest update: #16549] on 31 March 2018 at 10:44:47 am'!

!ProportionalSplitterMorph methodsFor: '*People-spfa-fixes' stamp: 'spfa 3/30/2018 17:18'!
balanceOffsets

	self layoutFrame hasFixedHeight ifTrue: [
		| otop obot ctop cbot topf |

		otop := (owner submorphs detect: [:m | 
					m layoutFrame topFraction isZero] ifNone: [^ self]) in: [:tm | 
						tm top - (tm layoutFrame topOffset ifNil: [0])].

		obot := (owner submorphs detect: [:m | 
					m layoutFrame bottomFraction = 1] ifNone: [^ self]) in: [:tm | 
						tm bottom - (tm layoutFrame bottomOffset ifNil: [0])].

		ctop := (self layoutFrame topFraction * (obot - otop)) rounded 
					+ otop + (self layoutFrame topOffset ifNil: [0]).
		cbot := (self layoutFrame bottomFraction * (obot - otop)) rounded 
					+ otop + (self layoutFrame bottomOffset ifNil: [0]).

		topf := self layoutFrame topFraction.
		self layoutFrame topFraction:  ((ctop + cbot) * 0.5 - otop) / (obot - otop) asFloat.
		self layoutFrame bottomFraction: self layoutFrame topFraction.
		self layoutFrame topOffset: ctop - 
			(self layoutFrame topFraction * (obot - otop) + otop) rounded.
		self layoutFrame bottomOffset: cbot - 
			(self layoutFrame bottomFraction * (obot - otop) + otop) rounded..

		(leftOrTop copy union: rightOrBottom) do: [:m |
			(m layoutFrame topFraction closeTo: topf) ifTrue: [
				m layoutFrame topFraction: self layoutFrame topFraction.
				m layoutFrame topOffset: 
					m layoutFrame topOffset - (self valueOfProperty: #fullDelta) y].
			(m layoutFrame bottomFraction closeTo: topf) ifTrue: [
				m layoutFrame bottomFraction: self layoutFrame topFraction.
				m layoutFrame bottomOffset: 
					m layoutFrame bottomOffset - (self valueOfProperty: #fullDelta) y.]]] .

	self layoutFrame hasFixedWidth ifTrue: [
		| oleft oright cleft cright leftf |

		oleft := (owner submorphs detect: [:m | 
			m layoutFrame leftFraction isZero] ifNone: [^ self]) in: [:tm | 
				tm left - (tm layoutFrame leftOffset ifNil: [0])].

		oright := (owner submorphs detect: [:m | 
			m layoutFrame rightFraction = 1] ifNone: [^ self]) in: [:tm | 
				tm right - (tm layoutFrame rightOffset ifNil: [0])].

		cleft := (self layoutFrame leftFraction * (oright - oleft)) rounded 
					+ oleft + (self layoutFrame leftOffset ifNil: [0]).
		cright := (self layoutFrame rightFraction * (oright - oleft)) rounded 
					+ oleft + (self layoutFrame rightOffset ifNil: [0]).

		leftf := self layoutFrame leftFraction.
		self layoutFrame leftFraction: ((cleft + cright) * 0.5 - oleft) / (oright - oleft) asFloat.
		self layoutFrame rightFraction: self layoutFrame leftFraction.

		self layoutFrame leftOffset: cleft - 
			(self layoutFrame leftFraction * (oright - oleft) + oleft) rounded.
		self layoutFrame rightOffset: cright - 
			(self layoutFrame rightFraction * (oright - oleft) + oleft) rounded.

		(leftOrTop copy union: rightOrBottom) do: [:m |
			(m layoutFrame leftFraction closeTo: leftf) ifTrue: [
				m layoutFrame leftFraction: self layoutFrame leftFraction.
				m layoutFrame leftOffset: 
					m layoutFrame leftOffset - (self valueOfProperty: #fullDelta) x].
			(m layoutFrame rightFraction closeTo: leftf) ifTrue: [
				m layoutFrame rightFraction: self layoutFrame leftFraction.
				m layoutFrame rightOffset: 
					m layoutFrame rightOffset - (self valueOfProperty: #fullDelta) x.]]] .

	self removeProperty: #fullDelta.
	owner layoutChanged
! !

!ProportionalSplitterMorph methodsFor: '*People-spfa-fixes' stamp: 'spfa 3/30/2018 16:55'!
mouseDown: anEvent 
	"If the user manually drags me, don't override him with auto positioning."

	self setProperty: #fullDelta toValue: 0 at 0.

	anEvent redButtonChanged
		ifTrue: [ self withSiblingSplittersDo: [ : each | each stopStepping ] ]
		ifFalse:
			[ anEvent shiftPressed
				ifTrue: [ self startStepping ]
				ifFalse:
					[ self startStepping.
					self withSiblingSplittersDo: [ : each | each startStepping ] ] ].
	(self class showSplitterHandles not and: [ self bounds containsPoint: anEvent cursorPoint ]) ifTrue:
		[ oldColor := self color.
		self color: Color black ].
	^ super mouseDown: anEvent! !

!ProportionalSplitterMorph methodsFor: '*People-spfa-fixes' stamp: 'spfa 3/30/2018 17:18'!
mouseUp: anEvent 
	(self bounds containsPoint: anEvent cursorPoint)
		ifFalse: [anEvent hand showTemporaryCursor: nil].
	self class fastSplitterResize
		ifTrue: [self updateFromEvent: anEvent].
	traceMorph ifNotNil: [traceMorph delete. traceMorph := nil].
	self color: self getOldColor.

	self balanceOffsets! !

!ProportionalSplitterMorph methodsFor: '*People-spfa-fixes' stamp: 'spfa 3/31/2018 10:38'!
repositionBy: delta
	| selfTop selfBottom selfLeft selfRight |

	self setProperty: #fullDelta toValue: ((self valueOfProperty: #fullDelta) ifNil: [0 at 0]) + delta.

	leftOrTop do:
		[ : each | | firstRight firstBottom firstLeft firstTop |
		firstRight := each layoutFrame rightOffset ifNil: [ 0 ].
		firstBottom := each layoutFrame bottomOffset ifNil: [ 0 ].
		each layoutFrame rightOffset: firstRight + delta x.
		each layoutFrame bottomOffset: firstBottom + delta y.
		each layoutFrame hasFixedHeight ifTrue: [
			firstTop := each layoutFrame topOffset ifNil: [ 0 ].
			each layoutFrame topOffset: firstTop + delta y ].
		each layoutFrame hasFixedWidth ifTrue: [
			firstLeft := each layoutFrame leftOffset ifNil: [ 0 ].
			each layoutFrame leftOffset: firstLeft + delta x. ] ].
	rightOrBottom do:
		[ : each | | secondLeft secondTop secondRight secondBottom |
		secondLeft := each layoutFrame leftOffset ifNil: [ 0 ].
		secondTop := each layoutFrame topOffset ifNil: [ 0 ].
		each layoutFrame leftOffset: secondLeft + delta x.
		each layoutFrame topOffset: secondTop + delta y.
		each layoutFrame hasFixedHeight ifTrue: [
			secondBottom := each layoutFrame bottomOffset ifNil: [ 0 ].
			each layoutFrame bottomOffset: secondBottom + delta y. ].
		each layoutFrame hasFixedWidth ifTrue: [
			secondRight := each layoutFrame rightOffset ifNil: [ 0 ].
			each layoutFrame rightOffset: secondRight + delta x. ] ].

	selfTop := self layoutFrame topOffset ifNil: [ 0 ].
	selfBottom := self layoutFrame bottomOffset ifNil: [ 0 ].
	selfLeft := self layoutFrame leftOffset ifNil: [ 0 ].
	selfRight := self layoutFrame rightOffset ifNil: [ 0 ].
	self layoutFrame
		 topOffset: selfTop + delta y ;
		 bottomOffset: selfBottom + delta y ;
		 leftOffset: selfLeft + delta x ;
		 rightOffset: selfRight + delta x.
	self owner layoutChanged.
	self movements removeFirst; add: (splitsTopAndBottom ifTrue: [ delta y sign ] ifFalse: [ delta x sign ])! !



More information about the Squeak-dev mailing list