[squeak-dev] The Trunk: Morphic-mt.1582.mcz

Thiede, Christoph Christoph.Thiede at student.hpi.uni-potsdam.de
Fri Nov 1 23:42:45 UTC 2019


Looks great! Some ideas:


- I find it confusing that filters from columns that are not currently selected are not displayed, but still active. In this example, I filtered the left column for "tex" and then selected the right one. Now there is no visual indication of the left filter:


[cid:17e775c3-8a76-46c9-9596-4e080bfb8df5]


Would it be possible to display such filters as by giving them a grey background color?


- If I pressed Tab again on the screenshot above, I would like no column to be selected again. Why not implement tab cycling along the series "all columns, col1, col2, ..., coln, all columns"?

- Wouldn't it be more convenient if you could also use the cursor to focus a column? :)


Best,

Christoph

________________________________
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Chris Muller <asqueaker at gmail.com>
Gesendet: Freitag, 25. Oktober 2019 01:36:31
An: squeak dev
Cc: packages at lists.squeakfoundation.org
Betreff: Re: [squeak-dev] The Trunk: Morphic-mt.1582.mcz

Very nice, looking forward to trying it out.

Thanks!

On Wed, Oct 23, 2019 at 8:31 AM <commits at source.squeak.org<mailto:commits at source.squeak.org>> wrote:
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1582.mcz

==================== Summary ====================

Name: Morphic-mt.1582
Author: mt
Time: 23 October 2019, 3:31:24.67861 pm
UUID: 82af72b9-4198-4bd2-8e7e-e8733d9018c7
Ancestors: Morphic-mt.1581

Adds things for column-specific list filtering:

- backgroundColor for LazyListMorph
- optional filter-term indication for LazyListMorph
- column highlights for multi-column lists
- Character tab to cycle between columns

Note that I opted to not use the [space] key for column toggling because (a) we have to widget-focus cycling via [tab] at the moment and (b) the space character might be a valuable filter term.

=============== Diff against Morphic-mt.1581 ===============

Item was changed:
  Morph subclass: #LazyListMorph
+       instanceVariableNames: 'listItems listIcons listFilterOffsets font selectedRow selectedRows preSelectedRow listSource maxWidth columnIndex iconExtent backgroundColor showFilter'
-       instanceVariableNames: 'listItems listIcons listFilterOffsets font selectedRow selectedRows preSelectedRow listSource maxWidth columnIndex iconExtent'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Morphic-Widgets'!

  !LazyListMorph commentStamp: 'mt 10/13/2019 19:44' prior: 0!
  The morph that displays the list in a PluggableListMorph.  It is "lazy" because it will only request the list items that it actually needs to display.

  I will cache the maximum width of my items in maxWidth to avoid this potentially expensive and frequent computation.

  The following layout properties are supported:
  - #cellPositioning: #leftCenter [default], #center, #rightCenter
  - #cellInset: [default: 3 at 0 corner: 3 at 0]!

Item was added:
+ ----- Method: LazyListMorph>>backgroundColor (in category 'accessing') -----
+ backgroundColor
+       "Since #color is this morph's default text color, this extra property is used for the actual background color. Supports nil."
+
+       ^ backgroundColor!

Item was added:
+ ----- Method: LazyListMorph>>backgroundColor: (in category 'accessing') -----
+ backgroundColor: aColor
+
+       backgroundColor = aColor ifTrue: [^ self].
+       backgroundColor := aColor.
+
+       self changed.
+       "Invalidate owner because we want to fill the vertical axis in the viewport entirely."
+       self owner ifNotNil: [:o | o changed].!

Item was changed:
  ----- Method: LazyListMorph>>displayFilterOn:for:in:font: (in category 'drawing') -----
  displayFilterOn: canvas for: row in: drawBounds font: font
        "Draw filter matches if any."

        | fillStyle fillHeight |
+       self showFilter ifFalse: [^ self].
-       listSource filterableList ifFalse: [^ self].

        fillHeight := font height.
        fillStyle := self filterColor isColor
                ifTrue: [SolidFillStyle color: self filterColor]
                ifFalse: [self filterColor].
        fillStyle isGradientFill ifTrue: [
                fillStyle origin: drawBounds topLeft.
                fillStyle direction: 0@ fillHeight].

        (self filterOffsets: row) do: [:offset |
                | highlightRectangle |
                highlightRectangle := ((drawBounds left + offset first first) @ drawBounds top
                        corner: (drawBounds left + offset first last) @ (drawBounds top + fillHeight)).
                canvas
                        frameAndFillRoundRect: (highlightRectangle outsetBy: 1 at 0)
                        radius: (3 * RealEstateAgent scaleFactor) truncated
                        fillStyle: fillStyle
                        borderWidth: (1 * RealEstateAgent scaleFactor) truncated
                        borderColor: fillStyle asColor twiceDarker.
                canvas
                        drawString: offset second
                        in: highlightRectangle
                        font: font
                        color: self filterTextColor].!

