]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Further progress on Polylines: Polylines can be selected and moved.
[architektonas] / src / drawingview.cpp
index dc6853203769404357e2ac7ca05c5e57f9c7329f..e65bbe92de99f12d47f6f2e12596c25d33485c1d 100644 (file)
 #include "global.h"
 #include "mathconstants.h"
 #include "painter.h"
+#include "penwidget.h"
 #include "structs.h"
+#include "units.h"
 #include "utils.h"
 
-
 #define BACKGROUND_MAX_SIZE    512
 
-
 DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        // The value in the settings file will override this.
        useAntialiasing(true), numHovered(0), shiftDown(false),
        ctrlDown(false), altDown(false),
        gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
-       scale(1.0), offsetX(-10), offsetY(-10), document(true),
-       gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false),
-       hoveringIntersection(false), dragged(NULL), draggingObject(false),
+       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),
        angleSnap(false), dirty(false)
 {
 //wtf? doesn't work except in c++11??? document = { 0 };
        setBackgroundRole(QPalette::Base);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
+       curMarker = QCursor(QPixmap(":/res/cursor-marker.png"), 1, 18);
+       curDropper = QCursor(QPixmap(":/res/cursor-dropper.png"), 1, 20);
+
        Global::gridSpacing = 12.0;             // In base units (inch is default)
 
        Line * line = new Line(Vector(5, 5), Vector(50, 40), 2.0, 0xFF7F00, LSDash);
@@ -118,117 +123,68 @@ 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! :-)
-
 */
-       SetGridSize(12);        // This is in pixels
 }
 
-
-void DrawingView::SetGridSize(uint32_t size)
+void DrawingView::DrawBackground(Painter * painter)
 {
-       // Sanity check
-       if (size == gridPixels)
-               return;
+       Point ul = Painter::QtToCartesianCoords(Vector(0, 0));
+       Point br = Painter::QtToCartesianCoords(Vector(Global::screenSize.x, Global::screenSize.y));
 
-       // 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));
+       painter->SetBrush(0xF0F0F0);
+       painter->SetPen(0xF0F0F0, 1, 1);
+       painter->DrawRect(Rect(ul, br));
 
-       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);
-       }
+       double spacing = Global::gridSpacing;
 
-       pmp.end();
+       if (spacing < 1.0)
+               spacing = 1.0;
 
-       // 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();
-}
+       double leftx = floor(ul.x / spacing) * spacing;
+       double bottomy = floor(br.y / spacing) * spacing;
 
+       double w = (br.x - ul.x) + Global::gridSpacing + 1.0;
+       double h = (ul.y - br.y) + Global::gridSpacing + 1.0;
 
-void DrawingView::UpdateGridBackground(void)
-{
-       // 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;
+       Vector start(leftx, bottomy), size(w, h);
 
-       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);
+       if (Global::gridSpacing <= 0.015625)
+               DrawSubGrid(painter, 0xFFD2D2, 0.015625, start, size);
+
+       if (Global::gridSpacing <= 0.03125)
+               DrawSubGrid(painter, 0xFFD2D2, 0.03125, start, size);
+
+       if (Global::gridSpacing <= 0.0625)
+               DrawSubGrid(painter, 0xB8ECFF, 0.0625, start, size);
+
+       if (Global::gridSpacing <= 0.125)
+               DrawSubGrid(painter, 0xB8ECFF, 0.125, start, size);
+
+       if (Global::gridSpacing <= 0.25)
+               DrawSubGrid(painter, 0xE6E6FF, 0.25, start, size);
+
+       if (Global::gridSpacing <= 0.5)
+               DrawSubGrid(painter, 0xE6E6FF, 0.5, start, size);
+
+       painter->SetPen(QPen(QColor(0xE0, 0xE0, 0xFF), 2.0, Qt::SolidLine));
+
+       for(double i=0; i<=w; i+=spacing)
+               painter->DrawVLine(leftx + i);
+
+       for(double i=0; i<=h; i+=spacing)
+               painter->DrawHLine(bottomy + i);
 }
 
+void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Vector start, Vector size)
+{
+       painter->SetPen(color, 1, 1);
+
+       for(double i=-step; i<=size.x; i+=step*2.0)
+               painter->DrawVLine(start.x + i);
+
+       for(double i=-step; i<=size.y; i+=step*2.0)
+               painter->DrawHLine(start.y + i);
+}
 
 //
 // Basically, we just make a single pass through the Container. If the layer #
