]> Shamusworld >> Repos - architektonas/commitdiff
Changes to make containers behave like a first-class object.
authorShamus Hammons <jlhamm@acm.org>
Thu, 23 Apr 2020 17:34:04 +0000 (12:34 -0500)
committerShamus Hammons <jlhamm@acm.org>
Thu, 23 Apr 2020 17:34:04 +0000 (12:34 -0500)
Also, added cut/copy/paste functionality, and ability to save layer
information with object data.  This change bumps the drawing version to
1.2; this required some infrastructure changes to the way layers are
represented and handled.  Also preliminary addition of Trim, Triangulate,
and Parallel tools, and support for snapping to line midpoints.

14 files changed:
src/applicationwindow.cpp
src/applicationwindow.h
src/drawingview.cpp
src/drawingview.h
src/fileio.cpp
src/fileio.h
src/global.cpp
src/global.h
src/layeritemwidget.cpp
src/layerwidget.cpp
src/layerwidget.h
src/structs.h
src/utils.cpp
src/utils.h

index 41e2f2c8a90176efa535fdcbce96d6fb9f13e030..7dd57aca22824c70f77ff62cb782808e47814569 100644 (file)
@@ -98,6 +98,7 @@ ApplicationWindow::ApplicationWindow():
        connect(lw, SIGNAL(LayerDeleted(int)), drawing, SLOT(DeleteCurrentLayer(int)));
        connect(lw, SIGNAL(LayerToggled()), drawing, SLOT(HandleLayerToggle()));
        connect(lw, SIGNAL(LayersSwapped(int, int)), drawing, SLOT(HandleLayerSwap(int, int)));
+       connect(this, SIGNAL(ReloadLayers()), lw, SLOT(Reload()));
 
        connect(drawing, SIGNAL(ObjectHovered(Object *)), ow, SLOT(ShowInfo(Object *)));
 }
@@ -113,9 +114,38 @@ void ApplicationWindow::closeEvent(QCloseEvent * event)
 
 void ApplicationWindow::FileNew(void)
 {
-       // Should warn the user if drawing hasn't been saved... !!! FIX !!!
+       // Warn the user if drawing has changed and hasn't been saved...
+       if (drawing->dirty)
+       {
+               QMessageBox msg;
+
+               msg.setText("The document has been modified.");
+               msg.setInformativeText("Do you want to save your changes?");
+               msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+               msg.setDefaultButton(QMessageBox::Save);
+               int response = msg.exec();
+
+               switch (response)
+               {
+               case QMessageBox::Save:
+                       // Save was clicked
+                       FileSave();
+                       break;
+               case QMessageBox::Discard:
+                       // Don't Save was clicked
+                       break;
+               case QMessageBox::Cancel:
+                       // Cancel was clicked
+                       return;
+//                     break;
+               }
+       }
+
+       FileIO::ResetLayerVectors();
+       emit ReloadLayers();
        DeleteContents(drawing->document.objects);
        drawing->document.objects.clear();
+       drawing->dirty = false;
        drawing->update();
        documentName.clear();
        setWindowTitle("Architektonas - Untitled");
@@ -161,9 +191,12 @@ void ApplicationWindow::FileOpen(void)
 //printf("FileOpen: container size = %li\n", container.objects.size());
        // Keep memory leaks from happening by getting rid of the old document
        DeleteContents(drawing->document.objects);
+       emit ReloadLayers();
        // We can do this because the vector is just a bunch of pointers to our
-       // Objects, and the Containers (non-empty) can be moved way with no problem.
+       // Objects, and the Containers (non-empty) can be moved this way with no
+       // problem.
        drawing->document = container;
+       drawing->dirty = false;
        drawing->update();
        documentName = filename;
        setWindowTitle(QString("Architektonas - %1").arg(documentName));
@@ -204,6 +237,7 @@ void ApplicationWindow::FileSave(void)
                return;
        }
 
+       drawing->dirty = false;
        setWindowTitle(QString("Architektonas - %1").arg(documentName));
        statusBar()->showMessage(tr("Drawing saved."));
 }
@@ -222,6 +256,16 @@ void ApplicationWindow::FileSaveAs(void)
 }
 
 
+void ApplicationWindow::contextMenuEvent(QContextMenuEvent * event)
+{
+       QMenu menu(this);
+       menu.addAction(mirrorAct);
+       menu.addAction(rotateAct);
+       menu.addAction(trimAct);
+       menu.exec(event->globalPos());
+}
+
+
 void ApplicationWindow::SnapToGridTool(void)
 {
        Global::snapToGrid = snapToGridAct->isChecked();
@@ -603,6 +647,11 @@ else
                ClearSelected(c->objects);
                c->selected = true;
                c->layer = Global::currentLayer;
+
+               Rect r = drawing->GetObjectExtents((Object *)c);
+               c->p[0] = r.TopLeft();
+               c->p[1] = r.BottomRight();
+
                drawing->select.clear();
                drawing->select.push_back(c);
                statusBar()->showMessage(QString(tr("Grouped %1 objects.")).arg(numSelected));
@@ -717,6 +766,9 @@ void ApplicationWindow::HandleGridSizeInBaseUnits(QString text)
 
 void ApplicationWindow::HandleDimensionSize(QString text)
 {
+/*
+This is the third input on the view toolbar; not sure what it was supposed to do...
+*/
        // Parse the text...
        bool ok;
        double value = text.toDouble(&ok);
@@ -729,6 +781,39 @@ void ApplicationWindow::HandleDimensionSize(QString text)
        drawing->update();
 }
 
+void ApplicationWindow::EditCopy(void)
+{
+       if (drawing->select.size() > 0)
+       {
+               DeleteContents(clipboard);
+               CopySelectedObjectsTo(clipboard, drawing->document.objects);
+       }
+}
+
+
+void ApplicationWindow::EditCut(void)
+{
+       if (drawing->select.size() > 0)
+       {
+               DeleteContents(clipboard);
+               MoveSelectedObjectsTo(clipboard, drawing->document.objects);
+               drawing->update();
+       }
+}
+
+
+void ApplicationWindow::EditPaste(void)
+{
+       if (clipboard.size() > 0)
+       {
+               // We want to maybe make it so that the pasted objects are being moved in a "mouse drag" state...
+               // This only moves the cut/copied from the clipboard to the drawing.
+//             AddObjectsTo(drawing->document.objects, clipboard);
+               CopyObjects(clipboard, drawing->document.objects);
+               drawing->update();
+       }
+}
+
 
 void ApplicationWindow::CreateActions(void)
 {
@@ -815,6 +900,14 @@ void ApplicationWindow::CreateActions(void)
        triangulateAct = CreateAction(tr("&Triangulate"), tr("Triangulate"), tr("Make triangles from selected lines, preserving their lengths."), QIcon(":/res/triangulate-tool.png"), QKeySequence("t,g"), true);
        connect(triangulateAct, SIGNAL(triggered()), this, SLOT(TriangulateTool()));
 
+       editCutAct = CreateAction(tr("&Cut Objects"), tr("Cut Objects"), tr("Cut objects from the drawing to the clipboard."), QIcon(":/res/editcut2.png"), QKeySequence(tr("Ctrl+x")));
+       connect(editCutAct, SIGNAL(triggered()), this, SLOT(EditCut()));
+
+       editCopyAct = CreateAction(tr("&Copy Objects"), tr("Copy Objects"), tr("Copy objects from the drawing to the clipboard."), QIcon(":/res/editcopy2.png"), QKeySequence(tr("Ctrl+c")));
+       connect(editCopyAct, SIGNAL(triggered()), this, SLOT(EditCopy()));
+
+       editPasteAct = CreateAction(tr("&Paste Objects"), tr("Paste Objects"), tr("Paste objects from the clipboard to the drawing."), QIcon(":/res/editpaste2.png"), QKeySequence(tr("Ctrl+v")));
+       connect(editPasteAct, SIGNAL(triggered()), this, SLOT(EditPaste()));
 
 //Hm. I think we'll have to have separate logic to do the "Radio Group Toolbar" thing...
 // Yup, in order to turn them off, we'd have to have an "OFF" toolbar button. Ick.
@@ -830,8 +923,8 @@ void ApplicationWindow::CreateActions(void)
 //
 // Consolidates action creation from a multi-step process to a single-step one.
 //
-QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
-       QIcon icon, QKeySequence key, bool checkable/*= false*/)
+QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
+       QString statustip, QIcon icon, QKeySequence key, bool checkable/*= false*/)
 {
        QAction * action = new QAction(icon, name, this);
        action->setToolTip(tooltip);
@@ -847,8 +940,9 @@ QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString
 // This is essentially the same as the previous function, but this allows more
 // than one key sequence to be added as key shortcuts.
 //
-QAction * ApplicationWindow::CreateAction(QString name, QString tooltip, QString statustip,
-       QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
+QAction * ApplicationWindow::CreateAction(QString name, QString tooltip,
+       QString statustip, QIcon icon, QKeySequence key1, QKeySequence key2,
+       bool checkable/*= false*/)
 {
        QAction * action = new QAction(icon, name, this);
        action->setToolTip(tooltip);
@@ -890,6 +984,9 @@ void ApplicationWindow::CreateMenus(void)
        menu->addAction(connectAct);
        menu->addAction(disconnectAct);
        menu->addSeparator();
+       menu->addAction(editCutAct);
+       menu->addAction(editCopyAct);
+       menu->addAction(editPasteAct);
        menu->addAction(deleteAct);
        menu->addSeparator();
        menu->addAction(addLineAct);
@@ -938,6 +1035,9 @@ void ApplicationWindow::CreateToolbars(void)
        toolbar->addAction(mirrorAct);
        toolbar->addAction(trimAct);
        toolbar->addAction(triangulateAct);
+       toolbar->addAction(editCutAct);
+       toolbar->addAction(editCopyAct);
+       toolbar->addAction(editPasteAct);
        toolbar->addAction(deleteAct);
        toolbar->addAction(connectAct);
        toolbar->addAction(disconnectAct);
index 32ac8f6001d9ca2db668f5bc29ffac130ef276d7..d10e4dd6c791a1b9db83481912bf6d68e0c99516 100644 (file)
@@ -19,6 +19,7 @@ class ApplicationWindow: public QMainWindow
 
        protected:
                void closeEvent(QCloseEvent * event);
+               void contextMenuEvent(QContextMenuEvent * event);
 
        private slots:
                void FileNew(void);
@@ -49,6 +50,12 @@ class ApplicationWindow: public QMainWindow
                void HandleGridSizeInPixels(int);
                void HandleGridSizeInBaseUnits(QString);
                void HandleDimensionSize(QString);
+               void EditCut(void);
+               void EditCopy(void);
+               void EditPaste(void);
+
+       signals:
+               void ReloadLayers(void);
 
        private:
                void ClearUIToolStatesExcept(QAction *);
@@ -98,6 +105,11 @@ class ApplicationWindow: public QMainWindow
                QAction * mirrorAct;
                QAction * trimAct;
                QAction * triangulateAct;
+               QAction * editCutAct;
+               QAction * editCopyAct;
+               QAction * editPasteAct;
+
+               std::vector<void *> clipboard;
 
        // Class variables
        public:
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;
+       }
+}
+
index 08f347f6cac05e26193f9df07e9114f30a86296c..768c5c029b26a518b2f7959eaa8d2987f9aa53b9 100644 (file)
@@ -25,7 +25,8 @@ class DrawingView: public QWidget
                void RenderObjects(Painter *, std::vector<void *> &, int, bool ignoreLayer = false);
                void AddHoveredToSelection(void);
                void GetSelection(std::vector<void *> &);
-               void GetHovered(std::vector<void *> &);
+//             void GetHovered(std::vector<void *> &);
+               std::vector<void *> GetHovered(void);
                void ToolHandler(int, Point);
                void ToolDraw(Painter *);
                void LineHandler(int, Point);
@@ -34,12 +35,16 @@ class DrawingView: public QWidget
                void RotateHandler(int, Point);
                void MirrorHandler(int, Point);
                void DimensionHandler(int, Point);
+               void TriangulateHandler(int, Point);
+               void TrimHandler(int, Point);
+               void ParallelHandler(int, Point);
                Rect GetObjectExtents(Object *);
                void CheckObjectBounds(void);
                bool HitTestObjects(Point);
                bool HitTest(Object *, Point);
                bool HandleObjectClicked(void);
                void HandleObjectMovement(Point);
+               void AddDimensionTo(void * obj);
 
        public slots:
                void DeleteCurrentLayer(int);
@@ -54,6 +59,7 @@ class DrawingView: public QWidget
                void ObjectSelected(Object *);
 
        protected:
+               void focusOutEvent(QFocusEvent * event);
                void paintEvent(QPaintEvent * event);
                void resizeEvent(QResizeEvent * event);
                void mousePressEvent(QMouseEvent * event);
@@ -69,7 +75,6 @@ class DrawingView: public QWidget
 
        public:
                bool useAntialiasing;
-//             uint32_t numSelected;
                uint32_t numHovered;
                bool shiftDown;
                bool ctrlDown;
@@ -91,10 +96,12 @@ class DrawingView: public QWidget
 
        public:
                std::vector<void *> select;
-               std::vector<void *> hover;
+//             std::vector<void *> hover;
                std::vector<void *> toolObjects;
                std::vector<Object> toolScratch;
+               std::vector<void *> toolScratch2;
                Point toolPoint[32];
+               Object * toolObj[32];
                Point intersectionPoint;
                Point hoverPoint;
                bool hoverPointValid;
@@ -102,6 +109,7 @@ class DrawingView: public QWidget
                Object * dragged;
                bool draggingObject;
                bool angleSnap;
+               bool dirty;
 };
 
 #endif // __DRAWINGVIEW_H__
index 02ab2f577dc60af0a95f392a60e069b32b57b631..ace5bfa247713a3adc4aabee61f0dc3871a4c0aa 100644 (file)
@@ -19,6 +19,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <vector>
+#include "applicationwindow.h"
+#include "drawingview.h"
+#include "global.h"
 #include "structs.h"
 
 /*
@@ -125,7 +128,13 @@ enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
           virtual Object function that reports the object by itself if it's a non-
           Container, otherwise it enumerates all objects within itself. */
 
-       fprintf(file, "ARCHITEKTONAS DRAWING V1.1\n");
+       fprintf(file, "ARCHITEKTONAS DRAWING V1.2\n");
+       fprintf(file, "LAYERS %i\n", Global::numLayers);
+
+       for(int i=0; i<Global::numLayers; i++)
+               fprintf(file, "%i %i \"%s\"\n", (Global::layerHidden[i] ? 1 : 0), (Global::layerLocked[i] ? 1 : 0), Global::layerName[i].c_str());
+
+       fprintf(file, "ACTIVE %i\n", Global::activeLayer);
        WriteObjectToFile(file, (Object *)c);
        fprintf(file, "END\n");
        return true;
@@ -136,18 +145,36 @@ enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
 {
        float version;
 
-       fscanf(file, "ARCHITEKTONAS DRAWING V%f", &version);
+       fscanf(file, "ARCHITEKTONAS DRAWING V%f\n", &version);
+
+       // Clear out layer vectors
+       Global::layerHidden.clear();
+       Global::layerLocked.clear();
+       Global::layerName.clear();
 
        if (version == 1.0f)
                return LoadVersion1_0(file, drawing);
        else if (version == 1.1f)
                return LoadVersion1_1(file, drawing);
+       else if (version == 1.2f)
+               return LoadVersion1_2(file, drawing);
 
 //printf("LoadAtnsFile: Could not locate version! (version=%f)\n", version);
        return false;
 }
 
 
+/*static*/ void FileIO::ResetLayerVectors(void)
+{
+       // Set up layer vectors
+       Global::layerHidden.insert(Global::layerHidden.begin(), false);
+       Global::layerLocked.insert(Global::layerLocked.begin(), false);
+       Global::layerName.insert(Global::layerName.begin(), "Background");
+       Global::numLayers = 1;
+       Global::activeLayer = 0;
+}
+
+
 /*static*/ bool FileIO::LoadVersion1_0(FILE * file, Container * drawing)
 {
        // Approach: read each object in the file, one by one. If the object is a
@@ -155,6 +182,7 @@ enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
        // This will require a stack to maintain the current Container.
        std::vector<Container *> containerStack;
        Container * currentTopContainer = drawing;
+       ResetLayerVectors();
 
        while (!feof(file))
        {
@@ -197,6 +225,76 @@ enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
 
 /*static*/ bool FileIO::LoadVersion1_1(FILE * file, Container * drawing)
 {
+       // Approach: read each object in the file, one by one. If the object is a
+       // Container, add objects to it until an "endContainer" marker is found.
+       // This will require a stack to maintain the current Container.
+       std::vector<Container *> containerStack;
+       Container * currentTopContainer = drawing;
+       ResetLayerVectors();
+
+       while (!feof(file))
+       {
+               // Reconstruct the object (extended format!)
+               Object * obj = GetObjectFromFile(file, true);
+
+               // objectFileType is set in GetObjectFromFile()...
+               if (objectFileType == OTFObject)
+               {
+                       if (obj == NULL)
+                               return false;
+
+                       currentTopContainer->objects.push_back(obj);
+//printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+
+                       // If the object is a container, push current TLC on the stack and
+                       // set it as the new TLC
+                       if (obj->type == OTContainer)
+                       {
+                               containerStack.push_back(currentTopContainer);
+                               currentTopContainer = (Container *)obj;
+                       }
+               }
+               else if (objectFileType == OTFContainerEnd)
+               {
+                       // Add the extents of the current container
+                       Rect r = ApplicationWindow::drawing->GetObjectExtents((Object *)currentTopContainer);
+                       currentTopContainer->p[0] = r.TopLeft();
+                       currentTopContainer->p[1] = r.BottomRight();
+//printf("Container extents: <%lf, %lf>, <%lf, %lf>\n", r.l, r.t, r.r, r.b);
+
+                       // Container is done, so pop the stack to get back the previous TLC
+                       currentTopContainer = containerStack.back();
+                       containerStack.pop_back();
+               }
+               else if (objectFileType == OTFEndOfFile)
+               {
+//printf("Load: container size = %li\n", drawing->objects.size());
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
+/*static*/ bool FileIO::LoadVersion1_2(FILE * file, Container * drawing)
+{
+       int hidden, locked;
+       char textBuffer[65536];
+
+       // Load layer information first
+       fscanf(file, "LAYERS %i\n", &Global::numLayers);
+
+       for(int i=0; i<Global::numLayers; i++)
+       {
+               fscanf(file, "%i %i \"%[^\"]\"\n", &hidden, &locked, textBuffer);
+               Global::layerHidden.push_back(hidden ? true : false);
+               Global::layerLocked.push_back(locked ? true : false);
+               Global::layerName.push_back(textBuffer);
+       }
+
+       fscanf(file, "ACTIVE %i\n", &Global::activeLayer);
+
        // Approach: read each object in the file, one by one. If the object is a
        // Container, add objects to it until an "endContainer" marker is found.
        // This will require a stack to maintain the current Container.
@@ -227,6 +325,12 @@ enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
                }
                else if (objectFileType == OTFContainerEnd)
                {
+                       // Add the extents of the current container
+                       Rect r = ApplicationWindow::drawing->GetObjectExtents((Object *)currentTopContainer);
+                       currentTopContainer->p[0] = r.TopLeft();
+                       currentTopContainer->p[1] = r.BottomRight();
+//printf("Container extents: <%lf, %lf>, <%lf, %lf>\n", r.l, r.t, r.r, r.b);
+
                        // Container is done, so pop the stack to get back the previous TLC
                        currentTopContainer = containerStack.back();
                        containerStack.pop_back();
@@ -280,6 +384,7 @@ if (errno)
 }
 
        // Need to add pen attributes as well... do that for v1.1 :-P
+       // And fill attributes... do that for v1.3 (1.2 added layers)
        if (strcmp(buffer, "LINE") == 0)
        {
                Point p1, p2;
index 8aa7511f26366df767fa648a3db159733de428a6..29a9afe09abd56b269a56d034c6518a3325e2a60 100644 (file)
@@ -12,10 +12,12 @@ class FileIO
        public:
                static bool SaveAtnsFile(FILE *, Container *);
                static bool LoadAtnsFile(FILE *, Container *);
+               static void ResetLayerVectors(void);
 
        private:
                static bool LoadVersion1_0(FILE *, Container *);
                static bool LoadVersion1_1(FILE *, Container *);
+               static bool LoadVersion1_2(FILE *, Container *);
 //             static bool GetObjectFromFile(FILE *, Object *, Object **, int *);
                static Object * GetObjectFromFile(FILE *, bool extended = false);
                static bool WriteObjectToFile(FILE *, Object *);
index e408a5deb2eb7ac53e9a469c3ee39fc0ee095535..f9e016fef6cd92e09ce0439750c9316476dc9678 100644 (file)
@@ -52,4 +52,4 @@ int Global::activeLayer = 0;
 int Global::numLayers = 1;
 std::vector<bool> Global::layerHidden;
 std::vector<bool> Global::layerLocked;
-
+std::vector<std::string> Global::layerName;
index 4f4d46a118cded8012d3506283fc217ea7987848..06c04e80d288c688e91826f473b648bf2a207e3d 100644 (file)
@@ -5,6 +5,7 @@
 // to do any instantiation shite.
 
 #include <stdint.h>
+#include <string>
 #include <vector>
 #include <QRectF>
 #include "vector.h"
@@ -58,6 +59,7 @@ class Global
                static int numLayers;
                static std::vector<bool> layerHidden;
                static std::vector<bool> layerLocked;
+               static std::vector<std::string> layerName;
 };
 
 #endif // __GLOBALS_H__
index 40c8b01b5d141c0bd7c2fe5603ad852add5eed5d..f86017ba8e8a7a80dcb2630da782d9495784fb21 100644 (file)
@@ -31,7 +31,7 @@ LayerItemWidget::LayerItemWidget(QString s, bool i/*=false*/, bool l/*=false*/,
        // This is required, otherwise the layout engine puts too much space around
        // this widget. :-/
        mainLayout->setContentsMargins(0, 0, 0, 0);
-       
+
        invisible->setFlat(true);
        invisible->setIcon(visibleIcon);
        invisible->setCheckable(true);
@@ -62,13 +62,13 @@ LayerItemWidget::~LayerItemWidget()
 void LayerItemWidget::HandleHideToggle(bool state)
 {
 //     printf("Eye is: %s\n", !state ? "OPEN" : "closed");
-       emit(HideToggled(parent, state));
+       emit HideToggled(parent, state);
 }
 
 
 void LayerItemWidget::HandleLockToggle(bool state)
 {
 //     printf("Lock is: %s\n", !state ? "OPEN" : "closed");
-       emit(LockToggled(parent, state));
+       emit LockToggled(parent, state);
 }
 
index 9ac85a87379fab084125300448db2f32ccb2429a..9177b206594aa3979a986495f3e8a079d200e89d 100644 (file)
@@ -69,8 +69,10 @@ LayerWidget::LayerWidget(void): QWidget(),
        Global::numLayers = 1;
        Global::layerHidden.clear();
        Global::layerLocked.clear();
+       Global::layerName.clear();
        Global::layerHidden.push_back(false);
        Global::layerLocked.push_back(false);
+       Global::layerName.push_back("Background");
 }
 
 
@@ -79,10 +81,33 @@ LayerWidget::~LayerWidget()
 }
 
 
+void LayerWidget::Reload(void)
+{
+       list->clear();
+
+       for(int i=0; i<Global::numLayers; i++)
+       {
+               QListWidgetItem * qlwi = new QListWidgetItem();
+               LayerItemWidget * liw = new LayerItemWidget(Global::layerName[i].c_str(), Global::layerHidden[i], Global::layerLocked[i], qlwi);
+               list->insertItem(0, qlwi);
+               list->setItemWidget(qlwi, liw);
+
+               // Set up SIGNAL/SLOTs for this LayerItemWidget
+               connect(liw, SIGNAL(HideToggled(QListWidgetItem *, bool)), this, SLOT(HandleHideToggle(QListWidgetItem *, bool)));
+               connect(liw, SIGNAL(LockToggled(QListWidgetItem *, bool)), this, SLOT(HandleLockToggle(QListWidgetItem *, bool)));
+       }
+
+       int layer = (Global::numLayers - Global::activeLayer) - 1;
+       list->setCurrentRow(layer, QItemSelectionModel::SelectCurrent);
+       SetButtonStates();
+}
+
+
 void LayerWidget::HandleLayerSelected(int currentRow)
 {
-//printf("LayerWidget::HandleLayerSelected(): currentRow = %i\n", currentRow);
-//     emit(LayerSelected(currentRow));
+       // If LayerWidget is empty, bail out
+       if (currentRow == -1)
+               return;
 
        // This is numbered opposite of how it's presented. In other words, the
        // bottom of the list is 0, and items above it count upwards. So like this:
@@ -93,7 +118,7 @@ void LayerWidget::HandleLayerSelected(int currentRow)
        //
        // which is the opposite of the internal numbering.
        Global::activeLayer = (Global::numLayers - currentRow) - 1;
-//printf("LayerWidget::HandleLayerSelected(): currentRow = %i, numLayers = %i, active = %i\n", currentRow, Global::numLayers, Global::activeLayer);
+
        // Set button states to sane values
        SetButtonStates();
 }
@@ -114,7 +139,7 @@ void LayerWidget::HandleHideToggle(QListWidgetItem * qlwi, bool state)
 //printf("Item #%i, new hide state is %s\n", currentRow, (state ? "ON" : "off"));
 //printf("LayerWidget: New hide state of layer %i is %s.\n", layer, (state ? "ON" : "off"));
        // We do this last, because otherwise the Document would get the wrong state
-       emit(LayerToggled());
+       emit LayerToggled();
 }
 
 
@@ -136,7 +161,8 @@ void LayerWidget::HandleDblClick(QListWidgetItem * /*qlwi*/)
 
 void LayerWidget::AddLayer(void)
 {
-       // We always stick the newest layer at the top of the list...
+       // We always stick the newest layer at the top of the list (visually, the
+       // top of the list is the end, the bottom is the beginning)...
        int count = list->count();
        QString text = QString("Layer #%1").arg(count);
        QListWidgetItem * qlwi = new QListWidgetItem();
@@ -151,8 +177,9 @@ void LayerWidget::AddLayer(void)
        SetButtonStates();
 
        // Fix up the global state
-       Global::layerHidden.insert(Global::layerHidden.begin(), false);
-       Global::layerLocked.insert(Global::layerLocked.begin(), false);
+       Global::layerHidden.push_back(false);
+       Global::layerLocked.push_back(false);
+       Global::layerName.push_back(text.toUtf8().data());
        Global::numLayers++;
 }
 
@@ -168,7 +195,7 @@ void LayerWidget::DeleteLayer(void)
        //       HandleLayerSelected() to be fired off which causes the numbers to
        //       be off. You have been warned!
        // Tell the DrawingView to delete this layer in its Container:
-       emit(LayerDeleted(Global::activeLayer));
+       emit LayerDeleted(Global::activeLayer);
 
        int currentRow = list->currentRow();
        QListWidgetItem * qlwi = list->currentItem();
@@ -181,6 +208,7 @@ void LayerWidget::DeleteLayer(void)
        int layer = (Global::numLayers - currentRow) - 1;
        Global::layerHidden.erase(Global::layerHidden.begin() + layer);
        Global::layerLocked.erase(Global::layerLocked.begin() + layer);
+       Global::layerName.erase(Global::layerName.begin() + layer);
        Global::numLayers--;
 
        // If we're deleting from the top of the list, we have to decrement the
@@ -201,7 +229,13 @@ void LayerWidget::EditLayer(void)
        QString result = QInputDialog::getText(this, tr("Edit Layer Name"), tr("Layer Name:"), QLineEdit::Normal, s, &ok);
 
        if (ok && !result.isEmpty())
+       {
                li->name->setText(result);
+
+               int layer = (Global::numLayers - Global::activeLayer) - 1;
+               std::vector<std::string>::iterator i = Global::layerName.begin() + layer;
+               (*i) = result.toUtf8().data();
+       }
 }
 
 
@@ -236,8 +270,11 @@ void LayerWidget::MoveLayerUp(void)
        old = Global::layerLocked[layer];
        Global::layerLocked[layer] = Global::layerLocked[layer + 1];
        Global::layerLocked[layer + 1] = old;
+       std::string oldStr = Global::layerName[layer];
+       Global::layerName[layer] = Global::layerName[layer + 1];
+       Global::layerName[layer + 1] = oldStr;
        // We also have to tell the document to shuffle its layers too
-       emit(LayersSwapped(layer, layer + 1));
+       emit LayersSwapped(layer, layer + 1);
 }
 
 
@@ -272,8 +309,11 @@ void LayerWidget::MoveLayerDown(void)
        old = Global::layerLocked[layer];
        Global::layerLocked[layer] = Global::layerLocked[layer - 1];
        Global::layerLocked[layer - 1] = old;
+       std::string oldStr = Global::layerName[layer];
+       Global::layerName[layer] = Global::layerName[layer - 1];
+       Global::layerName[layer - 1] = oldStr;
        // We also have to tell the document to shuffle its layers too
-       emit(LayersSwapped(layer, layer - 1));
+       emit LayersSwapped(layer, layer - 1);
 }
 
 
index 875c3cdf5942d48f4b9084ef6716e77c4caae8ad..5da5ee9f900c6acdd75f5c8c5320241d52c91c11 100644 (file)
@@ -11,6 +11,9 @@ class LayerWidget: public QWidget
                LayerWidget(void);
                ~LayerWidget();
 
+       public slots:
+               void Reload(void);
+
        private slots:
                void HandleLayerSelected(int);
                void HandleHideToggle(QListWidgetItem *, bool);
index cdd11ecac46540b778ac61659d62a20c981d4aa9..c1b33fb2958ee3133aae136199c345df547a0039 100644 (file)
@@ -12,10 +12,19 @@ enum ObjectType { OTNone = 0, OTLine, OTCircle, OTEllipse, OTArc, OTPolygon, OTD
 
 enum DimensionType { DTLinear = 0, DTLinearVert, DTLinearHorz, DTRadial, DTDiametric, DTCircumferential, DTAngular, DTLeader, DTCount };
 
-enum ToolType { TTNone, TTLine, TTCircle, TTEllipse, TTArc, TTDimension, TTText, TTPolygon, TTSpline, TTRotate, TTMirror, TTTrim, TTTriangulate, TTDelete };
+enum ToolType { TTNone, TTLine, TTCircle, TTEllipse, TTArc, TTDimension, TTText, TTPolygon, TTSpline, TTRotate, TTMirror, TTTrim, TTTriangulate, TTDelete, TTParallel };
 
 enum ToolState { TSNone, TSPoint1, TSPoint2, TSPoint3, TSPoint4, TSDone };
 
+const char objName[OTCount][16] = {
+       "None", "Line", "Circle", "Ellipse", "Arc", "Polygon", "Dimension",
+       "Spline", "Text", "Container"
+};
+const char dimName[DTCount][32] = {
+       "Linear", "Vertical", "Horizontal", "Radial", "Diametric",
+       "Circumferential", "Angular", "Leader"
+};
+
 #define OBJECT_COMMON \
        int type;         \
        uint32_t id;      \
@@ -29,7 +38,8 @@ enum ToolState { TSNone, TSPoint1, TSPoint2, TSPoint3, TSPoint4, TSDone };
        bool hitObject;   \
        Point p[5];       \
        double angle[2];  \
-       double radius[2];
+       double radius[2]; \
+       double length;
 
 struct Object {
        OBJECT_COMMON;
@@ -38,10 +48,10 @@ struct Object {
 struct Line {
        OBJECT_COMMON;
 
-       Line(): type(OTLine), id(Global::objectID++) {}
+       Line(): type(OTLine), id(Global::objectID++), selected(false), hovered(false), hitObject(false) { hitPoint[0] = hitPoint[1] = false; }
        Line(Vector pt1, Vector pt2, float th = 1.0, uint32_t c = 0, int l = LSSolid):
                type(OTLine), id(Global::objectID++), layer(0), color(c), thickness(th),
-               style(l), selected(false), hovered(false), hitObject(false) { p[0] = pt1; p[1] = pt2; }
+               style(l), selected(false), hovered(false), hitObject(false) { p[0] = pt1; p[1] = pt2; hitPoint[0] = hitPoint[1] = false; }
 };
 
 struct Circle {
@@ -51,7 +61,7 @@ struct Circle {
        Circle(Vector pt1, double r, float th = 1.0, uint32_t c = 0, int l = LSSolid):
                type(OTCircle), id(Global::objectID++), layer(0), color(c), thickness(th),
                style(l), selected(false), hovered(false), hitObject(false)
-               { p[0] = pt1; radius[0] = r; }
+               { p[0] = pt1; radius[0] = r; hitPoint[0] = hitPoint[1] = false; }
 };
 
 struct Ellipse {
@@ -61,7 +71,7 @@ struct Ellipse {
        Ellipse(Vector pt1, Vector pt2, double r1, double r2, float th = 1.0, uint32_t c = 0, int l = LSSolid):
                type(OTEllipse), id(Global::objectID++), layer(0), color(c), thickness(th),
                style(l), selected(false), hovered(false), hitObject(false)
-               { p[0] = pt1; p[1] = pt2; radius[0] = r1; radius[1] = r2; }
+               { p[0] = pt1; p[1] = pt2; radius[0] = r1; radius[1] = r2; hitPoint[0] = hitPoint[1] = false; }
 };
 
 struct Arc {
@@ -71,7 +81,7 @@ struct Arc {
        Arc(Vector pt1, double r, double a1, double a2, float th = 1.0, uint32_t c = 0, int l = LSSolid):
                type(OTArc), id(Global::objectID++), layer(0), color(c), thickness(th),
                style(l), selected(false), hovered(false), hitObject(false)
-               { p[0] = pt1; radius[0] = r; angle[0] = a1, angle[1] = a2; }
+               { p[0] = pt1; radius[0] = r; angle[0] = a1, angle[1] = a2; hitPoint[0] = hitPoint[1] = hitPoint[2] = false; }
 };
 
 struct Dimension {
@@ -81,11 +91,14 @@ struct Dimension {
        Point lp[2];            // Line point, the actual dimension line
        Object * obj[2];        // Pointer to attached objects (circle, lines for angle)
 
-       Dimension(): type(OTDimension), id(Global::objectID++) {}
+       Dimension(): type(OTDimension), id(Global::objectID++), selected(false),
+               hovered(false), hitObject(false)
+               { hitPoint[0] = hitPoint[1] = hitPoint[2] = hitPoint[3] = hitPoint[4] = false; }
        Dimension(Vector pt1, Vector pt2, DimensionType dt = DTLinear, float th = 1.0, uint32_t c = 0x0000FF, int l = LSSolid):
                type(OTDimension), id(Global::objectID++), layer(0), color(c),
                thickness(th), style(l), selected(false), hovered(false),
-               hitObject(false), subtype(dt), offset(0) { p[0] = pt1; p[1] = pt2; }
+               hitObject(false), subtype(dt), offset(0)
+               { p[0] = pt1; p[1] = pt2; hitPoint[0] = hitPoint[1] = hitPoint[2] = hitPoint[3] = hitPoint[4] = false; }
 };
 
 struct Text {
@@ -118,8 +131,10 @@ struct Container {
        std::vector<void *> objects;
        double scale;
        bool topLevel;
+       Object * clicked;
 
-       Container(bool tl = false): type(OTContainer), id(Global::objectID++), selected(false), hovered(false), hitObject(false), topLevel(tl) {}
+       Container(bool tl = false): type(OTContainer), id(Global::objectID++), selected(false), hovered(false), hitObject(false), topLevel(tl), clicked(NULL) {}
+       void Add(void * obj) { objects.push_back(obj); }
 //     void DeleteContents(void) {}
 /*     void DeleteContents(Container * c)
        {
index 2263d7d224c6d4d66d76d69144e288b2fbfece68..98902d7a80a439de0b39a6a0613e963dde30d1aa 100644 (file)
@@ -1,7 +1,7 @@
 // utils.cpp: Stuff that's useful to have kicking around, in one spot
 //
 // Part of the Architektonas Project
-// (C) 2015 Underground Software
+// (C) 2020 Underground Software
 // See the README and GPLv3 files for licensing and warranty information
 //
 // JLH = James Hammons <jlhamm@acm.org>
@@ -13,6 +13,7 @@
 
 #include "utils.h"
 #include <string.h>            // For memcpy()
+#include "geometry.h"
 
 
 //
@@ -21,9 +22,7 @@
 //
 void CopyObjects(std::vector<void *> & from, std::vector<void *> & to)
 {
-       std::vector<void *>::iterator i;
-
-       for(i=from.begin(); i!=from.end(); i++)
+       for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
        {
                Object * obj = (Object *)(*i);
                Object * newObject = CopyObject(obj);
@@ -37,45 +36,47 @@ void CopyObjects(std::vector<void *> & from, std::vector<void *> & to)
 //
 Object * CopyObject(Object * obj)
 {
-       Object * newObject = NULL;
+       void * newObject = NULL;
 
        switch (obj->type)
        {
        case OTLine:
-               newObject = (Object *)new Line();
+               newObject = new Line();
                memcpy(newObject, obj, sizeof(Line));
                break;
        case OTCircle:
-               newObject = (Object *)new Circle();
+               newObject = new Circle();
                memcpy(newObject, obj, sizeof(Circle));
                break;
        case OTEllipse:
-               newObject = (Object *)new Ellipse();
+               newObject = new Ellipse();
                memcpy(newObject, obj, sizeof(Ellipse));
                break;
        case OTArc:
-               newObject = (Object *)new Arc();
+               newObject = new Arc();
                memcpy(newObject, obj, sizeof(Arc));
                break;
        case OTDimension:
-               newObject = (Object *)new Dimension();
+               newObject = new Dimension();
                memcpy(newObject, obj, sizeof(Dimension));
                break;
 #if 0
        case OTSpline:
-               newObject = (Object *)new Spline();
+               newObject = new Spline();
                memcpy(newObject, obj, sizeof(Spline));
                break;
 #endif
        case OTText:
-               newObject = (Object *)new Text();
+               newObject = new Text();
                memcpy(newObject, obj, sizeof(Text));
                ((Text *)newObject)->s = ((Text *)obj)->s;
                break;
        case OTContainer:
-               newObject = (Object *)new Container();
+               newObject = new Container();
 //this won't work...
 //             memcpy(newObject, obj, sizeof(Line));
+               ((Container *)newObject)->p[0] = obj->p[0];
+               ((Container *)newObject)->p[1] = obj->p[1];
                CopyObjects(((Container *)obj)->objects, ((Container *)newObject)->objects);
                break;
        default:
@@ -83,10 +84,10 @@ Object * CopyObject(Object * obj)
        }
 
        // Fix objectID
-       if (newObject && (newObject->type != OTContainer))
-               newObject->id = Global::objectID;
+       if (newObject && (((Object *)newObject)->type != OTContainer))
+               ((Object *)newObject)->id = Global::objectID++;
 
-       return newObject;
+       return (Object *)newObject;
 }
 
 
@@ -109,6 +110,23 @@ void MoveSelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & fro
 }
 
 
+//hmm, this won't work, as these are just pointers...
+//[should work now]
+void CopySelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+{
+       for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->selected)
+//             {
+//                     Object * newObject = CopyObject(obj);
+                       dest.push_back(CopyObject(obj));
+//             }
+       }
+}
+
+
 void AddObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
 {
        for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
@@ -136,11 +154,11 @@ void SelectAll(std::vector<void *> & v)
 
 //
 // Recursively go down thru the Container's vectors, deleting all the objects
-// contained therein. Once that is done, the main Container can be deleted. We
-// don't have to worry about the underlying std::vectors, as they have their
+// contained therein.  Once that is done, the main Container can be deleted.
+// We don't have to worry about the underlying std::vectors, as they have their
 // own destructors--plus they don't take ownership of objects, which is why we
-// have to keep track of that stuff ourselves. :-P Believe it or not, this is a
-// Good Thing(TM). ;-)
+// have to keep track of that stuff ourselves.  :-P  Believe it or not, this is
+// a Good Thing(TM).  ;-)
 //
 void DeleteContents(std::vector<void *> & v)
 {
@@ -155,8 +173,11 @@ void DeleteContents(std::vector<void *> & v)
 
                delete obj;
        }
+
+       v.clear();
 }
 
+
 void DeleteSelectedObjects(std::vector<void *> & v)
 {
        std::vector<void *>::iterator i = v.begin();
@@ -203,7 +224,7 @@ void SavePointsFrom(std::vector<void *> & v, std::vector<Object> & save)
 
        for(std::vector<void *>::iterator i=v.begin(); i!=v.end(); i++)
        {
-               memcpy(&o, (*i), sizeof(Object));
+               memcpy(&o, (Object *)(*i), sizeof(Object));
                save.push_back(o);
        }
 }
@@ -227,6 +248,32 @@ void RestorePointsTo(std::vector<void *> & v, std::vector<Object> & s)
 }
 
 
+void RestorePointsTo(std::vector<void *> & v, std::vector<void *> & s)
+{
+       std::vector<void *>::iterator i = s.begin();
+       std::vector<void *>::iterator j = v.begin();
+
+       for(; i!=s.end(); i++, j++)
+       {
+               Object * objS = (Object *)(*i);
+               Object * objV = (Object *)(*j);
+
+               if (objV->type == OTContainer)
+               {
+                       RestorePointsTo(((Container *)objV)->objects, ((Container *)objS)->objects);
+                       return;
+               }
+
+               objV->p[0] = objS->p[0];
+               objV->p[1] = objS->p[1];
+               objV->angle[0] = objS->angle[0];
+               objV->angle[1] = objS->angle[1];
+//we don't do this because we want to keep selected & friends from changing
+//             memcpy(obj2, *j, sizeof(Object));
+       }
+}
+
+
 void TranslateObject(Object * obj, Point delta)
 {
        if (obj->type == OTContainer)
@@ -237,11 +284,61 @@ void TranslateObject(Object * obj, Point delta)
                for(i=c->objects.begin(); i!=c->objects.end(); i++)
                        TranslateObject((Object *)*i, delta);
        }
-       else
-       {
+//     else
+//     {
                obj->p[0] += delta;
                obj->p[1] += delta;
+//     }
+}
+
+
+/*
+So we need to make it so that we pick the container's point clicked on, and translate all the other parts *not* clicked on.
+*/
+void TranslateContainer(Container * c, Point point, Point delta)
+{
+       if (c->clicked == NULL)
+       {
+//             TranslateObject((Object *)c, delta);
+               return;
        }
+
+static int i=0;
+printf("TranslateContainer: boop (%i)\n", i++);
+       Point clickedPoint;
+
+       switch (c->clicked->type)
+       {
+       case OTLine:
+               if (c->clicked->hitPoint[0])
+                       clickedPoint = c->clicked->p[0];
+               else if (c->clicked->hitPoint[1])
+                       clickedPoint = c->clicked->p[1];
+               else if (c->clicked->hitObject)
+                       clickedPoint = Geometry::Midpoint((Line *)(c->clicked));
+
+               break;
+
+       case OTCircle:
+               if (c->clicked->hitPoint[0])
+                       clickedPoint = c->clicked->p[0];
+               else if (c->clicked->hitObject)
+                       clickedPoint = point;
+
+               break;
+
+       case OTArc:
+               break;
+
+       case OTDimension:
+               break;
+
+       case OTText:
+               break;
+       }
+
+       Point clickedDelta = point - clickedPoint;
+       TranslateObject((Object *)c, clickedDelta);
 }
 
 
@@ -274,3 +371,24 @@ void TranslateObjects(std::vector<void *> & v, Point delta)
 }
 
 
+std::vector<void *> Flatten(Container * src)
+{
+       std::vector<void *> flat;
+       std::vector<void *>::iterator i;
+
+       for(i=src->objects.begin(); i!=src->objects.end(); i++)
+       {
+               flat.push_back(*i);
+               Object * obj = (Object *)(*i);
+
+               // Recursively add objects to the flat vector, if necessary
+               if (obj->type == OTContainer)
+               {
+                       std::vector<void *> sub = Flatten((Container *)obj);
+                       flat.insert(flat.end(), sub.begin(), sub.end());
+               }
+       }
+
+       return flat;
+}
+
index 90e6d9f7f8d03a5afe423181d10b42a59055c5ab..a72ca394750078324440e9a7c54598600bce50c1 100644 (file)
@@ -7,6 +7,7 @@
 void CopyObjects(std::vector<void *> & from, std::vector<void *> & to);
 Object * CopyObject(Object * obj);
 void MoveSelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
+void CopySelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
 void AddObjectsTo(std::vector<void *> & dest, std::vector<void *> & from);
 void ClearSelected(std::vector<void *> & v);
 void SelectAll(std::vector<void *> & v);
@@ -15,8 +16,10 @@ void DeleteSelectedObjects(std::vector<void *> & v);
 void RemoveSelectedObjects(std::vector<void *> & v);
 void SavePointsFrom(std::vector<void *> & v, std::vector<Object> & s);
 void RestorePointsTo(std::vector<void *> & v, std::vector<Object> & s);
+void RestorePointsTo(std::vector<void *> & v, std::vector<void *> & s);
 void TranslateObject(Object * obj, Point delta);
+void TranslateContainer(Container * c, Point point, Point delta);
 void TranslateObjects(std::vector<void *> & v, Point delta);
+std::vector<void *> Flatten(Container * src);
 
 #endif // __UTILS_H__
-