blob: 4ff9c1ba37ce8c355677958feb2f780881145b9d [file]
#ifndef _RIVE_DRAWABLE_HPP_
#define _RIVE_DRAWABLE_HPP_
#include "rive/generated/drawable_base.hpp"
#include "rive/hit_info.hpp"
#include "rive/lazy_vector.hpp"
#include "rive/renderer.hpp"
#include "rive/clip_result.hpp"
#include "rive/drawable_flag.hpp"
#include <vector>
namespace rive
{
class ClippingShape;
class Artboard;
class DrawRules;
class LayoutComponent;
class Drawable : public DrawableBase
{
friend class Artboard;
friend class StateMachineInstance;
private:
LazyVector<ClippingShape*> m_ClippingShapes;
/// Used exclusively by the artboard;
DrawRules* flattenedDrawRules = nullptr;
Drawable* prev = nullptr;
Drawable* next = nullptr;
protected:
bool m_needsSaveOperation = true;
public:
BlendMode blendMode() const { return (BlendMode)blendModeValue(); }
virtual void draw(Renderer* renderer) = 0;
virtual Core* hitTest(HitInfo*, const Mat2D&) = 0;
bool hitTestPoint(const Vec2D& position,
bool skipOnUnclipped,
bool isPrimaryHit) override;
void addClippingShape(ClippingShape* shape);
inline const std::vector<ClippingShape*>& clippingShapes() const
{
return m_ClippingShapes.view();
}
#ifdef WITH_RIVE_EDITOR
// Editor-only removal companion to `addClippingShape`. Fires from
// `ClippingShape::editorParentChanged` when a ClippingShape is
// reparented away from this drawable's clip-affecting ancestor (or
// about to be freed) so the typed list doesn't dangle. Runtime
// assumes immutable hierarchy and never needs this. Body in
// `editor_native/.../component_parent_editor.cpp`.
void removeClippingShapeForEditor(ClippingShape* shape);
#endif
virtual bool isHidden() const
{
if ((static_cast<DrawableFlag>(drawableFlags()) &
DrawableFlag::Hidden) == DrawableFlag::Hidden ||
hasDirt(ComponentDirt::Collapsed))
{
return true;
}
#ifdef WITH_RIVE_EDITOR
// Editor-only: respect the hierarchy panel's eye toggle.
// Walks the parent chain since `ComponentFlags::hidden`
// doesn't physically cascade to children. Mirrors dart's
// [stage_hideable.dart:76-80](packages/editor/lib/rive/stage/stage_hideable.dart#L76-L80).
// Runtime flags() is always 0, so this branch is dead weight
// there but free at runtime build time.
if (isFlaggedRecursive(EditorFlagHidden))
{
return true;
}
// Isolation: when any component in the artboard has the
// isolated bit set, everything outside the isolated subtree
// is hidden on stage. After-Effects-style.
if (isOutsideEditorIsolationScope())
{
return true;
}
#endif
return false;
}
#ifdef WITH_RIVE_EDITOR
/// True iff the active artboard has at least one component with
/// `EditorFlagIsolated` set AND this drawable is NOT a descendant
/// of one of those isolated subtrees. Walks the artboard's full
/// hierarchy on each call — cheap because flagged components are
/// rare and the walk short-circuits on the first match. Mirrors
/// dart's [Artboard.hasIsolatedComponents]/[isInIsolationScope]
/// pair used by
/// [stage_hideable.dart:87-92](packages/editor/lib/rive/stage/stage_hideable.dart#L87-L92).
/// Body in `editor_native/native/src/editor/drawable_editor.cpp`
/// so this header doesn't depend on the full Artboard def.
bool isOutsideEditorIsolationScope() const;
#endif
virtual bool isTargetOpaque()
{
return (static_cast<DrawableFlag>(drawableFlags()) &
DrawableFlag::Opaque) == DrawableFlag::Opaque;
}
virtual bool isProxy() { return false; }
virtual bool isClipStart() { return false; }
virtual bool isClipEnd() { return false; }
virtual bool willClip() { return false; }
virtual bool willDraw();
void needsSaveOperation(bool value) { m_needsSaveOperation = value; }
bool isChildOfLayout(LayoutComponent* layout);
StatusCode onAddedDirty(CoreContext* context) override;
virtual Drawable* hittableComponent() { return this; }
virtual int emptyClipCount() { return 0; }
// Public accessors for the artboard's draw-order linked list.
// Order is back-to-front (firstDrawable() is bottom-most).
Drawable* nextDrawable() const { return next; }
Drawable* prevDrawable() const { return prev; }
};
class ProxyDrawing
{
public:
virtual void drawProxy(Renderer* renderer) = 0;
virtual bool isProxyHidden() = 0;
};
class DrawableProxy : public Drawable
{
private:
ProxyDrawing* m_proxyDrawing;
public:
DrawableProxy(ProxyDrawing* proxy) : m_proxyDrawing(proxy) {}
void draw(Renderer* renderer) override
{
m_proxyDrawing->drawProxy(renderer);
}
bool isHidden() const override { return m_proxyDrawing->isProxyHidden(); }
Drawable* hittableComponent() override;
bool isTargetOpaque() override;
Core* hitTest(HitInfo*, const Mat2D&) override { return nullptr; }
bool isProxy() override { return true; }
ProxyDrawing* proxyDrawing() const { return m_proxyDrawing; }
};
} // namespace rive
#endif