]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Miscellaneous fixes/updates:
[architektonas] / src / drawingview.cpp
index 842c5b382fefd3a88f9e2936550a2fc3bd7ce95a..9acf00cd7e29fb1878b4c9c04a9c7d856c3fe68a 100644 (file)
 #include "global.h"
 #include "mathconstants.h"
 #include "painter.h"
+#include "penwidget.h"
 #include "structs.h"
 #include "utils.h"
 
-
 #define BACKGROUND_MAX_SIZE    512
 
-
 DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        // The value in the settings file will override this.
-       useAntialiasing(true), /*numSelected(0),*/ numHovered(0), shiftDown(false),
+       useAntialiasing(true), numHovered(0), shiftDown(false),
        ctrlDown(false), altDown(false),
        gridBackground(BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE),
-       scale(1.0), offsetX(-10), offsetY(-10), document(true),
+       scale(1.0), offsetX(-10), offsetY(-10), supressSelected(false),
+       document(true),
        gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false),
        hoveringIntersection(false), dragged(NULL), draggingObject(false),
        angleSnap(false), dirty(false)
@@ -60,6 +60,9 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        setBackgroundRole(QPalette::Base);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
+       curMarker = QCursor(QPixmap(":/res/cursor-marker.png"), 1, 18);
+       curDropper = QCursor(QPixmap(":/res/cursor-dropper.png"), 1, 20);
+
        Global::gridSpacing = 12.0;             // In base units (inch is default)
 
        Line * line = new Line(Vector(5, 5), Vector(50, 40), 2.0, 0xFF7F00, LSDash);
@@ -118,116 +121,68 @@ scaled the same way as the arrowheads.
 Need a way to scale line widths as well. :-/ Shouldn't be too difficult, just
 need a thickness parameter similar to the "size" param for dimensions. (And now
 we do! :-)
-
 */
-       SetGridSize(12);        // This is in pixels
 }
 
-
-void DrawingView::SetGridSize(uint32_t size)
+void DrawingView::DrawBackground(Painter * painter)
 {
-       // Sanity check
-       if (size == gridPixels)
-               return;
+       Point ul = Painter::QtToCartesianCoords(Vector(0, 0));
+       Point br = Painter::QtToCartesianCoords(Vector(Global::screenSize.x, Global::screenSize.y));
 
-       // Recreate the background bitmap
-       gridPixels = size;
-       QPainter pmp(&gridBackground);
-       pmp.fillRect(0, 0, BACKGROUND_MAX_SIZE, BACKGROUND_MAX_SIZE, QColor(240, 240, 240));
-       pmp.setPen(QPen(QColor(210, 210, 255), 2.0, Qt::SolidLine));
+       painter->SetBrush(0xF0F0F0);
+       painter->SetPen(0xF0F0F0, 1, 1);
+       painter->DrawRect(QRectF(QPointF(ul.x, ul.y), QPointF(br.x, br.y)));
 
-       for(int i=0; i<(BACKGROUND_MAX_SIZE-1); i+=gridPixels)
-       {
-               pmp.drawLine(i, 0, i, BACKGROUND_MAX_SIZE - 1);
-               pmp.drawLine(0, i, BACKGROUND_MAX_SIZE - 1, i);
-       }
+       double spacing = Global::gridSpacing;
 
-       pmp.end();
+       if (spacing < 1.0)
+               spacing = 1.0;
 
-       // Set up new BG brush & zoom level (pixels per base unit)
-       Global::zoom = gridPixels / Global::gridSpacing;
-       UpdateGridBackground();
-}
+       double leftx = floor(ul.x / spacing) * spacing;
+       double bottomy = floor(br.y / spacing) * spacing;
 
+       double w = (br.x - ul.x) + Global::gridSpacing + 1.0;
+       double h = (ul.y - br.y) + Global::gridSpacing + 1.0;
 
