From 78077982bc3ef90188b6b42e632b0d3a11ecba71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Mon, 15 Jun 2026 19:58:41 +0200 Subject: [PATCH 1/9] Allow to add new properties from a variable parameter --- ...EventsBasedBehaviorOrObjectEditorDialog.js | 170 ++++++++++++++++++ .../PropertyListEditor/index.js | 40 ++++- .../EventsFunctionsExtensionEditor/index.js | 112 ++++++++++++ .../src/EventsSheet/InlineParameterEditor.js | 3 + .../InstructionEditorDialog.js | 1 + .../InstructionEditorMenu.js | 1 + .../ParameterFields/AnyVariableField.js | 1 + .../AnyVariableOrPropertyField.js | 2 + .../AnyVariableOrPropertyOrParameterField.js | 2 + .../ParameterFields/GlobalVariableField.js | 1 + .../ParameterFields/ObjectVariableField.js | 1 + .../ParameterFields/ParameterFieldCommons.js | 1 + .../ParameterFields/SceneVariableField.js | 1 + .../ParameterFields/VariableField.js | 56 +++++- newIDE/app/src/EventsSheet/index.js | 6 + .../EditorContainers/EventsEditorContainer.js | 7 +- .../ExternalEventsEditorContainer.js | 3 +- newIDE/app/src/Version/index.js | 8 - .../EventsSheet/EventsSheet.stories.js | 2 + .../src/stories/everything-else.stories.js | 12 ++ 20 files changed, 413 insertions(+), 17 deletions(-) create mode 100644 newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js new file mode 100644 index 000000000000..b373e944e528 --- /dev/null +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js @@ -0,0 +1,170 @@ +// @flow +import { Trans } from '@lingui/macro'; +import * as React from 'react'; +import { type UnsavedChanges } from '../../MainFrame/UnsavedChangesContext'; +import { type ExtensionItemConfigurationAttribute } from '../../EventsFunctionsExtensionEditor'; +import { ProjectScopedContainersAccessor } from '../../InstructionOrExpression/EventsScope'; +import { LineStackLayout } from '../../UI/Layout'; +import { + EventsBasedBehaviorOrObjectEditor, + type EventsBasedBehaviorOrObjectEditorInterface, +} from '.'; +import PropertyListEditor, { + type PropertyListEditorInterface, +} from '../PropertyListEditor'; +import FlatButton from '../../UI/FlatButton'; +import HelpButton from '../../UI/HelpButton'; +import Dialog from '../../UI/Dialog'; +import { type VariableDialogOpeningProps } from '../../VariablesList/VariablesEditorDialog'; + +const styles = { + simpleSizeContainer: { + display: 'flex', + flex: 1, + }, + doubleSizeContainer: { + display: 'flex', + flex: 2, + }, +}; + +type Props = {| + project: gdProject, + projectScopedContainersAccessor: ProjectScopedContainersAccessor, + eventsFunctionsExtension: gdEventsFunctionsExtension, + eventsBasedBehavior?: ?gdEventsBasedBehavior, + eventsBasedObject?: ?gdEventsBasedObject, + onRenameProperty: (oldName: string, newName: string) => void, + onRenameSharedProperty: (oldName: string, newName: string) => void, + onPropertyTypeChanged: (propertyName: string) => void, + onPropertiesUpdated: () => void, + onEventsFunctionsAdded: () => void, + unsavedChanges?: ?UnsavedChanges, + onConfigurationUpdated?: (?ExtensionItemConfigurationAttribute) => void, + onOpenCustomObjectEditor: () => void, + onEventsBasedObjectChildrenEdited: ( + eventsBasedObject: gdEventsBasedObject + ) => void, + onWillInstallExtension: (extensionNames: Array) => void, + onExtensionInstalled: (extensionNames: Array) => void, + onClose: () => void, + initiallySelectedProperty: VariableDialogOpeningProps | null, +|}; + +export default function EventsBasedBehaviorOrObjectEditorDialog({ + eventsBasedBehavior, + eventsBasedObject, + eventsFunctionsExtension, + project, + projectScopedContainersAccessor, + onRenameProperty, + onRenameSharedProperty, + onPropertyTypeChanged, + unsavedChanges, + onEventsFunctionsAdded, + onConfigurationUpdated, + onPropertiesUpdated, + onOpenCustomObjectEditor, + onEventsBasedObjectChildrenEdited, + onWillInstallExtension, + onExtensionInstalled, + onClose, + initiallySelectedProperty, +}: Props): React.Node { + const editor = React.useRef( + null + ); + const propertyList = React.useRef(null); + + return ( + Properties} + secondaryActions={[]} + actions={[ + Close} + primary={false} + onClick={onClose} + id="close-button" + />, + ]} + onRequestClose={onClose} + onApply={onClose} + open + flexBody + fullHeight + id="properties-editor-dialog" + > + +
+ { + if (propertyList.current) { + propertyList.current.forceUpdateList(); + } + onPropertiesUpdated(); + }} + onFocusProperty={(propertyName, isSharedProperties) => { + if (propertyList.current) { + propertyList.current.setSelectedProperty( + propertyName, + isSharedProperties + ); + } + }} + /> +
+
+ { + if (editor.current) { + editor.current.forceUpdateProperties(); + } + onPropertiesUpdated(); + }} + onOpenConfiguration={propertyName => { + if (editor.current) { + editor.current.scrollToConfiguration(); + } + }} + onOpenProperty={(propertyName, isSharedProperties) => { + if (editor.current) { + editor.current.scrollToProperty( + propertyName, + isSharedProperties + ); + } + }} + onEventsFunctionsAdded={onEventsFunctionsAdded} + initiallySelectedProperty={initiallySelectedProperty} + /> +
+
+
+ ); +} diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js index c8ebb46e48b1..4510743f7af5 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js @@ -53,6 +53,7 @@ import { getFoldersAscendanceWithoutRootFolder, enumerateFoldersInContainer, } from './EnumeratePropertyFolderOrProperty'; +import { type VariableDialogOpeningProps } from '../../VariablesList/VariablesEditorDialog'; const configurationItemId = 'events-based-entity-configuration'; export const propertiesRootFolderId = 'properties'; @@ -504,6 +505,7 @@ type Props = {| onOpenConfiguration: () => void, onOpenProperty: (name: string, isSharedProperties: boolean) => void, onEventsFunctionsAdded: () => void, + initiallySelectedProperty: VariableDialogOpeningProps | null, |}; const PropertyListEditor = React.forwardRef( @@ -519,6 +521,7 @@ const PropertyListEditor = React.forwardRef( onOpenConfiguration, onOpenProperty, onEventsFunctionsAdded, + initiallySelectedProperty, }, ref ) => { @@ -600,11 +603,13 @@ const PropertyListEditor = React.forwardRef( properties: gdPropertiesContainer, isSharedProperties: boolean, parentFolder: gdPropertyFolderOrProperty, - index: number + index: number, + name?: string, + type?: string | null ) => { if (!properties) return; - const newName = newNameGenerator('Property', name => + const newName = newNameGenerator(name || 'Property', name => properties.has(name) ); const property = properties.insertNewPropertyInFolder( @@ -612,7 +617,7 @@ const PropertyListEditor = React.forwardRef( parentFolder, index ); - property.setType('Number'); + property.setType(type || 'Number'); onPropertiesUpdated(); @@ -1184,6 +1189,35 @@ const PropertyListEditor = React.forwardRef( }, })); + React.useEffect( + () => { + if (!initiallySelectedProperty || !properties) { + return; + } + if (initiallySelectedProperty.shouldCreate) { + const propertyType = + initiallySelectedProperty.variableType === 'number' + ? 'Number' + : initiallySelectedProperty.variableType === 'string' + ? 'String' + : initiallySelectedProperty.variableType === 'boolean' + ? 'Boolean' + : initiallySelectedProperty.variableType; + addProperty( + properties, + false, + properties.getRootFolder(), + 0, + initiallySelectedProperty.variableName, + propertyType + ); + } else { + setSelectedProperty(initiallySelectedProperty.variableName, false); + } + }, + [addProperty, initiallySelectedProperty, properties, setSelectedProperty] + ); + const canMoveSelectionTo = React.useCallback( (destinationItem: TreeViewItem, where: 'before' | 'inside' | 'after') => selectedItems.every(item => { diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index 12165ca57515..a3a9f18e6d20 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -25,6 +25,7 @@ import { EventsBasedBehaviorOrObjectEditor, type EventsBasedBehaviorOrObjectEditorInterface, } from './EventsBasedBehaviorOrObjectEditor'; +import EventsBasedBehaviorOrObjectEditorDialog from './EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog'; import { type ResourceManagementProps } from '../ResourcesList/ResourceSource'; import BehaviorMethodSelectorDialog from './BehaviorMethodSelectorDialog'; import ObjectMethodSelectorDialog from './ObjectMethodSelectorDialog'; @@ -117,6 +118,7 @@ type State = {| extensionFunctionSelectorDialogOpen: boolean, eventsBasedObjectSelectorDialogOpen: boolean, variablesEditorOpen: { isGlobalTabInitiallyOpen: boolean } | null, + eventsBasedEntityPropertiesDialogOpen: VariableDialogOpeningProps | null, onAddEventsFunctionCb: ?( parameters: ?EventsFunctionCreationParameters ) => void, @@ -158,6 +160,7 @@ export default class EventsFunctionsExtensionEditor extends React.Component< extensionFunctionSelectorDialogOpen: false, eventsBasedObjectSelectorDialogOpen: false, variablesEditorOpen: null, + eventsBasedEntityPropertiesDialogOpen: null, onAddEventsFunctionCb: null, onAddEventsBasedObjectCb: null, }; @@ -1342,6 +1345,12 @@ export default class EventsFunctionsExtensionEditor extends React.Component< this.eventsFunctionConfigurationEditor.editEventsFunctionParameter(props); }; + _editEventsBasedEntityProperty = (props: VariableDialogOpeningProps) => { + this.setState({ + eventsBasedEntityPropertiesDialogOpen: props, + }); + }; + render(): any { const { project, eventsFunctionsExtension } = this.props; @@ -1355,6 +1364,7 @@ export default class EventsFunctionsExtensionEditor extends React.Component< extensionFunctionSelectorDialogOpen, eventsBasedObjectSelectorDialogOpen, variablesEditorOpen, + eventsBasedEntityPropertiesDialogOpen, } = this.state; const scope = { @@ -1495,6 +1505,7 @@ export default class EventsFunctionsExtensionEditor extends React.Component< this.eventsFunctionList.forceUpdateList(); } }} + initiallySelectedProperty={null} /> ) : ( @@ -1563,6 +1574,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component< onWillInstallExtension={this.props.onWillInstallExtension} onExtensionInstalled={this.props.onExtensionInstalled} editEventsFunctionParameter={this._editEventsFunctionParameter} + editEventsBasedEntityProperty={ + this._editEventsBasedEntityProperty + } /> ) : selectedEventsBasedBehavior && @@ -1886,6 +1900,104 @@ export default class EventsFunctionsExtensionEditor extends React.Component< initiallySelectedVariable={null} /> )} + {eventsBasedEntityPropertiesDialogOpen && + this._projectScopedContainersAccessor && + (selectedEventsBasedBehavior ? ( + { + this.setState({ + eventsBasedEntityPropertiesDialogOpen: null, + }); + }} + project={project} + projectScopedContainersAccessor={ + this._projectScopedContainersAccessor + } + eventsFunctionsExtension={eventsFunctionsExtension} + eventsBasedBehavior={selectedEventsBasedBehavior} + unsavedChanges={this.props.unsavedChanges} + onRenameProperty={(oldName, newName) => + this._onBehaviorPropertyRenamed( + selectedEventsBasedBehavior, + oldName, + newName + ) + } + onRenameSharedProperty={(oldName, newName) => + this._onBehaviorSharedPropertyRenamed( + selectedEventsBasedBehavior, + oldName, + newName + ) + } + onPropertyTypeChanged={propertyName => { + gd.WholeProjectRefactorer.changeEventsBasedBehaviorPropertyType( + project, + eventsFunctionsExtension, + selectedEventsBasedBehavior, + propertyName + ); + }} + onPropertiesUpdated={() => {}} + onEventsFunctionsAdded={() => { + if (this.eventsFunctionList) { + this.eventsFunctionList.forceUpdateList(); + } + }} + onConfigurationUpdated={this._onConfigurationUpdated} + onOpenCustomObjectEditor={() => {}} + onEventsBasedObjectChildrenEdited={() => {}} + onWillInstallExtension={this.props.onWillInstallExtension} + onExtensionInstalled={this.props.onExtensionInstalled} + /> + ) : selectedEventsBasedObject ? ( + { + this.setState({ + eventsBasedEntityPropertiesDialogOpen: null, + }); + }} + project={project} + projectScopedContainersAccessor={ + this._projectScopedContainersAccessor + } + eventsFunctionsExtension={eventsFunctionsExtension} + eventsBasedObject={selectedEventsBasedObject} + unsavedChanges={this.props.unsavedChanges} + onRenameProperty={(oldName, newName) => + this._onObjectPropertyRenamed( + selectedEventsBasedObject, + oldName, + newName + ) + } + onRenameSharedProperty={() => {}} + onPropertyTypeChanged={propertyName => { + gd.WholeProjectRefactorer.changeEventsBasedObjectPropertyType( + project, + eventsFunctionsExtension, + selectedEventsBasedObject, + propertyName + ); + }} + onPropertiesUpdated={() => {}} + onEventsFunctionsAdded={() => { + if (this.eventsFunctionList) { + this.eventsFunctionList.forceUpdateList(); + } + }} + onOpenCustomObjectEditor={() => + this.props.onOpenCustomObjectEditor(selectedEventsBasedObject) + } + onEventsBasedObjectChildrenEdited={ + this.props.onEventsBasedObjectChildrenEdited + } + onWillInstallExtension={this.props.onWillInstallExtension} + onExtensionInstalled={this.props.onExtensionInstalled} + /> + ) : null)} {objectMethodSelectorDialogOpen && selectedEventsBasedObject && ( void, + editEventsBasedEntityProperty: VariableDialogOpeningProps => void, |}; const InlineParameterEditor = ({ @@ -60,6 +61,7 @@ const InlineParameterEditor = ({ anchorEl, resourceManagementProps, editEventsFunctionParameter, + editEventsBasedEntityProperty, }: Props): null | React.Node => { const portalContainer = React.useContext(PortalContainerContext); const [ @@ -191,6 +193,7 @@ const InlineParameterEditor = ({ isInline resourceManagementProps={resourceManagementProps} editEventsFunctionParameter={editEventsFunctionParameter} + editEventsBasedEntityProperty={editEventsBasedEntityProperty} /> ); diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js index 13092e982abf..51807fd72db9 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js @@ -81,6 +81,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, + editEventsBasedEntityProperty: VariableDialogOpeningProps => void, |}; const getInitialStepName = (isNewInstruction: boolean): StepName => { diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js index dd3b723f74b5..1604d83c6b0d 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js @@ -64,6 +64,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, + editEventsBasedEntityProperty: VariableDialogOpeningProps => void, |}; /** diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js index 56b756d6659f..59325eda7fe0 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js @@ -129,6 +129,7 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} + editEventsBasedEntityProperty={null} /> {editorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js index 2310bde7a9fe..8abe03ca89f9 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js @@ -41,6 +41,7 @@ export default (React.forwardRef( projectScopedContainersAccessor, onChange, value, + editEventsBasedEntityProperty, } = props; const enumerateGlobalAndSceneVariables = React.useCallback( @@ -127,6 +128,7 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} + editEventsBasedEntityProperty={editEventsBasedEntityProperty || null} /> {editorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js index 149a44cc8691..f3c37d6cf8a3 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js @@ -42,6 +42,7 @@ export default (React.forwardRef( onChange, value, editEventsFunctionParameter, + editEventsBasedEntityProperty, } = props; const enumerateGlobalAndSceneVariables = React.useCallback( @@ -131,6 +132,7 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={editEventsFunctionParameter || null} + editEventsBasedEntityProperty={editEventsBasedEntityProperty || null} /> {editorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( diff --git a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js index e17603f5daa1..4af2f98dc05c 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js @@ -66,6 +66,7 @@ export default (React.forwardRef( scope={scope} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} + editEventsBasedEntityProperty={null} /> {editorOpen && project && ( ( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} + editEventsBasedEntityProperty={null} /> {editorOpen && project && diff --git a/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js b/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js index d814f598a7c9..f479fdb414c0 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js @@ -58,6 +58,7 @@ export type ParameterFieldProps = {| parameterIndex?: number, onInstructionTypeChanged?: () => void, editEventsFunctionParameter?: VariableDialogOpeningProps => void, + editEventsBasedEntityProperty?: VariableDialogOpeningProps => void, |}; export type FieldFocusFunction = ( diff --git a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js index 6ef3a899933b..cf28815072a9 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js @@ -98,6 +98,7 @@ export default (React.forwardRef( } getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} + editEventsBasedEntityProperty={null} /> {editorOpen && layout && project && ( void) | null, editEventsFunctionParameter: (VariableDialogOpeningProps => void) | null, + editEventsBasedEntityProperty: (VariableDialogOpeningProps => void) | null, }; type VariableNameQuickAnalyzeResult = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; @@ -273,6 +274,7 @@ export default (React.forwardRef( getVariableSourceFromIdentifier, onOpenDialog, editEventsFunctionParameter, + editEventsBasedEntityProperty, } = props; const field = React.useRef(null); @@ -396,6 +398,36 @@ export default (React.forwardRef( ] ); + const openPropertyEditor = React.useCallback( + () => { + if (!editEventsBasedEntityProperty) { + return; + } + // Access to the input directly because the value + // may not have been sent to onChange yet. + const fieldCurrentValue = field.current + ? field.current.getInputValue() + : value; + + onChange(fieldCurrentValue); + editEventsBasedEntityProperty({ + variableName: fieldCurrentValue, + shouldCreate: !isRootVariableDeclared( + fieldCurrentValue, + variablesContainers + ), + variableType: getVariableTypeName(variableType), + }); + }, + [ + editEventsBasedEntityProperty, + value, + onChange, + variablesContainers, + variableType, + ] + ); + const description = parameterMetadata ? parameterMetadata.getDescription() : undefined; @@ -505,10 +537,10 @@ export default (React.forwardRef( ? ['edit-parameters'] : variableSourceType === gd.VariablesContainer.Properties ? // TODO Allow to edit properties from the event sheet. - [] + ['edit-properties'] : ['edit-variables'] : fieldCurrentValue - ? ['add-variable', 'add-parameter'] + ? ['add-variable', 'add-parameter', 'add-property'] : ['edit-or-add-variables']; return optionIds.includes(id); @@ -590,6 +622,26 @@ export default (React.forwardRef( }, ] : []), + ...(editEventsBasedEntityProperty + ? [ + { + id: 'edit-properties', + translatableValue: t`Edit properties...`, + text: '', + value: '', + renderIcon: () => , + onClick: openPropertyEditor, + }, + { + id: 'add-property', + translatableValue: t`Add property...`, + text: '', + value: '', + renderIcon: () => , + onClick: openPropertyEditor, + }, + ] + : []), ]} openOnFocus={!isInline} ref={field} diff --git a/newIDE/app/src/EventsSheet/index.js b/newIDE/app/src/EventsSheet/index.js index 750a5f60423e..e88b7b52c11c 100644 --- a/newIDE/app/src/EventsSheet/index.js +++ b/newIDE/app/src/EventsSheet/index.js @@ -195,6 +195,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, + editEventsBasedEntityProperty: VariableDialogOpeningProps => void, |}; type ComponentProps = {| @@ -2520,6 +2521,9 @@ export class EventsSheetComponentWithoutHandle extends React.Component< onWillInstallExtension={this.props.onWillInstallExtension} onExtensionInstalled={this.props.onExtensionInstalled} editEventsFunctionParameter={this.props.editEventsFunctionParameter} + editEventsBasedEntityProperty={ + this.props.editEventsBasedEntityProperty + } /> )} @@ -2603,6 +2607,7 @@ export class EventsSheetComponentWithoutHandle extends React.Component< screenType, highlightedAiGeneratedEventIds, editEventsFunctionParameter, + editEventsBasedEntityProperty, } = this.props; if (!project) return null; @@ -2937,6 +2942,7 @@ export class EventsSheetComponentWithoutHandle extends React.Component< }} resourceManagementProps={resourceManagementProps} editEventsFunctionParameter={editEventsFunctionParameter} + editEventsBasedEntityProperty={editEventsBasedEntityProperty} /> diff --git a/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js b/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js index 450c6228c30a..3285e846058a 100644 --- a/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js +++ b/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js @@ -18,6 +18,7 @@ import { type HotReloadSteps, } from '../../EmbeddedGame/EmbeddedGameFrame'; import type { SearchFilterParams } from '../../Utils/Search'; +import { type EventsScope } from '../../InstructionOrExpression/EventsScope'; export class EventsEditorContainer extends React.Component { editor: ?EventsSheetInterface; @@ -184,7 +185,7 @@ export class EventsEditorContainer extends React.ComponentNo layout called {projectItemName} found!; } - const scope = { + const scope: EventsScope = { project, layout, }; @@ -204,7 +205,6 @@ export class EventsEditorContainer extends React.Component {}} + editEventsBasedEntityProperty={() => {}} /> ); } diff --git a/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js b/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js index f55816da5870..5f901a59e2fd 100644 --- a/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js +++ b/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js @@ -288,8 +288,9 @@ export class ExternalEventsEditorContainer extends React.Component< hotReloadPreviewButtonProps={this.props.hotReloadPreviewButtonProps} onWillInstallExtension={this.props.onWillInstallExtension} onExtensionInstalled={this.props.onExtensionInstalled} - // Scene events don't have parameters + // Scene events don't have parameters nor properties editEventsFunctionParameter={() => {}} + editEventsBasedEntityProperty={() => {}} /> )} {!layout && ( diff --git a/newIDE/app/src/Version/index.js b/newIDE/app/src/Version/index.js index d7e6a03d868e..96b485262307 100644 --- a/newIDE/app/src/Version/index.js +++ b/newIDE/app/src/Version/index.js @@ -20,14 +20,6 @@ export const shouldHideExtension = ( extension: gdPlatformExtension ): boolean => { const initialGDVersion = project.getInitialGDVersion(); - if (initialGDVersion && extension.isDeprecated()) { - console.log( - 'shouldHideExtension', - extension.getDeprecationGDVersion(), - initialGDVersion, - !semverGreaterThan(extension.getDeprecationGDVersion(), initialGDVersion) - ); - } return ( !!initialGDVersion && extension.isDeprecated() && diff --git a/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js b/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js index fbef3d87e232..fd03848d4262 100644 --- a/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js +++ b/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js @@ -40,6 +40,7 @@ export const DefaultNoScope = (): React.Node => ( onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('edit function parameter')} + editEventsBasedEntityProperty={action('editEventsBasedEntityProperty')} /> @@ -73,6 +74,7 @@ export const EmptyNoScope = (): React.Node => ( onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('edit function parameter')} + editEventsBasedEntityProperty={action('editEventsBasedEntityProperty')} /> diff --git a/newIDE/app/src/stories/everything-else.stories.js b/newIDE/app/src/stories/everything-else.stories.js index 6f7289b933ab..3dda5744395d 100644 --- a/newIDE/app/src/stories/everything-else.stories.js +++ b/newIDE/app/src/stories/everything-else.stories.js @@ -2058,6 +2058,9 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} + editEventsBasedEntityProperty={action( + 'editEventsBasedEntityProperty' + )} /> )} @@ -2087,6 +2090,9 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} + editEventsBasedEntityProperty={action( + 'editEventsBasedEntityProperty' + )} /> )} @@ -2125,6 +2131,9 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} + editEventsBasedEntityProperty={action( + 'editEventsBasedEntityProperty' + )} /> )} @@ -2176,6 +2185,9 @@ storiesOf('InstructionEditorMenu', module) editEventsFunctionParameter={action( 'editEventsFunctionParameter' )} + editEventsBasedEntityProperty={action( + 'editEventsBasedEntityProperty' + )} /> )} From 5978309683e2b5041a42e1d286934790fb10f117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Tue, 16 Jun 2026 12:06:40 +0200 Subject: [PATCH 2/9] Fix variable type --- .../PropertyListEditor/index.js | 3 ++- newIDE/app/src/EventsFunctionsExtensionEditor/index.js | 8 ++++++-- .../src/EventsSheet/ParameterFields/VariableField.js | 10 ++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js index 4510743f7af5..f6c61785bb7b 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js @@ -1215,7 +1215,8 @@ const PropertyListEditor = React.forwardRef( setSelectedProperty(initiallySelectedProperty.variableName, false); } }, - [addProperty, initiallySelectedProperty, properties, setSelectedProperty] + // eslint-disable-next-line react-hooks/exhaustive-deps + [] ); const canMoveSelectionTo = React.useCallback( diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index a3a9f18e6d20..940ce5ee4bcb 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -1939,7 +1939,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component< propertyName ); }} - onPropertiesUpdated={() => {}} + onPropertiesUpdated={() => { + this.forceUpdate(); + }} onEventsFunctionsAdded={() => { if (this.eventsFunctionList) { this.eventsFunctionList.forceUpdateList(); @@ -1982,7 +1984,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component< propertyName ); }} - onPropertiesUpdated={() => {}} + onPropertiesUpdated={() => { + this.forceUpdate(); + }} onEventsFunctionsAdded={() => { if (this.eventsFunctionList) { this.eventsFunctionList.forceUpdateList(); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index 06570fb85fb9..608ee4b00c64 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -416,15 +416,21 @@ export default (React.forwardRef( fieldCurrentValue, variablesContainers ), - variableType: getVariableTypeName(variableType), + variableType: instruction + ? getVariableTypeName( + gd.VariableInstructionSwitcher.getSwitchableInstructionVariableType( + instruction.getType() + ) + ) + : 'number', }); }, [ editEventsBasedEntityProperty, value, onChange, + instruction, variablesContainers, - variableType, ] ); From 920217c8cdbc11fea929ea6a8b2ce36f2f130986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Tue, 16 Jun 2026 19:06:46 +0200 Subject: [PATCH 3/9] Handle mobile --- ...EventsBasedBehaviorOrObjectEditorDialog.js | 336 ++++++++++++++---- ...tsBasedBehaviorOrObjectPropertiesEditor.js | 21 ++ .../index.js | 16 +- .../PropertyListEditor/index.js | 30 -- .../EventsFunctionsExtensionEditor/index.js | 6 +- 5 files changed, 309 insertions(+), 100 deletions(-) diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js index b373e944e528..c7590a7fa136 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js @@ -1,6 +1,8 @@ // @flow import { Trans } from '@lingui/macro'; import * as React from 'react'; +import { t } from '@lingui/macro'; + import { type UnsavedChanges } from '../../MainFrame/UnsavedChangesContext'; import { type ExtensionItemConfigurationAttribute } from '../../EventsFunctionsExtensionEditor'; import { ProjectScopedContainersAccessor } from '../../InstructionOrExpression/EventsScope'; @@ -16,6 +18,12 @@ import FlatButton from '../../UI/FlatButton'; import HelpButton from '../../UI/HelpButton'; import Dialog from '../../UI/Dialog'; import { type VariableDialogOpeningProps } from '../../VariablesList/VariablesEditorDialog'; +import EditorNavigator from '../../UI/EditorMosaic/EditorNavigator'; +import { type Editor } from '../../UI/EditorMosaic'; +import TuneIcon from '../../UI/CustomSvgIcons/Tune'; +import { useResponsiveWindowSize } from '../../UI/Responsive/ResponsiveWindowMeasurer'; +import AddIcon from '../../UI/CustomSvgIcons/Add'; +import newNameGenerator from '../../Utils/NewNameGenerator'; const styles = { simpleSizeContainer: { @@ -28,6 +36,8 @@ const styles = { }, }; +const noop = () => {}; + type Props = {| project: gdProject, projectScopedContainersAccessor: ProjectScopedContainersAccessor, @@ -71,15 +81,200 @@ export default function EventsBasedBehaviorOrObjectEditorDialog({ onClose, initiallySelectedProperty, }: Props): React.Node { - const editor = React.useRef( + const propertyEditor = React.useRef( null ); const propertyList = React.useRef(null); + const lastFocusedProperty = React.useRef<{ + propertyName: string, + isSharedProperties: boolean, + } | null>(null); + + const eventsBasedEntity = eventsBasedBehavior || eventsBasedObject; + + const addProperty = React.useCallback( + (name?: string, type?: string | null) => { + if (!eventsBasedEntity) { + return; + } + const properties = eventsBasedEntity.getPropertyDescriptors(); + const newName = newNameGenerator(name || 'Property', name => + properties.has(name) + ); + const property = properties.insertNew(newName, properties.getCount()); + property.setType(type || 'Number'); + + if (propertyEditor.current) { + propertyEditor.current.forceUpdateProperties(); + } + if (propertyList.current) { + propertyList.current.forceUpdateList(); + } + // Scroll to the selected property. + // Ideally, we'd wait for the list to be updated to scroll, but + // to simplify the code, we just wait a few ms for a new render + // to be done. + setTimeout(() => { + if (propertyList.current) { + propertyList.current.setSelectedProperty(newName, false); + } + if (propertyEditor.current) { + propertyEditor.current.scrollToProperty(newName, false); + } + if (propertyEditor.current) { + propertyEditor.current.focusOnProperty(newName, false); + } + }, 100); // A few ms is enough for a new render to be done. + onPropertiesUpdated(); + }, + [eventsBasedEntity, onPropertiesUpdated] + ); + + React.useEffect( + () => { + if (!eventsBasedEntity) { + return; + } + const properties = eventsBasedEntity.getPropertyDescriptors(); + if (!initiallySelectedProperty || !properties) { + return; + } + if (initiallySelectedProperty.shouldCreate) { + const propertyType = + initiallySelectedProperty.variableType === 'number' + ? 'Number' + : initiallySelectedProperty.variableType === 'string' + ? 'String' + : initiallySelectedProperty.variableType === 'boolean' + ? 'Boolean' + : initiallySelectedProperty.variableType; + addProperty(initiallySelectedProperty.variableName, propertyType); + } else { + const currentPropertyEditor = propertyEditor.current; + if (currentPropertyEditor) { + currentPropertyEditor.scrollToProperty( + initiallySelectedProperty.variableName, + false + ); + } + const currentPropertyList = propertyList.current; + if (currentPropertyList) { + currentPropertyList.setSelectedProperty( + initiallySelectedProperty.variableName, + false + ); + } + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + const editors: { + [string]: Editor, + } = { + propertyList: { + type: 'primary', + noTitleBar: true, + title: t`Properties`, + toolbarControls: [], + renderEditor: () => ( + { + if (propertyEditor.current) { + propertyEditor.current.forceUpdateProperties(); + } + onPropertiesUpdated(); + }} + onOpenConfiguration={propertyName => { + if (propertyEditor.current) { + propertyEditor.current.scrollToConfiguration(); + } + }} + onOpenProperty={(propertyName, isSharedProperties) => { + if (propertyEditor.current) { + propertyEditor.current.scrollToProperty( + propertyName, + isSharedProperties + ); + } + }} + onEventsFunctionsAdded={onEventsFunctionsAdded} + initiallySelectedProperty={initiallySelectedProperty} + /> + ), + }, + propertyEditor: { + type: 'primary', + noTitleBar: true, + noSoftKeyboardAvoidance: true, + title: eventsBasedBehavior + ? t`Behavior Configuration` + : eventsBasedObject + ? t`Object Configuration` + : null, + toolbarControls: [], + renderEditor: () => ( + { + if (propertyList.current) { + propertyList.current.forceUpdateList(); + } + onPropertiesUpdated(); + }} + onFocusProperty={(propertyName, isSharedProperties) => { + lastFocusedProperty.current = { propertyName, isSharedProperties }; + if (propertyList.current) { + propertyList.current.setSelectedProperty( + propertyName, + isSharedProperties + ); + } + }} + shouldHideAddPropertyButton={true} + /> + ), + }, + }; + + const { isMobile } = useResponsiveWindowSize(); + return ( Properties} - secondaryActions={[]} + secondaryActions={[ + , + Add a property} + onClick={() => addProperty()} + leftIcon={} + />, + ]} actions={[ -
- { - if (propertyList.current) { - propertyList.current.forceUpdateList(); - } - onPropertiesUpdated(); + {isMobile ? ( + , + nextLabel: Property list, + previousEditor: null, + nextEditor: () => { + const selection = lastFocusedProperty.current; + if (selection) { + const { propertyName, isSharedProperties } = selection; + // Scroll to the selected property. + // Ideally, we'd wait for the list to be updated to scroll, but + // to simplify the code, we just wait a few ms for a new render + // to be done. + setTimeout(() => { + if (propertyList.current) { + propertyList.current.setSelectedProperty( + propertyName, + isSharedProperties + ); + } + }, 100); // A few ms is enough for a new render to be done. + } + return 'propertyList'; + }, + }, + propertyList: { + nextIcon: null, + nextLabel: null, + nextEditor: null, + previousEditor: () => { + if (propertyList.current) { + const selection = propertyList.current.getSelectedProperty(); + if (selection) { + const { propertyName, isSharedProperties } = selection; + // Scroll to the selected property. + // Ideally, we'd wait for the list to be updated to scroll, but + // to simplify the code, we just wait a few ms for a new render + // to be done. + setTimeout(() => { + if (propertyEditor.current) { + propertyEditor.current.scrollToProperty( + propertyName, + isSharedProperties + ); + } + }, 100); // A few ms is enough for a new render to be done. + } + } + return 'propertyEditor'; + }, + }, }} - onFocusProperty={(propertyName, isSharedProperties) => { - if (propertyList.current) { - propertyList.current.setSelectedProperty( - propertyName, - isSharedProperties - ); - } - }} - /> -
-
- { - if (editor.current) { - editor.current.forceUpdateProperties(); - } - onPropertiesUpdated(); - }} - onOpenConfiguration={propertyName => { - if (editor.current) { - editor.current.scrollToConfiguration(); - } - }} - onOpenProperty={(propertyName, isSharedProperties) => { - if (editor.current) { - editor.current.scrollToProperty( - propertyName, - isSharedProperties - ); - } - }} - onEventsFunctionsAdded={onEventsFunctionsAdded} - initiallySelectedProperty={initiallySelectedProperty} + onEditorChanged={ + // It's important that this callback is the same across renders, + // to avoid confusing EditorNavigator into thinking it's changed + // and immediately calling it, which would trigger an infinite loop. + // Search for "callback-prevent-infinite-rerendering" in the codebase. + noop + } /> -
+ ) : ( + <> +
+ {editors.propertyEditor.renderEditor()} +
+
+ {editors.propertyList.renderEditor()} +
+ + )}
); diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js index 93afcbd4dd63..ddf17c735685 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js @@ -41,6 +41,7 @@ import VariableStringIcon from '../../VariablesList/Icons/VariableStringIcon'; import VariableNumberIcon from '../../VariablesList/Icons/VariableNumberIcon'; import VariableBooleanIcon from '../../VariablesList/Icons/VariableBooleanIcon'; import NewBehaviorDialog from '../../BehaviorsEditor/NewBehaviorDialog'; +import { type CompactTextFieldInterface } from '../../UI/CompactTextField'; const gd: libGDevelop = global.gd; @@ -179,6 +180,7 @@ const getChoicesArray = ( export type EventsBasedBehaviorOrObjectPropertiesEditorInterface = {| forceUpdate: () => void, getPropertyEditorRef: (propertyName: string) => React.ElementRef, + focusOnProperty: (propertyName: string) => void, |}; export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ @@ -214,7 +216,19 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ forceUpdate, getPropertyEditorRef: (propertyName: string) => propertyRefs ? propertyRefs.current.get(propertyName) : null, + focusOnProperty: (propertyName: string) => { + const propertyNameField = propertyNameFieldRefs.current.get( + propertyName + ); + if (propertyNameField) { + propertyNameField.focus(); + propertyNameField.select(); + } + }, })); + const propertyNameFieldRefs = React.useRef( + new Map() + ); const [newBehaviorDialogOpen, setNewBehaviorDialogOpen] = React.useState<{ behaviorProperty: gdNamedPropertyDescriptor, @@ -309,6 +323,7 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ ); propertyRefs.current.clear(); + propertyNameFieldRefs.current.clear(); return ( @@ -349,6 +364,12 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ { + propertyNameFieldRefs.current.set( + property.getName(), + ref + ); + }} commitOnBlur placeholder={i18n._( t`Enter the property name` diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/index.js index 3fbcdab2cd2a..199105e96169 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/index.js @@ -42,12 +42,14 @@ type Props = {| ) => void, onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, + shouldHideAddPropertyButton?: boolean, |}; export type EventsBasedBehaviorOrObjectEditorInterface = {| forceUpdateProperties: () => void, scrollToConfiguration: () => void, scrollToProperty: (propertyName: string, isSharedProperties: boolean) => void, + focusOnProperty: (propertyName: string, isSharedProperties: boolean) => void, |}; export const EventsBasedBehaviorOrObjectEditor: React.ComponentType<{ @@ -73,6 +75,7 @@ export const EventsBasedBehaviorOrObjectEditor: React.ComponentType<{ onEventsBasedObjectChildrenEdited, onWillInstallExtension, onExtensionInstalled, + shouldHideAddPropertyButton, }: Props, ref ) => { @@ -127,6 +130,17 @@ export const EventsBasedBehaviorOrObjectEditor: React.ComponentType<{ scenePropertiesEditor.current.forceUpdate(); } }, + focusOnProperty: (propertyName: string, isSharedProperties: boolean) => { + if (isSharedProperties) { + if (scenePropertiesEditor.current) { + scenePropertiesEditor.current.focusOnProperty(propertyName); + } + } else { + if (propertiesEditor.current) { + propertiesEditor.current.focusOnProperty(propertyName); + } + } + }, scrollToConfiguration: () => { if (scrollView.current) { scrollView.current.scrollToPosition(0); @@ -271,7 +285,7 @@ export const EventsBasedBehaviorOrObjectEditor: React.ComponentType<{ - {windowSize === 'small' && ( + {windowSize === 'small' && !shouldHideAddPropertyButton && ( ( }, })); - React.useEffect( - () => { - if (!initiallySelectedProperty || !properties) { - return; - } - if (initiallySelectedProperty.shouldCreate) { - const propertyType = - initiallySelectedProperty.variableType === 'number' - ? 'Number' - : initiallySelectedProperty.variableType === 'string' - ? 'String' - : initiallySelectedProperty.variableType === 'boolean' - ? 'Boolean' - : initiallySelectedProperty.variableType; - addProperty( - properties, - false, - properties.getRootFolder(), - 0, - initiallySelectedProperty.variableName, - propertyType - ); - } else { - setSelectedProperty(initiallySelectedProperty.variableName, false); - } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); - const canMoveSelectionTo = React.useCallback( (destinationItem: TreeViewItem, where: 'before' | 'inside' | 'after') => selectedItems.every(item => { diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index 940ce5ee4bcb..8b8f196eb351 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -10,6 +10,7 @@ import EditorMosaic, { type EditorMosaicInterface, mosaicContainsNode, } from '../UI/EditorMosaic'; +import { type Editor } from '../UI/EditorMosaic'; import EmptyMessage from '../UI/EmptyMessage'; import EventsFunctionConfigurationEditor, { type EventsFunctionConfigurationEditorInterface, @@ -1380,7 +1381,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component< const selectedEventsBasedEntity = selectedEventsBasedBehavior || selectedEventsBasedObject; - const editors = { + const editors: { + [string]: Editor, + } = { parameters: { type: 'primary', title: selectedEventsFunction @@ -1769,7 +1772,6 @@ export default class EventsFunctionsExtensionEditor extends React.Component< ref={editorNavigator => (this._editorNavigator = editorNavigator) } - // $FlowFixMe[incompatible-type] editors={editors} initialEditorName={'functions-list'} transitions={{ From 4ced85a9c2d5016021499e660a3d5fc4566f8755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 11:32:11 +0200 Subject: [PATCH 4/9] Some renaming --- .../EventsFunctionsExtensionEditor/index.js | 22 ++++++---- .../src/EventsSheet/InlineParameterEditor.js | 8 ++-- .../InstructionEditorDialog.js | 2 +- .../InstructionEditorMenu.js | 2 +- .../ParameterFields/AnyVariableField.js | 20 ++++----- .../AnyVariableOrPropertyField.js | 24 ++++++----- .../AnyVariableOrPropertyOrParameterField.js | 31 ++++++-------- .../ParameterFields/GlobalVariableField.js | 16 ++++---- .../ParameterFields/ObjectVariableField.js | 6 ++- .../ParameterFields/ParameterFieldCommons.js | 2 +- .../ParameterFields/SceneVariableField.js | 22 +++++----- .../ParameterFields/VariableField.js | 41 +++++++++++-------- newIDE/app/src/EventsSheet/index.js | 12 +++--- .../EditorContainers/EventsEditorContainer.js | 2 +- .../ExternalEventsEditorContainer.js | 2 +- .../EventsSheet/EventsSheet.stories.js | 8 +++- .../src/stories/everything-else.stories.js | 16 ++++---- 17 files changed, 128 insertions(+), 108 deletions(-) diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index 8b8f196eb351..6c6d564e9b4d 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -1193,7 +1193,7 @@ export default class EventsFunctionsExtensionEditor extends React.Component< }); }; - _editVariables = ( + _openVariableEditorDialog = ( options: { isGlobalTabInitiallyOpen: boolean } | null = { isGlobalTabInitiallyOpen: false, } @@ -1346,7 +1346,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component< this.eventsFunctionConfigurationEditor.editEventsFunctionParameter(props); }; - _editEventsBasedEntityProperty = (props: VariableDialogOpeningProps) => { + _openEventsBasedEntityPropertyEditorDialog = ( + props: VariableDialogOpeningProps + ) => { this.setState({ eventsBasedEntityPropertiesDialogOpen: props, }); @@ -1577,8 +1579,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component< onWillInstallExtension={this.props.onWillInstallExtension} onExtensionInstalled={this.props.onExtensionInstalled} editEventsFunctionParameter={this._editEventsFunctionParameter} - editEventsBasedEntityProperty={ - this._editEventsBasedEntityProperty + openEventsBasedEntityPropertyEditorDialog={ + this._openEventsBasedEntityPropertyEditorDialog } /> @@ -1749,9 +1751,13 @@ export default class EventsFunctionsExtensionEditor extends React.Component< onAddEventsBasedObject={this._onAddEventsBasedObject} onSelectExtensionProperties={() => this._editOptions(true)} onSelectExtensionGlobalVariables={() => - this._editVariables({ isGlobalTabInitiallyOpen: true }) + this._openVariableEditorDialog({ + isGlobalTabInitiallyOpen: true, + }) + } + onSelectExtensionSceneVariables={() => + this._openVariableEditorDialog() } - onSelectExtensionSceneVariables={() => this._editVariables()} onOpenCustomObjectEditor={this.props.onOpenCustomObjectEditor} onEventBasedObjectTypeChanged={ this.props.onEventBasedObjectTypeChanged @@ -1895,8 +1901,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component< }) } open - onCancel={() => this._editVariables(null)} - onApply={() => this._editVariables(null)} + onCancel={() => this._openVariableEditorDialog(null)} + onApply={() => this._openVariableEditorDialog(null)} hotReloadPreviewButtonProps={this.props.hotReloadPreviewButtonProps} isListLocked={false} initiallySelectedVariable={null} diff --git a/newIDE/app/src/EventsSheet/InlineParameterEditor.js b/newIDE/app/src/EventsSheet/InlineParameterEditor.js index b9a2567be063..387a5cc77634 100644 --- a/newIDE/app/src/EventsSheet/InlineParameterEditor.js +++ b/newIDE/app/src/EventsSheet/InlineParameterEditor.js @@ -42,7 +42,7 @@ type Props = {| resourceManagementProps: ResourceManagementProps, editEventsFunctionParameter: VariableDialogOpeningProps => void, - editEventsBasedEntityProperty: VariableDialogOpeningProps => void, + openEventsBasedEntityPropertyEditorDialog: VariableDialogOpeningProps => void, |}; const InlineParameterEditor = ({ @@ -61,7 +61,7 @@ const InlineParameterEditor = ({ anchorEl, resourceManagementProps, editEventsFunctionParameter, - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, }: Props): null | React.Node => { const portalContainer = React.useContext(PortalContainerContext); const [ @@ -193,7 +193,9 @@ const InlineParameterEditor = ({ isInline resourceManagementProps={resourceManagementProps} editEventsFunctionParameter={editEventsFunctionParameter} - editEventsBasedEntityProperty={editEventsBasedEntityProperty} + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog + } /> ); diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js index 51807fd72db9..d8a70d0d4237 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js @@ -81,7 +81,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, - editEventsBasedEntityProperty: VariableDialogOpeningProps => void, + openEventsBasedEntityPropertyEditorDialog: VariableDialogOpeningProps => void, |}; const getInitialStepName = (isNewInstruction: boolean): StepName => { diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js index 1604d83c6b0d..f714017f4ca2 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorMenu.js @@ -64,7 +64,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, - editEventsBasedEntityProperty: VariableDialogOpeningProps => void, + openEventsBasedEntityPropertyEditorDialog: VariableDialogOpeningProps => void, |}; /** diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js index 59325eda7fe0..c8f31e03e27c 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js @@ -23,8 +23,8 @@ export default (React.forwardRef( function AnyVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); const [ - editorOpen, - setEditorOpen, + variableEditorOpen, + setVariableEditorOpen, ] = React.useState(null); const focus: FieldFocusFunction = options => { if (field.current) field.current.focus(options); @@ -78,7 +78,7 @@ export default (React.forwardRef( if (selectedVariableName && selectedVariableName.startsWith(value)) { onChange(selectedVariableName); } - setEditorOpen(null); + setVariableEditorOpen(null); // The variable editor may have refactor the events for a variable type // change which may have change the currently edited instruction type. if (onInstructionTypeChanged) onInstructionTypeChanged(); @@ -116,7 +116,7 @@ export default (React.forwardRef( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={setEditorOpen} + openVariableEditorDialog={setVariableEditorOpen} globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} @@ -129,9 +129,9 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} - editEventsBasedEntityProperty={null} + openEventsBasedEntityPropertyEditorDialog={null} /> - {editorOpen && + {variableEditorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( project && ( ( } variablesContainer={variablesContainer} open - onCancel={() => setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} isListLocked={false} /> ) @@ -151,12 +151,12 @@ export default (React.forwardRef( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} isGlobalTabInitiallyOpen={ variableSourceType === gd.VariablesContainer.Global } - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js index 8abe03ca89f9..4a3ce6103aab 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js @@ -23,8 +23,8 @@ export default (React.forwardRef( function AnyVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); const [ - editorOpen, - setEditorOpen, + variableEditorOpen, + setVariableEditorOpen, ] = React.useState(null); const focus: FieldFocusFunction = options => { if (field.current) field.current.focus(options); @@ -41,7 +41,7 @@ export default (React.forwardRef( projectScopedContainersAccessor, onChange, value, - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, } = props; const enumerateGlobalAndSceneVariables = React.useCallback( @@ -77,7 +77,7 @@ export default (React.forwardRef( if (selectedVariableName && selectedVariableName.startsWith(value)) { onChange(selectedVariableName); } - setEditorOpen(null); + setVariableEditorOpen(null); // The variable editor may have refactor the events for a variable type // change which may have change the currently edited instruction type. if (onInstructionTypeChanged) onInstructionTypeChanged(); @@ -115,7 +115,7 @@ export default (React.forwardRef( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={setEditorOpen} + openVariableEditorDialog={setVariableEditorOpen} globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} @@ -128,9 +128,11 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} - editEventsBasedEntityProperty={editEventsBasedEntityProperty || null} + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog || null + } /> - {editorOpen && + {variableEditorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( project && ( ( } variablesContainer={variablesContainer} open - onCancel={() => setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} isListLocked={false} /> ) @@ -150,13 +152,13 @@ export default (React.forwardRef( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} isGlobalTabInitiallyOpen={ variableSourceType === gd.VariablesContainer.Global || variableSourceType === gd.VariablesContainer.ExtensionGlobal } - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js index f3c37d6cf8a3..39573d8a670e 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js @@ -23,8 +23,8 @@ export default (React.forwardRef( function AnyVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); const [ - editorOpen, - setEditorOpen, + variableEditorOpen, + setVariableEditorOpen, ] = React.useState(null); const focus: FieldFocusFunction = options => { if (field.current) field.current.focus(options); @@ -42,7 +42,7 @@ export default (React.forwardRef( onChange, value, editEventsFunctionParameter, - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, } = props; const enumerateGlobalAndSceneVariables = React.useCallback( @@ -74,7 +74,7 @@ export default (React.forwardRef( if (selectedVariableName && selectedVariableName.startsWith(value)) { onChange(selectedVariableName); } - setEditorOpen(null); + setVariableEditorOpen(null); // The variable editor may have refactor the events for a variable type // change which may have change the currently edited instruction type. if (onInstructionTypeChanged) onInstructionTypeChanged(); @@ -96,13 +96,6 @@ export default (React.forwardRef( ); const variableSourceType = variablesContainer.getSourceType(); - const onOpenDialog = React.useCallback( - (props: VariableDialogOpeningProps) => { - setEditorOpen(props); - }, - [] - ); - return ( ( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={onOpenDialog} + openVariableEditorDialog={setVariableEditorOpen} globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} @@ -132,9 +125,11 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={editEventsFunctionParameter || null} - editEventsBasedEntityProperty={editEventsBasedEntityProperty || null} + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog || null + } /> - {editorOpen && + {variableEditorOpen && (variableSourceType === gd.VariablesContainer.Local ? ( project && ( ( } variablesContainer={variablesContainer} open - onCancel={() => setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} isListLocked={false} /> ) @@ -154,13 +149,13 @@ export default (React.forwardRef( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} isGlobalTabInitiallyOpen={ variableSourceType === gd.VariablesContainer.Global || variableSourceType === gd.VariablesContainer.ExtensionGlobal } - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> diff --git a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js index 4af2f98dc05c..7409b6a98dd5 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js @@ -20,8 +20,8 @@ export default (React.forwardRef( function GlobalVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); const [ - editorOpen, - setEditorOpen, + variableEditorOpen, + setVariableEditorOpen, ] = React.useState(null); const focus: FieldFocusFunction = options => { if (field.current) field.current.focus(options); @@ -59,20 +59,20 @@ export default (React.forwardRef( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={setEditorOpen} + openVariableEditorDialog={setVariableEditorOpen} globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} scope={scope} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} - editEventsBasedEntityProperty={null} + openEventsBasedEntityPropertyEditorDialog={null} /> - {editorOpen && project && ( + {variableEditorOpen && project && ( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={(selectedVariableName: string | null) => { if ( selectedVariableName && @@ -80,10 +80,10 @@ export default (React.forwardRef( ) { props.onChange(selectedVariableName); } - setEditorOpen(null); + setVariableEditorOpen(null); if (field.current) field.current.updateAutocompletions(); }} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> diff --git a/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js index 77b58da066a7..548d62398fa9 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js @@ -197,7 +197,9 @@ export default (React.forwardRef( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={canObjectDeclareVariable ? setEditorOpen : null} + openVariableEditorDialog={ + canObjectDeclareVariable ? setEditorOpen : null + } globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} @@ -210,7 +212,7 @@ export default (React.forwardRef( onInstructionTypeChanged={onInstructionTypeChanged} getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} - editEventsBasedEntityProperty={null} + openEventsBasedEntityPropertyEditorDialog={null} /> {editorOpen && project && diff --git a/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js b/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js index f479fdb414c0..40e266d9bb4d 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/ParameterFieldCommons.js @@ -58,7 +58,7 @@ export type ParameterFieldProps = {| parameterIndex?: number, onInstructionTypeChanged?: () => void, editEventsFunctionParameter?: VariableDialogOpeningProps => void, - editEventsBasedEntityProperty?: VariableDialogOpeningProps => void, + openEventsBasedEntityPropertyEditorDialog?: VariableDialogOpeningProps => void, |}; export type FieldFocusFunction = ( diff --git a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js index cf28815072a9..421e9855a468 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js @@ -21,8 +21,8 @@ export default (React.forwardRef( function SceneVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); const [ - editorOpen, - setEditorOpen, + variableEditorOpen, + setVariableEditorOpen, ] = React.useState(null); const focus: FieldFocusFunction = options => { if (field.current) field.current.focus(options); @@ -67,7 +67,7 @@ export default (React.forwardRef( if (selectedVariableName && selectedVariableName.startsWith(value)) { onChange(selectedVariableName); } - setEditorOpen(null); + setVariableEditorOpen(null); if (field.current) field.current.updateAutocompletions(); }, [onChange, value] @@ -86,7 +86,7 @@ export default (React.forwardRef( onRequestClose={props.onRequestClose} onApply={props.onApply} ref={field} - onOpenDialog={setEditorOpen} + openVariableEditorDialog={setVariableEditorOpen} globalObjectsContainer={props.globalObjectsContainer} objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} @@ -98,28 +98,28 @@ export default (React.forwardRef( } getVariableSourceFromIdentifier={getVariableSourceFromIdentifier} editEventsFunctionParameter={null} - editEventsBasedEntityProperty={null} + openEventsBasedEntityPropertyEditorDialog={null} /> - {editorOpen && layout && project && ( + {variableEditorOpen && layout && project && ( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> )} - {editorOpen && eventsFunctionsExtension && !layout && ( + {variableEditorOpen && eventsFunctionsExtension && !layout && ( setEditorOpen(null)} + onCancel={() => setVariableEditorOpen(null)} onApply={onVariableEditorApply} isGlobalTabInitiallyOpen={false} - initiallySelectedVariable={editorOpen} + initiallySelectedVariable={variableEditorOpen} hotReloadPreviewButtonProps={null} isListLocked={false} /> diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index 608ee4b00c64..012eb3b44f93 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -77,9 +77,11 @@ type Props = { ) => VariablesContainer_SourceType, enumerateVariables: () => Array, forceDeclaration?: boolean, - onOpenDialog: (VariableDialogOpeningProps => void) | null, + openVariableEditorDialog: (VariableDialogOpeningProps => void) | null, editEventsFunctionParameter: (VariableDialogOpeningProps => void) | null, - editEventsBasedEntityProperty: (VariableDialogOpeningProps => void) | null, + openEventsBasedEntityPropertyEditorDialog: + | (VariableDialogOpeningProps => void) + | null, }; type VariableNameQuickAnalyzeResult = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; @@ -272,9 +274,9 @@ export default (React.forwardRef( onInstructionTypeChanged, isObjectVariable, getVariableSourceFromIdentifier, - onOpenDialog, + openVariableEditorDialog, editEventsFunctionParameter, - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, } = props; const field = React.useRef(null); @@ -335,7 +337,7 @@ export default (React.forwardRef( const openVariableEditor = React.useCallback( () => { - if (!onOpenDialog) { + if (!openVariableEditorDialog) { return; } // Access to the input directly because the value @@ -345,7 +347,7 @@ export default (React.forwardRef( : value; onChange(fieldCurrentValue); - onOpenDialog({ + openVariableEditorDialog({ variableName: fieldCurrentValue, shouldCreate: !!fieldCurrentValue && @@ -359,7 +361,13 @@ export default (React.forwardRef( : 'number', }); }, - [instruction, onChange, onOpenDialog, value, variablesContainers] + [ + instruction, + onChange, + openVariableEditorDialog, + value, + variablesContainers, + ] ); const openParameterEditor = React.useCallback( @@ -400,7 +408,7 @@ export default (React.forwardRef( const openPropertyEditor = React.useCallback( () => { - if (!editEventsBasedEntityProperty) { + if (!openEventsBasedEntityPropertyEditorDialog) { return; } // Access to the input directly because the value @@ -410,7 +418,7 @@ export default (React.forwardRef( : value; onChange(fieldCurrentValue); - editEventsBasedEntityProperty({ + openEventsBasedEntityPropertyEditorDialog({ variableName: fieldCurrentValue, shouldCreate: !isRootVariableDeclared( fieldCurrentValue, @@ -426,7 +434,7 @@ export default (React.forwardRef( }); }, [ - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, value, onChange, instruction, @@ -542,8 +550,7 @@ export default (React.forwardRef( ? variableSourceType === gd.VariablesContainer.Parameters ? ['edit-parameters'] : variableSourceType === gd.VariablesContainer.Properties - ? // TODO Allow to edit properties from the event sheet. - ['edit-properties'] + ? ['edit-properties'] : ['edit-variables'] : fieldCurrentValue ? ['add-variable', 'add-parameter', 'add-property'] @@ -580,7 +587,7 @@ export default (React.forwardRef( // $FlowFixMe[incompatible-type] dataSource={[ ...autocompletionVariableNames, - ...(onOpenDialog + ...(openVariableEditorDialog ? [ { id: 'edit-variables', @@ -628,7 +635,7 @@ export default (React.forwardRef( }, ] : []), - ...(editEventsBasedEntityProperty + ...(openEventsBasedEntityPropertyEditorDialog ? [ { id: 'edit-properties', @@ -658,12 +665,12 @@ export default (React.forwardRef( !isInline ? ( } - disabled={!onOpenDialog} + disabled={!openVariableEditorDialog} primary style={style} onClick={() => { - if (onOpenDialog) { - onOpenDialog({ + if (openVariableEditorDialog) { + openVariableEditorDialog({ variableName: value, shouldCreate: false, variableType: getVariableTypeName(variableType), diff --git a/newIDE/app/src/EventsSheet/index.js b/newIDE/app/src/EventsSheet/index.js index e88b7b52c11c..b695abcfab64 100644 --- a/newIDE/app/src/EventsSheet/index.js +++ b/newIDE/app/src/EventsSheet/index.js @@ -195,7 +195,7 @@ type Props = {| onWillInstallExtension: (extensionNames: Array) => void, onExtensionInstalled: (extensionNames: Array) => void, editEventsFunctionParameter: VariableDialogOpeningProps => void, - editEventsBasedEntityProperty: VariableDialogOpeningProps => void, + openEventsBasedEntityPropertyEditorDialog: VariableDialogOpeningProps => void, |}; type ComponentProps = {| @@ -2521,8 +2521,8 @@ export class EventsSheetComponentWithoutHandle extends React.Component< onWillInstallExtension={this.props.onWillInstallExtension} onExtensionInstalled={this.props.onExtensionInstalled} editEventsFunctionParameter={this.props.editEventsFunctionParameter} - editEventsBasedEntityProperty={ - this.props.editEventsBasedEntityProperty + openEventsBasedEntityPropertyEditorDialog={ + this.props.openEventsBasedEntityPropertyEditorDialog } /> )} @@ -2607,7 +2607,7 @@ export class EventsSheetComponentWithoutHandle extends React.Component< screenType, highlightedAiGeneratedEventIds, editEventsFunctionParameter, - editEventsBasedEntityProperty, + openEventsBasedEntityPropertyEditorDialog, } = this.props; if (!project) return null; @@ -2942,7 +2942,9 @@ export class EventsSheetComponentWithoutHandle extends React.Component< }} resourceManagementProps={resourceManagementProps} editEventsFunctionParameter={editEventsFunctionParameter} - editEventsBasedEntityProperty={editEventsBasedEntityProperty} + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog + } /> diff --git a/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js b/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js index 3285e846058a..2f28ffd41f08 100644 --- a/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js +++ b/newIDE/app/src/MainFrame/EditorContainers/EventsEditorContainer.js @@ -217,7 +217,7 @@ export class EventsEditorContainer extends React.Component {}} - editEventsBasedEntityProperty={() => {}} + openEventsBasedEntityPropertyEditorDialog={() => {}} /> ); } diff --git a/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js b/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js index 5f901a59e2fd..7ea454e775e5 100644 --- a/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js +++ b/newIDE/app/src/MainFrame/EditorContainers/ExternalEventsEditorContainer.js @@ -290,7 +290,7 @@ export class ExternalEventsEditorContainer extends React.Component< onExtensionInstalled={this.props.onExtensionInstalled} // Scene events don't have parameters nor properties editEventsFunctionParameter={() => {}} - editEventsBasedEntityProperty={() => {}} + openEventsBasedEntityPropertyEditorDialog={() => {}} /> )} {!layout && ( diff --git a/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js b/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js index fd03848d4262..61a693fabebf 100644 --- a/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js +++ b/newIDE/app/src/stories/componentStories/EventsSheet/EventsSheet.stories.js @@ -40,7 +40,9 @@ export const DefaultNoScope = (): React.Node => ( onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('edit function parameter')} - editEventsBasedEntityProperty={action('editEventsBasedEntityProperty')} + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' + )} /> @@ -74,7 +76,9 @@ export const EmptyNoScope = (): React.Node => ( onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('edit function parameter')} - editEventsBasedEntityProperty={action('editEventsBasedEntityProperty')} + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' + )} /> diff --git a/newIDE/app/src/stories/everything-else.stories.js b/newIDE/app/src/stories/everything-else.stories.js index 3dda5744395d..e2068464cda7 100644 --- a/newIDE/app/src/stories/everything-else.stories.js +++ b/newIDE/app/src/stories/everything-else.stories.js @@ -2058,8 +2058,8 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} - editEventsBasedEntityProperty={action( - 'editEventsBasedEntityProperty' + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' )} /> )} @@ -2090,8 +2090,8 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} - editEventsBasedEntityProperty={action( - 'editEventsBasedEntityProperty' + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' )} /> )} @@ -2131,8 +2131,8 @@ storiesOf('InstructionEditorDialog', module) onWillInstallExtension={action('extension will be installed')} onExtensionInstalled={action('extension installed')} editEventsFunctionParameter={action('editEventsFunctionParameter')} - editEventsBasedEntityProperty={action( - 'editEventsBasedEntityProperty' + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' )} /> )} @@ -2185,8 +2185,8 @@ storiesOf('InstructionEditorMenu', module) editEventsFunctionParameter={action( 'editEventsFunctionParameter' )} - editEventsBasedEntityProperty={action( - 'editEventsBasedEntityProperty' + openEventsBasedEntityPropertyEditorDialog={action( + 'openEventsBasedEntityPropertyEditorDialog' )} /> )} From c02f8b5b1fda203de391c7836523dfd0bedb83c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 13:22:03 +0200 Subject: [PATCH 5/9] Fix callback --- .../EventsBasedBehaviorOrObjectEditorDialog.js | 11 ++++++++++- .../InstructionEditor/InstructionEditorDialog.js | 4 ++++ .../InstructionEditor/InstructionParametersEditor.js | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js index c7590a7fa136..f2c83c3fd4e4 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js @@ -24,6 +24,7 @@ import TuneIcon from '../../UI/CustomSvgIcons/Tune'; import { useResponsiveWindowSize } from '../../UI/Responsive/ResponsiveWindowMeasurer'; import AddIcon from '../../UI/CustomSvgIcons/Add'; import newNameGenerator from '../../Utils/NewNameGenerator'; +import { Divider } from '@material-ui/core'; const styles = { simpleSizeContainer: { @@ -267,7 +268,14 @@ export default function EventsBasedBehaviorOrObjectEditorDialog({ Properties} secondaryActions={[ - , + , Add a property} @@ -361,6 +369,7 @@ export default function EventsBasedBehaviorOrObjectEditorDialog({
{editors.propertyEditor.renderEditor()}
+
{editors.propertyList.renderEditor()}
diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js index d8a70d0d4237..630940aa4d50 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionEditorDialog.js @@ -119,6 +119,7 @@ const InstructionEditorDialog = ({ onExtensionInstalled, i18n, editEventsFunctionParameter, + openEventsBasedEntityPropertyEditorDialog, }: Props) => { const forceUpdate = useForceUpdate(); const [ @@ -394,6 +395,9 @@ const InstructionEditorDialog = ({ focusOnMount={shouldAutofocusInput && !!instructionType} noHelpButton id="object-instruction-parameters" + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog + } /> ); diff --git a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionParametersEditor.js b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionParametersEditor.js index 842361ae0c81..a27077d0e816 100644 --- a/newIDE/app/src/EventsSheet/InstructionEditor/InstructionParametersEditor.js +++ b/newIDE/app/src/EventsSheet/InstructionEditor/InstructionParametersEditor.js @@ -40,6 +40,7 @@ import { } from '../ParameterFields/ParameterFieldCommons'; import Edit from '../../UI/CustomSvgIcons/Edit'; import { ProjectScopedContainersAccessor } from '../../InstructionOrExpression/EventsScope'; +import { type VariableDialogOpeningProps } from '../../VariablesList/VariablesEditorDialog'; const gd: libGDevelop = global.gd; @@ -90,6 +91,7 @@ type Props = {| ) => void, noHelpButton?: boolean, id?: string, + openEventsBasedEntityPropertyEditorDialog: VariableDialogOpeningProps => void, |}; const isParameterVisible = ( @@ -136,6 +138,7 @@ const InstructionParametersEditor: React.ComponentType<{ openInstructionOrExpression, resourceManagementProps, id, + openEventsBasedEntityPropertyEditorDialog, }, ref ) => { @@ -434,6 +437,9 @@ const InstructionParametersEditor: React.ComponentType<{ firstVisibleField.current = field; } }} + openEventsBasedEntityPropertyEditorDialog={ + openEventsBasedEntityPropertyEditorDialog + } /> ); })} From 01f598432da005c713a1293b07dd3648ed7ced3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 14:21:44 +0200 Subject: [PATCH 6/9] Put parameters and properties first --- .../ParameterFields/VariableField.js | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index 012eb3b44f93..565acb28f744 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -553,8 +553,8 @@ export default (React.forwardRef( ? ['edit-properties'] : ['edit-variables'] : fieldCurrentValue - ? ['add-variable', 'add-parameter', 'add-property'] - : ['edit-or-add-variables']; + ? ['add-parameter', 'add-property', 'add-variable'] + : ['edit-or-add-properties', 'edit-or-add-variables']; return optionIds.includes(id); }, @@ -587,71 +587,79 @@ export default (React.forwardRef( // $FlowFixMe[incompatible-type] dataSource={[ ...autocompletionVariableNames, - ...(openVariableEditorDialog + ...(editEventsFunctionParameter ? [ { - id: 'edit-variables', - translatableValue: t`Edit variables...`, + id: 'edit-parameters', + translatableValue: t`Edit parameters...`, text: '', value: '', renderIcon: () => , - onClick: openVariableEditor, + onClick: openParameterEditor, }, { - id: 'add-variable', - translatableValue: t`Add variable...`, + id: 'add-parameter', + translatableValue: t`Add parameter...`, text: '', value: '', renderIcon: () => , - onClick: openVariableEditor, + onClick: openParameterEditor, }, + ] + : []), + ...(openEventsBasedEntityPropertyEditorDialog + ? [ { - id: 'edit-or-add-variables', - translatableValue: t`Edit or add variables...`, + id: 'edit-properties', + translatableValue: t`Edit properties...`, text: '', value: '', renderIcon: () => , - onClick: openVariableEditor, + onClick: openPropertyEditor, }, - ] - : []), - ...(editEventsFunctionParameter - ? [ { - id: 'edit-parameters', - translatableValue: t`Edit parameters...`, + id: 'add-property', + translatableValue: t`Add property...`, text: '', value: '', renderIcon: () => , - onClick: openParameterEditor, + onClick: openPropertyEditor, }, { - id: 'add-parameter', - translatableValue: t`Add parameter...`, + id: 'edit-or-add-properties', + translatableValue: t`Edit or add properties...`, text: '', value: '', renderIcon: () => , - onClick: openParameterEditor, + onClick: openPropertyEditor, }, ] : []), - ...(openEventsBasedEntityPropertyEditorDialog + ...(openVariableEditorDialog ? [ { - id: 'edit-properties', - translatableValue: t`Edit properties...`, + id: 'edit-variables', + translatableValue: t`Edit variables...`, text: '', value: '', renderIcon: () => , - onClick: openPropertyEditor, + onClick: openVariableEditor, }, { - id: 'add-property', - translatableValue: t`Add property...`, + id: 'add-variable', + translatableValue: t`Add variable...`, text: '', value: '', renderIcon: () => , - onClick: openPropertyEditor, + onClick: openVariableEditor, + }, + { + id: 'edit-or-add-variables', + translatableValue: t`Edit or add variables...`, + text: '', + value: '', + renderIcon: () => , + onClick: openVariableEditor, }, ] : []), From ae08430d47e4986a489873ab1b43610af5ee0f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 14:26:40 +0200 Subject: [PATCH 7/9] Fix flow --- .../EventsSheet/ParameterFields/VariableField.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index 565acb28f744..3b0837aed4e6 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -91,7 +91,9 @@ export type VariableFieldInterface = {| updateAutocompletions: () => void, |}; -export const VariableNameQuickAnalyzeResults = { +export const VariableNameQuickAnalyzeResults: { + [string]: VariableNameQuickAnalyzeResult, +} = { OK: 0, WRONG_QUOTE: 1, WRONG_SPACE: 2, @@ -142,7 +144,6 @@ export const quicklyAnalyzeVariableName = ( projectScopedContainersAccessor?: ProjectScopedContainersAccessor, isObjectVariable: boolean = false ): VariableNameQuickAnalyzeResult => { - // $FlowFixMe[incompatible-type] if (!name) return VariableNameQuickAnalyzeResults.OK; for (let i = 0; i < name.length; ++i) { @@ -152,10 +153,8 @@ export const quicklyAnalyzeVariableName = ( // This probably starts an expression, so stop the analysis. break; } else if (character === ' ') { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.WRONG_SPACE; } else if (character === '"') { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.WRONG_QUOTE; } else if ( character === '(' || @@ -164,7 +163,6 @@ export const quicklyAnalyzeVariableName = ( character === '/' || character === '*' ) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.WRONG_EXPRESSION; } } @@ -172,12 +170,10 @@ export const quicklyAnalyzeVariableName = ( const rootVariableName = getRootVariableName(name); // Check at least the name of the root variable, it's the best we can do. if (!isRootVariableDeclared(rootVariableName, variablesContainers)) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.UNDECLARED_VARIABLE; } if (!projectScopedContainersAccessor) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.OK; } const projectScopedContainers = projectScopedContainersAccessor.get(); @@ -188,7 +184,6 @@ export const quicklyAnalyzeVariableName = ( .getObjectsContainersList() .hasObjectOrGroupNamed(rootVariableName) ) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.NAME_COLLISION_WITH_OBJECT; } @@ -202,16 +197,13 @@ export const quicklyAnalyzeVariableName = ( ); if (variableSource === gd.VariablesContainer.Parameters) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.PARAMETER_WITH_CHILD; } if (variableSource === gd.VariablesContainer.Properties) { - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.PROPERTY_WITH_CHILD; } } - // $FlowFixMe[incompatible-type] return VariableNameQuickAnalyzeResults.OK; }; @@ -584,7 +576,6 @@ export default (React.forwardRef( onRequestClose={onRequestClose} onApply={onApply} filterOptionById={filterOptionById} - // $FlowFixMe[incompatible-type] dataSource={[ ...autocompletionVariableNames, ...(editEventsFunctionParameter From 08f5870f46ca30c4bf7f9fbc5638fdd84693bd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 14:33:00 +0200 Subject: [PATCH 8/9] Fix should not add a property when the field is empty --- .../EventsSheet/ParameterFields/VariableField.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index 3b0837aed4e6..dbe583808cd2 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -376,10 +376,9 @@ export default (React.forwardRef( onChange(fieldCurrentValue); editEventsFunctionParameter({ variableName: fieldCurrentValue, - shouldCreate: !isRootVariableDeclared( - fieldCurrentValue, - variablesContainers - ), + shouldCreate: + !!fieldCurrentValue && + !isRootVariableDeclared(fieldCurrentValue, variablesContainers), variableType: instruction ? getVariableTypeName( gd.VariableInstructionSwitcher.getSwitchableInstructionVariableType( @@ -412,10 +411,9 @@ export default (React.forwardRef( onChange(fieldCurrentValue); openEventsBasedEntityPropertyEditorDialog({ variableName: fieldCurrentValue, - shouldCreate: !isRootVariableDeclared( - fieldCurrentValue, - variablesContainers - ), + shouldCreate: + !!fieldCurrentValue && + !isRootVariableDeclared(fieldCurrentValue, variablesContainers), variableType: instruction ? getVariableTypeName( gd.VariableInstructionSwitcher.getSwitchableInstructionVariableType( From dca6adad4d297197af8394c39efbdd97e2c78793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 17 Jun 2026 15:47:58 +0200 Subject: [PATCH 9/9] Remove dead code --- ...EventsBasedBehaviorOrObjectEditorDialog.js | 35 +++++++++++-------- ...tsBasedBehaviorOrObjectPropertiesEditor.js | 7 ++-- .../PropertyListEditor/index.js | 11 ++---- .../EventsFunctionsExtensionEditor/index.js | 7 ++-- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js index f2c83c3fd4e4..35f6021c1780 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectEditorDialog.js @@ -152,20 +152,26 @@ export default function EventsBasedBehaviorOrObjectEditorDialog({ : initiallySelectedProperty.variableType; addProperty(initiallySelectedProperty.variableName, propertyType); } else { - const currentPropertyEditor = propertyEditor.current; - if (currentPropertyEditor) { - currentPropertyEditor.scrollToProperty( - initiallySelectedProperty.variableName, - false - ); - } - const currentPropertyList = propertyList.current; - if (currentPropertyList) { - currentPropertyList.setSelectedProperty( - initiallySelectedProperty.variableName, - false - ); - } + // Scroll to the selected property. + // Ideally, we'd wait for the list to be updated to scroll, but + // to simplify the code, we just wait a few ms for a new render + // to be done. + setTimeout(() => { + const currentPropertyEditor = propertyEditor.current; + if (currentPropertyEditor) { + currentPropertyEditor.scrollToProperty( + initiallySelectedProperty.variableName, + false + ); + } + const currentPropertyList = propertyList.current; + if (currentPropertyList) { + currentPropertyList.setSelectedProperty( + initiallySelectedProperty.variableName, + false + ); + } + }, 100); // A few ms is enough for a new render to be done. } }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -209,7 +215,6 @@ export default function EventsBasedBehaviorOrObjectEditorDialog({ } }} onEventsFunctionsAdded={onEventsFunctionsAdded} - initiallySelectedProperty={initiallySelectedProperty} /> ), }, diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js index ddf17c735685..6127bdea0ae2 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/EventsBasedBehaviorOrObjectEditor/EventsBasedBehaviorOrObjectPropertiesEditor.js @@ -212,6 +212,9 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ ) => { const forceUpdate = useForceUpdate(); const propertyRefs = React.useRef(new Map>()); + const propertyNameFieldRefs = React.useRef( + new Map() + ); React.useImperativeHandle(ref, () => ({ forceUpdate, getPropertyEditorRef: (propertyName: string) => @@ -226,9 +229,6 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ } }, })); - const propertyNameFieldRefs = React.useRef( - new Map() - ); const [newBehaviorDialogOpen, setNewBehaviorDialogOpen] = React.useState<{ behaviorProperty: gdNamedPropertyDescriptor, @@ -247,7 +247,6 @@ export const EventsBasedBehaviorOrObjectPropertiesEditor: React.ComponentType<{ property.setType('Number'); forceUpdate(); onPropertiesUpdated(); - //setJustAddedPropertyName(newName); }, [forceUpdate, onPropertiesUpdated, properties] ); diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js index 0902b5a050de..c8ebb46e48b1 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/PropertyListEditor/index.js @@ -53,7 +53,6 @@ import { getFoldersAscendanceWithoutRootFolder, enumerateFoldersInContainer, } from './EnumeratePropertyFolderOrProperty'; -import { type VariableDialogOpeningProps } from '../../VariablesList/VariablesEditorDialog'; const configurationItemId = 'events-based-entity-configuration'; export const propertiesRootFolderId = 'properties'; @@ -505,7 +504,6 @@ type Props = {| onOpenConfiguration: () => void, onOpenProperty: (name: string, isSharedProperties: boolean) => void, onEventsFunctionsAdded: () => void, - initiallySelectedProperty: VariableDialogOpeningProps | null, |}; const PropertyListEditor = React.forwardRef( @@ -521,7 +519,6 @@ const PropertyListEditor = React.forwardRef( onOpenConfiguration, onOpenProperty, onEventsFunctionsAdded, - initiallySelectedProperty, }, ref ) => { @@ -603,13 +600,11 @@ const PropertyListEditor = React.forwardRef( properties: gdPropertiesContainer, isSharedProperties: boolean, parentFolder: gdPropertyFolderOrProperty, - index: number, - name?: string, - type?: string | null + index: number ) => { if (!properties) return; - const newName = newNameGenerator(name || 'Property', name => + const newName = newNameGenerator('Property', name => properties.has(name) ); const property = properties.insertNewPropertyInFolder( @@ -617,7 +612,7 @@ const PropertyListEditor = React.forwardRef( parentFolder, index ); - property.setType(type || 'Number'); + property.setType('Number'); onPropertiesUpdated(); diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index 6c6d564e9b4d..816e0430a011 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -8,6 +8,7 @@ import * as React from 'react'; import EventsSheet, { type EventsSheetInterface } from '../EventsSheet'; import EditorMosaic, { type EditorMosaicInterface, + type EditorMosaicNode, mosaicContainsNode, } from '../UI/EditorMosaic'; import { type Editor } from '../UI/EditorMosaic'; @@ -132,7 +133,7 @@ const extensionEditIconReactNode = ; // The event based object editor is hidden in releases // because it's not handled by GDJS. -const getInitialMosaicEditorNodes = () => ({ +const getInitialMosaicEditorNodes = (): EditorMosaicNode => ({ direction: 'row', first: 'functions-list', second: { @@ -1510,7 +1511,6 @@ export default class EventsFunctionsExtensionEditor extends React.Component< this.eventsFunctionList.forceUpdateList(); } }} - initiallySelectedProperty={null} /> ) : ( @@ -1862,16 +1862,13 @@ export default class EventsFunctionsExtensionEditor extends React.Component< mosaicContainsNode( getDefaultEditorMosaicNode( 'events-functions-extension-editor' - // $FlowFixMe[incompatible-type] ) || getInitialMosaicEditorNodes(), 'functions-list' ) ? getDefaultEditorMosaicNode( 'events-functions-extension-editor' - // $FlowFixMe[incompatible-type] ) || getInitialMosaicEditorNodes() : // Force the mosaic to reset to default. - // $FlowFixMe[incompatible-type] getInitialMosaicEditorNodes() } />