#pragma once #include "include/core/SkCanvas.h" #include #include #include #include #include #include #include #include #include #include #include namespace NXKit { class CALayerDelegate { public: virtual std::shared_ptr actionForKey(std::string event) = 0; virtual void display(std::shared_ptr layer) = 0; virtual void updateCurrentEnvironment() = 0; virtual bool isHierarchyRoot() { return false; } }; class CALayer: public enable_shared_from_this { public: CALayer(); CALayer(CALayer* layer); virtual ~CALayer() {} std::weak_ptr delegate; // Getter Setters void setContentsGravity(CALayerContentsGravity contentsGravity) { _contentsGravity = contentsGravity; } [[nodiscard]] CALayerContentsGravity contentsGravity() const { return _contentsGravity; } void setContentsScale(NXFloat contentsScale); [[nodiscard]] NXFloat contentsScale() const { return _contentsScale; } void setScaleModifier(NXFloat scaleModifier); [[nodiscard]] NXFloat scaleModifier() const { return _scaleModifier; } void setAnchorPoint(NXPoint anchorPoint); [[nodiscard]] NXPoint anchorPoint() const { return _anchorPoint; } void setOpacity(NXFloat opacity); [[nodiscard]] NXFloat opacity() const { return _opacity; } void setBounds(NXRect bounds); [[nodiscard]] NXRect bounds() const { return _bounds; } void setPosition(NXPoint position); [[nodiscard]] NXPoint position() const { return _position; } void setZPosition(NXFloat position); [[nodiscard]] NXFloat zPosition() { return _zPosition; } void setBackgroundColor(const std::optional& backgroundColor); [[nodiscard]] std::optional backgroundColor() const { return _backgroundColor; } void setBorderColor(const std::optional& borderColor); [[nodiscard]] std::optional borderColor() const { return _borderColor; } void setBorderWidth(NXFloat borderWidth); [[nodiscard]] NXFloat borderWidth() const { return _borderWidth; } void setShadowColor(const std::optional& shadowColor); [[nodiscard]] std::optional shadowColor() const { return _shadowColor; } void setShadowOffset(NXPoint shadowOffset); [[nodiscard]] NXPoint shadowOffset() const { return _shadowOffset; } void setShadowRadius(NXFloat shadowRadius); [[nodiscard]] NXFloat shadowRadius() const { return _shadowRadius; } void setShadowOpacity(NXFloat shadowOpacity); [[nodiscard]] NXFloat shadowOpacity() const { return _shadowOpacity; } void setCornerRadius(NXFloat cornerRadius); [[nodiscard]] NXFloat cornerRadius() const { return _cornerRadius; } void setTransform(NXTransform3D transform); [[nodiscard]] NXTransform3D transform() const { return _transform; } void setAffineTransform(NXAffineTransform transform); [[nodiscard]] NXAffineTransform affineTransform(); void setMask(const std::shared_ptr& mask); [[nodiscard]] std::shared_ptr mask() const { return _mask; } void setContentsTemplateMode(bool newValue) { _isContentsTemplate = newValue; } [[nodiscard]] bool isContentsTemplateMode() { return _isContentsTemplate; } void setMasksToBounds(bool newValue) { _masksToBounds = newValue; } [[nodiscard]] bool masksToBounds() { return _masksToBounds; } void setContents(std::shared_ptr contents); [[nodiscard]] std::shared_ptr contents() { return _contents; } void setHidden(bool hidden); [[nodiscard]] bool isHidden() const { return _isHidden; } NXRect getFrame(); void setFrame(NXRect frame); virtual void draw(SkCanvas* context); // Layers [[nodiscard]] std::vector> sublayers() { return _sublayers; } void addSublayer(const std::shared_ptr& layer); void insertSublayerAt(const std::shared_ptr& layer, int index); void insertSublayerAbove(const std::shared_ptr& layer, const std::shared_ptr& sibling); void insertSublayerBelow(const std::shared_ptr& layer, const std::shared_ptr& sibling); void removeFromSuperlayer(); virtual std::shared_ptr copy(); std::shared_ptr actionForKey(std::string event) const; static std::shared_ptr defaultActionForKey(const std::string& event); static NXFloat defaultAnimationDuration; std::shared_ptr createPresentation(); std::shared_ptr presentation() { return _presentation; } std::shared_ptr presentationOrSelf(); bool needsDisplay() { return _needsDisplay; } void setNeedsDisplay() { _needsDisplay = true; } void display(); // Animations void add(const std::shared_ptr& animation, const std::string& keyPath); void removeAnimation(const std::string& forKey); void removeAllAnimations(); void onWillSet(const std::string& keyPath); void onDidSetAnimations(bool wasEmpty); static void requestFramerate(int framerate); // Override to add new animatable virtual std::optional value(std::string forKeyPath); void animateAt(Timer currentTime); void skiaRender(SkCanvas* canvas); protected: // Override to add new animatable virtual void update(std::shared_ptr presentation, std::shared_ptr animation, float progress); private: friend class UIView; friend bool applicationRunLoop(); void setLayerTreeDirtyIfNeeded() const; /// Defaults to 1.0 but if the layer is associated with a view, /// the view sets this value to match the screen. NXFloat _contentsScale = 1.0f; NXFloat _scaleModifier = 1.0f; CALayerContentsGravity _contentsGravity = CALayerContentsGravity::resize; std::weak_ptr _superlayer; std::vector> _sublayers; std::shared_ptr _mask; bool _isHidden = false; bool _needsDisplay = true; bool _isContentsTemplate = false; std::shared_ptr _contents; bool _masksToBounds = false; // Animatable NXPoint _anchorPoint = NXPoint(0.5, 0.5); NXPoint _position; NXFloat _opacity = 1; NXFloat _zPosition = 0.0; NXRect _bounds; NXFloat _cornerRadius = 0; std::optional _backgroundColor; NXFloat _borderWidth = 0; std::optional _borderColor; NXTransform3D _transform = NXTransform3D::identity; std::optional _shadowColor; // _shadowPath ?? NXPoint _shadowOffset; NXFloat _shadowRadius; NXFloat _shadowOpacity = 1; /** Indicates whether a layer somewhere has changed since the last render pass. The current implementation of this is quite simple and doesn't check whether the layer is actually in the layer hierarchy or not. In theory this means that we're wasting render passes if users frequently update layers that aren't in the tree. In practice it's not expected that UIKit users would do that often enough for us to care about it. **/ static bool layerTreeIsDirty; static void setLayerTreeIsDirty(); static int maxFramerateRequired; std::shared_ptr _presentation; std::map> animations; bool isPresentationForAnotherLayer = false; /// We disable animation on parameters of views / layers that haven't been rendered yet. /// This is both a performance optimization (avoids lots of animations at the start) /// as well as a correctness fix (matches iOS behaviour). Maybe there's a better way though? bool hasBeenRenderedInThisPartOfOverallLayerHierarchy = false; /// Prohibit layers from making layout dirty if they are not in visible hierarchy void updateIsPartOfPresentedHierarchy(bool value); bool isPartOfPresentedHierarchy() const; bool _isPartOfPresentedHierarchy = false; }; }