]> Shamusworld >> Repos - architektonas/blobdiff - src/utils.cpp
Changes to make containers behave like a first-class object.
[architektonas] / src / utils.cpp
index 6f3c73ae0941733bbfd8764a8ac0996cab79cbbf..98902d7a80a439de0b39a6a0613e963dde30d1aa 100644 (file)
@@ -1,18 +1,19 @@
 // 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>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  ------------------------------------------------------------
 // JLH  05/01/2015  Created this file
 //
 
 #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,53 @@ 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 (Object *)newObject;
+}
+
+
+void MoveSelectedObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+{
+       std::vector<void *>::iterator i = from.begin();
+
+       while (i != from.end())
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->selected)
+               {
+                       dest.push_back(*i);
+                       from.erase(i);
+               }
+               else
+                       i++;
+       }
+}
+
+
+//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));
+//             }
+       }
+}
+
 
-       return newObject;
+void AddObjectsTo(std::vector<void *> & dest, std::vector<void *> & from)
+{
+       for(std::vector<void *>::iterator i=from.begin(); i!=from.end(); i++)
+               dest.push_back(*i);
 }
 
 
@@ -99,3 +143,252 @@ void ClearSelected(std::vector<void *> & v)
 }
 
 
+void SelectAll(std::vector<void *> & v)
+{
+       std::vector<void *>::iterator i;
+
+       for(i=v.begin(); i!=v.end(); i++)
+               ((Object *)(*i))->selected = true;
+}
+
+
+//
+// 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
+// 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).  ;-)
+//
+void DeleteContents(std::vector<void *> & v)
+{
+       std::vector<void *>::iterator i;
+
+       for(i=v.begin(); i!=v.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->type == OTContainer)
+                       DeleteContents(((Container *)obj)->objects);
+
+               delete obj;
+       }
+
+       v.clear();
+}
+
+
+void DeleteSelectedObjects(std::vector<void *> & v)
+{
+       std::vector<void *>::iterator i = v.begin();
+
+       while (i != v.end())
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->selected)
+               {
+                       delete obj;
+                       v.erase(i);
+               }
+               else
+                       i++;
+       }
+}
+
+
+//
+// This is used to remove selected objects from one container in order to move
+// them to a different container.
+//
+void RemoveSelectedObjects(std::vector<void *> & v)
+{
+       std::vector<void *>::iterator i = v.begin();
+
+       while (i != v.end())
+       {
+               Object * obj = (Object *)(*i);
+
+               if (obj->selected)
+                       v.erase(i);
+               else
+                       i++;
+       }
+}
+
+
+void SavePointsFrom(std::vector<void *> & v, std::vector<Object> & save)
+{
+       save.clear();
+       Object o;
+
+       for(std::vector<void *>::iterator i=v.begin(); i!=v.end(); i++)
+       {
+               memcpy(&o, (Object *)(*i), sizeof(Object));
+               save.push_back(o);
+       }
+}
+
+
+void RestorePointsTo(std::vector<void *> & v, std::vector<Object> & s)
+{
+       std::vector<Object>::iterator i = s.begin();
+       std::vector<void *>::iterator j = v.begin();
+
+       for(; i!=s.end(); i++, j++)
+       {
+               Object * obj2 = (Object *)(*j);
+               obj2->p[0] = (*i).p[0];
+               obj2->p[1] = (*i).p[1];
+               obj2->angle[0] = (*i).angle[0];
+               obj2->angle[1] = (*i).angle[1];
+//we don't do this because we want to keep selected & friends from changing
+//             memcpy(obj2, *j, sizeof(Object));
+       }
+}
+
+
+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)
+       {
+               Container * c = (Container *)obj;
+               std::vector<void *>::iterator i;
+
+               for(i=c->objects.begin(); i!=c->objects.end(); i++)
+                       TranslateObject((Object *)*i, delta);
+       }
+//     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);
+}
+
+
+void TranslateObjects(std::vector<void *> & v, Point delta)
+{
+#if 0
+       if (obj->type == OTContainer)
+       {
+               Container * c = (Container *)obj;
+               std::vector<void *>::iterator i;
+
+               for(i=c->objects.begin(); i!=c->objects.end(); i++)
+                       TranslateObject((Object *)*i, delta);
+       }
+       else
+       {
+               obj->p[0] += delta;
+               obj->p[1] += delta;
+       }
+#endif
+       // Handle containters too???
+       std::vector<void *>::iterator i;
+
+       for(i=v.begin(); i!=v.end(); i++)
+       {
+               Object * obj = (Object *)(*i);
+               obj->p[0] += delta;
+               obj->p[1] += 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;
+}
+