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)//, needUpdate(false)
33 Container::Container(const Container & copy): Object(copy.position, copy.parent)
35 // Use overloaded assignment operator
42 Container::~Container()
48 // Assignment operator
49 Container & Container::operator=(const Container & from)
51 // Take care of self-assignment
57 // Small problem with this approach: if the copied object goes out of scope,
58 // all of the objects we copied in here will be deleted. D'oh!
59 for(uint i=0; i<from.objects.size(); i++)
61 Object * object = from.objects[i];
63 // Need to copy the object here...
65 objects.push_back(object);
72 /*virtual*/ void Container::Draw(Painter * painter)
76 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
79 boundary = boundary.united((*i)->Extents());
82 if ((state == OSSelected) || hit)
85 painter->SetPen(QPen(Qt::magenta, 1.0, Qt::DashLine));
87 painter->SetPen(QPen(Qt::blue, 2.0, Qt::DashLine));
89 painter->SetBrush(QBrush(Qt::NoBrush));
90 painter->DrawPaddedRect(boundary);
95 /*virtual*/ Vector Container::Center(void)
102 We need at least *three* handles for this object:
107 We need to think about the intuitive way (if there is any) to grab and
108 manipulate a complex object like this... Need to think, "What should happen when
109 I click here and drag there?"
111 Also: should put the snap logic into the Object base class (as a static method)...
115 // Need to add checking here for clicking on a member of a group (Container),
116 // and checking for if it's a top level container (the DrawingView's document).
118 One approach is to check for the parent of the container: If it's NULL, then it's
119 the DrawingView's document. It might be better, though, to set a boolean like
120 isTopLevelContainer so that we can do things like edit members of a group without
121 having to ungroup them first (like Inkscape).
123 /*virtual*/ bool Container::Collided(Vector point)
125 objectWasDragged = false;
126 // Vector v1 = position - point;
128 bool collision = false;
130 // NOTE that this deletes the object on mouse down instead of mouse up. Have to
131 // check to see how it feels to do it that way...
134 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
136 if ((*i)->Collided(point))
138 printf("Container::Collided: Deleting object ($%X)\n", *i);
139 Object * objectToDelete = *i;
141 delete objectToDelete;
149 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
151 if ((*i)->Collided(point))
156 // We check to see if the container we're trying to access is the
157 // DrawingView's document. If so, we ignore the state of the container.
158 // Otherwise, we care about the state of the container. :-)
159 if (isTopLevelContainer)
163 state = (collision ? OSSelected : OSInactive);
165 if (state == OSSelected)
177 What we need to do is check for whether or not we're a top level container,
178 and override the passing of stuff into the objects held. So here, if we're *NOT*
179 a top level container, instead of passing PointerMoved to our contained objects,
180 we check to see if our bounds are met (for selection rectangle, e.g.).
182 Also, for things like being able to split point's hot spots we need to be able
183 to check for that crap in the top level container. Which means that objects can
184 still know how to move themselves, but they can also defer to their container
185 as well. Which also means that things like HitTest() need to be in the Object
186 class so that we can leverage that stuff here as well.
189 // The TLC is passing all mouse movement here, so we're doing the same here.
190 // Need to adjust all other objects to handle things correctly.
192 // One optimization that will need to be done eventually is to subdivide the screen
193 // into parts and keep subdividing until an acceptable number of objects lie within
194 // the slice. This way, the GUI will still be responsive and *not* have to test
195 // every object for collision.
196 /*virtual*/ void Container::PointerMoved(Vector point)
198 std::vector<Object *>::iterator i;
200 if (!isTopLevelContainer)
202 // check for selection rectangle too
203 if (selectionInProgress)
205 if (selection.contains(Extents()))
213 // No need to do any checking if we're already selected...
214 // if (state == OSSelected)
218 // needUpdate = true;
223 for(i=objects.begin(); i!=objects.end(); i++)
225 if ((*i)->HitTest(point))
227 // state = OSSelected;
234 needUpdate = (oldHit != hit ? true : false);
239 Vector delta = point - oldPoint;
241 for(i=objects.begin(); i!=objects.end(); i++)
242 (*i)->Translate(delta);
251 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
253 // if (objects[i]->GetState() == OSSelected)
254 (*i)->PointerMoved(point);
257 // Generic container doesn't need this???
258 // needUpdate = false;
262 /*virtual*/ void Container::PointerReleased(void)
264 if (!isTopLevelContainer)
271 draggingHandle1 = false;
272 draggingHandle2 = false;
274 // Here we check for just a click: If object was clicked and dragged, then
275 // revert to the old state (OSInactive). Otherwise, keep the new state that
278 Maybe it would be better to just check for "object was dragged" state and not
279 have to worry about keeping track of old states...
281 if (objectWasDragged)
283 //Note that the preceeding is unnecessary for a generic container!
286 // for(int i=0; i<(int)objects.size(); i++)
287 // objects[i]->PointerReleased();
288 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
289 (*i)->PointerReleased();
293 /*virtual*/ bool Container::NeedsUpdate(void)
295 // If this is *not* a top level container, then we treat it as an
297 if (!isTopLevelContainer)
302 // Search through objects for one that needs an update; if one is found,
303 // return immediately.
304 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
306 if ((*i)->NeedsUpdate())
314 /*virtual*/ void Container::Add(Object * object)
316 objects.push_back(object);
317 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
321 /*virtual*/ QRectF Container::Extents(void)
325 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
326 bounds = bounds.united((*i)->Extents());
332 void Container::Delete(Object * objectToDelete)
334 std::vector<Object *>::iterator i = objects.begin();
336 while (i != objects.end())
338 if (*i == objectToDelete)
341 delete objectToDelete;
350 void Container::DeleteSelectedItems(void)
352 std::vector<Object *>::iterator i = objects.begin();
354 while (i != objects.end())
356 if ((*i)->state == OSSelected)
367 void Container::Clear(void)
369 std::vector<Object *>::iterator i = objects.begin();
371 while (i != objects.end())
373 printf("Container: Deleting object ($%X)...\n", *i);
380 void Container::SelectAll(void)
382 for(unsigned int i=0; i<objects.size(); i++)
383 objects[i]->state = OSSelected;
387 void Container::DeselectAll(void)
389 for(unsigned int i=0; i<objects.size(); i++)
390 objects[i]->state = OSInactive;
394 int Container::ItemsSelected(void)
398 for(uint i=0; i<objects.size(); i++)
399 if (objects[i]->state == OSSelected)
406 Object * Container::SelectedItem(unsigned int index)
408 unsigned int selectedIndex = 0;
410 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
412 if ((*i)->state == OSSelected)
414 if (selectedIndex == index)
425 void Container::MoveContentsTo(Container * newContainer)
428 if (newContainer == NULL)
431 // Shuffle the contents of this container to the new one
432 // for(unsigned int i=0; i<objects.size(); i++)
433 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
435 newContainer->Add(*i);
436 (*i)->Reparent(newContainer);
439 // & clear our vector
444 void Container::MoveSelectedContentsTo(Container * newContainer)
447 if (newContainer == NULL)
450 // Shuffle the contents of this container to the new one
451 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
453 if ((*i)->state != OSSelected)
459 newContainer->Add(*i);
460 (*i)->Reparent(newContainer);
466 void Container::ResizeAllDimensions(double newSize)
468 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
470 if ((*i)->type == OTDimension)
471 ((Dimension *)(*i))->size = newSize;
472 if ((*i)->type == OTContainer)
473 ((Container *)(*i))->ResizeAllDimensions(newSize);
478 /*virtual*/ void Container::Enumerate(FILE * file)
480 // Only put "CONTAINER" markers if *not* the top level container
481 // if (parent != NULL)
482 if (!isTopLevelContainer)
483 fprintf(file, "CONTAINER\n");
485 for(uint i=0; i<objects.size(); i++)
486 objects[i]->Enumerate(file);
488 // if (parent != NULL)
489 if (!isTopLevelContainer)
490 fprintf(file, "ENDCONTAINER\n");