mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Add support for dragging points in PointsPreview
This commit is contained in:
1
newIDE/app/flow-typed/libGD.js
vendored
1
newIDE/app/flow-typed/libGD.js
vendored
@@ -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;
|
||||||
|
@@ -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);
|
||||||
|
@@ -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>
|
||||||
|
@@ -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>
|
||||||
);
|
);
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user