-void DrawingView::UpdateGridBackground(void)
-{
-       // Transform the origin to Qt coordinates
-       Vector pixmapOrigin = Painter::CartesianToQtCoords(Vector());
-       int x = (int)pixmapOrigin.x;
-       int y = (int)pixmapOrigin.y;
-       // Use mod arithmetic to grab the correct swatch of background
-/*
-Negative numbers still screw it up... Need to think about what we're
-trying to do here. The fact that it worked with 72 seems to have been pure luck.
-It seems the problem is negative numbers: We can't let that happen.
-When taking away the zero, it pops over 1 px at zero, then goes about 1/2 a
-grid at x<0.
-
-The bitmap looks like this:
-
-+---+---+---+---+---
-|   |   |   |   |
-|   |   |   |   |
-+---+---+---+---+---
-|   |   |   |   |
-|   |   |   |   |
-|   |   |   |   |
-
-@ x = 1, we want it to look like:
-
--+---+---+---+---+---
- |   |   |   |   |
- |   |   |   |   |
--+---+---+---+---+---
- |   |   |   |   |
- |   |   |   |   |
- |   |   |   |   |
-
-Which means we need to grab the sample from x = 3. @ x = -1:
-
----+---+---+---+---
-   |   |   |   |
-   |   |   |   |
----+---+---+---+---
-   |   |   |   |
-   |   |   |   |
-   |   |   |   |
-
-Which means we need to grab the sample from x = 1. Which means we have to take
-the mirror of the modulus of gridPixels.
-
-Doing a mod of a negative number is problematic: 1st, the compiler converts the
-negative number to an unsigned int, then it does the mod. Gets you wrong answers
-most of the time, unless you use a power of 2. :-P So what we do here is just
-take the modulus of the negation, which means we don't have to worry about
-mirroring it later.
-
-The positive case looks gruesome (and it is) but it boils down to this: We take
-the modulus of the X coordinate, then mirror it by subtraction from the
-maximum (in this case, gridPixels). This gives us a number in the range of 1 to
-gridPixels. But we need the case where the result equalling gridPixels to be
-zero; so we do another modulus operation on the result to achieve this.
-*/
-       if (x < 0)
-               x = -x % gridPixels;
-       else
-               x = (gridPixels - (x % gridPixels)) % gridPixels;
+       Vector start(leftx, bottomy), size(w, h);
 
-       if (y < 0)
-               y = -y % gridPixels;
-       else
-               y = (gridPixels - (y % gridPixels)) % gridPixels;
-
-       // Here we grab a section of the bigger pixmap, so that the background
-       // *looks* like it's scrolling...
-       QPixmap pm = gridBackground.copy(x, y, gridPixels, gridPixels);
-       QPalette pal = palette();
-       pal.setBrush(backgroundRole(), QBrush(pm));
-       setAutoFillBackground(true);
-       setPalette(pal);
+       if (Global::gridSpacing <= 0.015625)
+               DrawSubGrid(painter, 0xFFD2D2, 0.015625, start, size);
+
+       if (Global::gridSpacing <= 0.03125)
+               DrawSubGrid(painter, 0xFFD2D2, 0.03125, start, size);
+
+       if (Global::gridSpacing <= 0.0625)
+               DrawSubGrid(painter, 0xB8ECFF, 0.0625, start, size);
+
+       if (Global::gridSpacing <= 0.125)
+               DrawSubGrid(painter, 0xB8ECFF, 0.125, start, size);
+
+       if (Global::gridSpacing <= 0.25)
+               DrawSubGrid(painter, 0xDBDBFF, 0.25, start, size);
+
+       if (Global::gridSpacing <= 0.5)
+               DrawSubGrid(painter, 0xDBDBFF, 0.5, start, size);
+
+       painter->SetPen(QPen(QColor(0xD2, 0xD2, 0xFF), 2.0, Qt::SolidLine));
+
+       for(double i=0; i<=w; i+=spacing)
+               painter->DrawVLine(leftx + i);
+
+       for(double i=0; i<=h; i+=spacing)
+               painter->DrawHLine(bottomy + i);
 }
 
+void DrawingView::DrawSubGrid(Painter * painter, uint32_t color, double step, Vector start, Vector size)
+{
+       painter->SetPen(color, 1, 1);
+
+       for(double i=-step; i<=size.x; i+=step*2.0)
+               painter->DrawVLine(start.x + i);
+
+       for(double i=-step; i<=size.y; i+=step*2.0)
+               painter->DrawHLine(start.y + i);
+}
 
 //
 // Basically, we just make a single pass through the Container. If the layer #
@@ -239,7 +194,7 @@ zero; so we do another modulus operation on the result to achieve this.
 void DrawingView::DeleteCurrentLayer(int layer)
 {
 //printf("DrawingView::DeleteCurrentLayer(): currentLayer = %i\n", layer);
-       std::vector<void *>::iterator i = document.objects.begin();
+       VPVectorIter i = document.objects.begin();
 
        while (i != document.objects.end())
        {
@@ -263,14 +218,12 @@ void DrawingView::DeleteCurrentLayer(int layer)
        update();
 }
 
-
 void DrawingView::HandleLayerToggle(void)
 {
        // A layer's visibility was toggled, so update the screen...
        update();
 }
 
-
 //
 // A layer was moved up or down in the layer list, so we have to swap the
 // document's object's layer numbers in the layers that were swapped.
@@ -278,9 +231,15 @@ void DrawingView::HandleLayerToggle(void)
 void DrawingView::HandleLayerSwap(int layer1, int layer2)
 {
 //printf("DrawingView: Swapping layers %i and %i.\n", layer1, layer2);
-       std::vector<void *>::iterator i;
+       HandleLayerSwap(layer1, layer2, document.objects);
+}
 
-       for(i=document.objects.begin(); i!=document.objects.end(); i++)
+/*
+We can roll this into the main one above, by having the LayerWidget's emit() call sending NULL for the VPVector, which we can test for and set to document.objects to grab the top layer.  Or, keep it a top level call and a recursive call.  Which is worse?  :-P
+*/
+void DrawingView::HandleLayerSwap(int layer1, int layer2, VPVector & v)
+{
+       for(VPVectorIter i=v.begin(); i!=v.end(); i++)
        {
                Object * obj = (Object *)(*i);
 
@@ -288,45 +247,80 @@ void DrawingView::HandleLayerSwap(int layer1, int layer2)
                        obj->layer = layer2;
                else if (obj->layer == layer2)
                        obj->layer = layer1;
+
+               if (obj->type == OTContainer)
+                       HandleLayerSwap(layer1, layer2, ((Container *)obj)->objects);
        }
 }
 
-
 void DrawingView::HandlePenWidth(float width)
 {
-       std::vector<void *>::iterator i = select.begin();
-
-       for(; i!=select.end(); i++)
+       for(VPVectorIter i=select.begin(); i!=select.end(); i++)
        {
                Object * obj = (Object *)(*i);
                obj->thickness = width;
        }
-}
 
+       supressSelected = true;
+       update();
+}
 
 void DrawingView::HandlePenStyle(int style)
 {
-       std::vector<void *>::iterator i = select.begin();
-
-       for(; i!=select.end(); i++)
+       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)
 {
-       std::vector<void *>::iterator i = select.begin();
-
-       for(; i!=select.end(); i++)
+       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();
+       pw->dropperAction->setChecked(false);
+       Global::penDropper = false;
+       Global::penStamp = action->isChecked();
+
+       if (Global::penStamp)
+               setCursor(curMarker);
+       else
+               setCursor(Qt::ArrowCursor);
+
+       if (Global::penStamp == false)
+               ClearSelected(document.objects);
+
+       update();
 }
 
