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