375 lines
15 KiB
C++
375 lines
15 KiB
C++
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// NoesisGUI - http://www.noesisengine.com
|
|
// Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#ifndef __GUI_DEPENDENCYOBJECT_H__
|
|
#define __GUI_DEPENDENCYOBJECT_H__
|
|
|
|
|
|
#include <NsCore/Noesis.h>
|
|
#include <NsCore/ReflectionDeclare.h>
|
|
#include <NsCore/CompilerTools.h>
|
|
#include <NsCore/Delegate.h>
|
|
#include <NsCore/HashMap.h>
|
|
#include <NsCore/String.h>
|
|
#include <NsGui/IComponentInitializer.h>
|
|
#include <NsGui/DispatcherObject.h>
|
|
#include <NsGui/DependencySystemApi.h>
|
|
#include <NsGui/ValueDestination.h>
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// The following macro should be used by DependencyObject derived classes inside their constructors
|
|
/// when they need to set dependency properties. This way derived classes ensure that dependency
|
|
/// property identifiers are properly created.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#define ForceCreateDependencyProperties Noesis::TypeOf<SelfClass>
|
|
|
|
|
|
namespace Noesis
|
|
{
|
|
|
|
class DependencyObject;
|
|
class DependencyProperty;
|
|
class PropertyMetadata;
|
|
class Freezable;
|
|
struct StoredValue;
|
|
struct ProviderValue;
|
|
struct DependencyPropertyChangedEventArgs;
|
|
class Expression;
|
|
template<class T> class ValueStorageManagerImpl;
|
|
enum FreezableEventReason: int32_t;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Param type for DependencyObject::SetValue<T>
|
|
//
|
|
// Property Type | Param Type
|
|
// ---------------------------------------
|
|
// Ptr<T> T*
|
|
// String const char*
|
|
// T T (basic types) or T&
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
template<class T> struct SetValueType
|
|
{
|
|
typedef typename Param<T>::Type Type;
|
|
};
|
|
template<> struct SetValueType<String>
|
|
{
|
|
typedef const char* Type;
|
|
};
|
|
template<class T> struct SetValueType<Ptr<T>>
|
|
{
|
|
typedef T* Type;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// DependencyPropertyChangedEventArgs. Args passed on property changed event notification.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
struct DependencyPropertyChangedEventArgs
|
|
{
|
|
const DependencyProperty* prop;
|
|
const void* oldValue;
|
|
const void* newValue;
|
|
|
|
template<class T> const T& OldValue() const;
|
|
template<class T> const T& NewValue() const;
|
|
|
|
private:
|
|
friend class DependencyObject;
|
|
friend class FrameworkElement;
|
|
friend class BindingExpression;
|
|
friend class ShaderEffect;
|
|
friend class UIElement;
|
|
|
|
DependencyPropertyChangedEventArgs(const DependencyProperty* dp, const void* oldValue,
|
|
const void* newValue, const PropertyMetadata* metadata);
|
|
|
|
private:
|
|
const PropertyMetadata* metadata;
|
|
};
|
|
|
|
typedef Delegate<void (BaseComponent*, const DependencyPropertyChangedEventArgs&)>
|
|
DependencyPropertyChangedEventHandler;
|
|
|
|
NS_WARNING_PUSH
|
|
NS_MSVC_WARNING_DISABLE(4251 4275)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/// Represents an object that participates in the dependency property system.
|
|
///
|
|
/// The DependencyObject class enables the property system services on its many derived classes.
|
|
/// The property system's primary function is to compute the values of properties, and to provide
|
|
/// system notification about values that have changed. Another key class that participates in the
|
|
/// property system is DependencyProperty. DependencyProperty enables the registration of
|
|
/// dependency properties into the property system, and provides identification and information
|
|
/// about each dependency property, whereas DependencyObject as a base class enables objects to use
|
|
/// the dependency properties.
|
|
///
|
|
/// http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.aspx
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
class NS_GUI_DEPENDENCYSYSTEM_API DependencyObject: public DispatcherObject,
|
|
public IComponentInitializer
|
|
{
|
|
public:
|
|
DependencyObject();
|
|
DependencyObject(const DependencyObject&) = delete;
|
|
DependencyObject& operator=(const DependencyObject&) = delete;
|
|
virtual ~DependencyObject() = 0;
|
|
|
|
/// Gets the provider that returns the effective value for the specified dependency property
|
|
uint8_t GetValueProvider(const DependencyProperty* dp) const;
|
|
|
|
/// Returns the current effective value of a dependency property on this instance of a
|
|
/// DependencyObject
|
|
template<class T>
|
|
const T& GetValue(const DependencyProperty* dp) const;
|
|
|
|
/// Returns the current effective value of a dependency property on this instance of a
|
|
/// DependencyObject as a boxed value
|
|
Ptr<BaseComponent> GetValueObject(const DependencyProperty* dp) const;
|
|
|
|
/// Returns the local value of a dependency property, if it exists
|
|
Ptr<BaseComponent> GetLocalValue(const DependencyProperty* dp) const;
|
|
|
|
/// Returns the base value without animation nor coerce (this never returns Expression like
|
|
/// GetLocalValue)
|
|
template<class T>
|
|
const T& GetBaseValue(const DependencyProperty* dp) const;
|
|
|
|
/// Gets the expression, if any, used to evaluate the specified property value
|
|
Expression* GetExpression(const DependencyProperty* dp) const;
|
|
|
|
/// Sets the local value of a dependency property
|
|
/// \remarks Once set, local value is only removed when calling ClearValue()
|
|
template<class T>
|
|
void SetValue(const DependencyProperty* dp, typename SetValueType<T>::Type value);
|
|
|
|
/// Sets the local value (boxed) of a dependency property
|
|
void SetValueObject(const DependencyProperty* dp, BaseComponent* value);
|
|
|
|
/// Sets the current value of a dependency property. The current value is set on the coerce
|
|
/// field, without modifying source or animated value
|
|
template<class T>
|
|
void SetCurrentValue(const DependencyProperty* dp, typename SetValueType<T>::Type value);
|
|
|
|
/// Sets the current value of a dependency property using a boxed value
|
|
void SetCurrentValueObject(const DependencyProperty* dp, BaseComponent* value);
|
|
|
|
/// Sets the expression to be evaluated dynamically to obtain the value of the property
|
|
void SetExpression(const DependencyProperty* dp, Expression* expression);
|
|
|
|
/// Clears the local value of a property
|
|
/// The property to be cleared is specified by a DependencyProperty identifier
|
|
void ClearLocalValue(const DependencyProperty* dp);
|
|
|
|
/// Re-evaluates the effective value for the specified dependency property if necessary
|
|
/// If null is passed, a full re-evaluation could be needed
|
|
void InvalidateProperty(const DependencyProperty* dp, uint8_t priority = 1);
|
|
|
|
/// Sets the animated value of a property
|
|
template<class T>
|
|
void SetAnimation(const DependencyProperty* dp, typename SetValueType<T>::Type value);
|
|
void SetAnimation(const DependencyProperty* dp, BaseComponent* value);
|
|
|
|
/// Clears the animation value of a property
|
|
template<class T>
|
|
void ClearAnimation(const DependencyProperty* dp);
|
|
void ClearAnimation(const DependencyProperty* dp);
|
|
|
|
/// Coerces and validates the effective property value
|
|
template<class T>
|
|
void CoerceValue(const DependencyProperty* dp);
|
|
void CoerceValue(const DependencyProperty* dp);
|
|
|
|
/// Returns if the value is stored in the cache. If true, the priority is returned in the
|
|
/// provider field
|
|
bool IsCached(const DependencyProperty* dp, uint8_t* provider) const;
|
|
|
|
/// Gets a value that indicates whether this instance is currently sealed (read-only)
|
|
bool IsSealed() const;
|
|
|
|
/// Returns true if there is any animated property
|
|
bool HasAnimatedProperties() const;
|
|
|
|
/// Returns the PropertyChanged event
|
|
DependencyPropertyChangedEventHandler& DependencyPropertyChanged();
|
|
|
|
typedef Delegate<void(DependencyObject*)> DestroyedDelegate;
|
|
|
|
/// Destroyed delegate is raised when object is going to be destroyed
|
|
DestroyedDelegate& Destroyed();
|
|
|
|
/// From IComponentInitializer
|
|
//@{
|
|
bool IsInitialized() const override final;
|
|
void Init() override final;
|
|
void BeginInit() override final;
|
|
void EndInit() override final;
|
|
//@}
|
|
|
|
NS_IMPLEMENT_INTERFACE_FIXUP
|
|
|
|
protected:
|
|
// Calls Destroyed delegate before destroying the object
|
|
int32_t OnDestroy() override;
|
|
|
|
// Indicates whether the property is set to its default value
|
|
bool IsDefaultValue(const DependencyProperty* dp) const;
|
|
|
|
// Sealed objects cannot be modified
|
|
void Seal();
|
|
|
|
// Called to initialize inheritors
|
|
virtual void OnInit();
|
|
|
|
// Called when initialization process is completed
|
|
virtual void OnPostInit();
|
|
|
|
// Called to allow descendants to manage a property value change
|
|
// \return True when it has been processed, otherwise false
|
|
virtual bool OnPropertyChanged(const DependencyPropertyChangedEventArgs& args);
|
|
|
|
// Called to allow descendants to manage a sub property value change
|
|
// \return True when it has been processed, otherwise false
|
|
virtual bool OnSubPropertyChanged(const DependencyProperty* dp);
|
|
|
|
// Called to allow descendants to manage a component value change
|
|
virtual void OnObjectValueSet(BaseComponent* oldValue, BaseComponent* newValue);
|
|
|
|
// Called when uncached properties are locally set
|
|
virtual void OnUncachedPropertySet(const DependencyProperty* dp);
|
|
|
|
// Gets the value of a dependency property from the active provider
|
|
//@{
|
|
virtual ProviderValue GetProviderValue(const DependencyProperty* dp) const;
|
|
virtual ProviderValue GetNonCachedProviderValue(const DependencyProperty* dp) const;
|
|
virtual uint8_t GetNonCachedValueProvider(const DependencyProperty* dp) const;
|
|
//@}
|
|
|
|
template<class T>
|
|
void SetReadOnlyProperty(const DependencyProperty* dp,
|
|
typename SetValueType<T>::Type value) const;
|
|
|
|
void ClearReadOnlyProperty(const DependencyProperty* dp);
|
|
void SetReadOnlyExpression(const DependencyProperty* dp, Expression* expr) const;
|
|
|
|
void InternalSetExpression(const DependencyProperty* dp, Expression* newExpression,
|
|
uint8_t priority);
|
|
|
|
protected:
|
|
// Friend classes and functions
|
|
//@{
|
|
friend class ChangedHandler;
|
|
friend class DependencyObjectTestHelper;
|
|
friend struct BindingOperations;
|
|
friend class BindingExpression;
|
|
friend class VisualTreeInspectorHelper;
|
|
friend class XamlContext;
|
|
template<class T> friend class ValueStorageManagerImpl;
|
|
//@}
|
|
|
|
/// Hash of stored properties
|
|
typedef HashMap<const DependencyProperty*, StoredValue*> Values;
|
|
mutable Values mValues;
|
|
|
|
private:
|
|
bool CheckSealed(const DependencyProperty* dp) const;
|
|
bool CheckReadOnly(const DependencyProperty* dp) const;
|
|
bool CheckTypes(const Type* valueType, const DependencyProperty* dp) const;
|
|
bool CheckTypes(BaseComponent* value, const DependencyProperty* dp) const;
|
|
|
|
// SetValue helpers
|
|
//@{
|
|
typedef Int2Type<0> IsNotBaseComponent;
|
|
typedef Int2Type<1> IsBaseComponent;
|
|
typedef Int2Type<2> IsString;
|
|
|
|
template<class T>
|
|
void SetValue_(IsNotBaseComponent, const DependencyProperty* dp,
|
|
typename Param<T>::Type value, Value::Destination destination, bool readonly);
|
|
|
|
template<class T>
|
|
void SetValue_(IsBaseComponent, const DependencyProperty* dp, BaseComponent* value,
|
|
Value::Destination destination, bool readonly);
|
|
|
|
template<class T>
|
|
void SetValue_(IsString, const DependencyProperty* dp,
|
|
const char* value, Value::Destination destination, bool readonly);
|
|
//@}
|
|
|
|
void InternalSetValue(const DependencyProperty* dp, uint32_t sizeOfT, void* oldValue,
|
|
const void* newValue, void* coercedValue, uint8_t priority, Expression* newExpression,
|
|
const PropertyMetadata* metadata, Value::Destination destination, bool isBaseComponent);
|
|
void SetValue(const DependencyProperty* dp, uint32_t sizeOfT, void* oldValue,
|
|
const void* newValue, void* coercedValue, Value::Destination destination,const Type* type,
|
|
bool readonly);
|
|
void SetValuePtr(const DependencyProperty* dp, void* oldValue, const void* newValue,
|
|
void* coercedValue, Value::Destination destination, bool readonly);
|
|
|
|
void ClearAnimation(const DependencyProperty* dp, uint32_t sizeOfT, void* oldValue,
|
|
void* coercedValue, void* baseValue, bool isBaseComponent);
|
|
|
|
void InternalInvalidateProperty(const DependencyProperty* dp, uint8_t priority);
|
|
const void* InternalGetUncachedValue(const DependencyProperty* dp,
|
|
const void* defaultValue, const PropertyMetadata* metadata) const;
|
|
const void* GetValue(const DependencyProperty* dp, uint32_t sizeOfT) const;
|
|
const void* GetBaseValue(const DependencyProperty* dp, uint32_t sizeOfT) const;
|
|
|
|
// Implementation of coerce value
|
|
void InternalCoerceValue(const DependencyProperty* dp, uint32_t sizeOfT, StoredValue* sv,
|
|
const void* defaultValue, void* oldValue, void* coercedValue,
|
|
const PropertyMetadata* metadata, bool isBaseComponent);
|
|
void CoerceValue(const DependencyProperty* dp, uint32_t sizeOfT, void* oldValue,
|
|
void* coercedValue, bool isBaseComponent);
|
|
|
|
// Management of properties that contain Freezable objects
|
|
//@{
|
|
void AddChangedHandler(const DependencyProperty* dp, Freezable* freezable);
|
|
void RemoveChangedHandler(const DependencyProperty* dp);
|
|
//@}
|
|
|
|
// Launches OnPropertyChange when value changes by a SetValue or ClearValue
|
|
void NotifyPropertyChanged(const DependencyProperty* dp, StoredValue* storedValue,
|
|
const void* oldValue, const void* newValue, bool valueChanged, bool isBaseComponent,
|
|
const PropertyMetadata* metadata);
|
|
|
|
private:
|
|
uint32_t mFlags;
|
|
|
|
struct ChangedHandler
|
|
{
|
|
ChangedHandler() = default;
|
|
ChangedHandler(ChangedHandler&& handler);
|
|
ChangedHandler(const ChangedHandler& handler) = delete;
|
|
ChangedHandler& operator=(ChangedHandler&) = delete;
|
|
ChangedHandler& operator=(ChangedHandler&&) = delete;
|
|
|
|
void OnChanged(Freezable* freezable, FreezableEventReason reason);
|
|
void Attach(Freezable* object);
|
|
void Detach();
|
|
|
|
Freezable* obj = nullptr;
|
|
DependencyObject* owner = nullptr;
|
|
const DependencyProperty* ownerProperty = nullptr;
|
|
};
|
|
|
|
typedef Vector<ChangedHandler> ChangedHandlers;
|
|
ChangedHandlers mChangedHandlers;
|
|
|
|
/// Dependency property changed event
|
|
DependencyPropertyChangedEventHandler mDependencyPropertyChangedEvent;
|
|
DestroyedDelegate mDestroyedDelegate;
|
|
|
|
NS_DECLARE_REFLECTION(DependencyObject, DispatcherObject)
|
|
};
|
|
|
|
NS_WARNING_POP
|
|
|
|
}
|
|
|
|
#include <NsGui/DependencyObject.inl>
|
|
|
|
#endif
|