@@ -239,7 +195,6 @@ zero; so we do another modulus operation on the result to achieve this.
 //
 void DrawingView::DeleteCurrentLayer(int layer)
 {
-//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
        VPVectorIter i = document.objects.begin();
 
        while (i != document.objects.end())
@@ -264,23 +219,27 @@ void DrawingView::DeleteCurrentLayer(int layer)
        update();
 }
 
-
 void DrawingView::HandleLayerToggle(void)
 {
        // A layer's visibility was toggled, so update the screen...
        update();
 }
 
-
 //
 // 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)
 {
-// !!! FIX !!! This doesn't properly handle container contents...
-//printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2);
-       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
+       HandleLayerSwap(layer1, layer2, document.objects);
+}
+
+/*
+We can roll this into the main one above, by having the LayerWidget's emit() call sending NULL for the VPVector, which we can test for and set to document.objects to grab the top layer.  Or, keep it a top level call and a recursive call.  Which is worse?  :-P
+*/
+void DrawingView::HandleLayerSwap(int layer1, int layer2, VPVector & v)
+{
+       for(VPVectorIter i=v.begin(); i!=v.end(); i++)
        {
                Object * obj = (Object *)(*i);
 
@@ -288,59 +247,45 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2)
                        obj->layer = layer2;
                else if (obj->layer == layer2)
                        obj->layer = layer1;
-       }
-}
-
 
-void DrawingView::HandlePenWidth(float width)
-{
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->thickness = width;
+               if (obj->type == OTContainer)
+                       HandleLayerSwap(layer1, layer2, ((Container *)obj)->objects);
        }
 }
 
-
-void DrawingView::HandlePenStyle(int style)
+void DrawingView::HandlePenStamp(QAction * action)
 {
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->style = style;
-       }
-}
+       PenWidget * pw = (PenWidget *)action->parentWidget();
+       pw->dropperAction->setChecked(false);
+       Global::penDropper = false;
+       Global::penStamp = action->isChecked();
 
+       if (Global::penStamp)
+               setCursor(curMarker);
+       else
+               setCursor(Qt::ArrowCursor);
 
-void DrawingView::HandlePenColor(uint32_t color)
-{
-       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-               obj->color = color;
-       }
-}
+       if (Global::penStamp == false)
+               ClearSelected(document.objects);
 
+       update();
+}
 
-void DrawingView::HandlePenStamp(void)
+void DrawingView::HandlePenDropper(QAction * action)
 {
-       VPVector flat = Flatten(select);
+       PenWidget * pw = (PenWidget *)action->parentWidget();
+       pw->stampAction->setChecked(false);
+       Global::penStamp = false;
+       Global::penDropper = action->isChecked();
 
-       for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
-       {
-               Object * obj = (Object *)(*i);
-
-               if (obj->type != OTText)
-                       obj->thickness = Global::penWidth;
-
-               obj->style = Global::penStyle;
-               obj->color = Global::penColor;
-       }
+       if (Global::penDropper)
+               setCursor(curDropper);
+       else
+               setCursor(Qt::ArrowCursor);
 
        update();
 }
 
-
 QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
 {
        // This is undoing the transform, e.g. going from client coords to local
@@ -349,7 +294,6 @@ QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
        return QPoint(offsetX + event->x(), offsetY + (size().height() - event->y()));
 }
 
-
 QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
 {
        // VOODOO ALERT (ON Y COMPONENT!!!!) (eh?)
@@ -358,10 +302,8 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
        return QPoint(-offsetX + x, (size().height() - (-offsetY + y)) * +1.0);
 }
 
-
 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)
@@ -370,6 +312,13 @@ void DrawingView::focusOutEvent(QFocusEvent * /*event*/)
        setCursor(Qt::ArrowCursor);
 }
 
+void DrawingView::focusInEvent(QFocusEvent * /*event*/)
+{
+       if (Global::penStamp)
+               setCursor(curMarker);
+       else if (Global::penDropper)
+               setCursor(curDropper);
+}
 
 void DrawingView::paintEvent(QPaintEvent * /*event*/)
 {
@@ -381,6 +330,8 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
 
        Global::viewportHeight = size().height();
 
+       DrawBackground(&painter);
+
        // Draw coordinate axes
        painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine));
        painter.DrawLine(0, -16384, 0, 16384);
