/// <summary> /// ChangeRule: typeof(ORMSolutions.ORMArchitect.Core.ObjectModel.ValueComparisonConstraint), FireTime=TopLevelCommit, Priority=DiagramFixupConstants.AddConnectionRulePriority; /// </summary> private static void ValueComparisonConstraintPropertyChangeRule(ElementPropertyChangedEventArgs e) { if (e.DomainProperty.Id == ValueComparisonConstraint.OperatorDomainPropertyId) { ModelElement element = e.ModelElement; if (!element.IsDeleted) { // Redraw the ring constraint wherever it is displayed. foreach (PresentationElement pel in PresentationViewsSubject.GetPresentation(element)) { ValueComparisonConstraintShape constraintShape; if (null != (constraintShape = pel as ValueComparisonConstraintShape)) { ((IInvalidateDisplay)constraintShape).InvalidateRequired(true); if (ValueComparisonConstraint.IsDirectionalOperator((ValueComparisonOperator)e.OldValue) ^ ValueComparisonConstraint.IsDirectionalOperator((ValueComparisonOperator)e.NewValue)) { foreach (LinkShape linkShape in LinkConnectsToNode.GetLink(constraintShape)) { ExternalConstraintLink constraintLink; if (null != (constraintLink = linkShape as ExternalConstraintLink)) { ((IInvalidateDisplay)constraintLink).InvalidateRequired(true); } } } } } } } }
/// <summary> /// Paint the shape contents based on the operator type. /// </summary> protected override void OnPaintShape(DiagramPaintEventArgs e, ref PaintHelper helper) { base.OnPaintShape(e, ref helper); ValueComparisonConstraint comparisonConstraint = this.AssociatedValueComparisonConstraint; RectangleD bounds = this.AbsoluteBounds; RectangleF boundsF = RectangleD.ToRectangleF(bounds); Graphics g = e.Graphics; ValueComparisonOperator comparisonOperator = comparisonConstraint.Operator; Brush brush = helper.Brush; // Draw the left and right comparison dots float heightF = boundsF.Height; float dotDiameter = heightF * DOT_FACTOR; float dotRadius = dotDiameter / 2; float dotTop = boundsF.Top + heightF / 2 - dotRadius; g.FillEllipse(brush, boundsF.Left - dotRadius, dotTop, dotDiameter, dotDiameter); g.FillEllipse(brush, boundsF.Right - dotRadius, dotTop, dotDiameter, dotDiameter); if (comparisonOperator != ValueComparisonOperator.Undefined) // Undefined just draws the error state { // Draw the operator using a different pen. Pen pen = StyleSet.GetPen(OperatorResource); // Get the correct pen color from the provided outline pen Color startColor = pen.Color; Color shapeColor = helper.Pen.Color; // The paint helper has already updated the color, just use it. bool updateColor; if (updateColor = (startColor != shapeColor)) { pen.Color = shapeColor; } // Get a clipping rectangle we can draw inside of. This // gives us a nice vertical clip on the open side of the // comparator, as well as a region safely inside the shape // outline. const double inscribedRectAngle = 1d / 3 * Math.PI; // 60 degrees from center point of shape to shape border. const float equalsOffsetFactor = .8f; const double noEqualityPiDivisor = 6d; // 30 degree angle on comparator line const double withEqualityPiDivisor = 7.5d; // 24 degree angle on comparator line double inscribedCos = Math.Cos(inscribedRectAngle); double inscribedSin = Math.Sin(inscribedRectAngle); double width = bounds.Width; double height = bounds.Height; bounds = new RectangleD( bounds.Left + (1 - inscribedCos) * width / 2, bounds.Top + (1 - inscribedSin) * height / 2, inscribedCos * width, inscribedSin * height); //width = bounds.Width; // not used below height = bounds.Height; boundsF = RectangleD.ToRectangleF(bounds); bool drawComparator = true; bool drawEquality = false; bool slashEquality = false; float penWidth = pen.Width; float openSideX = 0f; float closedSideX = 0f; switch (comparisonOperator) { case ValueComparisonOperator.LessThanOrEqual: drawEquality = true; goto case ValueComparisonOperator.LessThan; case ValueComparisonOperator.LessThan: openSideX = boundsF.Right; closedSideX = boundsF.Left + penWidth / 2; break; case ValueComparisonOperator.GreaterThanOrEqual: drawEquality = true; goto case ValueComparisonOperator.GreaterThan; case ValueComparisonOperator.GreaterThan: openSideX = boundsF.Left; closedSideX = boundsF.Right - penWidth / 2; break; case ValueComparisonOperator.Equal: drawComparator = false; drawEquality = true; break; case ValueComparisonOperator.NotEqual: drawComparator = false; drawEquality = true; slashEquality = true; break; } double halfHeight = height / 2; double top = bounds.Top; float middle = (float)(top + halfHeight); float topTip; float bottomTip; if (drawComparator) { g.SetClip(boundsF); // Use a path so that we get a clean join between the top and bottom lines. float equalsOffset = drawEquality ? penWidth * equalsOffsetFactor : 0f; double offsetSin = Math.Sin(Math.PI / (drawEquality ? withEqualityPiDivisor : noEqualityPiDivisor)); topTip = (float)(top + halfHeight * (1d - offsetSin)); bottomTip = (float)(top + halfHeight * (1d + offsetSin)); using (GraphicsPath path = new GraphicsPath()) { path.AddLines(new PointF[] { new PointF(openSideX, topTip - equalsOffset), new PointF(closedSideX, middle - equalsOffset), new PointF(openSideX, bottomTip - equalsOffset) }); g.DrawPath(pen, path); } if (drawEquality) { bottomTip += equalsOffset; g.DrawLine( pen, boundsF.Left, bottomTip, boundsF.Right, bottomTip); } } else if (drawEquality) { g.SetClip(boundsF); openSideX = boundsF.Left; // Convenient variables, used for left and right closedSideX = boundsF.Right; float equalsOffset = 1.5f * penWidth; topTip = middle - equalsOffset; bottomTip = middle + equalsOffset; g.DrawLine(pen, openSideX, topTip, closedSideX, topTip); g.DrawLine(pen, openSideX, bottomTip, closedSideX, bottomTip); if (slashEquality) { // Clip tighter so that the top and bottom of the lines // are clipped horizontally and don't touch the edge lines. g.ResetClip(); boundsF.Inflate(0f, -penWidth * 1.25f); g.SetClip(boundsF); g.DrawLine(pen, openSideX + penWidth, boundsF.Bottom, closedSideX - penWidth, boundsF.Top); } } g.ResetClip(); // Restore the pen color if (updateColor) { pen.Color = startColor; } } }