private void GenerateCells() { foreach (var cell in cells.Values) { cell.Clear(); cellPool.Push(cell); } cells.Clear(); foreach (var animator in node.Animators) { if (animator.IsZombie) { continue; } for (var j = 0; j < animator.ReadonlyKeys.Count; j++) { var key = animator.ReadonlyKeys[j]; var colorIndex = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(animator.Animable.GetType(), animator.TargetPropertyPath)?.ColorIndex ?? 0; if (!cells.TryGetValue(key.Frame, out var cell)) { cell = cellPool.Count == 0 ? new Cell() : cellPool.Pop(); cells.Add(key.Frame, cell); } if (cell.StripCount == 0) { cell.Func1 = key.Function; } else if (cell.StripCount == 1) { var lastColorIndex = 0; for (int i = 0; i < cell.Strips.Count; i++) { if (cell.Strips[i]) { lastColorIndex = i; break; } } if (lastColorIndex < colorIndex) { cell.Func2 = key.Function; } else { var a = cell.Func1; cell.Func1 = key.Function; cell.Func2 = a; } } cell.Strips[colorIndex] = true; cell.StripCount++; cells[key.Frame] = cell; } } }
InspectorPropertyRegistry() { Items = new List <RegistryItem>(); AddEditor(c => PropertyAttributes <TangerineDropDownListPropertyEditorAttribute> .Get(c.Type, c.PropertyName) != null, c => { var a = PropertyAttributes <TangerineDropDownListPropertyEditorAttribute> .Get(c.Type, c.PropertyName); Type specializedDropDownListPropertyEditorType = typeof(DropDownListPropertyEditor <>).MakeGenericType(c.PropertyInfo.PropertyType); return(Activator.CreateInstance(specializedDropDownListPropertyEditorType, new object[] { c, a.EnumerateItems(c.Objects.First()) }) as IPropertyEditor); } ); AddEditor(c => PropertyAttributes <TangerineFilePropertyAttribute> .Get(c.Type, c.PropertyName) != null, c => { var a = PropertyAttributes <TangerineFilePropertyAttribute> .Get(c.Type, c.PropertyName); Type specializedCustomFilePropertyEditorType = typeof(CustomFilePropertyEditor <>).MakeGenericType(c.PropertyInfo.PropertyType); return(Activator.CreateInstance(specializedCustomFilePropertyEditorType, new object[] { c, a }) as IPropertyEditor); } ); AddEditor(c => c.PropertyName == "ContentsPath" && c.Objects.All(o => o is Node), c => AllowChildren(c) ? new ContentsPathPropertyEditor(c) : null); AddEditor(c => c.PropertyName == "Trigger", c => AllowChildren(c) ? new TriggerPropertyEditor(c) : null); AddEditor(typeof(Vector2), c => new Vector2PropertyEditor(c)); AddEditor(typeof(Vector3), c => new Vector3PropertyEditor(c)); AddEditor(typeof(Quaternion), c => new QuaternionPropertyEditor(c)); AddEditor(typeof(NumericRange), c => new NumericRangePropertyEditor(c)); AddEditor(c => c.PropertyName == "Text", c => new TextPropertyEditor(c)); AddEditor(c => c.PropertyName == "Id", c => new NodeIdPropertyEditor(c)); AddEditor(typeof(string), c => new StringPropertyEditor(c)); AddEditor(typeof(float), c => new FloatPropertyEditor(c)); AddEditor(typeof(double), c => new DoublePropertyEditor(c)); AddEditor(typeof(bool), c => new BooleanPropertyEditor(c)); AddEditor(typeof(int), c => new IntPropertyEditor(c)); AddEditor(typeof(sbyte), c => new SBytePropertyEditor(c)); AddEditor(typeof(Color4), c => new Color4PropertyEditor(c)); AddEditor(typeof(ColorGradient), c => new ColorGradientPropertyEditor(c)); AddEditor(typeof(Anchors), c => new AnchorsPropertyEditor(c)); AddEditor(typeof(Blending), c => new BlendingPropertyEditor(c)); AddEditor(typeof(RenderTarget), c => new RenderTargetPropertyEditor(c)); AddEditor(c => { return (!c.Objects.Skip(1).Any() && c.PropertyInfo.PropertyType == typeof(ITexture) && c.PropertyInfo.GetValue(c.Objects.First())?.GetType() == typeof(RenderTexture)); }, c => new RenderTexturePropertyEditor(c)); AddEditor(typeof(ITexture), c => new TexturePropertyEditor <ITexture>(c)); AddEditor(typeof(SerializableTexture), c => new TexturePropertyEditor <SerializableTexture>(c)); AddEditor(typeof(SerializableSample), c => new AudioSamplePropertyEditor(c)); AddEditor(typeof(SerializableFont), c => new FontPropertyEditor(c)); AddEditor(typeof(NodeReference <Camera3D>), c => new NodeReferencePropertyEditor <Camera3D>(c)); AddEditor(typeof(NodeReference <Image>), c => new NodeReferencePropertyEditor <Image>(c)); AddEditor(typeof(NodeReference <Spline>), c => new NodeReferencePropertyEditor <Spline>(c)); AddEditor(typeof(NodeReference <Widget>), c => new NodeReferencePropertyEditor <Widget>(c)); AddEditor(typeof(NodeReference <Node3D>), c => new NodeReferencePropertyEditor <Node3D>(c)); AddEditor(typeof(NodeReference <Spline3D>), c => new NodeReferencePropertyEditor <Spline3D>(c)); AddEditor(typeof(SkinningWeights), c => new SkinningWeightsPropertyEditor(c)); AddEditor(typeof(Alignment), c => new AlignmentPropertyEditor(c)); AddEditor(typeof(Thickness), c => new ThicknessPropertyEditor(c)); }
private IEnumerable <IPropertyEditor> PopulatePropertyEditors(Type type, IEnumerable <object> objects, IEnumerable <object> rootObjects, Widget widget, Dictionary <string, List <PropertyEditorParams> > editorParams) { foreach (var header in editorParams.Keys.OrderBy((s) => s)) { AddGroupHeader(header, widget); foreach (var param in editorParams[header]) { bool isPropertyRegistered = false; IPropertyEditor editor = null; foreach (var i in InspectorPropertyRegistry.Instance.Items) { if (i.Condition(param)) { isPropertyRegistered = true; editor = i.Builder(param); break; } } if (!isPropertyRegistered) { var propertyType = param.PropertyInfo.PropertyType; var iListInterface = propertyType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList <>)); if (propertyType.IsEnum) { editor = CreateEditorForEnum(param); } else if (iListInterface != null) { editor = PopulateEditorsForListType(objects, rootObjects, param, iListInterface); } else if ((propertyType.IsClass || propertyType.IsInterface) && !propertyType.GetInterfaces().Contains(typeof(IEnumerable))) { editor = PopulateEditorsForInstanceType(objects, rootObjects, param); } } if (editor != null) { DecoratePropertyEditor(editor, row++); editors.Add(editor); var showCondition = PropertyAttributes <TangerineIgnoreIfAttribute> .Get(type, param.PropertyInfo.Name); if (showCondition != null) { editor.ContainerWidget.Updated += (delta) => { editor.ContainerWidget.Visible = !showCondition.Check(param.Objects.First()); }; } yield return(editor); } } } }
public PropertyEditorParams(Widget inspectorPane, List <object> objects, Type type, string propertyName) { InspectorPane = inspectorPane; Objects = objects; Type = type; PropertyName = propertyName; TangerineAttribute = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(Type, PropertyName) ?? new TangerineKeyframeColorAttribute(0); Group = PropertyAttributes <TangerineGroupAttribute> .Get(Type, PropertyName)?.Name ?? String.Empty; PropertyInfo = Type.GetProperty(PropertyName); PropertySetter = SetProperty; NumericEditBoxFactory = () => new ThemedNumericEditBox(); DropDownListFactory = () => new ThemedDropDownList(); EditBoxFactory = () => new ThemedEditBox(); }
private void Render(Widget widget) { widget.PrepareRendererState(); Renderer.DrawRect(Vector2.Zero, widget.ContentSize, ColorTheme.Current.TimelineGrid.PropertyRowBackground); var colorIndex = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(animator.Animable.GetType(), animator.TargetPropertyPath)?.ColorIndex ?? 0; var color = KeyframePalette.Colors[colorIndex]; for (int i = 0; i < animator.ReadonlyKeys.Count; i++) { var key = animator.ReadonlyKeys[i]; var a = new Vector2(key.Frame * TimelineMetrics.ColWidth + 1, 0); var b = a + new Vector2(TimelineMetrics.ColWidth - 1, widget.Height); KeyframeFigure.Render(a, b, color, key.Function); } }
protected virtual void Render(Widget widget) { var maxCol = Timeline.Instance.ColumnCount; widget.PrepareRendererState(); if (maxCol > keyStrips.Length) { keyStrips = new BitSet32[maxCol]; } for (int i = 0; i < maxCol; i++) { keyStrips[i] = BitSet32.Empty; } foreach (var a in node.Animators) { for (int j = 0; j < a.ReadonlyKeys.Count; j++) { var key = a.ReadonlyKeys[j]; var colorIndex = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(node.GetType(), a.TargetProperty)?.ColorIndex ?? 0; keyStrips[key.Frame][colorIndex] = true; } } for (int i = 0; i < maxCol; i++) { if (keyStrips[i] != BitSet32.Empty) { var s = keyStrips[i]; int c = 0; for (int j = 0; j < 32; j++) { c += s[j] ? 1 : 0; } var a = new Vector2(i * TimelineMetrics.ColWidth + 1, 0); var d = widget.Height / c; for (int j = 0; j < 32; j++) { if (s[j]) { var b = a + new Vector2(TimelineMetrics.ColWidth - 1, d); Renderer.DrawRect(a, b, KeyframePalette.Colors[j]); a.Y += d; } } } } }
private void DecoratePropertyEditor(IPropertyEditor editor, int row) { var ctr = editor.ContainerWidget; if (!(editor is IExpandablePropertyEditor)) { ctr.Nodes.Insert(0, new HSpacer(20)); } var index = ctr.Nodes.Count() - 1; if (PropertyAttributes <TangerineStaticPropertyAttribute> .Get(editor.EditorParams.PropertyInfo) == null) { var keyFunctionButton = new KeyFunctionButton { LayoutCell = new LayoutCell(Alignment.LeftCenter, stretchX: 0), }; var keyframeButton = new KeyframeButton { LayoutCell = new LayoutCell(Alignment.LeftCenter, stretchX: 0), KeyColor = KeyframePalette.Colors[editor.EditorParams.TangerineAttribute.ColorIndex], }; keyFunctionButton.Clicked += editor.SetFocus; keyframeButton.Clicked += editor.SetFocus; ctr.Nodes.Insert(index++, keyFunctionButton); ctr.Nodes.Insert(index++, keyframeButton); ctr.Nodes.Insert(index, new HSpacer(4)); ctr.Tasks.Add(new KeyframeButtonBinding(editor.EditorParams, keyframeButton)); ctr.Tasks.Add(new KeyFunctionButtonBinding(editor.EditorParams, keyFunctionButton)); } else { ctr.Nodes.Insert(2, new HSpacer(42)); } editor.ContainerWidget.Padding = new Thickness { Left = 4, Top = 1, Right = 12, Bottom = 1 }; editor.ContainerWidget.CompoundPresenter.Add(new WidgetFlatFillPresenter( row % 2 == 0 ? ColorTheme.Current.Inspector.StripeBackground1 : ColorTheme.Current.Inspector.StripeBackground2 ) { IgnorePadding = true }); }
private void Render(Widget widget) { var maxCol = Timeline.Instance.ColumnCount; widget.PrepareRendererState(); Renderer.DrawRect(Vector2.Zero, widget.ContentSize, ColorTheme.Current.TimelineGrid.PropertyRowBackground); var colorIndex = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(animator.Animable.GetType(), animator.TargetPropertyPath)?.ColorIndex ?? 0; var color = KeyframePalette.Colors[colorIndex]; for (int i = 0; i < animator.ReadonlyKeys.Count; i++) { var key = animator.ReadonlyKeys[i]; Renderer.Transform1 = Matrix32.RotationRough(Mathf.Pi / 4) * Matrix32.Translation((key.Frame + 0.5f) * TimelineMetrics.ColWidth + 0.5f, widget.Height / 2 + 0.5f) * widget.LocalToWorldTransform; var v = TimelineMetrics.ColWidth / 3 * Vector2.One; Renderer.DrawRect(-v, v, color); } }
private bool ShouldInspectProperty(Type type, IEnumerable <object> objects, PropertyInfo property) { if (property.GetIndexParameters().Length > 0) { // we dont inspect indexers (they have "Item" name by default return(false); } var yuzuItem = Yuzu.Metadata.Meta.Get(type, Serialization.YuzuCommonOptions).Items.Find(i => i.PropInfo == property); var tang = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(type, property.Name); var tangIgnore = PropertyAttributes <TangerineIgnoreAttribute> .Get(type, property.Name); var tangInspect = PropertyAttributes <TangerineInspectAttribute> .Get(type, property.Name); if (tangInspect == null && (yuzuItem == null && tang == null || tangIgnore != null)) { return(false); } if (type.IsSubclassOf(typeof(Node))) { // Root must be always visible if (Document.Current.InspectRootNode && property.Name == nameof(Widget.Visible)) { return(false); } if (objects.Any(obj => obj is Node node && !string.IsNullOrEmpty(node.ContentsPath) && obj is IExternalScenePropertyOverrideChecker checker && !checker.IsPropertyOverridden(property) )) { return(false); } } return(true); }
private void PopulateContentForType(Type type, List <object> objects) { int row = 0; var categoryLabelAdded = false; var editorParams = new Dictionary <string, List <PropertyEditorParams> >(); foreach (var property in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) { if (property.Name == "Item") { // WTF, Bug in Mono? continue; } var yuzuField = PropertyAttributes <YuzuField> .Get(type, property.Name); var tang = PropertyAttributes <TangerineKeyframeColorAttribute> .Get(type, property.Name); var tangIgnore = PropertyAttributes <TangerineIgnoreAttribute> .Get(type, property.Name); var tangInspect = PropertyAttributes <TangerineInspectAttribute> .Get(type, property.Name); if (tangInspect == null && (yuzuField == null && tang == null || tangIgnore != null)) { continue; } if (!categoryLabelAdded) { categoryLabelAdded = true; var text = type.Name; if (text == "Node" && objects.Count == 1) { text += $" of type '{objects[0].GetType().Name}'"; } var label = new Widget { LayoutCell = new LayoutCell { StretchY = 0 }, Layout = new StackLayout(), MinHeight = Theme.Metrics.DefaultButtonSize.Y, Nodes = { new ThemedSimpleText { Text = text, Padding = new Thickness(4, 0), VAlignment = VAlignment.Center, ForceUncutText = false, } } }; label.CompoundPresenter.Add(new WidgetFlatFillPresenter(ColorTheme.Current.Inspector.CategoryLabelBackground)); widget.AddNode(label); } var context = new PropertyEditorParams(widget, objects, type, property.Name) { NumericEditBoxFactory = () => new TransactionalNumericEditBox(), PropertySetter = SetAnimableProperty, DefaultValueGetter = () => { var ctr = type.GetConstructor(new Type[] {}); if (ctr != null) { var obj = ctr.Invoke(null); var prop = type.GetProperty(property.Name); return(prop.GetValue(obj)); } return(null); } }; if (!editorParams.Keys.Contains(context.Group)) { editorParams.Add(context.Group, new List <PropertyEditorParams>()); } editorParams[context.Group].Add(context); } foreach (var header in editorParams.Keys.OrderBy((s) => s)) { AddGroupHeader(header); foreach (var param in editorParams[header]) { foreach (var i in InspectorPropertyRegistry.Instance.Items) { if (i.Condition(param)) { var propertyEditor = i.Builder(param); if (propertyEditor != null) { DecoratePropertyEditor(propertyEditor, row++); editors.Add(propertyEditor); var showCondition = PropertyAttributes <TangerineIgnoreIfAttribute> .Get(type, param.PropertyInfo.Name); if (showCondition != null) { propertyEditor.ContainerWidget.Updated += (delta) => { propertyEditor.ContainerWidget.Visible = !showCondition.Check(param.Objects[0]); }; } } break; } } } } }