diff --git a/src/BaselineOfBrickExamplesReordering/BaselineOfBrickExamplesReordering.class.st b/src/BaselineOfBrickExamplesReordering/BaselineOfBrickExamplesReordering.class.st new file mode 100644 index 0000000..d83ed93 --- /dev/null +++ b/src/BaselineOfBrickExamplesReordering/BaselineOfBrickExamplesReordering.class.st @@ -0,0 +1,18 @@ +Class { + #name : #BaselineOfBrickExamplesReordering, + #superclass : #BaselineOf, + #category : #BaselineOfBrickExamplesReordering +} + +{ #category : #baselines } +BaselineOfBrickExamplesReordering >> baseline: spec [ + + spec for: #common do: [ + spec + baseline: 'NewBrick' + with: [ spec repository: 'github://pharo-graphics/Brick/src' ]. + spec + package: #'Brick-Examples-Reordering' with: [ + spec requires: #( #NewBrick ) ] ] + +] diff --git a/src/BaselineOfBrickExamplesReordering/package.st b/src/BaselineOfBrickExamplesReordering/package.st new file mode 100644 index 0000000..80cdf75 --- /dev/null +++ b/src/BaselineOfBrickExamplesReordering/package.st @@ -0,0 +1 @@ +Package { #name : #BaselineOfBrickExamplesReordering } diff --git a/src/Brick-Examples-Reordering/BrLeftButtonAptitude.class.st b/src/Brick-Examples-Reordering/BrLeftButtonAptitude.class.st new file mode 100644 index 0000000..4010d49 --- /dev/null +++ b/src/Brick-Examples-Reordering/BrLeftButtonAptitude.class.st @@ -0,0 +1,47 @@ +Class { + #name : #BrLeftButtonAptitude, + #superclass : #BrGlamorousButtonRectangularAptitude, + #category : #'Brick-Examples-Reordering' +} + +{ #category : #initialization } +BrLeftButtonAptitude >> initialize [ + super initialize. + self addAll: { + BrGlamorousButtonExteriorAptitude new. + BrGlamorousButtonIconAptitude new. + }. + self default geometry: ( BlRoundedRectangleGeometry cornerRadii: (BlCornerRadii new + topLeft: 4; + topRight: 0; + bottomLeft: 4; + bottomRight: 0)). + self add: (BrSizeAdjustmentAptitude new + mini: [ :aStyle | + aStyle + vExact: 12; + padding: (BlInsets left: 4 right: 4) ]; + tiny: [ :aStyle | + aStyle + vExact: 16; + padding: (BlInsets left: 6 right: 6) ]; + small: [ :aStyle | + aStyle + vExact: 20; + padding: (BlInsets left: 8 right: 8) ]; + normal: [ :aStyle | + aStyle + vExact: 24; + padding: (BlInsets left: 10 right: 10) ]; + large: [ :aStyle | + aStyle + vExact: 30; + padding: (BlInsets left: 10 right: 10) ]; + huge: [ :aStyle | + aStyle + vExact: 48; + padding: (BlInsets left: 16 right: 16) ]). + + self add: BrGlamorousButtonLayoutAptitude new + +] diff --git a/src/Brick-Examples-Reordering/BrRightButtonAptitude.class.st b/src/Brick-Examples-Reordering/BrRightButtonAptitude.class.st new file mode 100644 index 0000000..c6a0260 --- /dev/null +++ b/src/Brick-Examples-Reordering/BrRightButtonAptitude.class.st @@ -0,0 +1,47 @@ +Class { + #name : #BrRightButtonAptitude, + #superclass : #BrGlamorousButtonRectangularAptitude, + #category : #'Brick-Examples-Reordering' +} + +{ #category : #initialization } +BrRightButtonAptitude >> initialize [ + super initialize. + self addAll: { + BrGlamorousButtonExteriorAptitude new. + BrGlamorousButtonIconAptitude new. + }. + self default geometry: ( BlRoundedRectangleGeometry cornerRadii: (BlCornerRadii new + topLeft: 0; + topRight: 4; + bottomLeft: 0; + bottomRight: 4)). + self add: (BrSizeAdjustmentAptitude new + mini: [ :aStyle | + aStyle + vExact: 12; + padding: (BlInsets left: 4 right: 4) ]; + tiny: [ :aStyle | + aStyle + vExact: 16; + padding: (BlInsets left: 6 right: 6) ]; + small: [ :aStyle | + aStyle + vExact: 20; + padding: (BlInsets left: 8 right: 8) ]; + normal: [ :aStyle | + aStyle + vExact: 24; + padding: (BlInsets left: 10 right: 10) ]; + large: [ :aStyle | + aStyle + vExact: 30; + padding: (BlInsets left: 10 right: 10) ]; + huge: [ :aStyle | + aStyle + vExact: 48; + padding: (BlInsets left: 16 right: 16) ]). + + self add: BrGlamorousButtonLayoutAptitude new + +] diff --git a/src/Brick-Examples-Reordering/DTMultiPaneReorderingHandler.class.st b/src/Brick-Examples-Reordering/DTMultiPaneReorderingHandler.class.st new file mode 100644 index 0000000..bdb246e --- /dev/null +++ b/src/Brick-Examples-Reordering/DTMultiPaneReorderingHandler.class.st @@ -0,0 +1,228 @@ +" +In planning boards, we want to drag and drop tasks from one pane to another. This event handler supports that. The container is the space where the dragging and dropping is to happen, the panes are the elements that contain tasks +" +Class { + #name : #DTMultiPaneReorderingHandler, + #superclass : #DTReorderingHandler, + #instVars : [ + 'container', + 'panes' + ], + #category : #'Brick-Examples-Reordering' +} + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> cards [ + + | plusSize minSize bar pane scene aSpace | + pane := self threeColumns + constraintsDo: [ :c | + c horizontal matchParent. + c vertical matchParent ]. + plusSize := self plusButton + action: [ | subject | + subject := (pane childAt: 1) childAt: 1. + subject size: subject size + (20 @ 20) ]; + yourself. + minSize := self minButton + action: [ | subject | + subject := (pane childAt: 1) childAt: 1. + subject size: (subject size - (20 @ 20) max: 10 @ 10) ]; + yourself. + bar := BlElement new + size: 800 @ 40; + background: Color lightGray muchLighter; + layout: BlLinearLayout horizontal; + constraintsDo: [ :c | + c horizontal matchParent. + c vertical exact: 40 ]; + addChild: minSize; + addChild: plusSize; + yourself. + scene := BlElement new + constraintsDo: [ :c | + c horizontal matchParent. + c vertical matchParent ]; + layout: BlLinearLayout vertical; + addChild: bar; + addChild: pane; + requestLayout; + yourself. + aSpace := BlSpace new + addChild: scene; + extent: 800 @ 600; + title: 'Cards'. + ^ aSpace show +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> container: theContainer [ + container := theContainer +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> dragEndEvent: anEvent [ + "anEvent consumed: true." + | draggable | + draggable := anEvent currentTarget. + overlay removeChild: draggable. + parent replaceChild: placeholder with: draggable. + overlay detach. + + anEvent currentTarget dispatchEvent: BlPullEndEvent new +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> dragEvent: anEvent [ + | dragPosition dragDelta aNewPosition | + dragPosition := anEvent currentTarget + globalPointToParent: anEvent position. + self movePlaceholderIfOverOtherChild: anEvent. + dragDelta := dragPosition + - (dragStartPosition ifNil: [ dragStartPosition := dragPosition ]). + dragDelta := self computePullDelta: dragDelta. + aNewPosition := (originalPosition + ifNil: [ originalPosition := anEvent currentTarget position ]) + + dragDelta. + allowedOutOfBounds + ifFalse: [ | aMaxPosition | + aMaxPosition := anEvent currentTarget hasParent + ifTrue: [ anEvent currentTarget parent extent - anEvent currentTarget extent ] + ifFalse: [ 0 @ 0 ]. + aNewPosition := aNewPosition min: aMaxPosition max: 0 @ 0 ]. + anEvent currentTarget relocate: aNewPosition. + anEvent consumed: true. + anEvent currentTarget + dispatchEvent: + (BlPullEvent new + initialPosition: originalPosition; + oldPosition: dragPosition; + newPosition: aNewPosition; + delta: dragDelta) +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> dragStartEvent: anEvent [ + |draggable | + anEvent consumed: true. + draggable := anEvent currentTarget. + parent := panes detect: [ :aPane | aPane containsGlobalPoint: anEvent position ]. + overlay := BlOverlayElement on: container. + container parent addChild: overlay. + + "drag start position in parent" + dragStartPosition := draggable globalPointToParent: anEvent position. + + "element position in parent" + originalPosition := draggable position. + placeholder := self placeholderFor: draggable. + parent replaceChild: draggable with: placeholder. + overlay addChild: draggable. + + anEvent currentTarget dispatchEvent: BlPullStartEvent new +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> minButton [ + ^BrButton new + margin: + (BlInsets + top: 10 + left: 10 + bottom: 10 + right: 0); + aptitude: BrLeftButtonAptitude; + icon: BrGlamorousVectorIcons remove; + yourself. +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> movePlaceholderIfOverOtherChild: anEvent [ + | mouseOverOther | + self movePlaceholderToCorrectParent: anEvent. + mouseOverOther := placeholder. + parent children + do: [ :each | + (each containsGlobalPoint: anEvent position) + ifTrue: [ mouseOverOther := each ] ]. + mouseOverOther = placeholder + ifFalse: [ | index | + index := parent childIndexOf: mouseOverOther. + parent removeChild: placeholder. + parent addChild: placeholder at: index ] +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> movePlaceholderToCorrectParent: anEvent [ + | currentPane | + currentPane := panes + detect: [ :aPane | aPane containsGlobalPoint: anEvent position ] + ifNone: [ parent ]. + currentPane = parent + ifFalse: [ parent removeChild: placeholder. + parent := currentPane. + parent addChild: placeholder ] +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> panes: thePanes [ + panes := thePanes +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> plusButton [ + ^BrButton new + margin: + (BlInsets + top: 10 + left: 0 + bottom: 10 + right: 10); + aptitude: BrRightButtonAptitude; + icon: BrGlamorousVectorIcons add; + yourself. +] + +{ #category : #'as yet unclassified' } +DTMultiPaneReorderingHandler >> threeColumns [ + + |pane columnBlock toDo doing done columns handler| + pane := BlElement new + size: 800 @ 600; + background: (Color lightGray muchLighter); + padding: (BlInsets all: 2); + layout: BlLinearLayout horizontal; + yourself. + +columnBlock := [BlElement new + border: (BlBorder paint: Color lightGray lighter); + background: Color yellow muchLighter muchLighter lighter; + layout: BlFlowLayout new; + margin: (BlInsets all: 2); + padding: (BlInsets all: 2); + constraintsDo: [ :c | + c horizontal matchParent. + c vertical matchParent]]. + +toDo := columnBlock value. +doing := columnBlock value. +done := columnBlock value. +columns := { toDo . doing . done}. + +handler := DTMultiPaneReorderingHandler new + container: pane; + panes: columns; + yourself. + +pane addChildren: columns. +10 timesRepeat: [ |element| + element := BlElement new + size: 80 @ 60; + border: (BlBorder paint: Color black); + background: Color random; + margin: (BlInsets all: 2); + addEventHandler: handler; + yourself. + toDo addChild: element]. +^pane +] diff --git a/src/Brick-Examples-Reordering/DTPaneCreatingReorderingHandler.class.st b/src/Brick-Examples-Reordering/DTPaneCreatingReorderingHandler.class.st new file mode 100644 index 0000000..d19ff7d --- /dev/null +++ b/src/Brick-Examples-Reordering/DTPaneCreatingReorderingHandler.class.st @@ -0,0 +1,136 @@ +Class { + #name : #DTPaneCreatingReorderingHandler, + #superclass : #DTMultiPaneReorderingHandler, + #instVars : [ + 'draggableOffset' + ], + #category : #'Brick-Examples-Reordering' +} + +{ #category : #adding } +DTPaneCreatingReorderingHandler >> addPaneWith: draggable at: anEvent [ + |column| + column := self columnBlock value. + panes add: column. + column addChild: draggable. + container addChild: column. + column relocate: (column globalPointToParent: anEvent position) - draggableOffset + (-4@ -12). + column when: BlPullStartEvent do: [ self makeLast: column]. + +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> columnBlock [ + ^ [ BlElement new + border: (BlBorder paint: Color lightGray lighter); + background: Color yellow muchLighter muchLighter lighter; + layout: BlFlowLayout new; + margin: (BlInsets all: 2); + padding: (BlInsets top: 10 left: 2 bottom: 2 right: 2); + constraintsDo: [ :c | + c horizontal exact: 86*3. + c vertical fitContent ]; + addEventHandler: BlPullHandler new ] +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> dragEndEvent: anEvent [ + "anEvent consumed: true." + | draggable | + draggable := anEvent currentTarget. + overlay removeChild: draggable. + (parent containsGlobalPoint: anEvent position) ifTrue: [ + parent replaceChild: placeholder with: draggable] + ifFalse: [ + parent removeChild: placeholder. + self addPaneWith: draggable at: anEvent]. + overlay detach. + panes do: [:each | |nrOfChildren| + nrOfChildren := each childrenCount. + nrOfChildren = 0 ifTrue: [ container removeChild: each] + ifFalse: [ each constraintsDo: [ :c | + c horizontal exact: 86*(nrOfChildren sqrt roundUpTo: 1)]]. +]. + (panes removeAllSuchThat: [:each | each childrenCount = 0]). + anEvent currentTarget dispatchEvent: BlPullEndEvent new +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> dragStartEvent: anEvent [ + |draggable | + anEvent consumed: true. + draggable := anEvent currentTarget. + parent := panes detect: [ :aPane | (aPane containsGlobalPoint: anEvent position) + and: [ draggable hasParent: aPane]]. + overlay := BlOverlayElement on: container. + container parent addChild: overlay. + + "drag start position in parent" + dragStartPosition := draggable globalPointToParent: anEvent position. + draggableOffset := dragStartPosition - draggable position. + "element position in parent" + originalPosition := draggable position. + placeholder := self placeholderFor: draggable. + parent replaceChild: draggable with: placeholder. + overlay addChild: draggable. + + anEvent currentTarget dispatchEvent: BlPullStartEvent new +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> fittingColumns [ + + | pane columnBlock toDo columns handler | + pane := BlElement new + size: 800 @ 600; + background: Color lightGray muchLighter; + padding: (BlInsets all: 2); + layout: BlBasicLayout new; + yourself. + columnBlock := self columnBlock. + toDo := columnBlock value. + columns := {toDo} asOrderedCollection. + handler := self class new + container: pane; + panes: columns; + yourself. + columns do: [:column | + column when: BlPullStartEvent do: [ handler makeLast: column]]. + pane addChildren: columns. + 10 + timesRepeat: [ | element | + element := BlElement new + size: 80 @ 60; + border: (BlBorder paint: Color black); + background: Color random; + margin: (BlInsets all: 2); + addEventHandler: handler; + yourself. + toDo addChild: element ]. + ^ pane +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> makeLast: aPane [ + panes swap: (panes indexOf: aPane) with: panes size. + container removeChildren. + container addChildren: panes +] + +{ #category : #'as yet unclassified' } +DTPaneCreatingReorderingHandler >> movePlaceholderToCorrectParent: anEvent [ + | currentPane | + currentPane := panes reversed + detect: [ :aPane |(aPane containsGlobalPoint: anEvent position)] + ifNone: [ parent ]. + currentPane = parent + ifFalse: [ + parent removeChild: placeholder. + parent constraintsDo: [ :c | + c horizontal exact: 86*(parent childrenCount sqrt roundUpTo: 1)]. + parent := currentPane. + parent addChild: placeholder. + parent constraintsDo: [ :c | + c horizontal exact: 86*(parent childrenCount sqrt roundUpTo: 1)]. + ] +] diff --git a/src/Brick-Examples-Reordering/DTReorderingHandler.class.st b/src/Brick-Examples-Reordering/DTReorderingHandler.class.st new file mode 100644 index 0000000..fdac18f --- /dev/null +++ b/src/Brick-Examples-Reordering/DTReorderingHandler.class.st @@ -0,0 +1,196 @@ +" +I support dragging and dropping to reorder +" +Class { + #name : #DTReorderingHandler, + #superclass : #BlCustomEventHandler, + #instVars : [ + 'originalPosition', + 'dragStartPosition', + 'allowedOutOfBounds', + 'direction', + 'overlay', + 'parent', + 'placeholder' + ], + #classVars : [ + 'Any', + 'Horizontal', + 'Vertical' + ], + #category : #'Brick-Examples-Reordering' +} + +{ #category : #initialization } +DTReorderingHandler class >> initialize [ + Any := #any. + Vertical := #vertical. + Horizontal := #horizontal +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> allowOutOfBounds [ + "Allow the pulled element to be pulled outside of the parent bounds" + + allowedOutOfBounds := true +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> beFree [ + direction := Any +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> beHorizontal [ + direction := Horizontal +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> beVertical [ + direction := Vertical +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> computePullDelta: aDragDelta [ + + + direction = Any + ifTrue: [ ^ aDragDelta ]. + + direction = Vertical + ifTrue: [ ^ 0 @ aDragDelta y ]. + + direction = Horizontal + ifTrue: [ ^ aDragDelta x @ 0 ]. + + ^ direction +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> disallowOutOfBounds [ + "Do not allow the pulled element to be pulled outside of the parent bounds" + + allowedOutOfBounds := false +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> dragEndEvent: anEvent [ + "anEvent consumed: true." + | draggable | + draggable := anEvent currentTarget. + overlay removeChild: draggable. + parent replaceChild: placeholder with: draggable. + overlay detach. + + anEvent currentTarget dispatchEvent: BlPullEndEvent new +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> dragEvent: anEvent [ + | dragPosition dragDelta aNewPosition | + dragPosition := anEvent currentTarget + globalPointToParent: anEvent position. + self movePlaceholderIfOverOtherChild: anEvent. + dragDelta := dragPosition + - (dragStartPosition ifNil: [ dragStartPosition := dragPosition ]). + dragDelta := self computePullDelta: dragDelta. + aNewPosition := (originalPosition + ifNil: [ originalPosition := anEvent currentTarget position ]) + + dragDelta. + allowedOutOfBounds + ifFalse: [ | aMaxPosition | + aMaxPosition := anEvent currentTarget hasParent + ifTrue: [ anEvent currentTarget parent extent - anEvent currentTarget extent ] + ifFalse: [ 0 @ 0 ]. + aNewPosition := aNewPosition min: aMaxPosition max: 0 @ 0 ]. + anEvent currentTarget relocate: aNewPosition. + anEvent consumed: true. + anEvent currentTarget + dispatchEvent: + (BlPullEvent new + initialPosition: originalPosition; + oldPosition: dragPosition; + newPosition: aNewPosition; + delta: dragDelta) +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> dragStartEvent: anEvent [ + |draggable | + anEvent consumed: true. + draggable := anEvent currentTarget. + parent := draggable parent. + overlay := BlOverlayElement on: parent. + parent parent addChild: overlay. + + "drag start position in parent" + dragStartPosition := draggable globalPointToParent: anEvent position. + + "element position in parent" + originalPosition := draggable position. + placeholder := self placeholderFor: draggable. + parent replaceChild: draggable with: placeholder. + overlay addChild: draggable. + + anEvent currentTarget dispatchEvent: BlPullStartEvent new +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> eventsToHandle [ + ^ { BlDragStartEvent . BlDragEvent . BlDragEndEvent } +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> initialize [ + super initialize. + + allowedOutOfBounds := true. + direction := Any +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> inplaceSorting [ + + | pane | + pane := BlElement new + size: 700 @ 600; + layout: BlFlowLayout new; + border: (BlBorder paint: Color black); + padding: (BlInsets all: 5) + yourself. + 10 timesRepeat: [ |element| + element := BlElement new + size: 150 @ 100; + border: (BlBorder paint: Color black); + background: Color random; + margin: (BlInsets all: 5); + addEventHandler: DTReorderingHandler new; + yourself. + pane addChild: element]. +^pane +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> movePlaceholderIfOverOtherChild: anEvent [ + | mouseOverOther | + mouseOverOther := placeholder. + parent children + do: [ :each | + (each containsGlobalPoint: anEvent position) + ifTrue: [ mouseOverOther := each ] ]. + mouseOverOther = placeholder + ifFalse: [ | index | + index := parent childIndexOf: mouseOverOther. + parent removeChild: placeholder. + parent addChild: placeholder at: index ] +] + +{ #category : #'api - pull handler' } +DTReorderingHandler >> placeholderFor: draggable [ + ^BlElement new + size: draggable size; + border: (draggable border copyWithStyle: BlStrokeStyle dashed); + margin: draggable margin; + background: (draggable background paint color alpha: 0.2); + yourself +] diff --git a/src/Brick-Examples-Reordering/package.st b/src/Brick-Examples-Reordering/package.st new file mode 100644 index 0000000..4579d4b --- /dev/null +++ b/src/Brick-Examples-Reordering/package.st @@ -0,0 +1 @@ +Package { #name : #'Brick-Examples-Reordering' }