'From Squeak2.8alpha of 13 January 2000 [latest update: #2158] on 22 May 2000 at 5:18:18 pm'! "Change Set: HiddenScrollBar-dew Date: 23 May 2000 Author: Doug Way and Carl Gundel This enhancment optimizes Morphic scrollbars so that they are hidden when the contents of a pane are too small to be scrolled. This incorporates Carl Gundel's original fix for popup scrollbars, but now includes inboard scrollbars as well. For popup scrollbars, this fix eliminates some of the choppy feel of the UI for slow computers. For inboard scrollbars, it's more of a real-estate saving measure, allowing you to see more of the width of the pane. (Note that a new inst var 'hasFocus' was added to ScrollPane which was needed to accurately track focus. This inst var should probably be moved to a higher superclass (Morph?) eventually.) Works with Squeak 2.6 and 2.7."! ComponentLikeModel subclass: #ScrollPane instanceVariableNames: 'scrollBar scroller retractableScrollBar scrollBarOnLeft getMenuSelector getMenuTitleSelector hasFocus ' classVariableNames: '' poolDictionaries: '' category: 'Morphic-Windows'! !ScrollBar methodsFor: 'other events' stamp: 'dew 10/17/1999 19:41'! mouseDownInSlider: event interval = 1.0 ifTrue: ["make the entire scrollable area visible if a full scrollbar is clicked on" self setValue: 0. self model hideOrShowScrollBar]. super mouseDownInSlider: event! ! !ScrollPane methodsFor: 'initialization' stamp: 'dew 5/22/2000 14:32'! initialize super initialize. hasFocus _ false. borderWidth _ 2. borderColor _ Color black. retractableScrollBar _ (Preferences valueOfFlag: #inboardScrollbars) not. scrollBarOnLeft _ (Preferences valueOfFlag: #scrollBarsOnRight) not. scrollBar := ScrollBar new model: self slotName: 'scrollBar'. scrollBar borderWidth: 1; borderColor: Color black. scroller := TransformMorph new color: Color transparent. scroller offset: -3@0. self addMorph: scroller. self on: #mouseEnter send: #mouseEnter: to: self. self on: #mouseLeave send: #mouseLeave: to: self. self extent: 150@120! ! !ScrollPane methodsFor: 'initialization' stamp: 'dew 10/17/1999 19:41'! setScrollDeltas | range delta | self hideOrShowScrollBar. scroller hasSubmorphs ifFalse: [scrollBar interval: 1.0. ^ self]. range _ self leftoverScrollRange. delta _ self scrollDeltaHeight. 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: (delta / range) asFloat pageDelta: ((self innerBounds height - delta) / range) asFloat. scrollBar interval: ((self innerBounds height - delta) / self totalScrollRange) asFloat. ! ! !ScrollPane methodsFor: 'access' stamp: 'dew 5/22/2000 15:06'! hasFocus "hasFocus is currently set by mouse enter/leave events. This inst var should probably be moved up to a higher superclass, in order to support a general keyboard focus mechanism." hasFocus ifNil: [^ false]. ^ hasFocus.! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 10/17/1999 19:41'! innerBounds | inner w | inner _ super innerBounds. w _ self scrollbarWidth. retractableScrollBar | (submorphs includes: scrollBar) not ifTrue: [^ inner] ifFalse: [^ (scrollBarOnLeft ifTrue: [inner topLeft + ((w-1)@0) corner: inner bottomRight] ifFalse: [inner topLeft corner: inner bottomRight - ((w-2)@0)])]! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 10/17/1999 19:41'! resetExtent "Reset the extent. (may be overridden by subclasses which need to do more than this)" self resizeScroller! ! !ScrollPane methodsFor: 'geometry' stamp: 'dew 10/17/1999 19:41'! unadjustedScrollRange "Return the difference between the height extent of the receiver's submorphs and its own height extent (plus an extra 1/2 line height)." scroller submorphBounds ifNil: [^ 0]. ^ self totalScrollRange - bounds height + (self scrollDeltaHeight / 2) max: 0! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 5/22/2000 15:18'! hideOrShowScrollBar "Hide or show the scrollbar depending on if the pane is scrolled/scrollable." "Don't do anything with the retractable scrollbar unless we have focus" retractableScrollBar & self hasFocus not ifTrue: [^self]. self isScrollable not & self isScrolledFromTop not ifTrue: [self hideScrollBar]. self isScrollable | self isScrolledFromTop ifTrue: [self showScrollBar]. ! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 10/17/1999 19:40'! hideScrollBar (submorphs includes: scrollBar) ifFalse: [^self]. self privateRemoveMorph: scrollBar. scrollBar privateOwner: nil. self resetExtent.! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 5/22/2000 16:28'! isScrollable (Preferences valueOfFlag: #hiddenScrollBars) ifFalse: [^ true]. "If the contents of the pane are too small to scroll, return false." ^ self unadjustedScrollRange > 0 "treat a single line as non-scrollable" and: [self totalScrollRange > (self scrollDeltaHeight * 3/2)]! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 5/22/2000 15:17'! isScrolledFromTop "Have the contents of the pane been scrolled, so that the top of the contents are not visible?" ^scroller offset y > 0 ! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 5/22/2000 15:55'! mouseEnter: event hasFocus _ true. (owner isKindOf: SystemWindow) ifTrue: [owner paneTransition: event]. self hideOrShowScrollBar. ! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 10/17/1999 19:41'! mouseLeave: event hasFocus _ false. retractableScrollBar ifTrue: [self hideScrollBar]. (owner isKindOf: SystemWindow) ifTrue: [owner paneTransition: event]! ! !ScrollPane methodsFor: 'scrolling' stamp: 'dew 10/17/1999 19:41'! showScrollBar (submorphs includes: scrollBar) ifTrue: [^self]. self privateAddMorph: scrollBar atIndex: 1. self resizeScrollBar. scrollBar changed. self resetExtent.! ! !PluggableTextMorph methodsFor: 'geometry' stamp: 'dew 5/22/2000 14:33'! resetExtent "Reset the extent while maintaining the current selection. Needed when resizing while the editor is active (when inside the pane)." | tempSelection | textMorph notNil ifTrue: ["the current selection gets munged by resetting the extent, so store it" tempSelection _ self selectionInterval. "don't reset it if it's not active" tempSelection = (Interval from: 0 to: 1) ifTrue: [^self]. self extent: self extent. self setSelection: tempSelection].! ! "Postscript: Leave the line above, and replace the rest of this comment by a useful one. Executable statements should follow this comment, and should be separated by periods, with no exclamation points (!!). Be sure to put any further comments in double-quotes, like this one." (Preferences respondsTo: #addPreference:category:default:balloonHelp:) ifFalse: [Preferences enable: #hiddenScrollBars] ifTrue: [Preferences addPreference: #hiddenScrollBars category: #scrolling default: true balloonHelp: 'If true, then scrollbars will only be shown if a pane''s contents are too large to fit inside the pane.'].!