+void DrawingView::HandlePenDropper(QAction * action)
+{
+       PenWidget * pw = (PenWidget *)action->parentWidget();
+       pw->stampAction->setChecked(false);
+       Global::penStamp = false;
+       Global::penDropper = action->isChecked();
+
+       if (Global::penDropper)
+               setCursor(curDropper);
+       else
+               setCursor(Qt::ArrowCursor);
+
+       update();
+}
 
 QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
 {
@@ -336,7 +330,6 @@ QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
        return QPoint(offsetX + event->x(), offsetY + (size().height() - event->y()));
 }
 
-
 QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
 {
        // VOODOO ALERT (ON Y COMPONENT!!!!) (eh?)
@@ -345,7 +338,6 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
        return QPoint(-offsetX + x, (size().height() - (-offsetY + y)) * +1.0);
 }
 
-
 void DrawingView::focusOutEvent(QFocusEvent * /*event*/)
 {
 //     printf("DrawingView::focusOutEvent()...\n");
@@ -357,6 +349,16 @@ void DrawingView::focusOutEvent(QFocusEvent * /*event*/)
        setCursor(Qt::ArrowCursor);
 }
 
+void DrawingView::focusInEvent(QFocusEvent * /*event*/)
+{
+       if (Global::penStamp)
+               setCursor(curMarker);
+       else if (Global::penDropper)
+               setCursor(curDropper);
+//FocusOut already set this...
+//     else
+//             setCursor(Qt::ArrowCursor);
+}
 
 void DrawingView::paintEvent(QPaintEvent * /*event*/)
 {
@@ -368,6 +370,8 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
 
        Global::viewportHeight = size().height();
 
+       DrawBackground(&painter);
+
        // Draw coordinate axes
        painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine));
        painter.DrawLine(0, -16384, 0, 16384);
@@ -406,7 +410,6 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
                painter.DrawInformativeText(informativeText);
 }
 
-
 //
 // Renders objects in the passed in vector
 //
@@ -416,11 +419,9 @@ N.B.: Since we have "hoverPointValid" drawing regular object handles above,
       !!! FIX !!!
       [Well, it seems to work OK *except* when you move one of the points, then you get to see nothing. Is it worth fixing there to get rid of problems here? Have to investigate...]
 */
-void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int layer, bool ignoreLayer/*= false*/)
+void DrawingView::RenderObjects(Painter * painter, VPVector & v, int layer, bool ignoreLayer/*= false*/)
 {
-       std::vector<void *>::iterator i;
-
-       for(i=v.begin(); i!=v.end(); i++)
+       for(VPVectorIter i=v.begin(); i!=v.end(); i++)
        {
                Object * obj = (Object *)(*i);
                float scaledThickness = Global::scale * obj->thickness;
@@ -438,7 +439,16 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                        painter->SetPen(obj->color, Global::zoom * scaledThickness, obj->style);
                        painter->SetBrush(obj->color);
 
-                       if (obj->selected || obj->hitObject)
+                       // penStamp supresses object highlighting, so that changes can be seen.
+                       if (supressSelected || Global::penStamp)
+                       {
+                               if (obj->hitObject)
+                               {
+                                       painter->SetPen(Global::penColor, Global::zoom * Global::scale * Global::penWidth, Global::penStyle);
+                                       painter->SetBrush(Global::penColor);
+                               }
+                       }
+                       else if (obj->selected || obj->hitObject)
                                painter->SetPen(0xFF0000, Global::zoom * scaledThickness, LSDash);
                }
 
@@ -541,10 +551,10 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
 
                        unit = Vector(d->lp[0], d->lp[1]).Unit();
 
-                       Point p1 = d->lp[0] + (ortho * (10.0 + d->offset) * scaledThickness);
-                       Point p2 = d->lp[1] + (ortho * (10.0 + d->offset) * scaledThickness);
-                       Point p3 = d->lp[0] + (ortho * (16.0 + d->offset) * scaledThickness);
-                       Point p4 = d->lp[1] + (ortho * (16.0 + d->offset) * scaledThickness);
+                       Point p1 = d->lp[0] + (ortho * (d->offset + (10.0 * scaledThickness)));
+                       Point p2 = d->lp[1] + (ortho * (d->offset + (10.0 * scaledThickness)));
+                       Point p3 = d->lp[0] + (ortho * (d->offset + (16.0 * scaledThickness)));
+                       Point p4 = d->lp[1] + (ortho * (d->offset + (16.0 * scaledThickness)));
                        Point p5 = d->p[0] + (ortho * 4.0 * scaledThickness);
                        Point p6 = d->p[1] + (ortho * 4.0 * scaledThickness);
 
@@ -599,6 +609,9 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                                        dimText = QString("%1' %2\"").arg(feet).arg(inches);
                        }
 
