Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions newIDE/app/src/AiGeneration/AskAiEditorContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { type I18n as I18nType } from '@lingui/core';
import { type MessageDescriptor } from '../Utils/i18n/MessageDescriptor.flow';
import { exceptionallyGuardAgainstDeadObject } from '../Utils/IsNullPtr';
import { I18n } from '@lingui/react';
import { type RenderEditorContainerPropsWithRef } from '../MainFrame/EditorContainers/BaseEditor';
import {
type RenderEditorContainerPropsWithRef,
type SceneEventsOutsideEditorChanges,
type InstancesOutsideEditorChanges,
type ObjectsOutsideEditorChanges,
type ObjectGroupsOutsideEditorChanges,
} from '../MainFrame/EditorContainers/BaseEditor';
type SceneRenamedOutsideEditorChanges,
} from '../EditorFunctions/OutsideEditorChanges';
import { type ObjectWithContext } from '../ObjectsList/EnumerateObjects';
import Paper from '../UI/Paper';
import { AiRequestChat, type AiRequestChatInterface } from './AiRequestChat';
Expand Down Expand Up @@ -152,6 +153,9 @@ type Props = {|
onObjectGroupsModifiedOutsideEditor: (
changes: ObjectGroupsOutsideEditorChanges
) => void,
onSceneRenamedOutsideEditor: (
changes: SceneRenamedOutsideEditorChanges
) => void,
onWillInstallExtension: (extensionNames: Array<string>) => void,
onExtensionInstalled: (extensionNames: Array<string>) => void,
onOpenAskAi: ({|
Expand Down Expand Up @@ -250,6 +254,7 @@ export const AskAiEditor: React.ComponentType<Props> = React.memo<Props>(
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
onWillInstallExtension,
onExtensionInstalled,
onOpenAskAi,
Expand Down Expand Up @@ -916,6 +921,7 @@ export const AskAiEditor: React.ComponentType<Props> = React.memo<Props>(
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
i18n,
onWillInstallExtension,
onExtensionInstalled,
Expand Down Expand Up @@ -1627,6 +1633,7 @@ export const renderAskAiEditorContainer = (
onObjectGroupsModifiedOutsideEditor={
props.onObjectGroupsModifiedOutsideEditor
}
onSceneRenamedOutsideEditor={props.onSceneRenamedOutsideEditor}
onWillInstallExtension={props.onWillInstallExtension}
onExtensionInstalled={props.onExtensionInstalled}
onOpenAskAi={props.onOpenAskAi}
Expand Down
1 change: 1 addition & 0 deletions newIDE/app/src/AiGeneration/AskAiStandAloneForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ export const AskAiStandAloneForm = ({
onInstancesModifiedOutsideEditor: () => {},
onObjectsModifiedOutsideEditor: () => {},
onObjectGroupsModifiedOutsideEditor: () => {},
onSceneRenamedOutsideEditor: () => {},
onWillInstallExtension,
onExtensionInstalled,
isReadyToProcessFunctionCalls: true,
Expand Down
15 changes: 14 additions & 1 deletion newIDE/app/src/AiGeneration/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
type InstancesOutsideEditorChanges,
type ObjectsOutsideEditorChanges,
type ObjectGroupsOutsideEditorChanges,
} from '../MainFrame/EditorContainers/BaseEditor';
type SceneRenamedOutsideEditorChanges,
} from '../EditorFunctions/OutsideEditorChanges';
import {
getAiRequest,
getAiRequestSuggestions,
Expand Down Expand Up @@ -222,6 +223,7 @@ export const useProcessFunctionCalls = ({
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
onWillInstallExtension,
onExtensionInstalled,
isReadyToProcessFunctionCalls,
Expand Down Expand Up @@ -259,6 +261,9 @@ export const useProcessFunctionCalls = ({
onObjectGroupsModifiedOutsideEditor: (
changes: ObjectGroupsOutsideEditorChanges
) => void,
onSceneRenamedOutsideEditor: (
changes: SceneRenamedOutsideEditorChanges
) => void,
onWillInstallExtension: (extensionNames: Array<string>) => void,
onExtensionInstalled: (extensionNames: Array<string>) => void,
isReadyToProcessFunctionCalls: boolean,
Expand Down Expand Up @@ -483,6 +488,7 @@ export const useProcessFunctionCalls = ({
const accumulatedInstancesScenes: Set<gdLayout> = new Set();
const accumulatedObjectsChanges: Map<gdLayout, boolean> = new Map();
const accumulatedObjectGroupsScenes: Set<gdLayout> = new Set();
const accumulatedSceneRenames: Array<SceneRenamedOutsideEditorChanges> = [];
const flushAccumulatedOutsideEditorChanges = () => {
accumulatedSceneEventsChanges.forEach((eventIds, scene) =>
onSceneEventsModifiedOutsideEditor({
Expand All @@ -499,6 +505,9 @@ export const useProcessFunctionCalls = ({
accumulatedObjectGroupsScenes.forEach(scene =>
onObjectGroupsModifiedOutsideEditor({ scene })
);
accumulatedSceneRenames.forEach(changes =>
onSceneRenamedOutsideEditor(changes)
);
};

try {
Expand Down Expand Up @@ -550,6 +559,9 @@ export const useProcessFunctionCalls = ({
onObjectGroupsModifiedOutsideEditor: changes => {
accumulatedObjectGroupsScenes.add(changes.scene);
},
onSceneRenamedOutsideEditor: changes => {
accumulatedSceneRenames.push(changes);
},
ensureExtensionInstalled,
onWillInstallExtension,
onExtensionInstalled,
Expand Down Expand Up @@ -600,6 +612,7 @@ export const useProcessFunctionCalls = ({
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
ensureExtensionInstalled,
onWillInstallExtension,
onExtensionInstalled,
Expand Down
12 changes: 10 additions & 2 deletions newIDE/app/src/EditorFunctions/EditorFunctionCallRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ import {
type RelatedAiRequestLastMessages,
type ResourceSearchAndInstallOptions,
type ResourceSearchAndInstallResult,
type ToolOptions,
} from '.';
import {
type SceneEventsOutsideEditorChanges,
type InstancesOutsideEditorChanges,
type ObjectsOutsideEditorChanges,
type ObjectGroupsOutsideEditorChanges,
type ToolOptions,
} from '.';
type SceneRenamedOutsideEditorChanges,
} from './OutsideEditorChanges';
import PixiResourcesLoader from '../ObjectsRendering/PixiResourcesLoader';
import { type EnsureExtensionInstalledOptions } from '../AiGeneration/UseEnsureExtensionInstalled';

Expand All @@ -48,6 +51,9 @@ type ProcessEditorFunctionCallsOptions = {|
onObjectGroupsModifiedOutsideEditor: (
changes: ObjectGroupsOutsideEditorChanges
) => void,
onSceneRenamedOutsideEditor: (
changes: SceneRenamedOutsideEditorChanges
) => void,
ensureExtensionInstalled: (
options: EnsureExtensionInstalledOptions
) => Promise<void>,
Expand All @@ -73,6 +79,7 @@ export const processEditorFunctionCalls = async ({
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
relatedAiRequestId,
getRelatedAiRequestLastMessages,
ensureExtensionInstalled,
Expand Down Expand Up @@ -187,6 +194,7 @@ export const processEditorFunctionCalls = async ({
onInstancesModifiedOutsideEditor,
onObjectsModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
ensureExtensionInstalled,
onWillInstallExtension,
onExtensionInstalled,
Expand Down
61 changes: 61 additions & 0 deletions newIDE/app/src/EditorFunctions/EditorFunctions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe('editorFunctions', () => {
onInstancesModifiedOutsideEditor: jest.fn(),
onObjectGroupsModifiedOutsideEditor: jest.fn(),
onSceneEventsModifiedOutsideEditor: jest.fn(),
onSceneRenamedOutsideEditor: jest.fn(),
toolOptions: {
includeEventsJson: true,
},
Expand Down Expand Up @@ -2468,5 +2469,65 @@ describe('editorFunctions', () => {
expect(project.getScaleMode()).toBe('nearest');
expect(project.getName()).toBe('My Game');
});

it('renames the scene when setting the "name" property', async () => {
const onSceneRenamedOutsideEditor: JestMockFn<any, any> = jest.fn();
const wasFirstScene = project.getFirstLayout() === 'TestScene';

const result = await editorFunctions.change_scene_properties_layers_effects_groups.launchFunction(
{
...makeFakeLaunchFunctionOptionsWithProject(project),
onSceneRenamedOutsideEditor,
args: {
scene_name: 'TestScene',
changed_properties: [
{ property_name: 'name', new_value: 'GameScene' },
],
},
}
);

expect(result.success).toBe(true);
expect(result.message).toContain(
'Renamed scene "TestScene" to "GameScene"'
);

// The scene is actually renamed in the project.
expect(project.hasLayoutNamed('TestScene')).toBe(false);
expect(project.hasLayoutNamed('GameScene')).toBe(true);
// The kept layout pointer is the same one.
expect(testScene.getName()).toBe('GameScene');
if (wasFirstScene) {
expect(project.getFirstLayout()).toBe('GameScene');
}

// The editor is notified so open tabs can be kept and updated.
expect(onSceneRenamedOutsideEditor).toHaveBeenCalledWith({
oldName: 'TestScene',
newName: 'GameScene',
});
});

it('does nothing when renaming a scene to its current name', async () => {
const onSceneRenamedOutsideEditor: JestMockFn<any, any> = jest.fn();

const result = await editorFunctions.change_scene_properties_layers_effects_groups.launchFunction(
{
...makeFakeLaunchFunctionOptionsWithProject(project),
onSceneRenamedOutsideEditor,
args: {
scene_name: 'TestScene',
changed_properties: [
{ property_name: 'name', new_value: 'TestScene' },
],
},
}
);

expect(result.success).toBe(true);
expect(result.message).toContain('Scene already named "TestScene".');
expect(project.hasLayoutNamed('TestScene')).toBe(true);
expect(onSceneRenamedOutsideEditor).not.toHaveBeenCalled();
});
});
});
24 changes: 24 additions & 0 deletions newIDE/app/src/EditorFunctions/OutsideEditorChanges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// @flow

export type SceneEventsOutsideEditorChanges = {|
scene: gdLayout,
newOrChangedAiGeneratedEventIds: Set<string>,
|};

export type InstancesOutsideEditorChanges = {|
scene: gdLayout,
|};

export type ObjectsOutsideEditorChanges = {|
scene: gdLayout,
isNewObjectTypeUsed: boolean,
|};

export type ObjectGroupsOutsideEditorChanges = {|
scene: gdLayout,
|};

export type SceneRenamedOutsideEditorChanges = {|
oldName: string,
newName: string,
|};
55 changes: 35 additions & 20 deletions newIDE/app/src/EditorFunctions/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// @flow
import * as React from 'react';
import { getInstancesInLayoutForLayer } from '../Utils/Layout';
import {
getInstancesInLayoutForLayer,
renameLayoutInProject,
} from '../Utils/Layout';
import { mapFor, mapVector } from '../Utils/MapFor';
import { SafeExtractor } from '../Utils/SafeExtractor';
import {
Expand Down Expand Up @@ -35,6 +38,13 @@ import {
} from '../ProjectCreation/CreateProject';
import { retryIfFailed } from '../Utils/RetryIfFailed';
import newNameGenerator from '../Utils/NewNameGenerator';
import type {
SceneEventsOutsideEditorChanges,
InstancesOutsideEditorChanges,
ObjectsOutsideEditorChanges,
ObjectGroupsOutsideEditorChanges,
SceneRenamedOutsideEditorChanges,
} from './OutsideEditorChanges';

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring

import { type AssetShortHeader } from '../Utils/GDevelopServices/Asset';
import { type ExampleShortHeader } from '../Utils/GDevelopServices/Example';
import { swapAsset } from '../AssetStore/AssetSwapper';
Expand Down Expand Up @@ -224,24 +234,6 @@ export type EditorCallbacks = {|
|}>,
|};

export type SceneEventsOutsideEditorChanges = {|
scene: gdLayout,
newOrChangedAiGeneratedEventIds: Set<string>,
|};

export type InstancesOutsideEditorChanges = {|
scene: gdLayout,
|};

export type ObjectsOutsideEditorChanges = {|
scene: gdLayout,
isNewObjectTypeUsed: boolean,
|};

export type ObjectGroupsOutsideEditorChanges = {|
scene: gdLayout,
|};

export type ToolOptions = {
includeEventsJson?: boolean,
...
Expand Down Expand Up @@ -286,6 +278,9 @@ type LaunchFunctionOptionsWithoutProject = {|
onObjectGroupsModifiedOutsideEditor: (
changes: ObjectGroupsOutsideEditorChanges
) => void,
onSceneRenamedOutsideEditor: (
changes: SceneRenamedOutsideEditorChanges
) => void,
ensureExtensionInstalled: (
options: EnsureExtensionInstalledOptions
) => Promise<void>,
Expand Down Expand Up @@ -4775,6 +4770,7 @@ const inspectScenePropertiesLayersEffects: EditorFunction = {
success: true,
propertiesLayersEffectsForSceneNamed: scene.getName(),
properties: {
name: scene.getName(),
backgroundColor: rgbColorToHex(
scene.getBackgroundColorRed(),
scene.getBackgroundColorGreen(),
Expand Down Expand Up @@ -4930,6 +4926,7 @@ const changeScenePropertiesLayersEffectsGroups: EditorFunction = {
args,
onInstancesModifiedOutsideEditor,
onObjectGroupsModifiedOutsideEditor,
onSceneRenamedOutsideEditor,
}) => {
const scene_name = extractRequiredString(args, 'scene_name');

Expand Down Expand Up @@ -4977,7 +4974,25 @@ const changeScenePropertiesLayersEffectsGroups: EditorFunction = {
return;
}

if (isFuzzyMatch(propertyName, 'backgroundColor')) {
if (isFuzzyMatch(propertyName, 'name')) {
const oldName = scene.getName();
if (newValue === oldName) {
changes.push(`Scene already named "${newValue}".`);
return;
}

const newSceneName = newNameGenerator(
gd.Project.getSafeName(newValue),
tentativeNewName => project.hasLayoutNamed(tentativeNewName)
);

renameLayoutInProject(project, oldName, newSceneName);
onSceneRenamedOutsideEditor({ oldName, newName: newSceneName });

changes.push(
`Renamed scene "${oldName}" to "${newSceneName}" (events and references updated).`
);
} else if (isFuzzyMatch(propertyName, 'backgroundColor')) {
const colorAsRgb = hexNumberToRGBArray(rgbOrHexToHexNumber(newValue));
scene.setBackgroundColor(colorAsRgb[0], colorAsRgb[1], colorAsRgb[2]);
changes.push(
Expand Down
Loading
Loading