xref: /haiku/src/apps/icon-o-matic/transformable/PerspectiveBox.cpp (revision c6c2c0428420c1a7a9b16a843b41ab26903bc5fb)
1*c6c2c042SZardshard /*
2*c6c2c042SZardshard  * Copyright 2006-2009, 2023, Haiku.
3*c6c2c042SZardshard  * Distributed under the terms of the MIT License.
4*c6c2c042SZardshard  *
5*c6c2c042SZardshard  * Authors:
6*c6c2c042SZardshard  *		Stephan Aßmus <superstippi@gmx.de>
7*c6c2c042SZardshard  *		Zardshard
8*c6c2c042SZardshard  */
9*c6c2c042SZardshard 
10*c6c2c042SZardshard #include "PerspectiveBox.h"
11*c6c2c042SZardshard 
12*c6c2c042SZardshard #include <stdio.h>
13*c6c2c042SZardshard 
14*c6c2c042SZardshard #include <agg_trans_affine.h>
15*c6c2c042SZardshard #include <agg_math.h>
16*c6c2c042SZardshard 
17*c6c2c042SZardshard #include <View.h>
18*c6c2c042SZardshard 
19*c6c2c042SZardshard #include "CanvasView.h"
20*c6c2c042SZardshard #include "StateView.h"
21*c6c2c042SZardshard #include "support.h"
22*c6c2c042SZardshard #include "PerspectiveBoxStates.h"
23*c6c2c042SZardshard #include "PerspectiveCommand.h"
24*c6c2c042SZardshard #include "PerspectiveTransformer.h"
25*c6c2c042SZardshard 
26*c6c2c042SZardshard 
27*c6c2c042SZardshard #define INSET 8.0
28*c6c2c042SZardshard 
29*c6c2c042SZardshard 
30*c6c2c042SZardshard using std::nothrow;
31*c6c2c042SZardshard using namespace PerspectiveBoxStates;
32*c6c2c042SZardshard 
33*c6c2c042SZardshard 
PerspectiveBox(CanvasView * view,PerspectiveTransformer * parent)34*c6c2c042SZardshard PerspectiveBox::PerspectiveBox(CanvasView* view,
35*c6c2c042SZardshard 		PerspectiveTransformer* parent)
36*c6c2c042SZardshard 	:
37*c6c2c042SZardshard 	Manipulator(NULL),
38*c6c2c042SZardshard 
39*c6c2c042SZardshard 	fLeftTop(parent->LeftTop()),
40*c6c2c042SZardshard 	fRightTop(parent->RightTop()),
41*c6c2c042SZardshard 	fLeftBottom(parent->LeftBottom()),
42*c6c2c042SZardshard 	fRightBottom(parent->RightBottom()),
43*c6c2c042SZardshard 
44*c6c2c042SZardshard 	fCurrentCommand(NULL),
45*c6c2c042SZardshard 	fCurrentState(NULL),
46*c6c2c042SZardshard 
47*c6c2c042SZardshard 	fDragging(false),
48*c6c2c042SZardshard 	fMousePos(-10000.0, -10000.0),
49*c6c2c042SZardshard 	fModifiers(0),
50*c6c2c042SZardshard 
51*c6c2c042SZardshard 	fPreviousBox(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN),
52*c6c2c042SZardshard 
53*c6c2c042SZardshard 	fCanvasView(view),
54*c6c2c042SZardshard 	fPerspective(parent),
55*c6c2c042SZardshard 
56*c6c2c042SZardshard 	fDragLTState(new DragCornerState(this, &fLeftTop)),
57*c6c2c042SZardshard 	fDragRTState(new DragCornerState(this, &fRightTop)),
58*c6c2c042SZardshard 	fDragLBState(new DragCornerState(this, &fLeftBottom)),
59*c6c2c042SZardshard 	fDragRBState(new DragCornerState(this, &fRightBottom))
60*c6c2c042SZardshard {
61*c6c2c042SZardshard }
62*c6c2c042SZardshard 
63*c6c2c042SZardshard 
~PerspectiveBox()64*c6c2c042SZardshard PerspectiveBox::~PerspectiveBox()
65*c6c2c042SZardshard {
66*c6c2c042SZardshard 	_NotifyDeleted();
67*c6c2c042SZardshard 
68*c6c2c042SZardshard 	delete fCurrentCommand;
69*c6c2c042SZardshard 	delete fDragLTState;
70*c6c2c042SZardshard 	delete fDragRTState;
71*c6c2c042SZardshard 	delete fDragLBState;
72*c6c2c042SZardshard 	delete fDragRBState;
73*c6c2c042SZardshard }
74*c6c2c042SZardshard 
75*c6c2c042SZardshard 
76*c6c2c042SZardshard void
Draw(BView * into,BRect updateRect)77*c6c2c042SZardshard PerspectiveBox::Draw(BView* into, BRect updateRect)
78*c6c2c042SZardshard {
79*c6c2c042SZardshard 	// convert to canvas view coordinates
80*c6c2c042SZardshard 	BPoint lt = fLeftTop;
81*c6c2c042SZardshard 	BPoint rt = fRightTop;
82*c6c2c042SZardshard 	BPoint lb = fLeftBottom;
83*c6c2c042SZardshard 	BPoint rb = fRightBottom;
84*c6c2c042SZardshard 
85*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&lt);
86*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&rt);
87*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&lb);
88*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&rb);
89*c6c2c042SZardshard 
90*c6c2c042SZardshard 	into->SetDrawingMode(B_OP_COPY);
91*c6c2c042SZardshard 	into->SetHighColor(255, 255, 255, 255);
92*c6c2c042SZardshard 	into->SetLowColor(0, 0, 0, 255);
93*c6c2c042SZardshard 
94*c6c2c042SZardshard 	_StrokeBWLine(into, lt, rt);
95*c6c2c042SZardshard 	_StrokeBWLine(into, rt, rb);
96*c6c2c042SZardshard 	_StrokeBWLine(into, rb, lb);
97*c6c2c042SZardshard 	_StrokeBWLine(into, lb, lt);
98*c6c2c042SZardshard 
99*c6c2c042SZardshard 	_StrokeBWPoint(into, lt, 0.0);
100*c6c2c042SZardshard 	_StrokeBWPoint(into, rt, 90.0);
101*c6c2c042SZardshard 	_StrokeBWPoint(into, rb, 180.0);
102*c6c2c042SZardshard 	_StrokeBWPoint(into, lb, 270.0);
103*c6c2c042SZardshard }
104*c6c2c042SZardshard 
105*c6c2c042SZardshard 
106*c6c2c042SZardshard // #pragma mark -
107*c6c2c042SZardshard 
108*c6c2c042SZardshard 
109*c6c2c042SZardshard bool
MouseDown(BPoint where)110*c6c2c042SZardshard PerspectiveBox::MouseDown(BPoint where)
111*c6c2c042SZardshard {
112*c6c2c042SZardshard 	fCanvasView->FilterMouse(&where);
113*c6c2c042SZardshard 	fCanvasView->ConvertToCanvas(&where);
114*c6c2c042SZardshard 
115*c6c2c042SZardshard 	fDragging = true;
116*c6c2c042SZardshard 	if (fCurrentState) {
117*c6c2c042SZardshard 		fCurrentState->SetOrigin(where);
118*c6c2c042SZardshard 
119*c6c2c042SZardshard 		delete fCurrentCommand;
120*c6c2c042SZardshard 		fCurrentCommand = new (nothrow) PerspectiveCommand(this, fPerspective,
121*c6c2c042SZardshard 			fPerspective->LeftTop(), fPerspective->RightTop(),
122*c6c2c042SZardshard 			fPerspective->LeftBottom(), fPerspective->RightBottom());
123*c6c2c042SZardshard 	}
124*c6c2c042SZardshard 
125*c6c2c042SZardshard 	return true;
126*c6c2c042SZardshard }
127*c6c2c042SZardshard 
128*c6c2c042SZardshard 
129*c6c2c042SZardshard void
MouseMoved(BPoint where)130*c6c2c042SZardshard PerspectiveBox::MouseMoved(BPoint where)
131*c6c2c042SZardshard {
132*c6c2c042SZardshard 	fCanvasView->FilterMouse(&where);
133*c6c2c042SZardshard 	fCanvasView->ConvertToCanvas(&where);
134*c6c2c042SZardshard 
135*c6c2c042SZardshard 	if (fMousePos != where) {
136*c6c2c042SZardshard 		fMousePos = where;
137*c6c2c042SZardshard 		if (fCurrentState) {
138*c6c2c042SZardshard 			fCurrentState->DragTo(fMousePos, fModifiers);
139*c6c2c042SZardshard 			fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
140*c6c2c042SZardshard 		}
141*c6c2c042SZardshard 	}
142*c6c2c042SZardshard }
143*c6c2c042SZardshard 
144*c6c2c042SZardshard 
145*c6c2c042SZardshard Command*
MouseUp()146*c6c2c042SZardshard PerspectiveBox::MouseUp()
147*c6c2c042SZardshard {
148*c6c2c042SZardshard 	fDragging = false;
149*c6c2c042SZardshard 	return FinishTransaction();
150*c6c2c042SZardshard }
151*c6c2c042SZardshard 
152*c6c2c042SZardshard 
153*c6c2c042SZardshard bool
MouseOver(BPoint where)154*c6c2c042SZardshard PerspectiveBox::MouseOver(BPoint where)
155*c6c2c042SZardshard {
156*c6c2c042SZardshard 	fCanvasView->ConvertToCanvas(&where);
157*c6c2c042SZardshard 
158*c6c2c042SZardshard 	fMousePos = where;
159*c6c2c042SZardshard 	fCurrentState = _DragStateFor(where, fCanvasView->ZoomLevel());
160*c6c2c042SZardshard 
161*c6c2c042SZardshard 	if (fCurrentState) {
162*c6c2c042SZardshard 		fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
163*c6c2c042SZardshard 		return true;
164*c6c2c042SZardshard 	}
165*c6c2c042SZardshard 
166*c6c2c042SZardshard 	return false;
167*c6c2c042SZardshard }
168*c6c2c042SZardshard 
169*c6c2c042SZardshard 
170*c6c2c042SZardshard // #pragma mark -
171*c6c2c042SZardshard 
172*c6c2c042SZardshard 
173*c6c2c042SZardshard BRect
Bounds()174*c6c2c042SZardshard PerspectiveBox::Bounds()
175*c6c2c042SZardshard {
176*c6c2c042SZardshard 	// convert from canvas view coordinates
177*c6c2c042SZardshard 	BPoint lt = fLeftTop;
178*c6c2c042SZardshard 	BPoint rt = fRightTop;
179*c6c2c042SZardshard 	BPoint lb = fLeftBottom;
180*c6c2c042SZardshard 	BPoint rb = fRightBottom;
181*c6c2c042SZardshard 
182*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&lt);
183*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&rt);
184*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&lb);
185*c6c2c042SZardshard 	fCanvasView->ConvertFromCanvas(&rb);
186*c6c2c042SZardshard 
187*c6c2c042SZardshard 	BRect bounds;
188*c6c2c042SZardshard 	bounds.left = min4(lt.x, rt.x, lb.x, rb.x);
189*c6c2c042SZardshard 	bounds.top = min4(lt.y, rt.y, lb.y, rb.y);
190*c6c2c042SZardshard 	bounds.right = max4(lt.x, rt.x, lb.x, rb.x);
191*c6c2c042SZardshard 	bounds.bottom = max4(lt.y, rt.y, lb.y, rb.y);
192*c6c2c042SZardshard 	return bounds;
193*c6c2c042SZardshard }
194*c6c2c042SZardshard 
195*c6c2c042SZardshard 
196*c6c2c042SZardshard BRect
TrackingBounds(BView * withinView)197*c6c2c042SZardshard PerspectiveBox::TrackingBounds(BView* withinView)
198*c6c2c042SZardshard {
199*c6c2c042SZardshard 	return withinView->Bounds();
200*c6c2c042SZardshard }
201*c6c2c042SZardshard 
202*c6c2c042SZardshard 
203*c6c2c042SZardshard // #pragma mark -
204*c6c2c042SZardshard 
205*c6c2c042SZardshard 
206*c6c2c042SZardshard void
ModifiersChanged(uint32 modifiers)207*c6c2c042SZardshard PerspectiveBox::ModifiersChanged(uint32 modifiers)
208*c6c2c042SZardshard {
209*c6c2c042SZardshard 	fModifiers = modifiers;
210*c6c2c042SZardshard 	if (fDragging && fCurrentState) {
211*c6c2c042SZardshard 		fCurrentState->DragTo(fMousePos, fModifiers);
212*c6c2c042SZardshard 	}
213*c6c2c042SZardshard }
214*c6c2c042SZardshard 
215*c6c2c042SZardshard 
216*c6c2c042SZardshard bool
UpdateCursor()217*c6c2c042SZardshard PerspectiveBox::UpdateCursor()
218*c6c2c042SZardshard {
219*c6c2c042SZardshard 	if (fCurrentState) {
220*c6c2c042SZardshard 		fCurrentState->UpdateViewCursor(fCanvasView, fMousePos);
221*c6c2c042SZardshard 		return true;
222*c6c2c042SZardshard 	}
223*c6c2c042SZardshard 	return false;
224*c6c2c042SZardshard }
225*c6c2c042SZardshard 
226*c6c2c042SZardshard 
227*c6c2c042SZardshard // #pragma mark -
228*c6c2c042SZardshard 
229*c6c2c042SZardshard 
230*c6c2c042SZardshard void
AttachedToView(BView * view)231*c6c2c042SZardshard PerspectiveBox::AttachedToView(BView* view)
232*c6c2c042SZardshard {
233*c6c2c042SZardshard 	view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET));
234*c6c2c042SZardshard }
235*c6c2c042SZardshard 
236*c6c2c042SZardshard 
237*c6c2c042SZardshard void
DetachedFromView(BView * view)238*c6c2c042SZardshard PerspectiveBox::DetachedFromView(BView* view)
239*c6c2c042SZardshard {
240*c6c2c042SZardshard 	view->Invalidate(Bounds().InsetByCopy(-INSET, -INSET));
241*c6c2c042SZardshard }
242*c6c2c042SZardshard 
243*c6c2c042SZardshard 
244*c6c2c042SZardshard // pragma mark -
245*c6c2c042SZardshard 
246*c6c2c042SZardshard 
247*c6c2c042SZardshard void
ObjectChanged(const Observable * object)248*c6c2c042SZardshard PerspectiveBox::ObjectChanged(const Observable* object)
249*c6c2c042SZardshard {
250*c6c2c042SZardshard }
251*c6c2c042SZardshard 
252*c6c2c042SZardshard 
253*c6c2c042SZardshard // pragma mark -
254*c6c2c042SZardshard 
255*c6c2c042SZardshard 
256*c6c2c042SZardshard void
TransformTo(BPoint leftTop,BPoint rightTop,BPoint leftBottom,BPoint rightBottom)257*c6c2c042SZardshard PerspectiveBox::TransformTo(
258*c6c2c042SZardshard 	BPoint leftTop, BPoint rightTop, BPoint leftBottom, BPoint rightBottom)
259*c6c2c042SZardshard {
260*c6c2c042SZardshard 	if (fLeftTop == leftTop
261*c6c2c042SZardshard 		&& fRightTop == rightTop
262*c6c2c042SZardshard 		&& fLeftBottom == leftBottom
263*c6c2c042SZardshard 		&& fRightBottom == rightBottom)
264*c6c2c042SZardshard 		return;
265*c6c2c042SZardshard 
266*c6c2c042SZardshard 	fLeftTop = leftTop;
267*c6c2c042SZardshard 	fRightTop = rightTop;
268*c6c2c042SZardshard 	fLeftBottom = leftBottom;
269*c6c2c042SZardshard 	fRightBottom = rightBottom;
270*c6c2c042SZardshard 
271*c6c2c042SZardshard 	Update();
272*c6c2c042SZardshard }
273*c6c2c042SZardshard 
274*c6c2c042SZardshard 
275*c6c2c042SZardshard void
Update(bool deep)276*c6c2c042SZardshard PerspectiveBox::Update(bool deep)
277*c6c2c042SZardshard {
278*c6c2c042SZardshard 	BRect r = Bounds();
279*c6c2c042SZardshard 	BRect dirty(r | fPreviousBox);
280*c6c2c042SZardshard 	dirty.InsetBy(-INSET, -INSET);
281*c6c2c042SZardshard 	fCanvasView->Invalidate(dirty);
282*c6c2c042SZardshard 	fPreviousBox = r;
283*c6c2c042SZardshard 
284*c6c2c042SZardshard 	if (deep)
285*c6c2c042SZardshard 		fPerspective->TransformTo(fLeftTop, fRightTop, fLeftBottom, fRightBottom);
286*c6c2c042SZardshard }
287*c6c2c042SZardshard 
288*c6c2c042SZardshard 
289*c6c2c042SZardshard Command*
FinishTransaction()290*c6c2c042SZardshard PerspectiveBox::FinishTransaction()
291*c6c2c042SZardshard {
292*c6c2c042SZardshard 	Command* command = fCurrentCommand;
293*c6c2c042SZardshard 	if (fCurrentCommand) {
294*c6c2c042SZardshard 		fCurrentCommand->SetNewPerspective(
295*c6c2c042SZardshard 			fPerspective->LeftTop(), fPerspective->RightTop(),
296*c6c2c042SZardshard 			fPerspective->LeftBottom(), fPerspective->RightBottom());
297*c6c2c042SZardshard 		fCurrentCommand = NULL;
298*c6c2c042SZardshard 	}
299*c6c2c042SZardshard 	return command;
300*c6c2c042SZardshard }
301*c6c2c042SZardshard 
302*c6c2c042SZardshard 
303*c6c2c042SZardshard // #pragma mark -
304*c6c2c042SZardshard 
305*c6c2c042SZardshard 
306*c6c2c042SZardshard bool
AddListener(PerspectiveBoxListener * listener)307*c6c2c042SZardshard PerspectiveBox::AddListener(PerspectiveBoxListener* listener)
308*c6c2c042SZardshard {
309*c6c2c042SZardshard 	if (listener && !fListeners.HasItem((void*)listener))
310*c6c2c042SZardshard 		return fListeners.AddItem((void*)listener);
311*c6c2c042SZardshard 	return false;
312*c6c2c042SZardshard }
313*c6c2c042SZardshard 
314*c6c2c042SZardshard 
315*c6c2c042SZardshard bool
RemoveListener(PerspectiveBoxListener * listener)316*c6c2c042SZardshard PerspectiveBox::RemoveListener(PerspectiveBoxListener* listener)
317*c6c2c042SZardshard {
318*c6c2c042SZardshard 	return fListeners.RemoveItem((void*)listener);
319*c6c2c042SZardshard }
320*c6c2c042SZardshard 
321*c6c2c042SZardshard 
322*c6c2c042SZardshard // #pragma mark -
323*c6c2c042SZardshard 
324*c6c2c042SZardshard 
325*c6c2c042SZardshard void
_NotifyDeleted() const326*c6c2c042SZardshard PerspectiveBox::_NotifyDeleted() const
327*c6c2c042SZardshard {
328*c6c2c042SZardshard 	BList listeners(fListeners);
329*c6c2c042SZardshard 	int32 count = listeners.CountItems();
330*c6c2c042SZardshard 	for (int32 i = 0; i < count; i++) {
331*c6c2c042SZardshard 		PerspectiveBoxListener* listener
332*c6c2c042SZardshard 			= (PerspectiveBoxListener*)listeners.ItemAtFast(i);
333*c6c2c042SZardshard 		listener->PerspectiveBoxDeleted(this);
334*c6c2c042SZardshard 	}
335*c6c2c042SZardshard }
336*c6c2c042SZardshard 
337*c6c2c042SZardshard 
338*c6c2c042SZardshard //! where is expected in canvas view coordinates
339*c6c2c042SZardshard DragState*
_DragStateFor(BPoint where,float canvasZoom)340*c6c2c042SZardshard PerspectiveBox::_DragStateFor(BPoint where, float canvasZoom)
341*c6c2c042SZardshard {
342*c6c2c042SZardshard 	DragState* state = NULL;
343*c6c2c042SZardshard 
344*c6c2c042SZardshard 	// convert to canvas zoom level
345*c6c2c042SZardshard 	//
346*c6c2c042SZardshard 	// the conversion is necessary, because the "hot regions"
347*c6c2c042SZardshard 	// around a point should be the same size no matter what
348*c6c2c042SZardshard 	// zoom level the canvas is displayed at
349*c6c2c042SZardshard 	float inset = INSET / canvasZoom;
350*c6c2c042SZardshard 
351*c6c2c042SZardshard 	// check if the cursor is over the corners
352*c6c2c042SZardshard 	float dLT = point_point_distance(fLeftTop, where);
353*c6c2c042SZardshard 	float dRT = point_point_distance(fRightTop, where);
354*c6c2c042SZardshard 	float dLB = point_point_distance(fLeftBottom, where);
355*c6c2c042SZardshard 	float dRB = point_point_distance(fRightBottom, where);
356*c6c2c042SZardshard 	float d = min4(dLT, dRT, dLB, dRB);
357*c6c2c042SZardshard 	if (d < inset) {
358*c6c2c042SZardshard 		if (d == dLT)
359*c6c2c042SZardshard 			state = fDragLTState;
360*c6c2c042SZardshard 		else if (d == dRT)
361*c6c2c042SZardshard 			state = fDragRTState;
362*c6c2c042SZardshard 		else if (d == dLB)
363*c6c2c042SZardshard 			state = fDragLBState;
364*c6c2c042SZardshard 		else if (d == dRB)
365*c6c2c042SZardshard 			state = fDragRBState;
366*c6c2c042SZardshard 	}
367*c6c2c042SZardshard 
368*c6c2c042SZardshard 	return state;
369*c6c2c042SZardshard }
370*c6c2c042SZardshard 
371*c6c2c042SZardshard 
372*c6c2c042SZardshard void
_StrokeBWLine(BView * into,BPoint from,BPoint to) const373*c6c2c042SZardshard PerspectiveBox::_StrokeBWLine(BView* into, BPoint from, BPoint to) const
374*c6c2c042SZardshard {
375*c6c2c042SZardshard 	// find out how to offset the second line optimally
376*c6c2c042SZardshard 	BPoint offset(0.0, 0.0);
377*c6c2c042SZardshard 	// first, do we have a more horizontal line or a more vertical line?
378*c6c2c042SZardshard 	float xDiff = to.x - from.x;
379*c6c2c042SZardshard 	float yDiff = to.y - from.y;
380*c6c2c042SZardshard 	if (fabs(xDiff) > fabs(yDiff)) {
381*c6c2c042SZardshard 		// horizontal
382*c6c2c042SZardshard 		if (xDiff > 0.0) {
383*c6c2c042SZardshard 			offset.y = -1.0;
384*c6c2c042SZardshard 		} else {
385*c6c2c042SZardshard 			offset.y = 1.0;
386*c6c2c042SZardshard 		}
387*c6c2c042SZardshard 	} else {
388*c6c2c042SZardshard 		// vertical
389*c6c2c042SZardshard 		if (yDiff < 0.0) {
390*c6c2c042SZardshard 			offset.x = -1.0;
391*c6c2c042SZardshard 		} else {
392*c6c2c042SZardshard 			offset.x = 1.0;
393*c6c2c042SZardshard 		}
394*c6c2c042SZardshard 	}
395*c6c2c042SZardshard 	// stroke two lines in high and low color of the view
396*c6c2c042SZardshard 	into->StrokeLine(from, to, B_SOLID_LOW);
397*c6c2c042SZardshard 	from += offset;
398*c6c2c042SZardshard 	to += offset;
399*c6c2c042SZardshard 	into->StrokeLine(from, to, B_SOLID_HIGH);
400*c6c2c042SZardshard }
401*c6c2c042SZardshard 
402*c6c2c042SZardshard 
403*c6c2c042SZardshard void
_StrokeBWPoint(BView * into,BPoint point,double angle) const404*c6c2c042SZardshard PerspectiveBox::_StrokeBWPoint(BView* into, BPoint point, double angle) const
405*c6c2c042SZardshard {
406*c6c2c042SZardshard 	double x = point.x;
407*c6c2c042SZardshard 	double y = point.y;
408*c6c2c042SZardshard 
409*c6c2c042SZardshard 	double x1 = x;
410*c6c2c042SZardshard 	double y1 = y - 5.0;
411*c6c2c042SZardshard 
412*c6c2c042SZardshard 	double x2 = x - 5.0;
413*c6c2c042SZardshard 	double y2 = y - 5.0;
414*c6c2c042SZardshard 
415*c6c2c042SZardshard 	double x3 = x - 5.0;
416*c6c2c042SZardshard 	double y3 = y;
417*c6c2c042SZardshard 
418*c6c2c042SZardshard 	agg::trans_affine m;
419*c6c2c042SZardshard 
420*c6c2c042SZardshard 	double xOffset = -x;
421*c6c2c042SZardshard 	double yOffset = -y;
422*c6c2c042SZardshard 
423*c6c2c042SZardshard 	agg::trans_affine_rotation r(angle * M_PI / 180.0);
424*c6c2c042SZardshard 
425*c6c2c042SZardshard 	r.transform(&xOffset, &yOffset);
426*c6c2c042SZardshard 	xOffset = x + xOffset;
427*c6c2c042SZardshard 	yOffset = y + yOffset;
428*c6c2c042SZardshard 
429*c6c2c042SZardshard 	m.multiply(r);
430*c6c2c042SZardshard 	m.multiply(agg::trans_affine_translation(xOffset, yOffset));
431*c6c2c042SZardshard 
432*c6c2c042SZardshard 	m.transform(&x, &y);
433*c6c2c042SZardshard 	m.transform(&x1, &y1);
434*c6c2c042SZardshard 	m.transform(&x2, &y2);
435*c6c2c042SZardshard 	m.transform(&x3, &y3);
436*c6c2c042SZardshard 
437*c6c2c042SZardshard 	BPoint p[4];
438*c6c2c042SZardshard 	p[0] = BPoint(x, y);
439*c6c2c042SZardshard 	p[1] = BPoint(x1, y1);
440*c6c2c042SZardshard 	p[2] = BPoint(x2, y2);
441*c6c2c042SZardshard 	p[3] = BPoint(x3, y3);
442*c6c2c042SZardshard 
443*c6c2c042SZardshard 	into->FillPolygon(p, 4, B_SOLID_HIGH);
444*c6c2c042SZardshard 
445*c6c2c042SZardshard 	into->StrokeLine(p[0], p[1], B_SOLID_LOW);
446*c6c2c042SZardshard 	into->StrokeLine(p[1], p[2], B_SOLID_LOW);
447*c6c2c042SZardshard 	into->StrokeLine(p[2], p[3], B_SOLID_LOW);
448*c6c2c042SZardshard 	into->StrokeLine(p[3], p[0], B_SOLID_LOW);
449*c6c2c042SZardshard }
450