From aeaf1e1c24b574786610c6e6746f27e5216d78bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 18 Sep 2024 12:09:33 +0200 Subject: [PATCH 1/7] Add vertical alignment property for text object --- Extensions/TextObject/TextObject.cpp | 16 +++++ Extensions/TextObject/TextObject.h | 6 ++ .../textruntimeobject-pixi-renderer.ts | 10 +++ Extensions/TextObject/textruntimeobject.ts | 28 ++++++++ GDevelop.js/Bindings/Bindings.idl | 2 + GDevelop.js/types.d.ts | 2 + GDevelop.js/types/gdtextobject.js | 2 + .../src/ObjectEditor/Editors/TextEditor.js | 70 +++++++++++++++++-- .../Renderers/RenderedTextInstance.js | 23 +++++- .../UI/CustomSvgIcons/BottomTextAlignment.js | 19 +++++ .../CenterVerticalTextAlignment.js | 25 +++++++ .../src/UI/CustomSvgIcons/TopTextAlignment.js | 19 +++++ 12 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 newIDE/app/src/UI/CustomSvgIcons/BottomTextAlignment.js create mode 100644 newIDE/app/src/UI/CustomSvgIcons/CenterVerticalTextAlignment.js create mode 100644 newIDE/app/src/UI/CustomSvgIcons/TopTextAlignment.js diff --git a/Extensions/TextObject/TextObject.cpp b/Extensions/TextObject/TextObject.cpp index f33901302124..519170ee0be8 100644 --- a/Extensions/TextObject/TextObject.cpp +++ b/Extensions/TextObject/TextObject.cpp @@ -27,6 +27,7 @@ TextObject::TextObject() underlined(false), color("0;0;0"), textAlignment("left"), + verticalTextAlignment("top"), isOutlineEnabled(false), outlineThickness(2), outlineColor("255;255;255"), @@ -69,6 +70,10 @@ bool TextObject::UpdateProperty(const gd::String& propertyName, textAlignment = newValue; return true; } + if (propertyName == "verticalTextAlignment") { + verticalTextAlignment = newValue; + return true; + } if (propertyName == "isOutlineEnabled") { isOutlineEnabled = newValue == "1"; return true; @@ -163,6 +168,15 @@ std::map TextObject::GetProperties() const { .SetGroup(_("Font")) .SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden); + objectProperties["verticalTextAlignment"] + .SetValue(verticalTextAlignment) + .SetType("choice") + .AddExtraInfo("top") + .AddExtraInfo("center") + .AddExtraInfo("bottom") + .SetLabel(_("Vertical alignment, when multiple lines are displayed")) + .SetGroup(_("Font")); + objectProperties["isOutlineEnabled"] .SetValue(isOutlineEnabled ? "true" : "false") .SetType("boolean") @@ -252,6 +266,7 @@ void TextObject::DoUnserializeFrom(gd::Project& project, SetFontName(content.GetChild("font", 0, "Font").GetValue().GetString()); SetTextAlignment(content.GetChild("textAlignment").GetValue().GetString()); + SetVerticalTextAlignment(content.GetStringAttribute("verticalTextAlignment", "top")); SetCharacterSize(content.GetChild("characterSize", 0, "CharacterSize") .GetValue() .GetInt()); @@ -321,6 +336,7 @@ void TextObject::DoSerializeTo(gd::SerializerElement& element) const { content.AddChild("text").SetValue(GetText()); content.AddChild("font").SetValue(GetFontName()); content.AddChild("textAlignment").SetValue(GetTextAlignment()); + content.AddChild("verticalTextAlignment").SetValue(GetVerticalTextAlignment()); content.AddChild("characterSize").SetValue(GetCharacterSize()); content.AddChild("color").SetValue(GetColor()); diff --git a/Extensions/TextObject/TextObject.h b/Extensions/TextObject/TextObject.h index 37f20435568b..667228988899 100644 --- a/Extensions/TextObject/TextObject.h +++ b/Extensions/TextObject/TextObject.h @@ -62,6 +62,11 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration { textAlignment = textAlignment_; }; + inline const gd::String& GetVerticalTextAlignment() const { return verticalTextAlignment; }; + void SetVerticalTextAlignment(const gd::String& verticalTextAlignment_) { + verticalTextAlignment = verticalTextAlignment_; + }; + bool IsBold() const { return bold; }; void SetBold(bool enable) { bold = enable; }; bool IsItalic() const { return italic; }; @@ -120,6 +125,7 @@ class GD_EXTENSION_API TextObject : public gd::ObjectConfiguration { bool bold, italic, underlined; gd::String color; gd::String textAlignment; + gd::String verticalTextAlignment; bool isOutlineEnabled; double outlineThickness; diff --git a/Extensions/TextObject/textruntimeobject-pixi-renderer.ts b/Extensions/TextObject/textruntimeobject-pixi-renderer.ts index 42f7224e7dc8..60770f7b5075 100644 --- a/Extensions/TextObject/textruntimeobject-pixi-renderer.ts +++ b/Extensions/TextObject/textruntimeobject-pixi-renderer.ts @@ -118,6 +118,16 @@ namespace gdjs { this._text.anchor.x = 0.5; } this._text.position.y = this._object.y + this._text.height / 2; + + const alignmentY = + this._object._verticalTextAlignment === 'bottom' + ? 1 + : this._object._verticalTextAlignment === 'center' + ? 0.5 + : 0; + this._text.position.y = + this._object.y + this._text.height * (0.5 - alignmentY); + this._text.anchor.y = 0.5; } updateAngle(): void { diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index 01a63207f617..29566efe16cd 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -21,6 +21,7 @@ namespace gdjs { /** The text of the object */ text: string; textAlignment: string; + verticalTextAlignment: string; isOutlineEnabled: boolean; outlineThickness: float; @@ -83,6 +84,7 @@ namespace gdjs { _gradientType: string = ''; opacity: float = 255; _textAlign: string = 'left'; + _verticalTextAlignment: string = 'top'; _wrapping: boolean = false; // A wrapping of 1 makes games crash on Firefox _wrappingWidth: float = 100; @@ -124,6 +126,7 @@ namespace gdjs { this._color = gdjs.rgbOrHexToRGBColor(content.color); this._str = content.text; this._textAlign = content.textAlignment; + this._verticalTextAlignment = content.verticalTextAlignment; this._isOutlineEnabled = content.isOutlineEnabled; this._outlineThickness = content.outlineThickness; @@ -175,6 +178,11 @@ namespace gdjs { if (oldContent.textAlignment !== newContent.textAlignment) { this.setTextAlignment(newContent.textAlignment); } + if ( + oldContent.verticalTextAlignment !== newContent.verticalTextAlignment + ) { + this.setVerticalTextAlignment(newContent.verticalTextAlignment); + } if (oldContent.isOutlineEnabled !== newContent.isOutlineEnabled) { this.setOutlineEnabled(newContent.isOutlineEnabled); } @@ -267,6 +275,9 @@ namespace gdjs { if (networkSyncData.ta !== undefined) { this.setTextAlignment(networkSyncData.ta); } + if (networkSyncData.ta !== undefined) { + this.setVerticalTextAlignment(networkSyncData.ta); + } if (networkSyncData.wrap !== undefined) { this.setWrapping(networkSyncData.wrap); } @@ -594,6 +605,23 @@ namespace gdjs { return this._color[0] + ';' + this._color[1] + ';' + this._color[2]; } + /** + * Set the text alignment on Y axis for multiline text objects. + * @param alignment The text alignment. + */ + setVerticalTextAlignment(alignment: string): void { + this._verticalTextAlignment = alignment; + this._renderer.updateStyle(); + } + + /** + * Get the text alignment on Y axis of text object. + * @return The text alignment. + */ + getVerticalTextAlignment(): string { + return this._verticalTextAlignment; + } + /** * Set the text alignment for multiline text objects. * @param alignment The text alignment. diff --git a/GDevelop.js/Bindings/Bindings.idl b/GDevelop.js/Bindings/Bindings.idl index 5cb5e6bf7369..0bca0c2031ef 100644 --- a/GDevelop.js/Bindings/Bindings.idl +++ b/GDevelop.js/Bindings/Bindings.idl @@ -3524,6 +3524,8 @@ interface TextObject { [Const, Ref] DOMString GetColor(); void SetTextAlignment([Const] DOMString textAlignment); [Const, Ref] DOMString GetTextAlignment(); + void SetVerticalTextAlignment([Const] DOMString value); + [Const, Ref] DOMString GetVerticalTextAlignment(); void SetOutlineEnabled(boolean enable); boolean IsOutlineEnabled(); diff --git a/GDevelop.js/types.d.ts b/GDevelop.js/types.d.ts index c8c294d356ff..0796b3e59a8a 100644 --- a/GDevelop.js/types.d.ts +++ b/GDevelop.js/types.d.ts @@ -2623,6 +2623,8 @@ export class TextObject extends ObjectConfiguration { getColor(): string; setTextAlignment(textAlignment: string): void; getTextAlignment(): string; + setVerticalTextAlignment(value: string): void; + getVerticalTextAlignment(): string; setOutlineEnabled(enable: boolean): void; isOutlineEnabled(): boolean; setOutlineThickness(value: number): void; diff --git a/GDevelop.js/types/gdtextobject.js b/GDevelop.js/types/gdtextobject.js index 384aab5e7cf8..23a8d5c22562 100644 --- a/GDevelop.js/types/gdtextobject.js +++ b/GDevelop.js/types/gdtextobject.js @@ -17,6 +17,8 @@ declare class gdTextObject extends gdObjectConfiguration { getColor(): string; setTextAlignment(textAlignment: string): void; getTextAlignment(): string; + setVerticalTextAlignment(value: string): void; + getVerticalTextAlignment(): string; setOutlineEnabled(enable: boolean): void; isOutlineEnabled(): boolean; setOutlineThickness(value: number): void; diff --git a/newIDE/app/src/ObjectEditor/Editors/TextEditor.js b/newIDE/app/src/ObjectEditor/Editors/TextEditor.js index 2a69214d90ea..f19e77b736d5 100644 --- a/newIDE/app/src/ObjectEditor/Editors/TextEditor.js +++ b/newIDE/app/src/ObjectEditor/Editors/TextEditor.js @@ -7,7 +7,11 @@ import Checkbox from '../../UI/Checkbox'; import { Line, Column } from '../../UI/Grid'; import ColorPicker from '../../UI/ColorField/ColorPicker'; import { MiniToolbarText } from '../../UI/MiniToolbar'; -import { ColumnStackLayout, ResponsiveLineStackLayout } from '../../UI/Layout'; +import { + ColumnStackLayout, + LineStackLayout, + ResponsiveLineStackLayout, +} from '../../UI/Layout'; import ResourceSelector from '../../ResourcesList/ResourceSelector'; import ResourcesLoader from '../../ResourcesLoader'; import { type EditorProps } from './EditorProps.flow'; @@ -18,6 +22,9 @@ import Tooltip from '@material-ui/core/Tooltip'; import LeftTextAlignment from '../../UI/CustomSvgIcons/LeftTextAlignment'; import CenterTextAlignment from '../../UI/CustomSvgIcons/CenterTextAlignment'; import RightTextAlignment from '../../UI/CustomSvgIcons/RightTextAlignment'; +import TopTextAlignment from '../../UI/CustomSvgIcons/TopTextAlignment'; +import CenterVerticalTextAlignment from '../../UI/CustomSvgIcons/CenterVerticalTextAlignment'; +import BottomTextAlignment from '../../UI/CustomSvgIcons/BottomTextAlignment'; import Text from '../../UI/Text'; import { rgbColorToRGBString, @@ -55,6 +62,7 @@ export default class TextEditor extends React.Component { ); const textAlignment = textObjectConfiguration.getTextAlignment(); + const verticalTextAlignment = textObjectConfiguration.getVerticalTextAlignment(); return ( @@ -94,8 +102,6 @@ export default class TextEditor extends React.Component { this.forceUpdate(); }} /> - - Bold} checked={textObjectConfiguration.isBold()} @@ -114,6 +120,8 @@ export default class TextEditor extends React.Component { }} style={styles.checkbox} /> + + Align text on the left}> - + + Align text on the top}> + + + Align text on the center}> + + + Align text on the bottom}> + + + + ( + + + + +)); diff --git a/newIDE/app/src/UI/CustomSvgIcons/CenterVerticalTextAlignment.js b/newIDE/app/src/UI/CustomSvgIcons/CenterVerticalTextAlignment.js new file mode 100644 index 000000000000..600578e67f29 --- /dev/null +++ b/newIDE/app/src/UI/CustomSvgIcons/CenterVerticalTextAlignment.js @@ -0,0 +1,25 @@ +import React from 'react'; +import SvgIcon from '@material-ui/core/SvgIcon'; + +export default React.memo(props => ( + + + + + +)); diff --git a/newIDE/app/src/UI/CustomSvgIcons/TopTextAlignment.js b/newIDE/app/src/UI/CustomSvgIcons/TopTextAlignment.js new file mode 100644 index 000000000000..f69507490814 --- /dev/null +++ b/newIDE/app/src/UI/CustomSvgIcons/TopTextAlignment.js @@ -0,0 +1,19 @@ +import React from 'react'; +import SvgIcon from '@material-ui/core/SvgIcon'; + +export default React.memo(props => ( + + + + +)); From c3e11b8362d2a657537d7b8f9ca4793402e65390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 18 Sep 2024 18:21:18 +0200 Subject: [PATCH 2/7] Fix types --- Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js | 1 + Extensions/TweenBehavior/tests/TweenBehavior.spec.js | 1 + 2 files changed, 2 insertions(+) diff --git a/Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js b/Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js index 7026da0f6147..ee6839646e63 100644 --- a/Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js +++ b/Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js @@ -135,6 +135,7 @@ describe('gdjs.TweenRuntimeBehavior', () => { color: '0;0;0', text: '', textAlignment: 'left', + verticalTextAlignment: 'top', isOutlineEnabled: false, outlineThickness: 2, outlineColor: '255;255;255', diff --git a/Extensions/TweenBehavior/tests/TweenBehavior.spec.js b/Extensions/TweenBehavior/tests/TweenBehavior.spec.js index 4934df903436..f9f6c40f1f3b 100644 --- a/Extensions/TweenBehavior/tests/TweenBehavior.spec.js +++ b/Extensions/TweenBehavior/tests/TweenBehavior.spec.js @@ -135,6 +135,7 @@ describe('gdjs.TweenRuntimeBehavior', () => { color: '0;0;0', text: '', textAlignment: 'left', + verticalTextAlignment: 'top', isOutlineEnabled: false, outlineThickness: 2, outlineColor: '255;255;255', From 2c63a9aeb398218e3690ff640399a167a0482dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 18 Sep 2024 18:49:27 +0200 Subject: [PATCH 3/7] Fix tests. --- GDevelop.js/__tests__/Serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GDevelop.js/__tests__/Serializer.js b/GDevelop.js/__tests__/Serializer.js index eac4945081d4..49a5038f38da 100644 --- a/GDevelop.js/__tests__/Serializer.js +++ b/GDevelop.js/__tests__/Serializer.js @@ -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","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,"color":"0;0;0"}}' ); }); }); From 3d8aee744a6437ff6cb2a9f2d14ea99c07dbc9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Tue, 1 Oct 2024 11:18:38 +0200 Subject: [PATCH 4/7] Review changes --- Extensions/TextObject/TextObject.cpp | 2 +- Extensions/TextObject/textruntimeobject.ts | 8 +- .../src/ObjectEditor/Editors/TextEditor.js | 163 ++++++++---------- 3 files changed, 77 insertions(+), 96 deletions(-) diff --git a/Extensions/TextObject/TextObject.cpp b/Extensions/TextObject/TextObject.cpp index 519170ee0be8..dbd66db75dda 100644 --- a/Extensions/TextObject/TextObject.cpp +++ b/Extensions/TextObject/TextObject.cpp @@ -174,7 +174,7 @@ std::map TextObject::GetProperties() const { .AddExtraInfo("top") .AddExtraInfo("center") .AddExtraInfo("bottom") - .SetLabel(_("Vertical alignment, when multiple lines are displayed")) + .SetLabel(_("Vertical alignment")) .SetGroup(_("Font")); objectProperties["isOutlineEnabled"] diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index 29566efe16cd..bf5fb3c643e9 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -83,8 +83,8 @@ namespace gdjs { _gradient: Array> = []; _gradientType: string = ''; opacity: float = 255; - _textAlign: string = 'left'; - _verticalTextAlignment: string = 'top'; + _textAlign: string; + _verticalTextAlignment: string; _wrapping: boolean = false; // A wrapping of 1 makes games crash on Firefox _wrappingWidth: float = 100; @@ -125,8 +125,8 @@ namespace gdjs { this._underlined = content.underlined; this._color = gdjs.rgbOrHexToRGBColor(content.color); this._str = content.text; - this._textAlign = content.textAlignment; - this._verticalTextAlignment = content.verticalTextAlignment; + this._textAlign = content.textAlignment || 'left'; + this._verticalTextAlignment = content.verticalTextAlignment || 'top'; this._isOutlineEnabled = content.isOutlineEnabled; this._outlineThickness = content.outlineThickness; diff --git a/newIDE/app/src/ObjectEditor/Editors/TextEditor.js b/newIDE/app/src/ObjectEditor/Editors/TextEditor.js index f19e77b736d5..b577ed2dfbb0 100644 --- a/newIDE/app/src/ObjectEditor/Editors/TextEditor.js +++ b/newIDE/app/src/ObjectEditor/Editors/TextEditor.js @@ -18,7 +18,6 @@ import { type EditorProps } from './EditorProps.flow'; import SemiControlledTextField from '../../UI/SemiControlledTextField'; import ButtonGroup from '@material-ui/core/ButtonGroup'; import Button from '@material-ui/core/Button'; -import Tooltip from '@material-ui/core/Tooltip'; import LeftTextAlignment from '../../UI/CustomSvgIcons/LeftTextAlignment'; import CenterTextAlignment from '../../UI/CustomSvgIcons/CenterTextAlignment'; import RightTextAlignment from '../../UI/CustomSvgIcons/RightTextAlignment'; @@ -123,98 +122,80 @@ export default class TextEditor extends React.Component { - Align text on the left}> - - - Align text on the center}> - - - Align text on the right}> - - + + + - Align text on the top}> - - - Align text on the center}> - - - Align text on the bottom}> - - + + + From b50b93346ef82df5ac2ceea46dabef35ada3d7ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Tue, 1 Oct 2024 19:07:33 +0200 Subject: [PATCH 5/7] Fix anchored text objects. --- .../AnchorBehavior/anchorruntimebehavior.ts | 58 ++++++++++--- .../tests/anchorruntimebehavior.spec.js | 21 +++++ Extensions/TextObject/textruntimeobject.ts | 18 +++- .../Renderers/CustomObjectLayoutingModel.js | 83 +++++++++---------- 4 files changed, 125 insertions(+), 55 deletions(-) diff --git a/Extensions/AnchorBehavior/anchorruntimebehavior.ts b/Extensions/AnchorBehavior/anchorruntimebehavior.ts index eba11c0b47c6..b920d654a9d6 100644 --- a/Extensions/AnchorBehavior/anchorruntimebehavior.ts +++ b/Extensions/AnchorBehavior/anchorruntimebehavior.ts @@ -38,7 +38,8 @@ namespace gdjs { owner: gdjs.RuntimeObject ) { super(instanceContainer, behaviorData, owner); - this._relativeToOriginalWindowSize = !!behaviorData.relativeToOriginalWindowSize; + this._relativeToOriginalWindowSize = + !!behaviorData.relativeToOriginalWindowSize; this._leftEdgeAnchor = behaviorData.leftEdgeAnchor; this._rightEdgeAnchor = behaviorData.rightEdgeAnchor; this._topEdgeAnchor = behaviorData.topEdgeAnchor; @@ -88,7 +89,6 @@ namespace gdjs { const workingPoint: FloatPoint = gdjs.staticArray( gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents ) as FloatPoint; - // TODO EBO Make it work with event based objects or hide this behavior for them. let parentMinX = instanceContainer.getUnrotatedViewportMinX(); let parentMinY = instanceContainer.getUnrotatedViewportMinY(); let parentMaxX = instanceContainer.getUnrotatedViewportMaxX(); @@ -111,10 +111,11 @@ namespace gdjs { } //Calculate the distances from the window's bounds. - const topLeftPixel = layer.convertCoords( + const topLeftPixel = this._convertCoords( + instanceContainer, + layer, this.owner.getDrawableX(), this.owner.getDrawableY(), - 0, workingPoint ); @@ -141,10 +142,11 @@ namespace gdjs { } // It's fine to reuse workingPoint as topLeftPixel is no longer used. - const bottomRightPixel = layer.convertCoords( + const bottomRightPixel = this._convertCoords( + instanceContainer, + layer, this.owner.getDrawableX() + this.owner.getWidth(), this.owner.getDrawableY() + this.owner.getHeight(), - 0, workingPoint ); @@ -225,19 +227,21 @@ namespace gdjs { } // It's fine to reuse workingPoint as topLeftPixel is no longer used. - const topLeftCoord = layer.convertInverseCoords( + const topLeftCoord = this._convertInverseCoords( + instanceContainer, + layer, leftPixel, topPixel, - 0, workingPoint ); const left = topLeftCoord[0]; const top = topLeftCoord[1]; - const bottomRightCoord = layer.convertInverseCoords( + const bottomRightCoord = this._convertInverseCoords( + instanceContainer, + layer, rightPixel, bottomPixel, - 0, workingPoint ); const right = bottomRightCoord[0]; @@ -328,6 +332,40 @@ namespace gdjs { } doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {} + + private _convertCoords( + instanceContainer: gdjs.RuntimeInstanceContainer, + layer: gdjs.RuntimeLayer, + x: float, + y: float, + result: FloatPoint + ) { + const isParentACustomObject = + instanceContainer !== instanceContainer.getScene(); + if (isParentACustomObject) { + result[0] = x; + result[1] = y; + return result; + } + return layer.convertCoords(x, y, 0, result); + } + + private _convertInverseCoords( + instanceContainer: gdjs.RuntimeInstanceContainer, + layer: gdjs.RuntimeLayer, + x: float, + y: float, + result: FloatPoint + ) { + const isParentACustomObject = + instanceContainer !== instanceContainer.getScene(); + if (isParentACustomObject) { + result[0] = x; + result[1] = y; + return result; + } + return layer.convertInverseCoords(x, y, 0, result); + } } gdjs.registerBehavior( 'AnchorBehavior::AnchorBehavior', diff --git a/Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js b/Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js index 9c7c47724681..608a51fcdc22 100644 --- a/Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js +++ b/Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js @@ -265,5 +265,26 @@ describe('gdjs.AnchorRuntimeBehavior', function () { expect(object.getWidth()).to.equal(2000); expect(object.getHeight()).to.equal(3000); }); + + it('can fill the screen with an object using proportional anchors (with custom origin)', () => { + setGameResolutionSizeAndStep(1000, 500); + + const object = createSpriteWithOriginAtCenter({ + leftEdgeAnchor: 3, + topEdgeAnchor: 3, + rightEdgeAnchor: 3, + bottomEdgeAnchor: 3, + }); + object.setCustomWidthAndHeight(1000, 500); + object.setPosition(500, 250); + runtimeScene.renderAndStep(1000 / 60); + + setGameResolutionSizeAndStep(2000, 3000); + + expect(object.getX()).to.equal(1000); + expect(object.getY()).to.equal(1500); + expect(object.getWidth()).to.equal(2000); + expect(object.getHeight()).to.equal(3000); + }); }); }); diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index bf5fb3c643e9..3ecdfc50c788 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -72,7 +72,8 @@ namespace gdjs { */ export class TextRuntimeObject extends gdjs.RuntimeObject - implements gdjs.TextContainer, gdjs.OpacityHandler { + implements gdjs.TextContainer, gdjs.OpacityHandler + { _characterSize: number; _fontName: string; _bold: boolean; @@ -684,6 +685,21 @@ namespace gdjs { } } + setWidth(width: float): void { + this.setWrappingWidth(width); + } + + getDrawableY(): float { + return ( + this.getY() - + (this._verticalTextAlignment === 'center' + ? this.getHeight() / 2 + : this._verticalTextAlignment === 'bottom' + ? this.getHeight() + : 0) + ); + } + /** * Set the outline for the text object. * @param str color as a "R;G;B" string, for example: "255;0;0" diff --git a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js index d7c2dd968f50..6c7cbefe576f 100644 --- a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js +++ b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js @@ -97,6 +97,11 @@ export class LayoutedInstance { constructor(instance: gdInitialInstance) { this.instance = instance; this.ptr = instance.ptr; + this._hasCustomSize = instance.hasCustomSize(); + this._hasCustomDepth = instance.hasCustomDepth(); + this._customWidth = instance.getCustomWidth(); + this._customHeight = instance.getCustomHeight(); + this._customDepth = instance.getCustomWidth(); } getX() { @@ -365,7 +370,7 @@ export const getLayoutedRenderedInstance = ( const initialInstanceOriginX = (renderedInstance.getOriginX() * initialInstanceWidth) / - renderedInstance.getDefaultWidth(); + Math.max(1, renderedInstance.getWidth()); const initialInstanceMinX = initialInstanceX - initialInstanceOriginX; const initialInstanceMaxX = initialInstanceMinX + initialInstanceWidth; @@ -397,28 +402,23 @@ export const getLayoutedRenderedInstance = ( right = parentCenterX + initialInstanceMaxX - parentInitialCenterX; } - let x, width; - if (rightEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor) { - width = initialInstanceWidth; - const originX = - (renderedInstance.getOriginX() * width) / - renderedInstance.getDefaultWidth(); - x = left + originX; - } else if (leftEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor) { - width = initialInstanceWidth; - const originX = - (renderedInstance.getOriginX() * width) / - renderedInstance.getDefaultWidth(); - x = right - width + originX; - } else { - width = right - left; - const originX = - (renderedInstance.getOriginX() * width) / - renderedInstance.getDefaultWidth(); - x = left + originX; - } - layoutedInstance.x = x; + const width = + rightEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? initialInstanceWidth + : leftEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? initialInstanceWidth + : right - left; layoutedInstance.setCustomWidth(width); + + // The originX according to the new width. + const originX = renderedInstance.getOriginX(); + const x = + rightEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? left + originX + : leftEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? right - width + originX + : left + originX; + layoutedInstance.x = x; } const initialInstanceY = initialInstance.getY(); @@ -438,7 +438,7 @@ export const getLayoutedRenderedInstance = ( const initialInstanceOriginY = (renderedInstance.getOriginY() * initialInstanceHeight) / - renderedInstance.getDefaultHeight(); + Math.max(1, renderedInstance.getHeight()); const initialInstanceMinY = initialInstanceY - initialInstanceOriginY; const initialInstanceMaxY = initialInstanceMinY + initialInstanceHeight; @@ -470,28 +470,23 @@ export const getLayoutedRenderedInstance = ( top = parentCenterY + initialInstanceMinY - parentInitialCenterY; } - let y, height; - if (bottomEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor) { - height = initialInstanceHeight; - const originY = - (renderedInstance.getOriginY() * height) / - renderedInstance.getDefaultHeight(); - y = top + originY; - } else if (topEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor) { - height = initialInstanceHeight; - const originY = - (renderedInstance.getOriginY() * height) / - renderedInstance.getDefaultHeight(); - y = bottom - height + originY; - } else { - height = bottom - top; - const originY = - (renderedInstance.getOriginY() * height) / - renderedInstance.getDefaultHeight(); - y = top + originY; - } - layoutedInstance.y = y; + const height = + bottomEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? initialInstanceHeight + : topEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? initialInstanceHeight + : bottom - top; layoutedInstance.setCustomHeight(height); + + // The originY according to the new height. + const originY = renderedInstance.getOriginY(); + const y = + bottomEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? top + originY + : topEdgeAnchor === gd.CustomObjectConfiguration.NoAnchor + ? bottom - height + originY + : top + originY; + layoutedInstance.y = y; } return renderedInstance; }; From cd0b3f120e47dfb426965e0a346ae18bce610236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Tue, 1 Oct 2024 19:24:48 +0200 Subject: [PATCH 6/7] Fix flow. --- Extensions/AnchorBehavior/anchorruntimebehavior.ts | 3 +-- Extensions/TextObject/textruntimeobject.ts | 3 +-- .../Renderers/CustomObjectLayoutingModel.js | 2 ++ .../Renderers/CustomObjectLayoutingModel.spec.js | 12 ++++++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Extensions/AnchorBehavior/anchorruntimebehavior.ts b/Extensions/AnchorBehavior/anchorruntimebehavior.ts index b920d654a9d6..25db5f94107d 100644 --- a/Extensions/AnchorBehavior/anchorruntimebehavior.ts +++ b/Extensions/AnchorBehavior/anchorruntimebehavior.ts @@ -38,8 +38,7 @@ namespace gdjs { owner: gdjs.RuntimeObject ) { super(instanceContainer, behaviorData, owner); - this._relativeToOriginalWindowSize = - !!behaviorData.relativeToOriginalWindowSize; + this._relativeToOriginalWindowSize = !!behaviorData.relativeToOriginalWindowSize; this._leftEdgeAnchor = behaviorData.leftEdgeAnchor; this._rightEdgeAnchor = behaviorData.rightEdgeAnchor; this._topEdgeAnchor = behaviorData.topEdgeAnchor; diff --git a/Extensions/TextObject/textruntimeobject.ts b/Extensions/TextObject/textruntimeobject.ts index 3ecdfc50c788..e44561aa307d 100644 --- a/Extensions/TextObject/textruntimeobject.ts +++ b/Extensions/TextObject/textruntimeobject.ts @@ -72,8 +72,7 @@ namespace gdjs { */ export class TextRuntimeObject extends gdjs.RuntimeObject - implements gdjs.TextContainer, gdjs.OpacityHandler - { + implements gdjs.TextContainer, gdjs.OpacityHandler { _characterSize: number; _fontName: string; _bold: boolean; diff --git a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js index 6c7cbefe576f..936ca7211cf7 100644 --- a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js +++ b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.js @@ -290,6 +290,8 @@ export interface ChildRenderedInstance { _pixiObject: { height: number }; getDefaultWidth(): number; getDefaultHeight(): number; + getWidth(): number; + getHeight(): number; getOriginX(): number; getOriginY(): number; update(): void; diff --git a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js index 97801c19e60f..f1cd209e5498 100644 --- a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js +++ b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js @@ -579,6 +579,18 @@ class MockedChildRenderedInstance implements ChildRenderedInstance { this.heightAfterUpdate = defaultHeight; } + getWidth(): number { + return this._instance.hasCustomSize() + ? this._instance.getCustomWidth() + : this.getDefaultWidth(); + } + + getHeight(): number { + return this._instance.hasCustomSize() + ? this._instance.getCustomHeight() + : this.getDefaultHeight(); + } + getDefaultWidth(): number { return this.defaultWidth; } From 3002865f403cacaf38f63ea88d45e77c30dde121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davy=20H=C3=A9lard?= Date: Wed, 2 Oct 2024 10:59:22 +0200 Subject: [PATCH 7/7] Fix tests --- .../Renderers/CustomObjectLayoutingModel.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js index f1cd209e5498..c6418604df01 100644 --- a/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js +++ b/newIDE/app/src/ObjectsRendering/Renderers/CustomObjectLayoutingModel.spec.js @@ -600,11 +600,11 @@ class MockedChildRenderedInstance implements ChildRenderedInstance { } getOriginX(): number { - return this.originX; + return (this.originX * this.getWidth()) / this.getDefaultWidth(); } getOriginY(): number { - return this.originY; + return (this.originY * this.getHeight()) / this.getDefaultHeight(); } update(): void {