]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Added miscellaneous features.
[architektonas] / src / drawingview.cpp
index 1fd0482a83d266c0e313081f878ded884655b649..f50fca562d11ce438a51c61d70ef16e689ba92e1 100644 (file)
 DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        // The value in the settings file will override this.
        useAntialiasing(true), /*numSelected(0),*/ numHovered(0), shiftDown(false),
-       ctrlDown(false),
+       ctrlDown(false), altDown(false),
        gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
        scale(1.0), offsetX(-10), offsetY(-10), document(true),
-       gridPixels(0), collided(false), hoveringIntersection(false)
+       gridPixels(0), collided(false), hoveringIntersection(false),
+       dragged(NULL), draggingObject(false), angleSnap(false)
 {
 //wtf? doesn't work except in c++11??? document = { 0 };
        setBackgroundRole(QPalette::Base);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
        Global::gridSpacing = 12.0;             // In base units (inch is default)
-
 #if 0
        Line * line = new Line(Vector(5, 5), Vector(50, 40), &document);
        document.Add(line);
@@ -311,6 +311,42 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2)
 }
 
 
+void DrawingView::HandlePenWidth(float width)
+{
+       std::vector<void *>::iterator i = select.begin();
+
+       for(; i!=select.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+               obj->thickness = width;
+       }
+}
+
+
+void DrawingView::HandlePenStyle(int style)
+{
+       std::vector<void *>::iterator i = select.begin();
+
+       for(; i!=select.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+               obj->style = style;
+       }
+}
+
+
+void DrawingView::HandlePenColor(uint32_t color)
+{
+       std::vector<void *>::iterator i = select.begin();
+
+       for(; i!=select.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+               obj->color = color;
+       }
+}
+
+
 QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
 {
        // This is undoing the transform, e.g. going from client coords to local
@@ -444,7 +480,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                        Vector v(d->p[0], d->p[1]);
                        double angle = v.Angle();
                        Vector unit = v.Unit();
-                       Vector linePt1 = d->p[0], linePt2 = d->p[1];
+                       d->lp[0] = d->p[0], d->lp[1] = d->p[1];
                        Vector ortho;
                        double x1, y1, length;
 
@@ -465,7 +501,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                                        angle = QTR_TAU;
                                }
 
-                               linePt1.x = linePt2.x = x1;
+                               d->lp[0].x = d->lp[1].x = x1;
                                length = fabs(d->p[0].y - d->p[1].y);
                        }
                        else if (d->subtype == DTLinearHorz)
@@ -485,22 +521,22 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                                        angle = HALF_TAU;
                                }
 
-                               linePt1.y = linePt2.y = y1;
+                               d->lp[0].y = d->lp[1].y = y1;
                                length = fabs(d->p[0].x - d->p[1].x);
                        }
                        else if (d->subtype == DTLinear)
                        {
-                               angle = Vector(linePt1, linePt2).Angle();
-                               ortho = Vector::Normal(linePt1, linePt2);
+                               angle = Vector(d->lp[0], d->lp[1]).Angle();
+                               ortho = Vector::Normal(d->lp[0], d->lp[1]);
                                length = v.Magnitude();
                        }
 
-                       unit = Vector(linePt1, linePt2).Unit();
+                       unit = Vector(d->lp[0], d->lp[1]).Unit();
 
-                       Point p1 = linePt1 + (ortho * 10.0 * scaledThickness);
-                       Point p2 = linePt2 + (ortho * 10.0 * scaledThickness);
-                       Point p3 = linePt1 + (ortho * 16.0 * scaledThickness);
-                       Point p4 = linePt2 + (ortho * 16.0 * scaledThickness);
+                       Point p1 = d->lp[0] + (ortho * 10.0 * scaledThickness);
+                       Point p2 = d->lp[1] + (ortho * 10.0 * scaledThickness);
+                       Point p3 = d->lp[0] + (ortho * 16.0 * scaledThickness);
+                       Point p4 = d->lp[1] + (ortho * 16.0 * scaledThickness);
                        Point p5 = d->p[0] + (ortho * 4.0 * scaledThickness);
                        Point p6 = d->p[1] + (ortho * 4.0 * scaledThickness);
 
@@ -514,7 +550,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
 
                        // Calculate whether or not the arrowheads are too crowded to put
                        // inside the extension lines. 9.0 is the length of the arrowhead.
-                       double t = Geometry::ParameterOfLineAndPoint(linePt1, linePt2, linePt2 - (unit * 9.0 * scaledThickness));
+                       double t = Geometry::ParameterOfLineAndPoint(d->lp[0], d->lp[1], d->lp[1] - (unit * 9.0 * scaledThickness));
 
                        // On the screen, it's acting like this is actually 58%...
                        // This is correct, we want it to happen at > 50%
