Handle undo and redo.

This commit is contained in:
Davy Hélard
2025-07-18 18:20:41 +02:00
parent 3762ccf639
commit e030adbb72
4 changed files with 137 additions and 0 deletions

View File

@@ -30,6 +30,8 @@ namespace gdjs {
const Q_KEY = 81;
const E_KEY = 69;
const F_KEY = 70;
const Y_KEY = 90;
const Z_KEY = 90;
let hasWindowFocus = true;
if (typeof window !== 'undefined') {
@@ -111,6 +113,22 @@ namespace gdjs {
);
};
const isControlPressedOnly = (inputManager: gdjs.InputManager) => {
return (
isControlOrCmdPressed(inputManager) &&
!isShiftPressed(inputManager) &&
!isAltPressed(inputManager)
);
};
const isControlPlusShiftPressedOnly = (inputManager: gdjs.InputManager) => {
return (
isControlOrCmdPressed(inputManager) &&
isShiftPressed(inputManager) &&
!isAltPressed(inputManager)
);
};
const isSpacePressed = (inputManager: gdjs.InputManager) =>
inputManager.isKeyPressed(SPACE_KEY);
@@ -436,6 +454,10 @@ namespace gdjs {
this._editorId = editorId;
}
getEditedInstanceDataList(): InstanceData[] {
return this._editedInstanceDataList;
}
setEditedInstanceDataList(editedInstanceDataList: InstanceData[]) {
this._editedInstanceDataList = editedInstanceDataList;
}
@@ -1502,6 +1524,34 @@ namespace gdjs {
debuggerClient.sendOpenContextMenu(cursorX, cursorY);
}
private _handleShortcuts() {
const inputManager = this._runtimeGame.getInputManager();
if (isControlPressedOnly(inputManager)) {
if (inputManager.wasKeyReleased(Z_KEY)) {
this._sendUndo();
} else if (inputManager.wasKeyReleased(Y_KEY)) {
this._sendRedo();
}
}
if (isControlPlusShiftPressedOnly(inputManager)) {
if (inputManager.wasKeyReleased(Z_KEY)) {
this._sendRedo();
}
}
}
private _sendUndo() {
const debuggerClient = this._runtimeGame._debuggerClient;
if (!debuggerClient) return;
debuggerClient.sendUndo();
}
private _sendRedo() {
const debuggerClient = this._runtimeGame._debuggerClient;
if (!debuggerClient) return;
debuggerClient.sendRedo();
}
cancelDragNewInstance() {
const editedInstanceContainer = this._getEditedInstanceContainer();
if (!editedInstanceContainer) return;
@@ -1932,6 +1982,7 @@ namespace gdjs {
this._updateSelectionControls();
this._updateInnerAreaOutline();
this._handleContextMenu();
this._handleShortcuts();
this._wasMovingSelectionLastFrame =
!!this._selectionControlsMovementTotalDelta;
if (!this._selectionControlsMovementTotalDelta) {

View File

@@ -298,6 +298,18 @@ namespace gdjs {
);
}
}
} else if (data.command === 'hotReloadAllInstances') {
if (runtimeGame._inGameEditor) {
const editedInstanceContainer =
runtimeGame._inGameEditor._getEditedInstanceContainer();
if (editedInstanceContainer) {
that._hotReloader.hotReloadRuntimeInstances(
runtimeGame._inGameEditor.getEditedInstanceDataList(),
data.payload.instances,
editedInstanceContainer
);
}
}
} else if (data.command === 'switchForInGameEdition') {
if (!this._runtimegame.isInGameEdition()) return;
@@ -738,6 +750,34 @@ namespace gdjs {
);
}
sendUndo(): void {
const inGameEditor = this._runtimegame._inGameEditor;
if (!inGameEditor) {
return;
}
this._sendMessage(
circularSafeStringify({
command: 'undo',
editorId: inGameEditor.getEditorId(),
payload: {},
})
);
}
sendRedo(): void {
const inGameEditor = this._runtimegame._inGameEditor;
if (!inGameEditor) {
return;
}
this._sendMessage(
circularSafeStringify({
command: 'redo',
editorId: inGameEditor.getEditorId(),
payload: {},
})
);
}
/**
* Send profiling results.
* @param framesAverageMeasures The measures made for each frames.

View File

@@ -1451,6 +1451,28 @@ namespace gdjs {
}
}
hotReloadRuntimeInstances(
oldInstances: InstanceData[],
newInstances: InstanceData[],
runtimeInstanceContainer: RuntimeInstanceContainer
): void {
const projectData: ProjectData = gdjs.projectData;
const objects: Array<ObjectData> = [];
runtimeInstanceContainer._objects.values(objects);
projectData.layouts;
this._hotReloadRuntimeSceneInstances(
projectData,
projectData,
[],
objects,
objects,
oldInstances,
newInstances,
runtimeInstanceContainer
);
gdjs.copyArray(oldInstances, newInstances);
}
_hotReloadRuntimeSceneInstances(
oldProjectData: ProjectData,
newProjectData: ProjectData,

View File

@@ -307,6 +307,14 @@ export default class SceneEditor extends React.Component<Props, State> {
parsedMessage.payload.cursorX,
parsedMessage.payload.cursorY
);
} else if (parsedMessage.command === 'undo') {
if (canUndo(this.state.history)) {
this.undo();
}
} else if (parsedMessage.command === 'redo') {
if (canRedo(this.state.history)) {
this.redo();
}
}
},
}
@@ -782,6 +790,7 @@ export default class SceneEditor extends React.Component<Props, State> {
if (this.editorDisplay)
this.editorDisplay.instancesHandlers.forceRemountInstancesRenderers();
this.updateToolbar();
this._sendHotReloadAllInstances();
}
);
};
@@ -798,10 +807,25 @@ export default class SceneEditor extends React.Component<Props, State> {
if (this.editorDisplay)
this.editorDisplay.instancesHandlers.forceRemountInstancesRenderers();
this.updateToolbar();
this._sendHotReloadAllInstances();
}
);
};
_sendHotReloadAllInstances = () => {
const { previewDebuggerServer } = this.props;
if (!previewDebuggerServer) return;
previewDebuggerServer.getExistingDebuggerIds().forEach(debuggerId => {
previewDebuggerServer.sendMessage(debuggerId, {
command: 'hotReloadAllInstances',
payload: {
instances: serializeToJSObject(this.props.initialInstances),
},
});
});
};
_onObjectFolderOrObjectWithContextSelected = (
objectFolderOrObjectWithContext: ?ObjectFolderOrObjectWithContext = null
) => {