]> Shamusworld >> Repos - architektonas/blobdiff - src/drawingview.cpp
Changes to make containers behave like a first-class object.
[architektonas] / src / drawingview.cpp
index f50fca562d11ce438a51c61d70ef16e689ba92e1..60f941e94c37a3e63d738d15369b7b69c8cd1bfe 100644 (file)
@@ -1,3 +1,4 @@
+//
 // drawingview.cpp
 //
 // Part of the Architektonas Project
 //
 // - Redo rendering code to *not* use Qt's transform functions, as they are tied
 //   to a left-handed system and we need a right-handed one. [DONE]
+// - Fixed length tool doesn't work on lines [DONE]
 //
 // STILL TO BE DONE:
 //
 // - Lots of stuff
 // - Layer locking (hiding works)
+// - Fixed angle tool doesn't work on lines
+// - Make it so "dirty" flag reflects drawing state
 //
 
 // Uncomment this for debugging...
@@ -48,50 +52,27 @@ DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
        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),
-       dragged(NULL), draggingObject(false), angleSnap(false)
+       gridPixels(0), collided(false), scrollDrag(false), hoverPointValid(false),
+       hoveringIntersection(false), dragged(NULL), draggingObject(false),
+       angleSnap(false), dirty(false)
 {
 //wtf? doesn't work except in c++11??? document = { 0 };
        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);
+
+       Line * line = new Line(Vector(5, 5), Vector(50, 40), 2.0, 0xFF7F00, LSDash);
        document.Add(line);
-       document.Add(new Line(Vector(50, 40), Vector(10, 83), &document));
-       document.Add(new Line(Vector(10, 83), Vector(17, 2), &document));
-       document.Add(new Circle(Vector(100, 100), 36, &document));
-       document.Add(new Circle(Vector(50, 150), 49, &document));
-       document.Add(new Arc(Vector(300, 300), 32, PI / 4.0, PI * 1.3, &document)),
-       document.Add(new Arc(Vector(200, 200), 60, PI / 2.0, PI * 1.5, &document));
-#if 1
-       Dimension * dimension = new Dimension(Vector(0, 0), Vector(0, 0), DTLinear, &document);
-       line->SetDimensionOnLine(dimension);
-       document.Add(dimension);
-#else
-       // Alternate way to do the above...
-       line->SetDimensionOnLine();
-#endif
-#else
-       Line * line = new Line;//(Vector(5, 5), Vector(50, 40), &document);
-       line->p[0] = Vector(5, 5);
-       line->p[1] = Vector(50, 40);
-       line->type = OTLine;
-       line->thickness = 2.0;
-       line->style = LSDash;
-       line->color = 0xFF7F00;
-       line->layer = 0;
-       document.objects.push_back(line);
-       document.objects.push_back(new Line(Vector(50, 40), Vector(10, 83)));
-       document.objects.push_back(new Line(Vector(10, 83), Vector(17, 2)));
-       document.objects.push_back(new Circle(Vector(100, 100), 36));
-       document.objects.push_back(new Circle(Vector(50, 150), 49));
-       document.objects.push_back(new Arc(Vector(300, 300), 32, TAU / 8.0, TAU * 0.65)),
-       document.objects.push_back(new Arc(Vector(200, 200), 60, TAU / 4.0, TAU * 0.75));
-       document.objects.push_back(new Dimension(Vector(50, 40), Vector(5, 5)));
-       document.objects.push_back(new Text(Vector(10, 83), "Here is some awesome text!"));
-#endif
+       document.Add(new Line(Vector(50, 40), Vector(10, 83)));
+       document.Add(new Line(Vector(10, 83), Vector(17, 2)));
+       document.Add(new Circle(Vector(100, 100), 36));
+       document.Add(new Circle(Vector(50, 150), 49));
+       document.Add(new Arc(Vector(300, 300), 32, TAU / 8.0, TAU * 0.65)),
+       document.Add(new Arc(Vector(200, 200), 60, TAU / 4.0, TAU * 0.75));
+       document.Add(new Text(Vector(10, 83), "Here is some awesome text!"));
+
+       AddDimensionTo(line);
 
 /*
 Here we set the grid size in pixels--12 in this case. Initially, we have our
@@ -365,6 +346,18 @@ QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
 }
 
 
+void DrawingView::focusOutEvent(QFocusEvent * /*event*/)
+{
+//     printf("DrawingView::focusOutEvent()...\n");
+       // Make sure all modkeys being held are marked as released when the app
+       // loses focus (N.B.: This only works because the app sets the focus policy
+       // of this object to something other than Qt::NoFocus)
+       shiftDown = ctrlDown = altDown = false;
+       scrollDrag = false;
+       setCursor(Qt::ArrowCursor);
+}
+
+
 void DrawingView::paintEvent(QPaintEvent * /*event*/)
 {
        QPainter qtPainter(this);
@@ -406,6 +399,9 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
        if (hoveringIntersection)
                painter.DrawHandle(intersectionPoint);
 
+       if (hoverPointValid)
+               painter.DrawHandle(hoverPoint);
+
        if (!informativeText.isEmpty())
                painter.DrawInformativeText(informativeText);
 }
