<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>