]> Shamusworld >> Repos - architektonas/blob - src/circle.cpp
35c9d7c2e53f224dd97323229027b37c246ce88a
[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 L. 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 Circle::~Circle()
28 {
29 }
30
31 /*virtual*/ void Circle::Draw(Painter * painter)
32 {
33         if (state == OSSelected || hitCircle || hitCenter)
34                 painter->SetPen(QPen(Qt::red, 2.0, Qt::DotLine));
35         else
36                 painter->SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
37
38         // Draw handles (if needed)
39         if (state == OSSelected || hitCenter)
40                 painter->DrawHandle(position);
41
42         if (state == OSSelected && draggingEdge && objectWasDragged)
43                 painter->DrawHandle(dragPoint);
44
45         // & finally, draw the object!
46         painter->DrawEllipse(position, radius, radius);
47 }
48
49 /*virtual*/ Vector Circle::Center(void)
50 {
51         return position;
52 }
53
54 /*virtual*/ bool Circle::Collided(Vector point)
55 {
56         // We can assume this, since this is a mouse down event here.
57         objectWasDragged = false;
58         HitTest(point);
59
60         draggingCenter = hitCenter;
61         draggingEdge = hitCircle;
62
63         if (hitCenter || hitCircle)
64         {
65                 dragPoint = point;
66                 oldState = state;
67                 state = OSSelected;
68                 return true;
69         }
70
71         // We didn't hit anything, so deselect this object and report failure to hit
72         state = OSInactive;
73         return false;
74 }
75
76 /*virtual*/ void Circle::PointerMoved(Vector point)
77 {
78         // Hit test tells us what we hit (if anything) through boolean variables. It
79         // also tells us whether or not the state changed.
80         needUpdate = HitTest(point);
81         objectWasDragged = (draggingEdge | draggingCenter);
82
83         if (draggingEdge)
84                 radius = Vector::Magnitude(point, position);
85         else if (draggingCenter)
86                 position = point;
87
88         // Save this point so the rendering code knows where to draw the handle...
89         dragPoint = point;
90 }
91
92 /*virtual*/ void Circle::PointerReleased(void)
93 {
94         // Mouse went up, so our dragging is done (if any *was* done, that is)
95         draggingEdge = draggingCenter = false;
96         hitCenter = hitCircle = false;
97
98         // If the object was dragged, then revert to the old state.
99         // Otherwise, we were probably just clicked, and want to stay in the selected state.
100         if (objectWasDragged)
101                 state = oldState;
102 }
103
104 bool Circle::HitTest(Point point)
105 {
106         SaveState();
107         hitCenter = hitCircle = false;
108         double length = Vector::Magnitude(position, point);
109 //printf("Circle::length = %lf, radius = %lf\n", length, radius);
110 //How to translate this into pixels from Document space???
111 //Maybe we need to pass a scaling factor in here from the caller? That would make sense, as
112 //the caller knows about the zoom factor and all that good kinda crap
113 /*
114 Document passes in the correct Cartesian coordinates being pointed to by the mouse.
115 So all we have to be concerned with is properly scaling our hot zones/handle sizes,
116 since we generally *don't* want those to scale with the zoom level. ;-)
117 */
118         if (length < 8.0)
119                 hitCenter = true;
120         else if ((length < (radius + 2.0)) && (length > (radius - 2.0)))
121                 hitCircle = true;
122
123         return StateChanged();
124 }
125
126 void Circle::SaveState(void)
127 {
128         oldHitCenter = hitCenter;
129         oldHitCircle = hitCircle;
130 }
131
132 bool Circle::StateChanged(void)
133 {
134         if ((hitCenter != oldHitCenter) || (hitCircle != oldHitCircle))
135                 return true;
136
137         return false;
138 }