Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
BindingContext.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Reflection;
7 using System.Text;
8 using Android.Content;
9 using Android.Widget;
10 
11 namespace MonoDroid.Dialog
12 {
13  public class BindingContext : IDisposable
14  {
15  public RootElement Root;
16  Dictionary<Element, MemberAndInstance> mappings;
17  private Context _context;
18 
19  class MemberAndInstance
20  {
21  public MemberAndInstance(MemberInfo mi, object o)
22  {
23  Member = mi;
24  Obj = o;
25  }
26  public MemberInfo Member;
27  public object Obj;
28  }
29 
30  static object GetValue(MemberInfo mi, object o)
31  {
32  var fi = mi as FieldInfo;
33  if (fi != null)
34  return fi.GetValue(o);
35  var pi = mi as PropertyInfo;
36 
37  var getMethod = pi.GetGetMethod();
38  return getMethod.Invoke(o, new object[0]);
39  }
40 
41  static void SetValue(MemberInfo mi, object o, object val)
42  {
43  var fi = mi as FieldInfo;
44  if (fi != null)
45  {
46  fi.SetValue(o, val);
47  return;
48  }
49  var pi = mi as PropertyInfo;
50  var setMethod = pi.GetSetMethod();
51  setMethod.Invoke(o, new object[] { val });
52  }
53 
54  static string MakeCaption(string name)
55  {
56  var sb = new StringBuilder(name.Length);
57  bool nextUp = true;
58 
59  foreach (char c in name)
60  {
61  if (nextUp)
62  {
63  sb.Append(Char.ToUpper(c));
64  nextUp = false;
65  }
66  else
67  {
68  if (c == '_')
69  {
70  sb.Append(' ');
71  continue;
72  }
73  if (Char.IsUpper(c))
74  sb.Append(' ');
75  sb.Append(c);
76  }
77  }
78  return sb.ToString();
79  }
80 
81  // Returns the type for fields and properties and null for everything else
82  static Type GetTypeForMember(MemberInfo mi)
83  {
84  if (mi is FieldInfo)
85  return ((FieldInfo)mi).FieldType;
86  else if (mi is PropertyInfo)
87  return ((PropertyInfo)mi).PropertyType;
88  return null;
89  }
90 
91  public BindingContext(Context context, object callbacks, object o, string title)
92  {
93  _context = context;
94 
95  if (o == null)
96  throw new ArgumentNullException("o");
97 
98  mappings = new Dictionary<Element, MemberAndInstance>();
99 
100  Root = new RootElement(title);
101  Populate(callbacks, o, Root);
102  }
103 
104  void Populate(object callbacks, object o, RootElement root)
105  {
106  MemberInfo last_radio_index = null;
107  var members = o.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public |
108  BindingFlags.NonPublic | BindingFlags.Instance);
109 
110  Section section = null;
111 
112  foreach (var mi in members)
113  {
114  Type mType = GetTypeForMember(mi);
115 
116  if (mType == null)
117  continue;
118 
119  string caption = null;
120  object[] attrs = mi.GetCustomAttributes(false);
121  bool skip = false;
122  foreach (var attr in attrs)
123  {
124  if (attr is SkipAttribute)
125  skip = true;
126  if (attr is CaptionAttribute)
127  caption = ((CaptionAttribute)attr).Caption;
128  else if (attr is SectionAttribute)
129  {
130  if (section != null)
131  root.Add(section);
132  var sa = attr as SectionAttribute;
133  section = new Section(sa.Caption, sa.Footer);
134  }
135  }
136  if (skip)
137  continue;
138 
139  if (caption == null)
140  caption = MakeCaption(mi.Name);
141 
142  if (section == null)
143  section = new Section();
144 
145  Element element = null;
146 
147  if (mType == typeof(string)) {
148  PasswordAttribute pa = null;
149  AlignmentAttribute align = null;
150  EntryAttribute ea = null;
151  object html = null;
152  EventHandler invoke = null;
153  bool multi = false;
154 
155  foreach (object attr in attrs) {
156  if (attr is PasswordAttribute)
157  pa = attr as PasswordAttribute;
158  else if (attr is EntryAttribute)
159  ea = attr as EntryAttribute;
160  else if (attr is MultilineAttribute)
161  multi = true;
162  else if (attr is HtmlAttribute)
163  html = attr;
164  else if (attr is AlignmentAttribute)
165  align = attr as AlignmentAttribute;
166 
167  if (attr is OnTapAttribute) {
168  string mname = ((OnTapAttribute)attr).Method;
169 
170  if (callbacks == null) {
171  throw new Exception("Your class contains [OnTap] attributes, but you passed a null object for `context' in the constructor");
172  }
173 
174  var method = callbacks.GetType().GetMethod(mname);
175  if (method == null)
176  throw new Exception("Did not find method " + mname);
177  invoke = delegate {
178  method.Invoke(method.IsStatic ? null : callbacks, new object[0]);
179  };
180  }
181  }
182 
183  string value = (string)GetValue(mi, o);
184  if (pa != null)
185  element = new EntryElement(caption, value) { Hint = pa.Placeholder, Password = true };
186  else if (ea != null)
187  element = new EntryElement(caption, value) { Hint = ea.Placeholder };
188  else if (multi)
189  element = new MultilineElement(caption, value);
190  else if (html != null)
191  element = new HtmlElement(caption, value);
192  else
193  {
194  var selement = new StringElement(caption, value);
195  element = selement;
196 
197  if (align != null)
198  selement.Alignment = align.Alignment;
199  }
200 
201  if (invoke != null)
202  {
203  // ((StringElement)element).Click += invoke;
204  }
205  }
206  else if (mType == typeof(float))
207  {
208  var floatElement = new FloatElement(null, null, (int)GetValue(mi, o));
209  floatElement.Caption = caption;
210  element = floatElement;
211 
212  foreach (object attr in attrs)
213  {
214  if (attr is RangeAttribute)
215  {
216  var ra = attr as RangeAttribute;
217  floatElement.MinValue = ra.Low;
218  floatElement.MaxValue = ra.High;
219  floatElement.ShowCaption = ra.ShowCaption;
220  }
221  }
222  }
223  else if (mType == typeof(bool))
224  {
225  bool checkbox = false;
226  foreach (object attr in attrs)
227  {
228  if (attr is CheckboxAttribute)
229  checkbox = true;
230  }
231 
232  if (checkbox)
233  element = new CheckboxElement(caption, (bool)GetValue(mi, o));
234  else
235  element = new BooleanElement(caption, (bool)GetValue(mi, o));
236  }
237  else if (mType == typeof(DateTime))
238  {
239  var dateTime = (DateTime)GetValue(mi, o);
240  bool asDate = false, asTime = false;
241 
242  foreach (object attr in attrs)
243  {
244  if (attr is DateAttribute)
245  asDate = true;
246  else if (attr is TimeAttribute)
247  asTime = true;
248  }
249 
250  if (asDate)
251  element = new DateElement(caption, dateTime);
252  else if (asTime)
253  element = new TimeElement(caption, dateTime);
254  else
255  element = new DateTimeElement(caption, dateTime);
256  }
257  else if (mType.IsEnum)
258  {
259  var csection = new Section();
260  ulong evalue = Convert.ToUInt64(GetValue(mi, o), null);
261  int idx = 0;
262  int selected = 0;
263 
264  foreach (var fi in mType.GetFields(BindingFlags.Public | BindingFlags.Static))
265  {
266  ulong v = Convert.ToUInt64(GetValue(fi, null));
267 
268  if (v == evalue)
269  selected = idx;
270 
271  csection.Add(new RadioElement(MakeCaption(fi.Name)));
272  idx++;
273  }
274 
275  element = new RootElement(caption, new RadioGroup(null, selected)) { csection };
276  }
277  else if (mType == typeof(ImageView))
278  {
279  element = new ImageElement(null); // (ImageView)GetValue(mi, o));
280  }
281  else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(mType))
282  {
283  var csection = new Section();
284  int count = 0;
285 
286  if (last_radio_index == null)
287  throw new Exception("IEnumerable found, but no previous int found");
288  foreach (var e in (IEnumerable)GetValue(mi, o))
289  {
290  csection.Add(new RadioElement(e.ToString()));
291  count++;
292  }
293  int selected = (int)GetValue(last_radio_index, o);
294  if (selected >= count || selected < 0)
295  selected = 0;
296  element = new RootElement(caption, new MemberRadioGroup(null, selected, last_radio_index)) { csection };
297  last_radio_index = null;
298  }
299  else if (typeof(int) == mType)
300  {
301  foreach (object attr in attrs)
302  {
303  if (attr is RadioSelectionAttribute)
304  {
305  last_radio_index = mi;
306  break;
307  }
308  }
309  }
310  else
311  {
312  var nested = GetValue(mi, o);
313  if (nested != null)
314  {
315  var newRoot = new RootElement(caption);
316  Populate(callbacks, nested, newRoot);
317  element = newRoot;
318  }
319  }
320 
321  if (element == null)
322  continue;
323 
324  section.Add(element);
325  mappings[element] = new MemberAndInstance(mi, o);
326  }
327  root.Add(section);
328  }
329 
330  class MemberRadioGroup : RadioGroup
331  {
332  public MemberInfo mi;
333 
334  public MemberRadioGroup(string key, int selected, MemberInfo mi)
335  : base(key, selected)
336  {
337  this.mi = mi;
338  }
339  }
340 
341  public void Dispose()
342  {
343  Dispose(true);
344  }
345 
346  protected virtual void Dispose(bool disposing)
347  {
348  if (disposing)
349  {
350  foreach (var element in mappings.Keys)
351  {
352  element.Dispose();
353  }
354  mappings = null;
355  }
356  }
357 
358  public void Fetch()
359  {
360  foreach (var dk in mappings)
361  {
362  Element element = dk.Key;
363  MemberInfo mi = dk.Value.Member;
364  object obj = dk.Value.Obj;
365 
366  if (element is DateTimeElement)
367  SetValue(mi, obj, ((DateTimeElement)element).DateValue);
368  else if (element is FloatElement)
369  SetValue(mi, obj, ((FloatElement)element).Value);
370  else if (element is BooleanElement)
371  SetValue(mi, obj, ((BooleanElement)element).Value);
372  else if (element is CheckboxElement)
373  SetValue(mi, obj, ((CheckboxElement)element).Value);
374  else if (element is EntryElement)
375  {
376  var entry = (EntryElement)element;
377  // TODO: entry.FetchValue();
378  SetValue(mi, obj, entry.Value);
379  }
380  else if (element is ImageElement)
381  SetValue(mi, obj, ((ImageElement)element).Value);
382  else if (element is RootElement)
383  {
384  var re = element as RootElement;
385  if (re._group as MemberRadioGroup != null)
386  {
387  var group = re._group as MemberRadioGroup;
388  SetValue(group.mi, obj, re.RadioSelected);
389  }
390  else if (re._group as RadioGroup != null)
391  {
392  var mType = GetTypeForMember(mi);
393  var fi = mType.GetFields(BindingFlags.Public | BindingFlags.Static)[re.RadioSelected];
394 
395  SetValue(mi, obj, fi.GetValue(null));
396  }
397  }
398  }
399  }
400  }
401 }
Used to display toggle button on the screen.
virtual void Dispose(bool disposing)
BindingContext(Context context, object callbacks, object o, string title)
_In_ size_t count
Definition: DirectXTexP.h:174
Definition: EntryElement.cs:13
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
Sections contain individual Element instances that are rendered by MonoDroid.Dialog ...
Definition: Section.cs:28
Captures the information about mutually exclusive elements in a RootElement
Definition: Group.cs:22