Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/grid drag initial delta #6037

Merged
merged 4 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ export interface CustomStrategyState {
strategyGeneratedUidsCache: { [elementPath: string]: string | undefined }
elementsToRerender: Array<ElementPath>
action: ActiveFrameAction | null
targetGridCell: GridCellCoordinates | null
grid: GridCustomStrategyState
}

export type GridCustomStrategyState = {
targetCell: GridCellCoordinates | null
draggingFromCell: GridCellCoordinates | null
rootCell: GridCellCoordinates | null
}

export type CustomStrategyStatePatch = Partial<CustomStrategyState>
Expand All @@ -34,7 +40,11 @@ export function defaultCustomStrategyState(): CustomStrategyState {
strategyGeneratedUidsCache: {},
elementsToRerender: [],
action: null,
targetGridCell: null,
grid: {
targetCell: null,
draggingFromCell: null,
rootCell: null,
},
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ElementPath } from 'utopia-shared/src/types'
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import type {
ElementInstanceMetadata,
ElementInstanceMetadataMap,
GridElementProperties,
} from '../../../../core/shared/element-template'
Expand All @@ -14,10 +15,11 @@ import {
import { create } from '../../../../core/shared/property-path'
import type { CanvasCommand } from '../../commands/commands'
import { setProperty } from '../../commands/set-property-command'
import type { GridCellCoordinates } from '../../controls/grid-controls'
import { gridCellCoordinates } from '../../controls/grid-controls'
import { canvasPointToWindowPoint } from '../../dom-lookup'
import type { DragInteractionData } from '../interaction-state'
import type { GridCustomStrategyState } from '../canvas-strategy-types'
import type { GridCellCoordinates } from '../../controls/grid-controls'
import { gridCellCoordinates } from '../../controls/grid-controls'

export function getGridCellUnderMouse(mousePoint: WindowPoint) {
return getGridCellAtPoint(mousePoint, false)
Expand Down Expand Up @@ -77,13 +79,21 @@ export function runGridRearrangeMove(
interactionData: DragInteractionData,
canvasScale: number,
canvasOffset: CanvasVector,
targetGridCell: GridCellCoordinates | null,
customState: GridCustomStrategyState,
duplicating: boolean,
): { commands: CanvasCommand[]; targetGridCell: GridCellCoordinates | null } {
let commands: CanvasCommand[] = []

): {
commands: CanvasCommand[]
targetCell: GridCellCoordinates | null
draggingFromCell: GridCellCoordinates | null
rootCell: GridCellCoordinates | null
} {
if (interactionData.drag == null) {
return { commands: [], targetGridCell: null }
return {
commands: [],
targetCell: null,
rootCell: null,
draggingFromCell: null,
}
}

const mouseWindowPoint = canvasPointToWindowPoint(
Expand All @@ -92,63 +102,117 @@ export function runGridRearrangeMove(
canvasOffset,
)

let newTargetGridCell = targetGridCell ?? null
const cellUnderMouse = duplicating
? getGridCellUnderMouseRecursive(mouseWindowPoint)
: getGridCellUnderMouse(mouseWindowPoint)
if (cellUnderMouse != null) {
newTargetGridCell = cellUnderMouse.coordinates
}

if (newTargetGridCell == null || newTargetGridCell.row < 1 || newTargetGridCell.column < 1) {
return { commands: [], targetGridCell: null }
const newTargetCell = getTargetCell(customState.targetCell, duplicating, mouseWindowPoint)
if (newTargetCell == null) {
return {
commands: [],
targetCell: null,
draggingFromCell: null,
rootCell: null,
}
}

const originalElementMetadata = MetadataUtils.findElementByElementPath(
jsxMetadata,
selectedElement,
)
if (originalElementMetadata == null) {
return { commands: [], targetGridCell: null }
return {
commands: [],
targetCell: null,
rootCell: null,
draggingFromCell: null,
}
}

const gridProperties = getElementGridProperties(originalElementMetadata)

// calculate the difference between the cell the mouse started the interaction from, and the "root"
// cell of the element, meaning the top-left-most cell the element occupies.
const draggingFromCell = customState.draggingFromCell ?? newTargetCell
const rootCell =
customState.rootCell ?? gridCellCoordinates(gridProperties.row, gridProperties.column)
const coordsDiff = getCellCoordsDelta(draggingFromCell, rootCell)

// get the new adjusted row
const row = getCoordBounds(newTargetCell, 'row', gridProperties.width, coordsDiff.row)
// get the new adjusted column
const column = getCoordBounds(newTargetCell, 'column', gridProperties.height, coordsDiff.column)

return {
commands: [
setProperty('always', targetElement, create('style', 'gridColumnStart'), column.start),
setProperty('always', targetElement, create('style', 'gridColumnEnd'), column.end),
setProperty('always', targetElement, create('style', 'gridRowStart'), row.start),
setProperty('always', targetElement, create('style', 'gridRowEnd'), row.end),
],
targetCell: newTargetCell,
rootCell: rootCell,
draggingFromCell: draggingFromCell,
}
}

function getTargetCell(
previousTargetCell: GridCellCoordinates | null,
duplicating: boolean,
mouseWindowPoint: WindowPoint,
): GridCellCoordinates | null {
let cell = previousTargetCell ?? null
const cellUnderMouse = duplicating
? getGridCellUnderMouseRecursive(mouseWindowPoint)
: getGridCellUnderMouse(mouseWindowPoint)
if (cellUnderMouse != null) {
cell = cellUnderMouse.coordinates
}
if (cell == null || cell.row < 1 || cell.column < 1) {
return null
}
return cell
}

function getElementGridProperties(element: ElementInstanceMetadata): {
row: number
width: number
column: number
height: number
} {
// get the grid fixtures (start and end for column and row) from the element metadata
function getGridProperty(field: keyof GridElementProperties, fallback: number) {
const propValue = originalElementMetadata?.specialSizeMeasurements.elementGridProperties[field]
const propValue = element.specialSizeMeasurements.elementGridProperties[field]
return propValue == null || propValue === 'auto' ? 0 : propValue.numericalPosition ?? fallback
}

const gridColumnStart = getGridProperty('gridColumnStart', 0)
const gridColumnEnd = getGridProperty('gridColumnEnd', 1)
const gridRowStart = getGridProperty('gridRowStart', 0)
const gridRowEnd = getGridProperty('gridRowEnd', 1)

commands.push(
setProperty(
'always',
targetElement,
create('style', 'gridColumnStart'),
newTargetGridCell.column,
),
setProperty(
'always',
targetElement,
create('style', 'gridColumnEnd'),
Math.max(
newTargetGridCell.column,
newTargetGridCell.column + (gridColumnEnd - gridColumnStart),
),
),
setProperty('always', targetElement, create('style', 'gridRowStart'), newTargetGridCell.row),
setProperty(
'always',
targetElement,
create('style', 'gridRowEnd'),
Math.max(newTargetGridCell.row, newTargetGridCell.row + (gridRowEnd - gridRowStart)),
),
)
const column = getGridProperty('gridColumnStart', 0)
const height = getGridProperty('gridColumnEnd', 1) - column
const row = getGridProperty('gridRowStart', 0)
const width = getGridProperty('gridRowEnd', 1) - row

return {
commands: commands,
targetGridCell: newTargetGridCell,
row,
width,
column,
height,
}
}

function getCellCoordsDelta(
dragFrom: GridCellCoordinates,
rootCell: GridCellCoordinates,
): GridCellCoordinates {
const rowDiff = dragFrom.row - rootCell.row
const columnDiff = dragFrom.column - rootCell.column

return gridCellCoordinates(rowDiff, columnDiff)
}

function getCoordBounds(
cell: GridCellCoordinates,
coord: 'column' | 'row',
size: number, // width or height
adjustOffset: number, // adjustment based on the difference between the initial dragging cell and the root cell
): { start: number; end: number } {
// the start is the first cell's coord the element will occupy
const start = Math.max(1, cell[coord] - adjustOffset)
// the end is the last cell's coord the element will occupy
const end = Math.max(1, start + size)
return { start, end }
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,19 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = (

const targetElement = EP.appendToPath(EP.parentPath(selectedElement), newUid)

const { commands: moveCommands, targetGridCell: newTargetGridCell } = runGridRearrangeMove(
const {
commands: moveCommands,
targetCell: targetGridCell,
draggingFromCell,
rootCell,
} = runGridRearrangeMove(
targetElement,
selectedElement,
canvasState.startingMetadata,
interactionSession.interactionData,
canvasState.scale,
canvasState.canvasOffset,
customState.targetGridCell,
customState.grid,
true,
)
if (moveCommands.length === 0) {
Expand All @@ -109,7 +114,11 @@ export const gridRearrangeMoveDuplicateStrategy: CanvasStrategyFactory = (
setCursorCommand(CSSCursor.Duplicate),
],
{
targetGridCell: newTargetGridCell,
grid: {
targetCell: targetGridCell,
draggingFromCell: draggingFromCell,
rootCell: rootCell,
},
duplicatedElementNewUids: duplicatedElementNewUids,
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,31 @@ export const gridRearrangeMoveStrategy: CanvasStrategyFactory = (

const targetElement = selectedElement

const { commands: moveCommands, targetGridCell: newTargetGridCell } = runGridRearrangeMove(
const {
commands: moveCommands,
targetCell: targetGridCell,
draggingFromCell,
rootCell,
} = runGridRearrangeMove(
targetElement,
selectedElement,
canvasState.startingMetadata,
interactionSession.interactionData,
canvasState.scale,
canvasState.canvasOffset,
customState.targetGridCell,
customState.grid,
false,
)
if (moveCommands.length === 0) {
return emptyStrategyApplicationResult
}

return strategyApplicationResult(moveCommands, {
targetGridCell: newTargetGridCell,
grid: {
targetCell: targetGridCell,
draggingFromCell: draggingFromCell,
rootCell: rootCell,
},
})
},
}
Expand Down
Loading