]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Added base units & display style to drawing.
[architektonas] / src / drawingview.cpp
index 5b0eeeef6b214c5d4ef4b67f8f87b6af9c2c195c..3b6f92c6663c363bba9b1cf68e006793f101a7e0 100644 (file)
@@ -41,6 +41,7 @@
 #include "painter.h"
 #include "penwidget.h"
 #include "structs.h"
+#include "units.h"
 #include "utils.h"
 
 #define BACKGROUND_MAX_SIZE    512
@@ -52,8 +53,9 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
        scale(1.0), offsetX(-10), offsetY(-10), supressSelected(false),
        document(true),
-       gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false),
-       hoveringIntersection(false), dragged(NULL), draggingObject(false),
+       gridPixels(0), collided(false), scrollDrag(false),
+       hoverPointValid(false), hoveringIntersection(false),
+       dragged(NULL), draggingObject(false),
        angleSnap(false), dirty(false)
 {
 //wtf? doesn't work except in c++11??? document = { 0 };
@@ -121,10 +123,7 @@ scaled the same way as the arrowheads.
 Need a way to scale line widths as well. :-/ Shouldn't be too difficult, just
 need a thickness parameter similar to the "size" param for dimensions. (And now
 we do! :-)
-
 */
-//     gridPixels = 12; //tmp???
-//     SetGridSize(12.0);      // This is in pixels
 }
 
 void DrawingView::DrawBackground(Painter * painter)
@@ -162,12 +161,12 @@ void DrawingView::DrawBackground(Painter * painter)
                DrawSubGrid(painter, 0xB8ECFF, 0.125, start, size);
 
        if (Global::gridSpacing <= 0.25)
-               DrawSubGrid(painter, 0xDBDBFF, 0.25, start, size);
+               DrawSubGrid(painter, 0xE6E6FF, 0.25, start, size);
 
        if (Global::gridSpacing <= 0.5)
-               DrawSubGrid(painter, 0xDBDBFF, 0.5, start, size);
+               DrawSubGrid(painter, 0xE6E6FF, 0.5, start, size);
 
-       painter->SetPen(QPen(QColor(0xD2, 0xD2, 0xFF), 2.0, Qt::SolidLine));
+       painter->SetPen(QPen(QColor(0xE0, 0xE0, 0xFF), 2.0, Qt::SolidLine));
 
        for(double i=0; i<=w; i+=spacing)
                painter->DrawVLine(leftx + i);
@@ -187,182 +186,6 @@ void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Ve
                painter->DrawHLine(start.y + i);
 }
 
