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 gdSprite = EmscriptenObject;
declare type gdDirection = EmscriptenObject; declare type gdDirection = EmscriptenObject;
declare type gdAnimation = EmscriptenObject; declare type gdAnimation = EmscriptenObject;
declare type gdPoint = EmscriptenObject;
declare type gdVectorEventsSearchResult = EmscriptenObject; declare type gdVectorEventsSearchResult = EmscriptenObject;
declare type gdMapStringPropertyDescriptor = EmscriptenObject; declare type gdMapStringPropertyDescriptor = EmscriptenObject;

View File

@@ -20,7 +20,7 @@ type Props = {|
isDefaultBoundingBox: boolean, isDefaultBoundingBox: boolean,
imageWidth: number, imageWidth: number,
imageHeight: number, imageHeight: number,
onVertexMoved: () => void, onPolygonsUpdated: () => void,
|}; |};
type State = {| type State = {|
@@ -36,18 +36,6 @@ export default class CollisionMasksPreview extends React.Component<
draggedVertex: null, draggedVertex: null,
}; };
_onEndDragVertex = () => {
const draggingWasDone = !!this.state.draggedVertex;
this.setState(
{
draggedVertex: null,
},
() => {
if (draggingWasDone) this.props.onVertexMoved();
}
);
};
_onStartDragVertex = (draggedVertex: gdVector2f) => { _onStartDragVertex = (draggedVertex: gdVector2f) => {
if (this.state.draggedVertex) return; 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) => { _onMouseMove = (event: any) => {
const { draggedVertex } = this.state; const { draggedVertex } = this.state;
if (!draggedVertex) return; if (!draggedVertex) return;
var pointOnScreen = this._svg.createSVGPoint(); const pointOnScreen = this._svg.createSVGPoint();
pointOnScreen.x = event.clientX; pointOnScreen.x = event.clientX;
pointOnScreen.y = event.clientY; pointOnScreen.y = event.clientY;
var screenToSvgMatrix = this._svg.getScreenCTM().inverse(); const screenToSvgMatrix = this._svg.getScreenCTM().inverse();
var pointOnSvg = pointOnScreen.matrixTransform(screenToSvgMatrix); const pointOnSvg = pointOnScreen.matrixTransform(screenToSvgMatrix);
draggedVertex.set_x(pointOnSvg.x); draggedVertex.set_x(pointOnSvg.x);
draggedVertex.set_y(pointOnSvg.y); draggedVertex.set_y(pointOnSvg.y);

View File

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

View File

@@ -1,25 +1,114 @@
// @flow
import React from 'react'; import React from 'react';
import { mapVector } from '../../../../Utils/MapFor'; import { mapVector } from '../../../../Utils/MapFor';
const styles = { const styles = {
container: { container: {
position: 'relative', position: 'relative',
width: '100%',
height: '100%',
}, },
}; };
export default class PointsPreview extends React.Component { const pointKindIdentifiers = {
_renderPoint = (name, x, y, imageSrc = undefined) => { 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 ( return (
<img <img
src={imageSrc || 'res/point.png'} src={imageSrc}
style={{ style={{
position: 'absolute', position: 'absolute',
left: x, left: x,
top: y, top: y,
transform: 'translate(-6px, -5px)', transform: 'translate(-6px, -5px)',
cursor: 'move',
}} }}
alt="" alt=""
key={name} 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 { pointsContainer, imageWidth, imageHeight } = this.props;
const nonDefaultPoints = pointsContainer.getAllNonDefaultPoints(); const nonDefaultPoints = pointsContainer.getAllNonDefaultPoints();
const points = mapVector(nonDefaultPoints, (point, i) => 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(); const originPoint = pointsContainer.getOrigin();
@@ -36,19 +131,26 @@ export default class PointsPreview extends React.Component {
const automaticCenterPosition = pointsContainer.isDefaultCenterPoint(); const automaticCenterPosition = pointsContainer.isDefaultCenterPoint();
return ( return (
<div style={styles.container}> <div
style={styles.container}
onMouseMove={this._onMouseMove}
onMouseUp={this._onEndDragPoint}
ref={container => (this._container = container)}
>
{points} {points}
{this._renderPoint( {this._renderPoint(
'Origin', 'Origin',
originPoint.getX(), originPoint.getX(),
originPoint.getY(), originPoint.getY(),
'res/originPoint.png' pointKindIdentifiers.ORIGIN,
originPoint
)} )}
{this._renderPoint( {this._renderPoint(
'Center', 'Center',
!automaticCenterPosition ? centerPoint.getX() : imageWidth / 2, !automaticCenterPosition ? centerPoint.getX() : imageWidth / 2,
!automaticCenterPosition ? centerPoint.getY() : imageHeight / 2, !automaticCenterPosition ? centerPoint.getY() : imageHeight / 2,
'res/centerPoint.png' pointKindIdentifiers.CENTER,
centerPoint
)} )}
</div> </div>
); );

View File

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