Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParameterPath.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.Linq;
5 using System.Collections.Generic;
6 using System.Reflection;
7 
8 namespace SiliconStudio.Paradox.Effects
9 {
10  [Obsolete]
11  internal class ParameterPath
12  {
13  public ParameterPath(params ParameterKey[] keys)
14  {
15  Keys = keys.ToArray();
16  }
17 
18  public object GetValue(ParameterCollection parameterCollection)
19  {
20  for (int i = 0; i < Keys.Length; ++i)
21  {
22  if (!parameterCollection.ContainsKey(Keys[i]))
23  return null;
24 
25  var value = parameterCollection.GetObject(Keys[i]);
26 
27  // Last key, returns result
28  if (i == Keys.Length - 1)
29  return value;
30 
31  // Ohterwise, it should be a container
32  if (!(value is ParameterCollection))
33  return null;
34 
35  parameterCollection = (ParameterCollection)value;
36  }
37 
38  return null;
39  }
40 
41  internal ParameterKey[] Keys { get; set; }
42  }
43 
44  [Obsolete]
45  internal class ParameterListener
46  {
47  private List<KeyValuePair<ParameterKey, ParameterCollection>> containers = new List<KeyValuePair<ParameterKey, ParameterCollection>>();
48  private List<ParameterCollection.ValueChangedDelegate> delegates = new List<ParameterCollection.ValueChangedDelegate>();
49 
50  private ParameterPath path;
51 
52  private object currentValue;
53 
54  public delegate void ParameterUpdatedDelegate(ParameterCollection container, ParameterPath path, object newValue);
55 
56  public event ParameterUpdatedDelegate ParameterUpdated;
57 
58  public ParameterListener(ParameterCollection parameterCollection, ParameterPath path)
59  {
60  this.path = path;
61 
62  foreach (var currentContainer in ContainersInPath(parameterCollection, path.Keys))
63  {
64  AppendCurrentPath(currentContainer);
65  }
66 
67  currentValue = path.GetValue(containers[0].Value);
68  }
69 
70  private void AppendCurrentPath(ParameterCollection parameterCollection)
71  {
72  ParameterCollection.ValueChangedDelegate currentDelegate;
73 
74  // Check if this container is already used at some point in the path (cyclic ref)
75  var key = path.Keys[containers.Count];
76  var keyAndContainer = new KeyValuePair<ParameterKey, ParameterCollection>(key, parameterCollection);
77  var containerIndex = containers.IndexOf(keyAndContainer);
78 
79  if (containerIndex == -1)
80  {
81  var pathIndex = containers.Count;
82  currentDelegate = (internalValueKey, internalValue, oldValue) =>
83  propertyContainer_PropertyUpdated(parameterCollection, internalValue.Object, oldValue, pathIndex);
84  parameterCollection.AddEvent(key, currentDelegate);
85  }
86  else
87  {
88  currentDelegate = delegates[containerIndex];
89  }
90 
91  containers.Add(keyAndContainer);
92  delegates.Add(currentDelegate);
93  }
94 
95  private static IEnumerable<ParameterCollection> ContainersInPath(ParameterCollection parameterCollection, IEnumerable<ParameterKey> keys)
96  {
97  yield return parameterCollection;
98  foreach (var key in keys)
99  {
100  if (!parameterCollection.ContainsKey(key))
101  break;
102  var nextContainer = parameterCollection.GetObject(key) as ParameterCollection;
103  if (nextContainer == null)
104  break;
105  yield return nextContainer;
106  parameterCollection = nextContainer;
107  }
108  }
109 
110  private void propertyContainer_PropertyUpdated(ParameterCollection parameterCollection, object newValue, object oldValue, int pathIndex)
111  {
112  if (containers[pathIndex].Value != parameterCollection)
113  throw new InvalidOperationException("Unexpected PropertyContainer in PathListener.");
114 
115  // Optimize case where last item only changed (no need to recreate subpath)
116  if (pathIndex < path.Keys.Length - 1)
117  {
118  // Unregister listeners of this subpath
119  for (int i = pathIndex + 1; i < containers.Count; ++i)
120  {
121  // Only remove event handler if not present in first part of the path (otherwise we need to keep it)
122  if (containers.IndexOf(containers[i], 0, i) == -1)
123  containers[i].Value.RemoveEvent(path.Keys[i], delegates[i]);
124  }
125 
126  // Remove containers of this subpath
127  containers.RemoveRange(pathIndex + 1, containers.Count - pathIndex - 1);
128  delegates.RemoveRange(pathIndex + 1, delegates.Count - pathIndex - 1);
129 
130  // Recreate subpath hierarchy
131  foreach (var currentContainer in ContainersInPath(parameterCollection, path.Keys.Skip(pathIndex)).Skip(1))
132  {
133  // Only add event handler if not already in the path (if same PropertyContainer is multiple time in the path)
134  AppendCurrentPath(currentContainer);
135  }
136  }
137 
138  var newValue2 = path.GetValue(containers[0].Value);
139  if (ParameterUpdated != null && !ArePropertyValuesEqual(path.Keys.Last(), this.currentValue, newValue2))
140  ParameterUpdated(containers[0].Value, path, newValue2);
141  this.currentValue = newValue2;
142  }
143 
144  private static bool ArePropertyValuesEqual(ParameterKey propertyKey, object propertyValue1, object propertyValue2)
145  {
146  var propertyType = propertyKey.PropertyType;
147 
148  if (!propertyType.GetTypeInfo().IsValueType && propertyType != typeof(string))
149  {
150  return object.ReferenceEquals(propertyValue1, propertyValue2);
151  }
152 
153  return object.Equals(propertyValue1, propertyValue2);
154  }
155  }
156 }
SiliconStudio.Paradox.Input.Keys Keys