]> Shamusworld >> Repos - architektonas/blob - src/container.cpp
Fixes to accomodate object connections.
[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
21
22 Container::Container(Vector p1, Object * p/*= NULL*/): Object(p1, p),
23         dragging(false), draggingHandle1(false), draggingHandle2(false)//, needUpdate(false)
24 {
25 }
26
27
28 // Copy constructor
29 Container::Container(const Container & copy): Object(copy.position, copy.parent)
30 {
31         // Use overloaded assignment operator
32         *this = copy;
33 }
34
35
36 Container::~Container()
37 {
38         Clear();
39 }
40
41
42 // Assignment operator
43 Container & Container::operator=(const Container & from)
44 {
45         // Take care of self-assignment
46         if (this == &from)
47                 return *this;
48
49         Clear();
50
51         // Small problem with this approach: if the copied object goes out of scope,
52         // all of the objects we copied in here will be deleted. D'oh!
53         for(uint i=0; i<from.objects.size(); i++)
54         {
55                 Object * object = from.objects[i];
56
57                 // Need to copy the object here...
58
59                 objects.push_back(object);
60         }
61
62         return *this;
63 }
64
65
66 /*virtual*/ void Container::Draw(Painter * painter)
67 {
68         for(int i=0; i<(int)objects.size(); i++)
69         {
70 //printf("Container: About to draw (object = $%X)\n", objects[i]);
71                 objects[i]->Draw(painter);
72         }
73 }
74
75
76 /*virtual*/ Vector Container::Center(void)
77 {
78         return position;
79 }
80
81 /*
82  We need at least *three* handles for this object:
83  - one for moving
84  - one for resizing
85  - one for rotation
86
87 We need to think about the intuitive way (if there is any) to grab and
88 manipulate a complex object like this... Need to think, "What should happen when
89 I click here and drag there?"
90
91 Also: should put the snap logic into the Object base class (as a static method)...
92 */
93
94
95 /*virtual*/ bool Container::Collided(Vector point)
96 {
97         objectWasDragged = false;
98         Vector v1 = position - point;
99
100 #if 0
101         if (state == OSInactive)
102         {
103 //printf("Circle: pp = %lf, length = %lf, distance = %lf\n", parameterizedPoint, lineSegment.Magnitude(), distance);
104 //printf("      v1.Magnitude = %lf, v2.Magnitude = %lf\n", v1.Magnitude(), v2.Magnitude());
105 //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);
106 //printf("      \n", );
107 //How to translate this into pixels from Document space???
108 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
109 //the caller knows about the zoom factor and all that good kinda crap
110                 if (v1.Magnitude() < 10.0)
111                 {
112                         oldState = state;
113                         state = OSSelected;
114                         oldPoint = position; //maybe "position"?
115                         draggingHandle1 = true;
116                         return true;
117                 }
118                 else if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
119                 {
120                         oldState = state;
121                         state = OSSelected;
122                         oldPoint = point;
123                         dragging = true;
124                         return true;
125                 }
126         }
127         else if (state == OSSelected)
128         {
129                 // Here we test for collision with handles as well! (SOON!)
130 /*
131 Like so:
132                 if (v1.Magnitude() < 2.0) // Handle #1
133                 else if (v2.Magnitude() < 2.0) // Handle #2
134 */
135                 if ((v1.Magnitude() < radius + 2.0) && (v1.Magnitude() > radius - 2.0))
136                 {
137                         oldState = state;
138 //                      state = OSInactive;
139                         oldPoint = point;
140                         dragging = true;
141                         return true;
142                 }
143         }
144 #else
145         bool collision = false;
146
147         // NOTE that this deletes the object on mouse down instead of mouse up. Have to
148         // check to see how it feels to do it that way...
149         if (deleteActive)
150         {
151                 for(int i=0; i<(int)objects.size(); i++)
152                 {
153                         if (objects[i]->Collided(point))
154                         {
155 #if 0
156 Dimension * dimension = objects[i]->GetAttachedDimension();
157 #endif
158                                 Object * objectToDelete = objects[i];
159                                 objects.erase(objects.begin() + i);     // Calls the destructor, (deletes the object, I presume... O_o) [NOPE! SURE DOESN'T!]
160                                 delete objectToDelete;
161
162 // If this object had an attached dimension, reattach it to another object, if any...
163 // The only problem with that approach is if the object it gets attached to is deleted,
164 // it will call the dimension to use a NULL pointer and BLAMMO
165 #if 0
166 if (dimension)
167 {
168         Vector p1 = dimension->GetPoint1();
169         Vector p2 = dimension->GetPoint2();
170         for(int j=0; j<(int)objects.size(); j++)
171         {
172                 Vector * objectP1 = objects[i]->GetPointAt(p1);
173                 Vector * objectP2 = objects[i]->GetPointAt(p2);
174
175                 if (objectP1)
176                         dimension->SetPoint1(objectP1);
177
178                 if (objectP2)
179                         dimension->SetPoint2(objectP2);
180         }
181 }
182 #endif
183                                 // This only allows deleting objects one at a time...
184                                 break;
185                                 // however, this way of doing things could be problematic if we don't
186                                 // delete one at a time... Need to come up with a better approach.
187                         }
188                 }
189         }
190         else
191         {
192                 for(int i=0; i<(int)objects.size(); i++)
193                 {
194                         if (objects[i]->Collided(point))
195                                 collision = true;
196                 }
197         }
198 #endif
199
200         // Do we decouple the state of the generic container from the objects inside??? Mebbe.
201         state = OSInactive;
202 //      return false;
203         return collision;
204 }
205
206
207 // The TLC is passing all mouse movement here, so we're doing the same here.
208 // Need to adjust all other objects to handle things correctly.
209
210 // One optimization that will need to be done eventually is to subdivide the screen
211 // into parts and keep subdividing until an acceptable number of objects lie within
212 // the slice. This way, the GUI will still be responsive and *not* have to test
213 // every object for collision.
214 /*virtual*/ void Container::PointerMoved(Vector point)
215 {
216 //      objectWasDragged = true;
217 //printf("CONTAINER: PointerMoved()\n");
218
219         for(int i=0; i<(int)objects.size(); i++)
220         {
221 //              if (objects[i]->GetState() == OSSelected)
222                         objects[i]->PointerMoved(point);
223         }
224
225         // Generic container doesn't need this???
226 //      needUpdate = false;
227 }
228
229
230 /*virtual*/ void Container::PointerReleased(void)
231 {
232         dragging = false;
233         draggingHandle1 = false;
234         draggingHandle2 = false;
235
236         // Here we check for just a click: If object was clicked and dragged, then
237         // revert to the old state (OSInactive). Otherwise, keep the new state that
238         // we set.
239 /*Maybe it would be better to just check for "object was dragged" state and not have to worry
240 about keeping track of old states...
241 */
242         if (objectWasDragged)
243                 state = oldState;
244 //Note that the preceeding is unnecessary for a generic container!
245
246         for(int i=0; i<(int)objects.size(); i++)
247                 objects[i]->PointerReleased();
248 }
249
250
251 /*virtual*/ bool Container::NeedsUpdate(void)
252 {
253         needUpdate = false;
254
255         for(uint i=0; i<objects.size(); i++)
256         {
257                 if (objects[i]->NeedsUpdate())
258                         needUpdate = true;
259         }
260
261         return needUpdate;
262 }
263
264
265 /*virtual*/ void Container::Add(Object * object)
266 {
267         objects.push_back(object);
268 printf("Container: Added object (=$%X). size = %li\n", object, objects.size());
269 }
270
271
272 void Container::Clear(void)
273 {
274         // No memory leaks!
275         while (objects.size() > 0)
276         {
277 printf("Container: Deleting object ($%X)...\n", objects[0]);
278                 delete objects[0];
279                 objects.erase(objects.begin());
280         }
281 }
282
283
284 /*virtual*/ void Container::Enumerate(FILE * file)
285 {
286         // Only put "CONTAINER" markers if *not* the top level container
287         if (parent != NULL)
288                 fprintf(file, "CONTAINER\n");
289
290         for(uint i=0; i<objects.size(); i++)
291                 objects[i]->Enumerate(file);
292
293         if (parent != NULL)
294                 fprintf(file, "ENDCONTAINER\n");
295 }
296