@@ -396,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);
        }
 
@@ -419,7 +374,6 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
                painter.DrawInformativeText(informativeText);
 }
 
-
 //
 // Renders objects in the passed in vector
 //
@@ -449,7 +403,16 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool
                        painter->SetPen(obj->color, Global::zoom * scaledThickness, obj->style);
                        painter->SetBrush(obj->color);
 
-                       if (obj->selected || obj->hitObject)
+                       // penStamp supresses object highlighting, so that changes can be seen.
+                       if (supressSelected || Global::penStamp)
+                       {
+                               if (obj->hitObject)
+                               {
+                                       painter->SetPen(Global::penColor, Global::zoom * Global::scale * Global::penWidth, Global::penStyle);
+                                       painter->SetBrush(Global::penColor);
+                               }
+                       }
+                       else if (obj->selected || obj->hitObject)
                                painter->SetPen(0xFF0000, Global::zoom * scaledThickness, LSDash);
                }
 
@@ -492,6 +455,28 @@ void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool
 
                        break;
 
+               case OTPolyline:
+               {
+                       painter->SetBrush(QBrush(Qt::NoBrush));
+                       Polyline * pl = (Polyline *)obj;
+
+                       for(long unsigned int i=0; i<(pl->points.size()-1); i++)
+                       {
+                               Point p1 = pl->points[i];
+                               Point p2 = pl->points[i + 1];
+
+                               if (p1.b == 0)
+                                       painter->DrawLine(p1, p2);
+                               else
+                               {
+                                       Arc a = Geometry::Unpack(p1, p2, p1.b);
+                                       painter->DrawArc(a.p[0], a.radius[0], a.angle[0], a.angle[1]);
+                               }
+                       }
+
+                       break;
+               }
+
                case OTDimension:
                {
                        Dimension * d = (Dimension *)obj;
@@ -595,20 +580,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().
@@ -682,16 +654,18 @@ Where is the text offset?  It looks like it's drawing in the center, but obvious
                        break;
                }
 
+#if 0
                case OTPolygon:
                {
                        break;
                }
+#endif
 
                case OTContainer:
                {
                        // Containers require recursive rendering...
                        Container * c = (Container *)obj;
-printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), layer);
+//printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), layer);
                        RenderObjects(painter, (*c).objects, layer, ignoreLayer);
 
 //printf("Container extents: <%lf, %lf>, <%lf, %lf>\nsize: %i\n", r.l, r.t, r.r, r.b, c->objects.size());
@@ -710,22 +684,51 @@ printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(),
                        break;
                }
        }
-}
 
+       supressSelected = false;
+}
 
 //
-// 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)
 {
@@ -740,28 +743,51 @@ 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)
 {
        // Drop angle snap until it's needed
@@ -779,6 +805,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)
@@ -787,11 +815,11 @@ void DrawingView::ToolHandler(int mode, Point p)
                ParallelHandler(mode, p);
 }
 
-
 void DrawingView::ToolDraw(Painter * painter)
 {
-       if (Global::tool == TTLine)
+       switch (Global::tool)
        {
+       case TTLine:
                if (Global::toolState == TSNone)
                {
                        painter->DrawHandle(toolPoint[0]);
@@ -811,9 +839,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]);
@@ -831,9 +860,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]);
@@ -875,9 +905,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)
@@ -896,9 +927,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)
@@ -922,9 +954,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]);
@@ -944,15 +977,76 @@ 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;
        }
 }
 
-
 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
@@ -964,7 +1058,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;
 
