X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdrawingview.cpp;h=5ae9c9a9081e5ccf121c82958eac22e6634d6400;hb=6a7baa2814a8b4d0b93df776a4c99689bcfb3ffa;hp=f3cac0db04a00f44aa71934bfac4e6b21f122165;hpb=deb5512a6b35e73dc2c19ac4d2800cff87dd2e71;p=architektonas diff --git a/src/drawingview.cpp b/src/drawingview.cpp index f3cac0d..5ae9c9a 100644 --- a/src/drawingview.cpp +++ b/src/drawingview.cpp @@ -20,6 +20,7 @@ // STILL TO BE DONE: // // - Lots of stuff +// - Layer locking (hiding works) // // Uncomment this for debugging... @@ -40,8 +41,6 @@ #define BACKGROUND_MAX_SIZE 512 -enum { ToolMouseDown, ToolMouseMove, ToolMouseUp }; - // Class variable //Container DrawingView::document(Vector(0, 0)); @@ -49,10 +48,10 @@ enum { ToolMouseDown, ToolMouseMove, ToolMouseUp }; DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), // The value in the settings file will override this. useAntialiasing(true), numSelected(0), numHovered(0), shiftDown(false), - ctrlDown(false), overrideColor(false), + ctrlDown(false), gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE), - scale(1.0), offsetX(-10), offsetY(-10),// document(Vector(0, 0)), - gridPixels(0), collided(false)//, toolAction(NULL) + scale(1.0), offsetX(-10), offsetY(-10), + gridPixels(0), collided(false), hoveringIntersection(false) { // document.isTopLevelContainer = true; //wtf? doesn't work except in c++11??? document = { 0 }; @@ -86,6 +85,7 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent), line->thickness = 2.0; line->style = LSDash; line->color = 0xFF7F00; + line->layer = 0; document.objects.push_back(line); document.objects.push_back(new Line(Vector(50, 40), Vector(10, 83))); document.objects.push_back(new Line(Vector(10, 83), Vector(17, 2))); @@ -267,28 +267,74 @@ zero; so we do another modulus operation on the result to achieve this. } -void DrawingView::AddNewObjectToDocument(Object * object) +void DrawingView::SetCurrentLayer(int /*layer*/) +{ +//Not needed anymore... +// Global::currentLayer = layer; +//printf("DrawingView::CurrentLayer = %i\n", layer); +} + + +// +// Basically, we just make a single pass through the Container. If the layer # +// is less than the layer # being deleted, then do nothing. If the layer # is +// equal to the layer # being deleted, then delete the object. If the layer # +// is greater than the layer # being deleted, then set the layer # to its layer +// # - 1. +// +void DrawingView::DeleteCurrentLayer(int layer) { - if (object) +//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer); + std::vector::iterator i = document.objects.begin(); + + while (i != document.objects.end()) { -// object->Reparent(&document); -// document.Add(object); - update(); + Object * obj = (Object *)(*i); + + if (obj->layer < layer) + i++; + else if (obj->layer == layer) + { + document.objects.erase(i); + delete obj; + } + else + { + obj->layer--; + i++; + } } -//printf("DrawingView::AddNewObjectToDocument(). object=%08X\n", object); + + // We've just done a destructive action, so update the screen! + update(); } -void DrawingView::HandleActionUpdate(void) +void DrawingView::HandleLayerToggle(void) { + // A layer's visibility was toggled, so update the screen... update(); } -void DrawingView::SetCurrentLayer(int layer) +// +// A layer was moved up or down in the layer list, so we have to swap the +// document's object's layer numbers in the layers that were swapped. +// +void DrawingView::HandleLayerSwap(int layer1, int layer2) { - Global::currentLayer = layer; -//printf("DrawingView::CurrentLayer = %i\n", layer); +//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2); + std::vector::iterator i; + + for(i=document.objects.begin(); i!=document.objects.end(); i++) + { + Object * obj = (Object *)(*i); + + if (obj->layer == layer1) + obj->layer = layer2; + else if (obj->layer == layer2) + obj->layer = layer1; + } } @@ -326,7 +372,11 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/) painter.DrawLine(-16384, 0, 16384, 0); // Do object rendering... - RenderObjects(&painter, document.objects); + for(int i=0; i & v) +void DrawingView::RenderObjects(Painter * painter, std::vector & v, int layer) { std::vector::iterator i; @@ -358,7 +414,15 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v) Object * obj = (Object *)(*i); float scaledThickness = Global::scale * obj->thickness; - if (!overrideColor) + // If the object isn't on the current layer being drawn, skip it + if (obj->layer != layer) + continue; + + if ((Global::tool == TTRotate) && ctrlDown && obj->selected) + { + painter->SetPen(0x00FF00, 2.0, LSSolid); + } + else { painter->SetPen(obj->color, Global::zoom * scaledThickness, obj->style); painter->SetBrush(obj->color); @@ -370,31 +434,36 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v) switch (obj->type) { case OTLine: - { - Line * l = (Line *)obj; - painter->DrawLine(l->p[0], l->p[1]); + painter->DrawLine(obj->p[0], obj->p[1]); - if (l->hitPoint[0]) - painter->DrawHandle(l->p[0]); + if (obj->hitPoint[0]) + painter->DrawHandle(obj->p[0]); - if (l->hitPoint[1]) - painter->DrawHandle(l->p[1]); + if (obj->hitPoint[1]) + painter->DrawHandle(obj->p[1]); break; - } case OTCircle: - { - Circle * ci = (Circle *)obj; painter->SetBrush(QBrush(Qt::NoBrush)); - painter->DrawEllipse(ci->p[0], ci->radius, ci->radius); + painter->DrawEllipse(obj->p[0], obj->radius[0], obj->radius[0]); + + if (obj->hitPoint[0]) + painter->DrawHandle(obj->p[0]); + break; - } case OTArc: - { - Arc * a = (Arc *)obj; - painter->DrawArc(a->p[0], a->radius, a->angle1, a->angle2); + painter->DrawArc(obj->p[0], obj->radius[0], obj->angle[0], obj->angle[1]); + + if (obj->hitPoint[0]) + painter->DrawHandle(obj->p[0]); + + if (obj->hitPoint[1]) + painter->DrawHandle(obj->p[0] + (Vector(cos(obj->angle[0]), sin(obj->angle[0])) * obj->radius[0])); + + if (obj->hitPoint[2]) + painter->DrawHandle(obj->p[0] + (Vector(cos(obj->angle[0] + obj->angle[1]), sin(obj->angle[0] + obj->angle[1])) * obj->radius[0])); + break; - } case OTDimension: { Dimension * d = (Dimension *)obj; @@ -475,8 +544,8 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v) double t = Geometry::ParameterOfLineAndPoint(linePt1, linePt2, linePt2 - (unit * 9.0 * scaledThickness)); //printf("Dimension::Draw(): t = %lf\n", t); - // On the screen, it's acting like this is actually 58%... - // This is correct, we want it to happen at > 50% + // On the screen, it's acting like this is actually 58%... + // This is correct, we want it to happen at > 50% if (t > 0.58) { // Draw main dimension line + arrowheads @@ -535,34 +604,6 @@ void DrawingView::RenderObjects(Painter * painter, std::vector & v) } -void DrawingView::DeleteSelectedItems(void) -{ - std::vector::iterator i = document.objects.begin(); - - while (i != document.objects.end()) - { - Object * obj = (Object *)(*i); - - if (obj->selected) - { - delete obj; - document.objects.erase(i); - } - else - i++; - } -} - - -void DrawingView::ClearSelection(void) -{ - std::vector::iterator i; - - for(i=document.objects.begin(); i!=document.objects.end(); i++) - ((Object *)(*i))->selected = false; -} - - void DrawingView::AddHoveredToSelection(void) { std::vector::iterator i; @@ -611,12 +652,18 @@ void DrawingView::resizeEvent(QResizeEvent * /*event*/) } -void DrawingView::ToolMouse(int mode, Point p) +void DrawingView::ToolHandler(int mode, Point p) { if (Global::tool == TTLine) LineHandler(mode, p); + else if (Global::tool == TTCircle) + CircleHandler(mode, p); + else if (Global::tool == TTArc) + ArcHandler(mode, p); else if (Global::tool == TTRotate) RotateHandler(mode, p); + else if (Global::tool == TTMirror) + MirrorHandler(mode, p); } @@ -641,8 +688,72 @@ void DrawingView::ToolDraw(Painter * painter) double absAngle = v.Angle() * RADIANS_TO_DEGREES; double absLength = v.Magnitude(); QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2"); - text = text.arg(absLength).arg(absAngle); - painter->DrawInformativeText(text); + informativeText = text.arg(absLength).arg(absAngle); + } + } + else if (Global::tool == TTCircle) + { + if (Global::toolState == TSNone) + { + painter->DrawHandle(toolPoint[0]); + } + else if ((Global::toolState == TSPoint2) && shiftDown) + { + painter->DrawHandle(toolPoint[1]); + } + else + { + double length = Vector::Magnitude(toolPoint[0], toolPoint[1]); +// painter->DrawLine(toolPoint[0], toolPoint[1]); +// painter->DrawHandle(toolPoint[1]); + painter->SetBrush(QBrush(Qt::NoBrush)); + painter->DrawEllipse(toolPoint[0], length, length); + QString text = tr("Radius: %1 in.");//\n") + QChar(0x2221) + tr(": %2"); + informativeText = text.arg(length);//.arg(absAngle); + } + } + else if (Global::tool == TTArc) + { + if (Global::toolState == TSNone) + { + painter->DrawHandle(toolPoint[0]); + } + else if (Global::toolState == TSPoint2) + { + double length = Vector::Magnitude(toolPoint[0], toolPoint[1]); + painter->SetBrush(QBrush(Qt::NoBrush)); + painter->DrawEllipse(toolPoint[0], length, length); + painter->DrawLine(toolPoint[0], toolPoint[1]); + painter->DrawHandle(toolPoint[1]); + QString text = tr("Radius: %1 in."); + informativeText = text.arg(length); + } + else if (Global::toolState == TSPoint3) + { + double angle = Vector::Angle(toolPoint[0], toolPoint[2]); + painter->DrawLine(toolPoint[0], toolPoint[2]); + painter->SetBrush(QBrush(Qt::NoBrush)); + painter->DrawEllipse(toolPoint[0], toolPoint[1].x, toolPoint[1].x); + painter->DrawHandle(toolPoint[0] + (Vector(cos(angle), sin(angle)) * toolPoint[1].x)); + QString text = tr("Angle start: %1") + QChar(0x00B0); + informativeText = text.arg(RADIANS_TO_DEGREES * angle); + } + else + { + double angle = Vector::Angle(toolPoint[0], toolPoint[3]); + double span = angle - toolPoint[2].x; + + if (span < 0) + span += PI_TIMES_2; + + painter->DrawLine(toolPoint[0], toolPoint[3]); + painter->SetBrush(QBrush(Qt::NoBrush)); + painter->DrawEllipse(toolPoint[0], toolPoint[1].x, toolPoint[1].x); + painter->SetPen(0xFF00FF, 2.0, LSSolid); + painter->DrawArc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span); + painter->DrawHandle(toolPoint[0] + (Vector(cos(angle), sin(angle)) * toolPoint[1].x)); + QString text = tr("Arc span: %1") + QChar(0x00B0); + informativeText = text.arg(RADIANS_TO_DEGREES * span); } } else if (Global::tool == TTRotate) @@ -655,7 +766,7 @@ void DrawingView::ToolDraw(Painter * painter) { if (toolPoint[0] == toolPoint[1]) return; - + painter->DrawLine(toolPoint[0], toolPoint[1]); // Likely we need a tool container for this... (now we do!) #if 0 @@ -670,14 +781,49 @@ void DrawingView::ToolDraw(Painter * painter) #endif double absAngle = (Vector(toolPoint[1] - toolPoint[0]).Angle()) * RADIANS_TO_DEGREES; - QString text = QChar(0x2221) + QObject::tr(": %1"); - text = text.arg(absAngle); + informativeText = text.arg(absAngle); if (ctrlDown) - text += " (Copy)"; + informativeText += " (Copy)"; + } + } + else if (Global::tool == TTMirror) + { + if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1)) + painter->DrawHandle(toolPoint[0]); + else if ((Global::toolState == TSPoint2) && shiftDown) + painter->DrawHandle(toolPoint[1]); + else + { + if (toolPoint[0] == toolPoint[1]) + return; + + Point mirrorPoint = toolPoint[0] + Vector(toolPoint[1], toolPoint[0]); +// painter->DrawLine(toolPoint[0], toolPoint[1]); + painter->DrawLine(mirrorPoint, toolPoint[1]); + // Likely we need a tool container for this... (now we do!) +#if 0 + if (ctrlDown) + { + painter->SetPen(0x00FF00, 2.0, LSSolid); + overrideColor = true; + } + + RenderObjects(painter, toolObjects); + overrideColor = false; +#endif + + double absAngle = (Vector(toolPoint[1] - toolPoint[0]).Angle()) * RADIANS_TO_DEGREES; - painter->DrawInformativeText(text); + if (absAngle > 180.0) + absAngle -= 180.0; + + QString text = QChar(0x2221) + QObject::tr(": %1"); + informativeText = text.arg(absAngle); + + if (ctrlDown) + informativeText += " (Copy)"; } } } @@ -717,6 +863,7 @@ void DrawingView::LineHandler(int mode, Point p) else { Line * l = new Line(toolPoint[0], toolPoint[1]); + l->layer = Global::activeLayer; document.objects.push_back(l); toolPoint[0] = toolPoint[1]; } @@ -724,6 +871,120 @@ void DrawingView::LineHandler(int mode, Point p) } +void DrawingView::CircleHandler(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 + { + double length = Vector::Magnitude(toolPoint[0], toolPoint[1]); + Circle * c = new Circle(toolPoint[0], length); + c->layer = Global::activeLayer; + document.objects.push_back(c); + toolPoint[0] = toolPoint[1]; + Global::toolState = TSNone; + } + } +} + + +void DrawingView::ArcHandler(int mode, Point p) +{ + switch (mode) + { + case ToolMouseDown: + if (Global::toolState == TSNone) + toolPoint[0] = p; + else if (Global::toolState == TSPoint2) + toolPoint[1] = p; + else if (Global::toolState == TSPoint3) + toolPoint[2] = p; + else + toolPoint[3] = p; + + break; + 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; + else + toolPoint[3] = p; + + break; + case ToolMouseUp: + if (Global::toolState == TSNone) + { + // Prevent spurious line from drawing... + toolPoint[1] = toolPoint[0]; + Global::toolState = TSPoint2; + } + else if (Global::toolState == TSPoint2) + { + if (shiftDown) + { + // Key override is telling us to start circle at new center, not + // continue the current one. + toolPoint[0] = toolPoint[1]; + return; + } + + // Set the radius in toolPoint[1].x + toolPoint[1].x = Vector::Magnitude(toolPoint[0], toolPoint[1]); + Global::toolState = TSPoint3; + } + else if (Global::toolState == TSPoint3) + { + // Set the angle in toolPoint[2].x + toolPoint[2].x = Vector::Angle(toolPoint[0], toolPoint[2]); + Global::toolState = TSPoint4; + } + else + { + double endAngle = Vector::Angle(toolPoint[0], toolPoint[3]); + double span = endAngle - toolPoint[2].x; + + if (span < 0) + span += PI_TIMES_2; + + Arc * arc = new Arc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span); + arc->layer = Global::activeLayer; + document.objects.push_back(arc); + Global::toolState = TSNone; + } + } +} + + void DrawingView::RotateHandler(int mode, Point p) { switch (mode) @@ -732,9 +993,7 @@ void DrawingView::RotateHandler(int mode, Point p) if (Global::toolState == TSNone) { toolPoint[0] = p; - toolObjects.clear(); - CopyObjects(select, toolObjects); -// ClearSelected(toolObjects); + SavePointsFrom(select, toolScratch); Global::toolState = TSPoint1; } else if (Global::toolState == TSPoint1) @@ -744,39 +1003,138 @@ void DrawingView::RotateHandler(int mode, Point p) break; case ToolMouseMove: -/* -There's two approaches to this that we can do: - - -- Keep a copy of selected objects & rotate those (drawing rotated + selected) - -- Rotate the selected (drawing selected only) - -Either way, we need to have a copy of the points before we change them; we also need -to know whether or not to discard any changes made--maybe with a ToolCleanup() -function. -*/ if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone)) toolPoint[0] = p; else if (Global::toolState == TSPoint2) { -// need to reset the selected points to their non-rotated state in this case... + toolPoint[1] = p; + if (shiftDown) return; + double angle = Vector(toolPoint[0], toolPoint[1]).Angle(); + std::vector::iterator j = select.begin(); + std::vector::iterator i = toolScratch.begin(); + + for(; i!=toolScratch.end(); i++, j++) + { + Object obj = *i; + Point p1 = Geometry::RotatePointAroundPoint(obj.p[0], toolPoint[0], angle); + Point p2 = Geometry::RotatePointAroundPoint(obj.p[1], toolPoint[0], angle); + Object * obj2 = (Object *)(*j); + obj2->p[0] = p1; + obj2->p[1] = p2; + + if (obj.type == OTArc) + { + obj2->angle[0] = obj.angle[0] + angle; + + if (obj2->angle[0] > PI_TIMES_2) + obj2->angle[0] -= PI_TIMES_2; + } + } + } + + 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 + std::vector 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) + RotateHandler(ToolMouseMove, toolPoint[1]); + + break; + case ToolCleanup: + RestorePointsTo(select, toolScratch); + } +} + + +void DrawingView::MirrorHandler(int mode, Point p) +{ + switch (mode) + { + 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; - double angle = Vector(toolPoint[1], toolPoint[0]).Angle(); + if (shiftDown) + return; + + double angle = Vector(toolPoint[0], toolPoint[1]).Angle(); std::vector::iterator j = select.begin(); - std::vector::iterator i = toolObjects.begin(); + std::vector::iterator i = toolScratch.begin(); -// for(; i!=select.end(); i++, j++) - for(; i!=toolObjects.end(); i++, j++) + for(; i!=toolScratch.end(); i++, j++) { - Object * obj = (Object *)(*i); - Point p1 = Geometry::RotatePointAroundPoint(obj->p[0], toolPoint[0], angle); - Point p2 = Geometry::RotatePointAroundPoint(obj->p[1], toolPoint[0], angle); + 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; + + 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] > PI_TIMES_2) + obj2->angle[0] -= PI_TIMES_2; + } } } @@ -796,12 +1154,38 @@ function. } else { -#if 0 - Line * l = new Line(toolPoint[0], toolPoint[1]); - document.objects.push_back(l); - toolPoint[0] = toolPoint[1]; -#endif + // 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 + std::vector 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); } } @@ -824,13 +1208,14 @@ void DrawingView::mousePressEvent(QMouseEvent * event) // if (Global::snapPointIsValid) // point = Global::snapPoint; - ToolMouse(ToolMouseDown, point); + ToolHandler(ToolMouseDown, point); return; } // Clear the selection only if CTRL isn't being held on click if (!ctrlDown) - ClearSelection(); + ClearSelected(document.objects); +// ClearSelection(); // If any objects are being hovered on click, add them to the selection // & return @@ -841,6 +1226,7 @@ void DrawingView::mousePressEvent(QMouseEvent * event) GetHovered(hover); // prolly needed // Needed for grab & moving objects + // We do it *after*... why? (doesn't seem to confer any advantage...) if (Global::snapToGrid) oldPoint = SnapPointToGrid(point); @@ -868,6 +1254,7 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) Global::selection.setBottomRight(QPointF(point.x, point.y)); // Only needs to be done here, as mouse down is always preceded by movement Global::snapPointIsValid = false; + hoveringIntersection = false; // Scrolling... if (event->buttons() & Qt::MiddleButton) @@ -898,6 +1285,9 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) // Handle object movement (left button down & over an object) if ((event->buttons() & Qt::LeftButton) && numHovered && !Global::tool) { + if (Global::snapToGrid) + point = SnapPointToGrid(point); + HandleObjectMovement(point); update(); oldPoint = point; @@ -907,13 +1297,49 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event) // Do object hit testing... bool needUpdate = HitTestObjects(point); + // Check for multi-hover... + if (numHovered > 1) + { + GetHovered(hover); + +// double t, u; +// int numIntersecting = Geometry::Intersects((Object *)hover[0], (Object *)hover[1], &t, &u); + Geometry::Intersects((Object *)hover[0], (Object *)hover[1]); + int numIntersecting = Global::numIntersectParams; + double t = Global::intersectParam[0]; + double u = Global::intersectParam[1]; + + if (numIntersecting > 0) + { + Vector v1 = Geometry::GetPointForParameter((Object *)hover[0], t); + Vector v2 = Geometry::GetPointForParameter((Object *)hover[1], u); + QString text = tr("Intersection t=%1 (%3, %4), u=%2 (%5, %6)"); + informativeText = text.arg(t).arg(u).arg(v1.x).arg(v1.y).arg(v2.x).arg(v2.y); + + hoveringIntersection = true; + intersectionPoint = v1; + } + + numIntersecting = Global::numIntersectPoints; + + if (numIntersecting > 0) + { + Vector v1 = Global::intersectPoint[0]; + QString text = tr("Intersection <%1, %2>"); + informativeText = text.arg(v1.x).arg(v1.y); + + hoveringIntersection = true; + intersectionPoint = v1; + } + } + // Do tool handling, if any are active... if (Global::tool) { if (Global::snapToGrid) point = SnapPointToGrid(point); - ToolMouse(ToolMouseMove, point); + ToolHandler(ToolMouseMove, point); } // This is used to draw the tool crosshair... @@ -939,31 +1365,30 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event) if (Global::tool) { Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y())); - ToolMouse(ToolMouseUp, point); + ToolHandler(ToolMouseUp, point); return; } if (Global::selectionInProgress) - { - // Select all the stuff inside of selection Global::selectionInProgress = false; - // Clear our vectors - select.clear(); - hover.clear(); + informativeText.clear(); +// Should we be doing this automagically? Hmm... + // Clear our vectors + select.clear(); + hover.clear(); - // Scoop 'em up - std::vector::iterator i; + // Scoop 'em up + std::vector::iterator i; - for(i=document.objects.begin(); i!=document.objects.end(); i++) - { - if (((Object *)(*i))->selected) - select.push_back(*i); + for(i=document.objects.begin(); i!=document.objects.end(); i++) + { + if (((Object *)(*i))->selected) + select.push_back(*i); //hmm, this is no good, too late to do any good :-P -// if ((*i)->hovered) -// hover.push_back(*i); - } +// if ((*i)->hovered) +// hover.push_back(*i); } } else if (event->button() == Qt::MiddleButton) @@ -995,22 +1420,16 @@ void DrawingView::wheelEvent(QWheelEvent * event) Global::zoom /= zoomFactor; } -#if 1 // Global::gridSpacing = gridPixels / Painter::zoom; // UpdateGridBackground(); SetGridSize(Global::gridSpacing * Global::zoom); update(); // zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing)); -#endif } void DrawingView::keyPressEvent(QKeyEvent * event) { -#if 0 - if (toolAction) - toolAction->KeyDown(event->key()); -#endif bool oldShift = shiftDown; bool oldCtrl = ctrlDown; @@ -1020,16 +1439,17 @@ void DrawingView::keyPressEvent(QKeyEvent * event) ctrlDown = true; if ((oldShift != shiftDown) || (oldCtrl != ctrlDown)) + { + if (Global::tool) + ToolHandler(ToolKeyDown, Point(0, 0)); + update(); + } } void DrawingView::keyReleaseEvent(QKeyEvent * event) { -#if 0 - if (toolAction) - toolAction->KeyReleased(event->key()); -#endif bool oldShift = shiftDown; bool oldCtrl = ctrlDown; @@ -1039,9 +1459,15 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event) ctrlDown = false; if ((oldShift != shiftDown) || (oldCtrl != ctrlDown)) + { + if (Global::tool) + ToolHandler(ToolKeyUp, Point(0, 0)); + update(); + } } + // // This looks strange, but it's really quite simple: We want a point that's // more than half-way to the next grid point to snap there while conversely we @@ -1087,7 +1513,7 @@ void DrawingView::CheckObjectBounds(void) { Circle * c = (Circle *)obj; - if (Global::selection.contains(c->p[0].x - c->radius, c->p[0].y - c->radius) && Global::selection.contains(c->p[0].x + c->radius, c->p[0].y + c->radius)) + if (Global::selection.contains(c->p[0].x - c->radius[0], c->p[0].y - c->radius[0]) && Global::selection.contains(c->p[0].x + c->radius[0], c->p[0].y + c->radius[0])) c->selected = true; break; @@ -1096,8 +1522,8 @@ void DrawingView::CheckObjectBounds(void) { Arc * a = (Arc *)obj; - double start = a->angle1; - double end = start + a->angle2; + double start = a->angle[0]; + double end = start + a->angle[1]; QPointF p1(cos(start), sin(start)); QPointF p2(cos(end), sin(end)); QRectF bounds(p1, p2); @@ -1148,8 +1574,8 @@ void DrawingView::CheckObjectBounds(void) if ((start < ((3.0 * PI) + PI_OVER_2)) && (end > ((3.0 * PI) + PI_OVER_2))) bounds.setBottom(-1.0); - bounds.setTopLeft(QPointF(bounds.left() * a->radius, bounds.top() * a->radius)); - bounds.setBottomRight(QPointF(bounds.right() * a->radius, bounds.bottom() * a->radius)); + bounds.setTopLeft(QPointF(bounds.left() * a->radius[0], bounds.top() * a->radius[0])); + bounds.setBottomRight(QPointF(bounds.right() * a->radius[0], bounds.bottom() * a->radius[0])); bounds.translate(a->p[0].x, a->p[0].y); if (Global::selection.contains(bounds)) @@ -1181,13 +1607,12 @@ bool DrawingView::HitTestObjects(Point point) { case OTLine: { - Line * l = (Line *)obj; - bool oldHP0 = l->hitPoint[0], oldHP1 = l->hitPoint[1], oldHO = l->hitObject; - l->hitPoint[0] = l->hitPoint[1] = l->hitObject = false; - Vector lineSegment = l->p[1] - l->p[0]; - Vector v1 = point - l->p[0]; - Vector v2 = point - l->p[1]; - double t = Geometry::ParameterOfLineAndPoint(l->p[0], l->p[1], point); + bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHO = obj->hitObject; + obj->hitPoint[0] = obj->hitPoint[1] = obj->hitObject = false; + Vector lineSegment = obj->p[1] - obj->p[0]; + Vector v1 = point - obj->p[0]; + Vector v2 = point - obj->p[1]; + double t = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], point); double distance; if (t < 0.0) @@ -1200,34 +1625,71 @@ bool DrawingView::HitTestObjects(Point point) / lineSegment.Magnitude()); if ((v1.Magnitude() * Global::zoom) < 8.0) - { - l->hitPoint[0] = true; -// snapPoint = l->p1; -// snapPointIsValid = true; - } + obj->hitPoint[0] = true; else if ((v2.Magnitude() * Global::zoom) < 8.0) - { - l->hitPoint[1] = true; -// snapPoint = l->p2; -// snapPointIsValid = true; - } + obj->hitPoint[1] = true; else if ((distance * Global::zoom) < 5.0) - l->hitObject = true; + obj->hitObject = true; -// bool oldHovered = l->hovered; - l->hovered = (l->hitPoint[0] || l->hitPoint[1] || l->hitObject ? true : false); -// l->hovered = l->hitObject; + obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject ? true : false); -// if (oldHovered != l->hovered) - if ((oldHP0 != l->hitPoint[0]) || (oldHP1 != l->hitPoint[1]) || (oldHO != l->hitObject)) + if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHO != obj->hitObject)) needUpdate = true; break; } case OTCircle: { - Circle * c = (Circle *)obj; + bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject; + obj->hitPoint[0] = obj->hitObject = false; + double length = Vector::Magnitude(obj->p[0], point); + + if ((length * Global::zoom) < 8.0) + obj->hitPoint[0] = true; + else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) + obj->hitObject = true; + + obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false); + if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject)) + needUpdate = true; + + break; + } + case OTArc: + { + bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHO = obj->hitObject; + obj->hitPoint[0] = obj->hitPoint[1] = obj->hitPoint[2] = obj->hitObject = false; + double length = Vector::Magnitude(obj->p[0], point); + double angle = Vector::Angle(obj->p[0], point); + + // Make sure we get the angle in the correct spot + if (angle < obj->angle[0]) + angle += PI_TIMES_2; + + // Get the span that we're pointing at... + double span = angle - obj->angle[0]; + + // N.B.: Still need to hit test the arc start & arc span handles... + double spanAngle = obj->angle[0] + obj->angle[1]; + Point handle1 = obj->p[0] + (Vector(cos(obj->angle[0]), sin(obj->angle[0])) * obj->radius[0]); + Point handle2 = obj->p[0] + (Vector(cos(spanAngle), sin(spanAngle)) * obj->radius[0]); + double length2 = Vector::Magnitude(point, handle1); + double length3 = Vector::Magnitude(point, handle2); + + if ((length * Global::zoom) < 8.0) + obj->hitPoint[0] = true; + else if ((length2 * Global::zoom) < 8.0) + obj->hitPoint[1] = true; + else if ((length3 * Global::zoom) < 8.0) + obj->hitPoint[2] = true; + else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1])) + obj->hitObject = true; + + obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitObject ? true : false); + + if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHO != obj->hitObject)) + needUpdate = true; break; } @@ -1248,10 +1710,8 @@ bool DrawingView::HitTestObjects(Point point) void DrawingView::HandleObjectMovement(Point point) { - if (Global::snapToGrid) - point = SnapPointToGrid(point); - Point delta = point - oldPoint; +//printf("HOM: old = (%f,%f), new = (%f, %f), delta = (%f, %f)\n", oldPoint.x, oldPoint.y, point.x, point.y, delta.x, delta.y); Object * obj = (Object *)hover[0]; //printf("Object type = %i (size=%i), ", obj->type, hover.size()); //printf("Object (%X) move: hp1=%s, hp2=%s, hl=%s\n", obj, (obj->hitPoint[0] ? "true" : "false"), (obj->hitPoint[1] ? "true" : "false"), (obj->hitObject ? "true" : "false")); @@ -1259,21 +1719,99 @@ void DrawingView::HandleObjectMovement(Point point) switch (obj->type) { case OTLine: - { - Line * l = (Line *)obj; + if (obj->hitPoint[0]) + obj->p[0] = point; + else if (obj->hitPoint[1]) + obj->p[1] = point; + else if (obj->hitObject) + { + obj->p[0] += delta; + obj->p[1] += delta; + } - if (l->hitPoint[0]) - l->p[0] = point; - else if (l->hitPoint[1]) - l->p[1] = point; - else if (l->hitObject) + break; + case OTCircle: + if (obj->hitPoint[0]) + obj->p[0] = point; + else if (obj->hitObject) { - l->p[0] += delta; - l->p[1] += delta; +//this doesn't work. we need to save this on mouse down for this to work correctly! +// double oldRadius = obj->radius[0]; + obj->radius[0] = Vector::Magnitude(obj->p[0], point); + + QString text = QObject::tr("Radius: %1");//\nScale: %2%"); + informativeText = text.arg(obj->radius[0], 0, 'd', 4);//.arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0); + } + + break; + case OTArc: + if (obj->hitPoint[0]) + obj->p[0] = point; + else if (obj->hitPoint[1]) + { + // Change the Arc's span (handle #1) + if (shiftDown) + { + double angle = Vector::Angle(obj->p[0], point); + double delta = angle - obj->angle[0]; + + if (delta < 0) + delta += PI_TIMES_2; + + obj->angle[1] -= delta; + obj->angle[0] = angle; + + if (obj->angle[1] < 0) + obj->angle[1] += PI_TIMES_2; + + QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0); + informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2); + return; + } + + double angle = Vector::Angle(obj->p[0], point); + obj->angle[0] = angle; + QString text = QObject::tr("Start angle: %1") + QChar(0x00B0); + informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 4); + } + else if (obj->hitPoint[2]) + { + // Change the Arc's span (handle #2) + if (shiftDown) + { + double angle = Vector::Angle(obj->p[0], point); + obj->angle[1] = angle - obj->angle[0]; + + if (obj->angle[1] < 0) + obj->angle[1] += PI_TIMES_2; + + QString text = QObject::tr("Span: %1") + QChar(0x00B0) + QObject::tr("\n%2") + QChar(0x00B0) + QObject::tr(" - %3") + QChar(0x00B0); + informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'd', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'd', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 2); + return; + } + + double angle = Vector::Angle(obj->p[0], point); + obj->angle[0] = angle - obj->angle[1]; + + if (obj->angle[0] < 0) + obj->angle[0] += PI_TIMES_2; + + QString text = QObject::tr("End angle: %1") + QChar(0x00B0); + informativeText = text.arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 4); + } + else if (obj->hitObject) + { + if (shiftDown) + { + return; + } + + obj->radius[0] = Vector::Magnitude(obj->p[0], point); + QString text = QObject::tr("Radius: %1"); + informativeText = text.arg(obj->radius[0], 0, 'd', 4); } break; - } default: break; }