-#if 0
-void DrawingView::SetGridSize(uint32_t size)
-{
-#if 0
-       // Sanity check
-       if (size == gridPixels)
-               return;
-
-       // tmp...
-       if (size <= 1)
-               return;
-
-       // Recreate the background bitmap
-       gridPixels = size;
-       QPainter pmp(&gridBackground);
-       pmp.fillRect(0, 0, BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE, QColor(240, 240, 240));
-       pmp.setPen(QPen(QColor(210, 210, 255), 2.0, Qt::SolidLine));
-
-       for(int i=0; i<(BACKGROUND_MAX_SIZE-1); i+=gridPixels)
-       {
-               pmp.drawLine(i, 0, i, BACKGROUND_MAX_SIZE - 1);
-               pmp.drawLine(0, i, BACKGROUND_MAX_SIZE - 1, i);
-       }
-
-       pmp.end();
-
-       // Set up new BG brush & zoom level (pixels per base unit)
-// This shouldn't be done here, because it fucks up the scrollwheel zooming...
-//     Global::zoom = gridPixels / Global::gridSpacing;
-       UpdateGridBackground();
-#endif
-}
-
-void DrawingView::UpdateGridBackground(void)
-{
-#if 0
-       // Transform the origin to Qt coordinates
-       Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector());
-       int x = (int)pixmapOrigin.x;
-       int y = (int)pixmapOrigin.y;
-       // Use mod arithmetic to grab the correct swatch of background
-/*
-Negative numbers still screw it up... Need to think about what we're
-trying to do here. The fact that it worked with 72 seems to have been pure luck.
-It seems the problem is negative numbers: We can't let that happen.
-When taking away the zero, it pops over 1 px at zero, then goes about 1/2 a
-grid at x<0.
-
-The bitmap looks like this:
-
-+---+---+---+---+---
-|   |   |   |   |
-|   |   |   |   |
-+---+---+---+---+---
-|   |   |   |   |
-|   |   |   |   |
-|   |   |   |   |
-
-@ x = 1, we want it to look like:
-
--+---+---+---+---+---
- |   |   |   |   |
- |   |   |   |   |
--+---+---+---+---+---
- |   |   |   |   |
- |   |   |   |   |
- |   |   |   |   |
-
-Which means we need to grab the sample from x = 3. @ x = -1:
-
----+---+---+---+---
-   |   |   |   |
-   |   |   |   |
----+---+---+---+---
-   |   |   |   |
-   |   |   |   |
-   |   |   |   |
-
-Which means we need to grab the sample from x = 1. Which means we have to take
-the mirror of the modulus of gridPixels.
-
-Doing a mod of a negative number is problematic: 1st, the compiler converts the
-negative number to an unsigned int, then it does the mod. Gets you wrong answers
-most of the time, unless you use a power of 2. :-P So what we do here is just
-take the modulus of the negation, which means we don't have to worry about
-mirroring it later.
-
-The positive case looks gruesome (and it is) but it boils down to this: We take
-the modulus of the X coordinate, then mirror it by subtraction from the
-maximum (in this case, gridPixels). This gives us a number in the range of 1 to
-gridPixels. But we need the case where the result equalling gridPixels to be
-zero; so we do another modulus operation on the result to achieve this.
-*/
-       if (x < 0)
-               x = -x % gridPixels;
-       else
-               x = (gridPixels - (x % gridPixels)) % gridPixels;
-
-       if (y < 0)
-               y = -y % gridPixels;
-       else
-               y = (gridPixels - (y % gridPixels)) % gridPixels;
-
-       // Here we grab a section of the bigger pixmap, so that the background
-       // *looks* like it's scrolling...
-       QPixmap pm = gridBackground.copy(x, y, gridPixels, gridPixels);
-       QPalette pal = palette();
-       pal.setBrush(backgroundRole(), QBrush(pm));
-       setAutoFillBackground(true);
-       setPalette(pal);
-#endif
-}
-
-void DrawingView::SetGridSize(double size)
-{
-#if 0
-       // Sanity check
-       if (size == gridPixelsF)
-               return;
-
-       // tmp...
-       if (size <= 1)
-               return;
-
-       // Recreate the background bitmap
-       gridPixelsF = size;
-       QPainter pmp(&gridBackground);
-       pmp.fillRect(0, 0, BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE, QColor(240, 240, 240));
-       pmp.setPen(QPen(QColor(210, 210, 255), 2.0, Qt::SolidLine));
-
-       for(double i=0; i<(BACKGROUND_MAX_SIZE-1); i+=gridPixelsF)
-       {
-               pmp.drawLine(i, 0, i, (double)(BACKGROUND_MAX_SIZE - 1));
-               pmp.drawLine(0, i, (double)(BACKGROUND_MAX_SIZE - 1), i);
-       }
-
-       pmp.end();
-
-       // Set up new BG brush & zoom level (pixels per base unit)
-// This shouldn't be done here, because it fucks up the scrollwheel zooming...
-//     Global::zoom = gridPixels / Global::gridSpacing;
-       UpdateGridBackgroundF();
-#endif
-}
-
-
-void DrawingView::UpdateGridBackgroundF(void)
-{
-#if 0
-       // Transform the origin to Qt coordinates
-       Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector());
-       int x = 0;// (int)pixmapOrigin.x;
-       int y = 0;// (int)pixmapOrigin.y;
-       // Use mod arithmetic to grab the correct swatch of background
-
-/*     if (x < 0)
-               x = -x % gridPixels;
-       else
-               x = (gridPixels - (x % gridPixels)) % gridPixels;
-
-       if (y < 0)
-               y = -y % gridPixels;
-       else
-               y = (gridPixels - (y % gridPixels)) % gridPixels;*/
-
-       // Here we grab a section of the bigger pixmap, so that the background
-       // *looks* like it's scrolling...
-       QPixmap pm = gridBackground.copy(x, y, gridPixelsF, gridPixelsF);
-       QPalette pal = palette();
-       pal.setBrush(backgroundRole(), QBrush(pm));
-       setAutoFillBackground(true);
-       setPalette(pal);
-#endif
-}
-#endif
-
 //
 // 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
