Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout custom objects children according to their anchors in the editor #6939

Merged
merged 7 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Core/GDCore/Project/CustomObjectConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,16 @@ const SpriteAnimationList& CustomObjectConfiguration::GetAnimations() const {
SpriteAnimationList& CustomObjectConfiguration::GetAnimations() {
return animations;
}

const gd::CustomObjectConfiguration::EdgeAnchor
CustomObjectConfiguration::GetEdgeAnchorFromString(const gd::String &value) {
return (value == _("Window left") || value == _("Window top"))
? gd::CustomObjectConfiguration::EdgeAnchor::MinEdge
: (value == _("Window right") || value == _("Window bottom"))
? gd::CustomObjectConfiguration::EdgeAnchor::MaxEdge
: value == _("Proportional")
? gd::CustomObjectConfiguration::EdgeAnchor::Proportional
: value == _("Window center")
? gd::CustomObjectConfiguration::EdgeAnchor::Center
: gd::CustomObjectConfiguration::EdgeAnchor::NoAnchor;
}
11 changes: 11 additions & 0 deletions Core/GDCore/Project/CustomObjectConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
*/
SpriteAnimationList& GetAnimations();

enum EdgeAnchor {
NoAnchor = 0,
MinEdge = 1,
MaxEdge = 2,
Proportional = 3,
Center = 4,
};

static const gd::CustomObjectConfiguration::EdgeAnchor
GetEdgeAnchorFromString(const gd::String &value);

protected:
void DoSerializeTo(SerializerElement& element) const override;
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
Expand Down
11 changes: 11 additions & 0 deletions Core/GDCore/Project/EventsBasedObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ EventsBasedObject::EventsBasedObject()
isAnimatable(false),
isTextContainer(false),
isInnerAreaFollowingParentSize(false),
isUsingLegacyInstancesRenderer(false),
areaMinX(0),
areaMinY(0),
areaMinZ(0),
Expand All @@ -41,6 +42,7 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
if (isInnerAreaFollowingParentSize) {
element.SetBoolAttribute("isInnerAreaFollowingParentSize", true);
}
element.SetBoolAttribute("isUsingLegacyInstancesRenderer", isUsingLegacyInstancesRenderer);
element.SetIntAttribute("areaMinX", areaMinX);
element.SetIntAttribute("areaMinY", areaMinY);
element.SetIntAttribute("areaMinZ", areaMinZ);
Expand Down Expand Up @@ -88,6 +90,15 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
}

initialInstances.UnserializeFrom(element.GetChild("instances"));
if (element.HasAttribute("isUsingLegacyInstancesRenderer")) {
isUsingLegacyInstancesRenderer =
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
}
else {
// Compatibility with GD <= 5.4.212
isUsingLegacyInstancesRenderer = initialInstances.GetInstancesCount() == 0;
// end of compatibility code
}
}

} // namespace gd
21 changes: 20 additions & 1 deletion Core/GDCore/Project/EventsBasedObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
* adapt there size. This is removing the ScalableCapability.
*/
EventsBasedObject &
MarkAsInnerAreaExpandingWithParent(bool isInnerAreaExpandingWithParent_) {
MarkAsInnerAreaFollowingParentSize(bool isInnerAreaExpandingWithParent_) {
isInnerAreaFollowingParentSize = isInnerAreaExpandingWithParent_;
return *this;
}
Expand All @@ -130,6 +130,24 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
return isInnerAreaFollowingParentSize;
}

/**
* \brief Declare that custom object are rendered using their child-objects
* instead of their child-instances.
*/
EventsBasedObject &
MakAsUsingLegacyInstancesRenderer(bool isUsingLegacyInstancesRenderer_) {
isUsingLegacyInstancesRenderer = isUsingLegacyInstancesRenderer_;
return *this;
}

/**
* \brief Return true if custom object are rendered using their child-objects
* instead of their child-instances.
*/
bool IsUsingLegacyInstancesRenderer() const {
return isUsingLegacyInstancesRenderer;
}

/**
* \brief Return true if the object needs a TextContainer capability.
*/
Expand Down Expand Up @@ -304,6 +322,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
bool isAnimatable;
bool isTextContainer;
bool isInnerAreaFollowingParentSize;
bool isUsingLegacyInstancesRenderer;
gd::InitialInstancesContainer initialInstances;
gd::LayersContainer layers;
gd::ObjectsContainer objectsContainer;
Expand Down
24 changes: 14 additions & 10 deletions Extensions/AnchorBehavior/AnchorBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.SetDescription(_("otherwise, objects are anchored according to the "
"window size when the object is created."));

