]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Further progress on Polylines: Polylines can be selected and moved.
[architektonas] / src / drawingview.cpp
index 9acf00cd7e29fb1878b4c9c04a9c7d856c3fe68a..e65bbe92de99f12d47f6f2e12596c25d33485c1d 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 };
@@ -131,7 +133,7 @@ void DrawingView::DrawBackground(Painter * painter)
 
        painter->SetBrush(0xF0F0F0);
        painter->SetPen(0xF0F0F0, 1, 1);
-       painter->DrawRect(QRectF(QPointF(ul.x, ul.y), QPointF(br.x, br.y)));
+       painter->DrawRect(Rect(ul, br));
 
        double spacing = Global::gridSpacing;
 
@@ -159,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);
@@ -193,7 +195,6 @@ void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Ve
 //
 void DrawingView::DeleteCurrentLayer(int layer)
 {
-//printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
        VPVectorIter i = document.objects.begin();
 
        while (i != document.objects.end())
@@ -230,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);
 }
 
@@ -253,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();
@@ -340,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)
@@ -355,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*/)
@@ -387,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);
        }
 
@@ -491,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;
@@ -594,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().
@@ -681,15 +654,12 @@ Where is the text offset?  It looks like it's drawing in the center, but obvious
                        break;
                }
 
+#if 0
                case OTPolygon:
                {
                        break;
                }
-
-               case OTPolyline:
-               {
-                       break;
-               }
+#endif
 
                case OTContainer:
                {
@@ -719,16 +689,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)
@@ -773,6 +772,17 @@ VPVector DrawingView::GetHovered(bool exclude/*= false*/)
        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());
@@ -795,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)
@@ -805,8 +817,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]);
@@ -826,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]);
@@ -846,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]);
@@ -890,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)
@@ -911,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)
@@ -937,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]);
@@ -959,6 +977,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;
        }
 }
 
@@ -1489,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;
@@ -1497,7 +1564,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)
        {
@@ -1586,89 +1683,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.
-      Also: trim tool should ignore snap.
-*/
        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)
                {
@@ -1688,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)
@@ -1705,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:
@@ -1725,14 +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:
@@ -1753,7 +1905,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
@@ -1766,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;
                }
@@ -1779,49 +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
-// 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)
@@ -1835,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)
@@ -1852,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)
@@ -1875,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;
@@ -2081,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;
@@ -2242,6 +2384,7 @@ 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;
 }
 
@@ -2286,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;
        }
 
@@ -2355,6 +2473,8 @@ void DrawingView::CheckObjectBounds(void)
        {
                Object * obj = (Object *)(*i);
                obj->selected = false;
+               Rect selection = Global::selection;
+               selection.Normalize();
 
                switch (obj->type)
                {
@@ -2363,7 +2483,7 @@ void DrawingView::CheckObjectBounds(void)
                {
                        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;
@@ -2372,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;
@@ -2382,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;
                }
@@ -2451,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;
@@ -2461,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;
@@ -2506,6 +2582,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:
@@ -2542,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;
@@ -2565,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;
@@ -2587,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]);
@@ -2615,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;
@@ -2623,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;
@@ -2675,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;
@@ -2695,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;
@@ -2844,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)
@@ -2877,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;
@@ -2907,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])
                {
@@ -2928,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;
                        }
 
@@ -2938,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;