@@ -991,7 +1132,6 @@ void DrawingView::LineHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::CircleHandler(int mode, Point p)
 {
        switch (mode)
@@ -1037,7 +1177,6 @@ void DrawingView::CircleHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::ArcHandler(int mode, Point p)
 {
        switch (mode)
@@ -1115,7 +1254,6 @@ void DrawingView::ArcHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::RotateHandler(int mode, Point p)
 {
        switch (mode)
@@ -1270,7 +1408,6 @@ void DrawingView::RotateHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::MirrorHandler(int mode, Point p)
 {
        switch (mode)
@@ -1384,7 +1521,6 @@ N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have
        }
 }
 
-
 void DrawingView::DimensionHandler(int mode, Point p)
 {
        switch (mode)
@@ -1420,7 +1556,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;
@@ -1428,8 +1564,37 @@ void DrawingView::DimensionHandler(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;
 
-void DrawingView::TriangulateHandler(int mode, Point/*p*/)
+       case ToolCleanup:
+               break;
+       }
+}
+
+void DrawingView::TriangulateHandler(int mode, Point /*p*/)
 {
        switch (mode)
        {
@@ -1516,91 +1681,17 @@ 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)
                {
@@ -1620,6 +1711,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)
@@ -1637,13 +1729,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:
@@ -1657,15 +1806,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:
@@ -1682,12 +1901,10 @@ void DrawingView::ParallelHandler(int mode, Point /*p*/)
        }
 }
 
-
 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
@@ -1700,12 +1917,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;
                }
@@ -1713,31 +1924,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
-                       emit ObjectSelected(dragged);
-
-                       // See if anything is using just a straight click on a handle
-                       if (HandleObjectClicked())
+                       if (Global::penDropper)
+                       {
+                               Global::penColor = dragged->color;
+                               Global::penWidth = dragged->thickness;
+                               Global::penStyle = dragged->style;
+                               emit ObjectSelected(dragged);
+                               return;
+                       }
+                       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 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)
@@ -1751,9 +1972,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)
@@ -1768,8 +1994,8 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                // Didn't hit any object and not using a tool, so do a selection
                // rectangle
                Global::selectionInProgress = true;
-               Global::selection.setTopLeft(QPointF(point.x, point.y));
-               Global::selection.setBottomRight(QPointF(point.x, point.y));
+               Global::selection.l = Global::selection.r = point.x;
+               Global::selection.t = Global::selection.b = point.y;
                select = GetSelection();
        }
        else if (event->button() == Qt::MiddleButton)
@@ -1781,7 +2007,6 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
        }
 }
 
-
 void DrawingView::mouseMoveEvent(QMouseEvent * event)
 {
        // It seems that wheelEvent() triggers this for some reason...
@@ -1792,7 +2017,8 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
        }
 
        Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
-       Global::selection.setBottomRight(QPointF(point.x, point.y));
+       Global::selection.r = point.x;
+       Global::selection.b = point.y;
        // Only needs to be done here, as mouse down is always preceded by movement
        Global::snapPointIsValid = false;
        hoveringIntersection = false;
@@ -1810,7 +2036,7 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                delta.y = -delta.y;
                Global::origin -= delta;
 
-               UpdateGridBackground();
+//             UpdateGridBackground();
                update();
                oldPoint = point;
                return;
@@ -1824,7 +2050,11 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
 
                // Make sure previously selected objects stay selected (CTRL held)
                for(VPVectorIter i=select.begin(); i!=select.end(); i++)
-                       ((Object *)(*i))->selected = true;
+               {
+                       // Make sure *not* to select items on hidden layers
+                       if (Global::layerHidden[((Object *)(*i))->layer] == false)
+                               ((Object *)(*i))->selected = true;
+               }
 
                update();
                return;
@@ -1832,7 +2062,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)
@@ -1846,9 +2076,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);
@@ -1887,7 +2117,7 @@ if (needUpdate)
                        intersectionPoint = v1;
                }
        }
-       else if (numHovered == 1)
+       else if (hover2.size() == 1)
        {
                Object * obj = (Object *)hover2[0];
 
@@ -1895,7 +2125,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);
@@ -1909,6 +2138,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)
@@ -1952,7 +2205,6 @@ Except when lines are overlapping, then it doesn't work... !!! FIX !!!
                update();
 }
 
-
 void DrawingView::mouseReleaseEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
@@ -1972,16 +2224,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;
@@ -1989,45 +2240,45 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
        else if (event->button() == Qt::MiddleButton)
        {
                scrollDrag = false;
-               setCursor(Qt::ArrowCursor);
+
+               if (Global::penStamp)
+                       setCursor(curMarker);
+               else if (Global::penDropper)
+                       setCursor(curDropper);
+               else
+                       setCursor(Qt::ArrowCursor);
+
+               // Need to convert this, since it's in Qt coordinates (for wheelEvent)
+               oldPoint = Painter::QtToCartesianCoords(oldPoint);
        }
 }
 
