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(¤t); 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