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