properties[_("Left edge anchor")]
properties["leftEdgeAnchor"]
.SetValue(GetAnchorAsString(static_cast<HorizontalAnchor>(
behaviorContent.GetIntAttribute("leftEdgeAnchor"))))
.SetType("Choice")
Expand All @@ -75,9 +75,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window right"))
.AddExtraInfo(_("Proportional"))
.SetLabel(_("Left edge anchor"))
.SetDescription(_("Anchor the left edge of the object on X axis."));

properties[_("Right edge anchor")]
properties["rightEdgeAnchor"]
.SetValue(GetAnchorAsString(static_cast<HorizontalAnchor>(
behaviorContent.GetIntAttribute("rightEdgeAnchor"))))
.SetType("Choice")
Expand All @@ -86,9 +87,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window right"))
.AddExtraInfo(_("Proportional"))
.SetLabel(_("Right edge anchor"))
.SetDescription(_("Anchor the right edge of the object on X axis."));

properties[_("Top edge anchor")]
properties["topEdgeAnchor"]
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
behaviorContent.GetIntAttribute("topEdgeAnchor"))))
.SetType("Choice")
Expand All @@ -97,9 +99,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window bottom"))
.AddExtraInfo(_("Proportional"))
.SetLabel(_("Top edge anchor"))
.SetDescription(_("Anchor the top edge of the object on Y axis."));

properties[_("Bottom edge anchor")]
properties["bottomEdgeAnchor"]
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
behaviorContent.GetIntAttribute("bottomEdgeAnchor"))))
.SetType("Choice")
Expand All @@ -108,9 +111,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
.AddExtraInfo(_("Window center"))
.AddExtraInfo(_("Window bottom"))
.AddExtraInfo(_("Proportional"))
.SetLabel(_("Bottom edge anchor"))
.SetDescription(_("Anchor the bottom edge of the object on Y axis."));

