xref: /haiku/src/apps/icon-o-matic/transformable/TransformBoxStates.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "TransformBoxStates.h"
10 
11 #include <math.h>
12 #include <stdio.h>
13 
14 #include <Cursor.h>
15 #include <InterfaceDefs.h>
16 #include <View.h>
17 
18 #include "cursors.h"
19 #include "support.h"
20 
21 #include "TransformBox.h"
22 //#include "Strings.h"
23 
24 // constructor
25 DragState::DragState(TransformBox* parent)
26 	: fOrigin(0.0, 0.0),
27 	  fParent(parent)
28 {
29 }
30 
31 // SetOrigin
32 void
33 DragState::SetOrigin(BPoint origin)
34 {
35 	fOrigin = origin;
36 }
37 
38 // ActionName
39 const char*
40 DragState::ActionName() const
41 {
42 	return "Transformation";
43 }
44 
45 // ActionNameIndex
46 uint32
47 DragState::ActionNameIndex() const
48 {
49 	return TRANSFORMATION;
50 }
51 
52 // _SetViewCursor
53 void
54 DragState::_SetViewCursor(BView* view, const uchar* cursorData) const
55 {
56 	BCursor cursor(cursorData);
57 	view->SetViewCursor(&cursor);
58 }
59 
60 // #pragma mark - DragCornerState
61 
62 // constructor
63 DragCornerState::DragCornerState(TransformBox* parent, uint32 corner)
64 	: DragState(parent),
65 	  fCorner(corner)
66 {
67 }
68 
69 // SetOrigin
70 void
71 DragCornerState::SetOrigin(BPoint origin)
72 {
73 	fOldXScale = fParent->LocalXScale();
74 	fOldYScale = fParent->LocalYScale();
75 
76 	fOldOffset = fParent->Translation();
77 
78 	// copy the matrix at the start of the drag procedure
79 	fMatrix.reset();
80 	fMatrix.multiply(agg::trans_affine_scaling(fOldXScale, fOldYScale));
81 	fMatrix.multiply(agg::trans_affine_rotation(fParent->LocalRotation() * PI / 180.0));
82 	fMatrix.multiply(agg::trans_affine_translation(fParent->Translation().x,
83 												   fParent->Translation().y));
84 
85 	double x = origin.x;
86 	double y = origin.y;
87 	fMatrix.inverse_transform(&x, &y);
88 	origin.x = x;
89 	origin.y = y;
90 
91 	BRect box = fParent->Box();
92 	switch (fCorner) {
93 		case LEFT_TOP_CORNER:
94 			fXOffsetFromCorner = origin.x - box.left;
95 			fYOffsetFromCorner = origin.y - box.top;
96 			fOldWidth = box.left - box.right;
97 			fOldHeight = box.top - box.bottom;
98 			origin.x = box.right;
99 			origin.y = box.bottom;
100 			break;
101 		case RIGHT_TOP_CORNER:
102 			fXOffsetFromCorner = origin.x - box.right;
103 			fYOffsetFromCorner = origin.y - box.top;
104 			fOldWidth = box.right - box.left;
105 			fOldHeight = box.top - box.bottom;
106 			origin.x = box.left;
107 			origin.y = box.bottom;
108 			break;
109 		case LEFT_BOTTOM_CORNER:
110 			fXOffsetFromCorner = origin.x - box.left;
111 			fYOffsetFromCorner = origin.y - box.bottom;
112 			fOldWidth = box.left - box.right;
113 			fOldHeight = box.bottom - box.top;
114 			origin.x = box.right;
115 			origin.y = box.top;
116 			break;
117 		case RIGHT_BOTTOM_CORNER:
118 			fXOffsetFromCorner = origin.x - box.right;
119 			fYOffsetFromCorner = origin.y - box.bottom;
120 			fOldWidth = box.right - box.left;
121 			fOldHeight = box.bottom - box.top;
122 			origin.x = box.left;
123 			origin.y = box.top;
124 			break;
125 	}
126 	DragState::SetOrigin(origin);
127 }
128 // DragTo
129 void
130 DragCornerState::DragTo(BPoint current, uint32 modifiers)
131 {
132 	double x = current.x;
133 	double y = current.y;
134 	fMatrix.inverse_transform(&x, &y);
135 
136 	double xScale = 1.0;
137 	double yScale = 1.0;
138 	BPoint translation(0.0, 0.0);
139 	switch (fCorner) {
140 		case LEFT_TOP_CORNER:
141 		case RIGHT_TOP_CORNER:
142 		case LEFT_BOTTOM_CORNER:
143 		case RIGHT_BOTTOM_CORNER:
144 			x -= fOrigin.x;
145 			y -= fOrigin.y;
146 			if (fOldWidth != 0.0)
147 				xScale = (x - fXOffsetFromCorner) / (fOldWidth);
148 			if (fOldHeight != 0.0)
149 				yScale = (y - fYOffsetFromCorner) / (fOldHeight);
150 			// constrain aspect ratio if shift is pressed
151 			if (modifiers & B_SHIFT_KEY) {
152 				if (fabs(xScale) > fabs(yScale))
153 					yScale = yScale > 0.0 ? fabs(xScale) : -fabs(xScale);
154 				else
155 					xScale = xScale > 0.0 ? fabs(yScale) : -fabs(yScale);
156 			}
157 			translation.x = fOrigin.x - fOrigin.x * xScale;
158 			translation.y = fOrigin.y - fOrigin.y * yScale;
159 			break;
160 	}
161 	x = translation.x;
162 	y = translation.y;
163 	fMatrix.transform(&x, &y);
164 	translation.x = x;
165 	translation.y = y;
166 
167 	fParent->SetTranslationAndScale(translation,
168 									xScale * fOldXScale,
169 									yScale * fOldYScale);
170 }
171 
172 // UpdateViewCursor
173 void
174 DragCornerState::UpdateViewCursor(BView* view, BPoint current) const
175 {
176 	float rotation = fmod(360.0 - fParent->ViewSpaceRotation() + 22.5, 180.0);
177 	bool flipX = fParent->LocalXScale() < 0.0;
178 	bool flipY = fParent->LocalYScale() < 0.0;
179 	if (rotation < 45.0) {
180 		switch (fCorner) {
181 			case LEFT_TOP_CORNER:
182 			case RIGHT_BOTTOM_CORNER:
183 				if (flipX)
184 					_SetViewCursor(view, flipY ? kLeftTopRightBottomCursor
185 											   : kLeftBottomRightTopCursor);
186 				else
187 					_SetViewCursor(view, flipY ? kLeftBottomRightTopCursor
188 											   : kLeftTopRightBottomCursor);
189 				break;
190 			case RIGHT_TOP_CORNER:
191 			case LEFT_BOTTOM_CORNER:
192 				if (flipX)
193 					_SetViewCursor(view, flipY ? kLeftBottomRightTopCursor
194 											   : kLeftTopRightBottomCursor);
195 				else
196 					_SetViewCursor(view, flipY ? kLeftTopRightBottomCursor
197 											   : kLeftBottomRightTopCursor);
198 				break;
199 		}
200 	} else if (rotation < 90.0) {
201 		switch (fCorner) {
202 			case LEFT_TOP_CORNER:
203 			case RIGHT_BOTTOM_CORNER:
204 				if (flipX)
205 					_SetViewCursor(view, flipY ? kLeftRightCursor
206 											   : kUpDownCursor);
207 				else
208 					_SetViewCursor(view, flipY ? kUpDownCursor
209 											   : kLeftRightCursor);
210 				break;
211 			case RIGHT_TOP_CORNER:
212 			case LEFT_BOTTOM_CORNER:
213 				if (flipX)
214 					_SetViewCursor(view, flipY ? kUpDownCursor
215 											   : kLeftRightCursor);
216 				else
217 					_SetViewCursor(view, flipY ? kLeftRightCursor
218 											   : kUpDownCursor);
219 				break;
220 		}
221 	} else if (rotation < 135.0) {
222 		switch (fCorner) {
223 			case LEFT_TOP_CORNER:
224 			case RIGHT_BOTTOM_CORNER:
225 				if (flipX)
226 					_SetViewCursor(view, flipY ? kLeftBottomRightTopCursor
227 											   : kLeftTopRightBottomCursor);
228 				else
229 					_SetViewCursor(view, flipY ? kLeftTopRightBottomCursor
230 											   : kLeftBottomRightTopCursor);
231 				break;
232 				break;
233 			case RIGHT_TOP_CORNER:
234 			case LEFT_BOTTOM_CORNER:
235 				if (flipX)
236 					_SetViewCursor(view, flipY ? kLeftTopRightBottomCursor
237 											   : kLeftBottomRightTopCursor);
238 				else
239 					_SetViewCursor(view, flipY ? kLeftBottomRightTopCursor
240 											   : kLeftTopRightBottomCursor);
241 				break;
242 				break;
243 		}
244 	} else {
245 		switch (fCorner) {
246 			case LEFT_TOP_CORNER:
247 			case RIGHT_BOTTOM_CORNER:
248 				if (flipX)
249 					_SetViewCursor(view, flipY ? kUpDownCursor
250 											   : kLeftRightCursor);
251 				else
252 					_SetViewCursor(view, flipY ? kLeftRightCursor
253 											   : kUpDownCursor);
254 				break;
255 			case RIGHT_TOP_CORNER:
256 			case LEFT_BOTTOM_CORNER:
257 				if (flipX)
258 					_SetViewCursor(view, flipY ? kLeftRightCursor
259 											   : kUpDownCursor);
260 				else
261 					_SetViewCursor(view, flipY ? kUpDownCursor
262 											   : kLeftRightCursor);
263 				break;
264 		}
265 	}
266 }
267 
268 // ActionName
269 const char*
270 DragCornerState::ActionName() const
271 {
272 	return "Scale";
273 }
274 
275 // ActionNameIndex
276 uint32
277 DragCornerState::ActionNameIndex() const
278 {
279 	return SCALE;
280 }
281 
282 
283 // #pragma mark - DragSideState
284 
285 DragSideState::DragSideState(TransformBox* parent, uint32 side)
286 	: DragState(parent),
287 	  fSide(side)
288 {
289 }
290 
291 // SetOrigin
292 void
293 DragSideState::SetOrigin(BPoint origin)
294 {
295 	fOldXScale = fParent->LocalXScale();
296 	fOldYScale = fParent->LocalYScale();
297 
298 	fOldOffset = fParent->Translation();
299 
300 	// copy the matrix at the start of the drag procedure
301 	fMatrix.reset();
302 	fMatrix.multiply(agg::trans_affine_scaling(fOldXScale, fOldYScale));
303 	fMatrix.multiply(agg::trans_affine_rotation(fParent->LocalRotation() * PI / 180.0));
304 	fMatrix.multiply(agg::trans_affine_translation(fParent->Translation().x,
305 												   fParent->Translation().y));
306 
307 	double x = origin.x;
308 	double y = origin.y;
309 	fMatrix.inverse_transform(&x, &y);
310 	origin.x = x;
311 	origin.y = y;
312 
313 	BRect box = fParent->Box();
314 	switch (fSide) {
315 		case LEFT_SIDE:
316 			fOffsetFromSide = origin.x - box.left;
317 			fOldSideDist = box.left - box.right;
318 			origin.x = box.right;
319 			break;
320 		case RIGHT_SIDE:
321 			fOffsetFromSide = origin.x - box.right;
322 			fOldSideDist = box.right - box.left;
323 			origin.x = box.left;
324 			break;
325 		case TOP_SIDE:
326 			fOffsetFromSide = origin.y - box.top;
327 			fOldSideDist = box.top - box.bottom;
328 			origin.y = box.bottom;
329 			break;
330 		case BOTTOM_SIDE:
331 			fOffsetFromSide = origin.y - box.bottom;
332 			fOldSideDist = box.bottom - box.top;
333 			origin.y = box.top;
334 			break;
335 	}
336 	DragState::SetOrigin(origin);
337 }
338 
339 // DragTo
340 void
341 DragSideState::DragTo(BPoint current, uint32 modifiers)
342 {
343 	double x = current.x;
344 	double y = current.y;
345 	fMatrix.inverse_transform(&x, &y);
346 
347 	double xScale = 1.0;
348 	double yScale = 1.0;
349 	BPoint translation(0.0, 0.0);
350 	switch (fSide) {
351 		case LEFT_SIDE:
352 		case RIGHT_SIDE:
353 			x -= fOrigin.x;
354 			if (fOldSideDist != 0.0)
355 				xScale = (x - fOffsetFromSide) / (fOldSideDist);
356 			translation.x = fOrigin.x - fOrigin.x * xScale;
357 			break;
358 		case TOP_SIDE:
359 		case BOTTOM_SIDE:
360 			y -= fOrigin.y;
361 			if (fOldSideDist != 0.0)
362 				yScale = (y - fOffsetFromSide) / (fOldSideDist);
363 			translation.y = fOrigin.y - fOrigin.y * yScale;
364 			break;
365 	}
366 	x = translation.x;
367 	y = translation.y;
368 	fMatrix.transform(&x, &y);
369 	translation.x = x;
370 	translation.y = y;
371 
372 	fParent->SetTranslationAndScale(translation,
373 									xScale * fOldXScale,
374 									yScale * fOldYScale);
375 }
376 
377 // UpdateViewCursor
378 void
379 DragSideState::UpdateViewCursor(BView* view, BPoint current) const
380 {
381 	float rotation = fmod(360.0 - fParent->ViewSpaceRotation() + 22.5, 180.0);
382 	if (rotation < 45.0) {
383 		switch (fSide) {
384 			case LEFT_SIDE:
385 			case RIGHT_SIDE:
386 				_SetViewCursor(view, kLeftRightCursor);
387 				break;
388 			case TOP_SIDE:
389 			case BOTTOM_SIDE:
390 				_SetViewCursor(view, kUpDownCursor);
391 				break;
392 		}
393 	} else if (rotation < 90.0) {
394 		switch (fSide) {
395 			case LEFT_SIDE:
396 			case RIGHT_SIDE:
397 				_SetViewCursor(view, kLeftBottomRightTopCursor);
398 				break;
399 			case TOP_SIDE:
400 			case BOTTOM_SIDE:
401 				_SetViewCursor(view, kLeftTopRightBottomCursor);
402 				break;
403 		}
404 	} else if (rotation < 135.0) {
405 		switch (fSide) {
406 			case LEFT_SIDE:
407 			case RIGHT_SIDE:
408 				_SetViewCursor(view, kUpDownCursor);
409 				break;
410 			case TOP_SIDE:
411 			case BOTTOM_SIDE:
412 				_SetViewCursor(view, kLeftRightCursor);
413 				break;
414 		}
415 	} else {
416 		switch (fSide) {
417 			case LEFT_SIDE:
418 			case RIGHT_SIDE:
419 				_SetViewCursor(view, kLeftTopRightBottomCursor);
420 				break;
421 			case TOP_SIDE:
422 			case BOTTOM_SIDE:
423 				_SetViewCursor(view, kLeftBottomRightTopCursor);
424 				break;
425 		}
426 	}
427 }
428 
429 // ActionName
430 const char*
431 DragSideState::ActionName() const
432 {
433 	return "Scale";
434 }
435 
436 // ActionNameIndex
437 uint32
438 DragSideState::ActionNameIndex() const
439 {
440 	return SCALE;
441 }
442 
443 
444 // #pragma mark - DragBoxState
445 
446 // SetOrigin
447 void
448 DragBoxState::SetOrigin(BPoint origin)
449 {
450 	fOldTranslation = fParent->Translation();
451 	DragState::SetOrigin(origin);
452 }
453 
454 // DragTo
455 void
456 DragBoxState::DragTo(BPoint current, uint32 modifiers)
457 {
458 	BPoint offset = current - fOrigin;
459 	BPoint newTranslation = fOldTranslation + offset;
460 	if (modifiers & B_SHIFT_KEY) {
461 		if (fabs(offset.x) > fabs(offset.y))
462 			newTranslation.y = fOldTranslation.y;
463 		else
464 			newTranslation.x = fOldTranslation.x;
465 	}
466 	fParent->TranslateBy(newTranslation - fParent->Translation());
467 }
468 
469 // UpdateViewCursor
470 void
471 DragBoxState::UpdateViewCursor(BView* view, BPoint current) const
472 {
473 	_SetViewCursor(view, kMoveCursor);
474 }
475 
476 // ActionName
477 const char*
478 DragBoxState::ActionName() const
479 {
480 	return "Move";
481 }
482 
483 // ActionNameIndex
484 uint32
485 DragBoxState::ActionNameIndex() const
486 {
487 	return MOVE;
488 }
489 
490 
491 // #pragma mark - RotateBoxState
492 
493 // constructor
494 RotateBoxState::RotateBoxState(TransformBox* parent)
495 	: DragState(parent),
496 	  fOldAngle(0.0)
497 {
498 }
499 
500 // SetOrigin
501 void
502 RotateBoxState::SetOrigin(BPoint origin)
503 {
504 	DragState::SetOrigin(origin);
505 	fOldAngle = fParent->LocalRotation();
506 }
507 
508 // DragTo
509 void
510 RotateBoxState::DragTo(BPoint current, uint32 modifiers)
511 {
512 	double angle = calc_angle(fParent->Center(), fOrigin, current);
513 
514 	if (modifiers & B_SHIFT_KEY) {
515 		if (angle < 0.0)
516 			angle -= 22.5;
517 		else
518 			angle += 22.5;
519 		angle = 45.0 * ((int32)angle / 45);
520 	}
521 
522 	double newAngle = fOldAngle + angle;
523 
524 	fParent->RotateBy(fParent->Center(), newAngle - fParent->LocalRotation());
525 }
526 
527 // UpdateViewCursor
528 void
529 RotateBoxState::UpdateViewCursor(BView* view, BPoint current) const
530 {
531 	BPoint origin(fParent->Center());
532 	fParent->TransformToCanvas(origin);
533 	fParent->TransformToCanvas(current);
534 	BPoint from = origin + BPoint(sinf(22.5 * 180.0 / PI) * 50.0,
535 								  -cosf(22.5 * 180.0 / PI) * 50.0);
536 
537 	float rotation = calc_angle(origin, from, current) + 180.0;
538 
539 	if (rotation < 45.0) {
540 		_SetViewCursor(view, kRotateLCursor);
541 	} else if (rotation < 90.0) {
542 		_SetViewCursor(view, kRotateLTCursor);
543 	} else if (rotation < 135.0) {
544 		_SetViewCursor(view, kRotateTCursor);
545 	} else if (rotation < 180.0) {
546 		_SetViewCursor(view, kRotateRTCursor);
547 	} else if (rotation < 225.0) {
548 		_SetViewCursor(view, kRotateRCursor);
549 	} else if (rotation < 270.0) {
550 		_SetViewCursor(view, kRotateRBCursor);
551 	} else if (rotation < 315.0) {
552 		_SetViewCursor(view, kRotateBCursor);
553 	} else {
554 		_SetViewCursor(view, kRotateLBCursor);
555 	}
556 }
557 
558 // ActionName
559 const char*
560 RotateBoxState::ActionName() const
561 {
562 	return "Rotate";
563 }
564 
565 // ActionNameIndex
566 uint32
567 RotateBoxState::ActionNameIndex() const
568 {
569 	return ROTATE;
570 }
571 
572 
573 
574 // #pragma mark - OffsetCenterState
575 
576 // SetOrigin
577 void
578 OffsetCenterState::SetOrigin(BPoint origin)
579 {
580 	fParent->InverseTransform(&origin);
581 	DragState::SetOrigin(origin);
582 }
583 
584 
585 // DragTo
586 void
587 OffsetCenterState::DragTo(BPoint current, uint32 modifiers)
588 {
589 	fParent->InverseTransform(&current);
590 	fParent->OffsetCenter(current - fOrigin);
591 	fOrigin = current;
592 }
593 
594 // UpdateViewCursor
595 void
596 OffsetCenterState::UpdateViewCursor(BView* view, BPoint current) const
597 {
598 	_SetViewCursor(view, kPathMoveCursor);
599 }
600 
601 // ActionName
602 const char*
603 OffsetCenterState::ActionName() const
604 {
605 	return "Move Pivot";
606 }
607 
608 // ActionNameIndex
609 uint32
610 OffsetCenterState::ActionNameIndex() const
611 {
612 	return MOVE_PIVOT;
613 }
614 
615 
616