Example #1
0
            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);
            }
Example #2
0
 public static void Perform(Node container, FolderItemLocation location, IFolderItem item)
 {
     if (item is Node && !NodeCompositionValidator.Validate(container.GetType(), item.GetType()))
     {
         throw new InvalidOperationException($"Can't put {item.GetType()} into {container.GetType()}");
     }
     DocumentHistory.Current.Perform(new InsertFolderItem(container, location, item));
 }
Example #3
0
        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);
        }
Example #4
0
        private void CreateContextMenu(List <string> files)
        {
            var menu = new Menu();

            foreach (var imageType in imageTypes)
            {
                if (NodeCompositionValidator.Validate(Document.Current.Container.GetType(), imageType))
                {
                    menu.Add(new Command($"Create {imageType.Name}",
                                         () => CreateImageTypeInstance(imageType, files)));
                }
            }
            menu.Add(new Command("Create sprite animated Image", () => CreateSpriteAnimatedImage(files)));
            menu.Popup();
        }
Example #5
0
        public override void ExecuteTransaction()
        {
            var nodes = Document.Current?.SelectedNodes().Editable().ToList();

            if (nodes.Count != 1)
            {
                AlertDialog.Show("Please, select a single node");
                return;
            }
            if (!(nodes[0] is Widget w && NodeCompositionValidator.CanHaveChildren(w.GetType())))
            {
                AlertDialog.Show($"Can't export {nodes[0].GetType()}");
                return;
            }
            Export(w);
        }
Example #6
0
 public static bool Perform(Node container, bool selectFirstNode = true)
 {
     if (!NodeCompositionValidator.CanHaveChildren(container.GetType()))
     {
         return(false);
     }
     if (!string.IsNullOrEmpty(container.ContentsPath) && Project.Current.DocumentExists(container.ContentsPath))
     {
         OpenExternalScene(container.ContentsPath);
     }
     else
     {
         ChangeContainer(container, selectFirstNode);
         SetProperty.Perform(container, nameof(Node.TangerineFlags), container.TangerineFlags | TangerineFlags.DisplayContent, isChangingDocument: false);
     }
     return(true);
 }
Example #7
0
        public static bool Perform(Node container, bool selectFirstNode = true)
        {
            if (!NodeCompositionValidator.CanHaveChildren(container.GetType()))
            {
                return(false);
            }
            if (!string.IsNullOrEmpty(container.ContentsPath))
            {
                OpenExternalScene(container.ContentsPath);
            }
            else
            {
                ChangeContainer(container, selectFirstNode);
            }
            container.SetTangerineFlag(TangerineFlags.DisplayContent, true);

            return(true);
        }
Example #8
0
 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}"
                       );
         }
     }
 }
Example #9
0
        public override void ExecuteTransaction()
        {
            var nodes = Document.Current?.SelectedNodes().Editable().ToList();

            if (nodes.Count != 1)
            {
                AlertDialog.Show("Please, select a single node");
                return;
            }
            if (!(nodes[0] is Widget w && NodeCompositionValidator.CanHaveChildren(w.GetType()) && Document.Current != null))
            {
                AlertDialog.Show($"Can't inline {nodes[0].GetType()}");
                return;
            }
            var node  = nodes[0];
            var clone = node.Clone();

            clone.ContentsPath = null;
            var location = Document.Current.Container.RootFolder().Find(node);

            UnlinkFolderItem.Perform(Document.Current.Container, node);
            InsertFolderItem.Perform(Document.Current.Container, location, clone);
        }
