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