-
 void DrawingView::wheelEvent(QWheelEvent * event)
 {
-       double zoomFactor = 1.25;
+       double zoomFactor = 1.20;
        scrollWheelSeen = true;
 
-       if (event->delta() < 0)
+       if (event->angleDelta().y() < 0)
        {
-               if (Global::zoom > 20.0)
+               if (Global::zoom > 400.0)
                        return;
 
                Global::zoom *= zoomFactor;
-//             Point np = Painter::QtToCartesianCoords(oldScrollPoint);
-//             Global::origin += (oldPoint - np);
        }
        else
        {
-               if (Global::zoom < 0.25)
+               if (Global::zoom < 0.125)
                        return;
 
                Global::zoom /= zoomFactor;
-//             Point np = Painter::QtToCartesianCoords(oldScrollPoint);
-//             Global::origin += (oldPoint - np);
        }
 
        Point np = Painter::QtToCartesianCoords(oldScrollPoint);
        Global::origin += (oldPoint - np);
 
-//     Global::gridSpacing = gridPixels / Painter::zoom;
-       SetGridSize(Global::gridSpacing * Global::zoom);
-       update();
-//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
+       emit(NeedZoomUpdate());
 }
 
-
 void DrawingView::keyPressEvent(QKeyEvent * event)
 {
        bool oldShift = shiftDown;
@@ -2083,7 +2334,6 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
        }
 }
 
-
 void DrawingView::keyReleaseEvent(QKeyEvent * event)
 {
        bool oldShift = shiftDown;
@@ -2108,11 +2358,16 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event)
        if (oldAlt != altDown)
        {
                scrollDrag = false;
-               setCursor(Qt::ArrowCursor);
+
+               if (Global::penStamp)
+                       setCursor(curMarker);
+               else if (Global::penDropper)
+                       setCursor(curDropper);
+               else
+                       setCursor(Qt::ArrowCursor);
        }
 }
 
-
 //
 // 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
@@ -2129,10 +2384,10 @@ Point DrawingView::SnapPointToGrid(Point point)
        point.y = floor(point.y);
        point.z = 0;                                    // Make *sure* Z doesn't go anywhere!!!
        point *= Global::gridSpacing;
+
        return point;
 }
 
-
 Point DrawingView::SnapPointToAngle(Point point)
 {
        // Snap to a single digit angle (using toolpoint #1 as the center)
@@ -2150,7 +2405,6 @@ Point DrawingView::SnapPointToAngle(Point point)
        return point;
 }
 
-
 Rect DrawingView::GetObjectExtents(Object * obj)
 {
        // Default to empty rect, if object checks below fail for some reason
@@ -2175,39 +2429,14 @@ Rect DrawingView::GetObjectExtents(Object * obj)
        case OTArc:
        {
                Arc * a = (Arc *)obj;
+               rect = a->Bounds();
+               break;
+       }
 
-               double start = a->angle[0];
-               double end = start + a->angle[1];
-               rect = Rect(Point(cos(start), sin(start)), Point(cos(end), sin(end)));
-
-               // If the end of the arc is before the beginning, add 360 degrees to it
-               if (end < start)
-                       end += TAU;
-
-               // Adjust the bounds depending on which axes are crossed
-               if ((start < QTR_TAU) && (end > QTR_TAU))
-                       rect.t = 1.0;
-
-               if ((start < HALF_TAU) && (end > HALF_TAU))
-                       rect.l = -1.0;
-
-               if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU))
-                       rect.b = -1.0;
-
-               if ((start < TAU) && (end > TAU))
-                       rect.r = 1.0;
-
-               if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU)))
-                       rect.t = 1.0;
-
-               if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU)))
-                       rect.l = -1.0;
-
-               if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU)))
-                       rect.b = -1.0;
-
-               rect *= a->radius[0];
-               rect.Translate(a->p[0]);
+       case OTPolyline:
+       {
+               Polyline * p = (Polyline *)obj;
+               rect = p->Bounds();
                break;
        }
 
@@ -2236,7 +2465,6 @@ Rect DrawingView::GetObjectExtents(Object * obj)
        return rect;
 }
 
