diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 957acfcd2..df6e3dae7 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -222,11 +222,11 @@ namespace Greenshot.Drawing { [NonSerialized] // will store current bounds of this DrawableContainer before starting a resize - private Rectangle _boundsBeforeResize = Rectangle.Empty; + protected Rectangle _boundsBeforeResize = Rectangle.Empty; [NonSerialized] // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) - private RectangleF _boundsAfterResize = RectangleF.Empty; + protected RectangleF _boundsAfterResize = RectangleF.Empty; public Rectangle Bounds { get { return GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); } @@ -449,6 +449,7 @@ namespace Greenshot.Drawing { } private void GripperMouseMove(object sender, MouseEventArgs e) { + Invalidate(); Gripper originatingGripper = (Gripper)sender; int absX = originatingGripper.Left + e.X; int absY = originatingGripper.Top + e.Y; @@ -463,7 +464,6 @@ namespace Greenshot.Drawing { MakeBoundsChangeUndoable(false); } - Invalidate(); SuspendLayout(); // reset "workbench" rectangle to current bounds @@ -479,8 +479,8 @@ namespace Greenshot.Drawing { ApplyBounds(_boundsAfterResize); ResumeLayout(); - Invalidate(); } + Invalidate(); } public bool hasFilters { diff --git a/Greenshot/Drawing/Gripper.cs b/Greenshot/Drawing/Gripper.cs index 99f4c1bcb..20413a0b6 100644 --- a/Greenshot/Drawing/Gripper.cs +++ b/Greenshot/Drawing/Gripper.cs @@ -22,10 +22,9 @@ using System.Drawing; using System.Windows.Forms; -namespace Greenshot.Drawing -{ +namespace Greenshot.Drawing { /// - /// Description of Gripper. + /// Grippers are the dragable edges of our containers /// public class Gripper : Label { /// @@ -34,38 +33,24 @@ namespace Greenshot.Drawing /// 7 3 /// 6 5 4 /// - public const int POSITION_TOP_LEFT = 0; - public const int POSITION_TOP_CENTER = 1; - public const int POSITION_TOP_RIGHT = 2; - public const int POSITION_MIDDLE_RIGHT = 3; - public const int POSITION_BOTTOM_RIGHT = 4; + public const int POSITION_TOP_LEFT = 0; + public const int POSITION_TOP_CENTER = 1; + public const int POSITION_TOP_RIGHT = 2; + public const int POSITION_MIDDLE_RIGHT = 3; + public const int POSITION_BOTTOM_RIGHT = 4; public const int POSITION_BOTTOM_CENTER = 5; - public const int POSITION_BOTTOM_LEFT = 6; - public const int POSITION_MIDDLE_LEFT = 7; - - public int Position; - + public const int POSITION_BOTTOM_LEFT = 6; + public const int POSITION_MIDDLE_LEFT = 7; + + public int Position { + get; + set; + } + public Gripper() { Width = 5; Height = 5; BackColor = Color.Black; - - } - - public bool IsTop() { - return Position == 0 || Position == 1 || Position == 2; - } - public bool IsRight() { - return Position == 2 || Position == 3 || Position == 4; - } - public bool IsBottom() { - return Position == 4 || Position == 5 || Position == 6; - } - public bool IsLeft() { - return Position == 6 || Position == 7 || Position == 0; - } - public bool IsCorner() { - return Position == 0 || Position == 2 || Position == 4 || Position == 6; } } } diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs index c51a719ba..4d227e086 100644 --- a/Greenshot/Drawing/RectangleContainer.cs +++ b/Greenshot/Drawing/RectangleContainer.cs @@ -18,13 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Drawing.Drawing2D; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Plugin.Drawing; -using log4net; namespace Greenshot.Drawing { /// @@ -32,7 +32,6 @@ namespace Greenshot.Drawing { /// [Serializable] public class RectangleContainer : DrawableContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(RectangleContainer)); public RectangleContainer(Surface parent) : base(parent) { } diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs index 4b134f45f..156564ddf 100644 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ b/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -1,251 +1,319 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Plugin; -using Greenshot.Plugin.Drawing; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using System.Windows.Forms; - -namespace Greenshot.Drawing { - /// - /// Description of SpeechbubbleContainer. - /// - [Serializable] - public class SpeechbubbleContainer : TextContainer { - - #region TargetGripper serializing code - // Only used for serializing the TargetGripper location - private Point _storedTargetGripperLocation; - - /// - /// Store the current location of the target gripper - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (TargetGripper != null) { - _storedTargetGripperLocation = TargetGripper.Location; - } - } - - /// - /// Restore the target gripper - /// - /// - [OnDeserialized] - private void SetValuesOnDeserialized(StreamingContext context) { - InitTargetGripper(Color.Green, _storedTargetGripperLocation); - } - #endregion - - public SpeechbubbleContainer(Surface parent) - : base(parent) { - } - - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); - //AddField(GetType(), FieldType.SHADOW, false); - AddField(GetType(), FieldType.FONT_ITALIC, false); - AddField(GetType(), FieldType.FONT_BOLD, true); - AddField(GetType(), FieldType.FILL_COLOR, Color.White); - AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); - AddField(GetType(), FieldType.FONT_SIZE, 20f); - AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center); - AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, VerticalAlignment.CENTER); - } - - protected override void TargetGripperMove(int absX, int absY) { - base.TargetGripperMove(absX, absY); - Invalidate(); - } - - /// - /// Called from Surface (the _parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - if (TargetGripper == null) { - InitTargetGripper(Color.Green, new Point(mouseX, mouseY)); - } - return base.HandleMouseDown(mouseX + 20, mouseY + 20); - } - - public override Rectangle DrawingBounds { - get { - // TODO: Use the normal bounds and extend with the TargetGripper - return new Rectangle(0, 0, _parent.Width, _parent.Height); - } - } - - 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(); - - Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); - // adapt corner radius to small rectangle dimensions - int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); - int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); - if (cornerRadius > 0) { - 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); - } else { - bubble.AddRectangle(bubbleRect); - } - 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, lineColor, false, StringFormat, Text, Font); - } - - public override bool Contains(int x, int y) { - double xDistanceFromCenter = x - (Left + Width / 2); - double yDistanceFromCenter = y - (Top + Height / 2); - // ellipse: x^2/a^2 + y^2/b^2 = 1 - return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(Height / 2, 2) < 1; - } - - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - int lineThicknessPlusSafety = lineThickness + 10; - - // If we clicked inside the rectangle and it's visible we are clickable at. - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - if (!Color.Transparent.Equals(fillColor)) { - if (Contains(x, y)) { - return true; - } - } - - // check the rest of the lines - if (lineThicknessPlusSafety > 0) { - using (Pen pen = new Pen(Color.White, lineThicknessPlusSafety)) { - using (GraphicsPath path = new GraphicsPath()) { - path.AddEllipse(rect); - return path.IsOutlineVisible(x, y, pen); - } - } - } else { - return false; - } - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Text; +using System.Runtime.Serialization; +using System.Windows.Forms; +using GreenshotPlugin.UnmanagedHelpers; +using log4net; + +namespace Greenshot.Drawing { + /// + /// Description of SpeechbubbleContainer. + /// + [Serializable] + public class SpeechbubbleContainer : TextContainer { + private static readonly ILog LOG = LogManager.GetLogger(typeof(RectangleContainer)); + + private Point _initialGripperPoint; + + #region TargetGripper serializing code + // Only used for serializing the TargetGripper location + private Point _storedTargetGripperLocation; + + /// + /// Store the current location of the target gripper + /// + /// + [OnSerializing] + private void SetValuesOnSerializing(StreamingContext context) { + if (TargetGripper != null) { + _storedTargetGripperLocation = TargetGripper.Location; + } + } + + /// + /// Restore the target gripper + /// + /// + [OnDeserialized] + private void SetValuesOnDeserialized(StreamingContext context) { + InitTargetGripper(Color.Green, _storedTargetGripperLocation); + } + #endregion + + public SpeechbubbleContainer(Surface parent) + : base(parent) { + } + + /// + /// We set our own field values + /// + protected override void InitializeFields() { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); + //AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.FONT_ITALIC, false); + AddField(GetType(), FieldType.FONT_BOLD, true); + AddField(GetType(), FieldType.FILL_COLOR, Color.White); + AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); + AddField(GetType(), FieldType.FONT_SIZE, 20f); + AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center); + AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, VerticalAlignment.CENTER); + } + + protected override void TargetGripperMove(int absX, int absY) { + base.TargetGripperMove(absX, absY); + Invalidate(); + } + + /// + /// Called from Surface (the _parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) { + if (TargetGripper == null) { + _initialGripperPoint = new Point(mouseX, mouseY); + InitTargetGripper(Color.Green, new Point(mouseX, mouseY)); + } + return base.HandleMouseDown(mouseX, mouseY); + } + + /// + /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. + /// Should fix BUG-1682 + /// + /// + /// + /// + public override bool HandleMouseMove(int x, int y) { + bool returnValue = base.HandleMouseMove(x, y); + Point newGripperLocation = _initialGripperPoint; + if (_boundsAfterResize.Right - _boundsAfterResize.Left >= 0) { + newGripperLocation.Offset(-20, 0); + } else { + newGripperLocation.Offset(20, 0); + } + if (_boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0) { + newGripperLocation.Offset(0, -20); + } else { + newGripperLocation.Offset(0, 20); + } + if (TargetGripper.Location != newGripperLocation) { + TargetGripperMove(newGripperLocation.X, newGripperLocation.Y); + } + return returnValue; + } + + /// + /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. + /// + public override Rectangle DrawingBounds { + get { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using (Pen pen = new Pen(lineColor, lineThickness)) { + using (GraphicsPath tailPath = CreateTail()) { + return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)),GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), lineThickness+2, lineThickness+2); + } + } + } + } + + /// + /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds + /// + /// + /// + private GraphicsPath CreateBubble(int lineThickness) { + GraphicsPath bubble = new GraphicsPath(); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); + // adapt corner radius to small rectangle dimensions + int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); + int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); + if (cornerRadius > 0) { + 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); + } else { + bubble.AddRectangle(bubbleRect); + } + bubble.CloseAllFigures(); + using (Matrix bubbleMatrix = new Matrix()) { + bubbleMatrix.Translate(rect.Left, rect.Top); + bubble.Transform(bubbleMatrix); + } + return bubble; + } + + /// + /// Helper method to create the tail of the bubble, so we can also calculate the bounds + /// + /// + 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; + } + + /// + /// This is to draw the actual container + /// + /// + /// + 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); + } + + GraphicsPath bubble = CreateBubble(lineThickness); + + GraphicsPath tail = CreateTail(); + GraphicsState state = graphics.Save(); + // draw the tail border where the bubble is not visible + using (Region clipRegion = new Region(bubble)) { + graphics.SetClip(clipRegion, CombineMode.Exclude); + using (Pen pen = new Pen(lineColor, lineThickness)) { + graphics.DrawPath(pen, tail); + } + } + graphics.Restore(state); + + if (Colors.IsVisible(fillColor)) { + //draw the bubbleshape + state = graphics.Save(); + 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)) { + graphics.SetClip(clipRegion, CombineMode.Exclude); + 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(); + 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, lineColor, false, StringFormat, Text, Font); + } + + public override bool Contains(int x, int y) { + double xDistanceFromCenter = x - (Left + Width / 2); + double yDistanceFromCenter = y - (Top + Height / 2); + // ellipse: x^2/a^2 + y^2/b^2 = 1 + return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(Height / 2, 2) < 1; + } + + public override bool ClickableAt(int x, int y) { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + int lineThicknessPlusSafety = lineThickness + 10; + + // If we clicked inside the rectangle and it's visible we are clickable at. + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + if (!Color.Transparent.Equals(fillColor)) { + if (Contains(x, y)) { + return true; + } + } + + // check the rest of the lines + if (lineThicknessPlusSafety > 0) { + using (Pen pen = new Pen(Color.White, lineThicknessPlusSafety)) { + using (GraphicsPath path = new GraphicsPath()) { + path.AddEllipse(rect); + return path.IsOutlineVisible(x, y, pen); + } + } + } + return false; + } + } +} diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs index 86e358e5c..79583c5ab 100644 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ b/Greenshot/Drawing/StepLabelContainer.cs @@ -30,7 +30,6 @@ using System.Runtime.Serialization; namespace Greenshot.Drawing { /// - /// Description of StepLabelContainer. /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. /// To make sure that deleting recalculates, we check the location before every draw. /// diff --git a/GreenshotBoxPlugin/BoxUtils.cs b/GreenshotBoxPlugin/BoxUtils.cs index 3610cca74..e71b57aa5 100644 --- a/GreenshotBoxPlugin/BoxUtils.cs +++ b/GreenshotBoxPlugin/BoxUtils.cs @@ -71,7 +71,7 @@ namespace GreenshotBoxPlugin { /// /// string with the file content public static string PostAndReturn(Uri url, string postMessage) { - HttpWebRequest webRequest = (HttpWebRequest)NetworkHelper.CreateWebRequest(url); + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url); webRequest.Method = "POST"; webRequest.KeepAlive = true; webRequest.Credentials = CredentialCache.DefaultCredentials;