コード例 #1
0
        public static List <Layer.Group> findItemsToUngroup(List <Layer.LayerItem> itemsToUngroup)
        {
            // create a search list that we will expend and to keep the original selection intact
            List <Layer.LayerItem> searchList = new List <Layer.LayerItem>(itemsToUngroup);
            List <Layer.Group>     result     = new List <Layer.Group>(itemsToUngroup.Count);

            // Search the top group of the tree, because this action only ungroup the top of the tree
            // The list of items to ungroup can also be a forest, so keep all the top of the trees
            for (int i = 0; i < searchList.Count; ++i)
            {
                Layer.LayerItem item = searchList[i];
                // check if this item as a father group or is single (top item)
                if (item.Group == null)
                {
                    // check if this item is a group that can be ungrouped or a simple item by casting it
                    Layer.Group group = item as Layer.Group;
                    // if it is a group that can be ungrouped and not already in the list, add it to the list
                    if ((group != null) && group.CanUngroup && !result.Contains(group))
                    {
                        result.Add(group);
                    }
                }
                else if (!searchList.Contains(item.Group))
                {
                    // add it to the search list even if this father group is cannot be ungroup because a grand father
                    // could be ungroupable above, so we need to do the exhaustive forest search
                    searchList.Add(item.Group);
                }
            }

            return(result);
        }
コード例 #2
0
ファイル: ReplaceBrick.cs プロジェクト: Shevonar/BlueBrick
        private void replaceOneItem(LayerBrick layer, Layer.LayerItem itemToRemove, Layer.LayerItem itemToAdd)
        {
            // memorise the brick index order and the group of the old brick
            int oldItemIndex = -1;

            Layer.Group oldItemGroup = itemToRemove.Group;

            // first remove the item from its group, in case it belongs to a group
            // (so that later if someone ask all item of this group, it won't get this limbo item)
            if (itemToRemove.Group != null)
            {
                itemToRemove.Group.removeItem(itemToRemove);
            }

            // check if the item to remove is a group or a simple brick
            if (itemToRemove.IsAGroup)
            {
                List <Layer.LayerItem> bricksToRemove = (itemToRemove as Layer.Group).getAllLeafItems();
                foreach (Layer.LayerItem item in bricksToRemove)
                {
                    oldItemIndex = layer.removeBrick(item as LayerBrick.Brick);
                }
                // we alsways take the last index to be sure we don't keep an index bigger than the brick list
                // after removing all the parts of the group
            }
            else
            {
                oldItemIndex = layer.removeBrick(itemToRemove as LayerBrick.Brick);
            }

            // check if the item to add is a group or a simple brick
            if (itemToAdd.IsAGroup)
            {
                List <Layer.LayerItem> bricksToAdd = (itemToAdd as Layer.Group).getAllLeafItems();
                // since we will add all the brick at the same index, iterating in the normal order
                // the insertion order will be reversed. So we reverse the list to make the insertion in correct order
                bricksToAdd.Reverse();
                foreach (Layer.LayerItem item in bricksToAdd)
                {
                    layer.addBrick(item as LayerBrick.Brick, oldItemIndex);
                }
            }
            else
            {
                layer.addBrick(itemToAdd as LayerBrick.Brick, oldItemIndex);
            }

            // then once the item has been added to the layer, add it also to the group if the old item had a group
            if (oldItemGroup != null)
            {
                oldItemGroup.addItem(itemToAdd);
            }

            // notify the part list view (after actually adding and deleting the bricks because the total map size need to be recomputed)
            MainForm.Instance.NotifyPartListForBrickRemoved(layer, itemToRemove, false);
            MainForm.Instance.NotifyPartListForBrickAdded(layer, itemToAdd, false);
        }
コード例 #3
0
        private int mNextPreferedActiveConnectionIndex = 0; // the prefered active connection index according to the brick library

        #endregion Fields

        #region Constructors

        public AddConnectGroup(LayerBrick layer, string partNumber, int wantedConnexion)
        {
            // save the layer and construct the group
            mBrickLayer = layer;
            mGroup = new Layer.Group(partNumber);
            LayerBrick.Brick selectedBrick = layer.getConnectableBrick();

            // get the flat list of bricks from the hierarchical group
            mBricksInTheGroup = mGroup.getAllLeafItems();

            // check if we can attach the group to the unique selected object
            if (selectedBrick != null)
            {
                // find the brick of the group that will be connected to the selected brick
                LayerBrick.Brick brickToConnect = null;
                if (selectedBrick.HasConnectionPoint)
                    brickToConnect = findBrickToConnectAdnSetBestConnectionPointIndex(selectedBrick, ref wantedConnexion);

                // check if the selected brick has connection point
                if (brickToConnect != null && brickToConnect.HasConnectionPoint)
                {
                    // after setting the active connection point index from which this brick will be attached,
                    // get the prefered index from the library
                    mNextPreferedActiveConnectionIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(partNumber, wantedConnexion);

                    // Compute the orientation of the bricks
                    float newOrientation = AddConnectBrick.sGetOrientationOfConnectedBrick(selectedBrick, brickToConnect);
                    newOrientation -= brickToConnect.Orientation;
                    // Rotate all the bricks of the group first before translating
                    RotateBrickOnPivotBrick rotateBricksAction = new RotateBrickOnPivotBrick(layer, mBricksInTheGroup, newOrientation, brickToConnect);
                    rotateBricksAction.MustUpdateBrickConnectivity = false;
                    rotateBricksAction.redo();

                    // compute the translation to add to all the bricks
                    PointF translation = new PointF(selectedBrick.ActiveConnectionPosition.X - brickToConnect.ActiveConnectionPosition.X,
                                                    selectedBrick.ActiveConnectionPosition.Y - brickToConnect.ActiveConnectionPosition.Y);
                    mGroup.translate(translation);
                }
                else
                {
                    PointF position = selectedBrick.Position;
                    position.X += selectedBrick.DisplayArea.Width;
                    mGroup.Position = position;
                }

                // set the index of the brick in the list just after the selected brick
                mInsertIndex = layer.BrickList.IndexOf(selectedBrick) + 1;
            }
        }