@@ -372,7 +195,6 @@ void DrawingView::UpdateGridBackgroundF(void)
 //
 void DrawingView::DeleteCurrentLayer(int layer)
 {
-//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
        VPVectorIter i = document.objects.begin();
 
        while (i != document.objects.end())
@@ -409,7 +231,6 @@ void DrawingView::HandleLayerToggle(void)
 //
 void DrawingView::HandleLayerSwap(int layer1, int layer2)
 {
-//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2);
        HandleLayerSwap(layer1, layer2, document.objects);
 }
 
@@ -432,42 +253,6 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2, VPVector & v)
        }
 }
 
-void DrawingView::HandlePenWidth(float width)
-{
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->thickness = width;
-       }
-
-       supressSelected = true;
-       update();
-}
-
-void DrawingView::HandlePenStyle(int style)
-{
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->style = style;
-       }
-
-       supressSelected = true;
-       update();
-}
-
-void DrawingView::HandlePenColor(uint32_t color)
-{
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->color = color;
-       }
-
-       supressSelected = true;
-       update();
-}
-
 void DrawingView::HandlePenStamp(QAction * action)
 {
        PenWidget * pw = (PenWidget *)action->parentWidget();
@@ -519,7 +304,6 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
 
 void DrawingView::focusOutEvent(QFocusEvent * /*event*/)
 {
-//     printf("DrawingView::focusOutEvent()...\n");
        // Make sure all modkeys being held are marked as released when the app
        // loses focus (N.B.: This only works because the app sets the focus policy
        // of this object to something other than Qt::NoFocus)
@@ -534,9 +318,6 @@ void DrawingView::focusInEvent(QFocusEvent * /*event*/)
                setCursor(curMarker);
        else if (Global::penDropper)
                setCursor(curDropper);
-//FocusOut already set this...
-//     else
-//             setCursor(Qt::ArrowCursor);
 }
 
 void DrawingView::paintEvent(QPaintEvent * /*event*/)
@@ -566,16 +347,20 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
        // Do tool rendering, if any...
        if (Global::tool)
        {
-               painter.SetPen(QPen(QColor(200, 100, 0, 255), 1.0, Qt::DashLine));
-               painter.DrawCrosshair(oldPoint);
+               if (Global::toolSuppressCrosshair == false)
+               {
+                       painter.SetPen(QPen(QColor(200, 100, 0, 255), 1.0, Qt::DashLine));
+                       painter.DrawCrosshair(oldPoint);
+               }
+
                ToolDraw(&painter);
        }
 
        // Do selection rectangle rendering, if any
        if (Global::selectionInProgress)
        {
-               painter.SetPen(QPen(QColor(255, 127, 0, 255)));
-               painter.SetBrush(QBrush(QColor(255, 127, 0, 100)));
+               painter.SetPen(QPen(QColor(0xFF, 0x7F, 0x00, 0xFF)));
+               painter.SetBrush(QBrush(QColor(0xFF, 0x7F, 0x00, 0x64)));
                painter.DrawRect(Global::selection);
        }
 
@@ -773,20 +558,7 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool
                        painter->SetFont(QFont("Arial", 8.0 * Global::zoom * scaledThickness));
                        Point ctr = p2 + (Vector(p2, p1) / 2.0);
 
-                       QString dimText;
-
-                       if (length < 12.0)
-                               dimText = QString("%1\"").arg(length);
-                       else
-                       {
-                               double feet = (double)((int)length / 12);
-                               double inches = length - (feet * 12.0);
-
-                               if (inches == 0)
-                                       dimText = QString("%1'").arg(feet);
-                               else
-                                       dimText = QString("%1' %2\"").arg(feet).arg(inches);
-                       }
+                       QString dimText = GetDimensionText(&document, length);
 
 /*
 Where is the text offset?  It looks like it's drawing in the center, but obviously it isn't.  It isn't here, it's in Painter::DrawAngledText().
@@ -865,6 +637,11 @@ Where is the text offset?  It looks like it's drawing in the center, but obvious
                        break;
                }
 
+               case OTPolyline:
+               {
+                       break;
+               }
+
                case OTContainer:
                {
                        // Containers require recursive rendering...
@@ -893,16 +670,45 @@ Where is the text offset?  It looks like it's drawing in the center, but obvious
 }
 
 //
-// This toggles the selection being hovered (typically, only 1 object)
+// This toggles the selection being hovered (typically, only 1 object).  We
+// toggle because the CTRL key might be held, in which case, we want to
+// deselect a selected object.
 //
-void DrawingView::AddHoveredToSelection(void)
+void DrawingView::HandleSelectionClick(VPVector & v)
 {
-       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
+       if (ctrlDown)
        {
-               if (((Object *)(*i))->hovered)
-//                     ((Object *)(*i))->selected = true;
-                       ((Object *)(*i))->selected = !((Object *)(*i))->selected;
+               for(VPVectorIter i=v.begin(); i!=v.end(); i++)
+               {
+                       Object * obj = (Object *)(*i);
+
+                       if (obj->hovered)
+                               obj->selected = !obj->selected;
+               }
+
+               return;
+       }
+
+       for(VPVectorIter i=v.begin(); i!=v.end(); i++)
+               ((Object *)(*i))->selected = false;
+
+       // Check if the hover changed, and if so, reset the selection stack
+       if (oldHover.size() != v.size())
+       {
+               oldHover = v;
+               currentSelect = 0;
        }
+       else
+       {
+               // Select next object in the stack under the cursor
+               currentSelect++;
+
+               if (currentSelect >= v.size())
+                       currentSelect = 0;
+       }
+
+       dragged = (Object *)v[currentSelect];
+       dragged->selected = true;
 }
 
 VPVector DrawingView::GetSelection(void)
@@ -918,23 +724,49 @@ VPVector DrawingView::GetSelection(void)
        return v;
 }
 
-VPVector DrawingView::GetHovered(void)
+//
+// When testing for hovered intersections, we need to be able to exclude some
+// objects which have funky characteristics or handles; so we allow for that
+// here.
+//
+VPVector DrawingView::GetHovered(bool exclude/*= false*/)
 {
        VPVector v;
 
        for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
        {
-               if (((Object *)(*i))->hovered)
+               Object * obj = (Object *)(*i);
+
+               if (obj->hovered)
+               {
+                       if (exclude
+                               && ((obj->type == OTDimension)
+                                       || ((obj->type == OTCircle) && (obj->hitPoint[0] == true))
+                                       || ((obj->type == OTArc) && (obj->hitPoint[0] == true))
+                                       || (draggingObject && (obj == dragged))))
+                               continue;
+
                        v.push_back(*i);
+               }
        }
 
        return v;
 }
 
