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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetDefaultValue("True")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("yesorno", _("Value"))
Expand Down Expand Up @@ -887,7 +887,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetDefaultValue("True")
.SetHelpPath("/all-features/variables/object-variables/")
.SetRelevantForFunctionEventsOnly();

Expand Down
6 changes: 3 additions & 3 deletions Core/GDCore/Extensions/Builtin/VariablesExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/conditions/var.png")
.AddParameter("variableOrPropertyOrParameter", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetDefaultValue("True")
// This parameter allows to keep the operand expression
// when the editor switch between variable instructions.
.AddCodeOnlyParameter("trueorfalse", "");
Expand Down Expand Up @@ -318,7 +318,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetDefaultValue("True")
.SetRelevantForFunctionEventsOnly()
.SetHidden();

Expand Down Expand Up @@ -407,7 +407,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.AddParameter("trueorfalse", _("Check if the value is"))
.SetDefaultValue("true")
.SetDefaultValue("True")
.SetRelevantForFunctionEventsOnly()
.SetHidden();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,14 @@ bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction&
lastObjectName == groupName) {
if (typeChangedVariableNames.find(variableName) !=
typeChangedVariableNames.end()) {
const gd::String previousType = instruction.GetType();
gd::VariableInstructionSwitcher::
SwitchBetweenUnifiedInstructionIfNeeded(
platform, GetProjectScopedContainers(), instruction);
if (instruction.GetType() != previousType) {
gd::VariableInstructionSwitcher::ResetParametersAfterSwitch(
instruction);
}
}
}
});
Expand Down
72 changes: 72 additions & 0 deletions Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,76 @@ void VariableInstructionSwitcher::SwitchBetweenUnifiedInstructionIfNeeded(
}
}

void VariableInstructionSwitcher::ResetParametersAfterSwitch(
gd::Instruction &instruction) {
const gd::String &newType = instruction.GetType();

// Reset the operator parameter at `paramIndex` to `defaultValue` if its
// current value is not in `validValues`.
auto resetIfInvalid = [&instruction](
std::size_t paramIndex,
std::initializer_list<const char *> validValues,
const char *defaultValue) {
if (instruction.GetParametersCount() <= paramIndex) return;
const gd::String &value =
instruction.GetParameter(paramIndex).GetPlainString();
for (const char *v : validValues) {
if (value == v) return; // value is valid, nothing to do
}
instruction.SetParameter(paramIndex, gd::Expression(defaultValue));
};

// Helper: clear param at paramIndex if it holds a boolean-like value that is
// not a valid expression (left by a PushBoolean switch).
auto clearIfBooleanLiteral = [&instruction](std::size_t paramIndex) {
if (instruction.GetParametersCount() <= paramIndex) return;
const gd::String &value =
instruction.GetParameter(paramIndex).GetPlainString();
if (value == "True" || value == "False") {
instruction.SetParameter(paramIndex, gd::Expression(""));
}
};

// Scene variable conditions (operator at param 1)
if (newType == "BooleanVariable") {
resetIfInvalid(1, {"True", "False"}, "True");
} else if (newType == "NumberVariable") {
resetIfInvalid(1, {"=", "<", ">", "<=", ">=", "!="}, "=");
} else if (newType == "StringVariable") {
resetIfInvalid(1, {"=", "!=", "startsWith", "endsWith", "contains"}, "=");
// Scene variable Set actions (operator at param 1)
} else if (newType == "SetBooleanVariable") {
resetIfInvalid(1, {"True", "False", "Toggle"}, "True");
} else if (newType == "SetNumberVariable") {
resetIfInvalid(1, {"=", "+", "-", "*", "/"}, "=");
} else if (newType == "SetStringVariable") {
resetIfInvalid(1, {"=", "+"}, "=");
// Scene variable Push actions (expression at param 1)
} else if (newType == "PushBoolean") {
resetIfInvalid(1, {"True", "False"}, "True");
} else if (newType == "PushNumber" || newType == "PushString") {
clearIfBooleanLiteral(1);
// Object variable conditions (operator at param 2)
} else if (newType == "BooleanObjectVariable") {
resetIfInvalid(2, {"True", "False"}, "True");
} else if (newType == "NumberObjectVariable") {
resetIfInvalid(2, {"=", "<", ">", "<=", ">=", "!="}, "=");
} else if (newType == "StringObjectVariable") {
resetIfInvalid(2, {"=", "!=", "startsWith", "endsWith", "contains"}, "=");
// Object variable Set actions (operator at param 2)
} else if (newType == "SetBooleanObjectVariable") {
resetIfInvalid(2, {"True", "False", "Toggle"}, "True");
} else if (newType == "SetNumberObjectVariable") {
resetIfInvalid(2, {"=", "+", "-", "*", "/"}, "=");
} else if (newType == "SetStringObjectVariable") {
resetIfInvalid(2, {"=", "+"}, "=");
// Object variable Push actions (expression at param 2)
} else if (newType == "PushBooleanToObjectVariable") {
resetIfInvalid(2, {"True", "False"}, "True");
} else if (newType == "PushNumberToObjectVariable" ||
newType == "PushStringToObjectVariable") {
clearIfBooleanLiteral(2);
}
}

} // namespace gd
9 changes: 9 additions & 0 deletions Core/GDCore/IDE/VariableInstructionSwitcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ class GD_CORE_API VariableInstructionSwitcher {
const gd::ProjectScopedContainers &projectScopedContainers,
gd::Instruction &instruction);

