a5719643a06b917040094eb76199afd09beee3ff
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / Style.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Reflection;
4 using Tizen.NUI.StyleSheets;
5
6 namespace Tizen.NUI.Binding
7 {
8     [ContentProperty("Setters")]
9     internal sealed class Style : IStyle
10     {
11         internal const string StyleClassPrefix = "Tizen.NUI.Binding.StyleClass.";
12
13         readonly BindableProperty _basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(Style), typeof(Style), default(Style),
14             propertyChanged: OnBasedOnResourceChanged);
15
16         readonly List<WeakReference<BindableObject>> _targets = new List<WeakReference<BindableObject>>(4);
17
18         Style _basedOnStyle;
19
20         string _baseResourceKey;
21
22         IList<Behavior> _behaviors;
23
24         IList<TriggerBase> _triggers;
25
26         public Style([TypeConverter(typeof(TypeTypeConverter))] [Parameter("TargetType")] Type targetType)
27         {
28             if (targetType == null)
29                 throw new ArgumentNullException("targetType");
30
31             TargetType = targetType;
32             Setters = new List<Setter>();
33         }
34
35         public bool ApplyToDerivedTypes { get; set; }
36
37         public Style BasedOn
38         {
39             get { return _basedOnStyle; }
40             set
41             {
42                 if (_basedOnStyle == value)
43                     return;
44                 if (!ValidateBasedOn(value))
45                     throw new ArgumentException("BasedOn.TargetType is not compatible with TargetType");
46                 Style oldValue = _basedOnStyle;
47                 _basedOnStyle = value;
48                 BasedOnChanged(oldValue, value);
49                 if (value != null)
50                     BaseResourceKey = null;
51             }
52         }
53
54         public string BaseResourceKey
55         {
56             get { return _baseResourceKey; }
57             set
58             {
59                 if (_baseResourceKey == value)
60                     return;
61                 _baseResourceKey = value;
62                 //update all DynamicResources
63                 foreach (WeakReference<BindableObject> bindableWr in _targets)
64                 {
65                     BindableObject target;
66                     if (!bindableWr.TryGetTarget(out target))
67                         continue;
68                     target.RemoveDynamicResource(_basedOnResourceProperty);
69                     if (value != null)
70                         target.SetDynamicResource(_basedOnResourceProperty, value);
71                 }
72                 if (value != null)
73                     BasedOn = null;
74             }
75         }
76
77         internal IList<Behavior> Behaviors
78         {
79             get { return _behaviors ?? (_behaviors = new AttachedCollection<Behavior>()); }
80         }
81
82         public bool CanCascade { get; set; }
83
84         public string Class { get; set; }
85
86         public IList<Setter> Setters { get; }
87
88         internal IList<TriggerBase> Triggers
89         {
90             get { return _triggers ?? (_triggers = new AttachedCollection<TriggerBase>()); }
91         }
92
93         void IStyle.Apply(BindableObject bindable)
94         {
95             _targets.Add(new WeakReference<BindableObject>(bindable));
96             if (BaseResourceKey != null)
97                 bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey);
98             ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
99         }
100
101         public Type TargetType { get; }
102
103         void IStyle.UnApply(BindableObject bindable)
104         {
105             UnApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
106             bindable.RemoveDynamicResource(_basedOnResourceProperty);
107             _targets.RemoveAll(wr =>
108             {
109                 BindableObject target;
110                 return wr.TryGetTarget(out target) && target == bindable;
111             });
112         }
113
114         internal bool CanBeAppliedTo(Type targetType)
115         {
116             if (TargetType == targetType)
117                 return true;
118             if (!ApplyToDerivedTypes)
119                 return false;
120             do
121             {
122                 targetType = targetType.GetTypeInfo().BaseType;
123                 if (TargetType == targetType)
124                     return true;
125             } while (targetType != typeof(Element));
126             return false;
127         }
128
129         void ApplyCore(BindableObject bindable, Style basedOn)
130         {
131             if (basedOn != null)
132                 ((IStyle)basedOn).Apply(bindable);
133
134             foreach (Setter setter in Setters)
135                 setter.Apply(bindable, true);
136             ((AttachedCollection<Behavior>)Behaviors).AttachTo(bindable);
137             ((AttachedCollection<TriggerBase>)Triggers).AttachTo(bindable);
138         }
139
140         void BasedOnChanged(Style oldValue, Style newValue)
141         {
142             foreach (WeakReference<BindableObject> bindableRef in _targets)
143             {
144                 BindableObject bindable;
145                 if (!bindableRef.TryGetTarget(out bindable))
146                     continue;
147
148                 UnApplyCore(bindable, oldValue);
149                 ApplyCore(bindable, newValue);
150             }
151         }
152
153         Style GetBasedOnResource(BindableObject bindable)
154         {
155             return (Style)bindable.GetValue(_basedOnResourceProperty);
156         }
157
158         static void OnBasedOnResourceChanged(BindableObject bindable, object oldValue, object newValue)
159         {
160             // Style style = (bindable as /*VisualElement*/BaseHandle).Style;
161             // if (style == null)
162             //  return;
163             // style.UnApplyCore(bindable, (Style)oldValue);
164             // style.ApplyCore(bindable, (Style)newValue);
165         }
166
167         void UnApplyCore(BindableObject bindable, Style basedOn)
168         {
169             ((AttachedCollection<TriggerBase>)Triggers).DetachFrom(bindable);
170             ((AttachedCollection<Behavior>)Behaviors).DetachFrom(bindable);
171             foreach (Setter setter in Setters)
172                 setter.UnApply(bindable, true);
173
174             if (basedOn != null)
175                 ((IStyle)basedOn).UnApply(bindable);
176         }
177
178         bool ValidateBasedOn(Style value)
179         {
180             if (value == null)
181                 return true;
182             return value.TargetType.IsAssignableFrom(TargetType);
183         }
184     }
185 }