@@ -414,6 +410,12 @@ void DrawingView::paintEvent(QPaintEvent * /*event*/)
 //
 // Renders objects in the passed in vector
 //
+/*
+N.B.: Since we have "hoverPointValid" drawing regular object handles above,
+      we can probably do away with a lot of them that are being done down below.
+      !!! 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*/)
 {
        std::vector<void *>::iterator i;
@@ -451,7 +453,11 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                        if (obj->hitPoint[1])
                                painter->DrawHandle(obj->p[1]);
 
+                       if (obj->hitObject)
+                               painter->DrawSmallHandle(Geometry::Midpoint((Line *)obj));
+
                        break;
+
                case OTCircle:
                        painter->SetBrush(QBrush(Qt::NoBrush));
                        painter->DrawEllipse(obj->p[0], obj->radius[0], obj->radius[0]);
@@ -460,6 +466,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                                painter->DrawHandle(obj->p[0]);
 
                        break;
+
                case OTArc:
                        painter->DrawArc(obj->p[0], obj->radius[0], obj->angle[0], obj->angle[1]);
 
@@ -473,6 +480,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                                painter->DrawHandle(obj->p[0] + (Vector(cos(obj->angle[0] + obj->angle[1]), sin(obj->angle[0] + obj->angle[1])) * obj->radius[0]));
 
                        break;
+
                case OTDimension:
                {
                        Dimension * d = (Dimension *)obj;
@@ -640,6 +648,7 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
 
                        break;
                }
+
                case OTText:
                {
                        Text * t = (Text *)obj;
@@ -653,30 +662,36 @@ void DrawingView::RenderObjects(Painter * painter, std::vector<void *> & v, int
                        painter->DrawTextObject(t->p[0], t->s.c_str(), scaledThickness, t->angle[0]);
                        break;
                }
+
                case OTSpline:
                {
                        break;
                }
+
                case OTPolygon:
                {
                        break;
                }
+
                case OTContainer:
                {
                        // Containers require recursive rendering...
                        Container * c = (Container *)obj;
-                       RenderObjects(painter, (*c).objects, 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());
                        // Containers also have special indicators showing they are selected
                        if (c->selected || c->hitObject)
                        {
-                               Rect r = GetObjectExtents(obj);
-                               painter->DrawRectCorners(r);
+//                             Rect r = GetObjectExtents(obj);
+//                             painter->DrawRectCorners(r);
+                               painter->DrawRectCorners(Rect(c->p[0], c->p[1]));
                        }
 
                        break;
                }
+
                default:
                        break;
                }
@@ -709,6 +724,7 @@ void DrawingView::GetSelection(std::vector<void *> & v)
 }
 
 
+#if 0
 void DrawingView::GetHovered(std::vector<void *> & v)
 {
        v.clear();
@@ -723,6 +739,25 @@ void DrawingView::GetHovered(std::vector<void *> & v)
 //             }
        }
 }
+#endif
+
+
+std::vector<void *> DrawingView::GetHovered(void)
+{
+       std::vector<void *> v;
+       std::vector<void *>::iterator i;
+
+       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*/)
@@ -749,6 +784,12 @@ void DrawingView::ToolHandler(int mode, Point p)
                MirrorHandler(mode, p);
        else if (Global::tool == TTDimension)
                DimensionHandler(mode, p);
+       else if (Global::tool == TTTriangulate)
+               TriangulateHandler(mode, p);
+       else if (Global::tool == TTTrim)
+               TrimHandler(mode, p);
+       else if (Global::tool == TTParallel)
+               ParallelHandler(mode, p);
 }
 
 
