1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svx.hxx" 30 #include <svl/style.hxx> 31 #include <tools/bigint.hxx> 32 #include <svx/xlnwtit.hxx> 33 #include <svx/xlnedwit.hxx> 34 #include <svx/xlnstwit.hxx> 35 #include <svx/xlnstit.hxx> 36 #include <svx/xlnedit.hxx> 37 #include <svx/svdocirc.hxx> 38 #include <math.h> 39 #include <svx/xpool.hxx> 40 #include <svx/svdattr.hxx> 41 #include <svx/svdpool.hxx> 42 #include <svx/svdattrx.hxx> 43 #include <svx/svdtrans.hxx> 44 #include <svx/svdetc.hxx> 45 #include <svx/svddrag.hxx> 46 #include <svx/svdmodel.hxx> 47 #include <svx/svdpage.hxx> 48 #include <svx/svdopath.hxx> // fuer die Objektkonvertierung 49 #include <svx/svdview.hxx> // Zum Draggen (Ortho) 50 #include "svx/svdglob.hxx" // StringCache 51 #include "svx/svdstr.hrc" // Objektname 52 #include <editeng/eeitem.hxx> 53 #include "svdoimp.hxx" 54 #include <svx/sdr/properties/circleproperties.hxx> 55 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx> 56 #include <basegfx/point/b2dpoint.hxx> 57 #include <basegfx/polygon/b2dpolygon.hxx> 58 #include <basegfx/polygon/b2dpolygontools.hxx> 59 #include <basegfx/matrix/b2dhommatrix.hxx> 60 #include <basegfx/polygon/b2dpolygontools.hxx> 61 #include <basegfx/matrix/b2dhommatrixtools.hxx> 62 63 ////////////////////////////////////////////////////////////////////////////// 64 65 Point GetWinkPnt(const Rectangle& rR, long nWink) 66 { 67 Point aCenter(rR.Center()); 68 long nWdt=rR.Right()-rR.Left(); 69 long nHgt=rR.Bottom()-rR.Top(); 70 long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2; 71 double a; 72 a=nWink*nPi180; 73 Point aRetval(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad)); 74 if (nWdt==0) aRetval.X()=0; 75 if (nHgt==0) aRetval.Y()=0; 76 if (nWdt!=nHgt) { 77 if (nWdt>nHgt) { 78 if (nWdt!=0) { 79 // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384) 80 if (Abs(nHgt)>32767 || Abs(aRetval.Y())>32767) { 81 aRetval.Y()=BigMulDiv(aRetval.Y(),nHgt,nWdt); 82 } else { 83 aRetval.Y()=aRetval.Y()*nHgt/nWdt; 84 } 85 } 86 } else { 87 if (nHgt!=0) { 88 // eventuelle Ueberlaeufe bei sehr grossen Objekten abfangen (Bug 23384) 89 if (Abs(nWdt)>32767 || Abs(aRetval.X())>32767) { 90 aRetval.X()=BigMulDiv(aRetval.X(),nWdt,nHgt); 91 } else { 92 aRetval.X()=aRetval.X()*nWdt/nHgt; 93 } 94 } 95 } 96 } 97 aRetval+=aCenter; 98 return aRetval; 99 } 100 101 ////////////////////////////////////////////////////////////////////////////// 102 // BaseProperties section 103 104 sdr::properties::BaseProperties* SdrCircObj::CreateObjectSpecificProperties() 105 { 106 return new sdr::properties::CircleProperties(*this); 107 } 108 109 ////////////////////////////////////////////////////////////////////////////// 110 // DrawContact section 111 112 sdr::contact::ViewContact* SdrCircObj::CreateObjectSpecificViewContact() 113 { 114 return new sdr::contact::ViewContactOfSdrCircObj(*this); 115 } 116 117 ////////////////////////////////////////////////////////////////////////////// 118 119 TYPEINIT1(SdrCircObj,SdrRectObj); 120 121 SdrCircObj::SdrCircObj(SdrObjKind eNewKind) 122 { 123 nStartWink=0; 124 nEndWink=36000; 125 meCircleKind=eNewKind; 126 bClosedObj=eNewKind!=OBJ_CARC; 127 } 128 129 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect): 130 SdrRectObj(rRect) 131 { 132 nStartWink=0; 133 nEndWink=36000; 134 meCircleKind=eNewKind; 135 bClosedObj=eNewKind!=OBJ_CARC; 136 } 137 138 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect, long nNewStartWink, long nNewEndWink): 139 SdrRectObj(rRect) 140 { 141 long nWinkDif=nNewEndWink-nNewStartWink; 142 nStartWink=NormAngle360(nNewStartWink); 143 nEndWink=NormAngle360(nNewEndWink); 144 if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis 145 meCircleKind=eNewKind; 146 bClosedObj=eNewKind!=OBJ_CARC; 147 } 148 149 SdrCircObj::~SdrCircObj() 150 { 151 } 152 153 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const 154 { 155 FASTBOOL bCanConv=!HasText() || ImpCanConvTextToCurve(); 156 rInfo.bEdgeRadiusAllowed = sal_False; 157 rInfo.bCanConvToPath=bCanConv; 158 rInfo.bCanConvToPoly=bCanConv; 159 rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary()); 160 } 161 162 sal_uInt16 SdrCircObj::GetObjIdentifier() const 163 { 164 return sal_uInt16(meCircleKind); 165 } 166 167 FASTBOOL SdrCircObj::PaintNeedsXPolyCirc() const 168 { 169 // XPoly ist notwendig fuer alle gedrehten Ellipsenobjekte, 170 // fuer alle Kreis- und Ellipsenabschnitte 171 // und wenn nicht WIN dann (erstmal) auch fuer Kreis-/Ellipsenausschnitte 172 // und Kreis-/Ellipsenboegen (wg. Genauigkeit) 173 FASTBOOL bNeed=aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind==OBJ_CCUT; 174 // Wenn nicht Win, dann fuer alle ausser Vollkreis (erstmal!!!) 175 if (meCircleKind!=OBJ_CIRC) bNeed=sal_True; 176 177 const SfxItemSet& rSet = GetObjectItemSet(); 178 if(!bNeed) 179 { 180 // XPoly ist notwendig fuer alles was nicht LineSolid oder LineNone ist 181 XLineStyle eLine = ((XLineStyleItem&)(rSet.Get(XATTR_LINESTYLE))).GetValue(); 182 bNeed = eLine != XLINE_NONE && eLine != XLINE_SOLID; 183 184 // XPoly ist notwendig fuer dicke Linien 185 if(!bNeed && eLine != XLINE_NONE) 186 bNeed = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue() != 0; 187 188 // XPoly ist notwendig fuer Kreisboegen mit Linienenden 189 if(!bNeed && meCircleKind == OBJ_CARC) 190 { 191 // Linienanfang ist da, wenn StartPolygon und StartWidth!=0 192 bNeed=((XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue().count() != 0L && 193 ((XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue() != 0; 194 195 if(!bNeed) 196 { 197 // Linienende ist da, wenn EndPolygon und EndWidth!=0 198 bNeed = ((XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue().count() != 0L && 199 ((XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue() != 0; 200 } 201 } 202 } 203 204 // XPoly ist notwendig, wenn Fill !=None und !=Solid 205 if(!bNeed && meCircleKind != OBJ_CARC) 206 { 207 XFillStyle eFill=((XFillStyleItem&)(rSet.Get(XATTR_FILLSTYLE))).GetValue(); 208 bNeed = eFill != XFILL_NONE && eFill != XFILL_SOLID; 209 } 210 211 if(!bNeed && meCircleKind != OBJ_CIRC && nStartWink == nEndWink) 212 bNeed=sal_True; // Weil sonst Vollkreis gemalt wird 213 214 return bNeed; 215 } 216 217 basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind, const Rectangle& rRect1, long nStart, long nEnd) const 218 { 219 const basegfx::B2DRange aRange(rRect1.Left(), rRect1.Top(), rRect1.Right(), rRect1.Bottom()); 220 basegfx::B2DPolygon aCircPolygon; 221 222 if(OBJ_CIRC == eCicrleKind) 223 { 224 // create full circle. Do not use createPolygonFromEllipse; it's necessary 225 // to get the start point to the bottom of the circle to keep compatible to 226 // old geometry creation 227 aCircPolygon = basegfx::tools::createPolygonFromUnitCircle(1); 228 229 // needs own scaling and translation from unit circle to target size (same as 230 // would be in createPolygonFromEllipse) 231 const basegfx::B2DPoint aCenter(aRange.getCenter()); 232 const basegfx::B2DHomMatrix aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix( 233 aRange.getWidth() / 2.0, aRange.getHeight() / 2.0, 234 aCenter.getX(), aCenter.getY())); 235 aCircPolygon.transform(aMatrix); 236 } 237 else 238 { 239 // mirror start, end for geometry creation since model coordinate system is mirrored in Y 240 // #i111715# increase numerical correctness by first dividing and not using F_PI1800 241 const double fStart((((36000 - nEnd) % 36000) / 18000.0) * F_PI); 242 const double fEnd((((36000 - nStart) % 36000) / 18000.0) * F_PI); 243 244 // create circle segment. This is not closed by default 245 aCircPolygon = basegfx::tools::createPolygonFromEllipseSegment( 246 aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0, 247 fStart, fEnd); 248 249 // check closing states 250 const bool bCloseSegment(OBJ_CARC != eCicrleKind); 251 const bool bCloseUsingCenter(OBJ_SECT == eCicrleKind); 252 253 if(bCloseSegment) 254 { 255 if(bCloseUsingCenter) 256 { 257 // add center point at start (for historical reasons) 258 basegfx::B2DPolygon aSector; 259 aSector.append(aRange.getCenter()); 260 aSector.append(aCircPolygon); 261 aCircPolygon = aSector; 262 } 263 264 // close 265 aCircPolygon.setClosed(true); 266 } 267 } 268 269 // #i76950# 270 if(aGeo.nShearWink || aGeo.nDrehWink) 271 { 272 // translate top left to (0,0) 273 const basegfx::B2DPoint aTopLeft(aRange.getMinimum()); 274 basegfx::B2DHomMatrix aMatrix(basegfx::tools::createTranslateB2DHomMatrix( 275 -aTopLeft.getX(), -aTopLeft.getY())); 276 277 // shear, rotate and back to top left (if needed) 278 aMatrix = basegfx::tools::createShearXRotateTranslateB2DHomMatrix( 279 aGeo.nShearWink ? tan((36000 - aGeo.nShearWink) * F_PI18000) : 0.0, 280 aGeo.nDrehWink ? (36000 - aGeo.nDrehWink) * F_PI18000 : 0.0, 281 aTopLeft) * aMatrix; 282 283 // apply transformation 284 aCircPolygon.transform(aMatrix); 285 } 286 287 return aCircPolygon; 288 } 289 290 void SdrCircObj::RecalcXPoly() 291 { 292 const basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink)); 293 mpXPoly = new XPolygon(aPolyCirc); 294 } 295 296 void SdrCircObj::TakeObjNameSingul(XubString& rName) const 297 { 298 sal_uInt16 nID=STR_ObjNameSingulCIRC; 299 if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) { 300 switch (meCircleKind) { 301 case OBJ_CIRC: nID=STR_ObjNameSingulCIRC; break; 302 case OBJ_SECT: nID=STR_ObjNameSingulSECT; break; 303 case OBJ_CARC: nID=STR_ObjNameSingulCARC; break; 304 case OBJ_CCUT: nID=STR_ObjNameSingulCCUT; break; 305 default: break; 306 } 307 } else { 308 switch (meCircleKind) { 309 case OBJ_CIRC: nID=STR_ObjNameSingulCIRCE; break; 310 case OBJ_SECT: nID=STR_ObjNameSingulSECTE; break; 311 case OBJ_CARC: nID=STR_ObjNameSingulCARCE; break; 312 case OBJ_CCUT: nID=STR_ObjNameSingulCCUTE; break; 313 default: break; 314 } 315 } 316 rName=ImpGetResStr(nID); 317 318 String aName( GetName() ); 319 if(aName.Len()) 320 { 321 rName += sal_Unicode(' '); 322 rName += sal_Unicode('\''); 323 rName += aName; 324 rName += sal_Unicode('\''); 325 } 326 } 327 328 void SdrCircObj::TakeObjNamePlural(XubString& rName) const 329 { 330 sal_uInt16 nID=STR_ObjNamePluralCIRC; 331 if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) { 332 switch (meCircleKind) { 333 case OBJ_CIRC: nID=STR_ObjNamePluralCIRC; break; 334 case OBJ_SECT: nID=STR_ObjNamePluralSECT; break; 335 case OBJ_CARC: nID=STR_ObjNamePluralCARC; break; 336 case OBJ_CCUT: nID=STR_ObjNamePluralCCUT; break; 337 default: break; 338 } 339 } else { 340 switch (meCircleKind) { 341 case OBJ_CIRC: nID=STR_ObjNamePluralCIRCE; break; 342 case OBJ_SECT: nID=STR_ObjNamePluralSECTE; break; 343 case OBJ_CARC: nID=STR_ObjNamePluralCARCE; break; 344 case OBJ_CCUT: nID=STR_ObjNamePluralCCUTE; break; 345 default: break; 346 } 347 } 348 rName=ImpGetResStr(nID); 349 } 350 351 void SdrCircObj::operator=(const SdrObject& rObj) 352 { 353 SdrRectObj::operator=(rObj); 354 355 nStartWink = ((SdrCircObj&)rObj).nStartWink; 356 nEndWink = ((SdrCircObj&)rObj).nEndWink; 357 } 358 359 basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const 360 { 361 const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink)); 362 return basegfx::B2DPolyPolygon(aCircPolygon); 363 } 364 365 struct ImpCircUser : public SdrDragStatUserData 366 { 367 Rectangle aR; 368 Point aCenter; 369 Point aRadius; 370 Point aP1; 371 Point aP2; 372 long nMaxRad; 373 long nHgt; 374 long nWdt; 375 long nStart; 376 long nEnd; 377 long nWink; 378 FASTBOOL bRight; // noch nicht implementiert 379 380 public: 381 ImpCircUser() 382 : nMaxRad(0), 383 nHgt(0), 384 nWdt(0), 385 nStart(0), 386 nEnd(0), 387 bRight(sal_False) 388 {} 389 void SetCreateParams(SdrDragStat& rStat); 390 }; 391 392 sal_uInt32 SdrCircObj::GetHdlCount() const 393 { 394 if(OBJ_CIRC != meCircleKind) 395 { 396 return 10L; 397 } 398 else 399 { 400 return 8L; 401 } 402 } 403 404 SdrHdl* SdrCircObj::GetHdl(sal_uInt32 nHdlNum) const 405 { 406 if (meCircleKind==OBJ_CIRC) 407 { 408 nHdlNum += 2L; 409 } 410 411 SdrHdl* pH = NULL; 412 Point aPnt; 413 SdrHdlKind eLocalKind(HDL_MOVE); 414 sal_uInt32 nPNum(0); 415 416 switch (nHdlNum) 417 { 418 case 0: 419 aPnt = GetWinkPnt(aRect,nStartWink); 420 eLocalKind = HDL_CIRC; 421 nPNum = 1; 422 break; 423 case 1: 424 aPnt = GetWinkPnt(aRect,nEndWink); 425 eLocalKind = HDL_CIRC; 426 nPNum = 2L; 427 break; 428 case 2: 429 aPnt = aRect.TopLeft(); 430 eLocalKind = HDL_UPLFT; 431 break; 432 case 3: 433 aPnt = aRect.TopCenter(); 434 eLocalKind = HDL_UPPER; 435 break; 436 case 4: 437 aPnt = aRect.TopRight(); 438 eLocalKind = HDL_UPRGT; 439 break; 440 case 5: 441 aPnt = aRect.LeftCenter(); 442 eLocalKind = HDL_LEFT; 443 break; 444 case 6: 445 aPnt = aRect.RightCenter(); 446 eLocalKind = HDL_RIGHT; 447 break; 448 case 7: 449 aPnt = aRect.BottomLeft(); 450 eLocalKind = HDL_LWLFT; 451 break; 452 case 8: 453 aPnt = aRect.BottomCenter(); 454 eLocalKind = HDL_LOWER; 455 break; 456 case 9: 457 aPnt = aRect.BottomRight(); 458 eLocalKind = HDL_LWRGT; 459 break; 460 } 461 462 if (aGeo.nShearWink) 463 { 464 ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan); 465 } 466 467 if (aGeo.nDrehWink) 468 { 469 RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos); 470 } 471 472 if (eLocalKind != HDL_MOVE) 473 { 474 pH = new SdrHdl(aPnt,eLocalKind); 475 pH->SetPointNum(nPNum); 476 pH->SetObj((SdrObject*)this); 477 pH->SetDrehWink(aGeo.nDrehWink); 478 } 479 480 return pH; 481 } 482 483 //////////////////////////////////////////////////////////////////////////////////////////////////// 484 485 bool SdrCircObj::hasSpecialDrag() const 486 { 487 return true; 488 } 489 490 bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const 491 { 492 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind()); 493 494 if(bWink) 495 { 496 if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum()) 497 { 498 rDrag.SetNoSnap(true); 499 } 500 501 return true; 502 } 503 504 return SdrTextObj::beginSpecialDrag(rDrag); 505 } 506 507 bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag) 508 { 509 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind()); 510 511 if(bWink) 512 { 513 Point aPt(rDrag.GetNow()); 514 515 if (aGeo.nDrehWink!=0) 516 RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); 517 518 if (aGeo.nShearWink!=0) 519 ShearPoint(aPt,aRect.TopLeft(),-aGeo.nTan); 520 521 aPt-=aRect.Center(); 522 523 long nWdt=aRect.Right()-aRect.Left(); 524 long nHgt=aRect.Bottom()-aRect.Top(); 525 526 if(nWdt>=nHgt) 527 { 528 aPt.Y()=BigMulDiv(aPt.Y(),nWdt,nHgt); 529 } 530 else 531 { 532 aPt.X()=BigMulDiv(aPt.X(),nHgt,nWdt); 533 } 534 535 long nWink=NormAngle360(GetAngle(aPt)); 536 537 if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled()) 538 { 539 long nSA=rDrag.GetView()->GetSnapAngle(); 540 541 if (nSA!=0) 542 { 543 nWink+=nSA/2; 544 nWink/=nSA; 545 nWink*=nSA; 546 nWink=NormAngle360(nWink); 547 } 548 } 549 550 if(1 == rDrag.GetHdl()->GetPointNum()) 551 { 552 nStartWink = nWink; 553 } 554 else if(2 == rDrag.GetHdl()->GetPointNum()) 555 { 556 nEndWink = nWink; 557 } 558 559 SetRectsDirty(); 560 SetXPolyDirty(); 561 ImpSetCircInfoToAttr(); 562 SetChanged(); 563 564 return true; 565 } 566 else 567 { 568 return SdrTextObj::applySpecialDrag(rDrag); 569 } 570 } 571 572 String SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const 573 { 574 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj()); 575 576 if(bCreateComment) 577 { 578 XubString aStr; 579 ImpTakeDescriptionStr(STR_ViewCreateObj, aStr); 580 const sal_uInt32 nPntAnz(rDrag.GetPointAnz()); 581 582 if(OBJ_CIRC != meCircleKind && nPntAnz > 2) 583 { 584 ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser(); 585 sal_Int32 nWink; 586 587 aStr.AppendAscii(" ("); 588 589 if(3 == nPntAnz) 590 { 591 nWink = pU->nStart; 592 } 593 else 594 { 595 nWink = pU->nEnd; 596 } 597 598 aStr += GetWinkStr(nWink,sal_False); 599 aStr += sal_Unicode(')'); 600 } 601 602 return aStr; 603 } 604 else 605 { 606 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind()); 607 608 if(bWink) 609 { 610 XubString aStr; 611 const sal_Int32 nWink(1 == rDrag.GetHdl()->GetPointNum() ? nStartWink : nEndWink); 612 613 ImpTakeDescriptionStr(STR_DragCircAngle, aStr); 614 aStr.AppendAscii(" ("); 615 aStr += GetWinkStr(nWink,sal_False); 616 aStr += sal_Unicode(')'); 617 618 return aStr; 619 } 620 else 621 { 622 return SdrTextObj::getSpecialDragComment(rDrag); 623 } 624 } 625 } 626 627 //////////////////////////////////////////////////////////////////////////////////////////////////// 628 629 void ImpCircUser::SetCreateParams(SdrDragStat& rStat) 630 { 631 rStat.TakeCreateRect(aR); 632 aR.Justify(); 633 aCenter=aR.Center(); 634 nWdt=aR.Right()-aR.Left(); 635 nHgt=aR.Bottom()-aR.Top(); 636 nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2; 637 nStart=0; 638 nEnd=36000; 639 if (rStat.GetPointAnz()>2) { 640 Point aP(rStat.GetPoint(2)-aCenter); 641 if (nWdt==0) aP.X()=0; 642 if (nHgt==0) aP.Y()=0; 643 if (nWdt>=nHgt) { 644 if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt; 645 } else { 646 if (nWdt!=0) aP.X()=aP.X()*nHgt/nWdt; 647 } 648 nStart=NormAngle360(GetAngle(aP)); 649 if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) { 650 long nSA=rStat.GetView()->GetSnapAngle(); 651 if (nSA!=0) { // Winkelfang 652 nStart+=nSA/2; 653 nStart/=nSA; 654 nStart*=nSA; 655 nStart=NormAngle360(nStart); 656 } 657 } 658 aP1 = GetWinkPnt(aR,nStart); 659 nEnd=nStart; 660 aP2=aP1; 661 } else aP1=aCenter; 662 if (rStat.GetPointAnz()>3) { 663 Point aP(rStat.GetPoint(3)-aCenter); 664 if (nWdt>=nHgt) { 665 aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt); 666 } else { 667 aP.X()=BigMulDiv(aP.X(),nHgt,nWdt); 668 } 669 nEnd=NormAngle360(GetAngle(aP)); 670 if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) { 671 long nSA=rStat.GetView()->GetSnapAngle(); 672 if (nSA!=0) { // Winkelfang 673 nEnd+=nSA/2; 674 nEnd/=nSA; 675 nEnd*=nSA; 676 nEnd=NormAngle360(nEnd); 677 } 678 } 679 aP2 = GetWinkPnt(aR,nEnd); 680 } else aP2=aCenter; 681 } 682 683 void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const 684 { 685 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser(); 686 if (pU==NULL) { 687 pU=new ImpCircUser; 688 rStat.SetUser(pU); 689 } 690 pU->SetCreateParams(rStat); 691 } 692 693 FASTBOOL SdrCircObj::BegCreate(SdrDragStat& rStat) 694 { 695 rStat.SetOrtho4Possible(); 696 Rectangle aRect1(rStat.GetStart(), rStat.GetNow()); 697 aRect1.Justify(); 698 rStat.SetActionRect(aRect1); 699 aRect = aRect1; 700 ImpSetCreateParams(rStat); 701 return sal_True; 702 } 703 704 FASTBOOL SdrCircObj::MovCreate(SdrDragStat& rStat) 705 { 706 ImpSetCreateParams(rStat); 707 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser(); 708 rStat.SetActionRect(pU->aR); 709 aRect=pU->aR; // fuer ObjName 710 ImpJustifyRect(aRect); 711 nStartWink=pU->nStart; 712 nEndWink=pU->nEnd; 713 SetBoundRectDirty(); 714 bSnapRectDirty=sal_True; 715 SetXPolyDirty(); 716 717 // #i103058# push current angle settings to ItemSet to 718 // allow FullDrag visualisation 719 if(rStat.GetPointAnz() >= 4) 720 { 721 ImpSetCircInfoToAttr(); 722 } 723 724 return sal_True; 725 } 726 727 FASTBOOL SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) 728 { 729 ImpSetCreateParams(rStat); 730 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser(); 731 FASTBOOL bRet=sal_False; 732 if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC; 733 if (meCircleKind==OBJ_CIRC) { 734 bRet=rStat.GetPointAnz()>=2; 735 if (bRet) { 736 aRect=pU->aR; 737 ImpJustifyRect(aRect); 738 } 739 } else { 740 rStat.SetNoSnap(rStat.GetPointAnz()>=2); 741 rStat.SetOrtho4Possible(rStat.GetPointAnz()<2); 742 bRet=rStat.GetPointAnz()>=4; 743 if (bRet) { 744 aRect=pU->aR; 745 ImpJustifyRect(aRect); 746 nStartWink=pU->nStart; 747 nEndWink=pU->nEnd; 748 } 749 } 750 bClosedObj=meCircleKind!=OBJ_CARC; 751 SetRectsDirty(); 752 SetXPolyDirty(); 753 ImpSetCircInfoToAttr(); 754 if (bRet) { 755 delete pU; 756 rStat.SetUser(NULL); 757 } 758 return bRet; 759 } 760 761 void SdrCircObj::BrkCreate(SdrDragStat& rStat) 762 { 763 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser(); 764 delete pU; 765 rStat.SetUser(NULL); 766 } 767 768 FASTBOOL SdrCircObj::BckCreate(SdrDragStat& rStat) 769 { 770 rStat.SetNoSnap(rStat.GetPointAnz()>=3); 771 rStat.SetOrtho4Possible(rStat.GetPointAnz()<3); 772 return meCircleKind!=OBJ_CIRC; 773 } 774 775 basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const 776 { 777 ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser(); 778 779 if(rDrag.GetPointAnz() < 4L) 780 { 781 // force to OBJ_CIRC to get full visualisation 782 basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(OBJ_CIRC, pU->aR, pU->nStart, pU->nEnd)); 783 784 if(3L == rDrag.GetPointAnz()) 785 { 786 // add edge to first point on ellipse 787 basegfx::B2DPolygon aNew; 788 789 aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y())); 790 aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y())); 791 aRetval.append(aNew); 792 } 793 794 return aRetval; 795 } 796 else 797 { 798 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd)); 799 } 800 } 801 802 Pointer SdrCircObj::GetCreatePointer() const 803 { 804 switch (meCircleKind) { 805 case OBJ_CIRC: return Pointer(POINTER_DRAW_ELLIPSE); 806 case OBJ_SECT: return Pointer(POINTER_DRAW_PIE); 807 case OBJ_CARC: return Pointer(POINTER_DRAW_ARC); 808 case OBJ_CCUT: return Pointer(POINTER_DRAW_CIRCLECUT); 809 default: break; 810 } // switch 811 return Pointer(POINTER_CROSS); 812 } 813 814 void SdrCircObj::NbcMove(const Size& aSiz) 815 { 816 MoveRect(aRect,aSiz); 817 MoveRect(aOutRect,aSiz); 818 MoveRect(maSnapRect,aSiz); 819 SetXPolyDirty(); 820 SetRectsDirty(sal_True); 821 } 822 823 void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) 824 { 825 long nWink0=aGeo.nDrehWink; 826 FASTBOOL bNoShearRota=(aGeo.nDrehWink==0 && aGeo.nShearWink==0); 827 SdrTextObj::NbcResize(rRef,xFact,yFact); 828 bNoShearRota|=(aGeo.nDrehWink==0 && aGeo.nShearWink==0); 829 if (meCircleKind!=OBJ_CIRC) { 830 FASTBOOL bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0); 831 FASTBOOL bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0); 832 if (bXMirr || bYMirr) { 833 // bei bXMirr!=bYMirr muessten eigentlich noch die beiden 834 // Linienende vertauscht werden. Das ist jedoch mal wieder 835 // schlecht (wg. zwangslaeufiger harter Formatierung). 836 // Alternativ koennte ein bMirrored-Flag eingefuehrt werden 837 // (Vielleicht ja mal grundsaetzlich, auch fuer gepiegelten Text, ...). 838 long nS0=nStartWink; 839 long nE0=nEndWink; 840 if (bNoShearRota) { 841 // Das RectObj spiegelt bei VMirror bereits durch durch 180deg Drehung. 842 if (! (bXMirr && bYMirr)) { 843 long nTmp=nS0; 844 nS0=18000-nE0; 845 nE0=18000-nTmp; 846 } 847 } else { // Spiegeln fuer verzerrte Ellipsen 848 if (bXMirr!=bYMirr) { 849 nS0+=nWink0; 850 nE0+=nWink0; 851 if (bXMirr) { 852 long nTmp=nS0; 853 nS0=18000-nE0; 854 nE0=18000-nTmp; 855 } 856 if (bYMirr) { 857 long nTmp=nS0; 858 nS0=-nE0; 859 nE0=-nTmp; 860 } 861 nS0-=aGeo.nDrehWink; 862 nE0-=aGeo.nDrehWink; 863 } 864 } 865 long nWinkDif=nE0-nS0; 866 nStartWink=NormAngle360(nS0); 867 nEndWink =NormAngle360(nE0); 868 if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis 869 } 870 } 871 SetXPolyDirty(); 872 ImpSetCircInfoToAttr(); 873 } 874 875 void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, FASTBOOL bVShear) 876 { 877 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear); 878 SetXPolyDirty(); 879 ImpSetCircInfoToAttr(); 880 } 881 882 void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2) 883 { 884 //long nWink0=aGeo.nDrehWink; 885 FASTBOOL bFreeMirr=meCircleKind!=OBJ_CIRC; 886 Point aTmpPt1; 887 Point aTmpPt2; 888 if (bFreeMirr) { // bei freier Spiegelachse einige Vorbereitungen Treffen 889 Point aCenter(aRect.Center()); 890 long nWdt=aRect.GetWidth()-1; 891 long nHgt=aRect.GetHeight()-1; 892 long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2; 893 double a; 894 // Startpunkt 895 a=nStartWink*nPi180; 896 aTmpPt1=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad)); 897 if (nWdt==0) aTmpPt1.X()=0; 898 if (nHgt==0) aTmpPt1.Y()=0; 899 aTmpPt1+=aCenter; 900 // Endpunkt 901 a=nEndWink*nPi180; 902 aTmpPt2=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad)); 903 if (nWdt==0) aTmpPt2.X()=0; 904 if (nHgt==0) aTmpPt2.Y()=0; 905 aTmpPt2+=aCenter; 906 if (aGeo.nDrehWink!=0) { 907 RotatePoint(aTmpPt1,aRect.TopLeft(),aGeo.nSin,aGeo.nCos); 908 RotatePoint(aTmpPt2,aRect.TopLeft(),aGeo.nSin,aGeo.nCos); 909 } 910 if (aGeo.nShearWink!=0) { 911 ShearPoint(aTmpPt1,aRect.TopLeft(),aGeo.nTan); 912 ShearPoint(aTmpPt2,aRect.TopLeft(),aGeo.nTan); 913 } 914 } 915 SdrTextObj::NbcMirror(rRef1,rRef2); 916 if (meCircleKind!=OBJ_CIRC) { // Anpassung von Start- und Endwinkel 917 MirrorPoint(aTmpPt1,rRef1,rRef2); 918 MirrorPoint(aTmpPt2,rRef1,rRef2); 919 // Unrotate: 920 if (aGeo.nDrehWink!=0) { 921 RotatePoint(aTmpPt1,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung 922 RotatePoint(aTmpPt2,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin fuer Umkehrung 923 } 924 // Unshear: 925 if (aGeo.nShearWink!=0) { 926 ShearPoint(aTmpPt1,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung 927 ShearPoint(aTmpPt2,aRect.TopLeft(),-aGeo.nTan); // -tan fuer Umkehrung 928 } 929 Point aCenter(aRect.Center()); 930 aTmpPt1-=aCenter; 931 aTmpPt2-=aCenter; 932 // Weil gespiegelt sind die Winkel nun auch noch vertauscht 933 nStartWink=GetAngle(aTmpPt2); 934 nEndWink =GetAngle(aTmpPt1); 935 long nWinkDif=nEndWink-nStartWink; 936 nStartWink=NormAngle360(nStartWink); 937 nEndWink =NormAngle360(nEndWink); 938 if (nWinkDif==36000) nEndWink+=nWinkDif; // Vollkreis 939 } 940 SetXPolyDirty(); 941 ImpSetCircInfoToAttr(); 942 } 943 944 SdrObjGeoData* SdrCircObj::NewGeoData() const 945 { 946 return new SdrCircObjGeoData; 947 } 948 949 void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const 950 { 951 SdrRectObj::SaveGeoData(rGeo); 952 SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo; 953 rCGeo.nStartWink=nStartWink; 954 rCGeo.nEndWink =nEndWink; 955 } 956 957 void SdrCircObj::RestGeoData(const SdrObjGeoData& rGeo) 958 { 959 SdrRectObj::RestGeoData(rGeo); 960 SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo; 961 nStartWink=rCGeo.nStartWink; 962 nEndWink =rCGeo.nEndWink; 963 SetXPolyDirty(); 964 ImpSetCircInfoToAttr(); 965 } 966 967 void Union(Rectangle& rR, const Point& rP) 968 { 969 if (rP.X()<rR.Left ()) rR.Left ()=rP.X(); 970 if (rP.X()>rR.Right ()) rR.Right ()=rP.X(); 971 if (rP.Y()<rR.Top ()) rR.Top ()=rP.Y(); 972 if (rP.Y()>rR.Bottom()) rR.Bottom()=rP.Y(); 973 } 974 975 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle& rRect) const 976 { 977 rRect=aRect; 978 if (meCircleKind!=OBJ_CIRC) { 979 const Point aPntStart(GetWinkPnt(aRect,nStartWink)); 980 const Point aPntEnd(GetWinkPnt(aRect,nEndWink)); 981 long a=nStartWink; 982 long e=nEndWink; 983 rRect.Left ()=aRect.Right(); 984 rRect.Right ()=aRect.Left(); 985 rRect.Top ()=aRect.Bottom(); 986 rRect.Bottom()=aRect.Top(); 987 Union(rRect,aPntStart); 988 Union(rRect,aPntEnd); 989 if ((a<=18000 && e>=18000) || (a>e && (a<=18000 || e>=18000))) { 990 Union(rRect,aRect.LeftCenter()); 991 } 992 if ((a<=27000 && e>=27000) || (a>e && (a<=27000 || e>=27000))) { 993 Union(rRect,aRect.BottomCenter()); 994 } 995 if (a>e) { 996 Union(rRect,aRect.RightCenter()); 997 } 998 if ((a<=9000 && e>=9000) || (a>e && (a<=9000 || e>=9000))) { 999 Union(rRect,aRect.TopCenter()); 1000 } 1001 if (meCircleKind==OBJ_SECT) { 1002 Union(rRect,aRect.Center()); 1003 } 1004 if (aGeo.nDrehWink!=0) { 1005 Point aDst(rRect.TopLeft()); 1006 aDst-=aRect.TopLeft(); 1007 Point aDst0(aDst); 1008 RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos); 1009 aDst-=aDst0; 1010 rRect.Move(aDst.X(),aDst.Y()); 1011 } 1012 } 1013 if (aGeo.nShearWink!=0) { 1014 long nDst=Round((rRect.Bottom()-rRect.Top())*aGeo.nTan); 1015 if (aGeo.nShearWink>0) { 1016 Point aRef(rRect.TopLeft()); 1017 rRect.Left()-=nDst; 1018 Point aTmpPt(rRect.TopLeft()); 1019 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos); 1020 aTmpPt-=rRect.TopLeft(); 1021 rRect.Move(aTmpPt.X(),aTmpPt.Y()); 1022 } else { 1023 rRect.Right()-=nDst; 1024 } 1025 } 1026 } 1027 1028 void SdrCircObj::RecalcSnapRect() 1029 { 1030 if (PaintNeedsXPolyCirc()) { 1031 maSnapRect=GetXPoly().GetBoundRect(); 1032 } else { 1033 TakeUnrotatedSnapRect(maSnapRect); 1034 } 1035 } 1036 1037 void SdrCircObj::NbcSetSnapRect(const Rectangle& rRect) 1038 { 1039 if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind!=OBJ_CIRC) { 1040 Rectangle aSR0(GetSnapRect()); 1041 long nWdt0=aSR0.Right()-aSR0.Left(); 1042 long nHgt0=aSR0.Bottom()-aSR0.Top(); 1043 long nWdt1=rRect.Right()-rRect.Left(); 1044 long nHgt1=rRect.Bottom()-rRect.Top(); 1045 NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0)); 1046 NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top())); 1047 } else { 1048 aRect=rRect; 1049 ImpJustifyRect(aRect); 1050 } 1051 SetRectsDirty(); 1052 SetXPolyDirty(); 1053 ImpSetCircInfoToAttr(); 1054 } 1055 1056 sal_uInt32 SdrCircObj::GetSnapPointCount() const 1057 { 1058 if (meCircleKind==OBJ_CIRC) { 1059 return 1L; 1060 } else { 1061 return 3L; 1062 } 1063 } 1064 1065 Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const 1066 { 1067 switch (i) { 1068 case 1 : return GetWinkPnt(aRect,nStartWink); 1069 case 2 : return GetWinkPnt(aRect,nEndWink); 1070 default: return aRect.Center(); 1071 } 1072 } 1073 1074 void __EXPORT SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) 1075 { 1076 SetXPolyDirty(); 1077 SdrRectObj::Notify(rBC,rHint); 1078 ImpSetAttrToCircInfo(); 1079 } 1080 1081 //////////////////////////////////////////////////////////////////////////////////////////////////// 1082 1083 void SdrCircObj::ImpSetAttrToCircInfo() 1084 { 1085 const SfxItemSet& rSet = GetObjectItemSet(); 1086 SdrCircKind eNewKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue(); 1087 SdrObjKind eNewKind = meCircleKind; 1088 1089 if(eNewKindA == SDRCIRC_FULL) 1090 eNewKind = OBJ_CIRC; 1091 else if(eNewKindA == SDRCIRC_SECT) 1092 eNewKind = OBJ_SECT; 1093 else if(eNewKindA == SDRCIRC_ARC) 1094 eNewKind = OBJ_CARC; 1095 else if(eNewKindA == SDRCIRC_CUT) 1096 eNewKind = OBJ_CCUT; 1097 1098 sal_Int32 nNewStart = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue(); 1099 sal_Int32 nNewEnd = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue(); 1100 1101 sal_Bool bKindChg = meCircleKind != eNewKind; 1102 sal_Bool bWinkChg = nNewStart != nStartWink || nNewEnd != nEndWink; 1103 1104 if(bKindChg || bWinkChg) 1105 { 1106 meCircleKind = eNewKind; 1107 nStartWink = nNewStart; 1108 nEndWink = nNewEnd; 1109 1110 if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg)) 1111 { 1112 SetXPolyDirty(); 1113 SetRectsDirty(); 1114 } 1115 } 1116 } 1117 1118 void SdrCircObj::ImpSetCircInfoToAttr() 1119 { 1120 SdrCircKind eNewKindA = SDRCIRC_FULL; 1121 const SfxItemSet& rSet = GetObjectItemSet(); 1122 1123 if(meCircleKind == OBJ_SECT) 1124 eNewKindA = SDRCIRC_SECT; 1125 else if(meCircleKind == OBJ_CARC) 1126 eNewKindA = SDRCIRC_ARC; 1127 else if(meCircleKind == OBJ_CCUT) 1128 eNewKindA = SDRCIRC_CUT; 1129 1130 SdrCircKind eOldKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue(); 1131 sal_Int32 nOldStartWink = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue(); 1132 sal_Int32 nOldEndWink = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue(); 1133 1134 if(eNewKindA != eOldKindA || nStartWink != nOldStartWink || nEndWink != nOldEndWink) 1135 { 1136 // #81921# since SetItem() implicitly calls ImpSetAttrToCircInfo() 1137 // setting the item directly is necessary here. 1138 if(eNewKindA != eOldKindA) 1139 { 1140 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA)); 1141 } 1142 1143 if(nStartWink != nOldStartWink) 1144 { 1145 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink)); 1146 } 1147 1148 if(nEndWink != nOldEndWink) 1149 { 1150 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink)); 1151 } 1152 1153 SetXPolyDirty(); 1154 ImpSetAttrToCircInfo(); 1155 } 1156 } 1157 1158 SdrObject* SdrCircObj::DoConvertToPolyObj(sal_Bool bBezier) const 1159 { 1160 const sal_Bool bFill(OBJ_CARC == meCircleKind ? sal_False : sal_True); 1161 const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink)); 1162 SdrObject* pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier); 1163 pRet = ImpConvertAddText(pRet, bBezier); 1164 1165 return pRet; 1166 } 1167 1168 ////////////////////////////////////////////////////////////////////////////// 1169 // eof 1170