blob: 673de1432fac09ffa826f7d959ea92e3d31ecbb4 [file] [log] [blame]
#include "rive/shapes/list_path.hpp"
#include "rive/math/math_types.hpp"
#include "rive/artboard.hpp"
#include "rive/shapes/cubic_detached_vertex.hpp"
#include "rive/shapes/straight_vertex.hpp"
#include "rive/shapes/vertex.hpp"
#include "rive/shapes/path_vertex.hpp"
#include "rive/viewmodel/viewmodel_instance.hpp"
#include "rive/viewmodel/symbol_type.hpp"
#include "rive/viewmodel/viewmodel_instance_number.hpp"
#include "rive/generated/core_registry.hpp"
using namespace rive;
VertexListener::~VertexListener()
{
delete m_vertex;
deleteProperties();
}
void VertexListener::deleteProperties()
{
for (auto& property : m_properties)
{
delete property;
}
m_properties.clear();
}
VertexListener::VertexListener(Vertex* vertex,
rcp<ViewModelInstance> instance,
Path* path) :
m_vertex(vertex), m_instance(instance), m_path(path)
{
createProperties();
}
void VertexListener::createProperties()
{
createPropertyListener(SymbolType::vertexX);
createPropertyListener(SymbolType::vertexY);
createPropertyListener(SymbolType::rotation);
createPropertyListener(SymbolType::inRotation);
createPropertyListener(SymbolType::outRotation);
createPropertyListener(SymbolType::distance);
createPropertyListener(SymbolType::inDistance);
createPropertyListener(SymbolType::outDistance);
createInPointPropertyListener();
createOutPointPropertyListener();
}
void VertexListener::remap(rcp<ViewModelInstance> instance)
{
if (instance != m_instance)
{
m_instance = instance;
deleteProperties();
createProperties();
}
}
VertexPropertyListenerBase* VertexListener::createSinglePropertyListener(
SymbolType symbolType)
{
uint16_t propertyKey = 0;
float multiplier = 1.0f;
switch (symbolType)
{
case SymbolType::vertexX:
propertyKey = VertexBase::xPropertyKey;
break;
case SymbolType::vertexY:
propertyKey = VertexBase::yPropertyKey;
break;
case SymbolType::inRotation:
propertyKey = CubicDetachedVertexBase::inRotationPropertyKey;
multiplier = math::PI / 180.0f;
break;
case SymbolType::outRotation:
propertyKey = CubicDetachedVertexBase::outRotationPropertyKey;
multiplier = math::PI / 180.0f;
break;
case SymbolType::inDistance:
propertyKey = CubicDetachedVertexBase::inDistancePropertyKey;
break;
case SymbolType::outDistance:
propertyKey = CubicDetachedVertexBase::outDistancePropertyKey;
break;
default:
break;
}
auto prop = m_instance->propertyValue(symbolType);
if (prop != nullptr && prop->is<ViewModelInstanceNumber>())
{
auto vpl = new VertexPropertyListenerSingle(m_vertex,
this,
prop,
multiplier,
propertyKey);
return vpl;
}
return nullptr;
}
VertexPropertyListenerBase* VertexListener::createDistancePropertyListener()
{
auto prop = m_instance->propertyValue(SymbolType::distance);
if (prop != nullptr && prop->is<ViewModelInstanceNumber>())
{
std::vector<uint16_t> keys = {};
auto inPropKey = CubicDetachedVertexBase::inDistancePropertyKey;
keys.push_back(inPropKey);
auto outPropKey = CubicDetachedVertexBase::outDistancePropertyKey;
keys.push_back(outPropKey);
auto vpl =
new VertexPropertyListenerMulti(m_vertex, this, prop, 1.0f, keys);
return vpl;
}
return nullptr;
}
VertexPropertyListenerBase* VertexListener::createRotationPropertyListener()
{
auto prop = m_instance->propertyValue(SymbolType::rotation);
if (prop != nullptr && prop->is<ViewModelInstanceNumber>())
{
std::vector<uint16_t> keys = {};
auto inPropKey = CubicDetachedVertexBase::inRotationPropertyKey;
keys.push_back(inPropKey);
auto outPropKey = CubicDetachedVertexBase::outRotationPropertyKey;
keys.push_back(outPropKey);
auto vpl = new VertexPropertyListenerMulti(m_vertex,
this,
prop,
math::PI / 180.0f,
keys);
return vpl;
}
return nullptr;
}
void VertexListener::createInPointPropertyListener()
{
auto xProp = m_instance->propertyValue(SymbolType::cubicVertexInPointX);
auto yProp = m_instance->propertyValue(SymbolType::cubicVertexInPointY);
if ((xProp != nullptr && xProp->is<ViewModelInstanceNumber>()) ||
(yProp != nullptr && yProp->is<ViewModelInstanceNumber>()))
{
auto vpl = new VertexPropertyListenerPoint(
m_vertex,
this,
xProp,
yProp,
CubicDetachedVertexBase::inDistancePropertyKey,
CubicDetachedVertexBase::inRotationPropertyKey);
vpl->writeValue();
m_properties.push_back(vpl);
}
}
void VertexListener::createOutPointPropertyListener()
{
auto xProp = m_instance->propertyValue(SymbolType::cubicVertexOutPointX);
auto yProp = m_instance->propertyValue(SymbolType::cubicVertexOutPointY);
if ((xProp != nullptr && xProp->is<ViewModelInstanceNumber>()) ||
(yProp != nullptr && yProp->is<ViewModelInstanceNumber>()))
{
auto vpl = new VertexPropertyListenerPoint(
m_vertex,
this,
xProp,
yProp,
CubicDetachedVertexBase::outDistancePropertyKey,
CubicDetachedVertexBase::outRotationPropertyKey);
vpl->writeValue();
m_properties.push_back(vpl);
}
}
void VertexListener::createPropertyListener(SymbolType symbolType)
{
VertexPropertyListenerBase* listener = nullptr;
switch (symbolType)
{
case SymbolType::vertexX:
case SymbolType::vertexY:
case SymbolType::inRotation:
case SymbolType::outRotation:
case SymbolType::inDistance:
case SymbolType::outDistance:
listener = createSinglePropertyListener(symbolType);
break;
case SymbolType::distance:
listener = createDistancePropertyListener();
break;
case SymbolType::rotation:
listener = createRotationPropertyListener();
break;
default:
break;
}
if (listener != nullptr)
{
listener->writeValue();
m_properties.push_back(listener);
}
}
VertexPropertyListenerBase::VertexPropertyListenerBase(
Vertex* vertex,
VertexListener* vertexListener) :
m_vertex(vertex), m_vertexListener(vertexListener)
{}
void VertexPropertyListenerBase::addDirt(ComponentDirt value, bool recurse)
{
writeValue();
m_vertexListener->markDirty();
}
VertexPropertyListener::VertexPropertyListener(
Vertex* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* instanceValue,
float multiplier) :
VertexPropertyListenerBase(vertex, vertexListener),
m_instanceValue(instanceValue),
m_multiplier(multiplier)
{
if (m_instanceValue != nullptr)
{
m_instanceValue->addDependent(this);
}
}
VertexPropertyListener::~VertexPropertyListener()
{
if (m_instanceValue != nullptr)
{
m_instanceValue->removeDependent(this);
}
}
VertexPropertyListenerSingle::VertexPropertyListenerSingle(
Vertex* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* instanceValue,
float multiplier,
uint16_t propertyKey) :
VertexPropertyListener(vertex, vertexListener, instanceValue, multiplier),
m_propertyKey(propertyKey)
{}
VertexPropertyListenerSingle::~VertexPropertyListenerSingle() {}
void VertexPropertyListenerSingle::writeValue()
{
CoreRegistry::setDouble(
m_vertex,
m_propertyKey,
m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() *
m_multiplier);
}
VertexPropertyListenerMulti::VertexPropertyListenerMulti(
Vertex* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* instanceValue,
float multiplier,
std::vector<uint16_t> propertyKeys) :
VertexPropertyListener(vertex, vertexListener, instanceValue, multiplier),
m_propertyKeys(propertyKeys)
{}
void VertexPropertyListenerMulti::writeValue()
{
for (auto& key : m_propertyKeys)
{
CoreRegistry::setDouble(
m_vertex,
key,
m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() *
m_multiplier);
}
}
VertexPropertyListenerPoint::VertexPropertyListenerPoint(
Vertex* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* xValue,
ViewModelInstanceValue* yValue,
uint16_t distKey,
uint16_t rotKey) :
VertexPropertyListenerBase(vertex, vertexListener),
m_xValue(xValue),
m_yValue(yValue),
m_distKey(distKey),
m_rotKey(rotKey)
{
if (m_xValue)
{
m_xValue->addDependent(this);
}
if (m_yValue)
{
m_yValue->addDependent(this);
}
}
VertexPropertyListenerPoint::~VertexPropertyListenerPoint()
{
if (m_xValue)
{
m_xValue->removeDependent(this);
}
if (m_yValue)
{
m_yValue->removeDependent(this);
}
}
void VertexPropertyListenerPoint::writeValue()
{
auto x =
m_xValue ? m_xValue->as<ViewModelInstanceNumber>()->propertyValue() : 0;
auto y =
m_yValue ? m_yValue->as<ViewModelInstanceNumber>()->propertyValue() : 0;
auto vec = Vec2D(x, y);
auto length = vec.length();
auto rotation = std::atan2(vec.y, vec.x);
CoreRegistry::setDouble(m_vertex, m_distKey, length);
CoreRegistry::setDouble(m_vertex, m_rotKey, rotation);
}
ListPath::~ListPath()
{
for (auto& vertex : m_vertexListeners)
{
delete vertex;
}
}
void ListPath::updateList(std::vector<rcp<ViewModelInstanceListItem>>* list)
{
auto currentVertexSize = m_vertexListeners.size();
size_t index = 0;
for (auto& listItem : *list)
{
auto instance = listItem->viewModelInstance();
if (instance != nullptr)
{
if (index >= currentVertexSize)
{
// We treat all vertices as CubicDetached vertices because all
// others can be expressed by this one. There doesn't seem to be
// significant performance implications of doing so. But in the
// future it might be valuable to be smarter and build the
// corresponding one.
auto vertex = new CubicDetachedVertex();
auto vertexListener =
new VertexListener(vertex, instance, this);
m_vertexListeners.push_back(vertexListener);
addVertex(vertex);
}
else
{
auto vertexListener = m_vertexListeners[index];
vertexListener->remap(instance);
}
index++;
}
}
while (m_vertexListeners.size() > index)
{
auto vertex = m_vertexListeners.back();
m_vertexListeners.pop_back();
popVertex();
delete vertex;
}
markPathDirty();
}