<commit_before>Class {
	#name : #TRCompositeShape,
	#superclass : #TRShape,
	#instVars : [
		'shapeAndOffsets'
	],
	#category : #'Trachel-Shapes'
}

{ #category : #visitor }
TRCompositeShape >> accept: aVisitor [
	aVisitor visitMultiCompositeShape: self.
]

{ #category : #callbacks }
TRCompositeShape >> addCallback: aCallback [
	"Add a call back to only one subshape. This is necessary for example when one does not want to trigger many times the same callback when an action occurs"
	^ self firstShape addCallback: aCallback
]

{ #category : #callbacks }
TRCompositeShape >> addCallbackToAllShapes: aCallback [
	^ self shapesDo: [ :s | s addCallback: aCallback ]
]

{ #category : #'public - adding' }
TRCompositeShape >> addShape: aShape [
	"Add a shape in the composite. Shapes added using this method have all the same center"
	^ self addShape: aShape translateBy: 0 @ 0
]

{ #category : #'public - adding' }
TRCompositeShape >> addShape: aShape translateBy: aPoint [
	shapeAndOffsets add: (Array with: aShape with: aPoint)
]

{ #category : #actions }
TRCompositeShape >> addedIn: aCanvas [
	"Make sure we are in the center. This is apparently necessary for element Shape. The following code is not nice at all :-("

	self
		propagateElement;
		shapesDo: [ :s | s addedIn: aCanvas ];
		positionShapesAfterBeingAdded
]

{ #category : #actions }
TRCompositeShape >> addedIn: aCanvas atIndex: index [
	self propagateElement.
	shapeAndOffsets
		do: [ :tuple | 
			aCanvas addShape: tuple first atIndex: index.
			tuple first translateBy: tuple second ].
		
	"Make sure we are in the center"
	self translateBy: self position negated
]

{ #category : #'public - layout' }
TRCompositeShape >> alignRight [
	"Layout the shapes horizontally"

	"TRConstraint alignFromRight: self shapes."
	RTAlignment new elements: self shapes; right.
	shapeAndOffsets do: [ :tuple | tuple at: 2 put: tuple first position ].
	self resetInnerShapes
]

{ #category : #accessing }
TRCompositeShape >> allColor: aColor [
	"Set color of all shapes"
	self shapesDo: [ :s | s color: aColor ]
]

{ #category : #'public - layout' }
TRCompositeShape >> allOfSameSize [
	"All the same will have the same maximum size"

	| maxSize |
	maxSize := shapeAndOffsets inject: 0 @ 0 into: [ :max :tuple | tuple first extent max: max ].
	self shapesDo: [ :s | s extent: maxSize ]
]

{ #category : #'public - layout' }
TRCompositeShape >> allOfSameSizeWithPadding [
	"All the same will have the same maximum size"

	| maxSize padding |
	padding := 10 @ 10.
	maxSize := shapeAndOffsets inject: 0 @ 0 into: [ :max :tuple | tuple first extent max: max ].
	self shapesDo: [ :s | s extent: maxSize + padding ]
]

{ #category : #accessing }
TRCompositeShape >> allShapes [
	"Return all the shapes contained in me."
	^ shapeAndOffsets collect: #first as: Array
]

{ #category : #events }
TRCompositeShape >> announce: anEvent [
	self shapesDo: [ :s | s announce: anEvent ]
]

{ #category : #accessing }
TRCompositeShape >> announcer [
	self error: 'should not be called'
]

{ #category : #accessing }
TRCompositeShape >> announcer: anAnnouncer [
	self shapesDo: [ :s | s announcer: anAnnouncer ]
]

{ #category : #callbacks }
TRCompositeShape >> callbacks [
	^ self firstShape callbacks
]

{ #category : #accessing }
TRCompositeShape >> canvas [
	"Return the canvas of one of the shapes"
	^ self firstShape canvas	
]

{ #category : #accessing }
TRCompositeShape >> canvas: aSurface [
	"aCanvas is a AthensCairoSurface"
	self shapesDo: [ :s | s canvas: aSurface ]
]

{ #category : #accessing }
TRCompositeShape >> center [
	^ self encompassingRectangle center
]

{ #category : #accessing }
TRCompositeShape >> color [
	^ self firstShape color
	"shape2 color: aColor."
]

{ #category : #accessing }
TRCompositeShape >> color: aColor [
	"Simply set the first shape"
	self firstShape color: aColor.

]

{ #category : #private }
TRCompositeShape >> computePath [
	self shapesDo: [ :s | s computePath ]
]

{ #category : #drawing }
TRCompositeShape >> drawOn: athensCanvas [
	self shapesDo: [ :s | s drawOn: athensCanvas ]
]

{ #category : #accessing }
TRCompositeShape >> encompassingRectangle [
	"Really ugly method."
	| ans c |
	(self shapes anySatisfy: [ :s | s canvas notNil ])
		ifTrue: [ ^ Rectangle merging: (self shapes collect: #encompassingRectangle). ]. 
	
	c := shapeAndOffsets collect: [ :s | s first position ].
	self positionShapesAfterBeingAdded.
	ans := Rectangle merging: (self shapes collect: #encompassingRectangle).
	shapeAndOffsets with: c do: [ :s :p | s first translateTo: p ].
	^ ans
]

{ #category : #accessing }
TRCompositeShape >> extent [
	| res |
"	self shapesDo: [ :s | s translateTo: 0 @ 0 ]."
		
	shapeAndOffsets do: [ :tuple | tuple first translateBy: tuple second ].
	res := self encompassingRectangle extent.
	self shapesDo: [ :s | s translateTo: 0 @ 0 ].
	^ res

	"We cannot do that, because we may need to get the extent, without having the elements added (and correctly positioned)"
	"^ self encompassingRectangle extent"
]

{ #category : #actions }
TRCompositeShape >> extent: anExtent [
	self shapesDo: [ :s | s extent: anExtent ]
]

{ #category : #accessing }
TRCompositeShape >> firstShape [
	^ shapeAndOffsets first first
]

{ #category : #callbacks }
TRCompositeShape >> hasCallback [
	"Return true if at least one callback has been added to the shape"
	^ self firstShape hasCallback
]

{ #category : #accessing }
TRCompositeShape >> height [
	^ self encompassingRectangle height
]

{ #category : #accessing }
TRCompositeShape >> height: aValue [
	^ self extent: self width @ aValue
]

{ #category : #'public - layout' }
TRCompositeShape >> horizontal [
	"Layout the shapes horizontally"

	| previousShape newPosition |
	previousShape := self firstShape.
	shapeAndOffsets allButFirst
		do: [ :tuple | 
			newPosition := previousShape center + ((previousShape extent x / 2) @ 0) + ((tuple first extent x / 2) @ 0).
			tuple first translateTo: newPosition.
			tuple at: 2 put: newPosition.
			previousShape := tuple first ].
	self resetInnerShapes<commit_msg>Improved TRCompositeShape, to behave as a line<commit_after>Class {
	#name : #TRCompositeShape,
	#superclass : #TRShape,
	#instVars : [
		'shapeAndOffsets'
	],
	#category : #'Trachel-Shapes'
}

{ #category : #visitor }
TRCompositeShape >> accept: aVisitor [
	aVisitor visitMultiCompositeShape: self.
]

{ #category : #callbacks }
TRCompositeShape >> addCallback: aCallback [
	"Add a call back to only one subshape. This is necessary for example when one does not want to trigger many times the same callback when an action occurs"
	^ self firstShape addCallback: aCallback
]

{ #category : #callbacks }
TRCompositeShape >> addCallbackToAllShapes: aCallback [
	^ self shapesDo: [ :s | s addCallback: aCallback ]
]

{ #category : #'public - adding' }
TRCompositeShape >> addShape: aShape [
	"Add a shape in the composite. Shapes added using this method have all the same center"
	^ self addShape: aShape translateBy: 0 @ 0
]

{ #category : #'public - adding' }
TRCompositeShape >> addShape: aShape translateBy: aPoint [
	shapeAndOffsets add: (Array with: aShape with: aPoint)
]

{ #category : #actions }
TRCompositeShape >> addedIn: aCanvas [
	"Make sure we are in the center. This is apparently necessary for element Shape. The following code is not nice at all :-("

	self
		propagateElement;
		shapesDo: [ :s | s addedIn: aCanvas ];
		positionShapesAfterBeingAdded
]

{ #category : #actions }
TRCompositeShape >> addedIn: aCanvas atIndex: index [
	self propagateElement.
	shapeAndOffsets
		do: [ :tuple | 
			aCanvas addShape: tuple first atIndex: index.
			tuple first translateBy: tuple second ].
		
	"Make sure we are in the center"
	self translateBy: self position negated
]

{ #category : #'public - layout' }
TRCompositeShape >> alignRight [
	"Layout the shapes horizontally"

	"TRConstraint alignFromRight: self shapes."
	RTAlignment new elements: self shapes; right.
	shapeAndOffsets do: [ :tuple | tuple at: 2 put: tuple first position ].
	self resetInnerShapes
]

{ #category : #accessing }
TRCompositeShape >> allColor: aColor [
	"Set color of all shapes"
	self shapesDo: [ :s | s color: aColor ]
]

{ #category : #'public - layout' }
TRCompositeShape >> allOfSameSize [
	"All the same will have the same maximum size"

	| maxSize |
	maxSize := shapeAndOffsets inject: 0 @ 0 into: [ :max :tuple | tuple first extent max: max ].
	self shapesDo: [ :s | s extent: maxSize ]
]

{ #category : #'public - layout' }
TRCompositeShape >> allOfSameSizeWithPadding [
	"All the same will have the same maximum size"

	| maxSize padding |
	padding := 10 @ 10.
	maxSize := shapeAndOffsets inject: 0 @ 0 into: [ :max :tuple | tuple first extent max: max ].
	self shapesDo: [ :s | s extent: maxSize + padding ]
]

{ #category : #accessing }
TRCompositeShape >> allShapes [
	"Return all the shapes contained in me."
	^ shapeAndOffsets collect: #first as: Array
]

{ #category : #events }
TRCompositeShape >> announce: anEvent [
	self shapesDo: [ :s | s announce: anEvent ]
]

{ #category : #accessing }
TRCompositeShape >> announcer [
	self error: 'should not be called'
]

{ #category : #accessing }
TRCompositeShape >> announcer: anAnnouncer [
	self shapesDo: [ :s | s announcer: anAnnouncer ]
]

{ #category : #callbacks }
TRCompositeShape >> callbacks [
	^ self firstShape callbacks
]

{ #category : #accessing }
TRCompositeShape >> canvas [
	"Return the canvas of one of the shapes"
	^ self firstShape canvas	
]

{ #category : #accessing }
TRCompositeShape >> canvas: aSurface [
	"aCanvas is a AthensCairoSurface"
	self shapesDo: [ :s | s canvas: aSurface ]
]

{ #category : #accessing }
TRCompositeShape >> center [
	^ self encompassingRectangle center
]

{ #category : #accessing }
TRCompositeShape >> color [
	^ self firstShape color
	"shape2 color: aColor."
]

{ #category : #accessing }
TRCompositeShape >> color: aColor [
	"Simply set the first shape"
	self firstShape color: aColor.

]

{ #category : #private }
TRCompositeShape >> computePath [
	self shapesDo: [ :s | s computePath ]
]

{ #category : #drawing }
TRCompositeShape >> drawOn: athensCanvas [
	self shapesDo: [ :s | s drawOn: athensCanvas ]
]

{ #category : #accessing }
TRCompositeShape >> encompassingRectangle [
	"Really ugly method."
	| ans c |
	(self shapes anySatisfy: [ :s | s canvas notNil ])
		ifTrue: [ ^ Rectangle merging: (self shapes collect: #encompassingRectangle). ]. 
	
	c := shapeAndOffsets collect: [ :s | s first position ].
	self positionShapesAfterBeingAdded.
	ans := Rectangle merging: (self shapes collect: #encompassingRectangle).
	shapeAndOffsets with: c do: [ :s :p | s first translateTo: p ].
	^ ans
]

{ #category : #accessing }
TRCompositeShape >> extent [
	| res |
"	self shapesDo: [ :s | s translateTo: 0 @ 0 ]."
		
	shapeAndOffsets do: [ :tuple | tuple first translateBy: tuple second ].
	res := self encompassingRectangle extent.
	self shapesDo: [ :s | s translateTo: 0 @ 0 ].
	^ res

	"We cannot do that, because we may need to get the extent, without having the elements added (and correctly positioned)"
	"^ self encompassingRectangle extent"
]

{ #category : #actions }
TRCompositeShape >> extent: anExtent [
	self shapesDo: [ :s | s extent: anExtent ]
]

{ #category : #accessing }
TRCompositeShape >> firstShape [
	^ shapeAndOffsets first first
]

{ #category : #actions }
TRCompositeShape >> from: p1 to: p2 [
	"To be compatible with edges"
	self shapesDo: [ :s | 
		(s class canUnderstand: #from:to:) ifTrue: [ s from: p1 to: p2 ].
		(s class canUnderstand: #from:) ifTrue: [ s from: p1 ].
		(s class canUnderstand: #to:) ifTrue: [ s to: p2 ].
		 ]
]

{ #category : #callbacks }
TRCompositeShape >> hasCallback [
	"Return true if at least one callback has been added to the shape"
	^ self firstShape hasCallback
]

{ #category : #accessing }
TRCompositeShape >> height [
	^ self encompassingRectangle height
]

{ #category : #accessing }
TRCompositeShape >> height: aValue [
	^ self extent: self width @ aValue
]

{ #category : #'public - layout' }
TRCompositeShape >> horizontal [
	"Layout the shapes horizontally"

	| previousShape newPosition |
	previousShape := self firstShape.
	shapeAndOffsets allButFirst
		do: [ :tuple | 
			newPosition := previousShape center + ((previousShape extent x / 2) @ 0) + ((tuple first extent x / 2) @ 0).
			tuple first translateTo: newPosition.
			tuple at: 2 put: newPosition.
			previousShape := tuple first ].
	self resetInnerShapes
{'fraction_non_alphanumeric': 0.1109323465529724, 'fraction_numerical': 0.003861314455795994, 'mean_word_length': 4.182159233013755, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '655960', 'n_tokens_mistral': 4126, 'n_tokens_neox': 3969, 'n_words': 1330}