Example #10
0
        public RollNodeView(Row row)
        {
            this.row = row;
            nodeData = row.Components.Get <NodeRow>();
            label    = new ThemedSimpleText {
                ForceUncutText = false,
                VAlignment     = VAlignment.Center,
                OverflowMode   = TextOverflowMode.Ellipsis,
                LayoutCell     = new LayoutCell(Alignment.LeftCenter, float.MaxValue)
            };
            editBoxContainer = new Widget {
                Visible    = false,
                Layout     = new HBoxLayout(),
                LayoutCell = new LayoutCell(Alignment.LeftCenter, float.MaxValue),
            };
            nodeIcon = new Image(NodeIconPool.GetTexture(nodeData.Node.GetType()))
            {
                HitTestTarget = true,
                MinMaxSize    = new Vector2(21, 16),
                Padding       = new Thickness {
                    Left = 5
                }
            };
            expandButton = CreateExpandButton();
            var expandButtonContainer = new Widget {
                Layout = new StackLayout {
                    IgnoreHidden = false
                },
                LayoutCell = new LayoutCell(Alignment.Center, stretchX: 0),
                Nodes      = { expandButton }
            };

            expandButtonContainer.CompoundPresenter.Add(new SyncDelegatePresenter <Widget>(widget => {
                widget.PrepareRendererState();
                var a          = new Vector2(0, -4);
                var b          = widget.Size + new Vector2(0, 3);
                int colorIndex = nodeData.Node.EditorState().ColorIndex;
                Renderer.DrawRect(a, b, ColorMarks[colorIndex]);
                if (colorIndex != 0)
                {
                    Renderer.DrawRectOutline(a, b, ColorTheme.Current.TimelineRoll.Lines);
                }
            }));
            expandButtonContainer.Updating += delta => {
                bool visible = false;
                foreach (var a in nodeData.Node.Animators)
                {
                    if (!a.IsZombie && a.AnimationId == Document.Current.AnimationId)
                    {
                        visible = true;
                        break;
                    }
                }
                expandButton.Visible = visible;
            };
            enterButton         = NodeCompositionValidator.CanHaveChildren(nodeData.Node.GetType()) ? CreateEnterButton() : null;
            eyeButton           = CreateEyeButton();
            lockButton          = CreateLockButton();
            lockAnimationButton = CreateLockAnimationButton();
            widget = new Widget {
                HitTestTarget = true,
                Padding       = new Thickness {
                    Right = 2
                },
                MinHeight = TimelineMetrics.DefaultRowHeight,
                Layout    = new HBoxLayout {
                    DefaultCell = new DefaultLayoutCell(Alignment.Center)
                },
                Nodes =
                {
                    expandButtonContainer,
                    (indentSpacer = new Widget()),
                    nodeIcon,
                    Spacer.HSpacer(3),
                    label,
                    editBoxContainer,
                    linkIndicatorButtonContainer,
                    (Widget)enterButton ?? (Widget)Spacer.HSpacer(Theme.Metrics.DefaultToolbarButtonSize.X),
                    lockAnimationButton,
                    eyeButton,
                    lockButton,
                },
            };
            widget.Components.Add(new AwakeBehavior());
            label.AddChangeWatcher(() => nodeData.Node.Id, s => RefreshLabel());
            label.AddChangeWatcher(() => IsGrayedLabel(nodeData.Node), s => RefreshLabel());
            label.AddChangeWatcher(() => nodeData.Node.ContentsPath, s => RefreshLabel());
            widget.CompoundPresenter.Push(new SyncDelegatePresenter <Widget>(RenderBackground));
            nodeIdEditor        = new ObjectIdInplaceEditor(row, nodeData.Node, label, editBoxContainer);
            label.HitTestTarget = true;
            label.Gestures.Add(new DoubleClickGesture(() => {
                Document.Current.History.DoTransaction(() => {
                    if (NodeData.Node.EditorState().Locked)
                    {
                        return;
                    }
                    var labelExtent = label.MeasureUncutText();
                    if (label.LocalMousePosition().X < labelExtent.X)
                    {
                        nodeIdEditor.Rename();
                    }
                    else
                    {
                        EnterNode.Perform(nodeData.Node);
                    }
                });
            }));
            widget.Gestures.Add(new ClickGesture(1, ShowContextMenu));
        }
 static bool AllowChildren(PropertyEditorParams context)
 {
     return(context.Objects.All(o => NodeCompositionValidator.CanHaveChildren(o.GetType())));
 }