-
 void DrawingView::CheckObjectBounds(void)
 {
        VPVectorIter i;
@@ -2245,15 +2473,17 @@ void DrawingView::CheckObjectBounds(void)
        {
                Object * obj = (Object *)(*i);
                obj->selected = false;
+               Rect selection = Global::selection;
+               selection.Normalize();
 
                switch (obj->type)
                {
                case OTLine:
-               case OTDimension:
+               case OTDimension: // N.B.: We don't check this properly...
                {
                        Line * l = (Line *)obj;
 
-                       if (Global::selection.contains(l->p[0].x, l->p[0].y) && Global::selection.contains(l->p[1].x, l->p[1].y))
+                       if (selection.Contains(l->p[0]) && selection.Contains(l->p[1]))
                                l->selected = true;
 
                        break;
@@ -2262,8 +2492,9 @@ void DrawingView::CheckObjectBounds(void)
                case OTCircle:
                {
                        Circle * c = (Circle *)obj;
+                       Vector radVec(c->radius[0], c->radius[0]);
 
-                       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]))
+                       if (selection.Contains(c->p[0] - radVec) && selection.Contains(c->p[0] + radVec))
                                c->selected = true;
 
                        break;
@@ -2272,66 +2503,21 @@ void DrawingView::CheckObjectBounds(void)
                case OTArc:
                {
                        Arc * a = (Arc *)obj;
+                       Rect bounds = a->Bounds();
 
-                       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);
-
-#if 1
-                       // Swap X/Y coordinates if they're backwards...
-                       if (bounds.left() > bounds.right())
-                       {
-                               double temp = bounds.left();
-                               bounds.setLeft(bounds.right());
-                               bounds.setRight(temp);
-                       }
-
-                       if (bounds.bottom() > bounds.top())
-                       {
-                               double temp = bounds.bottom();
-                               bounds.setBottom(bounds.top());
-                               bounds.setTop(temp);
-                       }
-#else
-                       // Doesn't work as advertised! For shame!
-                       bounds = bounds.normalized();
-#endif
-
-                       // If the end of the arc is before the beginning, add 360 degrees
-                       // to it
-                       if (end < start)
-                               end += TAU;
-
-                       // Adjust the bounds depending on which axes are crossed
-                       if ((start < QTR_TAU) && (end > QTR_TAU))
-                               bounds.setTop(1.0);
-
-                       if ((start < HALF_TAU) && (end > HALF_TAU))
-                               bounds.setLeft(-1.0);
-
-                       if ((start < THREE_QTR_TAU) && (end > THREE_QTR_TAU))
-                               bounds.setBottom(-1.0);
-
-                       if ((start < TAU) && (end > TAU))
-                               bounds.setRight(1.0);
-
-                       if ((start < (TAU + QTR_TAU)) && (end > (TAU + QTR_TAU)))
-                               bounds.setTop(1.0);
-
-                       if ((start < (TAU + HALF_TAU)) && (end > (TAU + HALF_TAU)))
-                               bounds.setLeft(-1.0);
+                       if (selection.Contains(bounds))
+                               a->selected = true;
 
-                       if ((start < (TAU + THREE_QTR_TAU)) && (end > (TAU + THREE_QTR_TAU)))
-                               bounds.setBottom(-1.0);
+                       break;
+               }
 
-                       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);
+               case OTPolyline:
+               {
+                       Polyline * pl = (Polyline *)obj;
+                       Rect bounds = pl->Bounds();
 
-                       if (Global::selection.contains(bounds))
-                               a->selected = true;
+                       if (selection.Contains(bounds))
+                               pl->selected = true;
 
                        break;
                }
@@ -2341,7 +2527,7 @@ void DrawingView::CheckObjectBounds(void)
                        Text * t = (Text *)obj;
                        Rect r(obj->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height()));
 
-                       if (Global::selection.contains(r.l, r.t) && Global::selection.contains(r.r, r.b))
+                       if (selection.Contains(r))
                                t->selected = true;
 
                        break;
@@ -2351,7 +2537,7 @@ void DrawingView::CheckObjectBounds(void)
                {
                        Container * c = (Container *)obj;
 
-                       if (Global::selection.contains(c->p[0].x, c->p[0].y) && Global::selection.contains(c->p[1].x, c->p[1].y))
+                       if (selection.Contains(c->p[0]) && selection.Contains(c->p[1]))
                                c->selected = true;
 
                        break;
@@ -2363,7 +2549,6 @@ void DrawingView::CheckObjectBounds(void)
        }
 }
 
