mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Enable variables to be re-order with drag'n'drop in VariablesList in newIDE
This commit is contained in:
@@ -139,6 +139,16 @@ void VariablesContainer::Swap(std::size_t firstVariableIndex, std::size_t second
|
||||
variables[firstVariableIndex] = variables[secondVariableIndex];
|
||||
variables[secondVariableIndex] = temp;
|
||||
}
|
||||
|
||||
void VariablesContainer::Move(std::size_t oldIndex, std::size_t newIndex)
|
||||
{
|
||||
if ( oldIndex >= variables.size() || newIndex >= variables.size() )
|
||||
return;
|
||||
|
||||
auto nameAndVariable = variables[oldIndex];
|
||||
variables.erase(variables.begin() + oldIndex);
|
||||
Insert(nameAndVariable.first, nameAndVariable.second, newIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
void VariablesContainer::SerializeTo(SerializerElement & element) const
|
||||
|
@@ -108,6 +108,11 @@ public:
|
||||
* \brief Swap the position of the specified variables.
|
||||
*/
|
||||
void Swap(std::size_t firstVariableIndex, std::size_t secondVariableIndex);
|
||||
|
||||
/**
|
||||
* \brief Move the specified variable at a new position in the list.
|
||||
*/
|
||||
void Move(std::size_t oldIndex, std::size_t newIndex);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@@ -1,9 +1,8 @@
|
||||
export default {
|
||||
handleColumn: {
|
||||
width: 10,
|
||||
width: 24,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 0,
|
||||
marginRight: -8,
|
||||
},
|
||||
visibleColumn: {
|
||||
width: 48,
|
||||
|
@@ -43,7 +43,9 @@ a[href^="ftp://"] {
|
||||
user-drag: auto; /* Technically not supported in Electron yet */
|
||||
}
|
||||
|
||||
|
||||
/* Used for react-sortable-hoc SortableContainer, to make sure the
|
||||
* dragged element is visible (and not hidden behind a drawer for example)
|
||||
*/
|
||||
.sortable-helper {
|
||||
z-index: 9999;
|
||||
}
|
@@ -18,6 +18,7 @@ import ExternalLayoutEditor from '../SceneEditor/ExternalLayoutEditor';
|
||||
import ProjectManager from '../ProjectManager';
|
||||
import LoaderModal from '../UI/LoaderModal';
|
||||
import EditorBar from '../UI/EditorBar';
|
||||
import Window from '../Utils/Window';
|
||||
import defaultTheme from '../UI/Theme/DefaultTheme';
|
||||
import { Tabs, Tab } from '../UI/Tabs';
|
||||
import {
|
||||
@@ -56,7 +57,7 @@ export default class MainFrame extends Component {
|
||||
|
||||
componentWillMount() {
|
||||
if (!this.props.integratedEditor) this.openStartPage();
|
||||
if (this.props.introDialog) this._openIntroDialog(true);
|
||||
if (this.props.introDialog && !Window.isDev()) this._openIntroDialog(true);
|
||||
}
|
||||
|
||||
loadFullProject = (serializedProject, cb) => {
|
||||
|
@@ -1,13 +1,18 @@
|
||||
import React from 'react';
|
||||
import DragHandleIcon from 'material-ui/svg-icons/editor/drag-handle';
|
||||
import { SortableHandle } from 'react-sortable-hoc';
|
||||
|
||||
const styles = {
|
||||
handle: {
|
||||
color: '#BBB',
|
||||
fontSize: 15,
|
||||
cursor: 'move',
|
||||
marginRight: 4,
|
||||
},
|
||||
handleColor: '#DDD',
|
||||
};
|
||||
|
||||
const DragHandle = SortableHandle(() => <span style={styles.handle}>::</span>);
|
||||
const DragHandle = SortableHandle(() => (
|
||||
<span style={styles.handle}>
|
||||
<DragHandleIcon color={styles.handleColor} />
|
||||
</span>
|
||||
));
|
||||
export default DragHandle;
|
||||
|
@@ -1,23 +1,24 @@
|
||||
import React from 'react';
|
||||
|
||||
const styles = {
|
||||
messageStyle: {
|
||||
opacity: 0.4,
|
||||
textAlign: 'center',
|
||||
fontSize: '13px',
|
||||
textShadow: '1px 1px 0px white',
|
||||
},
|
||||
containerStyle: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
},
|
||||
};
|
||||
|
||||
export default props => (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
opacity: 0.4,
|
||||
textAlign: 'center',
|
||||
fontSize: '13px',
|
||||
textShadow: '1px 1px 0px white',
|
||||
}}
|
||||
>
|
||||
<div style={{...styles.containerStyle, ...props.style}}>
|
||||
<span style={styles.messageStyle}>
|
||||
{props.children}
|
||||
</span>
|
||||
</div>
|
||||
|
32
newIDE/app/src/UI/TreeTable/index.js
Normal file
32
newIDE/app/src/UI/TreeTable/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
|
||||
const styles = {
|
||||
row: {
|
||||
display: 'flex',
|
||||
},
|
||||
cell: {
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
}
|
||||
};
|
||||
|
||||
export const TreeTable = props => (
|
||||
<div>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const TreeTableRow = props => (
|
||||
<div style={{...styles.row, ...props.style}}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const TreeTableCell = props => (
|
||||
<div style={{...styles.cell, ...props.style}}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
@@ -1,19 +1,24 @@
|
||||
import React from 'react';
|
||||
import { TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
import { TreeTableRow, TreeTableCell } from '../UI/TreeTable';
|
||||
import Add from 'material-ui/svg-icons/content/add';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import styles from './styles';
|
||||
|
||||
const VariableRow = ({ onAdd }) => (
|
||||
<TableRow key="add-row">
|
||||
<TableRowColumn />
|
||||
<TableRowColumn />
|
||||
<TableRowColumn style={styles.toolColumn}>
|
||||
<TreeTableRow key="add-row">
|
||||
<TreeTableCell />
|
||||
<TreeTableCell>
|
||||
<EmptyMessage style={styles.addVariableMessage}>
|
||||
Click to add a variable:
|
||||
</EmptyMessage>
|
||||
</TreeTableCell>
|
||||
<TreeTableCell style={styles.toolColumn}>
|
||||
<IconButton onTouchTap={onAdd}>
|
||||
<Add />
|
||||
</IconButton>
|
||||
</TableRowColumn>
|
||||
</TableRow>
|
||||
</TreeTableCell>
|
||||
</TreeTableRow>
|
||||
);
|
||||
|
||||
export default VariableRow;
|
||||
|
@@ -1,70 +1,85 @@
|
||||
import React from 'react';
|
||||
import { TableRow, TableRowColumn } from 'material-ui/Table';
|
||||
import { TreeTableRow, TreeTableCell } from '../UI/TreeTable';
|
||||
import DragHandle from '../UI/DragHandle';
|
||||
import Delete from 'material-ui/svg-icons/action/delete';
|
||||
import AddCircle from 'material-ui/svg-icons/content/add-circle';
|
||||
import SubdirectoryArrowRight from 'material-ui/svg-icons/navigation/subdirectory-arrow-right';
|
||||
import TextField from 'material-ui/TextField';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import styles from './styles';
|
||||
|
||||
const Indent = ({width}) => (
|
||||
<div style={{ ...styles.indent, width }}>
|
||||
<SubdirectoryArrowRight color={styles.indentIconColor} />
|
||||
</div>
|
||||
)
|
||||
|
||||
const VariableRow = (
|
||||
{
|
||||
name,
|
||||
variable,
|
||||
depth,
|
||||
index,
|
||||
parentVariable,
|
||||
errorText,
|
||||
onBlur,
|
||||
onRemove,
|
||||
onAddChild,
|
||||
onChangeValue,
|
||||
children,
|
||||
}
|
||||
) => {
|
||||
const isStructure = variable.isStructure();
|
||||
const key = '' + depth + name;
|
||||
|
||||
const columns = [
|
||||
<TableRowColumn
|
||||
<TreeTableCell
|
||||
key="name"
|
||||
style={{ paddingLeft: (depth + 1) * styles.tableChildIndentation }}
|
||||
>
|
||||
{depth > 0 && <Indent width={(depth + 1) * styles.tableChildIndentation} />}
|
||||
{depth === 0 && <DragHandle />}
|
||||
<TextField
|
||||
fullWidth
|
||||
name={key + 'name'}
|
||||
defaultValue={name}
|
||||
errorText={errorText}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
</TableRowColumn>,
|
||||
</TreeTableCell>,
|
||||
];
|
||||
if (!isStructure) {
|
||||
columns.push(
|
||||
<TableRowColumn key="value">
|
||||
<TreeTableCell key="value">
|
||||
<TextField
|
||||
fullWidth
|
||||
name={key + 'value'}
|
||||
value={variable.getString()}
|
||||
onChange={onChangeValue}
|
||||
multiLine
|
||||
/>
|
||||
</TableRowColumn>
|
||||
</TreeTableCell>
|
||||
);
|
||||
} else {
|
||||
columns.push(<TableRowColumn key="value">(Structure)</TableRowColumn>);
|
||||
columns.push(<TreeTableCell key="value">(Structure)</TreeTableCell>);
|
||||
}
|
||||
columns.push(
|
||||
<TableRowColumn key="tools" style={styles.toolColumn}>
|
||||
<TreeTableCell key="tools" style={styles.toolColumn}>
|
||||
<IconButton onTouchTap={onRemove}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
<IconButton onTouchTap={onAddChild}>
|
||||
<AddCircle />
|
||||
</IconButton>
|
||||
</TableRowColumn>
|
||||
</TreeTableCell>
|
||||
);
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
{columns}
|
||||
</TableRow>
|
||||
<div>
|
||||
<TreeTableRow
|
||||
style={styles.variableRow}
|
||||
>
|
||||
{columns}
|
||||
</TreeTableRow>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHeader,
|
||||
TableHeaderColumn,
|
||||
TableRow,
|
||||
@@ -11,9 +10,26 @@ import { mapFor } from '../Utils/MapFor';
|
||||
import newNameGenerator from '../Utils/NewNameGenerator';
|
||||
import VariableRow from './VariableRow';
|
||||
import AddVariableRow from './AddVariableRow';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
import flatten from 'lodash/flatten';
|
||||
const gd = global.gd;
|
||||
|
||||
const SortableVariableRow = SortableElement(VariableRow);
|
||||
const SortableAddVariableRow = SortableElement(AddVariableRow);
|
||||
|
||||
class VariablesListBody extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const SortableVariablesListBody = SortableContainer(VariablesListBody);
|
||||
SortableVariablesListBody.muiName = 'TableBody';
|
||||
|
||||
export default class VariablesList extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -23,18 +39,18 @@ export default class VariablesList extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
_renderVariableChildren(name, parentVariable, depth, index) {
|
||||
_renderVariableChildren(name, parentVariable, depth) {
|
||||
const children = parentVariable.getAllChildren();
|
||||
const names = children.keys().toJSArray();
|
||||
|
||||
return flatten(
|
||||
names.map(name => {
|
||||
names.map((name, index) => {
|
||||
const variable = children.get(name);
|
||||
return this._renderVariableAndChildrenRows(
|
||||
name,
|
||||
variable,
|
||||
depth + 1,
|
||||
undefined,
|
||||
index,
|
||||
parentVariable
|
||||
);
|
||||
})
|
||||
@@ -44,16 +60,15 @@ export default class VariablesList extends Component {
|
||||
_renderVariableAndChildrenRows(name, variable, depth, index, parentVariable) {
|
||||
const { variablesContainer } = this.props;
|
||||
const isStructure = variable.isStructure();
|
||||
const key = '' + depth + name;
|
||||
|
||||
const variableRow = (
|
||||
<VariableRow
|
||||
return (
|
||||
<SortableVariableRow
|
||||
name={name}
|
||||
variable={variable}
|
||||
depth={depth}
|
||||
index={index}
|
||||
key={key}
|
||||
parentVariable={parentVariable}
|
||||
key={'variable-' + name}
|
||||
variable={variable}
|
||||
disabled={depth !== 0}
|
||||
depth={depth}
|
||||
errorText={
|
||||
this.state.nameErrors[variable.ptr]
|
||||
? 'This name is already taken'
|
||||
@@ -95,15 +110,9 @@ export default class VariablesList extends Component {
|
||||
variable.getChild(name).setString('');
|
||||
this.forceUpdate();
|
||||
}}
|
||||
children={isStructure ? this._renderVariableChildren(name, variable, depth) : null}
|
||||
/>
|
||||
);
|
||||
|
||||
return !isStructure
|
||||
? [variableRow]
|
||||
: [
|
||||
variableRow,
|
||||
this._renderVariableChildren(name, variable, depth, index),
|
||||
];
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -129,8 +138,10 @@ export default class VariablesList extends Component {
|
||||
);
|
||||
|
||||
const addRow = (
|
||||
<AddVariableRow
|
||||
<SortableAddVariableRow
|
||||
index={0}
|
||||
key={'add-variable-row'}
|
||||
disabled
|
||||
onAdd={() => {
|
||||
const variable = new gd.Variable();
|
||||
variable.setString('');
|
||||
@@ -153,14 +164,18 @@ export default class VariablesList extends Component {
|
||||
<TableRowColumn />
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody
|
||||
displayRowCheckbox={false}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
<SortableVariablesListBody
|
||||
variablesContainer={this.props.variablesContainer}
|
||||
onSortEnd={({ oldIndex, newIndex }) => {
|
||||
this.props.variablesContainer.move(oldIndex, newIndex);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
helperClass="sortable-helper"
|
||||
useDragHandle
|
||||
lockToContainerEdges
|
||||
>
|
||||
{flatten(containerVariablesTree).concat(addRow)}
|
||||
</TableBody>
|
||||
{containerVariablesTree.concat(addRow)}
|
||||
</SortableVariablesListBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
@@ -1,7 +1,21 @@
|
||||
export default {
|
||||
toolColumn: {
|
||||
width: 192,
|
||||
textAlign: 'right',
|
||||
minWidth: 72,
|
||||
flex: 0,
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
tableChildIndentation: 24,
|
||||
};
|
||||
indent: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
indentIconColor: '#DDD',
|
||||
variableRow: {
|
||||
backgroundColor: 'white',
|
||||
height: 42,
|
||||
},
|
||||
addVariableMessage: {
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
};
|
||||
|
@@ -10,6 +10,7 @@ import StartPage from '../MainFrame/StartPage';
|
||||
import AboutDialog from '../MainFrame/AboutDialog';
|
||||
import LocalCreateDialog from '../ProjectCreation/LocalCreateDialog';
|
||||
import { Tabs, Tab } from '../UI/Tabs';
|
||||
import DragHandle from '../UI/DragHandle';
|
||||
import LocalFolderPicker from '../UI/LocalFolderPicker';
|
||||
import LocalExport from '../Export/LocalExport';
|
||||
import LocalMobileExport from '../Export/LocalMobileExport';
|
||||
@@ -117,4 +118,8 @@ storiesOf('AboutDialog', module)
|
||||
|
||||
storiesOf('LocalCreateDialog', module)
|
||||
.addDecorator(muiDecorator)
|
||||
.add('default', () => <LocalCreateDialog open />);
|
||||
.add('default', () => <LocalCreateDialog open />);
|
||||
|
||||
storiesOf('DragHandle', module)
|
||||
.addDecorator(muiDecorator)
|
||||
.add('default', () => <DragHandle />);
|
Reference in New Issue
Block a user