mirror of
https://github.com/greenshot/greenshot
synced 2025-07-30 19:50:11 -07:00
Moving back to trunk!
git-svn-id: http://svn.code.sf.net/p/greenshot/code/trunk@1602 7dccd23d-a4a3-4e1f-8c07-b4c1b4018ab4
This commit is contained in:
parent
ad265b2c54
commit
8d458998a1
332 changed files with 17647 additions and 9466 deletions
272
Greenshot/Drawing/FreehandContainer.cs
Normal file
272
Greenshot/Drawing/FreehandContainer.cs
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2011 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Greenshot.Drawing.Fields;
|
||||
using Greenshot.Helpers;
|
||||
using Greenshot.Plugin.Drawing;
|
||||
|
||||
namespace Greenshot.Drawing {
|
||||
/// <summary>
|
||||
/// Description of PathContainer.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class FreehandContainer : DrawableContainer {
|
||||
private static readonly float [] POINT_OFFSET = new float[]{0.5f, 0.25f, 0.75f};
|
||||
|
||||
[NonSerialized]
|
||||
private GraphicsPath freehandPath = new GraphicsPath();
|
||||
private Rectangle myBounds = Rectangle.Empty;
|
||||
private Point lastMouse = Point.Empty;
|
||||
private List<Point> capturePoints = new List<Point>();
|
||||
private bool isRecalculated = false;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
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 void Init() {
|
||||
for(int i=0; i<grippers.Length; i++) {
|
||||
grippers[i].Enabled = false;
|
||||
grippers[i].Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
[OnDeserializedAttribute()]
|
||||
private void OnDeserialized(StreamingContext context) {
|
||||
InitGrippers();
|
||||
DoLayout();
|
||||
Init();
|
||||
RecalculatePath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
/// </summary>
|
||||
~FreehandContainer() {
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The public accessible Dispose
|
||||
/// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice
|
||||
/// </summary>
|
||||
public new void Dispose() {
|
||||
Dispose(true);
|
||||
base.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Dispose is called from the Dispose and the Destructor.
|
||||
/// </summary>
|
||||
/// <param name="disposing">When disposing==true all non-managed resources should be freed too!</param>
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (freehandPath != null) {
|
||||
freehandPath.Dispose();
|
||||
}
|
||||
}
|
||||
freehandPath = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from Surface (the parent) when the drawing begins (mouse-down)
|
||||
/// </summary>
|
||||
/// <returns>true if the surface doesn't need to handle the event</returns>
|
||||
public override bool HandleMouseDown(int mouseX, int mouseY) {
|
||||
lastMouse = new Point(mouseX, mouseY);
|
||||
capturePoints.Add(lastMouse);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from Surface (the parent) if a mouse move is made while drawing
|
||||
/// </summary>
|
||||
/// <returns>true if the surface doesn't need to handle the event</returns>
|
||||
public override bool HandleMouseMove(int mouseX, int mouseY) {
|
||||
Point previousPoint = capturePoints[capturePoints.Count-1];
|
||||
|
||||
if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY ) > 5) {
|
||||
capturePoints.Add(new Point(mouseX, mouseY));
|
||||
}
|
||||
if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) > 2 ) {
|
||||
//path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)});
|
||||
freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY));
|
||||
lastMouse = new Point(mouseX, mouseY);
|
||||
// Only re-calculate the bounds & redraw when we added something to the path
|
||||
myBounds = Rectangle.Round(freehandPath.GetBounds());
|
||||
Invalidate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the surface finishes drawing the element
|
||||
/// </summary>
|
||||
public override void HandleMouseUp(int mouseX, int mouseY) {
|
||||
// Make sure we don't loose the ending point
|
||||
if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) > 2) {
|
||||
capturePoints.Add(new Point(mouseX, mouseY));
|
||||
}
|
||||
RecalculatePath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Here we recalculate the freehand path by smoothing out the lines with Beziers.
|
||||
/// </summary>
|
||||
private void RecalculatePath() {
|
||||
isRecalculated = true;
|
||||
// Dispose the previous path, if we have one
|
||||
if (freehandPath != null) {
|
||||
freehandPath.Dispose();
|
||||
}
|
||||
freehandPath = new GraphicsPath();
|
||||
|
||||
// Here we can put some cleanup... like losing all the uninteresting points.
|
||||
if (capturePoints.Count > 3) {
|
||||
int index = 0;
|
||||
while ((capturePoints.Count - 1) % 3 != 0) {
|
||||
// duplicate points, first at 50% than 25% than 75%
|
||||
capturePoints.Insert((int)(capturePoints.Count*POINT_OFFSET[index]), capturePoints[(int)(capturePoints.Count*POINT_OFFSET[index++])]);
|
||||
}
|
||||
freehandPath.AddBeziers(capturePoints.ToArray());
|
||||
}
|
||||
|
||||
// Recalculate the bounds
|
||||
myBounds = Rectangle.Round(freehandPath.GetBounds());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do the drawing of the freehand "stroke"
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="renderMode"></param>
|
||||
public override void Draw(Graphics graphics, RenderMode renderMode) {
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
|
||||
Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR);
|
||||
using (Pen pen = new Pen(lineColor)) {
|
||||
pen.Width = lineThickness;
|
||||
if (pen.Width > 0) {
|
||||
// Make sure the lines are nicely rounded
|
||||
pen.EndCap = LineCap.Round;
|
||||
pen.StartCap = LineCap.Round;
|
||||
pen.LineJoin = LineJoin.Round;
|
||||
|
||||
// Move to where we need to draw
|
||||
graphics.TranslateTransform(Left,Top);
|
||||
if (isRecalculated && Selected && renderMode == RenderMode.EDIT) {
|
||||
DrawSelectionBorder(graphics, pen);
|
||||
}
|
||||
graphics.DrawPath(pen, freehandPath);
|
||||
// Move back, otherwise everything is shifted
|
||||
graphics.TranslateTransform(-Left,-Top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a selectionborder around the freehand path
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="linePen"></param>
|
||||
protected void DrawSelectionBorder(Graphics graphics, Pen linePen) {
|
||||
using (Pen selectionPen = (Pen) linePen.Clone()) {
|
||||
using (GraphicsPath selectionPath = (GraphicsPath) freehandPath.Clone()) {
|
||||
selectionPen.Width += 5;
|
||||
selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen);
|
||||
graphics.DrawPath(selectionPen, selectionPath);
|
||||
selectionPath.Widen(selectionPen);
|
||||
selectionPen.DashPattern = new float[]{2,2};
|
||||
selectionPen.Color = Color.LightSeaGreen;
|
||||
selectionPen.Width = 1;
|
||||
graphics.DrawPath(selectionPen, selectionPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds...
|
||||
/// </summary>
|
||||
public override Rectangle DrawingBounds {
|
||||
get {
|
||||
if (!myBounds.IsEmpty) {
|
||||
int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS));
|
||||
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)));
|
||||
} else {
|
||||
return parent.Bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FreehandContainer are regarded equal if they are of the same type and their paths are equal.
|
||||
public override bool Equals(object obj) {
|
||||
bool ret = false;
|
||||
if(obj != null && GetType().Equals(obj.GetType())) {
|
||||
FreehandContainer other = obj as FreehandContainer;
|
||||
if(freehandPath.Equals(other.freehandPath)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return freehandPath.GetHashCode();
|
||||
}
|
||||
|
||||
protected override void DoLayout() {
|
||||
}
|
||||
|
||||
public override void ShowGrippers() {
|
||||
this.ResumeLayout();
|
||||
}
|
||||
|
||||
public override bool ClickableAt(int x, int y) {
|
||||
bool returnValue = base.ClickableAt(x, y);
|
||||
if (returnValue) {
|
||||
int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS);
|
||||
using (Pen pen = new Pen(Color.White)) {
|
||||
pen.Width = lineThickness + 10;
|
||||
returnValue = freehandPath.IsOutlineVisible(x-Left,y-Top, pen);
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue