1 // container.cpp: Container object
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 03/30/2011 Created this file
12 // JLH 06/02/2011 Added code to delete objects in this container when they go
16 #include "container.h"
19 #include "dimension.h"
23 Container::Container(Vector p1, Object * p/*= NULL*/): Object(p1, p),
24 isTopLevelContainer(false),
25 dragging(false), draggingHandle1(false), draggingHandle2(false),
26 hit(false)//, needUpdate(false)
34 Container::Container(const Container & copy): Object(copy.position, copy.parent)
36 // Use overloaded assignment operator
43 Container::~Container()
49 // Assignment operator
50 Container & Container::operator=(const Container & from)
52 // Take care of self-assignment
58 // Small problem with this approach: if the copied object goes out of scope,
59 // all of the objects we copied in here will be deleted. D'oh!
60 // For this COPY constructor to be meaningful, we have to actually COPY the
61 // objects in this Container, not just MOVE a copy of the POINTER! D-:
62 std::vector<Object *>::const_iterator i;
64 // for(uint i=0; i<from.objects.size(); i++)
65 for(i=from.objects.begin(); i!=from.objects.end(); i++)
67 // Object * object = from.objects[i];
68 Object * object = (*i)->Copy();
70 // Need to actually COPY the object here, not copy the pointer only!!
71 // (which we do now, above :-P)
73 objects.push_back(object);
80 /*virtual*/ void Container::Draw(Painter * painter)
85 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
87 //printf("Containter::Draw item #%i [%X]...\n", a++, *i);
89 boundary = boundary.united((*i)->Extents());
92 if ((state == OSSelected) || hit)
95 painter->SetPen(QPen(Qt::magenta, 1.0, Qt::DashLine));
97 painter->SetPen(QPen(Qt::blue, 2.0, Qt::DashLine));
99 painter->SetBrush(QBrush(Qt::NoBrush));
100 painter->DrawPaddedRect(boundary);
105 /*virtual*/ Vector Container::Center(void)
112 We need at least *three* handles for this object:
117 We need to think about the intuitive way (if there is any) to grab and
118 manipulate a complex object like this... Need to think, "What should happen when
119 I click here and drag there?"
121 Also: should put the snap logic into the Object base class (as a static method)...
125 // Need to add checking here for clicking on a member of a group (Container),
126 // and checking for if it's a top level container (the DrawingView's document).
128 One approach is to check for the parent of the container: If it's NULL, then it's
129 the DrawingView's document. It might be better, though, to set a boolean like
130 isTopLevelContainer so that we can do things like edit members of a group without
131 having to ungroup them first (like Inkscape).
133 /*virtual*/ bool Container::Collided(Vector point)
135 objectWasDragged = false;
136 // Vector v1 = position - point;
138 bool collision = false;
140 // NOTE that this deletes the object on mouse down instead of mouse up. Have to
141 // check to see how it feels to do it that way...
144 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
146 if ((*i)->Collided(point))
148 printf("Container::Collided: Deleting object ($%X)\n", *i);
149 Object * objectToDelete = *i;
151 delete objectToDelete;
159 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
161 if ((*i)->Collided(point))
167 point = SnapPointToGrid(point);
169 // We check to see if the container we're trying to access is the
170 // DrawingView's document. If so, we ignore the state of the container.
171 // Otherwise, we care about the state of the container. :-)
172 if (isTopLevelContainer)
176 state = (collision ? OSSelected : OSInactive);
178 if (state == OSSelected)
190 What we need to do is check for whether or not we're a top level container,
191 and override the passing of stuff into the objects held. So here, if we're *NOT*
192 a top level container, instead of passing PointerMoved to our contained objects,
193 we check to see if our bounds are met (for selection rectangle, e.g.).
195 Also, for things like being able to split point's hot spots we need to be able
196 to check for that crap in the top level container. Which means that objects can
197 still know how to move themselves, but they can also defer to their container
198 as well. Which also means that things like HitTest() need to be in the Object
199 class so that we can leverage that stuff here as well.
202 // The TLC is passing all mouse movement here, so we're doing the same here.
203 // Need to adjust all other objects to handle things correctly.
205 // One optimization that will need to be done eventually is to subdivide the screen
206 // into parts and keep subdividing until an acceptable number of objects lie within
207 // the slice. This way, the GUI will still be responsive and *not* have to test
208 // every object for collision.
209 /*virtual*/ void Container::PointerMoved(Vector point)
211 std::vector<Object *>::iterator i;
213 if (!isTopLevelContainer)
215 // check for selection rectangle too
216 if (selectionInProgress)
218 if (selection.contains(Extents()))
226 // No need to do any checking if we're already selected...
227 // if (state == OSSelected)
231 // needUpdate = true;
236 for(i=objects.begin(); i!=objects.end(); i++)
238 if ((*i)->HitTest(point))
240 // state = OSSelected;
247 needUpdate = (oldHit != hit ? true : false);
252 Vector delta = point - oldPoint;
254 for(i=objects.begin(); i!=objects.end(); i++)
255 (*i)->Translate(delta);
264 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
266 // if (objects[i]->GetState() == OSSelected)
267 (*i)->PointerMoved(point);
270 // Generic container doesn't need this???
271 // needUpdate = false;
275 /*virtual*/ void Container::PointerReleased(void)
277 if (!isTopLevelContainer)
284 draggingHandle1 = false;
285 draggingHandle2 = false;
287 // Here we check for just a click: If object was clicked and dragged, then
288 // revert to the old state (OSInactive). Otherwise, keep the new state that
291 Maybe it would be better to just check for "object was dragged" state and not
292 have to worry about keeping track of old states...
294 if (objectWasDragged)
296 //Note that the preceeding is unnecessary for a generic container!
299 // for(int i=0; i<(int)objects.size(); i++)
300 // objects[i]->PointerReleased();
301 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
302 (*i)->PointerReleased();
306 /*virtual*/ bool Container::NeedsUpdate(void)
308 // If this is *not* a top level container, then we treat it as an
310 if (!isTopLevelContainer)
315 // Search through objects for one that needs an update; if one is found,
316 // return immediately.
317 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
319 if ((*i)->NeedsUpdate())
327 /*virtual*/ void Container::Add(Object * object)
329 objects.push_back(object);
330 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
334 /*virtual*/ QRectF Container::Extents(void)
338 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
339 bounds = bounds.united((*i)->Extents());
345 void Container::Delete(Object * objectToDelete)
347 std::vector<Object *>::iterator i = objects.begin();
349 while (i != objects.end())
351 if (*i == objectToDelete)
354 delete objectToDelete;
363 void Container::DeleteSelectedItems(void)
365 std::vector<Object *>::iterator i = objects.begin();
367 while (i != objects.end())
369 if ((*i)->state == OSSelected)
380 void Container::Clear(void)
382 std::vector<Object *>::iterator i = objects.begin();
384 while (i != objects.end())
386 printf("Container: Deleting object ($%X)...\n", *i);
393 void Container::SelectAll(void)
395 for(unsigned int i=0; i<objects.size(); i++)
396 objects[i]->state = OSSelected;
400 void Container::DeselectAll(void)
402 for(unsigned int i=0; i<objects.size(); i++)
403 objects[i]->state = OSInactive;
407 int Container::ItemsSelected(void)
411 for(uint i=0; i<objects.size(); i++)
412 if (objects[i]->state == OSSelected)
419 Object * Container::SelectedItem(unsigned int index)
421 unsigned int selectedIndex = 0;
423 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
425 if ((*i)->state == OSSelected)
427 if (selectedIndex == index)
438 void Container::MoveContentsTo(Container * newContainer)
441 if (newContainer == NULL)
444 // Shuffle the contents of this container to the new one
445 // for(unsigned int i=0; i<objects.size(); i++)
446 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
448 newContainer->Add(*i);
449 (*i)->Reparent(newContainer);
452 // & clear our vector
457 void Container::MoveSelectedContentsTo(Container * newContainer)
460 if (newContainer == NULL)
463 // Shuffle the contents of this container to the new one
464 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
466 if ((*i)->state != OSSelected)
472 newContainer->Add(*i);
473 (*i)->Reparent(newContainer);
479 void Container::CopySelectedContentsTo(Container * newContainer)
482 if (newContainer == NULL)
485 // Shuffle the contents of this container to the new one
486 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
488 if ((*i)->state == OSSelected)
489 newContainer->Add((*i)->Copy());
494 void Container::ResizeAllDimensions(double newSize)
496 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
498 if ((*i)->type == OTDimension)
499 ((Dimension *)(*i))->size = newSize;
500 if ((*i)->type == OTContainer)
501 ((Container *)(*i))->ResizeAllDimensions(newSize);
506 /*virtual*/ void Container::Enumerate(FILE * file)
508 // Only put "CONTAINER" markers if *not* the top level container
509 // if (parent != NULL)
510 if (!isTopLevelContainer)
511 fprintf(file, "CONTAINER %i\n", layer);
513 for(uint i=0; i<objects.size(); i++)
514 objects[i]->Enumerate(file);
516 // if (parent != NULL)
517 if (!isTopLevelContainer)
518 fprintf(file, "ENDCONTAINER\n");
522 /*virtual*/ Object * Container::Copy(void)
524 #warning "!!! This doesn't take care of attached Dimensions !!!"
526 This is a real problem. While having a pointer in the Dimension to this line's points
527 is fast & easy, it creates a huge problem when trying to replicate an object like this.
529 Maybe a way to fix that then, is to have reference numbers instead of pointers. That
530 way, if you copy them, ... you might still have problems. Because you can't be sure if
531 a copy will be persistant or not, you then *definitely* do not want them to have the
532 same reference number.
534 Container * c = new Container(position, parent);
540 /*virtual*/ void Container::Mirror(Point p1, Point p2)
542 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
543 (*i)->Mirror(p1, p2);
547 /*virtual*/ void Container::Save(void)
551 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
556 /*virtual*/ void Container::Restore(void)
560 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)