/// <summary> /// Helper method to create the tail of the bubble, so we can also calculate the bounds /// </summary> /// <returns></returns> private GraphicsPath CreateTail() { Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetGripper.Left, TargetGripper.Top); int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; // This should fix a problem with the tail being to wide tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); GraphicsPath tail = new GraphicsPath(); tail.AddLine(-tailWidth, 0, tailWidth, 0); tail.AddLine(tailWidth, 0, 0, -tailLength); tail.CloseFigure(); int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetGripper.Left, TargetGripper.Top); using (Matrix tailMatrix = new Matrix()) { tailMatrix.Translate(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2)); tailMatrix.Rotate(tailAngle); tail.Transform(tailMatrix); } return(tail); }
/// <summary> /// Helper method to create the tail of the bubble, so we can also calculate the bounds /// </summary> /// <returns></returns> private GraphicsPath CreateTail() { var rect = new NativeRect(Left, Top, Width, Height).Normalize(); var tailLength = GeometryHelper.Distance2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); var tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; // This should fix a problem with the tail being to wide tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); var tail = new GraphicsPath(); tail.AddLine(-tailWidth, 0, tailWidth, 0); tail.AddLine(tailWidth, 0, 0, -tailLength); tail.CloseFigure(); var tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); using (var tailMatrix = new Matrix()) { tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); tailMatrix.Rotate(tailAngle); tail.Transform(tailMatrix); } return(tail); }
public override void Draw(Graphics graphics, RenderMode renderMode) { if (TargetGripper == null) { return; } graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.None; graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); bool lineVisible = (lineThickness > 0 && Colors.IsVisible(lineColor)); Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); if (Selected && renderMode == RenderMode.EDIT) { DrawSelectionBorder(graphics, rect); } int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetGripper.Left, TargetGripper.Top); int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetGripper.Left, TargetGripper.Top); int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; GraphicsPath bubble = new GraphicsPath(); // adapt corner radius to small rectangle dimensions int smallerSideLength = Math.Min(rect.Width, rect.Height); int cornerRadius = smallerSideLength > 60 ? 30 : smallerSideLength / 2; if (cornerRadius > 5) { Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); bubbleRect = Rectangle.Inflate(bubbleRect, -lineThickness, -lineThickness); bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); } //bubble.AddRectangle(GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height)); //bubble.AddEllipse(0, 0, Math.Abs(rect.Width), Math.Abs(rect.Height)); bubble.CloseAllFigures(); GraphicsPath tail = new GraphicsPath(); tail.AddLine(-tailWidth, 0, tailWidth, 0); tail.AddLine(tailWidth, 0, 0, -tailLength); tail.CloseFigure(); GraphicsState state = graphics.Save(); // draw the tail border where the bubble is not visible using (Region clipRegion = new Region(bubble)) { clipRegion.Translate(rect.Left, rect.Top); graphics.SetClip(clipRegion, CombineMode.Exclude); graphics.TranslateTransform(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2)); graphics.RotateTransform(tailAngle); using (Pen pen = new Pen(lineColor, lineThickness)) { graphics.DrawPath(pen, tail); } } graphics.Restore(state); if (Colors.IsVisible(fillColor)) { //draw the bubbleshape state = graphics.Save(); graphics.TranslateTransform(rect.Left, rect.Top); using (Brush brush = new SolidBrush(fillColor)) { graphics.FillPath(brush, bubble); } graphics.Restore(state); } if (lineVisible) { //draw the bubble border state = graphics.Save(); // Draw bubble where the Tail is not visible. using (Region clipRegion = new Region(tail)) { using (Matrix transformMatrix = new Matrix()) { transformMatrix.Rotate(tailAngle); clipRegion.Transform(transformMatrix); } clipRegion.Translate(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2)); graphics.SetClip(clipRegion, CombineMode.Exclude); graphics.TranslateTransform(rect.Left, rect.Top); using (Pen pen = new Pen(lineColor, lineThickness)) { //pen.EndCap = pen.StartCap = LineCap.Round; graphics.DrawPath(pen, bubble); } } graphics.Restore(state); } if (Colors.IsVisible(fillColor)) { // Draw the tail border state = graphics.Save(); graphics.TranslateTransform(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2)); graphics.RotateTransform(tailAngle); using (Brush brush = new SolidBrush(fillColor)) { graphics.FillPath(brush, tail); } graphics.Restore(state); } // cleanup the paths bubble.Dispose(); tail.Dispose(); // Draw the text UpdateFormat(); DrawText(graphics, rect, lineThickness, ControlPaint.Dark(lineColor, 0.25f), false, StringFormat, Text, Font); }