+void DrawingView::MoveSelectedToLayer(int layer)
+{
+       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->selected || obj->hovered)
+                       obj->layer = layer;
+       }
+}
+
 void DrawingView::resizeEvent(QResizeEvent * /*event*/)
 {
        Global::screenSize = Vector(size().width(), size().height());
-//     UpdateGridBackground();
 }
 
 void DrawingView::ToolHandler(int mode, Point p)
@@ -954,6 +786,8 @@ void DrawingView::ToolHandler(int mode, Point p)
                MirrorHandler(mode, p);
        else if (Global::tool == TTDimension)
                DimensionHandler(mode, p);
+       else if (Global::tool == TTDelete)
+               DeleteHandler(mode, p);
        else if (Global::tool == TTTriangulate)
                TriangulateHandler(mode, p);
        else if (Global::tool == TTTrim)
@@ -964,8 +798,9 @@ void DrawingView::ToolHandler(int mode, Point p)
 
 void DrawingView::ToolDraw(Painter * painter)
 {
-       if (Global::tool == TTLine)
+       switch (Global::tool)
        {
+       case TTLine:
                if (Global::toolState == TSNone)
                {
                        painter->DrawHandle(toolPoint[0]);
@@ -985,9 +820,10 @@ void DrawingView::ToolDraw(Painter * painter)
                        QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
                        informativeText = text.arg(absLength).arg(absAngle);
                }
-       }
-       else if (Global::tool == TTCircle)
-       {
+
+               break;
+
+       case TTCircle:
                if (Global::toolState == TSNone)
                {
                        painter->DrawHandle(toolPoint[0]);
@@ -1005,9 +841,10 @@ void DrawingView::ToolDraw(Painter * painter)
                        QString text = tr("Radius: %1 in.");
                        informativeText = text.arg(length);
                }
-       }
-       else if (Global::tool == TTArc)
-       {
+
+               break;
+
+       case TTArc:
                if (Global::toolState == TSNone)
                {
                        painter->DrawHandle(toolPoint[0]);
@@ -1049,9 +886,10 @@ void DrawingView::ToolDraw(Painter * painter)
                        QString text = tr("Arc span: %1") + QChar(0x00B0);
                        informativeText = text.arg(RADIANS_TO_DEGREES * span);
                }
-       }
-       else if (Global::tool == TTRotate)
-       {
+
+               break;
+
+       case TTRotate:
                if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1))
                        painter->DrawHandle(toolPoint[0]);
                else if ((Global::toolState == TSPoint2) && shiftDown)
