Add support for dragging points in PointsPreview

This commit is contained in:
Florian Rival
2018-09-05 23:00:46 +01:00
parent a969d85fba
commit b44289dae6
5 changed files with 140 additions and 25 deletions

View File

@@ -37,6 +37,7 @@ declare type gdSpriteObject = EmscriptenObject;
declare type gdSprite = EmscriptenObject;
declare type gdDirection = EmscriptenObject;
declare type gdAnimation = EmscriptenObject;
declare type gdPoint = EmscriptenObject;
declare type gdVectorEventsSearchResult = EmscriptenObject;
declare type gdMapStringPropertyDescriptor = EmscriptenObject;

View File

@@ -20,7 +20,7 @@ type Props = {|
isDefaultBoundingBox: boolean,
imageWidth: number,
imageHeight: number,
onVertexMoved: () => void,
onPolygonsUpdated: () => void,
|};
type State = {|
@@ -36,18 +36,6 @@ export default class CollisionMasksPreview extends React.Component<
draggedVertex: null,
};
_onEndDragVertex = () => {
const draggingWasDone = !!this.state.draggedVertex;
this.setState(
{
draggedVertex: null,
},
() => {
if (draggingWasDone) this.props.onVertexMoved();
}
);
};
_onStartDragVertex = (draggedVertex: gdVector2f) => {
if (this.state.draggedVertex) return;
@@ -56,15 +44,34 @@ export default class CollisionMasksPreview extends React.Component<
});
};
_onEndDragVertex = () => {
const draggingWasDone = !!this.state.draggedVertex;
this.setState(
{
draggedVertex: null,
},
() => {
if (draggingWasDone) this.props.onPolygonsUpdated();
}
);
};
/**
* Move a vertex with the mouse. A similar dragging implementation is done in
* PointsPreview (but with div and img elements).
*
* If custom zoom is added, this should be adapted to properly set vertex coordinates.
* TODO: This could be optimized by avoiding the forceUpdate (not sure if worth it though).
*/
_onMouseMove = (event: any) => {
const { draggedVertex } = this.state;
if (!draggedVertex) return;
var pointOnScreen = this._svg.createSVGPoint();
const pointOnScreen = this._svg.createSVGPoint();
pointOnScreen.x = event.clientX;
pointOnScreen.y = event.clientY;
var screenToSvgMatrix = this._svg.getScreenCTM().inverse();
var pointOnSvg = pointOnScreen.matrixTransform(screenToSvgMatrix);
const screenToSvgMatrix = this._svg.getScreenCTM().inverse();
const pointOnSvg = pointOnScreen.matrixTransform(screenToSvgMatrix);
draggedVertex.set_x(pointOnSvg.x);
draggedVertex.set_y(pointOnSvg.y);

View File

@@ -210,7 +210,7 @@ export default class CollisionMasksEditor extends Component {
<CollisionMasksPreview
isDefaultBoundingBox={sprite.isCollisionMaskAutomatic()}
polygons={sprite.getCustomCollisionMask()}
onVertexMoved={this._updateCollisionMasks}
onPolygonsUpdated={this._updateCollisionMasks}
/>
)}
</ImagePreview>

View File

