]> Shamusworld >> Repos - architektonas/blob - src/container.cpp
Fixed delete key to delete selected objects.
[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         bool collision = false;
120
121         // NOTE that this deletes the object on mouse down instead of mouse up. Have to
122         // check to see how it feels to do it that way...
123         if (deleteActive)
124         {
125                 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
126                 {
127                         if ((*i)->Collided(point))
128                         {
129 printf("Container::Collided: Deleting object ($%X)\n", *i);
130                                 Object * objectToDelete = *i;
131                                 objects.erase(i);
132                                 delete objectToDelete;
133                         }
134                         else
135                                 i++;
136                 }
137         }
138         else
139         {
140                 for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
141                 {
142                         if ((*i)->Collided(point))
143                                 collision = true;
144                 }
145         }
146
147         // Do we decouple the state of the generic container from the objects inside??? Mebbe.
148         state = OSInactive;
149         return collision;
150 }
151
152
153 // The TLC is passing all mouse movement here, so we're doing the same here.
154 // Need to adjust all other objects to handle things correctly.
155
156 // One optimization that will need to be done eventually is to subdivide the screen
157 // into parts and keep subdividing until an acceptable number of objects lie within
158 // the slice. This way, the GUI will still be responsive and *not* have to test
159 // every object for collision.
160 /*virtual*/ void Container::PointerMoved(Vector point)
161 {
162 //      objectWasDragged = true;
163 //printf("CONTAINER: PointerMoved()\n");
164
165         for(int i=0; i<(int)objects.size(); i++)
166         {
167 //              if (objects[i]->GetState() == OSSelected)
168                         objects[i]->PointerMoved(point);
169         }
170
171         // Generic container doesn't need this???
172 //      needUpdate = false;
173 }
174
175
176 /*virtual*/ void Container::PointerReleased(void)
177 {
178         dragging = false;
179         draggingHandle1 = false;
180         draggingHandle2 = false;
181
182         // Here we check for just a click: If object was clicked and dragged, then
183         // revert to the old state (OSInactive). Otherwise, keep the new state that
184         // we set.
185 /*Maybe it would be better to just check for "object was dragged" state and not have to worry
186 about keeping track of old states...
187 */
188         if (objectWasDragged)
189                 state = oldState;
190 //Note that the preceeding is unnecessary for a generic container!
191
192         for(int i=0; i<(int)objects.size(); i++)
193                 objects[i]->PointerReleased();
194 }
195
196
197 /*virtual*/ bool Container::NeedsUpdate(void)
198 {
199         needUpdate = false;
200
201         for(uint i=0; i<objects.size(); i++)
202         {
203                 if (objects[i]->NeedsUpdate())
204                         needUpdate = true;
205         }
206
207         return needUpdate;
208 }
209
210
211 /*virtual*/ void Container::Add(Object * object)
212 {
213         objects.push_back(object);
214 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
215 }
216
217
218 #if 0
219 /*virtual*/ ObjectType Container::Type(void)
220 {
221         return OTContainer;
222 }
223 #endif
224
225
226 void Container::Delete(Object * objectToDelete)
227 {
228         std::vector<Object *>::iterator i = objects.begin();
229
230         while (i != objects.end())
231         {
232                 if (*i == objectToDelete)
233                 {
234                         objects.erase(i);
235                         delete objectToDelete;
236                         return;
237                 }
238
239                 i++;
240         }
241 }
242
243
244 void Container::DeleteSelectedItems(void)
245 {
246         std::vector<Object *>::iterator i = objects.begin();
247
248         while (i != objects.end())
249         {
250                 if ((*i)->state == OSSelected)
251                 {
252                         delete *i;
253                         objects.erase(i);
254                 }
255                 else
256                         i++;
257         }
258 }
259
260
261 void Container::Clear(void)
262 {
263 #if 0
264         // No memory leaks!
265         while (objects.size() > 0)
266         {
267 printf("Container: Deleting object ($%X)...\n", objects[0]);
268                 delete objects[0];
269                 objects.erase(objects.begin());
270         }
271 #else
272         std::vector<Object *>::iterator i = objects.begin();
273
274         while (i != objects.end())
275         {
276 printf("Container: Deleting object ($%X)...\n", *i);
277                 delete (*i);
278                 objects.erase(i);
279         }
280 #endif
281 }
282
283
284 void Container::SelectAll(void)
285 {
286         for(unsigned int i=0; i<objects.size(); i++)
287                 objects[i]->state = OSSelected;
288 }
289
290
291 void Container::DeselectAll(void)
292 {
293         for(unsigned int i=0; i<objects.size(); i++)
294                 objects[i]->state = OSInactive;
295 }
296
297
298 int Container::ItemsSelected(void)
299 {
300         int selected = 0;
301
302         for(uint i=0; i<objects.size(); i++)
303                 if (objects[i]->state == OSSelected)
304                         selected++;
305
306         return selected;
307 }
308
309
310 Object * Container::SelectedItem(unsigned int index)
311 {
312         unsigned int selectedIndex = 0;
313
314         for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end(); i++)
315         {
316                 if ((*i)->state == OSSelected)
317                 {
318                         if (selectedIndex == index)
319                                 return *i;
320                         else
321                                 selectedIndex++;
322                 }
323         }
324
325         return NULL;
326 }
327
328
329 void Container::MoveContentsTo(Container * newContainer)
330 {
331         // Sanity check
332         if (newContainer == NULL)
333                 return;
334
335         // Shuffle the contents of this container to the new one
336         for(unsigned int i=0; i<objects.size(); i++)
337                 newContainer->Add(objects[i]);
338
339         // & clear our vector
340         objects.clear();
341 }
342
343
344 void Container::MoveSelectedContentsTo(Container * newContainer)
345 {
346         // Sanity check
347         if (newContainer == NULL)
348                 return;
349
350         // Shuffle the contents of this container to the new one
351         for(std::vector<Object *>::iterator i=objects.begin(); i!=objects.end();)
352         {
353                 if ((*i)->state != OSSelected)
354                 {
355                         i++;
356                         continue;
357                 }
358
359                 newContainer->Add(*i);
360                 objects.erase(i);
361         }
362 }
363
364
365 /*virtual*/ void Container::Enumerate(FILE * file)
366 {
367         // Only put "CONTAINER" markers if *not* the top level container
368         if (parent != NULL)
369                 fprintf(file, "CONTAINER\n");
370
371         for(uint i=0; i<objects.size(); i++)
372                 objects[i]->Enumerate(file);
373
374         if (parent != NULL)
375                 fprintf(file, "ENDCONTAINER\n");
376 }
377