From cea300ada2bb21e4fcb1ccb30d77832cbbb7b355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Mon, 20 Jan 2025 18:36:16 +0100 Subject: [PATCH] Fix conflict between variable or property and parameter in variable setters --- .../CodeGeneration/EventsCodeGenerator.h | 13 +++- .../ExpressionCodeGenerator.cpp | 16 +++-- .../EventsVariableInstructionTypeSwitcher.cpp | 5 ++ .../Project/VariablesContainersList.cpp | 28 +++++++++ Core/GDCore/Project/VariablesContainersList.h | 12 ++++ .../CodeGeneration/EventsCodeGenerator.cpp | 17 +++-- .../Extensions/Builtin/VariablesExtension.cpp | 6 +- GDevelop.js/Bindings/Bindings.idl | 2 + ...SBehaviorCodeGenerationIntegrationTests.js | 63 +++++++++++++++++++ GDevelop.js/types.d.ts | 2 + .../types/gdvariablescontainerslist.js | 2 + .../Renderers/ForEachChildVariableEvent.js | 13 ++-- .../ParameterFields/AnyVariableField.js | 30 ++++++++- .../AnyVariableOrPropertyField.js | 31 ++++++++- .../AnyVariableOrPropertyOrParameterField.js | 29 ++++++++- .../ParameterFields/GlobalVariableField.js | 26 +++++++- .../ParameterFields/ObjectVariableField.js | 24 ++++++- .../ParameterFields/SceneVariableField.js | 26 +++++++- .../ParameterFields/VariableField.js | 61 ++++++++---------- 19 files changed, 340 insertions(+), 66 deletions(-) diff --git a/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h b/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h index 79f3c8ce04d4..e5ddafd15eaa 100644 --- a/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h +++ b/Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.h @@ -467,7 +467,14 @@ class GD_CORE_API EventsCodeGenerator { */ virtual gd::String GetCodeNamespace() { return ""; }; - enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE }; + enum VariableScope { + LAYOUT_VARIABLE = 0, + PROJECT_VARIABLE, + OBJECT_VARIABLE, + ANY_VARIABLE, + VARIABLE_OR_PROPERTY, + VARIABLE_OR_PROPERTY_OR_PARAMETER + }; /** * Generate a single unique number for the specified instruction. @@ -579,7 +586,9 @@ class GD_CORE_API EventsCodeGenerator { } else if (scope == PROJECT_VARIABLE) { return "getProjectVariable(" + variableName + ")"; - } else if (scope == ANY_VARIABLE) { + } else if (scope == ANY_VARIABLE || scope == VARIABLE_OR_PROPERTY || + scope == VARIABLE_OR_PROPERTY_OR_PARAMETER) { + // TODO Split the 3 cases to make tests stronger. return "getAnyVariable(" + variableName + ")"; } diff --git a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp index 9ec8b8a155b6..86aca52b5fc7 100644 --- a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp +++ b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp @@ -133,9 +133,12 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) { if (gd::ParameterMetadata::IsExpression("variable", type)) { // The node is a variable inside an expression waiting for a *variable* to be returned, not its value. EventsCodeGenerator::VariableScope scope = - type == "variable" || type == "variableOrProperty" || - type == "variableOrPropertyOrParameter" + type == "variable" ? gd::EventsCodeGenerator::ANY_VARIABLE + : type == "variableOrProperty" + ? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY + : type == "variableOrPropertyOrParameter" + ? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER : type == "globalvar" ? gd::EventsCodeGenerator::PROJECT_VARIABLE : type == "scenevar" ? gd::EventsCodeGenerator::LAYOUT_VARIABLE : gd::EventsCodeGenerator::OBJECT_VARIABLE; @@ -223,9 +226,12 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) { codeGenerator.GenerateObject(node.identifierName, type, context); } else if (gd::ParameterMetadata::IsExpression("variable", type)) { EventsCodeGenerator::VariableScope scope = - type == "variable" || type == "variableOrProperty" || - type == "variableOrPropertyOrParameter" + type == "variable" ? gd::EventsCodeGenerator::ANY_VARIABLE + : type == "variableOrProperty" + ? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY + : type == "variableOrPropertyOrParameter" + ? gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER : type == "globalvar" ? gd::EventsCodeGenerator::PROJECT_VARIABLE : type == "scenevar" ? gd::EventsCodeGenerator::LAYOUT_VARIABLE : gd::EventsCodeGenerator::OBJECT_VARIABLE; @@ -254,7 +260,7 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) { output += codeGenerator.GenerateVariableValueAs(type); }, [&]() { output += codeGenerator.GenerateGetVariable( - node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context, + node.identifierName, gd::EventsCodeGenerator::VARIABLE_OR_PROPERTY_OR_PARAMETER, context, "", !node.childIdentifierName.empty()); if (!node.childIdentifierName.empty()) { output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName); diff --git a/Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp b/Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp index a580c70cc4e4..fdac82ac5f18 100644 --- a/Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp +++ b/Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp @@ -71,6 +71,11 @@ bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction& .GetObjectsContainersList() .GetObjectOrGroupVariablesContainer(lastObjectName); } + } else if (type == "variableOrProperty") { + variablesContainer = + &GetProjectScopedContainers() + .GetVariablesContainersList() + .GetVariablesContainerFromVariableNameExcludingParameters(variableName); } else { if (GetProjectScopedContainers().GetVariablesContainersList().Has( variableName)) { diff --git a/Core/GDCore/Project/VariablesContainersList.cpp b/Core/GDCore/Project/VariablesContainersList.cpp index 683663ae7405..fc6f73418f0b 100644 --- a/Core/GDCore/Project/VariablesContainersList.cpp +++ b/Core/GDCore/Project/VariablesContainersList.cpp @@ -157,6 +157,34 @@ VariablesContainersList::GetVariablesContainerFromVariableName( return badVariablesContainer; } +const VariablesContainer &VariablesContainersList:: + GetVariablesContainerFromVariableNameExcludingParameters( + const gd::String &variableName) const { + for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend(); + ++it) { + if ((*it)->GetSourceType() != + gd::VariablesContainer::SourceType::Parameters && + (*it)->Has(variableName)) + return **it; + } + return badVariablesContainer; +} + +const VariablesContainer &VariablesContainersList:: + GetVariablesContainerFromVariableNameExcludingParametersAndProperties( + const gd::String &variableName) const { + for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend(); + ++it) { + if ((*it)->GetSourceType() != + gd::VariablesContainer::SourceType::Parameters && + (*it)->GetSourceType() != + gd::VariablesContainer::SourceType::Properties && + (*it)->Has(variableName)) + return **it; + } + return badVariablesContainer; +} + std::size_t VariablesContainersList::GetVariablesContainerPositionFromVariableName( const gd::String &variableName) const { diff --git a/Core/GDCore/Project/VariablesContainersList.h b/Core/GDCore/Project/VariablesContainersList.h index 0b481eea7b6d..c058134fdfb1 100644 --- a/Core/GDCore/Project/VariablesContainersList.h +++ b/Core/GDCore/Project/VariablesContainersList.h @@ -120,6 +120,18 @@ class GD_CORE_API VariablesContainersList { const VariablesContainer & GetVariablesContainerFromVariableName(const gd::String &variableName) const; + /** + * Get the variables container for a given variable. + */ + const VariablesContainer & + GetVariablesContainerFromVariableNameExcludingParameters(const gd::String &variableName) const; + + /** + * Get the variables container for a given variable. + */ + const VariablesContainer & + GetVariablesContainerFromVariableNameExcludingParametersAndProperties(const gd::String &variableName) const; + /** * Get the variables container index for a given variable. */ diff --git a/GDJS/GDJS/Events/CodeGeneration/EventsCodeGenerator.cpp b/GDJS/GDJS/Events/CodeGeneration/EventsCodeGenerator.cpp index bd062712b344..14ba154f7f2f 100644 --- a/GDJS/GDJS/Events/CodeGeneration/EventsCodeGenerator.cpp +++ b/GDJS/GDJS/Events/CodeGeneration/EventsCodeGenerator.cpp @@ -1363,12 +1363,21 @@ gd::String EventsCodeGenerator::GenerateGetVariable( bool hasChild) { gd::String output; const gd::VariablesContainer* variables = NULL; - if (scope == ANY_VARIABLE) { + if (scope == ANY_VARIABLE || scope == VARIABLE_OR_PROPERTY || + scope == VARIABLE_OR_PROPERTY_OR_PARAMETER) { const auto variablesContainersList = GetProjectScopedContainers().GetVariablesContainersList(); - const auto& variablesContainer = - variablesContainersList.GetVariablesContainerFromVariableName( - variableName); + const auto &variablesContainer = + scope == VARIABLE_OR_PROPERTY_OR_PARAMETER + ? variablesContainersList.GetVariablesContainerFromVariableName( + variableName) + : scope == VARIABLE_OR_PROPERTY + ? variablesContainersList + .GetVariablesContainerFromVariableNameExcludingParameters( + variableName) + : variablesContainersList + .GetVariablesContainerFromVariableNameExcludingParametersAndProperties( + variableName); const auto sourceType = variablesContainer.GetSourceType(); if (sourceType == gd::VariablesContainer::SourceType::Scene) { variables = &variablesContainer; diff --git a/GDJS/GDJS/Extensions/Builtin/VariablesExtension.cpp b/GDJS/GDJS/Extensions/Builtin/VariablesExtension.cpp index 0cdf7082a819..843eb21efb78 100644 --- a/GDJS/GDJS/Extensions/Builtin/VariablesExtension.cpp +++ b/GDJS/GDJS/Extensions/Builtin/VariablesExtension.cpp @@ -181,7 +181,7 @@ VariablesExtension::VariablesExtension() { const auto variablesContainersList = codeGenerator.GetProjectScopedContainers().GetVariablesContainersList(); const auto& variablesContainer = - variablesContainersList.GetVariablesContainerFromVariableName( + variablesContainersList.GetVariablesContainerFromVariableNameExcludingParameters( variableName); const auto sourceType = variablesContainer.GetSourceType(); if (sourceType == gd::VariablesContainer::SourceType::Properties) { @@ -244,7 +244,7 @@ VariablesExtension::VariablesExtension() { const auto variablesContainersList = codeGenerator.GetProjectScopedContainers().GetVariablesContainersList(); const auto& variablesContainer = - variablesContainersList.GetVariablesContainerFromVariableName( + variablesContainersList.GetVariablesContainerFromVariableNameExcludingParameters( variableName); const auto sourceType = variablesContainer.GetSourceType(); if (sourceType == gd::VariablesContainer::SourceType::Properties) { @@ -304,7 +304,7 @@ VariablesExtension::VariablesExtension() { const auto variablesContainersList = codeGenerator.GetProjectScopedContainers().GetVariablesContainersList(); const auto& variablesContainer = - variablesContainersList.GetVariablesContainerFromVariableName( + variablesContainersList.GetVariablesContainerFromVariableNameExcludingParameters( variableName); const auto sourceType = variablesContainer.GetSourceType(); if (sourceType == gd::VariablesContainer::SourceType::Properties) { diff --git a/GDevelop.js/Bindings/Bindings.idl b/GDevelop.js/Bindings/Bindings.idl index 845cc7eb43d8..9e620feead37 100644 --- a/GDevelop.js/Bindings/Bindings.idl +++ b/GDevelop.js/Bindings/Bindings.idl @@ -342,6 +342,8 @@ interface VariablesContainersList { boolean Has([Const] DOMString name); [Const, Ref] Variable Get([Const] DOMString name); [Const, Ref] VariablesContainer GetVariablesContainerFromVariableName([Const] DOMString variableName); + [Const, Ref] VariablesContainer GetVariablesContainerFromVariableNameExcludingParameters([Const] DOMString variableName); + [Const, Ref] VariablesContainer GetVariablesContainerFromVariableNameExcludingParametersAndProperties([Const] DOMString variableName); [Const, Ref] VariablesContainer GetVariablesContainer(unsigned long index); unsigned long GetVariablesContainersCount(); diff --git a/GDevelop.js/__tests__/GDJSBehaviorCodeGenerationIntegrationTests.js b/GDevelop.js/__tests__/GDJSBehaviorCodeGenerationIntegrationTests.js index e957c5c12fea..c89fd34193a2 100644 --- a/GDevelop.js/__tests__/GDJSBehaviorCodeGenerationIntegrationTests.js +++ b/GDevelop.js/__tests__/GDJSBehaviorCodeGenerationIntegrationTests.js @@ -260,6 +260,69 @@ describe('libGD.js - GDJS Behavior Code Generation integration tests', function expect(behavior._getMyProperty()).toBe(456); }); + it('Can use a property in a variable action when a parameter with the same name exits', () => { + const project = new gd.ProjectHelper.createNewGDJSProject(); + const eventsFunctionsExtension = project.insertNewEventsFunctionsExtension( + 'MyExtension', + 0 + ); + const eventsBasedBehavior = eventsFunctionsExtension + .getEventsBasedBehaviors() + .insertNew('MyBehavior', 0); + + eventsBasedBehavior + .getPropertyDescriptors() + .insertNew('MyIdentifier', 0) + .setValue('123') + .setType('Number'); + + const eventsSerializerElement = gd.Serializer.fromJSObject([ + { + type: 'BuiltinCommonInstructions::Standard', + conditions: [], + actions: [ + { + type: { value: 'SetNumberVariable' }, + parameters: ['MyIdentifier', '=', '456'], + }, + ], + }, + ]); + eventsBasedBehavior + .getEventsFunctions() + .insertNewEventsFunction('MyFunction', 0) + .getEvents() + .unserializeFrom(project, eventsSerializerElement); + gd.WholeProjectRefactorer.ensureBehaviorEventsFunctionsProperParameters( + eventsFunctionsExtension, + eventsBasedBehavior + ); + const eventsFunction = eventsBasedBehavior + .getEventsFunctions() + .insertNewEventsFunction('MyFunction', 0); + const parameter = eventsFunction + .getParameters() + .insertNewParameter( + 'MyIdentifier', + eventsFunction.getParameters().getParametersCount() + ); + parameter.setType('number'); + + const { runtimeScene, behavior } = generatedBehavior( + gd, + project, + eventsFunctionsExtension, + eventsBasedBehavior, + { logCode: false } + ); + + // Check the default value is set. + expect(behavior._getMyIdentifier()).toBe(123); + + behavior.MyFunction(); + expect(behavior._getMyIdentifier()).toBe(456); + }); + it('Can use a property in a variable condition', () => { const project = new gd.ProjectHelper.createNewGDJSProject(); const scene = project.insertNewLayout('MyScene', 0); diff --git a/GDevelop.js/types.d.ts b/GDevelop.js/types.d.ts index 6c480b6921d1..17e126cf5869 100644 --- a/GDevelop.js/types.d.ts +++ b/GDevelop.js/types.d.ts @@ -362,6 +362,8 @@ export class VariablesContainersList extends EmscriptenObject { has(name: string): boolean; get(name: string): Variable; getVariablesContainerFromVariableName(variableName: string): VariablesContainer; + getVariablesContainerFromVariableNameExcludingParameters(variableName: string): VariablesContainer; + getVariablesContainerFromVariableNameExcludingParametersAndProperties(variableName: string): VariablesContainer; getVariablesContainer(index: number): VariablesContainer; getVariablesContainersCount(): number; } diff --git a/GDevelop.js/types/gdvariablescontainerslist.js b/GDevelop.js/types/gdvariablescontainerslist.js index c6666e3f30dd..7ce255aaa5f7 100644 --- a/GDevelop.js/types/gdvariablescontainerslist.js +++ b/GDevelop.js/types/gdvariablescontainerslist.js @@ -3,6 +3,8 @@ declare class gdVariablesContainersList { has(name: string): boolean; get(name: string): gdVariable; getVariablesContainerFromVariableName(variableName: string): gdVariablesContainer; + getVariablesContainerFromVariableNameExcludingParameters(variableName: string): gdVariablesContainer; + getVariablesContainerFromVariableNameExcludingParametersAndProperties(variableName: string): gdVariablesContainer; getVariablesContainer(index: number): gdVariablesContainer; getVariablesContainersCount(): number; delete(): void; diff --git a/newIDE/app/src/EventsSheet/EventsTree/Renderers/ForEachChildVariableEvent.js b/newIDE/app/src/EventsSheet/EventsTree/Renderers/ForEachChildVariableEvent.js index 2bd7332de53d..f570f119f669 100644 --- a/newIDE/app/src/EventsSheet/EventsTree/Renderers/ForEachChildVariableEvent.js +++ b/newIDE/app/src/EventsSheet/EventsTree/Renderers/ForEachChildVariableEvent.js @@ -14,10 +14,9 @@ import { } from '../ClassNames'; import InlinePopover from '../../InlinePopover'; import AnyVariableField from '../../ParameterFields/AnyVariableField'; -import { - getVariableSourceIcon, - getVariablesContainerSourceType, -} from '../../ParameterFields/VariableField'; +import { getVariableSourceIcon } from '../../ParameterFields/VariableField'; +import { getVariableSourceFromVariableName } from '../../ParameterFields/AnyVariableField'; + import { type ParameterFieldInterface } from '../../ParameterFields/ParameterFieldCommons'; import { type EventRendererProps } from './EventRenderer'; import ConditionsActionsColumns from '../ConditionsActionsColumns'; @@ -31,9 +30,9 @@ export const getVariableSourceOrSceneIcon = ( projectScopedContainersAccessor: ProjectScopedContainersAccessor, variableName: string ) => { - const variablesContainerSourceType = getVariablesContainerSourceType( - projectScopedContainersAccessor, - variableName + const variablesContainerSourceType = getVariableSourceFromVariableName( + variableName, + projectScopedContainersAccessor.get() ); return getVariableSourceIcon( variablesContainerSourceType === gd.VariablesContainer.Unknown diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js index a4093362d300..817817b28060 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableField.js @@ -73,6 +73,18 @@ export default React.forwardRef( [projectScopedContainersAccessor] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => + projectScopedContainersAccessor + .get() + .getVariablesContainersList() + .getVariablesContainerFromVariableNameExcludingParametersAndProperties( + variableName + ) + .getSourceType(), + [projectScopedContainersAccessor] + ); + const onVariableEditorApply = React.useCallback( (selectedVariableName: string | null) => { if (selectedVariableName && selectedVariableName.startsWith(value)) { @@ -121,6 +133,7 @@ export default React.forwardRef( : undefined } onInstructionTypeChanged={onInstructionTypeChanged} + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && ( ( } ); +export const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => { + const rootVariableName = getRootVariableName(variableName); + const variablesContainersList = projectScopedContainers.getVariablesContainersList(); + return variablesContainersList.has(rootVariableName) + ? variablesContainersList + .getVariablesContainerFromVariableNameExcludingParametersAndProperties( + rootVariableName + ) + .getSourceType() + : gd.VariablesContainer.Unknown; +}; + export const renderInlineAnyVariable = (props: ParameterInlineRendererProps) => - renderVariableWithIcon(props, 'variable'); + renderVariableWithIcon(props, 'variable', getVariableSourceFromVariableName); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js index a352d2a27a3a..d1f009cebfa9 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyField.js @@ -71,6 +71,18 @@ export default React.forwardRef( [projectScopedContainersAccessor] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => + projectScopedContainersAccessor + .get() + .getVariablesContainersList() + .getVariablesContainerFromVariableNameExcludingParameters( + variableName + ) + .getSourceType(), + [projectScopedContainersAccessor] + ); + const onVariableEditorApply = React.useCallback( (selectedVariableName: string | null) => { if (selectedVariableName && selectedVariableName.startsWith(value)) { @@ -119,6 +131,7 @@ export default React.forwardRef( : undefined } onInstructionTypeChanged={onInstructionTypeChanged} + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && ( ( } ); +export const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => { + const rootVariableName = getRootVariableName(variableName); + const variablesContainersList = projectScopedContainers.getVariablesContainersList(); + return variablesContainersList.has(rootVariableName) + ? variablesContainersList + .getVariablesContainerFromVariableNameExcludingParameters( + rootVariableName + ) + .getSourceType() + : gd.VariablesContainer.Unknown; +}; + export const renderInlineAnyVariableOrProperty = ( props: ParameterInlineRendererProps -) => renderVariableWithIcon(props, 'variable'); +) => + renderVariableWithIcon(props, 'variable', getVariableSourceFromVariableName); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js index 2eae9458a193..6d992a81e44f 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/AnyVariableOrPropertyOrParameterField.js @@ -16,6 +16,8 @@ import { import { enumerateVariablesOrPropertiesOrParametersOfContainersList } from './EnumerateVariables'; import { mapFor } from '../../Utils/MapFor'; +const gd: libGDevelop = global.gd; + export default React.forwardRef( function AnyVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); @@ -65,6 +67,16 @@ export default React.forwardRef( [projectScopedContainersAccessor] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => + projectScopedContainersAccessor + .get() + .getVariablesContainersList() + .getVariablesContainerFromVariableName(variableName) + .getSourceType(), + [projectScopedContainersAccessor] + ); + const onVariableEditorApply = React.useCallback( (selectedVariableName: string | null) => { if (selectedVariableName && selectedVariableName.startsWith(value)) { @@ -113,6 +125,7 @@ export default React.forwardRef( : undefined } onInstructionTypeChanged={onInstructionTypeChanged} + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && ( ( } ); +export const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => { + const rootVariableName = getRootVariableName(variableName); + const variablesContainersList = projectScopedContainers.getVariablesContainersList(); + return variablesContainersList.has(rootVariableName) + ? variablesContainersList + .getVariablesContainerFromVariableName(rootVariableName) + .getSourceType() + : gd.VariablesContainer.Unknown; +}; + export const renderInlineAnyVariableOrPropertyOrParameter = ( props: ParameterInlineRendererProps -) => renderVariableWithIcon(props, 'variable'); +) => + renderVariableWithIcon(props, 'variable', getVariableSourceFromVariableName); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js index 020ae7b57936..43afbf5f6fce 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/GlobalVariableField.js @@ -13,7 +13,8 @@ import { type FieldFocusFunction, } from './ParameterFieldCommons'; import { enumerateVariables } from './EnumerateVariables'; -import GlobalVariableIcon from '../../UI/CustomSvgIcons/GlobalVariable'; + +const gd: libGDevelop = global.gd; export default React.forwardRef( function GlobalVariableField(props: ParameterFieldProps, ref) { @@ -38,6 +39,16 @@ export default React.forwardRef( [project] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => { + const variablesContainer = variablesContainers.find( + variablesContainer => variablesContainer.has(variableName) + ); + return variablesContainer ? variablesContainer.getSourceType() : null; + }, + [variablesContainers] + ); + const enumerateGlobaleVariables = React.useCallback( () => { return project ? enumerateVariables(project.getVariables()) : []; @@ -63,6 +74,7 @@ export default React.forwardRef( objectsContainer={props.objectsContainer} projectScopedContainersAccessor={projectScopedContainersAccessor} scope={scope} + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && project && ( ( } ); +const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => gd.VariableContainer.Global; + export const renderInlineGlobalVariable = ( props: ParameterInlineRendererProps -) => renderVariableWithIcon(props, 'global variable', GlobalVariableIcon); +) => + renderVariableWithIcon( + props, + 'global variable', + getVariableSourceFromVariableName + ); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js index 42e40f29a8fd..a2a733220429 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/ObjectVariableField.js @@ -16,7 +16,6 @@ import { import { getLastObjectParameterValue } from './ParameterMetadataTools'; import getObjectByName from '../../Utils/GetObjectByName'; import getObjectGroupByName from '../../Utils/GetObjectGroupByName'; -import ObjectVariableIcon from '../../UI/CustomSvgIcons/ObjectVariable'; import { enumerateVariables } from './EnumerateVariables'; import { intersectionBy } from 'lodash'; import EventsRootVariablesFinder from '../../Utils/EventsRootVariablesFinder'; @@ -135,6 +134,16 @@ export default React.forwardRef( ] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => { + const variablesContainer = variablesContainers.find( + variablesContainer => variablesContainer.has(variableName) + ); + return variablesContainer ? variablesContainer.getSourceType() : null; + }, + [variablesContainers] + ); + const enumerateObjectVariables = React.useCallback( () => variablesContainers.length > 0 @@ -205,6 +214,7 @@ export default React.forwardRef( : undefined } onInstructionTypeChanged={onInstructionTypeChanged} + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && project && @@ -248,6 +258,16 @@ export default React.forwardRef( } ); +const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => gd.VariableContainer.Object; + export const renderInlineObjectVariable = ( props: ParameterInlineRendererProps -) => renderVariableWithIcon(props, 'object variable', ObjectVariableIcon); +) => + renderVariableWithIcon( + props, + 'object variable', + getVariableSourceFromVariableName + ); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js index 1e1ae02950a5..900fa417b9ec 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/SceneVariableField.js @@ -13,9 +13,10 @@ import { type FieldFocusFunction, } from './ParameterFieldCommons'; import { enumerateVariables } from './EnumerateVariables'; -import SceneVariableIcon from '../../UI/CustomSvgIcons/SceneVariable'; import GlobalAndSceneVariablesDialog from '../../VariablesList/GlobalAndSceneVariablesDialog'; +const gd: libGDevelop = global.gd; + export default React.forwardRef( function SceneVariableField(props: ParameterFieldProps, ref) { const field = React.useRef(null); @@ -50,6 +51,16 @@ export default React.forwardRef( [eventsFunctionsExtension, layout] ); + const getVariableSourceFromVariableName = React.useCallback( + variableName => { + const variablesContainer = variablesContainers.find( + variablesContainer => variablesContainer.has(variableName) + ); + return variablesContainer ? variablesContainer.getSourceType() : null; + }, + [variablesContainers] + ); + const enumerateSceneVariables = React.useCallback( () => { return layout @@ -95,6 +106,7 @@ export default React.forwardRef( ? `parameter-${props.parameterIndex}-scene-variable-field` : undefined } + getVariableSourceFromVariableName={getVariableSourceFromVariableName} /> {editorOpen && layout && project && ( ( } ); +const getVariableSourceFromVariableName = ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers +): VariablesContainer_SourceType => gd.VariableContainer.Scene; + export const renderInlineSceneVariable = ( props: ParameterInlineRendererProps -) => renderVariableWithIcon(props, 'scene variable', SceneVariableIcon); +) => + renderVariableWithIcon( + props, + 'scene variable', + getVariableSourceFromVariableName + ); diff --git a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js index e210dccafb53..85cdfa6d0628 100644 --- a/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js +++ b/newIDE/app/src/EventsSheet/ParameterFields/VariableField.js @@ -22,7 +22,6 @@ import SemiControlledAutoComplete, { import { TextFieldWithButtonLayout } from '../../UI/Layout'; import { type ParameterInlineRendererProps } from './ParameterInlineRenderer.flow'; import ShareExternal from '../../UI/CustomSvgIcons/ShareExternal'; -import SvgIcon, { type SvgIconProps } from '@material-ui/core/SvgIcon'; import SelectField from '../../UI/SelectField'; import SelectOption from '../../UI/SelectOption'; import { ColumnStackLayout } from '../../UI/Layout'; @@ -55,6 +54,9 @@ type Props = { ...ParameterFieldProps, isObjectVariable: boolean, variablesContainers: Array, + getVariableSourceFromVariableName: ( + variableRootName: string + ) => VariablesContainer_SourceType | null, enumerateVariables: () => Array, forceDeclaration?: boolean, onOpenDialog: (VariableDialogOpeningProps => void) | null, @@ -99,6 +101,9 @@ export const getRootVariableName = (name: string): string => { export const quicklyAnalyzeVariableName = ( name: string, variablesContainers?: Array, + getVariableSourceFromVariableName?: ( + variableRootName: string + ) => VariablesContainer_SourceType | null, projectScopedContainersAccessor?: ProjectScopedContainersAccessor, isObjectVariable: boolean = false ): VariableNameQuickAnalyzeResult => { @@ -151,20 +156,13 @@ export const quicklyAnalyzeVariableName = ( } if (name.length !== rootVariableName.length) { - const variablesContainer = projectScopedContainers - .getVariablesContainersList() - .getVariablesContainerFromVariableName(rootVariableName); - if ( - variablesContainers && - variablesContainers.includes(variablesContainer) - ) { - const variableSource = variablesContainer.getSourceType(); - if (variableSource === gd.VariablesContainer.Parameters) { - return VariableNameQuickAnalyzeResults.PARAMETER_WITH_CHILD; - } - if (variableSource === gd.VariablesContainer.Properties) { - return VariableNameQuickAnalyzeResults.PROPERTY_WITH_CHILD; - } + const variableSource = getVariableSourceFromVariableName(rootVariableName); + + if (variableSource === gd.VariablesContainer.Parameters) { + return VariableNameQuickAnalyzeResults.PARAMETER_WITH_CHILD; + } + if (variableSource === gd.VariablesContainer.Properties) { + return VariableNameQuickAnalyzeResults.PROPERTY_WITH_CHILD; } } @@ -230,6 +228,7 @@ export default React.forwardRef( id, onInstructionTypeChanged, isObjectVariable, + getVariableSourceFromVariableName, } = props; const field = React.useRef(null); @@ -321,6 +320,7 @@ export default React.forwardRef( const quicklyAnalysisResult = quicklyAnalyzeVariableName( value, variablesContainers, + getVariableSourceFromVariableName, projectScopedContainersAccessor, isObjectVariable ); @@ -496,21 +496,6 @@ export default React.forwardRef( } ); -export const getVariablesContainerSourceType = ( - projectScopedContainersAccessor: ProjectScopedContainersAccessor, - variableName: string -) => { - const rootVariableName = getRootVariableName(variableName); - const variablesContainersList = projectScopedContainersAccessor - .get() - .getVariablesContainersList(); - return variablesContainersList.has(rootVariableName) - ? variablesContainersList - .getVariablesContainerFromVariableName(rootVariableName) - .getSourceType() - : gd.VariablesContainer.Unknown; -}; - export const renderVariableWithIcon = ( { value, @@ -521,16 +506,20 @@ export const renderVariableWithIcon = ( projectScopedContainersAccessor, }: ParameterInlineRendererProps, tooltip: string, - ForcedVariableIcon?: SvgIconProps => React.Element + getVariableSourceFromVariableName: ( + variableName: string, + projectScopedContainers: gdProjectScopedContainers + ) => VariablesContainer_SourceType ) => { if (!value && !parameterMetadata.isOptional()) { return ; } - const VariableIcon = - ForcedVariableIcon || - getVariableSourceIcon( - getVariablesContainerSourceType(projectScopedContainersAccessor, value) - ); + const VariableIcon = getVariableSourceIcon( + getVariableSourceFromVariableName( + value, + projectScopedContainersAccessor.get() + ) + ); const IconAndNameContainer = expressionIsValid ? React.Fragment