+/*
+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().
+*/
                        painter->DrawAngledText(ctr, angle, dimText, scaledThickness);
 
                        if (d->hitObject)
@@ -673,11 +686,16 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                        break;
                }
 
+               case OTPolyline:
+               {
+                       break;
+               }
+
                case OTContainer:
                {
                        // Containers require recursive rendering...
                        Container * c = (Container *)obj;
-printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), layer);
+//printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(), layer);
                        RenderObjects(painter, (*c).objects, layer, ignoreLayer);
 
 //printf("Container extents: <%lf, %lf>, <%lf, %lf>\nsize: %i\n", r.l, r.t, r.r, r.b, c->objects.size());
@@ -696,77 +714,70 @@ printf("About to render container: # objs=%i, layer=%i\n", (*c).objects.size(),
                        break;
                }
        }
-}
 
+       supressSelected = false;
+}
 
+//
+// This toggles the selection being hovered (typically, only 1 object)
+//
 void DrawingView::AddHoveredToSelection(void)
 {
-       std::vector<void *>::iterator i;
-
-       for(i=document.objects.begin(); i!=document.objects.end(); i++)
+       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
        {
                if (((Object *)(*i))->hovered)
-                       ((Object *)(*i))->selected = true;
+//                     ((Object *)(*i))->selected = true;
+                       ((Object *)(*i))->selected = !((Object *)(*i))->selected;
        }
 }
 
-
-void DrawingView::GetSelection(std::vector<void *> & v)
+VPVector DrawingView::GetSelection(void)
 {
-       v.clear();
-       std::vector<void *>::iterator i;
+       VPVector v;
 
-       for(i=document.objects.begin(); i!=document.objects.end(); i++)
+       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
        {
                if (((Object *)(*i))->selected)
                        v.push_back(*i);
        }
-}
 
+       return v;
+}
 
-#if 0
-void DrawingView::GetHovered(std::vector<void *> & v)
+//
+// When testing for hovered intersections, we need to be able to exclude some
+// objects which have funky characteristics or handles; so we allow for that
+// here.
+//
+VPVector DrawingView::GetHovered(bool exclude/*= false*/)
 {
-       v.clear();
-       std::vector<void *>::iterator i;
+       VPVector v;
 
-       for(i=document.objects.begin(); i!=document.objects.end(); i++)
+       for(VPVectorIter i=document.objects.begin(); i!=document.objects.end(); i++)
        {
-               if (((Object *)(*i))->hovered)
-//             {
-//printf("GetHovered: adding object (%X) to hover... hp1=%s, hp2=%s, hl=%s\n", (*i), (((Line *)(*i))->hitPoint[0] ? "true" : "false"), (((Line *)(*i))->hitPoint[1] ? "true" : "false"), (((Line *)(*i))->hitObject ? "true" : "false"));
-                       v.push_back(*i);
-//             }
-       }
-}
-#endif
-
+               Object * obj = (Object *)(*i);
 
-std::vector<void *> DrawingView::GetHovered(void)
-{
-       std::vector<void *> v;
-       std::vector<void *>::iterator i;
+               if (obj->hovered)
+               {
+                       if (exclude
+                               && ((obj->type == OTDimension)
+                                       || ((obj->type == OTCircle) && (obj->hitPoint[0] == true))
+                                       || ((obj->type == OTArc) && (obj->hitPoint[0] == true))
+                                       || (draggingObject && (obj == dragged))))
+                               continue;
 
-       for(i=document.objects.begin(); i!=document.objects.end(); i++)
-       {
-               if (((Object *)(*i))->hovered)
-//             {
-//printf("GetHovered: adding object (%X) to hover... hp1=%s, hp2=%s, hl=%s\n", (*i), (((Line *)(*i))->hitPoint[0] ? "true" : "false"), (((Line *)(*i))->hitPoint[1] ? "true" : "false"), (((Line *)(*i))->hitObject ? "true" : "false"));
                        v.push_back(*i);
-//             }
+               }
        }
 
        return v;
 }
 
-
 void DrawingView::resizeEvent(QResizeEvent * /*event*/)
 {
        Global::screenSize = Vector(size().width(), size().height());
-       UpdateGridBackground();
 }
 
-
 void DrawingView::ToolHandler(int mode, Point p)
 {
        // Drop angle snap until it's needed
@@ -792,7 +803,6 @@ void DrawingView::ToolHandler(int mode, Point p)
                ParallelHandler(mode, p);
 }
 
-
 void DrawingView::ToolDraw(Painter * painter)
 {
        if (Global::tool == TTLine)
@@ -952,12 +962,24 @@ void DrawingView::ToolDraw(Painter * painter)
        }
 }
 
