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++)
75 // for(int i=0; i<(int)objects.size(); i++)
78 //printf("Container: About to draw (object = $%X)\n", objects[i]);
79 objects[i]->Draw(painter);
80 bounds = bounds.united(objects[i].RectangularExtents());
83 boundary = boundary.united((*i)->Extents());
87 if (state == OSSelected)
89 painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DashLine));
90 painter->SetBrush(QBrush(Qt::NoBrush));
91 painter->DrawRect(boundary);
96 /*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)
173 // The TLC is passing all mouse movement here, so we're doing the same here.
174 // Need to adjust all other objects to handle things correctly.
176 // One optimization that will need to be done eventually is to subdivide the screen
177 // into parts and keep subdividing until an acceptable number of objects lie within
178 // the slice. This way, the GUI will still be responsive and *not* have to test
179 // every object for collision.
180 /*virtual*/ void Container::PointerMoved(Vector point)
182 // objectWasDragged = true;
183 //printf("CONTAINER: PointerMoved()\n");
185 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
186 // for(int i=0; i<(int)objects.size(); i++)
188 //// if (objects[i]->GetState() == OSSelected)
189 // objects[i]->PointerMoved(point);
190 (*i)->PointerMoved(point);
193 // Generic container doesn't need this???
194 // needUpdate = false;
198 /*virtual*/ void Container::PointerReleased(void)
201 draggingHandle1 = false;
202 draggingHandle2 = false;
204 // Here we check for just a click: If object was clicked and dragged, then
205 // revert to the old state (OSInactive). Otherwise, keep the new state that
207 /*Maybe it would be better to just check for "object was dragged" state and not have to worry
208 about keeping track of old states...
210 if (objectWasDragged)
212 //Note that the preceeding is unnecessary for a generic container!
214 for(int i=0; i<(int)objects.size(); i++)
215 objects[i]->PointerReleased();
219 /*virtual*/ bool Container::NeedsUpdate(void)
221 // Search through objects for one that needs an update; if one is found,
222 // return immediately.
223 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
225 if ((*i)->NeedsUpdate())
233 /*virtual*/ void Container::Add(Object * object)
235 objects.push_back(object);
236 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
240 void Container::Delete(Object * objectToDelete)
242 std::vector<Object *>::iterator i = objects.begin();
244 while (i != objects.end())
246 if (*i == objectToDelete)
249 delete objectToDelete;
258 void Container::DeleteSelectedItems(void)
260 std::vector<Object *>::iterator i = objects.begin();
262 while (i != objects.end())
264 if ((*i)->state == OSSelected)
275 void Container::Clear(void)
277 std::vector<Object *>::iterator i = objects.begin();
279 while (i != objects.end())
281 printf("Container: Deleting object ($%X)...\n", *i);
288 void Container::SelectAll(void)
290 for(unsigned int i=0; i<objects.size(); i++)
291 objects[i]->state = OSSelected;
295 void Container::DeselectAll(void)
297 for(unsigned int i=0; i<objects.size(); i++)
298 objects[i]->state = OSInactive;
302 int Container::ItemsSelected(void)
306 for(uint i=0; i<objects.size(); i++)
307 if (objects[i]->state == OSSelected)
314 Object * Container::SelectedItem(unsigned int index)
316 unsigned int selectedIndex = 0;
318 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
320 if ((*i)->state == OSSelected)
322 if (selectedIndex == index)
333 void Container::MoveContentsTo(Container * newContainer)
336 if (newContainer == NULL)
339 // Shuffle the contents of this container to the new one
340 for(unsigned int i=0; i<objects.size(); i++)
341 newContainer->Add(objects[i]);
343 // & clear our vector
348 void Container::MoveSelectedContentsTo(Container * newContainer)
351 if (newContainer == NULL)
354 // Shuffle the contents of this container to the new one
355 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
357 if ((*i)->state != OSSelected)
363 newContainer->Add(*i);
369 /*virtual*/ void Container::Enumerate(FILE * file)
371 // Only put "CONTAINER" markers if *not* the top level container
373 fprintf(file, "CONTAINER\n");
375 for(uint i=0; i<objects.size(); i++)
376 objects[i]->Enumerate(file);
379 fprintf(file, "ENDCONTAINER\n");