@@ -557,12 +593,64 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
 
                        painter->DrawAngledText(ctr, angle, dimText, scaledThickness);
 
+                       if (d->hitObject)
+                       {
+                               Point hp1 = (p1 + p2) / 2.0;
+                               Point hp2 = (p1 + hp1) / 2.0;
+                               Point hp3 = (hp1 + p2) / 2.0;
+
+                               if (d->hitPoint[2])
+                               {
+                                       painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+                                       painter->SetBrush(QBrush(QColor(Qt::magenta)));
+                                       painter->DrawArrowHandle(hp1, ortho.Angle() + HALF_TAU);
+                                       painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+                               }
+
+                               painter->DrawHandle(hp1);
+                               painter->SetPen(QPen(Qt::blue, 1.0 * Global::zoom * scaledThickness, Qt::SolidLine));
+
+                               if (d->hitPoint[3])
+                               {
+                                       painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+                                       painter->SetBrush(QBrush(QColor(Qt::magenta)));
+                                       painter->DrawArrowToLineHandle(hp2, (d->subtype == DTLinearVert ? v.Angle() - QTR_TAU : (v.Angle() < HALF_TAU ? HALF_TAU : 0)));
+                                       painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+                               }
+
+                               painter->DrawHandle(hp2);
+                               painter->SetPen(QPen(Qt::blue, 1.0 * Global::zoom * scaledThickness, Qt::SolidLine));
+
+                               if (d->hitPoint[4])
+                               {
+                                       painter->SetPen(QPen(Qt::magenta, 1.0, Qt::SolidLine));
+                                       painter->SetBrush(QBrush(QColor(Qt::magenta)));
+                                       painter->DrawArrowToLineHandle(hp3, (d->subtype == DTLinearHorz ? v.Angle() - QTR_TAU : (v.Angle() > HALF_TAU && v.Angle() < THREE_QTR_TAU ? THREE_QTR_TAU : QTR_TAU)));
+                                       painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DotLine));
+                               }
+
+                               painter->DrawHandle(hp3);
+                       }
+
+                       if (obj->hitPoint[0])
+                               painter->DrawHandle(obj->p[0]);
+
+                       if (obj->hitPoint[1])
+                               painter->DrawHandle(obj->p[1]);
+
                        break;
                }
                case OTText:
                {
                        Text * t = (Text *)obj;
-                       painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness);
+
+                       if (t->measured == false)
+                       {
+                               t->extents = painter->MeasureTextObject(t->s.c_str(), scaledThickness);
+                               t->measured = true;
+                       }
+
+                       painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness, t->angle[0]);
                        break;
                }
                case OTSpline:
@@ -646,6 +734,9 @@ void DrawingView::resizeEvent(QResizeEvent * /*event*/)
 
 void DrawingView::ToolHandler(int mode, Point p)
 {
+       // Drop angle snap until it's needed
+       angleSnap = false;
+
        if (Global::tool == TTLine)
                LineHandler(mode, p);
        else if (Global::tool == TTCircle)
@@ -656,6 +747,8 @@ void DrawingView::ToolHandler(int mode, Point p)
                RotateHandler(mode, p);
        else if (Global::tool == TTMirror)
                MirrorHandler(mode, p);
+       else if (Global::tool == TTDimension)
+               DimensionHandler(mode, p);
 }
 
 
@@ -778,7 +871,7 @@ void DrawingView::ToolDraw(Painter * painter)
                {
                        if (toolPoint[0] == toolPoint[1])
                                return;
-                       
+
                        Point mirrorPoint = toolPoint[0] + Vector(toolPoint[1], toolPoint[0]);
                        painter->DrawLine(mirrorPoint, toolPoint[1]);
 
@@ -794,6 +887,28 @@ void DrawingView::ToolDraw(Painter * painter)
                                informativeText += " (Copy)";
                }
        }
+       if (Global::tool == TTDimension)
+       {
+               if (Global::toolState == TSNone)
+               {
+                       painter->DrawHandle(toolPoint[0]);
+               }
+               else if ((Global::toolState == TSPoint2) && shiftDown)
+               {
+                       painter->DrawHandle(toolPoint[1]);
+               }
+               else
+               {
+                       painter->DrawLine(toolPoint[0], toolPoint[1]);
+                       painter->DrawHandle(toolPoint[1]);
+
+                       Vector v(toolPoint[0], toolPoint[1]);
+                       double absAngle = v.Angle() * RADIANS_TO_DEGREES;
+                       double absLength = v.Magnitude();
+                       QString text = tr("Length: %1 in.\n") + QChar(0x2221) + tr(": %2");
+                       informativeText = text.arg(absLength).arg(absAngle);
+               }
+       }
 }
 
 