/**
* \brief After a type switch, fix the operator parameter if its current value
* is no longer valid for the new instruction type. Call this when the type
* actually changed. Covers all switchable variable instruction variants:
* conditions, Set actions, and Push (array) actions, for both scene and
* object variables.
*/
static void ResetParametersAfterSwitch(gd::Instruction &instruction);

private:
static const gd::String variableGetterIdentifier;
static const gd::String variableSetterIdentifier;
Expand Down
44 changes: 30 additions & 14 deletions newIDE/app/src/EventsSheet/InlineParameterEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,26 +126,42 @@ const InlineParameterEditor = ({
// When the parameter is done being edited, ensure the instruction parameters
// are properly set up. For example, it's possible that the object name was
// changed, and so the associated behavior should be updated.
if (instruction && instructionMetadata) {
const objectParameterIndex = getObjectParameterIndex(
instructionMetadata
);
setupInstructionParameters(
project,
projectScopedContainersAccessor,
instruction,
instructionMetadata,
objectParameterIndex !== -1
? instruction.getParameter(objectParameterIndex).getPlainString()
: null
);
// Use the current instruction type to get metadata — the type may have
// switched during editing (e.g. boolean → number variable), so the
// metadata stored in state when the editor opened may be stale and using
// it would corrupt the operator parameter.
if (instruction) {
const currentType = instruction.getType();
const currentInstructionMetadata = isCondition
? gd.MetadataProvider.getConditionMetadata(
project.getCurrentPlatform(),
currentType
)
: gd.MetadataProvider.getActionMetadata(
project.getCurrentPlatform(),
currentType
);
if (currentInstructionMetadata) {
const objectParameterIndex = getObjectParameterIndex(
currentInstructionMetadata
);
setupInstructionParameters(
project,
projectScopedContainersAccessor,
instruction,
currentInstructionMetadata,
objectParameterIndex !== -1
? instruction.getParameter(objectParameterIndex).getPlainString()
: null
);
}
}

onApply();
},
[
instruction,
instructionMetadata,
isCondition,
onApply,
project,
projectScopedContainersAccessor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { getObjectParameterIndex } from '../../InstructionOrExpression/Enumerate
import Text from '../../UI/Text';
import { getInstructionMetadata } from './InstructionEditor';
import { ColumnStackLayout } from '../../UI/Layout';
import { setupInstructionParameters } from '../../InstructionOrExpression/SetupInstructionParameters';
import {
setupInstructionParameters,
resetParametersAfterSwitch,
} from '../../InstructionOrExpression/SetupInstructionParameters';
import ScrollView from '../../UI/ScrollView';
import { getInstructionTutorialIds } from '../../Utils/GDevelopServices/Tutorial';
import useForceUpdate from '../../Utils/UseForceUpdate';
Expand Down Expand Up @@ -241,11 +244,15 @@ const InstructionParametersEditor: React.ComponentType<{
[focus, focusOnMount]
);

const typeBeforeSwitch = instruction.getType();
gd.VariableInstructionSwitcher.switchBetweenUnifiedInstructionIfNeeded(
project.getCurrentPlatform(),
projectScopedContainersAccessor.get(),
instruction
);
if (instruction.getType() !== typeBeforeSwitch) {
resetParametersAfterSwitch(instruction);
}

const instructionType = instruction.getType();

Expand Down
5 changes: 5 additions & 0 deletions newIDE/app/src/EventsSheet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
unregisterOnResourceExternallyChangedCallback,
} from '../MainFrame/ResourcesWatcher';
import { ProjectScopedContainersAccessor } from '../InstructionOrExpression/EventsScope';
import { resetParametersAfterSwitch } from '../InstructionOrExpression/SetupInstructionParameters';
import LocalVariablesDialog from '../VariablesList/LocalVariablesDialog';
import GlobalAndSceneVariablesDialog from '../VariablesList/GlobalAndSceneVariablesDialog';
import { type HotReloadPreviewButtonProps } from '../HotReload/HotReloadPreviewButton';
Expand Down Expand Up @@ -2670,11 +2671,15 @@ export class EventsSheetComponentWithoutHandle extends React.Component<
}
instruction.setParameter(parameterIndex, value);

const typeBeforeSwitch = instruction.getType();
gd.VariableInstructionSwitcher.switchBetweenUnifiedInstructionIfNeeded(
project.getCurrentPlatform(),
editedParameterProjectScopedContainersAccessor.get(),
instruction
);
if (instruction.getType() !== typeBeforeSwitch) {
resetParametersAfterSwitch(instruction);
}

// Ask the component to re-render, so that the new parameter
// set for the instruction in the state
Expand Down
Loading
Loading