-
 void DrawingView::LineHandler(int mode, Point p)
 {
        switch (mode)
        {
        case ToolMouseDown:
+/*             toolObj[0] = NULL;
+
+               // Check to see if we can do a circle tangent snap
+               if (numHovered == 1)
+               {
+                       VPVector hover = GetHovered();
+                       Object * obj = (Object *)hover[0];
+
+                       // Save for later if the object clicked was a circle (need to check that it wasn't the center clicked on, because that will fuck up connecting centers of circles with lines... and now we do! :-)
+                       if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+                               toolObj[0] = obj;
+               }*/
+
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
                else
@@ -969,7 +991,54 @@ void DrawingView::LineHandler(int mode, Point p)
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
                else
+               {
                        toolPoint[1] = p;
+/*                     bool isCircle = false;
+
+                       if (numHovered == 1)
+                       {
+                               VPVector hover = GetHovered();
+                               Object * obj = (Object *)hover[0];
+
+                               if ((obj->type == OTCircle) && (obj->hitPoint[0] == false))
+                               {
+                                       isCircle = true;
+                                       toolObj[1] = obj;
+                               }
+                       }
+
+                       // Adjust initial point if it's on a circle (tangent point)
+                       if (toolObj[0] != NULL)
+                       {
+                               if (isCircle)
+                               {
+                                       Geometry::FindTangents(toolObj[0], toolObj[1]);
+
+                                       if (Global::numIntersectPoints > 0)
+                                       {
+                                               toolPoint[0] = Global::intersectPoint[0];
+                                               toolPoint[1] = Global::intersectPoint[1];
+                                       }
+                               }
+                               else
+                               {
+                                       Geometry::FindTangents(toolObj[0], p);
+
+                                       if (Global::numIntersectPoints > 0)
+                                               toolPoint[0] = Global::intersectPoint[0];
+                               }
+                       }
+                       else
+                       {
+                               if (isCircle)
+                               {
+                                       Geometry::FindTangents(toolObj[1], toolPoint[0]);
+
+                                       if (Global::numIntersectPoints > 0)
+                                               toolPoint[1] = Global::intersectPoint[0];
+                               }
+                       }*/
+               }
 
                break;
 
@@ -996,7 +1065,6 @@ void DrawingView::LineHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::CircleHandler(int mode, Point p)
 {
        switch (mode)
@@ -1042,7 +1110,6 @@ void DrawingView::CircleHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::ArcHandler(int mode, Point p)
 {
        switch (mode)
@@ -1120,7 +1187,6 @@ void DrawingView::ArcHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::RotateHandler(int mode, Point p)
 {
        switch (mode)
@@ -1152,9 +1218,9 @@ void DrawingView::RotateHandler(int mode, Point p)
 
                        angleSnap = true;
                        double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
-                       std::vector<void *>::iterator j = select.begin();
+                       VPVectorIter j = select.begin();
 //                     std::vector<Object>::iterator i = toolScratch.begin();
-                       std::vector<void *>::iterator i = toolScratch2.begin();
+                       VPVectorIter i = toolScratch2.begin();
 
 //                     for(; i!=toolScratch.end(); i++, j++)
                        for(; i!=toolScratch2.end(); i++, j++)
@@ -1187,10 +1253,10 @@ void DrawingView::RotateHandler(int mode, Point p)
 //                                     Container * c = (Container *)&objT;
                                        Container * c = (Container *)objT;
                                        Container * c2 = (Container *)objS;
-                                       std::vector<void *>::iterator l = c->objects.begin();
+                                       VPVectorIter l = c->objects.begin();
                                        // TODO: Rotate items in the container
                                        // TODO: Make this recursive
-                                       for(std::vector<void *>::iterator k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
+                                       for(VPVectorIter k=c2->objects.begin(); k!=c2->objects.end(); k++, l++)
                                        {
                                                Object * obj3 = (Object *)(*k);
                                                Object * obj4 = (Object *)(*l);
@@ -1235,7 +1301,7 @@ void DrawingView::RotateHandler(int mode, Point p)
                        if (ctrlDown)
                        {
                                // Stamp a copy of the selection at the current rotation & bail
-                               std::vector<void *> temp;
+                               VPVector temp;
                                CopyObjects(select, temp);
                                ClearSelected(temp);
                                AddObjectsTo(document.objects, temp);
@@ -1275,7 +1341,6 @@ void DrawingView::RotateHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::MirrorHandler(int mode, Point p)
 {
        switch (mode)
@@ -1306,7 +1371,7 @@ void DrawingView::MirrorHandler(int mode, Point p)
 
                        angleSnap = true;
                        double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
-                       std::vector<void *>::iterator j = select.begin();
+                       VPVectorIter j = select.begin();
                        std::vector<Object>::iterator i = toolScratch.begin();
 
                        for(; i!=toolScratch.end(); i++, j++)
@@ -1355,7 +1420,7 @@ N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have
                        if (ctrlDown)
                        {
                                // Stamp a copy of the selection at the current rotation & bail
-                               std::vector<void *> temp;
+                               VPVector temp;
                                CopyObjects(select, temp);
                                ClearSelected(temp);
                                AddObjectsTo(document.objects, temp);
@@ -1389,7 +1454,6 @@ N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have
        }
 }
 
-
 void DrawingView::DimensionHandler(int mode, Point p)
 {
        switch (mode)
@@ -1433,7 +1497,6 @@ void DrawingView::DimensionHandler(int mode, Point p)
        }
 }
 
-
 void DrawingView::TriangulateHandler(int mode, Point/*p*/)
 {
        switch (mode)
@@ -1444,7 +1507,7 @@ void DrawingView::TriangulateHandler(int mode, Point/*p*/)
                if (numHovered != 1)
                        break;
 
-               std::vector<void *> hover = GetHovered();
+               VPVector hover = GetHovered();
                Object * obj = (Object *)hover[0];
 
                // Skip if it's not a line...
@@ -1521,11 +1584,11 @@ 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.
+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)
        {
@@ -1613,7 +1676,7 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
                        return;
                }
 
-               std::vector<void *> hover = GetHovered();
+               VPVector hover = GetHovered();
                Object * obj = (Object *)hover[0];
 
                // Skip if it's not a line...
@@ -1628,7 +1691,7 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
 
                // Currently only deal with line against line trimming, can expand to
                // others as well (line/circle, circle/circle, line/arc, etc)
-               std::vector<void *>::iterator i;
+               VPVectorIter i;
                for(i=document.objects.begin(); i!=document.objects.end(); i++)
                {
                        obj = (Object *)(*i);
@@ -1662,7 +1725,6 @@ n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
        }
 }
 
-
 void DrawingView::ParallelHandler(int mode, Point /*p*/)
 {
        switch (mode)
@@ -1687,12 +1749,11 @@ void DrawingView::ParallelHandler(int mode, Point /*p*/)
        }
 }
 
-
 void DrawingView::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
        {
-printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
+//printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
                Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
                // Handle tool processing, if any
@@ -1727,13 +1788,31 @@ printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
                        AddHoveredToSelection();
                        update();       // needed??
 //                     GetHovered(hover);      // prolly needed
-                       std::vector<void *> hover2 = GetHovered();
+                       VPVector hover2 = GetHovered();
                        dragged = (Object *)hover2[0];
                        draggingObject = true;
-printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
+//printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
 
                        // Alert the pen widget
-                       emit ObjectSelected(dragged);
+// 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)
+                       {
+                               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())
@@ -1770,10 +1849,12 @@ printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged,
                        return;
                }
 
-               // Didn't hit any object and not using a tool, so do a selection rectangle
+               // 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));
+               select = GetSelection();
        }
        else if (event->button() == Qt::MiddleButton)
        {
@@ -1784,9 +1865,15 @@ printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged,
        }
 }
 
-
 void DrawingView::mouseMoveEvent(QMouseEvent * event)
 {
+       // It seems that wheelEvent() triggers this for some reason...
+       if (scrollWheelSeen)
+       {
+               scrollWheelSeen = false;
+               return;
+       }
+
        Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
        Global::selection.setBottomRight(QPointF(point.x, point.y));
        // Only needs to be done here, as mouse down is always preceded by movement
@@ -1806,7 +1893,7 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                delta.y = -delta.y;
                Global::origin -= delta;
 
-               UpdateGridBackground();
+//             UpdateGridBackground();
                update();
                oldPoint = point;
                return;
@@ -1817,14 +1904,23 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
        if (Global::selectionInProgress)
        {
                CheckObjectBounds();
+
+               // Make sure previously selected objects stay selected (CTRL held)
+               for(VPVectorIter i=select.begin(); i!=select.end(); i++)
+               {
+                       // Make sure *not* to select items on hidden layers
+                       if (Global::layerHidden[((Object *)(*i))->layer] == false)
+                               ((Object *)(*i))->selected = true;
+               }
+
                update();
                return;
        }
 
        // Do object hit testing...
        bool needUpdate = HitTestObjects(point);
-//     GetHovered(hover);
-       std::vector<void *> hover2 = GetHovered();
+       VPVector hover2 = GetHovered(true); // Exclude dimension objects and circle centers (probably need to add arc centers too) from hover (also dragged objects...)
+#if 0
 {
 if (needUpdate)
 {
@@ -1834,11 +1930,12 @@ if (needUpdate)
                printf("                 (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]);
 }
 }
+#endif
 
        // Check for multi-hover...
-       if (numHovered > 1)
+       if (hover2.size() > 1)
        {
-//need to check for case where hover is over 2 circles and a 3rd's center...
+//need to check for case where hover is over 2 circles and a 3rd's center (no longer a problem, I think)...
                Object * obj1 = (Object *)hover2[0], * obj2 = (Object *)hover2[1];
 
                Geometry::Intersects(obj1, obj2);
@@ -1877,7 +1974,7 @@ if (needUpdate)
                        intersectionPoint = v1;
                }
        }
-       else if (numHovered == 1)
+       else if (hover2.size() == 1)
        {
                Object * obj = (Object *)hover2[0];
 
@@ -1885,7 +1982,6 @@ if (needUpdate)
                {
 /*
 Not sure that this is the best way to handle this, but it works(TM)...
-Except when lines are overlapping, then it doesn't work... !!! FIX !!!
 */
                        Point midpoint = Geometry::Midpoint((Line *)obj);
                        Vector v1 = Vector::Magnitude(midpoint, point);
@@ -1899,6 +1995,30 @@ Except when lines are overlapping, then it doesn't work... !!! FIX !!!
                                needUpdate = true;
                        }
                }
+               else if (obj->type == OTCircle)
+               {
+                       if ((draggingObject && (dragged->type == OTLine)) && (dragged->hitPoint[0] || dragged->hitPoint[1]))
+                       {
+                               Point p = (dragged->hitPoint[0] ? dragged->p[1] : dragged->p[0]);
+                               Geometry::FindTangents(obj, p);
+
+                               if (Global::numIntersectPoints > 0)
+                               {
+                                       hoveringIntersection = true;
+                                       intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+                               }
+                       }
+                       else if ((Global::tool == TTLine) && (Global::toolState == TSPoint2))
+                       {
+                               Geometry::FindTangents(obj, toolPoint[0]);
+
+                               if (Global::numIntersectPoints > 0)
+                               {
+                                       hoveringIntersection = true;
+                                       intersectionPoint = Geometry::NearestTo(point, Global::intersectPoint[0], Global::intersectPoint[1]);
+                               }
+                       }
+               }
        }
 
        // Handle object movement (left button down & over an object)
@@ -1942,7 +2062,6 @@ Except when lines are overlapping, then it doesn't work... !!! FIX !!!
                update();
 }
 
-
 void DrawingView::mouseReleaseEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
@@ -1962,62 +2081,61 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
                        return;
                }
 
-               if (Global::selectionInProgress)
+//             if (Global::selectionInProgress)
                        Global::selectionInProgress = false;
 
                informativeText.clear();
 // Should we be doing this automagically? Hmm...
                // Clear our vectors
-               select.clear();
-//             hover.clear();
+//             select.clear();
+////           hover.clear();
 
-               // Scoop 'em up
-               std::vector<void *>::iterator i;
-
-               for(i=document.objects.begin(); i!=document.objects.end(); i++)
-               {
-                       if (((Object *)(*i))->selected)
-                               select.push_back(*i);
-               }
+               // 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)
+               select = GetSelection();
 
                draggingObject = false;
        }
        else if (event->button() == Qt::MiddleButton)
        {
                scrollDrag = false;
-               setCursor(Qt::ArrowCursor);
+
+               if (Global::penStamp)
+                       setCursor(curMarker);
+               else if (Global::penDropper)
+                       setCursor(curDropper);
+               else
+                       setCursor(Qt::ArrowCursor);
+
+               // Need to convert this, since it's in Qt coordinates (for wheelEvent)
+               oldPoint = Painter::QtToCartesianCoords(oldPoint);
        }
 }
 
