diff --git a/.squot-materialize b/.squot-materialize index 16c074d9..a5425418 100644 --- a/.squot-materialize +++ b/.squot-materialize @@ -1,54 +1,31 @@ [ - SquotCypressMapper { - #package : MCPackage { - #name : 'GM-UtilitiesTest' - }, - #path : FSAbsolutePath [ - 'source' - ] - }, - SquotTonelMapper { - #package : MCPackage { - #name : 'GM-TilemapMakerGui' - }, - #path : FSAbsolutePath [ - 'source' - ] - }, SquotImageMapper { #path : FSAbsolutePath [ 'GMTEIcons', - 'brush.png' + 'rectangle.png' ], #encoding : Class [ #PNGReadWriter ] }, SquotCypressMapper { #package : MCPackage { - #name : 'GM-Test' + #name : 'GM-Utilities' }, - #path : @7 + #path : FSAbsolutePath [ + 'source' + ] }, - SquotImageMapper { + SquotBlobMapper { #path : FSAbsolutePath [ - 'GMTEIcons', - 'undo.png' + 'testMapFile.morph' ], - #encoding : @10 + #encoding : 'bin' }, - SquotImageMapper { + SquotPlaintextMapper { #path : FSAbsolutePath [ 'testingResources', - 'squeak2.gif' + 'test.txt' ], - #encoding : Class [ #GIFReadWriter ] - }, - SquotCypressMapper { - #package : MCPackage { - #name : 'GM-Utilities' - }, - #path : FSAbsolutePath [ - 'source' - ] + #encoding : 'TXT' }, SquotTonelMapper { #package : MCPackage { @@ -58,13 +35,6 @@ 'source' ] }, - SquotImageMapper { - #path : FSAbsolutePath [ - 'GMTEIcons', - 'trash.png' - ], - #encoding : @10 - }, SquotPlaintextMapper { #path : FSAbsolutePath [ '.github', @@ -73,44 +43,17 @@ ], #encoding : 'TXT' }, - SquotImageMapper { - #path : FSAbsolutePath [ - 'GMTEIcons', - 'up.png' - ], - #encoding : @10 - }, - SquotTonelMapper { - #package : MCPackage { - #name : 'ToolBuilder-Kernel' - }, - #path : @7 - }, - SquotImageMapper { - #path : FSAbsolutePath [ - 'testingResources', - 'squeak.png' - ], - #encoding : @10 - }, SquotCypressMapper { #package : MCPackage { - #name : 'BaselineOfGM' + #name : 'GM-AcceptanceTest' }, #path : FSAbsolutePath [ 'source' ] }, - SquotImageMapper { - #path : FSAbsolutePath [ - 'GMTEIcons', - 'rename.png' - ], - #encoding : @10 - }, SquotPlaintextMapper { #path : FSAbsolutePath [ - '.gitignore' + 'LICENSE' ], #encoding : 'TXT' }, @@ -119,56 +62,80 @@ 'GMTEIcons', 'down.png' ], - #encoding : @10 + #encoding : @4 }, - SquotPlaintextMapper { + SquotImageMapper { #path : FSAbsolutePath [ - '.squot' + 'GMTEIcons', + 'add.png' ], - #encoding : 'TXT' + #encoding : @4 }, - SquotCypressMapper { - #package : MCPackage { - #name : 'GM-TestFixtures' - }, + SquotImageMapper { #path : FSAbsolutePath [ - 'source' - ] + 'GMTEIcons', + 'redo.png' + ], + #encoding : @4 }, - SquotCypressMapper { + SquotTonelMapper { #package : MCPackage { - #name : 'GM-Core' + #name : 'GM-TilemapMakerGui' }, #path : FSAbsolutePath [ 'source' ] }, + SquotBlobMapper { + #path : FSAbsolutePath [ + 'map.morph' + ], + #encoding : 'bin' + }, SquotImageMapper { #path : FSAbsolutePath [ 'GMTEIcons', 'fill.png' ], - #encoding : @10 + #encoding : @4 }, SquotTonelMapper { #package : MCPackage { - #name : 'ToolBuilder-Morphic' + #name : 'ToolBuilder-Kernel' }, - #path : @7 + #path : @30 }, - SquotSoundMapper { + SquotPlaintextMapper { #path : FSAbsolutePath [ - 'testingResources', - 'squeak.aiff' + 'README.md' ], - #encoding : 'AIFF' + #encoding : 'TXT' + }, + SquotPlaintextMapper { + #path : FSAbsolutePath [ + '.smalltalk.ston' + ], + #encoding : 'TXT' }, SquotImageMapper { #path : FSAbsolutePath [ 'GMTEIcons', 'merge.png' ], - #encoding : @10 + #encoding : @4 + }, + SquotTonelMapper { + #package : MCPackage { + #name : 'GM-TilemapMakerCore' + }, + #path : @30 + }, + SquotImageMapper { + #path : FSAbsolutePath [ + 'GMTEIcons', + 'line.png' + ], + #encoding : @4 }, SquotSoundMapper { #path : FSAbsolutePath [ @@ -177,111 +144,151 @@ ], #encoding : 'WAV' }, - SquotCypressMapper { - #package : MCPackage { - #name : 'GM-DemoGame' - }, + SquotImageMapper { #path : FSAbsolutePath [ - 'source' - ] + 'GMTEIcons', + 'up.png' + ], + #encoding : @4 }, - SquotPlaintextMapper { + SquotImageMapper { #path : FSAbsolutePath [ - 'README.md' + 'GMTEIcons', + 'trash.png' ], - #encoding : 'TXT' + #encoding : @4 + }, + SquotImageMapper { + #path : FSAbsolutePath [ + 'GMTEIcons', + 'eye.png' + ], + #encoding : @4 }, SquotTonelMapper { #package : MCPackage { - #name : 'GM-TE' + #name : 'ToolBuilder-Morphic' }, - #path : @4 + #path : @30 }, SquotPlaintextMapper { #path : FSAbsolutePath [ - 'testingResources', - 'test' + '.squot' ], #encoding : 'TXT' }, SquotImageMapper { #path : FSAbsolutePath [ - 'GMTEIcons', - 'broom.png' + 'testingResources', + 'squeak.png' ], - #encoding : @10 + #encoding : @4 }, SquotPlaintextMapper { #path : FSAbsolutePath [ - '.smalltalk.ston' + '.gitignore' ], #encoding : 'TXT' }, - SquotBlobMapper { + SquotImageMapper { #path : FSAbsolutePath [ - 'map.morph' + 'GMTEIcons', + 'rename.png' ], - #encoding : 'bin' + #encoding : @4 }, - SquotBlobMapper { + SquotImageMapper { #path : FSAbsolutePath [ - 'testMapFile.morph' + 'testingResources', + 'squeak2.gif' ], - #encoding : 'bin' + #encoding : Class [ #GIFReadWriter ] }, - SquotImageMapper { + SquotPlaintextMapper { #path : FSAbsolutePath [ - 'GMTEIcons', - 'eye.png' + 'testingResources', + 'test' ], - #encoding : @10 + #encoding : 'TXT' }, SquotCypressMapper { #package : MCPackage { - #name : 'GM-AcceptanceTest' + #name : 'GM-DemoGame' }, #path : FSAbsolutePath [ 'source' ] }, + SquotCypressMapper { + #package : MCPackage { + #name : 'GM-Core' + }, + #path : FSAbsolutePath [ + 'source' + ] + }, + SquotCypressMapper { + #package : MCPackage { + #name : 'GM-Test' + }, + #path : @30 + }, SquotImageMapper { #path : FSAbsolutePath [ 'GMTEIcons', - 'redo.png' + 'broom.png' ], - #encoding : @10 + #encoding : @4 }, - SquotPlaintextMapper { + SquotCypressMapper { + #package : MCPackage { + #name : 'GM-TestFixtures' + }, #path : FSAbsolutePath [ - 'LICENSE' - ], - #encoding : 'TXT' + 'source' + ] }, - SquotImageMapper { + SquotCypressMapper { + #package : MCPackage { + #name : 'BaselineOfGM' + }, #path : FSAbsolutePath [ - 'GMTEIcons', - 'rectangle.png' + 'source' + ] + }, + SquotSoundMapper { + #path : FSAbsolutePath [ + 'testingResources', + 'squeak.aiff' ], - #encoding : @10 + #encoding : 'AIFF' }, SquotImageMapper { #path : FSAbsolutePath [ 'GMTEIcons', - 'add.png' + 'undo.png' ], - #encoding : @10 + #encoding : @4 }, SquotTonelMapper { #package : MCPackage { - #name : 'GM-TilemapMakerCore' + #name : 'GM-TE' }, - #path : @7 + #path : FSAbsolutePath [ + 'source' + ] }, - SquotPlaintextMapper { + SquotCypressMapper { + #package : MCPackage { + #name : 'GM-UtilitiesTest' + }, + #path : @92 + }, + SquotImageMapper { #path : FSAbsolutePath [ - 'testingResources', - 'test.txt' + 'GMTEIcons', + 'brush.png' ], - #encoding : 'TXT' + #encoding : @4 } ] \ No newline at end of file diff --git a/GMTEIcons/line.png b/GMTEIcons/line.png new file mode 100644 index 00000000..d9dec798 Binary files /dev/null and b/GMTEIcons/line.png differ diff --git a/source/GM-TE/GMTEBrush.class.st b/source/GM-TE/GMTEBrush.class.st index 5d00dad2..a97ea5c2 100644 --- a/source/GM-TE/GMTEBrush.class.st +++ b/source/GM-TE/GMTEBrush.class.st @@ -12,6 +12,30 @@ Class { #category : #'GM-TE-UI' } +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:01' +} +GMTEBrush class >> borderingOffsets [ + + ^ {(-1)@0. 0@(-1). 1@0. 0@1} +] + +{ + #category : #forms, + #'squeak_changestamp' : 'JS 7/11/2024 15:40' +} +GMTEBrush >> calculateOffsetsForRadius: aRadius [ + + |offsets| + offsets := OrderedCollection new. + (0-radius to: radius) do: [:dx | + (0-radius to: radius) do: [:dy | + ((dx squared + dy squared) <= aRadius squared) ifTrue: [offsets add: dx @ dy]]]. + + ^offsets +] + { #category : #accessing, #'squeak_changestamp' : 'Valentin Teutschbein 7/6/2024 12:48' @@ -46,61 +70,56 @@ GMTEBrush >> currentMatrixIndex: anObject [ { #category : #'as yet unclassified', - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 08:47' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:10' } GMTEBrush >> executeWithMatrixIndex: anIndex andLayer: aLayer [ + anIndex ifNil: [^ nil]. self currentMatrixIndex: anIndex. self layer: aLayer. - ^ self currentBrush value. + ^ self currentBrush value ] { #category : #forms, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 22:04' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:10' } GMTEBrush >> fillBrush [ - | collection startTile visited | + | startTile visited | self resetOutputSet. - self currentMatrixIndex ifNil: [^nil]. visited := Matrix rows: (self layer rowCount) columns: self layer columnCount. - collection := OrderedCollection new. - startTile := layer at: self currentMatrixIndex y at: self currentMatrixIndex x. + startTile := self layer at: self currentMatrixIndex y at: self currentMatrixIndex x. - collection add: currentMatrixIndex. + self outputSet add: self currentMatrixIndex. visited at: self currentMatrixIndex y at: self currentMatrixIndex x put: true. - self fillDfsWithVisited: visited andIndex: self currentMatrixIndex andOriginTile: startTile andCollection: collection. - self outputSet: collection asSet. + self fillDfsWithVisited: visited andIndex: self currentMatrixIndex andOriginTile: startTile andSet: self outputSet. - ^ self outputSet. + ^ self outputSet ] { #category : #forms, - #'squeak_changestamp' : 'JS 7/6/2024 16:46' + #'squeak_changestamp' : 'JS 7/11/2024 18:28' } -GMTEBrush >> fillDfsWithVisited: aVisitedMatrix andIndex: anIndex andOriginTile: anOriginTile andCollection: aCollection [ - - | borderingOffsets | +GMTEBrush >> fillDfsWithVisited: aVisitedMatrix andIndex: anIndex andOriginTile: anOriginTile andSet: aSet [ self flag: 'REFACTOR!'. - borderingOffsets := {(-1)@0. 0@(-1). 1@0. 0@1}. - borderingOffsets do: [: offset| - | newIndex newTile | + + GMTEBrush borderingOffsets do: [:offset | + | newIndex newTile tilesNil tilesSame | newIndex := offset + anIndex. ((self layer inBounds: newIndex) and: [(aVisitedMatrix at: newIndex y at: newIndex x) isNil]) ifTrue:[ newTile := self layer at: newIndex y at: newIndex x. - anOriginTile - ifNil: [newTile ifNil: [aCollection add: newIndex. + + tilesNil := (anOriginTile isNil) and: [newTile isNil]. + tilesSame := (anOriginTile isNil not and: [newTile isNil not]) and: [anOriginTile imageForm bits hash = newTile imageForm bits hash]. + + (tilesNil or: tilesSame) ifTrue: [ + aSet add: newIndex. aVisitedMatrix at: newIndex y at: newIndex x put: true. - self fillDfsWithVisited: aVisitedMatrix andIndex: newIndex andOriginTile: anOriginTile andCollection: aCollection]] - ifNotNil: [ - (newTile isNil not and: [anOriginTile imageForm bits hash = newTile imageForm bits hash]) - ifTrue: [aCollection add: newIndex. - aVisitedMatrix at: newIndex y at: newIndex x put: true. - self fillDfsWithVisited: aVisitedMatrix andIndex: newIndex andOriginTile: anOriginTile andCollection: aCollection]]]] + self fillDfsWithVisited: aVisitedMatrix andIndex: newIndex andOriginTile: anOriginTile andSet: aSet]]] ] { @@ -121,12 +140,12 @@ GMTEBrush >> firstMatrixIndex: anObject [ { #category : #forms, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 21:33' + #'squeak_changestamp' : 'JS 7/11/2024 13:59' } GMTEBrush >> initialize [ super initialize. - self resetOutputSet. + self resetOutputSet ] { @@ -147,57 +166,29 @@ GMTEBrush >> layer: anObject [ { #category : #forms, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 22:53' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:11' } GMTEBrush >> lineBrush [ - | radius collection start end deltaX deltaY stepX stepY error error2 x y offsets | - radius := self radius - 1. self resetOutputSet. - self flag: 'todo: method extraction'. - "Helper method to generate radius offsets" - offsets := OrderedCollection new. - (0-radius to: radius) do: [:dx | - (0-radius to: radius) do: [:dy | - (dx * dx + dy * dy <= (radius * radius)) ifTrue: [ - offsets add: dx @ dy. - ]. - ]. - ]. - - self resetOutputSet. - (self currentMatrixIndex isNil or: [self firstMatrixIndex isNil]) ifTrue: [^nil]. - - start := self firstMatrixIndex. - end := self currentMatrixIndex. - deltaX := (end x - start x) abs. - deltaY := (end y - start y) abs. - stepX := (start x < end x) ifTrue: [1] ifFalse: [-1]. - stepY := (start y < end y) ifTrue: [1] ifFalse: [-1]. - error := deltaX - deltaY. - x := start x. - y := start y. - - collection := OrderedCollection new. - - [ - | point | - point := x @ y. - offsets do: [:offset | collection add: (point + offset)]. - (x = end x and: [y = end y]) ifTrue: [ - self outputSet: collection asSet. - ^ self outputSet.]. - error2 := 2 * error. - (error2 > (0 - deltaY)) ifTrue: [ - error := error - deltaY. - x := x + stepX. - ]. - (error2 < deltaX) ifTrue: [ - error := error + deltaX. - y := y + stepY. - ]. - ] repeat. + self firstMatrixIndex ifNil: [^nil]. + + (self rasterizeLineBetweenAStart: self firstMatrixIndex andAnEnd: self currentMatrixIndex) do: [:point | + (self calculateOffsetsForRadius: self offsetCorrectedRadius) do: [:offset | + self outputSet add: (point + offset)]]. + + ^(self outputSet) + +] + +{ + #category : #accessing, + #'squeak_changestamp' : 'JS 7/11/2024 16:16' +} +GMTEBrush >> offsetCorrectedRadius [ + "In order to display a more intuitive radius for the user, we need to offset it by 1 for the calculations" + ^ self radius - 1 ] { @@ -218,87 +209,97 @@ GMTEBrush >> outputSet: anObject [ { #category : #accessing, - #'squeak_changestamp' : 'Valentin Teutschbein 7/6/2024 12:48' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:11' } GMTEBrush >> radius [ + ^ radius ] { #category : #accessing, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 22:08' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:15' } -GMTEBrush >> radius: anObject [ - radius := anObject +GMTEBrush >> radius: aNumber [ + + radius := aNumber ] { #category : #forms, - #'squeak_changestamp' : 'Valentin Teutschbein 7/10/2024 12:37' + #'squeak_changestamp' : 'Valentin Teutschbein 7/11/2024 17:09' } GMTEBrush >> radiusBrush [ - | collection xMin xMax yMin yMax | - self currentMatrixIndex ifNil: [^nil]. - - collection := OrderedCollection new. - self flag: 'radius offset is bad'. - xMin := self currentMatrixIndex x - (self radius - 1). - xMax := self currentMatrixIndex x + (self radius - 1). - yMin := self currentMatrixIndex y - (self radius - 1). - yMax := self currentMatrixIndex y + (self radius - 1). + (self calculateOffsetsForRadius: self offsetCorrectedRadius) do: [:i | + self outputSet add: (self currentMatrixIndex + i)]. - (xMin to: xMax) do: [:x | - (yMin to: yMax) do: [:y | - (( self currentMatrixIndex x - x) squared + ( self currentMatrixIndex y - y) squared <= (self radius - 1) squared) ifTrue: [ - collection add: x@y - ]. - ]. - ]. + ^ self outputSet - collection do: [:i | self outputSet add: i]. +] - ^ self outputSet. +{ + #category : #forms, + #'squeak_changestamp' : 'JS 7/11/2024 18:26' +} +GMTEBrush >> rasterizeLineBetweenAStart: aStartPoint andAnEnd: anEndPoint [ + "implementation of Bresenhams Line Algorithm" + + | linePointsCollection deltaX deltaY stepX stepY error error2 x y | + + self flag: 'todo: method extraction? - Ich glaube geht schlecht'. + + deltaX := (anEndPoint x - aStartPoint x) abs. + deltaY := (anEndPoint y - aStartPoint y) abs. + stepX := (aStartPoint x < anEndPoint x) ifTrue: [1] ifFalse: [-1]. + stepY := (aStartPoint y < anEndPoint y) ifTrue: [1] ifFalse: [-1]. + error := deltaX - deltaY. + x := aStartPoint x. + y := aStartPoint y. + + linePointsCollection := OrderedCollection new. + + [ + | point | + point := x @ y. + linePointsCollection add: point. + (x = anEndPoint x and: [y = anEndPoint y]) ifTrue: [ + ^linePointsCollection]. + error2 := 2 * error. + (error2 > (0 - deltaY)) ifTrue: [ + error := error - deltaY. + x := x + stepX]. + (error2 < deltaX) ifTrue: [ + error := error + deltaX. + y := y + stepY] + ] repeat ] { #category : #forms, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 22:04' + #'squeak_changestamp' : 'JS 7/11/2024 17:34' } GMTEBrush >> rectangleBrush [ - | collection startRow endRow startCol endCol | self resetOutputSet. - (self currentMatrixIndex isNil or: [self firstMatrixIndex isNil]) ifTrue: [^nil]. - collection := OrderedCollection new. - - "Determine the starting and ending rows and columns" - - startRow := (self currentMatrixIndex x min: self firstMatrixIndex x). - endRow := (self currentMatrixIndex x max: self firstMatrixIndex x). - startCol := (self currentMatrixIndex y min: self firstMatrixIndex y). - endCol := (self currentMatrixIndex y max: self firstMatrixIndex y). + self firstMatrixIndex ifNil: [^ nil]. - "Fill the collection with all indices within the rectangle" - startRow to: endRow do: [:row | - startCol to: endCol do: [:col | - collection add: (row@col) - ]. - ]. - self outputSet: collection asSet. + (self currentMatrixIndex x min: self firstMatrixIndex x) to: (self currentMatrixIndex x max: self firstMatrixIndex x) do: [:row | + (self currentMatrixIndex y min: self firstMatrixIndex y) to: (self currentMatrixIndex y max: self firstMatrixIndex y) do: [:col | + self outputSet add: (row @ col)]]. - ^ self outputSet. + ^ self outputSet ] { #category : #select, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 21:26' + #'squeak_changestamp' : 'JS 7/11/2024 13:43' } GMTEBrush >> resetOutputSet [ - self outputSet: Set new. + self outputSet: Set new ] { diff --git a/source/GM-TE/GMTEDeleteLayersCommand.class.st b/source/GM-TE/GMTEDeleteLayersCommand.class.st index 4be78980..a6eafdc3 100644 --- a/source/GM-TE/GMTEDeleteLayersCommand.class.st +++ b/source/GM-TE/GMTEDeleteLayersCommand.class.st @@ -1,6 +1,6 @@ Class { #name : #GMTEDeleteLayersCommand, - #superclass : #GMTETilemapSizeCommand, + #superclass : #GMTEEditTilesCommand, #instVars : [ 'layers' ], diff --git a/source/GM-TE/GMTEEditTilesCommand.class.st b/source/GM-TE/GMTEEditTilesCommand.class.st index 10b268af..1972bc86 100644 --- a/source/GM-TE/GMTEEditTilesCommand.class.st +++ b/source/GM-TE/GMTEEditTilesCommand.class.st @@ -40,18 +40,38 @@ GMTEEditTilesCommand >> currentSprites: anObject [ { #category : #execution, - #'squeak_changestamp' : 'TW 7/2/2024 17:54' + #'squeak_changestamp' : 'Alex M 7/10/2024 13:42' } GMTEEditTilesCommand >> do [ + + self placeTilesFromList: self currentSprites +] + +{ + #category : #initialization, + #'squeak_changestamp' : 'Alex M 6/28/2024 02:45' +} +GMTEEditTilesCommand >> initialize [ + + self + previousSprites: Dictionary new; + currentSprites: Dictionary new +] + +{ + #category : #execution, + #'squeak_changestamp' : 'Alex M 7/10/2024 13:44' +} +GMTEEditTilesCommand >> placeTilesFromList: aList [ | tile sprite layer x y | - self currentSprites keysDo: [ :coordinates | + aList keysDo: [ :coordinates | x := coordinates at: 1. y := coordinates at: 2. layer := coordinates at: 3. tile := self tileMap tileMatrixStack layer: layer at: y at: x. - sprite := self currentSprites at: coordinates. + sprite := aList at: coordinates. tile ifNil: [sprite ifNotNil: [ @@ -61,18 +81,7 @@ GMTEEditTilesCommand >> do [ ifNil: [ self tileMap tileMatrixStack layer: layer at: y at: x put: nil. tile abandon] - ifNotNil: [tile updateSprite: (self currentSprites at: coordinates)]]] -] - -{ - #category : #initialization, - #'squeak_changestamp' : 'Alex M 6/28/2024 02:45' -} -GMTEEditTilesCommand >> initialize [ - - self - previousSprites: Dictionary new; - currentSprites: Dictionary new + ifNotNil: [tile updateSprite: (aList at: coordinates)]]] ] { @@ -109,26 +118,9 @@ GMTEEditTilesCommand >> tileMap: anObject [ { #category : #execution, - #'squeak_changestamp' : 'TW 7/2/2024 17:54' + #'squeak_changestamp' : 'Alex M 7/10/2024 13:43' } GMTEEditTilesCommand >> undo [ - | tile sprite layer x y | - self previousSprites keysDo: [ :coordinates | - x := coordinates at: 1. - y := coordinates at: 2. - layer := coordinates at: 3. - - tile := self tileMap tileMatrixStack layer: layer at: y at: x. - sprite := self previousSprites at: coordinates. - tile - ifNil: [sprite - ifNotNil: [ - tile := tileMap generateTileAtlayer: layer x: x y: y stack: self tileMap tileMatrixStack tileType: GMTETile. - tile updateSprite: sprite]] - ifNotNil: [sprite - ifNil: [ - self tileMap tileMatrixStack layer: layer at: y at: x put: nil. - tile abandon] - ifNotNil: [tile updateSprite: (self previousSprites at: coordinates)]]] + self placeTilesFromList: self previousSprites ] diff --git a/source/GM-TE/GMTEEditor.class.st b/source/GM-TE/GMTEEditor.class.st index 35bbe5dc..fedd96b3 100644 --- a/source/GM-TE/GMTEEditor.class.st +++ b/source/GM-TE/GMTEEditor.class.st @@ -75,6 +75,26 @@ GMTEEditor class >> getVisibilityIndicator: aBoolean [ ifFalse: [^ ' (h)'] ] +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'tw 7/11/2024 17:03' +} +GMTEEditor class >> hLayoutFrame: intI ofN: intN vSymmetric: aFloat [ + + ^ self hLayoutFrame: intI ofN: intN vUp: aFloat down: aFloat +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'tw 7/11/2024 17:05' +} +GMTEEditor class >> hLayoutFrame: intI ofN: intN vUp: aFloat down: anotherFloat [ + + "useful for building buttons, maybe move this to instance? TODO FLAG" + + ^ LayoutFrame fractions: ((intI - 1 / intN @ aFloat) corner: (intI / intN @ (1 - anotherFloat))) +] + { #category : #constants, #'squeak_changestamp' : 'TW 7/9/2024 11:28' @@ -214,6 +234,15 @@ GMTEEditor class >> tileMapMinPaddingSize [ ^ 0 ] +{ + #category : #constants, + #'squeak_changestamp' : 'tw 7/11/2024 16:52' +} +GMTEEditor class >> toolBarVSpace [ + + ^ 0.1 +] + { #category : #'command processing', #'squeak_changestamp' : 'Valentin Teutschbein 7/6/2024 11:56' @@ -373,7 +402,7 @@ GMTEEditor >> brushButtons: anObject [ { #category : #building, - #'squeak_changestamp' : 'TW 7/9/2024 18:15' + #'squeak_changestamp' : 'mcjj 7/11/2024 16:15' } GMTEEditor >> buildWith: builder [ "builds the editor with ToolBuilder" @@ -393,7 +422,9 @@ GMTEEditor >> buildWith: builder [ self createInspectorSpecWithBuilder: builder}; closeAction: #onClose; minimumExtent: GMTEEditor editorMinimumExtent). - + + newMorph addKeyboardCaptureFilter: self. + self commandBar: (newMorph submorphNamed: 'command bar'). "self commandBar vResizing: #rigid." self tileStore: (newMorph submorphNamed: 'tile store'). @@ -606,7 +637,7 @@ GMTEEditor >> createCommandBarSpecWithBuilder: aBuilder [ { #category : #building, - #'squeak_changestamp' : 'jj 6/22/2024 20:42' + #'squeak_changestamp' : 'tw 7/11/2024 17:48' } GMTEEditor >> createInspectorSpecWithBuilder: aBuilder [ "creates the spec for the inspector tab" @@ -621,8 +652,6 @@ GMTEEditor >> createInspectorSpecWithBuilder: aBuilder [ children: { self createAttributeSpecWithBuilder: aBuilder descriptor: 'Padding:' getter: #getPaddingAsString setter: #setPadding: model: self. - self createAttributeSpecWithBuilder: aBuilder descriptor: 'Tile Ratio:' getter: #getTileRatioAsString setter: #setTileRatio: model: self. - self createAttributeSpecWithBuilder: aBuilder descriptor: 'Grid Width:' getter: #getGridWidthAsString setter: #setGridWidth: model: self. self createAttributeSpecWithBuilder: aBuilder descriptor: 'Grid Height:' getter: #getGridHeightAsString setter: #setGridHeight: model: self @@ -634,7 +663,7 @@ GMTEEditor >> createInspectorSpecWithBuilder: aBuilder [ { #category : #building, - #'squeak_changestamp' : 'Alex M 7/10/2024 02:14' + #'squeak_changestamp' : 'Alex M 7/11/2024 18:04' } GMTEEditor >> createLayersSpecWithBuilder: aBuilder [ "creates the spec for layer viewer" @@ -642,6 +671,7 @@ GMTEEditor >> createLayersSpecWithBuilder: aBuilder [ ^ (aBuilder pluggablePanelSpec new) name: 'layer viewer'; model: self; + minimumExtent:150 @ 150; frame: (LayoutFrame fractions: (0.8 @ 0.25 corner: 1 @ 1)); children: { @@ -735,7 +765,7 @@ GMTEEditor >> createLayersSpecWithBuilder: aBuilder [ { #category : #building, - #'squeak_changestamp' : 'jj 6/22/2024 20:44' + #'squeak_changestamp' : 'Alex M 7/11/2024 18:04' } GMTEEditor >> createTileViewerSpecWithBuilder: aBuilder [ "creates the spec for the tile viewer" @@ -755,11 +785,10 @@ GMTEEditor >> createTileViewerSpecWithBuilder: aBuilder [ layout: #horizontal; model:self; frame: (LayoutFrame - fractions: (0@0 corner: 1@1) - offsets: (0@30 corner: 0@ 0)) + fractions: (0 @ 0 corner: 1 @ 0.9)) }; - minimumExtent:150@150; + minimumExtent:150 @ 150; yourself ] @@ -786,7 +815,7 @@ GMTEEditor >> createTilestoreSpecWithBuilder: aBuilder [ { #category : #building, - #'squeak_changestamp' : 'Alex M 7/10/2024 02:12' + #'squeak_changestamp' : 'tw 7/11/2024 17:05' } GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ "creates the spec for the tool bar" @@ -794,13 +823,13 @@ GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ ^ (aBuilder pluggablePanelSpec new) name: 'toolbar'; model: self; - frame: (LayoutFrame fractions: (0@0 corner: 1@0) offsets:(0@0 corner: 0@30)); + frame: (LayoutFrame fractions: (0.05@0.9 corner: 0.95@1)); children: { (aBuilder pluggableImageButtonSpec new) name: 'undo'; description: 'Undo'; model: self; - frame: (LayoutFrame fractions: (0 @ 0 corner: (1 / 6) @ 1) offsets: nil); + frame: (GMTEEditor hLayoutFrame: 1 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); action: #undo; project: 'GameMecha'; path: '/GMTEIcons/undo.png'. @@ -809,7 +838,7 @@ GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ name: 'redo'; description: 'Redo'; model: self; - frame: (LayoutFrame fractions: ((1 / 6) @ 0 corner: (2 / 6) @ 1) offsets: nil); + frame: (GMTEEditor hLayoutFrame: 2 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); action: #redo; project: 'GameMecha'; path: '/GMTEIcons/redo.png'. @@ -818,17 +847,27 @@ GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ name: 'radiusBrush'; description: 'Brush'; model: self; - frame: (LayoutFrame fractions: ((2 / 6) @ 0 corner: (3 / 6) @ 1) offsets: nil); + frame: (GMTEEditor hLayoutFrame: 3 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); action: #selectRadiusBrush; project: 'GameMecha'; buttonGroup: self brushButtons; path: '/GMTEIcons/brush.png'. + (aBuilder pluggableImageButtonSpec new) + name: 'lineBrush'; + description: 'Line Tool'; + model: self; + frame: (GMTEEditor hLayoutFrame: 4 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); + action: #selectLineBrush; + project: 'GameMecha'; + buttonGroup: self brushButtons; + path: '/GMTEIcons/line.png'. + (aBuilder pluggableImageButtonSpec new) name: 'fillBrush'; description: 'Fill Tool'; model: self; - frame: (LayoutFrame fractions: ((3 / 6) @ 0 corner: (4 / 6) @ 1) offsets: nil); + frame: (GMTEEditor hLayoutFrame: 5 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); action: #selectFillBrush; project: 'GameMecha'; buttonGroup: self brushButtons; @@ -838,7 +877,7 @@ GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ name: 'rectangleBrush'; description: 'Rectangle Tool'; model: self; - frame: (LayoutFrame fractions: ((4 / 6) @ 0 corner: (5 / 6) @ 1) offsets: nil); + frame: (GMTEEditor hLayoutFrame: 6 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace); action: #selectRectangleBrush; project: 'GameMecha'; buttonGroup: self brushButtons; @@ -849,11 +888,9 @@ GMTEEditor >> createToolBarSpecWithBuilder: aBuilder [ getter: #getBrushRadiusAsString setter: #setBrushRadiusFromText: model: self - frame:(LayoutFrame fractions: ((4.5 / 6) @ 0 corner: 0.95 @ 1) offsets: (20 @ 0 corner: 0 @ 0)). + frame: ((GMTEEditor hLayoutFrame: 7 ofN: 7 vSymmetric: GMTEEditor toolBarVSpace)). }; - - verticalResizing: #shrinkWrap; yourself ] @@ -1022,6 +1059,29 @@ GMTEEditor >> exportMenu [ builder open: aMenuSpec ] +{ + #category : #'input handling', + #'squeak_changestamp' : 'mcjj 7/12/2024 00:19' +} +GMTEEditor >> filterEvent: aKeyboardEvent for: anObject [ + | key | + + aKeyboardEvent isKeystroke + ifFalse: [^ aKeyboardEvent]. + + key := aKeyboardEvent keyCharacter. + + aKeyboardEvent commandKeyPressed ifTrue: [ + key caseOf: { + [$z] -> [self undo]. + [$y] -> [self redo]. + [$r] -> [self rotateSelectedTile]. + } otherwise: [^ aKeyboardEvent "no hit"]. + ^ aKeyboardEvent ignore "hit"]. + + ^ aKeyboardEvent "no hit" +] + { #category : #accessing, #'squeak_changestamp' : 'TW 7/9/2024 17:14' @@ -1487,15 +1547,14 @@ GMTEEditor >> moveLayerUp [ { #category : #building, - #'squeak_changestamp' : 'Alex M 6/28/2024 21:27' + #'squeak_changestamp' : 'Alex M 7/11/2024 00:34' } GMTEEditor >> onClose [ "asks the user whether they want to save their progress" - "self savedSinceModified + self savedSinceModified ifFalse: [(PopUpMenu confirm: 'Save before closing?') - ifTrue: [self exportAsMorph]]" - "COMMENTED FOR EASIER DEBUGGING" + ifTrue: [self exportAsMorph]] ] { @@ -1615,13 +1674,15 @@ GMTEEditor >> ratio: anObject [ { #category : #'command processing', - #'squeak_changestamp' : 'TW 7/2/2024 17:47' + #'squeak_changestamp' : 'Alex M 7/10/2024 14:17' } GMTEEditor >> redo [ (self currentCommand < self commands size) ifTrue: [ - self currentCommand: self currentCommand + 1. + self + savedSinceModified: false; + currentCommand: self currentCommand + 1. (self commands at: self currentCommand) do. self savedSinceModified: false] ] @@ -1723,12 +1784,14 @@ GMTEEditor >> resetSelectedLayers [ { #category : #TODO, - #'squeak_changestamp' : 'Alex M 6/25/2024 18:26' + #'squeak_changestamp' : 'mcjj 7/11/2024 17:52' } GMTEEditor >> rotateSelectedTile [ self selectedTile: (self selectedTile rotateBy: #right centerAt: (self selectedTile extent / 2)). - self tileMap tileSelectionSet highlightImage: self selectedTile + self tileMap tileSelectionSet removeAllHighlightings. + self tileMap tileSelectionSet highlightImage: self selectedTile. + self tileMap tileSelectionSet applyAllHighlightings ] { @@ -1785,6 +1848,15 @@ GMTEEditor >> selectLayer: anIndex [ ] +{ + #category : #'menu button functions', + #'squeak_changestamp' : 'tw 7/11/2024 16:23' +} +GMTEEditor >> selectLineBrush [ + + self brush selectLineBrush +] + { #category : #accessing, #'squeak_changestamp' : 'jj 6/22/2024 21:35' @@ -2131,14 +2203,16 @@ GMTEEditor >> trayViewer: anObject [ { #category : #'command processing', - #'squeak_changestamp' : 'Alex M 7/10/2024 03:49' + #'squeak_changestamp' : 'Alex M 7/10/2024 14:17' } GMTEEditor >> undo [ self flag: 'DO THIS USING TILEMAP FUNCTIONS'. (self currentCommand > 1) ifTrue: [(self commands at: self currentCommand) undo. - self currentCommand: self currentCommand - 1. + self + savedSinceModified: false; + currentCommand: self currentCommand - 1. ({GMTETilemapSizeCommand. GMTEDeleteLayersCommand} includes: (self commands at: self currentCommand + 1) class) ifTrue: [self redoAllCommandsUntil: self currentCommand]. self savedSinceModified: false] diff --git a/source/GM-TE/GMTEEditorTileMap.class.st b/source/GM-TE/GMTEEditorTileMap.class.st index 1f47a0f6..5de7b5f5 100644 --- a/source/GM-TE/GMTEEditorTileMap.class.st +++ b/source/GM-TE/GMTEEditorTileMap.class.st @@ -62,6 +62,24 @@ GMTEEditorTileMap >> currentTileChanges: anObject [ currentTileChanges := anObject ] +{ + #category : #updating, + #'squeak_changestamp' : 'JS 7/12/2024 11:30' +} +GMTEEditorTileMap >> deleteTiles: aCoordinateCollection inLayer: aLayer [ + "delete tiles from editable matrix stack at given indices" + + | tile | + aCoordinateCollection do: [:c | + ((self tileMatrixStack layer: aLayer) inBounds: c) ifTrue: [ + tile := self tileMatrixStack layer: aLayer at: c y at: c x. + tile ifNotNil: [ + self savePreviousImageFromMatrixCoordinate: c inLayer: aLayer. + tile abandon. + self tileMatrixStack layer: aLayer at: c y at: c x put: nil. + self saveNewImageFromPosition: tile position inLayer: aLayer]]]. +] + { #category : #'event handling', #'squeak_changestamp' : 'jj 6/23/2024 13:35' @@ -80,6 +98,15 @@ GMTEEditorTileMap >> handlesMouseMove: anEvent [ ^ true ] +{ + #category : #'event handling', + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 17:14' +} +GMTEEditorTileMap >> handlesMouseOver: anEvent [ + + ^ true +] + { #category : #initialization, #'squeak_changestamp' : 'Alex M 6/28/2024 20:24' @@ -113,18 +140,17 @@ GMTEEditorTileMap >> model: anObject [ { #category : #'event handling', - #'squeak_changestamp' : 'Valentin Teutschbein 7/10/2024 13:07' + #'squeak_changestamp' : 'JS 7/11/2024 14:13' } GMTEEditorTileMap >> mouseDown: anEvent [ "Implements placement of tiles" - | selectedCoordinates activeLayer selectedIndex | + | selectedIndex | self flag: 'refactor; method extraction for "Add tiles to layer" to minimize redundancy with mouseMove?'. self model singleLayerSelected ifFalse: [^nil]. - activeLayer := self model selectedLayers anyOne. selectedIndex := self tileIndexFromPosition: anEvent position. self model brush firstMatrixIndex: selectedIndex. - selectedCoordinates := self model brush executeWithMatrixIndex: selectedIndex andLayer: (self tileMatrixStack layer: activeLayer). + self model brush executeWithMatrixIndex: selectedIndex andLayer: (self tileMatrixStack layer: self model selectedLayers anyOne). anEvent yellowButtonPressed ifTrue: [self tileSelectionSet highlightImage: nil]. ^ true @@ -132,7 +158,18 @@ GMTEEditorTileMap >> mouseDown: anEvent [ { #category : #'event handling', - #'squeak_changestamp' : 'Valentin Teutschbein 7/10/2024 13:06' + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 17:18' +} +GMTEEditorTileMap >> mouseLeave: anEvent [ + + self tileSelectionSet clearAllHighlightings. + + ^ true +] + +{ + #category : #'event handling', + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 17:01' } GMTEEditorTileMap >> mouseMove: anEvent [ "Implements highlighting of tiles when hovering" @@ -147,14 +184,15 @@ GMTEEditorTileMap >> mouseMove: anEvent [ selectedCoordinates ifNil: [^ nil]. - (selectedCoordinates select: [:c | (self tileMatrixStack layer: activeLayer) inBounds: c]) do: [:t| - hoveredTileHighlighting := self highlightingTileFromIndex: t. - hoveredTileHighlighting ifNotNil: [self tileSelectionSet highlightTile: hoveredTileHighlighting]]. + (selectedCoordinates select: [:c | + (self tileMatrixStack layer: activeLayer) inBounds: c]) do: [:t | + hoveredTileHighlighting := self highlightingTileFromIndex: t. + hoveredTileHighlighting ifNotNil: [self tileSelectionSet highlightTile: hoveredTileHighlighting]] ] { #category : #'event handling', - #'squeak_changestamp' : 'Valentin Teutschbein 7/10/2024 13:11' + #'squeak_changestamp' : 'mcjj 7/11/2024 16:20' } GMTEEditorTileMap >> mouseUp: anEvent [ @@ -164,8 +202,28 @@ GMTEEditorTileMap >> mouseUp: anEvent [ activeLayer := self model selectedLayers anyOne. self updateTiles: (indicesToAdd asCollection) inLayer: activeLayer FromEvent: anEvent. self model brush resetOutputSet. - (self previousTileStates size > 0) ifTrue: [self saveTileEditChanges]. - self tileSelectionSet highlightImage: (self model selectedTile). + (self previousTileStates isEmpty) ifFalse: [self saveTileEditChanges]. + self tileSelectionSet clearAllHighlightings. + self tileSelectionSet highlightImage: (self model selectedTile) + +] + +{ + #category : #updating, + #'squeak_changestamp' : 'JS 7/12/2024 11:30' +} +GMTEEditorTileMap >> placeTiles: aCoordinateCollection inLayer: aLayer [ + "Add currently selected tile (model) to editable matrix stack at given indices" + + | tile | + aCoordinateCollection do: [:c | + self savePreviousImageFromMatrixCoordinate: c inLayer: aLayer. + ((self tileMatrixStack layer: aLayer) inBounds: c) ifTrue: [ + tile := self tileMatrixStack layer: aLayer at: c y at: c x. + tile ifNil: [ tile := self generateTileAtlayer: aLayer x: c x y: c y stack: tileMatrixStack tileType: GMTETile]. + self updateTileSprite: tile. + self saveNewImageFromPosition: tile position inLayer: aLayer]]. + ] { @@ -284,12 +342,12 @@ GMTEEditorTileMap >> savePreviousImageFromPosition: aPosition inLayer: aLayer [ { #category : #'command processing', - #'squeak_changestamp' : 'Valentin Teutschbein 7/6/2024 11:52' + #'squeak_changestamp' : 'JS 7/11/2024 14:07' } GMTEEditorTileMap >> saveTileEditChanges [ self - model addCommand: (GMTEEditTilesCommand previousTiles: previousTileStates currentTiles: currentTileChanges tilemap: self). + model addCommand: (GMTEEditTilesCommand previousTiles: self previousTileStates currentTiles: self currentTileChanges tilemap: self). self resetTileEditChanges. ] @@ -323,39 +381,14 @@ GMTEEditorTileMap >> updateTileSprite: aTile [ { #category : #updating, - #'squeak_changestamp' : 'Valentin Teutschbein 7/9/2024 22:07' + #'squeak_changestamp' : 'JS 7/12/2024 11:31' } GMTEEditorTileMap >> updateTiles: aCoordinateCollection inLayer: aLayer FromEvent: anEvent [ - "Add currently selected tile (model) to editable matrix stack at mouse position" - | tile | - self flag: 'saveNewImage confict with alex fix?'. + (self tileIndexFromPosition: anEvent position) ifNil: [^ nil]. - (anEvent redButtonChanged and: [self model selectedTile notNil]) - ifTrue: [ - aCoordinateCollection do: [:c | - self savePreviousImageFromMatrixCoordinate: c inLayer: aLayer. - ((self tileMatrixStack layer: aLayer) inBounds: c) ifTrue: [ - tile := self tileMatrixStack layer: aLayer at: c y at: c x. - tile - ifNil: [ tile := self generateTileAtlayer: aLayer x: c x y: c y stack: tileMatrixStack tileType: GMTETile]. - self updateTileSprite: tile. - self saveNewImageFromPosition: tile position inLayer: aLayer] - ]. - self model savedSinceModified: false]. - (anEvent yellowButtonChanged) - ifTrue: [ - aCoordinateCollection do: [:c | - | tilePos | - self savePreviousImageFromMatrixCoordinate: c inLayer: aLayer. - ((self tileMatrixStack layer: aLayer) inBounds: c) ifTrue: [ - tile := self tileMatrixStack layer: aLayer at: c y at: c x. - tile - ifNotNil: [ - tilePos := tile position. - tile abandon. - self tileMatrixStack layer: aLayer at: c y at: c x put: nil. - self saveNewImageFromPosition: tilePos inLayer: aLayer]. - ] - ]. - self model savedSinceModified: false] + + (anEvent redButtonChanged and: [self model selectedTile notNil]) ifTrue: [self placeTiles: aCoordinateCollection inLayer: aLayer]. + (anEvent yellowButtonChanged) ifTrue: [self deleteTiles: aCoordinateCollection inLayer: aLayer]. + + self model savedSinceModified: false ] diff --git a/source/GM-TE/GMTETileMap.class.st b/source/GM-TE/GMTETileMap.class.st index 647a97ac..11ad8354 100644 --- a/source/GM-TE/GMTETileMap.class.st +++ b/source/GM-TE/GMTETileMap.class.st @@ -90,6 +90,24 @@ GMTETileMap class >> tileWidth: aWidth tileHeight: aHeight padding: aPadding siz tileSizeRatio: aRatio ] +{ + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 22:20' +} +GMTETileMap >> absPointToViewCenter: aPoint [ + + ^ (self absPointToViewFraction: aPoint) - (self view extent / 2) +] + +{ + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 22:19' +} +GMTETileMap >> absPointToViewFraction: aPoint [ + + ^aPoint / self extent +] + { #category : #accessing, #'squeak_changestamp' : 'Ivo Zilkenat 6/19/2024 22:28' @@ -193,6 +211,17 @@ GMTETileMap >> borderTileWidth: anObject [ borderTileWidth := anObject ] +{ + #category : #view, + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 00:08' +} +GMTETileMap >> centerViewAt: aPoint [ + "Note: center must induce legal view (non-overlapping)" + + self view moveTo: (self inViewPointToViewCenter: aPoint). + self updateMap +] + { #category : #conversion, #'squeak_changestamp' : 'Ivo Zilkenat 6/24/2024 11:09' @@ -477,9 +506,36 @@ GMTETileMap >> highlightingTileFromIndex: anIndex [ ^ self tileMatrixStackHighlighting layer: 1 at: anIndex y at: anIndex x ] +{ + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 22:58' +} +GMTETileMap >> inViewPointToAbs: aPoint [ + + ^ (self viewOriginInPxl - self topLeft) + (aPoint / self viewScaleFactor) +] + +{ + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 00:01' +} +GMTETileMap >> inViewPointToViewCenter: aPoint [ + + ^ (self inViewPointToViewFraction: aPoint) - (self view extent / 2) +] + +{ + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 22:30' +} +GMTETileMap >> inViewPointToViewFraction: aPoint [ + + ^ self absPointToViewFraction: (self inViewPointToAbs: aPoint) +] + { #category : #initialization, - #'squeak_changestamp' : 'Ivo Zilkenat 7/9/2024 11:47' + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:15' } GMTETileMap >> initialize [ @@ -488,7 +544,7 @@ GMTETileMap >> initialize [ color: Color lightGray; clipSubmorphs: true; forceMapSizeRatio: false; - view: (GMTEView origin: 0 @ 0 extent: 1 @ 1); + view: GMTEView new; "TODO: spike solution. Size 1@1 sets quadratic base image. Generic resizing not working yet" "TODO: default background tiles (must not exist but practical as a visual indicator)" @@ -690,6 +746,16 @@ GMTETileMap >> rescaleMatrixStacks [ self generateHighlightingTiles] ] +{ + #category : #view, + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:47' +} +GMTETileMap >> resetView [ + + self view reset. + self updateMap +] + { #category : #conversion, #'squeak_changestamp' : 'Ivo Zilkenat 6/24/2024 11:11' @@ -721,7 +787,7 @@ GMTETileMap >> revertCorrectedTilePositionMap: aPoint [ ] { - #category : #view, + #category : #'view-conversion', #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:49' } GMTETileMap >> revertViewCorrectedTilePosition: aPoint [ @@ -731,7 +797,7 @@ GMTETileMap >> revertViewCorrectedTilePosition: aPoint [ ] { - #category : #view, + #category : #'view-conversion', #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:47' } GMTETileMap >> revertViewCorrectedTilePositionMap: aPoint [ @@ -1193,7 +1259,7 @@ GMTETileMap >> view: anObject [ ] { - #category : #view, + #category : #'view-conversion', #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:36' } GMTETileMap >> viewCorrectedTileExtent: anExtent [ @@ -1203,7 +1269,7 @@ GMTETileMap >> viewCorrectedTileExtent: anExtent [ ] { - #category : #view, + #category : #'view-conversion', #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:36' } GMTETileMap >> viewCorrectedTilePosition: aPoint [ @@ -1213,22 +1279,20 @@ GMTETileMap >> viewCorrectedTilePosition: aPoint [ ] { - #category : #view, - #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:36' + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 17:50' } GMTETileMap >> viewOriginInPxl [ - "Note: given that view has same ratio as tileMap" ^ self extent * self view origin + self topLeft ] { - #category : #view, - #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 19:47' + #category : #'view-conversion', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 17:50' } GMTETileMap >> viewScaleFactor [ - "Note: given that view has same ratio as tileMap" ^ 1 / (self view extent x) @@ -1253,3 +1317,13 @@ GMTETileMap >> vigenerateBackgroundTiles [ ] + +{ + #category : #view, + #'squeak_changestamp' : 'Ivo Zilkenat 7/11/2024 00:33' +} +GMTETileMap >> zoomInAt: aPoint [ + + self view shrinkBy: 0.1. + self centerViewAt: aPoint +] diff --git a/source/GM-TE/GMTETileSelectionSet.class.st b/source/GM-TE/GMTETileSelectionSet.class.st index 51ad30b8..44228e7d 100644 --- a/source/GM-TE/GMTETileSelectionSet.class.st +++ b/source/GM-TE/GMTETileSelectionSet.class.st @@ -7,6 +7,17 @@ Class { #category : #'GM-TE-TileMap' } +{ + #category : #highlighting, + #'squeak_changestamp' : 'mcjj 7/11/2024 17:11' +} +GMTETileSelectionSet >> applyAllHighlightings [ + + self do: [:tile | + self applyHighlightingVisuals: tile] + +] + { #category : #highlighting, #'squeak_changestamp' : 'Ivo Zilkenat 6/24/2024 11:51' @@ -71,6 +82,17 @@ GMTETileSelectionSet >> initialize: n [ ] +{ + #category : #highlighting, + #'squeak_changestamp' : 'mcjj 7/11/2024 17:52' +} +GMTETileSelectionSet >> removeAllHighlightings [ + "Remove applied highlightings if any" + + self do: [:tile | + self removeHighlightingVisuals: tile] +] + { #category : #highlighting, #'squeak_changestamp' : 'Ivo Zilkenat 6/24/2024 11:51' diff --git a/source/GM-TE/GMTETilemapSizeCommand.class.st b/source/GM-TE/GMTETilemapSizeCommand.class.st index 7613d036..fe18b4f0 100644 --- a/source/GM-TE/GMTETilemapSizeCommand.class.st +++ b/source/GM-TE/GMTETilemapSizeCommand.class.st @@ -1,6 +1,6 @@ Class { #name : #GMTETilemapSizeCommand, - #superclass : #GMTECommand, + #superclass : #GMTEEditTilesCommand, #instVars : [ 'editor', 'method', diff --git a/source/GM-TE/GMTEView.class.st b/source/GM-TE/GMTEView.class.st index 2b5353c5..9d55a807 100644 --- a/source/GM-TE/GMTEView.class.st +++ b/source/GM-TE/GMTEView.class.st @@ -4,6 +4,22 @@ Class { #category : #'GM-TE-TileMap' } +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:17' +} +GMTEView >> enlargeBy: aFloat [ + + | newExtent | + newExtent := (self extent + (aFloat@aFloat)). + + self flag: 'magic number'. + ((newExtent x > 1) or: [newExtent y > 1]) ifTrue: [^ nil]. + (self isOverlappingOrigin: self origin withExtent: newExtent) ifTrue: [^ nil]. + + self extent: newExtent +] + { #category : #'as yet unclassified', #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:20' @@ -15,22 +31,80 @@ GMTEView >> extent: anExtent [ { #category : #initialization, - #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 19:41' + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:15' } GMTEView >> initialize [ "Note: Viewport origin & extent interpreted as fraction of reference view (e.g. Morph)" super initialize. + self reset ] { #category : #'as yet unclassified', - #'squeak_changestamp' : 'Ivo Zilkenat 7/2/2024 20:14' + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:05' +} +GMTEView >> isOverlappingOrigin: anOrigin withExtent: anExtent [ + + | corner | + corner := anOrigin + anExtent. + ^ (corner x > 1) or: [corner y > 1] +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:20' +} +GMTEView >> moveTo: anOrigin [ + "Set origin but also respect view not overlapping reference view" + + (self isOverlappingOrigin: anOrigin withExtent: self extent) ifTrue: [^ nil]. + + self origin: anOrigin +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:33' } GMTEView >> origin: aPoint [ - self setOrigin: aPoint corner: self corner + self setOrigin: aPoint corner: (aPoint + self corner) +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:33' +} +GMTEView >> reset [ + + self setOrigin: 0 @ 0 corner: 1 @ 1. + +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 18:16' +} +GMTEView >> shrinkBy: aFloat [ + + | newExtent | + newExtent := (self extent - (aFloat@aFloat)). + + self flag: 'magic number'. + ((newExtent x <= 0.1) or: [newExtent y <= 0.1]) ifTrue: [^ nil]. + + self extent: newExtent +] + +{ + #category : #'as yet unclassified', + #'squeak_changestamp' : 'Ivo Zilkenat 7/10/2024 22:53' +} +GMTEView >> size: aFraction [ + + self extent: (aFraction @ aFraction) ]