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)
32 Container::Container(const Container & copy): Object(copy.position, copy.parent)
34 // Use overloaded assignment operator
40 Container::~Container()
46 // Assignment operator
47 Container & Container::operator=(const Container & from)
49 // Take care of self-assignment
55 // Small problem with this approach: if the copied object goes out of scope,
56 // all of the objects we copied in here will be deleted. D'oh!
57 for(uint i=0; i<from.objects.size(); i++)
59 Object * object = from.objects[i];
61 // Need to copy the object here...
63 objects.push_back(object);
70 /*virtual*/ void Container::Draw(Painter * painter)
74 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
77 boundary = boundary.united((*i)->Extents());
80 if ((state == OSSelected) || hit)
83 painter->SetPen(QPen(Qt::magenta, 1.0, Qt::DashLine));
85 painter->SetPen(QPen(Qt::blue, 2.0, Qt::DashLine));
87 painter->SetBrush(QBrush(Qt::NoBrush));
88 painter->DrawRect(boundary);
93 /*virtual*/ Vector Container::Center(void)
100 We need at least *three* handles for this object:
105 We need to think about the intuitive way (if there is any) to grab and
106 manipulate a complex object like this... Need to think, "What should happen when
107 I click here and drag there?"
109 Also: should put the snap logic into the Object base class (as a static method)...
113 // Need to add checking here for clicking on a member of a group (Container),
114 // and checking for if it's a top level container (the DrawingView's document).
116 One approach is to check for the parent of the container: If it's NULL, then it's
117 the DrawingView's document. It might be better, though, to set a boolean like
118 isTopLevelContainer so that we can do things like edit members of a group without
119 having to ungroup them first (like Inkscape).
121 /*virtual*/ bool Container::Collided(Vector point)
123 objectWasDragged = false;
124 // Vector v1 = position - point;
126 bool collision = false;
128 // NOTE that this deletes the object on mouse down instead of mouse up. Have to
129 // check to see how it feels to do it that way...
132 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
134 if ((*i)->Collided(point))
136 printf("Container::Collided: Deleting object ($%X)\n", *i);
137 Object * objectToDelete = *i;
139 delete objectToDelete;
147 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
149 if ((*i)->Collided(point))
154 // We check to see if the container we're trying to access is the
155 // DrawingView's document. If so, we ignore the state of the container.
156 // Otherwise, we care about the state of the container. :-)
157 if (isTopLevelContainer)
161 state = (collision ? OSSelected : OSInactive);
163 if (state == OSSelected)
175 What we need to do is check for whether or not we're a top level container,
176 and override the passing of stuff into the objects held. So here, if we're *NOT*
177 a top level container, instead of passing PointerMoved to our contained objects,
178 we check to see if our bounds are met (for selection rectangle, e.g.).
180 Also, for things like being able to split point's hot spots we need to be able
181 to check for that crap in the top level container. Which means that objects can
182 still know how to move themselves, but they can also defer to their container
183 as well. Which also means that things like HitTest() need to be in the Object
184 class so that we can leverage that stuff here as well.
187 // The TLC is passing all mouse movement here, so we're doing the same here.
188 // Need to adjust all other objects to handle things correctly.
190 // One optimization that will need to be done eventually is to subdivide the screen
191 // into parts and keep subdividing until an acceptable number of objects lie within
192 // the slice. This way, the GUI will still be responsive and *not* have to test
193 // every object for collision.
194 /*virtual*/ void Container::PointerMoved(Vector point)
196 std::vector<Object *>::iterator i;
198 if (!isTopLevelContainer)
200 // check for selection rectangle too
201 if (selectionInProgress)
203 if (selection.contains(Extents()))
211 // No need to do any checking if we're already selected...
212 // if (state == OSSelected)
216 // needUpdate = true;
221 for(i=objects.begin(); i!=objects.end(); i++)
223 if ((*i)->HitTest(point))
225 // state = OSSelected;
232 needUpdate = (oldHit != hit ? true : false);
237 Vector delta = point - oldPoint;
239 for(i=objects.begin(); i!=objects.end(); i++)
240 (*i)->Translate(delta);
249 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
251 // if (objects[i]->GetState() == OSSelected)
252 (*i)->PointerMoved(point);
255 // Generic container doesn't need this???
256 // needUpdate = false;
260 /*virtual*/ void Container::PointerReleased(void)
262 if (!isTopLevelContainer)
269 draggingHandle1 = false;
270 draggingHandle2 = false;
272 // Here we check for just a click: If object was clicked and dragged, then
273 // revert to the old state (OSInactive). Otherwise, keep the new state that
276 Maybe it would be better to just check for "object was dragged" state and not
277 have to worry about keeping track of old states...
279 if (objectWasDragged)
281 //Note that the preceeding is unnecessary for a generic container!
284 // for(int i=0; i<(int)objects.size(); i++)
285 // objects[i]->PointerReleased();
286 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
287 (*i)->PointerReleased();
291 /*virtual*/ bool Container::NeedsUpdate(void)
293 // If this is *not* a top level container, then we treat it as an
295 if (!isTopLevelContainer)
300 // Search through objects for one that needs an update; if one is found,
301 // return immediately.
302 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
304 if ((*i)->NeedsUpdate())
312 /*virtual*/ void Container::Add(Object * object)
314 objects.push_back(object);
315 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
319 /*virtual*/ QRectF Container::Extents(void)
323 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
324 bounds = bounds.united((*i)->Extents());
330 void Container::Delete(Object * objectToDelete)
332 std::vector<Object *>::iterator i = objects.begin();
334 while (i != objects.end())
336 if (*i == objectToDelete)
339 delete objectToDelete;
348 void Container::DeleteSelectedItems(void)
350 std::vector<Object *>::iterator i = objects.begin();
352 while (i != objects.end())
354 if ((*i)->state == OSSelected)
365 void Container::Clear(void)
367 std::vector<Object *>::iterator i = objects.begin();
369 while (i != objects.end())
371 printf("Container: Deleting object ($%X)...\n", *i);
378 void Container::SelectAll(void)
380 for(unsigned int i=0; i<objects.size(); i++)
381 objects[i]->state = OSSelected;
385 void Container::DeselectAll(void)
387 for(unsigned int i=0; i<objects.size(); i++)
388 objects[i]->state = OSInactive;
392 int Container::ItemsSelected(void)
396 for(uint i=0; i<objects.size(); i++)
397 if (objects[i]->state == OSSelected)
404 Object * Container::SelectedItem(unsigned int index)
406 unsigned int selectedIndex = 0;
408 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
410 if ((*i)->state == OSSelected)
412 if (selectedIndex == index)
423 void Container::MoveContentsTo(Container * newContainer)
426 if (newContainer == NULL)
429 // Shuffle the contents of this container to the new one
430 // for(unsigned int i=0; i<objects.size(); i++)
431 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
433 newContainer->Add(*i);
434 (*i)->Reparent(newContainer);
437 // & clear our vector
442 void Container::MoveSelectedContentsTo(Container * newContainer)
445 if (newContainer == NULL)
448 // Shuffle the contents of this container to the new one
449 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
451 if ((*i)->state != OSSelected)
457 newContainer->Add(*i);
458 (*i)->Reparent(newContainer);
464 void Container::ResizeAllDimensions(double newSize)
466 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
468 if ((*i)->type == OTDimension)
469 ((Dimension *)(*i))->size = newSize;
470 if ((*i)->type == OTContainer)
471 ((Container *)(*i))->ResizeAllDimensions(newSize);
476 /*virtual*/ void Container::Enumerate(FILE * file)
478 // Only put "CONTAINER" markers if *not* the top level container
479 // if (parent != NULL)
480 if (!isTopLevelContainer)
481 fprintf(file, "CONTAINER\n");
483 for(uint i=0; i<objects.size(); i++)
484 objects[i]->Enumerate(file);
486 // if (parent != NULL)
487 if (!isTopLevelContainer)
488 fprintf(file, "ENDCONTAINER\n");