@@ -923,6 +964,7 @@ void DrawingView::LineHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseMove:
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
@@ -930,6 +972,7 @@ void DrawingView::LineHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSNone)
                {
@@ -965,6 +1008,7 @@ void DrawingView::CircleHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseMove:
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
@@ -972,6 +1016,7 @@ void DrawingView::CircleHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSNone)
                {
@@ -1013,6 +1058,7 @@ void DrawingView::ArcHandler(int mode, Point p)
                        toolPoint[3] = p;
 
                break;
+
        case ToolMouseMove:
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
@@ -1030,6 +1076,7 @@ void DrawingView::ArcHandler(int mode, Point p)
                }
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSNone)
                {
@@ -1082,7 +1129,8 @@ void DrawingView::RotateHandler(int mode, Point p)
                if (Global::toolState == TSNone)
                {
                        toolPoint[0] = p;
-                       SavePointsFrom(select, toolScratch);
+//                     SavePointsFrom(select, toolScratch);
+                       CopyObjects(select, toolScratch2);
                        Global::toolState = TSPoint1;
                }
                else if (Global::toolState == TSPoint1)
@@ -1091,6 +1139,7 @@ void DrawingView::RotateHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseMove:
                if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone))
                        toolPoint[0] = p;
@@ -1104,28 +1153,69 @@ void DrawingView::RotateHandler(int mode, Point p)
                        angleSnap = true;
                        double angle = Vector(toolPoint[0], toolPoint[1]).Angle();
                        std::vector<void *>::iterator j = select.begin();
-                       std::vector<Object>::iterator i = toolScratch.begin();
+//                     std::vector<Object>::iterator i = toolScratch.begin();
+                       std::vector<void *>::iterator i = toolScratch2.begin();
 
-                       for(; i!=toolScratch.end(); i++, j++)
+//                     for(; i!=toolScratch.end(); i++, j++)
+                       for(; i!=toolScratch2.end(); i++, j++)
                        {
-                               Object obj = *i;
-                               Point p1 = Geometry::RotatePointAroundPoint(obj.p[0], toolPoint[0], angle);
-                               Point p2 = Geometry::RotatePointAroundPoint(obj.p[1], toolPoint[0], angle);
-                               Object * obj2 = (Object *)(*j);
-                               obj2->p[0] = p1;
-                               obj2->p[1] = p2;
+//                             Object objT = *i;
+//                             Point p1 = Geometry::RotatePointAroundPoint(objT.p[0], toolPoint[0], angle);
+//                             Point p2 = Geometry::RotatePointAroundPoint(objT.p[1], toolPoint[0], angle);
+                               Object * objT = (Object *)(*i);
+                               Object * objS = (Object *)(*j);
 
-                               if (obj.type == OTArc)
+                               Point p1 = Geometry::RotatePointAroundPoint(objT->p[0], toolPoint[0], angle);
+                               Point p2 = Geometry::RotatePointAroundPoint(objT->p[1], toolPoint[0], angle);
+
+                               objS->p[0] = p1;
+                               objS->p[1] = p2;
+
+//                             if (objT.type == OTArc || objT.type == OTText)
+                               if (objT->type == OTArc || objT->type == OTText)
                                {
-                                       obj2->angle[0] = obj.angle[0] + angle;
+//                                     objS->angle[0] = objT.angle[0] + angle;
+                                       objS->angle[0] = objT->angle[0] + angle;
 
-                                       if (obj2->angle[0] > TAU)
-                                               obj2->angle[0] -= TAU;
+                                       if (objS->angle[0] > TAU)
+                                               objS->angle[0] -= TAU;
+                               }
+//                             else if (objT.type == OTContainer)
+                               else if (objT->type == OTContainer)
+                               {
+                                       // OK, this doesn't work because toolScratch only has points and nothing in the containers... [ACTUALLY... toolScratch is is a vector of type Object... which DOESN'T have an objects vector in it...]
+//                                     Container * c = (Container *)&objT;
+                                       Container * c = (Container *)objT;
+                                       Container * c2 = (Container *)objS;
+                                       std::vector<void *>::iterator 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++)
+                                       {
+                                               Object * obj3 = (Object *)(*k);
+                                               Object * obj4 = (Object *)(*l);
+
+                                               p1 = Geometry::RotatePointAroundPoint(obj4->p[0], toolPoint[0], angle);
+                                               p2 = Geometry::RotatePointAroundPoint(obj4->p[1], toolPoint[0], angle);
+
+                                               obj3->p[0] = p1;
+                                               obj3->p[1] = p2;
+//                                             obj3->angle[0] = objT.angle[0] + angle;
+                                               obj3->angle[0] = obj4->angle[0] + angle;
+
+                                               if (obj3->angle[0] > TAU)
+                                                       obj3->angle[0] -= TAU;
+                                       }
+
+                                       Rect r = GetObjectExtents(objS);
+                                       c2->p[0] = r.TopLeft();
+                                       c2->p[1] = r.BottomRight();
                                }
                        }
                }
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSPoint1)
                {
@@ -1149,30 +1239,39 @@ void DrawingView::RotateHandler(int mode, Point p)
                                CopyObjects(select, temp);
                                ClearSelected(temp);
                                AddObjectsTo(document.objects, temp);
-                               RestorePointsTo(select, toolScratch);
+//                             RestorePointsTo(select, toolScratch);
+                               RestorePointsTo(select, toolScratch2);
                                return;
                        }
 
                        toolPoint[0] = p;
                        Global::toolState = TSPoint1;
