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