]> Shamusworld >> Repos - architektonas/blob - src/circle.cpp
Added 1st stab at grouping capability.
[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         // Hit test tells us what we hit (if anything) through boolean variables. It
91         // also tells us whether or not the state changed.
92         needUpdate = HitTest(point);
93         objectWasDragged = (draggingEdge | draggingCenter);
94
95         if (draggingEdge)
96                 radius = Vector::Magnitude(point, position);
97         else if (draggingCenter)
98                 position = point;
99
100         // Save this point so the rendering code knows where to draw the handle...
101         dragPoint = point;
102 }
103
104
105 /*virtual*/ void Circle::PointerReleased(void)
106 {
107         // Mouse went up, so our dragging is done (if any *was* done, that is)
108         draggingEdge = draggingCenter = false;
109         hitCenter = hitCircle = false;
110
111         // If the object was dragged, then revert to the old state.
112         // Otherwise, we were probably just clicked, and want to stay in the selected state.
113         if (objectWasDragged)
114                 state = oldState;
115 }
116
117
118 /*virtual*/ QRectF Circle::Extents(void)
119 {
120         return QRectF(QPointF(position.x - radius, position.y - radius), QPointF(position.x + radius, position.y + radius));
121 }
122
123
124 #if 0
125 /*virtual*/ ObjectType Circle::Type(void)
126 {
127         return OTCircle;
128 }
129 #endif
130
131
132 bool Circle::HitTest(Point point)
133 {
134         SaveState();
135         hitCenter = hitCircle = false;
136         double length = Vector::Magnitude(position, point);
137 //printf("Circle::length = %lf, radius = %lf\n", length, radius);
138 //How to translate this into pixels from Document space???
139 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
140 //the caller knows about the zoom factor and all that good kinda crap
141 /*
142 Document passes in the correct Cartesian coordinates being pointed to by the mouse.
143 So all we have to be concerned with is properly scaling our hot zones/handle sizes,
144 since we generally *don't* want those to scale with the zoom level. ;-)
145
146 What is going on here?
147 If we're zoomed out to, say, 50%, & our radius is 10.0 (absolute), then on screen
148 the radius will be 5.0. By multiplying the length by the zoom factor, we align our
149 pointed at length with our on screen length.
150 */
151         if ((length * Painter::zoom) < 8.0)
152                 hitCenter = true;
153 //wrong:        else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
154 /*NB: The following should be identical to what we have down below, but it doesn't work out that way... :-P */
155 //close, but no else if (((length * Painter::zoom) < ((radius * Painter::zoom) + 2.0)) && ((length * Painter::zoom) > ((radius * Painter::zoom) - 2.0)))
156 //really wrong! else if (((length * Painter::zoom) < (radius + 2.0)) && ((length * Painter::zoom) > (radius - 2.0)))
157 // close again, but sill no     else if (((length * Painter::zoom) < ((radius + 2.0) * Painter::zoom)) && ((length * Painter::zoom) > ((radius - 2.0) * Painter::zoom)))
158         else if ((fabs(length - radius) * Painter::zoom) < 2.0)
159                 hitCircle = true;
160
161         return StateChanged();
162 }
163
164
165 void Circle::SaveState(void)
166 {
167         oldHitCenter = hitCenter;
168         oldHitCircle = hitCircle;
169 }
170
171
172 bool Circle::StateChanged(void)
173 {
174         if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
175                 return true;
176
177         return false;
178 }
179
180
181 /*virtual*/ void Circle::Enumerate(FILE * file)
182 {
183         fprintf(file, "CIRCLE (%lf,%lf) %lf\n", position.x, position.y, radius);
184 }
185