Exemplo n.º 1
0
		public static void AttachEditorComponents(Entity result, ListProperty<Entity.Handle> target)
		{
			Transform transform = result.Get<Transform>();

			Property<bool> selected = result.GetOrMakeProperty<bool>("EditorSelected");

			Command<Entity> toggleEntityConnected = new Command<Entity>
			{
				Action = delegate(Entity entity)
				{
					if (target.Contains(entity))
						target.Remove(entity);
					else if (entity != result)
						target.Add(entity);
				}
			};
			result.Add("ToggleEntityConnected", toggleEntityConnected);

			LineDrawer connectionLines = new LineDrawer { Serialize = false };
			connectionLines.Add(new Binding<bool>(connectionLines.Enabled, selected));

			Color connectionLineColor = new Color(1.0f, 1.0f, 1.0f, 0.5f);
			ListBinding<LineDrawer.Line, Entity.Handle> connectionBinding = new ListBinding<LineDrawer.Line, Entity.Handle>(connectionLines.Lines, target, delegate(Entity.Handle entity)
			{
				return new LineDrawer.Line
				{
					A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor),
					B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(entity.Target.Get<Transform>().Position, connectionLineColor)
				};
			}, x => x.Target != null && x.Target.Active);
			result.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, selected));
			result.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, () => selected, transform.Position));
			connectionLines.Add(connectionBinding);
			result.Add(connectionLines);
		}
Exemplo n.º 2
0
    private Control CreatePropertyControl(ListProperty property)
    {
        Type type = property.UnderlyingType;

        BindListAttribute listAttribute = type.GetCustomAttribute <BindListAttribute>();

        listAttribute ??= property.PropertyInfo.GetCustomAttribute <BindListAttribute>();

        Control control = null;

        if (type == typeof(bool))
        {
            control = new TabControlCheckBox(property);
        }
        else if (type.IsEnum || listAttribute != null)
        {
            control = new TabControlComboBox(property, listAttribute);
        }
        else if (typeof(DateTime).IsAssignableFrom(type))
        {
            control = new TabDateTimePicker(property);
        }
        else if (!typeof(IList).IsAssignableFrom(type))
        {
            control = new TabControlTextBox(property);
        }

        return(control);
    }
Exemplo n.º 3
0
    private void SetWatermark(ListProperty property)
    {
        WatermarkAttribute attribute = property.PropertyInfo.GetCustomAttribute <WatermarkAttribute>();

        if (attribute == null)
        {
            return;
        }

        if (attribute.MemberName != null)
        {
            MemberInfo[] memberInfos = property.Object.GetType().GetMember(attribute.MemberName);
            if (memberInfos.Length != 1)
            {
                throw new Exception("Found " + memberInfos.Length + " members with name " + attribute.MemberName);
            }

            MemberInfo memberInfo = memberInfos.First();
            if (memberInfo is PropertyInfo propertyInfo)
            {
                Watermark = propertyInfo.GetValue(property.Object)?.ToString();
            }
            else if (memberInfo is FieldInfo fieldInfo)
            {
                Watermark = fieldInfo.GetValue(property.Object)?.ToString();
            }
        }
        Watermark ??= attribute.Text;
    }
Exemplo n.º 4
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="listProperty"></param>
 protected virtual void ListAreaSection()
 {
     for (int i = 0; i < ListProperty.arraySize; i++)
     {
         ListItemAreaSection(ListProperty.GetArrayElementAtIndex(i), i);
     }
 }
Exemplo n.º 5
0
        public static void AttachEditorComponents(Entity entity, string name, ListProperty <Entity.Handle> target)
        {
            entity.Add(name, target);
            if (entity.EditorSelected != null)
            {
                Transform transform = entity.Get <Transform>("Transform");

                LineDrawer connectionLines = new LineDrawer {
                    Serialize = false
                };
                connectionLines.Add(new Binding <bool>(connectionLines.Enabled, entity.EditorSelected));

                ListBinding <LineDrawer.Line, Entity.Handle> connectionBinding = new ListBinding <LineDrawer.Line, Entity.Handle>(connectionLines.Lines, target, delegate(Entity.Handle other)
                {
                    return(new LineDrawer.Line
                    {
                        A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor),
                        B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(other.Target.Get <Transform>("Transform").Position, connectionLineColor)
                    });
                }, x => x.Target != null && x.Target.Active);
                entity.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, entity.EditorSelected));
                entity.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, () => entity.EditorSelected, transform.Position));
                connectionLines.Add(connectionBinding);
                entity.Add(connectionLines);
            }
        }
Exemplo n.º 6
0
 /// <summary>
 /// Clears an object in the array, item will be null but still exist in the array.
 /// </summary>
 /// <param name="listProperty">The list SerializedProperty that has the associated array attached.</param>
 /// <param name="listItemProperty">The listItem SerializedProperty</param>
 /// <param name="index">Index of item</param>
 protected virtual void ClearItem(SerializedProperty listItemProperty, int index)
 {
     // Check value is not null, otherwise we will unset it
     if (listItemProperty.objectReferenceValue != null)
     {
         ListProperty.DeleteArrayElementAtIndex(index);
     }
 }
Exemplo n.º 7
0
        public static void WriteListObject(Type type, JObject jObject, Object obj)
        {
            List <PropertyInfo> propertyList = type.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(ListProperty))).ToList();

            foreach (PropertyInfo property in propertyList)
            {
                ListProperty listProperty = (ListProperty)property.GetCustomAttributes(typeof(ListProperty), false)[0];
                if (jObject[listProperty.SqlPropertyName] != null)
                {
                    switch (property.PropertyType.Name)
                    {
                    case "String":
                        property.SetValue(obj, jObject[listProperty.SqlPropertyName].ToString());
                        break;

                    case "Boolean":
                        property.SetValue(obj, Convert.ToBoolean(Convert.ToInt32(jObject[listProperty.SqlPropertyName].ToString())));
                        break;

                    case "DateTime":
                        System.Globalization.CultureInfo provider = System.Globalization.CultureInfo.InvariantCulture;
                        property.SetValue(obj, DateTime.Parse(jObject[listProperty.SqlPropertyName].ToString()));
                        break;

                    case "Nullable`1":
                        Type nullableType = property.PropertyType.GetGenericArguments()[0];
                        switch (nullableType.Name)
                        {
                        case "Int32":
                            if (jObject[listProperty.SqlPropertyName].ToString() != "")
                            {
                                property.SetValue(obj, Int32.Parse(jObject[listProperty.SqlPropertyName].ToString()));
                            }
                            break;

                        case "DateTime":
                            if (jObject[listProperty.SqlPropertyName].ToString() != "")
                            {
                                property.SetValue(obj, DateTime.Parse(jObject[listProperty.SqlPropertyName].ToString()));
                            }
                            break;

                        default:
                            throw new Exception("Nullable type not implemented yet.");
                        }
                        break;

                    case "Int32":
                        property.SetValue(obj, Convert.ToInt32(jObject[listProperty.SqlPropertyName].ToString()));
                        break;

                    default:
                        MessageBox.Show(property.PropertyType.Name);
                        break;
                    }
                }
            }
        }
Exemplo n.º 8
0
        protected override void Initialize()
        {
            world = target as World;

            scenes          = GetListProperty("scenes");
            activeScene     = GetBasicProperty("activeScene");
            mainScene       = GetBasicProperty("mainScene");
            isDeveloppement = GetBasicProperty("isDeveloppement");
        }
Exemplo n.º 9
0
        protected override void Initialize()
        {
            configuration = Configuration.Get();
            activity      = target as Activity;

            scene      = GetEnumProperty("scene", typeof(R.E.Scene));
            controller = GetEnumProperty("controller", typeof(R.E.GameObject));
            fragments  = GetListProperty("fragments");
            menus      = GetListProperty("menus");
        }
Exemplo n.º 10
0
        public ListProperty <T> ListProperty <T>(string name)
        {
            IProperty result;

            if (!this.properties.TryGetValue(name, out result))
            {
                this.properties[name] = result = new ListProperty <T>();
            }
            return((ListProperty <T>)result);
        }
Exemplo n.º 11
0
        public override void Load(Call call, TabModel model)
        {
            model.Items   = ListProperty.Create(_propertyTest);
            model.Editing = true;

            model.Actions = new List <TaskCreator>()
            {
                new TaskDelegate("Toggle", Toggle),
            };
        }
Exemplo n.º 12
0
    private void Bind(ListProperty property)
    {
        var binding = new Binding(property.PropertyInfo.Name)
        {
            Mode   = BindingMode.TwoWay,
            Source = property.Object,
        };

        this.Bind(IsCheckedProperty, binding);
    }
Exemplo n.º 13
0
        public static ListProperty <string> Get(Main main, string root, string[] directories, string extension = null, Func <IEnumerable <string> > extras = null)
        {
            if (main.EditorEnabled)
            {
                if (!setupBinding)
                {
                    new CommandBinding(main.MapLoaded, (Action)cache.Clear);
                    setupBinding = true;
                }

                Entry entry = new Entry {
                    Root = root, Directories = directories, Extension = extension
                };
                ListProperty <string> result;
                if (!cache.TryGetValue(entry, out result))
                {
                    result = cache[entry] = new ListProperty <string>();
                    result.Add(null);
                    int contentRootDirectoryIndex = root.Length + (root[root.Length - 1] == Path.DirectorySeparatorChar ? 0 : 1);
                    if (directories == null)
                    {
                        directories = new[] { "" }
                    }
                    ;
                    foreach (string dir in directories)
                    {
                        string fullDir = Path.Combine(root ?? "", dir);
                        if (Directory.Exists(fullDir))
                        {
                            foreach (string f in Directory.GetFiles(fullDir))
                            {
                                int    extensionIndex = f.LastIndexOf('.');
                                string ext            = f.Substring(extensionIndex);
                                if (extension == null || ext == extension)
                                {
                                    // Remove content root directory and extension
                                    string stripped = f.Substring(contentRootDirectoryIndex, extensionIndex - contentRootDirectoryIndex);
                                    if (ext != ".xnb" || !stripped.EndsWith("_0"))                                     // Exclude subordinate xnb files
                                    {
                                        result.Add(stripped);
                                    }
                                }
                            }
                        }
                    }
                    if (extras != null)
                    {
                        result.AddAll(extras());
                    }
                }
                return(result);
            }
            return(null);
        }
    }
Exemplo n.º 14
0
        /// <summary>
        /// Header Section. This overridden version displays the Add Object Field.
        /// </summary>
        /// <param name="property">The main SerializedProperty the list belongs to</param>
        /// <param name="listProperty">The list SerializedProperty that has the associated array attached.</param>
        /// <param name="label">Label provided to the main PropertyField</param>
        protected override void HeaderSection(GUIContent label)
        {
            T go = null;

            if ((go = AddObjectField(go)) != null)
            {
                int newItemIndex = ListProperty.arraySize;
                ListProperty.InsertArrayElementAtIndex(newItemIndex);
                ListProperty.GetArrayElementAtIndex(newItemIndex).objectReferenceValue = go;
            }
        }
Exemplo n.º 15
0
        public override void Load(Call call, TabModel model)
        {
            model.Items   = ListProperty.Create(Project.ProjectSettings);
            model.Editing = true;

            model.Actions = new List <TaskCreator>()
            {
                new TaskDelegate("Reset", Reset),
                new TaskDelegate("Save", Save),
            };
        }
Exemplo n.º 16
0
        public static void Transition(Main main, string nextMap, string spawn = null)
        {
            Stream stream = new MemoryStream();

            Animation anim = new Animation
                             (
                new Animation.Set <bool>(main.Menu.CanPause, false),
                main.Spawner.FlashAnimation(),
                new Animation.Execute(delegate()
            {
                // We are exiting the map; just save the state of the map without the player.
                ListProperty <RespawnLocation> respawnLocations = PlayerDataFactory.Instance.Get <PlayerData>().RespawnLocations;
                respawnLocations.Clear();

                List <Entity> persistentEntities = main.Entities.Where((Func <Entity, bool>)MapLoader.entityIsPersistent).ToList();

                IO.MapLoader.Serializer.Serialize(stream, persistentEntities);

                foreach (Entity e in persistentEntities)
                {
                    e.Delete.Execute();
                }

                main.Spawner.StartSpawnPoint.Value = spawn;

                if (PlayerFactory.Instance != null)
                {
                    PlayerFactory.Instance.Delete.Execute();
                }

                main.SaveCurrentMap();
                MapLoader.Load(main, nextMap);

                stream.Seek(0, SeekOrigin.Begin);
                List <Entity> entities = (List <Entity>)IO.MapLoader.Serializer.Deserialize(stream);
                foreach (Entity e in entities)
                {
                    Factory <Main> factory = Factory <Main> .Get(e.Type);
                    e.GUID = 0;
                    factory.Bind(e, main);
                    main.Add(e);
                }
                stream.Dispose();
            }),
                new Animation.Delay(0.01f),
                new Animation.Set <bool>(main.Menu.CanPause, true),
                new Animation.Execute(main.ScheduleSave)
                             );

            anim.EnabledWhenPaused = false;
            main.AddComponent(anim);
        }
Exemplo n.º 17
0
        public static void GenerateAOTCollectionFunctions <TProperty, TContainer, TValue>()
            where TProperty : ICollectionProperty <TContainer, TValue>
        {
            TProperty     property      = default(TProperty);
            TContainer    container     = default(TContainer);
            TValue        value         = default(TValue);
            ChangeTracker changeTracker = default(ChangeTracker);
            var           getter        = new VisitCollectionElementCallback <TContainer>();

            PropertyVisitor propertyVisitor = new PropertyVisitor();

            propertyVisitor.TryVisitContainerWithAdapters(property, ref container, ref value, ref changeTracker);
            propertyVisitor.TryVisitCollectionWithAdapters(property, ref container, ref value, ref changeTracker);
            propertyVisitor.TryVisitValueWithAdapters(property, ref container, ref value, ref changeTracker);
            PropertyVisitorAdapterExtensions.TryVisitCollection(null, null, property, ref container, ref value, ref changeTracker);
            PropertyVisitorAdapterExtensions.TryVisitContainer(null, null, property, ref container, ref value, ref changeTracker);
            PropertyVisitorAdapterExtensions.TryVisitValue(null, null, property, ref container, ref value, ref changeTracker);

            var arrayProperty = new ArrayProperty <TContainer, TValue>();

            arrayProperty.GetPropertyAtIndex(ref container, 0, ref changeTracker, ref getter);
            var arrayCollectionElementProperty = new ArrayProperty <TContainer, TValue> .CollectionElementProperty();

            arrayCollectionElementProperty.GetValue(ref container);
            arrayCollectionElementProperty.SetValue(ref container, value);
            propertyVisitor.VisitProperty <ArrayProperty <TContainer, TValue> .CollectionElementProperty, TContainer, TValue>(arrayCollectionElementProperty, ref container, ref changeTracker);

            var listProperty = new ListProperty <TContainer, TValue>();

            listProperty.GetPropertyAtIndex(ref container, 0, ref changeTracker, ref getter);
            var listCollectionElementProperty = new ListProperty <TContainer, TValue> .CollectionElementProperty();

            listCollectionElementProperty.GetValue(ref container);
            listCollectionElementProperty.SetValue(ref container, value);
            propertyVisitor.VisitProperty <ListProperty <TContainer, TValue> .CollectionElementProperty, TContainer, TValue>(listCollectionElementProperty, ref container, ref changeTracker);

            Actions.GetCollectionCountGetter <TContainer> getCollectionCountGetter       = new Actions.GetCollectionCountGetter <TContainer>();
            Actions.GetCountFromActualTypeCallback        getCountFromActualTypeCallback = new Actions.GetCountFromActualTypeCallback();
            getCountFromActualTypeCallback.Invoke <TContainer>();
            getCountFromActualTypeCallback.Invoke <TValue>();
            Actions.GetCountAtPathGetter <TContainer> getCountAtPathGetter = new Actions.GetCountAtPathGetter <TContainer>();
            Actions.VisitAtPathCallback visitAtPathCallback = default;
            visitAtPathCallback.Invoke <TContainer>();
            visitAtPathCallback.Invoke <TValue>();
            Actions.SetCountCallback setCountCallback = default;
            setCountCallback.Invoke <TContainer>();
            setCountCallback.Invoke <TValue>();

            Actions.TryGetCount(ref container, new PropertyPath(), 0, ref changeTracker, out var count);
            Actions.TryGetCountImpl(ref container, new PropertyPath(), 0, ref changeTracker, out var otherCount);
            Actions.GetCount(ref container, new PropertyPath(), 0, ref changeTracker);
        }
