mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
18 Commits
cursor/add
...
event-func
Author | SHA1 | Date | |
---|---|---|---|
![]() |
249775ee2f | ||
![]() |
6bcc810489 | ||
![]() |
2a763f18dd | ||
![]() |
b401a4cb08 | ||
![]() |
b2b0540f93 | ||
![]() |
be59a629f0 | ||
![]() |
a40b36d52e | ||
![]() |
cc12ab662d | ||
![]() |
0b8d6986ff | ||
![]() |
fbb985833f | ||
![]() |
1b3734ff6b | ||
![]() |
6288b30ac3 | ||
![]() |
ee435f7081 | ||
![]() |
d75b4eb2a9 | ||
![]() |
5eeb505807 | ||
![]() |
30566e35ce | ||
![]() |
e058b7f295 | ||
![]() |
902a30a9f8 |
@@ -18,19 +18,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAnimatableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("AnimatableCapability",
|
||||
_("Objects with animations"),
|
||||
_("Actions and conditions for objects having animations (sprite, 3D models...)."),
|
||||
_("Animate objects."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Animatable capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects with animations"))
|
||||
.SetIcon("res/actions/animation24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Animations and images"))
|
||||
.SetIcon("res/actions/animation24.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"AnimatableBehavior",
|
||||
_("Animatable capability"),
|
||||
_("Objects with animations"),
|
||||
"Animation",
|
||||
_("Actions and conditions for objects having animations (sprite, 3D models...).."),
|
||||
"",
|
||||
|
@@ -18,7 +18,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("EffectCapability",
|
||||
_("Effect capability"),
|
||||
_("Objects with effects"),
|
||||
_("Actions/conditions to enable/disable and change parameters of visual effects applied on objects."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
@@ -28,7 +28,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"EffectBehavior",
|
||||
_("Effect capability"),
|
||||
_("Objects with effects"),
|
||||
"Effect",
|
||||
_("Actions/conditions to enable/disable and change parameters of visual effects applied on objects."),
|
||||
"",
|
||||
|
@@ -18,7 +18,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("FlippableCapability",
|
||||
_("Flippable capability"),
|
||||
_("Flippable objects"),
|
||||
_("Actions/conditions for objects which can be flipped horizontally or vertically."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
@@ -28,7 +28,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFlippableExtension(
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"FlippableBehavior",
|
||||
_("Flippable capability"),
|
||||
_("Flippable objects"),
|
||||
"Flippable",
|
||||
_("Actions/conditions for objects which can be flipped horizontally or vertically."),
|
||||
"",
|
||||
|
@@ -18,13 +18,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("OpacityCapability",
|
||||
_("Opacity capability"),
|
||||
_("Objects with opacity"),
|
||||
_("Action/condition/expression to change or "
|
||||
"check the opacity of an object (0-255)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Opacity capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects with opacity"))
|
||||
.SetIcon("res/actions/opacity24.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Visibility"))
|
||||
.SetIcon("res/actions/opacity24.png");
|
||||
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsOpacityExtension(
|
||||
gd::BehaviorMetadata& aut =
|
||||
extension
|
||||
.AddBehavior("OpacityBehavior",
|
||||
_("Opacity capability"),
|
||||
_("Objects with opacity"),
|
||||
"Opacity",
|
||||
_("Action/condition/expression to change or check the "
|
||||
"opacity of an object (0-255)."),
|
||||
|
@@ -18,7 +18,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsResizableExtension(
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"ResizableCapability",
|
||||
_("Resizable capability"),
|
||||
_("Resizable objects"),
|
||||
_("Change or compare the size (width/height) of an object which can "
|
||||
"be resized (i.e: most objects)."),
|
||||
"Florian Rival",
|
||||
@@ -30,7 +30,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsResizableExtension(
|
||||
gd::BehaviorMetadata &aut =
|
||||
extension
|
||||
.AddBehavior("ResizableBehavior",
|
||||
_("Resizable capability"),
|
||||
_("Resizable objects"),
|
||||
"Resizable",
|
||||
_("Change or compare the size (width/height) of an "
|
||||
"object which can be resized (i.e: most objects)."),
|
||||
|
@@ -18,13 +18,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("ScalableCapability",
|
||||
_("Scalable capability"),
|
||||
_("Scalable objects"),
|
||||
_("Actions/conditions/expression to change or "
|
||||
"check the scale of an object (default: 1)."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Scalable capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Scalable objects"))
|
||||
.SetIcon("res/actions/scale24_black.png");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Size")).SetIcon(
|
||||
"res/actions/scale24_black.png");
|
||||
@@ -32,7 +32,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsScalableExtension(
|
||||
gd::BehaviorMetadata& aut =
|
||||
extension
|
||||
.AddBehavior("ScalableBehavior",
|
||||
_("Scalable capability"),
|
||||
_("Scalable objects"),
|
||||
"Scale",
|
||||
_("Actions/conditions/expression to change or check the "
|
||||
"scale of an object (default: 1)."),
|
||||
|
@@ -18,17 +18,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTextContainerExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("TextContainerCapability",
|
||||
_("Text capability"),
|
||||
_("Objects containing a text"),
|
||||
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Text capability"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Objects containing a text"))
|
||||
.SetIcon("res/conditions/text24_black.png");
|
||||
|
||||
gd::BehaviorMetadata& aut = extension.AddBehavior(
|
||||
"TextContainerBehavior",
|
||||
_("Text capability"),
|
||||
_("Objects containing a text"),
|
||||
"Text",
|
||||
_("Allows an object to contain a text, usually shown on screen, that can be modified."),
|
||||
"",
|
||||
|
@@ -235,6 +235,9 @@ class GD_CORE_API EventsFunction {
|
||||
|
||||
/**
|
||||
* \brief Return the parameters of the function that are used in the events.
|
||||
*
|
||||
* \warning `ActionWithOperator` function are muted by this function. Make sure
|
||||
* to use the right functions container to avoid strange side effects.
|
||||
*
|
||||
* \note During code/extension generation, new parameters are added
|
||||
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
|
||||
|
@@ -162,7 +162,12 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationX')
|
||||
.setGetter('getRotationX');
|
||||
|
||||
@@ -178,7 +183,12 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationY')
|
||||
.setGetter('getRotationY');
|
||||
|
||||
@@ -196,7 +206,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundX');
|
||||
|
||||
@@ -214,7 +224,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundY');
|
||||
|
||||
@@ -232,7 +242,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter('object', _('3D object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setFunctionName('turnAroundZ');
|
||||
}
|
||||
@@ -594,7 +604,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setHidden()
|
||||
.setFunctionName('setRotationX')
|
||||
.setGetter('getRotationX');
|
||||
@@ -611,7 +626,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setHidden()
|
||||
.setFunctionName('setRotationY')
|
||||
.setGetter('getRotationY');
|
||||
@@ -630,7 +650,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundX');
|
||||
@@ -649,7 +669,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundY');
|
||||
@@ -668,7 +688,7 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D model'), 'Model3DObject', false)
|
||||
.addParameter('number', _('Rotation angle'), '', false)
|
||||
.addParameter('number', _('Angle to add (in degrees)'), '', false)
|
||||
.markAsAdvanced()
|
||||
.setHidden()
|
||||
.setFunctionName('turnAroundZ');
|
||||
@@ -1493,7 +1513,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationX')
|
||||
.setHidden()
|
||||
.setGetter('getRotationX');
|
||||
@@ -1510,7 +1535,12 @@ module.exports = {
|
||||
'res/conditions/3d_box.svg'
|
||||
)
|
||||
.addParameter('object', _('3D cube'), 'Cube3DObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.useStandardParameters(
|
||||
'number',
|
||||
gd.ParameterOptions.makeNewOptions().setDescription(
|
||||
_('Angle (in degrees)')
|
||||
)
|
||||
)
|
||||
.setFunctionName('setRotationY')
|
||||
.setHidden()
|
||||
.setGetter('getRotationY');
|
||||
|
@@ -109,17 +109,6 @@ module.exports = {
|
||||
.setLabel(_('Visible on start'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
if (!objectContent.lineHeight) {
|
||||
objectContent.lineHeight = 0;
|
||||
}
|
||||
objectProperties
|
||||
.getOrCreate('lineHeight')
|
||||
.setValue(objectContent.lineHeight.toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Line height'))
|
||||
.setDescription(_('Line height for multiline text (0 for automatic)'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
objectBBText.content = {
|
||||
@@ -131,7 +120,6 @@ module.exports = {
|
||||
fontFamily: 'Arial',
|
||||
align: 'left',
|
||||
verticalTextAlignment: 'top',
|
||||
lineHeight: 0,
|
||||
};
|
||||
|
||||
objectBBText.updateInitialInstanceProperty = function (
|
||||
@@ -406,19 +394,6 @@ module.exports = {
|
||||
expressionLabel: _('Get the wrapping width'),
|
||||
expressionDescription: _('Get the wrapping width'),
|
||||
},
|
||||
{
|
||||
functionName: 'LineHeight',
|
||||
iconPath: 'res/actions/characterSize24.png',
|
||||
type: 'number',
|
||||
instructionLabel: _('Line height'),
|
||||
paramLabel: _('Line height (0 for automatic)'),
|
||||
conditionDescription: _('Compare the line height of the text.'),
|
||||
conditionSentence: _('the line height'),
|
||||
actionDescription: _('Set line height'),
|
||||
actionSentence: _('the line height'),
|
||||
expressionLabel: _('Get the line height'),
|
||||
expressionDescription: _('Get the line height'),
|
||||
},
|
||||
];
|
||||
|
||||
addSettersAndGettersToObject(object, setterAndGetterProperties, 'BBText');
|
||||
|
@@ -102,17 +102,6 @@ namespace gdjs {
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
updateStyle(): void {
|
||||
//@ts-ignore Private member usage.
|
||||
if (this._object._lineHeight > 0) {
|
||||
this._pixiObject.textStyles.default.lineHeight = this._object._lineHeight;
|
||||
} else {
|
||||
// Remove lineHeight to use automatic
|
||||
delete this._pixiObject.textStyles.default.lineHeight;
|
||||
}
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
updatePosition(): void {
|
||||
if (this._object.isWrapping() && this._pixiObject.width !== 0) {
|
||||
const alignmentX =
|
||||
|
@@ -20,8 +20,6 @@ namespace gdjs {
|
||||
/** Alignment of the text: "left", "center" or "right" */
|
||||
align: 'left' | 'center' | 'right';
|
||||
verticalTextAlignment: 'top' | 'center' | 'bottom';
|
||||
/** Line height for multiline text */
|
||||
lineHeight: float;
|
||||
};
|
||||
};
|
||||
export type BBTextObjectData = ObjectData & BBTextObjectDataType;
|
||||
@@ -37,7 +35,6 @@ namespace gdjs {
|
||||
align: string;
|
||||
vta: string;
|
||||
hidden: boolean;
|
||||
lh: float;
|
||||
};
|
||||
|
||||
export type BBTextObjectNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -64,7 +61,6 @@ namespace gdjs {
|
||||
|
||||
_textAlign: string;
|
||||
_verticalTextAlignment: string;
|
||||
_lineHeight: float;
|
||||
|
||||
_renderer: gdjs.BBTextRuntimeObjectRenderer;
|
||||
|
||||
@@ -91,7 +87,6 @@ namespace gdjs {
|
||||
this._textAlign = objectData.content.align;
|
||||
this._verticalTextAlignment =
|
||||
objectData.content.verticalTextAlignment || 'top';
|
||||
this._lineHeight = objectData.content.lineHeight || 0;
|
||||
this.hidden = !objectData.content.visible;
|
||||
|
||||
this._renderer = new gdjs.BBTextRuntimeObjectRenderer(
|
||||
@@ -147,9 +142,6 @@ namespace gdjs {
|
||||
newObjectData.content.verticalTextAlignment
|
||||
);
|
||||
}
|
||||
if (oldObjectData.content.lineHeight !== newObjectData.content.lineHeight) {
|
||||
this.setLineHeight(newObjectData.content.lineHeight || 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -166,7 +158,6 @@ namespace gdjs {
|
||||
align: this._textAlign,
|
||||
vta: this._verticalTextAlignment,
|
||||
hidden: this.hidden,
|
||||
lh: this._lineHeight,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -205,9 +196,6 @@ namespace gdjs {
|
||||
if (this.hidden !== undefined) {
|
||||
this.hide(networkSyncData.hidden);
|
||||
}
|
||||
if (this._lineHeight !== undefined) {
|
||||
this.setLineHeight(networkSyncData.lh);
|
||||
}
|
||||
}
|
||||
|
||||
override extraInitializationFromInitialInstance(
|
||||
@@ -409,23 +397,6 @@ namespace gdjs {
|
||||
: 0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line height of the BBText object.
|
||||
* @return line height in pixels (0 for automatic)
|
||||
*/
|
||||
getLineHeight(): number {
|
||||
return this._lineHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line height of the BBText object.
|
||||
* @param value line height in pixels (0 for automatic)
|
||||
*/
|
||||
setLineHeight(value: float): void {
|
||||
this._lineHeight = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
}
|
||||
// @ts-ignore
|
||||
gdjs.registerObject('BBText::BBText', gdjs.BBTextRuntimeObject);
|
||||
|
@@ -110,17 +110,6 @@ module.exports = {
|
||||
.setLabel(_('Font tint'))
|
||||
.setGroup(_('Font'));
|
||||
|
||||
if (!objectContent.lineHeight) {
|
||||
objectContent.lineHeight = 0;
|
||||
}
|
||||
objectProperties
|
||||
.getOrCreate('lineHeight')
|
||||
.setValue(objectContent.lineHeight.toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Line height'))
|
||||
.setDescription(_('Line height for multiline text (0 for automatic)'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
bitmapTextObject.content = {
|
||||
@@ -133,7 +122,6 @@ module.exports = {
|
||||
textureAtlasResourceName: '',
|
||||
align: 'left',
|
||||
verticalTextAlignment: 'top',
|
||||
lineHeight: 0,
|
||||
};
|
||||
|
||||
bitmapTextObject.updateInitialInstanceProperty = function (
|
||||
@@ -425,21 +413,6 @@ module.exports = {
|
||||
.setFunctionName('setWrappingWidth')
|
||||
.setGetter('getWrappingWidth');
|
||||
|
||||
object
|
||||
.addExpressionAndConditionAndAction(
|
||||
'number',
|
||||
'LineHeight',
|
||||
_('Line height'),
|
||||
_('the line height, in pixels, for multiline text'),
|
||||
_('the line height'),
|
||||
'',
|
||||
'res/actions/characterSize24.png'
|
||||
)
|
||||
.addParameter('object', _('Bitmap text'), 'BitmapTextObject', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions().setDescription(_('Line height (0 for automatic)')))
|
||||
.setFunctionName('setLineHeight')
|
||||
.setGetter('getLineHeight');
|
||||
|
||||
return extension;
|
||||
},
|
||||
|
||||
|
@@ -96,17 +96,6 @@ namespace gdjs {
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
updateStyle(): void {
|
||||
// Note: PIXI.BitmapText doesn't have built-in lineHeight support like PIXI.Text
|
||||
// The lineHeight would need to be handled at a higher level during text layout
|
||||
// For now, we just mark the object as dirty to trigger a re-render
|
||||
if (this._object._lineHeight > 0) {
|
||||
// Custom line height handling would go here
|
||||
// This is a placeholder for future implementation
|
||||
}
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tint of the bitmap object as a "R;G;B" string.
|
||||
* @returns the tint of bitmap object in "R;G;B" format.
|
||||
|
@@ -20,8 +20,6 @@ namespace gdjs {
|
||||
/** Alignment of the text. */
|
||||
align: 'left' | 'center' | 'right';
|
||||
verticalTextAlignment: 'top' | 'center' | 'bottom';
|
||||
/** Line height for multiline text */
|
||||
lineHeight: float;
|
||||
};
|
||||
};
|
||||
export type BitmapTextObjectData = ObjectData & BitmapTextObjectDataType;
|
||||
@@ -37,7 +35,6 @@ namespace gdjs {
|
||||
wwidth: float;
|
||||
align: string;
|
||||
vta: string;
|
||||
lh: float;
|
||||
};
|
||||
|
||||
export type BitmapTextObjectNetworkSyncData = ObjectNetworkSyncData &
|
||||
@@ -69,7 +66,6 @@ namespace gdjs {
|
||||
_wrappingWidth: float;
|
||||
_textAlign: string;
|
||||
_verticalTextAlignment: string;
|
||||
_lineHeight: float;
|
||||
|
||||
_renderer: gdjs.BitmapTextRuntimeObjectPixiRenderer;
|
||||
|
||||
@@ -96,7 +92,6 @@ namespace gdjs {
|
||||
this._textAlign = objectData.content.align;
|
||||
this._verticalTextAlignment =
|
||||
objectData.content.verticalTextAlignment || 'top';
|
||||
this._lineHeight = objectData.content.lineHeight;
|
||||
|
||||
this._renderer = new gdjs.BitmapTextRuntimeObjectRenderer(
|
||||
this,
|
||||
@@ -156,9 +151,6 @@ namespace gdjs {
|
||||
newObjectData.content.verticalTextAlignment
|
||||
);
|
||||
}
|
||||
if (oldObjectData.content.lineHeight !== newObjectData.content.lineHeight) {
|
||||
this.setLineHeight(newObjectData.content.lineHeight);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -176,7 +168,6 @@ namespace gdjs {
|
||||
wwidth: this._wrappingWidth,
|
||||
align: this._textAlign,
|
||||
vta: this._verticalTextAlignment,
|
||||
lh: this.getLineHeight(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -215,9 +206,6 @@ namespace gdjs {
|
||||
if (this._verticalTextAlignment !== undefined) {
|
||||
this.setVerticalTextAlignment(networkSyncData.vta);
|
||||
}
|
||||
if (this._lineHeight !== undefined) {
|
||||
this.setLineHeight(networkSyncData.lh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,23 +440,6 @@ namespace gdjs {
|
||||
: 0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line height of the bitmap text object.
|
||||
* @return line height in pixels (0 for automatic)
|
||||
*/
|
||||
getLineHeight(): number {
|
||||
return this._lineHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line height of the bitmap text object.
|
||||
* @param value line height in pixels (0 for automatic)
|
||||
*/
|
||||
setLineHeight(value: float): void {
|
||||
this._lineHeight = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
}
|
||||
gdjs.registerObject(
|
||||
'BitmapText::BitmapTextObject',
|
||||
|
@@ -389,26 +389,15 @@ namespace gdjs {
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
setColor(rgbColor): void {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._centerSprite.tint = gdjs.rgbToHexNumber(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
const tint = gdjs.rgbOrHexStringToNumber(rgbOrHexColor);
|
||||
this._centerSprite.tint = tint;
|
||||
for (
|
||||
let borderCounter = 0;
|
||||
borderCounter < this._borderSprites.length;
|
||||
borderCounter++
|
||||
) {
|
||||
this._borderSprites[borderCounter].tint = gdjs.rgbToHexNumber(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
this._borderSprites[borderCounter].tint = tint;
|
||||
}
|
||||
this._spritesContainer.cacheAsBitmap = false;
|
||||
}
|
||||
@@ -416,11 +405,11 @@ namespace gdjs {
|
||||
getColor() {
|
||||
const rgb = new PIXI.Color(this._centerSprite.tint).toRgbArray();
|
||||
return (
|
||||
Math.floor(rgb[0] * 255) +
|
||||
Math.round(rgb[0] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[1] * 255) +
|
||||
Math.round(rgb[1] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[2] * 255)
|
||||
Math.round(rgb[2] * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -235,18 +235,6 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
gd::ParameterOptions::MakeNewOptions().SetDescription(
|
||||
_("Blur radius")));
|
||||
|
||||
obj.AddExpressionAndConditionAndAction("number", "LineHeight",
|
||||
_("Line height"),
|
||||
_("the line height of the text"),
|
||||
_("the line height"),
|
||||
_("Font"),
|
||||
"res/actions/characterSize24.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardParameters(
|
||||
"number",
|
||||
gd::ParameterOptions::MakeNewOptions().SetDescription(
|
||||
_("Line height (0 for automatic)")));
|
||||
|
||||
obj.AddAction("SetSmooth",
|
||||
_("Smoothing"),
|
||||
_("Activate or deactivate text smoothing."),
|
||||
@@ -461,6 +449,16 @@ void DeclareTextObjectExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
|
||||
|
||||
obj.AddExpressionAndConditionAndAction("number",
|
||||
"LineHeight",
|
||||
_("Line height"),
|
||||
_("the line height of a text object"),
|
||||
_("the line height"),
|
||||
"",
|
||||
"res/actions/font24.png")
|
||||
.AddParameter("object", _("Object"), "Text")
|
||||
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions());
|
||||
|
||||
// Support for deprecated "Size" actions/conditions:
|
||||
obj.AddDuplicatedAction("Size", "Text::SetFontSize").SetHidden();
|
||||
obj.AddDuplicatedCondition("Size", "Text::FontSize").SetHidden();
|
||||
|
@@ -96,6 +96,14 @@ class TextObjectJsExtension : public gd::PlatformExtension {
|
||||
.SetFunctionName("setOutlineThickness")
|
||||
.SetGetter("getOutlineThickness");
|
||||
|
||||
GetAllExpressionsForObject("TextObject::Text")["LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetLineHeight"]
|
||||
.SetFunctionName("setLineHeight")
|
||||
.SetGetter("getLineHeight");
|
||||
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::ShowShadow"]
|
||||
.SetFunctionName("showShadow");
|
||||
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::IsShadowEnabled"]
|
||||
@@ -135,14 +143,6 @@ class TextObjectJsExtension : public gd::PlatformExtension {
|
||||
.SetFunctionName("setShadowBlurRadius")
|
||||
.SetGetter("getShadowBlurRadius");
|
||||
|
||||
GetAllExpressionsForObject("TextObject::Text")["LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllConditionsForObject("TextObject::Text")["TextObject::Text::LineHeight"]
|
||||
.SetFunctionName("getLineHeight");
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::Text::SetLineHeight"]
|
||||
.SetFunctionName("setLineHeight")
|
||||
.SetGetter("getLineHeight");
|
||||
|
||||
// Deprecated actions/conditions (use "FontSize"/"SetFontSize" instead):
|
||||
GetAllActionsForObject("TextObject::Text")["TextObject::Size"]
|
||||
.SetFunctionName("setCharacterSize")
|
||||
|
@@ -20,6 +20,7 @@ using namespace std;
|
||||
TextObject::TextObject()
|
||||
: text("Text"),
|
||||
characterSize(20),
|
||||
lineHeight(0),
|
||||
fontName(""),
|
||||
smoothed(true),
|
||||
bold(false),
|
||||
@@ -36,8 +37,7 @@ TextObject::TextObject()
|
||||
shadowOpacity(127),
|
||||
shadowAngle(90),
|
||||
shadowDistance(4),
|
||||
shadowBlurRadius(2),
|
||||
lineHeight(0) {}
|
||||
shadowBlurRadius(2) {}
|
||||
|
||||
TextObject::~TextObject() {};
|
||||
|
||||
@@ -51,6 +51,10 @@ bool TextObject::UpdateProperty(const gd::String& propertyName,
|
||||
characterSize = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "lineHeight") {
|
||||
lineHeight = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "font") {
|
||||
fontName = newValue;
|
||||
return true;
|
||||
@@ -111,10 +115,6 @@ bool TextObject::UpdateProperty(const gd::String& propertyName,
|
||||
shadowBlurRadius = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "lineHeight") {
|
||||
lineHeight = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -134,6 +134,13 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Font"));
|
||||
|
||||
objectProperties["lineHeight"]
|
||||
.SetValue(gd::String::From(lineHeight))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Line height"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Font"));
|
||||
|
||||
objectProperties["font"]
|
||||
.SetValue(fontName)
|
||||
.SetType("resource")
|
||||
@@ -260,15 +267,6 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
|
||||
.SetAdvanced()
|
||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
|
||||
|
||||
objectProperties["lineHeight"]
|
||||
.SetValue(gd::String::From(lineHeight))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Line height"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Font"))
|
||||
.SetDescription(_("Line height for multiline text (0 for automatic)"))
|
||||
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);
|
||||
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
@@ -285,6 +283,7 @@ void TextObject::DoUnserializeFrom(gd::Project& project,
|
||||
SetCharacterSize(content.GetChild("characterSize", 0, "CharacterSize")
|
||||
.GetValue()
|
||||
.GetInt());
|
||||
SetLineHeight(content.GetDoubleAttribute("lineHeight", 0));
|
||||
smoothed = content.GetBoolAttribute("smoothed");
|
||||
bold = content.GetBoolAttribute("bold");
|
||||
italic = content.GetBoolAttribute("italic");
|
||||
@@ -318,7 +317,6 @@ void TextObject::DoUnserializeFrom(gd::Project& project,
|
||||
SetShadowAngle(content.GetIntAttribute("shadowAngle", 90));
|
||||
SetShadowDistance(content.GetIntAttribute("shadowDistance", 4));
|
||||
SetShadowBlurRadius(content.GetIntAttribute("shadowBlurRadius", 2));
|
||||
SetLineHeight(content.GetIntAttribute("lineHeight", 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,6 +352,7 @@ void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
content.AddChild("textAlignment").SetValue(GetTextAlignment());
|
||||
content.AddChild("verticalTextAlignment").SetValue(GetVerticalTextAlignment());
|
||||
content.AddChild("characterSize").SetValue(GetCharacterSize());
|
||||
content.AddChild("lineHeight").SetValue(GetLineHeight());
|
||||
content.AddChild("color").SetValue(GetColor());
|
||||
|
||||
content.SetAttribute("smoothed", smoothed);
|
||||
@@ -371,7 +370,6 @@ void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
content.SetAttribute("shadowAngle", shadowAngle);
|
||||
content.SetAttribute("shadowDistance", shadowDistance);
|
||||
content.SetAttribute("shadowBlurRadius", shadowBlurRadius);
|
||||
content.SetAttribute("lineHeight", lineHeight);
|
||||
}
|
||||
|
||||
void TextObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
|
@@ -49,6 +49,12 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
*/
|
||||
inline double GetCharacterSize() const { return characterSize; };
|
||||
|
||||
/** \brief Change the line height. */
|
||||
inline void SetLineHeight(double value) { lineHeight = value; };
|
||||
|
||||
/** \brief Get the line height. */
|
||||
inline double GetLineHeight() const { return lineHeight; };
|
||||
|
||||
/** \brief Return the name of the font resource used for the text.
|
||||
*/
|
||||
inline const gd::String& GetFontName() const { return fontName; };
|
||||
@@ -113,9 +119,6 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
void SetShadowBlurRadius(double value) { shadowBlurRadius = value; };
|
||||
double GetShadowBlurRadius() const { return shadowBlurRadius; };
|
||||
|
||||
void SetLineHeight(double value) { lineHeight = value; };
|
||||
double GetLineHeight() const { return lineHeight; };
|
||||
|
||||
private:
|
||||
virtual void DoUnserializeFrom(gd::Project& project,
|
||||
const gd::SerializerElement& element) override;
|
||||
@@ -123,6 +126,7 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
|
||||
gd::String text;
|
||||
double characterSize;
|
||||
double lineHeight;
|
||||
gd::String fontName;
|
||||
bool smoothed;
|
||||
bool bold, italic, underlined;
|
||||
@@ -140,5 +144,4 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration {
|
||||
double shadowAngle;
|
||||
double shadowDistance;
|
||||
double shadowBlurRadius;
|
||||
double lineHeight;
|
||||
};
|
||||
|
@@ -64,9 +64,6 @@ namespace gdjs {
|
||||
style.wordWrap = this._object._wrapping;
|
||||
style.wordWrapWidth = this._object._wrappingWidth;
|
||||
style.breakWords = true;
|
||||
if (this._object._lineHeight > 0) {
|
||||
style.lineHeight = this._object._lineHeight;
|
||||
}
|
||||
style.stroke = gdjs.rgbToHexNumber(
|
||||
this._object._outlineColor[0],
|
||||
this._object._outlineColor[1],
|
||||
@@ -89,6 +86,7 @@ namespace gdjs {
|
||||
? style.dropShadowDistance + style.dropShadowBlur
|
||||
: 0;
|
||||
style.padding = Math.ceil(this._object._padding + extraPaddingForShadow);
|
||||
style.lineHeight = this._object._lineHeight;
|
||||
|
||||
// Prevent spikey outlines by adding a miter limit
|
||||
style.miterLimit = 3;
|
||||
|
@@ -22,6 +22,8 @@ namespace gdjs {
|
||||
text: string;
|
||||
textAlignment: string;
|
||||
verticalTextAlignment: string;
|
||||
/** The line height */
|
||||
lineHeight: float;
|
||||
|
||||
isOutlineEnabled: boolean;
|
||||
outlineThickness: float;
|
||||
@@ -34,7 +36,6 @@ namespace gdjs {
|
||||
shadowDistance: float;
|
||||
shadowAngle: float;
|
||||
shadowBlurRadius: float;
|
||||
lineHeight: float;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,10 +104,11 @@ namespace gdjs {
|
||||
_shadowAngle: float;
|
||||
_shadowBlur: float;
|
||||
|
||||
_lineHeight: float;
|
||||
|
||||
_padding: integer = 5;
|
||||
_str: string;
|
||||
_renderer: gdjs.TextRuntimeObjectRenderer;
|
||||
_lineHeight: float = 0;
|
||||
|
||||
// We can store the scale as nothing else can change it.
|
||||
_scaleX: number = 1;
|
||||
@@ -142,7 +144,6 @@ namespace gdjs {
|
||||
this._shadowDistance = content.shadowDistance;
|
||||
this._shadowBlur = content.shadowBlurRadius;
|
||||
this._shadowAngle = content.shadowAngle;
|
||||
|
||||
this._lineHeight = content.lineHeight || 0;
|
||||
|
||||
this._renderer = new gdjs.TextRuntimeObjectRenderer(
|
||||
@@ -216,7 +217,7 @@ namespace gdjs {
|
||||
if (oldContent.shadowBlurRadius !== newContent.shadowBlurRadius) {
|
||||
this.setShadowBlurRadius(newContent.shadowBlurRadius);
|
||||
}
|
||||
if (oldContent.lineHeight !== newContent.lineHeight) {
|
||||
if ((oldContent.lineHeight || 0) !== (newContent.lineHeight || 0)) {
|
||||
this.setLineHeight(newContent.lineHeight || 0);
|
||||
}
|
||||
return true;
|
||||
@@ -246,8 +247,8 @@ namespace gdjs {
|
||||
shd: this._shadowDistance,
|
||||
sha: this._shadowAngle,
|
||||
shb: this._shadowBlur,
|
||||
pad: this._padding,
|
||||
lh: this._lineHeight,
|
||||
pad: this._padding,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -321,12 +322,12 @@ namespace gdjs {
|
||||
if (networkSyncData.shb !== undefined) {
|
||||
this.setShadowBlurRadius(networkSyncData.shb);
|
||||
}
|
||||
if (networkSyncData.pad !== undefined) {
|
||||
this.setPadding(networkSyncData.pad);
|
||||
}
|
||||
if (networkSyncData.lh !== undefined) {
|
||||
this.setLineHeight(networkSyncData.lh);
|
||||
}
|
||||
if (networkSyncData.pad !== undefined) {
|
||||
this.setPadding(networkSyncData.pad);
|
||||
}
|
||||
}
|
||||
|
||||
override getRendererObject() {
|
||||
@@ -456,6 +457,22 @@ namespace gdjs {
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line height of the text.
|
||||
*/
|
||||
getLineHeight(): float {
|
||||
return this._lineHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the line height of the text.
|
||||
* @param value The new line height for the text.
|
||||
*/
|
||||
setLineHeight(value: float): void {
|
||||
this._lineHeight = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the resource to use for the font.
|
||||
* @param fontResourceName The name of the font resource.
|
||||
@@ -585,16 +602,10 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Change the text color.
|
||||
* @param colorString color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
*/
|
||||
setColor(colorString: string): void {
|
||||
const color = colorString.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._color[0] = parseInt(color[0], 10);
|
||||
this._color[1] = parseInt(color[1], 10);
|
||||
this._color[2] = parseInt(color[2], 10);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
this._color = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._useGradient = false;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
@@ -703,18 +714,12 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Set the outline for the text object.
|
||||
* @param str color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param thickness thickness of the outline (0 = disabled)
|
||||
* @deprecated Prefer independent setters.
|
||||
*/
|
||||
setOutline(str: string, thickness: number): void {
|
||||
const color = str.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._outlineColor[0] = parseInt(color[0], 10);
|
||||
this._outlineColor[1] = parseInt(color[1], 10);
|
||||
this._outlineColor[2] = parseInt(color[2], 10);
|
||||
setOutline(rgbOrHexColor: string, thickness: number): void {
|
||||
this._outlineColor = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._outlineThickness = thickness;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
@@ -756,25 +761,19 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Set the shadow for the text object.
|
||||
* @param str color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param rgbOrHexColor color as a "R;G;B" string, for example: "255;0;0"
|
||||
* @param distance distance between the shadow and the text, in pixels.
|
||||
* @param blur amount of shadow blur, in pixels.
|
||||
* @param angle shadow offset direction, in degrees.
|
||||
* @deprecated Prefer independent setters.
|
||||
*/
|
||||
setShadow(
|
||||
str: string,
|
||||
rgbOrHexColor: string,
|
||||
distance: number,
|
||||
blur: integer,
|
||||
angle: float
|
||||
): void {
|
||||
const color = str.split(';');
|
||||
if (color.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._shadowColor[0] = parseInt(color[0], 10);
|
||||
this._shadowColor[1] = parseInt(color[1], 10);
|
||||
this._shadowColor[2] = parseInt(color[2], 10);
|
||||
this._shadowColor = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
this._shadowDistance = distance;
|
||||
this._shadowBlur = blur;
|
||||
this._shadowAngle = angle;
|
||||
@@ -887,38 +886,18 @@ namespace gdjs {
|
||||
strThirdColor: string,
|
||||
strFourthColor: string
|
||||
): void {
|
||||
const colorFirst = strFirstColor.split(';');
|
||||
const colorSecond = strSecondColor.split(';');
|
||||
const colorThird = strThirdColor.split(';');
|
||||
const colorFourth = strFourthColor.split(';');
|
||||
this._gradient = [];
|
||||
if (colorFirst.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorFirst[0], 10),
|
||||
parseInt(colorFirst[1], 10),
|
||||
parseInt(colorFirst[2], 10),
|
||||
]);
|
||||
if (strFirstColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strFirstColor));
|
||||
}
|
||||
if (colorSecond.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorSecond[0], 10),
|
||||
parseInt(colorSecond[1], 10),
|
||||
parseInt(colorSecond[2], 10),
|
||||
]);
|
||||
if (strSecondColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strSecondColor));
|
||||
}
|
||||
if (colorThird.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorThird[0], 10),
|
||||
parseInt(colorThird[1], 10),
|
||||
parseInt(colorThird[2], 10),
|
||||
]);
|
||||
if (strThirdColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strThirdColor));
|
||||
}
|
||||
if (colorFourth.length == 3) {
|
||||
this._gradient.push([
|
||||
parseInt(colorFourth[0], 10),
|
||||
parseInt(colorFourth[1], 10),
|
||||
parseInt(colorFourth[2], 10),
|
||||
]);
|
||||
if (strFourthColor) {
|
||||
this._gradient.push(gdjs.rgbOrHexToRGBColor(strFourthColor));
|
||||
}
|
||||
this._gradientType = strGradientType;
|
||||
this._useGradient = this._gradient.length > 1 ? true : false;
|
||||
@@ -941,23 +920,6 @@ namespace gdjs {
|
||||
this._padding = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line height of the text object.
|
||||
* @return line height in pixels (0 for automatic)
|
||||
*/
|
||||
getLineHeight(): number {
|
||||
return this._lineHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line height of the text object.
|
||||
* @param value line height in pixels (0 for automatic)
|
||||
*/
|
||||
setLineHeight(value: float): void {
|
||||
this._lineHeight = value;
|
||||
this._renderer.updateStyle();
|
||||
}
|
||||
}
|
||||
gdjs.registerObject('TextObject::Text', gdjs.TextRuntimeObject);
|
||||
}
|
||||
|
@@ -92,28 +92,18 @@ namespace gdjs {
|
||||
-this._object._yOffset % this._tiledSprite.texture.height;
|
||||
}
|
||||
|
||||
setColor(rgbColor: string): void {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
this._tiledSprite.tint =
|
||||
'0x' +
|
||||
gdjs.rgbToHex(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
this._tiledSprite.tint = gdjs.rgbOrHexStringToNumber(rgbOrHexColor);
|
||||
}
|
||||
|
||||
getColor() {
|
||||
const rgb = new PIXI.Color(this._tiledSprite.tint).toRgbArray();
|
||||
return (
|
||||
Math.floor(rgb[0] * 255) +
|
||||
Math.round(rgb[0] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[1] * 255) +
|
||||
Math.round(rgb[1] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[2] * 255)
|
||||
Math.round(rgb[2] * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -145,6 +145,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
|
||||
shadowDistance: 4,
|
||||
shadowAngle: 90,
|
||||
shadowBlurRadius: 2,
|
||||
lineHeight: 0,
|
||||
},
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
|
@@ -145,6 +145,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
|
||||
shadowDistance: 4,
|
||||
shadowAngle: 90,
|
||||
shadowBlurRadius: 2,
|
||||
lineHeight: 0,
|
||||
},
|
||||
});
|
||||
runtimeScene.addObject(object);
|
||||
|
@@ -1326,11 +1326,11 @@ namespace gdjs {
|
||||
lightness
|
||||
);
|
||||
owner.setColor(
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
Math.round(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
Math.round(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
Math.round(rgbFromHslColor[2])
|
||||
);
|
||||
};
|
||||
} else {
|
||||
@@ -1439,12 +1439,11 @@ namespace gdjs {
|
||||
if (!isColorable(this.owner)) return;
|
||||
const owner = this.owner;
|
||||
|
||||
const rgbFromColor: string[] = owner.getColor().split(';');
|
||||
if (rgbFromColor.length < 3) return;
|
||||
const rgbFromColor = gdjs.rgbOrHexToRGBColor(owner.getColor());
|
||||
const hslFromColor = gdjs.evtTools.tween.rgbToHsl(
|
||||
parseFloat(rgbFromColor[0]),
|
||||
parseFloat(rgbFromColor[1]),
|
||||
parseFloat(rgbFromColor[2])
|
||||
rgbFromColor[0],
|
||||
rgbFromColor[1],
|
||||
rgbFromColor[2]
|
||||
);
|
||||
|
||||
const toH = animateHue ? toHue : hslFromColor[0];
|
||||
@@ -1474,11 +1473,11 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
owner.setColor(
|
||||
Math.floor(rgbFromHslColor[0]) +
|
||||
Math.round(rgbFromHslColor[0]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[1]) +
|
||||
Math.round(rgbFromHslColor[1]) +
|
||||
';' +
|
||||
Math.floor(rgbFromHslColor[2])
|
||||
Math.round(rgbFromHslColor[2])
|
||||
);
|
||||
},
|
||||
|
||||
|
@@ -40,6 +40,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
gdjs::EventsCodeGenerator& codeGenerator,
|
||||
gd::String fullyQualifiedFunctionName,
|
||||
gd::String functionArgumentsCode,
|
||||
gd::String contextClassCode,
|
||||
gd::String functionPreEventsCode,
|
||||
const gd::EventsList& events,
|
||||
gd::String functionPostEventsCode,
|
||||
@@ -81,6 +82,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
globalDeclarations +
|
||||
globalObjectLists + "\n\n" +
|
||||
codeGenerator.GetCustomCodeOutsideMain() + "\n\n" +
|
||||
contextClassCode + "\n\n" +
|
||||
fullyQualifiedFunctionName + " = function(" +
|
||||
functionArgumentsCode +
|
||||
") {\n" +
|
||||
@@ -112,6 +114,7 @@ gd::String EventsCodeGenerator::GenerateLayoutCode(
|
||||
codeGenerator,
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
"runtimeScene",
|
||||
"",
|
||||
"runtimeScene.getOnceTriggers().startNewFrame();\n",
|
||||
scene.GetEvents(),
|
||||
"",
|
||||
@@ -145,16 +148,40 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator, codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
auto parameterList = codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsFunctionsExtension.GetEventsFunctions()),
|
||||
0, true),
|
||||
0, true);
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator, codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
parameterList,
|
||||
codeGenerator.GenerateFreeEventsFunctionContext(
|
||||
eventsFunctionsExtension, eventsFunction,
|
||||
"runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetEvents(), "",
|
||||
"runtimeScene.getOnceTriggers()") +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = null;\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n",
|
||||
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() + "context) " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
parameterList + ");\n"
|
||||
"const eventsFunctionContext = " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted ? new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
parameterList + ") : " + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context;\n" + //
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted) {\n" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context.reinitialize(" + parameterList + ");\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted = true;\n"
|
||||
"}\n",
|
||||
|
||||
eventsFunction.GetEvents(),
|
||||
"if (eventsFunctionContext === " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context) " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
// TODO: the editor should pass the diagnostic report and display it to the
|
||||
@@ -201,44 +228,59 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
auto contextParameterList = codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()),
|
||||
2, true) + ", that";
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
preludeCode + "\n" + "const that = this;\n" +
|
||||
// runtimeScene is supposed to be always accessible, read
|
||||
// it from the behavior.
|
||||
// TODO: this should be renamed to "instanceContainer" and have the code generation
|
||||
// adapted for this (rely less on `gdjs.RuntimeScene`, and more on `RuntimeInstanceContainer`).
|
||||
"var runtimeScene = this._runtimeScene;\n" +
|
||||
// By convention of Behavior Events Function, the object is accessible
|
||||
// as a parameter called "Object", and thisObjectList is an array
|
||||
// containing it (for faster access, without having to go through the
|
||||
// hashmap).
|
||||
"var thisObjectList = [this.owner];\n" +
|
||||
"var Object = Hashtable.newFrom({Object: thisObjectList});\n" +
|
||||
// By convention of Behavior Events Function, the behavior is accessible
|
||||
// as a parameter called "Behavior".
|
||||
"var Behavior = this.name;\n" +
|
||||
codeGenerator.GenerateBehaviorEventsFunctionContext(
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object",
|
||||
"Behavior");
|
||||
// TODO: this should be renamed to "instanceContainer" and have the code
|
||||
// generation adapted for this (rely less on `gdjs.RuntimeScene`, and more
|
||||
// on `RuntimeInstanceContainer`).
|
||||
"const runtimeScene = this._runtimeScene;\n" +
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() + "context) " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
contextParameterList + ");\n"
|
||||
"const eventsFunctionContext = " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted ? new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
contextParameterList + ") : " + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context;\n" + //
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted) {\n" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context.reinitialize(" + contextParameterList + ");\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted = true;\n"
|
||||
"}\n";
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator,
|
||||
fullyQualifiedFunctionName,
|
||||
auto parameterList =
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()),
|
||||
2,
|
||||
false),
|
||||
2, false);
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator, fullyQualifiedFunctionName, parameterList,
|
||||
codeGenerator.GenerateBehaviorEventsFunctionContext(
|
||||
eventsFunctionsExtension, eventsBasedBehavior, eventsFunction,
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object", "Behavior") +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = null;\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n",
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
"if (eventsFunctionContext === " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context) {" +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context.clear();\n" +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n"
|
||||
"};\n",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
// TODO: the editor should pass the diagnostic report and display it to the
|
||||
@@ -286,53 +328,56 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
gd::DiagnosticReport diagnosticReport;
|
||||
codeGenerator.SetDiagnosticReport(&diagnosticReport);
|
||||
|
||||
auto contextParameterList = codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()),
|
||||
1, true) + ", that";
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
preludeCode + "\n" + "const that = this;\n" +
|
||||
// runtimeScene is supposed to be always accessible, read
|
||||
// it from the object.
|
||||
// TODO: this should be renamed to "instanceContainer" and have the code generation
|
||||
// adapted for this (rely less on `gdjs.RuntimeScene`, and more on `RuntimeInstanceContainer`).
|
||||
"var runtimeScene = this._instanceContainer;\n" +
|
||||
// By convention of Object Events Function, the object is accessible
|
||||
// as a parameter called "Object", and thisObjectList is an array
|
||||
// containing it (for faster access, without having to go through the
|
||||
// hashmap).
|
||||
"var thisObjectList = [this];\n" +
|
||||
"var Object = Hashtable.newFrom({Object: thisObjectList});\n";
|
||||
"const runtimeScene = this._instanceContainer;\n"
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() + "context) " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
contextParameterList + ");\n"
|
||||
"const eventsFunctionContext = " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted ? new " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "Context(" +
|
||||
contextParameterList + ") : " + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context;\n" + //
|
||||
"if (!" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted) {\n" + codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"context.reinitialize(" + contextParameterList + ");\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() +
|
||||
"isExecuted = true;\n"
|
||||
"}\n";
|
||||
|
||||
// Add child-objects
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
// child-object are never picked because they are not parameters.
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
fullPreludeCode += "var this" + childName +
|
||||
"List = [...runtimeScene.getObjects(" +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
")];\n" + "var " + childName + " = Hashtable.newFrom({" +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
": this" + childName + "List});\n";
|
||||
}
|
||||
|
||||
fullPreludeCode += codeGenerator.GenerateObjectEventsFunctionContext(
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedObject,
|
||||
eventsFunction,
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object");
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator,
|
||||
fullyQualifiedFunctionName,
|
||||
auto parameterList =
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
// TODO EBO use constants for firstParameterIndex
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()),
|
||||
1,
|
||||
false),
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
1, false);
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator, fullyQualifiedFunctionName, parameterList,
|
||||
codeGenerator.GenerateObjectEventsFunctionContext(
|
||||
eventsFunctionsExtension, eventsBasedObject, eventsFunction,
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object") +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context = null;\n" + //
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n",
|
||||
fullPreludeCode, eventsFunction.GetEvents(),
|
||||
"if (eventsFunctionContext === " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "context) " +
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "isExecuted = false;\n" +
|
||||
endingCode,
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
@@ -376,6 +421,33 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionParameterDeclarationsList(
|
||||
return declaration;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionParametersToAttribues(
|
||||
const gd::ParameterMetadataContainer ¶meters, int firstParameterIndex,
|
||||
bool addsSceneParameter) {
|
||||
gd::String declaration =
|
||||
addsSceneParameter ? " this.runtimeScene = runtimeScene;\n" : "";
|
||||
// By convention, the first two arguments of a behavior events function
|
||||
// are the object and the behavior, which are not passed to the called
|
||||
// function in the generated JS code.
|
||||
for (size_t i = firstParameterIndex; i < parameters.GetParametersCount(); ++i) {
|
||||
const auto ¶meter = parameters.GetParameter(i);
|
||||
if (parameter.GetValueTypeMetadata().IsObject() ||
|
||||
parameter.GetValueTypeMetadata().IsBehavior()) {
|
||||
continue;
|
||||
}
|
||||
gd::String parameterMangledName =
|
||||
parameter.GetName().empty()
|
||||
? "_"
|
||||
: EventsCodeNameMangler::GetMangledName(parameter.GetName());
|
||||
declaration +=
|
||||
" this." + parameterMangledName + " = " + parameterMangledName + ";\n";
|
||||
}
|
||||
declaration +=
|
||||
" this.parentEventsFunctionContext = parentEventsFunctionContext;\n";
|
||||
|
||||
return declaration;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateFreeEventsFunctionContext(
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
@@ -410,17 +482,17 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
// optimized getter for it (bypassing "Object" hashmap, and directly return
|
||||
// the array containing it).
|
||||
if (!thisObjectName.empty()) {
|
||||
objectsGettersMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": " + thisObjectName + "\n";
|
||||
objectArraysMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList\n";
|
||||
objectsGettersMap += " " +
|
||||
ConvertToStringExplicit(thisObjectName) + ": " + thisObjectName;
|
||||
objectArraysMap += " " +
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList";
|
||||
}
|
||||
|
||||
if (!thisBehaviorName.empty()) {
|
||||
// If we have a behavior considered as the current behavior ("this")
|
||||
// (usually called Behavior in behavior events function), generate a
|
||||
// slightly more optimized getter for it.
|
||||
behaviorNamesMap += ConvertToStringExplicit(thisBehaviorName) + ": " +
|
||||
behaviorNamesMap += " " + ConvertToStringExplicit(thisBehaviorName) + ": " +
|
||||
thisBehaviorName + "\n";
|
||||
|
||||
// Add required behaviors from properties
|
||||
@@ -437,11 +509,40 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
gd::String comma = behaviorNamesMap.empty() ? "" : ", ";
|
||||
behaviorNamesMap +=
|
||||
comma + ConvertToStringExplicit(propertyDescriptor.GetName()) +
|
||||
": this._get" + propertyDescriptor.GetName() + "()\n";
|
||||
": that._get" + propertyDescriptor.GetName() + "()\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gd::String constructorAdditionalCode =
|
||||
"this.that = that;\n"
|
||||
" const thisObjectList = [that.owner];\n";
|
||||
if (!thisObjectName.empty()) {
|
||||
constructorAdditionalCode += " const " + thisObjectName +
|
||||
" = Hashtable.newFrom({ " + thisObjectName +
|
||||
": thisObjectList });\n";
|
||||
}
|
||||
if (!thisBehaviorName.empty()) {
|
||||
constructorAdditionalCode +=
|
||||
" const " + thisBehaviorName + " = that.name;\n";
|
||||
}
|
||||
|
||||
gd::String reinitializeAdditionalCode = "";
|
||||
gd::String clearAdditionalCode = "";
|
||||
if (!thisObjectName.empty()) {
|
||||
reinitializeAdditionalCode += " this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(thisObjectName) +
|
||||
"][0] = that.owner;\n";
|
||||
clearAdditionalCode += " this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(thisObjectName) +
|
||||
"][0] = null;\n";
|
||||
}
|
||||
if (!thisBehaviorName.empty()) {
|
||||
reinitializeAdditionalCode += " this._behaviorNamesMap[" +
|
||||
ConvertToStringExplicit(thisBehaviorName) +
|
||||
"] = that.name;\n";
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(eventsFunctionsExtension,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
@@ -449,6 +550,9 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
constructorAdditionalCode,
|
||||
reinitializeAdditionalCode,
|
||||
clearAdditionalCode,
|
||||
thisObjectName,
|
||||
thisBehaviorName);
|
||||
}
|
||||
@@ -470,24 +574,69 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
// optimized getter for it (bypassing "Object" hashmap, and directly return
|
||||
// the array containing it).
|
||||
if (!thisObjectName.empty()) {
|
||||
objectsGettersMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": " + thisObjectName + "\n";
|
||||
objectArraysMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList\n";
|
||||
objectsGettersMap += " " +
|
||||
ConvertToStringExplicit(thisObjectName) + ": " + thisObjectName;
|
||||
objectArraysMap += " " +
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList";
|
||||
|
||||
// Add child-objects
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
// child-object are never picked because they are not parameters.
|
||||
objectsGettersMap += ", " +
|
||||
objectsGettersMap += ",\n " +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
": " + childName + "\n";
|
||||
objectArraysMap += ", " +
|
||||
": " + childName;
|
||||
objectArraysMap += ",\n " +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
": this" + childName + "List\n";
|
||||
": this" + childName + "List";
|
||||
}
|
||||
}
|
||||
|
||||
// By convention of Object Events Function, the object is accessible
|
||||
// as a parameter called "Object", and thisObjectList is an array
|
||||
// containing it (for faster access, without having to go through the
|
||||
// hashmap).
|
||||
gd::String constructorAdditionalCode = "this.that = that;\n"
|
||||
" const thisObjectList = [that];\n";
|
||||
if (!thisObjectName.empty()) {
|
||||
constructorAdditionalCode += " const " + thisObjectName +
|
||||
" = Hashtable.newFrom({" + thisObjectName +
|
||||
": thisObjectList});\n";
|
||||
}
|
||||
// Add child-objects
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
// child-object are never picked because they are not parameters.
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
constructorAdditionalCode +=
|
||||
" const this" + childName + "List = [...runtimeScene.getObjects(" +
|
||||
ConvertToStringExplicit(childObject->GetName()) + ")];\n" + //
|
||||
" const " + childName + " = Hashtable.newFrom({" +
|
||||
ConvertToStringExplicit(childObject->GetName()) + ": this" + childName +
|
||||
"List});\n";
|
||||
}
|
||||
|
||||
gd::String reinitializeAdditionalCode = "";
|
||||
gd::String clearAdditionalCode = "";
|
||||
if (!thisObjectName.empty()) {
|
||||
reinitializeAdditionalCode += " this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(thisObjectName) +
|
||||
"][0] = that;\n";
|
||||
clearAdditionalCode += " this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(thisObjectName) +
|
||||
"][0] = null;\n";
|
||||
}
|
||||
// Add child-objects
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
// child-object are never picked because they are not parameters.
|
||||
const auto& childName = ManObjListName(childObject->GetName());
|
||||
reinitializeAdditionalCode +=
|
||||
" gdjs.copyArray(runtimeScene.getObjects(" +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
"), "
|
||||
"this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(childObject->GetName()) + "]);\n";
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(eventsFunctionsExtension,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
@@ -495,6 +644,9 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
constructorAdditionalCode,
|
||||
reinitializeAdditionalCode,
|
||||
clearAdditionalCode,
|
||||
thisObjectName);
|
||||
}
|
||||
|
||||
@@ -506,6 +658,9 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
gd::String& objectsGettersMap,
|
||||
gd::String& objectArraysMap,
|
||||
gd::String& behaviorNamesMap,
|
||||
const gd::String& constructorAdditionalCode,
|
||||
const gd::String& reinitializeAdditionalCode,
|
||||
const gd::String& clearAdditionalCode,
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName) {
|
||||
const auto& extensionName = eventsFunctionsExtension.GetName();
|
||||
@@ -526,6 +681,11 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// Conditions/expressions are available to deal with them in events.
|
||||
|
||||
gd::String argumentsGetters;
|
||||
gd::String reinitializeObjectsMap;
|
||||
gd::String reinitializeArraysMap;
|
||||
gd::String reinitializeBehaviorNamesMap;
|
||||
gd::String clearObjectsMap;
|
||||
gd::String clearArraysMap;
|
||||
|
||||
for (const auto& parameterPtr : parameters.GetInternalVector()) {
|
||||
const auto& parameter = *parameterPtr;
|
||||
@@ -541,13 +701,26 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
|
||||
// Generate map that will be used to get the lists of objects passed
|
||||
// as parameters (either as objects lists or array).
|
||||
gd::String comma = objectsGettersMap.empty() ? "" : ", ";
|
||||
gd::String comma = objectsGettersMap.empty() ? "" : ",\n ";
|
||||
objectsGettersMap += comma +
|
||||
ConvertToStringExplicit(parameter.GetName()) + ": " +
|
||||
parameterMangledName + "\n";
|
||||
parameterMangledName;
|
||||
objectArraysMap += comma + ConvertToStringExplicit(parameter.GetName()) +
|
||||
": gdjs.objectsListsToArray(" + parameterMangledName +
|
||||
")\n";
|
||||
")";
|
||||
reinitializeObjectsMap += " this._objectsMap[" +
|
||||
ConvertToStringExplicit(parameter.GetName()) +
|
||||
"] = " + parameterMangledName + ";\n";
|
||||
reinitializeArraysMap +=
|
||||
" gdjs.objectsListsToArray(" + parameterMangledName +
|
||||
", this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(parameter.GetName()) + "]);\n";
|
||||
clearObjectsMap += " this._objectsMap[" +
|
||||
ConvertToStringExplicit(parameter.GetName()) +
|
||||
"] = null;\n";
|
||||
clearArraysMap += " this._objectArraysMap[" +
|
||||
ConvertToStringExplicit(parameter.GetName()) +
|
||||
"].length = 0;\n";
|
||||
} else if (gd::ParameterMetadata::IsBehavior(parameter.GetType())) {
|
||||
if (parameter.GetName() == thisBehaviorName) {
|
||||
continue;
|
||||
@@ -555,114 +728,171 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
|
||||
// Generate map that will be used to transform from behavior name used in
|
||||
// function to the "real" behavior name from the caller.
|
||||
gd::String comma = behaviorNamesMap.empty() ? "" : ", ";
|
||||
gd::String comma = behaviorNamesMap.empty() ? "" : ",\n";
|
||||
behaviorNamesMap += comma + ConvertToStringExplicit(parameter.GetName()) +
|
||||
": " + parameterMangledName + "\n";
|
||||
": " + parameterMangledName;
|
||||
reinitializeBehaviorNamesMap +=
|
||||
"this._behaviorNamesMap[" +
|
||||
ConvertToStringExplicit(parameter.GetName()) +
|
||||
"] = " + parameterMangledName + ";\n";
|
||||
} else {
|
||||
argumentsGetters +=
|
||||
"if (argName === " + ConvertToStringExplicit(parameter.GetName()) +
|
||||
") return " + parameterMangledName + ";\n";
|
||||
" if (argName === " + ConvertToStringExplicit(parameter.GetName()) +
|
||||
") return this." + parameterMangledName + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
const gd::String async = eventsFunction.IsAsync()
|
||||
? " task: new gdjs.ManuallyResolvableTask(),\n"
|
||||
? " this.task = new gdjs.ManuallyResolvableTask(),\n"
|
||||
: "";
|
||||
const gd::String clearAsync = eventsFunction.IsAsync()
|
||||
? " this.task = null,\n"
|
||||
: "";
|
||||
const int firstParameterIndex =
|
||||
(thisObjectName.empty() ? 0 : 1) + (thisBehaviorName.empty() ? 0 : 1);
|
||||
auto parameterList =
|
||||
GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsContainer),
|
||||
firstParameterIndex, true) +
|
||||
(thisObjectName.empty() && thisBehaviorName.empty() ? "" : ", that");
|
||||
|
||||
return gd::String("var eventsFunctionContext = {\n") +
|
||||
// The async task, if there is one
|
||||
async +
|
||||
return GetCodeNamespaceAccessor() + "Context = class {\n"
|
||||
"constructor(" + parameterList + ") {\n" +
|
||||
GenerateEventsFunctionParametersToAttribues(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsFunctionsContainer),
|
||||
firstParameterIndex, true) +
|
||||
constructorAdditionalCode +
|
||||
// The async task, if there is one
|
||||
async +
|
||||
// The object name to parameter map:
|
||||
" _objectsMap: {\n" + objectsGettersMap +
|
||||
"},\n"
|
||||
" this._objectsMap = {\n" +
|
||||
objectsGettersMap + "\n"
|
||||
" };\n"
|
||||
// The object name to arrays map:
|
||||
" _objectArraysMap: {\n" +
|
||||
objectArraysMap +
|
||||
"},\n"
|
||||
" this._objectArraysMap = {\n" +
|
||||
objectArraysMap + "\n"
|
||||
" };\n"
|
||||
// The behavior name to parameter map:
|
||||
" _behaviorNamesMap: {\n" +
|
||||
behaviorNamesMap +
|
||||
"},\n"
|
||||
" globalVariablesForExtension: "
|
||||
" this._behaviorNamesMap = {\n" +
|
||||
behaviorNamesMap + "\n"
|
||||
" };\n"
|
||||
" this.globalVariablesForExtension = "
|
||||
"runtimeScene.getGame().getVariablesForExtension(" +
|
||||
ConvertToStringExplicit(extensionName) + "),\n" +
|
||||
" sceneVariablesForExtension: "
|
||||
ConvertToStringExplicit(extensionName) + ");\n" +
|
||||
" this.sceneVariablesForExtension = "
|
||||
"runtimeScene.getScene().getVariablesForExtension(" +
|
||||
ConvertToStringExplicit(extensionName) + "),\n" +
|
||||
ConvertToStringExplicit(extensionName) + ");\n"
|
||||
// The local variables stack:
|
||||
" localVariables: [],\n"
|
||||
" this.localVariables = [];\n"
|
||||
"}\n"
|
||||
|
||||
"reinitialize(" + parameterList + ") {\n" +
|
||||
GenerateEventsFunctionParametersToAttribues(
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsFunctionsContainer),
|
||||
firstParameterIndex, true) +
|
||||
// The async task, if there is one
|
||||
async +
|
||||
// The object name to parameter map:
|
||||
reinitializeObjectsMap +
|
||||
// The object name to arrays map:
|
||||
reinitializeArraysMap +
|
||||
// The behavior name to parameter map:
|
||||
reinitializeBehaviorNamesMap +
|
||||
// globalVariablesForExtension stays the same.
|
||||
" this.sceneVariablesForExtension = "
|
||||
"runtimeScene.getScene().getVariablesForExtension(" +
|
||||
ConvertToStringExplicit(extensionName) + ");\n" +
|
||||
reinitializeAdditionalCode +
|
||||
"}\n"
|
||||
|
||||
"clear() {\n" +
|
||||
" this.runtimeScene = null;\n"
|
||||
" this.parentEventsFunctionContext = null;\n"
|
||||
// globalVariablesForExtension stays the same.
|
||||
" this.sceneVariablesForExtension = null;\n" +
|
||||
// The async task, if there is one
|
||||
clearAsync +
|
||||
// The object name to parameter map:
|
||||
clearObjectsMap +
|
||||
// The object name to arrays map:
|
||||
clearArraysMap +
|
||||
clearAdditionalCode +
|
||||
"}\n"
|
||||
|
||||
// Function that will be used to query objects, when a new object list
|
||||
// is needed by events. We assume it's used a lot by the events
|
||||
// generated code, so we cache the arrays in a map.
|
||||
" getObjects: function(objectName) {\n" +
|
||||
" return eventsFunctionContext._objectArraysMap[objectName] || "
|
||||
"[];\n" +
|
||||
" },\n" +
|
||||
" getObjects(objectName) {\n"
|
||||
" return this._objectArraysMap[objectName] || [];\n"
|
||||
" }\n"
|
||||
// Function that can be used in JS code to get the lists of objects
|
||||
// and filter/alter them (not actually used in events).
|
||||
" getObjectsLists: function(objectName) {\n" +
|
||||
" return eventsFunctionContext._objectsMap[objectName] || null;\n"
|
||||
" },\n" +
|
||||
" getObjectsLists(objectName) {\n"
|
||||
" return this._objectsMap[objectName] || null;\n"
|
||||
" }\n"
|
||||
// Function that will be used to query behavior name (as behavior name
|
||||
// can be different between the parameter name vs the actual behavior
|
||||
// name passed as argument).
|
||||
" getBehaviorName: function(behaviorName) {\n" +
|
||||
" getBehaviorName(behaviorName) {\n"
|
||||
// TODO EBO Handle behavior name collision between parameters and
|
||||
// children
|
||||
" return eventsFunctionContext._behaviorNamesMap[behaviorName] || "
|
||||
" return this._behaviorNamesMap[behaviorName] || "
|
||||
"behaviorName;\n"
|
||||
" },\n" +
|
||||
" }\n"
|
||||
// Creator function that will be used to create new objects. We
|
||||
// need to check if the function was given the context of the calling
|
||||
// function (parentEventsFunctionContext). If this is the case, use it
|
||||
// to create the new object as the object names used in the function
|
||||
// are not the same as the objects available in the scene.
|
||||
" createObject: function(objectName) {\n"
|
||||
" const objectsList = "
|
||||
"eventsFunctionContext._objectsMap[objectName];\n" +
|
||||
" createObject(objectName) {\n"
|
||||
" const objectsList = this._objectsMap[objectName];\n"
|
||||
// TODO: we could speed this up by storing a map of object names, but
|
||||
// the cost of creating/storing it for each events function might not
|
||||
// be worth it.
|
||||
" if (objectsList) {\n" +
|
||||
" const object = parentEventsFunctionContext ?\n" +
|
||||
" if (objectsList) {\n"
|
||||
" const object = this.parentEventsFunctionContext ?\n"
|
||||
" "
|
||||
"parentEventsFunctionContext.createObject(objectsList.firstKey()) "
|
||||
":\n" +
|
||||
" runtimeScene.createObject(objectsList.firstKey());\n" +
|
||||
"this.parentEventsFunctionContext.createObject(objectsList.firstKey()) "
|
||||
":\n"
|
||||
" this.runtimeScene.createObject(objectsList.firstKey());\n"
|
||||
// Add the new instance to object lists
|
||||
" if (object) {\n" +
|
||||
" objectsList.get(objectsList.firstKey()).push(object);\n" +
|
||||
" "
|
||||
"eventsFunctionContext._objectArraysMap[objectName].push(object);\n" +
|
||||
" }\n" + " return object;" + " }\n" +
|
||||
" if (object) {\n"
|
||||
" objectsList.get(objectsList.firstKey()).push(object);\n"
|
||||
" this._objectArraysMap[objectName].push(object);\n"
|
||||
" }\n"
|
||||
" return object;\n"
|
||||
" }\n"
|
||||
// Unknown object, don't create anything:
|
||||
" return null;\n" +
|
||||
" },\n"
|
||||
" return null;\n"
|
||||
" }\n"
|
||||
// Function to count instances on the scene. We need it here because
|
||||
// it needs the objects map to get the object names of the parent
|
||||
// context.
|
||||
" getInstancesCountOnScene: function(objectName) {\n"
|
||||
" const objectsList = "
|
||||
"eventsFunctionContext._objectsMap[objectName];\n" +
|
||||
" let count = 0;\n" + " if (objectsList) {\n" +
|
||||
" for(const objectName in objectsList.items)\n" +
|
||||
" count += parentEventsFunctionContext ?\n" +
|
||||
"parentEventsFunctionContext.getInstancesCountOnScene(objectName) "
|
||||
":\n" +
|
||||
" runtimeScene.getInstancesCountOnScene(objectName);\n" +
|
||||
" }\n" + " return count;\n" +
|
||||
" },\n"
|
||||
" getInstancesCountOnScene(objectName) {\n"
|
||||
" const objectsList = this._objectsMap[objectName];\n"
|
||||
" let count = 0;\n"
|
||||
" if (objectsList) {\n"
|
||||
" for(const objectName in objectsList.items)\n"
|
||||
" count += this.parentEventsFunctionContext ?\n"
|
||||
" this.parentEventsFunctionContext.getInstancesCountOnScene(objectName) :\n"
|
||||
" this.runtimeScene.getInstancesCountOnScene(objectName);\n"
|
||||
" }\n"
|
||||
" return count;\n"
|
||||
" }\n"
|
||||
// Allow to get a layer directly from the context for convenience:
|
||||
" getLayer: function(layerName) {\n"
|
||||
" return runtimeScene.getLayer(layerName);\n"
|
||||
" },\n"
|
||||
" getLayer(layerName) {\n"
|
||||
" return this.runtimeScene.getLayer(layerName);\n"
|
||||
" }\n"
|
||||
// Getter for arguments that are not objects
|
||||
" getArgument: function(argName) {\n" +
|
||||
argumentsGetters + " return \"\";\n" + " },\n" +
|
||||
" getArgument(argName) {\n" + argumentsGetters + //
|
||||
" return \"\";\n"
|
||||
" }\n"
|
||||
// Expose OnceTriggers (will be pointing either to the runtime scene
|
||||
// ones, or the ones from the behavior):
|
||||
" getOnceTriggers: function() { return " + onceTriggersVariable +
|
||||
"; }\n" + "};\n";
|
||||
" getOnceTriggers() { return this." + onceTriggersVariable + "; }\n"
|
||||
"}\n";
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionReturn(
|
||||
|
@@ -375,6 +375,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
gdjs::EventsCodeGenerator& codeGenerator,
|
||||
gd::String fullyQualifiedFunctionName,
|
||||
gd::String functionArgumentsCode,
|
||||
gd::String contextClassCode,
|
||||
gd::String functionPreEventsCode,
|
||||
const gd::EventsList& events,
|
||||
gd::String functionPostEventsCode,
|
||||
@@ -409,6 +410,16 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
int firstParameterIndex,
|
||||
bool addsSceneParameter);
|
||||
|
||||
/**
|
||||
* \brief Generate the affectation from parameters to class attributes.
|
||||
*
|
||||
* \note runtimeScene is always added as the first parameter, and
|
||||
* parentEventsFunctionContext as the last parameter.
|
||||
*/
|
||||
gd::String GenerateEventsFunctionParametersToAttribues(
|
||||
const gd::ParameterMetadataContainer ¶meters, int firstParameterIndex,
|
||||
bool addsSceneParameter);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a free
|
||||
* function to provides access objects, object creation and access to
|
||||
@@ -475,6 +486,9 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
gd::String &objectsGettersMap,
|
||||
gd::String &objectArraysMap,
|
||||
gd::String &behaviorNamesMap,
|
||||
const gd::String &constructorAdditionalCode = "",
|
||||
const gd::String &reinitializeAdditionalCode = "",
|
||||
const gd::String& clearAdditionalCode = "",
|
||||
const gd::String &thisObjectName = "",
|
||||
const gd::String &thisBehaviorName = "");
|
||||
};
|
||||
|
@@ -841,13 +841,23 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
event.GetParameterObjects(),
|
||||
parentContext.GetCurrentObject());
|
||||
|
||||
callingCode += "var objects = [];\n";
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i) {
|
||||
parentContext.ObjectsListNeeded(realObjects[i]);
|
||||
if (realObjects.size() == 1) {
|
||||
parentContext.ObjectsListNeeded(realObjects[0]);
|
||||
callingCode +=
|
||||
"objects.push.apply(objects," +
|
||||
codeGenerator.GetObjectListName(realObjects[i], parentContext) +
|
||||
");\n";
|
||||
"const objects = " +
|
||||
codeGenerator.GetObjectListName(realObjects[0], parentContext) +
|
||||
";\n";
|
||||
} else {
|
||||
// Groups are rarely used in JS events so it's fine to make
|
||||
// allocations.
|
||||
callingCode += "const objects = [];\n";
|
||||
for (unsigned int i = 0; i < realObjects.size(); ++i) {
|
||||
parentContext.ObjectsListNeeded(realObjects[i]);
|
||||
callingCode += "objects.push.apply(objects," +
|
||||
codeGenerator.GetObjectListName(realObjects[i],
|
||||
parentContext) +
|
||||
");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,28 @@ The game engine is in the _Runtime_ folder. If you want to work on the engine di
|
||||
|
||||
- To launch type checking with TypeScript, run `npm install` and `npm run check-types` in `GDJS` folder.
|
||||
|
||||
#### Building GDJS Runtime
|
||||
|
||||
To build the GDJS Runtime, run `npm run build` in the `GDJS` folder.
|
||||
|
||||
**Build Options:**
|
||||
|
||||
- **Production build (default)**: `npm run build` - builds with minification enabled
|
||||
- **Debug build**: `npm run build -- --debug` - builds without minification for easier debugging
|
||||
- **Custom output path**: `npm run build -- --out=/path/to/output` - specify custom output directory
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# Standard production build
|
||||
npm run build
|
||||
|
||||
# Debug build for development (no minification)
|
||||
npm run build -- --debug
|
||||
|
||||
# Debug build with custom output path
|
||||
npm run build -- --debug --out=./debug-build
|
||||
```
|
||||
|
||||
### GDJS Platform (exporters, code generation...)
|
||||
|
||||
Check the [GDJS Platform](https://docs.gdevelop.io/GDJS%20Documentation/index.html) documentation or the [full GDevelop developers documentation](https://docs.gdevelop.io/).
|
||||
|
@@ -462,12 +462,12 @@ namespace gdjs {
|
||||
/**
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layerName The lighting layer with the ambient color.
|
||||
* @param rgbColor The color, in RGB format ("128;200;255").
|
||||
* @param rgbOrHexColor The color, in RGB format ("128;200;255").
|
||||
*/
|
||||
export const setLayerAmbientLightColor = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layerName: string,
|
||||
rgbColor: string
|
||||
rgbOrHexColor: string
|
||||
) {
|
||||
if (
|
||||
!instanceContainer.hasLayer(layerName) ||
|
||||
@@ -475,17 +475,10 @@ namespace gdjs {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
const color = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
return instanceContainer
|
||||
.getLayer(layerName)
|
||||
.setClearColor(
|
||||
parseInt(colors[0], 10),
|
||||
parseInt(colors[1], 10),
|
||||
parseInt(colors[2], 10)
|
||||
);
|
||||
.setClearColor(color[0], color[1], color[2]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -24,19 +24,12 @@ namespace gdjs {
|
||||
|
||||
export const setBackgroundColor = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
rgbColor: string
|
||||
rgbOrHexColor: string
|
||||
) {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
const color = gdjs.rgbOrHexToRGBColor(rgbOrHexColor);
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.setBackgroundColor(
|
||||
parseInt(colors[0]),
|
||||
parseInt(colors[1]),
|
||||
parseInt(colors[2])
|
||||
);
|
||||
.setBackgroundColor(color[0], color[1], color[2]);
|
||||
};
|
||||
|
||||
export const getElapsedTimeInSeconds = function (
|
||||
|
@@ -12,7 +12,6 @@ namespace gdjs {
|
||||
const logger = new gdjs.Logger('Engine runtime');
|
||||
const hexStringRegex = /^(#{0,1}[A-Fa-f0-9]{6})$/;
|
||||
const shorthandHexStringRegex = /^(#{0,1}[A-Fa-f0-9]{3})$/;
|
||||
const rgbStringRegex = /^(\d{1,3};\d{1,3};\d{1,3})/;
|
||||
|
||||
/**
|
||||
* Contains functions used by events (this is a convention only, functions can actually
|
||||
@@ -105,9 +104,9 @@ namespace gdjs {
|
||||
export const rgbOrHexToRGBColor = function (
|
||||
value: string
|
||||
): [number, number, number] {
|
||||
const rgbColor = extractRGBString(value);
|
||||
if (rgbColor) {
|
||||
const splitValue = rgbColor.split(';');
|
||||
// TODO Add a `result` parameter to allow to reuse the returned array.
|
||||
if (!value.startsWith('#')) {
|
||||
const splitValue = value.split(';');
|
||||
// If a RGB string is provided, return the RGB object.
|
||||
if (splitValue.length === 3) {
|
||||
return [
|
||||
@@ -145,11 +144,11 @@ namespace gdjs {
|
||||
* @param b Blue
|
||||
*/
|
||||
export const rgbToHexNumber = function (
|
||||
r: integer,
|
||||
g: integer,
|
||||
b: integer
|
||||
r: float,
|
||||
g: float,
|
||||
b: float
|
||||
): integer {
|
||||
return (r << 16) + (g << 8) + b;
|
||||
return (Math.round(r) << 16) + (Math.round(g) << 8) + Math.round(b);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -192,12 +191,6 @@ namespace gdjs {
|
||||
return matches[0];
|
||||
};
|
||||
|
||||
export const extractRGBString = (str: string): string | null => {
|
||||
const matches = str.match(rgbStringRegex);
|
||||
if (!matches) return null;
|
||||
return matches[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a random integer between 0 and max.
|
||||
* @param max The maximum value (inclusive).
|
||||
@@ -509,18 +502,21 @@ namespace gdjs {
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const objectsListsToArray = function (
|
||||
objectsLists: Hashtable<RuntimeObject>
|
||||
objectsLists: Hashtable<RuntimeObject>,
|
||||
result: Array<RuntimeObject> = []
|
||||
): Array<RuntimeObject> {
|
||||
var lists = gdjs.staticArray(gdjs.objectsListsToArray);
|
||||
const lists = gdjs.staticArray(gdjs.objectsListsToArray);
|
||||
objectsLists.values(lists);
|
||||
|
||||
var result: Array<RuntimeObject> = [];
|
||||
for (var i = 0; i < lists.length; ++i) {
|
||||
var arr = lists[i];
|
||||
for (var k = 0; k < arr.length; ++k) {
|
||||
result.push(arr[k]);
|
||||
let resultIndex = 0;
|
||||
for (let i = 0; i < lists.length; ++i) {
|
||||
const arr = lists[i];
|
||||
for (let k = 0; k < arr.length; ++k) {
|
||||
result[resultIndex] = arr[k];
|
||||
resultIndex++;
|
||||
}
|
||||
}
|
||||
result.length = resultIndex;
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -531,8 +527,8 @@ namespace gdjs {
|
||||
* @param dst The destination array
|
||||
*/
|
||||
export const copyArray = function <T>(src: Array<T>, dst: Array<T>): void {
|
||||
var len = src.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
const len = src.length;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
dst.length = len;
|
||||
|
@@ -140,18 +140,18 @@ namespace gdjs {
|
||||
this._sprite.visible = !this._object.hidden;
|
||||
}
|
||||
|
||||
setColor(rgbOrHexColor): void {
|
||||
setColor(rgbOrHexColor: string): void {
|
||||
this._sprite.tint = gdjs.rgbOrHexStringToNumber(rgbOrHexColor);
|
||||
}
|
||||
|
||||
getColor() {
|
||||
const rgb = new PIXI.Color(this._sprite.tint).toRgbArray();
|
||||
return (
|
||||
Math.floor(rgb[0] * 255) +
|
||||
Math.round(rgb[0] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[1] * 255) +
|
||||
Math.round(rgb[1] * 255) +
|
||||
';' +
|
||||
Math.floor(rgb[2] * 255)
|
||||
Math.round(rgb[2] * 255)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,8 @@ const {
|
||||
} = require('./lib/runtime-files-list');
|
||||
const args = require('minimist')(process.argv.slice(2), {
|
||||
string: ['out'],
|
||||
boolean: ['debug'],
|
||||
default: { debug: false }
|
||||
});
|
||||
const fs = require('fs').promises;
|
||||
|
||||
@@ -52,7 +54,7 @@ shell.mkdir('-p', bundledOutPath);
|
||||
return build({
|
||||
sourcemap: true,
|
||||
entryPoints: [inPath],
|
||||
minify: true,
|
||||
minify: !args.debug,
|
||||
outfile: renameBuiltFile(outPath),
|
||||
}).catch(() => {
|
||||
// Error is already logged by esbuild.
|
||||
|
@@ -36,11 +36,11 @@ describe('gdjs', function () {
|
||||
expect(gdjs.rgbOrHexToRGBColor('255;255;300')).to.eql([255, 255, 255]);
|
||||
expect(gdjs.rgbOrHexToRGBColor('999;12;6')).to.eql([255, 12, 6]);
|
||||
});
|
||||
it('should cut rgb values if string too long', function () {
|
||||
it('should cap rgb values', function () {
|
||||
expect(gdjs.rgbOrHexToRGBColor('255;255;200456')).to.eql([
|
||||
255,
|
||||
255,
|
||||
200,
|
||||
255,
|
||||
]);
|
||||
});
|
||||
it('should return components for black if unrecognized input', function () {
|
||||
@@ -48,7 +48,6 @@ describe('gdjs', function () {
|
||||
expect(gdjs.rgbOrHexToRGBColor('19819830803')).to.eql([0, 0, 0]);
|
||||
expect(gdjs.rgbOrHexToRGBColor('Infinity')).to.eql([0, 0, 0]);
|
||||
expect(gdjs.rgbOrHexToRGBColor('-4564')).to.eql([0, 0, 0]);
|
||||
expect(gdjs.rgbOrHexToRGBColor('9999;12;6')).to.eql([0, 0, 0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3728,6 +3728,8 @@ interface TextObject {
|
||||
[Const, Ref] DOMString GetText();
|
||||
void SetCharacterSize(double size);
|
||||
double GetCharacterSize();
|
||||
void SetLineHeight(double value);
|
||||
double GetLineHeight();
|
||||
void SetFontName([Const] DOMString string);
|
||||
[Const, Ref] DOMString GetFontName();
|
||||
boolean IsBold();
|
||||
|
@@ -239,7 +239,8 @@ function generateCompiledEventsForSerializedEventsBasedExtension(
|
||||
gd,
|
||||
serializedEventsFunctionsExtension,
|
||||
gdjs,
|
||||
runtimeScene
|
||||
runtimeScene,
|
||||
options
|
||||
) {
|
||||
const project = new gd.ProjectHelper.createNewGDJSProject();
|
||||
const extension = project.insertNewEventsFunctionsExtension(
|
||||
@@ -294,7 +295,8 @@ function generateCompiledEventsForSerializedEventsBasedExtension(
|
||||
project,
|
||||
extension,
|
||||
behavior,
|
||||
gdjs
|
||||
gdjs,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -531,7 +531,7 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
|
||||
// Check that the context for the events function is here...
|
||||
expect(code).toMatch('function(runtimeScene, eventsFunctionContext)');
|
||||
expect(code).toMatch('var eventsFunctionContext =');
|
||||
expect(code).toMatch('const eventsFunctionContext =');
|
||||
|
||||
// Check that the parameters, with the (optional) context of the parent function,
|
||||
// are all here
|
||||
@@ -544,8 +544,8 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
expect(code).toMatch('"MySprite": MySprite');
|
||||
|
||||
// ...and arguments should be able to get queried too:
|
||||
expect(code).toMatch('if (argName === "MyNumber") return MyNumber;');
|
||||
expect(code).toMatch('if (argName === "MyString") return MyString;');
|
||||
expect(code).toMatch('if (argName === "MyNumber") return this.MyNumber;');
|
||||
expect(code).toMatch('if (argName === "MyString") return this.MyString;');
|
||||
|
||||
// GetArgumentAsString("MyString") should be generated code to query and cast as a string
|
||||
// the argument
|
||||
@@ -635,7 +635,7 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
|
||||
// Check that the context for the events function is here...
|
||||
expect(code).toMatch('function(runtimeScene, eventsFunctionContext)');
|
||||
expect(code).toMatch('var eventsFunctionContext =');
|
||||
expect(code).toMatch('const eventsFunctionContext =');
|
||||
|
||||
// Check that the parameters, with the (optional) context of the parent function,
|
||||
// are all here
|
||||
|
@@ -80,7 +80,7 @@ describe('libGD.js - GDJS Behavior Code Generation integration tests', function
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedBehavior,
|
||||
gdjs,
|
||||
{logCode: false}
|
||||
{ logCode: false }
|
||||
);
|
||||
project.delete();
|
||||
|
||||
|
@@ -3578,7 +3578,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
|
||||
gd,
|
||||
require('./extensions/EBAsyncAction.json'),
|
||||
gdjs,
|
||||
runtimeScene
|
||||
runtimeScene,
|
||||
{ logCode: true }
|
||||
);
|
||||
|
||||
const {
|
||||
@@ -3618,7 +3619,8 @@ describe('libGD.js - GDJS Async Code Generation integration tests', function ()
|
||||
gd,
|
||||
require('./extensions/EBAsyncAction.json'),
|
||||
gdjs,
|
||||
runtimeScene
|
||||
runtimeScene,
|
||||
{ logCode: false }
|
||||
);
|
||||
|
||||
const {
|
||||
|
@@ -12,7 +12,7 @@ describe('libGD.js - GDJS Object Code Generation integration tests', function ()
|
||||
});
|
||||
|
||||
describe('SceneInstancesCount', () => {
|
||||
const prepareCompiledEvents = () => {
|
||||
const prepareCompiledEvents = (options = {}) => {
|
||||
const eventsSerializerElement = gd.Serializer.fromJSObject([
|
||||
{
|
||||
type: 'BuiltinCommonInstructions::Standard',
|
||||
@@ -62,7 +62,8 @@ describe('libGD.js - GDJS Object Code Generation integration tests', function ()
|
||||
const runCompiledEvents = generateCompiledEventsForEventsFunction(
|
||||
gd,
|
||||
project,
|
||||
eventsFunction
|
||||
eventsFunction,
|
||||
options.logCode
|
||||
);
|
||||
|
||||
eventsFunction.delete();
|
||||
@@ -71,7 +72,7 @@ describe('libGD.js - GDJS Object Code Generation integration tests', function ()
|
||||
};
|
||||
|
||||
it('counts instances from the scene in a function, when no instances are passed as parameters', () => {
|
||||
const { runCompiledEvents } = prepareCompiledEvents();
|
||||
const { runCompiledEvents } = prepareCompiledEvents({ logCode: false });
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
runtimeScene.getOnceTriggers().startNewFrame();
|
||||
|
||||
@@ -106,7 +107,7 @@ describe('libGD.js - GDJS Object Code Generation integration tests', function ()
|
||||
});
|
||||
|
||||
it('counts instances from the scene in a function, when some instances are passed as parameters', () => {
|
||||
const { runCompiledEvents } = prepareCompiledEvents();
|
||||
const { runCompiledEvents } = prepareCompiledEvents({ logCode: false });
|
||||
const { gdjs, runtimeScene } = makeMinimalGDJSMock();
|
||||
runtimeScene.getOnceTriggers().startNewFrame();
|
||||
|
||||
|
@@ -737,7 +737,7 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
},
|
||||
],
|
||||
{
|
||||
logCode: true,
|
||||
logCode: false,
|
||||
}
|
||||
);
|
||||
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
|
||||
@@ -787,7 +787,7 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
},
|
||||
],
|
||||
{
|
||||
logCode: true,
|
||||
logCode: false,
|
||||
}
|
||||
);
|
||||
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
|
||||
@@ -882,7 +882,7 @@ describe('libGD.js - GDJS Code Generation integration tests', function () {
|
||||
},
|
||||
],
|
||||
{
|
||||
logCode: true,
|
||||
logCode: false,
|
||||
}
|
||||
);
|
||||
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
|
||||
|
@@ -64,7 +64,7 @@ describe('libGD.js object serialization', function() {
|
||||
obj.delete();
|
||||
|
||||
expect(jsonObject).toBe(
|
||||
'{"bold":false,"italic":false,"smoothed":true,"underlined":false,"string":"Text of the object, with 官话 characters","font":"","textAlignment":"left","characterSize":20.0,"color":{"b":0,"g":0,"r":0},"content":{"bold":false,"isOutlineEnabled":false,"isShadowEnabled":false,"italic":false,"outlineColor":"255;255;255","outlineThickness":2.0,"shadowAngle":90.0,"shadowBlurRadius":2.0,"shadowColor":"0;0;0","shadowDistance":4.0,"shadowOpacity":127.0,"smoothed":true,"underlined":false,"text":"Text of the object, with 官话 characters","font":"","textAlignment":"left","verticalTextAlignment":"top","characterSize":20.0,"color":"0;0;0"}}'
|
||||
'{"bold":false,"italic":false,"smoothed":true,"underlined":false,"string":"Text of the object, with 官话 characters","font":"","textAlignment":"left","characterSize":20.0,"color":{"b":0,"g":0,"r":0},"content":{"bold":false,"isOutlineEnabled":false,"isShadowEnabled":false,"italic":false,"outlineColor":"255;255;255","outlineThickness":2.0,"shadowAngle":90.0,"shadowBlurRadius":2.0,"shadowColor":"0;0;0","shadowDistance":4.0,"shadowOpacity":127.0,"smoothed":true,"underlined":false,"text":"Text of the object, with 官话 characters","font":"","textAlignment":"left","verticalTextAlignment":"top","characterSize":20.0,"lineHeight":0.0,"color":"0;0;0"}}'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
2
GDevelop.js/types.d.ts
vendored
2
GDevelop.js/types.d.ts
vendored
@@ -2758,6 +2758,8 @@ export class TextObject extends ObjectConfiguration {
|
||||
getText(): string;
|
||||
setCharacterSize(size: number): void;
|
||||
getCharacterSize(): number;
|
||||
setLineHeight(value: number): void;
|
||||
getLineHeight(): number;
|
||||
setFontName(string: string): void;
|
||||
getFontName(): string;
|
||||
isBold(): boolean;
|
||||
|
@@ -5,6 +5,8 @@ declare class gdTextObject extends gdObjectConfiguration {
|
||||
getText(): string;
|
||||
setCharacterSize(size: number): void;
|
||||
getCharacterSize(): number;
|
||||
setLineHeight(value: number): void;
|
||||
getLineHeight(): number;
|
||||
setFontName(string: string): void;
|
||||
getFontName(): string;
|
||||
isBold(): boolean;
|
||||
|
@@ -19,6 +19,7 @@ import { type ExtensionItemConfigurationAttribute } from '../EventsFunctionsExte
|
||||
import SelectField from '../UI/SelectField';
|
||||
import SelectOption from '../UI/SelectOption';
|
||||
import Window from '../Utils/Window';
|
||||
import ScrollView from '../UI/ScrollView';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
@@ -67,150 +68,154 @@ export default function EventsBasedBehaviorEditor({
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<DismissableAlertMessage
|
||||
identifier="events-based-behavior-explanation"
|
||||
kind="info"
|
||||
>
|
||||
<Trans>
|
||||
This is the configuration of your behavior. Make sure to choose a
|
||||
proper internal name as it's hard to change it later. Enter a
|
||||
description explaining what the behavior is doing to the object.
|
||||
</Trans>
|
||||
</DismissableAlertMessage>
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Internal Name</Trans>}
|
||||
value={eventsBasedBehavior.getName()}
|
||||
disabled
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Name displayed in editor</Trans>}
|
||||
value={eventsBasedBehavior.getFullName()}
|
||||
onChange={text => {
|
||||
eventsBasedBehavior.setFullName(text);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Description</Trans>}
|
||||
helperMarkdownText={i18n._(
|
||||
t`Explain what the behavior is doing to the object. Start with a verb when possible.`
|
||||
)}
|
||||
value={eventsBasedBehavior.getDescription()}
|
||||
onChange={text => {
|
||||
eventsBasedBehavior.setDescription(text);
|
||||
onChange();
|
||||
}}
|
||||
multiline
|
||||
fullWidth
|
||||
rows={3}
|
||||
/>
|
||||
<ObjectTypeSelector
|
||||
floatingLabelText={
|
||||
<Trans>Object on which this behavior can be used</Trans>
|
||||
}
|
||||
project={project}
|
||||
value={eventsBasedBehavior.getObjectType()}
|
||||
onChange={(objectType: string) => {
|
||||
eventsBasedBehavior.setObjectType(objectType);
|
||||
onChange();
|
||||
}}
|
||||
allowedObjectTypes={
|
||||
allObjectTypes.length === 0
|
||||
? undefined /* Allow anything as the behavior is not used */
|
||||
: allObjectTypes.length === 1
|
||||
? [
|
||||
'',
|
||||
allObjectTypes[0],
|
||||
] /* Allow only the type of the objects using the behavior */
|
||||
: [
|
||||
'',
|
||||
] /* More than one type of object are using the behavior. Only "any object" can be used on this behavior */
|
||||
}
|
||||
/>
|
||||
{allObjectTypes.length > 1 && (
|
||||
<AlertMessage kind="info">
|
||||
<Trans>
|
||||
This behavior is being used by multiple types of objects. Thus,
|
||||
you can't restrict its usage to any particular object type. All
|
||||
the object types using this behavior are listed here:
|
||||
{allObjectTypes.join(', ')}
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
)}
|
||||
{isDev && (
|
||||
<SelectField
|
||||
floatingLabelText={
|
||||
<Trans>Visibility in quick customization dialog</Trans>
|
||||
}
|
||||
value={eventsBasedBehavior.getQuickCustomizationVisibility()}
|
||||
onChange={(e, i, valueString: string) => {
|
||||
// $FlowFixMe
|
||||
const value: QuickCustomization_Visibility = valueString;
|
||||
eventsBasedBehavior.setQuickCustomizationVisibility(value);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Default}
|
||||
label={t`Default (visible)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Visible}
|
||||
label={t`Always visible`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Hidden}
|
||||
label={t`Hidden`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
<Checkbox
|
||||
label={<Trans>Private</Trans>}
|
||||
checked={eventsBasedBehavior.isPrivate()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedBehavior.setPrivate(checked);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated('isPrivate');
|
||||
onChange();
|
||||
}}
|
||||
tooltipOrHelperText={
|
||||
eventsBasedBehavior.isPrivate() ? (
|
||||
<Trans>
|
||||
This behavior won't be visible in the scene and events
|
||||
editors.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
This behavior will be visible in the scene and events editors.
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
{eventsBasedBehavior
|
||||
.getEventsFunctions()
|
||||
.getEventsFunctionsCount() === 0 && (
|
||||
<ScrollView>
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<DismissableAlertMessage
|
||||
identifier="empty-events-based-behavior-explanation"
|
||||
identifier="events-based-behavior-explanation"
|
||||
kind="info"
|
||||
>
|
||||
<Trans>
|
||||
Once you're done, start adding some functions to the behavior.
|
||||
Then, test the behavior by adding it to an object in a scene.
|
||||
This is the configuration of your behavior. Make sure to choose
|
||||
a proper internal name as it's hard to change it later. Enter a
|
||||
description explaining what the behavior is doing to the object.
|
||||
</Trans>
|
||||
</DismissableAlertMessage>
|
||||
)}
|
||||
<Line noMargin>
|
||||
<HelpButton
|
||||
key="help"
|
||||
helpPagePath="/behaviors/events-based-behaviors"
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Internal Name</Trans>}
|
||||
value={eventsBasedBehavior.getName()}
|
||||
disabled
|
||||
fullWidth
|
||||
/>
|
||||
</Line>
|
||||
</ColumnStackLayout>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Name displayed in editor</Trans>}
|
||||
value={eventsBasedBehavior.getFullName()}
|
||||
onChange={text => {
|
||||
eventsBasedBehavior.setFullName(text);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Description</Trans>}
|
||||
helperMarkdownText={i18n._(
|
||||
t`Explain what the behavior is doing to the object. Start with a verb when possible.`
|
||||
)}
|
||||
value={eventsBasedBehavior.getDescription()}
|
||||
onChange={text => {
|
||||
eventsBasedBehavior.setDescription(text);
|
||||
onChange();
|
||||
}}
|
||||
multiline
|
||||
fullWidth
|
||||
rows={3}
|
||||
/>
|
||||
<ObjectTypeSelector
|
||||
floatingLabelText={
|
||||
<Trans>Object on which this behavior can be used</Trans>
|
||||
}
|
||||
project={project}
|
||||
value={eventsBasedBehavior.getObjectType()}
|
||||
onChange={(objectType: string) => {
|
||||
eventsBasedBehavior.setObjectType(objectType);
|
||||
onChange();
|
||||
}}
|
||||
allowedObjectTypes={
|
||||
allObjectTypes.length === 0
|
||||
? undefined /* Allow anything as the behavior is not used */
|
||||
: allObjectTypes.length === 1
|
||||
? [
|
||||
'',
|
||||
allObjectTypes[0],
|
||||
] /* Allow only the type of the objects using the behavior */
|
||||
: [
|
||||
'',
|
||||
] /* More than one type of object are using the behavior. Only "any object" can be used on this behavior */
|
||||
}
|
||||
/>
|
||||
{allObjectTypes.length > 1 && (
|
||||
<AlertMessage kind="info">
|
||||
<Trans>
|
||||
This behavior is being used by multiple types of objects.
|
||||
Thus, you can't restrict its usage to any particular object
|
||||
type. All the object types using this behavior are listed
|
||||
here:
|
||||
{allObjectTypes.join(', ')}
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
)}
|
||||
{isDev && (
|
||||
<SelectField
|
||||
floatingLabelText={
|
||||
<Trans>Visibility in quick customization dialog</Trans>
|
||||
}
|
||||
value={eventsBasedBehavior.getQuickCustomizationVisibility()}
|
||||
onChange={(e, i, valueString: string) => {
|
||||
// $FlowFixMe
|
||||
const value: QuickCustomization_Visibility = valueString;
|
||||
eventsBasedBehavior.setQuickCustomizationVisibility(value);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Default}
|
||||
label={t`Default (visible)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Visible}
|
||||
label={t`Always visible`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.QuickCustomization.Hidden}
|
||||
label={t`Hidden`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
<Checkbox
|
||||
label={<Trans>Private</Trans>}
|
||||
checked={eventsBasedBehavior.isPrivate()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedBehavior.setPrivate(checked);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated('isPrivate');
|
||||
onChange();
|
||||
}}
|
||||
tooltipOrHelperText={
|
||||
eventsBasedBehavior.isPrivate() ? (
|
||||
<Trans>
|
||||
This behavior won't be visible in the scene and events
|
||||
editors.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
This behavior will be visible in the scene and events
|
||||
editors.
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
{eventsBasedBehavior
|
||||
.getEventsFunctions()
|
||||
.getEventsFunctionsCount() === 0 && (
|
||||
<DismissableAlertMessage
|
||||
identifier="empty-events-based-behavior-explanation"
|
||||
kind="info"
|
||||
>
|
||||
<Trans>
|
||||
Once you're done, start adding some functions to the behavior.
|
||||
Then, test the behavior by adding it to an object in a scene.
|
||||
</Trans>
|
||||
</DismissableAlertMessage>
|
||||
)}
|
||||
<Line noMargin>
|
||||
<HelpButton
|
||||
key="help"
|
||||
helpPagePath="/behaviors/events-based-behaviors"
|
||||
/>
|
||||
</Line>
|
||||
</ColumnStackLayout>
|
||||
</ScrollView>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
|
@@ -72,6 +72,7 @@ export default function EventsBasedObjectEditorPanel({
|
||||
</Line>
|
||||
{currentTab === 'configuration' && (
|
||||
<EventsBasedObjectEditor
|
||||
eventsFunctionsExtension={eventsFunctionsExtension}
|
||||
eventsBasedObject={eventsBasedObject}
|
||||
unsavedChanges={unsavedChanges}
|
||||
onOpenCustomObjectEditor={onOpenCustomObjectEditor}
|
||||
|
@@ -6,7 +6,8 @@ import * as React from 'react';
|
||||
import TextField from '../UI/TextField';
|
||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||
import DismissableAlertMessage from '../UI/DismissableAlertMessage';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import { ColumnStackLayout, LineStackLayout } from '../UI/Layout';
|
||||
import useForceUpdate from '../Utils/UseForceUpdate';
|
||||
import Checkbox from '../UI/Checkbox';
|
||||
import HelpButton from '../UI/HelpButton';
|
||||
@@ -14,12 +15,15 @@ import { Line } from '../UI/Grid';
|
||||
import { type UnsavedChanges } from '../MainFrame/UnsavedChangesContext';
|
||||
import RaisedButton from '../UI/RaisedButton';
|
||||
import Window from '../Utils/Window';
|
||||
import ScrollView from '../UI/ScrollView';
|
||||
import { Column } from '../UI/Grid';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
const isDev = Window.isDev();
|
||||
|
||||
type Props = {|
|
||||
eventsFunctionsExtension: gdEventsFunctionsExtension,
|
||||
eventsBasedObject: gdEventsBasedObject,
|
||||
onOpenCustomObjectEditor: () => void,
|
||||
unsavedChanges?: ?UnsavedChanges,
|
||||
@@ -29,6 +33,7 @@ type Props = {|
|
||||
|};
|
||||
|
||||
export default function EventsBasedObjectEditor({
|
||||
eventsFunctionsExtension,
|
||||
eventsBasedObject,
|
||||
onOpenCustomObjectEditor,
|
||||
unsavedChanges,
|
||||
@@ -47,135 +52,155 @@ export default function EventsBasedObjectEditor({
|
||||
);
|
||||
|
||||
return (
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<DismissableAlertMessage
|
||||
identifier="events-based-object-explanation"
|
||||
kind="info"
|
||||
>
|
||||
<Trans>
|
||||
This is the configuration of your object. Make sure to choose a proper
|
||||
internal name as it's hard to change it later.
|
||||
</Trans>
|
||||
</DismissableAlertMessage>
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Internal Name</Trans>}
|
||||
value={eventsBasedObject.getName()}
|
||||
disabled
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Name displayed in editor</Trans>}
|
||||
value={eventsBasedObject.getFullName()}
|
||||
onChange={text => {
|
||||
eventsBasedObject.setFullName(text);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Description</Trans>}
|
||||
floatingLabelFixed
|
||||
translatableHintText={t`The description of the object should explain what the object is doing, and, briefly, how to use it.`}
|
||||
value={eventsBasedObject.getDescription()}
|
||||
onChange={text => {
|
||||
eventsBasedObject.setDescription(text);
|
||||
onChange();
|
||||
}}
|
||||
multiline
|
||||
fullWidth
|
||||
rows={3}
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Default name for created objects</Trans>}
|
||||
value={
|
||||
eventsBasedObject.getDefaultName() || eventsBasedObject.getName()
|
||||
}
|
||||
onChange={newName => {
|
||||
eventsBasedObject.setDefaultName(gd.Project.getSafeName(newName));
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Use 3D rendering</Trans>}
|
||||
checked={eventsBasedObject.isRenderedIn3D()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsRenderedIn3D(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Has animations</Trans>}
|
||||
checked={eventsBasedObject.isAnimatable()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsAnimatable(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Contains text</Trans>}
|
||||
checked={eventsBasedObject.isTextContainer()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsTextContainer(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Expand inner area with parent</Trans>}
|
||||
checked={eventsBasedObject.isInnerAreaFollowingParentSize()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsInnerAreaFollowingParentSize(checked);
|
||||
onChange();
|
||||
onEventsBasedObjectChildrenEdited(eventsBasedObject);
|
||||
}}
|
||||
/>
|
||||
{isDev && (
|
||||
<ScrollView>
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<DismissableAlertMessage
|
||||
identifier="events-based-object-explanation"
|
||||
kind="info"
|
||||
>
|
||||
<Trans>
|
||||
This is the configuration of your object. Make sure to choose a
|
||||
proper internal name as it's hard to change it later.
|
||||
</Trans>
|
||||
</DismissableAlertMessage>
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Internal Name</Trans>}
|
||||
value={eventsBasedObject.getName()}
|
||||
disabled
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Name displayed in editor</Trans>}
|
||||
value={eventsBasedObject.getFullName()}
|
||||
onChange={text => {
|
||||
eventsBasedObject.setFullName(text);
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Description</Trans>}
|
||||
floatingLabelFixed
|
||||
translatableHintText={t`The description of the object should explain what the object is doing, and, briefly, how to use it.`}
|
||||
value={eventsBasedObject.getDescription()}
|
||||
onChange={text => {
|
||||
eventsBasedObject.setDescription(text);
|
||||
onChange();
|
||||
}}
|
||||
multiline
|
||||
fullWidth
|
||||
rows={3}
|
||||
/>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Default name for created objects</Trans>}
|
||||
value={
|
||||
eventsBasedObject.getDefaultName() || eventsBasedObject.getName()
|
||||
}
|
||||
onChange={newName => {
|
||||
eventsBasedObject.setDefaultName(gd.Project.getSafeName(newName));
|
||||
onChange();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Use legacy renderer</Trans>}
|
||||
checked={eventsBasedObject.isUsingLegacyInstancesRenderer()}
|
||||
label={<Trans>Use 3D rendering</Trans>}
|
||||
checked={eventsBasedObject.isRenderedIn3D()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.makAsUsingLegacyInstancesRenderer(checked);
|
||||
eventsBasedObject.markAsRenderedIn3D(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Has animations</Trans>}
|
||||
checked={eventsBasedObject.isAnimatable()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsAnimatable(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Contains text</Trans>}
|
||||
checked={eventsBasedObject.isTextContainer()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsTextContainer(checked);
|
||||
onChange();
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label={<Trans>Expand inner area with parent</Trans>}
|
||||
checked={eventsBasedObject.isInnerAreaFollowingParentSize()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.markAsInnerAreaFollowingParentSize(checked);
|
||||
onChange();
|
||||
onEventsBasedObjectChildrenEdited(eventsBasedObject);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Checkbox
|
||||
label={<Trans>Private</Trans>}
|
||||
checked={eventsBasedObject.isPrivate()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.setPrivate(checked);
|
||||
onChange();
|
||||
onEventsBasedObjectChildrenEdited(eventsBasedObject);
|
||||
}}
|
||||
tooltipOrHelperText={
|
||||
eventsBasedObject.isPrivate() ? (
|
||||
<Trans>
|
||||
This object won't be visible in the scene and events editors.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
This object will be visible in the scene and events editors.
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Line noMargin justifyContent="center">
|
||||
<RaisedButton
|
||||
label={<Trans>Open visual editor for the object</Trans>}
|
||||
primary
|
||||
onClick={onOpenCustomObjectEditor}
|
||||
{isDev && (
|
||||
<Checkbox
|
||||
label={<Trans>Use legacy renderer</Trans>}
|
||||
checked={eventsBasedObject.isUsingLegacyInstancesRenderer()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.makAsUsingLegacyInstancesRenderer(checked);
|
||||
onChange();
|
||||
onEventsBasedObjectChildrenEdited(eventsBasedObject);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Checkbox
|
||||
label={<Trans>Private</Trans>}
|
||||
checked={eventsBasedObject.isPrivate()}
|
||||
onCheck={(e, checked) => {
|
||||
eventsBasedObject.setPrivate(checked);
|
||||
onChange();
|
||||
onEventsBasedObjectChildrenEdited(eventsBasedObject);
|
||||
}}
|
||||
tooltipOrHelperText={
|
||||
eventsBasedObject.isPrivate() ? (
|
||||
<Trans>
|
||||
This object won't be visible in the scene and events editors.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
This object will be visible in the scene and events editors.
|
||||
</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Line>
|
||||
<Line noMargin>
|
||||
<HelpButton
|
||||
key="help"
|
||||
helpPagePath="/objects/custom-objects-prefab-template"
|
||||
/>
|
||||
</Line>
|
||||
</ColumnStackLayout>
|
||||
{eventsFunctionsExtension.getOriginName() ===
|
||||
'gdevelop-extension-store' ? (
|
||||
<AlertMessage
|
||||
kind="error"
|
||||
renderRightButton={() => (
|
||||
<RaisedButton
|
||||
label={<Trans>Edit the default variant</Trans>}
|
||||
primary
|
||||
onClick={onOpenCustomObjectEditor}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<Trans>
|
||||
The default variant is erased when the extension is updated.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
) : (
|
||||
<Line noMargin justifyContent="center">
|
||||
<RaisedButton
|
||||
label={<Trans>Open visual editor for the object</Trans>}
|
||||
primary
|
||||
onClick={onOpenCustomObjectEditor}
|
||||
/>
|
||||
</Line>
|
||||
)}
|
||||
<Line noMargin>
|
||||
<HelpButton
|
||||
key="help"
|
||||
helpPagePath="/objects/custom-objects-prefab-template"
|
||||
/>
|
||||
</Line>
|
||||
</ColumnStackLayout>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ describe('EnumerateInstructions', () => {
|
||||
expect.objectContaining({
|
||||
displayedName: 'Animation finished',
|
||||
fullGroupName:
|
||||
'General ❯ Animatable capability ❯ Animations and images',
|
||||
'General ❯ Objects with animations ❯ Animations and images',
|
||||
type: 'AnimatableCapability::AnimatableBehavior::HasAnimationEnded',
|
||||
})
|
||||
);
|
||||
|
@@ -545,6 +545,20 @@ const useCourses = () => {
|
||||
]
|
||||
);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
if (language) {
|
||||
console.info(
|
||||
`Resetting course chapters cache as language changed to ${language}.`
|
||||
);
|
||||
setChaptersByCourseIdByUserId(() => ({
|
||||
'': noCourseChapters,
|
||||
}));
|
||||
}
|
||||
},
|
||||
[language]
|
||||
);
|
||||
|
||||
// This callback will change (triggering re-renders)
|
||||
// anytime the chapters are fetched for a course for a user.
|
||||
const getCourseChapters = React.useCallback(
|
||||
|
@@ -89,24 +89,6 @@ export default class TextEditor extends React.Component<EditorProps, void> {
|
||||
this.forceUpdate();
|
||||
}}
|
||||
/>
|
||||
<MiniToolbarText>
|
||||
<Trans>Line height:</Trans>
|
||||
</MiniToolbarText>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
id="text-object-line-height"
|
||||
type="number"
|
||||
margin="none"
|
||||
style={styles.sizeTextField}
|
||||
value={textObjectConfiguration.getLineHeight()}
|
||||
onChange={value => {
|
||||
textObjectConfiguration.setLineHeight(
|
||||
parseInt(value, 10) || 0
|
||||
);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
placeholder="Auto"
|
||||
/>
|
||||
<MiniToolbarText>
|
||||
<Trans>Color:</Trans>
|
||||
</MiniToolbarText>
|
||||
@@ -389,6 +371,21 @@ export default class TextEditor extends React.Component<EditorProps, void> {
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
<Text size="block-title" noMargin>
|
||||
<Trans>Multiline</Trans>
|
||||
</Text>
|
||||
<Line noMargin>
|
||||
<SemiControlledTextField
|
||||
floatingLabelText={<Trans>Line height</Trans>}
|
||||
type="number"
|
||||
fullWidth
|
||||
value={textObjectConfiguration.getLineHeight()}
|
||||
onChange={value => {
|
||||
textObjectConfiguration.setLineHeight(parseFloat(value) || 0);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
/>
|
||||
</Line>
|
||||
</ColumnStackLayout>
|
||||
);
|
||||
}
|
||||
|
@@ -98,6 +98,7 @@ export default class RenderedTextInstance extends RenderedInstance {
|
||||
textObjectConfiguration.isItalic() !== this._isItalic ||
|
||||
textObjectConfiguration.isBold() !== this._isBold ||
|
||||
textObjectConfiguration.getCharacterSize() !== this._characterSize ||
|
||||
textObjectConfiguration.getLineHeight() !== this._lineHeight ||
|
||||
textObjectConfiguration.getTextAlignment() !== this._textAlignment ||
|
||||
textObjectConfiguration.getVerticalTextAlignment() !==
|
||||
this._verticalTextAlignment ||
|
||||
@@ -114,12 +115,12 @@ export default class RenderedTextInstance extends RenderedInstance {
|
||||
textObjectConfiguration.getShadowBlurRadius() !==
|
||||
this._shadowBlurRadius ||
|
||||
this._instance.hasCustomSize() !== this._wrapping ||
|
||||
(this.getCustomWidth() !== this._wrappingWidth && this._wrapping) ||
|
||||
textObjectConfiguration.getLineHeight() !== this._lineHeight
|
||||
(this.getCustomWidth() !== this._wrappingWidth && this._wrapping)
|
||||
) {
|
||||
this._isItalic = textObjectConfiguration.isItalic();
|
||||
this._isBold = textObjectConfiguration.isBold();
|
||||
this._characterSize = textObjectConfiguration.getCharacterSize();
|
||||
this._lineHeight = textObjectConfiguration.getLineHeight();
|
||||
this._textAlignment = textObjectConfiguration.getTextAlignment();
|
||||
this._verticalTextAlignment = textObjectConfiguration.getVerticalTextAlignment();
|
||||
this._color = textObjectConfiguration.getColor();
|
||||
@@ -134,7 +135,6 @@ export default class RenderedTextInstance extends RenderedInstance {
|
||||
this._shadowColor = textObjectConfiguration.getShadowColor();
|
||||
this._shadowOpacity = textObjectConfiguration.getShadowOpacity();
|
||||
this._shadowBlurRadius = textObjectConfiguration.getShadowBlurRadius();
|
||||
this._lineHeight = textObjectConfiguration.getLineHeight();
|
||||
|
||||
this._wrapping = this._instance.hasCustomSize();
|
||||
this._wrappingWidth = this.getCustomWidth();
|
||||
@@ -170,14 +170,12 @@ export default class RenderedTextInstance extends RenderedInstance {
|
||||
style.fontSize = Math.max(1, this._characterSize);
|
||||
style.fontStyle = this._isItalic ? 'italic' : 'normal';
|
||||
style.fontWeight = this._isBold ? 'bold' : 'normal';
|
||||
style.lineHeight = this._lineHeight !== 0 ? this._lineHeight : undefined;
|
||||
style.fill = rgbStringToHexNumber(this._color);
|
||||
style.wordWrap = this._wrapping;
|
||||
style.wordWrapWidth = this._wrappingWidth <= 1 ? 1 : this._wrappingWidth;
|
||||
style.breakWords = true;
|
||||
style.align = this._textAlignment;
|
||||
if (this._lineHeight > 0) {
|
||||
style.lineHeight = this._lineHeight;
|
||||
}
|
||||
|
||||
style.stroke = rgbStringToHexNumber(this._outlineColor);
|
||||
style.strokeThickness = this._isOutlineEnabled
|
||||
|
@@ -104,6 +104,7 @@ export class ExtensionTreeViewItemContent implements TreeViewItemContent {
|
||||
if (oldName === newName) {
|
||||
return;
|
||||
}
|
||||
this.eventsFunctionsExtension.setOrigin('', '');
|
||||
this.props.onRenameEventsFunctionsExtension(oldName, newName);
|
||||
}
|
||||
|
||||
@@ -219,6 +220,9 @@ export class ExtensionTreeViewItemContent implements TreeViewItemContent {
|
||||
project
|
||||
);
|
||||
newEventsFunctionsExtension.setName(newName); // Unserialization has overwritten the name.
|
||||
if (newName !== name) {
|
||||
newEventsFunctionsExtension.setOrigin('', '');
|
||||
}
|
||||
|
||||
this._onProjectItemModified();
|
||||
this.props.onReloadEventsFunctionsExtensions();
|
||||
|
@@ -17,6 +17,7 @@ export default {
|
||||
|
||||
export const Default = () => (
|
||||
<EventsBasedObjectEditor
|
||||
eventsFunctionsExtension={testProject.testEventsFunctionsExtension}
|
||||
eventsBasedObject={testProject.testEventsBasedObject}
|
||||
onOpenCustomObjectEditor={action('onOpenCustomObjectEditor')}
|
||||
onEventsBasedObjectChildrenEdited={action(
|
||||
|
Reference in New Issue
Block a user