@@ -1,25 +1,114 @@
// @flow
import React from 'react';
import { mapVector } from '../../../../Utils/MapFor';
const styles = {
container: {
position: 'relative',
width: '100%',
height: '100%',
},
};
export default class PointsPreview extends React.Component {
_renderPoint = (name, x, y, imageSrc = undefined) => {
const pointKindIdentifiers = {
NORMAL: 1,
ORIGIN: 2,
CENTER: 3,
};
type PointKind = 1 | 2 | 3;
type Props = {|
pointsContainer: gdSprite, // Could potentially be generalized to other things than Sprite in the future.
imageWidth: number,
imageHeight: number,
onPointsUpdated: () => void,
|};
type State = {|
draggedPoint: ?gdPoint,
draggedPointKind: ?PointKind,
|};
export default class PointsPreview extends React.Component<Props, State> {
_container: ?any;
state = {
draggedPoint: null,
draggedPointKind: null,
};
_onStartDragPoint = (draggedPoint: gdPoint, draggedPointKind: PointKind) => {
if (this.state.draggedPoint) return;
this.setState({
draggedPoint,
draggedPointKind,
});
};
_onEndDragPoint = () => {
const draggingWasDone = !!this.state.draggedPoint;
this.setState(
{
draggedPoint: null,
draggedPointKind: null,
},
() => {
if (draggingWasDone) this.props.onPointsUpdated();
}
);
};
/**
* Move a point with the mouse. A similar dragging implementation is done in
* CollisionMasksPreview (but with svg elements).
*
* If custom zoom is added, this should be adapted to properly set point coordinates.
* TODO: This could be optimized by avoiding the forceUpdate (not sure if worth it though).
*/
_onMouseMove = (event: any) => {
const { draggedPoint, draggedPointKind } = this.state;
if (!draggedPoint || !this._container) return;
const containerBoundingRect = this._container.getBoundingClientRect();
const xOnContainer = event.clientX - containerBoundingRect.left;
const yOnContainer = event.clientY - containerBoundingRect.top;
if (draggedPointKind === pointKindIdentifiers.CENTER) {
this.props.pointsContainer.setDefaultCenterPoint(false);
}
draggedPoint.setX(xOnContainer);
draggedPoint.setY(yOnContainer);
this.forceUpdate();
};
_renderPoint = (
name: string,
x: number,
y: number,
kind: PointKind,
point: gdPoint
) => {
const imageSrc =
kind === pointKindIdentifiers.ORIGIN
? 'res/originPoint.png'
: kind === pointKindIdentifiers.CENTER
? 'res/centerPoint.png'
: 'res/point.png';
return (
<img
src={imageSrc || 'res/point.png'}
src={imageSrc}
style={{
position: 'absolute',
left: x,
top: y,
transform: 'translate(-6px, -5px)',
cursor: 'move',
}}
alt=""
key={name}
onMouseDown={() => {
this._onStartDragPoint(point, kind);
}}
/>
);
};
@@ -28,7 +117,13 @@ export default class PointsPreview extends React.Component {
const { pointsContainer, imageWidth, imageHeight } = this.props;
const nonDefaultPoints = pointsContainer.getAllNonDefaultPoints();
const points = mapVector(nonDefaultPoints, (point, i) =>
this._renderPoint(point.getName(), point.getX(), point.getY())
this._renderPoint(
point.getName(),
point.getX(),
point.getY(),
pointKindIdentifiers.NORMAL,
point
)
);
const originPoint = pointsContainer.getOrigin();
@@ -36,19 +131,26 @@ export default class PointsPreview extends React.Component {
const automaticCenterPosition = pointsContainer.isDefaultCenterPoint();
return (
<div style={styles.container}>
<div
style={styles.container}
onMouseMove={this._onMouseMove}
onMouseUp={this._onEndDragPoint}
ref={container => (this._container = container)}
>
{points}
{this._renderPoint(
'Origin',
originPoint.getX(),
originPoint.getY(),
'res/originPoint.png'
pointKindIdentifiers.ORIGIN,
originPoint
)}
{this._renderPoint(
'Center',
!automaticCenterPosition ? centerPoint.getX() : imageWidth / 2,
!automaticCenterPosition ? centerPoint.getY() : imageHeight / 2,
'res/centerPoint.png'
pointKindIdentifiers.CENTER,
centerPoint
)}
</div>
);

View File

@@ -170,7 +170,12 @@ export default class PointsEditor extends Component {
resourcesLoader={resourcesLoader}
project={project}
>
{hasValidSprite && <PointsPreview pointsContainer={sprite} />}
{hasValidSprite && (
<PointsPreview
pointsContainer={sprite}
onPointsUpdated={this._updatePoints}
/>
)}
</ImagePreview>
<Line>
<Column expand>