-
 void DrawingView::wheelEvent(QWheelEvent * event)
 {
-       double zoomFactor = 1.25;
-       QSize sizeWin = size();
-       Vector center(sizeWin.width() / 2.0, sizeWin.height() / 2.0);
-       center = Painter::QtToCartesianCoords(center);
+       double zoomFactor = 1.20;
+       scrollWheelSeen = true;
 
-       // This is not centering for some reason. Need to figure out why. :-/
-       if (event->delta() > 0)
+       if (event->angleDelta().y() < 0)
        {
-               Vector newOrigin = center - ((center - Global::origin) / zoomFactor);
-               Global::origin = newOrigin;
+               if (Global::zoom > 400.0)
+                       return;
+
                Global::zoom *= zoomFactor;
        }
        else
        {
-               Vector newOrigin = center + ((-center + Global::origin) * zoomFactor);
-               Global::origin = newOrigin;
+               if (Global::zoom < 0.125)
+                       return;
+
                Global::zoom /= zoomFactor;
        }
 
-//     Global::gridSpacing = gridPixels / Painter::zoom;
-//     UpdateGridBackground();
-       SetGridSize(Global::gridSpacing * Global::zoom);
-       update();
-//     zoomIndicator->setText(QString("Grid: %1\", BU: Inch").arg(Global::gridSpacing));
-}
+       Point np = Painter::QtToCartesianCoords(oldScrollPoint);
+       Global::origin += (oldPoint - np);
 