Exemplo n.º 18
0
    public void LoadObject(object obj)
    {
        ClearControls();

        AddSummary();

        ItemCollection <ListProperty> properties = ListProperty.Create(obj);

        foreach (ListProperty property in properties)
        {
            AddPropertyRow(property);
        }
    }
Exemplo n.º 19
0
 public void EditorProperties()
 {
     if (this.main.EditorEnabled && ParticleEmitter.particleTypes == null)
     {
         ParticleEmitter.particleTypes = new ListProperty <string>();
         ParticleEmitter.particleTypes.AddAll(ParticleSystem.Types);
     }
     this.Entity.Add("ParticleType", this.ParticleType, new PropertyEntry.EditorData
     {
         Options = ParticleEmitter.particleTypes,
     });
     this.Entity.Add("Jitter", this.Jitter);
     this.Entity.Add("ParticlesPerSecond", this.ParticlesPerSecond);
 }
Exemplo n.º 20
0
        protected override void Initialize()
        {
            logo = GetLogo();

            productNameProperty = GetProductNameProperty();
            companyNameProperty = GetCompanyNameProperty();

            startingScene   = GetEnumProperty("startingScene", typeof(R.E.Scene));
            utilitaryScenes = GetListProperty("utilitaryScenes");

            tags   = GetTagsProperty();
            layers = GetLayersProperty();

            physics2DLayerMatrixProperty = GetPhysics2DLayerMatrixProperty();
        }
Exemplo n.º 21
0
    public static new ItemCollection <ListProperty> Create(object obj, bool includeBaseTypes = true)
    {
        // this doesn't work for virtual methods (or any method modifier?)
        var propertyInfos = obj.GetType().GetProperties()
                            .Where(p => IsVisible(p))
                            .Where(p => includeBaseTypes || p.DeclaringType == obj.GetType())
                            .OrderBy(p => p.MetadataToken);

        var listProperties  = new ItemCollection <ListProperty>();
        var propertyToIndex = new Dictionary <string, int>();

        foreach (PropertyInfo propertyInfo in propertyInfos)
        {
            var listProperty = new ListProperty(obj, propertyInfo);

            // move this to later?
            if (propertyInfo.GetCustomAttribute <HideNullAttribute>() != null)
            {
                if (listProperty.Value == null)
                {
                    continue;
                }
            }

            var hideAttribute = propertyInfo.GetCustomAttribute <HideAttribute>();
            if (hideAttribute != null && hideAttribute.Values != null)
            {
                if (hideAttribute.Values.Contains(listProperty.Value))
                {
                    continue;
                }
            }

            if (propertyToIndex.TryGetValue(propertyInfo.Name, out int index))
            {
                listProperties.RemoveAt(index);
                listProperties.Insert(index, listProperty);
            }
            else
            {
                propertyToIndex[propertyInfo.Name] = listProperties.Count;
                listProperties.Add(listProperty);
            }
        }
        return(listProperties);
    }
Exemplo n.º 22
0
		public static ListProperty<string> Get(Main main, string root, string[] directories, string extension = null, Func<IEnumerable<string>> extras = null)
		{
			if (main.EditorEnabled)
			{
				if (!setupBinding)
				{
					new CommandBinding(main.MapLoaded, (Action)cache.Clear);
					setupBinding = true;
				}

				Entry entry = new Entry { Root = root, Directories = directories, Extension = extension };
				ListProperty<string> result;
				if (!cache.TryGetValue(entry, out result))
				{
					result = cache[entry] = new ListProperty<string>();
					result.Add(null);
					int contentRootDirectoryIndex = root.Length + (root[root.Length - 1] == Path.DirectorySeparatorChar ? 0 : 1);
					if (directories == null)
						directories = new[] { "" };
					foreach (string dir in directories)
					{
						string fullDir = Path.Combine(root ?? "", dir);
						if (Directory.Exists(fullDir))
						{
							foreach (string f in Directory.GetFiles(fullDir))
							{
								int extensionIndex = f.LastIndexOf('.');
								string ext = f.Substring(extensionIndex);
								if (extension == null || ext == extension)
								{
									// Remove content root directory and extension
									string stripped = f.Substring(contentRootDirectoryIndex, extensionIndex - contentRootDirectoryIndex);
									if (ext != ".xnb" || !stripped.EndsWith("_0")) // Exclude subordinate xnb files
										result.Add(stripped);
								}
							}
						}
					}
					if (extras != null)
						result.AddAll(extras());
				}
				return result;
			}
			return null;
		}
Exemplo n.º 23
0
    public Control AddPropertyRow(ListProperty property)
    {
        Control control = CreatePropertyControl(property);

        if (control == null)
        {
            return(null);
        }

        int rowIndex = RowDefinitions.Count;
        {
            var spacerRow = new RowDefinition()
            {
                Height = new GridLength(5),
            };
            RowDefinitions.Add(spacerRow);
            rowIndex++;
        }
        var rowDefinition = new RowDefinition()
        {
            Height = new GridLength(1, GridUnitType.Auto),
        };

        RowDefinitions.Add(rowDefinition);

        var textLabel = new TextBlock()
        {
            Text              = property.Name,
            Margin            = new Thickness(0, 3, 10, 3),
            Foreground        = Theme.BackgroundText,
            VerticalAlignment = VerticalAlignment.Center,
            //HorizontalAlignment = HorizontalAlignment.Stretch,
            MaxWidth              = 500,
            [Grid.RowProperty]    = rowIndex,
            [Grid.ColumnProperty] = 0,
        };

        Children.Add(textLabel);

        AddControl(control, 1, rowIndex);

        return(control);
    }
Exemplo n.º 24
0
 private string CheckBoxEditor(ListProperty list, string value)
 {
     string[] values = list.Values.Split(new char[] { ';', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
     List<string> selectedValues = new List<string>(value.Split(new char[] { ',' }));
     StringBuilder sb = new StringBuilder();
     int index = 0;
     foreach (var item in values)
     {
         string[] parts = item.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
         index++;
         string selected = selectedValues.Contains(parts[1]) ? "checked=\"checked\"" : "";
         sb.Append("<div class=\"Entry InlineEntry\">");
         sb.AppendFormat("<input type=\"checkbox\" name=\"Property{0}\" id=\"property{0}{1}\" class=\"ListProperty\" value=\"{2}\" {3}/> ",
             list.Name, index, parts[1], selected);
         sb.AppendFormat("<label for=\"property{0}{1}\">{2}</label>", list.Name, index, parts[0]);
         sb.Append("</div>");
     }
     return sb.ToString();
 }
Exemplo n.º 25
0
		public static ListProperty<KeyValuePair<uint, string>> Get(Main main)
		{
			if (main.EditorEnabled)
			{
				if (list == null)
				{
					list = new ListProperty<KeyValuePair<uint, string>>();
					list.Add(new KeyValuePair<uint, string>(0, "[null]"));
					FieldInfo[] members = typeof(AK.EVENTS).GetFields(BindingFlags.Static | BindingFlags.Public);
					for (int i = 0; i < members.Length; i++)
					{
						FieldInfo field = members[i];
						list.Add(new KeyValuePair<uint, string>((uint)field.GetValue(null), field.Name));
					}
				}
				return list;
			}
			else
				return null;
		}
Exemplo n.º 26
0
    private void BindProperty(ListProperty property)
    {
        var binding = new Binding(property.PropertyInfo.Name)
        {
            Converter = new EditValueConverter(),
            //StringFormat = "Hello {0}",
            Source = property.Object,
        };
        Type type = property.UnderlyingType;

        if (type == typeof(string) || type.IsPrimitive)
        {
            binding.Mode = BindingMode.TwoWay;
        }
        else
        {
            binding.Mode = BindingMode.OneWay;
        }
        this.Bind(TextBlock.TextProperty, binding);
    }
Exemplo n.º 27
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            Transform transform = entity.GetOrCreate <Transform>("Transform");

            AnimatedModel model = entity.GetOrCreate <AnimatedModel>("Model");

            model.MapContent.Value = true;

            AnimatedProp prop = entity.GetOrCreate <AnimatedProp>("AnimatedProp");

            this.SetMain(entity, main);

            VoxelAttachable.MakeAttachable(entity, main).EditorProperties();

            model.EditorProperties();

            model.Add(new Binding <Matrix>(model.Transform, transform.Matrix));

            entity.Add("Visible", model.Enabled);
            ListProperty <string> clips = null;

            if (main.EditorEnabled)
            {
                clips = new ListProperty <string>();
                model.Add(new ChangeBinding <string>(model.Filename, delegate(string old, string value)
                {
                    if (model.IsValid)
                    {
                        clips.Clear();
                        clips.AddAll(model.Clips.Keys);
                    }
                }));
            }
            entity.Add("Clip", prop.Clip, new PropertyEntry.EditorData {
                Options = clips,
            });
            entity.Add("Loop", prop.Loop);
            entity.Add("Enabled", prop.Enabled);
            entity.Add("Enable", prop.Enable);
            entity.Add("Disable", prop.Disable);
        }
Exemplo n.º 28
0
 public static ListProperty <KeyValuePair <uint, string> > Get(Main main)
 {
     if (main.EditorEnabled)
     {
         if (list == null)
         {
             list = new ListProperty <KeyValuePair <uint, string> >();
             list.Add(new KeyValuePair <uint, string>(0, "[null]"));
             FieldInfo[] members = typeof(AK.EVENTS).GetFields(BindingFlags.Static | BindingFlags.Public);
             for (int i = 0; i < members.Length; i++)
             {
                 FieldInfo field = members[i];
                 list.Add(new KeyValuePair <uint, string>((uint)field.GetValue(null), field.Name));
             }
         }
         return(list);
     }
     else
     {
         return(null);
     }
 }
Exemplo n.º 29
0
    public TabControlComboBox(ListProperty property, BindListAttribute propertyListAttribute)
    {
        Property = property;

        InitializeComponent();

        IsEnabled = property.Editable;
        MaxWidth  = TabControlParams.ControlMaxWidth;

        Type type = property.UnderlyingType;

        if (propertyListAttribute != null)
        {
            PropertyInfo propertyInfo = property.Object.GetType().GetProperty(propertyListAttribute.Name);
            Items = propertyInfo.GetValue(property.Object) as IEnumerable;
        }
        else
        {
            var values = type.GetEnumValues();
            Items = values;
        }
        Bind(property.Object, property.PropertyInfo.Name);
    }
Exemplo n.º 30
0
    private void InitializeProperty(ListProperty property)
    {
        IsReadOnly = !property.Editable;
        if (IsReadOnly)
        {
            Background = Theme.TextBackgroundDisabled;
        }

        PasswordCharAttribute passwordCharAttribute = property.PropertyInfo.GetCustomAttribute <PasswordCharAttribute>();

        if (passwordCharAttribute != null)
        {
            PasswordChar = passwordCharAttribute.Character;
        }

        SetWatermark(property);

        if (property.PropertyInfo.GetCustomAttribute <WordWrapAttribute>() != null)
        {
            TextWrapping  = TextWrapping.Wrap;
            AcceptsReturn = true;
            MaxHeight     = 500;
        }

        AcceptsReturnAttribute acceptsReturnAttribute = property.PropertyInfo.GetCustomAttribute <AcceptsReturnAttribute>();

        if (acceptsReturnAttribute != null)
        {
            AcceptsReturn = acceptsReturnAttribute.Allow;
        }

        MaxWidth = TabControlParams.ControlMaxWidth;

        BindProperty(property);

        AvaloniaUtils.AddContextMenu(this);         // Custom menu to handle ReadOnly items better
    }
Exemplo n.º 31
0
        private Property parseProperty()
        {
            next();
            if (currentToken == TOK_EOF)
            {
                return(new StringProperty(""));
            }
            ListProperty propList = null;

            while (true)
            {
                Property prop = parseAdditiveExpr();
                if (currentToken == TOK_EOF)
                {
                    if (propList != null)
                    {
                        propList.addProperty(prop);
                        return(propList);
                    }
                    else
                    {
                        return(prop);
                    }
                }
                else
                {
                    if (propList == null)
                    {
                        propList = new ListProperty(prop);
                    }
                    else
                    {
                        propList.addProperty(prop);
                    }
                }
            }
        }
Exemplo n.º 32
0
 private Property parseProperty()
 {
     next();
     if (currentToken == TOK_EOF)
     {
         return new StringProperty("");
     }
     ListProperty propList = null;
     while (true)
     {
         Property prop = parseAdditiveExpr();
         if (currentToken == TOK_EOF)
         {
             if (propList != null)
             {
                 propList.addProperty(prop);
                 return propList;
             }
             else
             {
                 return prop;
             }
         }
         else
         {
             if (propList == null)
             {
                 propList = new ListProperty(prop);
             }
             else
             {
                 propList.addProperty(prop);
             }
         }
     }
 }
Exemplo n.º 33
0
		public static void AttachEditorComponents(Entity entity, string name, ListProperty<Entity.Handle> target)
		{
			entity.Add(name, target);
			if (entity.EditorSelected != null)
			{
				Transform transform = entity.Get<Transform>("Transform");

				LineDrawer connectionLines = new LineDrawer { Serialize = false };
				connectionLines.Add(new Binding<bool>(connectionLines.Enabled, entity.EditorSelected));

				ListBinding<LineDrawer.Line, Entity.Handle> connectionBinding = new ListBinding<LineDrawer.Line, Entity.Handle>(connectionLines.Lines, target, delegate(Entity.Handle other)
				{
					return new LineDrawer.Line
					{
						A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor),
						B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(other.Target.Get<Transform>("Transform").Position, connectionLineColor)
					};
				}, x => x.Target != null && x.Target.Active);
				entity.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, entity.EditorSelected));
				entity.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, transform.Position));
				connectionLines.Add(connectionBinding);
				entity.Add(connectionLines);
			}
		}