コード例 #4
0
ファイル: ReplaceBrick.cs プロジェクト: Shevonar/BlueBrick
        private Layer.LayerItem createReplacementBrick(Layer.LayerItem brick, string newPartNumber)
        {
            // compute the altitude of the brick we want to replace
            float altitude = 0.0f;

            if (brick.IsAGroup)
            {
                // get the average altitude of all the children
                List <Layer.LayerItem> children = (brick as Layer.Group).getAllLeafItems();
                if (children.Count > 0)
                {
                    foreach (Layer.LayerItem child in children)
                    {
                        altitude += (child as LayerBrick.Brick).Altitude;
                    }
                    altitude /= children.Count;
                }
            }
            else
            {
                altitude = (brick as LayerBrick.Brick).Altitude;
            }

            // create a new brick and copy all the parameters of the old one
            Layer.LayerItem newBrick = null;
            if (BrickLibrary.Instance.isAGroup(newPartNumber))
            {
                newBrick = new Layer.Group(newPartNumber);
                // set the altitude to all children
                List <Layer.LayerItem> children = (newBrick as Layer.Group).getAllLeafItems();
                foreach (Layer.LayerItem child in children)
                {
                    (child as LayerBrick.Brick).Altitude = altitude;
                }
            }
            else
            {
                newBrick = new LayerBrick.Brick(newPartNumber);
                (newBrick as LayerBrick.Brick).Altitude = altitude;
            }
            newBrick.Orientation = brick.Orientation;
            newBrick.Center      = brick.Center;
            // return the new brick
            return(newBrick);
        }
