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