public void SelectComponent(ParameterStructure.Component.Component _comp)
        {
            if (_comp == null)
            {
                return;
            }

            // deselect all
            this.DeselectAllNodes();

            // starts w top-level parent and ends with _comp
            List <ParameterStructure.Component.Component> parent_chain = this.CompFactory.GetParentComponentChain(_comp);
            List <long> parent_id_chain = parent_chain.Select(x => x.ID).ToList();

            if (parent_id_chain.Count < 1)
            {
                return;
            }

            foreach (object child in this.Children)
            {
                ComponentVisualization cv = child as ComponentVisualization;
                if (cv == null)
                {
                    continue;
                }

                if (cv.VisID == parent_id_chain[0])
                {
                    cv.SelectChild(parent_id_chain);
                    break;
                }
            }
        }
        protected void cv_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            ComponentVisualization cv = sender as ComponentVisualization;

            if (cv == null || e == null)
            {
                return;
            }

            if (!cv.VisState.HasFlag(NodeVisHighlight.Manipulated))
            {
                return;
            }
            if (!cv.IsUserManipulatable)
            {
                return;
            }

            Point  mPos   = e.GetPosition(this);
            Vector offset = mPos - cv.Anchor;

            cv.Translate(offset);
            cv.TranslateConnectionsIn(offset);
            cv.TranslateRefConnections(offset);
        }
        private void ReorderNodes()
        {
            if (this.nodes_to_order != null && this.nodes_to_order.Count == this.nodes_to_order_NR)
            {
                // debug
                string debug = string.Empty;

                // perform the reordering
                this.nodes_to_order.Reverse();
                foreach (NodeVisualization nv in this.nodes_to_order)
                {
                    ComponentVisualization cv = nv as ComponentVisualization;
                    if (cv == null)
                    {
                        continue;
                    }
                    if (cv.Node_Children.Where(x => x is ComponentVisualization).Count() == 0)
                    {
                        continue;
                    }

                    //debug += cv.node_component.CurrentSlot + ": " + cv.node_component.Name + " " + cv.node_component.Description + "\n";

                    cv.RepositionChildren();
                }

                // reset
                this.nodes_to_order_NR    = 0;
                this.nodes_to_order       = null;
                this.node_order_list_full = false;
            }
        }
        internal void DeselectNode(ComponentVisualization _cv)
        {
            if (_cv == null || this.CompFactory == null)
            {
                return;
            }

            _cv.VisState &= ~NodeVisHighlight.Selected;
            this.CompFactory.SelectComponent(null);
        }
        protected void cv_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ComponentVisualization cv = sender as ComponentVisualization;

            if (cv == null || e == null)
            {
                return;
            }

            cv.VisState |= NodeVisHighlight.Manipulated;
            cv.Anchor    = e.GetPosition(this);
        }
        protected void GraphCanvas_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            foreach (var child in this.Children)
            {
                ComponentVisualization cv = child as ComponentVisualization;
                if (cv == null)
                {
                    continue;
                }

                cv.VisState &= ~NodeVisHighlight.Manipulated;
            }
        }
        protected void DeselectAllNodes()
        {
            foreach (object child in this.Children)
            {
                ComponentVisualization cv = child as ComponentVisualization;
                if (cv == null)
                {
                    continue;
                }

                cv.VisState &= ~NodeVisHighlight.Selected;
            }
        }
        protected void cv_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ComponentVisualization cv = sender as ComponentVisualization;

            if (cv == null || e == null)
            {
                return;
            }

            cv.VisState &= ~NodeVisHighlight.Manipulated;

            // announce change in child extents to parent
            Vector offset_total = cv.Extents.ParentTranslation;

            cv.Extents.ParentTranslation = offset_total;
        }
        private void compFactory_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            ComponentFactory cf = sender as ComponentFactory;

            if (cf == null || e == null)
            {
                return;
            }

            if (e.PropertyName == "MarkedId")
            {
                if (cf.MarkedId > 0)
                {
                    if (!cf.MarkedTrue)
                    {
                        // remove node from the graph
                        foreach (object child in this.Children)
                        {
                            ComponentVisualization cv = child as ComponentVisualization;
                            if (cv == null)
                            {
                                continue;
                            }
                            if (cv.VisID == cf.MarkedId)
                            {
                                cv.RemoveAllGraphics();
                                this.Children.Remove(cv);
                                break;
                            }
                        }
                    }
                    else
                    {
                        ParameterStructure.Component.Component c_to_add = this.CompFactory.ComponentRecord.Find(x => x.ID == cf.MarkedId);
                        if (c_to_add != null)
                        {
                            // expand graph
                            this.canvas_expand = new Vector(NodeVisualization.NODE_WIDTH_DEFAULT, NodeVisualization.NODE_COMP_HEIGHT * 1.5);
                            this.AdaptSize2Content();
                            // add node to the graph
                            ComponentVisualization cv = new ComponentVisualization(this, c_to_add, 3, this.Height - NodeVisualization.NODE_COMP_HEIGHT);
                        }
                    }
                }
            }
        }
        protected void ExpandAll()
        {
            if (!this.IsUserManipulatable)
            {
                return;
            }

            if (!this.IsExpanded)
            {
                this.IsExpanded = true;
            }

            ParameterStructure.Component.Component comp = this.node_data as ParameterStructure.Component.Component;
            if (this.parent_canvas != null && comp != null)
            {
                // tell the parent canvas how many nodes need to be reordered
                if (this.parent_canvas.nodes_to_order_NR == 0)
                {
                    this.parent_canvas.nodes_to_order_NR = comp.GetFlatSubCompList().Count + 1;
                    // add to the nodes the parent canvas needs to reorder
                    if (this.parent_canvas.nodes_to_order == null)
                    {
                        this.parent_canvas.nodes_to_order = new List <NodeVisualization>();
                    }
                    this.parent_canvas.nodes_to_order.Add(this);
                }
            }

            foreach (NodeVisualization nv in this.node_children)
            {
                ComponentVisualization cv = nv as ComponentVisualization;
                if (cv == null)
                {
                    continue;
                }

                cv.to_be_expanded = true;
                // the logic is completed and called recursively in the Loaded event handler
                // because expansion can only be completed after the respective node has been loaded
            }
        }
        protected void PopulateCanvas()
        {
            CalculatePositions();

            int counter = 0;

            foreach (ParameterStructure.Component.Component c in this.CompFactory.ComponentRecord)
            {
                if (c == null)
                {
                    continue;
                }
                if (c.IsMarkable && !c.IsMarked)
                {
                    continue;
                }
                counter++;

                ComponentVisualization cv = new ComponentVisualization(this, c, 3, counter * this.node_dist_vert + (counter - 1) * this.node_height);
            }
        }
        public void Highlight(List <ComponentManagerType> _mans, bool _or = true)
        {
            // reset
            this.UnHighlight();
            List <ComponentVisualization> to_highlight = new List <ComponentVisualization>();

            // gather information
            foreach (object child in this.Children)
            {
                ComponentVisualization cv = child as ComponentVisualization;
                if (cv == null)
                {
                    continue;
                }

                bool take = !_or;
                foreach (ComponentManagerType man in _mans)
                {
                    if (_or)
                    {
                        take |= cv.CompManagerHasWritingAccess(man);
                    }
                    else
                    {
                        take &= cv.CompManagerHasWritingAccess(man);
                    }
                }

                if (take)
                {
                    to_highlight.Add(cv);
                }
            }

            // perform highlighting
            foreach (ComponentVisualization cv in to_highlight)
            {
                cv.VisState |= NodeVisHighlight.Highlighted;
            }
        }
        // to use after adding new children to the canvas
        internal void AdaptSize2Content()
        {
            if (this.canvas_expand.X == 0 && this.canvas_expand.Y == 0)
            {
                return;
            }
            this.Width        += this.canvas_expand.X;
            this.Height       += this.canvas_expand.Y;
            this.canvas_expand = new Vector(0, 0);
            this.UpdateSizeLabel();
            this.UpdateTicks();

            if (this.content_offset.X == 0 && this.content_offset.Y == 0)
            {
                return;
            }
            foreach (ParameterStructure.Component.Component c in this.CompFactory.ComponentRecord)
            {
                foreach (object child in this.Children)
                {
                    ComponentVisualization cv = child as ComponentVisualization;
                    if (cv == null)
                    {
                        continue;
                    }

                    if (cv.VisID == c.ID)
                    {
                        cv.Translate(this.content_offset);
                        cv.TranslateConnectionsIn(this.content_offset);
                        cv.TranslateRefConnections(this.content_offset);
                    }
                }
            }

            this.content_offset = new Vector(0, 0);
        }
        // the id_chain starts with the parent on a higher hierarchy level and ends with the child to be selected
        internal void SelectChild(List <long> _id_chain)
        {
            if (_id_chain == null)
            {
                return;
            }
            if (_id_chain.Count < 1)
            {
                return;
            }

            long current_id = _id_chain[0];

            if (this.VisID != current_id)
            {
                return;
            }

            long target_id = _id_chain[_id_chain.Count - 1];

            if (!this.IsUserManipulatable)
            {
                this.IsUserManipulatable = true;
            }

            // recursion end
            if (this.VisID == target_id)
            {
                this.to_be_expanded_chain = null;
                this.VisState            |= NodeVisHighlight.Selected;
                this.BringIntoView();
                return;
            }

            // go deeper
            List <long> id_chain_rest = new List <long>(_id_chain);

            id_chain_rest.Remove(current_id);
            if (id_chain_rest.Count < 1)
            {
                return;
            }

            if (this.IsExpanded)
            {
                foreach (NodeVisualization nv in this.node_children)
                {
                    ComponentVisualization cv = nv as ComponentVisualization;
                    if (cv == null)
                    {
                        continue;
                    }
                    cv.SelectChild(id_chain_rest);
                }
            }
            else
            {
                this.IsExpanded = true;
                foreach (NodeVisualization nv in this.node_children)
                {
                    ComponentVisualization cv = nv as ComponentVisualization;
                    if (cv == null)
                    {
                        continue;
                    }

                    if (cv.VisID == id_chain_rest[0])
                    {
                        cv.to_be_expanded_chain = id_chain_rest;
                    }
                    // the logic is completed and called recursively in the Loaded event handler
                    // because expansion/selection can only be completed after the respective node has been loaded
                }
            }
        }