-
 bool DrawingView::HitTestObjects(Point point)
 {
        VPVectorIter i;
@@ -2393,11 +2578,14 @@ bool DrawingView::HitTestObjects(Point point)
        return needUpdate;
 }
 
-
 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:
@@ -2434,7 +2622,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                else if ((distance * Global::zoom) < 5.0)
                        obj->hitObject = true;
 
-               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject ? true : false);
+               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject);
 
                if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHO != obj->hitObject))
                        needUpdate = true;
@@ -2457,7 +2645,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0)
                        obj->hitObject = true;
 
-               obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false);
+               obj->hovered = (obj->hitPoint[0] || obj->hitObject);
 
                if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject))
                        needUpdate = true;
@@ -2479,7 +2667,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                // 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...
+               // N.B.: Still need to hit test the arc start & arc span handles... [looks like it's DONE?]
                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]);
@@ -2507,7 +2695,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                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);
+               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitObject);
 
                if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHO != obj->hitObject))
                        needUpdate = true;
@@ -2515,6 +2703,86 @@ bool DrawingView::HitTest(Object * obj, Point point)
                break;
        }
 
+       case OTPolyline:
+       {
+               Polyline * pl = (Polyline *)obj;
+               bool oldHP0 = pl->hitPoint[0], oldHO = pl->hitObject;
+               pl->hitPoint[0] = pl->hitObject = false;
+
+               for(long unsigned int i=0; i<(pl->points.size()-1); i++)
+               {
+                       Point p1 = pl->points[i];
+                       Point p2 = pl->points[i + 1];
+
+                       double dist1 = Vector::Magnitude(p1, point) * Global::zoom;
+                       double dist2 = Vector::Magnitude(p2, point) * Global::zoom;
+
+                       // Check for endpoints of lines and/or arcs first
+                       if (dist1 < 8.0)
+                       {
+                               pl->hitPoint[0] = true;
+                               hoverPoint = p1;
+                               hoverPointValid = true;
+                               pl->ptNum = i;
+                       }
+                       else if (dist2 < 8.0)
+                       {
+                               pl->hitPoint[0] = true;
+                               hoverPoint = p2;
+                               hoverPointValid = true;
+                               pl->ptNum = i + 1;
+                       }
+                       // Check for object (line/arc) last
+                       else if (p1.b == 0)
+                       {
+                               double t = Geometry::ParameterOfLineAndPoint(p1, p2, point);
+                               double objDist;
+
+                               // No bump == check for line proximity
+                               if (t < 0.0)
+                                       objDist = dist1;
+                               else if (t > 1.0)
+                                       objDist = dist2;
+                               else
+                               {
+                                       Line l(p1, p2);
+                                       Vector v1 = l.Vect();
+                                       Vector v2(p1, point);
+                                       objDist = fabs((v1.x * v2.y - v2.x * v1.y) / l.Length()) * Global::zoom;
+                               }
+
+                               if (objDist < 5.0)
+                                       pl->hitObject = true;
+                       }
+                       else
+                       {
+                               // We have a bump == check for arc proximity
+                               Arc a = Geometry::Unpack(p1, p2, p1.b);
+                               double length = Vector::Magnitude(a.p[0], point);
+                               double angle = Vector::Angle(a.p[0], point);
+                               double span = angle - a.angle[0];
+
+                               // Ensure point span is positive if we have a positive arc span
+                               if (span < 0 && a.angle[1] > 0)
+                                       span += TAU;
+
+                               // Ensure point span is negative if we have a negative arc span
+                               if (span > 0 && a.angle[1] < 0)
+                                       span -= TAU;
+
+                               if (((fabs(length - a.radius[0]) * Global::zoom) < 2.5) && (fabs(span) < fabs(a.angle[1])))
+                                       pl->hitObject = true;
+                       }
+               }
+
+               pl->hovered = (pl->hitPoint[0] || pl->hitObject);
+
+               if ((oldHP0 != pl->hitPoint[0]) || (oldHO != pl->hitObject))
+                       needUpdate = true;
+
+               break;
+       }
+
        case OTDimension:
        {
                bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHP3 = obj->hitPoint[3], oldHP4 = obj->hitPoint[4], oldHO = obj->hitObject;
@@ -2567,7 +2835,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                else if ((hCS2Point.Magnitude() * Global::zoom) < 8.0)
                        obj->hitPoint[4] = true;
 
-               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject ? true : false);
+               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject);
 
                if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHP3 != obj->hitPoint[3]) || (oldHP4 != obj->hitPoint[4]) || (oldHO != obj->hitObject))
                        needUpdate = true;
