1// States.cpp
2
3#include <View.h>
4
5#include "States.h"
6
7// constructor
8State::State()
9	: fValid(false),
10	  fEditing(true),
11	  fTracking(TRACKING_NONE),
12	  fStartPoint(-1.0, -1.0),
13	  fEndPoint(-1.0, -1.0),
14	  fColor((rgb_color){ 0, 0, 0, 255 }),
15	  fDrawingMode(B_OP_COPY),
16	  fFill(true),
17	  fPenSize(1.0)
18{
19}
20
21// destructor
22State::~State()
23{
24}
25
26// Init
27void
28State::Init(rgb_color color, drawing_mode mode, bool fill, float penSize)
29{
30	fColor = color;
31	fDrawingMode = mode;
32	fFill = fill;
33	fPenSize = penSize;
34}
35
36// MouseDown
37void
38State::MouseDown(BPoint where)
39{
40	where.x = floorf(where.x + 0.5);
41	where.y = floorf(where.y + 0.5);
42
43	if (_HitTest(where, fStartPoint)) {
44		fTracking = TRACKING_START;
45		fClickOffset = fStartPoint - where;
46	} else if (_HitTest(where, fEndPoint)) {
47		fTracking = TRACKING_END;
48		fClickOffset = fEndPoint - where;
49	} else if (!fValid) {
50		fTracking = TRACKING_END;
51		fStartPoint = fEndPoint = where;
52		fClickOffset.Set(0.0, 0.0);
53	}
54}
55
56// MouseUp
57void
58State::MouseUp()
59{
60	fTracking = TRACKING_NONE;
61}
62
63// MouseMoved
64void
65State::MouseMoved(BPoint where)
66{
67	where.x = floorf(where.x + 0.5);
68	where.y = floorf(where.y + 0.5);
69
70	if (fTracking == TRACKING_START) {
71		fStartPoint = where + fClickOffset;
72		fValid = true;
73	} else if (fTracking == TRACKING_END) {
74		fEndPoint = where + fClickOffset;
75		fValid = true;
76	}
77}
78
79// SetColor
80void
81State::SetColor(rgb_color color)
82{
83	fColor = color;
84}
85
86// SetDrawingMode
87void
88State::SetDrawingMode(drawing_mode mode)
89{
90	fDrawingMode = mode;
91}
92
93// SetFill
94void
95State::SetFill(bool fill)
96{
97	fFill = fill;
98}
99
100// SetPenSize
101void
102State::SetPenSize(float penSize)
103{
104	fPenSize = penSize;
105}
106
107// SetEditing
108void
109State::SetEditing(bool editing)
110{
111	fEditing = editing;
112}
113
114// Bounds
115BRect
116State::Bounds() const
117{
118	if (fValid) {
119		BRect r = _ValidRect();
120		float inset = -2.0; // for the dots
121		if (!SupportsFill() || !fFill) {
122			inset = min_c(inset, -ceilf(fPenSize / 2.0));
123		}
124		r.InsetBy(inset, inset);
125		return r;
126	}
127	return BRect(0.0, 0.0, -1.0, -1.0);
128}
129
130// Draw
131void
132State::Draw(BView* view) const
133{
134	if (fValid && fEditing) {
135		_RenderDot(view, fStartPoint);
136		_RenderDot(view, fEndPoint);
137	}
138}
139
140// _ValidRect
141BRect
142State::_ValidRect() const
143{
144	return BRect(min_c(fStartPoint.x, fEndPoint.x),
145				 min_c(fStartPoint.y, fEndPoint.y),
146				 max_c(fStartPoint.x, fEndPoint.x),
147				 max_c(fStartPoint.y, fEndPoint.y));
148}
149
150// _RenderDot
151void
152State::_RenderDot(BView* view, BPoint where) const
153{
154	view->SetHighColor(0, 0, 0, 255);
155	view->SetPenSize(1.0);
156	view->SetDrawingMode(B_OP_COPY);
157	BRect r(where, where);
158	r.InsetBy(-2.0, -2.0);
159	view->StrokeRect(r);
160	view->SetHighColor(255, 255, 255, 255);
161	r.InsetBy(1.0, 1.0);
162	view->FillRect(r);
163}
164
165// _AdjustViewState
166void
167State::_AdjustViewState(BView* view) const
168{
169	view->SetDrawingMode(fDrawingMode);
170	view->SetHighColor(fColor);
171
172	if (!SupportsFill() || !fFill)
173		view->SetPenSize(fPenSize);
174}
175
176// _HitTest
177bool
178State::_HitTest(BPoint where, BPoint point) const
179{
180	BRect r(point, point);
181	r.InsetBy(-8.0, -8.0);
182	return r.Contains(where);
183}
184
185// LineState
186class LineState : public State {
187 public:
188					LineState()
189						: State() {}
190
191	virtual	void	Draw(BView* view) const
192					{
193						if (fValid) {
194							_AdjustViewState(view);
195							view->StrokeLine(fStartPoint, fEndPoint);
196						}
197						State::Draw(view);
198					}
199	virtual	bool	SupportsFill() const
200					{
201						return false;
202					}
203};
204
205// RectState
206class RectState : public State {
207 public:
208					RectState()
209						: State() {}
210
211	virtual	void	Draw(BView* view) const
212					{
213						if (fValid) {
214							_AdjustViewState(view);
215							if (fFill)
216								view->FillRect(_ValidRect());
217							else
218								view->StrokeRect(_ValidRect());
219						}
220						State::Draw(view);
221					}
222};
223
224// RoundRectState
225class RoundRectState : public State {
226 public:
227					RoundRectState()
228						: State() {}
229
230	virtual	void	Draw(BView* view) const
231					{
232						if (fValid) {
233							_AdjustViewState(view);
234							BRect r = _ValidRect();
235							float radius = min_c(r.Width() / 3.0, r.Height() / 3.0);
236							if (fFill)
237								view->FillRoundRect(r, radius, radius);
238							else
239								view->StrokeRoundRect(r, radius, radius);
240						}
241						State::Draw(view);
242					}
243};
244
245// EllipseState
246class EllipseState : public State {
247 public:
248					EllipseState()
249						: State() {}
250
251	virtual	void	Draw(BView* view) const
252					{
253						if (fValid) {
254							_AdjustViewState(view);
255							if (fFill)
256								view->FillEllipse(_ValidRect());
257							else
258								view->StrokeEllipse(_ValidRect());
259						}
260						State::Draw(view);
261					}
262};
263
264// StateFor
265State*
266State::StateFor(int32 objectType, rgb_color color, drawing_mode mode,
267				bool fill, float penSize)
268{
269	State* state = NULL;
270	switch (objectType) {
271		case OBJECT_LINE:
272			state = new LineState();
273			break;
274		case OBJECT_RECT:
275			state = new RectState();
276			break;
277		case OBJECT_ROUND_RECT:
278			state = new RoundRectState();
279			break;
280		case OBJECT_ELLIPSE:
281			state = new EllipseState();
282			break;
283		default:
284			break;
285	}
286	if (state)
287		state->Init(color, mode, fill, penSize);
288	return state;
289}
290
291