@@ -1070,9 +908,10 @@ void DrawingView::ToolDraw(Painter * painter)
                        if (ctrlDown)
                                informativeText += " (Copy)";
                }
-       }
-       else if (Global::tool == TTMirror)
-       {
+
+               break;
+
+       case TTMirror:
                if ((Global::toolState == TSNone) || (Global::toolState == TSPoint1))
                        painter->DrawHandle(toolPoint[0]);
                else if ((Global::toolState == TSPoint2) && shiftDown)
@@ -1096,9 +935,10 @@ void DrawingView::ToolDraw(Painter * painter)
                        if (ctrlDown)
                                informativeText += " (Copy)";
                }
-       }
-       if (Global::tool == TTDimension)
-       {
+
+               break;
+
+       case TTDimension:
                if (Global::toolState == TSNone)
                {
                        painter->DrawHandle(toolPoint[0]);
@@ -1118,6 +958,55 @@ void DrawingView::ToolDraw(Painter * painter)
                        QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
                        informativeText = text.arg(absLength).arg(absAngle);
                }
+
+               break;
+
+       case TTTrim:
+               if (toolObj[0] != NULL)
+               {
+                       // We're assuming ATM it's just a line...
+                       painter->SetPen(0xAF0000, 3.0, LSSolid);
+                       painter->DrawLine(toolPoint[0], toolPoint[1]);
+//                     QString text = tr("Arc span: %1") + QChar(0x00B0);
+//                     informativeText = text.arg(RADIANS_TO_DEGREES * span);
+               }
+
+               break;
+
+       case TTParallel:
+               if (Global::toolState == TSPoint1)
+               {
+                       painter->SetPen(0xFF00FF, 2.0, LSSolid);
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+
+                       double length = Vector::Magnitude(toolObj[0]->p[0], toolPoint[0]);
+                       bool inside = (length >= toolObj[0]->radius[0] ? false : true);
+
+                       for(int i=1; i<=Global::parallelNum; i++)
+                       {
+                               if (toolObj[0]->type == OTLine)
+                               {
+                                       painter->DrawLine(toolObj[0]->p[0] + (toolPoint[0] * Global::parallelDist * (double)i), toolObj[0]->p[1] + (toolPoint[0] * Global::parallelDist * (double)i));
+                               }
+                               else if ((toolObj[0]->type == OTCircle) || (toolObj[0]->type == OTArc))
+                               {
+                                       double radius = toolObj[0]->radius[0] + ((double)i * Global::parallelDist * (inside ? -1.0 : 1.0));
+
+                                       if (radius > 0)
+                                       {
+                                               if (toolObj[0]->type == OTCircle)
+                                                       painter->DrawEllipse(toolObj[0]->p[0], radius, radius);
+                                               else
+                                                       painter->DrawArc(toolObj[0]->p[0], radius, toolObj[0]->angle[0], toolObj[0]->angle[1]);
+                                       }
+                               }
+                       }
+               }
+
+               break;
+
+       default:
+               break;
        }
 }
 