properties[("useLegacyBottomAndRightAnchors")]
properties["useLegacyBottomAndRightAnchors"]
.SetLabel(_(
"Stretch object when anchoring right or bottom edge (deprecated, "
"it's recommended to leave this unchecked and anchor both sides if "
Expand Down Expand Up @@ -158,20 +162,20 @@ AnchorBehavior::VerticalAnchor GetVerticalAnchorFromString(
bool AnchorBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
const gd::String& name,
const gd::String& value) {
if (name == _("relativeToOriginalWindowSize"))
if (name == "relativeToOriginalWindowSize")
behaviorContent.SetAttribute("relativeToOriginalWindowSize", value == "1");
else if (name == _("Left edge anchor"))
else if (name == "leftEdgeAnchor")
behaviorContent.SetAttribute(
"leftEdgeAnchor",
static_cast<int>(GetHorizontalAnchorFromString(value)));
else if (name == _("Right edge anchor"))
else if (name == "rightEdgeAnchor")
behaviorContent.SetAttribute(
"rightEdgeAnchor",
static_cast<int>(GetHorizontalAnchorFromString(value)));
else if (name == _("Top edge anchor"))
else if (name == "topEdgeAnchor")
behaviorContent.SetAttribute(
"topEdgeAnchor", static_cast<int>(GetVerticalAnchorFromString(value)));
else if (name == _("Bottom edge anchor"))
else if (name == "bottomEdgeAnchor")
behaviorContent.SetAttribute(
"bottomEdgeAnchor",
static_cast<int>(GetVerticalAnchorFromString(value)));
Expand Down
14 changes: 13 additions & 1 deletion GDevelop.js/Bindings/Bindings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,14 @@ interface ObjectJsImplementation {
// void DoUnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
};

enum CustomObjectConfiguration_EdgeAnchor {
"CustomObjectConfiguration::NoAnchor",
"CustomObjectConfiguration::MinEdge",
"CustomObjectConfiguration::MaxEdge",
"CustomObjectConfiguration::Proportional",
"CustomObjectConfiguration::Center",
};

interface CustomObjectConfiguration {
[Value] UniquePtrObjectConfiguration Clone();

Expand All @@ -896,6 +904,8 @@ interface CustomObjectConfiguration {
DOMString value);

[Ref] SpriteAnimationList GetAnimations();

CustomObjectConfiguration_EdgeAnchor STATIC_GetEdgeAnchorFromString([Const] DOMString value);
};
CustomObjectConfiguration implements ObjectConfiguration;

Expand Down Expand Up @@ -2971,8 +2981,10 @@ interface EventsBasedObject {
boolean IsAnimatable();
[Ref] EventsBasedObject MarkAsTextContainer(boolean isTextContainer);
boolean IsTextContainer();
[Ref] EventsBasedObject MarkAsInnerAreaExpandingWithParent(boolean value);
[Ref] EventsBasedObject MarkAsInnerAreaFollowingParentSize(boolean value);
boolean IsInnerAreaFollowingParentSize();
[Ref] EventsBasedObject MakAsUsingLegacyInstancesRenderer(boolean value);
boolean IsUsingLegacyInstancesRenderer();

[Ref] InitialInstancesContainer GetInitialInstances();
[Ref] LayersContainer GetLayers();
Expand Down
3 changes: 3 additions & 0 deletions GDevelop.js/Bindings/Wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ typedef std::vector<UnfilledRequiredBehaviorPropertyProblem>
typedef std::vector<const gd::ObjectFolderOrObject*> VectorObjectFolderOrObject;
typedef QuickCustomization::Visibility
QuickCustomization_Visibility;
typedef CustomObjectConfiguration::EdgeAnchor
CustomObjectConfiguration_EdgeAnchor;

typedef ExtensionAndMetadata<BehaviorMetadata> ExtensionAndBehaviorMetadata;
typedef ExtensionAndMetadata<ObjectMetadata> ExtensionAndObjectMetadata;
Expand Down Expand Up @@ -808,6 +810,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_GetDefaultMeasurementUnitAtIndex GetDefaultMeasurementUnitAtIndex
#define STATIC_GetDefaultMeasurementUnitByName GetDefaultMeasurementUnitByName
#define STATIC_HasDefaultMeasurementUnitNamed HasDefaultMeasurementUnitNamed
#define STATIC_GetEdgeAnchorFromString GetEdgeAnchorFromString

// We postfix some methods with "At" as Javascript does not support overloading
#define GetLayoutAt GetLayout
Expand Down
18 changes: 18 additions & 0 deletions GDevelop.js/scripts/generate-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,24 @@ type QuickCustomization_Visibility = 0 | 1 | 2`
].join('\n'),
'types/gdquickcustomization.js'
);
fs.writeFileSync(
'types/customobjectconfiguration_edgeAnchor.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
type CustomObjectConfiguration_EdgeAnchor = 0 | 1 | 2 | 3 | 4`
);
shell.sed(
'-i',
'declare class gdCustomObjectConfiguration extends gdObjectConfiguration {',
[
'declare class gdCustomObjectConfiguration extends gdObjectConfiguration {',
' static NoAnchor: 0;',
' static MinEdge: 1;',
' static MaxEdge: 2;',
' static Proportional: 3;',
' static Center: 4;',
].join('\n'),
'types/gdcustomobjectconfiguration.js'
);

// Add convenience methods that are manually added (see postjs.js):
shell.sed(
Expand Down
13 changes: 12 additions & 1 deletion GDevelop.js/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ export enum ObjectsContainersList_VariableExistence {
ExistsOnlyOnSomeObjectsOfTheGroup = 3,
}

export enum CustomObjectConfiguration_EdgeAnchor {
NoAnchor = 0,
MinEdge = 1,
MaxEdge = 2,
Proportional = 3,
Center = 4,
}

export enum QuickCustomization_Visibility {
Default = 0,
Visible = 1,
Expand Down Expand Up @@ -741,6 +749,7 @@ export class CustomObjectConfiguration extends ObjectConfiguration {
getInitialInstanceProperties(instance: InitialInstance): MapStringPropertyDescriptor;
updateInitialInstanceProperty(instance: InitialInstance, name: string, value: string): boolean;
getAnimations(): SpriteAnimationList;
static getEdgeAnchorFromString(value: string): CustomObjectConfiguration_EdgeAnchor;
}

export class Layout extends EmscriptenObject {
Expand Down Expand Up @@ -2164,8 +2173,10 @@ export class EventsBasedObject extends AbstractEventsBasedEntity {
isAnimatable(): boolean;
markAsTextContainer(isTextContainer: boolean): EventsBasedObject;
isTextContainer(): boolean;
markAsInnerAreaExpandingWithParent(value: boolean): EventsBasedObject;
markAsInnerAreaFollowingParentSize(value: boolean): EventsBasedObject;
isInnerAreaFollowingParentSize(): boolean;
makAsUsingLegacyInstancesRenderer(value: boolean): EventsBasedObject;
isUsingLegacyInstancesRenderer(): boolean;
getInitialInstances(): InitialInstancesContainer;
getLayers(): LayersContainer;
getObjects(): ObjectsContainer;
Expand Down
2 changes: 2 additions & 0 deletions GDevelop.js/types/customobjectconfiguration_edgeanchor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
type CustomObjectConfiguration_EdgeAnchor = 0 | 1 | 2 | 3 | 4
6 changes: 6 additions & 0 deletions GDevelop.js/types/gdcustomobjectconfiguration.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdCustomObjectConfiguration extends gdObjectConfiguration {
static NoAnchor: 0;
static MinEdge: 1;
static MaxEdge: 2;
static Proportional: 3;
static Center: 4;
clone(): gdUniquePtrObjectConfiguration;
isForcedToOverrideEventsBasedObjectChildrenConfiguration(): boolean;
isMarkedAsOverridingEventsBasedObjectChildrenConfiguration(): boolean;
Expand All @@ -11,6 +16,7 @@ declare class gdCustomObjectConfiguration extends gdObjectConfiguration {
getInitialInstanceProperties(instance: gdInitialInstance): gdMapStringPropertyDescriptor;
updateInitialInstanceProperty(instance: gdInitialInstance, name: string, value: string): boolean;
getAnimations(): gdSpriteAnimationList;
static getEdgeAnchorFromString(value: string): CustomObjectConfiguration_EdgeAnchor;
delete(): void;
ptr: number;
};
4 changes: 3 additions & 1 deletion GDevelop.js/types/gdeventsbasedobject.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ declare class gdEventsBasedObject extends gdAbstractEventsBasedEntity {
isAnimatable(): boolean;
markAsTextContainer(isTextContainer: boolean): gdEventsBasedObject;
isTextContainer(): boolean;
markAsInnerAreaExpandingWithParent(value: boolean): gdEventsBasedObject;
markAsInnerAreaFollowingParentSize(value: boolean): gdEventsBasedObject;
isInnerAreaFollowingParentSize(): boolean;
makAsUsingLegacyInstancesRenderer(value: boolean): gdEventsBasedObject;
isUsingLegacyInstancesRenderer(): boolean;
getInitialInstances(): gdInitialInstancesContainer;
getLayers(): gdLayersContainer;
getObjects(): gdObjectsContainer;
Expand Down
1 change: 1 addition & 0 deletions GDevelop.js/types/libgdevelop.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ declare class libGDevelop {
gdObject: Class<gdObject>;
UniquePtrObject: Class<gdUniquePtrObject>;
ObjectJsImplementation: Class<gdObjectJsImplementation>;
CustomObjectConfiguration_EdgeAnchor: Class<CustomObjectConfiguration_EdgeAnchor>;
CustomObjectConfiguration: Class<gdCustomObjectConfiguration>;
Layout: Class<gdLayout>;
ExternalEvents: Class<gdExternalEvents>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Props = {|
onEventsFunctionsAdded: () => void,
onOpenCustomObjectEditor: () => void,
unsavedChanges?: ?UnsavedChanges,
onEventsBasedObjectChildrenEdited: () => void,
|};

export default function EventsBasedObjectEditorPanel({
Expand All @@ -31,6 +32,7 @@ export default function EventsBasedObjectEditorPanel({
onEventsFunctionsAdded,
onOpenCustomObjectEditor,
unsavedChanges,
onEventsBasedObjectChildrenEdited,
}: Props) {
const [currentTab, setCurrentTab] = React.useState<TabName>('configuration');

Expand Down Expand Up @@ -69,6 +71,9 @@ export default function EventsBasedObjectEditorPanel({
eventsBasedObject={eventsBasedObject}
unsavedChanges={unsavedChanges}
onOpenCustomObjectEditor={onOpenCustomObjectEditor}
onEventsBasedObjectChildrenEdited={
onEventsBasedObjectChildrenEdited
}
/>
)}
{currentTab === 'properties' && (
Expand Down
Loading
Loading