blob: 3186d29d93952aa4218c933efab91b8034321f97 [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(Vertex* vertex,
rcp<ViewModelInstance> instance,
Path* path) :
CoreObjectListener(vertex, instance), m_path(path)
{
createProperties();
}
void VertexListener::createProperties()
{
CoreObjectListener::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();
}
PropertySymbolDependent* 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_core,
this,
prop,
propertyKey,
multiplier);
return vpl;
}
return nullptr;
}
PropertySymbolDependent* 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_core, this, prop, keys, 1.0f);
return vpl;
}
return nullptr;
}
PropertySymbolDependent* 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_core,
this,
prop,
keys,
math::PI / 180.0f);
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_core,
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_core,
this,
xProp,
yProp,
CubicDetachedVertexBase::outDistancePropertyKey,
CubicDetachedVertexBase::outRotationPropertyKey);
vpl->writeValue();
m_properties.push_back(vpl);
}
}
void VertexListener::createPropertyListener(SymbolType symbolType)
{
PropertySymbolDependent* 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);
}
}
VertexPropertyListenerSingle::VertexPropertyListenerSingle(
Core* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* instanceValue,
uint16_t propertyKey,
float multiplier) :
PropertySymbolDependentSingle(vertex,
vertexListener,
instanceValue,
propertyKey),
m_multiplier(multiplier)
{}
void VertexPropertyListenerSingle::writeValue()
{
CoreRegistry::setDouble(
m_coreObject,
m_propertyKey,
m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() *
m_multiplier);
}
VertexPropertyListenerMulti::VertexPropertyListenerMulti(
Core* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* instanceValue,
std::vector<uint16_t> propertyKeys,
float multiplier) :
PropertySymbolDependentMulti(vertex,
vertexListener,
instanceValue,
propertyKeys),
m_multiplier(multiplier)
{}
void VertexPropertyListenerMulti::writeValue()
{
for (auto& key : m_propertyKeys)
{
CoreRegistry::setDouble(
m_coreObject,
key,
m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() *
m_multiplier);
}
}
VertexPropertyListenerPoint::VertexPropertyListenerPoint(
Core* vertex,
VertexListener* vertexListener,
ViewModelInstanceValue* xValue,
ViewModelInstanceValue* yValue,
uint16_t distKey,
uint16_t rotKey) :
PropertySymbolDependent(vertex, vertexListener, xValue),
m_yValue(yValue),
m_distKey(distKey),
m_rotKey(rotKey)
{
if (m_yValue)
{
m_yValue->addDependent(this);
}
}
VertexPropertyListenerPoint::~VertexPropertyListenerPoint()
{
if (m_yValue)
{
m_yValue->removeDependent(this);
}
}
void VertexPropertyListenerPoint::writeValue()
{
auto x =
m_instanceValue
? m_instanceValue->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_coreObject, m_distKey, length);
CoreRegistry::setDouble(m_coreObject, 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();
}