@@ -1126,6 +1015,19 @@ void DrawingView::LineHandler(int mode, Point p)
        switch (mode)
        {
        case ToolMouseDown:
+/*             toolObj[0] = NULL;
+
+               // Check to see if we can do a circle tangent snap
+               if (numHovered == 1)
+               {
+                       VPVector hover = GetHovered();
+                       Object * obj = (Object *)hover[0];
+
+                       // Save for later if the object clicked was a circle (need to check that it wasn't the center clicked on, because that will fuck up connecting centers of circles with lines... and now we do! :-)
+                       if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+                               toolObj[0] = obj;
+               }*/
+
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
                else
@@ -1137,7 +1039,54 @@ void DrawingView::LineHandler(int mode, Point p)
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
                else
+               {
                        toolPoint[1] = p;
+/*                     bool isCircle = false;
+
+                       if (numHovered == 1)
+                       {
+                               VPVector hover = GetHovered();
+                               Object * obj = (Object *)hover[0];
+
+                               if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+                               {
+                                       isCircle = true;
+                                       toolObj[1] = obj;
+                               }
+                       }
+
+                       // Adjust initial point if it's on a circle (tangent point)
+                       if (toolObj[0] != NULL)
+                       {
+                               if (isCircle)
+                               {
+                                       Geometry::FindTangents(toolObj[0], toolObj[1]);
+
+                                       if (Global::numIntersectPoints > 0)
+                                       {
+                                               toolPoint[0] = Global::intersectPoint[0];
+                                               toolPoint[1] = Global::intersectPoint[1];
+                                       }
+                               }
+                               else
+                               {
+                                       Geometry::FindTangents(toolObj[0], p);
+
+                                       if (Global::numIntersectPoints > 0)
+                                               toolPoint[0] = Global::intersectPoint[0];
+                               }
+                       }
+                       else
+                       {
+                               if (isCircle)
+                               {
+                                       Geometry::FindTangents(toolObj[1], toolPoint[0]);
+
+                                       if (Global::numIntersectPoints > 0)
+                                               toolPoint[1] = Global::intersectPoint[0];
+                               }
+                       }*/
+               }
 
                break;
 
@@ -1588,7 +1537,7 @@ void DrawingView::DimensionHandler(int mode, Point p)
                }
                else
                {
-                       Dimension * d = new Dimension(toolPoint[0], toolPoint[1], DTLinear);
+                       Dimension * d = new Dimension(toolPoint[0], toolPoint[1], DTLinear, 0, Global::penWidth);
                        d->layer = Global::activeLayer;
                        document.objects.push_back(d);
                        Global::toolState = TSNone;
@@ -1596,7 +1545,37 @@ void DrawingView::DimensionHandler(int mode, Point p)
        }
 }
 
-void DrawingView::TriangulateHandler(int mode, Point/*p*/)
+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)
        {
@@ -1685,88 +1664,15 @@ void DrawingView::TriangulateHandler(int mode, Point/*p*/)
 
 void DrawingView::TrimHandler(int mode, Point p)
 {
-/*
-n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
-*/
        switch (mode)
        {
        case ToolMouseDown:
        {
-#if 0
-               Object * toTrim = doc->lastObjectHovered;
-
-               if (toTrim == NULL)
-                       return;
-
-               Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint);
-
-               // Check to see which case we have...
-               // We're trimming point #1...
-               if (t == 0)
-               {
-                       ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u);
-               }
-               else if (u == 1.0)
-               {
-                       ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t);
-               }
-               else
-               {
-                       Point p1 = ((Line *)toTrim)->position + (v * t);
-                       Point p2 = ((Line *)toTrim)->position + (v * u);
-                       Point p3 = ((Line *)toTrim)->endpoint;
-                       ((Line *)toTrim)->endpoint = p1;
-                       Line * line = new Line(p2, p3);
-                       emit ObjectReady(line);
-               }
-
-               doc->lastObjectHovered = NULL;
-#endif
        }
                break;
 
        case ToolMouseMove:
        {
-#if 0
-               Object * toTrim = doc->lastObjectHovered;
-               t = 0, u = 1.0;
-
-               if (toTrim == NULL)
-                       return;
-
-               if (toTrim->type != OTLine)
-                       return;
-
-               double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point);
-
-               std::vector<Object *>::iterator i;
-
-               for(i=doc->objects.begin(); i!=doc->objects.end(); i++)
-               {
-                       // Can't trim against yourself... :-P
-                       if (*i == toTrim)
-                               continue;
-
-                       Object * trimAgainst = *i;
-                       double t1;//, u1;
-
-                       if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine))
-                               continue;
-
-                       int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1);
-
-                       if (intersects)
-                       {
-                               // Now what? We don't know which side to trim!
-                               // ... now we do, we know which side of the Line we're on!
-                               if ((t1 > t) && (t1 < pointHoveredT))
-                                       t = t1;
-
-                               if ((t1 < u) && (t1 > pointHoveredT))
-                                       u = t1;
-                       }
-               }
-#endif
                // Bail out if nothing hovered...
                if (numHovered != 1)
                {
@@ -1786,6 +1692,7 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
 
                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)
@@ -1803,13 +1710,70 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
 
                        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:
@@ -1823,14 +1787,85 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
        }
 }
 
