// ===========================================================================
// ©2013-2026 WebSupergoo. All rights reserved.
//
// This source code is for use exclusively with the ABCpdf product with
// which it is distributed, under the terms of the license for that
// product. Details can be found at
//
// http://www.websupergoo.com/
//
// This copyright notice must not be deleted and must be reproduced alongside
// any sections of code extracted from this module.
// ===========================================================================
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace ABCpdfControls {
/// <summary>
/// Summary description for DraggingUtils.
/// </summary>
internal class DraggingUtilities {
private const int kDragWindowMimimumSize = 10;
/// <summary>
/// Object returned by the GetDragWindowSize() Method.
/// </summary>
internal struct DragWindowInfo {
/// <summary>
/// Creates a new object with the size, and point already initialized.
/// </summary>
/// <param name="size">Size of the drag window drawn.</param>
/// <param name="topLeft">Top left point of the drag window created.</param>
public DragWindowInfo(Size size, Point topLeft) {
WindowSize = size;
TopLeft = topLeft;
}
/// <summary>
/// Size of the drag window drawn.
/// </summary>
public Size WindowSize;
/// <summary>
/// Top left point of the drag window created.
/// </summary>
public Point TopLeft;
public Rectangle GetRectangle() {
Rectangle theRect = new Rectangle(TopLeft, WindowSize);
return theRect;
}
}
/// <summary>
/// Gets the size of the drag window drawn by the user.
/// </summary>
/// <param name="dragCurrent">The current position of the curser.</param>
/// <param name="dragStart">The position of the cursor where the drag was started.</param>
/// <returns>Drag Window Information.</returns>
static public DragWindowInfo GetDragWindowSize(Point dragCurrent, Point dragStart) {
Point topLeft = new Point(0,0);
Point bottomRight = new Point(0,0);
if ( dragStart.X < dragCurrent.X ) {
// Dragging to the right.
if ( dragStart.Y < dragCurrent.Y ) {
// Right & Down
topLeft = dragStart;
bottomRight = dragCurrent;
}
else {
// Right & Up
topLeft = new Point(dragStart.X, dragCurrent.Y);
bottomRight = new Point(dragCurrent.X, dragStart.Y);
}
}
else if ( dragCurrent.X < dragStart.X ) {
// Dragging to the left.
if ( dragStart.Y < dragCurrent.Y ) {
// Left & Down
topLeft = new Point(dragCurrent.X, dragStart.Y);
bottomRight = new Point(dragStart.X, dragCurrent.Y);
}
else {
// Left & Up
topLeft = dragCurrent;
bottomRight = dragStart;
}
}
int width = bottomRight.X - topLeft.X;
int height = bottomRight.Y - topLeft.Y;
DragWindowInfo dwi = new DragWindowInfo(new Size(width, height), topLeft);
return dwi;
}
/// <summary>
/// Make sure that dragged rect is big enough
/// </summary>
/// <param name="dragStart">Start dragging point</param>
/// <param name="dragEnd">End dragging point</param>
/// <returns>True if height and witdh of the rectangle are bigger than kDragWindowMimimumSize</returns>
static public bool CheckDragBoxSize(Point dragStart, Point dragEnd) {
DragWindowInfo dwi = GetDragWindowSize(dragEnd, dragStart);
Size size = dwi.WindowSize;
int height = size.Height;
int width = size.Width;
if ( height > kDragWindowMimimumSize && width > kDragWindowMimimumSize )
return true;
else
return false;
}
/// <summary>
/// Invert 3-dimensional matrix
/// </summary>
/// <param name="a">Original matrix</param>
/// <param name="r">on output: Inverted matrix</param>
static void matrix3Invert(float[,] a, float[,] r) {
float a11 = a[0,0],a12=a[0,1],a13=a[0,2];
float a21 = a[1,0],a22=a[1,1],a23=a[1,2];
float a31 = a[2,0],a32=a[2,1],a33=a[2,2];
float d =(a11*a22*a33-a11*a23*a32-a21*a12*a33+a21*a13*a32+a31*a12*a23-a31*a13*a22);
if (d != 0)
r[0,0]= (a22*a33-a23*a32)/d;
r[0,1]=-(a12*a33-a13*a32)/d;
r[0,2]= (a12*a23-a13*a22)/d;
r[1,0]=-(a21*a33-a23*a31)/d;
r[1,1]= (a11*a33-a13*a31)/d;
r[1,2]=-(a11*a23-a13*a21)/d;
r[2,0]= (a21*a32-a22*a31)/d;
r[2,1]=-(a11*a32-a12*a31)/d;
r[2,2]= (a11*a22-a12*a21)/d;
}
static public Matrix GetDraggingMatrix(Point dragNewPoint, GraphicsPath path, int draggingPointIndex) {
PointF[] points = path.PathPoints;
//A bit of mathematics to calculate transformation factors
PointF pointA = points[(draggingPointIndex + 2) % 4];
PointF pointB = points[(draggingPointIndex + 1) % 4];
PointF pointC = points[(draggingPointIndex + 3) % 4];
PointF pointM = dragNewPoint;
//Calculate new points positions
float ub = ((pointA.X - pointM.X)*(pointC.Y - pointA.Y) - (pointA.Y - pointM.Y)*(pointC.X - pointA.X)) /
((pointB.Y - pointA.Y)*(pointC.X - pointA.X) - (pointB.X - pointA.X)*(pointC.Y - pointA.Y));
PointF pointBnew = new PointF(pointA.X + (pointB.X - pointA.X )*ub, pointA.Y + (pointB.Y - pointA.Y )*ub);
float uc = ((pointA.X - pointM.X)*(pointB.Y - pointA.Y) - (pointA.Y - pointM.Y)*(pointB.X - pointA.X)) /
((pointC.Y - pointA.Y)*(pointB.X - pointA.X) - (pointC.X - pointA.X)*(pointB.Y - pointA.Y));
PointF pointCnew = new PointF(pointA.X + (pointC.X - pointA.X )*uc, pointA.Y + (pointC.Y - pointA.Y )*uc);
//Find the transformation Matrix
float[,] m = new float[3,3];
m[0,0] = pointA.X;
m[0,1] = pointA.Y;
m[0,2] = 1;
m[1,0] = pointB.X;
m[1,1] = pointB.Y;
m[1,2] = 1;
m[2,0] = pointC.X;
m[2,1] = pointC.Y;
m[2,2] = 1;
float[,] r = new float[3,3];
matrix3Invert(m, r);
float a = r[0,0]*pointA.X + r[0,1]*pointBnew.X + r[0,2]*pointCnew.X;
float c = r[1,0]*pointA.X + r[1,1]*pointBnew.X + r[1,2]*pointCnew.X;
float e = r[2,0]*pointA.X + r[2,1]*pointBnew.X + r[2,2]*pointCnew.X;
float b = r[0,0]*pointA.Y + r[0,1]*pointBnew.Y + r[0,2]*pointCnew.Y;
float d = r[1,0]*pointA.Y + r[1,1]*pointBnew.Y + r[1,2]*pointCnew.Y;
float f = r[2,0]*pointA.Y + r[2,1]*pointBnew.Y + r[2,2]*pointCnew.Y;
Matrix theMatrix = new Matrix(a, b, c, d, e, f);
return theMatrix;
}
static double GetVectorAngle(PointF p1, PointF p2) {
double angle = Math.Atan2(p1.Y - p2.Y, p2.X - p1.X);
return angle*180/Math.PI;
}
public static Cursor GetGrabBarCursor(int index, GraphicsPath inPath) {
PointF pointA = inPath.PathPoints[index];
PointF pointB = inPath.PathPoints[(index + 1) % 4];
PointF pointC = inPath.PathPoints[(index + 3) % 4];
double bisectorAngle = 180 + (GetVectorAngle(pointB, pointA) + GetVectorAngle(pointC, pointA)) / 2;
Cursor theCursor = Cursors.Default;
if ( (0 <= bisectorAngle && bisectorAngle <= 45/2 ) || (315/2 <= bisectorAngle && bisectorAngle <= 405/2) || bisectorAngle >=675/2)
theCursor = Cursors.SizeWE;
else
if ( (45/2 <= bisectorAngle && bisectorAngle <= 135/2) || (405/2 <=bisectorAngle && bisectorAngle <= 495/2))
theCursor = Cursors.SizeNESW;
else
if ( (135/2 <= bisectorAngle && bisectorAngle <= 225/2) || (495/2 <= bisectorAngle && bisectorAngle <= 585/2))
theCursor = Cursors.SizeNS;
else
if ( (225/2 <= bisectorAngle && bisectorAngle <= 315/2) || (585/2 <= bisectorAngle && bisectorAngle <= 675/2))
theCursor = Cursors.SizeNWSE;
return theCursor;
}
public static bool IsOverGrabBars(Point p, GraphicsPath path, int grabBarWidth, out int grabPoint) {
for (int i = 0; i < path.PathPoints.Length; i++) {
Rectangle theRect = new Rectangle((int)path.PathPoints[i].X - grabBarWidth / 2 , (int)path.PathPoints[i].Y - grabBarWidth / 2, grabBarWidth, grabBarWidth);
if (theRect.Contains(p) ) {
grabPoint = i;
return true;
}
}
grabPoint = -1;
return false;
}
}
}