Example #12
0
        public RollNodeView(Row row)
        {
            this.row = row;
            nodeData = row.Components.Get <NodeRow>();
            label    = new ThemedSimpleText {
                ForceUncutText = false,
                VAlignment     = VAlignment.Center,
                LayoutCell     = new LayoutCell(Alignment.LeftCenter, float.MaxValue)
            };
            editBox = new ThemedEditBox {
                LayoutCell = new LayoutCell(Alignment.LeftCenter, float.MaxValue)
            };
            nodeIcon = new Image(NodeIconPool.GetTexture(nodeData.Node.GetType()))
            {
                HitTestTarget = true,
                MinMaxSize    = new Vector2(21, 16),
                Padding       = new Thickness {
                    Left = 5
                }
            };
            expandButton = CreateExpandButton();
            var expandButtonContainer = new Widget {
                Layout = new StackLayout {
                    IgnoreHidden = false
                },
                LayoutCell = new LayoutCell(Alignment.Center, stretchX: 0),
                Nodes      = { expandButton }
            };

            expandButtonContainer.CompoundPresenter.Add(new DelegatePresenter <Widget>(widget => {
                widget.PrepareRendererState();
                var a = new Vector2(0, -4);
                var b = widget.Size + new Vector2(0, 3);
                Renderer.DrawRect(a, b, nodeData.Node.GetColor());
                if (nodeData.Node.GetColorIndex() != 0)
                {
                    Renderer.DrawRectOutline(a, b, ColorTheme.Current.TimelineRoll.Lines);
                }
            }));
            expandButtonContainer.Updating += delta =>
                                              expandButton.Visible = nodeData.Node.Animators.Count > 0;
            enterButton         = NodeCompositionValidator.CanHaveChildren(nodeData.Node.GetType()) ? CreateEnterButton() : null;
            eyeButton           = CreateEyeButton();
            lockButton          = CreateLockButton();
            lockAnimationButton = CreateLockAnimationButton();
            widget = new Widget {
                Padding = new Thickness {
                    Right = 2
                },
                MinHeight = TimelineMetrics.DefaultRowHeight,
                Layout    = new HBoxLayout {
                    CellDefaults = new LayoutCell(Alignment.Center)
                },
                HitTestTarget = true,
                Nodes         =
                {
                    expandButtonContainer,
                    (indentSpacer = new Widget()),
                    nodeIcon,
                    new HSpacer(3),
                    label,
                    editBox,
                    new Widget(),
                    (Widget)enterButton ?? (Widget) new HSpacer(Theme.Metrics.DefaultToolbarButtonSize.X),
                    lockAnimationButton,
                    eyeButton,
                    lockButton,
                }
            };
            label.AddChangeWatcher(() => nodeData.Node.Id, s => RefreshLabel());
            label.AddChangeWatcher(() => IsGrayedLabel(nodeData.Node), s => RefreshLabel());
            label.AddChangeWatcher(() => nodeData.Node.ContentsPath, s => RefreshLabel());
            widget.CompoundPresenter.Push(new DelegatePresenter <Widget>(RenderBackground));
            editBox.Visible = false;
            widget.Gestures.Add(new ClickGesture(1, ShowPropertyContextMenu));
            widget.Gestures.Add(new DoubleClickGesture(() => {
                var labelExtent = label.MeasureUncutText();
                if (label.LocalMousePosition().X < labelExtent.X)
                {
                    Rename();
                }
                else
                {
                    Core.Operations.EnterNode.Perform(nodeData.Node);
                }
            }));
            nodeIcon.Gestures.Add(new DoubleClickGesture(() => {
                Core.Operations.ClearRowSelection.Perform();
                Core.Operations.SelectRow.Perform(row);
                Rename();
            }));
        }
Example #13
0
        private void Handle(IEnumerable <string> files)
        {
            Handling?.Invoke();
            using (Document.Current.History.BeginTransaction()) {
                pendingImages = new List <string>();
                foreach (var file in files)
                {
                    try {
                        string assetPath, assetType;
                        if (!Utils.ExtractAssetPathOrShowAlert(file, out assetPath, out assetType) ||
                            !Utils.AssertCurrentDocument(assetPath, assetType))
                        {
                            continue;
                        }

                        var nodeCreatingEventArgs = new NodeCreatingEventArgs(assetPath, assetType);
                        NodeCreating?.Invoke(nodeCreatingEventArgs);
                        if (nodeCreatingEventArgs.Cancel)
                        {
                            continue;
                        }

                        var fileName = Path.GetFileNameWithoutExtension(assetPath);
                        switch (assetType)
                        {
                        case ".png":
                            pendingImages.Add(assetPath);
                            break;

                        case ".ogg": {
                            var node   = CreateNode.Perform(typeof(Audio));
                            var sample = new SerializableSample(assetPath);
                            SetProperty.Perform(node, nameof(Audio.Sample), sample);
                            SetProperty.Perform(node, nameof(Node.Id), fileName);
                            SetProperty.Perform(node, nameof(Audio.Volume), 1);
                            var key = new Keyframe <AudioAction> {
                                Frame = Document.Current.AnimationFrame,
                                Value = AudioAction.Play
                            };
                            SetKeyframe.Perform(node, nameof(Audio.Action), Document.Current.AnimationId, key);
                            OnNodeCreated(node);
                            break;
                        }

                        case ".tan":
                        case ".model":
                        case ".scene":
                            DropSceneContextMenu.Create(assetPath, assetType, NodeCreated);
                            break;
                        }
                    } catch (System.Exception e) {
                        AlertDialog.Show(e.Message);
                    }
                }

                if (pendingImages.Count > 0)
                {
                    var menu = new Menu();
                    foreach (var kv in imageDropCommands.Commands)
                    {
                        if (NodeCompositionValidator.Validate(Document.Current.Container.GetType(), kv.Value))
                        {
                            menu.Add(kv.Key);
                        }
                    }
                    menu.Popup();
                }
                Document.Current.History.CommitTransaction();
            }
        }
