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

Marcel Taeumel marcel.taeumel at hpi.de
Wed Oct 23 13:33:46 UTC 2019


Best,
Marcel
Am 23.10.2019 15:31:47 schrieb commits at source.squeak.org <commits at source.squeak.org>:
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
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/20191023/5a1c0779/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 19886 bytes
Desc: not available
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20191023/5a1c0779/attachment.png>


More information about the Squeak-dev mailing list