-                       SavePointsFrom(select, toolScratch);
+//                     SavePointsFrom(select, toolScratch);
+                       DeleteContents(toolScratch2);
+                       CopyObjects(select, toolScratch2);
                }
 
                break;
+
        case ToolKeyDown:
                // Reset the selection if shift held down...
                if (shiftDown)
-                       RestorePointsTo(select, toolScratch);
+//                     RestorePointsTo(select, toolScratch);
+                       RestorePointsTo(select, toolScratch2);
 
                break;
+
        case ToolKeyUp:
                // Reset selection when key is let up
                if (!shiftDown)
                        RotateHandler(ToolMouseMove, toolPoint[1]);
 
                break;
+
        case ToolCleanup:
-               RestorePointsTo(select, toolScratch);
+//             RestorePointsTo(select, toolScratch);
+               RestorePointsTo(select, toolScratch2);
+               DeleteContents(toolScratch2);
        }
 }
 
@@ -1194,6 +1293,7 @@ void DrawingView::MirrorHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseMove:
                if ((Global::toolState == TSPoint1) || (Global::toolState == TSNone))
                        toolPoint[0] = p;
@@ -1218,6 +1318,11 @@ void DrawingView::MirrorHandler(int mode, Point p)
                                obj2->p[0] = p1;
                                obj2->p[1] = p2;
 
+/*
+N.B.: When mirroring an arc thru a horizontal axis, this causes the arc to have
+      a negative start angle which makes it impossible to interact with.
+      !!! FIX !!!
+*/
                                if (obj.type == OTArc)
                                {
                                        // This is 2*mirror angle - obj angle - obj span
@@ -1230,6 +1335,7 @@ void DrawingView::MirrorHandler(int mode, Point p)
                }
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSPoint1)
                {
@@ -1263,18 +1369,21 @@ void DrawingView::MirrorHandler(int mode, Point p)
                }
 
                break;
+
        case ToolKeyDown:
                // Reset the selection if shift held down...
                if (shiftDown)
                        RestorePointsTo(select, toolScratch);
 
                break;
+
        case ToolKeyUp:
                // Reset selection when key is let up
                if (!shiftDown)
                        MirrorHandler(ToolMouseMove, toolPoint[1]);
 
                break;
+
        case ToolCleanup:
                RestorePointsTo(select, toolScratch);
        }
@@ -1292,6 +1401,7 @@ void DrawingView::DimensionHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseMove:
                if (Global::toolState == TSNone)
                        toolPoint[0] = p;
@@ -1299,6 +1409,7 @@ void DrawingView::DimensionHandler(int mode, Point p)
                        toolPoint[1] = p;
 
                break;
+
        case ToolMouseUp:
                if (Global::toolState == TSNone)
                {
@@ -1323,10 +1434,265 @@ void DrawingView::DimensionHandler(int mode, Point p)
 }
 
 