@@ -2587,7 +2855,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
                if (r.Contains(point))
                        obj->hitObject = true;
 
-               obj->hovered = (obj->hitObject ? true : false);
+               obj->hovered = obj->hitObject;
 
                if (oldHO != obj->hitObject)
                        needUpdate = true;
@@ -2679,7 +2947,6 @@ Well, you could if there was only one object in the Container.  But since there
        return needUpdate;
 }
 
-
 bool DrawingView::HandleObjectClicked(void)
 {
        if (dragged->type == OTDimension)
@@ -2723,7 +2990,6 @@ bool DrawingView::HandleObjectClicked(void)
        return false;
 }
 
-
 void DrawingView::HandleObjectMovement(Point point)
 {
        Point delta = point - oldPoint;
@@ -2738,24 +3004,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)
@@ -2771,11 +3053,16 @@ void DrawingView::HandleObjectMovement(Point point)
                        obj->p[0] = point;
                else if (obj->hitObject)
                {
-                       double oldRadius = obj->length;
-                       obj->radius[0] = Vector::Magnitude(obj->p[0], point);
+                       if (shiftDown)
+                       {
+                               double oldRadius = obj->length;
+                               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);
+                               QString text = QObject::tr("Radius: %1\nScale: %2%");
+                               informativeText = text.arg(obj->radius[0], 0, 'f', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'f', 0);
+                       }
+                       else
+                               obj->p[0] += delta;
                }
 
                break;
@@ -2801,14 +3088,14 @@ void DrawingView::HandleObjectMovement(Point point)
                                        obj->angle[1] += TAU;
 
                                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);
+                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 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);
+                       informativeText = text.arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 4);
                }
                else if (obj->hitPoint[2])
                {
@@ -2822,7 +3109,7 @@ void DrawingView::HandleObjectMovement(Point point)
                                        obj->angle[1] += TAU;
 
                                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);
+                               informativeText = text.arg(obj->angle[1] * RADIANS_TO_DEGREES, 0, 'f', 4).arg(obj->angle[0] * RADIANS_TO_DEGREES, 0, 'f', 2).arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'f', 2);
                                return;
                        }
 
@@ -2832,23 +3119,46 @@ void DrawingView::HandleObjectMovement(Point point)
                        if (obj->angle[0] < 0)
                                obj->angle[0] += TAU;
 
+                       double endAngle = obj->angle[0] + obj->angle[1];
+
+                       if (endAngle > TAU)
+                               endAngle -= TAU;
+
                        QString text = QObject::tr("End angle: %1") + QChar(0x00B0);
-                       informativeText = text.arg((obj->angle[0] + obj->angle[1]) * RADIANS_TO_DEGREES, 0, 'd', 4);
+                       informativeText = text.arg(endAngle * RADIANS_TO_DEGREES, 0, 'f', 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, 'f', 4);
                        }
-
-                       obj->radius[0] = Vector::Magnitude(obj->p[0], point);
-                       QString text = QObject::tr("Radius: %1");
-                       informativeText = text.arg(obj->radius[0], 0, 'd', 4);
+                       else
+                               obj->p[0] += delta;
                }
 
                break;
 
+       case OTPolyline:
+       {
+#if 1
+               // Do this for now...
+               ((Polyline *)obj)->Translate(delta);
+//             Polyline * pl = (Polyline *)obj;
+
+//             for(long unsigned int i=0; i<pl->points.size(); i++)
+//                     pl->points[i] += delta;
+#else
+               Polyline * pl = (Polyline *)obj;
+
+               for(long unsigned int i=0; i<(pl->points.size()-1); i++)
+#endif
+
+               break;
+       }
+
        case OTDimension:
                if (obj->hitPoint[0])
                        obj->p[0] = point;
@@ -2899,7 +3209,6 @@ The idea is to make it so whichever point on the object in question is being dra
        }
 }
 
-
 void DrawingView::AddDimensionTo(void * o)
 {
        Object * obj = (Object *)o;
@@ -2919,4 +3228,3 @@ void DrawingView::AddDimensionTo(void * o)
                break;
        }
 }
-