+ case ToolMouseDown:
+ if (Global::toolState == TSNone)
+ {
+ toolPoint[0] = p;
+ SavePointsFrom(select, toolScratch);
+ Global::toolState = TSPoint1;
+ }
+ else if (Global::toolState == TSPoint1)
+ toolPoint[0] = p;
+ else
+ toolPoint[1] = p;
+
+ break;
+
+ case ToolMouseMove:
+ if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone))
+ toolPoint[0] = p;
+ else if (Global::toolState == TSPoint2)
+ {
+ toolPoint[1] = p;
+
+ if (shiftDown)
+ return;
+
+ angleSnap = true;
+ double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
+ VPVectorIter j = select.begin();
+ std::vector<Object>::iterator i = toolScratch.begin();
+
+ for(; i!=toolScratch.end(); i++, j++)
+ {
+ Object obj = *i;
+ Point p1 = Geometry::MirrorPointAroundLine(obj.p[0], toolPoint[0], toolPoint[1]);
+ Point p2 = Geometry::MirrorPointAroundLine(obj.p[1], toolPoint[0], toolPoint[1]);
+ Object * obj2 = (Object *)(*j);
+ obj2->p[0] = p1;
+ obj2->p[1] = p2;
+
+/*
+N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have
+ a negative start angle which makes it impossible to interact with.
+ !!! FIX !!!
+*/
+ if (obj.type == OTArc)
+ {
+ // This is 2*mirror angle - obj angle - obj span
+ obj2->angle[0] = (2.0 * angle) - obj.angle[0] - obj.angle[1];
+
+ if (obj2->angle[0] > TAU)
+ obj2->angle[0] -= TAU;
+ }
+ }
+ }
+
+ break;
+
+ case ToolMouseUp:
+ if (Global::toolState == TSPoint1)
+ {
+ Global::toolState = TSPoint2;
+ // Prevent spurious line from drawing...
+ toolPoint[1] = toolPoint[0];
+ }
+ else if ((Global::toolState == TSPoint2) && shiftDown)
+ {
+ // Key override is telling us to make a new line, not continue the
+ // previous one.
+ toolPoint[0] = toolPoint[1];
+ }
+ else
+ {
+ // Either we're finished with our rotate, or we're stamping a copy.
+ if (ctrlDown)
+ {
+ // Stamp a copy of the selection at the current rotation & bail
+ VPVector temp;
+ CopyObjects(select, temp);
+ ClearSelected(temp);
+ AddObjectsTo(document.objects, temp);
+ RestorePointsTo(select, toolScratch);
+ return;
+ }
+
+ toolPoint[0] = p;
+ Global::toolState = TSPoint1;
+ SavePointsFrom(select, toolScratch);
+ }
+
+ break;
+
+ case ToolKeyDown:
+ // Reset the selection if shift held down...
+ if (shiftDown)
+ RestorePointsTo(select, toolScratch);
+
+ break;
+
+ case ToolKeyUp:
+ // Reset selection when key is let up
+ if (!shiftDown)
+ MirrorHandler(ToolMouseMove, toolPoint[1]);
+
+ break;
+
+ case ToolCleanup:
+ RestorePointsTo(select, toolScratch);
+ }
+}
+
+void DrawingView::DimensionHandler(int mode, Point p)
+{
+ switch (mode)
+ {
+ case ToolMouseDown:
+ if (Global::toolState == TSNone)
+ toolPoint[0] = p;
+ else
+ toolPoint[1] = p;
+
+ break;
+
+ case ToolMouseMove:
+ if (Global::toolState == TSNone)
+ toolPoint[0] = p;
+ else
+ toolPoint[1] = p;
+
+ break;
+
+ case ToolMouseUp:
+ if (Global::toolState == TSNone)
+ {
+ Global::toolState = TSPoint2;
+ // Prevent spurious line from drawing...
+ toolPoint[1] = toolPoint[0];
+ }
+ else if ((Global::toolState == TSPoint2) && shiftDown)
+ {
+ // Key override is telling us to make a new line, not continue the
+ // previous one.
+ toolPoint[0] = toolPoint[1];
+ }
+ else
+ {
+ Dimension * d = new Dimension(toolPoint[0], toolPoint[1], DTLinear, 0, Global::penWidth);
+ d->layer = Global::activeLayer;
+ document.objects.push_back(d);
+ Global::toolState = TSNone;
+ }
+ }
+}
+
+void DrawingView::DeleteHandler(int mode, Point /*p*/)
+{
+ switch (mode)
+ {
+ case ToolMouseDown:
+ {
+ VPVector hovered = GetHovered();
+
+ RemoveHoveredObjects(document.objects);
+ DeleteContents(hovered);
+ }
+ break;
+
+ case ToolMouseMove:
+ break;
+
+ case ToolMouseUp:
+ break;
+
+ case ToolKeyDown:
+ break;
+
+ case ToolKeyUp:
+ break;
+
+ case ToolCleanup:
+ break;
+ }
+}
+
+void DrawingView::TriangulateHandler(int mode, Point /*p*/)
+{
+ switch (mode)
+ {
+ case ToolMouseDown:
+ {
+ // Skip if nothing hovered...
+ if (numHovered != 1)
+ break;
+
+ VPVector hover = GetHovered();
+ Object * obj = (Object *)hover[0];
+
+ // Skip if it's not a line...
+ if (obj->type != OTLine)
+ break;
+
+ if (Global::toolState == TSNone)
+ toolObj[0] = obj;
+ else if (Global::toolState == TSPoint2)
+ toolObj[1] = obj;
+ else
+ toolObj[2] = obj;
+
+ break;
+ }
+#if 0
+ case ToolMouseMove:
+ if (Global::toolState == TSNone)
+ toolPoint[0] = p;
+ else if (Global::toolState == TSPoint2)
+ toolPoint[1] = p;
+ else if (Global::toolState == TSPoint3)
+ {
+ toolPoint[2] = p;
+ angleSnap = true;
+ }
+ else
+ {
+ toolPoint[3] = p;
+ angleSnap = true;
+ }
+
+ break;
+#endif
+ case ToolMouseUp:
+ if (Global::toolState == TSNone)
+ {
+ Global::toolState = TSPoint2;
+ }
+ else if (Global::toolState == TSPoint2)
+ {
+/* if (shiftDown)
+ {
+ // Key override is telling us to start arc at new center, not
+ // continue the current one.
+ toolPoint[0] = toolPoint[1];
+ return;
+ }*/
+
+ Global::toolState = TSPoint3;
+ }
+ else
+ {
+ double len2 = Vector::Magnitude(toolObj[1]->p[0], toolObj[1]->p[1]);
+ double len3 = Vector::Magnitude(toolObj[2]->p[0], toolObj[2]->p[1]);
+
+ Circle c1(toolObj[0]->p[0], len2);
+ Circle c2(toolObj[0]->p[1], len3);
+
+ Geometry::CheckCircleToCircleIntersection((Object *)&c1, (Object *)&c2);
+
+ // Only move lines if the triangle formed by them is not degenerate
+ if (Global::numIntersectPoints > 0)
+ {
+ toolObj[1]->p[0] = toolObj[0]->p[0];
+ toolObj[1]->p[1] = Global::intersectPoint[0];
+
+ toolObj[2]->p[0] = Global::intersectPoint[0];
+ toolObj[2]->p[1] = toolObj[0]->p[1];
+ }
+
+ Global::toolState = TSNone;
+ }
+ }
+}
+
+void DrawingView::TrimHandler(int mode, Point p)
+{
+ switch (mode)
+ {
+ case ToolMouseDown:
+ {
+ }
+ break;
+
+ case ToolMouseMove:
+ {
+ // Bail out if nothing hovered...
+ if (numHovered != 1)
+ {
+ toolObj[0] = NULL;
+ return;
+ }
+
+ VPVector hover = GetHovered();
+ Object * obj = (Object *)hover[0];
+
+ // Skip if it's not a line...
+ if (obj->type != OTLine)
+ {
+ toolObj[0] = NULL;
+ return;
+ }
+
+ toolObj[0] = obj;
+ double hoveredParam = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], p);
+ double t = 0, u = 1.0;
+
+ // Currently only deal with line against line trimming, can expand to
+ // others as well (line/circle, circle/circle, line/arc, etc)
+ VPVectorIter i;
+ for(i=document.objects.begin(); i!=document.objects.end(); i++)
+ {
+ obj = (Object *)(*i);
+
+ if (obj == toolObj[0])
+ continue;
+ else if (obj->type != OTLine)
+ continue;
+
+ Geometry::CheckLineToLineIntersection(toolObj[0], obj);
+
+ if (Global::numIntersectParams > 0)
+ {
+ // Skip endpoint-endpoint intersections
+ if ((Global::numIntersectParams == 2)
+ && (Global::intersectParam[0] == 0
+ || Global::intersectParam[0] == 1.0)
+ && (Global::intersectParam[1] == 0
+ || Global::intersectParam[1] == 1.0))
+ continue;
+
+ // Mark the line segment somehow (the side the mouse is on) so that it can be drawn & trimmed when we hit ToolMouseDown.
+ if ((Global::intersectParam[0] > t) && (Global::intersectParam[0] < hoveredParam))
+ t = Global::intersectParam[0];
+
+ if ((Global::intersectParam[0] < u) && (Global::intersectParam[0] > hoveredParam))
+ u = Global::intersectParam[0];
+ }
+ }
+
+ toolParam[0] = t;
+ toolParam[1] = u;
+ toolPoint[0] = Geometry::GetPointForParameter(toolObj[0], t);
+ toolPoint[1] = Geometry::GetPointForParameter(toolObj[0], u);
+ }
+ break;
+
+ case ToolMouseUp:
+ {
+ // Bail out if there's no object to trim
+ if (toolObj[0] == NULL)
+ return;
+
+ Vector v(toolObj[0]->p[0], toolObj[0]->p[1]);
+
+ // Check to see which case we have.
+ if ((toolParam[0] == 0) && (toolParam[1] == 1.0))
+ {
+ // There was no intersection, so delete the object
+ toolObj[0]->selected = true;
+ DeleteSelectedObjects(document.objects);
+ }
+ else if (toolParam[0] == 0)
+ {
+ // We delete the end near point #1
+ toolObj[0]->p[0] = toolObj[0]->p[0] + (v * toolParam[1]);
+ }
+ else if (toolParam[1] == 1.0)
+ {
+ // We delete the end near point #2
+ toolObj[0]->p[1] = toolObj[0]->p[0] + (v * toolParam[0]);
+ }
+ else
+ {
+ // We delete the segment in between, and create a new line in the process
+ Point p1 = toolObj[0]->p[0] + (v * toolParam[0]);
+ Point p2 = toolObj[0]->p[0] + (v * toolParam[1]);
+ Point p3 = toolObj[0]->p[1];
+ toolObj[0]->p[1] = p1;
+ Line * l = new Line(p2, p3, toolObj[0]->thickness, toolObj[0]->color, toolObj[0]->style);
+ document.objects.push_back(l);
+// Global::toolState = TSNone;
+ }
+
+ toolObj[0]->hitObject = toolObj[0]->hitPoint[0] = toolObj[0]->hitPoint[1] = false;
+ toolObj[0] = NULL;
+ }
+ break;
+
+ case ToolKeyDown:
+ break;
+
+ case ToolKeyUp:
+ break;
+
+ case ToolCleanup:
+ break;
+ }
+}
+
+void DrawingView::ParallelHandler(int mode, Point p)
+{
+ switch (mode)
+ {
+ case ToolMouseDown:
+ if (numHovered == 1)
+ {
+ // New selection made...
+ VPVector hover = GetHovered();
+ toolObj[0] = (Object *)hover[0];
+ Global::toolState = TSNone;
+ }
+ else if ((numHovered == 0) && (toolObj[0] != NULL))
+ {
+ double length = Vector::Magnitude(toolObj[0]->p[0], toolPoint[0]);
+ bool inside = (length >= toolObj[0]->radius[0] ? false : true);
+
+ // Stamp out new parallel object(s)...
+ for(int i=1; i<=Global::parallelNum; i++)
+ {
+ if (toolObj[0]->type == OTLine)
+ {
+ Line * l = new Line(toolObj[0]->p[0] + (toolPoint[0] * Global::parallelDist * (double)i), toolObj[0]->p[1] + (toolPoint[0] * Global::parallelDist * (double)i), Global::penWidth, Global::penColor, Global::penStyle);
+ // Should probably have a user selection for this whether it goes into the selected objects layer or the global layer...
+ l->layer = toolObj[0]->layer;
+ document.objects.push_back(l);
+ }
+ else if (toolObj[0]->type == OTCircle)
+ {
+ double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0));
+
+ if (radius > 0)
+ {
+ Circle * c = new Circle(toolObj[0]->p[0], radius, Global::penWidth, Global::penColor, Global::penStyle);
+ c->layer = toolObj[0]->layer;
+ document.objects.push_back(c);
+ }
+ }
+ else if (toolObj[0]->type == OTArc)
+ {
+ double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0));
+
+ if (radius > 0)
+ {
+ Arc * a = new Arc(toolObj[0]->p[0], radius, toolObj[0]->angle[0], toolObj[0]->angle[1], Global::penWidth, Global::penColor, Global::penStyle);
+ a->layer = toolObj[0]->layer;
+ document.objects.push_back(a);
+ }
+ }
+ }
+
+ // Then reset the state
+ toolObj[0]->selected = false;
+ toolObj[0] = NULL;
+ Global::toolState = TSNone;
+ }
+
+ break;
+
+ case ToolMouseMove:
+ if ((numHovered == 0) && toolObj[0] != NULL)
+ Global::toolState = TSPoint1;
+ else
+ Global::toolState = TSNone;
+
+ if (Global::toolState == TSPoint1)
+ {
+ // Figure out which side of the object we're on, and draw the preview on that side...
+ if (toolObj[0]->type == OTLine)
+ {
+ Vector normal = Geometry::GetNormalOfPointAndLine(p, (Line *)toolObj[0]);
+ toolPoint[0] = normal;
+ }
+ else if ((toolObj[0]->type == OTCircle) || (toolObj[0]->type == OTArc))
+ {
+ toolPoint[0] = p;
+ }
+ }
+
+ break;
+
+ case ToolMouseUp:
+ break;
+
+ case ToolKeyDown:
+ break;
+
+ case ToolKeyUp:
+ break;
+
+ case ToolCleanup:
+ break;
+ }
+}
+
+void DrawingView::mousePressEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ {
+ Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+
+ // Handle tool processing, if any
+ if (Global::tool)
+ {
+ if (hoveringIntersection)
+ point = intersectionPoint;
+ else if (hoverPointValid)
+ point = hoverPoint;
+ else if (Global::snapToGrid)