Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Spec2-Adapters-Morphic/LayoutPolicy.extension.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Extension { #name : 'LayoutPolicy' }

{ #category : '*Spec2-Adapters-Morphic' }
LayoutPolicy >> isFromEnd [
^ false
]
4 changes: 2 additions & 2 deletions src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ SpMorphicBackend >> inform: aString [
"If we are not in interactive mode, we log in the stdout. Else we delegate to the Morphic notification"

Smalltalk isInteractive
ifTrue: [ GrowlMorph openWithLabel: 'Information' translated contents: aString ]
ifTrue: [ GrowlMorph openWithLabel: 'Information' contents: aString ]
ifFalse: [
| logBlock |
logBlock := [ :logger |
Expand Down Expand Up @@ -99,7 +99,7 @@ SpMorphicBackend >> notifyError: aSpecNotification [
SpMorphicBackend >> notifyInfo: aSpecNotification [

GrowlMorph
openWithLabel: 'Information' translated
openWithLabel: 'Information'
contents: aSpecNotification message
]

Expand Down
146 changes: 98 additions & 48 deletions src/Spec2-Adapters-Morphic/SpMorphicPanedLayout.class.st
Original file line number Diff line number Diff line change
@@ -1,63 +1,109 @@
"
I'm a table layout for PanedLayouts.
I add some posibilities to layouting (like defining the initial position in proportional
numbers instead a fixed number).

This is needed because sometimes I want to express a position like:

SpecPanedLayout new
position: 80 percent;
...

instead a fixed number I may change in other places.

I am a specialized TableLayout for PanedLayouts in the Morphic adapter.

I manage rigid and spaceFill resizing constraints for the first and second child submorphs based on `#position`:
- Fixed values (|position| >= 1):
Positive (e.g. 200): First submorph is rigid with specified width/height; last submorph is spaceFill.
Negative (e.g. -200): Last submorph is rigid with absolute width/height; first submorph is spaceFill.
- Proportional values (|position| < 1):
Submorph sizes are updated proportionally on layout passes.
- Splitter interaction:
When the splitter is dragged, the sizing mode (fixed vs proportional, start vs end) is preserved rather than being forcibly coerced into a percentage.
"
Class {
#name : 'SpMorphicPanedLayout',
#superclass : 'TableLayout',
#instVars : [
'position'
'position',
'isResizing'
],
#category : 'Spec2-Adapters-Morphic-Layout',
#package : 'Spec2-Adapters-Morphic',
#tag : 'Layout'
}

{ #category : 'private' }
SpMorphicPanedLayout >> ensureHeightPosition: aMorph in: aRect [
| firstMorph height |
SpMorphicPanedLayout >> computePreservedPositionOn: layoutedMorph [
| targetMorph newDimension delta |
targetMorph := self isFromEnd
ifTrue: [ layoutedMorph submorphs last ]
ifFalse: [ layoutedMorph submorphs first ].

newDimension := self isHorizontal
ifTrue: [ targetMorph width ]
ifFalse: [ targetMorph height ].

self isFixed ifTrue: [
^ self isFromEnd
ifTrue: [ newDimension asInteger negated ]
ifFalse: [ newDimension asInteger ] ].

delta := self isHorizontal
ifTrue: [ (newDimension * 100 / layoutedMorph width) asInteger percent ]
ifFalse: [ (newDimension * 100 / layoutedMorph height) asInteger percent ].

^ self isFromEnd
ifTrue: [ delta negated ]
ifFalse: [ delta ]
]

{ #category : 'private' }
SpMorphicPanedLayout >> ensureHeightPosition: aMorph in: aRect [
| targetMorph otherMorph height |
self position ifNil: [ ^ self ].
self isResizing ifTrue: [ ^ self ].
aMorph submorphs size < 3 ifTrue: [ ^ self ].

targetMorph := self isFromEnd
ifTrue: [ aMorph submorphs last ]
ifFalse: [ aMorph submorphs first ].
otherMorph := self isFromEnd
ifTrue: [ aMorph submorphs first ]
ifFalse: [ aMorph submorphs last ].

targetMorph vResizing = #rigid ifFalse: [ targetMorph vResizing: #rigid ].
otherMorph vResizing = #spaceFill ifFalse: [ otherMorph vResizing: #spaceFill ].

firstMorph := aMorph submorphs first.
firstMorph vResizing = #rigid
ifFalse: [ firstMorph vResizing: #rigid ].
height := self heightPositionIn: aRect extent.
firstMorph height = height
ifFalse: [ firstMorph height: height ]
targetMorph height = height ifFalse: [ targetMorph height: height ]
]

{ #category : 'private' }
SpMorphicPanedLayout >> ensureWidthPosition: aMorph in: aRect [
| firstMorph width |

| targetMorph otherMorph width |
self position ifNil: [ ^ self ].
self isResizing ifTrue: [ ^ self ].
aMorph submorphs size < 3 ifTrue: [ ^ self ].

targetMorph := self isFromEnd
ifTrue: [ aMorph submorphs last ]
ifFalse: [ aMorph submorphs first ].
otherMorph := self isFromEnd
ifTrue: [ aMorph submorphs first ]
ifFalse: [ aMorph submorphs last ].

targetMorph hResizing = #rigid ifFalse: [ targetMorph hResizing: #rigid ].
otherMorph hResizing = #spaceFill ifFalse: [ otherMorph hResizing: #spaceFill ].

firstMorph := aMorph submorphs first.
firstMorph hResizing = #rigid
ifFalse: [ firstMorph hResizing: #rigid ].
width := self widthPositionIn: aRect extent.
firstMorph width = width
ifFalse: [ firstMorph width: width ].

targetMorph width = width ifFalse: [ targetMorph width: width ]
]

{ #category : 'private' }
SpMorphicPanedLayout >> heightPositionIn: aPoint [
SpMorphicPanedLayout >> heightPositionIn: aPoint [
self position ifNil: [ ^ (aPoint y * 0.5) asInteger ].
self isFixed ifTrue: [ ^ self position abs asInteger ].
^ (aPoint y * self position abs) asInteger
]

^ self position < 1
ifTrue: [ (aPoint y * self position) asInteger ]
ifFalse: [ self position ]
{ #category : 'testing' }
SpMorphicPanedLayout >> isFixed [
^ self position isNotNil and: [ self position abs >= 1 ]
]

{ #category : 'testing' }
SpMorphicPanedLayout >> isFromEnd [
^ self position isNotNil and: [ self position < 0 ]
]

{ #category : 'testing' }
Expand All @@ -67,14 +113,19 @@ SpMorphicPanedLayout >> isHorizontal [
or: [ properties listDirection == #bottomToTop ]) not
]

{ #category : 'private' }
{ #category : 'testing' }
SpMorphicPanedLayout >> isResizing [
^ isResizing ifNil: [ false ]
]

{ #category : 'layout' }
SpMorphicPanedLayout >> layoutLeftToRight: aMorph in: newBounds [

self ensureWidthPosition: aMorph in: newBounds.
super layoutLeftToRight: aMorph in: newBounds
]

{ #category : 'private' }
{ #category : 'layout' }
SpMorphicPanedLayout >> layoutTopToBottom: aMorph in: newBounds [

self ensureHeightPosition: aMorph in: newBounds.
Expand All @@ -88,29 +139,28 @@ SpMorphicPanedLayout >> position [

{ #category : 'accessing' }
SpMorphicPanedLayout >> position: anObject [
position := anObject
position := anObject.
isResizing := false
]

{ #category : 'accessing' }
{ #category : 'actions' }
SpMorphicPanedLayout >> preservePositionProportionOn: layoutedMorph [
isResizing := false.
layoutedMorph submorphs size < 3 ifTrue: [ ^ self ].

| referenceMorph |
referenceMorph := layoutedMorph submorphs first.
position := self isHorizontal
ifTrue: [ (referenceMorph width * 100 / layoutedMorph width) asInteger percent ]
ifFalse: [ (referenceMorph height * 100 / layoutedMorph height) asInteger percent ]
position := self computePreservedPositionOn: layoutedMorph.
layoutedMorph layoutChanged
]

{ #category : 'accessing' }
{ #category : 'actions' }
SpMorphicPanedLayout >> resetPosition [

position := nil
"Flag that splitter dragging is active so intermediate relayout passes do not override manual adjustment."
isResizing := true
]

{ #category : 'private' }
SpMorphicPanedLayout >> widthPositionIn: aPoint [

^ self position < 1
ifTrue: [ (aPoint x * self position) asInteger ]
ifFalse: [ self position ]
self position ifNil: [ ^ (aPoint x * 0.5) asInteger ].
self isFixed ifTrue: [ ^ self position abs asInteger ].
^ (aPoint x * self position abs) asInteger
]
2 changes: 1 addition & 1 deletion src/Spec2-Adapters-Morphic/SpNotebookMorph.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ SpNotebookMorph >> newCloseButtonFor: aSpNotebookPage [
newCloseControlIn: self
for: aSpNotebookPage
action: [ aSpNotebookPage removeFromNotebook ]
help: 'Close this page' translated
help: 'Close this page'
]

{ #category : 'factory' }
Expand Down
21 changes: 13 additions & 8 deletions src/Spec2-Adapters-Morphic/SpPanedResizerHorizontalMorph.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,21 @@ SpPanedResizerHorizontalMorph >> setLayoutSizing [

{ #category : 'private' }
SpPanedResizerHorizontalMorph >> setTargetBounds [
| target |

target := self target.
target bounds: (target bounds withRight: self left - 1)
self target ifNotNil: [ :t |
t bounds: (t bounds withRight: self left) ].
self targetAfter ifNotNil: [ :ta |
ta bounds: (self right @ ta top corner: ta bottomRight) ]
]

{ #category : 'private' }
SpPanedResizerHorizontalMorph >> setTargetLayoutSizing [

(self target hResizing = #rigid) ifTrue: [ ^ self ].
self target hResizing: #rigid.
self targetAfter hResizing: #spaceFill.
self isFromEnd
ifTrue: [
self targetAfter hResizing = #rigid ifTrue: [ ^ self ].
self targetAfter hResizing: #rigid.
self target hResizing: #spaceFill ]
ifFalse: [
self target hResizing = #rigid ifTrue: [ ^ self ].
self target hResizing: #rigid.
self targetAfter hResizing: #spaceFill ]
]
7 changes: 7 additions & 0 deletions src/Spec2-Adapters-Morphic/SpPanedResizerMorph.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ SpPanedResizerMorph >> initialize [
extent: self defaultWidth @ self defaultHeight
]

{ #category : 'testing' }
SpPanedResizerMorph >> isFromEnd [
^ self owner
ifNotNil: [ :o | o layoutPolicy ifNotNil: [ :lp | lp isFromEnd ] ]
ifNil: [ false ]
]

{ #category : 'testing' }
SpPanedResizerMorph >> isHorizontal [
"Answer true if the receiver has a horizontal layout."
Expand Down
21 changes: 13 additions & 8 deletions src/Spec2-Adapters-Morphic/SpPanedResizerVerticalMorph.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,21 @@ SpPanedResizerVerticalMorph >> setLayoutSizing [

{ #category : 'private' }
SpPanedResizerVerticalMorph >> setTargetBounds [

| target |
target := self target.
target bounds: (target position corner: (target right @ (self top - 1)))
self target ifNotNil: [ :t |
t bounds: (t position corner: (t right @ self top)) ].
self targetAfter ifNotNil: [ :ta |
ta bounds: (ta left @ self bottom corner: ta bottomRight) ]
]

{ #category : 'private' }
SpPanedResizerVerticalMorph >> setTargetLayoutSizing [

(self target vResizing = #rigid) ifTrue: [ ^ self ].
self target vResizing: #rigid.
self targetAfter vResizing: #spaceFill
self isFromEnd
ifTrue: [
self targetAfter vResizing = #rigid ifTrue: [ ^ self ].
self targetAfter vResizing: #rigid.
self target vResizing: #spaceFill ]
ifFalse: [
self target vResizing = #rigid ifTrue: [ ^ self ].
self target vResizing: #rigid.
self targetAfter vResizing: #spaceFill ]
]
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,6 @@ SpAbstractListAdapterSingleSelectionTest >> testUnselectWidgetIndexRaisesSelecti
presenter selection
whenChangedDo: [ :selection | selectedIndex := selection selectedIndex ].
self adapter selectIndex: 0.
backendForTest waitUntilUIRedrawed.
self assert: selectedIndex equals: 0
]
15 changes: 15 additions & 0 deletions src/Spec2-Backend-Tests/SpPanedLayoutAdapterTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ SpPanedLayoutAdapterTest >> testAddSecondTwiceSetsChildrenSingleTime [
self assert: self adapter children size equals: 1
]

{ #category : 'tests' }
SpPanedLayoutAdapterTest >> testBuildWithVariousSliderPositions [
layout positionOfSlider: -200.
layout first: SpButtonPresenter new.
layout second: SpButtonPresenter new.
self openInstance.
self assert: self adapter children size equals: 2.

layout positionOfSlider: 300.
self assert: layout positionOfSlider equals: 300.

layout positionOfSlider: -0.3.
self assert: layout positionOfSlider closeTo: -0.3
]

{ #category : 'tests' }
SpPanedLayoutAdapterTest >> testLayoutWithFirstElementIsNotEmpty [

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,6 @@ SpTreeAdapterSingleSelectionTest >> testUnselectWidgetIndexRaisesSelectionIndexC
presenter selection
whenChangedDo: [ :selection | selectedPath := selection ].
self adapter selectPath: #().
backendForTest waitUntilUIRedrawed.
self assertEmpty: selectedPath
]
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,6 @@ SpTreeTableAdapterSingleSelectionTest >> testUnselectWidgetIndexRaisesSelectionI
presenter selection
whenChangedDo: [ :selection | selectedPath := selection ].
self adapter selectPath: #().
backendForTest waitUntilUIRedrawed.
self assertEmpty: selectedPath
]
7 changes: 4 additions & 3 deletions src/Spec2-Code/SpCodePresenter.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,12 @@ SpCodePresenter >> doBrowseSenders [

| variableOrClassName variable |
variableOrClassName := self selectedSelector ifNil: [ ^ nil ].
variable := self lookupEnvironment lookupVar: variableOrClassName. "For global and class variables, sender-of shows intead the using methods"
variable := self lookupEnvironment lookupVar: variableOrClassName.

"For global and class variables, sender-of shows intead the using methods"
(variable isNotNil and: [ variable isGlobalVariable or: [ variable isClassVariable ] ])
ifTrue: [ self systemNavigation openBrowserFor: variable withMethods: variable usingMethods ]
ifFalse: [
(Smalltalk tools toolNamed: #messageList) browseSendersOfAll: { variableOrClassName } from: self interactionModel behavior ]
ifFalse: [ self systemNavigation browseAllSendersOf: variableOrClassName ]
]

{ #category : 'private - bindings' }
Expand Down
Loading