'From Squeak 2.3 of January 14, 1999 on 27 February 1999 at 8:21:21 pm'! "Change Set: SizedScrollBar Date: 27 February 1999 Author: Doug Way This enhances the Morphic scrollbars so that they are proportionally sized, i.e. the size of the bar expands to show how much of the entire contents you're seeing in the viewable area. All of the tools in Morphic which use PluggableListMorphs and PluggableTextMorphs will use the enhanced scrollbars. In addition to the proportioned scrollbars, a fix was made to the arrow buttons on the Morphic scrollbar... previously, clicking on the up-arrow scrolled up 2 lines at a time instead of 1."! !ScrollPane methodsFor: 'initialization' stamp: 'dew 2/19/1999 20:27'! setScrollDeltas | range | scroller hasSubmorphs ifFalse: [scrollBar interval: 1.0. ^ self]. range _ self leftoverScrollRange. range = 0 ifTrue: [^ scrollBar scrollDelta: 0.02 pageDelta: 0.2; interval: 1.0]. "Set up for one line (for arrow scrolling), or a full pane less one line (for paging)." scrollBar scrollDelta: (self scrollDeltaHeight / range) asFloat pageDelta: ((self innerBounds height - self scrollDeltaHeight) / range) asFloat. scrollBar interval: ((self innerBounds height - self scrollDeltaHeight) / self totalScrollRange) asFloat. ! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 2/19/1999 18:46'! leftoverScrollRange "Return the entire scrolling range minus the currently viewed area." ^ self totalScrollRange - (bounds height * 3 // 4) max: 0 ! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 2/19/1999 18:49'! scrollBy: delta "Move the contents in the direction delta." "For now, delta is assumed to have a zero x-component" | newYoffset r | newYoffset _ scroller offset y - delta y max: 0. scroller offset: scroller offset x @ newYoffset. (r _ self leftoverScrollRange) = 0 ifTrue: [scrollBar value: 0.0] ifFalse: [scrollBar value: newYoffset asFloat / r]! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 2/19/1999 17:08'! scrollDeltaHeight "Return the increment in pixels which this pane should be scrolled (normally a subclass responsibility)." ^ 12 ! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 2/19/1999 20:24'! totalScrollRange "Return the entire scrolling range." ^ (scroller submorphBounds encompass: 0@0) height ! ! !ScrollPane methodsFor: 'scroll bar events' stamp: 'dew 2/19/1999 18:48'! scrollBarValue: scrollValue scroller hasSubmorphs ifFalse: [^ self]. scroller offset: -3 @ (self leftoverScrollRange * scrollValue)! ! !PluggableListMorph methodsFor: 'initialization' stamp: 'dew 2/21/1999 03:03'! list: listOfStrings | morphList handler h loc index | scroller removeAllMorphs. list _ listOfStrings ifNil: [Array new]. list isEmpty ifTrue: [self setScrollDeltas. ^ self selectedMorph: nil]. "NOTE: we will want a quick StringMorph init message, possibly even combined with event install and positioning" morphList _ list collect: [:item | StringMorph contents: item font: font]. "Sensitize first morph and copy handler to all the rest" morphList first on: #mouseDown send: #mouseDown:onItem: to: self. handler _ morphList first eventHandler. morphList do: [:m | m eventHandler: handler]. "Lay items out vertically and install them in the scroller" h _ morphList first height "self listItemHeight". loc _ 0@0. morphList do: [:m | m bounds: (loc extent: 9999@h). loc _ loc + (0@h)]. scroller addAllMorphs: morphList. index _ self getCurrentSelectionIndex. self selectedMorph: (index = 0 ifTrue: [nil] ifFalse: [morphList at: index]). self setScrollDeltas. scrollBar setValue: 0.0.! ! !PluggableListMorph methodsFor: 'selection' stamp: 'dew 2/19/1999 18:47'! selectionIndex: index "Called internally to select the index-th item." | theMorph range | (index isNil or: [index > scroller submorphs size]) ifTrue: [^ self]. (theMorph _ index = 0 ifTrue: [nil] ifFalse: [scroller submorphs at: index]) ifNotNil: [((theMorph bounds top - scroller offset y) >= 0 and: [(theMorph bounds bottom - scroller offset y) <= bounds height]) ifFalse: ["Scroll into view -- should be elsewhere" range _ self leftoverScrollRange. scrollBar value: (range > 0 ifTrue: [((index-1 * theMorph height) / self leftoverScrollRange) truncateTo: scrollBar scrollDelta] ifFalse: [0]). scroller offset: -3 @ (range * scrollBar value)]]. self selectedMorph: theMorph! ! !PluggableListMorph methodsFor: 'geometry' stamp: 'dew 2/19/1999 17:09'! scrollDeltaHeight "Return the increment in pixels which this pane should be scrolled." ^ scroller firstSubmorph height ! ! !PluggableTextMorph methodsFor: 'initialization' stamp: 'dew 2/21/1999 03:07'! extent: newExtent super extent: (newExtent max: 36@16). textMorph ifNotNil: [textMorph extent: (self innerBounds width-6)@self height]. self setScrollDeltas! ! !PluggableTextMorph methodsFor: 'geometry' stamp: 'dew 2/19/1999 17:08'! scrollDeltaHeight "Return the increment in pixels which this pane should be scrolled." ^ scroller firstSubmorph defaultLineHeight ! ! !Slider methodsFor: 'initialize' stamp: 'dew 2/27/1999 01:31'! initializeSlider slider := RectangleMorph newBounds: self totalSliderArea color: Color veryLightGray. slider on: #mouseStillDown send: #scrollAbsolute: to: self. slider on: #mouseDown send: #mouseDownInSlider: to: self. slider setBorderWidth: 2 borderColor: #raised. self addMorph: slider. self computeSlider. ! ! !Slider methodsFor: 'geometry' stamp: 'dew 2/21/1999 03:08'! extent: newExtent newExtent = bounds extent ifTrue: [^ self]. bounds isWide ifTrue: [super extent: (newExtent x max: self sliderThickness * 2) @ newExtent y] ifFalse: [super extent: newExtent x @ (newExtent y max: self sliderThickness * 2)]. self removeAllMorphs; initializeSlider! ! !Slider methodsFor: 'scrolling' stamp: 'dew 2/21/1999 03:09'! scrollAbsolute: event | r p | r _ self roomToMove. bounds isWide ifTrue: [r width = 0 ifTrue: [^self]] ifFalse: [r height = 0 ifTrue: [^self]]. p _ event targetPoint adhereTo: r. self setValue: (bounds isWide ifTrue: [(p x - r left) asFloat / r width] ifFalse: [(p y - r top) asFloat / r height])! ! !Slider methodsFor: 'other events' stamp: 'dew 2/27/1999 01:36'! mouseDownInSlider: event ! ! !ScrollBar methodsFor: 'access' stamp: 'dew 2/21/1999 03:08'! interval: d "Supply an optional floating fraction so slider can expand to indicate range" interval _ d min: 1.0. self expandSlider. self computeSlider.! ! !ScrollBar methodsFor: 'geometry' stamp: 'dew 2/21/1999 03:08'! computeSlider "interval ifNotNil: [self expandSlider]." super computeSlider. ! ! !ScrollBar methodsFor: 'geometry' stamp: 'dew 2/27/1999 18:22'! expandSlider "Compute the new size of the slider (use the old sliderThickness as a minimum)." | r | r _ self totalSliderArea. slider extent: (bounds isWide ifTrue: [((r width * interval) asInteger max: self sliderThickness) @ slider height] ifFalse: [slider width @ ((r height * interval) asInteger max: self sliderThickness)])! ! !ScrollBar methodsFor: 'geometry' stamp: 'dew 2/21/1999 03:08'! sliderExtent "The sliderExtent is now stored in the slider itself, not hardcoded as it is in the superclass." ^slider extent! ! !ScrollBar methodsFor: 'scrolling' stamp: 'dew 2/21/1999 03:08'! setValue: newValue "Using roundTo: instead of truncateTo: ensures that scrollUp will scroll the same distance as scrollDown." ^ super setValue: (newValue roundTo: scrollDelta)! ! !ScrollBar methodsFor: 'other events' stamp: 'dew 2/27/1999 01:34'! mouseDownInSlider: event "this makes sure the entire scrollable area is in fact visible if the interval is 1.0" interval = 1.0 ifTrue: [self setValue: value]. super mouseDownInSlider: event! ! !TextMorphForEditView methodsFor: 'private' stamp: 'dew 2/21/1999 03:09'! updateFromParagraph super updateFromParagraph. editView setScrollDeltas.! ! PluggableListMorph removeSelector: #setScrollDeltas! PluggableTextMorph removeSelector: #setScrollDeltas!