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