diff --git a/.agent/plans/resource_shared_ownership_architecture.md b/.agent/plans/resource_shared_ownership_architecture.md index 3d75f9a27..397009c24 100644 --- a/.agent/plans/resource_shared_ownership_architecture.md +++ b/.agent/plans/resource_shared_ownership_architecture.md @@ -350,14 +350,14 @@ Resource resolution caches immutable source data. UI consumers own per-consumer ```cpp using DrawablePtr = ResourcePtr; -DrawablePtr Drawable::createInstance() const; +DrawablePtr Drawable::clone() 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 +`clone()` 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. @@ -387,18 +387,21 @@ 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. +`getSource()` supports lookup, measurement, and immediate rendering 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 for callers that retain the drawable +or need persistent independent state. -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. +Immediate, single-threaded render paths may borrow an icon source and temporarily change +presentation state when they restore every changed value before returning and never retain the raw +pointer. Retained widget, menu, model, animated, or otherwise independently stateful consumers must +create and own an instance. Shared child mutation remains forbidden where drawing can be reentrant +or where the complete state cannot be restored locally. -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: +No rendering callback may call `clone()`, `UIIcon::createDrawable()`, or an API that performs either +operation internally. It must render either a previously retained instance or a borrowed source +under the temporary-state contract above. The Stage 4 call-site audit classifies all remaining +direct `clone()` calls as: - implementations recursively cloning their private child state; - constructors and setters adopting a private region/sprite/map instance; @@ -407,8 +410,8 @@ consumer. The Stage 4 call-site audit classifies all remaining direct `createIns - 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. +borrow their per-size icon sources at the point of immediate rendering and restore temporary color +changes before returning. Icons assigned to widgets, menus, or models still use owned instances. ### 7.2 Consumer API @@ -684,22 +687,28 @@ Exit criteria: Status: complete, 2026-07-20. Drawable ownership now uses `DrawablePtr`; textures create private -`TextureDrawable` wrappers; mutable prototypes implement `createInstance()`; sprites, state lists, +`TextureDrawable` wrappers; mutable prototypes implement `clone()`; 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. +Callback state is allocated lazily on the first connection, so ordinary drawable resources carry +no callback allocation. Callback storage and notification snapshots use small inline buffers; +snapshotting preserves safe self-disconnection and reentrant mutation during notification without +allocating in the common case. `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::getSource()` now returns a cached source/prototype for lookup, measurement, and immediate +single-threaded rendering under the temporary-state restoration contract, 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. +`UISVGIcon` cache their lazily materialized sources under the same contract. The complete `clone()` +call-site audit found no remaining render-loop cloning. The code editor, debugger, linter, LSP +breadcrumb, and autocomplete draw-only paths borrow sources directly; retained widget and menu +icons continue to own 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 diff --git a/include/eepp/graphics/arcdrawable.hpp b/include/eepp/graphics/arcdrawable.hpp index 7b3d5b185..6d339b4c6 100644 --- a/include/eepp/graphics/arcdrawable.hpp +++ b/include/eepp/graphics/arcdrawable.hpp @@ -30,7 +30,7 @@ class EE_API ArcDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; Float getRadius() const; diff --git a/include/eepp/graphics/circledrawable.hpp b/include/eepp/graphics/circledrawable.hpp index 0f3523123..a2dca7fde 100644 --- a/include/eepp/graphics/circledrawable.hpp +++ b/include/eepp/graphics/circledrawable.hpp @@ -15,7 +15,7 @@ class EE_API CircleDrawable : public ArcDrawable { CircleDrawable( const Float& radius, const Uint32& segmentsCount ); - DrawablePtr createInstance() const; + DrawablePtr clone() const; }; }} // namespace EE::Graphics diff --git a/include/eepp/graphics/convexshapedrawable.hpp b/include/eepp/graphics/convexshapedrawable.hpp index cc5601c05..fc6c665f7 100644 --- a/include/eepp/graphics/convexshapedrawable.hpp +++ b/include/eepp/graphics/convexshapedrawable.hpp @@ -24,7 +24,7 @@ class EE_API ConvexShapeDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; void setPolygon( const Polygon2f& polygon ); diff --git a/include/eepp/graphics/drawable.hpp b/include/eepp/graphics/drawable.hpp index 5b33592ca..27c623166 100644 --- a/include/eepp/graphics/drawable.hpp +++ b/include/eepp/graphics/drawable.hpp @@ -65,7 +65,7 @@ class EE_API Drawable { /** 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; + virtual DrawablePtr clone() const; void setAlpha( Uint8 alpha ); diff --git a/include/eepp/graphics/drawablegroup.hpp b/include/eepp/graphics/drawablegroup.hpp index a214f762a..e1ba8c80c 100644 --- a/include/eepp/graphics/drawablegroup.hpp +++ b/include/eepp/graphics/drawablegroup.hpp @@ -26,7 +26,7 @@ class EE_API DrawableGroup : public Drawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; void clearDrawables(); diff --git a/include/eepp/graphics/drawableresource.hpp b/include/eepp/graphics/drawableresource.hpp index e0aabac64..9a2754284 100644 --- a/include/eepp/graphics/drawableresource.hpp +++ b/include/eepp/graphics/drawableresource.hpp @@ -2,6 +2,7 @@ #define EE_GRAPHICS_DRAWABLERESOURCE_HPP #include +#include #include #include @@ -12,7 +13,7 @@ class DrawableResource; struct DrawableResourceCallbackState { using Callback = std::function; Uint32 nextId{ 0 }; - UnorderedMap callbacks; + SmallVector, 2> callbacks; }; class EE_API DrawableResourceConnection { diff --git a/include/eepp/graphics/glyphdrawable.hpp b/include/eepp/graphics/glyphdrawable.hpp index 653f6d941..94f8efc4d 100644 --- a/include/eepp/graphics/glyphdrawable.hpp +++ b/include/eepp/graphics/glyphdrawable.hpp @@ -35,7 +35,7 @@ class EE_API GlyphDrawable : public DrawableResource { virtual bool isStateful(); - DrawablePtr createInstance() const; + DrawablePtr clone() 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 d2041fd12..71233271f 100644 --- a/include/eepp/graphics/ninepatch.hpp +++ b/include/eepp/graphics/ninepatch.hpp @@ -51,7 +51,7 @@ class EE_API NinePatch : public DrawableResource { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; TextureRegion* getTextureRegion( const int& side ); diff --git a/include/eepp/graphics/rectangledrawable.hpp b/include/eepp/graphics/rectangledrawable.hpp index 9f951082a..6ecae2dd5 100644 --- a/include/eepp/graphics/rectangledrawable.hpp +++ b/include/eepp/graphics/rectangledrawable.hpp @@ -28,7 +28,7 @@ class EE_API RectangleDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; Float getRotation() const; diff --git a/include/eepp/graphics/sprite.hpp b/include/eepp/graphics/sprite.hpp index 899f7a80a..471b7c507 100644 --- a/include/eepp/graphics/sprite.hpp +++ b/include/eepp/graphics/sprite.hpp @@ -317,7 +317,7 @@ class EE_API Sprite : public Drawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; /** Set the number of repetitions of the animation. Any number below 0 the animation will loop. */ @@ -386,8 +386,8 @@ class EE_API Sprite : public Drawable { /** Pop the event callback id indicated. */ bool popEventsCallback( const Uint32& callbackId ); - /** Creates an independent instance sharing the same texture resources. */ - SpritePtr clone() const; + /** Creates an independent sprite sharing the same texture resources. */ + SpritePtr cloneSprite() const; /** Update the sprite animation */ void update( const Time& ElapsedTime ); diff --git a/include/eepp/graphics/statelistdrawable.hpp b/include/eepp/graphics/statelistdrawable.hpp index 7912581de..c01bb266e 100644 --- a/include/eepp/graphics/statelistdrawable.hpp +++ b/include/eepp/graphics/statelistdrawable.hpp @@ -28,7 +28,7 @@ class EE_API StateListDrawable : public StatefulDrawable { virtual bool isStateful(); - DrawablePtr createInstance() const; + DrawablePtr clone() const; virtual StatefulDrawable* setState( Uint32 state ); diff --git a/include/eepp/graphics/texture.hpp b/include/eepp/graphics/texture.hpp index 4bc18c46d..e3395ee79 100644 --- a/include/eepp/graphics/texture.hpp +++ b/include/eepp/graphics/texture.hpp @@ -294,7 +294,7 @@ class EE_API Texture : public DrawableResource, public Image, private NonCopyabl virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() 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 index 527ae3f13..8b6b994ea 100644 --- a/include/eepp/graphics/texturedrawable.hpp +++ b/include/eepp/graphics/texturedrawable.hpp @@ -22,7 +22,7 @@ class EE_API TextureDrawable : public DrawableResource { void draw( const Vector2f& position ); void draw( const Vector2f& position, const Sizef& size ); bool isStateful(); - DrawablePtr createInstance() const; + DrawablePtr clone() const; const TexturePtr& getTexture() const; diff --git a/include/eepp/graphics/textureregion.hpp b/include/eepp/graphics/textureregion.hpp index 6342b4d79..4d13158a7 100644 --- a/include/eepp/graphics/textureregion.hpp +++ b/include/eepp/graphics/textureregion.hpp @@ -129,7 +129,7 @@ class EE_API TextureRegion : public DrawableResource { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() 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 c5b1c67e9..625fc68d0 100644 --- a/include/eepp/graphics/triangledrawable.hpp +++ b/include/eepp/graphics/triangledrawable.hpp @@ -28,7 +28,7 @@ class EE_API TriangleDrawable : public PrimitiveDrawable { virtual bool isStateful() { return false; } - DrawablePtr createInstance() const; + DrawablePtr clone() const; void setSize( const Sizef& size ); diff --git a/include/eepp/ui/lineargradientdrawable.hpp b/include/eepp/ui/lineargradientdrawable.hpp index 4b28292d5..e4fe8e1e7 100644 --- a/include/eepp/ui/lineargradientdrawable.hpp +++ b/include/eepp/ui/lineargradientdrawable.hpp @@ -50,7 +50,7 @@ class EE_API LinearGradientDrawable : public Graphics::Drawable { virtual bool isStateful() { return false; } - Graphics::DrawablePtr createInstance() const; + Graphics::DrawablePtr clone() const; const std::vector& getColorStops() const; diff --git a/include/eepp/ui/radialgradientdrawable.hpp b/include/eepp/ui/radialgradientdrawable.hpp index 626a92f7c..1161f1753 100644 --- a/include/eepp/ui/radialgradientdrawable.hpp +++ b/include/eepp/ui/radialgradientdrawable.hpp @@ -54,7 +54,7 @@ class EE_API RadialGradientDrawable : public Graphics::Drawable { virtual bool isStateful() { return false; } - Graphics::DrawablePtr createInstance() const; + Graphics::DrawablePtr clone() const; const std::vector& getColorStops() const; diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 6529e7512..c59a66c69 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -997,8 +997,6 @@ 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 }; DrawablePtr mFoldDrawable; diff --git a/include/eepp/ui/uiskin.hpp b/include/eepp/ui/uiskin.hpp index 8b10d2844..3ab26de28 100644 --- a/include/eepp/ui/uiskin.hpp +++ b/include/eepp/ui/uiskin.hpp @@ -20,9 +20,9 @@ class EE_API UISkin : public StateListDrawable { virtual Sizef getPixelsSize(); - DrawablePtr createInstance() const; + DrawablePtr clone() const; - ResourcePtr clone() const; + ResourcePtr cloneSkin() const; ResourcePtr clone( const std::string& newName ) const; diff --git a/src/eepp/graphics/arcdrawable.cpp b/src/eepp/graphics/arcdrawable.cpp index 8577151ab..959435d14 100644 --- a/src/eepp/graphics/arcdrawable.cpp +++ b/src/eepp/graphics/arcdrawable.cpp @@ -31,7 +31,7 @@ ArcDrawable::ArcDrawable( const Float& radius, Uint32 segmentsCount, const Float mSegmentsCount = mSegmentsCount > 360 ? 360 : mSegmentsCount; } -DrawablePtr ArcDrawable::createInstance() const { +DrawablePtr ArcDrawable::clone() const { auto instance = makeResource( mRadius, mSegmentsCount, mArcAngle, mArcStartAngle ); instance->mOffset = mOffset; instance->mFillMode = mFillMode; diff --git a/src/eepp/graphics/circledrawable.cpp b/src/eepp/graphics/circledrawable.cpp index 78033d7eb..575f2323c 100644 --- a/src/eepp/graphics/circledrawable.cpp +++ b/src/eepp/graphics/circledrawable.cpp @@ -15,7 +15,7 @@ CircleDrawable::CircleDrawable() : ArcDrawable( 0, 64 ) {} CircleDrawable::CircleDrawable( const Float& radius, const Uint32& segmentsCount ) : ArcDrawable( radius, segmentsCount ) {} -DrawablePtr CircleDrawable::createInstance() const { +DrawablePtr CircleDrawable::clone() const { auto instance = makeResource( mRadius, mSegmentsCount ); instance->mArcAngle = mArcAngle; instance->mArcStartAngle = mArcStartAngle; diff --git a/src/eepp/graphics/convexshapedrawable.cpp b/src/eepp/graphics/convexshapedrawable.cpp index 5bd602ab7..2f1d3d0fd 100644 --- a/src/eepp/graphics/convexshapedrawable.cpp +++ b/src/eepp/graphics/convexshapedrawable.cpp @@ -9,7 +9,7 @@ ConvexShapeDrawable* ConvexShapeDrawable::New() { ConvexShapeDrawable::ConvexShapeDrawable() : PrimitiveDrawable( Drawable::CONVEXSHAPE ) {} -DrawablePtr ConvexShapeDrawable::createInstance() const { +DrawablePtr ConvexShapeDrawable::clone() const { auto instance = makeResource(); instance->mPolygon = mPolygon; instance->mIndexColor = mIndexColor; diff --git a/src/eepp/graphics/drawable.cpp b/src/eepp/graphics/drawable.cpp index 5f1ae516f..fce244bbf 100644 --- a/src/eepp/graphics/drawable.cpp +++ b/src/eepp/graphics/drawable.cpp @@ -9,7 +9,7 @@ Drawable::Drawable( Type drawableType ) : Drawable::~Drawable() {} -DrawablePtr Drawable::createInstance() const { +DrawablePtr Drawable::clone() const { return {}; } diff --git a/src/eepp/graphics/drawablegroup.cpp b/src/eepp/graphics/drawablegroup.cpp index 6e0bf1e1b..93ae78534 100644 --- a/src/eepp/graphics/drawablegroup.cpp +++ b/src/eepp/graphics/drawablegroup.cpp @@ -15,7 +15,7 @@ DrawableGroup::~DrawableGroup() { clearDrawables(); } -DrawablePtr DrawableGroup::createInstance() const { +DrawablePtr DrawableGroup::clone() const { auto instance = makeResource(); instance->mPosition = mPosition; instance->mColor = mColor; @@ -25,7 +25,7 @@ DrawablePtr DrawableGroup::createInstance() const { for ( const auto& drawable : mGroup ) { if ( !drawable ) continue; - DrawablePtr drawableInstance = drawable->createInstance(); + DrawablePtr drawableInstance = drawable->clone(); if ( !drawableInstance ) return {}; instance->addDrawable( std::move( drawableInstance ) ); diff --git a/src/eepp/graphics/drawableresource.cpp b/src/eepp/graphics/drawableresource.cpp index 6d433a12d..cc7261a99 100644 --- a/src/eepp/graphics/drawableresource.cpp +++ b/src/eepp/graphics/drawableresource.cpp @@ -1,5 +1,7 @@ #include +#include + namespace EE { namespace Graphics { DrawableResourceConnection::DrawableResourceConnection( @@ -29,8 +31,13 @@ DrawableResourceConnection::operator=( DrawableResourceConnection&& other ) noex void DrawableResourceConnection::disconnect() { if ( mId != 0 ) { - if ( auto state = mState.lock() ) - state->callbacks.erase( mId ); + if ( auto state = mState.lock() ) { + auto callback = + std::find_if( state->callbacks.begin(), state->callbacks.end(), + [this]( const auto& callback ) { return callback.first == mId; } ); + if ( callback != state->callbacks.end() ) + state->callbacks.erase( callback ); + } } mState.reset(); mId = 0; @@ -40,17 +47,12 @@ DrawableResourceConnection::operator bool() const { return mId != 0 && !mState.expired(); } -DrawableResource::DrawableResource( Type drawableType ) : - Drawable( drawableType ), - mId( 0 ), - mCallbackState( std::make_shared() ) { +DrawableResource::DrawableResource( Type drawableType ) : Drawable( drawableType ), mId( 0 ) { createUnnamed(); } DrawableResource::DrawableResource( Type drawableType, const std::string& name ) : - Drawable( drawableType ), - mId( 0 ), - mCallbackState( std::make_shared() ) { + Drawable( drawableType ), mId( 0 ) { setName( name ); } @@ -83,8 +85,10 @@ void DrawableResource::onResourceChange() { } void DrawableResource::sendResourceChanged() { - std::vector callbacks; - callbacks.reserve( mCallbackState->callbacks.size() ); + if ( !mCallbackState ) + return; + + SmallVector callbacks; for ( const auto& callback : mCallbackState->callbacks ) callbacks.emplace_back( callback.second ); for ( const auto& callback : callbacks ) @@ -93,8 +97,11 @@ void DrawableResource::sendResourceChanged() { DrawableResourceConnection DrawableResource::connectResourceChange( OnResourceChangeCallback callback ) { + if ( !mCallbackState ) + mCallbackState = std::make_shared(); + Uint32 id = ++mCallbackState->nextId; - mCallbackState->callbacks.emplace( id, std::move( callback ) ); + mCallbackState->callbacks.emplace_back( id, std::move( callback ) ); return DrawableResourceConnection( mCallbackState, id ); } diff --git a/src/eepp/graphics/drawablesearcher.cpp b/src/eepp/graphics/drawablesearcher.cpp index 74986327a..6207820c6 100644 --- a/src/eepp/graphics/drawablesearcher.cpp +++ b/src/eepp/graphics/drawablesearcher.cpp @@ -43,11 +43,11 @@ static DrawablePtr searchByNameInternal( const std::string& name, ResourceScope& } if ( source ) { - return source->createInstance(); + return source->clone(); } TexturePtr texture = resourceScope.findTexture( name ); - return texture ? texture->createInstance() : DrawablePtr{}; + return texture ? texture->clone() : DrawablePtr{}; } static DrawablePtr parseDataURI( const std::string& name, ResourceScope& scope ) { @@ -106,7 +106,7 @@ static DrawablePtr parseDataURI( const std::string& name, ResourceScope& scope ) texture = std::move( tex ); } } - return texture ? texture->createInstance() : DrawablePtr{}; + return texture ? texture->clone() : DrawablePtr{}; } DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstSearchSprite, @@ -137,20 +137,20 @@ DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstS if ( String::startsWith( name, "@textureregion/" ) ) { if ( Drawable* source = TextureAtlasManager::instance()->getTextureRegionByName( name.substr( 12 ) ) ) - drawable = source->createInstance(); + drawable = source->clone(); } else if ( String::startsWith( name, "@image/" ) ) { TexturePtr texture = resourceScope.findTexture( name.substr( 7 ) ); - drawable = texture ? texture->createInstance() : DrawablePtr{}; + drawable = texture ? texture->clone() : DrawablePtr{}; } else if ( String::startsWith( name, "@texture/" ) ) { TexturePtr texture = resourceScope.findTexture( name.substr( 9 ) ); - drawable = texture ? texture->createInstance() : DrawablePtr{}; + drawable = texture ? texture->clone() : 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/" ) ) { if ( Drawable* source = NinePatchManager::instance()->getByName( name.substr( 4 ) ) ) - drawable = source->createInstance(); + drawable = source->clone(); } else { drawable = searchByNameInternal( name, resourceScope ); } @@ -176,7 +176,7 @@ DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstS texture = std::move( tex ); } } - drawable = texture ? texture->createInstance() : DrawablePtr{}; + drawable = texture ? texture->clone() : DrawablePtr{}; } else if ( String::startsWith( name, "http://" ) || String::startsWith( name, "https://" ) ) { TexturePtr texture = resourceScope.findTexture( name ); @@ -209,7 +209,7 @@ DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstS URI( name ), Seconds( 5 ), {}, headers ); } - drawable = texture ? texture->createInstance() : DrawablePtr{}; + drawable = texture ? texture->clone() : DrawablePtr{}; } else if ( String::startsWith( name, "data:image/" ) ) { drawable = parseDataURI( name, resourceScope ); } else { @@ -225,7 +225,7 @@ DrawablePtr DrawableSearcher::searchByName( const std::string& name, bool firstS DrawablePtr DrawableSearcher::searchById( const Uint32& id ) { Drawable* source = TextureAtlasManager::instance()->getTextureRegionById( id ); - DrawablePtr drawable = source ? source->createInstance() : DrawablePtr{}; + DrawablePtr drawable = source ? source->clone() : DrawablePtr{}; if ( !drawable && sPrintWarnings ) Log::warning( "DrawableSearcher::searchById: \"%ld\" not found", id ); diff --git a/src/eepp/graphics/glyphdrawable.cpp b/src/eepp/graphics/glyphdrawable.cpp index 0d26c68f5..1ddea05de 100644 --- a/src/eepp/graphics/glyphdrawable.cpp +++ b/src/eepp/graphics/glyphdrawable.cpp @@ -80,7 +80,7 @@ bool GlyphDrawable::isStateful() { return false; } -DrawablePtr GlyphDrawable::createInstance() const { +DrawablePtr GlyphDrawable::clone() const { auto instance = makeResource( mTexture, mSrcRect.asInt(), mDestSize, mName ); instance->setPixelDensity( mPixelDensity ); instance->setGlyphOffset( mGlyphOffset ); diff --git a/src/eepp/graphics/ninepatch.cpp b/src/eepp/graphics/ninepatch.cpp index 05c3d5e63..d2a12a3b7 100644 --- a/src/eepp/graphics/ninepatch.cpp +++ b/src/eepp/graphics/ninepatch.cpp @@ -65,14 +65,14 @@ NinePatch::NinePatch( TextureRegion* textureRegion, int left, int top, int right NinePatch::~NinePatch() {} -DrawablePtr NinePatch::createInstance() const { +DrawablePtr NinePatch::clone() 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() ) + mDrawable[i] ? std::static_pointer_cast( mDrawable[i]->clone() ) : TextureRegionPtr{}; if ( mDrawable[i] && !instance->mDrawable[i] ) return {}; diff --git a/src/eepp/graphics/rectangledrawable.cpp b/src/eepp/graphics/rectangledrawable.cpp index fc48542e7..8ea6e6e03 100644 --- a/src/eepp/graphics/rectangledrawable.cpp +++ b/src/eepp/graphics/rectangledrawable.cpp @@ -29,7 +29,7 @@ RectangleDrawable::RectangleDrawable( const Vector2f& position, const Sizef& siz mPosition = position; } -DrawablePtr RectangleDrawable::createInstance() const { +DrawablePtr RectangleDrawable::clone() const { auto instance = makeResource( mPosition, mSize ); instance->mRotation = mRotation; instance->mScale = mScale; diff --git a/src/eepp/graphics/scrollparallax.cpp b/src/eepp/graphics/scrollparallax.cpp index fd633b2b3..3535b80a9 100644 --- a/src/eepp/graphics/scrollparallax.cpp +++ b/src/eepp/graphics/scrollparallax.cpp @@ -20,7 +20,7 @@ TextureRegion* ScrollParallax::getTextureRegion() const { void ScrollParallax::setTextureRegion( TextureRegion* textureRegion ) { mTextureRegion = - textureRegion ? std::static_pointer_cast( textureRegion->createInstance() ) + textureRegion ? std::static_pointer_cast( textureRegion->clone() ) : TextureRegionPtr{}; setTextureRegion(); @@ -46,7 +46,7 @@ bool ScrollParallax::create( TextureRegion* textureRegion, const Vector2f& Posit const Sizef& Size, const Vector2f& Speed, const Color& Color, const BlendMode& Blend ) { mTextureRegion = - textureRegion ? std::static_pointer_cast( textureRegion->createInstance() ) + textureRegion ? std::static_pointer_cast( textureRegion->clone() ) : TextureRegionPtr{}; mPos = Position; mSize = Size; diff --git a/src/eepp/graphics/sprite.cpp b/src/eepp/graphics/sprite.cpp index 42bc69a60..9f0bebf4b 100644 --- a/src/eepp/graphics/sprite.cpp +++ b/src/eepp/graphics/sprite.cpp @@ -77,7 +77,7 @@ Sprite& Sprite::operator=( const Sprite& Other ) { frame.Spr.reserve( otherFrame.Spr.size() ); for ( const TextureRegionPtr& region : otherFrame.Spr ) { frame.Spr.emplace_back( - region ? std::static_pointer_cast( region->createInstance() ) + region ? std::static_pointer_cast( region->clone() ) : nullptr ); } mFrames.emplace_back( std::move( frame ) ); @@ -115,12 +115,12 @@ Sprite& Sprite::operator=( const Sprite& Other ) { return *this; } -SpritePtr Sprite::clone() const { +SpritePtr Sprite::cloneSprite() const { return makeResource( *this ); } -DrawablePtr Sprite::createInstance() const { - return clone(); +DrawablePtr Sprite::clone() const { + return cloneSprite(); } void Sprite::clearFrame() { @@ -381,7 +381,7 @@ 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() ) + TextureRegion->clone() ) : TextureRegionPtr{}, NumFrame, NumSubFrame ); } diff --git a/src/eepp/graphics/statelistdrawable.cpp b/src/eepp/graphics/statelistdrawable.cpp index 18ad874df..11824d8e9 100644 --- a/src/eepp/graphics/statelistdrawable.cpp +++ b/src/eepp/graphics/statelistdrawable.cpp @@ -20,14 +20,14 @@ void StateListDrawable::clearDrawables() { mDrawables.clear(); } -DrawablePtr StateListDrawable::createInstance() const { +DrawablePtr StateListDrawable::clone() 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(); + DrawablePtr drawable = state.second->clone(); if ( !drawable ) return {}; instance->setStateDrawable( state.first, std::move( drawable ) ); diff --git a/src/eepp/graphics/texture.cpp b/src/eepp/graphics/texture.cpp index a4bead9dc..9c5dc43a0 100644 --- a/src/eepp/graphics/texture.cpp +++ b/src/eepp/graphics/texture.cpp @@ -18,7 +18,7 @@ using namespace EE::Graphics::Private; namespace EE { namespace Graphics { -DrawablePtr Texture::createInstance() const { +DrawablePtr Texture::clone() const { TexturePtr texture = TextureFactory::instance()->getTexture( getTextureId() ); if ( !texture ) return {}; diff --git a/src/eepp/graphics/texturedrawable.cpp b/src/eepp/graphics/texturedrawable.cpp index ea7d19d56..ef8dbcd5d 100644 --- a/src/eepp/graphics/texturedrawable.cpp +++ b/src/eepp/graphics/texturedrawable.cpp @@ -41,7 +41,7 @@ bool TextureDrawable::isStateful() { return false; } -DrawablePtr TextureDrawable::createInstance() const { +DrawablePtr TextureDrawable::clone() const { TextureDrawablePtr instance = New( mTexture ); instance->setColor( mColor ); instance->setPosition( mPosition ); diff --git a/src/eepp/graphics/textureregion.cpp b/src/eepp/graphics/textureregion.cpp index b8f372d45..cee22e335 100644 --- a/src/eepp/graphics/textureregion.cpp +++ b/src/eepp/graphics/textureregion.cpp @@ -117,7 +117,7 @@ TextureRegion::~TextureRegion() { clearCache(); } -DrawablePtr TextureRegion::createInstance() const { +DrawablePtr TextureRegion::clone() const { auto instance = makeResource( mTexture, mSrcRect, mDestSize, mOffset, mName ); instance->setOriDestSize( mOriDestSize ); instance->setPixelDensity( mPixelDensity ); diff --git a/src/eepp/graphics/triangledrawable.cpp b/src/eepp/graphics/triangledrawable.cpp index 896acb2ad..1c77650f0 100644 --- a/src/eepp/graphics/triangledrawable.cpp +++ b/src/eepp/graphics/triangledrawable.cpp @@ -18,7 +18,7 @@ TriangleDrawable::TriangleDrawable( const Vector2f& position, const Sizef& size mPosition = position; } -DrawablePtr TriangleDrawable::createInstance() const { +DrawablePtr TriangleDrawable::clone() const { auto instance = makeResource( mPosition, mSize ); instance->mTriangle = mTriangle; instance->mComputedTriangle = mComputedTriangle; diff --git a/src/eepp/ui/css/drawableimageparser.cpp b/src/eepp/ui/css/drawableimageparser.cpp index 856fc289a..28ce99ebb 100644 --- a/src/eepp/ui/css/drawableimageparser.cpp +++ b/src/eepp/ui/css/drawableimageparser.cpp @@ -966,7 +966,7 @@ void DrawableImageParser::registerBaseParsers() { } Drawable* drawable = font->getGlyphDrawable( codePoint, node->convertLength( params[1], size.getWidth() ) ); - return drawable ? drawable->createInstance() : DrawablePtr{}; + return drawable ? drawable->clone() : DrawablePtr{}; }; } diff --git a/src/eepp/ui/lineargradientdrawable.cpp b/src/eepp/ui/lineargradientdrawable.cpp index 2340d8f57..268ebceb9 100644 --- a/src/eepp/ui/lineargradientdrawable.cpp +++ b/src/eepp/ui/lineargradientdrawable.cpp @@ -18,7 +18,7 @@ LinearGradientDrawable* LinearGradientDrawable::NewRepeating() { LinearGradientDrawable::LinearGradientDrawable( Graphics::Drawable::Type drawableType ) : Drawable( drawableType ) {} -DrawablePtr LinearGradientDrawable::createInstance() const { +DrawablePtr LinearGradientDrawable::clone() const { auto instance = makeResource( mDrawableType ); instance->mColorStops = mColorStops; instance->mAngle = mAngle; diff --git a/src/eepp/ui/radialgradientdrawable.cpp b/src/eepp/ui/radialgradientdrawable.cpp index 05a98c363..a9b80792b 100644 --- a/src/eepp/ui/radialgradientdrawable.cpp +++ b/src/eepp/ui/radialgradientdrawable.cpp @@ -18,7 +18,7 @@ RadialGradientDrawable* RadialGradientDrawable::NewRepeating() { RadialGradientDrawable::RadialGradientDrawable( Graphics::Drawable::Type drawableType ) : Drawable( drawableType ) {} -DrawablePtr RadialGradientDrawable::createInstance() const { +DrawablePtr RadialGradientDrawable::clone() const { auto instance = makeResource( mDrawableType ); instance->mColorStops = mColorStops; instance->mShape = mShape; diff --git a/src/eepp/ui/tools/uitabwidgetsplitter.cpp b/src/eepp/ui/tools/uitabwidgetsplitter.cpp index b5b6df8bf..7fc460016 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->createInstance() ); + tab->setIcon( result.icon->clone() ); } } if ( curTabWidget->getTabCount() > 0 ) { diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 7c8cd3f98..a1ab4161f 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -484,17 +484,6 @@ 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() ) ) { @@ -1157,21 +1146,27 @@ void UICodeEditor::updateIMELocation() { } void UICodeEditor::drawLockedIcon( const Vector2f start ) { - if ( mFileLockDrawable == nullptr ) + if ( mFileLockIcon == nullptr && !mFileLockIconName.empty() ) + mFileLockIcon = getUISceneNode()->findIcon( mFileLockIconName ); + if ( mFileLockIcon == nullptr ) return; - Float w = mFileLockDrawable->getPixelsSize().getWidth(); + Drawable* fileLockIcon = mFileLockIcon->getSource( PixelDensity::dpToPxI( 16 ) ).get(); + if ( fileLockIcon == nullptr ) + return; + + Float w = fileLockIcon->getPixelsSize().getWidth(); Float posX = mMinimapEnabled ? getMinimapRect( getScreenStart() ).Left - w : ( start.x + mSize.getWidth() - ( mVScrollBar->isVisible() ? mVScrollBar->getPixelsSize().getWidth() : 0 ) ) - mPadding.Right - w; - Color col( mFileLockDrawable->getColor() ); - mFileLockDrawable->setColor( Color( mFontStyleConfig.getFontColor() ).blendAlpha( mAlpha ) ); + Color col( fileLockIcon->getColor() ); + fileLockIcon->setColor( Color( mFontStyleConfig.getFontColor() ).blendAlpha( mAlpha ) ); Float margin = PixelDensity::dpToPxI( 4 ); - mFileLockDrawable->draw( { posX - margin, start.y + margin } ); - mFileLockDrawable->setColor( col ); + fileLockIcon->draw( { posX - margin, start.y + margin } ); + fileLockIcon->setColor( col ); } size_t UICodeEditor::getTotalVisibleLines() const { @@ -3758,8 +3753,6 @@ void UICodeEditor::setFileLockIconName( const std::string& fileLockIconName ) { if ( mFileLockIconName != fileLockIconName ) { mFileLockIconName = fileLockIconName; mFileLockIcon = nullptr; - mFileLockDrawable.reset(); - mFileLockDrawableSize = 0; } } diff --git a/src/eepp/ui/uiicon.cpp b/src/eepp/ui/uiicon.cpp index 323929178..b3c03d905 100644 --- a/src/eepp/ui/uiicon.cpp +++ b/src/eepp/ui/uiicon.cpp @@ -36,7 +36,7 @@ const DrawablePtr& UIIcon::getSource( const int& size ) const { DrawablePtr UIIcon::createDrawable( const int& size ) const { const DrawablePtr& source = getSource( size ); - return source ? source->createInstance() : DrawablePtr{}; + return source ? source->clone() : DrawablePtr{}; } void UIIcon::setSource( const int& size, DrawablePtr drawable ) { @@ -57,7 +57,7 @@ const DrawablePtr& UIGlyphIcon::getSource( const int& size ) const { GlyphDrawable* drawable = mFont->getGlyphDrawable( mCodePoint, size ); if ( !drawable ) return empty; - const_cast( this )->setSource( size, drawable->createInstance() ); + const_cast( this )->setSource( size, drawable->clone() ); return UIIcon::getSource( size ); } diff --git a/src/eepp/ui/uiimage.cpp b/src/eepp/ui/uiimage.cpp index 0d5b3b02d..2b6baef26 100644 --- a/src/eepp/ui/uiimage.cpp +++ b/src/eepp/ui/uiimage.cpp @@ -68,8 +68,7 @@ UIImage::UIImage( const std::string& tag ) : UIWidget( tag ), mScaleType( UIScaleType::None ), mColor(), - mAlignOffset( 0, 0 ), - mAsyncImageAlive( std::make_shared>( true ) ) { + mAlignOffset( 0, 0 ) { mFlags |= UI_AUTO_SIZE; applyDefaultTheme(); @@ -347,6 +346,8 @@ bool UIImage::loadFileDrawable( const Network::URI& uri ) { auto resourceState = scene->getAsyncResourceLoadState(); Uint64 resourceGeneration = resourceState ? resourceState->generation.load( std::memory_order_acquire ) : 0; + if ( !mAsyncImageAlive ) + mAsyncImageAlive = std::make_shared>( true ); auto alive = mAsyncImageAlive; scene->getThreadPool()->run( [resourceState, resourceGeneration, resourceScope, alive, loadId, @@ -396,6 +397,8 @@ void UIImage::loadRemoteDrawable( const Network::URI& uri ) { Uint64 resourceGeneration = resourceState ? resourceState->generation.load( std::memory_order_acquire ) : 0; Uint64 loadId = ++mRemoteImageLoadId; + if ( !mAsyncImageAlive ) + mAsyncImageAlive = std::make_shared>( true ); auto alive = mAsyncImageAlive; TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 1, 1, 4, Color::Transparent, false, Texture::ClampMode::ClampToEdge, false, false, url ); diff --git a/src/eepp/ui/uinode.cpp b/src/eepp/ui/uinode.cpp index a8861f8cb..8fe08d863 100644 --- a/src/eepp/ui/uinode.cpp +++ b/src/eepp/ui/uinode.cpp @@ -1253,7 +1253,7 @@ UINode* UINode::setThemeSkin( UITheme* Theme, const std::string& skinName ) { UINode* UINode::setSkin( const UISkin& Skin ) { removeSkin(); - mSkinState = UISkinState::New( Skin.clone() ); + mSkinState = UISkinState::New( Skin.cloneSkin() ); onThemeLoaded(); @@ -1273,7 +1273,7 @@ UINode* UINode::setSkin( UISkin* skin ) { removeSkin(); - mSkinState = UISkinState::New( skin->clone() ); + mSkinState = UISkinState::New( skin->cloneSkin() ); mSkinState->setState( InitialState ); onThemeLoaded(); diff --git a/src/eepp/ui/uinodedrawable.cpp b/src/eepp/ui/uinodedrawable.cpp index e1271682e..b6cecd7bc 100644 --- a/src/eepp/ui/uinodedrawable.cpp +++ b/src/eepp/ui/uinodedrawable.cpp @@ -415,8 +415,7 @@ UINodeDrawable::LayerDrawable::LayerDrawable( UINodeDrawable* container ) : mAttachmentEq( "scroll" ), mOrigin( Origin::PaddingBox ), mClip( Clip::BorderBox ), - mAttachment( Attachment::Scroll ), - mAsyncDrawableAlive( std::make_shared>( true ) ) {} + mAttachment( Attachment::Scroll ) {} UINodeDrawable::LayerDrawable::~LayerDrawable() { if ( mAsyncDrawableAlive ) @@ -695,6 +694,8 @@ bool UINodeDrawable::LayerDrawable::loadRemoteDrawable( const std::string& value Uint64 resourceGeneration = resourceState ? resourceState->generation.load( std::memory_order_acquire ) : 0; Uint64 loadId = ++mRemoteDrawableLoadId; + if ( !mAsyncDrawableAlive ) + mAsyncDrawableAlive = std::make_shared>( true ); auto alive = mAsyncDrawableAlive; TexturePtr texture = TextureFactory::instance()->createEmptyTexture( 1, 1, 4, Color::Transparent, false, Texture::ClampMode::ClampToEdge, false, false, url ); diff --git a/src/eepp/ui/uiskin.cpp b/src/eepp/ui/uiskin.cpp index 9d144db82..5a611a3bd 100644 --- a/src/eepp/ui/uiskin.cpp +++ b/src/eepp/ui/uiskin.cpp @@ -38,7 +38,7 @@ ResourcePtr UISkin::clone( const std::string& newName ) const { for ( const auto& state : mDrawables ) { if ( !state.second ) continue; - DrawablePtr drawable = state.second->createInstance(); + DrawablePtr drawable = state.second->clone(); if ( !drawable ) return {}; skin->setStateDrawable( state.first, std::move( drawable ) ); @@ -48,12 +48,12 @@ ResourcePtr UISkin::clone( const std::string& newName ) const { return skin; } -ResourcePtr UISkin::clone() const { +ResourcePtr UISkin::cloneSkin() const { return clone( mName ); } -DrawablePtr UISkin::createInstance() const { - return clone(); +DrawablePtr UISkin::clone() const { + return cloneSkin(); } Rectf UISkin::getBorderSize() { diff --git a/src/eepp/ui/uitheme.cpp b/src/eepp/ui/uitheme.cpp index a20bb6e9d..f3c0524cc 100644 --- a/src/eepp/ui/uitheme.cpp +++ b/src/eepp/ui/uitheme.cpp @@ -101,7 +101,7 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* if ( String::startsWith( name, sAbbrIcon ) ) { auto* icon = UIIcon::New( name.substr( sAbbrIcon.size() ) ); icon->setSource( textureRegion->getPixelsSize().getWidth(), - textureRegion->createInstance() ); + textureRegion->clone() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { std::vector dotParts = String::split( name, '.' ); @@ -141,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->createInstance() ); + skins[skinName]->setStateDrawable( stateNum, drawable->clone() ); } else { std::vector nameParts = String::split( name, '_' ); @@ -157,7 +157,7 @@ UITheme* UITheme::loadFromTextureAtlas( UITheme* tTheme, Graphics::TextureAtlas* if ( -1 != stateNum ) skins[skinName]->setStateDrawable( stateNum, - textureRegion->createInstance() ); + textureRegion->clone() ); } } } @@ -201,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->setSource( drawable->getPixelsSize().getWidth(), drawable->createInstance() ); + icon->setSource( drawable->getPixelsSize().getWidth(), drawable->clone() ); tTheme->getIconTheme()->add( icon ); } else if ( String::startsWith( name, sAbbr ) ) { std::vector dotParts = String::split( name, '.' ); @@ -242,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->createInstance() ); + skins[skinName]->setStateDrawable( stateNum, drawable->clone() ); } else { std::vector nameParts = String::split( name, '_' ); @@ -261,7 +261,7 @@ UITheme* UITheme::loadFromDirectory( UITheme* tTheme, const std::string& Path, if ( -1 != stateNum ) skins[skinName]->setStateDrawable( - stateNum, textureRegion->createInstance() ); + stateNum, textureRegion->clone() ); } } } diff --git a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp index 23eeca3de..e419073b9 100644 --- a/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjecttextureregion.cpp @@ -107,7 +107,7 @@ Graphics::TextureRegion* GameObjectTextureRegion::getTextureRegion() const { void GameObjectTextureRegion::setTextureRegion( Graphics::TextureRegion* TextureRegion ) { mTextureRegion = TextureRegion - ? std::static_pointer_cast( TextureRegion->createInstance() ) + ? std::static_pointer_cast( TextureRegion->clone() ) : TextureRegionPtr{}; } diff --git a/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp b/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp index 4d0a9b5aa..3b42a6a55 100644 --- a/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp +++ b/src/modules/maps/src/eepp/maps/gameobjectvirtual.cpp @@ -18,7 +18,7 @@ GameObjectVirtual::GameObjectVirtual( TextureRegion* TextureRegion, MapLayer* La if ( NULL != TextureRegion ) { mDataId = TextureRegion->getId(); mTextureRegion = std::static_pointer_cast( - TextureRegion->createInstance() ); + TextureRegion->clone() ); } } diff --git a/src/tests/test_all/test.cpp b/src/tests/test_all/test.cpp index 2e33477b7..56e55f81f 100644 --- a/src/tests/test_all/test.cpp +++ b/src/tests/test_all/test.cpp @@ -741,7 +741,7 @@ void EETest::createNewUI() { UISprite* sprite = UISprite::New(); sprite->setFlags( UI_AUTO_SIZE ); sprite->setPosition( 50, 600 )->setParent( container ); - sprite->setSprite( SP.clone() ); + sprite->setSprite( SP.cloneSprite() ); UIScrollBar* scrollBar = UIScrollBar::New(); scrollBar->setOrientation( UIOrientation::Horizontal ) diff --git a/src/tests/unit_tests/resource_prerequisite_tests.cpp b/src/tests/unit_tests/resource_prerequisite_tests.cpp index 63c2e04e8..967018e89 100644 --- a/src/tests/unit_tests/resource_prerequisite_tests.cpp +++ b/src/tests/unit_tests/resource_prerequisite_tests.cpp @@ -108,6 +108,7 @@ class TestDrawableResource : public DrawableResource { bool isStateful() { return false; } void notifyChange() { onResourceChange(); } + bool hasCallbackState() const { return mCallbackState != nullptr; } }; class CountingDrawable : public Drawable { @@ -122,7 +123,7 @@ class CountingDrawable : public Drawable { void draw( const Vector2f&, const Sizef& ) {} bool isStateful() { return false; } - DrawablePtr createInstance() const { + DrawablePtr clone() const { ++*mInstanceCount; auto instance = makeResource( mInstanceCount ); instance->setColor( mColor ); @@ -527,10 +528,12 @@ UTEST( ResourcePrerequisites, textureRegionRetainsItsTexture ) { UTEST( ResourcePrerequisites, drawableResourceConnectionsDisconnectWithTheirLifetime ) { auto resource = makeResource(); + EXPECT_FALSE( resource->hasCallbackState() ); int notifications = 0; { DrawableResourceConnection connection = resource->connectResourceChange( [¬ifications]( DrawableResource& ) { ++notifications; } ); + EXPECT_TRUE( resource->hasCallbackState() ); EXPECT_TRUE( static_cast( connection ) ); resource->notifyChange(); EXPECT_EQ( notifications, 1 ); @@ -546,13 +549,27 @@ UTEST( ResourcePrerequisites, drawableResourceConnectionsDisconnectWithTheirLife expiredConnection.disconnect(); } +UTEST( ResourcePrerequisites, drawableResourceCallbacksCanDisconnectDuringNotification ) { + auto resource = makeResource(); + int notifications = 0; + DrawableResourceConnection connection; + connection = resource->connectResourceChange( [&]( DrawableResource& ) { + ++notifications; + connection.disconnect(); + } ); + + resource->notifyChange(); + resource->notifyChange(); + EXPECT_EQ( notifications, 1 ); +} + 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(); + DrawablePtr firstDrawable = texture->clone(); + DrawablePtr secondDrawable = texture->clone(); ASSERT_TRUE( firstDrawable != nullptr ); ASSERT_TRUE( secondDrawable != nullptr ); ASSERT_EQ( firstDrawable->getDrawableType(), Drawable::TEXTUREDRAWABLE ); @@ -620,7 +637,7 @@ UTEST( ResourcePrerequisites, stateListsCloneStateAndChildrenIndependently ) { source->setStateDrawable( 2, secondRegion ); source->setState( 1 ); - DrawablePtr drawableInstance = source->createInstance(); + DrawablePtr drawableInstance = source->clone(); ASSERT_TRUE( drawableInstance != nullptr ); ASSERT_EQ( drawableInstance->getDrawableType(), Drawable::STATELIST ); auto instance = std::static_pointer_cast( drawableInstance ); @@ -659,7 +676,7 @@ UTEST( ResourcePrerequisites, spritesCloneFramesAndAnimationStateIndependently ) source->addFrame( texture, Sizef( 2.f, 2.f ) ); source->setCurrentFrame( 0 ); - SpritePtr instance = source->clone(); + SpritePtr instance = source->cloneSprite(); ASSERT_TRUE( instance != nullptr ); TextureRegion* sourceFrame = source->getTextureRegion( 0 ); TextureRegion* instanceFrame = instance->getTextureRegion( 0 ); @@ -724,7 +741,7 @@ UTEST( ResourcePrerequisites, drawableGroupsAndVariantsHoldSafeIndependentHandle auto rectangle = makeResource( Vector2f( 1.f, 2.f ), Sizef( 3.f, 4.f ) ); source->addDrawable( rectangle ); - DrawablePtr drawableInstance = source->createInstance(); + DrawablePtr drawableInstance = source->clone(); ASSERT_TRUE( drawableInstance != nullptr ); ASSERT_EQ( drawableInstance->getDrawableType(), Drawable::GROUP ); auto instance = std::static_pointer_cast( drawableInstance ); @@ -898,7 +915,7 @@ UTEST( ResourcePrerequisites, engineTeardownReleasesGraphicsBeforeContextsAcross auto* scene = UISceneNode::New(); SceneManager::instance()->add( scene ); scene->enableFrameBuffer(); - UIImage::New()->setDrawable( ninePatch->createInstance() )->setParent( scene->getRoot() ); + UIImage::New()->setDrawable( ninePatch->clone() )->setParent( scene->getRoot() ); auto* font = FontTrueType::New( "engine-teardown-font" ); ASSERT_TRUE( diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp index c810c3a5c..93076a0e4 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.cpp @@ -1451,21 +1451,6 @@ std::string AutoCompletePlugin::getPartialSymbol( TextDocument* doc ) { } 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 ); @@ -1717,8 +1702,11 @@ void AutoCompletePlugin::postDraw( UICodeEditor* editor, const Vector2f& startSc text.draw( cursorPos.x + iconSpace.getWidth() + mBoxPadding.Left, cursorPos.y + mRowHeight * count + mBoxPadding.Top ); - auto iconIt = mSuggestionIconDrawables.find( (int)suggestion.kind ); - DrawablePtr icon = iconIt != mSuggestionIconDrawables.end() ? iconIt->second : DrawablePtr{}; + Drawable* icon = nullptr; + UIIcon* iconSource = editor->getUISceneNode()->findIcon( + LSPCompletionItemHelper::toIconString( suggestion.kind ) ); + if ( iconSource ) + icon = iconSource->getSource( PixelDensity::dpToPxI( 12 ) ).get(); if ( icon ) { Color iconColor( icon->getColor() ); diff --git a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp index ed4e45f11..0ed35f94d 100644 --- a/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp +++ b/src/tools/ecode/plugins/autocomplete/autocompleteplugin.hpp @@ -187,8 +187,6 @@ 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 15edcf137..cc96c43ae 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -183,23 +183,6 @@ 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 ) { @@ -1619,11 +1602,12 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, .blendAlpha( editor->getAlpha() ) ); bool iconDrawn = false; + if ( mBreakpointIcon == nullptr ) + mBreakpointIcon = getUISceneNode()->findIcon( "circle-perfect" ); if ( mBreakpointIcon ) { Float finalHeight = eefloor( radius * 1.75f ); - auto drawableIt = mBreakpointDrawables.find( (int)finalHeight ); - if ( drawableIt != mBreakpointDrawables.end() && drawableIt->second ) { - DrawablePtr& drawable = drawableIt->second; + Drawable* drawable = mBreakpointIcon->getSource( (int)finalHeight ).get(); + if ( drawable ) { Color oldColor = drawable->getColor(); drawable->setColor( color ); drawable->draw( @@ -1664,12 +1648,16 @@ void DebuggerPlugin::drawLineNumbersBefore( UICodeEditor* editor, Float dim = radius * 2; Float gutterSpace = editor->getGutterSpace( this ); + if ( mStackFrameIcon == nullptr ) + mStackFrameIcon = getUISceneNode()->findIcon( "debug-stackframe" ); 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() ); + Drawable* drawable = mStackFrameIcon->getSource( iconSize ).get(); + if ( drawable ) { + Color oldColor = drawable->getColor(); + drawable->setColor( color ); + drawable->draw( lnPos.floor() ); + drawable->setColor( oldColor ); return; } } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index 605920f8d..6690f6c60 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -139,9 +139,7 @@ class DebuggerPlugin : public PluginBase { std::string mCurConfiguration; std::vector mRegisteredCommands; UIIcon* mBreakpointIcon{ nullptr }; - UnorderedMap mBreakpointDrawables; UIIcon* mStackFrameIcon{ nullptr }; - UnorderedMap mStackFrameDrawables; class DebuggerPluginClient : public TextDocument::Client { public: @@ -218,8 +216,6 @@ 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/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index fa627e1e7..89e7305a7 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -744,15 +744,6 @@ 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 ) { @@ -1153,12 +1144,15 @@ void LinterPlugin::drawAfterLineText( UICodeEditor* editor, const Int64& index, if ( !match.diagnostic.codeActions.empty() ) { Color wcolor( editor->getColorScheme().getEditorSyntaxStyle( "warning"_sst ).color ); + if ( mLightbulbIcon == nullptr ) + mLightbulbIcon = + editor->getUISceneNode()->getUIIconThemeManager()->findIcon( + "lightbulb-autofix" ); if ( nullptr != mLightbulbIcon ) { const int iconSize = (int)eefloor( lineHeight ); - auto drawableIt = mLightbulbDrawables.find( iconSize ); - if ( drawableIt == mLightbulbDrawables.end() || drawableIt->second == nullptr ) + Drawable* drawable = mLightbulbIcon->getSource( iconSize ).get(); + if ( drawable == nullptr ) return; - DrawablePtr& drawable = drawableIt->second; Color oldColor( drawable->getColor() ); drawable->setColor( wcolor ); diff --git a/src/tools/ecode/plugins/linter/linterplugin.hpp b/src/tools/ecode/plugins/linter/linterplugin.hpp index 8275b0b53..7dd8df2f0 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.hpp +++ b/src/tools/ecode/plugins/linter/linterplugin.hpp @@ -157,7 +157,6 @@ 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 130abf6d4..19ac79f69 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -271,42 +271,8 @@ LSPClientPlugin::~LSPClientPlugin() { } } -void LSPClientPlugin::update( UICodeEditor* editor ) { +void LSPClientPlugin::update( UICodeEditor* ) { 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 { @@ -1998,28 +1964,34 @@ void LSPClientPlugin::drawTop( UICodeEditor* editor, const Vector2f& screenStart pos.x += drawn.getWidth(); Float textHeight = drawn.getHeight(); + if ( mDrawSepIcon == nullptr ) + mDrawSepIcon = getUISceneNode()->findIcon( "chevron-right" ); + Drawable* separatorDrawable = + mDrawSepIcon + ? mDrawSepIcon->getSource( PixelDensity::dpToPxI( drawn.getHeight() * 0.5f ) ).get() + : nullptr; const auto& symbolsInfo = symbolsInfoIt->second; for ( const auto& info : symbolsInfo ) { - if ( mDrawSepDrawable ) { + if ( separatorDrawable ) { pos.x += eefloor( PixelDensity::dpToPx( 8 ) ); - Color c = mDrawSepDrawable->getColor(); - mDrawSepDrawable->setColor( textColor ); - Float iconHeight = mDrawSepDrawable->getPixelsSize().getHeight(); + Color c = separatorDrawable->getColor(); + separatorDrawable->setColor( textColor ); + Float iconHeight = separatorDrawable->getPixelsSize().getHeight(); Vector2f iconPos( { pos.x, screenStart.y + textOffsetY + eefloor( ( textHeight - iconHeight ) * 0.5f ) } ); - mDrawSepDrawable->draw( iconPos ); + separatorDrawable->draw( iconPos ); pos.x += - mDrawSepDrawable->getPixelsSize().getWidth() + eefloor( PixelDensity::dpToPx( 8 ) ); - mDrawSepDrawable->setColor( c ); + separatorDrawable->getPixelsSize().getWidth() + eefloor( PixelDensity::dpToPx( 8 ) ); + separatorDrawable->setColor( c ); } else { pos.x += eefloor( PixelDensity::dpToPx( 16 ) ); } - auto iconIt = mBreadcrumbIconDrawables.find( info.icon ); - if ( iconIt != mBreadcrumbIconDrawables.end() && iconIt->second ) { - DrawablePtr& iconDrawable = iconIt->second; + UIIcon* icon = getUISceneNode()->findIcon( info.icon ); + Drawable* iconDrawable = icon ? icon->getSource( (int)fontSize ).get() : nullptr; + if ( iconDrawable ) { 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 bb50c7780..4d8fac0c4 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.hpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.hpp @@ -149,10 +149,6 @@ 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 );