Item was changed:
  ----- Method: LazyListMorph>>drawOn: (in category 'drawing') -----
  drawOn: aCanvas

        | topRow bottomRow |
+       self backgroundColor ifNotNil: [:color |
+               aCanvas fillRectangle: (self topLeft corner: self right @ ((self owner ifNil: [self]) bottom)) color: color].
+
        self getListSize = 0 ifTrue: [ ^self ].

        self drawPreSelectionOn: aCanvas.

        topRow := self topVisibleRowForCanvas: aCanvas.
        bottomRow := self bottomVisibleRowForCanvas: aCanvas.

        "Draw multi-selection."
        self listSource hasMultiSelection ifTrue: [
                topRow to: bottomRow do: [ :row |
                        (self listSource itemSelectedAmongMultiple: row) ifTrue: [
                                self drawBackgroundForMulti: row on: aCanvas ] ] ].
        self drawSelectionOn: aCanvas.

        "Draw hovered row if preference enabled."
        PluggableListMorph highlightHoveredRow ifTrue: [
                self listSource hoverRow > 0 ifTrue: [
                        self highlightHoverRow: listSource hoverRow on: aCanvas ] ].

        "Draw all visible rows."
        topRow to: bottomRow do: [ :row |
                self display: (self item: row) atRow: row on: aCanvas ].

        "Finally, highlight drop row for drag/drop operations.."
        self listSource potentialDropRow > 0 ifTrue: [
                self highlightPotentialDropRow: self listSource potentialDropRow on: aCanvas ].!

Item was added:
+ ----- Method: LazyListMorph>>showFilter (in category 'accessing') -----
+ showFilter
+
+       ^ (showFilter ~~ false and: [listSource filterableList])!