@@ -830,7 +945,7 @@ void DrawingView::LineHandler(int mode, Point p)
                }
                else
                {
-                       Line * l = new Line(toolPoint[0], toolPoint[1]);
+                       Line * l = new Line(toolPoint[0], toolPoint[1], Global::penWidth, Global::penColor, Global::penStyle);
                        l->layer = Global::activeLayer;
                        document.objects.push_back(l);
                        toolPoint[0] = toolPoint[1];
@@ -873,7 +988,7 @@ void DrawingView::CircleHandler(int mode, Point p)
                else
                {
                        double length = Vector::Magnitude(toolPoint[0], toolPoint[1]);
-                       Circle * c = new Circle(toolPoint[0], length);
+                       Circle * c = new Circle(toolPoint[0], length, Global::penWidth, Global::penColor, Global::penStyle);
                        c->layer = Global::activeLayer;
                        document.objects.push_back(c);
                        toolPoint[0] = toolPoint[1];
@@ -904,9 +1019,15 @@ void DrawingView::ArcHandler(int mode, Point p)
                else if (Global::toolState == TSPoint2)
                        toolPoint[1] = p;
                else if (Global::toolState == TSPoint3)
+               {
                        toolPoint[2] = p;
+                       angleSnap = true;
+               }
                else
+               {
                        toolPoint[3] = p;
+                       angleSnap = true;
+               }
 
                break;
        case ToolMouseUp:
@@ -920,7 +1041,7 @@ void DrawingView::ArcHandler(int mode, Point p)
                {
                        if (shiftDown)
                        {
-                               // Key override is telling us to start circle at new center, not
+                               // Key override is telling us to start arc at new center, not
                                // continue the current one.
                                toolPoint[0] = toolPoint[1];
                                return;
@@ -944,7 +1065,7 @@ void DrawingView::ArcHandler(int mode, Point p)
                        if (span < 0)
                                span += TAU;
 
-                       Arc * arc = new Arc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span);
+                       Arc * arc = new Arc(toolPoint[0], toolPoint[1].x, toolPoint[2].x, span, Global::penWidth, Global::penColor, Global::penStyle);
                        arc->layer = Global::activeLayer;
                        document.objects.push_back(arc);
                        Global::toolState = TSNone;
@@ -980,6 +1101,7 @@ void DrawingView::RotateHandler(int mode, Point p)
                        if (shiftDown)
                                return;
 
+                       angleSnap = true;
                        double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
                        std::vector<void *>::iterator j = select.begin();
                        std::vector<Object>::iterator i = toolScratch.begin();
@@ -1082,6 +1204,7 @@ void DrawingView::MirrorHandler(int mode, Point p)
                        if (shiftDown)
                                return;
 
+                       angleSnap = true;
                        double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
                        std::vector<void *>::iterator j = select.begin();
                        std::vector<Object>::iterator i = toolScratch.begin();
@@ -1158,6 +1281,48 @@ void DrawingView::MirrorHandler(int mode, Point p)
 }
 
 
+void DrawingView::DimensionHandler(int mode, Point p)
+{
+       switch (mode)
+       {
+       case ToolMouseDown:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else
+                       toolPoint[1] = p;
+
+               break;
+       case ToolMouseMove:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = p;
+               else
+                       toolPoint[1] = p;
+
+               break;
+       case ToolMouseUp:
+               if (Global::toolState == TSNone)
+               {
+                       Global::toolState = TSPoint2;
+                       // Prevent spurious line from drawing...
+                       toolPoint[1] = toolPoint[0];
+               }
+               else if ((Global::toolState == TSPoint2) && shiftDown)
+               {
+                       // Key override is telling us to make a new line, not continue the
+                       // previous one.
+                       toolPoint[0] = toolPoint[1];
+               }
+               else
+               {
+                       Dimension * d = new Dimension(toolPoint[0], toolPoint[1], DTLinear);
+                       d->layer = Global::activeLayer;
+                       document.objects.push_back(d);
+                       Global::toolState = TSNone;
+               }
+       }
+}
+
+
 void DrawingView::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
@@ -1172,12 +1337,12 @@ 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.
+                       //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;
                }
@@ -1194,6 +1359,19 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                        AddHoveredToSelection();
                        update();       // needed??
                        GetHovered(hover);      // prolly needed
+                       dragged = (Object *)hover[0];
+                       draggingObject = true;
+
+                       // Alert the pen widget
+                       emit(ObjectSelected(dragged));
+
+                       // See if anything is using just a straight click on a handle
+                       if (HandleObjectClicked())
+                       {
+                               draggingObject = false;
+                               update();
+                               return;
+                       }
 
                        // Needed for grab & moving objects
                        // We do it *after*... why? (doesn't seem to confer any advantage...)
@@ -1227,9 +1405,10 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
        // Only needs to be done here, as mouse down is always preceded by movement
        Global::snapPointIsValid = false;
        hoveringIntersection = false;
+       oldScrollPoint = Vector(event->x(), event->y());
 
        // Scrolling...
-       if (event->buttons() & Qt::MiddleButton)
+       if ((event->buttons() & Qt::MiddleButton) || scrollDrag)
        {
                point = Vector(event->x(), event->y());
                // Since we're using Qt coords for scrolling, we have to adjust them
@@ -1255,36 +1434,25 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                return;
        }
 
-       // Handle object movement (left button down & over an object)
-       if ((event->buttons() & Qt::LeftButton) && numHovered && !Global::tool)
-       {
-               if (hoveringIntersection)
-                       point = intersectionPoint;
-               else if (Global::snapToGrid)
-                       point = SnapPointToGrid(point);
-
-               HandleObjectMovement(point);
-               update();
-               oldPoint = point;
-               return;
-       }
-
        // Do object hit testing...
        bool needUpdate = HitTestObjects(point);
+       GetHovered(hover);
 
        // Check for multi-hover...
        if (numHovered > 1)
        {
-               GetHovered(hover);
-               Geometry::Intersects((Object *)hover[0], (Object *)hover[1]);
+//need to check for case where hover is over 2 circles and a 3rd's center...
+               Object * obj1 = (Object *)hover[0], * obj2 = (Object *)hover[1];
+
+               Geometry::Intersects(obj1, obj2);
                int numIntersecting = Global::numIntersectParams;
                double t = Global::intersectParam[0];
                double u = Global::intersectParam[1];
 
                if (numIntersecting > 0)
                {
-                       Vector v1 = Geometry::GetPointForParameter((Object *)hover[0], t);
-                       Vector v2 = Geometry::GetPointForParameter((Object *)hover[1], u);
+                       Vector v1 = Geometry::GetPointForParameter(obj1, t);
+                       Vector v2 = Geometry::GetPointForParameter(obj2, u);
                        QString text = tr("Intersection t=%1 (%3, %4), u=%2 (%5, %6)");
                        informativeText = text.arg(t).arg(u).arg(v1.x).arg(v1.y).arg(v2.x).arg(v2.y);
 
@@ -1313,14 +1481,13 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                }
        }
 
-//this doesn't work down here for some reason... :-P
-//could be because the object being moved is part of the intersection, and this is screwing things up. In which case, we need to exclude the moving object somehow from the hit test function...
-#if 0
        // Handle object movement (left button down & over an object)
-       if ((event->buttons() & Qt::LeftButton) && numHovered && !Global::tool)
+       if ((event->buttons() & Qt::LeftButton) && draggingObject && !Global::tool)
        {
                if (hoveringIntersection)
                        point = intersectionPoint;
+               else if (hoverPointValid)
+                       point = hoverPoint;
                else if (Global::snapToGrid)
                        point = SnapPointToGrid(point);
 
@@ -1329,15 +1496,21 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                oldPoint = point;
                return;
        }
-#endif
 
        // Do tool handling, if any are active...
        if (Global::tool)
        {
                if (hoveringIntersection)
                        point = intersectionPoint;
+               else if (hoverPointValid)
+                       point = hoverPoint;
                else if (Global::snapToGrid)
-                       point = SnapPointToGrid(point);
+               {
+                       if (angleSnap)
+                               point = SnapPointToAngle(point);
+                       else
+                               point = SnapPointToGrid(point);
+               }
 
                ToolHandler(ToolMouseMove, point);
        }
@@ -1385,11 +1558,9 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
                {
                        if (((Object *)(*i))->selected)
                                select.push_back(*i);
-
-//hmm, this is no good, too late to do any good :-P
-//                     if ((*i)->hovered)
-//                             hover.push_back(*i);
                }
+
+               draggingObject = false;
        }
        else if (event->button() == Qt::MiddleButton)
        {
@@ -1432,11 +1603,14 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
 {
        bool oldShift = shiftDown;
        bool oldCtrl = ctrlDown;
+       bool oldAlt = altDown;
 
        if (event->key() == Qt::Key_Shift)
                shiftDown = true;
        else if (event->key() == Qt::Key_Control)
                ctrlDown = true;
+       else if (event->key() == Qt::Key_Alt)
+               altDown = true;
 
        if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
        {
@@ -1445,6 +1619,38 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
 
                update();
        }
+
+       if (oldAlt != altDown)
+       {
+               scrollDrag = true;
+               setCursor(Qt::SizeAllCursor);
+//             oldPoint = Vector();
+               oldPoint = oldScrollPoint;
+       }
+
+       if (select.size() > 0)
+       {
+               if (event->key() == Qt::Key_Up)
+               {
+                       TranslateObjects(select, Point(0, +1.0));
+                       update();
+               }
+               else if (event->key() == Qt::Key_Down)
+               {
+                       TranslateObjects(select, Point(0, -1.0));
+                       update();
+               }
+               else if (event->key() == Qt::Key_Right)
+               {
+                       TranslateObjects(select, Point(+1.0, 0));
+                       update();
+               }
+               else if (event->key() == Qt::Key_Left)
+               {
+                       TranslateObjects(select, Point(-1.0, 0));
+                       update();
+               }
+       }
 }
 
 
@@ -1452,11 +1658,14 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event)
 {
        bool oldShift = shiftDown;
        bool oldCtrl = ctrlDown;
+       bool oldAlt = altDown;
 
        if (event->key() == Qt::Key_Shift)
                shiftDown = false;
        else if (event->key() == Qt::Key_Control)
                ctrlDown = false;
+       else if (event->key() == Qt::Key_Alt)
+               altDown = false;
 
        if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
        {
@@ -1465,6 +1674,12 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event)
 
                update();
        }
