private static void BuildList(ObservableCollection <Lime.NodeComponent> source, Widget container) { var list = new Widget { Layout = new VBoxLayout { Spacing = 5 }, Padding = new Thickness { Top = AttachmentMetrics.Spacing }, }; container.AddNode(list); var validComponents = Project.Current.RegisteredComponentTypes .Where(t => NodeCompositionValidator.ValidateComponentType(typeof(Node3D), t)).ToList(); var widgetFactory = new AttachmentWidgetFactory <NodeComponent>(w => new NodeComponentRow(w, source), source); var footer = DeletableRow <NodeComponentRow> .CreateFooter(() => { var menu = new Menu(); foreach (var type in validComponents.Except(GetExceptedTypes(source))) { ICommand command = new Command(CamelCaseToLabel(type.Name), () => { var constructor = type.GetConstructor(Type.EmptyTypes); history.DoTransaction(() => Core.Operations.InsertIntoList.Perform( source, source.Count, constructor.Invoke(new object[] { }))); }); menu.Add(command); } menu.Popup(); }); footer.AddChangeWatcher(() => validComponents.Except(GetExceptedTypes(source)).Any(), any => footer.Visible = any); widgetFactory.AddFooter(footer); list.Components.Add(widgetFactory); }
private void AddComponentsMenu(IReadOnlyList <Node> nodes, Widget widget) { if (nodes.Any(n => !string.IsNullOrEmpty(n.ContentsPath))) { return; } var nodesTypes = nodes.Select(n => n.GetType()).ToList(); var types = new List <Type>(); foreach (var type in Project.Current.RegisteredComponentTypes) { if ( !nodes.All(n => n.Components.Contains(type)) && nodesTypes.All(t => NodeCompositionValidator.ValidateComponentType(t, type)) ) { types.Add(type); } } types.Sort((a, b) => a.Name.CompareTo(b.Name)); var label = new Widget { LayoutCell = new LayoutCell { StretchY = 0 }, Layout = new HBoxLayout(), MinHeight = Theme.Metrics.DefaultButtonSize.Y, Nodes = { new ThemedAddButton { Clicked = () => { var menu = new Menu(); foreach (var type in types) { ICommand command = new Command(CamelCaseToLabel(type.Name), () => CreateComponent(type, nodes)); menu.Add(command); } menu.Popup(); }, Enabled = types.Count > 0 }, new ThemedSimpleText { Text = "Add Component", Padding = new Thickness(4, 0), VAlignment = VAlignment.Center, ForceUncutText = false, } } }; label.CompoundPresenter.Add(new WidgetFlatFillPresenter(ColorTheme.Current.Inspector.CategoryLabelBackground)); widget.AddNode(label); }
private static void Validate(Node source, Type destType, Type commonParent) { foreach (var child in source.Nodes) { if (!NodeCompositionValidator.Validate(destType, child.GetType())) { throw new InvalidOperationException( $"Node {source} has child {child} that will be incompatible with {destType}" ); } } foreach (var component in source.Components) { if (!NodeCompositionValidator.ValidateComponentType(destType, component.GetType())) { throw new InvalidOperationException( $"Node {source} has component {component} that will be incompatible with {destType}" ); } } if (!(source.GetType().IsSubclassOf(commonParent) && destType.IsSubclassOf(commonParent))) { throw new InvalidOperationException( $"Node {source} type or/and destination {destType} type are not subclasses of {commonParent}" ); } foreach (var animator in source.Animators) { var prop = destType.GetProperty(animator.TargetPropertyPath); if ( prop == null || prop.PropertyType != source.GetType().GetProperty(animator.TargetPropertyPath).PropertyType ) { throw new InvalidOperationException( $"Node {source} has animator on property {animator.TargetPropertyPath}, which doesn't exist in {destType}" ); } } }