+       emit(NeedZoomUpdate());
+}
 
 void DrawingView::keyPressEvent(QKeyEvent * event)
 {
@@ -2032,6 +2150,8 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
        else if (event->key() == Qt::Key_Alt)
                altDown = true;
 
+       // If there's a change in any of the modifier key states, pass it on to
+       // the current tool's handler
        if ((oldShift != shiftDown) || (oldCtrl != ctrlDown))
        {
                if (Global::tool)
@@ -2072,7 +2192,6 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
        }
 }
 
-
 void DrawingView::keyReleaseEvent(QKeyEvent * event)
 {
        bool oldShift = shiftDown;
@@ -2097,11 +2216,16 @@ void DrawingView::keyReleaseEvent(QKeyEvent * event)
        if (oldAlt != altDown)
        {
                scrollDrag = false;
-               setCursor(Qt::ArrowCursor);
+
+               if (Global::penStamp)
+                       setCursor(curMarker);
+               else if (Global::penDropper)
+                       setCursor(curDropper);
+               else
+                       setCursor(Qt::ArrowCursor);
        }
 }
 
-
 //
 // This looks strange, but it's really quite simple: We want a point that's
 // more than half-way to the next grid point to snap there while conversely we
@@ -2121,7 +2245,6 @@ Point DrawingView::SnapPointToGrid(Point point)
        return point;
 }
 
-
 Point DrawingView::SnapPointToAngle(Point point)
 {
        // Snap to a single digit angle (using toolpoint #1 as the center)
@@ -2139,7 +2262,6 @@ Point DrawingView::SnapPointToAngle(Point point)
        return point;
 }
 
