blob: bf1f65a75a4ac16b775aa62292fe995c5982d397 [file]
#include "rive/data_bind/context/context_target_value.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind/data_values/data_value.hpp"
#include "rive/data_bind/data_values/data_value_asset_image.hpp"
#include "rive/data_bind/data_values/data_value_asset_font.hpp"
#include "rive/data_bind/data_values/data_value_asset_blob.hpp"
#include "rive/data_bind/bindable_property_asset.hpp"
#include "rive/data_bind/data_values/data_value_boolean.hpp"
#include "rive/data_bind/data_values/data_value_color.hpp"
#include "rive/data_bind/data_values/data_value_integer.hpp"
#include "rive/data_bind/data_values/data_value_number.hpp"
#include "rive/data_bind/data_values/data_value_string.hpp"
#include "rive/data_bind/data_values/data_value_viewmodel.hpp"
#include "rive/data_bind/bindable_property_viewmodel.hpp"
#include "rive/core/field_types/core_bool_type.hpp"
#include "rive/core/field_types/core_color_type.hpp"
#include "rive/core/field_types/core_double_type.hpp"
#include "rive/core/field_types/core_string_type.hpp"
#include "rive/core/field_types/core_uint_type.hpp"
#include "rive/viewmodel/viewmodel_instance.hpp"
#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
#include "rive/generated/core_registry.hpp"
using namespace rive;
DataBindContextTargetValue::~DataBindContextTargetValue()
{
if (m_targetValue != nullptr)
{
delete m_targetValue;
}
};
void DataBindContextTargetValue::initialize(DataBind* dataBind)
{
switch (CoreRegistry::propertyFieldId(dataBind->propertyKey()))
{
case CoreUintType::id:
{
// Solos are a special case where the output type is relevant to
// apply the reverse conversion. In the furute we might need to
// traverse the full conversion chain to make sure we create the
// right type.
if (dataBind->propertyKey() == SoloBase::activeComponentIdPropertyKey)
{
if (dataBind->sourceOutputType() == DataType::string)
{
m_targetValue = new DataValueString();
}
else if (dataBind->sourceOutputType() == DataType::number)
{
m_targetValue = new DataValueNumber();
}
else if (dataBind->sourceOutputType() == DataType::enumType)
{
m_targetValue = new DataValueInteger();
}
}
else if (
dataBind->source() != nullptr &&
dataBind->source()->coreType() ==
ViewModelInstanceAssetImageBase::typeKey)
{
m_targetValue = new DataValueAssetImage();
}
else if (
dataBind->source() != nullptr &&
dataBind->source()->coreType() ==
ViewModelInstanceAssetFontBase::typeKey)
{
m_targetValue = new DataValueAssetFont();
}
else if (
dataBind->source() != nullptr &&
dataBind->source()->coreType() ==
ViewModelInstanceAssetBlobBase::typeKey)
{
m_targetValue = new DataValueAssetBlob();
}
else if (
dataBind->source() != nullptr &&
dataBind->source()->coreType() ==
ViewModelInstanceViewModelBase::typeKey)
{
m_targetValue = new DataValueViewModel();
}
else if (dataBind->sourceOutputType() == DataType::number)
{
m_targetValue = new DataValueNumber();
}
else
{
m_targetValue = new DataValueInteger();
}
}
break;
case CoreColorType::id:
{
m_targetValue = new DataValueColor();
}
break;
case CoreDoubleType::id:
{
m_targetValue = new DataValueNumber();
}
break;
case CoreStringType::id:
{
m_targetValue = new DataValueString();
}
break;
case CoreBoolType::id:
{
m_targetValue = new DataValueBoolean();
}
break;
default:
break;
}
}
bool DataBindContextTargetValue::syncTargetValue(DataBind* dataBind)
{
if (!dataBind->target())
{
return false;
}
switch (CoreRegistry::propertyFieldId(dataBind->propertyKey()))
{
case CoreUintType::id:
{
if (dataBind->propertyKey() == SoloBase::activeComponentIdPropertyKey &&
dataBind->target()->is<Solo>())
{
auto target = dataBind->target()->as<Solo>();
if (dataBind->sourceOutputType() == DataType::string)
{
auto value = target->getActiveChildName();
return updateValue<DataValueString, std::string>(value);
}
else if (dataBind->sourceOutputType() == DataType::number)
{
auto value = (float)target->getActiveChildIndex();
return updateValue<DataValueNumber, float>(value);
}
else if (dataBind->sourceOutputType() == DataType::integer)
{
auto value = target->getActiveChildIndex();
return updateValue<DataValueInteger, int>(value);
}
else if (dataBind->sourceOutputType() == DataType::enumType)
{
auto activeChildName = target->getActiveChildName();
if (dataBind->source() &&
dataBind->source()->is<ViewModelInstanceEnum>())
{
auto viewModelInstanceEnum = dataBind->source()
->as<ViewModelInstanceEnum>();
if (viewModelInstanceEnum->viewModelProperty())
{
auto enumProperty = viewModelInstanceEnum->viewModelProperty()
->as<ViewModelPropertyEnum>();
if (enumProperty && enumProperty->dataEnum())
{
auto dataEnum = enumProperty->dataEnum();
auto index = dataEnum->valueIndex(activeChildName);
return updateValue<DataValueInteger, int>(index);
}
}
}
}
}
else if (
dataBind->target()->coreType() == BindablePropertyAssetBase::typeKey)
{
auto bindableAsset = dataBind->target()->as<BindablePropertyAsset>();
auto value = CoreRegistry::getUint(
dataBind->target(),
dataBind->propertyKey());
bool didChange = false;
if (updateValue<DataValueInteger, int>(value))
{
didChange = true;
}
// BindablePropertyAsset carries either a live image or a live
// font; sync whichever matches the target value's kind (the id
// above is always synced).
if (m_targetValue->is<DataValueAssetImage>())
{
auto image = bindableAsset->fileAsset()->renderImage();
if (image != m_targetValue->as<DataValueAssetImage>()->imageValue())
{
m_targetValue->as<DataValueAssetImage>()->imageValue(image);
didChange = true;
}
}
else if (m_targetValue->is<DataValueAssetFont>())
{
auto font = bindableAsset->fontValue();
if (font != m_targetValue->as<DataValueAssetFont>()->fontValue())
{
m_targetValue->as<DataValueAssetFont>()->fontValue(font);
didChange = true;
}
}
else if (m_targetValue->is<DataValueAssetBlob>())
{
auto blob = bindableAsset->blobValue();
if (blob != m_targetValue->as<DataValueAssetBlob>()->blobValue())
{
m_targetValue->as<DataValueAssetBlob>()->blobValue(blob);
didChange = true;
}
}
return didChange;
}
else if (
dataBind->target()->coreType() ==
BindablePropertyViewModelBase::typeKey)
{
bool didChange = false;
auto viewModelInstance = dataBind->target()
->as<BindablePropertyViewModel>()
->viewModelInstanceValue();
if (m_targetValue->is<DataValueViewModel>() &&
m_targetValue->as<DataValueViewModel>()->value() !=
viewModelInstance)
{
m_targetValue->as<DataValueViewModel>()->value(viewModelInstance);
didChange = true;
}
return didChange;
}
else if (
dataBind->target()->coreType() ==
ViewModelInstanceViewModelBase::typeKey)
{
bool didChange = false;
auto
viewModelInstanceViewModel = dataBind->target()
->as<ViewModelInstanceViewModel>();
if (viewModelInstanceViewModel->referenceViewModelInstance().get() !=
m_targetValue->as<DataValueViewModel>()->value())
{
m_targetValue->as<DataValueViewModel>()->value(
viewModelInstanceViewModel->referenceViewModelInstance().get());
didChange = true;
}
return didChange;
}
else
{
int32_t value;
if (CoreRegistry::isSignedInt(dataBind->propertyKey()))
{
value = CoreRegistry::getInt(
dataBind->target(),
dataBind->propertyKey());
}
else
{
value = (int32_t)CoreRegistry::getUint(
dataBind->target(),
dataBind->propertyKey());
}
// Match whatever target value type initialize() created: a
// number source (e.g. a color channel bound to a VM number)
// reads back as a DataValueNumber; integer/enum sources stay
// DataValueInteger. Keying off the real type keeps the two
// methods in lockstep regardless of source-resolution timing.
if (m_targetValue != nullptr && m_targetValue->is<DataValueNumber>())
{
return updateValue<DataValueNumber, float>((float)value);
}
// initialize() picks a view model value when the source is a
// view model reference, so a plain uint target whose path
// lands on one pairs them wrongly. Writing an integer through
// that value would overwrite the ViewModelInstance pointer it
// holds. Asset values are integers and pass.
if (m_targetValue == nullptr || !m_targetValue->is<DataValueInteger>())
{
return false;
}
return updateValue<DataValueInteger, int>(value);
}
}
break;
case CoreColorType::id:
{
auto value = CoreRegistry::getColor(
dataBind->target(),
dataBind->propertyKey());
return updateValue<DataValueColor, int>(value);
}
break;
case CoreDoubleType::id:
{
auto value = CoreRegistry::getDouble(
dataBind->target(),
dataBind->propertyKey());
return updateValue<DataValueNumber, float>(value);
}
break;
case CoreStringType::id:
{
auto value = CoreRegistry::getString(
dataBind->target(),
dataBind->propertyKey());
return updateValue<DataValueString, std::string>(value);
}
break;
case CoreBoolType::id:
{
auto value = CoreRegistry::getBool(
dataBind->target(),
dataBind->propertyKey());
return updateValue<DataValueBoolean, bool>(value);
}
break;
default:
break;
}
return false;
}