HierarchicalListView.st
changeset 1390 62dc950b9140
child 1391 83ed7574be4c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HierarchicalListView.st	Sun May 23 14:56:33 1999 +0200
@@ -0,0 +1,889 @@
+SelectionInListModelView subclass:#HierarchicalListView
+	instanceVariableNames:'imageInset imageWidth lineMask lineColor showRoot showLines
+		showLeftIndicators indicatorAction useDefaultIcons icons
+		openIndicator closeIndicator'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'AAA'
+!
+
+!HierarchicalListView class methodsFor:'documentation'!
+
+documentation
+"
+    This class implements a hierarchical list view based on a
+    hierachical list
+
+    [Instance variables:]
+        textStartLeft       <Integer>              inset between icon and text 
+        imageInset          <Integer>              inset between left side and icon
+        imageWidth          <Integer>              width of widest icon
+        lineMask            <Form>                 line mask
+        lineColor           <Color>                line color
+        showRoot            <Boolean>              root element is shown or hidden
+                                                   derives from the hierachical list.
+        showLines           <Boolean>              show or hide lines
+        useDefaultIcons     <Boolean>              use the default icons if no icon
+                                                   for an item is specified
+        icons               <IdentityDictionary>   list of registered icons;
+                                                   identifier := <key> value := <icon>
+        showLeftIndicators  <Boolean>              show or hide indicator for most left items
+        indicatorAction     <Block>                action evaluated if indicator is pressed
+        openIndicator       <Icon, Image or Form>  expanded indicator      
+        closeIndicator      <Icon, Image or Form>  collapsed indicator
+
+    [author:]
+        Claus Atzkern
+
+    [see also:]
+        ListModelView
+        SelectionInListModelView
+        HierarchicalList
+        HierarchicalItem
+"
+
+
+!
+
+examples
+"
+                                                                        [exBegin]
+    |top sel list item|
+
+    list := HierarchicalList new.
+    item := HierarchicalItem::Example labeled:'Root Item'.
+
+    item expand.
+    list showRoot:false.
+    list root:item.
+
+    top := StandardSystemView new; extent:300@300.
+    sel := ScrollableView for:HierarchicalListView miniScroller:true
+                       origin:0.0@0.0 corner:1.0@1.0 in:top.
+
+    sel list:list.
+    sel multipleSelectOk:true.
+
+    sel doubleClickAction:[:i| (list at:i) toggleExpand ].
+    sel   indicatorAction:[:i| (list at:i) toggleExpand ].
+
+    top open.
+                                                                        [exEnd]
+
+
+"
+! !
+
+!HierarchicalListView class methodsFor:'resources'!
+
+closeIndicator
+    "returns a little [+] bitmap"
+
+    <resource: #fileImage>
+
+    ^ Icon constantNamed:#plus
+             ifAbsentPut:[Image fromFile:('xpmBitmaps/plus.xpm')]
+
+
+!
+
+collapsedIcon
+    "returns icon to indicate a collapsed entry
+    "
+    <resource: #fileImage>
+
+    ^ Icon constantNamed:#directory
+             ifAbsentPut:[Image fromFile:('xpmBitmaps/document_images/tiny_yellow_dir.xpm')]
+
+!
+
+emptyIcon
+    "returns icon to indicate an not extendable entry
+    "
+    <resource: #fileImage>
+
+    ^ Icon constantNamed:#plainFile
+             ifAbsentPut:[Image fromFile:('xpmBitmaps/document_images/tiny_file_plain.xpm')]
+
+!
+
+expandedIcon
+    "returns icon to indicate an extended entry
+    "
+    <resource: #fileImage>
+
+    ^ Icon constantNamed:#directoryOpened
+             ifAbsentPut:[Image fromFile:('xpmBitmaps/document_images/tiny_yellow_dir_open.xpm')]
+
+!
+
+openIndicator
+    "returns a little [-] bitmap"
+
+    <resource: #fileImage>
+
+    ^ Icon constantNamed:#minus
+             ifAbsentPut:[Image fromFile:('xpmBitmaps/minus.xpm')]
+
+! !
+
+!HierarchicalListView methodsFor:'accessing'!
+
+list:aList
+    "get the status of <showRoot> from the list
+    "
+    aList notNil ifTrue:[
+        showRoot := aList showRoot
+    ].
+    super list:aList
+! !
+
+!HierarchicalListView methodsFor:'accessing colors'!
+
+lineColor
+    "get the line color
+    "
+    ^ lineColor
+
+
+!
+
+lineColor:aColor
+    "set the line color
+    "
+    (aColor notNil and:[aColor ~= lineColor]) ifTrue:[
+        lineColor := aColor.
+
+        shown ifTrue:[
+            lineColor := lineColor on:device.
+
+            showLines ifTrue:[
+                self invalidate
+            ]
+        ]
+    ]
+
+! !
+
+!HierarchicalListView methodsFor:'accessing look'!
+
+registerKeysAndIcons:aDictionary
+    "register icons by key and value derived from a directory
+    "
+    |image|
+
+    (aDictionary isNil or:[aDictionary isEmpty]) ifTrue:[
+        ^ self
+    ].
+
+    aDictionary keysAndValuesDo:[:aKey :anImage|
+        (image := self imageOnDevice:anImage) notNil ifTrue:[
+            icons at:aKey put:image
+        ]
+    ]
+
+!
+
+showLeftIndicators
+    "show or hide the indicators for the most left items
+    "
+    ^ showLeftIndicators
+
+!
+
+showLeftIndicators:aState
+    "show or hide the indicators for the most left items
+    "
+    aState ~~ showLeftIndicators ifTrue:[
+        showLeftIndicators := aState.
+        self invalidate
+    ].
+
+!
+
+showLines
+    "returns true if lines are shown
+    "
+  ^ showLines
+
+!
+
+showLines:aState
+    "show or hide lines
+    "
+    aState ~~ showLines ifTrue:[
+        showLines := aState.
+        self invalidate
+    ].
+
+!
+
+useDefaultIcons
+    "use the default icons if no icon for an item is specified;
+     ** default: true
+    "
+    ^ useDefaultIcons
+!
+
+useDefaultIcons:aBool
+    "use the default icons if no icon for an item is specified;
+     ** default: true
+    "
+    useDefaultIcons ~~ aBool ifTrue:[
+        useDefaultIcons := aBool.
+
+        shown ifTrue:[
+            self invalidate
+        ]
+    ]
+! !
+
+!HierarchicalListView methodsFor:'actions'!
+
+indicatorAction
+    "if the action is not nil, indicators are shown and a click on the indicator
+     will evaluate the action with none or one argument, the index into the list
+    "
+    ^ indicatorAction
+!
+
+indicatorAction:anAction
+    "if the action is not nil, indicators are shown and a click on the indicator
+     will evaluate the action with none or one argument, the index into the list
+    "
+    |wasNilBefore|
+
+    wasNilBefore    := indicatorAction isNil.
+    indicatorAction := anAction.
+
+    wasNilBefore == (anAction isNil) ifTrue:[
+        self invalidate
+    ].
+! !
+
+!HierarchicalListView methodsFor:'change & update'!
+
+lineChangedAt:aLnNr with:arg
+    "line changed at position; check whether line height changed
+    "
+    |item
+     lv "{ Class:SmallInteger }"
+     x0 "{ Class:SmallInteger }"
+     x1 "{ Class:SmallInteger }"
+     h  "{ Class:SmallInteger }"
+     y0 "{ Class:SmallInteger }"
+     y1 "{ Class:SmallInteger }"
+    |
+
+    (arg == #icon or:[arg == #hierarchy]) ifFalse:[
+        ^ super lineChangedAt:aLnNr with:arg
+    ].
+    y0 := (self yVisibleOfLine:aLnNr)       max:margin.
+    y1 := (self yVisibleOfLine:(aLnNr + 1)) min:(height - margin).
+
+    (h := y1 - y0) > 0 ifTrue:[
+        x0 := margin.
+        x1 := width - margin.
+
+        (item := list at:aLnNr ifAbsent:nil) isNil ifFalse:[
+            lv := item level.
+            x0 := self xOfFigureLevel:lv.
+            x1 := x0 + imageWidth.
+
+            arg == #hierarchy ifTrue:[
+                x0 := self xOfFigureLevel:(lv -1).
+            ].
+            x0 := x0 max:margin.
+            x1 := x1 min:(width - margin).
+
+            x1 > x0 ifFalse:[
+                ^ self
+            ]
+        ].
+        self redrawX:x0 y:y0 width:x1 - x0 height:h.
+    ]
+
+
+
+
+!
+
+update:what with:aPara from:chgObj
+    "get the status of <showRoot> from the list
+    "
+    chgObj == list ifTrue:[
+        showRoot ~~ list showRoot ifTrue:[
+            showRoot := list showRoot.
+            self invalidate.
+        ]
+    ].
+    super update:what with:aPara from:chgObj
+! !
+
+!HierarchicalListView methodsFor:'drawing basics'!
+
+drawElementsFrom:start to:stop x:x0 y:y0 width:aWidth
+    "draw the items between start to stop without clearing the background
+    "
+    |item prevItem parent icon showIndc showIcon showText nxtPrnt
+
+     x1       "{ Class:SmallInteger }"
+     yTop     "{ Class:SmallInteger }"
+     yCtr     "{ Class:SmallInteger }"
+     yBot     "{ Class:SmallInteger }"
+
+     xIndc    "{ Class:SmallInteger }"
+     xIcon    "{ Class:SmallInteger }"
+     xText    "{ Class:SmallInteger }"
+
+     widthLvl "{ Class:SmallInteger }"
+     insetTxt "{ Class:SmallInteger }"
+
+     offIndcX "{ Class:SmallInteger }"
+     offIndcY "{ Class:SmallInteger }"
+     offIconX "{ Class:SmallInteger }"
+    |
+    x1       := x0 + aWidth.
+    widthLvl := imageInset    + imageWidth.
+    insetTxt := textStartLeft + imageWidth.
+    offIconX := self xOfFigureLevel:0.
+    showIndc := false.
+
+    indicatorAction notNil ifTrue:[
+        icon     := openIndicator extent // 2.
+        offIndcX := imageWidth // 2 - widthLvl.
+        offIndcX := offIndcX - icon x.
+        offIndcY := icon y.
+    ].
+
+    showLines ifTrue:[
+        self drawLinesFrom:start to:stop x:x0 y:y0 width:aWidth
+    ].
+
+    parent   := 4711.   "/ to force a recompute
+    prevItem := 4711.   "/ to force a recomputation of the level
+    yBot     := y0.
+
+    start to:stop do:[:anIndex|
+        (item := list at:anIndex ifAbsent:nil) isNil ifTrue:[
+            ^ self      "/ list changed
+        ].
+        yTop := yBot.
+        yBot := self yVisibleOfLine:(anIndex + 1).
+        yCtr := yTop + (yBot - yTop // 2).
+
+        (nxtPrnt := item parent) ~~ parent ifTrue:[
+            parent := nxtPrnt.
+            xIcon  := prevItem == parent ifTrue:[xIcon + widthLvl]
+                                        ifFalse:[item level * widthLvl + offIconX].
+
+            xText    := xIcon + insetTxt.
+            showIcon := xIcon < x1 and:[xText > x0].
+            showText := xText < x1.
+
+            indicatorAction notNil ifTrue:[
+                xIndc := xIcon + offIndcX.
+
+                showIndc := (      (parent notNil or:[showLeftIndicators])
+                              and:[(xIcon > x0 and:[xIndc < x1])]
+                            )
+            ]
+        ].
+
+        (showIcon and:[(icon := self figureFor:item) notNil]) ifTrue:[
+            icon width > imageWidth ifTrue:[
+                imageWidth := icon width.
+                StopRedrawSignal raise
+            ].
+            self displayForm:icon x:xIcon y:(yCtr - (icon height // 2))
+        ].
+
+        showText ifTrue:[
+            self drawLabelAt:xText y:yTop h:(yBot - yTop) index:anIndex
+        ].
+        (showIndc and:[item hasChildren]) ifTrue:[
+            icon := item isExpanded ifTrue:[openIndicator] ifFalse:[closeIndicator].
+            self displayForm:icon x:xIndc y:(yCtr - offIndcY)
+        ].
+        prevItem := item.
+    ]
+!
+
+drawLinesFrom:start to:stop x:x0 y:y0 width:aWidth
+    "draw the lines between start to stop without clearing the background
+    "
+    |item prevItem parent p1 p2 showVLines showHLine lv nxtPrnt
+     showRootNot isFirst buildInArray
+
+     x        "{ Class:SmallInteger }"
+     x1       "{ Class:SmallInteger }"
+     y        "{ Class:SmallInteger }"
+
+     yTop     "{ Class:SmallInteger }"
+     yBot     "{ Class:SmallInteger }"
+     yCtr     "{ Class:SmallInteger }"
+
+     begHLnY  "{ Class:SmallInteger }"
+     runHLnY  "{ Class:SmallInteger }"
+     begHLnX  "{ Class:SmallInteger }"
+     endHLnX  "{ Class:SmallInteger }"
+
+     widthLvl "{ Class:SmallInteger }"
+     offsHLnX "{ Class:SmallInteger }"
+
+     level    "{ Class:SmallInteger }"
+     startLvI "{ Class:SmallInteger }"
+     startLvX "{ Class:SmallInteger }"
+     limitLvI "{ Class:SmallInteger }"
+     limitLvX "{ Class:SmallInteger }"
+    |
+    x1       := x0 + aWidth.
+    widthLvl := imageInset + imageWidth.
+    offsHLnX := imageWidth // 2 + (self xOfFigureLevel:-1).
+
+    parent   := 4711.                           "/ to force a recompute
+    prevItem := 4711.                           "/ to force a recomputation of the level
+
+    self setMaskOrigin:(self viewOrigin + (0 @ 1) \\ (lineMask extent)).
+    self paint:lineColor on:bgColor.
+    self mask:lineMask.
+    startLvI := self smallestLevelBetween:start and:stop.
+    startLvX := self xOfFigureLevel:startLvI.
+    limitLvI := 2.
+    limitLvX := limitLvI * widthLvl + offsHLnX.
+
+    buildInArray := Array new:20.
+    buildInArray atAllPut:0.
+
+    showRootNot := showRoot not.
+    yBot := y0.
+    begHLnY := runHLnY := y0.
+
+    start to:stop do:[:anIndex|
+        (item := list at:anIndex ifAbsent:nil) isNil ifTrue:[
+            ^ self mask:nil     "/ list changed
+        ].
+        yTop := yBot.
+        yBot := self yVisibleOfLine:(anIndex + 1).
+        yCtr := yTop + (yBot - yTop // 2).
+        anIndex == 1 ifTrue:[ begHLnY := runHLnY := yCtr ].
+
+        (nxtPrnt := item parent) ~~ parent ifTrue:[
+            parent := nxtPrnt.
+
+            prevItem == parent ifTrue:[
+                level := level + 1.
+                begHLnX := endHLnX.
+            ] ifFalse:[
+                level   := item level.
+                begHLnX := item level * widthLvl + offsHLnX.
+            ].
+
+            isFirst    := parent isNil or:[(showRootNot and:[level == 2])].
+            endHLnX    := begHLnX + widthLvl.
+            showVLines := begHLnX >= x0 and:[level > 1].
+            showHLine  := x0 < endHLnX and:[x1 > begHLnX].
+
+            (showHLine and:[isFirst]) ifTrue:[
+                showHLine := showLeftIndicators and:[indicatorAction notNil]
+            ]
+        ].
+
+        showHLine ifTrue:[
+            self displayLineFromX:begHLnX y:yCtr toX:endHLnX y:yCtr
+        ].
+
+        showVLines ifTrue:[
+            y  := (parent last == item) ifTrue:[yCtr] ifFalse:[yBot].
+            x  := begHLnX.
+            p2 := parent.
+            lv := level - 1.
+            self displayLineFromX:x y:runHLnY toX:x y:y.
+
+            [((p1 := p2 parent) notNil and:[(x := x - widthLvl) >= limitLvX])] whileTrue:[
+                (p1 last ~~ p2 and:[x <= x1]) ifTrue:[
+                    x >= startLvX ifTrue:[
+                        self displayLineFromX:x y:(yTop - 1) toX:x y:yBot
+                    ] ifFalse:[
+                        buildInArray at:lv put:yBot
+                    ].
+                ].
+                lv := lv - 1.
+                p2 := p1
+            ]
+        ].
+        prevItem := item.
+        runHLnY  := yCtr.
+    ].
+
+    "/
+    "/ draw outstanding verical lines to left
+    "/
+    x := limitLvX.
+    y := begHLnY.
+
+    limitLvI to:startLvI do:[:i|
+        (yBot := buildInArray at:i) ~~ 0 ifTrue:[
+            self displayLineFromX:x y:y toX:x y:yBot
+        ].
+        x := x + widthLvl.
+    ].
+    (     start == stop
+     and:[(item := list at:start ifAbsent:nil) notNil
+     and:[item isExpanded
+     and:[item hasChildren]]]
+    ) ifTrue:[
+        x := begHLnX + widthLvl.
+
+        (x >= x0 and:[x <= x1]) ifTrue:[
+            yBot := self yVisibleOfLine:(start + 1).
+            yCtr := y0 + (yBot - y0 // 2).
+            self displayLineFromX:x y:yCtr toX:x y:yBot.
+        ]
+    ].
+    self mask:nil.
+
+
+!
+
+redrawLabelFromItem:anItem atY:y h:h
+    "called to redraw a label caused by a selection change
+    "
+    |w "{ Class:SmallInteger }"
+     x "{ Class:SmallInteger }"
+    |
+    x := (self xOfStringLevel:(anItem level)) - (textStartLeft // 2).
+    x := x max:margin.
+
+    (w := width - x) > 0 ifTrue:[
+        self redrawX:x y:y width:w height:h
+    ]
+
+
+! !
+
+!HierarchicalListView methodsFor:'event handling'!
+
+buttonMultiPress:button x:x y:y
+    "handle a button multiPress event
+    "
+    |lnNr|
+
+    enabled ifTrue:[
+        (     (button == 1 or:[button == #select])
+         and:[(lnNr := self indicatorLineAtX:x y:y) notNil]
+        ) ifFalse:[
+            super buttonMultiPress:button x:x y:y
+        ]
+    ]
+!
+
+buttonPress:button x:x y:y
+    "handle a button press event
+    "
+    |lnNr menu item appl|
+
+    enabled ifTrue:[
+        ((button == 2) or:[button == #menu]) ifTrue:[
+            (     (item := self selectedElement)  notNil
+             and:[(menu := item middleButtonMenu) notNil]
+            ) ifTrue:[
+                menu isCollection ifTrue:[
+                    menu := Menu new fromLiteralArrayEncoding:menu.
+                    appl := self application.
+
+                    appl notNil ifTrue:[
+                        menu findGuiResourcesIn:appl.
+                        menu receiver:appl
+                    ] ifFalse:[
+                        menu receiver:item
+                    ]
+                ].
+                ^ menu startUp
+            ].
+        ] ifFalse:[
+            (lnNr := self indicatorLineAtX:x y:y) notNil ifTrue:[
+                (indicatorAction numArgs == 1) ifTrue:[
+                    indicatorAction value:lnNr
+                ] ifFalse:[
+                    indicatorAction value
+                ].
+                ^ self
+            ]
+        ].
+        super buttonPress:button x:x y:y
+    ]
+!
+
+keyPress:aKey x:x y:y
+    "a key was pressed - handle page-keys here
+    "
+    <resource: #keyboard( #CursorLeft #CursorRight )>
+
+    |item parent index size stop step|
+
+    (aKey == #CursorLeft or:[aKey == #CursorRight]) ifFalse:[
+        ^ super keyPress:aKey x:x y:y
+    ].
+
+    (     enabled
+     and:[(size  := list size) > 1
+     and:[(index := self selectedIndex) ~~ 0
+     and:[(item  := list at:index ifAbsent:nil) notNil]]]
+    ) ifTrue:[
+        parent := item parent.
+
+        aKey == #CursorLeft ifTrue:[step := -1. stop :=    1]
+                           ifFalse:[step :=  1. stop := size].    
+
+        (index + step) to:stop by:step do:[:i|
+            item := list at:i ifAbsent:[^ nil ].
+            item parent ~~ parent ifTrue:[^ self selection:i]
+        ].
+
+        index := aKey == #CursorLeft ifTrue:[size] ifFalse:[1].
+        self selection:index
+    ].
+! !
+
+!HierarchicalListView methodsFor:'fetch resources'!
+
+fetchResources
+    "fetch device colors and ..., to avoid reallocation at redraw time;
+     *** called after a create or snapin to fetch all device resources
+    "
+    |image|
+
+    super fetchResources.
+
+    lineMask       := lineMask  onDevice:device.
+    lineColor      := lineColor onDevice:device.
+    openIndicator  := self imageOnDevice:openIndicator.
+    closeIndicator := self imageOnDevice:closeIndicator.
+    imageWidth     := 4.
+
+    icons keysAndValuesDo:[:aKey :anImage|
+        image := self imageOnDevice:anImage.
+        icons at:aKey put:image.
+        imageWidth := image width  max:imageWidth.
+    ].
+    imageWidth := imageWidth // 2.
+    imageWidth odd ifTrue:[imageWidth := imageWidth + 1].
+    imageWidth := imageWidth * 2.
+
+
+
+! !
+
+!HierarchicalListView methodsFor:'initialize / release'!
+
+initStyle
+    "setup viewStyle specifics
+    "
+    |cls|
+
+    super initStyle.
+
+    cls := self class.
+
+    lineMask := Form width:2 height:2 fromArray:#[16rAA 16r55].
+    icons    := IdentityDictionary new.
+
+    icons at:#expanded  ifAbsentPut:[cls expandedIcon].
+    icons at:#collapsed ifAbsentPut:[cls collapsedIcon].
+    icons at:#empty     ifAbsentPut:[cls emptyIcon].
+
+    openIndicator      := self class openIndicator.
+    closeIndicator     := self class closeIndicator.
+    lineColor          := fgColor.
+    highlightMode      := #label.
+    showRoot           := true.
+    showLeftIndicators := true.
+    useDefaultIcons    := true.
+    showLines          := true.
+    imageInset         := 4.
+    imageWidth         := 8.    "/ default
+! !
+
+!HierarchicalListView methodsFor:'private'!
+
+figureFor:anItem
+    "return a (bitmap) figure for an item
+    "
+    |key image w h|
+
+    "/ the item may provide an icon
+    "/ (it knows for itself if its open or closed)
+
+    (key := anItem icon) notNil ifTrue:[
+        (key isImageOrForm and:[key device == device]) ifTrue:[
+            ^ key
+        ].
+
+        (image := icons at:key ifAbsent:nil) notNil ifTrue:[
+            ^ image
+        ].
+
+        key isImageOrForm ifTrue:[
+            image := self imageOnDevice:key.
+            icons at:key put:image.
+          ^ image
+        ]
+    ].
+
+    useDefaultIcons ifFalse:[^ nil].
+
+    "/ ok, item did not return an icon - use default.
+
+    anItem hasChildren ifTrue:[
+        key := anItem isExpanded ifTrue:[#expanded] ifFalse:[#collapsed]
+    ] ifFalse:[
+        key := #empty
+    ].
+    ^ icons at:key
+!
+
+heightOfLineAt:aLineNr
+    "returns the total height for a line at an index, including
+     lineSpacing, the figure and the label
+    "
+    |item icon height|
+
+    item   := list at:aLineNr ifAbsent:[^ 4].
+    height := item heightOn:self.
+
+    (icon := self figureFor:item) notNil ifTrue:[
+        height := (item heightOn:self) max:height.
+    ].
+  ^ lineSpacing + height
+
+
+!
+
+indicatorLineAtX:x y:y
+    "returns the lineNumber assigned to an indicator at x/y or nil
+    "
+    |lnNr item x0|
+
+    (    indicatorAction isNil
+     or:[(lnNr := self yVisibleToLineNr:y)   isNil
+     or:[(item := list at:lnNr ifAbsent:nil) isNil
+     or:[item hasChildren not]]]
+    ) ifFalse:[
+        x0 := self xOfFigureLevel:(item level - 1).
+
+        (x > x0 and:[(x0 + imageWidth) > x]) ifTrue:[
+            ^ lnNr
+        ]
+    ].
+    ^ nil
+!
+
+smallestLevelBetween:start and:stop
+    "returns the smallest level between a range
+    "
+    |prevItem currParent nextParent item
+
+     lvl "{ Class:SmallInteger }"
+     min "{ Class:SmallInteger }"
+     beg "{ Class:SmallInteger }"
+    |
+
+    prevItem := list at:start ifAbsent:[ ^ 1 ].
+
+    (currParent := prevItem parent) isNil ifTrue:[
+        ^ 1
+    ].
+
+    (min := prevItem level) == 2 ifTrue:[
+        ^ min
+    ].
+    beg := start + 1.
+
+    beg to:stop do:[:i|
+        item := list at:i ifAbsent:[^ min].
+
+        (nextParent := item parent) == currParent ifFalse:[
+            (currParent := nextParent) == prevItem ifFalse:[
+                (lvl := item level) == 2 ifTrue:[
+                    ^ 2
+                ].
+                min := min min:lvl
+            ]
+        ].
+        prevItem := item
+    ].
+    ^ min
+
+
+
+
+
+!
+
+widthOfWidestLineBetween:firstLine and:lastLine
+    "return the width of the longest line in pixels
+    "
+    |nprnt pprnt pitem item
+     textX     "{ Class: SmallInteger }"
+     level     "{ Class: SmallInteger }"
+     width     "{ Class: SmallInteger }"
+     deltaX    "{ Class: SmallInteger }"
+     startX    "{ Class: SmallInteger }"
+    |
+
+    pprnt  := 4711.  "/ force a computation
+    pitem  := 4712.  "/ force a computation
+    width  := 20.
+    deltaX := imageInset + imageWidth.
+    startX := self xOfStringLevel:1.
+
+    firstLine to:lastLine do:[:idx|
+        item := list at:idx ifAbsent:[^ width + startX].
+
+        (nprnt := item parent) ~~ pprnt ifTrue:[
+            (pprnt := nprnt) == pitem ifTrue:[
+                level := level + 1.
+                textX := textX + deltaX.
+            ] ifFalse:[
+                level := item level.
+                textX := level - 1 * deltaX.
+            ]
+        ].
+        pitem := item.
+        width := (item widthOn:self) max:width
+    ].
+    ^ width + startX
+
+
+!
+
+xOfFigureLevel:aLevel
+    "origin x where to draw the icon
+    "
+    |l "{ Class:SmallInteger }"|
+
+    l := showRoot ifTrue:[aLevel] ifFalse:[aLevel - 1].
+
+    indicatorAction isNil ifTrue:[
+        l := l - 1
+    ] ifFalse:[
+        showLeftIndicators ifFalse:[
+            l := l - 1
+        ]
+    ].
+  ^ (l * (imageInset + imageWidth)) + imageInset - (viewOrigin x)
+!
+
+xOfStringLevel:aLevel
+    "origin x where to draw the text( label )
+    "
+    ^ (self xOfFigureLevel:aLevel) + imageWidth + textStartLeft
+
+! !
+
+!HierarchicalListView class methodsFor:'documentation'!
+
+version
+    ^ '$Header: /cvs/stx/stx/libwidg2/HierarchicalListView.st,v 1.1 1999-05-23 12:56:26 cg Exp $'
+! !