SelectionInListView.st
changeset 31 2224b4d173f7
parent 24 966098a893f8
child 38 4b9b70b2cc87
--- a/SelectionInListView.st	Tue Apr 26 15:46:00 1994 +0200
+++ b/SelectionInListView.st	Thu Jun 02 20:30:26 1994 +0200
@@ -18,8 +18,10 @@
                               selectConditionBlock
                               listAttributes multipleSelectOk clickLine
                               listSymbol initialSelectionSymbol printItems oneItem
-                              hilightLevel hilightFrameColor ignoreReselect'
-       classVariableNames:   'RightArrowShadowForm RightArrowLightForm RightArrowForm'
+                              hilightLevel hilightFrameColor ignoreReselect
+                              arrowLevel smallArrow'
+       classVariableNames:   'RightArrowShadowForm RightArrowLightForm RightArrowForm
+                              SmallRightArrowShadowForm SmallRightArrowLightForm'
        poolDictionaries:''
        category:'Views-Text'
 !
@@ -34,14 +36,55 @@
 
 documentation
 "
-this one is a ListView with a selected line (which is shown highlighted)
-If multipleSelectionsOk is true, it is also allowed to shift-click multiple entries.
+    this one is a ListView with a selected line (which is shown highlighted)
+    If multipleSelectionsOk is true, it is also allowed to shift-click multiple entries.
+
+    Whenever the selection changes, an action-block is called for,
+    passing the current selection as argument.
+    Currently, the selection can be nil, aNumber or a collection of
+    numbers; this will change to be either nil or a collection, making
+    selection handling easier in the future.
+    The actionBlock is called with the current selection as argument.
+
+    InstanceVariables:
+        selection               <misc>          the current selection. nil, a number or collection of numbers
+
+        actionBlock             <Block>         block to be evaluated on selection changes
+
+        enabled                 <Boolean>       true: selection changes allowed; false: ignore clicks
+
+        hilightFgColor
+        hilightBgColor          <Color>         how highlighted items are drawn
+
+        halfIntensityColor      <Color>         foreground for disabled items
+
+        selectConditionBlock    <Block>         if non-nil, this nlock can decide if selection is ok
 
-$Header: /cvs/stx/stx/libwidg/SelectionInListView.st,v 1.7 1994-01-13 00:18:21 claus Exp $
+        doubleClickActionBlock  <Block>         action to perform on double-click
+
+        listAttributes                          dont use - will vanish
+
+        multipleSelectOk        <Boolean>       if true, multiple selections (with shift) are ok
+        hilightLevel            <Integer>       level to draw selections (i.e. for 3D effect)
+        hilightFrameColor       <Color>         rectangle around highlighted items
+
+        ignoreReselect          <Boolean>       if true, selecting same again does not trigger action;
+                                                if false, every select triggers it
 
-written spring/summer 89 by claus
-3D Jan 90 by claus
-multiselect Jun 92 my claus
+        arrowLevel              <Integer>       level to draw right-arrows (for submenus etc.)
+        smallArrow              <Boolean>       if true, uses a small arrow bitmap
+
+        listSymbol                              if non-nil, use ST-80 style (model-access)
+        initialSelectionSymbol 
+        printItems 
+        oneItem
+
+
+    $Header: /cvs/stx/stx/libwidg/SelectionInListView.st,v 1.8 1994-06-02 18:30:26 claus Exp $
+
+    written spring/summer 89 by claus
+    3D Jan 90 by claus
+    multiselect Jun 92 my claus
 "
 ! !
 
@@ -147,6 +190,60 @@
         RightArrowForm := f
     ].
     ^ f
