From dc377335b9c5e29230964e28d5906c863d4d324f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Mon, 20 Jul 2026 01:09:36 -0300 Subject: [PATCH] graphics: migrate drawables to shared ownership - introduce DrawablePtr and per-consumer createInstance() semantics - add TextureDrawable wrappers backed by shared TexturePtr handles - migrate regions, sprites, nine-patches, state lists, skins, groups, gradients, UI widgets, tools, modules, ecode, and eeiv to shared drawable ownership - remove ownIt flags, manual drawable deletion, and unload-based lifetime handling - replace drawable callback IDs with RAII change connections - move Variant drawable storage outside its scalar union - split UIIcon source lookup from explicit drawable instance creation - retain icon instances used by rendering loops instead of cloning per frame - avoid shared source mutation in texture-region consumers - use drawable type tags instead of RTTI casts - fix nearest-size UIIcon lookup - document the drawable source/instance contract and add ownership tests --- .../resource_shared_ownership_architecture.md | 74 ++++- include/eepp/graphics.hpp | 1 + include/eepp/graphics/arcdrawable.hpp | 2 + include/eepp/graphics/circledrawable.hpp | 2 + include/eepp/graphics/convexshapedrawable.hpp | 2 + include/eepp/graphics/drawable.hpp | 10 + include/eepp/graphics/drawablegroup.hpp | 15 +- include/eepp/graphics/drawableresource.hpp | 47 ++- include/eepp/graphics/drawablesearcher.hpp | 4 +- include/eepp/graphics/glyphdrawable.hpp | 2 + include/eepp/graphics/ninepatch.hpp | 4 +- include/eepp/graphics/rectangledrawable.hpp | 2 + include/eepp/graphics/resource.hpp | 4 + include/eepp/graphics/scrollparallax.hpp | 2 +- include/eepp/graphics/sprite.hpp | 33 ++- include/eepp/graphics/statelistdrawable.hpp | 8 +- include/eepp/graphics/texture.hpp | 2 + include/eepp/graphics/texturedrawable.hpp | 36 +++ include/eepp/graphics/textureregion.hpp | 5 + include/eepp/graphics/triangledrawable.hpp | 4 +- include/eepp/ui/css/drawableimageparser.hpp | 11 +- include/eepp/ui/lineargradientdrawable.hpp | 2 + include/eepp/ui/models/variant.hpp | 27 +- include/eepp/ui/radialgradientdrawable.hpp | 2 + include/eepp/ui/uicodeeditor.hpp | 16 +- include/eepp/ui/uiconsole.hpp | 2 +- include/eepp/ui/uiicon.hpp | 19 +- include/eepp/ui/uiimage.hpp | 15 +- include/eepp/ui/uimenu.hpp | 11 +- include/eepp/ui/uinode.hpp | 10 +- include/eepp/ui/uinodedrawable.hpp | 17 +- include/eepp/ui/uipushbutton.hpp | 2 +- include/eepp/ui/uiscenenode.hpp | 2 +- include/eepp/ui/uiskin.hpp | 6 +- include/eepp/ui/uiskinstate.hpp | 7 +- include/eepp/ui/uisprite.hpp | 20 +- include/eepp/ui/uitabwidget.hpp | 6 +- include/eepp/ui/uitextinput.hpp | 2 +- include/eepp/ui/uitextureregion.hpp | 6 +- src/eepp/graphics/arcdrawable.cpp | 12 + src/eepp/graphics/circledrawable.cpp | 14 + src/eepp/graphics/convexshapedrawable.cpp | 13 + src/eepp/graphics/drawable.cpp | 4 + src/eepp/graphics/drawablegroup.cpp | 57 ++-- src/eepp/graphics/drawableresource.cpp | 76 +++-- src/eepp/graphics/drawablesearcher.cpp | 68 +++-- src/eepp/graphics/glyphdrawable.cpp | 12 + src/eepp/graphics/ninepatch.cpp | 52 ++-- src/eepp/graphics/rectangledrawable.cpp | 15 + src/eepp/graphics/scrollparallax.cpp | 49 ++-- src/eepp/graphics/sprite.cpp | 134 ++++----- src/eepp/graphics/statelistdrawable.cpp | 75 ++--- src/eepp/graphics/texture.cpp | 11 + src/eepp/graphics/texturedrawable.cpp | 55 ++++ src/eepp/graphics/texturefactory.cpp | 5 + src/eepp/graphics/textureregion.cpp | 9 + src/eepp/graphics/triangledrawable.cpp | 16 + src/eepp/ui/abstract/uiabstracttableview.cpp | 8 +- src/eepp/ui/css/drawableimageparser.cpp | 155 +++++----- src/eepp/ui/lineargradientdrawable.cpp | 10 + src/eepp/ui/radialgradientdrawable.cpp | 36 ++- src/eepp/ui/tools/uicolorpicker.cpp | 11 +- src/eepp/ui/tools/uidiffview.cpp | 6 +- src/eepp/ui/tools/uifontpickerdialog.cpp | 14 +- src/eepp/ui/tools/uiimageviewer.cpp | 20 +- src/eepp/ui/tools/uitabwidgetsplitter.cpp | 2 +- src/eepp/ui/tools/uitextureviewer.cpp | 6 +- src/eepp/ui/tools/uiwidgetinspector.cpp | 4 +- src/eepp/ui/uicodeeditor.cpp | 51 ++-- src/eepp/ui/uiconsole.cpp | 6 +- src/eepp/ui/uifiledialog.cpp | 10 +- src/eepp/ui/uiicon.cpp | 49 ++-- src/eepp/ui/uiimage.cpp | 113 +++----- src/eepp/ui/uimenu.cpp | 27 +- src/eepp/ui/uimessagebox.cpp | 9 +- src/eepp/ui/uinode.cpp | 23 +- src/eepp/ui/uinodedrawable.cpp | 92 ++---- src/eepp/ui/uipushbutton.cpp | 19 +- src/eepp/ui/uiscenenode.cpp | 7 +- src/eepp/ui/uiskin.cpp | 34 ++- src/eepp/ui/uiskinstate.cpp | 9 +- src/eepp/ui/uisprite.cpp | 71 ++--- src/eepp/ui/uisvg.cpp | 31 +- src/eepp/ui/uitabwidget.cpp | 12 +- src/eepp/ui/uitextinput.cpp | 6 +- src/eepp/ui/uitextureregion.cpp | 76 ++--- src/eepp/ui/uitheme.cpp | 15 +- src/eepp/ui/uitreeview.cpp | 10 +- .../eterm/include/eterm/ui/uiterminal.hpp | 2 +- src/modules/eterm/src/eterm/ui/uiterminal.cpp | 6 +- .../include/eepp/maps/gameobjectsprite.hpp | 13 +- .../eepp/maps/gameobjecttextureregion.hpp | 2 +- .../include/eepp/maps/gameobjectvirtual.hpp | 2 +- .../maps/src/eepp/maps/gameobjectsprite.cpp | 19 +- .../src/eepp/maps/gameobjecttextureregion.cpp | 13 +- .../maps/src/eepp/maps/gameobjectvirtual.cpp | 26 +- .../src/eepp/maps/mapeditor/mapeditor.cpp | 10 +- .../eepp/physics/shapecirclesprite.hpp | 14 +- .../include/eepp/physics/shapepolysprite.hpp | 22 +- .../src/eepp/physics/shapecirclesprite.cpp | 15 +- .../src/eepp/physics/shapepolysprite.cpp | 25 +- src/tests/test_all/test.cpp | 15 +- src/tests/test_all/test.hpp | 4 +- .../unit_tests/drawableimageparser_tests.cpp | 129 +++------ .../resource_prerequisite_tests.cpp | 274 +++++++++++++++++- src/tests/unit_tests/uihtml_tests.cpp | 41 ++- src/tools/ecode/appconfig.cpp | 2 +- src/tools/ecode/appconfig.hpp | 2 +- src/tools/ecode/ecode.cpp | 18 +- src/tools/ecode/ecode.hpp | 4 +- .../ecode/plugins/aiassistant/chatui.cpp | 8 +- .../ecode/plugins/aiassistant/chatui.hpp | 2 +- .../autocomplete/autocompleteplugin.cpp | 23 +- .../autocomplete/autocompleteplugin.hpp | 2 + .../ecode/plugins/debugger/debuggerplugin.cpp | 47 ++- .../ecode/plugins/debugger/debuggerplugin.hpp | 6 + src/tools/ecode/plugins/git/gitplugin.cpp | 8 +- .../ecode/plugins/linter/linterplugin.cpp | 21 +- .../ecode/plugins/linter/linterplugin.hpp | 1 + .../ecode/plugins/lsp/lspclientplugin.cpp | 60 +++- .../ecode/plugins/lsp/lspclientplugin.hpp | 4 + src/tools/ecode/plugins/plugin.cpp | 4 +- src/tools/ecode/plugins/plugin.hpp | 2 +- .../ecode/plugins/plugincontextprovider.hpp | 4 +- .../spellchecker/spellcheckerplugin.cpp | 2 +- src/tools/ecode/projectbuild.cpp | 2 +- src/tools/ecode/settingsmenu.cpp | 2 +- src/tools/ecode/settingsmenu.hpp | 2 +- src/tools/ecode/statusterminalcontroller.cpp | 2 +- src/tools/uieditor/uieditor.cpp | 2 +- src/tools/uieditor/uieditor.hpp | 2 +- 131 files changed, 1747 insertions(+), 1178 deletions(-) create mode 100644 include/eepp/graphics/texturedrawable.hpp create mode 100644 src/eepp/graphics/texturedrawable.cpp diff --git a/.agent/plans/resource_shared_ownership_architecture.md b/.agent/plans/resource_shared_ownership_architecture.md index 45bdc5e74..3d75f9a27 100644 --- a/.agent/plans/resource_shared_ownership_architecture.md +++ b/.agent/plans/resource_shared_ownership_architecture.md @@ -1,7 +1,6 @@ # eepp shared-resource ownership architecture -Status: active implementation baseline; Stage 0 through Stage 3 complete; Stage 4 is next, -2026-07-19. +Status: active implementation baseline; Stage 0 through Stage 4 complete, 2026-07-20. This document freezes the contracts that must be true before the public texture API is changed. The implementation may refine names and small mechanics, but changing an invariant below requires an @@ -344,35 +343,73 @@ fixed: Shared lifetime and shareable instance state are separate concerns. `isStateful()` is not a sharing contract and will not be used as one. -### 7.1 Frozen source/instance split +### 7.1 Source/instance split Resource resolution caches immutable source data. UI consumers own per-consumer drawable instances: ```cpp -using DrawableSourcePtr = ResourcePtr; using DrawablePtr = ResourcePtr; -DrawableSourcePtr DrawableResolver::findSource( const DrawableRequest& request ); +DrawablePtr Drawable::createInstance() const; DrawablePtr DrawableResolver::createDrawable( const DrawableRequest& request ); ``` +Stage 4 established this contract without introducing a parallel `DrawableSource` class hierarchy. +Existing drawable resource types serve as source prototypes while retained by an atlas, theme, +icon, catalog, or resolver. A prototype is never handed directly to an unrelated consumer: +`createInstance()` returns independently mutable presentation state while sharing underlying +texture/resource handles. This is simpler than duplicating every drawable type into source and +instance classes and remains compatible with introducing immutable source-only types later when a +concrete resource requires one. + +eepp continues to use `Drawable::Type` for runtime drawable dispatch. Generic handle conversion +checks that tag and then uses `static_pointer_cast`; cloning code for a statically known concrete +type also uses `static_pointer_cast`. The ownership migration does not introduce RTTI casts. + Representative split: - `Texture` is shared GPU/resource data, not a globally shared mutable drawable instance. -- `TextureRegionSource` contains a TexturePtr, immutable source rectangle, offset, and intrinsic size. -- `NinePatchSource` contains immutable region and border data. -- `TextureDrawable`/`TextureRegionDrawable` hold per-consumer destination size, tint, alpha, position, - and other presentation state while retaining their source. +- `TextureRegion` prototypes and instances retain a TexturePtr; instances copy rectangle, offset, + intrinsic size, destination size, tint, and position. +- `NinePatch` instances clone their nine mutable region children while sharing the textures. +- `TextureDrawable` holds per-consumer destination size, tint, alpha, and position while retaining + the shared TexturePtr. - `StateListDrawable`, `DrawableGroup`, and `Sprite` are per-consumer state machines/instances that refer to source handles or private child instances. `DrawableImageParser::createDrawable()` always returns a fresh consumer instance for CSS-generated or resolved content, even when its immutable source came from a cache. +`UIIcon`, `UIGlyphIcon`, and `UISVGIcon` expose the split directly: + +```cpp +const DrawablePtr& UIIcon::getSource( int size ) const; +DrawablePtr UIIcon::createDrawable( int size ) const; +``` + +`getSource()` supports lookup and measurement without cloning an existing prototype. Glyph and SVG +icons may materialize and cache a missing size source once. `createDrawable()` is the explicit +consumer-instance boundary. Callers retain its result for as long as they render that icon. + The migration will remove draw-time mutation of shared child/source objects. Rendering APIs may use external draw parameters where that simplifies an implementation, but no shared source can be temporarily recolored, resized, repositioned, or advanced by a consumer. +No rendering callback may call `createInstance()`, `UIIcon::createDrawable()`, or an API that +performs either operation internally. Rendered instances are prepared during assignment, +deserialization, style/resource resolution, scheduled update, or plugin update and retained by the +consumer. The Stage 4 call-site audit classifies all remaining direct `createInstance()` calls as: + +- implementations recursively cloning their private child state; +- constructors and setters adopting a private region/sprite/map instance; +- theme, skin, icon, CSS, and name-resolution source-to-instance boundaries; +- widget deserialization and one-time assignment; or +- focused ownership tests. + +The code editor lock icon and ecode debugger, linter, LSP breadcrumb, and autocomplete icon paths +retain instances populated before drawing. Draw callbacks only look up and render those retained +instances; a cache miss skips the icon for that frame instead of cloning while rendering. + ### 7.2 Consumer API Consumers store a strong per-consumer instance: @@ -645,6 +682,25 @@ Exit criteria: ### Stage 4: drawable source/instance conversion +Status: complete, 2026-07-20. Drawable ownership +now uses `DrawablePtr`; textures create private +`TextureDrawable` wrappers; mutable prototypes implement `createInstance()`; sprites, state lists, +skins, groups, nine-patches, regions, glyphs, gradients, and primitive drawables clone their +presentation state. UIImage, UINodeDrawable, menus/icons/themes, parsers, editor/tool consumers, +maps, physics, ecode, and eeiv were migrated in the same API cut. + +`DrawableResource::Unload` and callback IDs were replaced by Change-only RAII connections. +`Variant` stores DrawablePtr outside its scalar union. UITextureRegion and ScrollParallax render +with local geometry rather than temporarily resizing shared source regions; region-based map +objects retain private instances. `DrawableSearcher` already returns fresh instances as a safe +bridge, but its replacement by the layered UI resolver remains Stage 5. + +`UIIcon::getSource()` now returns a cached source/prototype for lookup and measurement, while +`UIIcon::createDrawable()` explicitly creates one private consumer instance. `UIGlyphIcon` and +`UISVGIcon` cache their lazily materialized sources under the same contract. The complete +`createInstance()` call-site audit found no remaining render-loop cloning; previously hot code +editor, debugger, linter, LSP breadcrumb, and autocomplete paths retain update-time instances. + Introduce source types and per-consumer instances, remove shared draw-state mutation, replace manual ownership with DrawablePtr, remove Unload lifetime callbacks, add RAII change connections, and migrate Variant's storage. diff --git a/include/eepp/graphics.hpp b/include/eepp/graphics.hpp index 52cc62dc9..c3a8a5dc3 100644 --- a/include/eepp/graphics.hpp +++ b/include/eepp/graphics.hpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eepp/graphics/arcdrawable.hpp b/include/eepp/graphics/arcdrawable.hpp index 470c0103b..7b3d5b185 100644 --- a/include/eepp/graphics/arcdrawable.hpp +++ b/include/eepp/graphics/arcdrawable.hpp @@ -30,6 +30,8 @@ class EE_API ArcDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + Float getRadius() const; void setRadius( const Float& radius ); diff --git a/include/eepp/graphics/circledrawable.hpp b/include/eepp/graphics/circledrawable.hpp index a85071ed9..0f3523123 100644 --- a/include/eepp/graphics/circledrawable.hpp +++ b/include/eepp/graphics/circledrawable.hpp @@ -14,6 +14,8 @@ class EE_API CircleDrawable : public ArcDrawable { CircleDrawable(); CircleDrawable( const Float& radius, const Uint32& segmentsCount ); + + DrawablePtr createInstance() const; }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/convexshapedrawable.hpp b/include/eepp/graphics/convexshapedrawable.hpp index fc945faff..cc5601c05 100644 --- a/include/eepp/graphics/convexshapedrawable.hpp +++ b/include/eepp/graphics/convexshapedrawable.hpp @@ -24,6 +24,8 @@ class EE_API ConvexShapeDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + void setPolygon( const Polygon2f& polygon ); void addPoint( const Vector2f& point ); diff --git a/include/eepp/graphics/drawable.hpp b/include/eepp/graphics/drawable.hpp index 2b5e4cfd8..5b33592ca 100644 --- a/include/eepp/graphics/drawable.hpp +++ b/include/eepp/graphics/drawable.hpp @@ -2,6 +2,7 @@ #define EE_GRAPHICS_DRAWABLE_HPP #include +#include #include #include #include @@ -10,12 +11,17 @@ using namespace EE::System; namespace EE { namespace Graphics { +class Drawable; class StatefulDrawable; +using DrawablePtr = ResourcePtr; +using DrawableWeakPtr = ResourceWeakPtr; + class EE_API Drawable { public: enum Type { TEXTURE, + TEXTUREDRAWABLE, TEXTUREREGION, SPRITE, ARC, @@ -57,6 +63,10 @@ class EE_API Drawable { virtual bool isStateful() = 0; + /** Creates an independently mutable instance backed by the same immutable resource data. + * This is an ownership/setup operation; rendering loops must retain and reuse the result. */ + virtual DrawablePtr createInstance() const; + void setAlpha( Uint8 alpha ); const Uint8& getAlpha(); diff --git a/include/eepp/graphics/drawablegroup.hpp b/include/eepp/graphics/drawablegroup.hpp index cbdc45d01..a214f762a 100644 --- a/include/eepp/graphics/drawablegroup.hpp +++ b/include/eepp/graphics/drawablegroup.hpp @@ -8,7 +8,7 @@ namespace EE { namespace Graphics { class EE_API DrawableGroup : public Drawable { public: - static DrawableGroup* New(); + static ResourcePtr New(); DrawableGroup(); @@ -26,9 +26,11 @@ class EE_API DrawableGroup : public Drawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + void clearDrawables(); - Drawable* addDrawable( Drawable* drawable ); + DrawablePtr addDrawable( DrawablePtr drawable ); Uint32 getDrawableCount() const; @@ -36,19 +38,14 @@ class EE_API DrawableGroup : public Drawable { void setClipEnabled( bool clipEnabled ); - bool isDrawableOwner() const; - - void setDrawableOwner( bool drawableOwner ); - - std::vector& getGroup(); + std::vector& getGroup(); protected: - std::vector mGroup; + std::vector mGroup; std::vector mPos; Sizef mSize; bool mNeedsUpdate; bool mClipEnabled; - bool mDrawableOwner; virtual void onPositionChange(); diff --git a/include/eepp/graphics/drawableresource.hpp b/include/eepp/graphics/drawableresource.hpp index e68a48194..e0aabac64 100644 --- a/include/eepp/graphics/drawableresource.hpp +++ b/include/eepp/graphics/drawableresource.hpp @@ -3,16 +3,43 @@ #include #include +#include namespace EE { namespace Graphics { +class DrawableResource; + +struct DrawableResourceCallbackState { + using Callback = std::function; + Uint32 nextId{ 0 }; + UnorderedMap callbacks; +}; + +class EE_API DrawableResourceConnection { + public: + DrawableResourceConnection() = default; + ~DrawableResourceConnection(); + DrawableResourceConnection( DrawableResourceConnection&& other ) noexcept; + DrawableResourceConnection& operator=( DrawableResourceConnection&& other ) noexcept; + DrawableResourceConnection( const DrawableResourceConnection& ) = delete; + DrawableResourceConnection& operator=( const DrawableResourceConnection& ) = delete; + + void disconnect(); + explicit operator bool() const; + + private: + friend class DrawableResource; + DrawableResourceConnection( std::weak_ptr state, Uint32 id ); + + std::weak_ptr mState; + Uint32 mId{ 0 }; +}; + class EE_API DrawableResource : public Drawable { public: - enum Event { Change, Unload }; - virtual ~DrawableResource(); - typedef std::function OnResourceChangeCallback; + using OnResourceChangeCallback = DrawableResourceCallbackState::Callback; /** @return The DrawableResource Id. The Id is the String::hash of the name. */ const String::HashType& getId() const; @@ -26,19 +53,13 @@ class EE_API DrawableResource : public Drawable { /** Always true */ bool isDrawableResource() const; - /** Push a new on resource change callback. - * @return The Callback Id - */ - Uint32 pushResourceChangeCallback( const OnResourceChangeCallback& cb ); - - /** Pop the on resource change callback id indicated. */ - bool popResourceChangeCallback( const Uint32& callbackId ); + /** Connects a callback for mutable resource data changes. */ + DrawableResourceConnection connectResourceChange( OnResourceChangeCallback cb ); protected: std::string mName; String::HashType mId; - Uint32 mNumCallBacks; - UnorderedMap mCallbacks; + std::shared_ptr mCallbackState; explicit DrawableResource( Type drawableType ); @@ -48,7 +69,7 @@ class EE_API DrawableResource : public Drawable { virtual void onResourceChange(); - void sendEvent( const Event& event ); + void sendResourceChanged(); }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/drawablesearcher.hpp b/include/eepp/graphics/drawablesearcher.hpp index b42d1e20c..c95ea9cb4 100644 --- a/include/eepp/graphics/drawablesearcher.hpp +++ b/include/eepp/graphics/drawablesearcher.hpp @@ -11,11 +11,11 @@ class ResourceScope; class EE_API DrawableSearcher { public: - static Drawable* searchByName( const std::string& name, bool firstSearchSprite = false, + static DrawablePtr searchByName( const std::string& name, bool firstSearchSprite = false, Network::URI referer = "", ResourceScope* resourceScope = nullptr ); - static Drawable* searchById( const Uint32& id ); + static DrawablePtr searchById( const Uint32& id ); static void setPrintWarnings( const bool& print ); diff --git a/include/eepp/graphics/glyphdrawable.hpp b/include/eepp/graphics/glyphdrawable.hpp index c399fa893..653f6d941 100644 --- a/include/eepp/graphics/glyphdrawable.hpp +++ b/include/eepp/graphics/glyphdrawable.hpp @@ -35,6 +35,8 @@ class EE_API GlyphDrawable : public DrawableResource { virtual bool isStateful(); + DrawablePtr createInstance() const; + /** @return The texture instance used by the GlyphDrawable. */ const TexturePtr& getTexture() const; diff --git a/include/eepp/graphics/ninepatch.hpp b/include/eepp/graphics/ninepatch.hpp index e81f0af1d..d2041fd12 100644 --- a/include/eepp/graphics/ninepatch.hpp +++ b/include/eepp/graphics/ninepatch.hpp @@ -51,10 +51,12 @@ class EE_API NinePatch : public DrawableResource { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + TextureRegion* getTextureRegion( const int& side ); protected: - TextureRegion* mDrawable[SideCount]; + TextureRegionPtr mDrawable[SideCount]; Rect mRect; Rectf mRectf; Sizef mSize; diff --git a/include/eepp/graphics/rectangledrawable.hpp b/include/eepp/graphics/rectangledrawable.hpp index 933b65349..9f951082a 100644 --- a/include/eepp/graphics/rectangledrawable.hpp +++ b/include/eepp/graphics/rectangledrawable.hpp @@ -28,6 +28,8 @@ class EE_API RectangleDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + Float getRotation() const; void setRotation( const Float& rotation ); diff --git a/include/eepp/graphics/resource.hpp b/include/eepp/graphics/resource.hpp index afd5979a3..8473e92cd 100644 --- a/include/eepp/graphics/resource.hpp +++ b/include/eepp/graphics/resource.hpp @@ -51,6 +51,10 @@ template struct ResourceDeleter { void operator()( T* resource ) const noexcept { eeDelete( resource ); } }; +template ResourcePtr makeResource( Args&&... args ) { + return ResourcePtr( eeNew( T, ( std::forward( args )... ) ), ResourceDeleter() ); +} + }} // namespace EE::Graphics #endif diff --git a/include/eepp/graphics/scrollparallax.hpp b/include/eepp/graphics/scrollparallax.hpp index 034f28b2b..40c92e13a 100644 --- a/include/eepp/graphics/scrollparallax.hpp +++ b/include/eepp/graphics/scrollparallax.hpp @@ -89,7 +89,7 @@ class EE_API ScrollParallax { const Vector2f& getSpeed() const; private: - TextureRegion* mTextureRegion; + TextureRegionPtr mTextureRegion; BlendMode mBlend; Color mColor; Vector2f mInitPos; diff --git a/include/eepp/graphics/sprite.hpp b/include/eepp/graphics/sprite.hpp index 38dc9232d..899f7a80a 100644 --- a/include/eepp/graphics/sprite.hpp +++ b/include/eepp/graphics/sprite.hpp @@ -11,6 +11,9 @@ using namespace EE::System; namespace EE { namespace Graphics { +class Sprite; +using SpritePtr = ResourcePtr; + /** @brief A Sprite controller class, can hold and control sprites animations. */ class EE_API Sprite : public Drawable { public: @@ -26,22 +29,24 @@ class EE_API Sprite : public Drawable { SPRITE_EVENT_USER // User vents }; - static Sprite* New(); + static SpritePtr New(); - static Sprite* New( const std::string& name, const std::string& extension = "", + static SpritePtr New( const std::string& name, const std::string& extension = "", TextureAtlas* SearchInTextureAtlas = NULL ); - static Sprite* New( TextureRegion* TextureRegion ); + static SpritePtr New( TextureRegion* TextureRegion ); - static Sprite* New( ResourceId textureId, const Sizef& DestSize = Sizef( 0, 0 ), + static SpritePtr New( ResourceId textureId, const Sizef& DestSize = Sizef( 0, 0 ), const Vector2i& offset = Vector2i( 0, 0 ), const Rect& TexSector = Rect( 0, 0, 0, 0 ) ); - static Sprite* fromGif( IOStream& gif ); + static SpritePtr fromGif( IOStream& gif ); /** Instantiate an empty sprite */ Sprite(); + Sprite( const Sprite& other ); + /** Creates an animated Sprite from a animation name. It will search for a pattern name. * For example search for name "car" with extensions "png", i will try to find car00.png * car01.png car02.png, and so on, it will continue if find something, otherwise it will stop ( @@ -312,6 +317,8 @@ class EE_API Sprite : public Drawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + /** Set the number of repetitions of the animation. Any number below 0 the animation will loop. */ void setRepetitions( const int& Repeations ); @@ -379,8 +386,8 @@ class EE_API Sprite : public Drawable { /** Pop the event callback id indicated. */ bool popEventsCallback( const Uint32& callbackId ); - /** Creates a copy of the current sprite and returns it */ - Sprite clone(); + /** Creates an independent instance sharing the same texture resources. */ + SpritePtr clone() const; /** Update the sprite animation */ void update( const Time& ElapsedTime ); @@ -391,10 +398,6 @@ class EE_API Sprite : public Drawable { /** Fire a User Event in the sprite */ void fireEvent( const Uint32& Event ); - Sprite& setAsTextureRegionOwner( bool set ); - - bool isTextureRegionOwner() const; - protected: enum SpriteFlags { SPRITE_FLAG_AUTO_ANIM = ( 1 << 0 ), @@ -402,7 +405,6 @@ class EE_API Sprite : public Drawable { SPRITE_FLAG_ANIM_PAUSED = ( 1 << 2 ), SPRITE_FLAG_ANIM_TO_FRAME_AND_STOP = ( 1 << 3 ), SPRITE_FLAG_EVENTS_ENABLED = ( 1 << 4 ), - SPRITE_FLAG_TEXTURE_REGION_OWNER = ( 1 << 6 ), }; Uint32 mFlags{ SPRITE_FLAG_AUTO_ANIM | SPRITE_FLAG_EVENTS_ENABLED }; @@ -433,7 +435,7 @@ class EE_API Sprite : public Drawable { UnorderedMap mCallbacks; struct Frame { - std::vector Spr; + std::vector Spr; }; std::vector mFrames; @@ -441,11 +443,12 @@ class EE_API Sprite : public Drawable { void clearFrame(); - void cleanUpResources(); - unsigned int getFrame( const unsigned int& FrameNum ); unsigned int getSubFrame( const unsigned int& SubFrame ); + + bool addSubFrame( TextureRegionPtr textureRegion, const unsigned int& numFrame, + const unsigned int& numSubFrame ); }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/statelistdrawable.hpp b/include/eepp/graphics/statelistdrawable.hpp index 9b2c50371..7912581de 100644 --- a/include/eepp/graphics/statelistdrawable.hpp +++ b/include/eepp/graphics/statelistdrawable.hpp @@ -28,14 +28,15 @@ class EE_API StateListDrawable : public StatefulDrawable { virtual bool isStateful(); + DrawablePtr createInstance() const; + virtual StatefulDrawable* setState( Uint32 state ); virtual const Uint32& getState() const; virtual Drawable* getStateDrawable( const Uint32& state ); - virtual StateListDrawable* setStateDrawable( const Uint32& state, Drawable* drawable, - bool ownIt = false ); + virtual StateListDrawable* setStateDrawable( const Uint32& state, DrawablePtr drawable ); virtual Sizef getStateSize( const Uint32& state ); @@ -56,8 +57,7 @@ class EE_API StateListDrawable : public StatefulDrawable { protected: Uint32 mCurrentState; Drawable* mCurrentDrawable; - std::map mDrawables; - std::map mDrawablesOwnership; + std::map mDrawables; std::map mDrawableColors; explicit StateListDrawable( const std::string& name = "" ); diff --git a/include/eepp/graphics/texture.hpp b/include/eepp/graphics/texture.hpp index 676a094b6..4bc18c46d 100644 --- a/include/eepp/graphics/texture.hpp +++ b/include/eepp/graphics/texture.hpp @@ -294,6 +294,8 @@ class EE_API Texture : public DrawableResource, public Image, private NonCopyabl virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + /** @return The process-wide identity assigned to this texture. */ ResourceId getTextureId() const; diff --git a/include/eepp/graphics/texturedrawable.hpp b/include/eepp/graphics/texturedrawable.hpp new file mode 100644 index 000000000..527ae3f13 --- /dev/null +++ b/include/eepp/graphics/texturedrawable.hpp @@ -0,0 +1,36 @@ +#ifndef EE_GRAPHICS_TEXTUREDRAWABLE_HPP +#define EE_GRAPHICS_TEXTUREDRAWABLE_HPP + +#include +#include + +namespace EE { namespace Graphics { + +class TextureDrawable; +using TextureDrawablePtr = ResourcePtr; + +/** Per-consumer drawable state backed by a shared texture resource. */ +class EE_API TextureDrawable : public DrawableResource { + public: + static TextureDrawablePtr New( TexturePtr texture ); + + explicit TextureDrawable( TexturePtr texture ); + + Sizef getSize(); + Sizef getPixelsSize(); + void draw(); + void draw( const Vector2f& position ); + void draw( const Vector2f& position, const Sizef& size ); + bool isStateful(); + DrawablePtr createInstance() const; + + const TexturePtr& getTexture() const; + + protected: + TexturePtr mTexture; + DrawableResourceConnection mTextureChangeConnection; +}; + +}} // namespace EE::Graphics + +#endif diff --git a/include/eepp/graphics/textureregion.hpp b/include/eepp/graphics/textureregion.hpp index 7ac5f3941..6342b4d79 100644 --- a/include/eepp/graphics/textureregion.hpp +++ b/include/eepp/graphics/textureregion.hpp @@ -8,6 +8,9 @@ namespace EE { namespace Graphics { +class TextureRegion; +using TextureRegionPtr = ResourcePtr; + /** @brief A TextureRegion is a part of a texture that represent an sprite.*/ class EE_API TextureRegion : public DrawableResource { public: @@ -126,6 +129,8 @@ class EE_API TextureRegion : public DrawableResource { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + /** @return The texture instance used by the TextureRegion. */ const TexturePtr& getTexture() const; diff --git a/include/eepp/graphics/triangledrawable.hpp b/include/eepp/graphics/triangledrawable.hpp index 5c3560018..c5b1c67e9 100644 --- a/include/eepp/graphics/triangledrawable.hpp +++ b/include/eepp/graphics/triangledrawable.hpp @@ -28,6 +28,8 @@ class EE_API TriangleDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } + DrawablePtr createInstance() const; + void setSize( const Sizef& size ); const Triangle2f& getTriangle() const; @@ -41,7 +43,7 @@ class EE_API TriangleDrawable : public PrimitiveDrawable { Triangle2f mComputedTriangle; Sizef mSize; Color mColors[3]; - bool mCustomColors; + bool mCustomColors{ false }; virtual void onColorFilterChange(); diff --git a/include/eepp/ui/css/drawableimageparser.hpp b/include/eepp/ui/css/drawableimageparser.hpp index 5e9160a45..d70809597 100644 --- a/include/eepp/ui/css/drawableimageparser.hpp +++ b/include/eepp/ui/css/drawableimageparser.hpp @@ -2,14 +2,12 @@ #define EE_UI_CSS_DRAWABLEIMAGEPARSER_HPP #include +#include #include #include #include #include -namespace EE { namespace Graphics { -class Drawable; -}} // namespace EE::Graphics namespace EE { namespace UI { class UINode; }} // namespace EE::UI @@ -20,8 +18,8 @@ using namespace EE::System; namespace EE { namespace UI { namespace CSS { -typedef std::function +typedef std::function DrawableImageParserFunc; class EE_API DrawableImageParser { @@ -30,8 +28,7 @@ class EE_API DrawableImageParser { bool exists( const std::string& name ) const; - Drawable* createDrawable( const std::string& value, const Sizef& size, bool& ownIt, - UINode* node ); + DrawablePtr createDrawable( const std::string& value, const Sizef& size, UINode* node ); void addParser( const std::string& name, const DrawableImageParserFunc& func ); diff --git a/include/eepp/ui/lineargradientdrawable.hpp b/include/eepp/ui/lineargradientdrawable.hpp index 5f2ea908f..4b28292d5 100644 --- a/include/eepp/ui/lineargradientdrawable.hpp +++ b/include/eepp/ui/lineargradientdrawable.hpp @@ -50,6 +50,8 @@ class EE_API LinearGradientDrawable : public Graphics::Drawable { virtual bool isStateful() { return false; } + Graphics::DrawablePtr createInstance() const; + const std::vector& getColorStops() const; void setColorStops( std::vector stops ); diff --git a/include/eepp/ui/models/variant.hpp b/include/eepp/ui/models/variant.hpp index 4c47e67c0..15d30c646 100644 --- a/include/eepp/ui/models/variant.hpp +++ b/include/eepp/ui/models/variant.hpp @@ -43,10 +43,7 @@ class EE_API Variant { explicit Variant( const String* string ) : mType( Type::StringPtr ) { mValue.asStringPtr = string; } - Variant( Drawable* drawable, bool ownDrawable = false ) : mType( Type::Drawable ) { - mValue.asDrawable = drawable; - mOwnsObject = ownDrawable; - } + Variant( DrawablePtr drawable ) : mDrawable( std::move( drawable ) ), mType( Type::Drawable ) {} Variant( UIIcon* icon ) : mType( Type::Icon ) { mValue.asIcon = icon; } Variant( const Vector2f& v ) : mType( Type::Vector2f ) { mValue.asVector2f = eeNew( Vector2f, ( v ) ); @@ -62,7 +59,7 @@ class EE_API Variant { explicit Variant( const char* data ) : mType( Type::cstr ) { mValue.asCStr = data; } ~Variant() { reset(); } - Variant( const Variant& other ) : mType( Type::Invalid ), mOwnsObject( other.mOwnsObject ) { + Variant( const Variant& other ) : mType( Type::Invalid ) { switch ( other.mType ) { case Type::StdString: mValue.asStdString = eeNew( std::string, ( *other.mValue.asStdString ) ); @@ -74,7 +71,7 @@ class EE_API Variant { mValue.asStringPtr = other.mValue.asStringPtr; break; case Type::Drawable: - mValue.asDrawable = other.mValue.asDrawable; + mDrawable = other.mDrawable; break; case Type::Icon: mValue.asIcon = other.mValue.asIcon; @@ -116,9 +113,8 @@ class EE_API Variant { } Variant( Variant&& other ) noexcept : - mValue( other.mValue ), mType( other.mType ), mOwnsObject( other.mOwnsObject ) { + mValue( other.mValue ), mDrawable( std::move( other.mDrawable ) ), mType( other.mType ) { other.mType = Type::Invalid; - other.mOwnsObject = false; other.mValue = {}; } @@ -134,10 +130,9 @@ class EE_API Variant { if ( this != &other ) { reset(); mType = other.mType; - mOwnsObject = other.mOwnsObject; + mDrawable = std::move( other.mDrawable ); mValue = other.mValue; other.mType = Type::Invalid; - other.mOwnsObject = false; other.mValue = {}; } return *this; @@ -146,7 +141,7 @@ class EE_API Variant { const std::string& asStdString() const { return *mValue.asStdString; } const String& asString() const { return *mValue.asString; } const String& asStringPtr() const { return *mValue.asStringPtr; } - Drawable* asDrawable() const { return mValue.asDrawable; } + const DrawablePtr& asDrawable() const { return mDrawable; } const bool& asBool() const { return mValue.asBool; } const Float& asFloat() const { return mValue.asFloat; } const int& asInt() const { return mValue.asInt; } @@ -172,8 +167,7 @@ class EE_API Variant { eeSAFE_DELETE( mValue.asString ); break; case Type::Drawable: - if ( mOwnsObject ) - eeSAFE_DELETE( mValue.asDrawable ); + mDrawable.reset(); break; case Type::Vector2f: eeSAFE_DELETE( mValue.asVector2f ); @@ -210,7 +204,7 @@ class EE_API Variant { return asStringPtr(); case Type::Drawable: return asDrawable()->isDrawableResource() - ? static_cast( asDrawable() )->getName() + ? static_cast( asDrawable().get() )->getName() : "Drawable"; case Type::Icon: return asIcon()->getName(); @@ -330,7 +324,7 @@ class EE_API Variant { case Type::StringPtr: return asStringPtr().size(); case Type::Drawable: - return sizeof( mValue.asDrawable ); + return sizeof( mDrawable ); case Type::Icon: return asIcon()->getName().size(); case Type::DataPtr: @@ -350,7 +344,6 @@ class EE_API Variant { private: union { void* asDataPtr{ nullptr }; - Drawable* asDrawable; UIIcon* asIcon; std::string* asStdString; String* asString; @@ -365,8 +358,8 @@ class EE_API Variant { Rectf* asRectf; const char* asCStr; } mValue; + DrawablePtr mDrawable; Type mType; - bool mOwnsObject{ false }; }; }}} // namespace EE::UI::Models diff --git a/include/eepp/ui/radialgradientdrawable.hpp b/include/eepp/ui/radialgradientdrawable.hpp index 1a9b94b83..626a92f7c 100644 --- a/include/eepp/ui/radialgradientdrawable.hpp +++ b/include/eepp/ui/radialgradientdrawable.hpp @@ -54,6 +54,8 @@ class EE_API RadialGradientDrawable : public Graphics::Drawable { virtual bool isStateful() { return false; } + Graphics::DrawablePtr createInstance() const; + const std::vector& getColorStops() const; void setColorStops( std::vector stops ); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index bce99ca02..6529e7512 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -768,13 +768,13 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void setShowFoldingRegion( bool showFoldingRegion ); - Drawable* getFoldDrawable() const; + const DrawablePtr& getFoldDrawable() const; - void setFoldDrawable( Drawable* foldDrawable ); + void setFoldDrawable( DrawablePtr foldDrawable ); - Drawable* getFoldedDrawable() const; + const DrawablePtr& getFoldedDrawable() const; - void setFoldedDrawable( Drawable* foldedDrawable ); + void setFoldedDrawable( DrawablePtr foldedDrawable ); bool getFoldsAlwaysVisible() const; @@ -997,10 +997,12 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { Text mLineTextCache; size_t mJumpLinesLength{ 5 }; UIIcon* mFileLockIcon{ nullptr }; + DrawablePtr mFileLockDrawable; + int mFileLockDrawableSize{ 0 }; std::string mFileLockIconName{ "file-lock-fill" }; LineWrapType mLineWrapType{ LineWrapType::Viewport }; - Drawable* mFoldDrawable{ nullptr }; - Drawable* mFoldedDrawable{ nullptr }; + DrawablePtr mFoldDrawable; + DrawablePtr mFoldedDrawable; String::HashType mTagFoldRange{ 0 }; Uint32 mTabIndentCharacter{ 187 /*'»'*/ }; CharacterAlignment mTabIndentAlignment{ CharacterAlignment::Center }; @@ -1157,7 +1159,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void updateGlyphWidth(); - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); void createDefaultContextMenuOptions( UIPopUpMenu* menu ); diff --git a/include/eepp/ui/uiconsole.hpp b/include/eepp/ui/uiconsole.hpp index 884052ab4..68b159196 100644 --- a/include/eepp/ui/uiconsole.hpp +++ b/include/eepp/ui/uiconsole.hpp @@ -343,7 +343,7 @@ class EE_API UIConsole : public UIWidget, UIMenuItem* menuAdd( UIPopUpMenu* menu, const String& translateString, const std::string& icon, const std::string& cmd ); - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); void copySelection(); diff --git a/include/eepp/ui/uiicon.hpp b/include/eepp/ui/uiicon.hpp index f53fcb690..8028086aa 100644 --- a/include/eepp/ui/uiicon.hpp +++ b/include/eepp/ui/uiicon.hpp @@ -20,15 +20,23 @@ class EE_API UIIcon { const std::string& getName() const; - virtual Drawable* getSize( const int& size ) const; + /** Returns the icon source closest to the requested size. + * + * The returned drawable is shared icon data and must not be mutated by consumers. Use + * createDrawable() when a consumer needs its own mutable drawable instance. */ + virtual const DrawablePtr& getSource( const int& size ) const; - virtual void setSize( const int& size, Drawable* drawable ); + /** Creates a private drawable instance for a consumer. This must not be called from a rendering + * loop; retain the returned instance instead. */ + DrawablePtr createDrawable( const int& size ) const; + + virtual void setSource( const int& size, DrawablePtr drawable ); protected: UIIcon( const std::string& name ); std::string mName; - mutable UnorderedMap mSizes; + mutable UnorderedMap mSizes; }; class EE_API UIGlyphIcon : public UIIcon { @@ -37,7 +45,7 @@ class EE_API UIGlyphIcon : public UIIcon { virtual ~UIGlyphIcon(); - virtual Drawable* getSize( const int& size ) const; + virtual const DrawablePtr& getSource( const int& size ) const; protected: UIGlyphIcon( const std::string& name, FontTrueType* font, const Uint32& codePoint ); @@ -53,13 +61,12 @@ class EE_API UISVGIcon : public UIIcon { virtual ~UISVGIcon(); - virtual Drawable* getSize( const int& size ) const; + virtual const DrawablePtr& getSource( const int& size ) const; protected: UISVGIcon( const std::string& name, const std::string& svgXML ); std::string mSVGXml; - mutable UnorderedMap mSVGs; mutable Sizei mOriSize; mutable int mOriChannels{ 0 }; }; diff --git a/include/eepp/ui/uiimage.hpp b/include/eepp/ui/uiimage.hpp index aa926d993..3467cb2d6 100644 --- a/include/eepp/ui/uiimage.hpp +++ b/include/eepp/ui/uiimage.hpp @@ -24,9 +24,9 @@ class EE_API UIImage : public UIWidget { virtual void setAlpha( const Float& alpha ); - Drawable* getDrawable() const; + const DrawablePtr& getDrawable() const; - UIImage* setDrawable( Drawable* drawable, bool ownIt = false ); + UIImage* setDrawable( DrawablePtr drawable ); UIImage* setDrawable( TexturePtr texture ); @@ -55,13 +55,12 @@ class EE_API UIImage : public UIWidget { protected: UIScaleType mScaleType; - Drawable* mDrawable; - TexturePtr mTexture; + DrawablePtr mDrawable; Color mColor; Vector2f mAlignOffset; Vector2f mDestSize; - Uint32 mResourceChangeCb; - bool mDrawableOwner; + DrawableResourceConnection mResourceChangeConnection; + Uint32 mSpriteChangeCb{ 0 }; bool mDeferLoad{ false }; std::shared_ptr> mAsyncImageAlive; Uint64 mRemoteImageLoadId{ 0 }; @@ -82,9 +81,9 @@ class EE_API UIImage : public UIWidget { void autoAlign(); - void safeDeleteDrawable(); + void clearDrawable(); - void onDrawableResourceEvent( DrawableResource::Event event, DrawableResource* ); + void onDrawableResourceChange(); bool loadFileDrawable( const Network::URI& uri ); diff --git a/include/eepp/ui/uimenu.hpp b/include/eepp/ui/uimenu.hpp index c6b04ee45..923fe7c49 100644 --- a/include/eepp/ui/uimenu.hpp +++ b/include/eepp/ui/uimenu.hpp @@ -24,7 +24,7 @@ class EE_API UIMenu : public UIWidget { virtual bool isType( const Uint32& type ) const; - UIMenuItem* add( const String& text, Drawable* icon = NULL, const String& shortcutText = "" ); + UIMenuItem* add( const String& text, DrawablePtr icon = {}, const String& shortcutText = "" ); UIWidget* add( UIWidget* widget ); @@ -35,7 +35,8 @@ class EE_API UIMenu : public UIWidget { UIMenuRadioButton* addRadioButton( const String& text, const bool& active = false ); - UIMenuSubMenu* addSubMenu( const String& text, Drawable* icon = NULL, UIMenu* subMenu = NULL ); + UIMenuSubMenu* addSubMenu( const String& text, DrawablePtr icon = {}, + UIMenu* subMenu = NULL ); UIWidget* getItem( const Uint32& index ); @@ -55,7 +56,7 @@ class EE_API UIMenu : public UIWidget { void removeAll(); - void insert( const String& text, Drawable* icon, const Uint32& index ); + void insert( const String& text, DrawablePtr icon, const Uint32& index ); void insert( UIWidget* widget, const Uint32& index ); @@ -121,7 +122,7 @@ class EE_API UIMenu : public UIWidget { void resizeMe(); - UIMenuItem* createMenuItem( const String& text, Drawable* icon, + UIMenuItem* createMenuItem( const String& text, DrawablePtr icon, const String& shortcutText = "" ); UIMenuCheckBox* createMenuCheckBox( const String& text, const bool& active, @@ -129,7 +130,7 @@ class EE_API UIMenu : public UIWidget { UIMenuRadioButton* createMenuRadioButton( const String& text, const bool& active ); - UIMenuSubMenu* createSubMenu( const String& text, Drawable* icon, UIMenu* subMenu ); + UIMenuSubMenu* createSubMenu( const String& text, DrawablePtr icon, UIMenu* subMenu ); void onThemeLoaded(); diff --git a/include/eepp/ui/uinode.hpp b/include/eepp/ui/uinode.hpp index f78228dd3..d24270fbd 100644 --- a/include/eepp/ui/uinode.hpp +++ b/include/eepp/ui/uinode.hpp @@ -336,12 +336,11 @@ class EE_API UINode : public Node { * * Enables background fill and sets the specified drawable at the given index. * - * @param drawable Pointer to the Drawable to use. - * @param ownIt If true, the node takes ownership of the drawable. + * @param drawable Drawable instance to use. * @param index The layer index (0-based). * @return Pointer to this node for method chaining. */ - UINode* setBackgroundDrawable( Drawable* drawable, bool ownIt = false, int index = 0 ); + UINode* setBackgroundDrawable( DrawablePtr drawable, int index = 0 ); /** * @brief Sets a background drawable from a skin name. @@ -521,12 +520,11 @@ class EE_API UINode : public Node { * * Enables foreground fill and sets the specified drawable at the given index. * - * @param drawable Pointer to the Drawable to use. - * @param ownIt If true, the node takes ownership of the drawable. + * @param drawable Drawable instance to use. * @param index The layer index (0-based). * @return Pointer to this node for method chaining. */ - UINode* setForegroundDrawable( Drawable* drawable, bool ownIt = false, int index = 0 ); + UINode* setForegroundDrawable( DrawablePtr drawable, int index = 0 ); /** * @brief Sets a foreground drawable from a skin name. diff --git a/include/eepp/ui/uinodedrawable.hpp b/include/eepp/ui/uinodedrawable.hpp index f129580ff..64d1b8744 100644 --- a/include/eepp/ui/uinodedrawable.hpp +++ b/include/eepp/ui/uinodedrawable.hpp @@ -56,11 +56,11 @@ class EE_API UINodeDrawable : public Drawable { virtual void setSize( const Sizef& size ); - Drawable* getDrawable() const; + const DrawablePtr& getDrawable() const; const std::string& getDrawableRef() const; - void setDrawable( Drawable* drawable, const bool& ownIt ); + void setDrawable( DrawablePtr drawable ); void setDrawable( TexturePtr texture ); @@ -131,12 +131,10 @@ class EE_API UINodeDrawable : public Drawable { std::string mPositionY; std::string mSizeEq; bool mNeedsUpdate{ false }; - bool mOwnsDrawable{ false }; bool mColorWasSet{ false }; - Drawable* mDrawable; - TexturePtr mTexture; + DrawablePtr mDrawable; std::string mDrawableRef; - Uint32 mResourceChangeCbId; + DrawableResourceConnection mResourceChangeConnection; RepeatX mRepeatX{ RepeatX::NoRepeat }; RepeatY mRepeatY{ RepeatY::NoRepeat }; std::string mOriginEq{ "padding-box" }; @@ -154,7 +152,7 @@ class EE_API UINodeDrawable : public Drawable { void update(); - Drawable* createDrawable( const std::string& value, const Sizef& size, bool& ownIt ); + DrawablePtr createDrawable( const std::string& value, const Sizef& size ); bool loadRemoteDrawable( const std::string& value ); }; @@ -191,7 +189,7 @@ class EE_API UINodeDrawable : public Drawable { LayerDrawable* getLayer( int index ); - void setDrawable( int index, Drawable* drawable, bool ownIt ); + void setDrawable( int index, DrawablePtr drawable ); void setDrawable( int index, const std::string& drawable ); @@ -238,7 +236,8 @@ class EE_API UINodeDrawable : public Drawable { protected: UINode* mOwner; UIBackgroundDrawable mBackgroundColor; - std::map mGroup; + using LayerDrawablePtr = std::unique_ptr>; + std::map mGroup; Sizef mSize; bool mNeedsUpdate{ true }; bool mClipEnabled{ false }; diff --git a/include/eepp/ui/uipushbutton.hpp b/include/eepp/ui/uipushbutton.hpp index 87e81276d..5367bcb2a 100644 --- a/include/eepp/ui/uipushbutton.hpp +++ b/include/eepp/ui/uipushbutton.hpp @@ -40,7 +40,7 @@ class EE_API UIPushButton : public UIWidget { virtual void setTheme( UITheme* Theme ); - virtual UIPushButton* setIcon( Drawable* icon, bool ownIt = false ); + virtual UIPushButton* setIcon( DrawablePtr icon ); virtual UIImage* getIcon(); diff --git a/include/eepp/ui/uiscenenode.hpp b/include/eepp/ui/uiscenenode.hpp index 26d73a761..de70bd2b0 100644 --- a/include/eepp/ui/uiscenenode.hpp +++ b/include/eepp/ui/uiscenenode.hpp @@ -564,7 +564,7 @@ class EE_API UISceneNode : public SceneNode { * @param drawableSize The desired size of the drawable in pixels. * @return Pointer to the Drawable, or nullptr if not found. */ - Drawable* findIconDrawable( const std::string& iconName, const size_t& drawableSize ); + DrawablePtr findIconDrawable( const std::string& iconName, const size_t& drawableSize ); /** * @brief Gets the keybindings manager. diff --git a/include/eepp/ui/uiskin.hpp b/include/eepp/ui/uiskin.hpp index 79846d2e9..8b10d2844 100644 --- a/include/eepp/ui/uiskin.hpp +++ b/include/eepp/ui/uiskin.hpp @@ -20,9 +20,11 @@ class EE_API UISkin : public StateListDrawable { virtual Sizef getPixelsSize(); - virtual UISkin* clone(); + DrawablePtr createInstance() const; - virtual UISkin* clone( const std::string& NewName ); + ResourcePtr clone() const; + + ResourcePtr clone( const std::string& newName ) const; virtual Rectf getBorderSize( const Uint32& state ); diff --git a/include/eepp/ui/uiskinstate.hpp b/include/eepp/ui/uiskinstate.hpp index 057dc1114..84b65ae88 100644 --- a/include/eepp/ui/uiskinstate.hpp +++ b/include/eepp/ui/uiskinstate.hpp @@ -2,6 +2,7 @@ #define EE_UI_UISKINSTATE_HPP #include +#include #include namespace EE { namespace UI { @@ -10,7 +11,7 @@ class UISkin; class EE_API UISkinState : public UIState { public: - static UISkinState* New( UISkin* skin ); + static UISkinState* New( ResourcePtr skin ); virtual ~UISkinState(); @@ -28,11 +29,11 @@ class EE_API UISkinState : public UIState { bool hasStateColor( const Uint32& state ) const; protected: - UISkin* mSkin; + ResourcePtr mSkin; std::map mColors; Color mCurrentColor; - explicit UISkinState( UISkin* Skin ); + explicit UISkinState( ResourcePtr skin ); void updateState(); diff --git a/include/eepp/ui/uisprite.hpp b/include/eepp/ui/uisprite.hpp index f76da0520..24736150e 100644 --- a/include/eepp/ui/uisprite.hpp +++ b/include/eepp/ui/uisprite.hpp @@ -1,13 +1,9 @@ #ifndef EE_UICUISPRITE_HPP #define EE_UICUISPRITE_HPP +#include #include -namespace EE { namespace Graphics { -class Sprite; -class TextureRegion; -}} // namespace EE::Graphics - namespace EE { namespace UI { class EE_API UISprite : public UIWidget { @@ -26,11 +22,9 @@ class EE_API UISprite : public UIWidget { virtual void setAlpha( const Float& alpha ); - Graphics::Sprite* getSprite() const; + const Graphics::SpritePtr& getSprite() const; - Drawable* getDrawable() const; - - UISprite* setSprite( Graphics::Sprite* sprite ); + UISprite* setSprite( Graphics::SpritePtr sprite ); Color getColor() const; @@ -42,10 +36,6 @@ class EE_API UISprite : public UIWidget { const Vector2f& getAlignOffset() const; - UISprite* setIsSpriteOwner( const bool& dealloc ); - - bool getDeallocSprite(); - virtual bool applyProperty( const StyleSheetProperty& attribute ); virtual std::string getPropertyString( const PropertyDefinition* propertyDef, @@ -54,11 +44,10 @@ class EE_API UISprite : public UIWidget { virtual std::vector getPropertiesImplemented() const; protected: - Graphics::Sprite* mSprite; + Graphics::SpritePtr mSprite; RenderMode mRender; Vector2f mAlignOffset; TextureRegion* mTextureRegionLast; - bool mDealloc; UISprite(); @@ -70,7 +59,6 @@ class EE_API UISprite : public UIWidget { virtual void onSizeChange(); - Uint32 deallocSprite(); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uitabwidget.hpp b/include/eepp/ui/uitabwidget.hpp index 48ccd3012..aa9632bc4 100644 --- a/include/eepp/ui/uitabwidget.hpp +++ b/include/eepp/ui/uitabwidget.hpp @@ -68,7 +68,7 @@ class EE_API UITabWidget : public UIWidget { virtual bool isType( const Uint32& type ) const; - UITab* add( const String& text, UINode* nodeOwned, Drawable* icon = NULL ); + UITab* add( const String& text, UINode* nodeOwned, DrawablePtr icon = {} ); UITabWidget* add( UITab* tab ); @@ -92,7 +92,7 @@ class EE_API UITabWidget : public UIWidget { void removeAllTabs( bool destroyOwnedNode = true, bool immediateClose = false ); - void insertTab( const String& text, UINode* nodeOwned, Drawable* icon, const Uint32& index ); + void insertTab( const String& text, UINode* nodeOwned, DrawablePtr icon, const Uint32& index ); void insertTab( UITab* tab, const Uint32& index ); @@ -265,7 +265,7 @@ class EE_API UITabWidget : public UIWidget { void onThemeLoaded(); - UITab* createTab( const String& text, UINode* nodeOwned, Drawable* icon ); + UITab* createTab( const String& text, UINode* nodeOwned, DrawablePtr icon ); void removeTab( const Uint32& index, bool destroyOwnedNode, bool destroyTab, bool immediateClose, diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index 4fa7c5e69..c2d4ada97 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -268,7 +268,7 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client { UIMenuItem* menuAdd( UIPopUpMenu* menu, const String& translateString, const std::string& icon, const std::string& cmd ); - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); }; }} // namespace EE::UI diff --git a/include/eepp/ui/uitextureregion.hpp b/include/eepp/ui/uitextureregion.hpp index 067fef7be..edc31c1da 100644 --- a/include/eepp/ui/uitextureregion.hpp +++ b/include/eepp/ui/uitextureregion.hpp @@ -51,7 +51,7 @@ class EE_API UITextureRegion : public UIWidget { virtual std::vector getPropertiesImplemented() const; protected: - UIScaleType mScaleType; + UIScaleType mScaleType{ UIScaleType::None }; Graphics::TextureRegion* mTextureRegion; Color mColor; RenderMode mRender; @@ -65,7 +65,9 @@ class EE_API UITextureRegion : public UIWidget { void autoAlign(); - void drawTextureRegion(); + void drawTextureRegion( const Sizef& destSize, const Vector2i& offset ); + + void autoAlign( const Sizef& drawableSize ); }; }} // namespace EE::UI diff --git a/src/eepp/graphics/arcdrawable.cpp b/src/eepp/graphics/arcdrawable.cpp index 5cbf6ace7..8577151ab 100644 --- a/src/eepp/graphics/arcdrawable.cpp +++ b/src/eepp/graphics/arcdrawable.cpp @@ -31,6 +31,18 @@ ArcDrawable::ArcDrawable( const Float& radius, Uint32 segmentsCount, const Float mSegmentsCount = mSegmentsCount > 360 ? 360 : mSegmentsCount; } +DrawablePtr ArcDrawable::createInstance() const { + auto instance = makeResource( mRadius, mSegmentsCount, mArcAngle, mArcStartAngle ); + instance->mOffset = mOffset; + instance->mFillMode = mFillMode; + instance->mBlendMode = mBlendMode; + instance->mLineWidth = mLineWidth; + instance->mSmooth = mSmooth; + instance->mColor = mColor; + instance->mPosition = mPosition; + return instance; +} + Sizef ArcDrawable::getSize() { return Sizef( mRadius * 2, mRadius * 2 ); } diff --git a/src/eepp/graphics/circledrawable.cpp b/src/eepp/graphics/circledrawable.cpp index f2d91b336..78033d7eb 100644 --- a/src/eepp/graphics/circledrawable.cpp +++ b/src/eepp/graphics/circledrawable.cpp @@ -15,4 +15,18 @@ CircleDrawable::CircleDrawable() : ArcDrawable( 0, 64 ) {} CircleDrawable::CircleDrawable( const Float& radius, const Uint32& segmentsCount ) : ArcDrawable( radius, segmentsCount ) {} +DrawablePtr CircleDrawable::createInstance() const { + auto instance = makeResource( mRadius, mSegmentsCount ); + instance->mArcAngle = mArcAngle; + instance->mArcStartAngle = mArcStartAngle; + instance->mOffset = mOffset; + instance->mFillMode = mFillMode; + instance->mBlendMode = mBlendMode; + instance->mLineWidth = mLineWidth; + instance->mSmooth = mSmooth; + instance->mColor = mColor; + instance->mPosition = mPosition; + return instance; +} + }} // namespace EE::Graphics diff --git a/src/eepp/graphics/convexshapedrawable.cpp b/src/eepp/graphics/convexshapedrawable.cpp index a6ee38dd7..5bd602ab7 100644 --- a/src/eepp/graphics/convexshapedrawable.cpp +++ b/src/eepp/graphics/convexshapedrawable.cpp @@ -9,6 +9,19 @@ ConvexShapeDrawable* ConvexShapeDrawable::New() { ConvexShapeDrawable::ConvexShapeDrawable() : PrimitiveDrawable( Drawable::CONVEXSHAPE ) {} +DrawablePtr ConvexShapeDrawable::createInstance() const { + auto instance = makeResource(); + instance->mPolygon = mPolygon; + instance->mIndexColor = mIndexColor; + instance->mFillMode = mFillMode; + instance->mBlendMode = mBlendMode; + instance->mLineWidth = mLineWidth; + instance->mSmooth = mSmooth; + instance->mColor = mColor; + instance->mPosition = mPosition; + return instance; +} + Sizef ConvexShapeDrawable::getSize() { return mPolygon.getBounds().getSize(); } diff --git a/src/eepp/graphics/drawable.cpp b/src/eepp/graphics/drawable.cpp index 5bce0691b..5f1ae516f 100644 --- a/src/eepp/graphics/drawable.cpp +++ b/src/eepp/graphics/drawable.cpp @@ -9,6 +9,10 @@ Drawable::Drawable( Type drawableType ) : Drawable::~Drawable() {} +DrawablePtr Drawable::createInstance() const { + return {}; +} + void Drawable::setAlpha( Uint8 alpha ) { if ( mColor.a != alpha ) { mColor.a = alpha; diff --git a/src/eepp/graphics/drawablegroup.cpp b/src/eepp/graphics/drawablegroup.cpp index 5148436f0..6e0bf1e1b 100644 --- a/src/eepp/graphics/drawablegroup.cpp +++ b/src/eepp/graphics/drawablegroup.cpp @@ -4,36 +4,47 @@ namespace EE { namespace Graphics { -DrawableGroup* DrawableGroup::New() { - return eeNew( DrawableGroup, () ); +ResourcePtr DrawableGroup::New() { + return makeResource(); } DrawableGroup::DrawableGroup() : - Drawable( Drawable::GROUP ), - mNeedsUpdate( true ), - mClipEnabled( false ), - mDrawableOwner( true ) {} + Drawable( Drawable::GROUP ), mNeedsUpdate( true ), mClipEnabled( false ) {} DrawableGroup::~DrawableGroup() { clearDrawables(); } -void DrawableGroup::clearDrawables() { - if ( mDrawableOwner ) { - for ( std::size_t i = 0; i < mGroup.size(); i++ ) { - Drawable* drawable = mGroup[i]; - eeSAFE_DELETE( drawable ); - } +DrawablePtr DrawableGroup::createInstance() const { + auto instance = makeResource(); + instance->mPosition = mPosition; + instance->mColor = mColor; + instance->mSize = mSize; + instance->mClipEnabled = mClipEnabled; + + for ( const auto& drawable : mGroup ) { + if ( !drawable ) + continue; + DrawablePtr drawableInstance = drawable->createInstance(); + if ( !drawableInstance ) + return {}; + instance->addDrawable( std::move( drawableInstance ) ); } + return instance; +} + +void DrawableGroup::clearDrawables() { mGroup.clear(); mPos.clear(); } -Drawable* DrawableGroup::addDrawable( Drawable* drawable ) { - mGroup.push_back( drawable ); +DrawablePtr DrawableGroup::addDrawable( DrawablePtr drawable ) { + if ( !drawable ) + return {}; mPos.push_back( drawable->getPosition() ); - return drawable; + mGroup.push_back( std::move( drawable ) ); + return mGroup.back(); } Uint32 DrawableGroup::getDrawableCount() const { @@ -48,15 +59,7 @@ void DrawableGroup::setClipEnabled( bool clipEnabled ) { mClipEnabled = clipEnabled; } -bool DrawableGroup::isDrawableOwner() const { - return mDrawableOwner; -} - -void DrawableGroup::setDrawableOwner( bool drawableOwner ) { - mDrawableOwner = drawableOwner; -} - -std::vector& DrawableGroup::getGroup() { +std::vector& DrawableGroup::getGroup() { return mGroup; } @@ -89,7 +92,7 @@ void DrawableGroup::draw( const Vector2f& position, const Sizef& size ) { GLi->getClippingMask()->clipPlaneEnable( mPosition.x, mPosition.y, mSize.x, mSize.y ); for ( std::size_t i = 0; i < mGroup.size(); i++ ) { - Drawable* drawable = mGroup[i]; + Drawable* drawable = mGroup[i].get(); drawable->draw(); } @@ -111,7 +114,7 @@ void DrawableGroup::onPositionChange() { void DrawableGroup::onAlphaChange() { for ( std::size_t i = 0; i < mGroup.size(); i++ ) { - Drawable* drawable = mGroup[i]; + Drawable* drawable = mGroup[i].get(); drawable->setAlpha( getAlpha() ); } } @@ -120,7 +123,7 @@ void DrawableGroup::update() { Sizef nSize( mSize ); for ( std::size_t i = 0; i < mGroup.size(); i++ ) { - Drawable* drawable = mGroup[i]; + Drawable* drawable = mGroup[i].get(); Vector2f pos( mPosition + mPos[i] ); Sizef s( mPos[i] + drawable->getSize() ); diff --git a/src/eepp/graphics/drawableresource.cpp b/src/eepp/graphics/drawableresource.cpp index cff407930..6d433a12d 100644 --- a/src/eepp/graphics/drawableresource.cpp +++ b/src/eepp/graphics/drawableresource.cpp @@ -2,19 +2,59 @@ namespace EE { namespace Graphics { +DrawableResourceConnection::DrawableResourceConnection( + std::weak_ptr state, Uint32 id ) : + mState( std::move( state ) ), mId( id ) {} + +DrawableResourceConnection::~DrawableResourceConnection() { + disconnect(); +} + +DrawableResourceConnection::DrawableResourceConnection( + DrawableResourceConnection&& other ) noexcept : + mState( std::move( other.mState ) ), mId( other.mId ) { + other.mId = 0; +} + +DrawableResourceConnection& +DrawableResourceConnection::operator=( DrawableResourceConnection&& other ) noexcept { + if ( this != &other ) { + disconnect(); + mState = std::move( other.mState ); + mId = other.mId; + other.mId = 0; + } + return *this; +} + +void DrawableResourceConnection::disconnect() { + if ( mId != 0 ) { + if ( auto state = mState.lock() ) + state->callbacks.erase( mId ); + } + mState.reset(); + mId = 0; +} + +DrawableResourceConnection::operator bool() const { + return mId != 0 && !mState.expired(); +} + DrawableResource::DrawableResource( Type drawableType ) : - Drawable( drawableType ), mId( 0 ), mNumCallBacks( 0 ) { + Drawable( drawableType ), + mId( 0 ), + mCallbackState( std::make_shared() ) { createUnnamed(); } DrawableResource::DrawableResource( Type drawableType, const std::string& name ) : - Drawable( drawableType ), mId( 0 ), mNumCallBacks( 0 ) { + Drawable( drawableType ), + mId( 0 ), + mCallbackState( std::make_shared() ) { setName( name ); } -DrawableResource::~DrawableResource() { - sendEvent( Event::Unload ); -} +DrawableResource::~DrawableResource() {} const String::HashType& DrawableResource::getId() const { return mId; @@ -39,23 +79,23 @@ bool DrawableResource::isDrawableResource() const { } void DrawableResource::onResourceChange() { - sendEvent( Event::Change ); + sendResourceChanged(); } -void DrawableResource::sendEvent( const Event& event ) { - for ( const auto& cb : mCallbacks ) { - cb.second( cb.first, event, this ); - } +void DrawableResource::sendResourceChanged() { + std::vector callbacks; + callbacks.reserve( mCallbackState->callbacks.size() ); + for ( const auto& callback : mCallbackState->callbacks ) + callbacks.emplace_back( callback.second ); + for ( const auto& callback : callbacks ) + callback( *this ); } -Uint32 DrawableResource::pushResourceChangeCallback( const OnResourceChangeCallback& cb ) { - mNumCallBacks++; - mCallbacks[mNumCallBacks] = cb; - return mNumCallBacks; -} - -bool DrawableResource::popResourceChangeCallback( const Uint32& callbackId ) { - return mCallbacks.erase( callbackId ) > 0; +DrawableResourceConnection +DrawableResource::connectResourceChange( OnResourceChangeCallback callback ) { + Uint32 id = ++mCallbackState->nextId; + mCallbackState->callbacks.emplace( id, std::move( callback ) ); + return DrawableResourceConnection( mCallbackState, id ); } }} // namespace EE::Graphics diff --git a/src/eepp/graphics/drawablesearcher.cpp b/src/eepp/graphics/drawablesearcher.cpp index c707bd42f..74986327a 100644 --- a/src/eepp/graphics/drawablesearcher.cpp +++ b/src/eepp/graphics/drawablesearcher.cpp @@ -19,42 +19,42 @@ namespace EE { namespace Graphics { bool DrawableSearcher::sPrintWarnings = false; -static Drawable* getSprite( const std::string& sprite ) { +static DrawablePtr getSprite( const std::string& sprite ) { std::vector tTextureRegionVec = TextureAtlasManager::instance()->getTextureRegionsByPattern( sprite ); if ( tTextureRegionVec.size() ) { - Sprite* tSprite = Graphics::Sprite::New(); + SpritePtr tSprite = Sprite::New(); tSprite->createAnimation(); tSprite->addFrames( tTextureRegionVec ); return tSprite; } - return NULL; + return {}; } -static Drawable* searchByNameInternal( const std::string& name, ResourceScope& resourceScope ) { +static DrawablePtr searchByNameInternal( const std::string& name, ResourceScope& resourceScope ) { String::HashType id = String::hash( name ); - Drawable* drawable = TextureAtlasManager::instance()->getTextureRegionById( id ); + Drawable* source = TextureAtlasManager::instance()->getTextureRegionById( id ); - if ( NULL == drawable ) { - drawable = NinePatchManager::instance()->getById( id ); + if ( NULL == source ) { + source = NinePatchManager::instance()->getById( id ); } - if ( NULL == drawable ) { - drawable = resourceScope.findTexture( name ).get(); + if ( source ) { + return source->createInstance(); } - return drawable; + TexturePtr texture = resourceScope.findTexture( name ); + return texture ? texture->createInstance() : DrawablePtr{}; } -static Drawable* parseDataURI( const std::string& name, ResourceScope& scope ) { +static DrawablePtr parseDataURI( const std::string& name, ResourceScope& scope ) { auto hash = MD5::fromString( name ).toHexString(); TexturePtr texture = scope.findTexture( hash ); - Drawable* drawable = texture.get(); std::string::size_type formatAndEncSep; - if ( nullptr == drawable && + if ( !texture && ( formatAndEncSep = name.find_first_of( ',' ) ) != std::string::npos ) { std::string decodingType = "urldecode"; std::string mediaType = name.substr( 0, formatAndEncSep ); @@ -103,16 +103,16 @@ static Drawable* parseDataURI( const std::string& name, ResourceScope& scope ) { if ( tex ) { tex->setName( hash ); scope.publishLocal( hash, tex ); - drawable = tex.get(); + texture = std::move( tex ); } } - return drawable; + return texture ? texture->createInstance() : DrawablePtr{}; } -Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSearchSprite, +DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstSearchSprite, Network::URI referer, ResourceScope* requestedResourceScope ) { - Drawable* drawable = NULL; + DrawablePtr drawable; if ( name.size() ) { ResourceScope& resourceScope = @@ -126,7 +126,7 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea drawable = getSprite( name ); } - if ( NULL != drawable ) { + if ( drawable ) { return drawable; } @@ -135,18 +135,22 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea if ( name[0] == '@' ) { if ( String::startsWith( name, "@textureregion/" ) ) { - drawable = - TextureAtlasManager::instance()->getTextureRegionByName( name.substr( 12 ) ); + if ( Drawable* source = + TextureAtlasManager::instance()->getTextureRegionByName( name.substr( 12 ) ) ) + drawable = source->createInstance(); } else if ( String::startsWith( name, "@image/" ) ) { - drawable = resourceScope.findTexture( name.substr( 7 ) ).get(); + TexturePtr texture = resourceScope.findTexture( name.substr( 7 ) ); + drawable = texture ? texture->createInstance() : DrawablePtr{}; } else if ( String::startsWith( name, "@texture/" ) ) { - drawable = resourceScope.findTexture( name.substr( 9 ) ).get(); + TexturePtr texture = resourceScope.findTexture( name.substr( 9 ) ); + drawable = texture ? texture->createInstance() : DrawablePtr{}; } else if ( String::startsWith( name, "@sprite/" ) && !searchedSprite ) { drawable = getSprite( name.substr( 8 ) ); } else if ( String::startsWith( name, "@drawable/" ) ) { drawable = searchByNameInternal( name.substr( 10 ), resourceScope ); } else if ( String::startsWith( name, "@9p/" ) ) { - drawable = NinePatchManager::instance()->getByName( name.substr( 4 ) ); + if ( Drawable* source = NinePatchManager::instance()->getByName( name.substr( 4 ) ) ) + drawable = source->createInstance(); } else { drawable = searchByNameInternal( name, resourceScope ); } @@ -162,16 +166,17 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea FileSystem::filePathRemoveProcessPath( filePath ); - drawable = resourceScope.findTexture( filePath ).get(); + TexturePtr texture = resourceScope.findTexture( filePath ); - if ( NULL == drawable ) { + if ( !texture ) { TexturePtr tex = TextureFactory::instance()->loadFromFile( filePath ); if ( tex ) { resourceScope.publishLocal( filePath, tex ); - drawable = tex.get(); + texture = std::move( tex ); } } + drawable = texture ? texture->createInstance() : DrawablePtr{}; } else if ( String::startsWith( name, "http://" ) || String::startsWith( name, "https://" ) ) { TexturePtr texture = resourceScope.findTexture( name ); @@ -204,7 +209,7 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea URI( name ), Seconds( 5 ), {}, headers ); } - drawable = texture.get(); + drawable = texture ? texture->createInstance() : DrawablePtr{}; } else if ( String::startsWith( name, "data:image/" ) ) { drawable = parseDataURI( name, resourceScope ); } else { @@ -212,16 +217,17 @@ Drawable* DrawableSearcher::searchByName( const std::string& name, bool firstSea } } - if ( NULL == drawable && sPrintWarnings ) + if ( !drawable && sPrintWarnings ) Log::warning( "DrawableSearcher::searchByName: \"%s\" not found", name.c_str() ); return drawable; } -Drawable* DrawableSearcher::searchById( const Uint32& id ) { - Drawable* drawable = TextureAtlasManager::instance()->getTextureRegionById( id ); +DrawablePtr DrawableSearcher::searchById( const Uint32& id ) { + Drawable* source = TextureAtlasManager::instance()->getTextureRegionById( id ); + DrawablePtr drawable = source ? source->createInstance() : DrawablePtr{}; - if ( NULL == drawable && sPrintWarnings ) + if ( !drawable && sPrintWarnings ) Log::warning( "DrawableSearcher::searchById: \"%ld\" not found", id ); return drawable; diff --git a/src/eepp/graphics/glyphdrawable.cpp b/src/eepp/graphics/glyphdrawable.cpp index f1d189749..0d26c68f5 100644 --- a/src/eepp/graphics/glyphdrawable.cpp +++ b/src/eepp/graphics/glyphdrawable.cpp @@ -80,6 +80,18 @@ bool GlyphDrawable::isStateful() { return false; } +DrawablePtr GlyphDrawable::createInstance() const { + auto instance = makeResource( mTexture, mSrcRect.asInt(), mDestSize, mName ); + instance->setPixelDensity( mPixelDensity ); + instance->setGlyphOffset( mGlyphOffset ); + instance->setDrawMode( mDrawMode ); + instance->setIsItalic( mIsItalic ); + instance->setAdvance( mAdvance ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; +} + const TexturePtr& GlyphDrawable::getTexture() const { return mTexture; } diff --git a/src/eepp/graphics/ninepatch.cpp b/src/eepp/graphics/ninepatch.cpp index 6b1e511b4..05c3d5e63 100644 --- a/src/eepp/graphics/ninepatch.cpp +++ b/src/eepp/graphics/ninepatch.cpp @@ -25,9 +25,6 @@ NinePatch::NinePatch( TexturePtr tex, int left, int top, int right, int bottom, DrawableResource( Drawable::NINEPATCH, name ), mRect( left, top, right, bottom ), mPixelDensity( pixelDensity ) { - for ( Int32 i = 0; i < SideCount; i++ ) - mDrawable[i] = NULL; - if ( NULL != tex ) { mSize = tex->getPixelsSize(); @@ -40,9 +37,6 @@ NinePatch::NinePatch( TextureRegion* textureRegion, int left, int top, int right DrawableResource( Drawable::NINEPATCH, name ), mRect( left, top, right, bottom ), mPixelDensity( 1 ) { - for ( Int32 i = 0; i < SideCount; i++ ) - mDrawable[i] = NULL; - if ( NULL != textureRegion && textureRegion->getTexture() != NULL ) { mPixelDensity = textureRegion->getPixelDensity(); @@ -53,7 +47,7 @@ NinePatch::NinePatch( TextureRegion* textureRegion, int left, int top, int right createFromTexture( textureRegion->getTexture(), left, top, right, bottom ); for ( int i = 0; i < SideCount; i++ ) { - TextureRegion* side = static_cast( mDrawable[i] ); + TextureRegion* side = mDrawable[i].get(); side->setPixelDensity( textureRegion->getPixelDensity() ); @@ -69,9 +63,27 @@ NinePatch::NinePatch( TextureRegion* textureRegion, int left, int top, int right } } -NinePatch::~NinePatch() { - for ( Int32 i = 0; i < SideCount; i++ ) - eeSAFE_DELETE( mDrawable[i] ); +NinePatch::~NinePatch() {} + +DrawablePtr NinePatch::createInstance() const { + if ( !mDrawable[Center] ) + return {}; + auto instance = makeResource( mDrawable[Center]->getTexture(), mRect.Left, mRect.Top, + mRect.Right, mRect.Bottom, mPixelDensity, mName ); + for ( int i = 0; i < SideCount; ++i ) { + instance->mDrawable[i] = + mDrawable[i] ? std::static_pointer_cast( mDrawable[i]->createInstance() ) + : TextureRegionPtr{}; + if ( mDrawable[i] && !instance->mDrawable[i] ) + return {}; + } + instance->mRect = mRect; + instance->mRectf = mRectf; + instance->mSize = mSize; + instance->mDestSize = mDestSize; + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; } Sizef NinePatch::getSize() { @@ -115,7 +127,7 @@ void NinePatch::draw( const Vector2f& position, const Sizef& size ) { TextureRegion* NinePatch::getTextureRegion( const int& side ) { if ( side < SideCount ) - return mDrawable[side]; + return mDrawable[side].get(); return NULL; } @@ -123,24 +135,24 @@ void NinePatch::createFromTexture( const TexturePtr& tex, int left, int top, int int bottom ) { Rect r; r = Rect( 0, top, left, mSize.getHeight() - bottom ); - mDrawable[Left] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[Left] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( mSize.getWidth() - right, top, mSize.getWidth(), mSize.getHeight() - bottom ); - mDrawable[Right] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[Right] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( left, mSize.getHeight() - bottom, mSize.getWidth() - right, mSize.getHeight() ); - mDrawable[Down] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[Down] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( left, 0, mSize.getWidth() - right, top ); - mDrawable[Up] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[Up] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( 0, 0, left, top ); - mDrawable[UpLeft] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[UpLeft] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( mSize.getWidth() - right, 0, mSize.getWidth(), top ); - mDrawable[UpRight] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[UpRight] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( 0, mSize.getHeight() - bottom, left, mSize.getHeight() ); - mDrawable[DownLeft] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[DownLeft] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( mSize.getWidth() - right, mSize.getHeight() - bottom, mSize.getWidth(), mSize.getHeight() ); - mDrawable[DownRight] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[DownRight] = makeResource( tex, r, r.getSize().asFloat() ); r = Rect( left, top, mSize.getWidth() - right, mSize.getHeight() - bottom ); - mDrawable[Center] = TextureRegion::New( tex, r, r.getSize().asFloat() ); + mDrawable[Center] = makeResource( tex, r, r.getSize().asFloat() ); mRect = Rect( left, top, right, bottom ); diff --git a/src/eepp/graphics/rectangledrawable.cpp b/src/eepp/graphics/rectangledrawable.cpp index 8a2e0e5f9..fc48542e7 100644 --- a/src/eepp/graphics/rectangledrawable.cpp +++ b/src/eepp/graphics/rectangledrawable.cpp @@ -29,6 +29,21 @@ RectangleDrawable::RectangleDrawable( const Vector2f& position, const Sizef& siz mPosition = position; } +DrawablePtr RectangleDrawable::createInstance() const { + auto instance = makeResource( mPosition, mSize ); + instance->mRotation = mRotation; + instance->mScale = mScale; + instance->mCorners = mCorners; + instance->mRectColors = mRectColors; + instance->mUsingRectColors = mUsingRectColors; + instance->mFillMode = mFillMode; + instance->mBlendMode = mBlendMode; + instance->mLineWidth = mLineWidth; + instance->mSmooth = mSmooth; + instance->mColor = mColor; + return instance; +} + Sizef RectangleDrawable::getSize() { return mSize; } diff --git a/src/eepp/graphics/scrollparallax.cpp b/src/eepp/graphics/scrollparallax.cpp index 16ebc652e..fd633b2b3 100644 --- a/src/eepp/graphics/scrollparallax.cpp +++ b/src/eepp/graphics/scrollparallax.cpp @@ -15,11 +15,13 @@ ScrollParallax::ScrollParallax( TextureRegion* textureRegion, const Vector2f& Po } TextureRegion* ScrollParallax::getTextureRegion() const { - return mTextureRegion; + return mTextureRegion.get(); } void ScrollParallax::setTextureRegion( TextureRegion* textureRegion ) { - mTextureRegion = textureRegion; + mTextureRegion = + textureRegion ? std::static_pointer_cast( textureRegion->createInstance() ) + : TextureRegionPtr{}; setTextureRegion(); } @@ -43,7 +45,9 @@ void ScrollParallax::setAABB() { bool ScrollParallax::create( TextureRegion* textureRegion, const Vector2f& Position, const Sizef& Size, const Vector2f& Speed, const Color& Color, const BlendMode& Blend ) { - mTextureRegion = textureRegion; + mTextureRegion = + textureRegion ? std::static_pointer_cast( textureRegion->createInstance() ) + : TextureRegionPtr{}; mPos = Position; mSize = Size; mInitPos = mPos; @@ -97,8 +101,8 @@ void ScrollParallax::draw() { Vector2f Pos = mPos; - Pos.x = ( Float )(Int32)Pos.x; - Pos.y = ( Float )(Int32)Pos.y; + Pos.x = (Float)(Int32)Pos.x; + Pos.y = (Float)(Int32)Pos.y; if ( mSpeed.x > 0.f ) Pos.x -= mRealSize.getWidth(); @@ -111,53 +115,52 @@ void ScrollParallax::draw() { for ( Int32 y = -1; y < mTiles.y; y++ ) { for ( Int32 x = -1; x < mTiles.x; x++ ) { - Rect Rect = mRect; + Rect rect = mRect; Rectf AABB( Pos.x, Pos.y, Pos.x + mRealSize.getWidth(), Pos.y + mRealSize.getHeight() ); if ( AABB.intersect( mAABB ) ) { if ( Pos.x < mAABB.Left ) { - Rect.Left += ( Int32 )( ( mAABB.Left - Pos.x ) * pd ); + rect.Left += (Int32)( ( mAABB.Left - Pos.x ) * pd ); AABB.Left = mAABB.Left; } if ( Pos.x + mRealSize.getWidth() > mAABB.Right ) { - Rect.Right -= - ( Int32 )( ( ( Pos.x + mRealSize.getWidth() ) - mAABB.Right ) * pd ); + rect.Right -= + (Int32)( ( ( Pos.x + mRealSize.getWidth() ) - mAABB.Right ) * pd ); } if ( Pos.y < mAABB.Top ) { - Rect.Top += ( Int32 )( ( mAABB.Top - Pos.y ) * pd ); + rect.Top += (Int32)( ( mAABB.Top - Pos.y ) * pd ); AABB.Top = mAABB.Top; } if ( Pos.y + mRealSize.getHeight() > mAABB.Bottom ) { - Rect.Bottom -= - ( Int32 )( ( ( Pos.y + mRealSize.getHeight() ) - mAABB.Bottom ) * pd ); + rect.Bottom -= + (Int32)( ( ( Pos.y + mRealSize.getHeight() ) - mAABB.Bottom ) * pd ); } - mTextureRegion->setSrcRect( Rect ); - mTextureRegion->setDestSize( - Vector2f( Rect.getSize().x * ps, Rect.getSize().y * ps ) ); - - if ( !( Rect.Right == 0 || Rect.Bottom == 0 ) ) - mTextureRegion->draw( AABB.Left, AABB.Top, mColor, 0.f, Vector2f::One, - mBlend ); + const TexturePtr& texture = mTextureRegion->getTexture(); + if ( texture && !( rect.Right == 0 || rect.Bottom == 0 ) ) { + const Vector2i& offset = mTextureRegion->getOffset(); + texture->drawEx( AABB.Left + offset.x, AABB.Top + offset.y, + rect.getSize().x * ps, rect.getSize().y * ps, 0.f, + Vector2f::One, mColor, mColor, mColor, mColor, mBlend, + RENDER_NORMAL, OriginPoint( OriginPoint::OriginCenter ), + rect ); + } } Pos.x += mRealSize.getWidth(); } - Pos.x = ( Float )(Int32)mPos.x; + Pos.x = (Float)(Int32)mPos.x; if ( mSpeed.x > 0.f ) Pos.x -= mRealSize.getWidth(); Pos.y += mRealSize.getHeight(); } - - mTextureRegion->setSrcRect( mRect ); - mTextureRegion->resetDestSize(); } } diff --git a/src/eepp/graphics/sprite.cpp b/src/eepp/graphics/sprite.cpp index 9517f2ad5..42bc69a60 100644 --- a/src/eepp/graphics/sprite.cpp +++ b/src/eepp/graphics/sprite.cpp @@ -10,38 +10,41 @@ using namespace EE::Window; namespace EE { namespace Graphics { -Sprite* Sprite::New() { - return eeNew( Sprite, () ); +SpritePtr Sprite::New() { + return makeResource(); } -Sprite* Sprite::New( const std::string& name, const std::string& extension, - TextureAtlas* SearchInTextureAtlas ) { - return eeNew( Sprite, ( name, extension, SearchInTextureAtlas ) ); +SpritePtr Sprite::New( const std::string& name, const std::string& extension, + TextureAtlas* SearchInTextureAtlas ) { + return makeResource( name, extension, SearchInTextureAtlas ); } -Sprite* Sprite::New( TextureRegion* TextureRegion ) { - return eeNew( Sprite, ( TextureRegion ) ); +SpritePtr Sprite::New( TextureRegion* TextureRegion ) { + return makeResource( TextureRegion ); } -Sprite* Sprite::New( ResourceId textureId, const Sizef& DestSize, const Vector2i& offset, - const Rect& TexSector ) { - return eeNew( Sprite, ( textureId, DestSize, offset, TexSector ) ); +SpritePtr Sprite::New( ResourceId textureId, const Sizef& DestSize, const Vector2i& offset, + const Rect& TexSector ) { + return makeResource( textureId, DestSize, offset, TexSector ); } -Sprite* Sprite::fromGif( IOStream& stream ) { +SpritePtr Sprite::fromGif( IOStream& stream ) { auto [gif, delay] = Texture::loadGif( stream ); - Sprite* sprite = Sprite::New(); + SpritePtr sprite = Sprite::New(); for ( const auto& texture : gif ) sprite->addFrame( texture ); sprite->setAnimationSpeed( 1000.f / (float)delay ); - sprite->setAsTextureRegionOwner( true ); return sprite; } Sprite::Sprite() : Drawable( Drawable::SPRITE ) {} +Sprite::Sprite( const Sprite& other ) : Drawable( Drawable::SPRITE ) { + *this = other; +} + Sprite::Sprite( const std::string& name, const std::string& extension, TextureAtlas* SearchInTextureAtlas ) : Drawable( Drawable::SPRITE ) { @@ -59,16 +62,30 @@ Sprite::Sprite( ResourceId textureId, const Sizef& DestSize, const Vector2i& Off } Sprite::~Sprite() { - cleanUpResources(); eeSAFE_DELETE_ARRAY( mVertexColors ); } Sprite& Sprite::operator=( const Sprite& Other ) { + if ( this == &Other ) + return *this; + mDrawableType = Other.mDrawableType; - mFrames = Other.mFrames; + mFrames.clear(); + mFrames.reserve( Other.mFrames.size() ); + for ( const Frame& otherFrame : Other.mFrames ) { + Frame frame; + frame.Spr.reserve( otherFrame.Spr.size() ); + for ( const TextureRegionPtr& region : otherFrame.Spr ) { + frame.Spr.emplace_back( + region ? std::static_pointer_cast( region->createInstance() ) + : nullptr ); + } + mFrames.emplace_back( std::move( frame ) ); + } mFlags = Other.mFlags; mColor = Other.mColor; mPosition = Other.mPosition; + mOrigin = Other.mOrigin; mRotation = Other.mRotation; mScale = Other.mScale; mAnimSpeed = Other.mAnimSpeed; @@ -80,8 +97,10 @@ Sprite& Sprite::operator=( const Sprite& Other ) { mCurrentSubFrame = Other.mCurrentSubFrame; mSubFrames = Other.mSubFrames; mAnimTo = Other.mAnimTo; - mCallbacks = Other.mCallbacks; - mNumCallBacks = Other.mNumCallBacks; + mCallbacks.clear(); + mNumCallBacks = 0; + + eeSAFE_DELETE_ARRAY( mVertexColors ); if ( NULL != Other.mVertexColors ) { mVertexColors = eeNewArray( Color, 4 ); @@ -96,39 +115,12 @@ Sprite& Sprite::operator=( const Sprite& Other ) { return *this; } -Sprite Sprite::clone() { - Sprite Spr; +SpritePtr Sprite::clone() const { + return makeResource( *this ); +} - Spr.mDrawableType = mDrawableType; - Spr.mColor = mColor; - Spr.mFrames = mFrames; - Spr.mFlags = mFlags; - Spr.mPosition = mPosition; - Spr.mRotation = mRotation; - Spr.mScale = mScale; - Spr.mAnimSpeed = mAnimSpeed; - Spr.mRepetitions = mRepetitions; - Spr.mBlend = mBlend; - Spr.mEffect = mEffect; - Spr.mCurrentFrame = mCurrentFrame; - Spr.mfCurrentFrame = mfCurrentFrame; - Spr.mCurrentSubFrame = mCurrentSubFrame; - Spr.mSubFrames = mSubFrames; - Spr.mAnimTo = mAnimTo; - Spr.mCallbacks = mCallbacks; - Spr.mNumCallBacks = mNumCallBacks; - - if ( NULL != mVertexColors ) { - Spr.mVertexColors = eeNewArray( Color, 4 ); - Spr.mVertexColors[0] = mVertexColors[0]; - Spr.mVertexColors[1] = mVertexColors[1]; - Spr.mVertexColors[2] = mVertexColors[2]; - Spr.mVertexColors[3] = mVertexColors[3]; - } else { - Spr.mVertexColors = NULL; - } - - return Spr; +DrawablePtr Sprite::createInstance() const { + return clone(); } void Sprite::clearFrame() { @@ -138,21 +130,7 @@ void Sprite::clearFrame() { mFrames.clear(); } -void Sprite::cleanUpResources() { - if ( isTextureRegionOwner() ) { - size_t frames = getNumFrames(); - - for ( size_t i = 0; i < frames; i++ ) { - for ( size_t f = 0; f < mFrames[i].Spr.size(); f++ ) { - TextureRegion* region = mFrames[i].Spr[f]; - GlobalTextureAtlas::instance()->remove( region ); - } - } - } -} - void Sprite::reset() { - cleanUpResources(); clearFrame(); mFlags = SPRITE_FLAG_AUTO_ANIM | SPRITE_FLAG_EVENTS_ENABLED; @@ -402,6 +380,14 @@ bool Sprite::addFramesByPattern( const std::string& name, const std::string& ext bool Sprite::addSubFrame( TextureRegion* TextureRegion, const unsigned int& NumFrame, const unsigned int& NumSubFrame ) { + return addSubFrame( TextureRegion ? std::static_pointer_cast( + TextureRegion->createInstance() ) + : TextureRegionPtr{}, + NumFrame, NumSubFrame ); +} + +bool Sprite::addSubFrame( TextureRegionPtr TextureRegion, const unsigned int& NumFrame, + const unsigned int& NumSubFrame ) { unsigned int NF, NSF; if ( NumFrame >= mFrames.size() ) @@ -458,7 +444,7 @@ bool Sprite::addSubFrame( TexturePtr tex, const unsigned int& NumFrame, const unsigned int& NumSubFrame, const Sizef& DestSize, const Vector2i& Offset, const Rect& TexSector ) { if ( tex ) { - TextureRegion* region = GlobalTextureAtlas::instance()->add( TextureRegion::New() ); + TextureRegionPtr region = makeResource(); region->setTexture( std::move( tex ) ); if ( TexSector.Right > 0 && TexSector.Bottom > 0 ) @@ -475,7 +461,7 @@ bool Sprite::addSubFrame( TexturePtr tex, const unsigned int& NumFrame, region->setDestSize( destSize ); region->setOffset( Offset ); - return addSubFrame( region, NumFrame, NumSubFrame ); + return addSubFrame( std::move( region ), NumFrame, NumSubFrame ); } return false; } @@ -732,21 +718,21 @@ bool Sprite::getAutoAnimate() const { TextureRegion* Sprite::getCurrentTextureRegion() { if ( mFrames.size() ) - return mFrames[mCurrentFrame].Spr[mCurrentSubFrame]; + return mFrames[mCurrentFrame].Spr[mCurrentSubFrame].get(); return NULL; } TextureRegion* Sprite::getTextureRegion( const unsigned int& frame ) { if ( frame < mFrames.size() ) - return mFrames[frame].Spr[mCurrentSubFrame]; + return mFrames[frame].Spr[mCurrentSubFrame].get(); return NULL; } TextureRegion* Sprite::getTextureRegion( const unsigned int& frame, const unsigned int& SubFrame ) { if ( frame < mFrames.size() ) - return mFrames[frame].Spr[SubFrame]; + return mFrames[frame].Spr[SubFrame].get(); return NULL; } @@ -897,18 +883,6 @@ void Sprite::fireEvent( const Uint32& Event ) { } } -Sprite& Sprite::setAsTextureRegionOwner( bool set ) { - if ( set ) - mFlags |= SPRITE_FLAG_TEXTURE_REGION_OWNER; - else - mFlags &= ~SPRITE_FLAG_TEXTURE_REGION_OWNER; - return *this; -} - -bool Sprite::isTextureRegionOwner() const { - return mFlags & SPRITE_FLAG_TEXTURE_REGION_OWNER; -} - void Sprite::setOrigin( const OriginPoint& origin ) { mOrigin = origin; } diff --git a/src/eepp/graphics/statelistdrawable.cpp b/src/eepp/graphics/statelistdrawable.cpp index 4010bdcc2..18ad874df 100644 --- a/src/eepp/graphics/statelistdrawable.cpp +++ b/src/eepp/graphics/statelistdrawable.cpp @@ -13,27 +13,29 @@ StateListDrawable::StateListDrawable( Type type, const std::string& name ) : StateListDrawable::StateListDrawable( const std::string& name ) : StatefulDrawable( STATELIST, name ), mCurrentState( 0 ), mCurrentDrawable( NULL ) {} -StateListDrawable::~StateListDrawable() { - clearDrawables(); -} +StateListDrawable::~StateListDrawable() {} void StateListDrawable::clearDrawables() { - std::vector removeOwnershipState; + mCurrentDrawable = nullptr; + mDrawables.clear(); +} - for ( auto it = mDrawables.begin(); it != mDrawables.end(); ++it ) { - Drawable* drawable = it->second; - - if ( mDrawablesOwnership[drawable] ) { - removeOwnershipState.push_back( drawable ); - eeSAFE_DELETE( drawable ); +DrawablePtr StateListDrawable::createInstance() const { + auto instance = ResourcePtr( eeNew( StateListDrawable, ( mName ) ), + ResourceDeleter() ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + for ( const auto& state : mDrawables ) { + if ( state.second ) { + DrawablePtr drawable = state.second->createInstance(); + if ( !drawable ) + return {}; + instance->setStateDrawable( state.first, std::move( drawable ) ); } } - - for ( auto& removeOwnership : removeOwnershipState ) { - mDrawablesOwnership.erase( removeOwnership ); - } - - mDrawables.clear(); + instance->mDrawableColors = mDrawableColors; + instance->setState( mCurrentState ); + return instance; } Sizef StateListDrawable::getSize() { @@ -94,17 +96,11 @@ bool StateListDrawable::isStateful() { } StatefulDrawable* StateListDrawable::setState( Uint32 state ) { - if ( state != mCurrentState || mCurrentDrawable == NULL || - mCurrentDrawable != mDrawables[mCurrentState] ) { + auto current = mDrawables.find( state ); + Drawable* stateDrawable = current != mDrawables.end() ? current->second.get() : nullptr; + if ( state != mCurrentState || mCurrentDrawable != stateDrawable ) { mCurrentState = state; - - auto it = mDrawables.find( state ); - - if ( it != mDrawables.end() ) { - mCurrentDrawable = it->second; - } else { - mCurrentDrawable = NULL; - } + mCurrentDrawable = stateDrawable; } return this; @@ -116,28 +112,21 @@ const Uint32& StateListDrawable::getState() const { Drawable* StateListDrawable::getStateDrawable( const Uint32& state ) { if ( hasDrawableState( state ) ) - return mDrawables[state]; + return mDrawables[state].get(); return NULL; } -StateListDrawable* StateListDrawable::setStateDrawable( const Uint32& state, Drawable* drawable, - bool ownIt ) { +StateListDrawable* StateListDrawable::setStateDrawable( const Uint32& state, + DrawablePtr drawable ) { if ( NULL != drawable ) { - if ( hasDrawableState( state ) && mDrawablesOwnership[mDrawables[state]] ) { + if ( hasDrawableState( state ) && mCurrentDrawable == mDrawables[state].get() ) + mCurrentDrawable = NULL; - if ( mCurrentDrawable == mDrawables[state] ) - mCurrentDrawable = NULL; - - mDrawablesOwnership.erase( mDrawables[state] ); - eeDelete( mDrawables[state] ); - } - - mDrawables[state] = drawable; - mDrawablesOwnership[drawable] = ownIt; + mDrawables[state] = std::move( drawable ); if ( hasDrawableStateColor( state ) ) - drawable->setColor( mDrawableColors[state] ); + mDrawables[state]->setColor( mDrawableColors[state] ); if ( state == mCurrentState ) setState( state ); @@ -194,9 +183,9 @@ bool StateListDrawable::hasDrawableStateColor( const Uint32& state ) const { void StateListDrawable::onColorFilterChange() { for ( auto it = mDrawables.begin(); it != mDrawables.end(); ++it ) { - Drawable* drawable = it->second; - - drawable->setColor( mColor ); + Drawable* drawable = it->second.get(); + if ( drawable ) + drawable->setColor( mColor ); } } diff --git a/src/eepp/graphics/texture.cpp b/src/eepp/graphics/texture.cpp index 3304dde78..a4bead9dc 100644 --- a/src/eepp/graphics/texture.cpp +++ b/src/eepp/graphics/texture.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,16 @@ using namespace EE::Graphics::Private; namespace EE { namespace Graphics { +DrawablePtr Texture::createInstance() const { + TexturePtr texture = TextureFactory::instance()->getTexture( getTextureId() ); + if ( !texture ) + return {}; + TextureDrawablePtr instance = TextureDrawable::New( std::move( texture ) ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; +} + Uint32 Texture::getMaximumSize() { static bool checked = false; static GLint size = 0; diff --git a/src/eepp/graphics/texturedrawable.cpp b/src/eepp/graphics/texturedrawable.cpp new file mode 100644 index 000000000..ea7d19d56 --- /dev/null +++ b/src/eepp/graphics/texturedrawable.cpp @@ -0,0 +1,55 @@ +#include + +namespace EE { namespace Graphics { + +TextureDrawablePtr TextureDrawable::New( TexturePtr texture ) { + return makeResource( std::move( texture ) ); +} + +TextureDrawable::TextureDrawable( TexturePtr texture ) : + DrawableResource( Drawable::TEXTUREDRAWABLE, texture ? texture->getName() : "" ), + mTexture( std::move( texture ) ) { + if ( mTexture ) { + mTextureChangeConnection = + mTexture->connectResourceChange( [this]( DrawableResource& ) { onResourceChange(); } ); + } +} + +Sizef TextureDrawable::getSize() { + return mTexture ? mTexture->getSize() : Sizef{}; +} + +Sizef TextureDrawable::getPixelsSize() { + return mTexture ? mTexture->getPixelsSize() : Sizef{}; +} + +void TextureDrawable::draw() { + draw( mPosition ); +} + +void TextureDrawable::draw( const Vector2f& position ) { + draw( position, getPixelsSize() ); +} + +void TextureDrawable::draw( const Vector2f& position, const Sizef& size ) { + if ( mTexture ) + mTexture->drawEx( position.x, position.y, size.x, size.y, 0, Vector2f::One, mColor, mColor, + mColor, mColor ); +} + +bool TextureDrawable::isStateful() { + return false; +} + +DrawablePtr TextureDrawable::createInstance() const { + TextureDrawablePtr instance = New( mTexture ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; +} + +const TexturePtr& TextureDrawable::getTexture() const { + return mTexture; +} + +}} // namespace EE::Graphics diff --git a/src/eepp/graphics/texturefactory.cpp b/src/eepp/graphics/texturefactory.cpp index fa166b428..20044115f 100644 --- a/src/eepp/graphics/texturefactory.cpp +++ b/src/eepp/graphics/texturefactory.cpp @@ -320,10 +320,15 @@ void TextureFactory::diagnoseLiveTexturesAtShutdown() { Log::error( "TextureFactory shutdown found %zu externally retained texture(s).", survivors.size() ); + eePRINTL( "TextureFactory shutdown found %zu externally retained texture(s).", + survivors.size() ); for ( const TexturePtr& texture : survivors ) { Log::error( "Texture %llu ('%s') survived shutdown with %zu external owner(s).", static_cast( texture->getTextureId().value() ), texture->getName().c_str(), texture.use_count() - 1 ); + eePRINTL( "Texture %llu ('%s') survived shutdown with %zu external owner(s).", + static_cast( texture->getTextureId().value() ), + texture->getName().c_str(), texture.use_count() - 1 ); texture->deleteTexture(); } diff --git a/src/eepp/graphics/textureregion.cpp b/src/eepp/graphics/textureregion.cpp index aa7305969..b8f372d45 100644 --- a/src/eepp/graphics/textureregion.cpp +++ b/src/eepp/graphics/textureregion.cpp @@ -117,6 +117,15 @@ TextureRegion::~TextureRegion() { clearCache(); } +DrawablePtr TextureRegion::createInstance() const { + auto instance = makeResource( mTexture, mSrcRect, mDestSize, mOffset, mName ); + instance->setOriDestSize( mOriDestSize ); + instance->setPixelDensity( mPixelDensity ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; +} + void TextureRegion::setTextureId( ResourceId textureId ) { mTexture = TextureFactory::instance()->getTexture( textureId ); } diff --git a/src/eepp/graphics/triangledrawable.cpp b/src/eepp/graphics/triangledrawable.cpp index c63975dc4..896acb2ad 100644 --- a/src/eepp/graphics/triangledrawable.cpp +++ b/src/eepp/graphics/triangledrawable.cpp @@ -18,6 +18,22 @@ TriangleDrawable::TriangleDrawable( const Vector2f& position, const Sizef& size mPosition = position; } +DrawablePtr TriangleDrawable::createInstance() const { + auto instance = makeResource( mPosition, mSize ); + instance->mTriangle = mTriangle; + instance->mComputedTriangle = mComputedTriangle; + instance->mColors[0] = mColors[0]; + instance->mColors[1] = mColors[1]; + instance->mColors[2] = mColors[2]; + instance->mCustomColors = mCustomColors; + instance->mFillMode = mFillMode; + instance->mBlendMode = mBlendMode; + instance->mLineWidth = mLineWidth; + instance->mSmooth = mSmooth; + instance->mColor = mColor; + return instance; +} + Sizef TriangleDrawable::getSize() { return mTriangle.getSize(); } diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index dd6e331a2..2f1818200 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -667,7 +667,7 @@ UIWidget* UIAbstractTableView::updateCell( const Vector2& posIndex, const cell->setIcon( icon.asDrawable() ); } else if ( icon.is( Variant::Type::Icon ) && icon.asIcon() ) { isVisible = true; - cell->setIcon( icon.asIcon()->getSize( mIconSize ) ); + cell->setIcon( icon.asIcon()->createDrawable( mIconSize ) ); } if ( cell->hasIcon() ) cell->getIcon()->setVisible( isVisible ); @@ -891,7 +891,7 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) { UIImage* image = columnData( model->keyColumn() ).widget->getExtraInnerWidget()->asType(); image->setForegroundFillEnabled( false ); - image->setDrawable( nullptr ); + image->setDrawable( DrawablePtr{} ); } SortOrder sortOrder = model->sortOrder() == SortOrder::Ascending ? SortOrder::Descending : SortOrder::Ascending; @@ -904,10 +904,10 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) { if ( image->getForeground() ) image->getForeground()->setAlpha( 255 ); if ( image && image->getForeground() == nullptr ) { - Drawable* icon = mUISceneNode->findIconDrawable( + DrawablePtr icon = mUISceneNode->findIconDrawable( sortOrder == SortOrder::Ascending ? "arrow-down" : "arrow-up", mSortIconSize ); if ( icon ) - image->setDrawable( icon ); + image->setDrawable( std::move( icon ) ); } model->sort( colIndex, sortOrder ); } diff --git a/src/eepp/ui/css/drawableimageparser.cpp b/src/eepp/ui/css/drawableimageparser.cpp index 67d40446e..856fc289a 100644 --- a/src/eepp/ui/css/drawableimageparser.cpp +++ b/src/eepp/ui/css/drawableimageparser.cpp @@ -153,27 +153,23 @@ bool DrawableImageParser::exists( const std::string& name ) const { return mFuncs.find( name ) != mFuncs.end(); } -Drawable* DrawableImageParser::createDrawable( const std::string& value, const Sizef& size, - bool& ownIt, UINode* node ) { +DrawablePtr DrawableImageParser::createDrawable( const std::string& value, const Sizef& size, + UINode* node ) { FunctionString functionType = FunctionString::parse( value ); - Drawable* res = NULL; - ownIt = false; if ( "none" == value ) - return NULL; + return {}; if ( !functionType.isEmpty() ) { if ( exists( functionType.getName() ) ) - return mFuncs[functionType.getName()]( functionType, size, ownIt, node ); - } else if ( NULL != ( res = DrawableSearcher::searchByName( - value, false, node->getUISceneNode()->getReferer(), - node->getUISceneNode()->getResourceScope().get() ) ) ) { - if ( res->getDrawableType() == Drawable::SPRITE ) - ownIt = true; - return res; + return mFuncs[functionType.getName()]( functionType, size, node ); + } else if ( DrawablePtr drawable = DrawableSearcher::searchByName( + value, false, node->getUISceneNode()->getReferer(), + node->getUISceneNode()->getResourceScope().get() ) ) { + return drawable; } - return res; + return {}; } void DrawableImageParser::addParser( const std::string& name, @@ -190,11 +186,11 @@ void DrawableImageParser::addParser( const std::string& name, void DrawableImageParser::registerBaseParsers() { // Shared parsing logic for linear-gradient and repeating-linear-gradient - auto parseGradient = []( const FunctionString& functionType, bool& ownIt, UINode* node, - bool repeating ) -> Drawable* { + auto parseGradient = []( const FunctionString& functionType, UINode* node, + bool repeating ) -> DrawablePtr { const auto& params( functionType.getParameters() ); if ( params.size() < 2 ) - return NULL; + return {}; size_t paramIdx = 0; Float angle = 180.f; /* default: to bottom */ @@ -332,7 +328,7 @@ void DrawableImageParser::registerBaseParsers() { colorStopCount++; } if ( colorStopCount < 2 ) - return NULL; + return {}; } // Sort by position. Hints with the same position as a color stop are @@ -451,34 +447,33 @@ void DrawableImageParser::registerBaseParsers() { } if ( stops.size() < 2 ) - return NULL; + return {}; - LinearGradientDrawable* drawable = - repeating ? LinearGradientDrawable::NewRepeating() : LinearGradientDrawable::New(); + auto drawable = makeResource( + repeating ? Drawable::REPEATINGLINEARGRADIENT : Drawable::LINEARGRADIENT ); drawable->setColorStops( std::move( stops ) ); drawable->setAngle( angle ); - ownIt = true; return drawable; }; mFuncs["linear-gradient"] = [parseGradient]( const FunctionString& functionType, - const Sizef& /*size*/, bool& ownIt, - UINode* node ) -> Drawable* { - return parseGradient( functionType, ownIt, node, false ); + const Sizef& /*size*/, + UINode* node ) -> DrawablePtr { + return parseGradient( functionType, node, false ); }; mFuncs["repeating-linear-gradient"] = [parseGradient]( const FunctionString& functionType, - const Sizef& /*size*/, bool& ownIt, - UINode* node ) -> Drawable* { - return parseGradient( functionType, ownIt, node, true ); + const Sizef& /*size*/, + UINode* node ) -> DrawablePtr { + return parseGradient( functionType, node, true ); }; // Shared parsing logic for radial-gradient and repeating-radial-gradient - auto parseRadialGradient = []( const FunctionString& functionType, bool& ownIt, UINode* node, - bool repeating ) -> Drawable* { + auto parseRadialGradient = []( const FunctionString& functionType, UINode* node, + bool repeating ) -> DrawablePtr { const auto& params( functionType.getParameters() ); if ( params.size() < 2 ) - return NULL; + return {}; size_t paramIdx = 0; RadialGradientDrawable::ShapeType shape = RadialGradientDrawable::CIRCLE; @@ -558,7 +553,7 @@ void DrawableImageParser::registerBaseParsers() { colorStopCount++; } if ( colorStopCount < 2 ) - return NULL; + return {}; } std::sort( gradientStops.begin(), gradientStops.end(), @@ -672,37 +667,36 @@ void DrawableImageParser::registerBaseParsers() { } if ( stops.size() < 2 ) - return NULL; + return {}; - RadialGradientDrawable* drawable = - repeating ? RadialGradientDrawable::NewRepeating() : RadialGradientDrawable::New(); + auto drawable = makeResource( + repeating ? Drawable::REPEATINGRADIALGRADIENT : Drawable::RADIALGRADIENT ); drawable->setColorStops( std::move( stops ) ); drawable->setShape( shape ); drawable->setExtent( extent ); drawable->setCenter( center ); - ownIt = true; return drawable; }; mFuncs["radial-gradient"] = [parseRadialGradient]( const FunctionString& functionType, - const Sizef& /*size*/, bool& ownIt, - UINode* node ) -> Drawable* { - return parseRadialGradient( functionType, ownIt, node, false ); + const Sizef& /*size*/, + UINode* node ) -> DrawablePtr { + return parseRadialGradient( functionType, node, false ); }; mFuncs["repeating-radial-gradient"] = [parseRadialGradient]( const FunctionString& functionType, - const Sizef& /*size*/, bool& ownIt, - UINode* node ) -> Drawable* { - return parseRadialGradient( functionType, ownIt, node, true ); + const Sizef& /*size*/, + UINode* node ) -> DrawablePtr { + return parseRadialGradient( functionType, node, true ); }; - mFuncs["circle"] = []( const FunctionString& functionType, const Sizef& size, bool& ownIt, - UINode* node ) -> Drawable* { + mFuncs["circle"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { if ( functionType.getParameters().size() < 1 ) { - return NULL; + return {}; } - CircleDrawable* drawable = CircleDrawable::New(); + auto drawable = makeResource(); const auto& params( functionType.getParameters() ); @@ -723,17 +717,16 @@ void DrawableImageParser::registerBaseParsers() { } drawable->setOffset( drawable->getSize() / 2.f ); - ownIt = true; return drawable; }; - mFuncs["rectangle"] = []( const FunctionString& functionType, const Sizef& size, bool& ownIt, - UINode* node ) -> Drawable* { + mFuncs["rectangle"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { if ( functionType.getParameters().size() < 1 ) { - return NULL; + return {}; } - RectangleDrawable* drawable = RectangleDrawable::New(); + auto drawable = makeResource(); RectColors rectColors; std::vector colors; @@ -780,22 +773,19 @@ void DrawableImageParser::registerBaseParsers() { rectColors.BottomRight = colors[2]; rectColors.TopRight = colors[3]; drawable->setRectColors( rectColors ); - ownIt = true; return drawable; - } else { - eeSAFE_DELETE( drawable ); } - return drawable; + return {}; }; - mFuncs["triangle"] = []( const FunctionString& functionType, const Sizef& size, bool& ownIt, - UINode* node ) -> Drawable* { + mFuncs["triangle"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { if ( functionType.getParameters().size() < 2 ) { - return NULL; + return {}; } - TriangleDrawable* drawable = TriangleDrawable::New(); + auto drawable = makeResource(); std::vector colors; std::vector vertices; @@ -850,22 +840,19 @@ void DrawableImageParser::registerBaseParsers() { } drawable->setTriangle( triangle ); - ownIt = true; return drawable; - } else { - eeSAFE_DELETE( drawable ); } - return drawable; + return {}; }; - mFuncs["poly"] = []( const FunctionString& functionType, const Sizef& size, bool& ownIt, - UINode* node ) -> Drawable* { + mFuncs["poly"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { if ( functionType.getParameters().size() < 2 ) { - return NULL; + return {}; } - ConvexShapeDrawable* drawable = ConvexShapeDrawable::New(); + auto drawable = makeResource(); std::vector colors; std::vector vertices; @@ -909,26 +896,24 @@ void DrawableImageParser::registerBaseParsers() { drawable->addPoint( vertices[i], colors[i % colors.size()] ); } - ownIt = true; return drawable; - } else { - eeSAFE_DELETE( drawable ); } - return drawable; + return {}; }; - mFuncs["url"] = []( const FunctionString& functionType, const Sizef& /*size*/, bool& /*ownIt*/, - UINode* node ) -> Drawable* { + mFuncs["url"] = []( const FunctionString& functionType, const Sizef& /*size*/, + UINode* node ) -> DrawablePtr { if ( functionType.getParameters().size() < 1 ) - return NULL; + return {}; const auto& param = functionType.getParameters().at( 0 ); if ( functionType.getName() == "url" && !param.empty() && param[0] != '@' && !String::startsWith( param, "data:image/" ) ) { - return DrawableSearcher::searchByName( + DrawablePtr drawable = DrawableSearcher::searchByName( node->getUISceneNode()->solveRelativePath( param ).toString(), false, node->getUISceneNode()->getReferer(), node->getUISceneNode()->getResourceScope().get() ); + return drawable; } else if ( functionType.getParameters().size() > 1 && String::startsWith( param, "data:image/" ) ) { auto cparam = functionType.getParameters().at( 0 ); @@ -936,16 +921,19 @@ void DrawableImageParser::registerBaseParsers() { cparam += ','; cparam += functionType.getParameters().at( i ); } - return DrawableSearcher::searchByName( + DrawablePtr drawable = DrawableSearcher::searchByName( cparam, false, node->getUISceneNode()->getReferer(), node->getUISceneNode()->getResourceScope().get() ); + return drawable; } - return DrawableSearcher::searchByName( param, false, node->getUISceneNode()->getReferer(), - node->getUISceneNode()->getResourceScope().get() ); + DrawablePtr drawable = DrawableSearcher::searchByName( + param, false, node->getUISceneNode()->getReferer(), + node->getUISceneNode()->getResourceScope().get() ); + return drawable; }; - mFuncs["icon"] = []( const FunctionString& functionType, const Sizef& size, bool&, - UINode* node ) -> Drawable* { + mFuncs["icon"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { auto* uiScene = SceneManager::instance()->getUISceneNode(); const auto& params = functionType.getParameters(); if ( params.size() < 2 ) @@ -955,8 +943,8 @@ void DrawableImageParser::registerBaseParsers() { node->convertLength( length, size.getWidth() ) ); }; - mFuncs["glyph"] = []( const FunctionString& functionType, const Sizef& size, bool&, - UINode* node ) -> Drawable* { + mFuncs["glyph"] = []( const FunctionString& functionType, const Sizef& size, + UINode* node ) -> DrawablePtr { const auto& params = functionType.getParameters(); if ( params.size() < 3 ) return nullptr; @@ -976,8 +964,9 @@ void DrawableImageParser::registerBaseParsers() { } else if ( String::fromString( value, buffer ) ) { codePoint = value; } - return font->getGlyphDrawable( codePoint, - node->convertLength( params[1], size.getWidth() ) ); + Drawable* drawable = font->getGlyphDrawable( + codePoint, node->convertLength( params[1], size.getWidth() ) ); + return drawable ? drawable->createInstance() : DrawablePtr{}; }; } diff --git a/src/eepp/ui/lineargradientdrawable.cpp b/src/eepp/ui/lineargradientdrawable.cpp index 3c42db598..2340d8f57 100644 --- a/src/eepp/ui/lineargradientdrawable.cpp +++ b/src/eepp/ui/lineargradientdrawable.cpp @@ -18,6 +18,16 @@ LinearGradientDrawable* LinearGradientDrawable::NewRepeating() { LinearGradientDrawable::LinearGradientDrawable( Graphics::Drawable::Type drawableType ) : Drawable( drawableType ) {} +DrawablePtr LinearGradientDrawable::createInstance() const { + auto instance = makeResource( mDrawableType ); + instance->mColorStops = mColorStops; + instance->mAngle = mAngle; + instance->mSize = mSize; + instance->mColor = mColor; + instance->mPosition = mPosition; + return instance; +} + Sizef LinearGradientDrawable::getSize() { return mSize; } diff --git a/src/eepp/ui/radialgradientdrawable.cpp b/src/eepp/ui/radialgradientdrawable.cpp index b506e35d0..05a98c363 100644 --- a/src/eepp/ui/radialgradientdrawable.cpp +++ b/src/eepp/ui/radialgradientdrawable.cpp @@ -18,6 +18,18 @@ RadialGradientDrawable* RadialGradientDrawable::NewRepeating() { RadialGradientDrawable::RadialGradientDrawable( Graphics::Drawable::Type drawableType ) : Drawable( drawableType ) {} +DrawablePtr RadialGradientDrawable::createInstance() const { + auto instance = makeResource( mDrawableType ); + instance->mColorStops = mColorStops; + instance->mShape = mShape; + instance->mExtent = mExtent; + instance->mCenter = mCenter; + instance->mSize = mSize; + instance->mColor = mColor; + instance->mPosition = mPosition; + return instance; +} + Sizef RadialGradientDrawable::getSize() { return mSize; } @@ -75,7 +87,6 @@ void RadialGradientDrawable::draw( const Vector2f& position, const Sizef& size ) std::sort( stops.begin(), stops.end(), []( const ColorStop& a, const ColorStop& b ) { return a.value < b.value; } ); - const int SEGMENTS = 48; Float angleStep = 2.f * EE_PI / (Float)SEGMENTS; @@ -133,16 +144,14 @@ void RadialGradientDrawable::draw( const Vector2f& position, const Sizef& size ) Float frac1 = ( clip1 - p0 ) / bw; const Color& sc0 = stops[i].color; const Color& sc1 = stops[i + 1].color; - Color cc0( - (Uint8)( (Float)sc0.r + frac0 * (Float)( sc1.r - sc0.r ) ), - (Uint8)( (Float)sc0.g + frac0 * (Float)( sc1.g - sc0.g ) ), - (Uint8)( (Float)sc0.b + frac0 * (Float)( sc1.b - sc0.b ) ), - (Uint8)( (Float)sc0.a + frac0 * (Float)( sc1.a - sc0.a ) ) ); - Color cc1( - (Uint8)( (Float)sc0.r + frac1 * (Float)( sc1.r - sc0.r ) ), - (Uint8)( (Float)sc0.g + frac1 * (Float)( sc1.g - sc0.g ) ), - (Uint8)( (Float)sc0.b + frac1 * (Float)( sc1.b - sc0.b ) ), - (Uint8)( (Float)sc0.a + frac1 * (Float)( sc1.a - sc0.a ) ) ); + Color cc0( (Uint8)( (Float)sc0.r + frac0 * (Float)( sc1.r - sc0.r ) ), + (Uint8)( (Float)sc0.g + frac0 * (Float)( sc1.g - sc0.g ) ), + (Uint8)( (Float)sc0.b + frac0 * (Float)( sc1.b - sc0.b ) ), + (Uint8)( (Float)sc0.a + frac0 * (Float)( sc1.a - sc0.a ) ) ); + Color cc1( (Uint8)( (Float)sc0.r + frac1 * (Float)( sc1.r - sc0.r ) ), + (Uint8)( (Float)sc0.g + frac1 * (Float)( sc1.g - sc0.g ) ), + (Uint8)( (Float)sc0.b + frac1 * (Float)( sc1.b - sc0.b ) ), + (Uint8)( (Float)sc0.a + frac1 * (Float)( sc1.a - sc0.a ) ) ); Color fc0 = ( mColor.a == 255 ) ? cc0 : Color( cc0 ).blendAlpha( mColor.a ); Color fc1 = ( mColor.a == 255 ) ? cc1 : Color( cc1 ).blendAlpha( mColor.a ); @@ -175,9 +184,8 @@ void RadialGradientDrawable::draw( const Vector2f& position, const Sizef& size ) Float cj = cosVals[j], sj = sinVals[j]; Float cj1 = cosVals[j + 1], sj1 = sinVals[j + 1]; - sBR->batchQuadFree( cx + r0 * cj + posX, cy + r0 * sj + posY, - cx + r1 * cj + posX, cy + r1 * sj + posY, - cx + r1 * cj1 + posX, cy + r1 * sj1 + posY, + sBR->batchQuadFree( cx + r0 * cj + posX, cy + r0 * sj + posY, cx + r1 * cj + posX, + cy + r1 * sj + posY, cx + r1 * cj1 + posX, cy + r1 * sj1 + posY, cx + r0 * cj1 + posX, cy + r0 * sj1 + posY ); } } diff --git a/src/eepp/ui/tools/uicolorpicker.cpp b/src/eepp/ui/tools/uicolorpicker.cpp index 8279e432b..1f1b21bc0 100644 --- a/src/eepp/ui/tools/uicolorpicker.cpp +++ b/src/eepp/ui/tools/uicolorpicker.cpp @@ -288,7 +288,8 @@ UIColorPicker::UIColorPicker( UIWindow* attachTo, const UIColorPicker::ColorPick mRoot->on( Event::OnLayoutUpdate, [this]( const Event* ) { if ( mHuePicker->getDrawable() == nullptr ) { mHuePicker->setDrawable( createHueTexture( mHuePicker->getPixelsSize() ) ); - mCurrentColor->setBackgroundDrawable( TextureRegion::New( createGridTexture() ), true ); + mCurrentColor->setBackgroundDrawable( + makeResource( createGridTexture() ) ); mCurrentColor->setBackgroundRepeat( "repeat" ); updateAll(); } @@ -404,9 +405,9 @@ TexturePtr UIColorPicker::createGridTexture() { } void UIColorPicker::updateColorPicker() { - DrawableGroup* colorRectangle = DrawableGroup::New(); + auto colorRectangle = DrawableGroup::New(); - RectangleDrawable* rectDrawable = RectangleDrawable::New(); + auto rectDrawable = makeResource(); RectColors rectColors; rectDrawable->setSize( mColorPicker->getPixelsSize() ); @@ -417,7 +418,7 @@ void UIColorPicker::updateColorPicker() { rectDrawable->setRectColors( rectColors ); colorRectangle->addDrawable( rectDrawable ); - rectDrawable = RectangleDrawable::New(); + rectDrawable = makeResource(); rectDrawable->setSize( mColorPicker->getPixelsSize() ); rectColors.TopLeft = Color::Transparent; rectColors.BottomLeft = Color::Black; @@ -426,7 +427,7 @@ void UIColorPicker::updateColorPicker() { rectDrawable->setRectColors( rectColors ); colorRectangle->addDrawable( rectDrawable ); - mColorPicker->setDrawable( colorRectangle, true ); + mColorPicker->setDrawable( std::move( colorRectangle ) ); } void UIColorPicker::updateGuideLines() { diff --git a/src/eepp/ui/tools/uidiffview.cpp b/src/eepp/ui/tools/uidiffview.cpp index 3fabb31ad..e58637438 100644 --- a/src/eepp/ui/tools/uidiffview.cpp +++ b/src/eepp/ui/tools/uidiffview.cpp @@ -67,12 +67,12 @@ static Sprite* setImageViewerImage( UIImageViewer* viewer, Image* image ) { auto sprite = Sprite::New(); sprite->createStatic( texture ); - sprite->setAsTextureRegionOwner( true ); + Sprite* spritePtr = sprite.get(); viewer->reset(); - viewer->getImage()->setDrawable( sprite, true ); + viewer->getImage()->setDrawable( std::move( sprite ) ); setImageViewerImageSize( viewer ); - return sprite; + return spritePtr; } UIScrollView* UIDiffView::NewMultiFileDiffViewer( const std::string& patchText, diff --git a/src/eepp/ui/tools/uifontpickerdialog.cpp b/src/eepp/ui/tools/uifontpickerdialog.cpp index 64d594144..72bdc158f 100644 --- a/src/eepp/ui/tools/uifontpickerdialog.cpp +++ b/src/eepp/ui/tools/uifontpickerdialog.cpp @@ -281,21 +281,21 @@ void UIFontPickerDialog::setTheme( UITheme* theme ) { UIWindow::setTheme( theme ); if ( mButtonOK ) { - if ( Drawable* icon = + if ( DrawablePtr icon = getUISceneNode()->findIconDrawable( "ok", PixelDensity::dpToPxI( 16 ) ) ) - mButtonOK->setIcon( icon ); + mButtonOK->setIcon( std::move( icon ) ); } if ( mButtonCancel ) { - if ( Drawable* icon = + if ( DrawablePtr icon = getUISceneNode()->findIconDrawable( "cancel", PixelDensity::dpToPxI( 16 ) ) ) - mButtonCancel->setIcon( icon ); + mButtonCancel->setIcon( std::move( icon ) ); } if ( mButtonBrowse ) { - if ( Drawable* icon = getUISceneNode()->findIconDrawable( "document-open", - PixelDensity::dpToPxI( 16 ) ) ) - mButtonBrowse->setIcon( icon ); + if ( DrawablePtr icon = getUISceneNode()->findIconDrawable( "document-open", + PixelDensity::dpToPxI( 16 ) ) ) + mButtonBrowse->setIcon( std::move( icon ) ); } onThemeLoaded(); diff --git a/src/eepp/ui/tools/uiimageviewer.cpp b/src/eepp/ui/tools/uiimageviewer.cpp index e6d0d7c37..0845ed089 100644 --- a/src/eepp/ui/tools/uiimageviewer.cpp +++ b/src/eepp/ui/tools/uiimageviewer.cpp @@ -155,7 +155,7 @@ void UIImageViewer::loadImageAsync( std::string_view path, bool isContents, bool if ( format == Image::Format::Unknown ) return; - Sprite* image = nullptr; + DrawablePtr image; if ( mClosing ) return; @@ -165,18 +165,16 @@ void UIImageViewer::loadImageAsync( std::string_view path, bool isContents, bool reinterpret_cast( path.c_str() ), path.size() ) : TextureFactory::instance()->loadFromFile( path ); - Sprite* sprite = Sprite::New(); + SpritePtr sprite = Sprite::New(); sprite->createStatic( tex ); - sprite->setAsTextureRegionOwner( true ); - image = sprite; + image = std::move( sprite ); } else { IOStream* stream = isContents ? (IOStream*)new IOStreamMemory( path.c_str(), path.size() ) : (IOStream*)new IOStreamFile( path ); - Sprite* sprite = Sprite::fromGif( *stream ); - sprite->setAsTextureRegionOwner( true ); + SpritePtr sprite = Sprite::fromGif( *stream ); sprite->setAutoAnimate( false ); - image = sprite; + image = std::move( sprite ); delete stream; } @@ -188,7 +186,7 @@ void UIImageViewer::loadImageAsync( std::string_view path, bool isContents, bool mCurFileType = format; runOnMainThread( [this, image] { - mImage->setDrawable( image, true ); + mImage->setDrawable( image ); updateTextDisplay(); auto s( image->getPixelsSize() ); auto scale( s.x > mSize.x || s.y > mSize.y @@ -210,7 +208,7 @@ void UIImageViewer::onSizeChange() { } void UIImageViewer::reset() { - mImage->setDrawable( nullptr )->setVisible( false ); + mImage->setDrawable( DrawablePtr{} )->setVisible( false ); } Uint32 UIImageViewer::onMessage( const NodeMessage* msg ) { @@ -311,7 +309,7 @@ Uint32 UIImageViewer::onKeyDown( const KeyEvent& event ) { } else if ( event.getKeyCode() == KEY_T ) { resetImageView(); } else if ( event.getKeyCode() == KEY_X ) { - auto sprite = static_cast( mImage->getDrawable() ); + auto sprite = static_cast( mImage->getDrawable().get() ); auto mode = sprite->getRenderMode(); if ( mode == RENDER_NORMAL ) mode = RENDER_FLIPPED; @@ -324,7 +322,7 @@ Uint32 UIImageViewer::onKeyDown( const KeyEvent& event ) { sprite->setRenderMode( mode ); invalidateDraw(); } else if ( event.getKeyCode() == KEY_C ) { - auto sprite = static_cast( mImage->getDrawable() ); + auto sprite = static_cast( mImage->getDrawable().get() ); auto mode = sprite->getRenderMode(); if ( mode == RENDER_NORMAL ) mode = RENDER_MIRROR; diff --git a/src/eepp/ui/tools/uitabwidgetsplitter.cpp b/src/eepp/ui/tools/uitabwidgetsplitter.cpp index c7acdbfc3..b5b6df8bf 100644 --- a/src/eepp/ui/tools/uitabwidgetsplitter.cpp +++ b/src/eepp/ui/tools/uitabwidgetsplitter.cpp @@ -912,7 +912,7 @@ void UITabWidgetSplitter::unserializeNode( const nlohmann::json& j, UITabWidget* !result.title.empty() ? result.title : file.value( "title", "" ); auto [tab, _] = createWidgetInTabWidget( curTabWidget, result.widget, title ); if ( result.icon ) - tab->setIcon( result.icon ); + tab->setIcon( result.icon->createInstance() ); } } if ( curTabWidget->getTabCount() > 0 ) { diff --git a/src/eepp/ui/tools/uitextureviewer.cpp b/src/eepp/ui/tools/uitextureviewer.cpp index 672c684d8..d81c4440a 100644 --- a/src/eepp/ui/tools/uitextureviewer.cpp +++ b/src/eepp/ui/tools/uitextureviewer.cpp @@ -22,12 +22,12 @@ void UITextureViewer::setImage( TexturePtr texture ) { return; mSelectedTexture = std::move( texture ); mImageLayout->setEnabled( true )->setVisible( true ); - imageView->setDrawable( mSelectedTexture.get() ); + imageView->setDrawable( mSelectedTexture ); } void UITextureViewer::clearSelectedTexture() { if ( UIImage* imageView = mImageLayout->findByType( UI_TYPE_IMAGE ) ) - imageView->setDrawable( nullptr ); + imageView->setDrawable( DrawablePtr{} ); mSelectedTexture.reset(); mImageLayout->setEnabled( false )->setVisible( false ); } @@ -110,7 +110,7 @@ void UITextureViewer::insertTexture( const TextureRegistryRecord& record ) { UIImage* img = UIImage::New(); std::string uid( String::format( "texture-%llu", static_cast( record.id.value() ) ) ); - img->setDrawable( texture.get() ) + img->setDrawable( texture ) ->setScaleType( UIScaleType::FitInside ) ->setClasses( { "texture-preview", uid } ) ->setTooltipText( getTextureDescription( texture.get() ) ) diff --git a/src/eepp/ui/tools/uiwidgetinspector.cpp b/src/eepp/ui/tools/uiwidgetinspector.cpp index df3853d43..ebbc8ab91 100644 --- a/src/eepp/ui/tools/uiwidgetinspector.cpp +++ b/src/eepp/ui/tools/uiwidgetinspector.cpp @@ -148,11 +148,11 @@ UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIc UIPushButton* button = cont->find( "pick_widget" ); if ( button->getIcon() == nullptr ) { - Drawable* cursorPointer = button->getUISceneNode()->findIconDrawable( + DrawablePtr cursorPointer = button->getUISceneNode()->findIconDrawable( "cursor-pointer", PixelDensity::dpToPx( 16 ) ); if ( cursorPointer ) - button->setIcon( cursorPointer, true ); + button->setIcon( std::move( cursorPointer ) ); } button->on( Event::MouseClick, [sceneNode, nodeTree, computedView]( const Event* event ) { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 34a515391..7c8cd3f98 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -484,6 +484,17 @@ void UICodeEditor::scheduledUpdate( const Time& ) { if ( !mVisible ) return; + if ( mLocked && mDisplayLockedIcon ) { + if ( mFileLockIcon == nullptr && !mFileLockIconName.empty() ) + mFileLockIcon = getUISceneNode()->findIcon( mFileLockIconName ); + const int iconSize = PixelDensity::dpToPxI( 16 ); + if ( mFileLockIcon && + ( mFileLockDrawable == nullptr || mFileLockDrawableSize != iconSize ) ) { + mFileLockDrawable = mFileLockIcon->createDrawable( iconSize ); + mFileLockDrawableSize = iconSize; + } + } + if ( mDoc && !mDoc->isLoading() && !mDoc->isEmpty() && !mDoc->getSyntaxDefinition().getPatterns().empty() && mDoc->getHighlighter()->updateDirty( getVisibleLinesCount() ) ) { @@ -1146,27 +1157,21 @@ void UICodeEditor::updateIMELocation() { } void UICodeEditor::drawLockedIcon( const Vector2f start ) { - if ( mFileLockIcon == nullptr && !mFileLockIconName.empty() ) - mFileLockIcon = getUISceneNode()->findIcon( mFileLockIconName ); - if ( mFileLockIcon == nullptr ) + if ( mFileLockDrawable == nullptr ) return; - Drawable* fileLockIcon = mFileLockIcon->getSize( PixelDensity::dpToPxI( 16 ) ); - if ( fileLockIcon == nullptr ) - return; - - Float w = fileLockIcon->getPixelsSize().getWidth(); + Float w = mFileLockDrawable->getPixelsSize().getWidth(); Float posX = mMinimapEnabled ? getMinimapRect( getScreenStart() ).Left - w : ( start.x + mSize.getWidth() - ( mVScrollBar->isVisible() ? mVScrollBar->getPixelsSize().getWidth() : 0 ) ) - mPadding.Right - w; - Color col( fileLockIcon->getColor() ); - fileLockIcon->setColor( Color( mFontStyleConfig.getFontColor() ).blendAlpha( mAlpha ) ); + Color col( mFileLockDrawable->getColor() ); + mFileLockDrawable->setColor( Color( mFontStyleConfig.getFontColor() ).blendAlpha( mAlpha ) ); Float margin = PixelDensity::dpToPxI( 4 ); - fileLockIcon->draw( { posX - margin, start.y + margin } ); - fileLockIcon->setColor( col ); + mFileLockDrawable->draw( { posX - margin, start.y + margin } ); + mFileLockDrawable->setColor( col ); } size_t UICodeEditor::getTotalVisibleLines() const { @@ -3533,11 +3538,9 @@ void UICodeEditor::updateGlyphWidth() { invalidateLineWrapMaxWidth( false ); } -Drawable* UICodeEditor::findIcon( const std::string& name ) { +DrawablePtr UICodeEditor::findIcon( const std::string& name ) { UIIcon* icon = getUISceneNode()->findIcon( name ); - if ( icon ) - return icon->getSize( mMenuIconSize ); - return nullptr; + return icon ? icon->createDrawable( mMenuIconSize ) : DrawablePtr{}; } const bool& UICodeEditor::getColorPreview() const { @@ -3755,6 +3758,8 @@ void UICodeEditor::setFileLockIconName( const std::string& fileLockIconName ) { if ( mFileLockIconName != fileLockIconName ) { mFileLockIconName = fileLockIconName; mFileLockIcon = nullptr; + mFileLockDrawable.reset(); + mFileLockDrawableSize = 0; } } @@ -4610,7 +4615,7 @@ void UICodeEditor::drawLineNumbers( const DocumentLineRange& lineRange, const Ve if ( mFoldsAlwaysVisible || mFoldsVisible || currentLineHasFold ) { if ( ( isFolded && mFoldedDrawable ) || ( !isFolded && mFoldedDrawable ) ) { - Drawable* drawable = isFolded ? mFoldedDrawable : mFoldDrawable; + Drawable* drawable = ( isFolded ? mFoldedDrawable : mFoldDrawable ).get(); GlyphDrawable::DrawMode oldMode; if ( drawable->getDrawableType() == Drawable::Type::GLYPH ) { @@ -5462,20 +5467,20 @@ void UICodeEditor::setShowFoldingRegion( bool showFoldingRegion ) { } } -Drawable* UICodeEditor::getFoldDrawable() const { +const DrawablePtr& UICodeEditor::getFoldDrawable() const { return mFoldDrawable; } -void UICodeEditor::setFoldDrawable( Drawable* foldDrawable ) { - mFoldDrawable = foldDrawable; +void UICodeEditor::setFoldDrawable( DrawablePtr foldDrawable ) { + mFoldDrawable = std::move( foldDrawable ); } -Drawable* UICodeEditor::getFoldedDrawable() const { +const DrawablePtr& UICodeEditor::getFoldedDrawable() const { return mFoldedDrawable; } -void UICodeEditor::setFoldedDrawable( Drawable* foldedDrawable ) { - mFoldedDrawable = foldedDrawable; +void UICodeEditor::setFoldedDrawable( DrawablePtr foldedDrawable ) { + mFoldedDrawable = std::move( foldedDrawable ); } bool UICodeEditor::getFoldsAlwaysVisible() const { diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 9d2064410..568053334 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -1226,11 +1226,9 @@ void UIConsole::onDocumentSaved( TextDocument* ) {} void UIConsole::onDocumentMoved( TextDocument* ) {} -Drawable* UIConsole::findIcon( const std::string& name ) { +DrawablePtr UIConsole::findIcon( const std::string& name ) { UIIcon* icon = getUISceneNode()->findIcon( name ); - if ( icon ) - return icon->getSize( mMenuIconSize ); - return nullptr; + return icon ? icon->createDrawable( mMenuIconSize ) : DrawablePtr{}; } void UIConsole::copySelection() { diff --git a/src/eepp/ui/uifiledialog.cpp b/src/eepp/ui/uifiledialog.cpp index fd30c2b44..b137dbda5 100644 --- a/src/eepp/ui/uifiledialog.cpp +++ b/src/eepp/ui/uifiledialog.cpp @@ -341,31 +341,31 @@ void UIFileDialog::setTheme( UITheme* Theme ) { mFile->setTheme( Theme ); mFiletype->setTheme( Theme ); - Drawable* icon = getUISceneNode()->findIconDrawable( "go-up", PixelDensity::dpToPxI( 16 ) ); + DrawablePtr icon = getUISceneNode()->findIconDrawable( "go-up", PixelDensity::dpToPxI( 16 ) ); if ( icon ) { mButtonUp->setText( "" ); - mButtonUp->setIcon( icon ); + mButtonUp->setIcon( std::move( icon ) ); mButtonUp->setTooltipText( i18n( "uifiledialog_go_up", "Up" ) ); } icon = getUISceneNode()->findIconDrawable( "folder-add", PixelDensity::dpToPxI( 16 ) ); if ( icon ) { mButtonNewFolder->setText( "" ); - mButtonNewFolder->setIcon( icon ); + mButtonNewFolder->setIcon( std::move( icon ) ); mButtonNewFolder->setTooltipText( i18n( "uifiledialog_new_folder", "New Folder" ) ); } icon = getUISceneNode()->findIconDrawable( "list-view", PixelDensity::dpToPxI( 16 ) ); if ( icon ) { mButtonListView->setText( "" ); - mButtonListView->setIcon( icon ); + mButtonListView->setIcon( std::move( icon ) ); mButtonListView->setTooltipText( i18n( "uifiledialog_list", "List" ) ); } icon = getUISceneNode()->findIconDrawable( "table-view", PixelDensity::dpToPxI( 16 ) ); if ( icon ) { mButtonTableView->setText( "" ); - mButtonTableView->setIcon( icon ); + mButtonTableView->setIcon( std::move( icon ) ); mButtonTableView->setTooltipText( i18n( "uifiledialog_table", "Table" ) ); } diff --git a/src/eepp/ui/uiicon.cpp b/src/eepp/ui/uiicon.cpp index e3a95533c..323929178 100644 --- a/src/eepp/ui/uiicon.cpp +++ b/src/eepp/ui/uiicon.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace EE { namespace UI { @@ -16,39 +17,48 @@ const std::string& UIIcon::getName() const { return mName; } -Drawable* UIIcon::getSize( const int& size ) const { +const DrawablePtr& UIIcon::getSource( const int& size ) const { + static const DrawablePtr empty; auto it = mSizes.find( size ); if ( it != mSizes.end() ) return it->second; - int distance = UINT32_MAX; - Drawable* closest = nullptr; + int distance = std::numeric_limits::max(); + const DrawablePtr* closest = nullptr; for ( const auto& sit : mSizes ) { int diff = abs( sit.first - size ); if ( diff < distance ) { distance = diff; - closest = sit.second; + closest = &sit.second; } } - return closest; + return closest ? *closest : empty; } -void UIIcon::setSize( const int& size, Drawable* drawable ) { - mSizes[size] = drawable; +DrawablePtr UIIcon::createDrawable( const int& size ) const { + const DrawablePtr& source = getSource( size ); + return source ? source->createInstance() : DrawablePtr{}; +} + +void UIIcon::setSource( const int& size, DrawablePtr drawable ) { + mSizes[size] = std::move( drawable ); } UIIcon* UIGlyphIcon::New( const std::string& name, FontTrueType* font, const Uint32& codePoint ) { return eeNew( UIGlyphIcon, ( name, font, codePoint ) ); } -Drawable* UIGlyphIcon::getSize( const int& size ) const { +const DrawablePtr& UIGlyphIcon::getSource( const int& size ) const { + static const DrawablePtr empty; if ( !mFont ) - return nullptr; + return empty; auto it = mSizes.find( size ); if ( it != mSizes.end() ) return it->second; GlyphDrawable* drawable = mFont->getGlyphDrawable( mCodePoint, size ); - const_cast( this )->setSize( size, drawable ); - return drawable; + if ( !drawable ) + return empty; + const_cast( this )->setSource( size, drawable->createInstance() ); + return UIIcon::getSource( size ); } UIGlyphIcon::UIGlyphIcon( const std::string& name, FontTrueType* font, const Uint32& codePoint ) : @@ -74,10 +84,11 @@ UIIcon* UISVGIcon::New( const std::string& name, const std::string& svgXML ) { UISVGIcon::~UISVGIcon() {} -Drawable* UISVGIcon::getSize( const int& size ) const { - auto it = mSVGs.find( size ); - if ( it != mSVGs.end() ) - return it->second.get(); +const DrawablePtr& UISVGIcon::getSource( const int& size ) const { + static const DrawablePtr empty; + auto it = mSizes.find( size ); + if ( it != mSizes.end() ) + return it->second; Image::FormatConfiguration format; if ( mOriSize == Sizei::Zero ) { @@ -87,7 +98,7 @@ Drawable* UISVGIcon::getSize( const int& size ) const { mOriSize = { w, h }; mOriChannels = c; } else { - return nullptr; + return empty; } } format.svgScale( size / (Float)eemax( mOriSize.x, mOriSize.y ) ); @@ -95,8 +106,10 @@ Drawable* UISVGIcon::getSize( const int& size ) const { (const unsigned char*)&mSVGXml[0], mSVGXml.size(), false, Texture::ClampMode::ClampToEdge, false, false, format ); - mSVGs[size] = texture; - return texture.get(); + if ( !texture ) + return empty; + const_cast( this )->setSource( size, std::move( texture ) ); + return UIIcon::getSource( size ); } UISVGIcon::UISVGIcon( const std::string& name, const std::string& svgXML ) : diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index 51924a47e..0d5b3b02d 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -66,11 +67,8 @@ UIImage* UIImage::NewWithTag( const std::string& tag ) { UIImage::UIImage( const std::string& tag ) : UIWidget( tag ), mScaleType( UIScaleType::None ), - mDrawable( NULL ), mColor(), mAlignOffset( 0, 0 ), - mResourceChangeCb( 0 ), - mDrawableOwner( false ), mAsyncImageAlive( std::make_shared>( true ) ) { mFlags |= UI_AUTO_SIZE; @@ -82,7 +80,7 @@ UIImage::UIImage() : UIImage( "image" ) {} UIImage::~UIImage() { if ( mAsyncImageAlive ) mAsyncImageAlive->store( false, std::memory_order_release ); - safeDeleteDrawable(); + clearDrawable(); } Uint32 UIImage::getType() const { @@ -93,16 +91,15 @@ bool UIImage::isType( const Uint32& type ) const { return UIImage::getType() == type ? true : UIWidget::isType( type ); } -UIImage* UIImage::setDrawable( Drawable* drawable, bool ownIt ) { +UIImage* UIImage::setDrawable( DrawablePtr drawable ) { if ( drawable == mDrawable ) return this; Sizef oldSize( mSize ); - safeDeleteDrawable(); + clearDrawable(); - mDrawable = drawable; - mDrawableOwner = ownIt; + mDrawable = std::move( drawable ); sendCommonEvent( Event::OnResourceChange ); if ( mDrawable ) { @@ -110,17 +107,15 @@ UIImage* UIImage::setDrawable( Drawable* drawable, bool ownIt ) { if ( !isSubscribedForScheduledUpdate() ) subscribeScheduledUpdate(); - mResourceChangeCb = - static_cast( mDrawable )->pushEventsCallback( [this]( auto, auto, auto ) { - invalidateDraw(); - } ); + mSpriteChangeCb = + static_cast( mDrawable.get() ) + ->pushEventsCallback( [this]( auto, auto, auto ) { invalidateDraw(); } ); } else { if ( mDrawable->isDrawableResource() ) { - mResourceChangeCb = - static_cast( mDrawable ) - ->pushResourceChangeCallback( [this]( auto, auto event, auto res ) { - onDrawableResourceEvent( event, res ); - } ); + mResourceChangeConnection = + static_cast( mDrawable.get() ) + ->connectResourceChange( + [this]( DrawableResource& ) { onDrawableResourceChange(); } ); } if ( isSubscribedForScheduledUpdate() ) @@ -141,10 +136,7 @@ UIImage* UIImage::setDrawable( Drawable* drawable, bool ownIt ) { } UIImage* UIImage::setDrawable( TexturePtr texture ) { - Texture* drawable = texture.get(); - setDrawable( drawable, false ); - mTexture = std::move( texture ); - return this; + return setDrawable( texture ? TextureDrawable::New( std::move( texture ) ) : DrawablePtr{} ); } void UIImage::onAutoSize() { @@ -278,7 +270,7 @@ void UIImage::setAlpha( const Float& alpha ) { mColor.a = (Uint8)alpha; } -Drawable* UIImage::getDrawable() const { +const DrawablePtr& UIImage::getDrawable() const { return mDrawable; } @@ -316,36 +308,25 @@ void UIImage::autoAlign() { } } -void UIImage::safeDeleteDrawable() { +void UIImage::clearDrawable() { if ( mDrawable && mDrawable->getDrawableType() == Drawable::SPRITE ) { - static_cast( mDrawable )->popEventsCallback( mResourceChangeCb ); - } else if ( mDrawable && mDrawable->isDrawableResource() ) { - static_cast( mDrawable )->popResourceChangeCallback( mResourceChangeCb ); - mResourceChangeCb = 0; + static_cast( mDrawable.get() )->popEventsCallback( mSpriteChangeCb ); + mSpriteChangeCb = 0; } - if ( mDrawable && mDrawableOwner ) { - eeSAFE_DELETE( mDrawable ); - - mDrawableOwner = false; - } - - mTexture.reset(); + mResourceChangeConnection.disconnect(); + mDrawable.reset(); } -void UIImage::onDrawableResourceEvent( DrawableResource::Event event, DrawableResource* ) { - if ( event == DrawableResource::Change ) { - runOnMainThread( [this] { - auto s = mSize; - onAutoSize(); - calcDestSize(); - if ( mSize != s ) - notifyLayoutAttrChangeParent( LayoutInvalidation::ParentReplacedFormatting ); - invalidateDraw(); - } ); - } else if ( event == DrawableResource::Unload ) { - mDrawable = NULL; - } +void UIImage::onDrawableResourceChange() { + runOnMainThread( [this] { + auto s = mSize; + onAutoSize(); + calcDestSize(); + if ( mSize != s ) + notifyLayoutAttrChangeParent( LayoutInvalidation::ParentReplacedFormatting ); + invalidateDraw(); + } ); } bool UIImage::loadFileDrawable( const Network::URI& uri ) { @@ -400,7 +381,11 @@ void UIImage::loadRemoteDrawable( const Network::URI& uri ) { std::string url = uri.toString(); ResourceScopePtr resourceScope = scene->getResourceScope(); if ( TexturePtr texture = resourceScope->findTexture( url ) ) { - if ( mDrawable != texture.get() ) { + TextureDrawable* textureDrawable = + mDrawable && mDrawable->getDrawableType() == Drawable::TEXTUREDRAWABLE + ? static_cast( mDrawable.get() ) + : nullptr; + if ( !textureDrawable || textureDrawable->getTexture() != texture ) { ++mRemoteImageLoadId; setDrawable( std::move( texture ) ); } @@ -436,7 +421,7 @@ void UIImage::loadRemoteDrawable( const Network::URI& uri ) { [alive, loadId, texture, imageData = std::move( imageData ), this]( UISceneNode* ) mutable { if ( !alive || !alive->load( std::memory_order_acquire ) || - loadId != mRemoteImageLoadId || mDrawable != texture.get() ) + loadId != mRemoteImageLoadId ) return; Image image( reinterpret_cast( imageData.data() ), @@ -515,7 +500,7 @@ std::string UIImage::getPropertyString( const PropertyDefinition* propertyDef, void UIImage::scheduledUpdate( const Time& time ) { if ( mDrawable && mDrawable->getDrawableType() == Drawable::SPRITE ) - static_cast( mDrawable )->update( time ); + static_cast( mDrawable.get() )->update( time ); } std::vector UIImage::getPropertiesImplemented() const { @@ -546,7 +531,6 @@ bool UIImage::applyProperty( const StyleSheetProperty& attribute ) { std::string path( attribute.getValue() ); URI uri( path ); - bool ownIt; UISceneNode* scene = getUISceneNode(); if ( scene && uri.getScheme().empty() && !scene->getURI().empty() ) { @@ -562,33 +546,28 @@ bool UIImage::applyProperty( const StyleSheetProperty& attribute ) { if ( mDeferLoad && uri.getScheme() == "file" && loadFileDrawable( uri ) ) break; - Drawable* createdDrawable = + DrawablePtr createdDrawable = StyleSheetSpecification::instance()->getDrawableImageParser().createDrawable( - path, mSize, ownIt, this ); + path, mSize, this ); if ( createdDrawable ) { - setDrawable( createdDrawable, ownIt ); + setDrawable( std::move( createdDrawable ) ); } else { - Drawable* res = NULL; - if ( NULL != ( res = DrawableSearcher::searchByName( - path, false, scene ? scene->getReferer() : URI(), - scene ? scene->getResourceScope().get() : nullptr ) ) ) - setDrawable( res, res->getDrawableType() == Drawable::SPRITE ); + setDrawable( DrawableSearcher::searchByName( + path, false, scene ? scene->getReferer() : URI(), + scene ? scene->getResourceScope().get() : nullptr ) ); } break; } case PropertyId::Icon: { std::string val = attribute.asString(); - Drawable* icon = NULL; - bool ownIt; UIIcon* iconF = getUISceneNode()->findIcon( val ); if ( iconF ) { setDrawable( - iconF->getSize( mSize.getHeight() - mPaddingPx.Top - mPadding.Bottom ) ); - } else if ( NULL != - ( icon = StyleSheetSpecification::instance() - ->getDrawableImageParser() - .createDrawable( val, getPixelsSize(), ownIt, this ) ) ) { - setDrawable( icon, ownIt ); + iconF->createDrawable( mSize.getHeight() - mPaddingPx.Top - mPadding.Bottom ) ); + } else if ( DrawablePtr icon = StyleSheetSpecification::instance() + ->getDrawableImageParser() + .createDrawable( val, getPixelsSize(), this ) ) { + setDrawable( std::move( icon ) ); } break; } diff --git a/src/eepp/ui/uimenu.cpp b/src/eepp/ui/uimenu.cpp index 469197ff0..0edc8ea03 100644 --- a/src/eepp/ui/uimenu.cpp +++ b/src/eepp/ui/uimenu.cpp @@ -58,20 +58,20 @@ void UIMenu::onPaddingChange() { widgetsSetPos(); } -UIMenuItem* UIMenu::createMenuItem( const String& text, Drawable* icon, +UIMenuItem* UIMenu::createMenuItem( const String& text, DrawablePtr icon, const String& shortcutText ) { UIMenuItem* widget = UIMenuItem::New(); widget->setHorizontalAlign( UI_HALIGN_LEFT ); widget->setParent( this ); widget->setIconMinimumSize( mIconMinSize ); - widget->setIcon( icon ); + widget->setIcon( std::move( icon ) ); widget->setText( text ); widget->setShortcutText( shortcutText ); return widget; } -UIMenuItem* UIMenu::add( const String& text, Drawable* icon, const String& shortcutText ) { - UIMenuItem* menuItem = createMenuItem( text, icon, shortcutText ); +UIMenuItem* UIMenu::add( const String& text, DrawablePtr icon, const String& shortcutText ) { + UIMenuItem* menuItem = createMenuItem( text, std::move( icon ), shortcutText ); add( menuItem ); return menuItem; } @@ -113,19 +113,19 @@ UIMenuRadioButton* UIMenu::addRadioButton( const String& text, const bool& activ return radioButton; } -UIMenuSubMenu* UIMenu::createSubMenu( const String& text, Drawable* icon, UIMenu* subMenu ) { +UIMenuSubMenu* UIMenu::createSubMenu( const String& text, DrawablePtr icon, UIMenu* subMenu ) { UIMenuSubMenu* menu = UIMenuSubMenu::New(); menu->setHorizontalAlign( UI_HALIGN_LEFT ); menu->setParent( this ); menu->setIconMinimumSize( mIconMinSize ); - menu->setIcon( icon ); + menu->setIcon( std::move( icon ) ); menu->setText( text ); menu->setSubMenu( subMenu ); return menu; } -UIMenuSubMenu* UIMenu::addSubMenu( const String& text, Drawable* icon, UIMenu* subMenu ) { - UIMenuSubMenu* menu = createSubMenu( text, icon, subMenu ); +UIMenuSubMenu* UIMenu::addSubMenu( const String& text, DrawablePtr icon, UIMenu* subMenu ) { + UIMenuSubMenu* menu = createSubMenu( text, std::move( icon ), subMenu ); add( menu ); return menu; } @@ -269,8 +269,8 @@ void UIMenu::removeAll() { resizeMe(); } -void UIMenu::insert( const String& text, Drawable* icon, const Uint32& index ) { - insert( createMenuItem( text, icon ), index ); +void UIMenu::insert( const String& text, DrawablePtr icon, const Uint32& index ) { + insert( createMenuItem( text, std::move( icon ) ), index ); } void UIMenu::insert( UIWidget* widget, const Uint32& index ) { @@ -553,13 +553,14 @@ Uint32 UIMenu::onKeyDown( const KeyEvent& event ) { return UIWidget::onKeyDown( event ); } -static Drawable* getIconDrawable( const std::string& name, UIIconThemeManager* iconThemeManager ) { - Drawable* iconDrawable = nullptr; +static DrawablePtr getIconDrawable( const std::string& name, + UIIconThemeManager* iconThemeManager ) { + DrawablePtr iconDrawable; if ( nullptr != iconThemeManager ) { UIIcon* icon = iconThemeManager->findIcon( name ); if ( icon ) { // TODO: Fix size - iconDrawable = icon->getSize( PixelDensity::dpToPx( 16 ) ); + iconDrawable = icon->createDrawable( PixelDensity::dpToPx( 16 ) ); } } if ( nullptr == iconDrawable ) diff --git a/src/eepp/ui/uimessagebox.cpp b/src/eepp/ui/uimessagebox.cpp index 444253374..7381b8f33 100644 --- a/src/eepp/ui/uimessagebox.cpp +++ b/src/eepp/ui/uimessagebox.cpp @@ -155,16 +155,17 @@ void UIMessageBox::setTheme( UITheme* theme ) { mButtonCancel->setTheme( theme ); if ( i18n( "msg_box_retry", "Retry" ) != mButtonOK->getText() ) { - Drawable* okIcon = getUISceneNode()->findIconDrawable( "ok", PixelDensity::dpToPxI( 16 ) ); - Drawable* cancelIcon = + DrawablePtr okIcon = + getUISceneNode()->findIconDrawable( "ok", PixelDensity::dpToPxI( 16 ) ); + DrawablePtr cancelIcon = getUISceneNode()->findIconDrawable( "cancel", PixelDensity::dpToPxI( 16 ) ); if ( NULL != okIcon ) { - mButtonOK->setIcon( okIcon ); + mButtonOK->setIcon( std::move( okIcon ) ); } if ( NULL != cancelIcon ) { - mButtonCancel->setIcon( cancelIcon ); + mButtonCancel->setIcon( std::move( cancelIcon ) ); } } diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index 997eb2e63..a8861f8cb 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -725,8 +725,8 @@ UINodeDrawable* UINode::setBackgroundFillEnabled( bool enabled ) { return mBackground; } -UINode* UINode::setBackgroundDrawable( Drawable* drawable, bool ownIt, int index ) { - setBackgroundFillEnabled( true )->setDrawable( index, drawable, ownIt ); +UINode* UINode::setBackgroundDrawable( DrawablePtr drawable, int index ) { + setBackgroundFillEnabled( true )->setDrawable( index, std::move( drawable ) ); return this; } @@ -838,8 +838,8 @@ UINodeDrawable* UINode::setForegroundFillEnabled( bool enabled ) { return mForeground; } -UINode* UINode::setForegroundDrawable( Drawable* drawable, bool ownIt, int index ) { - setForegroundFillEnabled( true )->setDrawable( index, drawable, ownIt ); +UINode* UINode::setForegroundDrawable( DrawablePtr drawable, int index ) { + setForegroundFillEnabled( true )->setDrawable( index, std::move( drawable ) ); return this; } @@ -1253,12 +1253,7 @@ UINode* UINode::setThemeSkin( UITheme* Theme, const std::string& skinName ) { UINode* UINode::setSkin( const UISkin& Skin ) { removeSkin(); - - writeNodeFlag( NODE_FLAG_SKIN_OWNER, 1 ); - - UISkin* SkinCopy = const_cast( &Skin )->clone(); - - mSkinState = UISkinState::New( SkinCopy ); + mSkinState = UISkinState::New( Skin.clone() ); onThemeLoaded(); @@ -1278,7 +1273,7 @@ UINode* UINode::setSkin( UISkin* skin ) { removeSkin(); - mSkinState = UISkinState::New( skin ); + mSkinState = UISkinState::New( skin->clone() ); mSkinState->setState( InitialState ); onThemeLoaded(); @@ -1302,12 +1297,6 @@ const Color& UINode::getSkinColor() const { } void UINode::removeSkin() { - if ( NULL != mSkinState && ( mNodeFlags & NODE_FLAG_SKIN_OWNER ) ) { - UISkin* tSkin = mSkinState->getSkin(); - - eeSAFE_DELETE( tSkin ); - } - eeSAFE_DELETE( mSkinState ); } diff --git a/src/eepp/ui/uinodedrawable.cpp b/src/eepp/ui/uinodedrawable.cpp index 467ccd1e6..e1271682e 100644 --- a/src/eepp/ui/uinodedrawable.cpp +++ b/src/eepp/ui/uinodedrawable.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -100,10 +101,6 @@ UINodeDrawable::~UINodeDrawable() { } void UINodeDrawable::clearDrawables() { - for ( auto& drawable : mGroup ) { - eeDelete( drawable.second ); - } - mGroup.clear(); mBackgroundColor.setColor( Color::Transparent ); } @@ -124,24 +121,24 @@ UINodeDrawable::LayerDrawable* UINodeDrawable::getLayer( int index ) { auto it = mGroup.find( index ); if ( it == mGroup.end() ) { - mGroup[index] = UINodeDrawable::LayerDrawable::New( this ); + mGroup[index] = LayerDrawablePtr( UINodeDrawable::LayerDrawable::New( this ) ); // HTML background-repeat defaults to "repeat", non-HTML to // "no-repeat". The LayerDrawable constructor uses NoRepeat // (the eepp/non-HTML default), so reset it for Html mode. if ( mBackgroundMode == BackgroundMode::Html ) { - auto* layer = mGroup[index]; + auto* layer = mGroup[index].get(); layer->setRepeatX( RepeatX::Repeat ); layer->setRepeatY( RepeatY::Repeat ); } } - return mGroup[index]; + return mGroup[index].get(); } -void UINodeDrawable::setDrawable( int index, Drawable* drawable, bool ownIt ) { +void UINodeDrawable::setDrawable( int index, DrawablePtr drawable ) { if ( drawable != getLayer( index )->getDrawable() ) { - getLayer( index )->setDrawable( drawable, ownIt ); + getLayer( index )->setDrawable( std::move( drawable ) ); } } @@ -245,7 +242,7 @@ void UINodeDrawable::setBackgroundMode( BackgroundMode mode ) { // still carry the LayerDrawable default (NoRepeat for both axes). if ( mode == BackgroundMode::Html ) { for ( auto& entry : mGroup ) { - auto* layer = entry.second; + auto* layer = entry.second.get(); if ( layer->getRepeatX() == RepeatX::NoRepeat && layer->getRepeatY() == RepeatY::NoRepeat ) { layer->setRepeatX( RepeatX::Repeat ); @@ -331,7 +328,7 @@ void UINodeDrawable::draw( const Vector2f& position, const Sizef& size, const Ui // "The background images are drawn on stacking context layers on top of each other. The first // layer specified is drawn as if it is closest to the user." for ( auto drawableIt = mGroup.rbegin(); drawableIt != mGroup.rend(); ++drawableIt ) { - UINodeDrawable::LayerDrawable* drawable = drawableIt->second; + UINodeDrawable::LayerDrawable* drawable = drawableIt->second.get(); bool clipContent = mBackgroundMode == BackgroundMode::Html && drawable->getClip() == LayerDrawable::Clip::ContentBox; @@ -411,9 +408,6 @@ UINodeDrawable::LayerDrawable::LayerDrawable( UINodeDrawable* container ) : mPositionY( "0px" ), mSizeEq( "auto" ), mNeedsUpdate( false ), - mOwnsDrawable( false ), - mDrawable( NULL ), - mResourceChangeCbId( 0 ), mRepeatX( RepeatX::NoRepeat ), mRepeatY( RepeatY::NoRepeat ), mOriginEq( "padding-box" ), @@ -428,13 +422,7 @@ UINodeDrawable::LayerDrawable::~LayerDrawable() { if ( mAsyncDrawableAlive ) mAsyncDrawableAlive->store( false, std::memory_order_release ); - if ( NULL != mDrawable && 0 != mResourceChangeCbId && mDrawable->isDrawableResource() ) { - reinterpret_cast( mDrawable ) - ->popResourceChangeCallback( mResourceChangeCbId ); - } - - if ( mOwnsDrawable ) - eeSAFE_DELETE( mDrawable ); + mResourceChangeConnection.disconnect(); } void UINodeDrawable::LayerDrawable::draw() { @@ -497,8 +485,8 @@ void UINodeDrawable::LayerDrawable::draw( const Vector2f& position, const Sizef& mDrawable->draw( Vector2f( xPos, effectivePos.y + mOffset.y ), tileSz ); break; case RepeatY::Repeat: - repeatYdraw( mDrawable, effectivePos, Vector2f( xPos - effectivePos.x, mOffset.y ), - mSize, tileSz ); + repeatYdraw( mDrawable.get(), effectivePos, + Vector2f( xPos - effectivePos.x, mOffset.y ), mSize, tileSz ); break; case RepeatY::Space: { if ( drawH <= 0 ) @@ -610,7 +598,7 @@ void UINodeDrawable::LayerDrawable::setSize( const Sizef& size ) { } } -Drawable* UINodeDrawable::LayerDrawable::getDrawable() const { +const DrawablePtr& UINodeDrawable::LayerDrawable::getDrawable() const { return mDrawable; } @@ -618,51 +606,30 @@ const std::string& UINodeDrawable::LayerDrawable::getDrawableRef() const { return mDrawableRef; } -void UINodeDrawable::LayerDrawable::setDrawable( Drawable* drawable, const bool& ownIt ) { +void UINodeDrawable::LayerDrawable::setDrawable( DrawablePtr drawable ) { if ( drawable == mDrawable ) return; - if ( NULL != mDrawable ) { - if ( mDrawable->isDrawableResource() ) { - reinterpret_cast( mDrawable ) - ->popResourceChangeCallback( mResourceChangeCbId ); - } + mResourceChangeConnection.disconnect(); - if ( mOwnsDrawable ) { - eeSAFE_DELETE( mDrawable ); - } - } - mTexture.reset(); - - mDrawable = drawable; + mDrawable = std::move( drawable ); mDrawableRef = ""; - mOwnsDrawable = ownIt; invalidate(); if ( NULL != mDrawable && mDrawable->isDrawableResource() ) { - mResourceChangeCbId = - reinterpret_cast( mDrawable ) - ->pushResourceChangeCallback( - [this]( Uint32, DrawableResource::Event event, DrawableResource* ) { - invalidate(); - if ( event == DrawableResource::Event::Unload ) { - mResourceChangeCbId = 0; - mDrawable = NULL; - mOwnsDrawable = false; - } - } ); + mResourceChangeConnection = + reinterpret_cast( mDrawable.get() ) + ->connectResourceChange( [this]( DrawableResource& ) { invalidate(); } ); } } void UINodeDrawable::LayerDrawable::setDrawable( TexturePtr texture ) { - Texture* drawable = texture.get(); - setDrawable( drawable, false ); - mTexture = std::move( texture ); + setDrawable( texture ? TextureDrawable::New( std::move( texture ) ) : DrawablePtr{} ); } void UINodeDrawable::LayerDrawable::setDrawable( const std::string& drawableRef ) { if ( drawableRef == "none" ) { - setDrawable( nullptr, false ); + setDrawable( DrawablePtr{} ); return; } @@ -671,10 +638,9 @@ void UINodeDrawable::LayerDrawable::setDrawable( const std::string& drawableRef return; } - bool ownIt; - Drawable* drawable = createDrawable( drawableRef, mSize, ownIt ); + DrawablePtr drawable = createDrawable( drawableRef, mSize ); - setDrawable( drawable, ownIt ); + setDrawable( std::move( drawable ) ); mDrawableRef = drawableRef; } @@ -714,7 +680,11 @@ bool UINodeDrawable::LayerDrawable::loadRemoteDrawable( const std::string& value std::string url = uri.toString(); ResourceScopePtr resourceScope = scene->getResourceScope(); if ( TexturePtr texture = resourceScope->findTexture( url ) ) { - if ( mDrawable != texture.get() ) { + TextureDrawable* textureDrawable = + mDrawable && mDrawable->getDrawableType() == Drawable::TEXTUREDRAWABLE + ? static_cast( mDrawable.get() ) + : nullptr; + if ( !textureDrawable || textureDrawable->getTexture() != texture ) { ++mRemoteDrawableLoadId; setDrawable( std::move( texture ) ); } @@ -750,7 +720,7 @@ bool UINodeDrawable::LayerDrawable::loadRemoteDrawable( const std::string& value [alive, loadId, texture, imageData = std::move( imageData ), this]( UISceneNode* ) mutable { if ( !alive || !alive->load( std::memory_order_acquire ) || - loadId != mRemoteDrawableLoadId || mDrawable != texture.get() ) + loadId != mRemoteDrawableLoadId ) return; Image image( reinterpret_cast( imageData.data() ), @@ -769,10 +739,10 @@ bool UINodeDrawable::LayerDrawable::loadRemoteDrawable( const std::string& value return true; } -Drawable* UINodeDrawable::LayerDrawable::createDrawable( const std::string& value, - const Sizef& size, bool& ownIt ) { +DrawablePtr UINodeDrawable::LayerDrawable::createDrawable( const std::string& value, + const Sizef& size ) { return CSS::StyleSheetSpecification::instance()->getDrawableImageParser().createDrawable( - value, size, ownIt, mContainer->getOwner() ); + value, size, mContainer->getOwner() ); } const Vector2f& UINodeDrawable::LayerDrawable::getOffset() const { diff --git a/src/eepp/ui/uipushbutton.cpp b/src/eepp/ui/uipushbutton.cpp index e65346603..fd913a2c5 100644 --- a/src/eepp/ui/uipushbutton.cpp +++ b/src/eepp/ui/uipushbutton.cpp @@ -397,13 +397,13 @@ void UIPushButton::updateTextBox() { } } -UIPushButton* UIPushButton::setIcon( Drawable* icon, bool ownIt ) { +UIPushButton* UIPushButton::setIcon( DrawablePtr icon ) { if ( nullptr == mIcon || mIcon->getDrawable() != icon ) { if ( icon ) getIcon()->setPixelsSize( icon->getPixelsSize() ); if ( icon == nullptr && mIcon == nullptr ) return this; - getIcon()->setDrawable( icon, ownIt ); + getIcon()->setDrawable( std::move( icon ) ); updateTextBox(); } return this; @@ -681,18 +681,15 @@ bool UIPushButton::applyProperty( const StyleSheetProperty& attribute ) { break; case PropertyId::Icon: { const std::string& val = attribute.value(); - Drawable* icon = NULL; - bool ownIt; UIIcon* iconF = getUISceneNode()->findIcon( val ); if ( iconF ) { - setIcon( iconF->getSize( + setIcon( iconF->createDrawable( eemax( mSize.getHeight() - mPaddingPx.Top - mPadding.Bottom, - PixelDensity::dpToPxI( 16 ) ) ) ); - } else if ( NULL != - ( icon = StyleSheetSpecification::instance() - ->getDrawableImageParser() - .createDrawable( val, getPixelsSize(), ownIt, this ) ) ) { - setIcon( icon, ownIt ); + PixelDensity::dpToPxI( 16 ) ) ) ); + } else if ( DrawablePtr icon = StyleSheetSpecification::instance() + ->getDrawableImageParser() + .createDrawable( val, getPixelsSize(), this ) ) { + setIcon( std::move( icon ) ); } break; } diff --git a/src/eepp/ui/uiscenenode.cpp b/src/eepp/ui/uiscenenode.cpp index 3831d3f04..450d4e939 100644 --- a/src/eepp/ui/uiscenenode.cpp +++ b/src/eepp/ui/uiscenenode.cpp @@ -1347,11 +1347,10 @@ UIIcon* UISceneNode::findIcon( const std::string& iconName ) { return getUIIconThemeManager()->findIcon( iconName ); } -Drawable* UISceneNode::findIconDrawable( const std::string& iconName, const size_t& drawableSize ) { +DrawablePtr UISceneNode::findIconDrawable( const std::string& iconName, + const size_t& drawableSize ) { UIIcon* icon = findIcon( iconName ); - if ( icon ) - return icon->getSize( drawableSize ); - return nullptr; + return icon ? icon->createDrawable( drawableSize ) : DrawablePtr{}; } CSS::MediaFeatures UISceneNode::getMediaFeatures() const { diff --git a/src/eepp/ui/uiskin.cpp b/src/eepp/ui/uiskin.cpp index efc498bdf..9d144db82 100644 --- a/src/eepp/ui/uiskin.cpp +++ b/src/eepp/ui/uiskin.cpp @@ -31,23 +31,31 @@ Sizef UISkin::getPixelsSize( const Uint32& state ) { return StateListDrawable::getPixelsSize( state ); } -UISkin* UISkin::clone( const std::string& NewName ) { - UISkin* SkinS = UISkin::New( NewName ); - - SkinS->mColor = mColor; - SkinS->mPosition = mPosition; - SkinS->mDrawables = mDrawables; - SkinS->mCurrentState = mCurrentState; - SkinS->mCurrentDrawable = mCurrentDrawable; - SkinS->mDrawablesOwnership = mDrawablesOwnership; - - return SkinS; +ResourcePtr UISkin::clone( const std::string& newName ) const { + auto skin = ResourcePtr( eeNew( UISkin, ( newName ) ), ResourceDeleter() ); + skin->setColor( mColor ); + skin->setPosition( mPosition ); + for ( const auto& state : mDrawables ) { + if ( !state.second ) + continue; + DrawablePtr drawable = state.second->createInstance(); + if ( !drawable ) + return {}; + skin->setStateDrawable( state.first, std::move( drawable ) ); + } + skin->mDrawableColors = mDrawableColors; + skin->setState( mCurrentState ); + return skin; } -UISkin* UISkin::clone() { +ResourcePtr UISkin::clone() const { return clone( mName ); } +DrawablePtr UISkin::createInstance() const { + return clone(); +} + Rectf UISkin::getBorderSize() { return getBorderSize( UIState::StateFlagNormal ); } @@ -55,7 +63,7 @@ Rectf UISkin::getBorderSize() { Rectf UISkin::getBorderSize( const Uint32& state ) { if ( hasDrawableState( state ) && mDrawables[state]->getDrawableType() == EE::Graphics::Drawable::Type::NINEPATCH ) { - NinePatch* ninePatch( static_cast( mDrawables[state] ) ); + NinePatch* ninePatch( static_cast( mDrawables[state].get() ) ); TextureRegion* stl( ninePatch->getTextureRegion( NinePatch::Left ) ); TextureRegion* str( ninePatch->getTextureRegion( NinePatch::Right ) ); TextureRegion* stt( ninePatch->getTextureRegion( NinePatch::Up ) ); diff --git a/src/eepp/ui/uiskinstate.cpp b/src/eepp/ui/uiskinstate.cpp index ab7a3164e..a81fcd21e 100644 --- a/src/eepp/ui/uiskinstate.cpp +++ b/src/eepp/ui/uiskinstate.cpp @@ -3,18 +3,19 @@ namespace EE { namespace UI { -UISkinState* UISkinState::New( UISkin* skin ) { - return eeNew( UISkinState, ( skin ) ); +UISkinState* UISkinState::New( ResourcePtr skin ) { + return eeNew( UISkinState, ( std::move( skin ) ) ); } -UISkinState::UISkinState( UISkin* Skin ) : mSkin( Skin ), mCurrentColor( Color::White ) { +UISkinState::UISkinState( ResourcePtr skin ) : + mSkin( std::move( skin ) ), mCurrentColor( Color::White ) { eeASSERT( NULL != mSkin ); } UISkinState::~UISkinState() {} UISkin* UISkinState::getSkin() const { - return mSkin; + return mSkin.get(); } bool UISkinState::stateExists( const Uint32& State ) const { diff --git a/src/eepp/ui/uisprite.cpp b/src/eepp/ui/uisprite.cpp index 91f34e117..5eb1eb4d5 100644 --- a/src/eepp/ui/uisprite.cpp +++ b/src/eepp/ui/uisprite.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -14,17 +15,13 @@ UISprite* UISprite::New() { UISprite::UISprite() : UIWidget( "sprite" ), - mSprite( NULL ), mRender( RENDER_NORMAL ), mAlignOffset( 0, 0 ), mTextureRegionLast( NULL ) { subscribeScheduledUpdate(); } -UISprite::~UISprite() { - if ( deallocSprite() ) - eeSAFE_DELETE( mSprite ); -} +UISprite::~UISprite() {} Uint32 UISprite::getType() const { return UI_TYPE_SPRITE; @@ -34,16 +31,10 @@ bool UISprite::isType( const Uint32& type ) const { return UISprite::getType() == type ? true : UIWidget::isType( type ); } -Uint32 UISprite::deallocSprite() { - return mNodeFlags & NODE_FLAG_FREE_USE; -} - -UISprite* UISprite::setSprite( Graphics::Sprite* sprite ) { - if ( deallocSprite() ) - eeSAFE_DELETE( mSprite ); - - mSprite = sprite; - mSprite->setAutoAnimate( false ); +UISprite* UISprite::setSprite( Graphics::SpritePtr sprite ) { + mSprite = std::move( sprite ); + if ( mSprite ) + mSprite->setAutoAnimate( false ); updateSize(); return this; @@ -103,11 +94,7 @@ void UISprite::setAlpha( const Float& alpha ) { UIWidget::setAlpha( alpha ); } -Graphics::Sprite* UISprite::getSprite() const { - return mSprite; -} - -Drawable* UISprite::getDrawable() const { +const Graphics::SpritePtr& UISprite::getSprite() const { return mSprite; } @@ -189,15 +176,6 @@ const Vector2f& UISprite::getAlignOffset() const { return mAlignOffset; } -UISprite* UISprite::setIsSpriteOwner( const bool& dealloc ) { - writeNodeFlag( NODE_FLAG_FREE_USE, dealloc ? 1 : 0 ); - return this; -} - -bool UISprite::getDeallocSprite() { - return 0 != ( mNodeFlags & NODE_FLAG_FREE_USE ); -} - void UISprite::onSizeChange() { autoAlign(); notifyLayoutAttrChange( LayoutInvalidation::Self ); @@ -238,7 +216,7 @@ bool UISprite::applyProperty( const StyleSheetProperty& attribute ) { path = func.getParameters().at( 0 ); } - Drawable* res = NULL; + DrawablePtr res; UISceneNode* scene = getUISceneNode(); if ( scene ) res = DrawableSearcher::searchByName( path, true, scene->getReferer(), @@ -246,15 +224,30 @@ bool UISprite::applyProperty( const StyleSheetProperty& attribute ) { else res = DrawableSearcher::searchByName( path, true ); - if ( NULL != res ) { - setIsSpriteOwner( true ); - - if ( res->getDrawableType() == Drawable::SPRITE ) { - setSprite( static_cast( res ) ); - } else if ( res->getDrawableType() == Drawable::TEXTUREREGION ) { - setSprite( Sprite::New( static_cast( res ) ) ); - } else if ( res->getDrawableType() == Drawable::TEXTURE ) { - setSprite( Sprite::New( static_cast( res )->getTextureId() ) ); + if ( res ) { + switch ( res->getDrawableType() ) { + case Drawable::SPRITE: + setSprite( std::static_pointer_cast( std::move( res ) ) ); + break; + case Drawable::TEXTUREREGION: + setSprite( + Sprite::New( std::static_pointer_cast( res ).get() ) ); + break; + case Drawable::TEXTUREDRAWABLE: { + auto sprite = Sprite::New(); + sprite->createStatic( + std::static_pointer_cast( res )->getTexture() ); + setSprite( std::move( sprite ) ); + break; + } + case Drawable::TEXTURE: { + auto sprite = Sprite::New(); + sprite->createStatic( std::static_pointer_cast( res ) ); + setSprite( std::move( sprite ) ); + break; + } + default: + break; } } break; diff --git a/src/eepp/ui/uisvg.cpp b/src/eepp/ui/uisvg.cpp index 03edcfafa..64f6eef2b 100644 --- a/src/eepp/ui/uisvg.cpp +++ b/src/eepp/ui/uisvg.cpp @@ -21,24 +21,6 @@ class XmlStringWriter : public pugi::xml_writer { } }; -class PendingSpriteTransfer { - public: - explicit PendingSpriteTransfer( Sprite* sprite ) : mSprite( sprite ) {} - PendingSpriteTransfer( const PendingSpriteTransfer& ) = delete; - PendingSpriteTransfer& operator=( const PendingSpriteTransfer& ) = delete; - - ~PendingSpriteTransfer() { eeSAFE_DELETE( mSprite ); } - - Sprite* release() { - Sprite* sprite = mSprite; - mSprite = nullptr; - return sprite; - } - - private: - Sprite* mSprite{ nullptr }; -}; - } // namespace UISvg* UISvg::New() { @@ -104,17 +86,12 @@ void UISvg::rasterizeSvg( const std::string& svgXml ) { if ( !texture ) return; - Sprite* sprite = Sprite::New(); + SpritePtr sprite = Sprite::New(); sprite->createStatic( std::move( texture ) ); - sprite->setAsTextureRegionOwner( true ); - auto spriteTransfer = std::make_shared( sprite ); - - runOnMainThread( [this, spriteTransfer] { - Sprite* sprite = spriteTransfer->release(); - if ( sprite ) { - setDrawable( sprite, true ); - } + runOnMainThread( [this, sprite = std::move( sprite )]() mutable { + if ( sprite ) + setDrawable( std::move( sprite ) ); } ); } diff --git a/src/eepp/ui/uitabwidget.cpp b/src/eepp/ui/uitabwidget.cpp index 128d2c3d8..35a4745c4 100644 --- a/src/eepp/ui/uitabwidget.cpp +++ b/src/eepp/ui/uitabwidget.cpp @@ -525,11 +525,11 @@ void UITabWidget::updateTabs() { } } -UITab* UITabWidget::createTab( const String& text, UINode* nodeOwned, Drawable* icon ) { +UITab* UITabWidget::createTab( const String& text, UINode* nodeOwned, DrawablePtr icon ) { UITab* tab = UITab::New(); tab->setParent( mTabBar ); tab->setFlags( UI_VALIGN_CENTER | UI_HALIGN_CENTER | UI_AUTO_SIZE ); - tab->setIcon( icon ); + tab->setIcon( std::move( icon ) ); tab->setText( text ); tab->setVisible( true ); tab->setEnabled( true ); @@ -553,8 +553,8 @@ UITab* UITabWidget::createTab( const String& text, UINode* nodeOwned, Drawable* return tab; } -UITab* UITabWidget::add( const String& text, UINode* nodeOwned, Drawable* icon ) { - UITab* tab = createTab( text, nodeOwned, icon ); +UITab* UITabWidget::add( const String& text, UINode* nodeOwned, DrawablePtr icon ) { + UITab* tab = createTab( text, nodeOwned, std::move( icon ) ); add( tab ); return tab; } @@ -789,9 +789,9 @@ void UITabWidget::removeAllTabs( bool destroyOwnedNode, bool immediateClose ) { } } -void UITabWidget::insertTab( const String& text, UINode* nodeOwned, Drawable* icon, +void UITabWidget::insertTab( const String& text, UINode* nodeOwned, DrawablePtr icon, const Uint32& index ) { - insertTab( createTab( text, nodeOwned, icon ), index ); + insertTab( createTab( text, nodeOwned, std::move( icon ) ), index ); } void UITabWidget::insertTab( UITab* Tab, const Uint32& index ) { diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index 44b09a486..8d103c349 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -979,11 +979,9 @@ void UITextInput::setEscapePastedText( bool escapePastedText ) { mEscapePastedText = escapePastedText; } -Drawable* UITextInput::findIcon( const std::string& name ) { +DrawablePtr UITextInput::findIcon( const std::string& name ) { UIIcon* icon = getUISceneNode()->findIcon( name ); - if ( icon ) - return icon->getSize( mMenuIconSize ); - return nullptr; + return icon ? icon->createDrawable( mMenuIconSize ) : DrawablePtr{}; } UIMenuItem* UITextInput::menuAdd( UIPopUpMenu* menu, const String& translateString, diff --git a/src/eepp/ui/uitextureregion.cpp b/src/eepp/ui/uitextureregion.cpp index aa4b481f6..0d86876bc 100644 --- a/src/eepp/ui/uitextureregion.cpp +++ b/src/eepp/ui/uitextureregion.cpp @@ -75,21 +75,15 @@ void UITextureRegion::draw() { UINode::draw(); if ( NULL != mTextureRegion && 0.f != mAlpha ) { - Sizef oDestSize = mTextureRegion->getDestSize(); - Vector2i oOff = mTextureRegion->getOffset(); + Sizef destSize = mTextureRegion->getDestSize(); + Vector2i offset = mTextureRegion->getOffset(); if ( mScaleType == UIScaleType::Expand ) { - mTextureRegion->setOffset( Vector2i( 0, 0 ) ); - mTextureRegion->setDestSize( - Vector2f( (int)mSize.x - mPaddingPx.Left - mPaddingPx.Right, - (int)mSize.y - mPaddingPx.Top - mPaddingPx.Bottom ) ); - - autoAlign(); - - drawTextureRegion(); - + offset = Vector2i::Zero; + destSize = Vector2f( (int)mSize.x - mPaddingPx.Left - mPaddingPx.Right, + (int)mSize.y - mPaddingPx.Top - mPaddingPx.Bottom ); } else if ( mScaleType == UIScaleType::FitInside ) { - mTextureRegion->setOffset( Vector2i( 0, 0 ) ); + offset = Vector2i::Zero; Sizef pxSize = mTextureRegion->getPixelsSize(); Float Scale1 = ( mSize.x - mPaddingPx.Left - mPaddingPx.Right ) / (Float)pxSize.x; @@ -99,44 +93,33 @@ void UITextureRegion::draw() { if ( Scale2 < Scale1 ) Scale1 = Scale2; - Sizef dst( pxSize.x * Scale1, pxSize.y * Scale1 ); - mTextureRegion->setDestSize( dst.floor() ); - - autoAlign(); - - drawTextureRegion(); + destSize = Sizef( pxSize.x * Scale1, pxSize.y * Scale1 ).floor(); } else { - mTextureRegion->setDestSize( Vector2f( (Float)pxSize.x, (Float)pxSize.y ) ); - - autoAlign(); - - drawTextureRegion(); + destSize = Vector2f( (Float)pxSize.x, (Float)pxSize.y ); } } else { - mTextureRegion->setOffset( - Vector2i( (Int32)( (Float)oOff.x / mTextureRegion->getPixelDensity() * - PixelDensity::getPixelDensity() ), - (Int32)( (Float)oOff.y / mTextureRegion->getPixelDensity() * - PixelDensity::getPixelDensity() ) ) ); - - mTextureRegion->setDestSize( Vector2f( (Float)mTextureRegion->getPixelsSize().x, - (Float)mTextureRegion->getPixelsSize().y ) ); - - autoAlign(); - - drawTextureRegion(); + offset = Vector2i( (Int32)( (Float)offset.x / mTextureRegion->getPixelDensity() * + PixelDensity::getPixelDensity() ), + (Int32)( (Float)offset.y / mTextureRegion->getPixelDensity() * + PixelDensity::getPixelDensity() ) ); + destSize = Vector2f( (Float)mTextureRegion->getPixelsSize().x, + (Float)mTextureRegion->getPixelsSize().y ); } - mTextureRegion->setDestSize( oDestSize ); - mTextureRegion->setOffset( oOff ); + autoAlign( destSize ); + drawTextureRegion( destSize, offset ); } } } -void UITextureRegion::drawTextureRegion() { - mTextureRegion->draw( std::trunc( mScreenPos.x ) + (int)mAlignOffset.x, - std::trunc( mScreenPos.y ) + (int)mAlignOffset.y, mColor, 0.f, - Vector2f::One, getBlendMode(), mRender ); +void UITextureRegion::drawTextureRegion( const Sizef& destSize, const Vector2i& offset ) { + const TexturePtr& texture = mTextureRegion->getTexture(); + if ( texture ) + texture->drawEx( std::trunc( mScreenPos.x ) + (int)mAlignOffset.x + offset.x, + std::trunc( mScreenPos.y ) + (int)mAlignOffset.y + offset.y, destSize.x, + destSize.y, 0.f, Vector2f::One, mColor, mColor, mColor, mColor, + getBlendMode(), mRender, OriginPoint( OriginPoint::OriginCenter ), + mTextureRegion->getSrcRect() ); } void UITextureRegion::setAlpha( const Float& alpha ) { @@ -169,19 +152,22 @@ void UITextureRegion::setRenderMode( const RenderMode& render ) { void UITextureRegion::autoAlign() { if ( NULL == mTextureRegion ) return; + autoAlign( mTextureRegion->getDestSize() ); +} +void UITextureRegion::autoAlign( const Sizef& drawableSize ) { if ( Font::getHorizontalAlign( mFlags ) == UI_HALIGN_CENTER ) { - mAlignOffset.x = ( mSize.getWidth() - mTextureRegion->getDestSize().x ) / 2; + mAlignOffset.x = ( mSize.getWidth() - drawableSize.x ) / 2; } else if ( Font::getHorizontalAlign( mFlags ) == UI_HALIGN_RIGHT ) { - mAlignOffset.x = mSize.getWidth() - mTextureRegion->getDestSize().x - mPaddingPx.Right; + mAlignOffset.x = mSize.getWidth() - drawableSize.x - mPaddingPx.Right; } else { mAlignOffset.x = mPaddingPx.Left; } if ( Font::getVerticalAlign( mFlags ) == UI_VALIGN_CENTER ) { - mAlignOffset.y = ( mSize.getHeight() - mTextureRegion->getDestSize().y ) / 2; + mAlignOffset.y = ( mSize.getHeight() - drawableSize.y ) / 2; } else if ( Font::getVerticalAlign( mFlags ) == UI_VALIGN_BOTTOM ) { - mAlignOffset.y = mSize.getHeight() - mTextureRegion->getDestSize().y - mPaddingPx.Bottom; + mAlignOffset.y = mSize.getHeight() - drawableSize.y - mPaddingPx.Bottom; } else { mAlignOffset.y = mPaddingPx.Top; } diff --git a/src/eepp/ui/uitheme.cpp b/src/eepp/ui/uitheme.cpp index 5ae328da0..a20bb6e9d 100644 --- a/src/eepp/ui/uitheme.cpp +++ b/src/eepp/ui/uitheme.cpp @@ -100,7 +100,8 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* if ( String::startsWith( name, sAbbrIcon ) ) { auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); - icon->setSize( textureRegion->getPixelsSize().getWidth(), textureRegion ); + icon->setSource( textureRegion->getPixelsSize().getWidth(), + textureRegion->createInstance() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { std::vector dotParts = String::split( name, '.' ); @@ -140,7 +141,7 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* int stateNum = UIState::getStateNumber( nameParts[nameParts.size() - 1] ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( stateNum, drawable ); + skins[skinName]->setStateDrawable( stateNum, drawable->createInstance() ); } else { std::vector nameParts = String::split( name, '_' ); @@ -155,7 +156,8 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* skins[skinName] = tTheme->add( UISkin::New( skinName ) ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( stateNum, textureRegion ); + skins[skinName]->setStateDrawable( stateNum, + textureRegion->createInstance() ); } } } @@ -199,7 +201,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, TextureRegion::New( TextureFactory::instance()->loadFromFile( fpath ), name ); tSG->add( drawable ); auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); - icon->setSize( drawable->getPixelsSize().getWidth(), drawable ); + icon->setSource( drawable->getPixelsSize().getWidth(), drawable->createInstance() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { std::vector dotParts = String::split( name, '.' ); @@ -240,7 +242,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, int stateNum = UIState::getStateNumber( nameParts[nameParts.size() - 1] ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( stateNum, drawable ); + skins[skinName]->setStateDrawable( stateNum, drawable->createInstance() ); } else { std::vector nameParts = String::split( name, '_' ); @@ -258,7 +260,8 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, skins[skinName] = tTheme->add( UISkin::New( skinName ) ); if ( -1 != stateNum ) - skins[skinName]->setStateDrawable( stateNum, textureRegion ); + skins[skinName]->setStateDrawable( + stateNum, textureRegion->createInstance() ); } } } diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 483a0a9d1..5d6fcb467 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -289,8 +289,8 @@ UIWidget* UITreeView::updateCell( const Vector2& posIndex, const ModelInd if ( !mExpandersAsIcons && mExpandIcon && mContractIcon ) { minIndent = eemax( - mExpandIcon->getSize( mExpanderIconSize )->getPixelsSize().getWidth(), - mContractIcon->getSize( mExpanderIconSize )->getPixelsSize().getWidth() ) + + mExpandIcon->getSource( mExpanderIconSize )->getPixelsSize().getWidth(), + mContractIcon->getSource( mExpanderIconSize )->getPixelsSize().getWidth() ) + image->getLayoutPixelsMargin().Right; } @@ -300,14 +300,14 @@ UIWidget* UITreeView::updateCell( const Vector2& posIndex, const ModelInd if ( hasChildren ) { UIIcon* icon = getIndexMetadata( index ).open ? mExpandIcon : mContractIcon; - Drawable* drawable = icon ? icon->getSize( mExpanderIconSize ) : nullptr; + DrawablePtr drawable = icon ? icon->createDrawable( mExpanderIconSize ) : DrawablePtr{}; if ( drawable == nullptr ) { image->setVisible( false ); } else { image->setVisible( true ); image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) ); - image->setDrawable( drawable ); + image->setDrawable( std::move( drawable ) ); if ( !mExpandersAsIcons ) indentation = indentation - image->getPixelsSize().getWidth(); } @@ -330,7 +330,7 @@ UIWidget* UITreeView::updateCell( const Vector2& posIndex, const ModelInd cell->setIcon( icon.asDrawable() ); } else if ( icon.is( Variant::Type::Icon ) && icon.asIcon() ) { isVisible = true; - cell->setIcon( icon.asIcon()->getSize( mIconSize ) ); + cell->setIcon( icon.asIcon()->createDrawable( mIconSize ) ); } if ( cell->hasIcon() ) cell->getIcon()->setVisible( isVisible ); diff --git a/src/modules/eterm/include/eterm/ui/uiterminal.hpp b/src/modules/eterm/include/eterm/ui/uiterminal.hpp index 697d5e7ee..8125bcbc7 100644 --- a/src/modules/eterm/include/eterm/ui/uiterminal.hpp +++ b/src/modules/eterm/include/eterm/ui/uiterminal.hpp @@ -171,7 +171,7 @@ class UITerminal : public UIWidget { virtual bool onCreateContextMenu( const Vector2i& position, const Uint32& flags ); - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); void createDefaultContextMenuOptions( UIPopUpMenu* menu ); diff --git a/src/modules/eterm/src/eterm/ui/uiterminal.cpp b/src/modules/eterm/src/eterm/ui/uiterminal.cpp index b44cdbd30..1346001c0 100644 --- a/src/modules/eterm/src/eterm/ui/uiterminal.cpp +++ b/src/modules/eterm/src/eterm/ui/uiterminal.cpp @@ -561,11 +561,9 @@ void UITerminal::createDefaultContextMenuOptions( UIPopUpMenu* menu ) { ->setEnabled( !getUISceneNode()->getWindow()->getClipboard()->getText().empty() ); } -Drawable* UITerminal::findIcon( const std::string& name ) { +DrawablePtr UITerminal::findIcon( const std::string& name ) { UIIcon* icon = getUISceneNode()->findIcon( name ); - if ( icon ) - return icon->getSize( mMenuIconSize ); - return nullptr; + return icon ? icon->createDrawable( mMenuIconSize ) : DrawablePtr{}; } UIMenuItem* UITerminal::menuAdd( UIPopUpMenu* menu, const String& translateString, diff --git a/src/modules/maps/include/eepp/maps/gameobjectsprite.hpp b/src/modules/maps/include/eepp/maps/gameobjectsprite.hpp index c906cc55f..376d34339 100644 --- a/src/modules/maps/include/eepp/maps/gameobjectsprite.hpp +++ b/src/modules/maps/include/eepp/maps/gameobjectsprite.hpp @@ -3,16 +3,13 @@ #include #include - -namespace EE { namespace Graphics { -class Sprite; -}} // namespace EE::Graphics +#include namespace EE { namespace Maps { class EE_MAPS_API GameObjectSprite : public GameObject { public: - GameObjectSprite( const Uint32& Flags, MapLayer* Layer, Graphics::Sprite* Sprite = NULL ); + GameObjectSprite( const Uint32& Flags, MapLayer* Layer, Graphics::SpritePtr sprite = {} ); virtual ~GameObjectSprite(); @@ -30,9 +27,9 @@ class EE_MAPS_API GameObjectSprite : public GameObject { virtual Sizei getSize(); - Graphics::Sprite* getSprite() const; + const Graphics::SpritePtr& getSprite() const; - void setSprite( Graphics::Sprite* sprite ); + void setSprite( Graphics::SpritePtr sprite ); virtual Uint32 getType() const; @@ -45,7 +42,7 @@ class EE_MAPS_API GameObjectSprite : public GameObject { virtual void setDataId( Uint32 Id ); protected: - Graphics::Sprite* mSprite; + Graphics::SpritePtr mSprite; Vector2i mTilePos; }; diff --git a/src/modules/maps/include/eepp/maps/gameobjecttextureregion.hpp b/src/modules/maps/include/eepp/maps/gameobjecttextureregion.hpp index 760d040b2..b000a62b8 100644 --- a/src/modules/maps/include/eepp/maps/gameobjecttextureregion.hpp +++ b/src/modules/maps/include/eepp/maps/gameobjecttextureregion.hpp @@ -42,7 +42,7 @@ class EE_MAPS_API GameObjectTextureRegion : public GameObject { virtual void setDataId( Uint32 Id ); protected: - Graphics::TextureRegion* mTextureRegion; + TextureRegionPtr mTextureRegion; Vector2f mPos; Vector2i mTilePos; }; diff --git a/src/modules/maps/include/eepp/maps/gameobjectvirtual.hpp b/src/modules/maps/include/eepp/maps/gameobjectvirtual.hpp index 61ee73a85..5bbb9f4f3 100644 --- a/src/modules/maps/include/eepp/maps/gameobjectvirtual.hpp +++ b/src/modules/maps/include/eepp/maps/gameobjectvirtual.hpp @@ -49,7 +49,7 @@ class EE_MAPS_API GameObjectVirtual : public GameObject { Uint32 mDataId; Vector2f mPos; MapLayer* mLayer; - TextureRegion* mTextureRegion; + TextureRegionPtr mTextureRegion; }; }} // namespace EE::Maps diff --git a/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp b/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp index e31a6ae25..13b4cca08 100644 --- a/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjectsprite.cpp @@ -7,8 +7,8 @@ namespace EE { namespace Maps { GameObjectSprite::GameObjectSprite( const Uint32& Flags, MapLayer* Layer, - Graphics::Sprite* Sprite ) : - GameObject( Flags, Layer ), mSprite( Sprite ) { + Graphics::SpritePtr sprite ) : + GameObject( Flags, Layer ), mSprite( std::move( sprite ) ) { if ( NULL != mSprite ) { mSprite->setRenderMode( getRenderModeFromFlags() ); mSprite->setBlendMode( getBlendModeFromFlags() ); @@ -17,9 +17,7 @@ GameObjectSprite::GameObjectSprite( const Uint32& Flags, MapLayer* Layer, assignTilePos(); } -GameObjectSprite::~GameObjectSprite() { - eeSAFE_DELETE( mSprite ); -} +GameObjectSprite::~GameObjectSprite() {} Uint32 GameObjectSprite::getType() const { return GAMEOBJECT_TYPE_SPRITE; @@ -109,13 +107,12 @@ Sizei GameObjectSprite::getSize() { return Sizei(); } -Graphics::Sprite* GameObjectSprite::getSprite() const { +const Graphics::SpritePtr& GameObjectSprite::getSprite() const { return mSprite; } -void GameObjectSprite::setSprite( Graphics::Sprite* sprite ) { - eeSAFE_DELETE( mSprite ); - mSprite = sprite; +void GameObjectSprite::setSprite( Graphics::SpritePtr sprite ) { + mSprite = std::move( sprite ); mSprite->setRenderMode( getRenderModeFromFlags() ); mSprite->setBlendMode( getBlendModeFromFlags() ); mSprite->setAutoAnimate( false ); @@ -134,7 +131,7 @@ Uint32 GameObjectSprite::getDataId() { } void GameObjectSprite::setDataId( Uint32 Id ) { - Graphics::Sprite* tSprite = NULL; + Graphics::SpritePtr tSprite; if ( mFlags & GObjFlags::GAMEOBJECT_ANIMATED ) { std::vector tTextureRegionVec = @@ -145,7 +142,7 @@ void GameObjectSprite::setDataId( Uint32 Id ) { tSprite->createAnimation(); tSprite->addFrames( tTextureRegionVec ); - setSprite( tSprite ); + setSprite( std::move( tSprite ) ); } } else { Graphics::TextureRegion* tTextureRegion = diff --git a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp index 77e7b1d23..23eeca3de 100644 --- a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp @@ -9,7 +9,8 @@ namespace EE { namespace Maps { GameObjectTextureRegion::GameObjectTextureRegion( const Uint32& Flags, MapLayer* Layer, Graphics::TextureRegion* TextureRegion, const Vector2f& Pos ) : - GameObject( Flags, Layer ), mTextureRegion( TextureRegion ), mPos( Pos ) { + GameObject( Flags, Layer ), mPos( Pos ) { + setTextureRegion( TextureRegion ); assignTilePos(); } @@ -44,7 +45,8 @@ void GameObjectTextureRegion::draw() { getRenderModeFromFlags() ); } else { mTextureRegion->draw( mPos.x, mPos.y, *LM->getTileColor( Tile ), getRotation(), - Vector2f::One, BlendMode::Alpha(), getRenderModeFromFlags() ); + Vector2f::One, BlendMode::Alpha(), + getRenderModeFromFlags() ); } } else { if ( LM->isByVertex() ) { @@ -99,11 +101,14 @@ Sizei GameObjectTextureRegion::getSize() { } Graphics::TextureRegion* GameObjectTextureRegion::getTextureRegion() const { - return mTextureRegion; + return mTextureRegion.get(); } void GameObjectTextureRegion::setTextureRegion( Graphics::TextureRegion* TextureRegion ) { - mTextureRegion = TextureRegion; + mTextureRegion = + TextureRegion + ? std::static_pointer_cast( TextureRegion->createInstance() ) + : TextureRegionPtr{}; } Uint32 GameObjectTextureRegion::getDataId() { diff --git a/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp b/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp index 45d5e592f..4d0a9b5aa 100644 --- a/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp @@ -10,23 +10,16 @@ namespace EE { namespace Maps { GameObjectVirtual::GameObjectVirtual( Uint32 DataId, MapLayer* Layer, const Uint32& Flags, Uint32 Type, const Vector2f& Pos ) : - GameObject( Flags, Layer ), - mType( Type ), - mDataId( DataId ), - mPos( Pos ), - mLayer( NULL ), - mTextureRegion( NULL ) {} + GameObject( Flags, Layer ), mType( Type ), mDataId( DataId ), mPos( Pos ), mLayer( NULL ) {} GameObjectVirtual::GameObjectVirtual( TextureRegion* TextureRegion, MapLayer* Layer, const Uint32& Flags, Uint32 Type, const Vector2f& Pos ) : - GameObject( Flags, Layer ), - mType( Type ), - mDataId( 0 ), - mPos( Pos ), - mLayer( Layer ), - mTextureRegion( TextureRegion ) { - if ( NULL != TextureRegion ) + GameObject( Flags, Layer ), mType( Type ), mDataId( 0 ), mPos( Pos ), mLayer( Layer ) { + if ( NULL != TextureRegion ) { mDataId = TextureRegion->getId(); + mTextureRegion = std::static_pointer_cast( + TextureRegion->createInstance() ); + } } GameObjectVirtual::~GameObjectVirtual() {} @@ -86,9 +79,10 @@ void GameObjectVirtual::draw() { Vector2f( mPos.x + mTextureRegion->getDestSize().x, mPos.y ) ), getBlendModeFromFlags(), getRenderModeFromFlags() ); } else { - mTextureRegion->draw( - mPos.x, mPos.y, LM->getColorFromPos( Vector2f( mPos.x, mPos.y ) ), - getRotation(), Vector2f::One, BlendMode::Alpha(), getRenderModeFromFlags() ); + mTextureRegion->draw( mPos.x, mPos.y, + LM->getColorFromPos( Vector2f( mPos.x, mPos.y ) ), + getRotation(), Vector2f::One, BlendMode::Alpha(), + getRenderModeFromFlags() ); } } } else { diff --git a/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp b/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp index 09726d946..9dec79224 100644 --- a/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp +++ b/src/modules/maps/src/eepp/maps/mapeditor/mapeditor.cpp @@ -1440,15 +1440,17 @@ GameObject* MapEditor::createGameObject() { if ( mChkAnim->isChecked() ) { - Sprite* tAnimSprite = Sprite::New( + SpritePtr tAnimSprite = Sprite::New( String::removeNumbersAtEnd( mGfxPreview->getTextureRegion()->getName() ) ); - tObj = eeNew( GameObjectSprite, ( mCurGOFlags, mCurLayer, tAnimSprite ) ); tAnimSprite->setAutoAnimate( false ); + tObj = eeNew( GameObjectSprite, + ( mCurGOFlags, mCurLayer, std::move( tAnimSprite ) ) ); } else { - Sprite* tStaticSprite = Sprite::New( mGfxPreview->getTextureRegion() ); - tObj = eeNew( GameObjectSprite, ( mCurGOFlags, mCurLayer, tStaticSprite ) ); + SpritePtr tStaticSprite = Sprite::New( mGfxPreview->getTextureRegion() ); + tObj = eeNew( GameObjectSprite, + ( mCurGOFlags, mCurLayer, std::move( tStaticSprite ) ) ); } } else { //! Creates an empty game object. The client will interpret the GameObject Type, and diff --git a/src/modules/physics/include/eepp/physics/shapecirclesprite.hpp b/src/modules/physics/include/eepp/physics/shapecirclesprite.hpp index fd47accce..daeccdc2a 100644 --- a/src/modules/physics/include/eepp/physics/shapecirclesprite.hpp +++ b/src/modules/physics/include/eepp/physics/shapecirclesprite.hpp @@ -5,9 +5,7 @@ #ifdef PHYSICS_RENDERER_ENABLED -namespace EE { namespace Graphics { -class Sprite; -}} // namespace EE::Graphics +#include using namespace EE::Graphics; namespace EE { namespace Physics { @@ -15,10 +13,9 @@ namespace EE { namespace Physics { class EE_PHYSICS_API ShapeCircleSprite : public ShapeCircle { public: static ShapeCircleSprite* New( Physics::Body* body, cpFloat radius, cVect offset, - Sprite* Sprite, bool AutoDeleteSprite = false ); + SpritePtr sprite ); - ShapeCircleSprite( Physics::Body* body, cpFloat radius, cVect offset, Sprite* Sprite, - bool AutoDeleteSprite = false ); + ShapeCircleSprite( Physics::Body* body, cpFloat radius, cVect offset, SpritePtr sprite ); virtual ~ShapeCircleSprite(); @@ -28,11 +25,10 @@ class EE_PHYSICS_API ShapeCircleSprite : public ShapeCircle { virtual void setOffset( const cVect& offset ); - Sprite* getSprite() const; + const SpritePtr& getSprite() const; protected: - Sprite* mSprite; - bool mSpriteAutoDelete; + SpritePtr mSprite; void offsetSet(); }; diff --git a/src/modules/physics/include/eepp/physics/shapepolysprite.hpp b/src/modules/physics/include/eepp/physics/shapepolysprite.hpp index 193ecf3f4..a4d8a9440 100644 --- a/src/modules/physics/include/eepp/physics/shapepolysprite.hpp +++ b/src/modules/physics/include/eepp/physics/shapepolysprite.hpp @@ -5,9 +5,7 @@ #ifdef PHYSICS_RENDERER_ENABLED -namespace EE { namespace Graphics { -class Sprite; -}} // namespace EE::Graphics +#include using namespace EE::Graphics; namespace EE { namespace Physics { @@ -15,26 +13,24 @@ namespace EE { namespace Physics { class EE_PHYSICS_API ShapePolySprite : public ShapePoly { public: static ShapePolySprite* New( Physics::Body* body, int numVerts, cVect* verts, cVect offset, - Sprite* Sprite, bool AutoDeleteSprite = false ); + SpritePtr sprite ); - static ShapePolySprite* New( Physics::Body* body, cpFloat width, cpFloat height, Sprite* Sprite, - bool AutoDeleteSprite = false ); + static ShapePolySprite* New( Physics::Body* body, cpFloat width, cpFloat height, + SpritePtr sprite ); - ShapePolySprite( Physics::Body* body, int numVerts, cVect* verts, cVect offset, Sprite* Sprite, - bool AutoDeleteSprite = false ); + ShapePolySprite( Physics::Body* body, int numVerts, cVect* verts, cVect offset, + SpritePtr sprite ); - ShapePolySprite( Physics::Body* body, cpFloat width, cpFloat height, Sprite* Sprite, - bool AutoDeleteSprite = false ); + ShapePolySprite( Physics::Body* body, cpFloat width, cpFloat height, SpritePtr sprite ); virtual ~ShapePolySprite(); virtual void draw( Space* space ); - Sprite* getSprite() const; + const SpritePtr& getSprite() const; protected: - Sprite* mSprite; - bool mSpriteAutoDelete; + SpritePtr mSprite; Vector2i mOffset; void offsetSet( cVect center ); diff --git a/src/modules/physics/src/eepp/physics/shapecirclesprite.cpp b/src/modules/physics/src/eepp/physics/shapecirclesprite.cpp index f51331e3f..1f3f85e9d 100644 --- a/src/modules/physics/src/eepp/physics/shapecirclesprite.cpp +++ b/src/modules/physics/src/eepp/physics/shapecirclesprite.cpp @@ -7,20 +7,17 @@ namespace EE { namespace Physics { ShapeCircleSprite* ShapeCircleSprite::New( Physics::Body* body, cpFloat radius, cVect offset, - Sprite* Sprite, bool AutoDeleteSprite ) { - return eeNew( ShapeCircleSprite, ( body, radius, offset, Sprite, AutoDeleteSprite ) ); + SpritePtr sprite ) { + return eeNew( ShapeCircleSprite, ( body, radius, offset, std::move( sprite ) ) ); } ShapeCircleSprite::ShapeCircleSprite( Physics::Body* body, cpFloat radius, cVect offset, - Sprite* Sprite, bool AutoDeleteSprite ) : - ShapeCircle( body, radius, offset ), mSprite( Sprite ), mSpriteAutoDelete( AutoDeleteSprite ) { + SpritePtr sprite ) : + ShapeCircle( body, radius, offset ), mSprite( std::move( sprite ) ) { offsetSet(); } -ShapeCircleSprite::~ShapeCircleSprite() { - if ( mSpriteAutoDelete ) - eeSAFE_DELETE( mSprite ); -} +ShapeCircleSprite::~ShapeCircleSprite() {} void ShapeCircleSprite::draw( Space* space ) { cVect Pos = getBody()->getPos(); @@ -36,7 +33,7 @@ void ShapeCircleSprite::offsetSet() { -ShapeCircle::getRadius() + ShapeCircle::getOffset().y ) ); } -Sprite* ShapeCircleSprite::getSprite() const { +const SpritePtr& ShapeCircleSprite::getSprite() const { return mSprite; } diff --git a/src/modules/physics/src/eepp/physics/shapepolysprite.cpp b/src/modules/physics/src/eepp/physics/shapepolysprite.cpp index 1696964e3..6fdfa39dd 100644 --- a/src/modules/physics/src/eepp/physics/shapepolysprite.cpp +++ b/src/modules/physics/src/eepp/physics/shapepolysprite.cpp @@ -7,34 +7,31 @@ namespace EE { namespace Physics { ShapePolySprite* ShapePolySprite::New( Physics::Body* body, int numVerts, cVect* verts, - cVect offset, Sprite* Sprite, bool AutoDeleteSprite ) { - return eeNew( ShapePolySprite, ( body, numVerts, verts, offset, Sprite, AutoDeleteSprite ) ); + cVect offset, SpritePtr sprite ) { + return eeNew( ShapePolySprite, + ( body, numVerts, verts, offset, std::move( sprite ) ) ); } ShapePolySprite* ShapePolySprite::New( Physics::Body* body, cpFloat width, cpFloat height, - Sprite* Sprite, bool AutoDeleteSprite ) { - return eeNew( ShapePolySprite, ( body, width, height, Sprite, AutoDeleteSprite ) ); + SpritePtr sprite ) { + return eeNew( ShapePolySprite, ( body, width, height, std::move( sprite ) ) ); } ShapePolySprite::ShapePolySprite( Physics::Body* body, int numVerts, cVect* verts, cVect offset, - Sprite* Sprite, bool AutoDeleteSprite ) : + SpritePtr sprite ) : ShapePoly( body, numVerts, verts, offset ), - mSprite( Sprite ), - mSpriteAutoDelete( AutoDeleteSprite ) { + mSprite( std::move( sprite ) ) { offsetSet( centroid( numVerts, verts ) ); } ShapePolySprite::ShapePolySprite( Physics::Body* body, cpFloat width, cpFloat height, - Sprite* Sprite, bool AutoDeleteSprite ) : - ShapePoly( body, width, height ), mSprite( Sprite ), mSpriteAutoDelete( AutoDeleteSprite ) { + SpritePtr sprite ) : + ShapePoly( body, width, height ), mSprite( std::move( sprite ) ) { mSprite->setSize( Sizef( width, height ) ); offsetSet( cVectNew( width / 2, height / 2 ) ); } -ShapePolySprite::~ShapePolySprite() { - if ( mSpriteAutoDelete ) - eeSAFE_DELETE( mSprite ); -} +ShapePolySprite::~ShapePolySprite() {} void ShapePolySprite::draw( Space* space ) { cVect Pos = getBody()->getPos(); @@ -52,7 +49,7 @@ void ShapePolySprite::offsetSet( cVect center ) { ( Int32 )( -myCenter.y + ( center.y - myCenter.y ) ) ); } -Sprite* ShapePolySprite::getSprite() const { +const SpritePtr& ShapePolySprite::getSprite() const { return mSprite; } diff --git a/src/tests/test_all/test.cpp b/src/tests/test_all/test.cpp index 1ac2f1bbf..2e33477b7 100644 --- a/src/tests/test_all/test.cpp +++ b/src/tests/test_all/test.cpp @@ -379,7 +379,6 @@ void EETest::createBaseUI() { sprite->setSprite( Sprite::New( "gn" ) ); sprite->setParent( C ); sprite->setPosition( 160, 100 ); - sprite->setIsSpriteOwner( true ); UITextView* Text = UITextView::New(); Text->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ) @@ -742,7 +741,7 @@ void EETest::createNewUI() { UISprite* sprite = UISprite::New(); sprite->setFlags( UI_AUTO_SIZE ); sprite->setPosition( 50, 600 )->setParent( container ); - sprite->setSprite( &SP ); + sprite->setSprite( SP.clone() ); UIScrollBar* scrollBar = UIScrollBar::New(); scrollBar->setOrientation( UIOrientation::Horizontal ) @@ -1802,26 +1801,26 @@ void EETest::screen5() { Color col( 0x000000CC ); if ( drawableGroup.getDrawableCount() == 0 ) { - ArcDrawable* arc = ArcDrawable::New(); + auto arc = makeResource(); arc->setPosition( Vector2f( 60, 60 ) ); arc->setArcStartAngle( 90 ); arc->setArcAngle( 180 ); arc->setRadius( 60 ); arc->setColor( col ); - RectangleDrawable* rect = RectangleDrawable::New(); + auto rect = makeResource(); rect->setPosition( Vector2f( 0, 60 ) ); rect->setSize( Sizef( 120, 60 ) ); rect->setColor( col ); - ArcDrawable* arc2 = ArcDrawable::New(); + auto arc2 = makeResource(); arc2->setPosition( Vector2f( 60, 120 ) ); arc2->setArcStartAngle( -90 ); arc2->setArcAngle( 180 ); arc2->setRadius( 60 ); arc2->setColor( col ); - ConvexShapeDrawable* poly = ConvexShapeDrawable::New(); + auto poly = makeResource(); poly->setPosition( Vector2f( 60, 90 ) ); poly->addPoint( Vector2f( -10, -10 ) ); poly->addPoint( Vector2f( -10, 10 ) ); @@ -2551,8 +2550,8 @@ void EETest::end() { eeSAFE_DELETE( mTGL ); eeSAFE_DELETE( mFBO ); eeSAFE_DELETE( mVBO ); - eeSAFE_DELETE( mBoxSprite ); - eeSAFE_DELETE( mCircleSprite ); + mBoxSprite.reset(); + mCircleSprite.reset(); eeSAFE_DELETE( PakTest ); Log::instance()->save(); diff --git a/src/tests/test_all/test.hpp b/src/tests/test_all/test.hpp index 86f159690..5e992ec20 100644 --- a/src/tests/test_all/test.hpp +++ b/src/tests/test_all/test.hpp @@ -225,8 +225,8 @@ class EETest : private Thread { std::vector mDemo; Uint32 mCurDemo; - Sprite* mBoxSprite; - Sprite* mCircleSprite; + SpritePtr mBoxSprite; + SpritePtr mCircleSprite; UITheme* mTheme; UISceneNode* mSceneNode; diff --git a/src/tests/unit_tests/drawableimageparser_tests.cpp b/src/tests/unit_tests/drawableimageparser_tests.cpp index ebc0a69d6..7416bbf5b 100644 --- a/src/tests/unit_tests/drawableimageparser_tests.cpp +++ b/src/tests/unit_tests/drawableimageparser_tests.cpp @@ -53,15 +53,13 @@ UTEST( DrawableImageParser, TwoStopsWithPosition ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(#f5eedd 0%, #ebe0c2 100%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(#f5eedd 0%, #ebe0c2 100%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - ASSERT_TRUE( ownIt ); ASSERT_EQ( drawable->getDrawableType(), Drawable::LINEARGRADIENT ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 0.f ); @@ -72,7 +70,6 @@ UTEST( DrawableImageParser, TwoStopsWithPosition ) { EXPECT_TRUE( stops[1].color == expectEbe ); EXPECT_EQ( grad->getAngle(), 180.f ); /* default: to bottom */ - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -85,18 +82,16 @@ UTEST( DrawableImageParser, DirectionToRight ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(to right, red, blue)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(to right, red, blue)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getAngle(), 90.f ); EXPECT_EQ( grad->getColorStops().size(), (size_t)2 ); EXPECT_TRUE( grad->getColorStops()[0].color == Color::fromString( "red" ) ); EXPECT_TRUE( grad->getColorStops()[1].color == Color::fromString( "blue" ) ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -109,16 +104,14 @@ UTEST( DrawableImageParser, AngleDegrees ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(45deg, red 0%, blue 100%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(45deg, red 0%, blue 100%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getAngle(), 45.f ); EXPECT_EQ( grad->getColorStops().size(), (size_t)2 ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -131,16 +124,14 @@ UTEST( DrawableImageParser, AngleTurn ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(0.25turn, red, blue)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(0.25turn, red, blue)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getAngle(), 90.f ); /* 0.25 * 360 = 90 */ EXPECT_EQ( grad->getColorStops().size(), (size_t)2 ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -153,12 +144,11 @@ UTEST( DrawableImageParser, ThreeStops ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(red 0%, green 50%, blue 100%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(red 0%, green 50%, blue 100%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)3 ); EXPECT_EQ( stops[0].value, 0.f ); @@ -166,7 +156,6 @@ UTEST( DrawableImageParser, ThreeStops ) { EXPECT_TRUE( stops[1].color == Color::fromString( "green" ) ); EXPECT_TRUE( stops[2].color == Color::fromString( "blue" ) ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -179,12 +168,11 @@ UTEST( DrawableImageParser, ColorHint ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(red 0%, 25%, blue 100%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(red 0%, 25%, blue 100%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); const auto& stops = grad->getColorStops(); /* Hint expands to 16 sampled sub-stops + 2 color stops = 18 total @@ -209,7 +197,6 @@ UTEST( DrawableImageParser, ColorHint ) { } EXPECT_TRUE( foundMidpoint ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -222,12 +209,11 @@ UTEST( DrawableImageParser, StopsWithoutPositions ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "linear-gradient(red, green, blue)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "linear-gradient(red, green, blue)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)3 ); /* Should be evenly distributed: 0%, 50%, 100% */ @@ -235,7 +221,6 @@ UTEST( DrawableImageParser, StopsWithoutPositions ) { EXPECT_NEAR( stops[1].value, 50.f, 0.01f ); EXPECT_EQ( stops[2].value, 100.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -248,17 +233,15 @@ UTEST( DrawableImageParser, EmptyAngleFallsThrough ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; /* No direction specified, should default to 180 (to bottom) */ - Drawable* drawable = - parser.createDrawable( "linear-gradient(red, blue)", Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = + parser.createDrawable( "linear-gradient(red, blue)", Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getAngle(), 180.f ); EXPECT_EQ( grad->getColorStops().size(), (size_t)2 ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -271,20 +254,18 @@ UTEST( DrawableImageParser, RepeatingTwoStops ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "repeating-linear-gradient(red, blue)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "repeating-linear-gradient(red, blue)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); ASSERT_TRUE( drawable->getDrawableType() == Drawable::REPEATINGLINEARGRADIENT ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_TRUE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 0.f ); EXPECT_EQ( stops[1].value, 100.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -297,18 +278,16 @@ UTEST( DrawableImageParser, RepeatingWithAngle ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( - "repeating-linear-gradient(45deg, #f00, #0f0, #00f)", Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( + "repeating-linear-gradient(45deg, #f00, #0f0, #00f)", Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getAngle(), 45.f ); EXPECT_TRUE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)3 ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -321,19 +300,17 @@ UTEST( DrawableImageParser, RepeatingWithPositions ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "repeating-linear-gradient(red 10%, blue 40%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "repeating-linear-gradient(red 10%, blue 40%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_TRUE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 10.f ); EXPECT_EQ( stops[1].value, 40.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -346,20 +323,18 @@ UTEST( DrawableImageParser, RadialTwoStops ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = - parser.createDrawable( "radial-gradient(red, blue)", Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = + parser.createDrawable( "radial-gradient(red, blue)", Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); ASSERT_TRUE( drawable->getDrawableType() == Drawable::RADIALGRADIENT ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_FALSE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 0.f ); EXPECT_EQ( stops[1].value, 1.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -372,16 +347,14 @@ UTEST( DrawableImageParser, RadialCircleKeyword ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "radial-gradient(circle, #f00, #00f)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "radial-gradient(circle, #f00, #00f)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_EQ( grad->getShape(), RadialGradientDrawable::CIRCLE ); EXPECT_EQ( grad->getColorStops().size(), (size_t)2 ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -394,18 +367,16 @@ UTEST( DrawableImageParser, RadialWithPositions ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "radial-gradient(red 10%, blue 80%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "radial-gradient(red 10%, blue 80%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 10.f ); EXPECT_EQ( stops[1].value, 80.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -418,20 +389,18 @@ UTEST( DrawableImageParser, RepeatingRadial ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( "repeating-radial-gradient(red 10%, blue 40%)", - Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( "repeating-radial-gradient(red 10%, blue 40%)", + Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); ASSERT_TRUE( drawable->getDrawableType() == Drawable::REPEATINGRADIALGRADIENT ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_TRUE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); ASSERT_EQ( stops.size(), (size_t)2 ); EXPECT_EQ( stops[0].value, 10.f ); EXPECT_EQ( stops[1].value, 40.f ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } @@ -444,12 +413,11 @@ UTEST( DrawableImageParser, TwoLengthStopSyntax ) { UINode* node = createTestNode( sceneNode ); auto& parser = StyleSheetSpecification::instance()->getDrawableImageParser(); - bool ownIt = false; - Drawable* drawable = parser.createDrawable( - "repeating-linear-gradient(red 0 10px, blue 10px 20px)", Sizef( 100, 100 ), ownIt, node ); + DrawablePtr drawable = parser.createDrawable( + "repeating-linear-gradient(red 0 10px, blue 10px 20px)", Sizef( 100, 100 ), node ); ASSERT_TRUE( drawable != NULL ); - auto* grad = static_cast( drawable ); + auto* grad = static_cast( drawable.get() ); EXPECT_TRUE( grad->isRepeating() ); const auto& stops = grad->getColorStops(); /* red 0 10px → two stops: raw pos 0 and raw pos 10. blue 10px 20px → @@ -465,6 +433,5 @@ UTEST( DrawableImageParser, TwoLengthStopSyntax ) { EXPECT_EQ( stops[3].value, 20.f ); EXPECT_EQ( stops[3].unit, EE::UI::CSS::StyleSheetLength::Px ); - eeSAFE_DELETE( drawable ); Engine::destroySingleton(); } diff --git a/src/tests/unit_tests/resource_prerequisite_tests.cpp b/src/tests/unit_tests/resource_prerequisite_tests.cpp index ba8e2394f..63c2e04e8 100644 --- a/src/tests/unit_tests/resource_prerequisite_tests.cpp +++ b/src/tests/unit_tests/resource_prerequisite_tests.cpp @@ -4,27 +4,35 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include +#include +#include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -88,6 +96,44 @@ class TestTextureAtlasLoader : public TextureAtlasLoader { } }; +class TestDrawableResource : public DrawableResource { + public: + TestDrawableResource() : DrawableResource( Drawable::CUSTOM ) {} + + Sizef getSize() { return {}; } + Sizef getPixelsSize() { return {}; } + void draw() {} + void draw( const Vector2f& ) {} + void draw( const Vector2f&, const Sizef& ) {} + bool isStateful() { return false; } + + void notifyChange() { onResourceChange(); } +}; + +class CountingDrawable : public Drawable { + public: + CountingDrawable( std::shared_ptr instanceCount ) : + Drawable( Drawable::CUSTOM ), mInstanceCount( std::move( instanceCount ) ) {} + + Sizef getSize() { return { 16.f, 16.f }; } + Sizef getPixelsSize() { return getSize(); } + void draw() {} + void draw( const Vector2f& ) {} + void draw( const Vector2f&, const Sizef& ) {} + bool isStateful() { return false; } + + DrawablePtr createInstance() const { + ++*mInstanceCount; + auto instance = makeResource( mInstanceCount ); + instance->setColor( mColor ); + instance->setPosition( mPosition ); + return instance; + } + + private: + std::shared_ptr mInstanceCount; +}; + class AsyncDeliveryProducerScene : public UISceneNode { public: static AsyncDeliveryProducerScene* New( EE::Window::Window* window ) { @@ -396,13 +442,6 @@ UTEST( ResourcePrerequisites, pendingBatchRetainsTextureUntilDisplayCollection ) TexturePtr texture = loader.getTexture(); ASSERT_TRUE( texture != nullptr ); - bool unloaded = false; - texture->pushResourceChangeCallback( - [&unloaded]( Uint32, DrawableResource::Event event, DrawableResource* ) { - if ( event == DrawableResource::Event::Unload ) - unloaded = true; - } ); - TextureRegistrySnapshot snapshot = factory->snapshotTextures(); auto record = std::find_if( snapshot.begin(), snapshot.end(), [&texture]( const auto& entry ) { return entry.id == texture->getTextureId(); @@ -419,13 +458,11 @@ UTEST( ResourcePrerequisites, pendingBatchRetainsTextureUntilDisplayCollection ) retainedTexture.reset(); EXPECT_FALSE( weakTexture.expired() ); - EXPECT_FALSE( unloaded ); EXPECT_EQ( factory->getPendingReleaseCount(), static_cast( 0 ) ); window->display( false ); EXPECT_TRUE( weakTexture.expired() ); - EXPECT_TRUE( unloaded ); EXPECT_EQ( factory->getPendingReleaseCount(), static_cast( 0 ) ); Engine::destroySingleton(); } @@ -488,6 +525,223 @@ UTEST( ResourcePrerequisites, textureRegionRetainsItsTexture ) { Engine::destroySingleton(); } +UTEST( ResourcePrerequisites, drawableResourceConnectionsDisconnectWithTheirLifetime ) { + auto resource = makeResource(); + int notifications = 0; + { + DrawableResourceConnection connection = resource->connectResourceChange( + [¬ifications]( DrawableResource& ) { ++notifications; } ); + EXPECT_TRUE( static_cast( connection ) ); + resource->notifyChange(); + EXPECT_EQ( notifications, 1 ); + } + + resource->notifyChange(); + EXPECT_EQ( notifications, 1 ); + + DrawableResourceConnection expiredConnection = + resource->connectResourceChange( []( DrawableResource& ) {} ); + resource.reset(); + EXPECT_FALSE( static_cast( expiredConnection ) ); + expiredConnection.disconnect(); +} + +UTEST( ResourcePrerequisites, textureCreatesIndependentDrawableInstances ) { + EE::Window::Window* window = createLifecycleTestWindow( "Texture drawable instance test" ); + TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 2, 2 ); + ASSERT_TRUE( texture != nullptr ); + + DrawablePtr firstDrawable = texture->createInstance(); + DrawablePtr secondDrawable = texture->createInstance(); + ASSERT_TRUE( firstDrawable != nullptr ); + ASSERT_TRUE( secondDrawable != nullptr ); + ASSERT_EQ( firstDrawable->getDrawableType(), Drawable::TEXTUREDRAWABLE ); + ASSERT_EQ( secondDrawable->getDrawableType(), Drawable::TEXTUREDRAWABLE ); + auto first = std::static_pointer_cast( firstDrawable ); + auto second = std::static_pointer_cast( secondDrawable ); + ASSERT_TRUE( first != nullptr ); + ASSERT_TRUE( second != nullptr ); + EXPECT_NE( first.get(), second.get() ); + EXPECT_EQ( first->getTexture().get(), texture.get() ); + EXPECT_EQ( second->getTexture().get(), texture.get() ); + + first->setColor( Color::Red ); + second->setColor( Color::Blue ); + first->setPosition( { 3.f, 4.f } ); + EXPECT_TRUE( first->getColor() == Color::Red ); + EXPECT_TRUE( second->getColor() == Color::Blue ); + EXPECT_TRUE( second->getPosition() == Vector2f::Zero ); + + firstDrawable.reset(); + secondDrawable.reset(); + first.reset(); + second.reset(); + texture.reset(); + window->display( false ); + Engine::destroySingleton(); +} + +UTEST( ResourcePrerequisites, uiIconSeparatesSourceLookupFromInstanceCreation ) { + auto instanceCount = std::make_shared( 0 ); + DrawablePtr source = makeResource( instanceCount ); + UIIcon* icon = UIIcon::New( "counting-icon" ); + icon->setSource( 16, source ); + + const DrawablePtr& exactSource = icon->getSource( 16 ); + const DrawablePtr& closestSource = icon->getSource( 14 ); + EXPECT_EQ( exactSource.get(), source.get() ); + EXPECT_EQ( closestSource.get(), source.get() ); + EXPECT_EQ( *instanceCount, 0 ); + + DrawablePtr first = icon->createDrawable( 16 ); + DrawablePtr second = icon->createDrawable( 14 ); + ASSERT_TRUE( first != nullptr ); + ASSERT_TRUE( second != nullptr ); + EXPECT_EQ( *instanceCount, 2 ); + EXPECT_NE( first.get(), second.get() ); + EXPECT_NE( first.get(), source.get() ); + + first->setColor( Color::Red ); + EXPECT_TRUE( source->getColor() == Color::White ); + EXPECT_TRUE( second->getColor() == Color::White ); + + eeDelete( icon ); +} + +UTEST( ResourcePrerequisites, stateListsCloneStateAndChildrenIndependently ) { + EE::Window::Window* window = createLifecycleTestWindow( "State list instance test" ); + TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 2, 2 ); + ASSERT_TRUE( texture != nullptr ); + auto firstRegion = makeResource( texture ); + auto secondRegion = makeResource( texture ); + auto source = ResourcePtr( StateListDrawable::New(), + ResourceDeleter() ); + source->setStateDrawable( 1, firstRegion ); + source->setStateDrawable( 2, secondRegion ); + source->setState( 1 ); + + DrawablePtr drawableInstance = source->createInstance(); + ASSERT_TRUE( drawableInstance != nullptr ); + ASSERT_EQ( drawableInstance->getDrawableType(), Drawable::STATELIST ); + auto instance = std::static_pointer_cast( drawableInstance ); + ASSERT_TRUE( instance != nullptr ); + EXPECT_EQ( source->getState(), 1u ); + EXPECT_EQ( instance->getState(), 1u ); + EXPECT_NE( source->getStateDrawable( 1 ), instance->getStateDrawable( 1 ) ); + + instance->setState( 2 ); + instance->setStateColor( 1, Color::Red ); + EXPECT_EQ( source->getState(), 1u ); + EXPECT_EQ( instance->getState(), 2u ); + EXPECT_TRUE( source->getStateDrawable( 1 )->getColor() == Color::White ); + EXPECT_TRUE( instance->getStateDrawable( 1 )->getColor() == Color::Red ); + EXPECT_FALSE( source->hasDrawableState( 99 ) ); + source->setState( 99 ); + EXPECT_FALSE( source->hasDrawableState( 99 ) ); + + instance.reset(); + drawableInstance.reset(); + source.reset(); + firstRegion.reset(); + secondRegion.reset(); + texture.reset(); + window->display( false ); + Engine::destroySingleton(); +} + +UTEST( ResourcePrerequisites, spritesCloneFramesAndAnimationStateIndependently ) { + EE::Window::Window* window = createLifecycleTestWindow( "Sprite instance test" ); + TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 2, 2 ); + ASSERT_TRUE( texture != nullptr ); + SpritePtr source = Sprite::New(); + source->createAnimation(); + source->addFrame( texture, Sizef( 2.f, 2.f ) ); + source->addFrame( texture, Sizef( 2.f, 2.f ) ); + source->setCurrentFrame( 0 ); + + SpritePtr instance = source->clone(); + ASSERT_TRUE( instance != nullptr ); + TextureRegion* sourceFrame = source->getTextureRegion( 0 ); + TextureRegion* instanceFrame = instance->getTextureRegion( 0 ); + ASSERT_TRUE( sourceFrame != nullptr ); + ASSERT_TRUE( instanceFrame != nullptr ); + EXPECT_NE( sourceFrame, instanceFrame ); + EXPECT_EQ( sourceFrame->getTexture().get(), instanceFrame->getTexture().get() ); + + instance->setCurrentFrame( 2 ); + instanceFrame->setDestSize( Sizef( 8.f, 9.f ) ); + EXPECT_EQ( source->getCurrentFrame(), 0u ); + EXPECT_EQ( instance->getCurrentFrame(), 1u ); + EXPECT_TRUE( sourceFrame->getDestSize() == Sizef( 2.f, 2.f ) ); + EXPECT_TRUE( instanceFrame->getDestSize() == Sizef( 8.f, 9.f ) ); + + instance.reset(); + source.reset(); + texture.reset(); + window->display( false ); + Engine::destroySingleton(); +} + +UTEST( ResourcePrerequisites, regionConsumersDoNotMutateSharedSourceGeometryWhileDrawing ) { + EE::Window::Window* window = createLifecycleTestWindow( "Texture region draw isolation test" ); + TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 8, 8 ); + ASSERT_TRUE( texture != nullptr ); + auto source = makeResource( texture, Rect( 1, 2, 7, 8 ), Sizef( 6.f, 6.f ), + Vector2i( 2, 3 ) ); + const Rect originalRect = source->getSrcRect(); + const Sizef originalSize = source->getDestSize(); + const Vector2i originalOffset = source->getOffset(); + + UITextureRegion* widget = UITextureRegion::New(); + widget->setTextureRegion( source.get() ); + widget->setSize( Sizef( 20.f, 20.f ) ); + widget->setScaleType( UIScaleType::Expand ); + widget->draw(); + EXPECT_TRUE( source->getSrcRect() == originalRect ); + EXPECT_TRUE( source->getDestSize() == originalSize ); + EXPECT_TRUE( source->getOffset() == originalOffset ); + eeDelete( widget ); + + { + ScrollParallax parallax( source.get(), Vector2f::Zero, Sizef( 20.f, 20.f ) ); + ASSERT_TRUE( parallax.getTextureRegion() != nullptr ); + EXPECT_NE( parallax.getTextureRegion(), source.get() ); + EXPECT_EQ( parallax.getTextureRegion()->getTexture().get(), texture.get() ); + parallax.draw(); + EXPECT_TRUE( source->getSrcRect() == originalRect ); + EXPECT_TRUE( source->getDestSize() == originalSize ); + EXPECT_TRUE( source->getOffset() == originalOffset ); + } + + source.reset(); + texture.reset(); + window->display( false ); + Engine::destroySingleton(); +} + +UTEST( ResourcePrerequisites, drawableGroupsAndVariantsHoldSafeIndependentHandles ) { + auto source = DrawableGroup::New(); + auto rectangle = makeResource( Vector2f( 1.f, 2.f ), Sizef( 3.f, 4.f ) ); + source->addDrawable( rectangle ); + + DrawablePtr drawableInstance = source->createInstance(); + ASSERT_TRUE( drawableInstance != nullptr ); + ASSERT_EQ( drawableInstance->getDrawableType(), Drawable::GROUP ); + auto instance = std::static_pointer_cast( drawableInstance ); + ASSERT_TRUE( instance != nullptr ); + ASSERT_EQ( instance->getDrawableCount(), 1u ); + EXPECT_NE( source->getGroup()[0].get(), instance->getGroup()[0].get() ); + instance->getGroup()[0]->setColor( Color::Blue ); + EXPECT_TRUE( source->getGroup()[0]->getColor() == Color::White ); + EXPECT_TRUE( instance->getGroup()[0]->getColor() == Color::Blue ); + + Variant original( instance ); + Variant copied( original ); + instance.reset(); + EXPECT_TRUE( original.asDrawable() != nullptr ); + EXPECT_EQ( original.asDrawable().get(), copied.asDrawable().get() ); +} + UTEST( ResourcePrerequisites, unsignedVariantPreservesTypeAndValue ) { const unsigned int value = std::numeric_limits::max(); Variant original( value ); @@ -644,7 +898,7 @@ UTEST( ResourcePrerequisites, engineTeardownReleasesGraphicsBeforeContextsAcross auto* scene = UISceneNode::New(); SceneManager::instance()->add( scene ); scene->enableFrameBuffer(); - UIImage::New()->setDrawable( ninePatch )->setParent( scene->getRoot() ); + UIImage::New()->setDrawable( ninePatch->createInstance() )->setParent( scene->getRoot() ); auto* font = FontTrueType::New( "engine-teardown-font" ); ASSERT_TRUE( diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index e4cfef37f..581587497 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -54,6 +56,25 @@ using namespace EE::Scene; using namespace EE::UI; using namespace EE::UI::Tools; +static Texture* getDrawableTexture( Drawable* drawable ) { + if ( !drawable ) + return nullptr; + switch ( drawable->getDrawableType() ) { + case Drawable::TEXTURE: + return static_cast( drawable ); + case Drawable::TEXTUREDRAWABLE: + return static_cast( drawable )->getTexture().get(); + case Drawable::TEXTUREREGION: + return static_cast( drawable )->getTexture().get(); + default: + return nullptr; + } +} + +static Texture* getDrawableTexture( const DrawablePtr& drawable ) { + return getDrawableTexture( drawable.get() ); +} + static void init_ui_test() { Engine::instance()->createWindow( WindowSettings( 1024, 650, "HTML Tables Test", WindowStyle::Default, WindowBackend::Default, @@ -3843,8 +3864,11 @@ UTEST( UIBackground, RemoteImageReusesCachedTexture ) { ASSERT_TRUE( second->getBackground() != nullptr ); ASSERT_TRUE( first->getBackground()->getLayer( 0 ) != nullptr ); ASSERT_TRUE( second->getBackground()->getLayer( 0 ) != nullptr ); - EXPECT_EQ( cached.get(), first->getBackground()->getLayer( 0 )->getDrawable() ); - EXPECT_EQ( cached.get(), second->getBackground()->getLayer( 0 )->getDrawable() ); + const DrawablePtr& firstDrawable = first->getBackground()->getLayer( 0 )->getDrawable(); + const DrawablePtr& secondDrawable = second->getBackground()->getLayer( 0 )->getDrawable(); + EXPECT_EQ( cached.get(), getDrawableTexture( firstDrawable ) ); + EXPECT_EQ( cached.get(), getDrawableTexture( secondDrawable ) ); + EXPECT_NE( firstDrawable.get(), secondDrawable.get() ); cached.reset(); Engine::destroySingleton(); @@ -5118,7 +5142,7 @@ UTEST( UIHTML, DeferredFileImageReusesCachedTexture ) { sceneNode->setURI( URI( "file://" + processPath ) ); URI imageURI = sceneNode->solveRelativePath( URI( "../assets/icon/ee.png" ) ); ASSERT_TRUE( FileSystem::fileExists( imageURI.getFSPath() ) ); - Drawable* cached = DrawableSearcher::searchByName( + DrawablePtr cached = DrawableSearcher::searchByName( imageURI.toString(), false, sceneNode->getReferer(), sceneNode->getResourceScope().get() ); ASSERT_TRUE( cached != nullptr ); @@ -5145,9 +5169,11 @@ UTEST( UIHTML, DeferredFileImageReusesCachedTexture ) { auto* second = secondNode->asType(); ASSERT_TRUE( first != nullptr ); ASSERT_TRUE( second != nullptr ); - EXPECT_EQ( cached, first->getDrawable() ); - EXPECT_EQ( cached, second->getDrawable() ); + EXPECT_EQ( getDrawableTexture( cached ), getDrawableTexture( first->getDrawable() ) ); + EXPECT_EQ( getDrawableTexture( cached ), getDrawableTexture( second->getDrawable() ) ); + EXPECT_NE( first->getDrawable().get(), second->getDrawable().get() ); + cached.reset(); Engine::destroySingleton(); } @@ -5187,8 +5213,9 @@ UTEST( UIHTML, RemoteImageReusesCachedTexture ) { auto* second = secondNode->asType(); ASSERT_TRUE( first != nullptr ); ASSERT_TRUE( second != nullptr ); - EXPECT_EQ( cached.get(), first->getDrawable() ); - EXPECT_EQ( cached.get(), second->getDrawable() ); + EXPECT_EQ( cached.get(), getDrawableTexture( first->getDrawable() ) ); + EXPECT_EQ( cached.get(), getDrawableTexture( second->getDrawable() ) ); + EXPECT_NE( first->getDrawable().get(), second->getDrawable().get() ); cached.reset(); Engine::destroySingleton(); diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index a0fb7d418..0cffcc316 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -838,7 +838,7 @@ void AppConfig::loadDocuments( UICodeEditorSplitter* editorSplitter, json j, editorSplitter->removeUnusedTab( curTabWidget, true, false ); if ( icon ) - tab->setIcon( icon ); + tab->setIcon( std::move( icon ) ); if ( curTabWidget->getTabCount() == totalToLoad ) curTabWidget->setTabSelected( diff --git a/src/tools/ecode/appconfig.hpp b/src/tools/ecode/appconfig.hpp index ef2786ace..09b92cb73 100644 --- a/src/tools/ecode/appconfig.hpp +++ b/src/tools/ecode/appconfig.hpp @@ -284,7 +284,7 @@ struct SessionSnapshotFile { struct TabWidgetData { UIWidget* widget{ nullptr }; - Drawable* icon{ nullptr }; + DrawablePtr icon; std::string title; }; diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index dee51bd74..e96c71cbb 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1316,17 +1316,17 @@ void App::setFocusEditorOnClose( UIMessageBox* msgBox ) { } ); } -Drawable* App::findIcon( const std::string& name ) { +DrawablePtr App::findIcon( const std::string& name ) { return findIcon( name, mMenuIconSize ); } -Drawable* App::findIcon( const std::string& name, const size_t iconSize ) { +DrawablePtr App::findIcon( const std::string& name, const size_t iconSize ) { if ( name.empty() ) - return nullptr; + return {}; UIIcon* icon = mUISceneNode->findIcon( name ); if ( icon ) - return icon->getSize( iconSize ); - return nullptr; + return icon->createDrawable( iconSize ); + return {}; } String App::i18n( const std::string& key, const String& def ) { @@ -2599,7 +2599,7 @@ void App::loadDiffFromMemory( const std::string& content, const std::string& ori auto scrollView = UIDiffView::NewMultiFileDiffViewer( content, repoPath ); auto [tab, iv] = getSplitter()->createWidget( scrollView, diffViewTitle ); if ( icon ) - tab->setIcon( icon->getSize( getMenuIconSize() ) ); + tab->setIcon( icon->createDrawable( getMenuIconSize() ) ); tab->setText( diffViewTitle ); auto diffView = scrollView->getFirstChild()->asType()->getFirstChild(); @@ -2629,7 +2629,7 @@ void App::loadDiffFromMemory( const std::string& content, const std::string& ori if ( !icon ) icon = getUISceneNode()->findIcon( "file" ); if ( icon ) - tab->setIcon( icon->getSize( getMenuIconSize() ) ); + tab->setIcon( icon->createDrawable( getMenuIconSize() ) ); diffView->setHeadersVisible( true ); diffView->loadFromPatch( content, originalFilePath, oldFilePath ); diffView->setSyntaxColorScheme( *getCurrentColorScheme() ); @@ -2651,7 +2651,7 @@ void App::loadDiffFromPath( const std::string& path ) { auto scrollView = UIDiffView::NewMultiFileDiffViewer( content ); auto [tab, iv] = getSplitter()->createWidget( scrollView, diffViewTitle ); if ( icon ) - tab->setIcon( icon->getSize( getMenuIconSize() ) ); + tab->setIcon( icon->createDrawable( getMenuIconSize() ) ); tab->setText( diffViewTitle ); auto diffView = scrollView->getFirstChild()->asType()->getFirstChild(); @@ -3158,7 +3158,7 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { return; if ( editor->getData() ) { UITab* tab = (UITab*)editor->getData(); - tab->setIcon( icon->getSize( mMenuIconSize ) ); + tab->setIcon( icon->createDrawable( mMenuIconSize ) ); } editor->getDocument().setHExtLanguageType( mProjectDocConfig.hExtLanguageType ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index a6f20ec70..e5b3927da 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -167,9 +167,9 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { std::string getCurrentFileDir() const; - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); - Drawable* findIcon( const std::string& name, const size_t iconSize ); + DrawablePtr findIcon( const std::string& name, const size_t iconSize ); const std::map& getRealDefaultKeybindings(); diff --git a/src/tools/ecode/plugins/aiassistant/chatui.cpp b/src/tools/ecode/plugins/aiassistant/chatui.cpp index 69a308b8d..87aa68c15 100644 --- a/src/tools/ecode/plugins/aiassistant/chatui.cpp +++ b/src/tools/ecode/plugins/aiassistant/chatui.cpp @@ -2695,13 +2695,13 @@ void LLMChatUI::toggleEnableChats( bool enabled ) { toggleEnableChat( chat, enabled ); } -Drawable* LLMChatUI::findIcon( const std::string& name, const size_t iconSize ) { +DrawablePtr LLMChatUI::findIcon( const std::string& name, const size_t iconSize ) { if ( name.empty() ) - return nullptr; + return {}; UIIcon* icon = getUISceneNode()->findIcon( name ); if ( icon ) - return icon->getSize( iconSize ); - return nullptr; + return icon->createDrawable( iconSize ); + return {}; } void LLMChatUI::addPermissionUI( const acp::RequestPermissionRequest& req, diff --git a/src/tools/ecode/plugins/aiassistant/chatui.hpp b/src/tools/ecode/plugins/aiassistant/chatui.hpp index e82a971d2..144553626 100644 --- a/src/tools/ecode/plugins/aiassistant/chatui.hpp +++ b/src/tools/ecode/plugins/aiassistant/chatui.hpp @@ -190,7 +190,7 @@ class LLMChatUI : public UILinearLayout, public WidgetCommandExecuter { void toggleEnableChats( bool enabled ); - Drawable* findIcon( const std::string& name, const size_t iconSize ); + DrawablePtr findIcon( const std::string& name, const size_t iconSize ); UIWidget* addChatUI( LLMChat::Role role ); diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index dc8581f07..c810c3a5c 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -1450,7 +1450,22 @@ std::string AutoCompletePlugin::getPartialSymbol( TextDocument* doc ) { return doc->getText( { start, end } ).toUtf8(); } -void AutoCompletePlugin::update( UICodeEditor* ) { +void AutoCompletePlugin::update( UICodeEditor* editor ) { + const int iconSize = PixelDensity::dpToPxI( 12 ); + if ( mSuggestionIconDrawableSize != iconSize ) { + mSuggestionIconDrawables.clear(); + mSuggestionIconDrawableSize = iconSize; + } + for ( const auto& suggestion : mSuggestions ) { + const int iconKind = (int)suggestion.kind; + if ( mSuggestionIconDrawables.find( iconKind ) != mSuggestionIconDrawables.end() ) + continue; + UIIcon* icon = editor->getUISceneNode()->findIcon( + LSPCompletionItemHelper::toIconString( suggestion.kind ) ); + if ( icon ) + mSuggestionIconDrawables[iconKind] = icon->createDrawable( iconSize ); + } + for ( auto clientIt = mSnippetClients.begin(); clientIt != mSnippetClients.end(); ) { if ( !clientIt->second->isAttached() ) clientIt = mSnippetClients.erase( clientIt ); @@ -1702,8 +1717,8 @@ void AutoCompletePlugin::postDraw( UICodeEditor* editor, const Vector2f& startSc text.draw( cursorPos.x + iconSpace.getWidth() + mBoxPadding.Left, cursorPos.y + mRowHeight * count + mBoxPadding.Top ); - Drawable* icon = editor->getUISceneNode()->findIconDrawable( - LSPCompletionItemHelper::toIconString( suggestion.kind ), PixelDensity::dpToPxI( 12 ) ); + auto iconIt = mSuggestionIconDrawables.find( (int)suggestion.kind ); + DrawablePtr icon = iconIt != mSuggestionIconDrawables.end() ? iconIt->second : DrawablePtr{}; if ( icon ) { Color iconColor( icon->getColor() ); @@ -2101,7 +2116,7 @@ bool AutoCompletePlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* menu->addSubMenu( i18n( "autocomplete", "Auto-Complete" ), mManager->getUISceneNode() ->findIcon( "symbol-string" ) - ->getSize( PixelDensity::dpToPxI( 12 ) ), + ->createDrawable( PixelDensity::dpToPxI( 12 ) ), subMenu ); return false; diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index 0ed35f94d..ed4e45f11 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -187,6 +187,8 @@ class AutoCompletePlugin : public Plugin { Float mRowHeight{ 0 }; Rectf mBoxRect; + UnorderedMap mSuggestionIconDrawables; + int mSuggestionIconDrawableSize{ 0 }; struct SnippetTabStopOccurrence { TextRange range; diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index 81ec6b39a..15edcf137 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -183,6 +183,23 @@ DebuggerPlugin::~DebuggerPlugin() { } } +void DebuggerPlugin::update( UICodeEditor* editor ) { + if ( mBreakpointIcon == nullptr ) + mBreakpointIcon = getUISceneNode()->findIcon( "circle-perfect" ); + if ( mBreakpointIcon ) { + const int iconSize = (int)eefloor( editor->getLineHeight() * 0.875f ); + if ( mBreakpointDrawables.find( iconSize ) == mBreakpointDrawables.end() ) + mBreakpointDrawables[iconSize] = mBreakpointIcon->createDrawable( iconSize ); + } + if ( mStackFrameIcon == nullptr ) + mStackFrameIcon = getUISceneNode()->findIcon( "debug-stackframe" ); + if ( mStackFrameIcon ) { + const int iconSize = (int)eefloor( editor->getLineHeight() ); + if ( mStackFrameDrawables.find( iconSize ) == mStackFrameDrawables.end() ) + mStackFrameDrawables[iconSize] = mStackFrameIcon->createDrawable( iconSize ); + } +} + void DebuggerPlugin::onSaveProject( const std::string& /*projectFolder*/, const std::string& projectStatePath, bool rewriteStateOnlyIfNeeded ) { @@ -761,7 +778,7 @@ void DebuggerPlugin::buildSidePanelTab() { return; UIIcon* icon = findIcon( "debug" ); mTab = mSidePanel->add( i18n( "debugger", "Debugger" ), mTabContents, - icon ? icon->getSize( PixelDensity::dpToPx( 12 ) ) : nullptr ); + icon ? icon->createDrawable( PixelDensity::dpToPx( 12 ) ) : nullptr ); mTab->setId( "debugger_tab" ); mTab->setTextAsFallback( true ); @@ -821,7 +838,7 @@ void DebuggerPlugin::buildSidePanelTab() { mTabContents = getUISceneNode()->loadLayoutFromString( STYLE, nullptr, String::hash( "debugger_plugin" ) ); mTab = mSidePanel->add( i18n( "debugger", "Debugger" ), mTabContents, - icon ? icon->getSize( PixelDensity::dpToPx( 12 ) ) : nullptr ); + icon ? icon->createDrawable( PixelDensity::dpToPx( 12 ) ) : nullptr ); mTab->setId( "debugger_tab" ); mTab->setTextAsFallback( true ); @@ -1601,20 +1618,22 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, : SyntaxStyleTypes::LineNumber2 ) ) .blendAlpha( editor->getAlpha() ) ); - static UIIcon* circleFilled = getUISceneNode()->findIcon( "circle-perfect" ); - - if ( circleFilled ) { + bool iconDrawn = false; + if ( mBreakpointIcon ) { Float finalHeight = eefloor( radius * 1.75f ); - Drawable* drawable = circleFilled->getSize( finalHeight ); - if ( drawable ) { + auto drawableIt = mBreakpointDrawables.find( (int)finalHeight ); + if ( drawableIt != mBreakpointDrawables.end() && drawableIt->second ) { + DrawablePtr& drawable = drawableIt->second; Color oldColor = drawable->getColor(); drawable->setColor( color ); drawable->draw( Sizef{ lnPos.x, lnPos.y + ( lineHeight - finalHeight ) * 0.5f } .floor() ); drawable->setColor( oldColor ); + iconDrawn = true; } - } else { + } + if ( !iconDrawn ) { p.setColor( color ); p.drawCircle( Sizef{ lnPos.x + radius + ( gutterSpace - radius ) * 0.5f, @@ -1645,12 +1664,12 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, Float dim = radius * 2; Float gutterSpace = editor->getGutterSpace( this ); - static UIIcon* sfIcon = getUISceneNode()->findIcon( "debug-stackframe" ); - if ( sfIcon ) { - Drawable* drawable = sfIcon->getSize( lineHeight ); - if ( drawable ) { - drawable->setColor( color ); - drawable->draw( lnPos.floor() ); + if ( mStackFrameIcon ) { + const int iconSize = (int)eefloor( lineHeight ); + auto drawableIt = mStackFrameDrawables.find( iconSize ); + if ( drawableIt != mStackFrameDrawables.end() && drawableIt->second ) { + drawableIt->second->setColor( color ); + drawableIt->second->draw( lnPos.floor() ); return; } } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index c805b26e6..605920f8d 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -138,6 +138,10 @@ class DebuggerPlugin : public PluginBase { std::string mCurDebugger; std::string mCurConfiguration; std::vector mRegisteredCommands; + UIIcon* mBreakpointIcon{ nullptr }; + UnorderedMap mBreakpointDrawables; + UIIcon* mStackFrameIcon{ nullptr }; + UnorderedMap mStackFrameDrawables; class DebuggerPluginClient : public TextDocument::Client { public: @@ -214,6 +218,8 @@ class DebuggerPlugin : public PluginBase { void onRegisterDocument( TextDocument* doc ) override; + void update( UICodeEditor* editor ) override; + void drawLineNumbersBefore( UICodeEditor* editor, const DocumentLineRange& lineRange, const Vector2f& startScroll, const Vector2f& screenStart, const Float& lineHeight, const Float& lineNumberWidth, diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 1401dcac0..ebab5a1d5 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -1303,7 +1303,7 @@ bool GitPlugin::onCreateContextMenu( UICodeEditor*, UIPopUpMenu* menu, const Vec const std::string& icon = "" ) { subMenu ->add( i18n( txtKey, txtVal ), - !icon.empty() ? findIcon( icon )->getSize( PixelDensity::dpToPxI( 12 ) ) + !icon.empty() ? findIcon( icon )->createDrawable( PixelDensity::dpToPxI( 12 ) ) : nullptr, KeyBindings::keybindFormat( mKeyBindings[txtKey] ) ) ->setId( txtKey ); @@ -1314,7 +1314,7 @@ bool GitPlugin::onCreateContextMenu( UICodeEditor*, UIPopUpMenu* menu, const Vec menu->addSubMenu( i18n( "git", "Git" ), mManager->getUISceneNode() ->findIcon( "source-control" ) - ->getSize( PixelDensity::dpToPxI( 12 ) ), + ->createDrawable( PixelDensity::dpToPxI( 12 ) ), subMenu ); return false; @@ -1453,7 +1453,7 @@ void GitPlugin::buildSidePanelTab() { return; UIIcon* icon = findIcon( "source-control" ); mTab = mSidePanel->add( i18n( "source_control", "Source Control" ), mTabContents, - icon ? icon->getSize( PixelDensity::dpToPx( 12 ) ) : nullptr ); + icon ? icon->createDrawable( PixelDensity::dpToPx( 12 ) ) : nullptr ); mTab->setId( "source_control_tab" ); mTab->setTextAsFallback( true ); return; @@ -1526,7 +1526,7 @@ void GitPlugin::buildSidePanelTab() { String::format( STYLE, color, color ), nullptr, String::hash( "git_plugin_style" ) ); mTab = mSidePanel->add( i18n( "source_control", "Source Control" ), mTabContents, - icon ? icon->getSize( PixelDensity::dpToPx( 12 ) ) : nullptr ); + icon ? icon->createDrawable( PixelDensity::dpToPx( 12 ) ) : nullptr ); mTab->setId( "source_control_tab" ); mTab->setTextAsFallback( true ); diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index e59d6bcfe..fa627e1e7 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -744,6 +744,15 @@ void LinterPlugin::onUnregister( UICodeEditor* editor ) { } void LinterPlugin::update( UICodeEditor* editor ) { + if ( mLightbulbIcon == nullptr ) + mLightbulbIcon = editor->getUISceneNode()->getUIIconThemeManager()->findIcon( + "lightbulb-autofix" ); + if ( mLightbulbIcon ) { + const int iconSize = (int)eefloor( editor->getLineHeight() ); + if ( mLightbulbDrawables.find( iconSize ) == mLightbulbDrawables.end() ) + mLightbulbDrawables[iconSize] = mLightbulbIcon->createDrawable( iconSize ); + } + std::shared_ptr doc = editor->getDocumentRef(); auto it = mDirtyDoc.find( doc.get() ); if ( it != mDirtyDoc.end() && it->second->getElapsedTime() >= mDelayTime ) { @@ -1144,14 +1153,12 @@ void LinterPlugin::drawAfterLineText( UICodeEditor* editor, const Int64& index, if ( !match.diagnostic.codeActions.empty() ) { Color wcolor( editor->getColorScheme().getEditorSyntaxStyle( "warning"_sst ).color ); - if ( nullptr == mLightbulbIcon ) { - mLightbulbIcon = editor->getUISceneNode()->getUIIconThemeManager()->findIcon( - "lightbulb-autofix" ); - } if ( nullptr != mLightbulbIcon ) { - Drawable* drawable = mLightbulbIcon->getSize( (int)eefloor( lineHeight ) ); - if ( drawable == nullptr ) + const int iconSize = (int)eefloor( lineHeight ); + auto drawableIt = mLightbulbDrawables.find( iconSize ); + if ( drawableIt == mLightbulbDrawables.end() || drawableIt->second == nullptr ) return; + DrawablePtr& drawable = drawableIt->second; Color oldColor( drawable->getColor() ); drawable->setColor( wcolor ); @@ -1501,7 +1508,7 @@ bool LinterPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* menu, match.lensBox[editor].contains( localPos ) ) { menu->addSeparator(); menu->add( editor->i18n( "linter_copy_error_message", "Copy Error Message" ), - mManager->getUISceneNode()->findIcon( "copy" )->getSize( + mManager->getUISceneNode()->findIcon( "copy" )->createDrawable( PixelDensity::dpToPxI( 12 ) ) ) ->setId( "linter-copy-error-message" ); mErrorMsg = match.text; diff --git a/src/tools/ecode/plugins/linter/linterplugin.hpp b/src/tools/ecode/plugins/linter/linterplugin.hpp index 7dd8df2f0..8275b0b53 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.hpp +++ b/src/tools/ecode/plugins/linter/linterplugin.hpp @@ -157,6 +157,7 @@ class LinterPlugin : public Plugin { std::set mLSPLanguagesDisabled; String::HashType mConfigHash{ 0 }; UIIcon* mLightbulbIcon{ nullptr }; + UnorderedMap mLightbulbDrawables; std::string mErrorMsg; Rectf mQuickFixRect; std::string mOldMaxWidth; diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index c5f823711..130abf6d4 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -271,8 +271,42 @@ LSPClientPlugin::~LSPClientPlugin() { } } -void LSPClientPlugin::update( UICodeEditor* ) { +void LSPClientPlugin::update( UICodeEditor* editor ) { mClientManager.updateDirty(); + + if ( !mBreadcrumb ) + return; + Font* font = getUISceneNode()->getUIThemeManager()->getDefaultFont(); + if ( !font ) + return; + + const Float fontSize = getUISceneNode()->getUIThemeManager()->getDefaultFontSize(); + const int separatorSize = + PixelDensity::dpToPxI( font->getLineSpacing( fontSize ) * 0.5f ); + if ( mDrawSepIcon == nullptr ) + mDrawSepIcon = getUISceneNode()->findIcon( "chevron-right" ); + if ( mDrawSepIcon && + ( mDrawSepDrawable == nullptr || mDrawSepDrawableSize != separatorSize ) ) { + mDrawSepDrawable = mDrawSepIcon->createDrawable( separatorSize ); + mDrawSepDrawableSize = separatorSize; + } + + const int symbolIconSize = (int)fontSize; + if ( mBreadcrumbIconDrawableSize != symbolIconSize ) { + mBreadcrumbIconDrawables.clear(); + mBreadcrumbIconDrawableSize = symbolIconSize; + } + Lock l( mDocCurrentSymbolsMutex ); + auto symbolsIt = mDocCurrentSymbols.find( editor->getDocument().getURI() ); + if ( symbolsIt == mDocCurrentSymbols.end() ) + return; + for ( const auto& symbol : symbolsIt->second ) { + if ( mBreadcrumbIconDrawables.find( symbol.icon ) != mBreadcrumbIconDrawables.end() ) + continue; + UIIcon* icon = getUISceneNode()->findIcon( symbol.icon ); + if ( icon ) + mBreadcrumbIconDrawables[symbol.icon] = icon->createDrawable( symbolIconSize ); + } } struct LSPPositionAndServer { @@ -1963,33 +1997,29 @@ void LSPClientPlugin::drawTop( UICodeEditor* editor, const Vector2f& screenStart return; pos.x += drawn.getWidth(); - if ( mDrawSepIcon == nullptr ) - mDrawSepIcon = getUISceneNode()->findIcon( "chevron-right" ); Float textHeight = drawn.getHeight(); const auto& symbolsInfo = symbolsInfoIt->second; for ( const auto& info : symbolsInfo ) { - if ( mDrawSepIcon ) { + if ( mDrawSepDrawable ) { pos.x += eefloor( PixelDensity::dpToPx( 8 ) ); - Float iconSize = PixelDensity::dpToPxI( drawn.getHeight() * 0.5f ); - auto iconDrawable = mDrawSepIcon->getSize( iconSize ); - Color c = iconDrawable->getColor(); - iconDrawable->setColor( textColor ); - Float iconHeight = iconDrawable->getPixelsSize().getHeight(); + Color c = mDrawSepDrawable->getColor(); + mDrawSepDrawable->setColor( textColor ); + Float iconHeight = mDrawSepDrawable->getPixelsSize().getHeight(); Vector2f iconPos( { pos.x, screenStart.y + textOffsetY + eefloor( ( textHeight - iconHeight ) * 0.5f ) } ); - iconDrawable->draw( iconPos ); + mDrawSepDrawable->draw( iconPos ); pos.x += - iconDrawable->getPixelsSize().getWidth() + eefloor( PixelDensity::dpToPx( 8 ) ); - iconDrawable->setColor( c ); + mDrawSepDrawable->getPixelsSize().getWidth() + eefloor( PixelDensity::dpToPx( 8 ) ); + mDrawSepDrawable->setColor( c ); } else { pos.x += eefloor( PixelDensity::dpToPx( 16 ) ); } - UIIcon* iconKind = getUISceneNode()->findIcon( info.icon ); - if ( iconKind ) { - auto iconDrawable = iconKind->getSize( fontSize ); + auto iconIt = mBreadcrumbIconDrawables.find( info.icon ); + if ( iconIt != mBreadcrumbIconDrawables.end() && iconIt->second ) { + DrawablePtr& iconDrawable = iconIt->second; Color c = iconDrawable->getColor(); iconDrawable->setColor( textColor ); Float iconHeight = iconDrawable->getPixelsSize().getHeight(); diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp index 4d8fac0c4..bb50c7780 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -149,6 +149,10 @@ class LSPClientPlugin : public Plugin { }; UnorderedMap> mDocCurrentSymbols; UIIcon* mDrawSepIcon{ nullptr }; + DrawablePtr mDrawSepDrawable; + int mDrawSepDrawableSize{ 0 }; + UnorderedMap mBreadcrumbIconDrawables; + int mBreadcrumbIconDrawableSize{ 0 }; std::string mConfigFileError; LSPClientPlugin( PluginManager* pluginManager, bool sync ); diff --git a/src/tools/ecode/plugins/plugin.cpp b/src/tools/ecode/plugins/plugin.cpp index 75b5c73f2..4c95998dc 100644 --- a/src/tools/ecode/plugins/plugin.cpp +++ b/src/tools/ecode/plugins/plugin.cpp @@ -64,9 +64,9 @@ UIIcon* Plugin::findIcon( const std::string& iconName ) { return getManager()->getUISceneNode()->findIcon( iconName ); } -Drawable* Plugin::iconDrawable( const std::string& iconName, Float dpSize ) { +DrawablePtr Plugin::iconDrawable( const std::string& iconName, Float dpSize ) { UIIcon* icon = findIcon( iconName ); - return icon ? icon->getSize( PixelDensity::dpToPx( dpSize ) ) : nullptr; + return icon ? icon->createDrawable( PixelDensity::dpToPx( dpSize ) ) : DrawablePtr{}; } void Plugin::showMessage( LSPMessageType type, const std::string& message, diff --git a/src/tools/ecode/plugins/plugin.hpp b/src/tools/ecode/plugins/plugin.hpp index 24a45b371..271166744 100644 --- a/src/tools/ecode/plugins/plugin.hpp +++ b/src/tools/ecode/plugins/plugin.hpp @@ -58,7 +58,7 @@ class Plugin : public UICodeEditorPlugin { UIIcon* findIcon( const std::string& iconName ); - Drawable* iconDrawable( const std::string& iconName, Float dpSize ); + DrawablePtr iconDrawable( const std::string& iconName, Float dpSize ); virtual void onVersionUpgrade( Uint32 /*oldVersion*/, Uint32 /*currentVersion*/ ) {} diff --git a/src/tools/ecode/plugins/plugincontextprovider.hpp b/src/tools/ecode/plugins/plugincontextprovider.hpp index 4bfd92c08..dfd1a9863 100644 --- a/src/tools/ecode/plugins/plugincontextprovider.hpp +++ b/src/tools/ecode/plugins/plugincontextprovider.hpp @@ -113,9 +113,9 @@ class PluginContextProvider { virtual ProjectDirectoryTree* getDirTree() const = 0; - virtual Drawable* findIcon( const std::string& name ) = 0; + virtual DrawablePtr findIcon( const std::string& name ) = 0; - virtual Drawable* findIcon( const std::string& name, const size_t iconSize ) = 0; + virtual DrawablePtr findIcon( const std::string& name, const size_t iconSize ) = 0; virtual TerminalConfig& termConfig() = 0; diff --git a/src/tools/ecode/plugins/spellchecker/spellcheckerplugin.cpp b/src/tools/ecode/plugins/spellchecker/spellcheckerplugin.cpp index dccc38b29..75e307857 100644 --- a/src/tools/ecode/plugins/spellchecker/spellcheckerplugin.cpp +++ b/src/tools/ecode/plugins/spellchecker/spellcheckerplugin.cpp @@ -529,7 +529,7 @@ bool SpellCheckerPlugin::onCreateContextMenu( UICodeEditor* editor, UIPopUpMenu* const std::string& icon = "" ) { subMenu ->add( i18n( txtKey, txtVal ), - !icon.empty() ? findIcon( icon )->getSize( PixelDensity::dpToPxI( 12 ) ) + !icon.empty() ? findIcon( icon )->createDrawable( PixelDensity::dpToPxI( 12 ) ) : nullptr, KeyBindings::keybindFormat( mKeyBindings[txtKey] ) ) ->setId( txtKey ); diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index f24e63700..8232866e8 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -1231,7 +1231,7 @@ void ProjectBuildManager::buildSidePanelTab() { )html" ); mTab = mSidePanel->add( mUISceneNode->i18n( "build", "Build" ), node, - icon ? icon->getSize( PixelDensity::dpToPx( 12 ) ) : nullptr ); + icon ? icon->createDrawable( PixelDensity::dpToPx( 12 ) ) : nullptr ); mTab->setId( "build_tab" ); mTab->setTextAsFallback( true ); diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index 460245f41..8d83c5bd6 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -14,7 +14,7 @@ std::string SettingsMenu::getKeybind( const std::string& command ) { return mApp->getKeybind( command ); } -Drawable* SettingsMenu::findIcon( const std::string& name ) { +DrawablePtr SettingsMenu::findIcon( const std::string& name ) { return mApp->findIcon( name ); } diff --git a/src/tools/ecode/settingsmenu.hpp b/src/tools/ecode/settingsmenu.hpp index f6dd2c4b7..7b6b436f6 100644 --- a/src/tools/ecode/settingsmenu.hpp +++ b/src/tools/ecode/settingsmenu.hpp @@ -14,7 +14,7 @@ class SettingsMenu { std::string getKeybind( const std::string& command ); - Drawable* findIcon( const std::string& name ); + DrawablePtr findIcon( const std::string& name ); void runCommand( const std::string& command ); diff --git a/src/tools/ecode/statusterminalcontroller.cpp b/src/tools/ecode/statusterminalcontroller.cpp index 308780021..50c094b1a 100644 --- a/src/tools/ecode/statusterminalcontroller.cpp +++ b/src/tools/ecode/statusterminalcontroller.cpp @@ -242,7 +242,7 @@ UITerminal* StatusTerminalController::createTerminal( UIIcon* icon = mUISceneNode->findIcon( "terminal" ); auto tab = mTabWidget->add( - program, term, icon != nullptr ? icon->getSize( PixelDensity::dpToPxI( 12 ) ) : nullptr ); + program, term, icon != nullptr ? icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) : nullptr ); term->setData( (UintPtr)tab ); term->on( Event::OnTitleChange, [tab, term]( auto ) { tab->setText( term->getTitle() ); } ); diff --git a/src/tools/uieditor/uieditor.cpp b/src/tools/uieditor/uieditor.cpp index 9194c7f0e..7ee2c5e05 100644 --- a/src/tools/uieditor/uieditor.cpp +++ b/src/tools/uieditor/uieditor.cpp @@ -1111,7 +1111,7 @@ void App::fileMenuClick( const Event* event ) { SceneManager::instance()->setCurrentUISceneNode( mUISceneNode ); } -Drawable* App::findIcon( const std::string& icon ) { +DrawablePtr App::findIcon( const std::string& icon ) { return mAppUISceneNode->findIconDrawable( icon, mMenuIconSize ); } diff --git a/src/tools/uieditor/uieditor.hpp b/src/tools/uieditor/uieditor.hpp index cd8b289b9..8efd57710 100644 --- a/src/tools/uieditor/uieditor.hpp +++ b/src/tools/uieditor/uieditor.hpp @@ -207,7 +207,7 @@ class App : public UICodeEditorSplitter::Client { std::unordered_set mTmpDocs; ColorSchemeExtPreference mUIColorScheme; - Drawable* findIcon( const std::string& icon ); + DrawablePtr findIcon( const std::string& icon ); }; } // namespace uieditor