+void DrawingView::TriangulateHandler(int mode, Point/*p*/)
+{
+       switch (mode)
+       {
+       case ToolMouseDown:
+       {
+               // Skip if nothing hovered...
+               if (numHovered != 1)
+                       break;
+
+               std::vector<void *> hover = GetHovered();
+               Object * obj = (Object *)hover[0];
+
+               // Skip if it's not a line...
+               if (obj->type != OTLine)
+                       break;
+
+               if (Global::toolState == TSNone)
+                       toolObj[0] = obj;
+               else if (Global::toolState == TSPoint2)
+                       toolObj[1] = obj;
+               else
+                       toolObj[2] = obj;
+
+               break;
+       }
+#if 0
+       case ToolMouseMove:
+               if (Global::toolState == TSNone)
+                       toolPoint[0] = 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;
+#endif
+       case ToolMouseUp:
+               if (Global::toolState == TSNone)
+               {
+                       Global::toolState = TSPoint2;
+               }
+               else if (Global::toolState == TSPoint2)
+               {
+/*                     if (shiftDown)
+                       {
+                               // Key override is telling us to start arc at new center, not
+                               // continue the current one.
+                               toolPoint[0] = toolPoint[1];
+                               return;
+                       }*/
+
+                       Global::toolState = TSPoint3;
+               }
+               else
+               {
+                       double len2 = Vector::Magnitude(toolObj[1]->p[0], toolObj[1]->p[1]);
+                       double len3 = Vector::Magnitude(toolObj[2]->p[0], toolObj[2]->p[1]);
+
+                       Circle c1(toolObj[0]->p[0], len2);
+                       Circle c2(toolObj[0]->p[1], len3);
+
+                       Geometry::CheckCircleToCircleIntersection((Object *)&c1, (Object *)&c2);
+
+                       // Only move lines if the triangle formed by them is not degenerate
+                       if (Global::numIntersectPoints > 0)
+                       {
+                               toolObj[1]->p[0] = toolObj[0]->p[0];
+                               toolObj[1]->p[1] = Global::intersectPoint[0];
+
+                               toolObj[2]->p[0] = Global::intersectPoint[0];
+                               toolObj[2]->p[1] = toolObj[0]->p[1];
+                       }
+
+                       Global::toolState = TSNone;
+               }
+       }
+}
+
+
+void DrawingView::TrimHandler(int mode, Point p)
+{
+/*
+n.b.: this code is lifted straight out of the old oo code.  needs to be updated.
+*/
+       switch (mode)
+       {
+       case ToolMouseDown:
+       {
+#if 0
+               Object * toTrim = doc->lastObjectHovered;
+
+               if (toTrim == NULL)
+                       return;
+
+               Vector v(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint);
+
+               // Check to see which case we have...
+               // We're trimming point #1...
+               if (t == 0)
+               {
+                       ((Line *)toTrim)->position = ((Line *)toTrim)->position + (v * u);
+               }
+               else if (u == 1.0)
+               {
+                       ((Line *)toTrim)->endpoint = ((Line *)toTrim)->position + (v * t);
+               }
+               else
+               {
+                       Point p1 = ((Line *)toTrim)->position + (v * t);
+                       Point p2 = ((Line *)toTrim)->position + (v * u);
+                       Point p3 = ((Line *)toTrim)->endpoint;
+                       ((Line *)toTrim)->endpoint = p1;
+                       Line * line = new Line(p2, p3);
+                       emit ObjectReady(line);
+               }
+
+               doc->lastObjectHovered = NULL;
+#endif
+       }
+               break;
+
+       case ToolMouseMove:
+       {
+#if 0
+               Object * toTrim = doc->lastObjectHovered;
+               t = 0, u = 1.0;
+
+               if (toTrim == NULL)
+                       return;
+
+               if (toTrim->type != OTLine)
+                       return;
+
+               double pointHoveredT = Geometry::ParameterOfLineAndPoint(((Line *)toTrim)->position, ((Line *)toTrim)->endpoint, point);
+
+               std::vector<Object *>::iterator i;
+
+               for(i=doc->objects.begin(); i!=doc->objects.end(); i++)
+               {
+                       // Can't trim against yourself... :-P
+                       if (*i == toTrim)
+                               continue;
+
+                       Object * trimAgainst = *i;
+                       double t1;//, u1;
+
+                       if ((toTrim->type != OTLine) || (trimAgainst->type != OTLine))
+                               continue;
+
+                       int intersects = Geometry::Intersects((Line *)toTrim, (Line *)trimAgainst, &t1);//, &u1);
+
+                       if (intersects)
+                       {
+                               // Now what? We don't know which side to trim!
+                               // ... now we do, we know which side of the Line we're on!
+                               if ((t1 > t) && (t1 < pointHoveredT))
+                                       t = t1;
+
+                               if ((t1 < u) && (t1 > pointHoveredT))
+                                       u = t1;
+                       }
+               }
+#endif
+               // Bail out if nothing hovered...
+               if (numHovered != 1)
+               {
+                       toolObj[0] = NULL;
+                       return;
+               }
+
+               std::vector<void *> hover = GetHovered();
+               Object * obj = (Object *)hover[0];
+
+               // Skip if it's not a line...
+               if (obj->type != OTLine)
+               {
+                       toolObj[0] = NULL;
+                       return;
+               }
+
+               toolObj[0] = obj;
+               double hoveredParam = Geometry::ParameterOfLineAndPoint(obj->p[0], obj->p[1], p);
+
+               // 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;
+               for(i=document.objects.begin(); i!=document.objects.end(); i++)
+               {
+                       obj = (Object *)(*i);
+
+                       if (obj == toolObj[0])
+                               continue;
+                       else if (obj->type != OTLine)
+                               continue;
+
+                       Geometry::CheckLineToLineIntersection(toolObj[0], obj);
+
+                       if (Global::numIntersectParams > 0)
+                       {
+                               // Mark the line segment somehow (the side the mouse is on) so that it can be drawn & trimmed when we hit ToolMouseDown.
+                       }
+               }
+       }
+               break;
+
+       case ToolMouseUp:
+               break;
+
+       case ToolKeyDown:
+               break;
+
+       case ToolKeyUp:
+               break;
+
+       case ToolCleanup:
+               break;
+       }
+}
+
+
+void DrawingView::ParallelHandler(int mode, Point /*p*/)
+{
+       switch (mode)
+       {
+       case ToolMouseDown:
+               break;
+
+       case ToolMouseMove:
+               break;
+
+       case ToolMouseUp:
+               break;
+
+       case ToolKeyDown:
+               break;
+
+       case ToolKeyUp:
+               break;
+
+       case ToolCleanup:
+               break;
+       }
+}
+
+
 void DrawingView::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::LeftButton)
        {
+printf("mousePressEvent::Qt::LeftButton numHovered=%li\n", numHovered);
                Vector point = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
                // Handle tool processing, if any
@@ -1334,6 +1700,8 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                {
                        if (hoveringIntersection)
                                point = intersectionPoint;
+                       else if (hoverPointValid)
+                               point = hoverPoint;
                        else if (Global::snapToGrid)
                                point = SnapPointToGrid(point);
 
@@ -1358,12 +1726,14 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                {
                        AddHoveredToSelection();
                        update();       // needed??
-                       GetHovered(hover);      // prolly needed
-                       dragged = (Object *)hover[0];
+//                     GetHovered(hover);      // prolly needed
+                       std::vector<void *> hover2 = GetHovered();
+                       dragged = (Object *)hover2[0];
                        draggingObject = true;
+printf("mousePressEvent::numHovered > 0 (hover2[0]=$%llx, type=%s)\n", dragged, objName[dragged->type]);
 
                        // Alert the pen widget
-                       emit(ObjectSelected(dragged));
+                       emit ObjectSelected(dragged);
 
                        // See if anything is using just a straight click on a handle
                        if (HandleObjectClicked())
@@ -1377,9 +1747,26 @@ void DrawingView::mousePressEvent(QMouseEvent * event)
                        // We do it *after*... why? (doesn't seem to confer any advantage...)
                        if (hoveringIntersection)
                                oldPoint = intersectionPoint;
+                       else if (hoverPointValid)
+                               oldPoint = hoverPoint;
                        else if (Global::snapToGrid)
                                oldPoint = SnapPointToGrid(point);
 
+                       // Needed for fixed length handling
+                       if (Global::fixedLength)
+                       {
+                               if (dragged->type == OTLine)
+                               {
+                                       dragged->length = Vector::Magnitude(dragged->p[0], dragged->p[1]);
+                               }
+                       }
+
+                       if (dragged->type == OTCircle)
+                       {
+                               // Save for informative text, uh, er, informing
+                               dragged->length = dragged->radius[0];
+                       }
+
                        return;
                }
 
@@ -1436,13 +1823,23 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
 
        // Do object hit testing...
        bool needUpdate = HitTestObjects(point);
-       GetHovered(hover);
+//     GetHovered(hover);
+       std::vector<void *> hover2 = GetHovered();
+{
+if (needUpdate)
+{
+       printf("mouseMoveEvent:: numHovered=%li, hover2.size()=%li\n", numHovered, hover2.size());
+
+       if (hover2.size() > 0)
+               printf("                 (hover2[0]=$%llX, type=%s)\n", hover2[0], objName[((Object *)hover2[0])->type]);
+}
+}
 
        // Check for multi-hover...
        if (numHovered > 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];
+               Object * obj1 = (Object *)hover2[0], * obj2 = (Object *)hover2[1];
 
                Geometry::Intersects(obj1, obj2);
                int numIntersecting = Global::numIntersectParams;
@@ -1480,6 +1877,29 @@ void DrawingView::mouseMoveEvent(QMouseEvent * event)
                        intersectionPoint = v1;
                }
        }
+       else if (numHovered == 1)
+       {
+               Object * obj = (Object *)hover2[0];
+
+               if (obj->type == OTLine)
+               {
+/*
+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);
+
+                       if ((v1.Magnitude() * Global::zoom) < 8.0)
+                       {
+                               QString text = tr("Midpoint <%1, %2>");
+                               informativeText = text.arg(midpoint.x).arg(midpoint.y);
+                               hoverPointValid = true;
+                               hoverPoint = midpoint;
+                               needUpdate = true;
+                       }
+               }
+       }
 
        // Handle object movement (left button down & over an object)
        if ((event->buttons() & Qt::LeftButton) && draggingObject && !Global::tool)
@@ -1549,7 +1969,7 @@ void DrawingView::mouseReleaseEvent(QMouseEvent * event)
 // Should we be doing this automagically? Hmm...
                // Clear our vectors
                select.clear();
-               hover.clear();
+//             hover.clear();
 
                // Scoop 'em up
                std::vector<void *>::iterator i;
@@ -1624,7 +2044,6 @@ void DrawingView::keyPressEvent(QKeyEvent * event)
        {
                scrollDrag = true;
                setCursor(Qt::SizeAllCursor);
-//             oldPoint = Vector();
                oldPoint = oldScrollPoint;
        }
 
@@ -1869,7 +2288,8 @@ void DrawingView::CheckObjectBounds(void)
                        bounds = bounds.normalized();
 #endif
 
-                       // If the end of the arc is before the beginning, add 360 degrees to it
+                       // If the end of the arc is before the beginning, add 360 degrees
+                       // to it
                        if (end < start)
                                end += TAU;
 
@@ -1916,9 +2336,19 @@ void DrawingView::CheckObjectBounds(void)
                        break;
                }
 
-               default:
+               case OTContainer:
+               {
+                       Container * c = (Container *)obj;
+
+                       if (Global::selection.contains(c->p[0].x, c->p[0].y) && Global::selection.contains(c->p[1].x, c->p[1].y))
+                               c->selected = true;
+
                        break;
                }
+
+//             default:
+//                     break;
+               }
        }
 }
 
@@ -1938,14 +2368,14 @@ bool DrawingView::HitTestObjects(Point point)
                if (draggingObject && (obj == dragged))
                        continue;
 
-               if (HitTest(obj, point))
+               if (HitTest(obj, point) == true)
                        needUpdate = true;
 
                if (obj->hovered)
                {
                        numHovered++;
 //printf("MouseMove: OBJECT HOVERED (numHovered = %i)\n", numHovered);
-                       emit(ObjectHovered(obj));
+                       emit ObjectHovered(obj);
                }
        }
 
@@ -2121,7 +2551,6 @@ bool DrawingView::HitTest(Object * obj, Point point)
                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))
@@ -2152,24 +2581,70 @@ bool DrawingView::HitTest(Object * obj, Point point)
 
        case OTContainer:
        {
-               // Containers must be recursively tested...
+               // Containers must be recursively tested...  Or do they???
+/*
+So the idea here is to flatten the structure, *then* test the objects within.  Flattening includes the Containers as well; we can do this because it's pointers all the way down.
+*/
+//             bool oldHitObj = c->hitObject, oldHovered = c->hovered;
+//             Object * oldClicked = c->clicked;
+/*
+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;
-               std::vector<void *>::iterator i;
+               c->clicked = NULL;
 
-               for(i=c->objects.begin(); i!=c->objects.end(); i++)
+               std::vector<void *> flat = Flatten(c);
+
+//printf("HitTest::OTContainer (size=%li)\n", flat.size());
+               for(std::vector<void *>::iterator i=flat.begin(); i!=flat.end(); i++)
                {
-                       Object * cObj = (Object *)*i;
+                       Object * cObj = (Object *)(*i);
+
+                       // Skip the flattened containers (if any)...
+                       if (cObj->type == OTContainer)
+                               continue;
 
-                       if (HitTest(cObj, point))
+                       // We do it this way instead of needUpdate = HitTest() because we
+                       // are checking more than one object, and that way of doing will
+                       // not return consistent results.
+                       if (HitTest(cObj, point) == true)
+//                     {
+//printf("HitTest::OTContainer, subobj ($%llX) hit!\n", cObj);
                                needUpdate = true;
+//                             c->hitObject = true;
+//                             c->clicked = cObj;
+//                             c->hovered = true;
+//                     }
 
+                       // Same reasons for doing it this way here apply.
                        if (cObj->hitObject == true)
+                       {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
                                c->hitObject = true;
+                               c->clicked = cObj;
+                       }//*/
+
+                       if (cObj->hitPoint[0] == true)
+                       {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
+                               c->hitPoint[0] = true;
+                               c->clicked = cObj;
+                       }//*/
+
+                       if (cObj->hitPoint[1] == true)
+                       {
+//printf("HitTest::cObj->hitObject == true! ($%llX)\n", cObj);
+                               c->hitPoint[1] = true;
+                               c->clicked = cObj;
+                       }//*/
 
                        if (cObj->hovered == true)
-                               c->hovered = true;
+                               c->hovered = true;//*/
                }
 
                break;
@@ -2240,9 +2715,27 @@ void DrawingView::HandleObjectMovement(Point point)
        {
        case OTLine:
                if (obj->hitPoint[0])
+               {
+                       if (Global::fixedLength)
+                       {
+                               Vector line = point - obj->p[1];
+                               Vector unit = line.Unit();
+                               point = obj->p[1] + (unit * obj->length);
+                       }
+
                        obj->p[0] = point;
+               }
                else if (obj->hitPoint[1])
+               {
+                       if (Global::fixedLength)
+                       {
+                               Vector line = point - obj->p[0];
+                               Vector unit = line.Unit();
+                               point = obj->p[0] + (unit * obj->length);
+                       }
+
                        obj->p[1] = point;
+               }
                else if (obj->hitObject)
                {
                        obj->p[0] += delta;
@@ -2256,12 +2749,11 @@ void DrawingView::HandleObjectMovement(Point point)
                        obj->p[0] = point;
                else if (obj->hitObject)
                {
-//this doesn't work. we need to save this on mouse down for this to work correctly!
-//                     double oldRadius = obj->radius[0];
+                       double oldRadius = obj->length;
                        obj->radius[0] = Vector::Magnitude(obj->p[0], point);
 
-                       QString text = QObject::tr("Radius: %1");//\nScale: %2%");
-                       informativeText = text.arg(obj->radius[0], 0, 'd', 4);//.arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0);
+                       QString text = QObject::tr("Radius: %1\nScale: %2%");
+                       informativeText = text.arg(obj->radius[0], 0, 'd', 4).arg(obj->radius[0] / oldRadius * 100.0, 0, 'd', 0);
                }
 
                break;
@@ -2357,7 +2849,11 @@ void DrawingView::HandleObjectMovement(Point point)
        case OTContainer:
                // This is shitty, but works for now until I can code up something
                // nicer :-)
-               TranslateObject(obj, delta);
+/*
+The idea is to make it so whichever point on the object in question is being dragged becomes the snap point for the container; shouldn't be too difficult to figure out how to do this.
+*/
+//             TranslateObject(obj, delta);
+               TranslateContainer((Container *)obj, point, delta);
 
                break;
        default:
@@ -2365,3 +2861,24 @@ void DrawingView::HandleObjectMovement(Point point)
        }
 }
 
+
+void DrawingView::AddDimensionTo(void * o)
+{
+       Object * obj = (Object *)o;
+
+       switch (obj->type)
+       {
+       case OTLine:
+               document.Add(new Dimension(obj->p[0], obj->p[1]));
+               break;
+       case OTCircle:
+               break;
+       case OTEllipse:
+               break;
+       case OTArc:
+               break;
+       case OTSpline:
+               break;
+       }
+}
+