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