-void DrawingView::ParallelHandler(int mode, Point /*p*/)
+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:
@@ -1851,7 +1886,6 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
        {
-//printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
                Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
                // Handle tool processing, if any
@@ -1864,12 +1898,6 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                        else if (Global::snapToGrid)
                                point = SnapPointToGrid(point);
 
-                       //Also, may want to figure out if hovering over a snap point on an
-                       //object, snap to grid if not.
-                       // Snap to object point if valid...
-//                     if (Global::snapPointIsValid)
-//                             point = Global::snapPoint;
-
                        ToolHandler(ToolMouseDown, point);
                        return;
                }
@@ -1877,49 +1905,41 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                // Clear the selection only if CTRL isn't being held on click
                if (!ctrlDown)
                        ClearSelected(document.objects);
-//                     ClearSelection();
 
-               // If any objects are being hovered on click, add them to the selection
-               // & return
+               // If any objects are being hovered on click, deal with 'em
                if (numHovered > 0)
                {
-                       AddHoveredToSelection();
-                       update();       // needed??
-//                     GetHovered(hover);      // prolly needed
                        VPVector hover2 = GetHovered();
                        dragged = (Object *)hover2[0];
-                       draggingObject = true;
-//printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
 
                        // Alert the pen widget
-// Maybe do this with an eyedropper tool on the pen bar?  [YES]
-//                     emit ObjectSelected(dragged);
                        if (Global::penDropper)
                        {
                                Global::penColor = dragged->color;
                                Global::penWidth = dragged->thickness;
                                Global::penStyle = dragged->style;
                                emit ObjectSelected(dragged);
-                               ClearSelected(document.objects);
                                return;
                        }
-
-                       if (Global::penStamp)
+                       else if (Global::penStamp)
                        {
                                dragged->color = Global::penColor;
                                dragged->thickness = Global::penWidth;
                                dragged->style = Global::penStyle;
                                return;
                        }
-
-                       // See if anything is using just a straight click on a handle
-                       if (HandleObjectClicked())
+                       // See if anything is using just a straight click on a custom
+                       // object handle (like Dimension objects)
+                       else if (HandleObjectClicked())
                        {
-                               draggingObject = false;
                                update();
                                return;
                        }
 
+                       draggingObject = true;
+                       HandleSelectionClick(hover2);
+                       update();       // needed??
+
                        // Needed for grab & moving objects
                        // We do it *after*... why? (doesn't seem to confer any advantage...)
                        if (hoveringIntersection)
@@ -1933,9 +1953,14 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                        if (Global::fixedLength)
                        {
                                if (dragged->type == OTLine)
-                               {
-                                       dragged->length = Vector::Magnitude(dragged->p[0], dragged->p[1]);
-                               }
+                                       dragged->length = ((Line *)dragged)->Length();
+                       }
+
+                       // Needed for fixed angle handling
+                       if (Global::fixedAngle)
+                       {
+                               if (dragged->type == OTLine)
+                                       dragged->p[2] = ((Line *)dragged)->Unit();
                        }
 
                        if (dragged->type == OTCircle)
@@ -2017,7 +2042,7 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
 
        // Do object hit testing...
        bool needUpdate = HitTestObjects(point);
-       VPVector hover2 = GetHovered();
+       VPVector hover2 = GetHovered(true); // Exclude dimension objects and circle centers (probably need to add arc centers too) from hover (also dragged objects...)
 #if 0
 {
 if (needUpdate)
@@ -2031,9 +2056,9 @@ if (needUpdate)
 #endif
 
        // Check for multi-hover...
-       if (numHovered > 1)
+       if (hover2.size() > 1)
        {
-//need to check for case where hover is over 2 circles and a 3rd's center...
+//need to check for case where hover is over 2 circles and a 3rd's center (no longer a problem, I think)...
                Object * obj1 = (Object *)hover2[0], * obj2 = (Object *)hover2[1];
 
                Geometry::Intersects(obj1, obj2);
@@ -2072,7 +2097,7 @@ if (needUpdate)
                        intersectionPoint = v1;
                }
        }
-       else if (numHovered == 1)
+       else if (hover2.size() == 1)
        {
                Object * obj = (Object *)hover2[0];
 
@@ -2080,7 +2105,6 @@ if (needUpdate)
                {
 /*
 Not sure that this is the best way to handle this, but it works(TM)...
-Except when lines are overlapping, then it doesn't work... !!! FIX !!!
 */
                        Point midpoint = Geometry::Midpoint((Line *)obj);
                        Vector v1 = Vector::Magnitude(midpoint, point);
@@ -2094,6 +2118,30 @@ Except when lines are overlapping, then it doesn't work... !!! FIX !!!
                                needUpdate = true;
                        }
                }
+               else if (obj->type == OTCircle)
+               {
+                       if ((draggingObject && (dragged->type == OTLine)) && (dragged->hitPoint[0] || dragged->hitPoint[1]))
+                       {
+                               Point p = (dragged->hitPoint[0] ? dragged->p[1] : dragged->p[0]);
+                               Geometry::FindTangents(obj, p);
+
+                               if (Global::numIntersectPoints > 0)
+                               {
+                                       hoveringIntersection = true;
+                                       intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+                               }
+                       }
+                       else if ((Global::tool == TTLine) && (Global::toolState == TSPoint2))
+                       {
+                               Geometry::FindTangents(obj, toolPoint[0]);
+
+                               if (Global::numIntersectPoints > 0)
+                               {
+                                       hoveringIntersection = true;
+                                       intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+                               }
+                       }
+               }
        }
 
        // Handle object movement (left button down & over an object)
