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 31DragState::DragState(TransformBox* parent) 32 : 33 fOrigin(0.0, 0.0), 34 fParent(parent) 35{ 36} 37 38 39// SetOrigin 40void 41DragState::SetOrigin(BPoint origin) 42{ 43 fOrigin = origin; 44} 45 46 47// ActionName 48const char* 49DragState::ActionName() const 50{ 51 return B_TRANSLATE("Transformation"); 52} 53 54 55// ActionNameIndex 56uint32 57DragState::ActionNameIndex() const 58{ 59 return TRANSFORMATION; 60} 61 62 63// _SetViewCursor 64void 65DragState::_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 76DragCornerState::DragCornerState(TransformBox* parent, uint32 corner) 77 : 78 DragState(parent), 79 fCorner(corner) 80{ 81} 82 83 84// SetOrigin 85void 86DragCornerState::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 147void 148DragCornerState::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 191void 192DragCornerState::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 294const char* 295DragCornerState::ActionName() const 296{ 297 return B_TRANSLATE("Scale"); 298} 299 300 301// ActionNameIndex 302uint32 303DragCornerState::ActionNameIndex() const 304{ 305 return SCALE; 306} 307 308 309// #pragma mark - DragSideState 310 311 312DragSideState::DragSideState(TransformBox* parent, uint32 side) 313 : 314 DragState(parent), 315 fSide(side) 316{ 317} 318 319 320// SetOrigin 321void 322DragSideState::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 371void 372DragSideState::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 409void 410DragSideState::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 462const char* 463DragSideState::ActionName() const 464{ 465 return B_TRANSLATE("Scale"); 466} 467 468 469// ActionNameIndex 470uint32 471DragSideState::ActionNameIndex() const 472{ 473 return SCALE; 474} 475 476 477// #pragma mark - DragBoxState 478 479 480// SetOrigin 481void 482DragBoxState::SetOrigin(BPoint origin) 483{ 484 fOldTranslation = fParent->Translation(); 485 DragState::SetOrigin(origin); 486} 487 488 489// DragTo 490void 491DragBoxState::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 506void 507DragBoxState::UpdateViewCursor(BView* view, BPoint current) const 508{ 509 _SetViewCursor(view, kMoveCursor); 510} 511 512 513// ActionName 514const char* 515DragBoxState::ActionName() const 516{ 517 return B_TRANSLATE("Move"); 518} 519 520 521// ActionNameIndex 522uint32 523DragBoxState::ActionNameIndex() const 524{ 525 return MOVE; 526} 527 528 529// #pragma mark - RotateBoxState 530 531 532// constructor 533RotateBoxState::RotateBoxState(TransformBox* parent) 534 : 535 DragState(parent), 536 fOldAngle(0.0) 537{ 538} 539 540 541// SetOrigin 542void 543RotateBoxState::SetOrigin(BPoint origin) 544{ 545 DragState::SetOrigin(origin); 546 fOldAngle = fParent->LocalRotation(); 547} 548 549 550// DragTo 551void 552RotateBoxState::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 571void 572RotateBoxState::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 603const char* 604RotateBoxState::ActionName() const 605{ 606 return B_TRANSLATE("Rotate"); 607} 608 609 610// ActionNameIndex 611uint32 612RotateBoxState::ActionNameIndex() const 613{ 614 return ROTATE; 615} 616 617 618// #pragma mark - OffsetCenterState 619 620 621// SetOrigin 622void 623OffsetCenterState::SetOrigin(BPoint origin) 624{ 625 fParent->InverseTransform(&origin); 626 DragState::SetOrigin(origin); 627} 628 629 630// DragTo 631void 632OffsetCenterState::DragTo(BPoint current, uint32 modifiers) 633{ 634 fParent->InverseTransform(¤t); 635 fParent->OffsetCenter(current - fOrigin); 636 fOrigin = current; 637} 638 639 640// UpdateViewCursor 641void 642OffsetCenterState::UpdateViewCursor(BView* view, BPoint current) const 643{ 644 _SetViewCursor(view, kPathMoveCursor); 645} 646 647 648// ActionName 649const char* 650OffsetCenterState::ActionName() const 651{ 652 return B_TRANSLATE("Move Pivot"); 653} 654 655 656// ActionNameIndex 657uint32 658OffsetCenterState::ActionNameIndex() const 659{ 660 return MOVE_PIVOT; 661} 662