Exemplo n.º 34
0
    public List <Control> AddObjectRow(object obj, List <PropertyInfo> properties = null)
    {
        properties ??= obj.GetType().GetVisibleProperties();

        int rowIndex    = AddRowDefinition();
        int columnIndex = 0;

        var controls = new List <Control>();

        foreach (PropertyInfo propertyInfo in properties)
        {
            var     property = new ListProperty(obj, propertyInfo);
            Control control  = CreatePropertyControl(property);
            if (control == null)
            {
                continue;
            }

            AddControl(control, columnIndex, rowIndex);
            controls.Add(control);
            columnIndex++;
        }
        return(controls);
    }
 public void ShouldGenerateStringForListPropertyObject()
 {
     var value = new ListProperty<int>(10, 20);
     Assert.That(value.ToString(), Is.EqualTo("Values: {10, 20}"));
 }
 public void ShouldGenerateStringForListPropertyObjectThatContainsNullElements()
 {
     var value = new ListProperty<string>(new string[] { null });
     Assert.That(value.ToString(), Is.EqualTo("Values: {<null>}"));
 }
 public void ShouldGenerateHashCodeForListPropertyObjectThatContainsNullElements()
 {
     var value = new ListProperty<string>(new string[] { null });
     Assert.That(value.GetHashCode(), Is.EqualTo(HashCode.FromOneNull()));
 }
Exemplo n.º 38
0
        public override void Bind(Entity entity, Main main, bool creating = false)
        {
            entity.CannotSuspend = true;
            Transform transform = entity.GetOrCreate <Transform>("Transform");
            Binder    binder    = entity.GetOrCreate <Binder>("Binder");

            base.Bind(entity, main, creating);

            entity.Add("Bind immediately", binder.BindImmediately, description: "Bind the properties on load");
            entity.Add("Bind", binder.Bind, description: "Link values together");
            entity.Add("Unbind", binder.UnBind, description: "Unlink values");
            entity.Add("Set", binder.Set, description: "Transfer value without binding");
            entity.Add("Two-way", binder.TwoWay, "Out property will also affect in property.");
            entity.Add("Type", binder.PropertyType);

            if (main.EditorEnabled)
            {
                Func <Setter.PropType, Property <bool> > visible = delegate(Setter.PropType t)
                {
                    Property <bool> result = new Property <bool>();
                    entity.Add(new Binding <bool, Setter.PropType>(result, x => x == t, binder.PropertyType));
                    return(result);
                };

                ListProperty <string> inTargetOptions  = new ListProperty <string>();
                ListProperty <string> outTargetOptions = new ListProperty <string>();
                Action populateInOptions = delegate()
                {
                    inTargetOptions.Clear();
                    Entity e = binder.InTarget.Value.Target;
                    if (e != null && e.Active)
                    {
                        Type t = Setter.TypeMapping[binder.PropertyType];
                        foreach (KeyValuePair <string, PropertyEntry> p in e.Properties)
                        {
                            if (p.Value.Property.GetType().GetGenericArguments().First() == t)
                            {
                                inTargetOptions.Add(p.Key);
                            }
                        }
                    }
                };

                Action populateOutOptions = delegate()
                {
                    outTargetOptions.Clear();
                    Entity e = binder.OutTarget.Value.Target;
                    if (e != null && e.Active)
                    {
                        Type t = Setter.TypeMapping[binder.PropertyType];
                        foreach (KeyValuePair <string, PropertyEntry> p in e.Properties)
                        {
                            if (p.Value.Property.GetType().GetGenericArguments().First() == t)
                            {
                                outTargetOptions.Add(p.Key);
                            }
                        }
                    }
                };

                Action populateOptions = delegate()
                {
                    populateInOptions();
                    populateOutOptions();
                };

                entity.Add(new NotifyBinding(populateOptions, binder.InTarget, binder.OutTarget, binder.PropertyType));
                entity.Add(new PostInitialization {
                    populateOptions
                });
                entity.Add("TargetInProperty", binder.TargetInProperty, new PropertyEntry.EditorData
                {
                    Options = inTargetOptions,
                });
                entity.Add("TargetOutProperty", binder.TargetOutProperty, new PropertyEntry.EditorData
                {
                    Options = outTargetOptions,
                });
            }
        }
 public void ShouldConsiderConformingListPropertyObjectsEqual()
 {
     var first = new ListProperty<int>(1, 2);
     var second = new ListProperty<int>(1, 2);
     Assert.That(first.Equals(second), Is.True);
 }
 public void ShouldConsiderDifferingListPropertyObjectsNotEqual()
 {
     var first = new ListProperty<int>(1, 2);
     var second = new ListProperty<int>(1, 3);
     Assert.That(first.Equals(second), Is.False);
 }
Exemplo n.º 41
0
 public virtual void Delete()
 {
     this.Active = false;
     this.freeData();
     foreach (Box box in this.Boxes)
     {
         if (box.Adjacent != null)
         {
             box.Adjacent.Clear();
             box.Adjacent = null;
         }
     }
     this.Boxes.Clear();
     this.Boxes = null;
 }
