Extract tile size change logic into a function
This commit is contained in:
		
					parent
					
						
							
								e99294c3f1
							
						
					
				
			
			
				commit
				
					
						4e35984900
					
				
			
		
					 1 changed files with 82 additions and 77 deletions
				
			
		|  | @ -236,6 +236,85 @@ const fillGaps = (g: Grid): Grid => { | ||||||
|   return result; |   return result; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | const cycleTileSize = (tileId: string, g: Grid): Grid => { | ||||||
|  |   // TODO: When unenlarging tiles, do all this in reverse somehow (deleting
 | ||||||
|  |   // rows and displacing tiles. pushing tiles outwards might be necessary)
 | ||||||
|  | 
 | ||||||
|  |   const from = g.cells.findIndex(c => c?.item.id === tileId) | ||||||
|  |   if (from === -1) return g // Tile removed, no change
 | ||||||
|  |   const fromWidth = g.cells[from]!.columns | ||||||
|  |   const fromHeight = g.cells[from]!.rows | ||||||
|  |   const fromEnd = areaEnd(from, fromWidth, fromHeight, g) | ||||||
|  | 
 | ||||||
|  |   const [toWidth, toHeight] = fromWidth === 1 && fromHeight === 1 ? [3, 2] : [1, 1] | ||||||
|  |   const newRows = Math.ceil((toWidth * toHeight - fromWidth * fromHeight) / g.columns) | ||||||
|  | 
 | ||||||
|  |   const candidateWidth = toWidth | ||||||
|  |   const candidateHeight = toHeight - newRows | ||||||
|  | 
 | ||||||
|  |   const nextScanLocations = new Set<number>([from]) | ||||||
|  |   const scanColumnOffset = Math.floor((toWidth - 1) / 2) | ||||||
|  |   const scanRowOffset = Math.floor((toHeight - 1) / 2) | ||||||
|  |   let to: number | null = null | ||||||
|  | 
 | ||||||
|  |   const displaceable = (c: Cell | undefined, i: number): boolean => c === undefined || (c.columns === 1 && c.rows === 1) || inArea(i, from, fromEnd, g) | ||||||
|  | 
 | ||||||
|  |   for (const scanLocation of nextScanLocations) { | ||||||
|  |     const start = scanLocation - scanColumnOffset - g.columns * scanRowOffset | ||||||
|  |     const end = areaEnd(start, candidateWidth, candidateHeight, g) | ||||||
|  |     const startColumn = column(start, g); | ||||||
|  |     const endColumn = column(end, g); | ||||||
|  | 
 | ||||||
|  |     if (start >= 0 && end < g.cells.length && endColumn - startColumn + 1 === candidateWidth) { | ||||||
|  |       if (allCellsInArea(start, end, g, displaceable)) { | ||||||
|  |         to = start | ||||||
|  |         break | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (startColumn > 0) nextScanLocations.add(scanLocation - 1) | ||||||
|  |     if (endColumn < g.columns - 1) nextScanLocations.add(scanLocation + 1) | ||||||
|  |     nextScanLocations.add(scanLocation - g.columns) | ||||||
|  |     nextScanLocations.add(scanLocation + g.columns) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // TODO: Don't give up on placing the tile yet
 | ||||||
|  |   if (to === null) return g | ||||||
|  | 
 | ||||||
|  |   const gappyGrid: Grid = { | ||||||
|  |     ...g, | ||||||
|  |     generation: g.generation + 1, | ||||||
|  |     cells: new Array(g.cells.length + newRows * g.columns), | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const toRow = row(to, g) | ||||||
|  | 
 | ||||||
|  |   for (let src = 0; src < g.cells.length; src++) { | ||||||
|  |     if (g.cells[src]?.item.id !== tileId) { | ||||||
|  |       const dest = row(src, g) > toRow + toHeight - 1 ? src + g.columns * newRows : src | ||||||
|  |       gappyGrid.cells[dest] = g.cells[src] | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const displacedTiles: Cell[] = [] | ||||||
|  |   const toEnd = areaEnd(to, toWidth, toHeight, g) | ||||||
|  |   forEachCellInArea(to, toEnd, gappyGrid, (c, i) => { | ||||||
|  |     if (c !== undefined) displacedTiles.push(c) | ||||||
|  |     gappyGrid.cells[i] = { | ||||||
|  |       item: g.cells[from]!.item, | ||||||
|  |       slot: i === to, | ||||||
|  |       columns: toWidth, | ||||||
|  |       rows: toHeight, | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   for (let i = 0; displacedTiles.length > 0; i++) { | ||||||
|  |     if (gappyGrid.cells[i] === undefined) gappyGrid.cells[i] = displacedTiles.shift() | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return fillGaps(gappyGrid) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export const NewVideoGrid: FC<Props> = ({ | export const NewVideoGrid: FC<Props> = ({ | ||||||
|   items, |   items, | ||||||
|   disableAnimations, |   disableAnimations, | ||||||
|  | @ -391,83 +470,9 @@ export const NewVideoGrid: FC<Props> = ({ | ||||||
|       const tileId = args[0] as string |       const tileId = args[0] as string | ||||||
| 
 | 
 | ||||||
|       if (tap) { |       if (tap) { | ||||||
|         // TODO: When unenlarging tiles, do this in reverse somehow (deleting
 |         setGrid(g => cycleTileSize(tileId, g)) | ||||||
|         // rows and displacing tiles. pushing tiles outwards might be necessary)
 |       } else { | ||||||
|         setGrid(g => { |         // TODO
 | ||||||
|           const from = g.cells.findIndex(c => c?.item.id === tileId) |  | ||||||
|           if (from === -1) return g // Tile removed, no change
 |  | ||||||
|           const fromWidth = g.cells[from]!.columns |  | ||||||
|           const fromHeight = g.cells[from]!.rows |  | ||||||
|           const fromEnd = areaEnd(from, fromWidth, fromHeight, g) |  | ||||||
| 
 |  | ||||||
|           const [toWidth, toHeight] = fromWidth === 1 && fromHeight === 1 ? [3, 2] : [1, 1] |  | ||||||
|           const newRows = Math.ceil((toWidth * toHeight - fromWidth * fromHeight) / g.columns) |  | ||||||
| 
 |  | ||||||
|           const candidateWidth = toWidth |  | ||||||
|           const candidateHeight = toHeight - newRows |  | ||||||
| 
 |  | ||||||
|           const nextScanLocations = new Set<number>([from]) |  | ||||||
|           const scanColumnOffset = Math.floor((toWidth - 1) / 2) |  | ||||||
|           const scanRowOffset = Math.floor((toHeight - 1) / 2) |  | ||||||
|           let to: number | null = null |  | ||||||
| 
 |  | ||||||
|           const displaceable = (c: Cell | undefined, i: number): boolean => c === undefined || (c.columns === 1 && c.rows === 1) || inArea(i, from, fromEnd, g) |  | ||||||
| 
 |  | ||||||
|           for (const scanLocation of nextScanLocations) { |  | ||||||
|             const start = scanLocation - scanColumnOffset - g.columns * scanRowOffset |  | ||||||
|             const end = areaEnd(start, candidateWidth, candidateHeight, g) |  | ||||||
|             const startColumn = column(start, g); |  | ||||||
|             const endColumn = column(end, g); |  | ||||||
| 
 |  | ||||||
|             if (start >= 0 && end < g.cells.length && endColumn - startColumn + 1 === candidateWidth) { |  | ||||||
|               if (allCellsInArea(start, end, g, displaceable)) { |  | ||||||
|                 to = start |  | ||||||
|                 break |  | ||||||
|               } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (startColumn > 0) nextScanLocations.add(scanLocation - 1) |  | ||||||
|             if (endColumn < g.columns - 1) nextScanLocations.add(scanLocation + 1) |  | ||||||
|             nextScanLocations.add(scanLocation - g.columns) |  | ||||||
|             nextScanLocations.add(scanLocation + g.columns) |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           // TODO: Don't give up on placing the tile yet
 |  | ||||||
|           if (to === null) return g |  | ||||||
| 
 |  | ||||||
|           const gappyGrid: Grid = { |  | ||||||
|             ...g, |  | ||||||
|             generation: g.generation + 1, |  | ||||||
|             cells: new Array(g.cells.length + newRows * g.columns), |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           const toRow = row(to, g) |  | ||||||
| 
 |  | ||||||
|           for (let src = 0; src < g.cells.length; src++) { |  | ||||||
|             if (g.cells[src]?.item.id !== tileId) { |  | ||||||
|               const dest = row(src, g) > toRow + toHeight - 1 ? src + g.columns * newRows : src |  | ||||||
|               gappyGrid.cells[dest] = g.cells[src] |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           const displacedTiles: Cell[] = [] |  | ||||||
|           const toEnd = areaEnd(to, toWidth, toHeight, g) |  | ||||||
|           forEachCellInArea(to, toEnd, gappyGrid, (c, i) => { |  | ||||||
|             if (c !== undefined) displacedTiles.push(c) |  | ||||||
|             gappyGrid.cells[i] = { |  | ||||||
|               item: g.cells[from]!.item, |  | ||||||
|               slot: i === to, |  | ||||||
|               columns: toWidth, |  | ||||||
|               rows: toHeight, |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
| 
 |  | ||||||
|           for (let i = 0; displacedTiles.length > 0; i++) { |  | ||||||
|             if (gappyGrid.cells[i] === undefined) gappyGrid.cells[i] = displacedTiles.shift() |  | ||||||
|           } |  | ||||||
| 
 |  | ||||||
|           return fillGaps(gappyGrid) |  | ||||||
|         }) |  | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     { filterTaps: true, pointer: { buttons: [1] } } |     { filterTaps: true, pointer: { buttons: [1] } } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue