src/drawingview.h \
src/drawcircleaction.h \
src/drawlineaction.h \
+ src/ellipse.h \
src/fileio.h \
src/generaltab.h \
src/line.h \
src/drawingview.cpp \
src/drawcircleaction.cpp \
src/drawlineaction.cpp \
+ src/ellipse.cpp \
src/fileio.cpp \
src/generaltab.cpp \
src/line.cpp \
return;
}
+printf("FileOpen: container size = %li\n", container.objects.size());
drawing->document = container;
drawing->update();
documentName = filename;
{
}
+
Arc::~Arc()
{
}
+
/*virtual*/ void Arc::Draw(Painter * painter)
{
QPen pen;
painter->DrawArc(position, radius, startAngle, angleSpan);
}
+
/*virtual*/ Vector Arc::Center(void)
{
return position;
}
+
/*
We need at least *four* handles for this object:
- one for moving
return false;
}
+
/*virtual*/ void Arc::PointerMoved(Vector point)
{
// The TLC will send these messages if the object is selected but not clicked on.
needUpdate = true;
}
+
/*virtual*/ void Arc::PointerReleased(void)
{
hitHandle1 = hitHandle2 = hitHandle3 = hitHandle4 = false;
}
#endif
+
/*
start = 350, span = 20, end = 10, angle = 5
angle < start, so angle = 365
return (passedInSpan <= angleSpan ? true : false);
}
+
+
+/*virtual*/ void Arc::Enumerate(FILE * file)
+{
+ fprintf(file, "ARC (%lf,%lf) %lf, %lf, %lf\n", position.x, position.y, radius, startAngle, angleSpan);
+}
+
virtual void PointerMoved(Vector);
virtual void PointerReleased(void);
// virtual bool NeedsUpdate(void);
+ virtual void Enumerate(FILE *);
+ virtual Object * Copy(void);
private:
bool AngleInArcSpan(double angle);
{
}
+
Circle::~Circle()
{
}
+
/*virtual*/ void Circle::Draw(Painter * painter)
{
if (state == OSSelected || hitCircle || hitCenter)
painter->DrawHandle(dragPoint);
}
+
/*virtual*/ Vector Circle::Center(void)
{
return position;
}
+
/*virtual*/ bool Circle::Collided(Vector point)
{
// We can assume this, since this is a mouse down event here.
return false;
}
+
/*virtual*/ void Circle::PointerMoved(Vector point)
{
// Hit test tells us what we hit (if anything) through boolean variables. It
dragPoint = point;
}
+
/*virtual*/ void Circle::PointerReleased(void)
{
// Mouse went up, so our dragging is done (if any *was* done, that is)
state = oldState;
}
+
bool Circle::HitTest(Point point)
{
SaveState();
return StateChanged();
}
+
void Circle::SaveState(void)
{
oldHitCenter = hitCenter;
oldHitCircle = hitCircle;
}
+
bool Circle::StateChanged(void)
{
if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
return false;
}
+
+
+/*virtual*/ void Circle::Enumerate(FILE * file)
+{
+ fprintf(file, "CIRCLE (%lf,%lf) %lf\n", position.x, position.y, radius);
+}
+
virtual bool Collided(Vector);
virtual void PointerMoved(Vector);
virtual void PointerReleased(void);
+ virtual void Enumerate(FILE *);
+ virtual Object * Copy(void);
protected:
bool HitTest(Point);
Container::~Container()
{
-#if 0
- // No memory leaks!
- while (objects.size() > 0)
- {
- delete objects[0];
- objects.erase(objects.begin());
- }
-#else
Clear();
-#endif
}
// Assignment operator
-Container & Container::operator=(const Container & copy)
+Container & Container::operator=(const Container & from)
{
// Take care of self-assignment
- if (this == ©)
+ if (this == &from)
return *this;
Clear();
- for(int i=0; i<(int)copy.objects.size(); i++)
- objects.push_back(copy.objects[i]);
+ // Small problem with this approach: if the copied object goes out of scope,
+ // all of the objects we copied in here will be deleted. D'oh!
+ for(uint i=0; i<from.objects.size(); i++)
+ {
+ Object * object = from.objects[i];
+
+ // Need to copy the object here...
+
+ objects.push_back(object);
+ }
return *this;
}
/*virtual*/ void Container::Draw(Painter * painter)
{
for(int i=0; i<(int)objects.size(); i++)
+ {
+printf("Container: About to draw (object = $%X)\n", objects[i]);
objects[i]->Draw(painter);
+ }
}
{
Dimension * dimension = objects[i]->GetAttachedDimension();
- objects.erase(objects.begin() + i); // Calls the destructor, (deletes the object, I presume... O_o)
+ Object * objectToDelete = objects[i];
+ objects.erase(objects.begin() + i); // Calls the destructor, (deletes the object, I presume... O_o) [NOPE! SURE DOESN'T!]
+ delete objectToDelete;
// If this object had an attached dimension, reattach it to another object, if any...
// The only problem with that approach is if the object it gets attached to is deleted,
{
needUpdate = false;
- for(int i=0; i<(int)objects.size(); i++)
+ for(uint i=0; i<objects.size(); i++)
{
if (objects[i]->NeedsUpdate())
needUpdate = true;
/*virtual*/ void Container::Add(Object * object)
{
objects.push_back(object);
+printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
}
// No memory leaks!
while (objects.size() > 0)
{
+printf("Container: Deleting object ($%X)...\n", objects[0]);
delete objects[0];
objects.erase(objects.begin());
}
}
+
+
+/*virtual*/ void Container::Enumerate(FILE * file)
+{
+ // Only put "CONTAINER" markers if *not* the top level container
+ if (parent != NULL)
+ fprintf(file, "CONTAINER\n");
+
+ for(uint i=0; i<objects.size(); i++)
+ objects[i]->Enumerate(file);
+
+ if (parent != NULL)
+ fprintf(file, "ENDCONTAINER\n");
+}
+
virtual void PointerReleased(void);
virtual bool NeedsUpdate(void);
virtual void Add(Object *);
+ virtual void Enumerate(FILE *);
void Clear(void);
protected:
Vector oldPoint; // Used for dragging
- private:
+ public:
std::vector<Object *> objects;
+ private:
bool dragging;
bool draggingHandle1;
bool draggingHandle2;
{
}
+
// This is bad, p1 & p2 could be NULL, causing much consternation...
Dimension::Dimension(Vector * p1, Vector * p2, DimensionType dt/*= DTLinear*/ , Object * p/*= NULL*/):
Object(*p1, p), endpoint(*p2),
{
}
+
Dimension::~Dimension()
{
}
+
/*virtual*/ void Dimension::Draw(Painter * painter)
{
// If there are valid Vector pointers in here, use them to update the internal
*/
}
+
/*virtual*/ Vector Dimension::Center(void)
{
// Technically, this is the midpoint but who are we to quibble? :-)
return endpoint + v;
}
+
/*virtual*/ bool Dimension::Collided(Vector /*point*/)
{
#if 0
return false;
}
+
/*virtual*/ void Dimension::PointerMoved(Vector point)
{
// We know this is true because mouse move messages don't come here unless
needUpdate = false;
}
+
/*virtual*/ void Dimension::PointerReleased(void)
{
if (draggingHandle1 || draggingHandle2)
state = oldState;
}
+
void Dimension::SetPoint1(Vector * v)
{
point1 = v;
needUpdate = true;
}
+
void Dimension::SetPoint2(Vector * v)
{
point2 = v;
needUpdate = true;
}
+
Vector Dimension::GetPoint1(void)
{
return position;
}
+
Vector Dimension::GetPoint2(void)
{
return endpoint;
}
+
void Dimension::FlipSides(void)
{
#if 0
needUpdate = true;
}
+
+/*virtual*/ void Dimension::Enumerate(FILE * file)
+{
+ fprintf(file, "DIMENSION (%lf,%lf) (%lf,%lf) %i\n", position.x, position.y, endpoint.x, endpoint.y, type);
+}
+
virtual bool Collided(Vector);
virtual void PointerMoved(Vector);
virtual void PointerReleased(void);
+ virtual void Enumerate(FILE *);
+ virtual Object * Copy(void);
void SetPoint1(Vector *);
void SetPoint2(Vector *);
Vector GetPoint1(void);
//#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <vector>
+#include "arc.h"
+#include "circle.h"
#include "container.h"
+#include "dimension.h"
+#include "line.h"
+
+enum ObjectType { OTContainer, OTContainerEnd, OTLine, OTCircle, OTArc, OTDimension,
+ OTPolygon, OTText, OTImage, OTBlock, OTEndOfFile };
/*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * object)
{
-// QString filename2 = QFileDialog::getSaveFileName(NULL, tr("Save Drawing"),
-// "", tr("Architektonas files (*.drawing)"));
+ /* Approach: loop through the container, doing a depth-first traversal. Any extra
+ containers found are looped through until there aren't any more down, then
+ ordinary objects are described. This can be handled by a 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.0\n");
+#if 1
+ object->Enumerate(file);
+ fprintf(file, "END\n");
+ return true;
+#else
return false;
+#endif
}
-/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * object)
+/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * drawing)
{
-// QString filename2 = QFileDialog::getOpenFileName(NULL, tr("Open Drawing"),
-// "", tr("Architektonas files (*.drawing)"));
+// char buffer[256];
+ float version;
+
+ fscanf(file, "ARCHITEKTONAS DRAWING V%f", &version);
+
+//printf("Load: version = %f\n", version);
+ if (version != 1.0)
+ return false;
+ /* 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. */
+
+#if 1
+ std::vector<Container *> containerStack;
+ Container * currentTopContainer = drawing;//new Container(Vector(0, 0));
+ Object * object;
+// ObjectType objectType;
+ int objectType;
+
+ while (!feof(file))
+ {
+ if (FileIO::GetObjectFromFile(file, currentTopContainer, &object, &objectType) == false)
+ return false;
+
+ // object->type down below can be replaced with objType.
+ // Above could be: bool FileIO::GetObjectFromFile(FILE *, Object *, ObjectType *);
+ // where the return value tells if it's a valid object, Object * returns the
+ // reconstructed object and ObjectType * returns the object type.
+
+ if (objectType == OTEndOfFile)
+ {
+printf("Load: container size = %li\n", drawing->objects.size());
+ return true;
+ }
+ else if (objectType == OTContainer)
+ {
+ containerStack.push_back(currentTopContainer);
+ currentTopContainer = new Container(Vector(0, 0), currentTopContainer);
+ }
+ else if (objectType == OTContainerEnd)
+ {
+ Container * containerToAdd = currentTopContainer;
+ currentTopContainer = containerStack.back();
+ containerStack.pop_back();
+ currentTopContainer->Add(containerToAdd);
+ }
+ else
+ {
+ currentTopContainer->Add(object);
+printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+ }
+ }
return false;
+#else
+ return false;
+#endif
}
+/*static*/ bool FileIO::GetObjectFromFile(FILE * file, Object * parent, Object ** object, int * objectType)
+{
+ char buffer[256];
+ fscanf(file, "%s ", buffer);
+ bool recognized = false;
+//printf("Load: buffer = \"%s\"\n", buffer);
+
+ if (strcmp(buffer, "LINE") == 0)
+ {
+//printf(" Found LINE.\n");
+ recognized = true;
+ Vector v1, v2;
+ fscanf(file, "(%lf,%lf) (%lf,%lf)", &v1.x, &v1.y, &v2.x, &v2.y);
+//printf(" Number of params recognized: %i\n", n);
+ *object = new Line(v1, v2, parent);
+ *objectType = OTLine;
+ }
+ else if (strcmp(buffer, "CIRCLE") == 0)
+ {
+ recognized = true;
+ Vector v;
+ double r;
+ fscanf(file, "(%lf,%lf) %lf", &v.x, &v.y, &r);
+ *object = new Circle(v, r, parent);
+ *objectType = OTCircle;
+ }
+ else if (strcmp(buffer, "ARC") == 0)
+ {
+ recognized = true;
+ Vector v;
+ double r, a1, a2;
+ fscanf(file, "(%lf,%lf) %lf, %lf, %lf", &v.x, &v.y, &r, &a1, &a2);
+ *object = new Arc(v, r, a1, a2, parent);
+ *objectType = OTArc;
+ }
+ else if (strcmp(buffer, "DIMENSION") == 0)
+ {
+ recognized = true;
+ Vector v1, v2;
+ DimensionType type;
+ fscanf(file, "(%lf,%lf) (%lf,%lf) %i", &v1.x, &v1.y, &v2.x, &v2.y, &type);
+ *object = new Dimension(v1, v2, type, parent);
+ *objectType = OTDimension;
+ }
+ else if (strcmp(buffer, "CONTAINER") == 0)
+ {
+ recognized = true;
+ *objectType = OTContainer;
+ }
+ else if (strcmp(buffer, "ENDCONTAINER") == 0)
+ {
+ recognized = true;
+ *objectType = OTContainerEnd;
+ }
+ else if (strcmp(buffer, "END") == 0)
+ {
+ recognized = true;
+ *objectType = OTEndOfFile;
+ }
+
+ return recognized;
+}
+
#include <stdio.h>
class Container;
+class Object;
// NB: The methods in this class are all static, so there's no need to
// instantiate an object of this type to use its functions.
public:
static bool SaveAtnsFile(FILE *, Container *);
static bool LoadAtnsFile(FILE *, Container *);
+
+ private:
+ static bool GetObjectFromFile(FILE *, Object *, Object **, int *);
};
#endif // __FILEIO_H__
}
*/
+/*virtual*/ void Line::Enumerate(FILE * file)
+{
+ fprintf(file, "LINE (%lf,%lf) (%lf,%lf)\n", position.x, position.y, endpoint.x, endpoint.y);
+}
+
+
+/*virtual*/ Object * Line::Copy(void)
+{
+#warning "!!! This doesn't take care of attached Dimensions !!!"
+/*
+This is a real problem. While having a pointer in the Dimension to this line's points is fast & easy,
+it creates a huge problem when trying to replicate an object like this.
+
+Maybe a way to fix that then, is to have reference numbers instead of pointers. That way, if you copy
+them, ... you might still have problems. Because you can't be sure if a copy will be persistant or not,
+you then *definitely* do not want them to have the same reference number.
+*/
+ return new Line(position, endpoint, parent);
+}
+
virtual void PointerMoved(Vector);
virtual void PointerReleased(void);
virtual Vector * GetPointAt(Vector);
+ virtual void Enumerate(FILE *);
+ virtual Object * Copy(void);
// void SetDimensionOnPoint1(Dimension *);
// void SetDimensionOnPoint2(Dimension *);
void SetDimensionOnLine(Dimension * d = 0);
{
}
+
Object::Object(Vector v, Object * passedInParent/*= 0*/): position(v), parent(passedInParent),
state(OSInactive), oldState(OSInactive), needUpdate(false), attachedDimension(0)
{
}
+
Object::~Object()
{
}
+
/*virtual*/ void Object::Draw(Painter *)
{
}
+
/*virtual*/ Vector Object::Center(void)
{
return Vector();
}
+
/*virtual*/ bool Object::Collided(Vector)
{
return false;
}
+
/*virtual*/ void Object::PointerMoved(Vector)
{
}
+
/*virtual*/ void Object::PointerReleased(void)
{
}
+
/*virtual*/ bool Object::NeedsUpdate(void)
{
return needUpdate;
}
+
// This is intended to be overridden by the Container class, for object morphing
/*virtual*/ void Object::Transmute(Object *, Object *)
{
}
+
/*virtual*/ Object * Object::GetParent(void)
{
return parent;
}
+
/*virtual*/ void Object::Add(Object *)
{
}
+
// This returns a pointer to the point passed in, if it coincides. Otherwise returns NULL.
/*virtual*/ Vector * Object::GetPointAt(Vector)
{
return 0;
}
+
+// This is meant for writing object data to a file.
+/*virtual*/ void Object::Enumerate(FILE *)
+{
+}
+
+
+/*virtual*/ Object * Object::Copy(void)
+{
+ return new Object(position, parent);
+}
+
+
ObjectState Object::GetState(void)
{
return state;
}
+
void Object::Reparent(Object * newParent)
{
parent = newParent;
}
+
Dimension * Object::GetAttachedDimension(void)
{
return attachedDimension;
}
+
// Class methods...
void Object::SetFixedAngle(bool state/*= true*/)
fixedAngle = state;
}
+
void Object::SetFixedLength(bool state/*= true*/)
{
fixedLength = state;
}
+
void Object::SetFont(QFont * f)
{
font = f;
}
+
void Object::SetViewportHeight(int height)
{
viewportHeight = height;
}
+
void Object::SetDeleteActive(bool state/*= true*/)
{
deleteActive = state;
}
+
void Object::SetDimensionActive(bool state/*= true*/)
{
dimensionActive = state;
}
+
void Object::SetSnapMode(bool state/*= true*/)
{
snapToGrid = state;
#include <vector> // This is a container
#include "vector.h" // This is the mathematical construct
+#include <stdio.h>
class Painter;
class QFont;
class Dimension;
+//class FILE;
enum ObjectState { OSInactive, OSSelected };
virtual Object * GetParent(void);
virtual void Add(Object *);
virtual Vector * GetPointAt(Vector);
+ virtual void Enumerate(FILE *);
+ virtual Object * Copy(void);
ObjectState GetState(void);
void Reparent(Object *);
Dimension * GetAttachedDimension(void);