+!
+
+smallRightArrowLightFormOn:aDevice
+    "return the form used for the small right arrow light pixels (3D only)"
+
+    |f|
+
+    ((aDevice == Display) and:[SmallRightArrowLightForm notNil]) ifTrue:[
+        ^ SmallRightArrowLightForm
+    ].
+    f := Form fromFile:'SmallRightArrowLight.xbm' resolution:100 on:aDevice.
+    f isNil ifTrue:[
+        f := Form width:9 height:9 fromArray:#(2r00000000 2r00000000 
+                                               2r01100000 2r00000000 
+                                               2r01011000 2r00000000 
+                                               2r01000110 2r00000000 
+                                               2r01000000 2r00000000 
+                                               2r01000000 2r00000000 
+                                               2r01000000 2r00000000 
+                                               2r01000000 2r00000000 
+                                               2r00000000 2r00000000)
+                                              on:aDevice
+    ].
+    (aDevice == Display) ifTrue:[
+        SmallRightArrowLightForm := f
+    ].
+    ^ f
+!
+
+smallRightArrowShadowFormOn:aDevice
+    "return the form used for the small right arrow light pixels (3D only)"
+
+    |f|
+
+    ((aDevice == Display) and:[SmallRightArrowShadowForm notNil]) ifTrue:[
+        ^ SmallRightArrowShadowForm
+    ].
+    f := Form fromFile:'SmallRightArrowShadow.xbm' resolution:100 on:aDevice.
+    f isNil ifTrue:[
+        f := Form width:9 height:9 fromArray:#(2r00000000 2r00000000 
+                                               2r00000000 2r00000000 
+                                               2r00000000 2r00000000 
+                                               2r00000000 2r00000000 
+                                               2r00000001 2r00000000 
+                                               2r00000110 2r00000000 
+                                               2r00011000 2r00000000 
+                                               2r00100000 2r00000000 
+                                               2r00000000 2r00000000)
+                                              on:aDevice
+    ].
+    (aDevice == Display) ifTrue:[
+        SmallRightArrowShadowForm := f
+    ].
+    ^ f
 ! !
 
 !SelectionInListView class methodsFor:'instance creation'!
@@ -179,11 +276,8 @@
     bgColor := viewBackground.
     hilightFrameColor := nil.
     hilightLevel := 0.
