/// <summary> /// Initializes a new instance of the <see cref="T:FolderMaterial"/> class. /// </summary> /// <param name="title">The title.</param> /// <param name="entries">The entries.</param> public FolderMaterial(string title, string[] entries) : this(title) { IconLabelMaterial label; for (int k = 0; k < entries.Length; k++) { label = new IconLabelMaterial("Resources.Text.png", entries[k]); mEntries.Add(label); } Collapse(); }
/// <summary> /// Perform undo of this command. /// </summary> public override void Undo() { //create a new group GroupShape group = new GroupShape(this.Controller.Model); //asign the entities to the group group.Entities = bundle.Entities; foreach (IDiagramEntity entity in group.Entities) { //this will be recursive if an entity is itself an IGroup entity.Group = group; } //add the new group to the layer this.Controller.Model.DefaultPage.DefaultLayer.Entities.Add(group); mGroup = group; //select the newly created group CollectionBase <IDiagramEntity> col = new CollectionBase <IDiagramEntity>(); col.Add(mGroup); Selection.SelectedItems = col; mGroup.Invalidate(); }
/// <summary> /// Perform redo of this command. /// </summary> public override void Redo() { //create a new group; use the standard GroupShape or the CollapsibleGroupShape for a painted group with collapse/expand features. //GroupShape group = new GroupShape(this.Controller.Model); CollapsibleGroupShape group = new CollapsibleGroupShape(this.controller.Model); //asign the entities to the group group.Entities.Clear(); foreach (IDiagramEntity entity in bundle.Entities) { //this will be recursive if an entity is itself an IGroup entity.Group = group; group.Entities.Add(entity); } //add the new group to the layer this.Controller.Model.DefaultPage.DefaultLayer.Entities.Add(group); mGroup = group; //select the newly created group CollectionBase <IDiagramEntity> col = new CollectionBase <IDiagramEntity>(); col.Add(mGroup); Selection.SelectedItems = col; mGroup.Invalidate(); }
/// <summary> /// Adds the given tool. /// </summary> /// <param name="tool">The tool.</param> public void AddTool(ITool tool) { tool.Controller = this; //add the tool to the collection even if it doesn't attach to anything (yet) registeredTools.Add(tool); IMouseListener mouseTool = null; if ((mouseTool = tool as IMouseListener) != null) { mouseListeners.Add(mouseTool); } IKeyboardListener keyboardTool = null; if ((keyboardTool = tool as IKeyboardListener) != null) { keyboardListeners.Add(keyboardTool); } IDragDropListener dragdropTool = null; if ((dragdropTool = tool as IDragDropListener) != null) { dragdropListeners.Add(dragdropTool); } }
/// <summary> /// Depth-first traversal of an <see cref="IGroup"/> /// </summary> /// <param name="group"></param> /// <param name="collection"></param> public static void TraverseCollect(IGroup group, ref CollectionBase <IDiagramEntity> collection) { #region Checks if (group == null) { throw new InconsistencyException("Cannot collect entities of a 'null' IGroup"); } if (collection == null) { throw new InconsistencyException("You need to instantiate a collection before using this method."); } #endregion foreach (IDiagramEntity entity in group.Entities) { if (entity is IGroup) { TraverseCollect(entity as IGroup, ref collection); } else { collection.Add(entity); } } }
// ------------------------------------------------------------------ /// <summary> /// Sets the current page. /// </summary> /// <param name="page">The page.</param> // ------------------------------------------------------------------ public void SetCurrentPage(IPage page) { mCurrentPage = page; RaiseOnAmbienceChanged(new AmbienceEventArgs(page.Ambience)); RaiseOnCurrentPageChanged(new PageEventArgs(page)); //change the paintables as well //Paintables = new CollectionBase<IDiagramEntity>(); #region Reload of the z-order, usually only necessary after deserialization CollectionBase <IDiagramEntity> collected = new CollectionBase <IDiagramEntity>(); //pick up the non-group entities foreach (IDiagramEntity entity in Paintables) { if (!typeof(IGroup).IsInstanceOfType(entity)) { collected.Add(entity); } } if (collected.Count > 0) { Algorithms.SortInPlace <IDiagramEntity>(collected, new SceneIndexComparer <IDiagramEntity>()); //Paintables.AddRange(collected); } #endregion }
/// <summary> /// Initializes a new instance of the <see cref="T:FolderMaterial"/> class. /// </summary> /// <param name="title">The title.</param> /// <param name="entries">The entries.</param> public FolderMaterial(string title, string[] entries) : this(title) { myTextStyle = new TextStyle( Color.Black, new Font("Arial", 10), StringAlignment.Near, StringAlignment.Near); IconLabelMaterial label; for (int k = 0; k < entries.Length; k++) { label = new IconLabelMaterial("Resources.Text.png", entries[k]); // We attach our ITextStyle to items when they're added to the // collection. mEntries.Add(label); } Collapse(); }
/// <summary> /// Returns a copy of this instance. /// </summary> /// <returns></returns> public CollectionBase <T> Copy() { CollectionBase <T> copy = new CollectionBase <T>(); foreach (T item in this.innerList) { copy.Add(item); } return(copy); }
/// <summary> /// Default constructor /// </summary> public Model() { //here I'll have to work on the scene graph //this.mShapes = new CollectionBase<IShape>(); //the default page //the page collection mPages = new CollectionBase <IPage>(); mPages.Add(new Page("Default Page", this)); Init(); }
///<summary> ///Default constructor ///</summary> public Page(string name, IModel model) { this.mModel = model; mName = name; mAmbience = new Ambience(this); //the one and only and indestructible layer mLayers = new CollectionBase <ILayer>(); mLayers.Add(new Layer("Default Layer")); Init(); }
/// <summary> /// Handles the OnEntityAdded event of the Page and adds the new entity to the Paintables. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="T:Netron.Diagramming.Core.EntityEventArgs"/> instance containing the event data.</param> void mDefaultPage_OnEntityAdded(object sender, EntityEventArgs e) { //don't add it if it's already there or if it's a group (unless you want to deploy something special to emphasize a group shape). if (!mPaintables.Contains(e.Entity)) { if ((e.Entity is IGroup) && !(e.Entity as IGroup).EmphasizeGroup) { return; } //set the new entity on top of the stack e.Entity.SceneIndex = mPaintables.Count; mPaintables.Add(e.Entity); } #region Addition callback IAdditionCallback callback = e.Entity.GetService(typeof(IAdditionCallback)) as IAdditionCallback; if (callback != null) { callback.OnAddition(); } #endregion RaiseOnEntityAdded(e); }
/// <summary> /// Sets the items. /// </summary> /// <param name="editValue">The edit value.</param> /// <param name="value">The value.</param> /// <returns></returns> protected override object SetItems(object editValue, object[] value) { CollectionBase <IShapeMaterial> entries = editValue as CollectionBase <IShapeMaterial>; entries.Clear(); for (int k = 0; k < value.Length; k++) { entries.Add(value[k] as IShapeMaterial); } object retValue = base.SetItems(entries, value); return(retValue); }
/// <summary> /// Default constructor /// </summary> public Model() { //here I'll have to work on the scene graph //this.mShapes = new CollectionBase<IShape>(); //the default page //the page collection mPages = new CollectionBase <IPage>(); mPages.Add(new Page("Default Page", this)); mConnectorHolders = new Dictionary <IConnector, IDiagramEntity>(); Init(); }
/// <summary> /// Handles the OnEntityAdded event of the Page and adds the new entity to the Paintables. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="T:Netron.Diagramming.Core.EntityEventArgs"/> instance containing the event data.</param> void mDefaultPage_OnEntityAdded(object sender, EntityEventArgs e) { IConnection cn = e.Entity as IConnection; if (cn != null) { mConnectorHolders.Add(cn.From, cn); mConnectorHolders.Add(cn.To, cn); } //IShape sp = e.Entity as IShape; //if(sp != null) //{ // foreach(IConnector cr in sp.Connectors) // mConnectorHolders.Add(cr, sp); //} //don't add it if it's already there or if it's a group (unless you want to deploy something special to emphasize a group shape). if (!mPaintables.Contains(e.Entity)) { if ((e.Entity is IGroup) && !(e.Entity as IGroup).EmphasizeGroup) { return; } //set the new entity on top of the stack e.Entity.SceneIndex = mPaintables.Count; mPaintables.Add(e.Entity); } #region Addition callback IAdditionCallback callback = e.Entity.GetService(typeof(IAdditionCallback)) as IAdditionCallback; if (callback != null) { callback.OnAddition(); } #endregion RaiseOnEntityAdded(e); }
// ------------------------------------------------------------------ /// <summary> /// Default constructor /// </summary> // ------------------------------------------------------------------ public Model() { //here I'll have to work on the scene graph //this.mShapes = new CollectionBase<IShape>(); //the default page //the page collection mPages = new CollectionBase <IPage>(); Page p = new Page("Default Page", this); p.Ambience.PageColor = ArtPalette.DefaultPageColor; mPages.Add(p); Init(); }
/// <summary> /// Attaches the given connector to this connector. /// <remarks>The method will remove a previous binding, if any, before creating the attachment. This method prohibits mutliple identical connections; /// you can attach a connector only once. /// </remarks> /// </summary> /// <param name="connector"></param> public void AttachConnector(IConnector connector) { if (connector == null || !Enabled) { return; } //only attach'm if not already present and not the parent if (!attachedConnectors.Contains(connector) && connector != attachedTo) { connector.DetachFromParent(); attachedConnectors.Add(connector); //make sure the attached connector is centered at this connector connector.Point = this.mPoint; connector.AttachedTo = this; } }
/// <summary> /// Creates a new bundle using a given collection of diagram entities. /// </summary> /// <param name="collection"></param> public Bundle(CollectionBase <IDiagramEntity> collection) { mEntities = new CollectionBase <IDiagramEntity>(); //we could assign it directly but let's make sure the collection does not //contain unwanted elements foreach (IDiagramEntity entity in collection) { if ((entity is IShape) || (entity is IConnection) || (entity is IGroup)) { mEntities.Add(entity); } } //the following line would give problem. The event handler attached to the Selection would be triggered when //the mEntities collection is changed! //mEntities = collection; }
internal void SelectEntity(IDiagramEntity entity, Point surfacePoint) { // Groups are treated specially because we can drill-down // into the group. The process of drilling is the first // mouse hit will select the group. The second mouse hit // will select a child, if there's a child at that point. if (entity is IGroup) { if (entity.IsSelected == false) { entity.IsSelected = true; mSelection.Add(entity); } else { IGroup group = entity as IGroup; for (int j = group.Entities.Count - 1; j >= 0; j--) { IDiagramEntity child = group.Entities[j]; if (child.Hit(surfacePoint)) { // Repeat the process because what if this // child is too a group! SelectEntity(child, surfacePoint); group.IsSelected = false; if (mSelection.Contains(group)) { mSelection.Remove(group); } break; } } } } //else if (entity.Group != null) //{ // //entity.Group.IsSelected = true; // //mSelection.Add(entity.Group); //} else { entity.IsSelected = true; mSelection.Add(entity); } }
/// <summary> /// Adds the given activity to the controller. /// </summary> /// <param name="activity">The activity.</param> public void AddActivity(IActivity activity) { registeredActivity.Add(activity); }
// ------------------------------------------------------------------ /// <summary> /// Initialize of the bundle /// </summary> // ------------------------------------------------------------------ protected override void Initialize() { base.Initialize(); Name = "Class Shape"; mTitle = "Class shape"; mSubTitle = "by The Netron Project"; this.Resizable = false; sf.Trimming = StringTrimming.EllipsisCharacter; //the initial size Transform(0, 0, 200, 50); //mList.OnItemAdded += new EventHandler<CollectionEventArgs<ClassShapeItem>>(mList_OnItemAdded); #region The icon material CreateShapeIcon(); #endregion #region The xpand icon material CreateXpansionIcon(); #endregion #region The free text textMaterial = new LabelMaterial(); textMaterial.Transform(new Rectangle(Rectangle.X + 5, Rectangle.Y + 18, Rectangle.Width - 10, bodyHeight)); textMaterial.Text = GetQuotation(); textMaterial.Visible = false; Children.Add(textMaterial); #endregion #region The folders /* The following code is only an example of what is possible. * You can add any shape material here but I guess the properties/methods nodes * are quite useful for many purposes. */ string[] props = new string[] { "Rectangle", "Size", "Visible" }; FolderMaterial folder1 = new FolderMaterial("Properties", props, "Resources.PublicProperty.ico"); folder1.Transform(new Rectangle(Rectangle.X + 5, Rectangle.Y + 55, Rectangle.Width - 10, FolderMaterial.HeaderHeight)); folder1.Visible = false; folder1.ShowLines = true; mFolders.Add(folder1); folder1.OnFolderChanged += new EventHandler <RectangleEventArgs>(folders_OnFolderChanged); Children.Add(folder1); mPropertiesNode = folder1; string[] methds = new string[] { "Invalidate", "Transform", "Update", "Reset", "Delete" }; FolderMaterial folder2 = new FolderMaterial("Methods", methds, "Resources.PublicMethod.ico"); folder2.Transform(new Rectangle(Rectangle.X + 5, Rectangle.Y + 55 + FolderMaterial.HeaderHeight + 10, Rectangle.Width - 10, FolderMaterial.HeaderHeight)); folder2.Visible = false; folder2.ShowLines = true; mFolders.Add(folder2); folder2.OnFolderChanged += new EventHandler <RectangleEventArgs>(folders_OnFolderChanged); Children.Add(folder2); mMethodsNode = folder2; #region this calculates the initial body height foreach (FolderMaterial folder in mFolders) { bodyHeight += folder.Rectangle.Height + 3; } //UpdateBody(); #endregion #endregion #region Connectors cTop = new Connector(new Point((int)(Rectangle.Left + Rectangle.Width / 2), Rectangle.Top), Model); cTop.Name = "Top connector"; cTop.Parent = this; Connectors.Add(cTop); cRight = new Connector(new Point(Rectangle.Right, (int)(Rectangle.Top + Rectangle.Height / 2)), Model); cRight.Name = "Right connector"; cRight.Parent = this; Connectors.Add(cRight); cBottom = new Connector(new Point((int)(Rectangle.Left + Rectangle.Width / 2), Rectangle.Bottom), Model); cBottom.Name = "Bottom connector"; cBottom.Parent = this; Connectors.Add(cBottom); cLeft = new Connector(new Point(Rectangle.Left, (int)(Rectangle.Top + Rectangle.Height / 2)), Model); cLeft.Name = "Left connector"; cLeft.Parent = this; Connectors.Add(cLeft); #endregion }
private CollectionBase <INode> sortedChildren(INode n) { double basevalue = 0; // update basevalue angle for node ordering INode p = n.ParentNode; if (p != null) { basevalue = normalize(Math.Atan2(p.Y - n.Y, p.X - n.X)); } int cc = n.ChildCount; if (cc == 0) { return(null); } INode c = (INode)n.FirstChild; // TODO: this is hacky and will break when filtering // how to know that a branch is newly expanded? // is there an alternative property we should check? //if ( !c.isStartVisible() ) //{ // // use natural ordering for previously invisible nodes // return n.Children; //} double[] angle = new double[cc]; int[] idx = new int[cc]; for (int i = 0; i < cc; ++i, c = c.NextSibling) { idx[i] = i; angle[i] = normalize(-basevalue + Math.Atan2(c.Y - n.Y, c.X - n.X)); } Array.Sort(angle, idx);//or is it the other way around CollectionBase <INode> col = new CollectionBase <INode>(); CollectionBase <INode> children = n.Children; for (int i = 0; i < cc; ++i) { col.Add(children[idx[i]]); } return(col); // return iterator over sorted children //return new Iterator() { // int cur = 0; // public Object next() { // return n.getChild(idx[cur++]); // } // public bool hasNext() { // return cur < idx.Length; // } // public void remove() { // throw new UnsupportedOperationException(); // } //}; }
/// <summary> /// Collects the shapes at the given (transformed surface) location. /// The shapes selected in this way are available /// </summary> /// <param name="surfacePoint">The surface point.</param> public static void CollectEntitiesAt(Point surfacePoint) { if (surfacePoint == Point.Empty) { return; } if (Selection.mController == null) { return; } //only change the current selection if the mouse did not hit an already selected element if (mSelection.Count > 0) { foreach (IDiagramEntity entity in mSelection) { if (entity.Rectangle.Contains(surfacePoint)) { return; } } } //here the scene-graph will play a role in the future, //for now we'll keep is simple Selection.Clear(); IConnection con; IShape sh; //we use the paintables here rather than traversing the scene-graph because only //visible things can be collected //We traverse the paintables from top to bottom since the highest z-order //is at the top of the stack. for (int k = Model.Paintables.Count - 1; k >= 0; k--) { IDiagramEntity entity = Model.Paintables[k]; #region we give priority to the connector selection if (typeof(IConnection).IsInstanceOfType(entity)) { con = entity as IConnection; if (con.From.Hit(surfacePoint)) { connector = con.From; connector.IsSelected = true; Invalidate(); return; } if (con.To.Hit(surfacePoint)) { connector = con.To; connector.IsSelected = true; Invalidate(); return; } } else if (entity is IGroup) { //should I care about the connectors at this point...? } else if (entity is IShape) { sh = entity as IShape; foreach (IConnector cn in sh.Connectors) { //if there are connectors attached to the shape connector, the attached ones should be picked up and not the one of the shape if (cn.Hit(surfacePoint) && cn.AttachedConnectors.Count == 0) { connector = cn; connector.IsSelected = true; Invalidate(); //this will invalidate only the selected connector return; //we hit a connector and quit the selection. If the user intended to select the entity it had to be away from the connector! } } } #endregion #region no connector was hit, maybe the entity itself if (entity.Hit(surfacePoint)) { //if the entity is part of an IGroup, the IGroup should be selected //rather than the entity itself //Note that the Group property returns the top group parent and not //just the immediate parent of an entity if (entity.Group != null) { entity.Group.IsSelected = true; mSelection.Add(entity.Group); } else { entity.IsSelected = true; mSelection.Add(entity); } break; } #endregion } RaiseOnNewSelection(); Invalidate(); //Using a full invalidate is rather expensive, so we'll only refresh the current selection //Controller.View.Invalidate(); }
// ------------------------------------------------------------------ /// <summary> /// Adds a page. This should be used when adding pages rather than /// though the Pages property so the page gets attached to the Model. /// </summary> /// <param name="page">IPage: The page to add.</param> /// <returns>IPage</returns> // ------------------------------------------------------------------ public IPage AddPage(IPage page) { mPages.Add(page); AttachToPage(page); return(page); }