[WIP] Add PointsEditor to edit the points of a Sprite in newIDE

This commit is contained in:
Florian Rival
2017-11-15 01:25:48 +01:00
parent 98d970de30
commit 5ef703eff4
6 changed files with 401 additions and 2 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>
);
}
}

View File

@@ -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>
);
}
}

View File

@@ -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,
},
};

View File

@@ -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)