Exemplo n.º 42
0
        public void Update(float dt)
        {
            // Spawn an editor or a player if needed
            if (this.main.EditorEnabled)
            {
                this.main.Renderer.InternalGamma.Value = 0.0f;
                this.main.Renderer.Brightness.Value    = 0.0f;
                if (this.editor == null || !this.editor.Active)
                {
                    this.editor = Factory.Get <EditorFactory>().CreateAndBind(this.main);
                    FPSInput.RecenterMouse();
                    this.editor.Get <Editor>().Position.Value = this.lastEditorPosition;
                    this.editor.Get <FPSInput>().Mouse.Value  = this.lastEditorMouse;
                    this.StartSpawnPoint.Value     = this.lastEditorSpawnPoint;
                    this.StartSpawnPointGUID.Value = this.lastEditorSpawnPointGUID;
                    this.main.Add(this.editor);
                }
                else
                {
                    this.lastEditorPosition = this.editor.Get <Editor>().Position;
                    this.lastEditorMouse    = this.editor.Get <FPSInput>().Mouse;
                }
            }
            else
            {
                if (this.main.MapFile.Value == null || !this.CanSpawn || CameraStop.CinematicActive)
                {
                    return;
                }

                this.editor = null;

                bool createPlayer = PlayerFactory.Instance == null;

                if (this.mapJustLoaded)
                {
                    if (!createPlayer)
                    {
                        // We just loaded a save game
                        this.main.Renderer.InternalGamma.Value = 0.0f;
                        this.main.Renderer.Brightness.Value    = 0.0f;
                        this.PlayerSpawned.Execute();
                        this.respawnTimer = 0;
                    }
                }
                else if (createPlayer)
                {
                    if (this.respawnTimer == 0)
                    {
                        this.main.AddComponent(new Animation(this.FlashAnimation()));
                    }

                    if (this.respawnTimer > this.RespawnInterval)
                    {
                        bool spawnFound = false;

                        RespawnLocation foundSpawnLocation         = default(RespawnLocation);
                        Vector3         foundSpawnAbsolutePosition = Vector3.Zero;

                        if (string.IsNullOrEmpty(this.StartSpawnPoint) && this.StartSpawnPointGUID == 0)
                        {
                            // Look for an autosaved spawn point
                            Entity playerData = PlayerDataFactory.Instance;
                            if (playerData != null)
                            {
                                ListProperty <RespawnLocation> respawnLocations = playerData.Get <PlayerData>().RespawnLocations;
                                int   supportedLocations = 0;
                                float lowerLimit         = Factory.Get <LowerLimitFactory>().GetLowerLimit();
                                while (respawnLocations.Length > 0)
                                {
                                    RespawnLocation respawnLocation  = respawnLocations[respawnLocations.Length - 1];
                                    Entity          respawnMapEntity = respawnLocation.Map.Target;
                                    if (respawnMapEntity != null && respawnMapEntity.Active)
                                    {
                                        Voxel   respawnMap  = respawnMapEntity.Get <Voxel>();
                                        Vector3 absolutePos = respawnMap.GetAbsolutePosition(respawnLocation.Coordinate);
                                        if (respawnMap.Active &&
                                            absolutePos.Y > lowerLimit &&
                                            respawnMap.GetAbsoluteVector(respawnMap.GetRelativeDirection(Direction.PositiveY).GetVector()).Y > 0.5f &&
                                            Agent.Query(absolutePos, 0.0f, 20.0f) == null &&
                                            Rift.Query(absolutePos) == null &&
                                            Zone.CanSpawnAt(absolutePos))
                                        {
                                            Voxel.State state = respawnMap[respawnLocation.Coordinate];
                                            if (state != Voxel.States.Empty && state != Voxel.States.Infected && state != Voxel.States.HardInfected && state != Voxel.States.Floater)
                                            {
                                                supportedLocations++;
                                                DynamicVoxel dynamicMap = respawnMap as DynamicVoxel;
                                                if (dynamicMap == null || absolutePos.Y > respawnLocation.OriginalPosition.Y - 1.0f)
                                                {
                                                    Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(absolutePos + new Vector3(0, 1, 0), Vector3.Up, 2);
                                                    if (hit.Voxel == null)
                                                    {
                                                        // We can spawn here
                                                        spawnFound                 = true;
                                                        foundSpawnLocation         = respawnLocation;
                                                        foundSpawnAbsolutePosition = absolutePos;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (supportedLocations >= 40 || (spawnFound && (foundSpawnAbsolutePosition - this.lastPlayerPosition).Length() > this.RespawnDistance))
                                    {
                                        if (supportedLocations > 3)                                         // We should try to spawn the player back at least a few steps
                                        {
                                            break;
                                        }
                                    }

                                    respawnLocations.RemoveAt(respawnLocations.Length - 1);
                                }
                            }
                        }

                        if (spawnFound)
                        {
                            // Spawn at an autosaved location
                            if (createPlayer)
                            {
                                this.spawn();
                            }
                            Vector3 absolutePos = foundSpawnLocation.Map.Target.Get <Voxel>().GetAbsolutePosition(foundSpawnLocation.Coordinate);
                            PlayerFactory.Instance.Get <Transform>().Position.Value = this.main.Camera.Position.Value = absolutePos + new Vector3(0, spawnHeightOffset, 0);

                            FPSInput.RecenterMouse();
                            PlayerFactory.Instance.Get <FPSInput>().Mouse.Value = new Vector2(foundSpawnLocation.Rotation, 0);
                        }
                        else
                        {
                            // Spawn at a spawn point
                            PlayerSpawn spawn       = null;
                            Entity      spawnEntity = null;
                            if (this.StartSpawnPointGUID != 0)
                            {
                                spawnEntity = this.main.GetByGUID(this.StartSpawnPointGUID);
                                if (spawnEntity != null)
                                {
                                    spawn = spawnEntity.Get <PlayerSpawn>();
                                }
                                this.lastEditorSpawnPointGUID  = this.StartSpawnPointGUID;
                                this.StartSpawnPointGUID.Value = 0;
                            }
                            else if (!string.IsNullOrEmpty(this.StartSpawnPoint.Value))
                            {
                                spawnEntity = this.main.GetByID(this.StartSpawnPoint);
                                if (spawnEntity != null)
                                {
                                    spawn = spawnEntity.Get <PlayerSpawn>();
                                }
                                this.lastEditorSpawnPoint  = this.StartSpawnPoint;
                                this.StartSpawnPoint.Value = null;
                            }

                            if (spawnEntity == null)
                            {
                                spawn       = PlayerSpawn.FirstActive();
                                spawnEntity = spawn == null ? null : spawn.Entity;
                            }

                            if (spawnEntity != null)
                            {
                                Vector3 pos = spawnEntity.Get <Transform>().Position;
                                main.Camera.Position.Value = pos;
                                WorldFactory.Instance.Get <World>().UpdateZones();
                                Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(pos + new Vector3(0, 2, 0), Vector3.Down, 8, null, false, true);
                                if (hit.Voxel == null)
                                {
                                    // There is nowhere to spawn. Reload the map.
                                    this.respawnTimer = 0;
                                    IO.MapLoader.Load(this.main, this.main.MapFile);
                                    return;
                                }
                                else
                                {
                                    if (createPlayer)
                                    {
                                        this.spawn();
                                    }
                                    pos = hit.Position + new Vector3(0, spawnHeightOffset, 0);
                                    PlayerFactory.Instance.Get <Transform>().Position.Value = this.main.Camera.Position.Value = pos;

                                    if (spawn != null)
                                    {
                                        spawn.IsActivated.Value = true;
                                        FPSInput.RecenterMouse();
                                        PlayerFactory.Instance.Get <FPSInput>().Mouse.Value = new Vector2(spawn.Rotation, 0);
                                        spawn.OnSpawn.Execute();
                                    }
                                }
                            }
                        }

                        // When the player teleports to a new map, show the number of orbs and notes on that map
                        // If mapJustLoaded is true, we just loaded a save game
                        if (this.main.TotalTime < Spawner.DefaultRespawnInterval * 2 && !this.mapJustLoaded)
                        {
                            WorldFactory.Instance.Add(new Animation
                                                      (
                                                          new Animation.Delay(1.5f),
                                                          new Animation.Execute(delegate()
                            {
                                int notes = Note.UncollectedCount;
                                if (notes > 0)
                                {
                                    this.main.Menu.HideMessage(WorldFactory.Instance, this.main.Menu.ShowMessageFormat(WorldFactory.Instance, notes == 1 ? "\\one note" : "\\note count", notes), 3.0f);
                                }

                                int orbs = Collectible.ActiveCount;
                                if (orbs > 0)
                                {
                                    this.main.Menu.HideMessage(WorldFactory.Instance, this.main.Menu.ShowMessageFormat(WorldFactory.Instance, orbs == 1 ? "\\one orb" : "\\orb count", orbs), 3.0f);
                                }
                            })
                                                      ));
                        }

                        WorldFactory.Instance.Add(new Animation(this.EndFlashAnimation()));
                        this.respawnTimer = 0;

                        this.PlayerSpawned.Execute();

                        this.RespawnInterval = Spawner.DefaultRespawnInterval;
                        this.RespawnDistance = Spawner.DefaultRespawnDistance;
                    }
                    else
                    {
                        this.respawnTimer += dt;
                    }
                }
                else
                {
                    this.lastPlayerPosition = PlayerFactory.Instance.Get <Transform>().Position;
                }
            }
            this.mapJustLoaded = false;
        }
Exemplo n.º 43
0
        public override Entity Create(Main main)
        {
            Entity result = new Entity(main, "World");
            result.Add("Transform", new Transform());
            result.Add("Gravity",
                new Property<Vector3>
                {
                    Get = delegate()
                    {
                        return main.Space.ForceUpdater.Gravity;
                    },
                    Set = delegate(Vector3 value)
                    {
                        main.Space.ForceUpdater.Gravity = value;
                    }
                }
            );

            result.Add("LightRampTexture", new Property<string> { Editable = true, Value = "Images\\default-ramp" });
            result.Add("BackgroundColor", new Property<Color> { Editable = true, Value = WorldFactory.defaultBackgroundColor });
            result.Add("FarPlaneDistance", new Property<float> { Editable = true, Value = 100.0f });

            ListProperty<Map.CellState> additionalMaterials = new ListProperty<Map.CellState>();

            result.Add("AdditionalMaterials", additionalMaterials);

            result.Add("ReverbAmount", new Property<float> { Value = 0.0f, Editable = true });

            result.Add("ReverbSize", new Property<float> { Value = 0.0f, Editable = true });

            return result;
        }
Exemplo n.º 44
0
 private string DropDownEditor(ListProperty list, string value)
 {
     string[] values = list.Values.Split(new char[] { ';', ',', '|' }, StringSplitOptions.RemoveEmptyEntries);
     StringBuilder sb = new StringBuilder();
     sb.AppendFormat("<label for=\"property{0}\">{1}</label>", list.Name, list.DisplayName);
     sb.AppendFormat("<select id=\"property{0}\" name=\"Property{0}\" class=\"Selection\">", list.Name);
     foreach (var item in values)
     {
         string[] parts = item.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
         string selected = parts[1] == value ? "selected=\"selected\"" : "";
         sb.AppendFormat("<option value=\"{0}\" {2}>{1}</option>", parts[1], parts[0], selected);
     }
     sb.AppendFormat("</select>");
     return sb.ToString();
 }
Exemplo n.º 45
0
 public BoxPropShorthandParser(ListProperty listprop) : base(listprop) { }
Exemplo n.º 46
0
        public override void Bind(Entity result, Main main, bool creating = false)
        {
            this.SetMain(result, main);
            Editor editor = result.Get<Editor>();
            EditorUI ui = result.Get<EditorUI>();
            Model model = result.Get<Model>("Model");
            FPSInput input = result.Get<FPSInput>("Input");
            UIRenderer uiRenderer = result.Get<UIRenderer>();

            ModelAlpha radiusVisual = new ModelAlpha();
            radiusVisual.Filename.Value = "Models\\alpha-sphere";
            radiusVisual.Color.Value = new Vector3(1.0f);
            radiusVisual.Alpha.Value = 0.1f;
            radiusVisual.Editable = false;
            radiusVisual.Serialize = false;
            radiusVisual.DrawOrder.Value = 11; // In front of water
            radiusVisual.DisableCulling.Value = true;
            result.Add(radiusVisual);
            radiusVisual.Add(new Binding<Matrix, Vector3>(radiusVisual.Transform, x => Matrix.CreateTranslation(x), editor.Position));
            radiusVisual.Add(new Binding<Vector3, int>(radiusVisual.Scale, x => new Vector3(x), editor.BrushSize));
            radiusVisual.Add(new Binding<bool>(radiusVisual.Enabled, () => editor.BrushSize > 1 && editor.MapEditMode, editor.BrushSize, editor.MapEditMode));
            radiusVisual.CullBoundingBox.Value = false;

            ModelAlpha selection = new ModelAlpha();
            selection.Filename.Value = "Models\\alpha-box";
            selection.Color.Value = new Vector3(1.0f, 0.7f, 0.4f);
            selection.Alpha.Value = 0.25f;
            selection.Editable = false;
            selection.Serialize = false;
            selection.DrawOrder.Value = 12; // In front of water and radius visualizer
            selection.DisableCulling.Value = true;
            result.Add(selection);
            selection.Add(new Binding<bool>(selection.Enabled, editor.VoxelSelectionActive));
            selection.Add(new Binding<Matrix>(selection.Transform, delegate()
            {
                const float padding = 0.1f;
                Map map = editor.SelectedEntities[0].Get<Map>();
                Vector3 start = map.GetRelativePosition(editor.VoxelSelectionStart) - new Vector3(0.5f), end = map.GetRelativePosition(editor.VoxelSelectionEnd) - new Vector3(0.5f);
                return Matrix.CreateScale((end - start) + new Vector3(padding)) * Matrix.CreateTranslation((start + end) * 0.5f) * map.Transform;
            }, () => selection.Enabled, editor.VoxelSelectionStart, editor.VoxelSelectionEnd));
            selection.CullBoundingBox.Value = false;

            Action<string, PCInput.Chord, Func<bool>, Command> addCommand = delegate(string description, PCInput.Chord chord, Func<bool> enabled, Command action)
            {
                ui.PopupCommands.Add(new EditorUI.PopupCommand { Description = description, Chord = chord, Enabled = enabled, Action = action });

                if (chord.Modifier != Keys.None)
                    input.Add(new CommandBinding(input.GetChord(chord), () => enabled() && !ui.StringPropertyLocked, action));
                else
                    input.Add(new CommandBinding(input.GetKeyDown(chord.Key), () => enabled() && !ui.StringPropertyLocked, action));

                ui.Add(new CommandBinding(action, delegate()
                {
                    Container container = new Container();
                    container.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                    container.Opacity.Value = 0.2f;
                    container.AnchorPoint.Value = new Vector2(1.0f, 0.0f);
                    container.Add(new Binding<Vector2, Point>(container.Position, x => new Vector2(x.X - 10.0f, 10.0f), main.ScreenSize));
                    TextElement display = new TextElement();
                    display.FontFile.Value = "Font";
                    display.Text.Value = description;
                    container.Children.Add(display);
                    uiRenderer.Root.Children.Add(container);
                    main.AddComponent(new Animation
                    (
                        new Animation.Parallel
                        (
                            new Animation.FloatMoveTo(container.Opacity, 0.0f, 1.0f),
                            new Animation.FloatMoveTo(display.Opacity, 0.0f, 1.0f)
                        ),
                        new Animation.Execute(delegate() { uiRenderer.Root.Children.Remove(container); })
                    ));
                }));
            };

            foreach (string key in Factory.factories.Keys)
            {
                string entityType = key;
                ui.PopupCommands.Add(new EditorUI.PopupCommand
                {
                    Description = "Add " + entityType,
                    Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode,
                    Action = new Command { Action = () => editor.Spawn.Execute(entityType) },
                });
            }

            Scroller scroller = (Scroller)uiRenderer.Root.GetChildByName("Scroller");

            Container popup = (Container)uiRenderer.Root.GetChildByName("Popup");
            ListContainer popupList = (ListContainer)popup.GetChildByName("PopupList");

            input.Add(new CommandBinding(input.GetKeyUp(Keys.Space), () => !editor.MapEditMode && !ui.StringPropertyLocked && !editor.MovementEnabled, delegate()
            {
                Vector2 pos = input.Mouse;
                pos.X = Math.Min(main.ScreenSize.Value.X - popup.Size.Value.X, pos.X);
                pos.Y = Math.Min(main.ScreenSize.Value.Y - popup.Size.Value.Y, pos.Y);
                popup.Position.Value = pos;
                ui.PopupVisible.Value = true;
            }));

            input.Add(new CommandBinding(input.GetKeyUp(Keys.Escape), () => ui.PopupVisible, delegate()
            {
                if (ui.PopupSearchText.Value == "_")
                    ui.PopupVisible.Value = false;
                else
                    ui.ClearSelectedStringProperty();
            }));

            input.Add(new CommandBinding(input.RightMouseButtonUp, () => ui.PopupVisible, delegate()
            {
                ui.PopupVisible.Value = false;
            }));

            uiRenderer.Add(new Binding<bool>(popup.Visible, ui.PopupVisible));
            uiRenderer.Add(new Binding<string>(((TextElement)popup.GetChildByName("PopupSearch")).Text, ui.PopupSearchText));
            uiRenderer.Add(new ListBinding<UIComponent>(popupList.Children, ui.PopupElements));

            AudioListener audioListener = result.Get<AudioListener>();
            audioListener.Add(new Binding<Vector3>(audioListener.Position, main.Camera.Position));
            audioListener.Add(new Binding<Vector3>(audioListener.Forward, main.Camera.Forward));

            model.Add(new Binding<bool>(model.Enabled, editor.MapEditMode));
            model.Add(new Binding<Matrix>(model.Transform, () => editor.Orientation.Value * Matrix.CreateTranslation(editor.Position), editor.Position, editor.Orientation));

            editor.Add(new TwoWayBinding<string>(main.MapFile, editor.MapFile));

            result.Add(new TwoWayBinding<string>(((GameMain)main).StartSpawnPoint, result.GetProperty<string>("StartSpawnPoint")));

            uiRenderer.Add(new ListBinding<UIComponent>(uiRenderer.Root.GetChildByName("PropertyList").Children, ui.UIElements));
            ui.Add(new ListBinding<Entity>(ui.SelectedEntities, editor.SelectedEntities));
            ui.Add(new Binding<bool>(ui.MapEditMode, editor.MapEditMode));
            ui.Add(new Binding<bool>(ui.EnablePrecision, x => !x, input.GetKey(Keys.LeftShift)));
            editor.Add(new Binding<bool>(editor.MovementEnabled, () => !ui.StringPropertyLocked && (input.MiddleMouseButton || editor.MapEditMode), ui.StringPropertyLocked, input.MiddleMouseButton, editor.MapEditMode));
            ui.Add(new TwoWayBinding<bool>(editor.NeedsSave, ui.NeedsSave));

            editor.Add(new Binding<Vector2>(editor.Movement, input.Movement));
            editor.Add(new Binding<bool>(editor.Up, input.GetKey(Keys.Space)));
            editor.Add(new Binding<bool>(editor.Down, input.GetKey(Keys.LeftControl)));
            editor.Add(new Binding<bool>(editor.Empty, input.RightMouseButton));
            editor.Add(new Binding<bool>(editor.SpeedMode, input.GetKey(Keys.LeftShift)));
            editor.Add(new Binding<bool>(editor.Extend, input.GetKey(Keys.F)));
            editor.Add(new Binding<bool>(editor.Fill, input.LeftMouseButton));
            editor.Add(new Binding<bool>(editor.EditSelection, () => input.MiddleMouseButton && editor.MapEditMode, input.MiddleMouseButton, editor.MapEditMode));

            addCommand("Delete", new PCInput.Chord { Key = Keys.X }, () => !editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None && editor.SelectedEntities.Count > 0, editor.DeleteSelected);
            addCommand("Duplicate", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.D }, () => !editor.MovementEnabled && editor.SelectedEntities.Count > 0, editor.Duplicate);

            // Start playing
            addCommand("Run", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.R }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    if (editor.NeedsSave)
                        editor.Save.Execute();
                    main.EditorEnabled.Value = false;
                    IO.MapLoader.Load(main, null, main.MapFile);
                }
            });

            result.Add(new CommandBinding(main.MapLoaded, delegate()
            {
                editor.Position.Value = Vector3.Zero;
                editor.NeedsSave.Value = false;
            }));

            addCommand("Quit", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.Q }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    throw new GameMain.ExitException();
                }
            });

            Property<bool> analyticsEnable = new Property<bool>();
            ListProperty<SessionEntry> analyticsSessions = new ListProperty<SessionEntry>();
            ListProperty<SessionEntry> analyticsActiveSessions = new ListProperty<SessionEntry>();
            ListProperty<EventEntry> analyticsEvents = new ListProperty<EventEntry>();
            ListProperty<EventEntry> analyticsActiveEvents = new ListProperty<EventEntry>();
            ListProperty<PropertyEntry> analyticsProperties = new ListProperty<PropertyEntry>();
            ListProperty<PropertyEntry> analyticsActiveProperties = new ListProperty<PropertyEntry>();
            Dictionary<Session, ModelInstance> sessionPositionModels = new Dictionary<Session, ModelInstance>();
            Dictionary<Session.EventList, List<ModelInstance>> eventPositionModels = new Dictionary<Session.EventList, List<ModelInstance>>();
            Property<bool> analyticsPlaying = new Property<bool>();
            Property<float> playbackSpeed = new Property<float> { Value = 1.0f };
            Property<float> playbackLocation = new Property<float>();

            const float timelineHeight = 32.0f;

            Scroller timelineScroller = new Scroller();
            timelineScroller.ScrollAmount.Value = 60.0f;
            timelineScroller.EnableScissor.Value = false;
            timelineScroller.DefaultScrollHorizontal.Value = true;
            timelineScroller.AnchorPoint.Value = new Vector2(0, 1);
            timelineScroller.ResizeVertical.Value = true;
            timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Position, x => new Vector2(0, x.Y), main.ScreenSize));
            timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Size, x => new Vector2(x.X, timelineHeight), main.ScreenSize));
            timelineScroller.Add(new Binding<bool>(timelineScroller.Visible, analyticsEnable));
            timelineScroller.Add(new Binding<bool>(timelineScroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
            uiRenderer.Root.Children.Add(timelineScroller);

            scroller.Add(new Binding<Vector2>(scroller.Size, () => new Vector2(scroller.Size.Value.X, main.ScreenSize.Value.Y - 20 - timelineScroller.ScaledSize.Value.Y), main.ScreenSize, timelineScroller.ScaledSize));

            ListContainer timelines = new ListContainer();
            timelines.Alignment.Value = ListContainer.ListAlignment.Min;
            timelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
            timelines.Reversed.Value = true;
            timelineScroller.Children.Add(timelines);

            Container timeline = new Container();
            timeline.Size.Value = new Vector2(0, timelineHeight);
            timeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            timeline.ResizeHorizontal.Value = false;
            timeline.ResizeVertical.Value = false;
            timelines.Children.Add(timeline);

            ui.PopupCommands.Add(new EditorUI.PopupCommand
            {
                Description = "Load analytics data",
                Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode && !analyticsEnable,
                Action = new Command
                {
                    Action = delegate()
                    {
                        if (main.MapFile.Value != null)
                        {
                            List<Session> sessions = ((GameMain)main).LoadAnalytics(main.MapFile);
                            if (sessions.Count > 0)
                            {
                                analyticsEnable.Value = true;
                                Dictionary<string, bool> distinctEventNames = new Dictionary<string, bool>();
                                Dictionary<string, bool> distinctPropertyNames = new Dictionary<string, bool>();
                                foreach (Session s in sessions)
                                {
                                    foreach (Session.EventList el in s.Events)
                                    {
                                        distinctEventNames[el.Name] = true;
                                        s.TotalTime = Math.Max(s.TotalTime, el.Events[el.Events.Count - 1].Time);
                                    }
                                    foreach (Session.ContinuousProperty p in s.ContinuousProperties)
                                    {
                                        if (p.Independent)
                                            distinctPropertyNames[p.Name] = true;
                                    }
                                    analyticsSessions.Add(new SessionEntry { Session = s });
                                }
                                analyticsEvents.Add(distinctEventNames.Keys.Select(x => new EventEntry { Name = x }));
                                analyticsProperties.Add(distinctPropertyNames.Keys.Select(x => new PropertyEntry { Name = x }));
                                timeline.Size.Value = new Vector2(analyticsSessions.Max(x => x.Session.TotalTime), timelineScroller.Size.Value.Y);
                                timelines.Scale.Value = new Vector2(timelineScroller.Size.Value.X / timeline.Size.Value.X, 1.0f);
                            }
                        }
                    }
                },
            });

            ListContainer sessionsSidebar = new ListContainer();
            sessionsSidebar.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Add(new Binding<Vector2>(sessionsSidebar.Position, () => new Vector2(main.ScreenSize.Value.X - 10, main.ScreenSize.Value.Y - timelineScroller.ScaledSize.Value.Y - 10), main.ScreenSize, timelineScroller.ScaledSize));
            sessionsSidebar.Add(new Binding<bool>(sessionsSidebar.Visible, analyticsEnable));
            sessionsSidebar.Alignment.Value = ListContainer.ListAlignment.Max;
            sessionsSidebar.Reversed.Value = true;
            uiRenderer.Root.Children.Add(sessionsSidebar);

            Func<string, ListContainer> createCheckboxListItem = delegate(string text)
            {
                ListContainer layout = new ListContainer();
                layout.Orientation.Value = ListContainer.ListOrientation.Horizontal;

                TextElement label = new TextElement();
                label.FontFile.Value = "Font";
                label.Text.Value = text;
                label.Name.Value = "Label";
                layout.Children.Add(label);

                Container checkboxContainer = new Container();
                checkboxContainer.PaddingBottom.Value = checkboxContainer.PaddingLeft.Value = checkboxContainer.PaddingRight.Value = checkboxContainer.PaddingTop.Value = 1.0f;
                layout.Children.Add(checkboxContainer);

                Container checkbox = new Container();
                checkbox.Name.Value = "Checkbox";
                checkbox.ResizeHorizontal.Value = checkbox.ResizeVertical.Value = false;
                checkbox.Size.Value = new Vector2(16.0f, 16.0f);
                checkboxContainer.Children.Add(checkbox);
                return layout;
            };

            Container sessionsContainer = new Container();
            sessionsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            sessionsContainer.Opacity.Value = 0.5f;
            sessionsContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(sessionsContainer);

            Scroller sessionsScroller = new Scroller();
            sessionsScroller.ResizeHorizontal.Value = true;
            sessionsScroller.ResizeVertical.Value = true;
            sessionsScroller.MaxVerticalSize.Value = 256;
            sessionsContainer.Children.Add(sessionsScroller);

            ListContainer sessionList = new ListContainer();
            sessionList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            sessionList.Alignment.Value = ListContainer.ListAlignment.Max;
            sessionsScroller.Children.Add(sessionList);

            Property<bool> allSessions = new Property<bool>();

            sessionList.Add(new ListBinding<UIComponent, SessionEntry>(sessionList.Children, analyticsSessions, delegate(SessionEntry entry)
            {
                ListContainer item = createCheckboxListItem(entry.Session.Date.ToShortDateString() + " (" + new TimeSpan(0, 0, (int)entry.Session.TotalTime).ToString() + ")");

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, entry.Active));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (entry.Active)
                    {
                        allSessions.Value = false;
                        analyticsActiveSessions.Remove(entry);
                    }
                    else
                        analyticsActiveSessions.Add(entry);
                }));

                return new[] { item };
            }));

            ListContainer allSessionsButton = createCheckboxListItem("[All]");
            allSessionsButton.Add(new CommandBinding<Point>(allSessionsButton.MouseLeftDown, delegate(Point p)
            {
                if (allSessions)
                {
                    allSessions.Value = false;
                    foreach (SessionEntry s in analyticsActiveSessions.ToList())
                        analyticsActiveSessions.Remove(s);
                }
                else
                {
                    allSessions.Value = true;
                    foreach (SessionEntry s in analyticsSessions)
                    {
                        if (!s.Active)
                            analyticsActiveSessions.Add(s);
                    }
                }
            }));

            Container allSessionsCheckbox = (Container)allSessionsButton.GetChildByName("Checkbox");
            allSessionsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allSessionsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allSessions));
            sessionList.Children.Add(allSessionsButton);

            Container eventsContainer = new Container();
            eventsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            eventsContainer.Opacity.Value = 0.5f;
            eventsContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(eventsContainer);

            Scroller eventsScroller = new Scroller();
            eventsScroller.ResizeHorizontal.Value = true;
            eventsScroller.ResizeVertical.Value = true;
            eventsScroller.MaxVerticalSize.Value = 256;
            eventsContainer.Children.Add(eventsScroller);

            ListContainer eventList = new ListContainer();
            eventList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            eventList.Alignment.Value = ListContainer.ListAlignment.Max;
            eventsScroller.Children.Add(eventList);

            Property<bool> allEvents = new Property<bool>();

            eventList.Add(new ListBinding<UIComponent, EventEntry>(eventList.Children, analyticsEvents, delegate(EventEntry e)
            {
                ListContainer item = createCheckboxListItem(e.Name);

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

                TextElement label = (TextElement)item.GetChildByName("Label");
                label.Tint.Value = new Microsoft.Xna.Framework.Color(this.colorHash(e.Name));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (e.Active)
                    {
                        allEvents.Value = false;
                        analyticsActiveEvents.Remove(e);
                    }
                    else
                        analyticsActiveEvents.Add(e);
                }));

                return new[] { item };
            }));

            ListContainer allEventsButton = createCheckboxListItem("[All]");
            allEventsButton.Add(new CommandBinding<Point>(allEventsButton.MouseLeftDown, delegate(Point p)
            {
                if (allEvents)
                {
                    allEvents.Value = false;
                    foreach (EventEntry e in analyticsActiveEvents.ToList())
                        analyticsActiveEvents.Remove(e);
                }
                else
                {
                    allEvents.Value = true;
                    foreach (EventEntry e in analyticsEvents)
                    {
                        if (!e.Active)
                            analyticsActiveEvents.Add(e);
                    }
                }
            }));
            Container allEventsCheckbox = (Container)allEventsButton.GetChildByName("Checkbox");
            allEventsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allEventsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allEvents));
            eventList.Children.Add(allEventsButton);

            Container propertiesContainer = new Container();
            propertiesContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            propertiesContainer.Opacity.Value = 0.5f;
            propertiesContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(propertiesContainer);

            Scroller propertiesScroller = new Scroller();
            propertiesScroller.ResizeHorizontal.Value = true;
            propertiesScroller.ResizeVertical.Value = true;
            propertiesScroller.MaxVerticalSize.Value = 256;
            propertiesContainer.Children.Add(propertiesScroller);

            ListContainer propertiesList = new ListContainer();
            propertiesList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            propertiesList.Alignment.Value = ListContainer.ListAlignment.Max;
            propertiesScroller.Children.Add(propertiesList);

            Property<bool> allProperties = new Property<bool>();

            propertiesList.Add(new ListBinding<UIComponent, PropertyEntry>(propertiesList.Children, analyticsProperties, delegate(PropertyEntry e)
            {
                ListContainer item = createCheckboxListItem(e.Name);

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

                TextElement label = (TextElement)item.GetChildByName("Label");
                label.Tint.Value = new Microsoft.Xna.Framework.Color(this.colorHash(e.Name));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (e.Active)
                    {
                        allProperties.Value = false;
                        analyticsActiveProperties.Remove(e);
                    }
                    else
                        analyticsActiveProperties.Add(e);
                }));

                return new[] { item };
            }));

            ListContainer allPropertiesButton = createCheckboxListItem("[All]");
            allPropertiesButton.Add(new CommandBinding<Point>(allPropertiesButton.MouseLeftDown, delegate(Point p)
            {
                if (allProperties)
                {
                    allProperties.Value = false;
                    foreach (PropertyEntry e in analyticsActiveProperties.ToList())
                        analyticsActiveProperties.Remove(e);
                }
                else
                {
                    allProperties.Value = true;
                    foreach (PropertyEntry e in analyticsProperties)
                    {
                        if (!e.Active)
                            analyticsActiveProperties.Add(e);
                    }
                }
            }));
            Container allPropertiesCheckbox = (Container)allPropertiesButton.GetChildByName("Checkbox");
            allPropertiesCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allPropertiesCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allProperties));
            propertiesList.Children.Add(allPropertiesButton);

            Func<Session.EventList, LineDrawer2D> createEventLines = delegate(Session.EventList el)
            {
                LineDrawer2D line = new LineDrawer2D();
                line.Color.Value = this.colorHash(el.Name);
                line.UserData.Value = el;

                foreach (Session.Event e in el.Events)
                {
                    line.Lines.Add(new LineDrawer2D.Line
                    {
                        A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, 0.0f, 0.0f), Microsoft.Xna.Framework.Color.White),
                        B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, timeline.Size.Value.Y, 0.0f), Microsoft.Xna.Framework.Color.White),
                    });
                }
                return line;
            };

            analyticsActiveEvents.ItemAdded += delegate(int index, EventEntry ee)
            {
                ee.Active.Value = true;
                foreach (SessionEntry s in analyticsActiveSessions)
                {
                    Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
                    foreach (Session.EventList el in s.Session.Events)
                    {
                        if (el.Name == ee.Name)
                        {
                            List<ModelInstance> models = new List<ModelInstance>();
                            Vector4 color = this.colorHash(el.Name);
                            int hash = (int)(new Color(color).PackedValue);
                            foreach (Session.Event e in el.Events)
                            {
                                ModelInstance i = new ModelInstance();
                                i.Setup("Models\\position-model", hash);
                                if (i.IsFirstInstance)
                                    i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
                                i.Scale.Value = new Vector3(0.25f);
                                i.Transform.Value = Matrix.CreateTranslation(positionProperty[e.Time]);
                                models.Add(i);
                                result.Add(i);
                            }
                            eventPositionModels[el] = models;
                        }
                    }

                    timeline.Children.Add(s.Session.Events.Where(x => x.Name == ee.Name).Select(createEventLines));
                }
            };

            analyticsActiveEvents.ItemRemoved += delegate(int index, EventEntry e)
            {
                e.Active.Value = false;
                foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
                {
                    if (pair.Key.Name == e.Name)
                    {
                        foreach (ModelInstance instance in pair.Value)
                            instance.Delete.Execute();
                        eventPositionModels.Remove(pair.Key);
                    }
                }
                timeline.Children.Remove(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Name == e.Name).ToList());
            };

            analyticsActiveProperties.ItemAdded += delegate(int index, PropertyEntry e)
            {
                e.Active.Value = true;
            };

            analyticsActiveProperties.ItemRemoved += delegate(int index, PropertyEntry e)
            {
                e.Active.Value = false;
            };

            ListContainer propertyTimelines = new ListContainer();
            propertyTimelines.Alignment.Value = ListContainer.ListAlignment.Min;
            propertyTimelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
            timelines.Children.Add(propertyTimelines);

            Action<LineDrawer2D> refreshPropertyGraph = delegate(LineDrawer2D lines)
            {
                string propertyName = ((PropertyEntry)lines.UserData.Value).Name;
                lines.Lines.Clear();
                float time = 0.0f, lastTime = 0.0f;
                float lastValue = 0.0f;
                bool firstLine = true;
                float max = float.MinValue, min = float.MaxValue;
                while (true)
                {
                    bool stop = true;

                    // Calculate average
                    int count = 0;
                    float sum = 0.0f;
                    foreach (SessionEntry s in analyticsActiveSessions)
                    {
                        if (time < s.Session.TotalTime)
                        {
                            Session.ContinuousProperty prop = s.Session.GetContinuousProperty(propertyName);
                            if (prop != null)
                            {
                                stop = false;
                                sum += prop[time];
                                count++;
                            }
                        }
                    }

                    if (stop)
                        break;
                    else
                    {
                        float value = sum / (float)count;
                        if (firstLine)
                            firstLine = false;
                        else
                        {
                            lines.Lines.Add(new LineDrawer2D.Line
                            {
                                A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                                {
                                    Color = Microsoft.Xna.Framework.Color.White,
                                    Position = new Vector3(lastTime, lastValue, 0.0f),
                                },
                                B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                                {
                                    Color = Microsoft.Xna.Framework.Color.White,
                                    Position = new Vector3(time, value, 0.0f),
                                },
                            });
                        }
                        min = Math.Min(min, value);
                        max = Math.Max(max, value);
                        lastValue = value;
                        lastTime = time;
                        time += Session.Recorder.Interval;
                    }

                    if (min < max)
                    {
                        float scale = -timelineHeight / (max - min);
                        lines.Scale.Value = new Vector2(1, scale);
                        lines.Position.Value = new Vector2(0, max * -scale);
                    }
                    else
                    {
                        lines.AnchorPoint.Value = Vector2.Zero;
                        if (min <= 0.0f)
                            lines.Position.Value = new Vector2(0, timelineHeight);
                        else
                            lines.Position.Value = new Vector2(0, timelineHeight * 0.5f);
                    }
                }
            };

            Action refreshPropertyGraphs = delegate()
            {
                foreach (LineDrawer2D line in propertyTimelines.Children.Select(x => x.Children.First()))
                    refreshPropertyGraph(line);
            };

            propertyTimelines.Add(new ListBinding<UIComponent, PropertyEntry>(propertyTimelines.Children, analyticsActiveProperties, delegate(PropertyEntry e)
            {
                Container propertyTimeline = new Container();
                propertyTimeline.Add(new Binding<Vector2>(propertyTimeline.Size, timeline.Size));
                propertyTimeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                propertyTimeline.Opacity.Value = 0.5f;
                propertyTimeline.ResizeHorizontal.Value = false;
                propertyTimeline.ResizeVertical.Value = false;

                LineDrawer2D line = new LineDrawer2D();
                line.Color.Value = this.colorHash(e.Name);
                line.UserData.Value = e;
                propertyTimeline.Children.Add(line);

                refreshPropertyGraph(line);

                return new[] { propertyTimeline };
            }));

            analyticsActiveSessions.ItemAdded += delegate(int index, SessionEntry s)
            {
                Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
                foreach (Session.EventList el in s.Session.Events)
                {
                    if (analyticsActiveEvents.FirstOrDefault(x => x.Name == el.Name) != null)
                    {
                        List<ModelInstance> models = new List<ModelInstance>();
                        Vector4 color = this.colorHash(el.Name);
                        int hash = (int)(new Color(color).PackedValue);
                        foreach (Session.Event e in el.Events)
                        {
                            ModelInstance i = new ModelInstance();
                            i.Setup("Models\\position-model", hash);
                            if (i.IsFirstInstance)
                                i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
                            i.Scale.Value = new Vector3(0.25f);
                            i.Transform.Value = Matrix.CreateTranslation(positionProperty[e.Time]);
                            result.Add(i);
                            models.Add(i);
                        }
                        eventPositionModels[el] = models;
                    }
                }

                ModelInstance instance = new ModelInstance();
                instance.Setup("Models\\position-model", 0);
                instance.Scale.Value = new Vector3(0.25f);
                result.Add(instance);
                sessionPositionModels.Add(s.Session, instance);
                s.Active.Value = true;
                timeline.Children.Add(s.Session.Events.Where(x => analyticsActiveEvents.FirstOrDefault(y => y.Name == x.Name) != null).Select(createEventLines));
                playbackLocation.Reset();

                refreshPropertyGraphs();
            };

            analyticsActiveSessions.ItemRemoved += delegate(int index, SessionEntry s)
            {
                ModelInstance instance = sessionPositionModels[s.Session];
                instance.Delete.Execute();

                foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
                {
                    if (pair.Key.Session == s.Session)
                    {
                        foreach (ModelInstance i in pair.Value)
                            i.Delete.Execute();
                        eventPositionModels.Remove(pair.Key);
                    }
                }

                sessionPositionModels.Remove(s.Session);
                s.Active.Value = false;
                timeline.Children.Remove(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Session == s.Session).ToList());

                refreshPropertyGraphs();
            };

            playbackLocation.Set = delegate(float value)
            {
                if (analyticsActiveSessions.Count == 0)
                    return;

                value = Math.Max(0.0f, value);
                float end = analyticsActiveSessions.Max(x => x.Session.TotalTime);
                if (value > end)
                {
                    playbackLocation.InternalValue = end;
                    analyticsPlaying.Value = false;
                }
                else
                    playbackLocation.InternalValue = value;

                foreach (KeyValuePair<Session, ModelInstance> pair in sessionPositionModels)
                    pair.Value.Transform.Value = Matrix.CreateTranslation(pair.Key.PositionProperties[0][playbackLocation]);
            };

            LineDrawer2D playbackLine = new LineDrawer2D();
            playbackLine.Color.Value = Vector4.One;
            playbackLine.Lines.Add(new LineDrawer2D.Line
            {
                A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                {
                    Color = Microsoft.Xna.Framework.Color.White,
                    Position = new Vector3(0.0f, -10.0f, 0.0f),
                },
                B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                {
                    Color = Microsoft.Xna.Framework.Color.White,
                    Position = new Vector3(0.0f, timeline.Size.Value.Y, 0.0f),
                },
            });
            playbackLine.Add(new Binding<Vector2, float>(playbackLine.Position, x => new Vector2(x, 0.0f), playbackLocation));
            timeline.Children.Add(playbackLine);

            result.Add(new NotifyBinding(delegate()
            {
                allEventsButton.Detach();
                allSessionsButton.Detach();
                allPropertiesButton.Detach();
                analyticsSessions.Clear();
                analyticsEvents.Clear();
                analyticsProperties.Clear();
                eventList.Children.Add(allEventsButton);
                sessionList.Children.Add(allSessionsButton);
                propertiesList.Children.Add(allPropertiesButton);

                foreach (ModelInstance instance in sessionPositionModels.Values)
                    instance.Delete.Execute();
                sessionPositionModels.Clear();

                foreach (ModelInstance instance in eventPositionModels.Values.SelectMany(x => x))
                    instance.Delete.Execute();
                eventPositionModels.Clear();

                allEvents.Value = false;
                allSessions.Value = false;
                allProperties.Value = false;
                analyticsEnable.Value = false;

                analyticsActiveEvents.Clear();
                analyticsActiveSessions.Clear();
                analyticsActiveProperties.Clear();

                propertyTimelines.Children.Clear();

                playbackLine.Detach();
                timeline.Children.Clear();
                timeline.Children.Add(playbackLine);

                analyticsPlaying.Value = false;
                playbackLocation.Value = 0.0f;
            }, main.MapFile));

            addCommand("Toggle analytics playback", new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.A }, () => analyticsEnable && !editor.MovementEnabled && analyticsActiveSessions.Count > 0, new Command
            {
                Action = delegate()
                {
                    analyticsPlaying.Value = !analyticsPlaying;
                }
            });

            addCommand("Stop analytics playback", new PCInput.Chord { Key = Keys.Escape }, () => analyticsPlaying, new Command
            {
                Action = delegate()
                {
                    analyticsPlaying.Value = false;
                }
            });

            Container playbackContainer = new Container();
            playbackContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            playbackContainer.Opacity.Value = 0.5f;
            sessionsSidebar.Children.Add(playbackContainer);
            playbackContainer.Add(new CommandBinding<Point, int>(playbackContainer.MouseScrolled, delegate(Point p, int delta)
            {
                playbackSpeed.Value = Math.Max(1.0f, Math.Min(10.0f, playbackSpeed.Value + delta));
            }));

            TextElement playbackLabel = new TextElement();
            playbackLabel.FontFile.Value = "Font";
            playbackLabel.Add(new Binding<string>(playbackLabel.Text, delegate()
            {
                return playbackLocation.Value.ToString("F") + " " + (analyticsPlaying ? "Playing" : "Stopped") + " " + playbackSpeed.Value.ToString("F") + "x";
            }, playbackLocation, playbackSpeed, analyticsPlaying));
            playbackContainer.Children.Add(playbackLabel);

            Container descriptionContainer = null;

            Updater timelineUpdate = new Updater
            {
                delegate(float dt)
                {
                    bool setTimelinePosition = false;

                    if (timelines.Highlighted || descriptionContainer != null)
                    {
                        if (input.LeftMouseButton)
                        {
                            setTimelinePosition = true;
                            playbackLocation.Value = Vector3.Transform(new Vector3(input.Mouse.Value.X, 0.0f, 0.0f), Matrix.Invert(timeline.GetAbsoluteTransform())).X;
                        }

                        float threshold = 3.0f / timelines.Scale.Value.X;
                        float mouseRelative = Vector3.Transform(new Vector3(input.Mouse, 0.0f), Matrix.Invert(timelines.GetAbsoluteTransform())).X;

                        if (descriptionContainer != null)
                        {
                            if (!timelines.Highlighted || (float)Math.Abs(descriptionContainer.Position.Value.X - mouseRelative) > threshold)
                            {
                                descriptionContainer.Delete.Execute();
                                descriptionContainer = null;
                            }
                        }

                        if (descriptionContainer == null && timeline.Highlighted)
                        {
                            bool stop = false;
                            foreach (UIComponent component in timeline.Children)
                            {
                                LineDrawer2D lines = component as LineDrawer2D;

                                if (lines == null)
                                    continue;

                                foreach (LineDrawer2D.Line line in lines.Lines)
                                {
                                    Session.EventList el = lines.UserData.Value as Session.EventList;
                                    if (el != null && (float)Math.Abs(line.A.Position.X - mouseRelative) < threshold)
                                    {
                                        descriptionContainer = new Container();
                                        descriptionContainer.AnchorPoint.Value = new Vector2(0.5f, 1.0f);
                                        descriptionContainer.Position.Value = new Vector2(line.A.Position.X, 0.0f);
                                        descriptionContainer.Opacity.Value = 1.0f;
                                        descriptionContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                                        descriptionContainer.Add(new Binding<Vector2>(descriptionContainer.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
                                        timeline.Children.Add(descriptionContainer);
                                        TextElement description = new TextElement();
                                        description.WrapWidth.Value = 256;
                                        description.Text.Value = el.Name;
                                        description.FontFile.Value = "Font";
                                        descriptionContainer.Children.Add(description);
                                        stop = true;
                                        break;
                                    }
                                }
                                if (stop)
                                    break;
                            }
                        }
                    }

                    if (analyticsPlaying && !setTimelinePosition)
                    {
                        if (analyticsActiveSessions.Count == 0)
                            analyticsPlaying.Value = false;
                        else
                            playbackLocation.Value += dt * playbackSpeed;
                    }
                }
            };
            timelineUpdate.EnabledInEditMode.Value = true;
            result.Add(timelineUpdate);

            // Save
            addCommand("Save", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.S }, () => !editor.MovementEnabled, editor.Save);

            // Deselect all entities
            addCommand("Deselect all", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.A }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    editor.SelectedEntities.Clear();
                }
            });

            int brush = 1;
            Action<int> changeBrush = delegate(int delta)
            {
                int foundIndex = WorldFactory.StateList.FindIndex(x => x.Name == editor.Brush);
                if (foundIndex != -1)
                    brush = foundIndex;
                int stateCount = WorldFactory.States.Count + 1;
                brush = 1 + ((brush - 1 + delta) % (stateCount - 1));
                if (brush < 1)
                    brush = stateCount + ((brush - 1) % stateCount);
                if (brush == stateCount - 1)
                    editor.Brush.Value = "[Procedural]";
                else
                    editor.Brush.Value = WorldFactory.StateList[brush].Name;
            };
            result.Add(new CommandBinding(input.GetKeyDown(Keys.Q), () => editor.MapEditMode, delegate()
            {
                changeBrush(-1);
            }));
            result.Add(new CommandBinding(input.GetKeyDown(Keys.E), () => editor.MapEditMode && !input.GetKey(Keys.LeftShift), delegate()
            {
                changeBrush(1);
            }));
            result.Add(new CommandBinding<int>(input.MouseScrolled, () => editor.MapEditMode && !input.GetKey(Keys.LeftAlt), delegate(int delta)
            {
                editor.BrushSize.Value = Math.Max(1, editor.BrushSize.Value + delta);
            }));

            addCommand("Propagate current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.E }, () => editor.MapEditMode, editor.PropagateMaterial);
            addCommand("Sample current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.Q }, () => editor.MapEditMode, editor.SampleMaterial);
            addCommand("Delete current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.X }, () => editor.MapEditMode, editor.DeleteMaterial);

            editor.Add(new Binding<Vector2>(editor.Mouse, input.Mouse, () => !input.EnableLook));

            Camera camera = main.Camera;

            Property<float> cameraDistance = new Property<float> { Value = 10.0f };
            scroller.Add(new Binding<bool>(scroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
            input.Add(new CommandBinding<int>(input.MouseScrolled, () => input.GetKey(Keys.LeftAlt), delegate(int delta)
            {
                if (timelineScroller.Highlighted && !editor.MapEditMode)
                {
                    float newScale = Math.Max(timelines.Scale.Value.X + delta * 6.0f, timelineScroller.Size.Value.X / timelines.Size.Value.X);
                    Matrix absoluteTransform = timelines.GetAbsoluteTransform();
                    float x = input.Mouse.Value.X + ((absoluteTransform.Translation.X - input.Mouse.Value.X) * (newScale / timelines.Scale.Value.X));
                    timelines.Position.Value = new Vector2(x, 0.0f);
                    timelines.Scale.Value = new Vector2(newScale, 1.0f);
                }
                else
                    cameraDistance.Value = Math.Max(5, cameraDistance.Value + delta * -2.0f);
            }));
            input.Add(new Binding<bool>(input.EnableLook, () => editor.MapEditMode || (input.MiddleMouseButton && editor.TransformMode.Value == Editor.TransformModes.None), input.MiddleMouseButton, editor.MapEditMode, editor.TransformMode));
            input.Add(new Binding<Vector3, Vector2>(camera.Angles, x => new Vector3(-x.Y, x.X, 0.0f), input.Mouse, () => input.EnableLook));
            input.Add(new Binding<bool>(main.IsMouseVisible, x => !x, input.EnableLook));
            editor.Add(new Binding<Vector3>(camera.Position, () => editor.Position.Value - (camera.Forward.Value * cameraDistance), editor.Position, input.Mouse, cameraDistance));

            PointLight editorLight = result.GetOrCreate<PointLight>("EditorLight");
            editorLight.Serialize = false;
            editorLight.Editable = false;
            editorLight.Shadowed.Value = false;
            editorLight.Add(new Binding<float>(editorLight.Attenuation, x => x * 2.0f, cameraDistance));
            editorLight.Color.Value = Vector3.One;
            editorLight.Add(new Binding<Vector3>(editorLight.Position, main.Camera.Position));
            editorLight.Enabled.Value = false;

            ui.PopupCommands.Add(new EditorUI.PopupCommand
            {
                Description = "Toggle editor light",
                Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode,
                Action = new Command { Action = () => editorLight.Enabled.Value = !editorLight.Enabled },
            });

            editor.Add(new CommandBinding(input.RightMouseButtonDown, () => !ui.PopupVisible && !editor.MapEditMode && !input.EnableLook && editor.TransformMode.Value == Editor.TransformModes.None, delegate()
            {
                // We're not editing a map
                // And we're not transforming entities
                // So we must be selecting / deselecting entities
                bool multiselect = input.GetKey(Keys.LeftShift);

                Vector2 mouse = input.Mouse;
                Microsoft.Xna.Framework.Graphics.Viewport viewport = main.GraphicsDevice.Viewport;
                Vector3 ray = Vector3.Normalize(viewport.Unproject(new Vector3(mouse.X, mouse.Y, 1), camera.Projection, camera.View, Matrix.Identity) - viewport.Unproject(new Vector3(mouse.X, mouse.Y, 0), camera.Projection, camera.View, Matrix.Identity));

                Entity closestEntity;
                Transform closestTransform;
                this.raycast(main, ray, out closestEntity, out closestTransform);

                if (closestEntity != null)
                {
                    if (editor.SelectedEntities.Count == 1 && input.GetKey(Keys.LeftControl).Value)
                    {
                        // The user is trying to connect the two entities
                        Entity entity = editor.SelectedEntities.First();
                        Command<Entity> toggleConnection = entity.GetCommand<Entity>("ToggleEntityConnected");
                        if (toggleConnection != null)
                        {
                            toggleConnection.Execute(closestEntity);
                            editor.NeedsSave.Value = true;
                        }
                        return;
                    }

                    if (multiselect)
                    {
                        if (editor.SelectedEntities.Contains(closestEntity))
                            editor.SelectedEntities.Remove(closestEntity);
                        else
                            editor.SelectedEntities.Add(closestEntity);
                    }
                    else
                    {
                        editor.SelectedEntities.Clear();
                        editor.SelectedEntities.Add(closestEntity);
                        editor.SelectedTransform.Value = closestTransform;
                    }
                }
                else
                {
                    editor.SelectedEntities.Clear();
                    editor.SelectedTransform.Value = null;
                }
            }));

            editor.Add(new CommandBinding(input.GetKeyDown(Keys.Escape), delegate()
            {
                if (editor.TransformMode.Value != Editor.TransformModes.None)
                    editor.RevertTransform.Execute();
                else if (editor.MapEditMode)
                    editor.MapEditMode.Value = false;
            }));

            addCommand("Toggle voxel edit", new PCInput.Chord { Key = Keys.Tab }, delegate()
            {
                if (editor.TransformMode.Value != Editor.TransformModes.None)
                    return false;

                if (editor.MapEditMode)
                    return true;
                else
                    return editor.SelectedEntities.Count == 1 && editor.SelectedEntities[0].Get<Map>() != null;
            },
            new Command
            {
                Action = delegate()
                {
                    editor.MapEditMode.Value = !editor.MapEditMode;
                }
            });

            addCommand
            (
                "Grab (move)",
                new PCInput.Chord { Key = Keys.G },
                () => editor.SelectedEntities.Count > 0 && !input.EnableLook && !editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartTranslation
            );
            addCommand
            (
                "Grab (move)",
                new PCInput.Chord { Key = Keys.G },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartVoxelTranslation
            );
            addCommand
            (
                "Voxel duplicate",
                new PCInput.Chord { Key = Keys.C },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelDuplicate
            );
            addCommand
            (
                "Voxel yank",
                new PCInput.Chord { Key = Keys.Y },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelCopy
            );
            addCommand
            (
                "Voxel paste",
                new PCInput.Chord { Key = Keys.P },
                () => editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelPaste
            );
            addCommand
            (
                "Rotate",
                new PCInput.Chord { Key = Keys.R },
                () => editor.SelectedEntities.Count > 0 && !editor.MapEditMode && !input.EnableLook && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartRotation
            );
            addCommand
            (
                "Lock X axis",
                new PCInput.Chord { Key = Keys.X },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.X }
            );
            addCommand
            (
                "Lock Y axis",
                new PCInput.Chord { Key = Keys.Y },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.Y }
            );
            addCommand
            (
                "Lock Z axis",
                new PCInput.Chord { Key = Keys.Z },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.Z }
            );

            editor.Add(new CommandBinding
            (
                input.LeftMouseButtonDown,
                () => editor.TransformMode.Value != Editor.TransformModes.None,
                editor.CommitTransform
            ));
            editor.Add(new CommandBinding
            (
                input.RightMouseButtonDown,
                () => editor.TransformMode.Value != Editor.TransformModes.None,
                editor.RevertTransform
            ));
        }
Exemplo n.º 47
0
        /// <summary>
        /// Initialze the Plugin.
        /// </summary>
        /// <returns>
        /// Success of the Operation.
        /// </returns>
        public override bool Initialize()
        {
            try {
                _imageProperty = GetProperty("Image") as ImageProperty;
                _deviceListProperty = GetProperty("Selected") as ListProperty;
                _resolutionListProperty = GetProperty("Resolution") as ListProperty;

                _resolutionListProperty.PropertyChanged += ResolutionListProperty_PropertyChanged;

                FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
                VideoCapabilities[] videoCapabilities;

                foreach (FilterInfo device in videoDevices) {
                    if (device.Name == _deviceListProperty.Value as string) {
                        _videoDevice = new VideoCaptureDevice(device.MonikerString);
                        break;
                    }
                }

                if (_videoDevice == null) return false;

                videoCapabilities = _videoDevice.VideoCapabilities;
                _videoDevice.VideoResolution = videoCapabilities[_resolutionListProperty.Index];

                _videoDevice.NewFrame += _videoDevice_NewFrame;
                _videoDevice.Start();
                _isTerminated = false;
                return true;
            } catch (Exception ex) {
                Trace.WriteLine(ex.Message, ex.StackTrace, LogCategory.Error);
                return false;
            }
        }
 public void ShouldGenerateHashCodeForListPropertyObject()
 {
     var value = new ListProperty<int>(10, 20);
     Assert.That(value.GetHashCode(), Is.EqualTo(HashCode.From(10, 20)));
 }
Exemplo n.º 49
0
		public static void Bind(Entity entity, Main main, ListContainer commandQueueContainer)
		{
			PCInput input = entity.Get<PCInput>();
			Editor editor = entity.Get<Editor>();
			EditorGeeUI gui = entity.Get<EditorGeeUI>();
			Property<bool> analyticsEnable = new Property<bool>();
			ListProperty<SessionEntry> analyticsSessions = new ListProperty<SessionEntry>();
			ListProperty<SessionEntry> analyticsActiveSessions = new ListProperty<SessionEntry>();
			ListProperty<EventEntry> analyticsEvents = new ListProperty<EventEntry>();
			ListProperty<EventEntry> analyticsActiveEvents = new ListProperty<EventEntry>();
			ListProperty<PropertyEntry> analyticsProperties = new ListProperty<PropertyEntry>();
			ListProperty<PropertyEntry> analyticsActiveProperties = new ListProperty<PropertyEntry>();
			Dictionary<Session, ModelInstance> sessionPositionModels = new Dictionary<Session, ModelInstance>();
			Dictionary<Session.EventList, List<ModelInstance>> eventPositionModels = new Dictionary<Session.EventList, List<ModelInstance>>();
			Property<bool> analyticsPlaying = new Property<bool>();
			Property<float> playbackSpeed = new Property<float> { Value = 1.0f };
			Property<float> playbackLocation = new Property<float>();

			const float timelineHeight = 32.0f;

			Scroller timelineScroller = new Scroller();
			timelineScroller.ScrollAmount.Value = 60.0f;
			timelineScroller.EnableScissor.Value = false;
			timelineScroller.DefaultScrollHorizontal.Value = true;
			timelineScroller.AnchorPoint.Value = new Vector2(0, 1);
			timelineScroller.ResizeVertical.Value = true;
			timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Position, x => new Vector2(0, x.Y), main.ScreenSize));
			timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Size, x => new Vector2(x.X, timelineHeight), main.ScreenSize));
			timelineScroller.Add(new Binding<bool>(timelineScroller.Visible, () => analyticsEnable && Editor.EditorModelsVisible, analyticsEnable, Editor.EditorModelsVisible));
			timelineScroller.Add(new Binding<bool>(timelineScroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
			entity.Add(new CommandBinding(entity.Delete, timelineScroller.Delete));
			main.UI.Root.Children.Add(timelineScroller);

			timelineScroller.Add(new Binding<bool>(editor.EnableCameraDistanceScroll, () => !timelineScroller.Highlighted || editor.VoxelEditMode, timelineScroller.Highlighted, editor.VoxelEditMode));
			timelineScroller.Add(new CommandBinding(timelineScroller.Delete, delegate()
			{
				editor.EnableCameraDistanceScroll.Value = true;
			}));

			ListContainer timelines = new ListContainer();
			timelines.Alignment.Value = ListContainer.ListAlignment.Min;
			timelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
			timelines.Reversed.Value = true;
			timelineScroller.Children.Add(timelines);

			input.Add(new CommandBinding<int>(input.MouseScrolled, () => input.GetKey(Keys.LeftAlt) && timelineScroller.Highlighted && !editor.VoxelEditMode, delegate(int delta)
			{
				float newScale = Math.Max(timelines.Scale.Value.X + delta * 6.0f, timelineScroller.Size.Value.X / timelines.Size.Value.X);
				Matrix absoluteTransform = timelines.GetAbsoluteTransform();
				float x = input.Mouse.Value.X + ((absoluteTransform.Translation.X - input.Mouse.Value.X) * (newScale / timelines.Scale.Value.X));
				timelines.Position.Value = new Vector2(x, 0.0f);
				timelines.Scale.Value = new Vector2(newScale, 1.0f);
			}));

			Container timeline = new Container();
			timeline.Size.Value = new Vector2(0, timelineHeight);
			timeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			timeline.ResizeHorizontal.Value = false;
			timeline.ResizeVertical.Value = false;
			timelines.Children.Add(timeline);

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Load analytics data", new PCInput.Chord(),
				new Command
				{
					Action = delegate()
					{
						if (main.MapFile.Value != null)
						{
							List<Session> sessions = main.LoadAnalytics(main.MapFile);
							if (sessions.Count > 0)
							{
								analyticsEnable.Value = true;
								Dictionary<string, bool> distinctEventNames = new Dictionary<string, bool>();
								Dictionary<string, bool> distinctPropertyNames = new Dictionary<string, bool>();
								foreach (Session s in sessions)
								{
									foreach (Session.EventList el in s.Events)
									{
										distinctEventNames[el.Name] = true;
										s.TotalTime = Math.Max(s.TotalTime, el.Events[el.Events.Count - 1].Time);
									}
									foreach (Session.ContinuousProperty p in s.ContinuousProperties)
									{
										if (p.Independent)
											distinctPropertyNames[p.Name] = true;
									}
									analyticsSessions.Add(new SessionEntry { Session = s });
								}
								analyticsEvents.AddAll(distinctEventNames.Keys.Select(x => new EventEntry { Name = x }));
								analyticsProperties.AddAll(distinctPropertyNames.Keys.Select(x => new PropertyEntry { Name = x }));
								timeline.Size.Value = new Vector2(analyticsSessions.Max(x => x.Session.TotalTime), timelineScroller.Size.Value.Y);
								timelines.Scale.Value = new Vector2(timelineScroller.Size.Value.X / timeline.Size.Value.X, 1.0f);
							}
						}
					}
				},
				gui.MapCommands,
				() => !analyticsEnable && !string.IsNullOrEmpty(main.MapFile) && !gui.PickNextEntity,
				analyticsEnable, main.MapFile, gui.PickNextEntity
			);

			ListContainer sessionsSidebar = new ListContainer();
			sessionsSidebar.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Add(new Binding<Vector2>(sessionsSidebar.Position, () => new Vector2(main.ScreenSize.Value.X - 10, main.ScreenSize.Value.Y - timelineScroller.ScaledSize.Value.Y - 10), main.ScreenSize, timelineScroller.ScaledSize));
			sessionsSidebar.Add(new Binding<bool>(sessionsSidebar.Visible, () => analyticsEnable && Editor.EditorModelsVisible, analyticsEnable, Editor.EditorModelsVisible));
			sessionsSidebar.Alignment.Value = ListContainer.ListAlignment.Max;
			sessionsSidebar.Reversed.Value = true;
			main.UI.Root.Children.Add(sessionsSidebar);
			entity.Add(new CommandBinding(entity.Delete, sessionsSidebar.Delete));

			Func<string, ListContainer> createCheckboxListItem = delegate(string text)
			{
				ListContainer layout = new ListContainer();
				layout.Orientation.Value = ListContainer.ListOrientation.Horizontal;

				TextElement label = new TextElement();
				label.FontFile.Value = main.Font;
				label.Text.Value = text;
				label.Name.Value = "Label";
				layout.Children.Add(label);

				Container checkboxContainer = new Container();
				checkboxContainer.PaddingBottom.Value = checkboxContainer.PaddingLeft.Value = checkboxContainer.PaddingRight.Value = checkboxContainer.PaddingTop.Value = 1.0f;
				layout.Children.Add(checkboxContainer);

				Container checkbox = new Container();
				checkbox.Name.Value = "Checkbox";
				checkbox.ResizeHorizontal.Value = checkbox.ResizeVertical.Value = false;
				checkbox.Size.Value = new Vector2(16.0f, 16.0f);
				checkboxContainer.Children.Add(checkbox);
				return layout;
			};

			Container sessionsContainer = new Container();
			sessionsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			sessionsContainer.Opacity.Value = UIFactory.Opacity;
			sessionsContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(sessionsContainer);

			Scroller sessionsScroller = new Scroller();
			sessionsScroller.ResizeHorizontal.Value = true;
			sessionsScroller.ResizeVertical.Value = true;
			sessionsScroller.MaxVerticalSize.Value = 256;
			sessionsContainer.Children.Add(sessionsScroller);

			ListContainer sessionList = new ListContainer();
			sessionList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			sessionList.Alignment.Value = ListContainer.ListAlignment.Max;
			sessionsScroller.Children.Add(sessionList);

			Property<bool> allSessions = new Property<bool>();

			sessionList.Add(new ListBinding<UIComponent, SessionEntry>(sessionList.Children, analyticsSessions, delegate(SessionEntry entry)
			{
				ListContainer item = createCheckboxListItem(string.Format("{0} {1:d} ({2})", entry.Session.UUID.Substring(0, 8), entry.Session.Date, new TimeSpan(0, 0, (int)entry.Session.TotalTime)));

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, entry.Active));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (entry.Active)
					{
						allSessions.Value = false;
						analyticsActiveSessions.Remove(entry);
					}
					else
						analyticsActiveSessions.Add(entry);
				}));

				return item;
			}));

			ListContainer allSessionsButton = createCheckboxListItem("[All]");
			allSessionsButton.Add(new CommandBinding(allSessionsButton.MouseLeftDown, delegate()
			{
				if (allSessions)
				{
					allSessions.Value = false;
					foreach (SessionEntry s in analyticsActiveSessions.ToList())
						analyticsActiveSessions.Remove(s);
				}
				else
				{
					allSessions.Value = true;
					foreach (SessionEntry s in analyticsSessions)
					{
						if (!s.Active)
							analyticsActiveSessions.Add(s);
					}
				}
			}));

			Container allSessionsCheckbox = (Container)allSessionsButton.GetChildByName("Checkbox");
			allSessionsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allSessionsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allSessions));
			sessionList.Children.Add(allSessionsButton);

			Container eventsContainer = new Container();
			eventsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			eventsContainer.Opacity.Value = UIFactory.Opacity;
			eventsContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(eventsContainer);

			Scroller eventsScroller = new Scroller();
			eventsScroller.ResizeHorizontal.Value = true;
			eventsScroller.ResizeVertical.Value = true;
			eventsScroller.MaxVerticalSize.Value = 256;
			eventsContainer.Children.Add(eventsScroller);

			ListContainer eventList = new ListContainer();
			eventList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			eventList.Alignment.Value = ListContainer.ListAlignment.Max;
			eventsScroller.Children.Add(eventList);

			Property<bool> allEvents = new Property<bool>();

			eventList.Add(new ListBinding<UIComponent, EventEntry>(eventList.Children, analyticsEvents, delegate(EventEntry e)
			{
				ListContainer item = createCheckboxListItem(e.Name);

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

				TextElement label = (TextElement)item.GetChildByName("Label");
				label.Tint.Value = new Microsoft.Xna.Framework.Color(colorHash(e.Name));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (e.Active)
					{
						allEvents.Value = false;
						analyticsActiveEvents.Remove(e);
					}
					else
						analyticsActiveEvents.Add(e);
				}));

				return item;
			}));

			ListContainer allEventsButton = createCheckboxListItem("[All]");
			allEventsButton.Add(new CommandBinding(allEventsButton.MouseLeftDown, delegate()
			{
				if (allEvents)
				{
					allEvents.Value = false;
					foreach (EventEntry e in analyticsActiveEvents.ToList())
						analyticsActiveEvents.Remove(e);
				}
				else
				{
					allEvents.Value = true;
					foreach (EventEntry e in analyticsEvents)
					{
						if (!e.Active)
							analyticsActiveEvents.Add(e);
					}
				}
			}));
			Container allEventsCheckbox = (Container)allEventsButton.GetChildByName("Checkbox");
			allEventsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allEventsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allEvents));
			eventList.Children.Add(allEventsButton);

			Container propertiesContainer = new Container();
			propertiesContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			propertiesContainer.Opacity.Value = UIFactory.Opacity;
			propertiesContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(propertiesContainer);

			Scroller propertiesScroller = new Scroller();
			propertiesScroller.ResizeHorizontal.Value = true;
			propertiesScroller.ResizeVertical.Value = true;
			propertiesScroller.MaxVerticalSize.Value = 256;
			propertiesContainer.Children.Add(propertiesScroller);

			ListContainer propertiesList = new ListContainer();
			propertiesList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			propertiesList.Alignment.Value = ListContainer.ListAlignment.Max;
			propertiesScroller.Children.Add(propertiesList);

			Property<bool> allProperties = new Property<bool>();

			propertiesList.Add(new ListBinding<UIComponent, PropertyEntry>(propertiesList.Children, analyticsProperties, delegate(PropertyEntry e)
			{
				ListContainer item = createCheckboxListItem(e.Name);

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

				TextElement label = (TextElement)item.GetChildByName("Label");
				label.Tint.Value = new Microsoft.Xna.Framework.Color(colorHash(e.Name));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (e.Active)
					{
						allProperties.Value = false;
						analyticsActiveProperties.Remove(e);
					}
					else
						analyticsActiveProperties.Add(e);
				}));

				return item;
			}));

			ListContainer allPropertiesButton = createCheckboxListItem("[All]");
			allPropertiesButton.Add(new CommandBinding(allPropertiesButton.MouseLeftDown, delegate()
			{
				if (allProperties)
				{
					allProperties.Value = false;
					foreach (PropertyEntry e in analyticsActiveProperties.ToList())
						analyticsActiveProperties.Remove(e);
				}
				else
				{
					allProperties.Value = true;
					foreach (PropertyEntry e in analyticsProperties)
					{
						if (!e.Active)
							analyticsActiveProperties.Add(e);
					}
				}
			}));
			Container allPropertiesCheckbox = (Container)allPropertiesButton.GetChildByName("Checkbox");
			allPropertiesCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allPropertiesCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allProperties));
			propertiesList.Children.Add(allPropertiesButton);

			Func<Session.EventList, LineDrawer2D> createEventLines = delegate(Session.EventList el)
			{
				LineDrawer2D line = new LineDrawer2D();
				line.Color.Value = colorHash(el.Name);
				line.UserData.Value = el;

				foreach (Session.Event e in el.Events)
				{
					line.Lines.Add(new LineDrawer2D.Line
					{
						A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, 0.0f, 0.0f), Microsoft.Xna.Framework.Color.White),
						B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, timeline.Size.Value.Y, 0.0f), Microsoft.Xna.Framework.Color.White),
					});
				}
				return line;
			};

			analyticsActiveEvents.ItemAdded += delegate(int index, EventEntry ee)
			{
				ee.Active.Value = true;
				foreach (SessionEntry s in analyticsActiveSessions)
				{
					Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
					foreach (Session.EventList el in s.Session.Events)
					{
						if (el.Name == ee.Name)
						{
							List<ModelInstance> models = new List<ModelInstance>();
							Vector4 color = colorHash(el.Name);
							int hash = (int)(new Color(color).PackedValue);
							foreach (Session.Event e in el.Events)
							{
								ModelInstance i = new ModelInstance();
								i.Serialize = false;
								i.Setup("InstancedModels\\position-model", hash);
								if (i.IsFirstInstance)
									i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
								i.Transform.Value = Matrix.CreateTranslation(positionProperty.GetLastRecordedPosition(e.Time));
								models.Add(i);
								entity.Add(i);
							}
							eventPositionModels[el] = models;
						}
					}

					timeline.Children.AddAll(s.Session.Events.Where(x => x.Name == ee.Name).Select(createEventLines));
				}
			};

			analyticsActiveEvents.ItemRemoved += delegate(int index, EventEntry e)
			{
				e.Active.Value = false;
				foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
				{
					if (pair.Key.Name == e.Name)
					{
						foreach (ModelInstance instance in pair.Value)
							instance.Delete.Execute();
						eventPositionModels.Remove(pair.Key);
					}
				}
				timeline.Children.RemoveAll(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Name == e.Name).ToList());
			};

			analyticsActiveProperties.ItemAdded += delegate(int index, PropertyEntry e)
			{
				e.Active.Value = true;
			};

			analyticsActiveProperties.ItemRemoved += delegate(int index, PropertyEntry e)
			{
				e.Active.Value = false;
			};

			ListContainer propertyTimelines = new ListContainer();
			propertyTimelines.Alignment.Value = ListContainer.ListAlignment.Min;
			propertyTimelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
			timelines.Children.Add(propertyTimelines);

			Action<Container> refreshPropertyGraph = delegate(Container container)
			{
				TextElement label = (TextElement)container.GetChildByName("Label");
				LineDrawer2D lines = (LineDrawer2D)container.GetChildByName("Graph");
				string propertyName = ((PropertyEntry)lines.UserData.Value).Name;
				lines.Lines.Clear();
				float time = 0.0f, lastTime = 0.0f;
				float lastValue = 0.0f;
				bool firstLine = true;
				float max = float.MinValue, min = float.MaxValue;
				while (true)
				{
					bool stop = true;

					// Calculate average
					int count = 0;
					float sum = 0.0f;
					foreach (SessionEntry s in analyticsActiveSessions)
					{
						if (time < s.Session.TotalTime)
						{
							Session.ContinuousProperty prop = s.Session.GetContinuousProperty(propertyName);
							if (prop != null)
							{
								stop = false;
								sum += prop[time];
								count++;
							}
						}
					}

					if (stop)
						break;
					else
					{
						float value = sum / (float)count;
						if (firstLine)
							firstLine = false;
						else
						{
							lines.Lines.Add(new LineDrawer2D.Line
							{
								A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
								{
									Color = Microsoft.Xna.Framework.Color.White,
									Position = new Vector3(lastTime, lastValue, 0.0f),
								},
								B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
								{
									Color = Microsoft.Xna.Framework.Color.White,
									Position = new Vector3(time, value, 0.0f),
								},
							});
						}
						min = Math.Min(min, value);
						max = Math.Max(max, value);
						lastValue = value;
						lastTime = time;
						time += Session.Recorder.Interval;
					}

					if (min < max)
					{
						float scale = -timelineHeight / (max - min);
						lines.Scale.Value = new Vector2(1, scale);
						lines.Position.Value = new Vector2(0, max * -scale);
					}
					else
					{
						lines.AnchorPoint.Value = Vector2.Zero;
						if (min <= 0.0f)
							lines.Position.Value = new Vector2(0, timelineHeight);
						else
							lines.Position.Value = new Vector2(0, timelineHeight * 0.5f);
					}
					label.Text.Value = max.ToString("F");
				}
			};

			Action refreshPropertyGraphs = delegate()
			{
				foreach (Container propertyTimeline in propertyTimelines.Children)
					refreshPropertyGraph(propertyTimeline);
			};

			propertyTimelines.Add(new ListBinding<UIComponent, PropertyEntry>(propertyTimelines.Children, analyticsActiveProperties, delegate(PropertyEntry e)
			{
				Container propertyTimeline = new Container();
				propertyTimeline.Add(new Binding<Vector2>(propertyTimeline.Size, timeline.Size));
				propertyTimeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
				propertyTimeline.Opacity.Value = UIFactory.Opacity;
				propertyTimeline.ResizeHorizontal.Value = false;
				propertyTimeline.ResizeVertical.Value = false;

				LineDrawer2D line = new LineDrawer2D();
				line.Name.Value = "Graph";
				line.Color.Value = colorHash(e.Name);
				line.UserData.Value = e;
				propertyTimeline.Children.Add(line);

				TextElement label = new TextElement();
				label.FontFile.Value = main.Font;
				label.Name.Value = "Label";
				label.Add(new Binding<Vector2>(label.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
				label.AnchorPoint.Value = new Vector2(0, 0);
				label.Position.Value = new Vector2(0, 0);
				propertyTimeline.Children.Add(label);

				refreshPropertyGraph(propertyTimeline);

				return propertyTimeline;
			}));

			analyticsActiveSessions.ItemAdded += delegate(int index, SessionEntry s)
			{
				Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
				foreach (Session.EventList el in s.Session.Events)
				{
					if (analyticsActiveEvents.FirstOrDefault(x => x.Name == el.Name) != null)
					{
						List<ModelInstance> models = new List<ModelInstance>();
						Vector4 color = colorHash(el.Name);
						int hash = (int)(new Color(color).PackedValue);
						foreach (Session.Event e in el.Events)
						{
							ModelInstance i = new ModelInstance();
							i.Serialize = false;
							i.Setup("InstancedModels\\position-model", hash);
							if (i.IsFirstInstance)
								i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
							i.Transform.Value = Matrix.CreateTranslation(positionProperty.GetLastRecordedPosition(e.Time));
							entity.Add(i);
							models.Add(i);
						}
						eventPositionModels[el] = models;
					}
				}

				ModelInstance instance = new ModelInstance();
				instance.Setup("InstancedModels\\position-model", 0);
				instance.Serialize = false;
				entity.Add(instance);
				sessionPositionModels.Add(s.Session, instance);
				s.Active.Value = true;
				timeline.Children.AddAll(s.Session.Events.Where(x => analyticsActiveEvents.FirstOrDefault(y => y.Name == x.Name) != null).Select(createEventLines));
				playbackLocation.Reset();

				refreshPropertyGraphs();
			};

			analyticsActiveSessions.ItemRemoved += delegate(int index, SessionEntry s)
			{
				ModelInstance instance = sessionPositionModels[s.Session];
				instance.Delete.Execute();

				foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
				{
					if (pair.Key.Session == s.Session)
					{
						foreach (ModelInstance i in pair.Value)
							i.Delete.Execute();
						eventPositionModels.Remove(pair.Key);
					}
				}

				sessionPositionModels.Remove(s.Session);
				s.Active.Value = false;
				timeline.Children.RemoveAll(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Session == s.Session).ToList());

				refreshPropertyGraphs();
			};

			entity.Add(new SetBinding<float>(playbackLocation, delegate(float value)
			{
				if (analyticsActiveSessions.Length == 0)
					return;

				if (value < 0.0f)
					playbackLocation.Value = 0.0f;
				float end = analyticsActiveSessions.Max(x => x.Session.TotalTime);
				if (value > end)
				{
					playbackLocation.Value = end;
					analyticsPlaying.Value = false;
				}

				foreach (KeyValuePair<Session, ModelInstance> pair in sessionPositionModels)
					pair.Value.Transform.Value = Matrix.CreateTranslation(pair.Key.PositionProperties[0][playbackLocation]);
			}));

			LineDrawer2D playbackLine = new LineDrawer2D();
			playbackLine.Color.Value = Vector4.One;
			playbackLine.Lines.Add(new LineDrawer2D.Line
			{
				A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
				{
					Color = Microsoft.Xna.Framework.Color.White,
					Position = new Vector3(0.0f, -10.0f, 0.0f),
				},
				B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
				{
					Color = Microsoft.Xna.Framework.Color.White,
					Position = new Vector3(0.0f, timeline.Size.Value.Y, 0.0f),
				},
			});
			playbackLine.Add(new Binding<Vector2, float>(playbackLine.Position, x => new Vector2(x, 0.0f), playbackLocation));
			timeline.Children.Add(playbackLine);

			entity.Add(new NotifyBinding(delegate()
			{
				allEventsButton.Detach();
				allSessionsButton.Detach();
				allPropertiesButton.Detach();
				analyticsSessions.Clear();
				analyticsEvents.Clear();
				analyticsProperties.Clear();
				eventList.Children.Add(allEventsButton);
				sessionList.Children.Add(allSessionsButton);
				propertiesList.Children.Add(allPropertiesButton);

				foreach (ModelInstance instance in sessionPositionModels.Values)
					instance.Delete.Execute();
				sessionPositionModels.Clear();

				foreach (ModelInstance instance in eventPositionModels.Values.SelectMany(x => x))
					instance.Delete.Execute();
				eventPositionModels.Clear();

				allEvents.Value = false;
				allSessions.Value = false;
				allProperties.Value = false;
				analyticsEnable.Value = false;

				analyticsActiveEvents.Clear();
				analyticsActiveSessions.Clear();
				analyticsActiveProperties.Clear();

				propertyTimelines.Children.Clear();

				playbackLine.Detach();
				timeline.Children.Clear();
				timeline.Children.Add(playbackLine);

				analyticsPlaying.Value = false;
				playbackLocation.Value = 0.0f;
			}, main.MapFile));

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Toggle analytics playback", new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.A },  new Command
				{
					Action = delegate()
					{
						analyticsPlaying.Value = !analyticsPlaying;
					}
				},
				gui.MapCommands,
				() => analyticsEnable && !editor.MovementEnabled && analyticsActiveSessions.Length > 0,
				analyticsEnable, editor.MovementEnabled, analyticsActiveSessions.Length
			);

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Stop analytics playback", new PCInput.Chord { Key = Keys.Escape }, new Command
				{
					Action = delegate()
					{
						analyticsPlaying.Value = false;
					}
				}, gui.MapCommands, () => analyticsPlaying, analyticsPlaying
			);

			Container playbackContainer = new Container();
			playbackContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			playbackContainer.Opacity.Value = UIFactory.Opacity;
			sessionsSidebar.Children.Add(playbackContainer);
			playbackContainer.Add(new CommandBinding<int>(playbackContainer.MouseScrolled, delegate(int delta)
			{
				playbackSpeed.Value = Math.Max(1.0f, Math.Min(10.0f, playbackSpeed.Value + delta));
			}));

			TextElement playbackLabel = new TextElement();
			playbackLabel.FontFile.Value = main.Font;
			playbackLabel.Add(new Binding<string>(playbackLabel.Text, delegate()
			{
				return string.Format("{0} {1} {2:F}x", TimeTrialUI.SecondsToTimeString(playbackLocation), (analyticsPlaying ? "Playing" : "Stopped"), playbackSpeed);
			}, playbackLocation, playbackSpeed, analyticsPlaying));
			playbackContainer.Children.Add(playbackLabel);

			Container descriptionContainer = null;

			Updater timelineUpdate = new Updater
			(
				delegate(float dt)
				{
					bool setTimelinePosition = false;

					if (timelines.Highlighted || descriptionContainer != null)
					{
						if (input.LeftMouseButton)
						{
							setTimelinePosition = true;
							playbackLocation.Value = Vector3.Transform(new Vector3(input.Mouse.Value.X, 0.0f, 0.0f), Matrix.Invert(timeline.GetAbsoluteTransform())).X;
						}

						float threshold = 3.0f / timelines.Scale.Value.X;
						float mouseRelative = Vector3.Transform(new Vector3(input.Mouse, 0.0f), Matrix.Invert(timelines.GetAbsoluteTransform())).X;

						if (descriptionContainer != null)
						{
							if (!timelines.Highlighted || (float)Math.Abs(descriptionContainer.Position.Value.X - mouseRelative) > threshold)
							{
								descriptionContainer.Delete.Execute();
								descriptionContainer = null;
							}
						}

						if (descriptionContainer == null && timeline.Highlighted)
						{
							foreach (UIComponent component in timeline.Children)
							{
								LineDrawer2D lines = component as LineDrawer2D;

								if (lines == null)
									continue;

								Session.EventList el = lines.UserData.Value as Session.EventList;
								if (el != null)
								{
									bool stop = false;
									foreach (Session.Event e in el.Events)
									{
										if (el != null && (float)Math.Abs(e.Time - mouseRelative) < threshold)
										{
											descriptionContainer = new Container();
											descriptionContainer.AnchorPoint.Value = new Vector2(0.5f, 1.0f);
											descriptionContainer.Position.Value = new Vector2(e.Time, 0.0f);
											descriptionContainer.Opacity.Value = 1.0f;
											descriptionContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
											descriptionContainer.Add(new Binding<Vector2>(descriptionContainer.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
											timeline.Children.Add(descriptionContainer);
											TextElement description = new TextElement();
											description.WrapWidth.Value = 256;

											if (string.IsNullOrEmpty(e.Data))
												description.Text.Value = el.Name;
											else
												description.Text.Value = string.Format("{0}\n{1}", el.Name, e.Data);

											description.FontFile.Value = main.Font;
											descriptionContainer.Children.Add(description);
											stop = true;
											break;
										}
									}
									if (stop)
										break;
								}
							}
						}
					}

					if (analyticsPlaying && !setTimelinePosition)
					{
						if (analyticsActiveSessions.Length == 0)
							analyticsPlaying.Value = false;
						else
							playbackLocation.Value += dt * playbackSpeed;
					}
				}
			);
			entity.Add(timelineUpdate);
			timelineUpdate.EnabledInEditMode = true;
		}