/// <summary> /// Find output pin, if any, at given point</summary> /// <param name="element">Element</param> /// <param name="g">Graphics object</param> /// <param name="p">Point to test</param> /// <returns>Output pin hit by p; null otherwise</returns> private TPin PickOutput(TElement element, Graphics g, Point p) { ElementTypeInfo info = GetElementTypeInfo(element, g); Point ep = element.Bounds.Location; int x = ep.X + info.Size.Width - m_pinSize; int y = ep.Y + m_rowSpacing + 2 * PinMargin + m_pinOffset; int width = m_pinSize; Rectangle bounds = new Rectangle(x, y, width, m_pinSize); int pickTolerance = m_theme.PickTolerance; bounds.Inflate(pickTolerance, pickTolerance); ICircuitElementType type = element.Type; foreach (TPin output in type.Outputs) { if (bounds.Contains(p.X, p.Y)) { return(output); } bounds.Y += m_rowSpacing; } return(null); }
/// <summary> /// Find input pin, if any, at given point</summary> /// <param name="element">Element</param> /// <param name="g">Graphics object</param> /// <param name="p">Point to test</param> /// <returns>Input pin hit by p; null otherwise</returns> private TPin PickInput(TElement element, Graphics g, Point p) { Point ep = element.Bounds.Location; int x = ep.X; int y = ep.Y + m_rowSpacing + 2 * PinMargin + m_pinOffset; int width = m_pinSize; //if (IsDraggingWire) //{ // ElementTypeInfo info = GetElementTypeInfo(element, g); // width = info.Width / 2 - m_pickTolerance; //} Rectangle bounds = new Rectangle(x, y, width, m_pinSize); int pickTolerance = m_theme.PickTolerance; bounds.Inflate(pickTolerance, pickTolerance); ICircuitElementType type = element.Type; foreach (TPin input in type.Inputs) { if (bounds.Contains(p.X, p.Y)) { return(input); } bounds.Y += m_rowSpacing; } return(null); }
private void DrawGhost(TElement element, Graphics g) { ElementTypeInfo info = GetElementTypeInfo(element, g); Point p = element.Bounds.Location; Rectangle bounds = new Rectangle(p, info.Size); // clip to window to speed up drawing when zoomed in if (g.ClipBounds.IntersectsWith(bounds)) { if (info.Path == null) { ICircuitElementType type = element.Type; BuildGraphics(type, info, g); } s_pathTransform.Translate(p.X, p.Y); info.Path.Transform(s_pathTransform); g.FillPath(m_theme.GhostBrush, info.Path); g.DrawPath(m_theme.GhostPen, info.Path); s_pathTransform.Translate(-2 * p.X, -2 * p.Y); info.Path.Transform(s_pathTransform); s_pathTransform.Reset(); } }
private void DomNodeOnChildRemoving(object sender, ChildEventArgs e) { if (Validating) { // removing a module from a sub-circuit? Element element = e.Child.As <Element>(); SubCircuit subCircuit = e.Parent.As <SubCircuit>(); if (element != null && subCircuit != null) { ICircuitElementType type = element.Type; // todo: this test isn't quite right, because not all circuit elements // necessarily have both inputs and outputs. For example, if the Speaker // element from the Circuit Editor sample app is the only element in a Master, // and then it is deleted, that will trigger this exception. if (type.Inputs.Count + type.Outputs.Count == 1) { // Ensures that sub-circuit inputs/outputs aren't added or removed, as this would // invalidate wiring on instances of them. throw new InvalidTransactionException( "Can't remove connectors from sub-circuits".Localize()); } } } }
/// <summary> /// Gets all the output pins for this element, including hidden pins (if this is a Group).</summary> /// <param name="type">The type</param> /// <returns>An enumeration of all the output pins for this type of circuit element</returns> public static IEnumerable <ICircuitPin> GetAllOutputPins(this ICircuitElementType type) { var group = type as Group; if (group == null) { return(type.Outputs); } return(group.AllOutputPins); }
/// <summary> /// Gets the output pin, taking into account whether 'type' is a Group or not.</summary> /// <param name="type">The type</param> /// <param name="index">The zero-based index</param> /// <returns>The output pin whose zero-based index is 'index'.</returns> public static ICircuitPin GetOutputPin(this ICircuitElementType type, NameString pinName) { var group = type as Group; if (group == null) { return(type.Outputs.GetPinByName(pinName)); } return(group.OutputPin(pinName)); }
/// <summary> /// Gets the output pin, taking into account whether 'type' is a Group or not.</summary> /// <param name="type">The type</param> /// <param name="index">The zero-based index</param> /// <returns>The output pin whose zero-based index is 'index'.</returns> public static ICircuitPin GetOutputPin(this ICircuitElementType type, int index) { var group = type as Group; if (group == null) { return(type.Outputs[index]); } return(group.OutputPin(index)); }
/// <summary> /// Gets the input pin index by pin name /// </summary> /// <param name="type">The type</param> /// <param name="pinName">Pin Name</param> /// <returns>The input pin indexwhose zero-based index is 'index'.</returns> public static int GetInputPinIndex(this ICircuitElementType type, NameString pinName) { var group = type as Group; if (group == null) { return(type.Inputs.IndexOf(pinName)); } return(group.Inputs.IndexOf(pinName)); }
/// <summary> /// Gets the input pin, taking into account whether 'type' is a Group or not.</summary> /// <param name="type">The type</param> /// <param name="index">The zero-based index</param> /// <returns>The input pin whose zero-based index is 'index'.</returns> public static ICircuitPin GetInputPin(this ICircuitElementType type, int index) { var group = type as Group; if (group == null) { return(type.Inputs.FirstOrDefault(p => p.Index == index)); } return(group.InputPin(index)); }
private void BuildGraphics(ICircuitElementType elementType, ElementTypeInfo info, Graphics g) { int width = info.Size.Width; int height = info.Size.Height; // create rounded corner rect GraphicsPath gp = new GraphicsPath(); const float r = 6; const float d = 2 * r; gp.AddLine(r, 0, width - d, 0); gp.AddArc(width - d, 0, d, d, 270, 90); gp.AddLine(width, r, width, height - d); gp.AddArc(width - d, height - d, d, d, 0, 90); gp.AddLine(width - d, height, r, height); gp.AddArc(0, height - d, d, d, 90, 90); gp.AddLine(0, height - d, 0, r); gp.AddArc(0, 0, d, d, 180, 90); info.Path = gp; }
private void DrawOutline(TElement element, Pen pen, Graphics g) { ElementTypeInfo info = GetElementTypeInfo(element, g); if (info.Path == null) { ICircuitElementType type = element.Type; BuildGraphics(type, info, g); } Point p = element.Bounds.Location; s_pathTransform.Translate(p.X, p.Y); info.Path.Transform(s_pathTransform); g.DrawPath(pen, info.Path); s_pathTransform.Translate(2 * -p.X, 2 * -p.Y); info.Path.Transform(s_pathTransform); s_pathTransform.Reset(); }
private ElementTypeInfo GetElementTypeInfo(TElement element, Graphics g) { // look it up in the cache ICircuitElementType type = element.Type; ElementTypeInfo cachedInfo; if (m_elementTypeCache.TryGetValue(type, out cachedInfo)) { return(cachedInfo); } // not in cache, recompute ElementSizeInfo sizeInfo = GetElementSizeInfo(type, g); ElementTypeInfo info = new ElementTypeInfo { Size = sizeInfo.Size, Interior = sizeInfo.Interior, OutputLeftX = sizeInfo.OutputLeftX.ToArray() }; m_elementTypeCache.Add(type, info); return(info); }
/// <summary> /// Invalidates cached info for element type name</summary> /// <param name="elementType">Element type to invalidate</param> public void Invalidate(ICircuitElementType elementType) { m_elementTypeCache.Remove(elementType); OnRedraw(); }
/// <summary> /// Computes interior and exterior size as well as the X positions of output pins</summary> /// <param name="type">Circuit element type</param> /// <param name="g">Graphics that can be used for measuring strings</param> /// <returns>Element size info, must not be null</returns> /// <remarks>Clients using customized rendering should override this method /// to adjust sizes accordingly. These sizes will be used by drag-fram picking.</remarks> protected virtual ElementSizeInfo GetElementSizeInfo(ICircuitElementType type, Graphics g) { SizeF typeNameSize = g.MeasureString(type.Name, m_theme.Font); int width = (int)typeNameSize.Width + 2 * PinMargin; IList <ICircuitPin> inputPins = type.Inputs; IList <ICircuitPin> outputPins = type.Outputs; int inputCount = inputPins.Count; int outputCount = outputPins.Count; int minRows = Math.Min(inputCount, outputCount); int maxRows = Math.Max(inputCount, outputCount); int[] outputLeftX = new int[outputCount]; int height = m_rowSpacing + 2 * PinMargin; height += Math.Max( maxRows * m_rowSpacing, minRows * m_rowSpacing + type.InteriorSize.Height - PinMargin); bool imageRight = true; for (int i = 0; i < maxRows; i++) { double rowWidth = 2 * PinMargin; if (inputCount > i) { SizeF labelSize = g.MeasureString(inputPins[i].Name, m_theme.Font); rowWidth += labelSize.Width + m_pinSize + PinMargin; } else { rowWidth += type.InteriorSize.Width; imageRight = false; } if (outputCount > i) { SizeF labelSize = g.MeasureString(outputPins[i].Name, m_theme.Font); outputLeftX[i] = (int)labelSize.Width; rowWidth += labelSize.Width + m_pinSize + PinMargin; } else { rowWidth += type.InteriorSize.Width; } width = Math.Max(width, (int)rowWidth); } if (inputCount == outputCount) { width = Math.Max(width, type.InteriorSize.Width + 2); } width = Math.Max(width, MinElementWidth); height = Math.Max(height, MinElementHeight); Size size = new Size(width, height); Rectangle interior = new Rectangle( imageRight ? width - type.InteriorSize.Width : 1, height - type.InteriorSize.Height, type.InteriorSize.Width, type.InteriorSize.Height); for (int i = 0; i < outputLeftX.Length; i++) { outputLeftX[i] = width - PinMargin - m_pinSize - outputLeftX[i]; } return(new ElementSizeInfo(size, interior, outputLeftX)); }
private void Draw(TElement element, Graphics g) { ElementTypeInfo info = GetElementTypeInfo(element, g); Point p = element.Bounds.Location; Rectangle bounds = new Rectangle(p, info.Size); // clip to window if (g.ClipBounds.IntersectsWith(bounds)) { ICircuitElementType type = element.Type; if (info.Path == null) { BuildGraphics(type, info, g); } s_pathTransform.Translate(p.X, p.Y); info.Path.Transform(s_pathTransform); // try to use custom brush if registered Brush fillBrush = m_theme.GetCustomBrush(type.Name); if (fillBrush != null) { g.FillPath(fillBrush, info.Path); } else { // use a default brush using (LinearGradientBrush lgb = new LinearGradientBrush( bounds, Color.White, Color.LightSteelBlue, LinearGradientMode.Vertical)) { g.FillPath(lgb, info.Path); } } g.DrawPath(m_theme.OutlinePen, info.Path); int titleHeight = m_rowSpacing + PinMargin; g.DrawLine(m_theme.OutlinePen, p.X, p.Y + titleHeight, p.X + info.Size.Width, p.Y + titleHeight); g.DrawString(type.Name, m_theme.Font, m_theme.TextBrush, p.X + PinMargin + 1, p.Y + PinMargin + 1); int pinY = p.Y + titleHeight + PinMargin; foreach (TPin inputPin in type.Inputs) { Pen pen = GetPen(inputPin); if (pen != null) { g.DrawRectangle(pen, p.X + 1, pinY + m_pinOffset, m_pinSize, m_pinSize); } g.DrawString(inputPin.Name, m_theme.Font, m_theme.TextBrush, p.X + m_pinSize + PinMargin, pinY); pinY += m_rowSpacing; } pinY = p.Y + titleHeight + PinMargin; int i = 0; foreach (TPin outputPin in type.Outputs) { Pen pen = GetPen(outputPin); if (pen != null) { g.DrawRectangle(pen, p.X + info.Size.Width - m_pinSize, pinY + m_pinOffset, m_pinSize, m_pinSize); } g.DrawString(outputPin.Name, m_theme.Font, m_theme.TextBrush, p.X + info.OutputLeftX[i], pinY); pinY += m_rowSpacing; i++; } Image image = type.Image; if (image != null) { g.DrawImage(image, p.X + info.Interior.X, p.Y + info.Interior.Y, info.Interior.Width, info.Interior.Height); } s_pathTransform.Translate(-2 * p.X, -2 * p.Y); info.Path.Transform(s_pathTransform); s_pathTransform.Reset(); string name = element.Name; if (!string.IsNullOrEmpty(name)) { RectangleF alignRect = new RectangleF( bounds.Left - MaxNameOverhang, bounds.Bottom + PinMargin, bounds.Width + 2 * MaxNameOverhang, m_rowSpacing); g.DrawString(name, m_theme.Font, m_theme.TextBrush, alignRect, m_theme.CenterStringFormat); } } }