コード例 #5
0
        /// <summary>
        /// Call this method when you want to notify the budget counter that a new brick has been added
        /// </summary>
        /// <param name="layer">The layer on which the brick is added</param>
        /// <param name="brick">the brick that was added</param>
        /// <param name="isDueToRegroup">tells if the brick is a group that was regrouped by an undo</param>
        public void addBrickNotification(LayerBrick layer, Layer.LayerItem brickOrGroup, bool isDueToRegroup)
        {
            string partID = brickOrGroup.PartNumber;

            if (partID != string.Empty)
            {
                // get the current count in the count dictionary
                int currentCount = 0;
                mCount.TryGetValue(partID, out currentCount);
                // and update the value in the global dictionnary
                mCount.Remove(partID);
                mCount.Add(partID, currentCount + 1);

                // also update in the layered dictionary
                Dictionary <string, int> layeredCount = null;
                if (mCountPerLayer.TryGetValue(layer, out layeredCount))
                {
                    int currentCountInLayer = 0;
                    layeredCount.TryGetValue(partID, out currentCountInLayer);
                    layeredCount.Remove(partID);
                    layeredCount.Add(partID, currentCountInLayer + 1);
                }
                else
                {
                    // this is a new layer (this layer didn't exist before), so add the layer and also the count
                    layeredCount = new Dictionary <string, int>();
                    layeredCount.Add(partID, 1);
                    mCountPerLayer.Add(layer, layeredCount);
                }
            }
            // add also all the named children if the brick is a group
            // (unless it is a regroup in that case the children are already counted)
            if (!isDueToRegroup)
            {
                Layer.Group group = brickOrGroup as Layer.Group;
                if (group != null)
                {
                    foreach (Layer.LayerItem item in group.Items)
                    {
                        addBrickNotification(layer, item, isDueToRegroup);
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Call this method when you want to notify the budget counter that a brick has been removed
        /// </summary>
        /// <param name="layer">The layer on which the brick is removed</param>
        /// <param name="brick">the brick that was removed</param>
        /// <param name="isDueToUngroup">tell if the brick is a group that is ungrouped</param>
        public void removeBrickNotification(LayerBrick layer, Layer.LayerItem brickOrGroup, bool isDueToUngroup)
        {
            string partID = brickOrGroup.PartNumber;

            if (partID != string.Empty)
            {
                // get the current count
                int currentCount = 0;
                mCount.TryGetValue(partID, out currentCount);
                if (currentCount > 0)
                {
                    // update the value
                    mCount.Remove(partID);
                    mCount.Add(partID, currentCount - 1);
                }

                // also update in the layered dictionary
                Dictionary <string, int> layeredCount = null;
                if (mCountPerLayer.TryGetValue(layer, out layeredCount))
                {
                    int currentCountInLayer = 0;
                    layeredCount.TryGetValue(partID, out currentCountInLayer);
                    if (currentCountInLayer > 0)
                    {
                        layeredCount.Remove(partID);
                        layeredCount.Add(partID, currentCountInLayer - 1);
                    }
                }
                // if the layer doesn't exist, we have nothing to remove
            }
            // remove also all the named children if the brick is a group
            // (unless it is a ungroup in that case we leave the children and just remove the one we ungrouped)
            if (!isDueToUngroup)
            {
                Layer.Group group = brickOrGroup as Layer.Group;
                if (group != null)
                {
                    foreach (Layer.LayerItem item in group.Items)
                    {
                        removeBrickNotification(layer, item, isDueToUngroup);
                    }
                }
            }
        }
コード例 #7
0
 /// <summary>
 /// This method check that the specified partNumber is not used inside the hierrachy of the group
 /// in order to avoid saving a group with cyclic reference (that will generate an error at loading).
 /// This is a recursive function on the specified group
 /// </summary>
 /// <param name="partNumber">the name of the group the user wants to use to save his group</param>
 /// <returns>true if some cyclic reference is detected</returns>
 private bool isCyclicReferenceDetected(Layer.Group group, string partNumber)
 {
     foreach (Layer.LayerItem item in group.Items)
     {
         // if we find a match, return true immediatly
         if (item.PartNumber.Equals(partNumber))
         {
             return(true);
         }
         // if it's a group, call recursively
         if (item.IsAGroup)
         {
             bool isCyclic = isCyclicReferenceDetected(item as Layer.Group, partNumber);
             // only return true if we found a match, if false continue to iterate on next item
             if (isCyclic)
             {
                 return(true);
             }
         }
     }
     // nothing detected, return false
     return(false);
 }
コード例 #8
0
        /// <summary>
        /// This tool method clones all the item of the specified list into a new list.
        /// This method also clone the groups that may belong to this list of bricks.
        /// The cloned items are in the same order as the original list
        /// </summary>
        /// <param name="listToClone">The original list of brick to copy</param>
        /// <param name="addGroupsInItemList">if this parameter is true, the groups are also added in the Items list</param>
        /// <returns>A clone list of cloned brick with there cloned groups</returns>
        protected List <Layer.LayerItem> cloneItemList(List <Layer.LayerItem> listToClone, bool addGroupsInItemList)
        {
            // the resulting list
            List <Layer.LayerItem> result = new List <Layer.LayerItem>(listToClone.Count);

            // use a dictionnary to recreate the groups that may be inside the list of brick to duplicate
            // this dictionnary makes an association between the group to duplicate and the new duplicated one
            Dictionary <Layer.Group, Layer.Group> groupsToCreate = new Dictionary <Layer.Group, Layer.Group>();
            // also use a list of item that we will make grow to create all the groups
            List <Layer.LayerItem> fullOriginalItemList = new List <Layer.LayerItem>(listToClone);

            // use a for instead of a foreach because the list will grow
            for (int i = 0; i < fullOriginalItemList.Count; ++i)
            {
                // get the current item
                Layer.LayerItem originalItem   = fullOriginalItemList[i];
                Layer.LayerItem duplicatedItem = null;

                // check if the item is a group or a brick
                if (originalItem.IsAGroup)
                {
                    // if the item is a group that means the list already grown, and that means we also have it in the dictionnary
                    Layer.Group associatedGroup = null;
                    groupsToCreate.TryGetValue(originalItem as Layer.Group, out associatedGroup);
                    duplicatedItem = associatedGroup;
                    // check if we also need to add the group
                    if (addGroupsInItemList)
                    {
                        result.Add(duplicatedItem);
                    }
                }
                else
                {
                    // if the item is a brick, just clone it and add it to the result
                    // clone the item (because the same list of text to add can be paste several times)
                    duplicatedItem = originalItem.Clone();
                    // add the duplicated item in the list
                    result.Add(duplicatedItem);
                }

                // check if the item to clone belongs to a group then also duplicate the group
                if (originalItem.Group != null)
                {
                    // get the duplicated group if already created otherwise create it and add it in the dictionary
                    Layer.Group duplicatedGroup = null;
                    groupsToCreate.TryGetValue(originalItem.Group, out duplicatedGroup);
                    if (duplicatedGroup == null)
                    {
                        duplicatedGroup = new Layer.Group(originalItem.Group);
                        groupsToCreate.Add(originalItem.Group, duplicatedGroup);
                        fullOriginalItemList.Add(originalItem.Group);
                    }
                    // assign the group to the brick
                    duplicatedGroup.addItem(duplicatedItem);
                    // check if we need to also assign the brick that hold the connection point
                    if (originalItem.Group.BrickThatHoldsActiveConnection == originalItem)
                    {
                        duplicatedGroup.BrickThatHoldsActiveConnection = (duplicatedItem as LayerBrick.Brick);
                    }
                }
            }

            // delete the dictionary
            groupsToCreate.Clear();
            fullOriginalItemList.Clear();
            // return the cloned list
            return(result);
        }
コード例 #9
0
ファイル: RotateItems.cs プロジェクト: Shevonar/BlueBrick
        protected PointF mCenter      = new PointF(0, 0); // in Stud coord

        /// <summary>
        /// A common method that can be called by the constructor to initialize many stuff
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="originalItems"></param>
        /// <param name="angle"></param>
        /// <param name="forceKeepLastCenter"></param>
        protected virtual void commonConstructor(Layer layer, List <Layer.LayerItem> originalItems, float angle, bool forceKeepLastCenter)
        {
            mLayer        = layer;
            mRotateCW     = (angle < 0.0f);
            mRotationStep = Math.Abs(angle);

            // we must invalidate the last center if the last action in the undo stack is not a rotation
            if (!forceKeepLastCenter && !ActionManager.Instance.getUndoableActionType().IsInstanceOfType(this))
            {
                sLastCenterIsValid = false;
            }

            // fill the brick list with the one provided and set the center of rotation for this action
            if (originalItems.Count > 0)
            {
                // copy the list, because the pointer may change (specially if it is the selection)
                // also compute the center of all the bricks
                PointF minCenter = new PointF(originalItems[0].DisplayArea.Left, originalItems[0].DisplayArea.Top);
                PointF maxCenter = new PointF(originalItems[0].DisplayArea.Right, originalItems[0].DisplayArea.Bottom);
                mItems = new List <Layer.LayerItem>(originalItems.Count);
                mNamedGroupsOfTheItems = new List <Layer.Group>(originalItems.Count);
                mTopGroupsOfTheItems   = new List <Layer.Group>(originalItems.Count);
                foreach (Layer.LayerItem obj in originalItems)
                {
                    mItems.Add(obj);
                    //compute the new center if the static one is not valid
                    if (!sLastCenterIsValid)
                    {
                        if (obj.DisplayArea.Left < minCenter.X)
                        {
                            minCenter.X = obj.DisplayArea.Left;
                        }
                        if (obj.DisplayArea.Top < minCenter.Y)
                        {
                            minCenter.Y = obj.DisplayArea.Top;
                        }
                        if (obj.DisplayArea.Right > maxCenter.X)
                        {
                            maxCenter.X = obj.DisplayArea.Right;
                        }
                        if (obj.DisplayArea.Bottom > maxCenter.Y)
                        {
                            maxCenter.Y = obj.DisplayArea.Bottom;
                        }
                    }

                    // Also collect the groups amongs all the items
                    Layer.Group parentGroup = obj.Group;
                    if (parentGroup != null)
                    {
                        // we found a group, add it to the list if it is a named group and if it is not already in
                        if (parentGroup.IsANamedGroup && !mNamedGroupsOfTheItems.Contains(parentGroup))
                        {
                            mNamedGroupsOfTheItems.Add(parentGroup);
                        }

                        // also if that group doesn't have a parent group, this is a top group, so add it to the top group list if not already in
                        if ((parentGroup.Group == null) && !mTopGroupsOfTheItems.Contains(parentGroup))
                        {
                            mTopGroupsOfTheItems.Add(parentGroup);
                        }
                    }
                }
                // set the center for this rotation action (keep the previous one or compute a new one
                if (sLastCenterIsValid)
                {
                    mCenter = sLastCenter;
                }
                else
                {
                    // recompute a new center
                    mCenter.X = (maxCenter.X + minCenter.X) * 0.5f;
                    mCenter.Y = (maxCenter.Y + minCenter.Y) * 0.5f;
                    // and assign it to the static one
                    sLastCenter        = mCenter;
                    sLastCenterIsValid = true;
                }
            }
        }
コード例 #10
0
        public SaveGroupNameForm()
        {
            InitializeComponent();

            // create an array of forbidden char for the group name (before setting the name of the group)
            List<char> charList = new List<char>(System.IO.Path.GetInvalidFileNameChars());
            foreach (char character in System.IO.Path.GetInvalidPathChars())
                if (!charList.Contains(character))
                    charList.Add(character);
            charList.Add('&'); // the ampersome is authorized in file name, but brings trouble in xml, since it is the escape char.
            mForbiddenChar = charList.ToArray();

            // save the error list from the text field
            char[] separator = { '|' };
            mErrorHint = this.nameErrorLabel.Text.Split(separator);

            // fill the language combo
            fillAndSelectLanguageComboBox();

            // set the author (could be overriden later)
            this.authorTextBox.Text = this.Author;

            // get the list of the top items
            List<Layer.LayerItem> topItems = Layer.sGetTopItemListFromList(Map.Instance.SelectedLayer.SelectedObjects);
            // fill the name if there's only one group selected
            if (topItems.Count == 1)
            {
                // if this window is called with one object, it should be normally a group
                // otherwise the save group cannot be called
                mGroupToSave = (topItems[0]) as Layer.Group;
                mWasGroupToSaveCreated = false;
                if (mGroupToSave.IsANamedGroup)
                {
                    string partNumber = mGroupToSave.PartNumber;
                    // set the name here and init the rest in the function
                    nameTextBox.Text = partNumber;
                    initControlWithPartInfo(partNumber);
                }
            }
            else
            {
                // sort the top items as on the layer
                topItems.Sort(Map.Instance.SelectedLayer.compareItemOrderOnLayer);
                // create a group temporally for the export purpose
                mGroupToSave = new Layer.Group();
                mGroupToSave.addItem(topItems);
                mWasGroupToSaveCreated = true;
            }

            // call explicitly the event to set the correct color and error message
            // after setting all the data members used to check the validity of the name
            this.nameTextBox_TextChanged(nameTextBox, null);

            // configure the xmlSetting for writing
            mXmlSettings.CheckCharacters = false;
            mXmlSettings.CloseOutput = true;
            mXmlSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;
            mXmlSettings.Encoding = new UTF8Encoding(false);
            mXmlSettings.Indent = true;
            mXmlSettings.IndentChars = "\t";
            mXmlSettings.NewLineChars = "\r\n";
            mXmlSettings.NewLineOnAttributes = false;
            mXmlSettings.OmitXmlDeclaration = false;
        }
コード例 #11
0
        public SaveGroupNameForm()
        {
            InitializeComponent();

            // create an array of forbidden char for the group name (before setting the name of the group)
            List <char> charList = new List <char>(System.IO.Path.GetInvalidFileNameChars());

            foreach (char character in System.IO.Path.GetInvalidPathChars())
            {
                if (!charList.Contains(character))
                {
                    charList.Add(character);
                }
            }
            charList.Add('&');             // the ampersome is authorized in file name, but brings trouble in xml, since it is the escape char.
            mForbiddenChar = charList.ToArray();

            // save the error list from the text field
            char[] separator = { '|' };
            mErrorHint = this.nameErrorLabel.Text.Split(separator);

            // fill the language combo
            fillAndSelectLanguageComboBox();

            // set the author (could be overriden later)
            this.authorTextBox.Text = this.Author;

            // get the list of the top items
            List <Layer.LayerItem> topItems = Layer.sGetTopItemListFromList(Map.Instance.SelectedLayer.SelectedObjects);

            // fill the name if there's only one group selected
            if (topItems.Count == 1)
            {
                // if this window is called with one object, it should be normally a group
                // otherwise the save group cannot be called
                mGroupToSave           = (topItems[0]) as Layer.Group;
                mWasGroupToSaveCreated = false;
                if (mGroupToSave.IsANamedGroup)
                {
                    string partNumber = mGroupToSave.PartNumber;
                    // set the name here and init the rest in the function
                    nameTextBox.Text = partNumber;
                    initControlWithPartInfo(partNumber);
                }
            }
            else
            {
                // sort the top items as on the layer
                topItems.Sort(Map.Instance.SelectedLayer.compareItemOrderOnLayer);
                // create a group temporally for the export purpose
                mGroupToSave = new Layer.Group();
                mGroupToSave.addItem(topItems);
                mWasGroupToSaveCreated = true;
            }

            // call explicitly the event to set the correct color and error message
            // after setting all the data members used to check the validity of the name
            this.nameTextBox_TextChanged(nameTextBox, null);

            // configure the xmlSetting for writing
            mXmlSettings.CheckCharacters     = false;
            mXmlSettings.CloseOutput         = true;
            mXmlSettings.ConformanceLevel    = System.Xml.ConformanceLevel.Document;
            mXmlSettings.Encoding            = new UTF8Encoding(false);
            mXmlSettings.Indent              = true;
            mXmlSettings.IndentChars         = "\t";
            mXmlSettings.NewLineChars        = "\r\n";
            mXmlSettings.NewLineOnAttributes = false;
            mXmlSettings.OmitXmlDeclaration  = false;
        }
コード例 #12
0
        /// <summary>
        /// Write a list of prefered connections. The list is computed as follow:
        /// First we get all the free connections in the whole group, then we split that
        /// list into sub-list per connection type, and then for each sub-list we create
        /// a loop of next connection preferences.
        /// For example if the group contains 4 track and 3 road connections, and the
        /// two track parts are connected, then we have only 2 free track connections
        /// and 3 free road connection. We will generate a first cycle for the track
        /// and a second cycle for the road.
        /// </summary>
        /// <param name="xmlWriter">The xmlWritter where to write the list</param>
        /// <param name="group">The group for which we are writting the list</param>
        private void writeGroupConnectionPreferenceList(XmlWriter xmlWriter, Layer.Group group)
        {
            // get all the bricks in a flat list (removing intermediate group)
            List <Layer.LayerItem> allBricks = group.getAllLeafItems();

            // if the group doesn't contains brick, just early exit
            if ((allBricks.Count == 0) || !(allBricks[0] is LayerBrick.Brick))
            {
                return;
            }

            // declare a dictionary of list of connections, to store all the connections separated by connection type (which is the key of the dictionnary)
            Dictionary <int, List <ConnectionAndIndex> > connectionsPerType = new Dictionary <int, List <ConnectionAndIndex> >();
            // declare a global counter to count the connection index inside the group
            int connectionCounter = 0;

            // now, iterate on all the connections of all the bricks, and create separated list of free connection
            foreach (Layer.LayerItem item in allBricks)
            {
                LayerBrick.Brick brick = item as LayerBrick.Brick;
                if (brick.HasConnectionPoint)
                {
                    foreach (LayerBrick.Brick.ConnectionPoint connection in brick.ConnectionPoints)
                    {
                        if (connection.IsFree)
                        {
                            // we found a free connection, check if the list for its type was already added in the dictionary
                            if (!connectionsPerType.ContainsKey(connection.Type))
                            {
                                connectionsPerType.Add(connection.Type, new List <ConnectionAndIndex>());
                            }
                            // now get the list corresponding to the type
                            List <ConnectionAndIndex> freeConnectionList = connectionsPerType[connection.Type];
                            // then add the connection in the list
                            freeConnectionList.Add(new ConnectionAndIndex(connection, connectionCounter));
                        }

                        // increase the connection counter, no matter if the current connection is free or not
                        connectionCounter++;
                    }
                }
            }

            // check if we found something
            if (connectionsPerType.Count > 0)
            {
                // write the header of the list
                xmlWriter.WriteStartElement("GroupConnectionPreferenceList");

                // now iterate on the dictionary, and for each list, create a cycle
                foreach (KeyValuePair <int, List <ConnectionAndIndex> > connectionsOfOneType in connectionsPerType)
                {
                    for (int i = 0; i < connectionsOfOneType.Value.Count; ++i)
                    {
                        // get the current and the next connection
                        ConnectionAndIndex currentConnection = connectionsOfOneType.Value[i];
                        ConnectionAndIndex nextConnection    = (i == connectionsOfOneType.Value.Count - 1) ? connectionsOfOneType.Value[0] : connectionsOfOneType.Value[i + 1];
                        // write the current prefered link
                        xmlWriter.WriteStartElement("nextIndex");
                        xmlWriter.WriteAttributeString("from", currentConnection.mIndexInTheGroup.ToString());
                        xmlWriter.WriteValue(nextConnection.mIndexInTheGroup);
                        xmlWriter.WriteEndElement();                         // nextIndex
                    }
                }

                xmlWriter.WriteEndElement();                 // GroupConnectionPreferenceList
            }
        }
コード例 #13
0
        /// <summary>
        /// Recursive function that save one xml file for the specified group in the custom library
        /// </summary>
        /// <param name="group">The group to save</param>
        /// <param name="groupName">the name of the group that should be used to save the file</param>
        /// <param name="groupNumber">The sequential number of the group, starting with 0 for the top group</param>
        private void saveGroup(Layer.Group group, string groupName, int groupNumber)
        {
            // use a counter for the sub-groups of this group, starting from this group number + 1
            int subGroupNumber = groupNumber + 1;

            // get the position of the first item to make it the origin
            PointF origin = new PointF();

            if (group.ItemsCount > 0)
            {
                origin = group.Items[0].Center;
            }

            // trim and uppercase the group name and save it in the array
            groupName = groupName.Trim().ToUpper();
            mNewGroupName.Add(groupName);

            // get the full filename and save it in the array
            string filename = getFullFileNameFromGroupName(groupName);

            mNewXmlFilesToLoad.Add(new FileInfo(filename));

            // open the stream
            XmlWriter xmlWriter = XmlWriter.Create(filename, mXmlSettings);

            // start to write the header and the top node
            xmlWriter.WriteStartDocument();
            xmlWriter.WriteStartElement("group");
            // author
            xmlWriter.WriteElementString("Author", this.authorTextBox.Text);
            // description
            xmlWriter.WriteStartElement("Description");
            foreach (KeyValuePair <string, string> keyValue in mDescription)
            {
                xmlWriter.WriteElementString(keyValue.Key, keyValue.Value);
            }
            xmlWriter.WriteEndElement();             // Description
            // sorting key
            xmlWriter.WriteElementString("SortingKey", this.sortingKeyTextBox.Text.Trim());
            // in library? Only the top group is in library, the other one are hidden (normal behavior)
            if (groupNumber != 0)
            {
                xmlWriter.WriteElementString("NotListedInLibrary", "true");
            }
            // image URL if it exists
            if (this.imageURLTextBox.Text != string.Empty)
            {
                xmlWriter.WriteElementString("ImageURL", this.imageURLTextBox.Text);
            }
            // can ungroup?
            if (this.canUngroupCheckBox.Checked)
            {
                xmlWriter.WriteElementString("CanUngroup", "true");
            }
            else
            {
                xmlWriter.WriteElementString("CanUngroup", "false");
            }
            // sub part list
            xmlWriter.WriteStartElement("SubPartList");
            foreach (Layer.LayerItem item in group.Items)
            {
                xmlWriter.WriteStartElement("SubPart");
                if (item.PartNumber != string.Empty)
                {
                    xmlWriter.WriteAttributeString("id", item.PartNumber);
                }
                else
                {
                    xmlWriter.WriteAttributeString("id", getSubGroupName(groupName, subGroupNumber++));
                }
                // position and angle
                PointF center = item.Center;
                center.X -= origin.X;
                center.Y -= origin.Y;
                XmlReadWrite.writePointFLowerCase(xmlWriter, "position", center);
                XmlReadWrite.writeFloat(xmlWriter, "angle", item.Orientation);
                // end of subpart
                xmlWriter.WriteEndElement();         // SubPart
            }
            xmlWriter.WriteEndElement();             // SubPartList

            // for the top group we should also write cyclic prefered connection lists (one cycle per type of connection among the free connections)
            if (groupNumber == 0)
            {
                writeGroupConnectionPreferenceList(xmlWriter, group);
            }

            // write the end element and close the stream
            xmlWriter.WriteEndElement();             // group
            xmlWriter.Close();

            // now iterate on all the unnamed group recursively
            // we do two iteration on the group list because we don't like to open several files at the same time
            subGroupNumber = groupNumber + 1;             // reinit the counter
            foreach (Layer.LayerItem item in group.Items)
            {
                if (item.PartNumber == string.Empty)
                {
                    saveGroup(item as Layer.Group, getSubGroupName(groupName, subGroupNumber), subGroupNumber);
                    subGroupNumber++;
                }
            }
        }
コード例 #14
0
ファイル: AddConnectGroup.cs プロジェクト: Shevonar/BlueBrick
        private int mNextPreferedActiveConnectionIndex = 0; // the prefered active connection index according to the brick library

        /// <summary>
        /// Add a new named group which has the specified partNumber on the specifier layer, and connected it to
        /// the specified selectedItem (part or group) using the specified wanted connection for that new part.
        /// </summary>
        /// <param name="layer">The layer on which to add the group, and in which the selectedItem is selected</param>
        /// <param name="selectedItem">The single selected item (this can be a single part or a single group). This parameter cannot be null.</param>
        /// <param name="partNumber">The number of the named group to add</param>
        /// <param name="wantedConnexion">The connection index of the group to add that should be used to connect to the selected item, or -1 if you don't care.</param>
        public AddConnectGroup(LayerBrick layer, Layer.LayerItem selectedItem, string partNumber, int wantedConnexion)
        {
            // the selected item should not be null
            System.Diagnostics.Debug.Assert(selectedItem != null);

            // save the layer and construct the group
            mBrickLayer = layer;
            mGroup      = new Layer.Group(partNumber);
            // get the flat list of bricks from the hierarchical group
            mBricksInTheGroup = mGroup.getAllLeafItems();

            // get the connectable brick among the selection, and also the selected item (in case the selected item is a single group without connections points)
            LayerBrick.Brick selectedBrick = layer.getConnectableBrick();
            LayerBrick.Brick brickToConnectInAddedGroup = null;

            // check if we can attach the group to the unique selected object
            if ((selectedBrick != null) && selectedBrick.HasConnectionPoint)
            {
                // find the brick of the group that will be connected to the selected brick
                brickToConnectInAddedGroup = findBrickToConnectAndSetBestConnectionPointIndex(selectedItem, ref wantedConnexion);
            }

            // check if the brick to connect is valid and has connection point
            if ((brickToConnectInAddedGroup != null) && brickToConnectInAddedGroup.HasConnectionPoint)
            {
                // after setting the active connection point index from which this brick will be attached,
                // get the prefered index from the library
                mNextPreferedActiveConnectionIndex = BrickLibrary.Instance.getConnectionNextPreferedIndex(partNumber, wantedConnexion);

                // Compute the orientation of the bricks
                float newOrientation = AddConnectBrick.sGetOrientationOfConnectedBrick(selectedBrick, brickToConnectInAddedGroup);
                newOrientation -= brickToConnectInAddedGroup.Orientation;
                // Rotate all the bricks of the group first before translating
                RotateBrickOnPivotBrick rotateBricksAction = new RotateBrickOnPivotBrick(layer, mBricksInTheGroup, newOrientation, brickToConnectInAddedGroup);
                rotateBricksAction.MustUpdateBrickConnectivity = false;
                rotateBricksAction.redo();

                // compute the translation to add to all the bricks
                PointF translation = new PointF(selectedBrick.ActiveConnectionPosition.X - brickToConnectInAddedGroup.ActiveConnectionPosition.X,
                                                selectedBrick.ActiveConnectionPosition.Y - brickToConnectInAddedGroup.ActiveConnectionPosition.Y);
                mGroup.translate(translation);
            }
            else
            {
                // and just compute the position to the right of the selected item
                PointF position = selectedItem.Position;
                position.X     += selectedItem.DisplayArea.Width;
                mGroup.Position = position;

                // the reassing the selected brick with the first brick of the group if the selected item is a group
                // so that the brick index can correctly be set
                if (selectedItem.IsAGroup)
                {
                    selectedBrick = (selectedItem as Layer.Group).getAllLeafItems()[0] as LayerBrick.Brick;
                }
                else
                {
                    selectedBrick = selectedItem as LayerBrick.Brick;
                }
            }

            // set the index of the group in the list just after the selected brick
            if (selectedBrick != null)
            {
                mInsertIndex = layer.BrickList.IndexOf(selectedBrick) + 1;
            }
        }
コード例 #15
0
ファイル: AddConnectGroup.cs プロジェクト: Shevonar/BlueBrick
        private LayerBrick.Brick findBrickToConnectAndSetBestConnectionPointIndex(Layer.LayerItem fixedItem, ref int wantedConnexion)
        {
            // the brick that will be used to attach the group
            LayerBrick.Brick brickToAttach = null;
            int originalWantedConnexion    = wantedConnexion;          // memorize the original wanted connection in case we need to reset it

            // get the type of the active connexion of the selected brick
            Layer.Group fixedGroup         = fixedItem as Layer.Group;
            int         fixedConnexionType = (fixedGroup != null) ? fixedGroup.ActiveConnectionPoint.Type : (fixedItem as LayerBrick.Brick).ActiveConnectionPoint.Type;

            // first connect all the connection inside the group. Normally the connection of the bricks of the group
            // are done directly on the layer, afer that the brick has been added. But here we need to connect the bricks
            // inisde the group, in order to check the free remaining connections
            LayerBrick.updateBrickConnectivityForASpareSetOfBrickAmongThemselve(mBricksInTheGroup);

            // try to give the correct connexion point, either the specified wanted one, or if
            // we add the same brick do a special case
            bool isActiveConnectionPointChosen = false;

            if (wantedConnexion >= 0)
            {
                // set the active connexion point with the wanted one
                brickToAttach = setActiveConnectionIndex(wantedConnexion);
                // check that the wanted connection type is the same as the selected brick
                isActiveConnectionPointChosen = (brickToAttach != null) &&
                                                (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) &&
                                                brickToAttach.ActiveConnectionPoint.IsFree;
            }
            else if ((fixedGroup != null) && (fixedGroup.PartNumber == mGroup.PartNumber))
            {
                // check if the new added brick is the same kind of the selected one, if so,
                // then we choose the previous connection point, but check if it is the same type
                wantedConnexion = BrickLibrary.Instance.getConnectionNextPreferedIndex(fixedGroup.PartNumber, fixedGroup.ActiveConnectionIndex);
                brickToAttach   = setActiveConnectionIndex(wantedConnexion);
                // check that the connection type is the same
                isActiveConnectionPointChosen = (brickToAttach != null) &&
                                                (brickToAttach.ActiveConnectionPoint.Type == fixedConnexionType) &&
                                                brickToAttach.ActiveConnectionPoint.IsFree;
            }

            // if we didn't find any valid active connexion point, set the active connection
            // with the first connexion of the same type that we can find (if the brick as any connection point)
            if (!isActiveConnectionPointChosen)
            {
                wantedConnexion = 0;
                foreach (Layer.LayerItem item in mBricksInTheGroup)
                {
                    LayerBrick.Brick brick = item as LayerBrick.Brick;
                    if (brick.HasConnectionPoint)
                    {
                        for (int i = 0; i < brick.ConnectionPoints.Count; ++i)
                        {
                            if ((brick.ConnectionPoints[i].Type == fixedConnexionType) &&
                                brick.ConnectionPoints[i].IsFree)
                            {
                                brick.ActiveConnectionPointIndex = i;
                                brickToAttach = brick;
                                isActiveConnectionPointChosen = true;
                                break;
                            }
                            // increase the connection count
                            ++wantedConnexion;
                        }
                    }
                    // break again if we found it
                    if (isActiveConnectionPointChosen)
                    {
                        break;
                    }
                }
            }

            // if we still didn't find a compatible brick, reset the wanted connection that we have modified
            if (!isActiveConnectionPointChosen)
            {
                wantedConnexion = originalWantedConnexion;
            }

            // finally return the brick selected for the attachement
            return(brickToAttach);
        }
コード例 #16
0
        /// <summary>
        /// This tool method clones all the item of the specified list into a new list.
        /// This method also clone the groups that may belong to this list of bricks.
        /// The cloned items are in the same order as the original list
        /// </summary>
        /// <param name="listToClone">The original list of brick to copy</param>
        /// <param name="addGroupsInItemList">if this parameter is true, the groups are also added in the Items list</param>
        /// <returns>A clone list of cloned brick with there cloned groups</returns>
        protected List<Layer.LayerItem> cloneItemList(List<Layer.LayerItem> listToClone, bool addGroupsInItemList)
        {
            // the resulting list
            List<Layer.LayerItem> result = new List<Layer.LayerItem>(listToClone.Count);

            // use a dictionnary to recreate the groups that may be inside the list of brick to duplicate
            // this dictionnary makes an association between the group to duplicate and the new duplicated one
            Dictionary<Layer.Group, Layer.Group> groupsToCreate = new Dictionary<Layer.Group, Layer.Group>();
            // also use a list of item that we will make grow to create all the groups
            List<Layer.LayerItem> fullOriginalItemList = new List<Layer.LayerItem>(listToClone);

            // use a for instead of a foreach because the list will grow
            for (int i = 0; i < fullOriginalItemList.Count; ++i)
            {
                // get the current item
                Layer.LayerItem originalItem = fullOriginalItemList[i];
                Layer.LayerItem duplicatedItem = null;

                // check if the item is a group or a brick
                if (originalItem.IsAGroup)
                {
                    // if the item is a group that means the list already grown, and that means we also have it in the dictionnary
                    Layer.Group associatedGroup = null;
                    groupsToCreate.TryGetValue(originalItem as Layer.Group, out associatedGroup);
                    duplicatedItem = associatedGroup;
                    // check if we also need to add the group
                    if (addGroupsInItemList)
                        result.Add(duplicatedItem);
                }
                else
                {
                    // if the item is a brick, just clone it and add it to the result
                    // clone the item (because the same list of text to add can be paste several times)
                    duplicatedItem = originalItem.Clone();
                    // add the duplicated item in the list
                    result.Add(duplicatedItem);
                }

                // check if the item to clone belongs to a group then also duplicate the group
                if (originalItem.Group != null)
                {
                    // get the duplicated group if already created otherwise create it and add it in the dictionary
                    Layer.Group duplicatedGroup = null;
                    groupsToCreate.TryGetValue(originalItem.Group, out duplicatedGroup);
                    if (duplicatedGroup == null)
                    {
                        duplicatedGroup = new Layer.Group(originalItem.Group);
                        groupsToCreate.Add(originalItem.Group, duplicatedGroup);
                        fullOriginalItemList.Add(originalItem.Group);
                    }
                    // assign the group to the brick
                    duplicatedGroup.addItem(duplicatedItem);
                    // check if we need to also assign the brick that hold the connection point
                    if (originalItem.Group.BrickThatHoldsActiveConnection == originalItem)
                        duplicatedGroup.BrickThatHoldsActiveConnection = (duplicatedItem as LayerBrick.Brick);
                }
            }

            // delete the dictionary
            groupsToCreate.Clear();
            fullOriginalItemList.Clear();
            // return the cloned list
            return result;
        }