-
 Rect DrawingView::GetObjectExtents(Object * obj)
 {
        // Default to empty rect, if object checks below fail for some reason
@@ -2210,7 +2332,7 @@ Rect DrawingView::GetObjectExtents(Object * obj)
        case OTContainer:
        {
                Container * c = (Container *)obj;
-               std::vector<void *>::iterator i = c->objects.begin();
+               VPVectorIter i = c->objects.begin();
                rect = GetObjectExtents((Object *)*i);
                i++;
 
@@ -2225,10 +2347,9 @@ Rect DrawingView::GetObjectExtents(Object * obj)
        return rect;
 }
 
-
 void DrawingView::CheckObjectBounds(void)
 {
-       std::vector<void *>::iterator i;
+       VPVectorIter i;
 
        for(i=document.objects.begin(); i!=document.objects.end(); i++)
        {
@@ -2238,7 +2359,7 @@ void DrawingView::CheckObjectBounds(void)
                switch (obj->type)
                {
                case OTLine:
-               case OTDimension:
+               case OTDimension: // N.B.: We don't check this properly...
                {
                        Line * l = (Line *)obj;
 
@@ -2352,10 +2473,9 @@ void DrawingView::CheckObjectBounds(void)
        }
 }
 
-
 bool DrawingView::HitTestObjects(Point point)
 {
-       std::vector<void *>::iterator i;
+       VPVectorIter i;
        numHovered = 0;
        bool needUpdate = false;
        hoverPointValid = false;
@@ -2382,7 +2502,6 @@ bool DrawingView::HitTestObjects(Point point)
        return needUpdate;
 }
 
-
 bool DrawingView::HitTest(Object * obj, Point point)
 {
        bool needUpdate = false;
@@ -2514,8 +2633,13 @@ bool DrawingView::HitTest(Object * obj, Point point)
                Vector orthogonal = Vector::Normal(d->lp[0], d->lp[1]);
                // Get our line parallel to our points
                float scaledThickness = Global::scale * obj->thickness;
+#if 1
+               Point p1 = d->lp[0] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+               Point p2 = d->lp[1] + (orthogonal * (d->offset + (10.0 * scaledThickness)));
+#else
                Point p1 = d->lp[0] + (orthogonal * (10.0 + d->offset) * scaledThickness);
                Point p2 = d->lp[1] + (orthogonal * (10.0 + d->offset) * scaledThickness);
+#endif
                Point p3(p1, point);
 
                Vector v1(d->p[0], point);
@@ -2592,16 +2716,15 @@ still need to compare old state to new state, and set things up based upon that.
 likely we can just rely on the object itself and steal its state like we have in the commented out portion below; can prolly rewrite the HitTest() portion to be one line: needUpdate = HitTest(cObj, point);
 Well, you could if there was only one object in the Container.  But since there isn't, we have to keep the if HitTest() == true then needUpdate = true bit.  Because otherwise, a false result anywhere will kill the needed update elsewhere.
 */
-
                Container * c = (Container *)obj;
                c->hitObject = false;
                c->hovered = false;
                c->clicked = NULL;
 
-               std::vector<void *> flat = Flatten(c);
+               VPVector flat = Flatten(c);
 
 //printf("HitTest::OTContainer (size=%li)\n", flat.size());
-               for(std::vector<void *>::iterator i=flat.begin(); i!=flat.end(); i++)
+               for(VPVectorIter i=flat.begin(); i!=flat.end(); i++)
                {
                        Object * cObj = (Object *)(*i);
 
@@ -2643,6 +2766,13 @@ Well, you could if there was only one object in the Container.  But since there
                                c->clicked = cObj;
                        }//*/
 
+                       if (cObj->hitPoint[2] == true)
+                       {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
+                               c->hitPoint[2] = true;
+                               c->clicked = cObj;
+                       }//*/
+
                        if (cObj->hovered == true)
                                c->hovered = true;//*/
                }
@@ -2657,7 +2787,6 @@ Well, you could if there was only one object in the Container.  But since there
        return needUpdate;
 }
 
-
 bool DrawingView::HandleObjectClicked(void)
 {
        if (dragged->type == OTDimension)
@@ -2701,7 +2830,6 @@ bool DrawingView::HandleObjectClicked(void)
        return false;
 }
 
-
 void DrawingView::HandleObjectMovement(Point point)
 {
        Point delta = point - oldPoint;
@@ -2834,8 +2962,24 @@ void DrawingView::HandleObjectMovement(Point point)
                        obj->p[1] = point;
                else if (obj->hitObject)
                {
-                       obj->p[0] += delta;
-                       obj->p[1] += delta;
+                       // Move measurement lines in/out
+                       if (shiftDown)
+                       {
+                               Dimension * d = (Dimension *)obj;
+                               double dist = Geometry::DistanceToLineFromPoint(d->lp[0], d->lp[1], point);
+                               float scaledThickness = Global::scale * obj->thickness;
+                               // Looks like offset is 0 to +MAX, but line is at 10.0.  So
+                               // anything less than 10.0 should set the offset to 0.
+                               d->offset = 0;
+
+                               if (dist > (10.0 * scaledThickness))
+                                       d->offset = dist - (10.0 * scaledThickness);
+                       }
+                       else
+                       {
+                               obj->p[0] += delta;
+                               obj->p[1] += delta;
+                       }
                }
 
                break;
@@ -2861,7 +3005,6 @@ The idea is to make it so whichever point on the object in question is being dra
        }
 }
 
-
 void DrawingView::AddDimensionTo(void * o)
 {
        Object * obj = (Object *)o;
@@ -2881,4 +3024,3 @@ void DrawingView::AddDimensionTo(void * o)
                break;
        }
 }
-