+
+       if (oldAlt != altDown)
+       {
+               scrollDrag = false;
+               setCursor(Qt::ArrowCursor);
+       }
 }
 
 
@@ -1488,6 +1703,24 @@ Point DrawingView::SnapPointToGrid(Point point)
 }
 
 
+Point DrawingView::SnapPointToAngle(Point point)
+{
+       // Snap to a single digit angle (using toolpoint #1 as the center)
+       double angle = Vector::Angle(toolPoint[0], point);
+       double length = Vector::Magnitude(toolPoint[0], point);
+
+       // Convert from radians to degrees
+       double degAngle = angle * RADIANS_TO_DEGREES;
+       double snapAngle = (double)((int)(degAngle + 0.5));
+
+       Vector v;
+       v.SetAngleAndLength(snapAngle * DEGREES_TO_RADIANS, length);
+       point = toolPoint[0] + v;
+
+       return point;
+}
+
+
 Rect DrawingView::GetObjectExtents(Object * obj)
 {
        // Default to empty rect, if object checks below fail for some reason
@@ -1496,16 +1729,19 @@ Rect DrawingView::GetObjectExtents(Object * obj)
        switch (obj->type)
        {
        case OTLine:
+       case OTDimension:
        {
                rect = Rect(obj->p[0], obj->p[1]);
                break;
        }
+
        case OTCircle:
        {
                rect = Rect(obj->p[0], obj->p[0]);
                rect.Expand(obj->radius[0]);
                break;
        }
+
        case OTArc:
        {
                Arc * a = (Arc *)obj;
@@ -1542,9 +1778,16 @@ Rect DrawingView::GetObjectExtents(Object * obj)
 
                rect *= a->radius[0];
                rect.Translate(a->p[0]);
+               break;
+       }
 
+       case OTText:
+       {
+               Text * t = (Text *)obj;
+               rect = Rect(t->p[0], Point(t->p[0].x + t->extents.Width(), t->p[0].y - t->extents.Height()));
                break;
        }
+
        case OTContainer:
        {
                Container * c = (Container *)obj;
@@ -1555,6 +1798,7 @@ Rect DrawingView::GetObjectExtents(Object * obj)
                for(; i!=c->objects.end(); i++)
                        rect |= GetObjectExtents((Object *)*i);
        }
+
        default:
                break;
        }
@@ -1575,6 +1819,7 @@ void DrawingView::CheckObjectBounds(void)
                switch (obj->type)
                {
                case OTLine:
+               case OTDimension:
                {
                        Line * l = (Line *)obj;
 
@@ -1583,6 +1828,7 @@ void DrawingView::CheckObjectBounds(void)
 
                        break;
                }
+
                case OTCircle:
                {
                        Circle * c = (Circle *)obj;
@@ -1592,6 +1838,7 @@ void DrawingView::CheckObjectBounds(void)
 
                        break;
                }
+
                case OTArc:
                {
                        Arc * a = (Arc *)obj;
@@ -1657,6 +1904,18 @@ void DrawingView::CheckObjectBounds(void)
 
                        break;
                }
+
+               case OTText:
+               {
+                       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))
+                               t->selected = true;
+
+                       break;
+               }
+
                default:
                        break;
                }
