Skip to content

Commit

Permalink
Add vertical alignment property for text object (#6975)
Browse files Browse the repository at this point in the history
- Fix proportional anchors on custom object children
  • Loading branch information
D8H authored Oct 2, 2024
1 parent f6cb203 commit 2a2c930
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 102 deletions.
55 changes: 46 additions & 9 deletions Extensions/AnchorBehavior/anchorruntimebehavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,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();
Expand All @@ -111,10 +110,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
);

Expand All @@ -141,10 +141,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
);

Expand Down Expand Up @@ -225,19 +226,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];
Expand Down Expand Up @@ -333,6 +336,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',
Expand Down
21 changes: 21 additions & 0 deletions Extensions/AnchorBehavior/tests/anchorruntimebehavior.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
16 changes: 16 additions & 0 deletions Extensions/TextObject/TextObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ TextObject::TextObject()
underlined(false),
color("0;0;0"),
textAlignment("left"),
verticalTextAlignment("top"),
isOutlineEnabled(false),
outlineThickness(2),
outlineColor("255;255;255"),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -163,6 +168,15 @@ std::map<gd::String, gd::PropertyDescriptor> TextObject::GetProperties() const {
.SetGroup(_("Font"))
.SetQuickCustomizationVisibility(gd::QuickCustomization::Hidden);

objectProperties["verticalTextAlignment"]
.SetValue(verticalTextAlignment)
.SetType("choice")
.AddExtraInfo("top")
.AddExtraInfo("center")
.AddExtraInfo("bottom")
.SetLabel(_("Vertical alignment"))
.SetGroup(_("Font"));

objectProperties["isOutlineEnabled"]
.SetValue(isOutlineEnabled ? "true" : "false")
.SetType("boolean")
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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());

Expand Down
6 changes: 6 additions & 0 deletions Extensions/TextObject/TextObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions Extensions/TextObject/textruntimeobject-pixi-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
47 changes: 45 additions & 2 deletions Extensions/TextObject/textruntimeobject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace gdjs {
/** The text of the object */
text: string;
textAlignment: string;
verticalTextAlignment: string;

isOutlineEnabled: boolean;
outlineThickness: float;
Expand Down Expand Up @@ -82,7 +83,8 @@ namespace gdjs {
_gradient: Array<Array<integer>> = [];
_gradientType: string = '';
opacity: float = 255;
_textAlign: string = 'left';
_textAlign: string;
_verticalTextAlignment: string;
_wrapping: boolean = false;
// A wrapping of 1 makes games crash on Firefox
_wrappingWidth: float = 100;
Expand Down Expand Up @@ -123,7 +125,8 @@ namespace gdjs {
this._underlined = content.underlined;
this._color = gdjs.rgbOrHexToRGBColor(content.color);
this._str = content.text;
this._textAlign = content.textAlignment;
this._textAlign = content.textAlignment || 'left';
this._verticalTextAlignment = content.verticalTextAlignment || 'top';

this._isOutlineEnabled = content.isOutlineEnabled;
this._outlineThickness = content.outlineThickness;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -656,6 +684,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"
Expand Down
1 change: 1 addition & 0 deletions Extensions/TweenBehavior/tests/LegacyTweenBehavior.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
color: '0;0;0',
text: '',
textAlignment: 'left',
verticalTextAlignment: 'top',
isOutlineEnabled: false,
outlineThickness: 2,
outlineColor: '255;255;255',
Expand Down
1 change: 1 addition & 0 deletions Extensions/TweenBehavior/tests/TweenBehavior.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ describe('gdjs.TweenRuntimeBehavior', () => {
color: '0;0;0',
text: '',
textAlignment: 'left',
verticalTextAlignment: 'top',
isOutlineEnabled: false,
outlineThickness: 2,
outlineColor: '255;255;255',
Expand Down
2 changes: 2 additions & 0 deletions GDevelop.js/Bindings/Bindings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion GDevelop.js/__tests__/Serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}'
);
});
});
Expand Down
2 changes: 2 additions & 0 deletions GDevelop.js/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions GDevelop.js/types/gdtextobject.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 2a2c930

Please sign in to comment.