From 59a118539ee5067034fa46f363eea7a8656cea6e Mon Sep 17 00:00:00 2001 From: AlexandreSi <32449369+AlexandreSi@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:22:33 +0200 Subject: [PATCH] Make rectangular selection possible in instance properties editor mobile --- .../CompactInstancePropertiesEditor/index.js | 12 ++- .../src/InstancesEditor/TileSetVisualizer.js | 86 +++++++++++++------ 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/newIDE/app/src/InstancesEditor/CompactInstancePropertiesEditor/index.js b/newIDE/app/src/InstancesEditor/CompactInstancePropertiesEditor/index.js index 499d8ec8ca12..659c93b4db77 100644 --- a/newIDE/app/src/InstancesEditor/CompactInstancePropertiesEditor/index.js +++ b/newIDE/app/src/InstancesEditor/CompactInstancePropertiesEditor/index.js @@ -15,7 +15,7 @@ import IconButton from '../../UI/IconButton'; import { Line, Column, Spacer, marginsSize } from '../../UI/Grid'; import Text from '../../UI/Text'; import { type UnsavedChanges } from '../../MainFrame/UnsavedChangesContext'; -import ScrollView from '../../UI/ScrollView'; +import ScrollView, { type ScrollViewInterface } from '../../UI/ScrollView'; import EventsRootVariablesFinder from '../../Utils/EventsRootVariablesFinder'; import VariablesList, { type HistoryHandler, @@ -95,7 +95,7 @@ const CompactInstancePropertiesEditor = ({ onSelectTileMapTile, }: Props) => { const forceUpdate = useForceUpdate(); - + const scrollViewRef = React.useRef(null); const instance = instances[0]; /** * TODO: multiple instances support for variables list. Expected behavior should be: @@ -105,6 +105,12 @@ const CompactInstancePropertiesEditor = ({ */ const shouldDisplayVariablesList = instances.length === 1; + const onScrollY = React.useCallback(deltaY => { + if (scrollViewRef.current) { + scrollViewRef.current.scrollBy(deltaY); + } + }, []); + const { object, instanceSchema } = React.useMemo<{| object?: gdObject, instanceSchema?: Schema, @@ -220,6 +226,7 @@ const CompactInstancePropertiesEditor = ({ scope="scene-editor-instance-properties" > diff --git a/newIDE/app/src/InstancesEditor/TileSetVisualizer.js b/newIDE/app/src/InstancesEditor/TileSetVisualizer.js index ec916ad0a817..758837c7acc1 100644 --- a/newIDE/app/src/InstancesEditor/TileSetVisualizer.js +++ b/newIDE/app/src/InstancesEditor/TileSetVisualizer.js @@ -30,6 +30,7 @@ const styles = { position: 'relative', display: 'flex', overflow: 'auto', + touchAction: 'none', }, atlasImage: { flex: 1, imageRendering: 'pixelated' }, icon: { fontSize: 18 }, @@ -217,6 +218,7 @@ type Props = {| e: SyntheticEvent, atlasResourceName: string ) => void, + onScrollY: number => void, |}; const TileSetVisualizer = ({ @@ -229,6 +231,7 @@ const TileSetVisualizer = ({ showPaintingToolbar, interactive, onAtlasImageLoaded, + onScrollY, }: Props) => { const forceUpdate = useForceUpdate(); const atlasResourceName = objectConfiguration @@ -278,9 +281,7 @@ const TileSetVisualizer = ({ x: number, y: number, |}>(null); - const [shouldCancelClick, setShouldCancelClick] = React.useState( - false - ); + const [isLongTouch, setIsLongTouch] = React.useState(false); const tooltipDisplayTimeoutId = React.useRef(null); const [ rectangularSelectionTilePreview, @@ -316,7 +317,6 @@ const TileSetVisualizer = ({ const displayTileIdTooltip = React.useCallback( (e: ClientCoordinates) => { - setShouldCancelClick(true); if (!displayedTileSize || isBadlyConfigured) return; const imageCoordinates = getImageCoordinatesFromPointerEvent(e); @@ -341,7 +341,15 @@ const TileSetVisualizer = ({ [displayedTileSize, columnCount, rowCount, isBadlyConfigured] ); - const longTouchProps = useLongTouch(displayTileIdTooltip); + const handleLongTouch = React.useCallback( + (e: ClientCoordinates) => { + setIsLongTouch(true); + displayTileIdTooltip(e); + }, + [displayTileIdTooltip] + ); + + const longTouchProps = useLongTouch(handleLongTouch, {doNotCancelOnScroll: true}); React.useEffect( () => { @@ -356,7 +364,12 @@ const TileSetVisualizer = ({ (event: PointerEvent) => { if (isBadlyConfigured) return; if (event.pointerType === 'touch') { - setTouchStartCoordinates({ x: event.pageX, y: event.pageY }); + const coordinates = getImageCoordinatesFromPointerEvent(event); + if (!coordinates) return; + setTouchStartCoordinates({ + x: coordinates.mouseX, + y: coordinates.mouseY, + }); } const imageCoordinates = getImageCoordinatesFromPointerEvent(event); if (!imageCoordinates) return; @@ -374,11 +387,33 @@ const TileSetVisualizer = ({ isBadlyConfigured || !clickStartCoordinates || !displayedTileSize || - (!allowMultipleSelection && !allowRectangleSelection) || - event.pointerType === 'touch' + (!allowMultipleSelection && !allowRectangleSelection) ) { return; } + + let startCoordinates = clickStartCoordinates; + + const isTouchDevice = event.pointerType === 'touch'; + + if (isTouchDevice) { + if (!touchStartCoordinates) return; + + if (isLongTouch) { + startCoordinates = touchStartCoordinates; + } else { + const coordinates = getImageCoordinatesFromPointerEvent(event); + if (!coordinates) return; + if (tilesetContainerRef.current) { + const deltaY = -event.movementY; + const deltaX = + touchStartCoordinates.x - coordinates.mouseXWithoutScrollLeft; + tilesetContainerRef.current.scrollLeft = deltaX; + onScrollY(deltaY); + } + return; + } + } const imageCoordinates = getImageCoordinatesFromPointerEvent(event); if (!imageCoordinates) return; @@ -389,10 +424,11 @@ const TileSetVisualizer = ({ rowCount, displayedTileSize, }); + const { x: startX, y: startY } = getGridCoordinatesFromPointerCoordinates( { - pointerX: clickStartCoordinates.x, - pointerY: clickStartCoordinates.y, + pointerX: startCoordinates.x, + pointerY: startCoordinates.y, columnCount, rowCount, displayedTileSize, @@ -416,6 +452,9 @@ const TileSetVisualizer = ({ allowMultipleSelection, allowRectangleSelection, clickStartCoordinates, + isLongTouch, + touchStartCoordinates, + onScrollY, ] ); @@ -423,21 +462,15 @@ const TileSetVisualizer = ({ (event: PointerEvent) => { try { if (!displayedTileSize || isBadlyConfigured) return; - if (shouldCancelClick) { - setShouldCancelClick(false); - return; - } - let isTouchDevice = false; + const isTouchDevice = event.pointerType === 'touch'; + let startCoordinates = clickStartCoordinates; - if (event.pointerType === 'touch') { - isTouchDevice = true; - if ( - !touchStartCoordinates || - Math.abs(event.pageX - touchStartCoordinates.x) > 30 || - Math.abs(event.pageY - touchStartCoordinates.y) > 30 - ) { + if (isTouchDevice) { + if (!isLongTouch || !touchStartCoordinates) { return; + } else { + startCoordinates = touchStartCoordinates; } } @@ -451,14 +484,14 @@ const TileSetVisualizer = ({ rowCount, displayedTileSize, }); - if (!clickStartCoordinates) return; + if (!startCoordinates) return; const { x: startX, y: startY, } = getGridCoordinatesFromPointerCoordinates({ - pointerX: clickStartCoordinates.x, - pointerY: clickStartCoordinates.y, + pointerX: startCoordinates.x, + pointerY: startCoordinates.y, columnCount, rowCount, displayedTileSize, @@ -525,6 +558,7 @@ const TileSetVisualizer = ({ setClickStartCoordinates(null); setRectangularSelectionTilePreview(null); setTouchStartCoordinates(null); + setIsLongTouch(false); } }, [ @@ -539,7 +573,7 @@ const TileSetVisualizer = ({ allowMultipleSelection, allowRectangleSelection, clickStartCoordinates, - shouldCancelClick, + isLongTouch, touchStartCoordinates, ] );