<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from text --><style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
</head>
<body>
<meta content="text/html; charset=UTF-8">
<style type="text/css" style="">
<!--
p
{margin-top:0;
margin-bottom:0}
-->
</style>
<div dir="ltr">
<div id="x_divtagdefaultwrapper" dir="ltr" style="font-size:12pt; color:#000000; font-family:Calibri,Helvetica,sans-serif">
<p><img size="0" id="x_img279664" tabindex="0" style="" src="cid:6dc46fbc-8e7f-419f-ab12-6c69a99290da"><img size="0" id="x_img999499" tabindex="0" style="" src="cid:210a9a93-5876-431a-8035-7d60d731253f"><br>
</p>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>Von:</b> Squeak-dev <squeak-dev-bounces@lists.squeakfoundation.org> im Auftrag von commits@source.squeak.org <commits@source.squeak.org><br>
<b>Gesendet:</b> Freitag, 27. Januar 2023 15:55:39<br>
<b>An:</b> squeak-dev@lists.squeakfoundation.org; packages@lists.squeakfoundation.org<br>
<b>Betreff:</b> [squeak-dev] The Trunk: Morphic-mt.2081.mcz</font>
<div> </div>
</div>
</div>
<font size="2"><span style="font-size:10pt;">
<div class="PlainText">Marcel Taeumel uploaded a new version of Morphic to project The Trunk:<br>
<a href="http://source.squeak.org/trunk/Morphic-mt.2081.mcz">http://source.squeak.org/trunk/Morphic-mt.2081.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Morphic-mt.2081<br>
Author: mt<br>
Time: 27 January 2023, 3:55:35.675326 pm<br>
UUID: 7b7a2680-c376-1245-bd89-7105ab3e8c51<br>
Ancestors: Morphic-mt.2080<br>
<br>
Next iteration on text filters in tree widgets. They do now look and feel more similar to filters in list widgets.<br>
<br>
Here are the features:<br>
- Everything revolves around the current selection. If that selection is expanded, you are already looking at the children, not your current siblings.<br>
- TYPE something to reduce the current list of siblings (or children). Use preferences to change the #clearFilterDelay from its default 500 ms if needed.<br>
- Hit [Backspace] to reset the filter. Selection should mostly remain stable on screen.<br>
- Hit [CMD]+[F] to start a tree search. [CMD]+[G] to "find again" like in text fields.<br>
- Hit [CMD]+[Dot] if the tree search takes forever...<br>
- Hit [Arrow-left] repeatedly to collapse items and jump to parent nodes.<br>
- Hit [SHIFT]+[Arrow-up/down] to navigate siblings only<br>
<br>
=============== Diff against Morphic-mt.2080 ===============<br>
<br>
Item was changed:<br>
StringMorph subclass: #IndentingListItemMorph<br>
+ instanceVariableNames: 'indentLevel canExpand isExpanded complexContents firstChild container nextSibling icon backgroundColor filterOffsets'<br>
+ classVariableNames: 'FilterBackgroundColor'<br>
- instanceVariableNames: 'indentLevel isExpanded complexContents firstChild container nextSibling icon backgroundColor'<br>
- classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Morphic-Explorer'!<br>
<br>
!IndentingListItemMorph commentStamp: '<historical>' prior: 0!<br>
An IndentingListItemMorph is a StringMorph that draws itself with an optional toggle at its left, as part of the display of the SimpleHierarchicalListMorph.<br>
<br>
It will also display lines around the toggle if the #showLinesInHierarchyViews Preference is set.<br>
<br>
Instance variables:<br>
<br>
indentLevel <SmallInteger> the indent level, from 0 at the root and increasing by 1 at each level of the hierarchy.<br>
<br>
isExpanded <Boolean> true if this item is expanded (showing its children)<br>
<br>
complexContents <ListItemWrapper> an adapter wrapping my represented item that can answer its children, etc.<br>
<br>
firstChild <IndentingListItemMorph|nil> my first child, or nil if none<br>
<br>
container <SimpleHierarchicalListMorph> my container<br>
<br>
nextSibling <IndentingListItemMorph|nil> the next item in the linked list of siblings, or nil if none.<br>
<br>
Contributed by Bob Arning as part of the ObjectExplorer package.<br>
Don't blame him if it's not perfect. We wanted to get it out for people to play with.!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph class>>applyUserInterfaceTheme (in category 'preferences') -----<br>
+ applyUserInterfaceTheme<br>
+ <br>
+ FilterBackgroundColor := (UserInterfaceTheme current get: #hoverSelectionModifier for: #PluggableListMorph)<br>
+ ifNil: [ Color white darker alpha: 0.3 ]<br>
+ ifNotNil: [:modifier | modifier value: ((UserInterfaceTheme current get: #color for: #ScrollPane)<br>
+ ifNil: [ Color white ]) ].!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph class>>initialize (in category 'class initialization') -----<br>
+ initialize<br>
+ <br>
+ FilterBackgroundColor := (Color gray: 0.85) alpha: 0.5.!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph class>>themePriority (in category 'preferences') -----<br>
+ themePriority<br>
+ <br>
+ ^ 65!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph class>>themeProperties (in category 'preferences') -----<br>
+ themeProperties<br>
+ <br>
+ ^ {<br>
+ { #backgroundFilterColor. 'Styling'. 'Background color for filter matches.' }.<br>
+ }!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>applyFilter: (in category 'filtering') -----<br>
applyFilter: filter<br>
<br>
+ (self matches: filter in: complexContents)<br>
+ ifTrue: [backgroundColor := FilterBackgroundColor. ^ true]<br>
+ ifFalse: [self hideByFilter. ^ false].!<br>
- self<br>
- applyFilter: filter<br>
- depthOffset: self indentLevel.!<br>
<br>
Item was removed:<br>
- ----- Method: IndentingListItemMorph>>applyFilter:depthOffset: (in category 'filtering') -----<br>
- applyFilter: filter depthOffset: offset<br>
- <br>
- | selfMatch childMatch |<br>
- self isExpanded ifTrue: [self toggleExpandedState].<br>
- <br>
- selfMatch := self matches: filter.<br>
- childMatch := self matchesAnyChild: filter depthOffset: offset.<br>
- <br>
- selfMatch | childMatch ifFalse: [^ self hide].<br>
- <br>
- selfMatch ifTrue: [<br>
- self backgroundColor: ((Color gray: 0.85) alpha: 0.5)].<br>
- childMatch ifTrue: [<br>
- self toggleExpandedState.<br>
- self childrenDo: [:child | child applyFilter: filter depthOffset: offset]].!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>applyUserInterfaceTheme (in category 'updating') -----<br>
+ applyUserInterfaceTheme<br>
+ <br>
+ filterOffsets := nil.!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>canExpand (in category 'testing') -----<br>
canExpand<br>
<br>
+ ^ canExpand ifNil: [canExpand := complexContents hasContents]!<br>
- ^complexContents hasContents!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>children (in category 'accessing') -----<br>
children<br>
+ <br>
+ ^ Array streamContents: [:stream |<br>
+ self childrenDo: [:each | stream add: each]]!<br>
- | children |<br>
- children := OrderedCollection new.<br>
- self childrenDo: [:each | children add: each].<br>
- ^children!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>drawFilterOn:in: (in category 'drawing') -----<br>
+ drawFilterOn: aCanvas in: drawBounds<br>
+ "Draw filter matches if any. Based on LazyListMorph >> #displayFilterOn:for:in:font:."<br>
+ <br>
+ | fillStyle fillHeight leading columnOffsets o cw |<br>
+ filterOffsets ifEmpty: [^ self].<br>
+ <br>
+ fillHeight := font lineGridForMorphs.<br>
+ fillStyle := container filterColor isColor<br>
+ ifTrue: [SolidFillStyle color: container filterColor]<br>
+ ifFalse: [container filterColor].<br>
+ fillStyle isGradientFill ifTrue: [<br>
+ fillStyle origin: drawBounds topLeft.<br>
+ fillStyle direction: 0@ fillHeight].<br>
+ <br>
+ leading := font lineGapSliceForMorphs.<br>
+ <br>
+ columnOffsets := (container columns isNil or: [container columns size = 1])<br>
+ ifTrue: [<br>
+ o := drawBounds left.<br>
+ icon ifNotNil: [o := o + icon width + 2 px].<br>
+ { o }]<br>
+ ifFalse: [<br>
+ (0 to: container columns size - 1) collect: [ :column |<br>
+ column = 0<br>
+ ifTrue: [o := drawBounds left]<br>
+ ifFalse: [<br>
+ cw := self widthOfColumn: column.<br>
+ column = 1<br>
+ ifTrue: [ "Reduce width by indentation present in first column only"<br>
+ cw := cw - (drawBounds left - self left) + self hMargin].<br>
+ column + 1 = self class iconColumnIndex ifTrue: [<br>
+ icon ifNotNil: [o := o + icon width + 2 px]].<br>
+ o := o + cw + 5 px]] ].<br>
+ <br>
+ filterOffsets do: [:offset |<br>
+ | highlightRectangle |<br>
+ highlightRectangle := (((columnOffsets at: offset third) + offset first first) @ drawBounds top<br>
+ corner: ((columnOffsets at: offset third) + offset first last) @ (drawBounds top + fillHeight)).<br>
+ aCanvas<br>
+ frameAndFillRoundRect: (highlightRectangle outsetBy: 1@0)<br>
+ radius: 3 px<br>
+ fillStyle: fillStyle<br>
+ borderWidth: 1 px<br>
+ borderColor: fillStyle asColor twiceDarker.<br>
+ aCanvas<br>
+ drawString: offset second<br>
+ in: (highlightRectangle origin + (0 @ leading) corner: highlightRectangle corner)<br>
+ font: font<br>
+ color: container filterTextColor].!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>drawLabelInColumnsOn:in: (in category 'drawing') -----<br>
drawLabelInColumnsOn: aCanvas in: drawBounds<br>
"Draw the receiver appearing in multiple columns. Use TAB character to move between columns."<br>
<br>
+ | columnScanner columnLeft columnRect columnData updateFilter |<br>
- | columnScanner columnLeft columnRect columnData |<br>
self assert: [container columns size > 1].<br>
+ <br>
columnScanner := ReadStream on: contents asString.<br>
+ <br>
+ "Update filter matches"<br>
+ updateFilter := backgroundColor notNil and: [filterOffsets isNil].<br>
+ filterOffsets ifNil: [filterOffsets := OrderedCollection new].<br>
+ <br>
+ 1 to: container columns size do: [ :column |<br>
- container columns withIndexDo: [ :widthSpec :column |<br>
| columnWidth |<br>
"Compute first/next column offset."<br>
column = 1<br>
ifTrue: [columnLeft := drawBounds left]<br>
ifFalse: [columnLeft := columnRect right + 5 px].<br>
"Draw icon."<br>
column = self class iconColumnIndex ifTrue: [<br>
icon ifNotNil: [<br>
aCanvas<br>
translucentImage: icon<br>
at: columnLeft @ (self top + (self height - icon height // 2)).<br>
+ columnLeft := columnLeft + icon width + 2 px]].<br>
- columnLeft := columnLeft + icon width + 2]].<br>
"Compute drawing bounds for label portion."<br>
columnWidth := self widthOfColumn: column.<br>
column = 1 ifTrue: [ "Reduce width by indentation present in first column only"<br>
columnWidth := columnWidth - (drawBounds left - self left) + self hMargin].<br>
columnRect := columnLeft @ drawBounds top extent: columnWidth @ drawBounds height.<br>
columnData := columnScanner upTo: Character tab.<br>
"Draw label portion."<br>
columnData ifNotEmpty: [<br>
+ aCanvas drawString: columnData in: columnRect font: self fontToUse color: self colorToUse.<br>
+ updateFilter ifTrue: [<br>
+ (column = 1 or: [PluggableTreeMorph filterByLabelsOnly not])<br>
+ ifTrue: [filterOffsets addAll: (self getFilterOffsetsFor: columnData column: column)]] ] ].<br>
- aCanvas drawString: columnData in: columnRect font: self fontToUse color: self colorToUse] ].<br>
<br>
"Handle trailing TAB issue in string representation."<br>
columnScanner upToEnd ifNotEmpty: [:rest |<br>
columnRect := columnLeft + (self fontToUse widthOfString: columnData) @ drawBounds top extent: columnRect extent.<br>
+ columnData := String tab, rest.<br>
+ aCanvas drawString: columnData in: columnRect font: self fontToUse color: self colorToUse.<br>
+ updateFilter ifTrue: [<br>
+ "column > 1" PluggableTreeMorph filterByLabelsOnly not <br>
+ ifTrue: [filterOffsets addAll: (self getFilterOffsetsFor: columnData column: container columns size)]] ].!<br>
- aCanvas drawString: String tab, rest in: columnRect font: self fontToUse color: self colorToUse].!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>drawLabelOn:in: (in category 'drawing') -----<br>
drawLabelOn: aCanvas in: drawBounds<br>
<br>
| labelBounds |<br>
icon<br>
ifNil: [labelBounds := drawBounds]<br>
ifNotNil: [<br>
aCanvas<br>
translucentImage: icon<br>
at: drawBounds left @ (self top + (self height - icon height // 2)).<br>
+ labelBounds := drawBounds left: drawBounds left + icon width + 2 px].<br>
- labelBounds := drawBounds left: drawBounds left + icon width + 2].<br>
<br>
aCanvas<br>
drawString: contents asString "i.e., the label"<br>
in: labelBounds<br>
font: self fontToUse<br>
+ color: self colorToUse.<br>
+ <br>
+ "Update filter matches"<br>
+ (backgroundColor notNil and: [filterOffsets isNil])<br>
+ ifTrue: [filterOffsets := self getFilterOffsetsFor: contents asString].<br>
+ filterOffsets ifNil: [filterOffsets := #()].<br>
+ !<br>
- color: self colorToUse.!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>drawOn: (in category 'drawing') -----<br>
drawOn: aCanvas<br>
<br>
| tRect sRect |<br>
self backgroundColor ifNotNil: [:c |<br>
aCanvas fillRectangle: self innerBounds color: c].<br>
<br>
tRect := self toggleRectangle. <br>
self drawToggleOn: aCanvas in: tRect.<br>
<br>
sRect := bounds withLeft: tRect right + self hMargin.<br>
sRect := sRect top: sRect top + sRect bottom - self fontToUse height // 2.
<br>
<br>
(container columns isNil or: [(contents asString indexOf: Character tab) = 0])<br>
ifTrue: [self drawLabelOn: aCanvas in: sRect]<br>
+ ifFalse: [self drawLabelInColumnsOn: aCanvas in: sRect].<br>
+ <br>
+ self drawFilterOn: aCanvas in: (bounds withLeft: tRect right + self hMargin).!<br>
- ifFalse: [self drawLabelInColumnsOn: aCanvas in: sRect].!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>expandFiltered (in category 'container protocol') -----<br>
+ expandFiltered<br>
+ <br>
+ | filter any |<br>
+ self expand.<br>
+ <br>
+ filter := container filterTerm.<br>
+ any := false.<br>
+ self childrenDo: [:each | (each applyFilter: filter) ifTrue: [any := true]].<br>
+ any ifFalse: [self childrenDo: [:each | each removeFilter]].!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>getFilterOffsetsFor: (in category 'filtering') -----<br>
+ getFilterOffsetsFor: item<br>
+ <br>
+ ^ self getFilterOffsetsFor: item column: 1!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>getFilterOffsetsFor:column: (in category 'filtering') -----<br>
+ getFilterOffsetsFor: item column: column<br>
+ "Calculate matching character indexes for the current filter term."<br>
+ <br>
+ | filter offsets currentIndex sub |<br>
+ filter := container filterTerm.<br>
+ filter ifEmpty: [^ Array empty].<br>
+ <br>
+ offsets := OrderedCollection new.<br>
+ <br>
+ currentIndex := 1.<br>
+ [currentIndex > 0] whileTrue: [<br>
+ currentIndex := item findString: filter startingAt: currentIndex caseSensitive: false.<br>
+ currentIndex > 0 ifTrue: [ | left width |<br>
+ left := font widthOfString: item from: 1 to: currentIndex-1.<br>
+ sub := item copyFrom: currentIndex to: currentIndex + filter size - 1.<br>
+ width := font widthOfString: sub.<br>
+ offsets addLast: {(left to: left + width). sub. column}.<br>
+ currentIndex := currentIndex + 1] ].<br>
+ ^ offsets!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>hideByFilter (in category 'filtering') -----<br>
+ hideByFilter<br>
+ <br>
+ self extension visible: false.<br>
+ backgroundColor := nil.<br>
+ self childrenDo: [:ea | ea hideByFilter].!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>isFilterMatch (in category 'testing') -----<br>
+ isFilterMatch<br>
+ <br>
+ ^ self visible and: [self backgroundColor notNil]!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>lastChild (in category 'accessing') -----<br>
+ lastChild<br>
+ <br>
+ | item |<br>
+ self childrenDo: [:child | item := child].<br>
+ ^ item!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>lastVisibleChild (in category 'accessing') -----<br>
+ lastVisibleChild<br>
+ <br>
+ | item |<br>
+ self childrenDo: [:child | child visible ifTrue: [item := child]].<br>
+ ^ item!<br>
<br>
Item was removed:<br>
- ----- Method: IndentingListItemMorph>>matches: (in category 'filtering') -----<br>
- matches: pattern<br>
- <br>
- ^ self matches: pattern in: complexContents!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>matches:in: (in category 'filtering') -----<br>
+ matches: pattern in: wrapper <br>
- matches: pattern in: model <br>
^ ((PluggableTreeMorph filterByLabelsOnly<br>
+ ifTrue: [ wrapper itemName ]<br>
+ ifFalse: [ contents ])<br>
- ifTrue: [ model itemName ]<br>
- ifFalse: [ self getLabelFor: model ])<br>
findString: pattern<br>
startingAt: 1<br>
caseSensitive: false) > 0!<br>
<br>
Item was removed:<br>
- ----- Method: IndentingListItemMorph>>matchesAnyChild:depthOffset: (in category 'filtering') -----<br>
- matchesAnyChild: pattern depthOffset: offset<br>
- <br>
- | maxDepth next current |<br>
- maxDepth := PluggableTreeMorph maximumSearchDepth - self indentLevel + offset.<br>
- maxDepth <= 0 ifTrue: [^ false].<br>
- <br>
- next := (self getChildren collect: [:obj | 1 -> obj]) asOrderedCollection.<br>
- [next notEmpty] whileTrue: [<br>
- current := next removeFirst.<br>
- <br>
- (self matches: pattern in: current value)<br>
- ifTrue: [^ true].<br>
- <br>
- current key < maxDepth ifTrue: [<br>
- next addAll: ((self getChildrenFor: current value) collect: [:obj | (current key + 1) -> obj])].<br>
- ].<br>
- <br>
- ^ false!<br>
<br>
Item was added:<br>
+ ----- Method: IndentingListItemMorph>>removeFilter (in category 'filtering') -----<br>
+ removeFilter<br>
+ <br>
+ self extension visible: true.<br>
+ <br>
+ backgroundColor := nil.<br>
+ filterOffsets := nil.!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>toggleRectangle (in category 'private') -----<br>
toggleRectangle<br>
<br>
| h indent |<br>
h := bounds height.<br>
+ indent := 12 px.<br>
- indent := (12 * RealEstateAgent scaleFactor) rounded.<br>
^(bounds left + self hMargin + (indent * indentLevel)) @ bounds top extent: indent@h!<br>
<br>
Item was changed:<br>
----- Method: IndentingListItemMorph>>update: (in category 'updating') -----<br>
update: aspect<br>
"See ListItemWrapper and subclasses for possible change aspects."<br>
<br>
aspect = #contents ifTrue: [<br>
+ canExpand := nil.<br>
self isExpanded ifTrue: [self toggleExpandedState].<br>
self canExpand ifTrue: [self toggleExpandedState].<br>
container adjustSubmorphPositions].<br>
<br>
super update: aspect.!<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph class>>wrappedNavigation (in category 'preferences') -----<br>
wrappedNavigation<br>
<preference: 'Wrapped Tree Navigation'<br>
category: 'Morphic'<br>
description: 'When enabled, use of the arrow keys at the top or bottom of a hierarchical list will wrap to the opposite side of the list.'<br>
type: #Boolean><br>
+ ^ WrappedNavigation ifNil: [ true ]!<br>
- ^ WrappedNavigation ifNil: [ false ]!<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph>>arrowKey: (in category 'keyboard navigation') -----<br>
arrowKey: asciiValue<br>
"Handle a keyboard navigation character. Answer true if handled, false if not."<br>
+ | keyEvent min max oldSelection nextSelection howManyItemsShowing keyHandled |<br>
- | keyEvent max oldSelection nextSelection howManyItemsShowing keyHandled |<br>
keyHandled := false.<br>
keyEvent := asciiValue.<br>
max := self maximumSelection.<br>
+ min := self minimumSelection.<br>
nextSelection := oldSelection := self getSelectionIndex.<br>
keyEvent = 31 ifTrue:["down"<br>
self currentEvent shiftPressed ifTrue: [<br>
self selectedMorph nextVisibleSibling<br>
+ ifNil: ["TODO: wrappedNavigation" ^ true]<br>
- ifNil: [^ true]<br>
ifNotNil: [:m | self setSelectedMorph: m. ^ true]].<br>
keyHandled := true.<br>
nextSelection :=oldSelection + 1.<br>
+ nextSelection > max ifTrue: [nextSelection := (self class wrappedNavigation ifTrue: [min] ifFalse: [^ true])]].<br>
- nextSelection > max ifTrue: [nextSelection := (self class wrappedNavigation ifTrue: [1] ifFalse: [^ true])]].<br>
keyEvent = 30 ifTrue:["up"<br>
self currentEvent shiftPressed ifTrue: [<br>
self selectedMorph previousVisibleSibling<br>
+ ifNil: ["TODO: wrappedNaviagtion" ^ true]<br>
- ifNil: [^ true]<br>
ifNotNil: [:m | self setSelectedMorph: m. ^ true]].<br>
keyHandled := true.<br>
nextSelection := oldSelection - 1.<br>
+ nextSelection < min ifTrue: [nextSelection := self class wrappedNavigation ifTrue: [max] ifFalse: [^ true]]].<br>
- nextSelection < 1 ifTrue: [nextSelection := self class wrappedNavigation ifTrue: [max] ifFalse: [^ true]]].<br>
keyEvent = 1 ifTrue: ["home"<br>
keyHandled := true.<br>
+ nextSelection := min].<br>
- nextSelection := 1].<br>
keyEvent = 4 ifTrue: ["end"<br>
keyHandled := true.<br>
nextSelection := max].<br>
howManyItemsShowing := self numSelectionsInView.<br>
keyEvent = 11 ifTrue: ["page up"<br>
keyHandled := true.<br>
+ nextSelection := min max: oldSelection - howManyItemsShowing].<br>
- nextSelection := 1 max: oldSelection - howManyItemsShowing].<br>
keyEvent = 12 ifTrue: ["page down"<br>
keyHandled := true.<br>
nextSelection := oldSelection + howManyItemsShowing min: max].<br>
<br>
(nextSelection ~= oldSelection or: [ keyHandled and: [ self class wrappedNavigation not ]]) ifTrue: [<br>
self setSelectionIndex: nextSelection.<br>
^ true].<br>
<br>
keyEvent = 29 ifTrue:["right"<br>
selectedMorph ifNotNil:[<br>
(selectedMorph canExpand and:[selectedMorph isExpanded not])<br>
ifTrue:[self toggleExpandedState: selectedMorph]<br>
ifFalse:[self setSelectionIndex: self getSelectionIndex+1].<br>
].<br>
^true].<br>
keyEvent = 28 ifTrue:["left"<br>
selectedMorph ifNotNil:[<br>
(selectedMorph isExpanded)<br>
ifTrue:[self toggleExpandedState: selectedMorph]<br>
ifFalse:[<br>
self selectedParentMorph<br>
ifNil: [self setSelectionIndex: (self getSelectionIndex-1 max: 1)]<br>
ifNotNil: [:pm | self setSelectedMorph: pm]]<br>
].<br>
^true].<br>
^false!<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph>>maximumSelection (in category 'selection') -----<br>
maximumSelection<br>
<br>
+ scroller submorphs size to: 1 by: -1 do: [:index |<br>
+ (scroller submorphs at: index) visible ifTrue: [^ index]].<br>
+ ^ 1!<br>
- ^ scroller submorphs size<br>
- !<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph>>minimumSelection (in category 'selection') -----<br>
minimumSelection<br>
+ <br>
+ 1 to: scroller submorphs size do: [:index |<br>
+ (scroller submorphs at: index) visible ifTrue: [^ index]].<br>
^ 1!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleHierarchicalListMorph>>scrollSelectionAndChildrenIntoView (in category 'selection') -----<br>
+ scrollSelectionAndChildrenIntoView<br>
+ "Make sure to show the current selection and as many children as possible."<br>
+ <br>
+ self selectedMorph<br>
+ ifNil: [self scrollToTop]<br>
+ ifNotNil: [:m |<br>
+ m isExpanded ifTrue: [self scrollToShow: m lastVisibleChild bounds].<br>
+ self scrollSelectionIntoView].!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleHierarchicalListMorph>>scrollSelectionAndExtraIntoView (in category 'selection') -----<br>
+ scrollSelectionAndExtraIntoView<br>
+ "Make sure to show the current selection and some of the previous and next items."<br>
+ <br>
+ | numExtraItemsToShow |<br>
+ numExtraItemsToShow := 2.<br>
+ self selectedMorph<br>
+ ifNil: [self scrollToTop]<br>
+ ifNotNil: [:m |<br>
+ self scrollToShow: (m bounds outsetBy: (0@ (m height * numExtraItemsToShow))).<br>
+ self scrollSelectionIntoView].!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleHierarchicalListMorph>>scrollSelectionIntoView (in category 'selection') -----<br>
+ scrollSelectionIntoView<br>
+ <br>
+ self selectedMorph<br>
+ ifNil: [self scrollToTop]<br>
+ ifNotNil: [:m | self scrollToShow: m bounds].!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleHierarchicalListMorph>>scrollSelectionParentIntoView (in category 'selection') -----<br>
+ scrollSelectionParentIntoView<br>
+ "Try to make current selection's parent visible. Yet, ensure that the selection stays visible."<br>
+ <br>
+ self scrollSelectionParentIntoView: self selectedParentMorph.!<br>
<br>
Item was added:<br>
+ ----- Method: SimpleHierarchicalListMorph>>scrollSelectionParentIntoView: (in category 'selection') -----<br>
+ scrollSelectionParentIntoView: parentOrNil<br>
+ "Try to make current selection's parent visible. Yet, ensure that the selection stays visible."<br>
+ <br>
+ parentOrNil ifNotNil: [:pm | self scrollToShow: pm bounds].<br>
+ self scrollSelectionIntoView.!<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph>>selectedMorph: (in category 'selection') -----<br>
selectedMorph: aMorph<br>
<br>
self unhighlightSelection.<br>
selectedMorph := aMorph.<br>
+ self highlightSelection.<br>
+ <br>
+ self scrollSelectionIntoView.!<br>
- self highlightSelection!<br>
<br>
Item was changed:<br>
----- Method: SimpleHierarchicalListMorph>>selectionIndex: (in category 'selection') -----<br>
selectionIndex: idx<br>
"Called internally to select the index-th item."<br>
+ <br>
+ | index |<br>
- | theMorph index |<br>
idx ifNil: [^ self].<br>
index := idx min: scroller submorphs size max: 0.<br>
+ self selectedMorph: (index = 0 ifFalse: [scroller submorphs at: index]).!<br>
- (theMorph := index = 0 ifTrue: [nil] ifFalse: [scroller submorphs at: index])<br>
- ifNotNil: [self scrollToShow: theMorph bounds].<br>
- self selectedMorph: theMorph!<br>
<br>
<br>
</div>
</span></font>
</body>
</html>