From 2680536448954902dd9633c6b98132fe1e948e75 Mon Sep 17 00:00:00 2001 From: Florian Rival Date: Wed, 18 Sep 2024 17:38:48 +0200 Subject: [PATCH] Allow to fold children object and add text for empty sections --- .../Project/CustomObjectConfiguration.h | 25 ++++++- Extensions/TextInput/JsExtension.js | 18 ++--- GDevelop.js/Bindings/Bindings.idl | 3 + GDevelop.js/types.d.ts | 2 + .../types/gdcustomobjectconfiguration.js | 2 + .../ChildObjectPropertiesEditor.js | 42 ++++++----- .../CompactObjectPropertiesEditor/index.js | 70 ++++++++++++++----- newIDE/app/src/Utils/Behavior.js | 4 ++ 8 files changed, 121 insertions(+), 45 deletions(-) diff --git a/Core/GDCore/Project/CustomObjectConfiguration.h b/Core/GDCore/Project/CustomObjectConfiguration.h index 179822734041..fd4cb17e6fe2 100644 --- a/Core/GDCore/Project/CustomObjectConfiguration.h +++ b/Core/GDCore/Project/CustomObjectConfiguration.h @@ -9,6 +9,7 @@ #include #include +#include #include "GDCore/Project/Object.h" #include "GDCore/Project/Project.h" #include "GDCore/Project/EventsBasedObject.h" @@ -109,6 +110,27 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration { static const gd::CustomObjectConfiguration::EdgeAnchor GetEdgeAnchorFromString(const gd::String &value); + /** + * Check if a child object properties must be displayed as folded in the editor. + * This is only useful when the object can override its children configuration (which + * is something being deprecated). + */ + bool IsChildObjectFolded(const gd::String& childName) const { + return unfoldedChildren.find(childName) == unfoldedChildren.end(); + } + + /** + * Set if a child object properties must be displayed as folded in the editor. + * This is only useful when the object can override its children configuration (which + * is something being deprecated). + */ + void SetChildObjectFolded(const gd::String& childName, bool folded) { + if (!folded) + unfoldedChildren.insert(childName); + else + unfoldedChildren.erase(childName); + } + protected: void DoSerializeTo(SerializerElement& element) const override; void DoUnserializeFrom(Project& project, const SerializerElement& element) override; @@ -121,7 +143,8 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration { const Project* project; ///< The project is used to get the ///< EventBasedObject from the fullType. gd::SerializerElement objectContent; - + std::unordered_set unfoldedChildren; + bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration; mutable std::map> childObjectConfigurations; diff --git a/Extensions/TextInput/JsExtension.js b/Extensions/TextInput/JsExtension.js index 7aa37e7b2d68..6a8f031960be 100644 --- a/Extensions/TextInput/JsExtension.js +++ b/Extensions/TextInput/JsExtension.js @@ -141,21 +141,21 @@ module.exports = { .setValue(objectContent.readOnly ? 'true' : 'false') .setType('boolean') .setLabel(_('Read only')) - .setGroup(_('Field appearance')); + .setGroup(_('Field')); objectProperties .getOrCreate('disabled') .setValue(objectContent.disabled ? 'true' : 'false') .setType('boolean') .setLabel(_('Disabled')) - .setGroup(_('Field appearance')); + .setGroup(_('Field')); objectProperties .getOrCreate('textColor') .setValue(objectContent.textColor || '0;0;0') .setType('color') .setLabel(_('Text color')) - .setGroup(_('Field appearance')); + .setGroup(_('Font')); objectProperties .getOrCreate('fillColor') @@ -180,8 +180,8 @@ module.exports = { .getOrCreate('borderColor') .setValue(objectContent.borderColor || '0;0;0') .setType('color') - .setLabel(_('Border color')) - .setGroup(_('Field appearance')); + .setLabel(_('Color')) + .setGroup(_('Border appearance')); objectProperties .getOrCreate('borderOpacity') @@ -192,15 +192,15 @@ module.exports = { ).toString() ) .setType('number') - .setLabel(_('Border opacity')) - .setGroup(_('Field appearance')); + .setLabel(_('Opacity')) + .setGroup(_('Border appearance')); objectProperties .getOrCreate('borderWidth') .setValue((objectContent.borderWidth || 0).toString()) .setType('number') - .setLabel(_('Border width')) - .setGroup(_('Field appearance')); + .setLabel(_('Width')) + .setGroup(_('Border appearance')); return objectProperties; }; diff --git a/GDevelop.js/Bindings/Bindings.idl b/GDevelop.js/Bindings/Bindings.idl index df6a988a5374..e31ff6cac9e3 100644 --- a/GDevelop.js/Bindings/Bindings.idl +++ b/GDevelop.js/Bindings/Bindings.idl @@ -905,6 +905,9 @@ interface CustomObjectConfiguration { [Ref] SpriteAnimationList GetAnimations(); + boolean IsChildObjectFolded([Const] DOMString childName); + void SetChildObjectFolded([Const] DOMString childName, boolean folded); + CustomObjectConfiguration_EdgeAnchor STATIC_GetEdgeAnchorFromString([Const] DOMString value); }; CustomObjectConfiguration implements ObjectConfiguration; diff --git a/GDevelop.js/types.d.ts b/GDevelop.js/types.d.ts index 1be5beb1567c..a4e98ba078fa 100644 --- a/GDevelop.js/types.d.ts +++ b/GDevelop.js/types.d.ts @@ -749,6 +749,8 @@ export class CustomObjectConfiguration extends ObjectConfiguration { getInitialInstanceProperties(instance: InitialInstance): MapStringPropertyDescriptor; updateInitialInstanceProperty(instance: InitialInstance, name: string, value: string): boolean; getAnimations(): SpriteAnimationList; + isChildObjectFolded(childName: string): boolean; + setChildObjectFolded(childName: string, folded: boolean): void; static getEdgeAnchorFromString(value: string): CustomObjectConfiguration_EdgeAnchor; } diff --git a/GDevelop.js/types/gdcustomobjectconfiguration.js b/GDevelop.js/types/gdcustomobjectconfiguration.js index 0c89704fa3c5..2dcee3d41e6f 100644 --- a/GDevelop.js/types/gdcustomobjectconfiguration.js +++ b/GDevelop.js/types/gdcustomobjectconfiguration.js @@ -16,6 +16,8 @@ declare class gdCustomObjectConfiguration extends gdObjectConfiguration { getInitialInstanceProperties(instance: gdInitialInstance): gdMapStringPropertyDescriptor; updateInitialInstanceProperty(instance: gdInitialInstance, name: string, value: string): boolean; getAnimations(): gdSpriteAnimationList; + isChildObjectFolded(childName: string): boolean; + setChildObjectFolded(childName: string, folded: boolean): void; static getEdgeAnchorFromString(value: string): CustomObjectConfiguration_EdgeAnchor; delete(): void; ptr: number; diff --git a/newIDE/app/src/ObjectEditor/CompactObjectPropertiesEditor/ChildObjectPropertiesEditor.js b/newIDE/app/src/ObjectEditor/CompactObjectPropertiesEditor/ChildObjectPropertiesEditor.js index c4554d57e529..eaf5b6438f36 100644 --- a/newIDE/app/src/ObjectEditor/CompactObjectPropertiesEditor/ChildObjectPropertiesEditor.js +++ b/newIDE/app/src/ObjectEditor/CompactObjectPropertiesEditor/ChildObjectPropertiesEditor.js @@ -9,6 +9,7 @@ import ChevronArrowRight from '../../UI/CustomSvgIcons/ChevronArrowRight'; import { Trans } from '@lingui/macro'; import FlatButton from '../../UI/FlatButton'; import ChevronArrowTop from '../../UI/CustomSvgIcons/ChevronArrowTop'; +import Text from '../../UI/Text'; const gd: libGDevelop = global.gd; @@ -81,25 +82,34 @@ export const ChildObjectPropertiesEditor = ({ [childObjectConfigurationAsGd] ); const hasObjectAdvancedProperties = objectAdvancedPropertiesSchema.length > 0; + const hasSomeObjectProperties = + objectBasicPropertiesSchema.length > 0 || hasObjectAdvancedProperties; return ( - { - // TODO: undo/redo? - }} - onRefreshAllFields={onRefreshAllFields} - /> + {!hasSomeObjectProperties && ( + + This object has no properties. + + )} + {hasSomeObjectProperties && ( + { + // TODO: undo/redo? + }} + onRefreshAllFields={onRefreshAllFields} + /> + )} {!showObjectAdvancedOptions && hasObjectAdvancedProperties && ( { const forceUpdate = useForceUpdate(); - const [showObjectAdvancedOptions, setShowObjectAdvancedOptions] = React.useState(false); + const [ + showObjectAdvancedOptions, + setShowObjectAdvancedOptions, + ] = React.useState(false); const [schemaRecomputeTrigger, forceRecomputeSchema] = useForceRecompute(); const variablesListRef = React.useRef(null); const object = objects[0]; @@ -216,6 +219,8 @@ export const CompactObjectPropertiesEditor = ({ [objectConfigurationAsGd, schemaRecomputeTrigger] ); const hasObjectAdvancedProperties = objectAdvancedPropertiesSchema.length > 0; + const hasSomeObjectProperties = + objectBasicPropertiesSchema.length > 0 || hasObjectAdvancedProperties; // Behaviors: const { @@ -304,19 +309,26 @@ export const CompactObjectPropertiesEditor = ({ - { - // TODO: undo/redo? - }} - onRefreshAllFields={forceRecomputeSchema} - /> + {!hasSomeObjectProperties && ( + + This object has no properties. + + )} + {hasSomeObjectProperties && ( + { + // TODO: undo/redo? + }} + onRefreshAllFields={forceRecomputeSchema} + /> + )} {!showObjectAdvancedOptions && hasObjectAdvancedProperties && ( )} - isFolded={false} - toggleFolded={() => {}} + isFolded={isFolded} + toggleFolded={() => { + customObjectConfiguration.setChildObjectFolded( + childObjectName, + !isFolded + ); + forceUpdate(); + }} title={ - {childObject.getName()} + {childObjectName} } /> @@ -409,6 +431,11 @@ export const CompactObjectPropertiesEditor = ({ + {!allVisibleBehaviors.length && ( + + There are no behaviors on this object. + + )} {allVisibleBehaviors.map(behavior => { const behaviorTypeName = behavior.getTypeName(); const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata( @@ -430,7 +457,7 @@ export const CompactObjectPropertiesEditor = ({ resourceManagementProps={resourceManagementProps} /> )} - isFolded={!behavior.isFolded()} + isFolded={behavior.isFolded()} toggleFolded={() => { behavior.setFolded(!behavior.isFolded()); forceUpdate(); @@ -533,6 +560,11 @@ export const CompactObjectPropertiesEditor = ({ + {effectsContainer.getEffectsCount() === 0 && ( + + There are no effects on this object. + + )} {mapFor( 0, effectsContainer.getEffectsCount(), @@ -574,7 +606,7 @@ export const CompactObjectPropertiesEditor = ({ /> )} - isFolded={!effect.isFolded()} + isFolded={effect.isFolded()} toggleFolded={() => { effect.setFolded(!effect.isFolded()); forceUpdate(); diff --git a/newIDE/app/src/Utils/Behavior.js b/newIDE/app/src/Utils/Behavior.js index 57a6faafe66f..862e9785cef1 100644 --- a/newIDE/app/src/Utils/Behavior.js +++ b/newIDE/app/src/Utils/Behavior.js @@ -35,6 +35,10 @@ export const addBehaviorToObject = ( type, name ); + + // Show the beahvior properties in the editor by default, when just added. + object.getBehavior(name).setFolded(false); + return true; };