@@ -1669,119 +1928,18 @@ bool DrawingView::HitTestObjects(Point point)
        std::vector<void *>::iterator i;
        numHovered = 0;
        bool needUpdate = false;
+       hoverPointValid = false;
 
        for(i=document.objects.begin(); i!=document.objects.end(); i++)
        {
                Object * obj = (Object *)(*i);
 
+               // If we're seeing the object we're dragging, skip it
+               if (draggingObject && (obj == dragged))
+                       continue;
+
                if (HitTest(obj, point))
                        needUpdate = true;
-#if 0
-               switch (obj->type)
-               {
-               case OTLine:
-               {
-                       bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHO = obj->hitObject;
-                       obj->hitPoint[0] = obj->hitPoint[1] = obj->hitObject = false;
-                       Vector lineSegment = obj->p[1] - obj->p[0];
-                       Vector v1 = point - obj->p[0];
-                       Vector v2 = point - obj->p[1];
-                       double t = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], point);
-                       double distance;
-
-                       if (t < 0.0)
-                               distance = v1.Magnitude();
-                       else if (t > 1.0)
-                               distance = v2.Magnitude();
-                       else
-                               // distance = ?Det?(ls, v1) / |ls|
-                               distance = fabs((lineSegment.x * v1.y - v1.x * lineSegment.y)
-                                       / lineSegment.Magnitude());
-
-                       if ((v1.Magnitude() * Global::zoom) < 8.0)
-                               obj->hitPoint[0] = true;
-                       else if ((v2.Magnitude() * Global::zoom) < 8.0)
-                               obj->hitPoint[1] = true;
-                       else if ((distance * Global::zoom) < 5.0)
-                               obj->hitObject = true;
-
-                       obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitObject ? true : false);
-
-                       if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHO != obj->hitObject))
-                               needUpdate = true;
-
-                       break;
-               }
-               case OTCircle:
-               {
-                       bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject;
-                       obj->hitPoint[0] = obj->hitObject = false;
-                       double length = Vector::Magnitude(obj->p[0], point);
-
-                       if ((length * Global::zoom) < 8.0)
-                               obj->hitPoint[0] = true;
-                       else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0)
-                               obj->hitObject = true;
-
-                       obj->hovered = (obj->hitPoint[0] || obj->hitObject ? true : false);
-
-                       if ((oldHP != obj->hitPoint[0]) || (oldHO != obj->hitObject))
-                               needUpdate = true;
-
-                       break;
-               }
-               case OTArc:
-               {
-                       bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHO = obj->hitObject;
-                       obj->hitPoint[0] = obj->hitPoint[1] = obj->hitPoint[2] = obj->hitObject = false;
-                       double length = Vector::Magnitude(obj->p[0], point);
-                       double angle = Vector::Angle(obj->p[0], point);
-
-                       // Make sure we get the angle in the correct spot
-                       if (angle < obj->angle[0])
-                               angle += TAU;
-
-                       // Get the span that we're pointing at...
-                       double span = angle - obj->angle[0];
-
-                       // N.B.: Still need to hit test the arc start & arc span handles...
-                       double spanAngle = obj->angle[0] + obj->angle[1];
-                       Point handle1 = obj->p[0] + (Vector(cos(obj->angle[0]), sin(obj->angle[0])) * obj->radius[0]);
-                       Point handle2 = obj->p[0] + (Vector(cos(spanAngle), sin(spanAngle)) * obj->radius[0]);
-                       double length2 = Vector::Magnitude(point, handle1);
-                       double length3 = Vector::Magnitude(point, handle2);
-
-                       if ((length * Global::zoom) < 8.0)
-                               obj->hitPoint[0] = true;
-                       else if ((length2 * Global::zoom) < 8.0)
-                               obj->hitPoint[1] = true;
-                       else if ((length3 * Global::zoom) < 8.0)
-                               obj->hitPoint[2] = true;
-                       else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1]))
-                               obj->hitObject = true;
-
-                       obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitObject ? true : false);
-
-                       if ((oldHP0 != obj->hitPoint[0]) || (oldHP1 != obj->hitPoint[1]) || (oldHP2 != obj->hitPoint[2]) || (oldHO != obj->hitObject))
-                               needUpdate = true;
-
-                       break;
-               }
-               case OTContainer:
-               {
-                       // Containers must be recursively tested...
-                       Container * c = (Container *)obj;
-                       std::vector<void *>::iterator i;
-
-                       for(i=c->objects.begin(); i!=c->objects.end(); i++)
-                       {
-                               
-                       }
-               }
-               default:
-                       break;
-               }
-#endif
 
                if (obj->hovered)
                {
@@ -1821,9 +1979,17 @@ bool DrawingView::HitTest(Object * obj, Point point)
                                / lineSegment.Magnitude());
 
                if ((v1.Magnitude() * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[0] = true;
+                       hoverPoint = obj->p[0];
+                       hoverPointValid = true;
+               }
                else if ((v2.Magnitude() * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[1] = true;
+                       hoverPoint = obj->p[1];
+                       hoverPointValid = true;
+               }
                else if ((distance * Global::zoom) < 5.0)
                        obj->hitObject = true;
 
@@ -1834,6 +2000,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
 
                break;
        }
+
        case OTCircle:
        {
                bool oldHP = obj->hitPoint[0], oldHO = obj->hitObject;
@@ -1841,7 +2008,11 @@ bool DrawingView::HitTest(Object * obj, Point point)
                double length = Vector::Magnitude(obj->p[0], point);
 
                if ((length * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[0] = true;
+                       hoverPoint = obj->p[0];
+                       hoverPointValid = true;
+               }
                else if ((fabs(length - obj->radius[0]) * Global::zoom) < 2.0)
                        obj->hitObject = true;
 
@@ -1852,6 +2023,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
 
                break;
        }
+
        case OTArc:
        {
                bool oldHP0 = obj->hitPoint[0], oldHP1 = obj->hitPoint[1], oldHP2 = obj->hitPoint[2], oldHO = obj->hitObject;
@@ -1874,11 +2046,23 @@ bool DrawingView::HitTest(Object * obj, Point point)
                double length3 = Vector::Magnitude(point, handle2);
 
                if ((length * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[0] = true;
+                       hoverPoint = obj->p[0];
+                       hoverPointValid = true;
+               }
                else if ((length2 * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[1] = true;
+                       hoverPoint = handle1;
+                       hoverPointValid = true;
+               }
                else if ((length3 * Global::zoom) < 8.0)
+               {
                        obj->hitPoint[2] = true;
+                       hoverPoint = handle2;
+                       hoverPointValid = true;
+               }
                else if (((fabs(length - obj->radius[0]) * Global::zoom) < 2.0) && (span < obj->angle[1]))
                        obj->hitObject = true;
 
@@ -1889,6 +2073,83 @@ bool DrawingView::HitTest(Object * obj, Point point)
 
                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;
+               obj->hitPoint[0] = obj->hitPoint[1] = obj->hitPoint[2] = obj->hitPoint[3] = obj->hitPoint[4] = obj->hitObject = false;
+
+               Dimension * d = (Dimension *)obj;
+
+               Vector orthogonal = Vector::Normal(d->lp[0], d->lp[1]);
+               // Get our line parallel to our points
+               float scaledThickness = Global::scale * obj->thickness;
+               Point p1 = d->lp[0] + (orthogonal * 10.0 * scaledThickness);
+               Point p2 = d->lp[1] + (orthogonal * 10.0 * scaledThickness);
+               Point p3(p1, point);
+
+               Vector v1(d->p[0], point);
+               Vector v2(d->p[1], point);
+               Vector lineSegment(p1, p2);
+               double t = Geometry::ParameterOfLineAndPoint(p1, p2, point);
+               double distance;
+               Point midpoint = (p1 + p2) / 2.0;
+               Point hFSPoint = Point(midpoint, point);
+               Point hCS1Point = Point((p1 + midpoint) / 2.0, point);
+               Point hCS2Point = Point((midpoint + p2) / 2.0, point);
+
+               if (t < 0.0)
+                       distance = v1.Magnitude();
+               else if (t > 1.0)
+                       distance = v2.Magnitude();
+               else
+                       // distance = ?Det?(ls, v1) / |ls|
+                       distance = fabs((lineSegment.x * p3.y - p3.x * lineSegment.y)
+                               / lineSegment.Magnitude());
+
+               if ((v1.Magnitude() * Global::zoom) < 8.0)
+                       obj->hitPoint[0] = true;
+               else if ((v2.Magnitude() * Global::zoom) < 8.0)
+                       obj->hitPoint[1] = true;
+               else if ((distance * Global::zoom) < 5.0)
+                       obj->hitObject = true;
+
+               if ((hFSPoint.Magnitude() * Global::zoom) < 8.0)
+                       obj->hitPoint[2] = true;
+               else if ((hCS1Point.Magnitude() * Global::zoom) < 8.0)
+                       obj->hitPoint[3] = true;
+               else if ((hCS2Point.Magnitude() * Global::zoom) < 8.0)
+                       obj->hitPoint[4] = true;
+
+//             return (hitPoint1 || hitPoint2 || hitLine || hitFlipSwitch || hitChangeSwitch1 || hitChangeSwitch2 ? true : false);
+               obj->hovered = (obj->hitPoint[0] || obj->hitPoint[1] || obj->hitPoint[2] || obj->hitPoint[3] || obj->hitPoint[4] || obj->hitObject ? true : false);
+
+               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;
+
+               break;
+       }
+
+       case OTText:
+       {
+               Text * t = (Text *)obj;
+               bool oldHO = obj->hitObject;
+               obj->hitObject = false;
+
+               Rect r(obj->p[0], Point(obj->p[0].x + t->extents.Width(), obj->p[0].y - t->extents.Height()));
+//printf("Text: p=<%lf, %lf>, w/h=%lf, %lf [lrtb=%lf, %lf, %lf, %lf]\n", obj->p[0].x, obj->p[0].y, t->extents.Width(), t->extents.Height(), t->extents.l, t->extents.r, t->extents.t, t->extents.b);
+
+               if (r.Contains(point))
+                       obj->hitObject = true;
+
+               obj->hovered = (obj->hitObject ? true : false);
+
+               if (oldHO != obj->hitObject)
+                       needUpdate = true;
+
+               break;
+       }
+
        case OTContainer:
        {
                // Containers must be recursively tested...
@@ -1913,6 +2174,7 @@ bool DrawingView::HitTest(Object * obj, Point point)
 
                break;
        }
+
        default:
                break;
        }
@@ -1921,11 +2183,56 @@ bool DrawingView::HitTest(Object * obj, Point point)
 }
 
 
+bool DrawingView::HandleObjectClicked(void)
+{
+       if (dragged->type == OTDimension)
+       {
+               Dimension * d = (Dimension *)dragged;
+
+               if (d->hitPoint[2])
+               {
+                       // Hit the "flip sides" switch, so flip 'em
+                       Point temp = d->p[0];
+                       d->p[0] = d->p[1];
+                       d->p[1] = temp;
+                       return true;
+               }
+               else if (d->hitPoint[3])
+               {
+                       // There are three cases here: aligned, horizontal, & vertical.
+                       // Aligned and horizontal do the same thing, vertical goes back to
+                       // linear.
+                       if (d->subtype == DTLinearVert)
+                               d->subtype = DTLinear;
+                       else
+                               d->subtype = DTLinearVert;
+
+                       return true;
+               }
+               else if (d->hitPoint[4])
+               {
+                       // There are three cases here: aligned, horizontal, & vertical.
+                       // Aligned and vertical do the same thing, horizontal goes back to
+                       // linear.
+                       if (d->subtype == DTLinearHorz)
+                               d->subtype = DTLinear;
+                       else
+                               d->subtype = DTLinearHorz;
+
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
 void DrawingView::HandleObjectMovement(Point point)
 {
        Point delta = point - oldPoint;
 //printf("HOM: old = (%f,%f), new = (%f, %f), delta = (%f, %f)\n", oldPoint.x, oldPoint.y, point.x, point.y, delta.x, delta.y);
-       Object * obj = (Object *)hover[0];
+//     Object * obj = (Object *)hover[0];
+       Object * obj = dragged;
 //printf("Object type = %i (size=%i), ", obj->type, hover.size());
 //printf("Object (%X) move: hp1=%s, hp2=%s, hl=%s\n", obj, (obj->hitPoint[0] ? "true" : "false"), (obj->hitPoint[1] ? "true" : "false"), (obj->hitObject ? "true" : "false"));
 
@@ -1943,6 +2250,7 @@ void DrawingView::HandleObjectMovement(Point point)
                }
 
                break;
+
        case OTCircle:
                if (obj->hitPoint[0])
                        obj->p[0] = point;
@@ -1957,6 +2265,7 @@ void DrawingView::HandleObjectMovement(Point point)
                }
 
                break;
+
        case OTArc:
                if (obj->hitPoint[0])
                        obj->p[0] = point;
@@ -2025,6 +2334,26 @@ void DrawingView::HandleObjectMovement(Point point)
                }
 
                break;
+
+       case OTDimension:
+               if (obj->hitPoint[0])
+                       obj->p[0] = point;
+               else if (obj->hitPoint[1])
+                       obj->p[1] = point;
+               else if (obj->hitObject)
+               {
+                       obj->p[0] += delta;
+                       obj->p[1] += delta;
+               }
+
+               break;
+
+       case OTText:
+               if (obj->hitObject)
+                       obj->p[0] += delta;
+
+               break;
+
        case OTContainer:
                // This is shitty, but works for now until I can code up something
                // nicer :-)