@@ -2156,16 +2204,15 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
                        return;
                }
 
-//             if (Global::selectionInProgress)
-                       Global::selectionInProgress = false;
-
+               Global::selectionInProgress = false;
                informativeText.clear();
+
 // Should we be doing this automagically? Hmm...
                // Clear our vectors
 //             select.clear();
 ////           hover.clear();
 
-               // Scoop 'em up (do we need to??? Seems we do, because keyboard movement uses it.  Also, tools use it too.  But we can move it out of here)
+               // Scoop 'em up (do we need to??? Seems we do, because keyboard movement uses it.  Also, tools use it too.  But we can move it out of here [where to???])
                select = GetSelection();
 
                draggingObject = false;
@@ -2434,7 +2481,7 @@ void DrawingView::CheckObjectBounds(void)
                switch (obj->type)
                {
                case OTLine:
-               case OTDimension:
+               case OTDimension: // N.B.: We don't check this properly...
                {
                        Line * l = (Line *)obj;
 
@@ -2581,6 +2628,10 @@ bool DrawingView::HitTest(Object * obj, Point point)
 {
        bool needUpdate = false;
 
+       // Make sure we don't hit test stuff on an invisible layer...
+       if (Global::layerHidden[obj->layer] == true)
+               return false;
+
        switch (obj->type)
        {
        case OTLine:
@@ -2919,24 +2970,40 @@ void DrawingView::HandleObjectMovement(Point point)
        case OTLine:
                if (obj->hitPoint[0])
                {
+/*
+N.B.: Mixing fixed length with fixed angle (and in this order) is probably *not* going to work out in any meaningful way, and we should probably make the GUI force these to be mutually exclusive.  Besides, this combined effect already works by dragging the line segment by clicking on it.  :-P
+*/
                        if (Global::fixedLength)
                        {
-                               Vector line = point - obj->p[1];
-                               Vector unit = line.Unit();
+                               Vector unit = Vector::Unit(obj->p[1], point);
                                point = obj->p[1] + (unit * obj->length);
                        }
 
+                       if (Global::fixedAngle)
+                       {
+                               // Calculate the component of the current vector along the
+                               // fixed angle: A_compB = (A • Bu) * Bu  (p[2] has the unit
+                               // vector "Bu".)
+                               double magnitudeAlongB = Vector::Dot(Vector(point - obj->p[1]), obj->p[2]);
+                               point = obj->p[1] + (obj->p[2] * magnitudeAlongB);
+                       }
+
                        obj->p[0] = point;
                }
                else if (obj->hitPoint[1])
                {
                        if (Global::fixedLength)
                        {
-                               Vector line = point - obj->p[0];
-                               Vector unit = line.Unit();
+                               Vector unit = Vector::Unit(obj->p[0], point);
                                point = obj->p[0] + (unit * obj->length);
                        }
 
+                       if (Global::fixedAngle)
+                       {
+                               double magnitudeAlongB = Vector::Dot(Vector(point - obj->p[0]), obj->p[2]);
+                               point = obj->p[0] + (obj->p[2] * magnitudeAlongB);
+                       }
+
                        obj->p[1] = point;
                }
                else if (obj->hitObject)
@@ -2956,7 +3023,7 @@ void DrawingView::HandleObjectMovement(Point point)
                        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);
+                       informativeText = text.arg(obj->radius[0], 0, 'f', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'f', 0);
                }
 
                break;