]> Shamusworld >> Repos - architektonas/blob - src/circle.cpp
Initial stab at getting Circle to respond to selection rectangle.
[architektonas] / src / circle.cpp
1 // circle.cpp: Circle 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/28/2011  Created this file
12 // JLH  09/26/2011  Added hover effects
13 // JLH  09/26/2011  Major cleanup of this class
14 //
15
16 #include "circle.h"
17
18 #include <QtGui>
19 #include "painter.h"
20
21
22 Circle::Circle(Vector p1, double r, Object * p/*= NULL*/): Object(p1, p), radius(r),
23         draggingEdge(false), draggingCenter(false), hitCenter(false), hitCircle(false)
24 {
25         type = OTCircle;
26 }
27
28
29 Circle::~Circle()
30 {
31 }
32
33
34 /*virtual*/ void Circle::Draw(Painter * painter)
35 {
36         if (state == OSSelected || hitCircle || hitCenter)
37                 painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
38         else
39                 painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
40
41         // Hatch/Fill...
42 //      QBrush brush(Qt::DiagCrossPattern);
43 //      brush.setColor(QColor(255, 255, 0));
44 //      painter->SetBrush(brush);
45         painter->SetBrush(QBrush(Qt::NoBrush));
46
47         // Draw the object...
48         painter->DrawEllipse(position, radius, radius);
49
50         // & draw handles (if needed)
51         if (state == OSSelected || hitCenter)
52                 painter->DrawHandle(position);
53
54         if (state == OSSelected && draggingEdge && objectWasDragged)
55                 painter->DrawHandle(dragPoint);
56 }
57
58
59 /*virtual*/ Vector Circle::Center(void)
60 {
61         return position;
62 }
63
64
65 /*virtual*/ bool Circle::Collided(Vector point)
66 {
67         // We can assume this, since this is a mouse down event here.
68         objectWasDragged = false;
69         HitTest(point);
70
71         draggingCenter = hitCenter;
72         draggingEdge = hitCircle;
73
74         if (hitCenter || hitCircle)
75         {
76                 dragPoint = point;
77                 oldState = state;
78                 state = OSSelected;
79                 return true;
80         }
81
82         // We didn't hit anything, so deselect this object and report failure to hit
83         state = OSInactive;
84         return false;
85 }
86
87
88 /*virtual*/ void Circle::PointerMoved(Vector point)
89 {
90         if (selectionInProgress)
91         {
92                 // Check for whether or not the rect contains this circle
93                 if (selection.normalized().contains(Extents()))
94                         state = OSSelected;
95                 else
96                         state = OSInactive;
97
98                 return;
99         }
100
101         // Hit test tells us what we hit (if anything) through boolean variables. It
102         // also tells us whether or not the state changed.
103         needUpdate = HitTest(point);
104         objectWasDragged = (draggingEdge | draggingCenter);
105
106         if (draggingEdge)
107                 radius = Vector::Magnitude(point, position);
108         else if (draggingCenter)
109                 position = point;
110
111         // Save this point so the rendering code knows where to draw the handle...
112         dragPoint = point;
113 }
114
115
116 /*virtual*/ void Circle::PointerReleased(void)
117 {
118         // Mouse went up, so our dragging is done (if any *was* done, that is)
119         draggingEdge = draggingCenter = false;
120         hitCenter = hitCircle = false;
121
122         // If the object was dragged, then revert to the old state.
123         // Otherwise, we were probably just clicked, and want to stay in the selected state.
124         if (objectWasDragged)
125                 state = oldState;
126 }
127
128
129 /*virtual*/ QRectF Circle::Extents(void)
130 {
131         return QRectF(QPointF(position.x - radius, position.y - radius), QPointF(position.x + radius, position.y + radius));
132 }
133
134
135 #if 0
136 /*virtual*/ ObjectType Circle::Type(void)
137 {
138         return OTCircle;
139 }
140 #endif
141
142
143 bool Circle::HitTest(Point point)
144 {
145         SaveState();
146         hitCenter = hitCircle = false;
147         double length = Vector::Magnitude(position, point);
148 //printf("Circle::length = %lf, radius = %lf\n", length, radius);
149 //How to translate this into pixels from Document space???
150 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
151 //the caller knows about the zoom factor and all that good kinda crap
152 /*
153 Document passes in the correct Cartesian coordinates being pointed to by the mouse.
154 So all we have to be concerned with is properly scaling our hot zones/handle sizes,
155 since we generally *don't* want those to scale with the zoom level. ;-)
156
157 What is going on here?
158 If we're zoomed out to, say, 50%, & our radius is 10.0 (absolute), then on screen
159 the radius will be 5.0. By multiplying the length by the zoom factor, we align our
160 pointed at length with our on screen length.
161 */
162         if ((length * Painter::zoom) < 8.0)
163                 hitCenter = true;
164 //wrong:        else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
165 /*NB: The following should be identical to what we have down below, but it doesn't work out that way... :-P */
166 //close, but no else if (((length * Painter::zoom) < ((radius * Painter::zoom) + 2.0)) && ((length * Painter::zoom) > ((radius * Painter::zoom) - 2.0)))
167 //really wrong! else if (((length * Painter::zoom) < (radius + 2.0)) && ((length * Painter::zoom) > (radius - 2.0)))
168 // close again, but sill no     else if (((length * Painter::zoom) < ((radius + 2.0) * Painter::zoom)) && ((length * Painter::zoom) > ((radius - 2.0) * Painter::zoom)))
169         else if ((fabs(length - radius) * Painter::zoom) < 2.0)
170                 hitCircle = true;
171
172         return StateChanged();
173 }
174
175
176 void Circle::SaveState(void)
177 {
178         oldHitCenter = hitCenter;
179         oldHitCircle = hitCircle;
180 }
181
182
183 bool Circle::StateChanged(void)
184 {
185         if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
186                 return true;
187
188         return false;
189 }
190
191
192 /*virtual*/ void Circle::Enumerate(FILE * file)
193 {
194         fprintf(file, "CIRCLE (%lf,%lf) %lf\n", position.x, position.y, radius);
195 }
196