Example #14
0
        public static bool PasteNodes(string data, RowLocation location, Vector2?mousePosition)
        {
            bool CanPaste()
            {
                // We are support only paste into folders for now.
                return(location.ParentRow.Components.Contains <FolderRow>() ||
                       location.ParentRow.Components.Contains <BoneRow>());
            }

            if (!CanPaste())
            {
                return(false);
            }
            Frame frame;

            try {
                var stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(data));
                frame = TangerinePersistence.Instance.ReadObject <Frame>(Document.Current.Path, stream);
            } catch (System.Exception e) {
                Debug.Write(e);
                return(false);
            }
            var animators = frame.Animators;
            var items     = frame.RootFolder().Items.Where(item => NodeCompositionValidator.IsCopyPasteAllowed(item.GetType())).ToList();

            if (items.Count == 0)
            {
                if (animators.Count != 0)
                {
                    foreach (var row in Document.Current.TopLevelSelectedRows().ToList())
                    {
                        if (!(row.Components.Get <NodeRow>()?.Node is IAnimationHost animable))
                        {
                            continue;
                        }
                        Document.Current.History.DoTransaction(() => {
                            foreach (var animator in animators)
                            {
                                if (animable.GetType().GetProperty(animator.TargetPropertyPath) == null)
                                {
                                    continue;
                                }
                                foreach (var keyframe in animator.Keys)
                                {
                                    SetKeyframe.Perform(animable, animator.TargetPropertyPath, animator.AnimationId, keyframe);
                                }
                            }
                        });
                    }
                }
                return(true);
            }
            var folderLocation = location.ParentRow.Rows.Count > 0 ?
                                 Row.GetFolderItemLocation(location.ParentRow.Rows[location.Index]) :
                                 new FolderItemLocation {
                Index = 0, Folder = location.ParentRow.Components.Get <FolderRow>().Folder
            };

            if (!folderLocation.Folder.Expanded)
            {
                SetProperty.Perform(folderLocation.Folder, nameof(Folder.Expanded), true);
            }
            mousePosition *= Document.Current.Container.AsWidget?.LocalToWorldTransform.CalcInversed();
            var shift = mousePosition - items.OfType <Widget>().FirstOrDefault()?.Position;

            foreach (var n in items.OfType <Node>())
            {
                Document.Current.Decorate(n);
            }
            if (shift.HasValue)
            {
                foreach (var w in items.OfType <Widget>())
                {
                    w.Position += shift.Value;
                }
            }
            frame.RootFolder().Items.Clear();
            frame.RootFolder().SyncDescriptorsAndNodes(frame);
            ClearRowSelection.Perform();
            while (items.Count > 0)
            {
                var item = items.First();
                if (item is Bone bone)
                {
                    if (bone.BaseIndex != 0)
                    {
                        continue;
                    }
                    var newIndex = 1;
                    var bones    = Document.Current.Container.Nodes.OfType <Bone>();
                    if (bones.Any())
                    {
                        newIndex = bones.Max(b => b.Index) + 1;
                    }
                    var children = BoneUtils.FindBoneDescendats(bone, items.OfType <Bone>()).ToList();
                    var map      = new Dictionary <int, int> {
                        { bone.Index, newIndex }
                    };
                    bone.BaseIndex = location.ParentRow.Components.Get <BoneRow>()?.Bone.Index ?? 0;
                    bone.Index     = newIndex;
                    InsertFolderItem.Perform(
                        Document.Current.Container,
                        folderLocation, bone);
                    folderLocation.Index++;
                    foreach (var b in children)
                    {
                        b.BaseIndex = map[b.BaseIndex];
                        map.Add(b.Index, b.Index = ++newIndex);
                        InsertFolderItem.Perform(
                            Document.Current.Container,
                            folderLocation, b);
                        folderLocation.Index++;
                        items.Remove(b);
                    }
                    Document.Current.Container.RootFolder().SyncDescriptorsAndNodes(Document.Current.Container);
                    SortBonesInChain.Perform(bone);
                    SelectRow.Perform(Document.Current.GetRowForObject(item));
                }
                else
                {
                    if (!location.ParentRow.Components.Contains <BoneRow>())
                    {
                        InsertFolderItem.Perform(
                            Document.Current.Container,
                            folderLocation, item);
                        folderLocation.Index++;
                        SelectRow.Perform(Document.Current.GetRowForObject(item));
                    }
                }
                items.Remove(item);
            }
            return(true);
        }