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); }
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); }
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; }
/// <summary> /// /// </summary> /// <param name="listProperty"></param> protected virtual void ListAreaSection() { for (int i = 0; i < ListProperty.arraySize; i++) { ListItemAreaSection(ListProperty.GetArrayElementAtIndex(i), i); } }
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); } }
/// <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); } }
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; } } } }
protected override void Initialize() { world = target as World; scenes = GetListProperty("scenes"); activeScene = GetBasicProperty("activeScene"); mainScene = GetBasicProperty("mainScene"); isDeveloppement = GetBasicProperty("isDeveloppement"); }
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"); }
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); }
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), }; }
private void Bind(ListProperty property) { var binding = new Binding(property.PropertyInfo.Name) { Mode = BindingMode.TwoWay, Source = property.Object, }; this.Bind(IsCheckedProperty, binding); }
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); } }
/// <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; } }
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), }; }
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); }
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); }
public void LoadObject(object obj) { ClearControls(); AddSummary(); ItemCollection <ListProperty> properties = ListProperty.Create(obj); foreach (ListProperty property in properties) { AddPropertyRow(property); } }
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); }
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(); }
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); }
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; }
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); }
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(); }
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; }
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); }
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); }
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); } }
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); }
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 }
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); } } } }
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); } } } }
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); } }
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())); }
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); }
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; }
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; }
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; }
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(); }
public BoxPropShorthandParser(ListProperty listprop) : base(listprop) { }
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 )); }
/// <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))); }
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; }