]> Shamusworld >> Repos - architektonas/blob - src/container.cpp
Added 1st stab at grouping capability.
[architektonas] / src / container.cpp
1 // container.cpp: Container object
2 //
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
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
13 //                  out of scope
14 //
15
16 #include "container.h"
17
18 #include <QtGui>
19 #include "dimension.h"
20 #include "painter.h"
21
22
23 Container::Container(Vector p1, Object * p/*= NULL*/): Object(p1, p),
24         dragging(false), draggingHandle1(false), draggingHandle2(false)//, needUpdate(false)
25 {
26         type = OTContainer;
27 }
28
29
30 // Copy constructor
31 Container::Container(const Container & copy): Object(copy.position, copy.parent)
32 {
33         // Use overloaded assignment operator
34         *this = copy;
35         type = OTContainer;
36 }
37
38
39 Container::~Container()
40 {
41         Clear();
42 }
43
44
45 // Assignment operator
46 Container & Container::operator=(const Container & from)
47 {
48         // Take care of self-assignment
49         if (this == &from)
50                 return *this;
51
52         Clear();
53
54         // Small problem with this approach: if the copied object goes out of scope,
55         // all of the objects we copied in here will be deleted. D'oh!
56         for(uint i=0; i<from.objects.size(); i++)
57         {
58                 Object * object = from.objects[i];
59
60                 // Need to copy the object here...
61
62                 objects.push_back(object);
63         }
64
65         return *this;
66 }
67
68
69 /*virtual*/ void Container::Draw(Painter * painter)
70 {
71         QRectF boundary;
72
73         for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
74 //      for(int i=0; i<(int)objects.size(); i++)
75         {
76 #if 0
77 //printf("Container: About to draw (object = $%X)\n", objects[i]);
78                 objects[i]->Draw(painter);
79                 bounds = bounds.united(objects[i].RectangularExtents());
80 #else
81                 (*i)->Draw(painter);
82                 boundary = boundary.united((*i)->Extents());
83 #endif
84         }
85
86         if (state == OSSelected)
87         {
88                 painter->SetPen(QPen(Qt::magenta, 2.0, Qt::DashLine));
89                 painter->SetBrush(QBrush(Qt::NoBrush));
90                 painter->DrawRect(boundary);
91         }
92 }
93
94
95 /*virtual*/ Vector Container::Center(void)
96 {
97         return position;
98 }
99
100 /*
101  We need at least *three* handles for this object:
102  - one for moving
103  - one for resizing
104  - one for rotation
105
106 We need to think about the intuitive way (if there is any) to grab and
107 manipulate a complex object like this... Need to think, "What should happen when
108 I click here and drag there?"
109
110 Also: should put the snap logic into the Object base class (as a static method)...
111 */
112
113
114 /*virtual*/ bool Container::Collided(Vector point)
115 {
116         objectWasDragged = false;
117         Vector v1 = position - point;
118
119 #if 0
120         if (state == OSInactive)
121         {
122 //printf("Circle: pp = %lf, length = %lf, distance = %lf\n", parameterizedPoint, lineSegment.Magnitude(), distance);
123 //printf("      v1.Magnitude = %lf, v2.Magnitude = %lf\n", v1.Magnitude(), v2.Magnitude());
124 //printf("      point = %lf,%lf,%lf; p1 = %lf,%lf,%lf; p2 = %lf,%lf,%lf\n", point.x, point.y, point.z, position.x, position.y, position.z, endpoint.x, endpoint.y, endpoint.z);
125 //printf("      \n", );
126 //How to translate this into pixels from Document space???
127 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
128 //the caller knows about the zoom factor and all that good kinda crap
129                 if (v1.Magnitude() < 10.0)
130                 {
131                         oldState = state;
132                         state = OSSelected;
133                         oldPoint = position; //maybe "position"?
134                         draggingHandle1 = true;
135                         return true;
136                 }
137                 else if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
138                 {
139                         oldState = state;
140                         state = OSSelected;
141                         oldPoint = point;
142                         dragging = true;
143                         return true;
144                 }
145         }
146         else if (state == OSSelected)
147         {
148                 // Here we test for collision with handles as well! (SOON!)
149 /*
150 Like so:
151                 if (v1.Magnitude() < 2.0) // Handle #1
152                 else if (v2.Magnitude() < 2.0) // Handle #2
153 */
154                 if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
155                 {
156                         oldState = state;
157 //                      state = OSInactive;
158                         oldPoint = point;
159                         dragging = true;
160                         return true;
161                 }
162         }
163 #else
164         bool collision = false;
165
166         // NOTE that this deletes the object on mouse down instead of mouse up. Have to
167         // check to see how it feels to do it that way...
168         if (deleteActive)
169         {
170                 for(int i=0; i<(int)objects.size(); i++)
171                 {
172                         if (objects[i]->Collided(point))
173                         {
174 #if 0
175 Dimension * dimension = objects[i]->GetAttachedDimension();
176 #endif
177                                 Object * objectToDelete = objects[i];
178                                 objects.erase(objects.begin() + i);     // Calls the destructor, (deletes the object, I presume... O_o) [NOPE! SURE DOESN'T!]
179                                 delete objectToDelete;
180
181 // If this object had an attached dimension, reattach it to another object, if any...
182 // The only problem with that approach is if the object it gets attached to is deleted,
183 // it will call the dimension to use a NULL pointer and BLAMMO
184 #if 0
185 if (dimension)
186 {
187         Vector p1 = dimension->GetPoint1();
188         Vector p2 = dimension->GetPoint2();
189         for(int j=0; j<(int)objects.size(); j++)
190         {
191                 Vector * objectP1 = objects[i]->GetPointAt(p1);
192                 Vector * objectP2 = objects[i]->GetPointAt(p2);
193
194                 if (objectP1)
195                         dimension->SetPoint1(objectP1);
196
197                 if (objectP2)
198                         dimension->SetPoint2(objectP2);
199         }
200 }
201 #endif
202                                 // This only allows deleting objects one at a time...
203                                 break;
204                                 // however, this way of doing things could be problematic if we don't
205                                 // delete one at a time... Need to come up with a better approach.
206                         }
207                 }
208         }
209         else
210         {
211                 for(int i=0; i<(int)objects.size(); i++)
212                 {
213                         if (objects[i]->Collided(point))
214                                 collision = true;
215                 }
216         }
217 #endif
218
219         // Do we decouple the state of the generic container from the objects inside??? Mebbe.
220         state = OSInactive;
221 //      return false;
222         return collision;
223 }
224
225
226 // The TLC is passing all mouse movement here, so we're doing the same here.
227 // Need to adjust all other objects to handle things correctly.
228
229 // One optimization that will need to be done eventually is to subdivide the screen
230 // into parts and keep subdividing until an acceptable number of objects lie within
231 // the slice. This way, the GUI will still be responsive and *not* have to test
232 // every object for collision.
233 /*virtual*/ void Container::PointerMoved(Vector point)
234 {
235 //      objectWasDragged = true;
236 //printf("CONTAINER: PointerMoved()\n");
237
238         for(int i=0; i<(int)objects.size(); i++)
239         {
240 //              if (objects[i]->GetState() == OSSelected)
241                         objects[i]->PointerMoved(point);
242         }
243
244         // Generic container doesn't need this???
245 //      needUpdate = false;
246 }
247
248
249 /*virtual*/ void Container::PointerReleased(void)
250 {
251         dragging = false;
252         draggingHandle1 = false;
253         draggingHandle2 = false;
254
255         // Here we check for just a click: If object was clicked and dragged, then
256         // revert to the old state (OSInactive). Otherwise, keep the new state that
257         // we set.
258 /*Maybe it would be better to just check for "object was dragged" state and not have to worry
259 about keeping track of old states...
260 */
261         if (objectWasDragged)
262                 state = oldState;
263 //Note that the preceeding is unnecessary for a generic container!
264
265         for(int i=0; i<(int)objects.size(); i++)
266                 objects[i]->PointerReleased();
267 }
268
269
270 /*virtual*/ bool Container::NeedsUpdate(void)
271 {
272         needUpdate = false;
273
274         for(uint i=0; i<objects.size(); i++)
275         {
276                 if (objects[i]->NeedsUpdate())
277                         needUpdate = true;
278         }
279
280         return needUpdate;
281 }
282
283
284 /*virtual*/ void Container::Add(Object * object)
285 {
286         objects.push_back(object);
287 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
288 }
289
290
291 #if 0
292 /*virtual*/ ObjectType Container::Type(void)
293 {
294         return OTContainer;
295 }
296 #endif
297
298
299 void Container::Delete(Object * objectToDelete)
300 {
301 #if 0
302         //this is wrong
303         for(unsigned int i=0; i<objects.size(); i++)
304         {
305                 if (objects[i] == objectToDelete)
306                 {
307                         objects.erase(i);
308                         delete objectToDelete;
309                         return;
310                 }
311         }
312 #else
313         std::vector<Object *>::iterator i = objects.begin();
314
315         while (i != objects.end())
316         {
317                 if (*i == objectToDelete)
318                 {
319                         objects.erase(i);
320                         delete objectToDelete;
321                         return;
322                 }
323
324                 i++;
325         }
326 #endif
327 }
328
329
330 void Container::Clear(void)
331 {
332         // No memory leaks!
333         while (objects.size() > 0)
334         {
335 printf("Container: Deleting object ($%X)...\n", objects[0]);
336                 delete objects[0];
337                 objects.erase(objects.begin());
338         }
339 }
340
341
342 void Container::SelectAll(void)
343 {
344         for(unsigned int i=0; i<objects.size(); i++)
345                 objects[i]->state = OSSelected;
346 }
347
348
349 void Container::DeselectAll(void)
350 {
351         for(unsigned int i=0; i<objects.size(); i++)
352                 objects[i]->state = OSInactive;
353 }
354
355
356 int Container::ItemsSelected(void)
357 {
358         int selected = 0;
359
360         for(uint i=0; i<objects.size(); i++)
361                 if (objects[i]->state == OSSelected)
362                         selected++;
363
364         return selected;
365 }
366
367
368 /*ObjectType Container::SelectedItemType(unsigned int index)
369 {
370         if (index >= objects.size())
371                 return OTNone;
372
373         return objects[index]->Type();
374 }*/
375
376
377 Object * Container::SelectedItem(unsigned int index)
378 {
379 //      if (index >= objects.size())
380 //              return NULL;
381
382         unsigned int selectedIndex = 0;
383
384         for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
385         {
386                 if ((*i)->state == OSSelected)
387                 {
388                         if (selectedIndex == index)
389                                 return *i;
390                         else
391                                 selectedIndex++;
392                 }
393         }
394
395         return NULL;
396 }
397
398
399 void Container::MoveContentsTo(Container * newContainer)
400 {
401         // Sanity check
402         if (newContainer == NULL)
403                 return;
404
405         // Shuffle the contents of this container to the new one
406         for(unsigned int i=0; i<objects.size(); i++)
407                 newContainer->Add(objects[i]);
408
409         // & clear our vector
410         objects.clear();
411 }
412
413
414 void Container::MoveSelectedContentsTo(Container * newContainer)
415 {
416         // Sanity check
417         if (newContainer == NULL)
418                 return;
419
420         // Shuffle the contents of this container to the new one
421         for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
422         {
423                 if ((*i)->state != OSSelected)
424                 {
425                         i++;
426                         continue;
427                 }
428
429                 newContainer->Add(*i);
430                 objects.erase(i);
431         }
432 }
433
434
435 /*virtual*/ void Container::Enumerate(FILE * file)
436 {
437         // Only put "CONTAINER" markers if *not* the top level container
438         if (parent != NULL)
439                 fprintf(file, "CONTAINER\n");
440
441         for(uint i=0; i<objects.size(); i++)
442                 objects[i]->Enumerate(file);
443
444         if (parent != NULL)
445                 fprintf(file, "ENDCONTAINER\n");
446 }
447