Mk0.Tools.ImageCropper/Mk0.Tools.ImageCropper/RubberBand.cs

842 lines
34 KiB
C#

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Mk0.Tools.ImageCropper
{
public enum Operation
{
none,
draw,
move,
left,
top,
right,
bottom,
topLeft,
topRight,
bottomRight,
bottomLeft
}
/// <summary>
/// Manages the cropping rectangle - allows drawing, resizing, and moving. _theRectangle and _backupRectangle are stored
/// in units of pixels.
/// </summary>
public partial class RubberBand : UserControl
{
#region Member Variables;
private Operation _curOp; // Indicates the current operation
private bool _isDragging = false; // Indicates if the left mouse button is down
private Point _startPoint; // Set in the mouse down event. The anchor for our rectangle
private bool _disabled = false; // Indicates cropping is not allowed
private Rectangle _theRectDrawing = new Rectangle( // We draw this rectangle on the screen as our cropping rectangle
new Point(0, 0), new Size(0, 0)); // It is populated in the MouseUp event
private Rectangle _backupRectangle = new Rectangle( // Helps us handle double click event - we need to restore the rectangle
new Point(0, 0), new Size(0, 0)); // because double click also triggers a single click event.
private Rectangle _picRectangle = new Rectangle( // The area of our image - not the same as area of PictureBox control
new Point(0, 0), new Size(0, 0));
private GDIWrap _myGDI = new GDIWrap(); // DrawReversibleFrame caused a lot of flickering - so we use GDI methods
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the CropperBox class
/// </summary>
public RubberBand()
{
InitializeComponent();
}
#endregion
public event EventHandler ImageCropped;
public event EventHandler<StatusEventArg> CursorMove;
#region Public Properties and Methods
/// <summary>
/// Gets or sets how images will be sized in the control - true sized or sized to fit the screen
/// </summary>
[Category("Custom"), Description("Size mode of the picturebox control")]
public PictureBoxSizeMode SizeMode
{
get
{
return thePicture.SizeMode;
}
set
{
Rectangle origSize = ImageRect(); // This defines the current image rectangle
// Set docking style before we set size mode
// Otherwise we have repaint problems if pic was scrolled.
if (value == PictureBoxSizeMode.AutoSize)
thePicture.Dock = DockStyle.None;
else
thePicture.Dock = DockStyle.Fill;
thePicture.SizeMode = value;
_picRectangle = ImageRect();
// Now we can transform our cropping rectangle
_theRectDrawing.Height = (int)Math.Round(_theRectDrawing.Height * (float)_picRectangle.Height / origSize.Height);
_theRectDrawing.Width = (int)Math.Round(_theRectDrawing.Width * (float)_picRectangle.Width / origSize.Width);
// Get the offset for the cropping rectangle
Point offset = new Point(_theRectDrawing.X - origSize.X, _theRectDrawing.Y - origSize.Y);
// Scale the offset
offset.X = (int)Math.Round(offset.X * (float)_picRectangle.Width / origSize.Width);
offset.Y = (int)Math.Round(offset.Y * (float)_picRectangle.Height / origSize.Height);
// Set our new position
_theRectDrawing.X = offset.X + ImageRect().X;
_theRectDrawing.Y = offset.Y + ImageRect().Y;
}
}
/// <summary>
/// Gets or sets the image that will be displayed. When we set a new image, we check if the current
/// cropping rectangle fits within the image. If not, we reset it to zero.
/// </summary>
[Category("Custom"), Description("Gets or sets the image from the picturebox")]
public Image Image
{
get
{
return thePicture.Image;
}
set
{
// Change the image
thePicture.Image = value;
// Is the cropping rectangle completely within the new image?
if (!ImageRect().Contains(_theRectDrawing))
_theRectDrawing = new Rectangle(0, 0, 0, 0);
}
}
/// <summary>
/// Gets the image selected by the cropping rectangle. Returns null if no image is selected.
/// Return the entire image if no cropping rectangle is selected.
/// </summary>
[Category("Custom"), Description("Gets the image selected by the cropping rectangle")]
public Image SelectedImage
{
get
{
bool tempRect = false;
// Create a bitmap from our image
Bitmap bmpImage = new Bitmap(thePicture.Image);
// If we dont have a cropping rectangle, set the cropping rectangle to the
// dimensions of the entire image.
if (_theRectDrawing.Width <= 0 || _theRectDrawing.Height <= 0)
{
_theRectDrawing = ImageRect();
tempRect = true;
}
// Scale the cropping rectangle
Rectangle cropRect = CroppingArea;
// Clone the image defined by cropRect. Use the same pixel format
// as our original image.
Bitmap bmpCrop = bmpImage.Clone(cropRect, bmpImage.PixelFormat);
bmpImage.Dispose();
if (tempRect)
_theRectDrawing = new Rectangle(0, 0, 0, 0);
return (Image)bmpCrop;
}
}
/// <summary>
/// Gets or sets the Disabled property. We disable the control when we display the home page.
/// </summary>
[Category("Custom"), Description("Gets or sets the cropping capability of the control")]
public bool Disabled
{
get
{
return _disabled;
}
set
{
_disabled = value;
if (_disabled)
_theRectDrawing = new Rectangle(0, 0, 0, 0);
}
}
#endregion
#region Private Properties And Methods
/// <summary>
/// Gets the cropping area scaled to the specified size
/// </summary>
/// <param name="basis"></param>
/// <returns></returns>
[Category("Custom"), Description("Obtain the current cropping rectangle scaled to the size of the specified image")]
private Rectangle CroppingArea
{
get
{
Rectangle cropRect = _theRectDrawing;
double ratio = GetScaleFactor(SizeMode == PictureBoxSizeMode.AutoSize);
if (ratio != 0.0)
{
cropRect.Offset(-_picRectangle.Left, -_picRectangle.Top);
cropRect.Height = (int)Math.Round(cropRect.Height / ratio);
cropRect.X = (int)Math.Round(cropRect.X / ratio);
cropRect.Width = (int)Math.Round(cropRect.Width / ratio);
cropRect.Y = (int)Math.Round(cropRect.Y / ratio);
}
return cropRect;
}
}
/// <summary>
/// Update the point based on the image size
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
private Point CroppingPoint(Point pt)
{
Point adjustedPt = pt;
double ratio = GetScaleFactor(SizeMode == PictureBoxSizeMode.AutoSize);
if (ratio != 0.0)
{
adjustedPt.Offset(-_picRectangle.Left, -_picRectangle.Top);
adjustedPt.X = (int)Math.Round(adjustedPt.X / ratio);
adjustedPt.Y = (int)Math.Round(adjustedPt.Y / ratio);
}
return adjustedPt;
}
/// <summary>
/// If the cursor is outside a cropping area, start a new rubberband. If the cursor is within the
/// bounds of a rubber band, trigger a move operation. If the cursor is on the border of a rubber
/// band, trigger a resize operation. This event is triggered by the PictureBox control.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseDown(object sender, MouseEventArgs e)
{
// Set the isDrag variable to true and get the starting point
// by using the PointToScreen method to convert form
// coordinates to screen coordinates.
Point myPoint = new Point(e.X, e.Y); // PictureBox coordinates are passed in
if (_disabled)
_curOp = Operation.none;
else if (e.Button == MouseButtons.Left)
{
this._isDragging = true;
this._picRectangle = ImageRect();
this._backupRectangle = _theRectDrawing; // Helps with undo if this is part of a double click event
this._curOp = DetermineMouseOperation(myPoint);
}
else
{
_curOp = Operation.none;
}
switch (_curOp)
{
case Operation.draw:
_startPoint = myPoint;
// Reset the rectangle.
_theRectDrawing = new Rectangle(0, 0, 0, 0);
thePicture.Invalidate();
break;
case Operation.none:
_isDragging = false;
// Reset the rectangle.
_theRectDrawing = new Rectangle(0, 0, 0, 0);
thePicture.Invalidate();
break;
default:
_startPoint = myPoint;
// Erase the inked rectangle
thePicture.Refresh();
// Draw the rectangle in reverse ink
Graphics g = thePicture.CreateGraphics();
_myGDI.DrawRectangle(g, _theRectDrawing);
g.Dispose();
break;
}
}
/// <summary>
/// If curOp is none, we will set the cursor depending on the current position. Otherwise,
/// we will modify or move the rubberand. This event is triggered by the PictureBox control.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseMove(object sender, MouseEventArgs e)
{
Point myPoint = new Point(e.X, e.Y); // Picture box coordinates
Graphics g = thePicture.CreateGraphics();
// Determine what our current operation is. This depends on if we are dragging the mouse or not
if (_isDragging)
{
_curOp = CheckOperationChange(_curOp, myPoint); // The operation can change during a mouse drag
// Erase the old rectangle created in the mouse down event
_myGDI.DrawRectangle(g, _theRectDrawing);
}
else
{
_curOp = DetermineMouseOperation(myPoint); // If not dragging, see which cursor to use
}
bool isActive = IsActivePoint(ref myPoint);
switch (_curOp)
{
case Operation.draw:
// Calculate the endpoint and dimensions for the new
_theRectDrawing = NormalizeRectangle(_startPoint, myPoint);
break;
case Operation.move:
Cursor = Cursors.SizeAll;
if (_isDragging)
{
// Compute how much the cursor has moved since the previous call
Point myDiff = new Point(myPoint.X - _startPoint.X, myPoint.Y - _startPoint.Y);
myDiff = CalcMaxOffset(myDiff);
_theRectDrawing.Offset(myDiff);
_startPoint = myPoint;
}
break;
case Operation.left:
Cursor = Cursors.SizeWE;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(myPoint.X, _theRectDrawing.Top, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.top:
Cursor = Cursors.SizeNS;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, myPoint.Y, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.right:
Cursor = Cursors.SizeWE;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, myPoint.X, _theRectDrawing.Bottom);
break;
case Operation.bottom:
Cursor = Cursors.SizeNS;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, _theRectDrawing.Right, myPoint.Y);
break;
case Operation.topLeft:
Cursor = Cursors.SizeNWSE;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(myPoint.X, myPoint.Y, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.topRight:
Cursor = Cursors.SizeNESW;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, myPoint.Y, myPoint.X, _theRectDrawing.Bottom);
break;
case Operation.bottomRight:
Cursor = Cursors.SizeNWSE;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, myPoint.X, myPoint.Y);
break;
case Operation.bottomLeft:
Cursor = Cursors.SizeNESW;
if (_isDragging)
_theRectDrawing = NormalizeRectangle(myPoint.X, _theRectDrawing.Top, _theRectDrawing.Right, myPoint.Y);
break;
default:
Cursor = Cursors.Cross;
break;
}
// Draw our new rectangle
if (_isDragging)
_myGDI.DrawRectangle(g, _theRectDrawing);
g.Dispose();
// Notify the host that the mouse is moved. If we have a cropping rectangle,
// size of the cropping rectangle. Otherwise, report the mouse position
if (CursorMove != null)
{
Rectangle crop = CroppingArea;
if (crop.Height <= 0 || crop.Width <= 0)
{
crop.Width = thePicture.Image.Width;
crop.Height = thePicture.Image.Height;
crop.X = 0;
crop.Y = 0;
// If we are within the picture, report the current mouse position
if (isActive)
CursorMove(this, new StatusEventArg(CroppingPoint(myPoint), crop));
else
CursorMove(this, new StatusEventArg(crop.Location, crop));
}
else
CursorMove(this, new StatusEventArg(crop.Location, crop));
}
}
/// <summary>
/// We are done with our mouse operation. This event is triggered by
/// the PictureBox.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseUp(object sender, MouseEventArgs e)
{
Point myPoint = new Point(e.X, e.Y);
IsActivePoint(ref myPoint);
// Erase the current rectangle
Graphics g = thePicture.CreateGraphics();
if (_curOp != Operation.none)
_myGDI.DrawRectangle(g, _theRectDrawing);
g.Dispose();
// If the MouseUp event occurs, the user has stopped dragging
_isDragging = false;
// Note that some operations can change mid stride depending on where the user moves the mouse
_curOp = CheckOperationChange(_curOp, myPoint);
switch (_curOp)
{
case Operation.move:
myPoint = new Point(myPoint.X - _startPoint.X, myPoint.Y - _startPoint.Y);
myPoint = CalcMaxOffset(myPoint);
_theRectDrawing.Offset(myPoint);
break;
case Operation.left:
_theRectDrawing = NormalizeRectangle(myPoint.X, _theRectDrawing.Top, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.right:
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, myPoint.X, _theRectDrawing.Bottom);
break;
case Operation.top:
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, myPoint.Y, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.bottom:
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, _theRectDrawing.Right, myPoint.Y);
break;
case Operation.topLeft:
_theRectDrawing = NormalizeRectangle(myPoint.X, myPoint.Y, _theRectDrawing.Right, _theRectDrawing.Bottom);
break;
case Operation.topRight:
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, myPoint.Y, myPoint.X, _theRectDrawing.Bottom);
break;
case Operation.bottomLeft:
_theRectDrawing = NormalizeRectangle(myPoint.X, _theRectDrawing.Top, _theRectDrawing.Right, myPoint.Y);
break;
case Operation.bottomRight:
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Left, _theRectDrawing.Top, myPoint.X, myPoint.Y);
break;
}
if (_curOp != Operation.none)
{
// Create our new cropping rectangle - scale it in terms of the current image size
// The rectangle is currently in pictureBox coordinates. We need to scale it in terms
// of the current image.
myPoint.X = _theRectDrawing.Right;
myPoint.Y = _theRectDrawing.Bottom;
_theRectDrawing = NormalizeRectangle(_theRectDrawing.Location, myPoint);
thePicture.Invalidate();
_curOp = Operation.none;
}
}
/// <summary>
/// Notify our host that someone double clicked the pictureBox. Keep in mind that a
/// double click event also causes two mouse down events and one mouse up event prior to
/// triggering this event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMouseDoubleClick(object sender, MouseEventArgs e)
{
_theRectDrawing = _backupRectangle;
_curOp = Operation.none;
_isDragging = false;
ImageCropped?.Invoke(this, e);
}
/// <summary>
/// Paint event of the picturebox control. Draw the rectangle only if not being drawn by
/// mouse events. The rectangle is drawn using client coordinates of the PictureBox
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnPaint(object sender, PaintEventArgs e)
{
if (!_isDragging)
_myGDI.DrawRectangle(e.Graphics, _theRectDrawing);
}
/// <summary>
/// Fired when the picturebox control is resized. We may also need to resize our cropping rectangle
/// and refresh the dimensions of picRectangle (thePicture is the PictureBox control).
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnResize(object sender, EventArgs e)
{
_picRectangle = ImageRect();
}
/// <summary>
/// Create a normalized rectangle from two points. There does not seem to be
/// any built in method to do this. The two points represent the top left and bottom
/// right corners.
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
private Rectangle NormalizeRectangle(Point p1, Point p2)
{
Rectangle rc = new Rectangle();
// Normalize the rectangle.
if (p1.X < p2.X)
{
rc.X = p1.X;
rc.Width = p2.X - p1.X;
}
else
{
rc.X = p2.X;
rc.Width = p1.X - p2.X;
}
if (p1.Y < p2.Y)
{
rc.Y = p1.Y;
rc.Height = p2.Y - p1.Y;
}
else
{
rc.Y = p2.Y;
rc.Height = p1.Y - p2.Y;
}
return rc;
}
private Rectangle NormalizeRectangle(int x1, int y1, int x2, int y2)
{
Point p1 = new Point(x1, y1);
Point p2 = new Point(x2, y2);
return NormalizeRectangle(p1, p2);
}
/// <summary>
/// The amount to change picture size to fit within our panel. If the
/// image is true sized, return 1. Otherwise return the factor we will
/// increase/reduce the actual image size.
/// </summary>
/// <param name="isTrueSize"></param>
/// <returns></returns>
private double GetScaleFactor(bool isTrueSize)
{
double ratio = 0.0;
double ratio1 = 0.0;
if (isTrueSize)
ratio = 1.0; // Image is true sized
else
{
// Get the dimensions of the picture so we can compute our sizing ratio
if (thePicture.Image != null)
{
ratio = ((float)panel1.Size.Width) / thePicture.Image.Width;
ratio1 = ((float)panel1.Size.Height) / thePicture.Image.Height;
}
if (ratio1 < ratio)
ratio = ratio1;
}
return ratio;
}
/// <summary>
/// When the picture is sized to fit, it is also centered inside the panel.
/// We need to determine how much it is offset from the 0,0 position.
/// </summary>
/// <param name="isTrueSize"></param>
/// <returns></returns>
private Point GetScaleOffset(bool isTrueSize)
{
Point topLeft = new Point();
if (thePicture.Image == null)
return topLeft;
double ratio = GetScaleFactor(isTrueSize);
int width = (int)(thePicture.Image.Width * ratio);
int height = (int)(thePicture.Image.Height * ratio);
// Get the location of the picture. If not trueSize, it is centered in the panel
// smaller than the panel.
if (isTrueSize || width > panel1.Width)
topLeft.X = 0;
else
topLeft.X = (panel1.Width - width) / 2;
if (isTrueSize || height > panel1.Height)
topLeft.Y = 0;
else
topLeft.Y = (panel1.Height - height) / 2;
return topLeft;
}
/// <summary>
/// Return the rectangle that defines the current displayed image
/// in the picture box. Seems there should already be a method to
/// do this, but I could not find one. thePicture is our PictureBox
/// control. theImage is the size of the image contained therein.
/// The size of the image depends on the current SizeMode - the
/// image might be scaled to fit the picturebox.
/// </summary>
/// <returns></returns>
private Rectangle ImageRect()
{
double ratio;
Point topLeft = new Point();
Rectangle imageRect = new Rectangle();
if (thePicture.Image == null)
return imageRect;
ratio = GetScaleFactor(thePicture.SizeMode == PictureBoxSizeMode.AutoSize);
topLeft = GetScaleOffset(thePicture.SizeMode == PictureBoxSizeMode.AutoSize);
imageRect.Width = (int)(thePicture.Image.Width * ratio);
imageRect.Height = (int)(thePicture.Image.Height * ratio);
imageRect.Location = topLeft;
return imageRect;
}
/// <summary>
/// Return true if the point is within the boundaries of the current
/// picturebox image. If not, modify pt so it is on the offending boundary.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
private bool IsActivePoint(ref Point pt)
{
bool isActive = false;
if (_picRectangle.Size.IsEmpty)
_picRectangle = ImageRect();
// Is the point within the picture area? The point must be in client coords
isActive = _picRectangle.Contains(pt);
if (!isActive)
{
// We will adjust the point to make it active
Rectangle myRect = _picRectangle;
if (pt.X < myRect.Left)
pt.X = myRect.Left;
if (pt.X > myRect.Right)
pt.X = myRect.Right;
if (pt.Y < myRect.Top)
pt.Y = myRect.Top;
if (pt.Y > myRect.Bottom)
pt.Y = myRect.Bottom;
}
return isActive;
}
/// <summary>
/// Return the appropriate operation type based on the point passed in
/// </summary>
/// <param name="pt">Client coordinates are passed in</param>
/// <returns></returns>
private Operation DetermineMouseOperation(Point pt)
{
Operation retVal = Operation.none;
Rectangle outerFrame = _theRectDrawing;
Rectangle innerFrame = outerFrame;
Size sz = new Size(2, 2); // The amount of leeway to give our user moving the mouse
outerFrame.Inflate(sz); // Create an outer rectangle around our cropping area
innerFrame.Inflate(-sz.Width, -sz.Height); // Create an inner rectangle within our cropping area
// Check if we are near any of the rectangle corners. We have to offset these four rectangles because the
// hotspot on the stock cursor for SizeNESW and SizeNWSE is not in the center of the cursor where it should be.
Rectangle picCorner;
// Check for top left corner
picCorner = new Rectangle(outerFrame.Left, outerFrame.Top, sz.Width, sz.Height);
picCorner.Inflate(8, 8);
picCorner.Offset(-8, -8);
if (picCorner.Contains(pt))
retVal = Operation.topLeft;
// Check for top right corner
picCorner = new Rectangle(innerFrame.Right, outerFrame.Top, sz.Width, sz.Height);
picCorner.Inflate(8, 8);
picCorner.Offset(-8, -8);
if (picCorner.Contains(pt))
retVal = Operation.topRight;
// Check for bottom right corner
picCorner = new Rectangle(innerFrame.Right, innerFrame.Bottom, sz.Width, sz.Height);
picCorner.Inflate(8, 8);
picCorner.Offset(-8, -8);
if (picCorner.Contains(pt))
retVal = Operation.bottomRight;
// Check for bottom left corner
picCorner = new Rectangle(outerFrame.Left, innerFrame.Bottom, sz.Width, sz.Height);
picCorner.Inflate(8, 8);
picCorner.Offset(-8, -8);
if (picCorner.Contains(pt))
retVal = Operation.bottomLeft;
// If we are not within any corners, do a little more checking
if (retVal == Operation.none)
{
// Are we inside the outer rectangle?
if (outerFrame.Contains(pt))
{
// Are we inside the inner rectangle?
if (innerFrame.Contains(pt))
retVal = Operation.move;
else if (pt.Y >= outerFrame.Top && pt.Y <= innerFrame.Top)
retVal = Operation.top;
else if (pt.Y >= innerFrame.Bottom && pt.Y <= outerFrame.Bottom)
{
System.Diagnostics.Debug.Print("Outer: " + outerFrame.ToString());
System.Diagnostics.Debug.Print("Inner: " + innerFrame.ToString());
System.Diagnostics.Debug.Print("Point: " + pt.ToString());
retVal = Operation.bottom;
}
else if (pt.X >= innerFrame.Right && pt.X <= outerFrame.Right)
retVal = Operation.right;
else if (pt.X >= outerFrame.Left && pt.X <= innerFrame.Left)
retVal = Operation.left;
}
}
// Are we inside the picture area?
if (retVal == Operation.none)
{
if (_picRectangle.Contains(pt) && _isDragging)
retVal = Operation.draw;
}
System.Diagnostics.Debug.Print(retVal.ToString());
return retVal;
}
/// <summary>
/// The operation can change depending on where the user moves the mouse
/// </summary>
/// <param name="curOp"></param>
/// <param name="myPoint"></param>
/// <returns></returns>
private Operation CheckOperationChange(Operation curOp, Point myPoint)
{
switch (curOp)
{
case Operation.left:
if (myPoint.X > _theRectDrawing.Right)
curOp = Operation.right;
break;
case Operation.right:
if (myPoint.X < _theRectDrawing.Left)
curOp = Operation.left;
break;
case Operation.top:
if (myPoint.Y > _theRectDrawing.Bottom)
curOp = Operation.bottom;
break;
case Operation.bottom:
if (myPoint.Y < _theRectDrawing.Top)
curOp = Operation.top;
break;
case Operation.topLeft:
if ((myPoint.X > _theRectDrawing.Right) && (myPoint.Y > _theRectDrawing.Bottom))
curOp = Operation.bottomRight;
else if (myPoint.X > _theRectDrawing.Right)
curOp = Operation.topRight;
else if (myPoint.Y > _theRectDrawing.Bottom)
curOp = Operation.bottomLeft;
break;
case Operation.topRight:
if ((myPoint.X < _theRectDrawing.Left) && (myPoint.Y > _theRectDrawing.Bottom))
curOp = Operation.bottomLeft;
else if (myPoint.X < _theRectDrawing.Left)
curOp = Operation.topLeft;
else if (myPoint.Y > _theRectDrawing.Bottom)
curOp = Operation.bottomRight;
break;
case Operation.bottomLeft:
if ((myPoint.X > _theRectDrawing.Right) && (myPoint.Y < _theRectDrawing.Top))
curOp = Operation.topRight;
else if (myPoint.X > _theRectDrawing.Right)
curOp = Operation.bottomRight;
else if (myPoint.Y < _theRectDrawing.Top)
curOp = Operation.topLeft;
break;
case Operation.bottomRight:
if ((myPoint.X < _theRectDrawing.Left) && (myPoint.Y < _theRectDrawing.Top))
curOp = Operation.topLeft;
else if (myPoint.X < _theRectDrawing.Left)
curOp = Operation.bottomLeft;
else if (myPoint.Y < _theRectDrawing.Top)
curOp = Operation.topRight;
break;
}
return curOp;
}
/// <summary>
/// Move the cropping rectangle - but not out of the picture boundaries
/// </summary>
/// <param name="offSet"></param>
/// <returns></returns>
private Point CalcMaxOffset(Point offSet)
{
Rectangle testRect = _theRectDrawing;
// Move the rectangle the specified amount and see if Kosher
testRect.Offset(offSet);
// Do we need to adjust our offset?
if (!_picRectangle.Contains(testRect))
{
if (testRect.Top < _picRectangle.Top)
offSet.Y = offSet.Y + (_picRectangle.Top - testRect.Top);
if (testRect.Right > _picRectangle.Right)
offSet.X = offSet.X + (_picRectangle.Right - testRect.Right);
if (testRect.Bottom > _picRectangle.Bottom)
offSet.Y = offSet.Y + (_picRectangle.Bottom - testRect.Bottom);
if (testRect.Left < _picRectangle.Left)
offSet.X = offSet.X + (_picRectangle.Left - testRect.Left);
}
return offSet;
}
#endregion
}
}