From ff3f898f541de75ab2c58f5ec7ee21d385f938ae Mon Sep 17 00:00:00 2001 From: RKrom Date: Fri, 23 May 2014 15:49:14 +0200 Subject: [PATCH] As 2.x takes longer as planned, I added the SpeechbubbleContainer and StepLabelContainer (Enumerable label) to the 1.2 branch. This code was stored somewhere on my hard-drive, is still experimental. --- Greenshot/Drawing/ArrowContainer.cs | 6 + Greenshot/Drawing/CropContainer.cs | 13 +- Greenshot/Drawing/DrawableContainer.cs | 264 +++++++++++------- Greenshot/Drawing/DrawableContainerList.cs | 2 +- Greenshot/Drawing/EllipseContainer.cs | 5 +- Greenshot/Drawing/FilterContainer.cs | 3 + Greenshot/Drawing/FreehandContainer.cs | 17 +- Greenshot/Drawing/HighlightContainer.cs | 14 +- Greenshot/Drawing/ImageContainer.cs | 5 +- Greenshot/Drawing/LineContainer.cs | 7 +- Greenshot/Drawing/ObfuscateContainer.cs | 6 +- Greenshot/Drawing/RectangleContainer.cs | 4 +- Greenshot/Drawing/SpeechbubbleContainer.cs | 203 ++++++++++++++ Greenshot/Drawing/StepLabelContainer.cs | 81 ++++++ Greenshot/Drawing/Surface.cs | 25 +- Greenshot/Drawing/TextContainer.cs | 83 +++--- Greenshot/Forms/ImageEditorForm.Designer.cs | 28 ++ Greenshot/Forms/ImageEditorForm.cs | 17 +- Greenshot/Greenshot.csproj | 2 + .../Interfaces/Drawing/Container.cs | 3 + GreenshotPlugin/Interfaces/Generic.cs | 26 +- 21 files changed, 648 insertions(+), 166 deletions(-) create mode 100644 Greenshot/Drawing/SpeechbubbleContainer.cs create mode 100644 Greenshot/Drawing/StepLabelContainer.cs diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs index 9958271ad..af3586df4 100644 --- a/Greenshot/Drawing/ArrowContainer.cs +++ b/Greenshot/Drawing/ArrowContainer.cs @@ -36,6 +36,12 @@ namespace Greenshot.Drawing { private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); public ArrowContainer(Surface parent) : base(parent) { + } + + /// + /// Do not use the base, just override so we have our own defaults + /// + protected override void InitializeFields() { AddField(GetType(), FieldType.ARROWHEADS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index 6a6aa20f4..a9363ec86 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -30,11 +30,14 @@ namespace Greenshot.Drawing { /// public class CropContainer : DrawableContainer { public CropContainer(Surface parent) : base(parent) { + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.FLAGS, FieldType.Flag.CONFIRMABLE); } public override void Invalidate() { - parent.Invalidate(); + _parent.Invalidate(); } /// @@ -43,7 +46,7 @@ namespace Greenshot.Drawing { /// public override Rectangle DrawingBounds { get { - return new Rectangle(0,0,parent.Width, parent.Height); + return new Rectangle(0,0,_parent.Width, _parent.Height); } } @@ -55,13 +58,13 @@ namespace Greenshot.Drawing { DrawSelectionBorder(g, selectionRect); // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, parent.Width, cropRectangle.Top)); + g.FillRectangle(cropBrush, new Rectangle(0, 0, _parent.Width, cropRectangle.Top)); // left g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); // right - g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, parent.Width, parent.Height - (cropRectangle.Top + cropRectangle.Height))); + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height))); } } diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 39a294fa1..96bf8d41f 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -18,22 +18,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; +using Greenshot.IniFile; +using Greenshot.Memento; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; +using log4net; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using Greenshot.Helpers; -using Greenshot.Plugin; -using Greenshot.Plugin.Drawing; -using Greenshot.Memento; using System.Drawing.Drawing2D; -using Greenshot.Configuration; -using Greenshot.IniFile; -using log4net; +using System.Windows.Forms; namespace Greenshot.Drawing { /// @@ -42,12 +42,19 @@ namespace Greenshot.Drawing { /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call /// OnPropertyChanged whenever a public property has been changed. /// - [Serializable()] + [Serializable] public abstract class DrawableContainer : AbstractFieldHolderWithChildren, INotifyPropertyChanged, IDrawableContainer { private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); protected static readonly EditorConfiguration editorConfig = IniConfig.GetIniSection(); private bool isMadeUndoable = false; + protected EditStatus _defaultEditMode = EditStatus.DRAWING; + public EditStatus DefaultEditMode { + get { + return _defaultEditMode; + } + } + public virtual void Dispose() { Dispose(true); GC.SuppressFinalize(this); @@ -55,17 +62,17 @@ namespace Greenshot.Drawing { protected virtual void Dispose(bool disposing) { if (disposing) { - if (grippers != null) { - for (int i = 0; i < grippers.Length; i++) { - if (grippers[i] != null) { - grippers[i].Dispose(); - grippers[i] = null; + if (_grippers != null) { + for (int i = 0; i < _grippers.Length; i++) { + if (_grippers[i] != null) { + _grippers[i].Dispose(); + _grippers[i] = null; } } - grippers = null; + _grippers = null; } - FieldAggregator aggProps = parent.FieldAggregator; + FieldAggregator aggProps = _parent.FieldAggregator; aggProps.UnbindElement(this); } } @@ -94,33 +101,42 @@ namespace Greenshot.Drawing { } [NonSerialized] - internal Surface parent; + internal Surface _parent; public ISurface Parent { - get { return parent; } + get { return _parent; } set { SwitchParent((Surface)value); } } [NonSerialized] - protected Gripper[] grippers; + protected Gripper[] _grippers; private bool layoutSuspended = false; - + [NonSerialized] - private bool selected = false; + private Gripper _targetGripper; + + public Gripper TargetGripper { + get { + return _targetGripper; + } + } + + [NonSerialized] + private bool _selected = false; public bool Selected { - get {return selected;} + get {return _selected;} set { - selected = value; + _selected = value; OnPropertyChanged("Selected"); } } [NonSerialized] - private EditStatus status = EditStatus.UNDRAWN; + private EditStatus _status = EditStatus.UNDRAWN; public EditStatus Status { get { - return status; + return _status; } set { - status = value; + _status = value; } } @@ -211,7 +227,8 @@ namespace Greenshot.Drawing { } public DrawableContainer(Surface parent) { - this.parent = parent; + InitializeFields(); + this._parent = parent; InitControls(); } @@ -240,7 +257,7 @@ namespace Greenshot.Drawing { get { foreach(IFilter filter in Filters) { if (filter.Invert) { - return new Rectangle(Point.Empty, parent.Image.Size); + return new Rectangle(Point.Empty, _parent.Image.Size); } } // Take a base safetymargin @@ -260,7 +277,7 @@ namespace Greenshot.Drawing { } public virtual void Invalidate() { - parent.Invalidate(DrawingBounds); + _parent.Invalidate(DrawingBounds); } public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { @@ -270,20 +287,20 @@ namespace Greenshot.Drawing { Left = lineThickness/2; } if (horizontalAlignment == HorizontalAlignment.Right) { - Left = parent.Width - Width - lineThickness/2; + Left = _parent.Width - Width - lineThickness/2; } if (horizontalAlignment == HorizontalAlignment.Center) { - Left = (parent.Width / 2) - (Width / 2) - lineThickness/2; + Left = (_parent.Width / 2) - (Width / 2) - lineThickness/2; } if (verticalAlignment == VerticalAlignment.TOP) { Top = lineThickness/2; } if (verticalAlignment == VerticalAlignment.BOTTOM) { - Top = parent.Height - Height - lineThickness/2; + Top = _parent.Height - Height - lineThickness/2; } if (verticalAlignment == VerticalAlignment.CENTER) { - Top = (parent.Height / 2) - (Height / 2) - lineThickness/2; + Top = (_parent.Height / 2) - (Height / 2) - lineThickness/2; } } @@ -296,24 +313,54 @@ namespace Greenshot.Drawing { DoLayout(); } - - protected void InitGrippers() { - grippers = new Gripper[8]; - for(int i=0; i + /// Should be overridden to handle gripper moves on the "TargetGripper" + /// + /// + /// + protected virtual void TargetGripperMove(int newX, int newY) { + _targetGripper.Left = newX; + _targetGripper.Top = newY; + } + + /// + /// Initialize a target gripper + /// + protected void InitTargetGripper(Color gripperColor, Point location) { + _targetGripper = new Gripper { + Cursor = Cursors.SizeAll, + BackColor = gripperColor, + Visible = false, + Parent = _parent, + Location = location + }; + _targetGripper.MouseDown += gripperMouseDown; + _targetGripper.MouseUp += gripperMouseUp; + _targetGripper.MouseMove += gripperMouseMove; + if (_parent != null) { + _parent.Controls.Add(_targetGripper); // otherwise we'll attach them in switchParent } - grippers[Gripper.POSITION_TOP_CENTER].Cursor = Cursors.SizeNS; - grippers[Gripper.POSITION_MIDDLE_RIGHT].Cursor = Cursors.SizeWE; - grippers[Gripper.POSITION_BOTTOM_CENTER].Cursor = Cursors.SizeNS; - grippers[Gripper.POSITION_MIDDLE_LEFT].Cursor = Cursors.SizeWE; - if (parent != null) { - parent.Controls.AddRange(grippers); // otherwise we'll attach them in switchParent + } + + protected void InitGrippers() { + + _grippers = new Gripper[8]; + for(int i=0; i<_grippers.Length; i++) { + _grippers[i] = new Gripper(); + _grippers[i].Position = i; + _grippers[i].MouseDown += gripperMouseDown; + _grippers[i].MouseUp += gripperMouseUp; + _grippers[i].MouseMove += gripperMouseMove; + _grippers[i].Visible = false; + _grippers[i].Parent = _parent; + } + _grippers[Gripper.POSITION_TOP_CENTER].Cursor = Cursors.SizeNS; + _grippers[Gripper.POSITION_MIDDLE_RIGHT].Cursor = Cursors.SizeWE; + _grippers[Gripper.POSITION_BOTTOM_CENTER].Cursor = Cursors.SizeNS; + _grippers[Gripper.POSITION_MIDDLE_LEFT].Cursor = Cursors.SizeWE; + if (_parent != null) { + _parent.Controls.AddRange(_grippers); // otherwise we'll attach them in switchParent } } @@ -327,40 +374,40 @@ namespace Greenshot.Drawing { } protected virtual void DoLayout() { - if (grippers == null) { + if (_grippers == null) { return; } if (!layoutSuspended) { int[] xChoords = new int[]{Left-2,Left+Width/2-2,Left+Width-2}; int[] yChoords = new int[]{Top-2,Top+Height/2-2,Top+Height-2}; - grippers[Gripper.POSITION_TOP_LEFT].Left = xChoords[0]; grippers[Gripper.POSITION_TOP_LEFT].Top = yChoords[0]; - grippers[Gripper.POSITION_TOP_CENTER].Left = xChoords[1]; grippers[Gripper.POSITION_TOP_CENTER].Top = yChoords[0]; - grippers[Gripper.POSITION_TOP_RIGHT].Left = xChoords[2]; grippers[Gripper.POSITION_TOP_RIGHT].Top = yChoords[0]; - grippers[Gripper.POSITION_MIDDLE_RIGHT].Left = xChoords[2]; grippers[Gripper.POSITION_MIDDLE_RIGHT].Top = yChoords[1]; - grippers[Gripper.POSITION_BOTTOM_RIGHT].Left = xChoords[2]; grippers[Gripper.POSITION_BOTTOM_RIGHT].Top = yChoords[2]; - grippers[Gripper.POSITION_BOTTOM_CENTER].Left = xChoords[1]; grippers[Gripper.POSITION_BOTTOM_CENTER].Top = yChoords[2]; - grippers[Gripper.POSITION_BOTTOM_LEFT].Left = xChoords[0]; grippers[Gripper.POSITION_BOTTOM_LEFT].Top = yChoords[2]; - grippers[Gripper.POSITION_MIDDLE_LEFT].Left = xChoords[0]; grippers[Gripper.POSITION_MIDDLE_LEFT].Top = yChoords[1]; + _grippers[Gripper.POSITION_TOP_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_TOP_LEFT].Top = yChoords[0]; + _grippers[Gripper.POSITION_TOP_CENTER].Left = xChoords[1]; _grippers[Gripper.POSITION_TOP_CENTER].Top = yChoords[0]; + _grippers[Gripper.POSITION_TOP_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_TOP_RIGHT].Top = yChoords[0]; + _grippers[Gripper.POSITION_MIDDLE_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_MIDDLE_RIGHT].Top = yChoords[1]; + _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left = xChoords[2]; _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top = yChoords[2]; + _grippers[Gripper.POSITION_BOTTOM_CENTER].Left = xChoords[1]; _grippers[Gripper.POSITION_BOTTOM_CENTER].Top = yChoords[2]; + _grippers[Gripper.POSITION_BOTTOM_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_BOTTOM_LEFT].Top = yChoords[2]; + _grippers[Gripper.POSITION_MIDDLE_LEFT].Left = xChoords[0]; _grippers[Gripper.POSITION_MIDDLE_LEFT].Top = yChoords[1]; - if((grippers[Gripper.POSITION_TOP_LEFT].Left < grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top < grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || - grippers[Gripper.POSITION_TOP_LEFT].Left > grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top > grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { - grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNWSE; - grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNESW; - grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNWSE; - grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNESW; - } else if((grippers[Gripper.POSITION_TOP_LEFT].Left > grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top < grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || - grippers[Gripper.POSITION_TOP_LEFT].Left < grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && grippers[Gripper.POSITION_TOP_LEFT].Top > grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { - grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNESW; - grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNWSE; - grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNESW; - grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNWSE; - } else if (grippers[Gripper.POSITION_TOP_LEFT].Left == grippers[Gripper.POSITION_BOTTOM_RIGHT].Left) { - grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNS; - grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNS; - } else if (grippers[Gripper.POSITION_TOP_LEFT].Top == grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { - grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeWE; - grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeWE; + if((_grippers[Gripper.POSITION_TOP_LEFT].Left < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || + _grippers[Gripper.POSITION_TOP_LEFT].Left > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + _grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNWSE; + _grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNESW; + _grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNWSE; + _grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNESW; + } else if((_grippers[Gripper.POSITION_TOP_LEFT].Left > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) || + _grippers[Gripper.POSITION_TOP_LEFT].Left < _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left && _grippers[Gripper.POSITION_TOP_LEFT].Top > _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + _grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNESW; + _grippers[Gripper.POSITION_TOP_RIGHT].Cursor = Cursors.SizeNWSE; + _grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNESW; + _grippers[Gripper.POSITION_BOTTOM_LEFT].Cursor = Cursors.SizeNWSE; + } else if (_grippers[Gripper.POSITION_TOP_LEFT].Left == _grippers[Gripper.POSITION_BOTTOM_RIGHT].Left) { + _grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeNS; + _grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeNS; + } else if (_grippers[Gripper.POSITION_TOP_LEFT].Top == _grippers[Gripper.POSITION_BOTTOM_RIGHT].Top) { + _grippers[Gripper.POSITION_TOP_LEFT].Cursor = Cursors.SizeWE; + _grippers[Gripper.POSITION_BOTTOM_RIGHT].Cursor = Cursors.SizeWE; } } } @@ -385,7 +432,12 @@ namespace Greenshot.Drawing { } private void gripperMouseMove(object sender, MouseEventArgs e) { - if(Status.Equals(EditStatus.RESIZING)) { + Gripper originatingGripper = (Gripper)sender; + int absX = originatingGripper.Left + e.X; + int absY = originatingGripper.Top + e.Y; + if (originatingGripper == _targetGripper && Status.Equals(EditStatus.MOVING)) { + TargetGripperMove(absX, absY); + } else if (Status.Equals(EditStatus.RESIZING)) { // check if we already made this undoable if (!isMadeUndoable) { // don't allow another undo until we are finished with this move @@ -397,10 +449,6 @@ namespace Greenshot.Drawing { Invalidate(); SuspendLayout(); - Gripper gr = (Gripper)sender; - int absX = gr.Left + e.X; - int absY = gr.Top + e.Y; - // reset "workbench" rectangle to current bounds boundsAfterResize.X = boundsBeforeResize.X; boundsAfterResize.Y = boundsBeforeResize.Y; @@ -408,7 +456,7 @@ namespace Greenshot.Drawing { boundsAfterResize.Height = boundsBeforeResize.Height; // calculate scaled rectangle - ScaleHelper.Scale(ref boundsAfterResize, gr.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions()); + ScaleHelper.Scale(ref boundsAfterResize, originatingGripper.Position, new PointF(absX, absY), ScaleHelper.GetScaleOptions()); // apply scaled bounds to this DrawableContainer ApplyBounds(boundsAfterResize); @@ -484,12 +532,12 @@ namespace Greenshot.Drawing { } public virtual void ShowGrippers() { - if (grippers != null) { - for (int i = 0; i < grippers.Length; i++) { - if (grippers[i].Enabled) { - grippers[i].Show(); + if (_grippers != null) { + for (int i = 0; i < _grippers.Length; i++) { + if (_grippers[i].Enabled) { + _grippers[i].Show(); } else { - grippers[i].Hide(); + _grippers[i].Hide(); } } } @@ -498,9 +546,9 @@ namespace Greenshot.Drawing { public void HideGrippers() { SuspendLayout(); - if (grippers != null) { - for (int i = 0; i < grippers.Length; i++) { - grippers[i].Hide(); + if (_grippers != null) { + for (int i = 0; i < _grippers.Length; i++) { + _grippers[i].Hide(); } } } @@ -517,7 +565,7 @@ namespace Greenshot.Drawing { /// /// true means allow the moves to be merged public void MakeBoundsChangeUndoable(bool allowMerge) { - parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); } public void MoveBy(int dx, int dy) { @@ -574,15 +622,15 @@ namespace Greenshot.Drawing { } private void SwitchParent(Surface newParent) { - if (parent != null && grippers != null) { - for (int i=0; iThe field to be changed /// The new value public virtual void BeforeFieldChange(Field fieldToBeChanged, object newValue) { - parent.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + _parent.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); Invalidate(); } @@ -653,15 +701,15 @@ namespace Greenshot.Drawing { GraphicsPath translatePath = new GraphicsPath(); translatePath.AddRectangle(beforeBounds); Matrix rotateMatrix = new Matrix(); - rotateMatrix.RotateAt(angle, new PointF(parent.Width >> 1, parent.Height >> 1)); + rotateMatrix.RotateAt(angle, new PointF(_parent.Width >> 1, _parent.Height >> 1)); translatePath.Transform(rotateMatrix); RectangleF newBounds = translatePath.GetBounds(); LOG.DebugFormat("New bounds by using graphics path: {0}", newBounds); int ox = 0; int oy = 0; - int centerX = parent.Width >> 1; - int centerY = parent.Height >> 1; + int centerX = _parent.Width >> 1; + int centerY = _parent.Height >> 1; // Transform from screen to normal coordinates int px = Left - centerX; int py = centerY - Top; @@ -717,5 +765,11 @@ namespace Greenshot.Drawing { throw new NotSupportedException("Object doesn't have a default size"); } } + + /// + /// Allows to override the initializing of the fields, so we can actually have our own defaults + /// + protected virtual void InitializeFields() { + } } } \ No newline at end of file diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 12dcf3ca8..62080def8 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -118,7 +118,7 @@ namespace Greenshot.Drawing { Surface surface = null; foreach(DrawableContainer dc in this) { movingList.Add(dc); - surface = dc.parent; + surface = dc._parent; } if (movingList.Count > 0 && surface != null) { surface.MakeUndoable(new DrawableContainerBoundsChangeMemento(movingList), allowMerge); diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs index ca1a3f5ed..dd3f61200 100644 --- a/Greenshot/Drawing/EllipseContainer.cs +++ b/Greenshot/Drawing/EllipseContainer.cs @@ -33,12 +33,15 @@ namespace Greenshot.Drawing { [Serializable()] public class EllipseContainer : DrawableContainer { public EllipseContainer(Surface parent) : base(parent) { + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); AddField(GetType(), FieldType.SHADOW, true); } - + public override void Draw(Graphics graphics, RenderMode renderMode) { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs index 583589a19..654e57ddb 100644 --- a/Greenshot/Drawing/FilterContainer.cs +++ b/Greenshot/Drawing/FilterContainer.cs @@ -40,6 +40,9 @@ namespace Greenshot.Drawing { } public FilterContainer(Surface parent) : base(parent) { + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.LINE_THICKNESS, 0); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.SHADOW, false); diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs index 2bd060e84..2b5fde975 100644 --- a/Greenshot/Drawing/FreehandContainer.cs +++ b/Greenshot/Drawing/FreehandContainer.cs @@ -49,19 +49,22 @@ namespace Greenshot.Drawing { /// public FreehandContainer(Surface parent) : base(parent) { Init(); - AddField(GetType(), FieldType.LINE_THICKNESS, 3); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); Width = parent.Width; Height = parent.Height; Top = 0; Left = 0; } + + protected override void InitializeFields() { + AddField(GetType(), FieldType.LINE_THICKNESS, 3); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + } protected void Init() { - if (grippers != null) { - for (int i = 0; i < grippers.Length; i++) { - grippers[i].Enabled = false; - grippers[i].Visible = false; + if (_grippers != null) { + for (int i = 0; i < _grippers.Length; i++) { + _grippers[i].Enabled = false; + _grippers[i].Visible = false; } } } @@ -229,7 +232,7 @@ namespace Greenshot.Drawing { int safetymargin = 10; return new Rectangle((myBounds.Left + Left) - (safetymargin+lineThickness), (myBounds.Top + Top) - (safetymargin+lineThickness), myBounds.Width + (2*(lineThickness+safetymargin)), myBounds.Height + (2*(lineThickness+safetymargin))); } - return new Rectangle(0, 0, parent.Width, parent.Height); + return new Rectangle(0, 0, _parent.Width, _parent.Height); } } diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs index 2f4e7fecb..4911b48fb 100644 --- a/Greenshot/Drawing/HighlightContainer.cs +++ b/Greenshot/Drawing/HighlightContainer.cs @@ -32,13 +32,17 @@ namespace Greenshot.Drawing { [Serializable] public class HighlightContainer : FilterContainer { public HighlightContainer(Surface parent) : base(parent) { - AddField(GetType(), FieldType.LINE_THICKNESS, 0); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); - AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); Init(); } - + + /// + /// Use settings from base, extend with our own field + /// + protected override void InitializeFields() { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); + } + [OnDeserialized] private void OnDeserialized(StreamingContext context) { Init(); diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs index 3d115f67e..6351bbb68 100644 --- a/Greenshot/Drawing/ImageContainer.cs +++ b/Greenshot/Drawing/ImageContainer.cs @@ -57,10 +57,13 @@ namespace Greenshot.Drawing { } public ImageContainer(Surface parent) : base(parent) { - AddField(GetType(), FieldType.SHADOW, false); FieldChanged += BitmapContainer_OnFieldChanged; } + protected override void InitializeFields() { + AddField(GetType(), FieldType.SHADOW, false); + } + protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { if (sender.Equals(this)) { if (e.Field.FieldType == FieldType.SHADOW) { diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs index 2fe79cf04..8b0393cf3 100644 --- a/Greenshot/Drawing/LineContainer.cs +++ b/Greenshot/Drawing/LineContainer.cs @@ -37,6 +37,9 @@ namespace Greenshot.Drawing { public LineContainer(Surface parent) : base(parent) { Init(); + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.SHADOW, true); @@ -50,9 +53,9 @@ namespace Greenshot.Drawing { } protected void Init() { - if (grippers != null) { + if (_grippers != null) { foreach (int index in new[] { 1, 2, 3, 5, 6, 7 }) { - grippers[index].Enabled = false; + _grippers[index].Enabled = false; } } } diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs index 572b70c6f..80a007931 100644 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ b/Greenshot/Drawing/ObfuscateContainer.cs @@ -30,9 +30,13 @@ namespace Greenshot.Drawing { [Serializable] public class ObfuscateContainer : FilterContainer { public ObfuscateContainer(Surface parent) : base(parent) { - AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); Init(); } + + protected override void InitializeFields() { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); + } [OnDeserialized] private void OnDeserialized(StreamingContext context) { diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs index 89b555a40..0c9f976f6 100644 --- a/Greenshot/Drawing/RectangleContainer.cs +++ b/Greenshot/Drawing/RectangleContainer.cs @@ -35,13 +35,15 @@ namespace Greenshot.Drawing { private static readonly ILog LOG = LogManager.GetLogger(typeof(RectangleContainer)); public RectangleContainer(Surface parent) : base(parent) { + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); AddField(GetType(), FieldType.SHADOW, true); } - public override void Draw(Graphics graphics, RenderMode rm) { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs new file mode 100644 index 000000000..e47ee0b68 --- /dev/null +++ b/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -0,0 +1,203 @@ +/* + * 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.Windows.Forms; + +namespace Greenshot.Drawing { + /// + /// Description of SpeechbubbleContainer. + /// + [Serializable()] + public class SpeechbubbleContainer : TextContainer { + public SpeechbubbleContainer(Surface parent) + : base(parent) { + } + + /// + /// We set our own field values + /// + protected override void InitializeFields() { + AddField(GetType(), FieldType.LINE_THICKNESS, 4); + AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); + AddField(GetType(), FieldType.SHADOW, true); + AddField(GetType(), FieldType.FONT_ITALIC, false); + AddField(GetType(), FieldType.FONT_BOLD, false); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + 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, mouseY); + } + + public override Rectangle DrawingBounds { + get { + 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; + + 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); + + int tailAngle = 90 + (int)GeometryHelper.Angle2D(Left + (Width / 2), Top + (Height / 2), TargetGripper.Left, TargetGripper.Top); + int tailLength = GeometryHelper.Distance2D(Left + (Width / 2), Top + (Height / 2), TargetGripper.Left, TargetGripper.Top); + int tailWidth = (Math.Abs(Width) + Math.Abs(Height)) / 20; + + GraphicsPath bubble = new GraphicsPath(); + 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(Left, Top); + graphics.SetClip(clipRegion, CombineMode.Exclude); + graphics.TranslateTransform(Left + (Width / 2), Top + (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(Left, 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)) { + Matrix transformMatrix = new Matrix(); + transformMatrix.Rotate(tailAngle); + clipRegion.Transform(transformMatrix); + clipRegion.Translate(Left + (Width / 2), Top + (Height / 2)); + graphics.SetClip(clipRegion, CombineMode.Exclude); + graphics.TranslateTransform(Left, Top); + using (Pen pen = new Pen(lineColor, lineThickness)) { + graphics.DrawPath(pen, bubble); + } + } + graphics.Restore(state); + } + + if (Colors.IsVisible(fillColor)) { + // Draw the tail border + state = graphics.Save(); + graphics.TranslateTransform(Left + (Width / 2), Top + (Height / 2)); + graphics.RotateTransform(tailAngle); + using (Brush brush = new SolidBrush(fillColor)) { + graphics.FillPath(brush, tail); + } + graphics.Restore(state); + } + + // Draw the text + StringFormat format = new StringFormat(); + format.Alignment = StringAlignment.Center; + format.LineAlignment = StringAlignment.Center; + DrawText(graphics, GuiRectangle.GetGuiRectangle(Left, Top, Width, Height), format); + + // cleanup + bubble.Dispose(); + tail.Dispose(); + } + + 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; + } + } + } +} diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs new file mode 100644 index 000000000..f238de252 --- /dev/null +++ b/Greenshot/Drawing/StepLabelContainer.cs @@ -0,0 +1,81 @@ +/* + * 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.Drawing; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; + +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. + /// + [Serializable()] + public class StepLabelContainer : TextContainer { + public StepLabelContainer(Surface parent) : base(parent) { + _defaultEditMode = EditStatus.IDLE; + parent.StepContainers.AddLast(this); + // Set defaults + Width = 40; + Height = 40; + } + + public override void Dispose() { + Parent.StepContainers.Remove(this); + base.Dispose(); + } + + /// + /// We set our own field values + /// + protected override void InitializeFields() { + AddField(GetType(), FieldType.LINE_COLOR, Color.White); + AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); + AddField(GetType(), FieldType.FONT_SIZE, 21f); + AddField(GetType(), FieldType.LINE_THICKNESS, 0); + base.InitializeFields(); + } + + /// + /// Override the parent, calculate the label number, than draw + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode rm) { + int number = 1; + foreach (StepLabelContainer possibleThis in Parent.StepContainers) { + if (possibleThis == this) { + break; + } + if (Parent.IsOnSurface(possibleThis)) { + number++; + } + } + this.Text = number.ToString(); + base.Draw(graphics, rm); + } + } +} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index c92b90969..ee5040193 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -209,6 +209,17 @@ namespace Greenshot.Drawing { [NonSerialized] private Bitmap buffer = null; + /// + /// all stepcontainers for the surface, needed with serialization + /// + private readonly LinkedList _stepContainers = new LinkedList(); + + public LinkedList StepContainers { + get { + return _stepContainers; + } + } + /// /// all elements on the surface, needed with serialization /// @@ -633,6 +644,12 @@ namespace Greenshot.Drawing { case DrawingModes.Text: undrawnElement = new TextContainer(this); break; + case DrawingModes.SpeechBubble: + undrawnElement = new SpeechbubbleContainer(this); + break; + case DrawingModes.StepLabel: + undrawnElement = new StepLabelContainer(this); + break; case DrawingModes.Line: undrawnElement = new LineContainer(this); break; @@ -1002,7 +1019,7 @@ namespace Greenshot.Drawing { } } drawingElement = undrawnElement; - drawingElement.Status = EditStatus.DRAWING; + drawingElement.Status = undrawnElement.DefaultEditMode; undrawnElement = null; // if a new element has been drawn, set location and register it if (drawingElement != null) { @@ -1274,7 +1291,7 @@ namespace Greenshot.Drawing { } elementToRemove.PropertyChanged -= ElementPropertyChanged; // Do not dispose, the memento should!! element.Dispose(); - elementToRemove.Invalidate(); + Invalidate(); if (makeUndoable) { MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); } @@ -1690,5 +1707,9 @@ namespace Greenshot.Drawing { public void element_FieldChanged(object sender, FieldChangedEventArgs e) { selectedElements.HandleFieldChangedEvent(sender, e); } + + public bool IsOnSurface(IDrawableContainer container) { + return elements.Contains(container); + } } } diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index fa018963f..70ad918bc 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -18,18 +18,19 @@ * 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.Memento; +using Greenshot.Plugin; +using Greenshot.Plugin.Drawing; using System; using System.ComponentModel; using System.Drawing; -using System.Runtime.Serialization; -using System.Windows.Forms; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Plugin; -using Greenshot.Plugin.Drawing; -using Greenshot.Memento; using System.Drawing.Drawing2D; using System.Drawing.Text; +using System.Runtime.Serialization; +using System.Windows.Forms; namespace Greenshot.Drawing { /// @@ -41,7 +42,7 @@ namespace Greenshot.Drawing { // If makeUndoable is true the next text-change will make the change undoable. // This is set to true AFTER the first change is made, as there is already a "add element" on the undo stack private bool makeUndoable; - private Font font; + private Font _font; /// /// The StringFormat object is not serializable!! @@ -49,22 +50,22 @@ namespace Greenshot.Drawing { [NonSerialized] StringFormat stringFormat = new StringFormat(); - private string text; + private string _text; // there is a binding on the following property! public string Text { - get { return text; } + get { return _text; } set { ChangeText(value, true); } } internal void ChangeText(string newText, bool allowUndoable) { - if ((text == null && newText != null) || !text.Equals(newText)) { + if ((_text == null && newText != null) || !_text.Equals(newText)) { if (makeUndoable && allowUndoable) { makeUndoable = false; - parent.MakeUndoable(new TextChangeMemento(this), false); + _parent.MakeUndoable(new TextChangeMemento(this), false); } - text = newText; + _text = newText; OnPropertyChanged("Text"); } } @@ -74,6 +75,11 @@ namespace Greenshot.Drawing { public TextContainer(Surface parent) : base(parent) { Init(); + stringFormat = new StringFormat(); + stringFormat.Trimming = StringTrimming.EllipsisWord; + } + + protected override void InitializeFields() { AddField(GetType(), FieldType.LINE_THICKNESS, 2); AddField(GetType(), FieldType.LINE_COLOR, Color.Red); AddField(GetType(), FieldType.SHADOW, true); @@ -84,8 +90,6 @@ namespace Greenshot.Drawing { AddField(GetType(), FieldType.FONT_SIZE, 11f); AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, HorizontalAlignment.Center); AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, VerticalAlignment.CENTER); - stringFormat = new StringFormat(); - stringFormat.Trimming = StringTrimming.EllipsisWord; } [OnDeserialized] @@ -97,9 +101,9 @@ namespace Greenshot.Drawing { protected override void Dispose(bool disposing) { if (disposing) { - if (font != null) { - font.Dispose(); - font = null; + if (_font != null) { + _font.Dispose(); + _font = null; } if (stringFormat != null) { stringFormat.Dispose(); @@ -121,7 +125,7 @@ namespace Greenshot.Drawing { public void FitToText() { UpdateFormat(); - Size textSize = TextRenderer.MeasureText(text, font); + Size textSize = TextRenderer.MeasureText(_text, _font); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); Width = textSize.Width + lineThickness; Height = textSize.Height + lineThickness; @@ -150,8 +154,8 @@ namespace Greenshot.Drawing { UpdateFormat(); //Invalidate(); } - font.Dispose(); - font = null; + _font.Dispose(); + _font = null; fontInvalidated = true; } @@ -175,8 +179,8 @@ namespace Greenshot.Drawing { } private void ShowTextBox() { - parent.KeysLocked = true; - parent.Controls.Add(textBox); + _parent.KeysLocked = true; + _parent.Controls.Add(textBox); EnsureTextBoxContrast(); textBox.Show(); textBox.Focus(); @@ -195,10 +199,10 @@ namespace Greenshot.Drawing { } private void HideTextBox() { - parent.Focus(); + _parent.Focus(); textBox.Hide(); - parent.KeysLocked = false; - parent.Controls.Remove(textBox); + _parent.KeysLocked = false; + _parent.Controls.Remove(textBox); } private void UpdateFormat() { @@ -236,7 +240,7 @@ namespace Greenshot.Drawing { } } } - font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel); + _font = new Font(fam, fontSize, fs, GraphicsUnit.Pixel); } fontInvalidated = false; } @@ -268,7 +272,7 @@ namespace Greenshot.Drawing { UpdateFormat(); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); textBox.ForeColor = lineColor; - textBox.Font = font; + textBox.Font = _font; } void textBox_KeyDown(object sender, KeyEventArgs e) { @@ -299,7 +303,7 @@ namespace Greenshot.Drawing { DrawSelectionBorder(graphics, rect); } - if (text == null || text.Length == 0 ) { + if (_text == null || _text.Length == 0 ) { return; } @@ -321,24 +325,37 @@ namespace Greenshot.Drawing { shadowRect.Inflate(-textOffset, -textOffset); } using (Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100))) { - graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat); + graphics.DrawString(_text, _font, fontBrush, shadowRect, stringFormat); currentStep++; alpha = alpha - basealpha / steps; } } } + DrawText(graphics, rect, null); + } + + protected void DrawText(Graphics graphics, Rectangle drawingRectange, StringFormat stringFormat) { + UpdateFormat(); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Rectangle fontRect = rect; + Rectangle fontRect = drawingRectange; + int textOffset = (lineThickness > 0) ? (int)Math.Ceiling(lineThickness / 2d) : 0; if (lineThickness > 0) { graphics.SmoothingMode = SmoothingMode.HighSpeed; fontRect.Inflate(-textOffset, -textOffset); } graphics.SmoothingMode = SmoothingMode.HighQuality; using (Brush fontBrush = new SolidBrush(lineColor)) { - graphics.DrawString(text, font, fontBrush, fontRect, stringFormat); + graphics.DrawString(_text, _font, fontBrush, fontRect); + if (stringFormat != null) { + graphics.DrawString(_text, _font, fontBrush, fontRect, stringFormat); + } else { + graphics.DrawString(_text, _font, fontBrush, fontRect); + } } } - + public override bool ClickableAt(int x, int y) { Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); r.Inflate(5, 5); diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index a5719f293..256b449ce 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -62,6 +62,8 @@ namespace Greenshot { this.btnArrow = new GreenshotPlugin.Controls.GreenshotToolStripButton(); this.btnFreehand = new GreenshotPlugin.Controls.GreenshotToolStripButton(); this.btnText = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnSpeechBubble = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnStepLabel = new GreenshotPlugin.Controls.GreenshotToolStripButton(); this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); this.btnHighlight = new GreenshotPlugin.Controls.GreenshotToolStripButton(); this.btnObfuscate = new GreenshotPlugin.Controls.GreenshotToolStripButton(); @@ -300,6 +302,8 @@ namespace Greenshot { this.btnArrow, this.btnFreehand, this.btnText, + this.btnSpeechBubble, + this.btnStepLabel, this.toolStripSeparator14, this.btnHighlight, this.btnObfuscate, @@ -397,6 +401,28 @@ namespace Greenshot { this.btnText.Size = new System.Drawing.Size(22, 20); this.btnText.Click += new System.EventHandler(this.BtnTextClick); // + // btnSpeechBubble + // + this.btnSpeechBubble.CheckOnClick = true; + this.btnSpeechBubble.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnSpeechBubble.Image = ((System.Drawing.Image)(resources.GetObject("btnText.Image"))); + this.btnSpeechBubble.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnSpeechBubble.LanguageKey = "editor_drawtextbox"; + this.btnSpeechBubble.Name = "btnSpeechBubble"; + this.btnSpeechBubble.Size = new System.Drawing.Size(22, 20); + this.btnSpeechBubble.Click += new System.EventHandler(this.BtnSpeechBubbleClick); + // + // btnStepLabel + // + this.btnStepLabel.CheckOnClick = true; + this.btnStepLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnStepLabel.Image = ((System.Drawing.Image)(resources.GetObject("btnText.Image"))); + this.btnStepLabel.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnStepLabel.LanguageKey = "editor_drawtextbox"; + this.btnStepLabel.Name = "btnStepLabel"; + this.btnStepLabel.Size = new System.Drawing.Size(22, 20); + this.btnStepLabel.Click += new System.EventHandler(this.BtnStepLabelClick); + // // toolStripSeparator14 // this.toolStripSeparator14.Name = "toolStripSeparator14"; @@ -1785,6 +1811,8 @@ namespace Greenshot { private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawArrowToolStripMenuItem; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawFreehandToolStripMenuItem; private GreenshotPlugin.Controls.GreenshotToolStripButton btnText; + private GreenshotPlugin.Controls.GreenshotToolStripButton btnSpeechBubble; + private GreenshotPlugin.Controls.GreenshotToolStripButton btnStepLabel; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawLineToolStripMenuItem; private GreenshotPlugin.Controls.GreenshotToolStripButton btnLine; private GreenshotPlugin.Controls.GreenshotToolStripButton btnSettings; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index f3544202d..7e7d42ec9 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -391,6 +391,12 @@ namespace Greenshot { case DrawingModes.Text: SetButtonChecked(btnText); break; + case DrawingModes.SpeechBubble: + SetButtonChecked(btnSpeechBubble); + break; + case DrawingModes.StepLabel: + SetButtonChecked(btnStepLabel); + break; case DrawingModes.Line: SetButtonChecked(btnLine); break; @@ -480,7 +486,16 @@ namespace Greenshot { surface.DrawingMode = DrawingModes.Text; refreshFieldControls(); } - + + void BtnSpeechBubbleClick(object sender, EventArgs e) { + surface.DrawingMode = DrawingModes.SpeechBubble; + refreshFieldControls(); + } + void BtnStepLabelClick(object sender, EventArgs e) { + surface.DrawingMode = DrawingModes.StepLabel; + refreshFieldControls(); + } + void BtnLineClick(object sender, EventArgs e) { surface.DrawingMode = DrawingModes.Line; refreshFieldControls(); diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index eed3687a5..21d162026 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -75,6 +75,7 @@ + @@ -115,6 +116,7 @@ + Component diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index 648536c69..74f4542c0 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -92,6 +92,9 @@ namespace Greenshot.Plugin.Drawing { bool HandleMouseMove(int x, int y); bool InitContent(); void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { + get; + } } public interface ITextContainer: IDrawableContainer { diff --git a/GreenshotPlugin/Interfaces/Generic.cs b/GreenshotPlugin/Interfaces/Generic.cs index ed3b04b57..5b52aa6d7 100644 --- a/GreenshotPlugin/Interfaces/Generic.cs +++ b/GreenshotPlugin/Interfaces/Generic.cs @@ -75,7 +75,21 @@ namespace Greenshot.Plugin { public delegate void SurfaceMessageEventHandler(object sender, SurfaceMessageEventArgs eventArgs); public delegate void SurfaceElementEventHandler(object sender, SurfaceElementEventArgs eventArgs); public delegate void SurfaceDrawingModeEventHandler(object sender, SurfaceDrawingModeEventArgs eventArgs); - public enum DrawingModes { None, Rect, Ellipse, Text, Line, Arrow, Crop, Highlight, Obfuscate, Bitmap, Path } + public enum DrawingModes { + None, + Rect, + Ellipse, + Text, + Line, + Arrow, + Crop, + Highlight, + Obfuscate, + Bitmap, + Path, + SpeechBubble, + StepLabel + } /// /// The interface to the Surface object, so Plugins can use it. @@ -152,6 +166,12 @@ namespace Greenshot.Plugin { void DeselectElement(IDrawableContainer container); void DeselectAllElements(); void SelectElement(IDrawableContainer container); + /// + /// Is the supplied container "on" the surface? + /// + /// + /// This returns false if the container is deleted but still in the undo stack + bool IsOnSurface(IDrawableContainer container); void Invalidate(Rectangle rectangleToInvalidate); void Invalidate(); bool Modified { @@ -178,5 +198,9 @@ namespace Greenshot.Plugin { get; set; } + + LinkedList StepContainers { + get; + } } } \ No newline at end of file