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