mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
[WIP] Add PointsEditor to edit the points of a Sprite in newIDE
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
import Add from 'material-ui/svg-icons/content/add';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import styles from './styles';
|
||||
|
||||
const AddLayerRow = ({ onAdd }) => (
|
||||
<TableRow>
|
||||
<TableRowColumn style={styles.handleColumn} />
|
||||
<TableRowColumn />
|
||||
<TableRowColumn style={styles.coordinateColumn} />
|
||||
<TableRowColumn style={styles.coordinateColumn} />
|
||||
<TableRowColumn style={styles.toolColumn}>
|
||||
<IconButton onTouchTap={onAdd}>
|
||||
<Add />
|
||||
</IconButton>
|
||||
</TableRowColumn>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
export default AddLayerRow;
|
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import { TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import Delete from 'material-ui/svg-icons/action/delete';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import DragHandle from '../../../../UI/DragHandle';
|
||||
import styles from './styles';
|
||||
|
||||
const PointRow = ({
|
||||
pointName,
|
||||
nameError,
|
||||
onBlur,
|
||||
onRemove,
|
||||
pointX,
|
||||
pointY,
|
||||
onChangePointX,
|
||||
onChangePointY,
|
||||
}) => (
|
||||
<TableRow
|
||||
style={{
|
||||
/* TODO */
|
||||
backgroundColor: 'white',
|
||||
}}
|
||||
>
|
||||
<TableRowColumn style={styles.handleColumn}>
|
||||
<DragHandle />
|
||||
</TableRowColumn>
|
||||
<TableRowColumn>
|
||||
<TextField
|
||||
defaultValue={pointName || 'Base layer'}
|
||||
id={pointName}
|
||||
fullWidth
|
||||
errorText={nameError ? 'This name is already taken' : undefined}
|
||||
disabled={!onBlur}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
<TableRowColumn style={styles.coordinateColumn}>
|
||||
<TextField
|
||||
value={pointX}
|
||||
id="point-x"
|
||||
onChange={(e, value) =>
|
||||
onChangePointX(parseFloat(value, 10))}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
<TableRowColumn style={styles.coordinateColumn}>
|
||||
<TextField
|
||||
value={pointY}
|
||||
id="point-y"
|
||||
onChange={(e, value) =>
|
||||
onChangePointY(parseFloat(value, 10))}
|
||||
/>
|
||||
</TableRowColumn>
|
||||
<TableRowColumn style={styles.toolColumn}>
|
||||
{!!onRemove && (
|
||||
<IconButton onTouchTap={onRemove}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
)}
|
||||
</TableRowColumn>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
export default PointRow;
|
@@ -0,0 +1,189 @@
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHeader,
|
||||
TableHeaderColumn,
|
||||
TableRow,
|
||||
TableRowColumn,
|
||||
} from 'material-ui/Table';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
import newNameGenerator from '../../../../Utils/NewNameGenerator';
|
||||
import styles from './styles';
|
||||
import PointRow from './PointRow';
|
||||
import AddPointRow from './AddPointRow';
|
||||
|
||||
const SortableAddPointRow = SortableElement(AddPointRow);
|
||||
const SortablePointRow = SortableElement(PointRow);
|
||||
|
||||
class PointsListBody extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
nameErrors: {},
|
||||
};
|
||||
}
|
||||
|
||||
updateOriginPointX = (newValue) => {
|
||||
this.props.pointsContainer.getOrigin().setX(newValue);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
updateOriginPointY = (newValue) => {
|
||||
this.props.pointsContainer.getOrigin().setY(newValue);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
updateCenterPointX = (newValue) => {
|
||||
this.props.pointsContainer.getCenter().setX(newValue);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
updateCenterPointY = (newValue) => {
|
||||
this.props.pointsContainer.getCenter().setY(newValue);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { pointsContainer } = this.props;
|
||||
|
||||
const pointsRows = [];
|
||||
// const pointsCount = pointsContainer.getPointsCount();
|
||||
// const pointsRows = mapReverseFor(0, pointsCount, i => {
|
||||
// const point = pointsContainer.getPointAt(i);
|
||||
// const pointName = point.getName();
|
||||
|
||||
// return (
|
||||
// <SortablePointRow
|
||||
// index={i}
|
||||
// key={'point-' + pointName}
|
||||
// pointX={point.getX()}
|
||||
// pointY={point.getY()}
|
||||
// pointName={pointName}
|
||||
// nameError={this.state.nameErrors[pointName]}
|
||||
// onBlur={event => {
|
||||
// const newName = event.target.value;
|
||||
// if (pointName === newName) return;
|
||||
|
||||
// let success = true;
|
||||
// if (pointsContainer.hasPointNamed(newName)) {
|
||||
// success = false;
|
||||
// } else {
|
||||
// point.setName(newName);
|
||||
// }
|
||||
|
||||
// this.setState({
|
||||
// nameErrors: {
|
||||
// ...this.state.nameErrors,
|
||||
// [pointName]: !success,
|
||||
// },
|
||||
// });
|
||||
// }}
|
||||
// onRemove={() => {
|
||||
// //eslint-disable-next-line
|
||||
// const answer = confirm(
|
||||
// "Are you sure you want to remove this point? This can't be undone."
|
||||
// );
|
||||
// if (!answer) return;
|
||||
|
||||
// pointsContainer.delPoint(pointName);
|
||||
// this.forceUpdate();
|
||||
// }}
|
||||
// />
|
||||
// );
|
||||
// });
|
||||
|
||||
const originPoint = pointsContainer.getOrigin();
|
||||
const centerPoint = pointsContainer.getCenter();
|
||||
|
||||
const originRow = (
|
||||
<SortablePointRow
|
||||
index={0}
|
||||
key={'origin-point-row'}
|
||||
pointName="Origin"
|
||||
pointX={originPoint.getX()}
|
||||
pointY={originPoint.getY()}
|
||||
onChangePointX={this.updateOriginPointX}
|
||||
onChangePointY={this.updateOriginPointY}
|
||||
disabled
|
||||
/>
|
||||
);
|
||||
const centerRow = (
|
||||
<SortablePointRow
|
||||
index={1}
|
||||
key={'center-point-row'}
|
||||
pointName="Center"
|
||||
pointX={centerPoint.getX()}
|
||||
pointY={centerPoint.getY()}
|
||||
onChangePointX={this.updateCenterPointX}
|
||||
onChangePointY={this.updateCenterPointY}
|
||||
disabled
|
||||
/>
|
||||
);
|
||||
|
||||
const addRow = (
|
||||
<SortableAddPointRow
|
||||
key={'add-point-row'}
|
||||
disabled
|
||||
onAdd={() => {
|
||||
const name = newNameGenerator('Point', name =>
|
||||
pointsContainer.hasPoint(name)
|
||||
);
|
||||
throw new Error('Unimplemented: add point');
|
||||
// pointsContainer.insertNewPoint(
|
||||
// name,
|
||||
// pointsContainer.getPointsCount()
|
||||
// );
|
||||
// this.forceUpdate();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<TableBody
|
||||
displayRowCheckbox={false}
|
||||
deselectOnClickaway={true}
|
||||
showRowHover={true}
|
||||
>
|
||||
{[originRow, centerRow, ...pointsRows, addRow]}
|
||||
</TableBody>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SortablePointsListBody = SortableContainer(PointsListBody);
|
||||
SortablePointsListBody.muiName = 'TableBody';
|
||||
|
||||
export default class PointsList extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Table selectable={false}>
|
||||
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
|
||||
<TableRow>
|
||||
<TableHeaderColumn style={styles.handleColumn} />
|
||||
<TableHeaderColumn>Point name</TableHeaderColumn>
|
||||
<TableHeaderColumn style={styles.coordinateColumn}>
|
||||
X
|
||||
</TableHeaderColumn>
|
||||
<TableHeaderColumn style={styles.coordinateColumn}>
|
||||
Y
|
||||
</TableHeaderColumn>
|
||||
<TableRowColumn style={styles.toolColumn} />
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<SortablePointsListBody
|
||||
pointsContainer={this.props.pointsContainer}
|
||||
onSortEnd={({ oldIndex, newIndex }) => {
|
||||
//TODO
|
||||
// const pointsCount = this.props.pointsContainer.getPointsCount();
|
||||
// this.props.pointsContainer.movePoint(oldIndex, newIndex);
|
||||
// this.forceUpdate();
|
||||
}}
|
||||
helperClass="sortable-helper"
|
||||
useDragHandle
|
||||
lockToContainerEdges
|
||||
/>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
import React, { Component } from 'react';
|
||||
import SelectField from 'material-ui/SelectField';
|
||||
import MenuItem from 'material-ui/MenuItem';
|
||||
import EmptyMessage from '../../../../UI/EmptyMessage';
|
||||
import { Line, Column } from '../../../../UI/Grid';
|
||||
import { mapFor } from '../../../../Utils/MapFor';
|
||||
import PointsList from './PointsList';
|
||||
const gd = global.gd;
|
||||
|
||||
export default class PointsEditor extends Component {
|
||||
state = {
|
||||
animationIndex: 0,
|
||||
directionIndex: 0,
|
||||
spriteIndex: 0,
|
||||
};
|
||||
|
||||
chooseAnimation = index => {
|
||||
this.setState({
|
||||
animationIndex: index,
|
||||
directionIndex: 0,
|
||||
spriteIndex: 0,
|
||||
});
|
||||
};
|
||||
|
||||
chooseDirection = index => {
|
||||
this.setState({
|
||||
directionIndex: index,
|
||||
spriteIndex: 0,
|
||||
});
|
||||
};
|
||||
|
||||
chooseSprite = index => {
|
||||
this.setState({
|
||||
spriteIndex: index,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { object } = this.props;
|
||||
const { animationIndex, directionIndex, spriteIndex } = this.state;
|
||||
const spriteObject = gd.asSpriteObject(object);
|
||||
|
||||
if (!object.getAnimationsCount()) return null;
|
||||
const hasValidAnimation = animationIndex < object.getAnimationsCount();
|
||||
const animation = hasValidAnimation
|
||||
? object.getAnimation(animationIndex)
|
||||
: null;
|
||||
const hasValidDirection =
|
||||
!!animation && directionIndex < animation.getDirectionsCount();
|
||||
const direction = hasValidDirection
|
||||
? animation.getDirection(directionIndex)
|
||||
: null;
|
||||
const hasValidSprite =
|
||||
!!direction && spriteIndex < direction.getSpritesCount();
|
||||
const sprite = hasValidSprite ? direction.getSprite(spriteIndex) : null;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Line>
|
||||
<SelectField
|
||||
floatingLabelText="Animation"
|
||||
value={this.state.animationIndex}
|
||||
onChange={(e, i, value) => this.chooseAnimation(value)}
|
||||
>
|
||||
{mapFor(0, spriteObject.getAnimationsCount(), i => {
|
||||
const animation = spriteObject.getAnimation(i);
|
||||
return (
|
||||
<MenuItem
|
||||
value={i}
|
||||
primaryText={`Animation #${i} ${animation.getName()}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</SelectField>
|
||||
{hasValidAnimation &&
|
||||
animation.getDirectionsCount() > 1 && (
|
||||
<SelectField
|
||||
floatingLabelText="Direction"
|
||||
value={this.state.directionIndex}
|
||||
onChange={(e, i, value) => this.chooseDirection(value)}
|
||||
>
|
||||
{mapFor(0, animation.getDirectionsCount(), i => {
|
||||
return <MenuItem value={i} primaryText={`Direction #${i}`} />;
|
||||
})}
|
||||
</SelectField>
|
||||
)}
|
||||
{hasValidDirection && (
|
||||
<SelectField
|
||||
floatingLabelText="Frame"
|
||||
value={this.state.spriteIndex}
|
||||
onChange={(e, i, value) => this.chooseSprite(value)}
|
||||
>
|
||||
{mapFor(0, direction.getSpritesCount(), i => {
|
||||
return <MenuItem value={i} primaryText={`Frame #${i}`} />;
|
||||
})}
|
||||
</SelectField>
|
||||
)}
|
||||
</Line>
|
||||
<Line>
|
||||
{!!sprite && <PointsList pointsContainer={sprite} />}
|
||||
{!sprite && <EmptyMessage>Choose an animation and frame to edit the points</EmptyMessage>}
|
||||
</Line>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
//TODO: Factor with styles.js from LayersList.
|
||||
export default {
|
||||
handleColumn: {
|
||||
width: 24,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 0,
|
||||
},
|
||||
coordinateColumn: {
|
||||
width: 48,
|
||||
},
|
||||
toolColumn: {
|
||||
width: 48,
|
||||
},
|
||||
};
|
@@ -19,6 +19,7 @@ import TextEditor from '../ObjectEditor/Editors/TextEditor';
|
||||
import TiledSpriteEditor from '../ObjectEditor/Editors/TiledSpriteEditor';
|
||||
import PanelSpriteEditor from '../ObjectEditor/Editors/PanelSpriteEditor';
|
||||
import SpriteEditor from '../ObjectEditor/Editors/SpriteEditor';
|
||||
import PointsEditor from '../ObjectEditor/Editors/SpriteEditor/PointsEditor';
|
||||
import EmptyEditor from '../ObjectEditor/Editors/EmptyEditor';
|
||||
import ShapePainterEditor from '../ObjectEditor/Editors/ShapePainterEditor';
|
||||
import AdMobEditor from '../ObjectEditor/Editors/AdMobEditor';
|
||||
@@ -220,13 +221,17 @@ storiesOf('PanelSpriteEditor', module)
|
||||
</SerializedObjectDisplay>
|
||||
));
|
||||
|
||||
storiesOf('SpriteEditor', module)
|
||||
storiesOf('SpriteEditor and related editors', module)
|
||||
.addDecorator(paperDecorator)
|
||||
.addDecorator(muiDecorator)
|
||||
.add('default', () => (
|
||||
.add('SpriteEditor', () => (
|
||||
<SerializedObjectDisplay object={spriteObject}>
|
||||
<SpriteEditor object={spriteObject} project={project} />
|
||||
</SerializedObjectDisplay>
|
||||
)).add('PointsEditor', () => (
|
||||
<SerializedObjectDisplay object={spriteObject}>
|
||||
<PointsEditor object={spriteObject} />
|
||||
</SerializedObjectDisplay>
|
||||
));
|
||||
|
||||
storiesOf('ShapePainterEditor', module)
|
||||
|
Reference in New Issue
Block a user