using System;
using System.Collections.Generic;
using System.Reflection;
using Tizen.NUI.StyleSheets;
using System.ComponentModel;
namespace Tizen.NUI.Binding
{
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
[ContentProperty("Setters")]
public sealed class Style : IStyle
{
internal const string StyleClassPrefix = "Tizen.NUI.Binding.StyleClass.";
readonly BindableProperty _basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(Style), typeof(Style), default(Style),
propertyChanged: OnBasedOnResourceChanged);
readonly List> _targets = new List>(4);
Style _basedOnStyle;
string _baseResourceKey;
IList _behaviors;
IList _triggers;
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public Style([TypeConverter(typeof(TypeTypeConverter))] [Parameter("TargetType")] Type targetType)
{
if (targetType == null)
throw new ArgumentNullException(nameof(targetType));
TargetType = targetType;
Setters = new List();
}
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ApplyToDerivedTypes { get; set; }
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public Style BasedOn
{
get { return _basedOnStyle; }
set
{
if (_basedOnStyle == value)
return;
if (!ValidateBasedOn(value))
throw new ArgumentException("BasedOn.TargetType is not compatible with TargetType");
Style oldValue = _basedOnStyle;
_basedOnStyle = value;
BasedOnChanged(oldValue, value);
if (value != null)
BaseResourceKey = null;
}
}
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public string BaseResourceKey
{
get { return _baseResourceKey; }
set
{
if (_baseResourceKey == value)
return;
_baseResourceKey = value;
//update all DynamicResources
foreach (WeakReference bindableWr in _targets)
{
BindableObject target;
if (!bindableWr.TryGetTarget(out target))
continue;
target.RemoveDynamicResource(_basedOnResourceProperty);
if (value != null)
target.SetDynamicResource(_basedOnResourceProperty, value);
}
if (value != null)
BasedOn = null;
}
}
internal IList Behaviors
{
get { return _behaviors ?? (_behaviors = new AttachedCollection()); }
}
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public bool CanCascade { get; set; }
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public string Class { get; set; }
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public IList Setters { get; }
/// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public IList Triggers
{
get { return _triggers ?? (_triggers = new AttachedCollection()); }
}
void IStyle.Apply(BindableObject bindable)
{
_targets.Add(new WeakReference(bindable));
if (BaseResourceKey != null)
bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey);
ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
}
/// 6
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public Type TargetType { get; }
void IStyle.UnApply(BindableObject bindable)
{
UnApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
bindable.RemoveDynamicResource(_basedOnResourceProperty);
_targets.RemoveAll(wr =>
{
BindableObject target;
return wr.TryGetTarget(out target) && target == bindable;
});
}
internal bool CanBeAppliedTo(Type targetType)
{
if (TargetType == targetType)
return true;
if (!ApplyToDerivedTypes)
return false;
do
{
targetType = targetType.GetTypeInfo().BaseType;
if (TargetType == targetType)
return true;
} while (targetType != typeof(Element));
return false;
}
void ApplyCore(BindableObject bindable, Style basedOn)
{
if (basedOn != null)
((IStyle)basedOn).Apply(bindable);
foreach (Setter setter in Setters)
setter.Apply(bindable, true);
((AttachedCollection)Behaviors).AttachTo(bindable);
((AttachedCollection)Triggers).AttachTo(bindable);
}
void BasedOnChanged(Style oldValue, Style newValue)
{
foreach (WeakReference bindableRef in _targets)
{
BindableObject bindable;
if (!bindableRef.TryGetTarget(out bindable))
continue;
UnApplyCore(bindable, oldValue);
ApplyCore(bindable, newValue);
}
}
Style GetBasedOnResource(BindableObject bindable)
{
return (Style)bindable.GetValue(_basedOnResourceProperty);
}
static void OnBasedOnResourceChanged(BindableObject bindable, object oldValue, object newValue)
{
// Style style = (bindable as /*VisualElement*/BaseHandle).Style;
// if (style == null)
// return;
// style.UnApplyCore(bindable, (Style)oldValue);
// style.ApplyCore(bindable, (Style)newValue);
}
void UnApplyCore(BindableObject bindable, Style basedOn)
{
((AttachedCollection)Triggers).DetachFrom(bindable);
((AttachedCollection)Behaviors).DetachFrom(bindable);
foreach (Setter setter in Setters)
setter.UnApply(bindable, true);
if (basedOn != null)
((IStyle)basedOn).UnApply(bindable);
}
bool ValidateBasedOn(Style value)
{
if (value == null)
return true;
return value.TargetType.IsAssignableFrom(TargetType);
}
}
}