-    (style == #openwin) ifTrue:[
-        lineSpacing := 3
-    ] ifFalse:[
-        lineSpacing := 2
-    ].
+    arrowLevel := 1.
+    smallArrow := false.
 
     (style == #next) ifTrue:[
         device hasGreyscales ifTrue:[
@@ -197,9 +291,13 @@
     ] ifFalse:[
         (style == #motif) ifTrue:[
             device hasGreyscales ifTrue:[
-                hilightFgColor := fgColor.
-                hilightBgColor := bgColor.
-                hilightLevel := 2.
+                fgColor := White.
+                bgColor := Grey.
+                viewBackground := bgColor.
+                hilightFgColor := bgColor  "fgColor" "White".
+                hilightBgColor := fgColor "bgColor lightened" "darkened".
+                hilightLevel := 0 "1".
+                arrowLevel := -1.
             ] ifFalse:[
                 hilightFgColor := White.
                 hilightBgColor := Black
@@ -210,6 +308,8 @@
                     hilightFgColor := fgColor.
                     hilightBgColor := Color grey.
                     hilightLevel := -1.
+                    arrowLevel := -1.
+                    smallArrow := true.
                 ] ifFalse:[
                     hilightFgColor := White.
                     hilightBgColor := Black
@@ -224,7 +324,7 @@
                         hilightBgColor := Black
                     ]
                 ] ifFalse:[
-                    self is3D ifTrue:[
+                    (style == #view3D) ifTrue:[
                         device hasColors ifTrue:[
                             hilightFgColor := Color name:'yellow'
                         ] ifFalse:[
@@ -241,6 +341,12 @@
         ]
     ].
 
+    (hilightLevel abs > 0) ifTrue:[
+        lineSpacing := 3
+    ] ifFalse:[
+        lineSpacing := 2
+    ].
+
     hilightFgColor isNil ifTrue:[
         hilightFgColor := bgColor.
         hilightBgColor := fgColor
@@ -281,10 +387,11 @@
 !
 
 ignoreReselect:aBoolean
-    "set/clear the ignoreReselect flag - if set,
-     a click on an already selected entry is ignored.
+    "set/clear the ignoreReselect flag - 
+     if set, a click on an already selected entry is ignored.
      Otherwise the notification is done, even if no
-     change in the selection occurs."
+     change in the selection occurs.
+     (for example, in browser to update a method)"
 
     ignoreReselect := aBoolean
 !
@@ -577,7 +684,7 @@
     |newSelection|
 
     selection notNil ifTrue:[
-        (selection isKindOf:Collection) ifTrue:[
+        (selection size > 0) ifTrue:[
             newSelection := OrderedCollection new.
             selection do:[:sel |
                 sel < lineNr ifTrue:[
@@ -586,6 +693,7 @@
                     sel > lineNr ifTrue:[
                         newSelection add:(sel - 1)
                     ]
+                    "otherwise remove it from the selection"
                 ]
             ].
             newSelection size == 1 ifTrue:[
@@ -661,6 +769,8 @@
     ].
 
     anySelectionInRange ifTrue:[
+        ^ width
+"
         self is3D ifFalse:[
             ^ width 
         ].
@@ -670,6 +780,7 @@
         viewBackground = background ifFalse:[
             ^ width 
         ]
+"
     ].
     ^ super widthForScrollBetween:start and:end
 !
@@ -727,7 +838,7 @@
      This method is not used here, but provided for subclasses such
      as menus or file-lists."
 
-    |w h y x l form|
+    |w h y x l form form2 topLeftColor botRightColor t|
 
     x := width - 16.
     y := (self yOfLine:visLineNr).
@@ -738,14 +849,36 @@
         self foreground:Black.
         self displayForm:form x:x y:y.
     ] ifFalse:[
-        form := self class rightArrowLightFormOn:device.
+        smallArrow ifTrue:[
+            form := self class smallRightArrowLightFormOn:device.
+            form2 := self class smallRightArrowShadowFormOn:device.
+        ] ifFalse:[
+            form := self class rightArrowLightFormOn:device.
+            form2 := self class rightArrowShadowFormOn:device.
+        ].
         y := y + ((font height - form height) // 2).
 
-        self foreground:lightColor.
-        self displayForm:form x:x y:y.
+        topLeftColor := lightColor.
+        botRightColor := shadowColor. 
 
-        self foreground:shadowColor.
-        self displayForm:(self class rightArrowShadowFormOn:device) x:x y:y.
+        "openwin arrow stays down"
+        style ~~ #openwin ifTrue:[
+            (self isInSelection:(self visibleLineToListLine:visLineNr)) ifTrue:[
+                t := topLeftColor.
+                topLeftColor := botRightColor.
+                botRightColor := t.
+            ]
+        ].
+        arrowLevel < 0 ifTrue:[
+            t := topLeftColor.
+            topLeftColor := botRightColor.
+            botRightColor := t.
+        ].
+
+        self foreground:topLeftColor.
+        self displayForm:form x:x y:y.
+        self foreground:botRightColor.
+        self displayForm:form2 x:x y:y.
     ]
 !
 
@@ -756,6 +889,9 @@
 !
 
 redrawVisibleLine:visLineNr col:colNr
+    "redraw a single character.
+     Must check, if its in the selection and handle this case."
+
     (self visibleLineNeedsSpecialCare:visLineNr) ifTrue:[
         ^ self redrawVisibleLine:visLineNr
     ].
@@ -763,6 +899,9 @@
 !
 
 redrawVisibleLine:visLineNr from:startCol
+    "redraw from a col to the right end.
+     Must check, if its in the selection and handle this case."
+
     (self visibleLineNeedsSpecialCare:visLineNr) ifTrue:[
         ^ self redrawVisibleLine:visLineNr
     ].
@@ -770,6 +909,9 @@
 !
 
 redrawVisibleLine:visLineNr from:startCol to:endCol
+    "redraw from a startCol to endCol.
+     Must check, if its in the selection and handle this case."
+
     (self visibleLineNeedsSpecialCare:visLineNr) ifTrue:[
         ^ self redrawVisibleLine:visLineNr
     ].
@@ -777,6 +919,10 @@
 !
 
 redrawFromVisibleLine:startVisLineNr to:endVisLineNr
+    "redraw a range of lines.
+     Must check, if any is in the selection and handle this case.
+     Otherwise draw it en-bloque using supers method."
+
     |special sel
      selNo "{ Class: SmallInteger }" |
 
@@ -787,6 +933,11 @@
         ^ self
     ].
 
+"XXX only if -1/+1"
+"/    hilightLevel ~~ 0 ifTrue:[
+"/     self paint:bgColor.
+"/     self fillRectangleX:0 y:(self yOfLine:startVisLineNr)-1 width:width height:1
+"/  ].
     special := true.
     selection isNil ifTrue:[
         special := false
@@ -814,39 +965,83 @@
 !
 
 redrawVisibleLine:visLineNr
-    |listLine fg bg
-     y "{ Class: SmallInteger }" |
+    "redraw a single line.
+     Must check, if any is in the selection and handle this case.
+     Otherwise draw using supers method."
+
+    |listLine fg bg|
 
     fg := fgColor.
     bg := bgColor.
     listLine := self visibleLineToListLine:visLineNr.
     listLine notNil ifTrue:[
+        (self isInSelection:listLine) ifTrue:[
+            ^ self drawVisibleLineSelected:visLineNr
+        ].
         (self attributeAt:listLine) == #halfIntensity ifTrue:[
             fg := halfIntensityFgColor
         ].
-        (self isInSelection:listLine) ifTrue:[
-            bg := hilightBgColor.
-            fg := hilightFgColor.
-            hilightFrameColor notNil ifTrue:[
-                self drawVisibleLine:visLineNr with:fg and:bg.
-                y := self yOfLine:visLineNr.
-                self paint:hilightFrameColor.
-                self displayLineFromX:0 y:y toX:width y:y.
-                y := y + fontHeight - 1.
-                self displayLineFromX:0 y:y toX:width y:y.
-                ^ self
-            ].
-            (hilightLevel ~~ 0) ifTrue:[
-                self drawVisibleLine:visLineNr with:fg and:bg.
-                y := self yOfLine:visLineNr.
-                self drawEdgesForX:0 y:y 
-                             width:width height:fontHeight 
-                             level:hilightLevel.
-                ^ self
-            ]
+    ].
+    ^ self drawVisibleLine:visLineNr with:fg and:bg
+!
+
+drawVisibleLineSelected:visLineNr
+    "redraw a single line as selected."
+
+    |listLine fg bg
+     y "{ Class: SmallInteger }" 
+     wEdge|
+
+    bg := hilightBgColor.
+    fg := hilightFgColor.
+    listLine := self visibleLineToListLine:visLineNr.
+    listLine notNil ifTrue:[
+"XXX only if -1/+1"
+"/        hilightLevel ~~ 0 ifTrue:[
+"/          self paint:bg.
+"/          self fillRectangleX:0 y:(self yOfLine:visLineNr)-1 width:width height:1
+"/      ].
+
+        self drawVisibleLine:visLineNr with:fg and:bg.
+        y := self yOfLine:visLineNr.
+
+        "
+         a line above and below
+        "
+        hilightFrameColor notNil ifTrue:[
+            self paint:hilightFrameColor.
+            self displayLineFromX:0 y:y toX:width y:y.
+            y := y + fontHeight - 1.
+            self displayLineFromX:0 y:y toX:width y:y.
+            ^ self
+        ].
+
+        "
+         an edge it around
+        "
+        (hilightLevel ~~ 0) ifTrue:[
+"XXX the -1/+1 need some more work"
+"/                self drawEdgesForX:0 y:y-1 
+"/                             width:width height:fontHeight+1 
+"/                             level:hilightLevel.
+
+            "
+             let edge start at left, extending to the full width
+             XXX: widthOfContents should be cached in ListView
+                  (instead of recumputing all over)
+            "
+            wEdge := width-(2 * margin).
+            wEdge := wEdge max:(self widthOfContents).
+
+            self drawEdgesForX:(margin - leftOffset) y:y 
+                         width:wEdge height:fontHeight 
+                         level:hilightLevel.
+
+
+            ^ self
         ]
     ].
-    ^ self drawVisibleLine:visLineNr with:fg and:bg
+    ^ super drawVisibleLine:visLineNr with:fg and:bg
 ! !
 
 !SelectionInListView methodsFor:'event handling'!
@@ -914,7 +1109,7 @@
 buttonPress:button x:x y:y
     |oldSelection listLineNr|
 
-    (button == 1) ifTrue:[
+    ((button == 1) or:[button == #select]) ifTrue:[
         enabled ifTrue:[
             (selectConditionBlock isNil or:[selectConditionBlock value]) ifTrue:[
                 oldSelection := selection.
@@ -941,7 +1136,7 @@
 buttonShiftPress:button x:x y:y
     |oldSelection listLineNr|
 
-    (button == 1) ifTrue:[
+    ((button == 1) or:[button == #select]) ifTrue:[
         enabled ifTrue:[
             (selectConditionBlock isNil or:[selectConditionBlock value]) ifTrue:[
                 oldSelection := selection copy.
@@ -960,7 +1155,9 @@
                 (selection ~= oldSelection) ifTrue:[
                     actionBlock notNil ifTrue:[actionBlock value:selection].
                     "the ST-80 way of doing things"
-                    model notNil ifTrue:[model perform:changeSymbol with:(self selectionValue)]
+                    (model notNil and:[changeSymbol notNil]) ifTrue:[
+                        model perform:changeSymbol with:(self selectionValue)
+                    ]
                 ].
                 clickLine := listLineNr
             ]
@@ -971,7 +1168,7 @@
 !
 
 buttonMultiPress:button x:x y:y
-    (button == 1) ifTrue:[
+    ((button == 1) or:[button == #select]) ifTrue:[
         doubleClickActionBlock isNil ifTrue:[
             self buttonPress:button x:x y:y
         ] ifFalse:[