Item was added:
+ ----- Method: LazyListMorph>>showFilter: (in category 'accessing') -----
+ showFilter: aBoolean
+
+       showFilter = aBoolean ifTrue: [^ self].
+       showFilter := aBoolean.
+       self changed.!

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>filterColumnColor (in category 'filtering') -----
+ filterColumnColor
+
+       ^ (Color gray: 0.85) alpha: 0.4!

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>filterColumnIndex (in category 'filtering') -----
+ filterColumnIndex
+       "Which column to apply the filter to?"
+
+       | i |
+       i := 0.
+       self listMorphs
+               detect: [:m | i := i + 1. m backgroundColor notNil]
+               ifNone: [i := 0].
+       ^ i!

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>filterList:columnIndex:matching: (in category 'filtering') -----
+ filterList: columns columnIndex: index matching: aPattern
+       "A matching row has a match in at least one column."
+
+       | frontMatching substringMatching rowCount columnCount tmp |
+       aPattern ifEmpty: [^ columns].
+       columns ifEmpty: [^ columns].
+
+       rowCount := columns first size.
+       rowCount = 0 ifTrue: [^ columns].
+       columnCount := columns size.
+
+       frontMatching := Array new: columnCount.
+       1 to: columnCount do: [:c | frontMatching at: c put: OrderedCollection new].
+       substringMatching := Array new: columnCount.
+       1 to: columnCount do: [:c | substringMatching at: c put: OrderedCollection new].
+
+       modelToView := Dictionary new.
+       viewToModel := Dictionary new.
+       tmp := OrderedCollection new.
+
+       1 to: rowCount do: [:rowIndex |
+               | match foundPos |
+               match := false.
+               foundPos := self
+                                               filterListItem: ((columns at: index) at: rowIndex)
+                                               matching: aPattern.
+               foundPos = 1
+                       ifTrue: [
+                               1 to: columnCount do: [:colIndex |
+                                       (frontMatching at: colIndex) add: ((columns at: colIndex) at: rowIndex)].
+                               modelToView at: rowIndex put: frontMatching first size.
+                               viewToModel at: frontMatching first size put: rowIndex]
+                       ifFalse: [foundPos > 1 ifTrue: [
+                               1 to: columnCount do: [:colIndex |
+                                       (substringMatching at: colIndex) add: ((columns at: colIndex) at: rowIndex)].
+                               tmp add: rowIndex; add: substringMatching first size]]
+       ].
+
+       tmp pairsDo: [:modelIndex :viewIndex |
+               modelToView at: modelIndex put: viewIndex + frontMatching first size.
+               viewToModel at: viewIndex + frontMatching first size put: modelIndex].
+
+       ^ (1 to: columnCount) collect: [:colIndex |
+               (frontMatching at: colIndex), (substringMatching at: colIndex)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !

Item was changed:
  ----- Method: PluggableMultiColumnListMorph>>filterList:matching: (in category 'filtering') -----
  filterList: columns matching: aPattern
        "A matching row has a match in at least one column."

        | frontMatching substringMatching rowCount columnCount tmp |
        aPattern ifEmpty: [^ columns].
        columns ifEmpty: [^ columns].

+       "Enable column-specific filtering."
+       self filterColumnIndex in: [:index |
+               index > 0 ifTrue: [^ self filterList: columns columnIndex: index matching: aPattern]].
+
        rowCount := columns first size.
        rowCount = 0 ifTrue: [^ columns].
        columnCount := columns size.

        frontMatching := Array new: columnCount.
        1 to: columnCount do: [:c | frontMatching at: c put: OrderedCollection new].
        substringMatching := Array new: columnCount.
        1 to: columnCount do: [:c | substringMatching at: c put: OrderedCollection new].

        modelToView := Dictionary new.
        viewToModel := Dictionary new.
        tmp := OrderedCollection new.

        1 to: rowCount do: [:rowIndex |
                | match foundPos |
                match := false.
                foundPos := 0.
                1 to: columnCount do: [:colIndex |
                        match := match or: [(foundPos := (self
                                                                        filterListItem: ((columns at: colIndex) at: rowIndex)
                                                                        matching: aPattern)+colIndex) > colIndex]].
                match & (foundPos = 2) "means front match in first column"
                        ifTrue: [
                                1 to: columnCount do: [:colIndex |
                                        (frontMatching at: colIndex) add: ((columns at: colIndex) at: rowIndex)].
                                modelToView at: rowIndex put: frontMatching first size.
                                viewToModel at: frontMatching first size put: rowIndex]
                        ifFalse: [match ifTrue: [
                                1 to: columnCount do: [:colIndex |
                                        (substringMatching at: colIndex) add: ((columns at: colIndex) at: rowIndex)].
                                tmp add: rowIndex; add: substringMatching first size]]
        ].

        tmp pairsDo: [:modelIndex :viewIndex |
                modelToView at: modelIndex put: viewIndex + frontMatching first size.
                viewToModel at: viewIndex + frontMatching first size put: modelIndex].

        ^ (1 to: columnCount) collect: [:colIndex |
                (frontMatching at: colIndex), (substringMatching at: colIndex)]













  !

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>highlightNextColumn (in category 'filtering') -----
+ highlightNextColumn
+
+       | i currentColumn nextColumn |
+       i := self filterColumnIndex.
+       i = 0 ifTrue: [self listMorphs do: [:m | m showFilter: false]].
+
+       currentColumn := self listMorphs at: (i max: 1).
+       nextColumn := self listMorphs at: i \\ self listMorphs size + 1.
+
+       currentColumn
+               showFilter: false;
+               backgroundColor: nil.
+
+       nextColumn
+               showFilter: true;
+               backgroundColor: self filterColumnColor.!

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>highlightNoColumn (in category 'filtering') -----
+ highlightNoColumn
+
+       self listMorphs do: [:m |
+               m showFilter: true; backgroundColor: nil].!

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>removeFilter (in category 'filtering') -----
+ removeFilter
+
+       self highlightNoColumn.
+       super removeFilter.
+ !

Item was added:
+ ----- Method: PluggableMultiColumnListMorph>>specialKeyPressed: (in category 'filtering') -----
+ specialKeyPressed: asciiValue
+       "Use the [Tab] key to filter specific columns."
+
+       ^ asciiValue = Character tab asciiValue
+               ifTrue: [self highlightNextColumn]
+               ifFalse: [super specialKeyPressed: asciiValue].!

Item was changed:
  ----- Method: PluggableMultiColumnListMorph>>updateColumns (in category 'updating') -----
  updateColumns
        "The number of columns must match the number of list morphs."

        | columnsChanged |
        columnsChanged := self columnCount ~= listMorphs size.

        [self columnCount < listMorphs size]
                whileTrue: [
                        listMorphs removeLast delete].

        [self columnCount > listMorphs size]
                whileTrue: [
                        listMorphs addLast: self createListMorph.
                        self scroller addMorphBack: listMorphs last].

        listMorphs doWithIndex: [:listMorph :columnIndex |
                listMorph
                        columnIndex: columnIndex;
+                       color: self textColor;
                        cellPositioning: (self cellPositioningAtColumn: columnIndex);
                        cellInset: (self cellInsetAtColumn: columnIndex);
                        hResizing: (self hResizingAtColumn: columnIndex);
                        spaceFillWeight: (self spaceFillWeightAtColumn: columnIndex)].

        columnsChanged ifTrue: [self setListParameters].!


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20191101/2b8571dd/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pastedImage.png
Type: image/png
Size: 136784 bytes
Desc: pastedImage.png
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20191101/2b8571dd/attachment-0001.png>


More information about the Squeak-dev mailing list