1160 lines
37 KiB
C++
1160 lines
37 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <basegfx/matrix/b2dhommatrix.hxx>
|
|
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
|
#include <basegfx/point/b2dpoint.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <math.h>
|
|
#include <rtl/ustrbuf.hxx>
|
|
|
|
#include <svx/dialmgr.hxx>
|
|
#include <svx/strings.hrc>
|
|
|
|
#include <sdr/contact/viewcontactofsdrcircobj.hxx>
|
|
#include <sdr/properties/circleproperties.hxx>
|
|
#include <svx/svddrag.hxx>
|
|
#include <svx/svdmodel.hxx>
|
|
#include <svx/svdocirc.hxx>
|
|
#include <svx/svdopath.hxx>
|
|
#include <svx/svdtrans.hxx>
|
|
#include <svx/svdview.hxx>
|
|
#include <svx/sxciaitm.hxx>
|
|
#include <sxcikitm.hxx>
|
|
#include <svx/xfillit0.hxx>
|
|
#include <svx/xlineit0.hxx>
|
|
#include <svx/xlnedit.hxx>
|
|
#include <svx/xlnedwit.hxx>
|
|
#include <svx/xlnstit.hxx>
|
|
#include <svx/xlnstwit.hxx>
|
|
#include <svx/xlnwtit.hxx>
|
|
#include <vcl/canvastools.hxx>
|
|
#include <vcl/ptrstyle.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
|
|
static Point GetAnglePnt(const tools::Rectangle& rR, Degree100 nAngle)
|
|
{
|
|
Point aCenter(rR.Center());
|
|
tools::Long nWdt=rR.Right()-rR.Left();
|
|
tools::Long nHgt=rR.Bottom()-rR.Top();
|
|
tools::Long nMaxRad=(std::max(nWdt,nHgt)+1) /2;
|
|
double a = toRadians(nAngle);
|
|
Point aRetval(basegfx::fround<tools::Long>(cos(a) * nMaxRad),
|
|
basegfx::fround<tools::Long>(-sin(a) * nMaxRad));
|
|
if (nWdt==0) aRetval.setX(0 );
|
|
if (nHgt==0) aRetval.setY(0 );
|
|
if (nWdt!=nHgt) {
|
|
if (nWdt>nHgt) {
|
|
if (nWdt!=0) {
|
|
// stop possible overruns for very large objects
|
|
if (std::abs(nHgt)>32767 || std::abs(aRetval.Y())>32767) {
|
|
aRetval.setY(BigMulDiv(aRetval.Y(),nHgt,nWdt) );
|
|
} else {
|
|
aRetval.setY(aRetval.Y()*nHgt/nWdt );
|
|
}
|
|
}
|
|
} else {
|
|
if (nHgt!=0) {
|
|
// stop possible overruns for very large objects
|
|
if (std::abs(nWdt)>32767 || std::abs(aRetval.X())>32767) {
|
|
aRetval.setX(BigMulDiv(aRetval.X(),nWdt,nHgt) );
|
|
} else {
|
|
aRetval.setX(aRetval.X()*nWdt/nHgt );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
aRetval+=aCenter;
|
|
return aRetval;
|
|
}
|
|
|
|
|
|
// BaseProperties section
|
|
|
|
std::unique_ptr<sdr::properties::BaseProperties> SdrCircObj::CreateObjectSpecificProperties()
|
|
{
|
|
return std::make_unique<sdr::properties::CircleProperties>(*this);
|
|
}
|
|
|
|
|
|
// DrawContact section
|
|
|
|
std::unique_ptr<sdr::contact::ViewContact> SdrCircObj::CreateObjectSpecificViewContact()
|
|
{
|
|
return std::make_unique<sdr::contact::ViewContactOfSdrCircObj>(*this);
|
|
}
|
|
|
|
SdrCircKind ToSdrCircKind(SdrObjKind eKind)
|
|
{
|
|
switch (eKind)
|
|
{
|
|
case SdrObjKind::CircleOrEllipse: return SdrCircKind::Full;
|
|
case SdrObjKind::CircleSection: return SdrCircKind::Section;
|
|
case SdrObjKind::CircleArc: return SdrCircKind::Arc;
|
|
case SdrObjKind::CircleCut: return SdrCircKind::Cut;
|
|
default: assert(false);
|
|
}
|
|
return SdrCircKind::Full;
|
|
}
|
|
|
|
SdrCircObj::SdrCircObj(
|
|
SdrModel& rSdrModel,
|
|
SdrCircKind eNewKind)
|
|
: SdrRectObj(rSdrModel)
|
|
{
|
|
nStartAngle=0_deg100;
|
|
nEndAngle=36000_deg100;
|
|
meCircleKind=eNewKind;
|
|
m_bClosedObj=eNewKind!=SdrCircKind::Arc;
|
|
}
|
|
|
|
SdrCircObj::SdrCircObj(SdrModel& rSdrModel, SdrCircObj const & rSource)
|
|
: SdrRectObj(rSdrModel, rSource)
|
|
{
|
|
meCircleKind = rSource.meCircleKind;
|
|
nStartAngle = rSource.nStartAngle;
|
|
nEndAngle = rSource.nEndAngle;
|
|
m_bClosedObj = rSource.m_bClosedObj;
|
|
}
|
|
|
|
SdrCircObj::SdrCircObj(
|
|
SdrModel& rSdrModel,
|
|
SdrCircKind eNewKind,
|
|
const tools::Rectangle& rRect)
|
|
: SdrRectObj(rSdrModel, rRect)
|
|
{
|
|
nStartAngle=0_deg100;
|
|
nEndAngle=36000_deg100;
|
|
meCircleKind=eNewKind;
|
|
m_bClosedObj=eNewKind!=SdrCircKind::Arc;
|
|
}
|
|
|
|
SdrCircObj::SdrCircObj(
|
|
SdrModel& rSdrModel,
|
|
SdrCircKind eNewKind,
|
|
const tools::Rectangle& rRect,
|
|
Degree100 nNewStartAngle,
|
|
Degree100 nNewEndAngle)
|
|
: SdrRectObj(rSdrModel, rRect)
|
|
{
|
|
Degree100 nAngleDif=nNewEndAngle-nNewStartAngle;
|
|
nStartAngle=NormAngle36000(nNewStartAngle);
|
|
nEndAngle=NormAngle36000(nNewEndAngle);
|
|
if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
|
|
meCircleKind=eNewKind;
|
|
m_bClosedObj=eNewKind!=SdrCircKind::Arc;
|
|
}
|
|
|
|
SdrCircObj::~SdrCircObj()
|
|
{
|
|
}
|
|
|
|
void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
|
|
{
|
|
bool bCanConv=!HasText() || ImpCanConvTextToCurve();
|
|
rInfo.bEdgeRadiusAllowed = false;
|
|
rInfo.bCanConvToPath=bCanConv;
|
|
rInfo.bCanConvToPoly=bCanConv;
|
|
rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
|
|
}
|
|
|
|
SdrObjKind SdrCircObj::GetObjIdentifier() const
|
|
{
|
|
switch (meCircleKind)
|
|
{
|
|
case SdrCircKind::Full: return SdrObjKind::CircleOrEllipse;
|
|
case SdrCircKind::Section: return SdrObjKind::CircleSection;
|
|
case SdrCircKind::Cut: return SdrObjKind::CircleCut;
|
|
case SdrCircKind::Arc: return SdrObjKind::CircleArc;
|
|
default: assert(false);
|
|
}
|
|
return SdrObjKind::CircleOrEllipse;
|
|
}
|
|
|
|
bool SdrCircObj::PaintNeedsXPolyCirc() const
|
|
{
|
|
// XPoly is necessary for all rotated ellipse objects, circle and
|
|
// ellipse segments.
|
|
// If not WIN, then (for now) also for circle/ellipse segments and circle/
|
|
// ellipse arcs (for precision)
|
|
bool bNeed = maGeo.m_nRotationAngle || maGeo.m_nShearAngle || meCircleKind == SdrCircKind::Cut;
|
|
// If not WIN, then for everything except full circle (for now!)
|
|
if (meCircleKind!=SdrCircKind::Full) bNeed = true;
|
|
|
|
const SfxItemSet& rSet = GetObjectItemSet();
|
|
if(!bNeed)
|
|
{
|
|
// XPoly is necessary for everything that isn't LineSolid or LineNone
|
|
drawing::LineStyle eLine = rSet.Get(XATTR_LINESTYLE).GetValue();
|
|
bNeed = eLine != drawing::LineStyle_NONE && eLine != drawing::LineStyle_SOLID;
|
|
|
|
// XPoly is necessary for thick lines
|
|
if(!bNeed && eLine != drawing::LineStyle_NONE)
|
|
bNeed = rSet.Get(XATTR_LINEWIDTH).GetValue() != 0;
|
|
|
|
// XPoly is necessary for circle arcs with line ends
|
|
if(!bNeed && meCircleKind == SdrCircKind::Arc)
|
|
{
|
|
// start of the line is here if StartPolygon, StartWidth!=0
|
|
bNeed=rSet.Get(XATTR_LINESTART).GetLineStartValue().count() != 0 &&
|
|
rSet.Get(XATTR_LINESTARTWIDTH).GetValue() != 0;
|
|
|
|
if(!bNeed)
|
|
{
|
|
// end of the line is here if EndPolygon, EndWidth!=0
|
|
bNeed = rSet.Get(XATTR_LINEEND).GetLineEndValue().count() != 0 &&
|
|
rSet.Get(XATTR_LINEENDWIDTH).GetValue() != 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// XPoly is necessary if Fill !=None and !=Solid
|
|
if(!bNeed && meCircleKind != SdrCircKind::Arc)
|
|
{
|
|
drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
|
|
bNeed = eFill != drawing::FillStyle_NONE && eFill != drawing::FillStyle_SOLID;
|
|
}
|
|
|
|
if(!bNeed && meCircleKind != SdrCircKind::Full && nStartAngle == nEndAngle)
|
|
bNeed = true; // otherwise we're drawing a full circle
|
|
|
|
return bNeed;
|
|
}
|
|
|
|
basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrCircKind eCircleKind, const tools::Rectangle& rRect1, Degree100 nStart, Degree100 nEnd) const
|
|
{
|
|
const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(rRect1);
|
|
basegfx::B2DPolygon aCircPolygon;
|
|
|
|
if(SdrCircKind::Full == eCircleKind)
|
|
{
|
|
// create full circle. Do not use createPolygonFromEllipse; it's necessary
|
|
// to get the start point to the bottom of the circle to keep compatible to
|
|
// old geometry creation
|
|
aCircPolygon = basegfx::utils::createPolygonFromUnitCircle(1);
|
|
|
|
// needs own scaling and translation from unit circle to target size (same as
|
|
// would be in createPolygonFromEllipse)
|
|
const basegfx::B2DPoint aCenter(aRange.getCenter());
|
|
const basegfx::B2DHomMatrix aMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
|
|
aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
|
|
aCenter.getX(), aCenter.getY()));
|
|
aCircPolygon.transform(aMatrix);
|
|
}
|
|
else
|
|
{
|
|
// mirror start, end for geometry creation since model coordinate system is mirrored in Y
|
|
const double fStart(toRadians((36000_deg100 - nEnd) % 36000_deg100));
|
|
const double fEnd(toRadians((36000_deg100 - nStart) % 36000_deg100));
|
|
|
|
// create circle segment. This is not closed by default
|
|
aCircPolygon = basegfx::utils::createPolygonFromEllipseSegment(
|
|
aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
|
|
fStart, fEnd);
|
|
|
|
// check closing states
|
|
const bool bCloseSegment(SdrCircKind::Arc != eCircleKind);
|
|
const bool bCloseUsingCenter(SdrCircKind::Section == eCircleKind);
|
|
|
|
if(bCloseSegment)
|
|
{
|
|
if(bCloseUsingCenter)
|
|
{
|
|
// add center point at start (for historical reasons)
|
|
basegfx::B2DPolygon aSector;
|
|
aSector.append(aRange.getCenter());
|
|
aSector.append(aCircPolygon);
|
|
aCircPolygon = std::move(aSector);
|
|
}
|
|
|
|
// close
|
|
aCircPolygon.setClosed(true);
|
|
}
|
|
}
|
|
|
|
// #i76950#
|
|
if (maGeo.m_nShearAngle || maGeo.m_nRotationAngle)
|
|
{
|
|
// translate top left to (0,0)
|
|
const basegfx::B2DPoint aTopLeft(aRange.getMinimum());
|
|
basegfx::B2DHomMatrix aMatrix(basegfx::utils::createTranslateB2DHomMatrix(
|
|
-aTopLeft.getX(), -aTopLeft.getY()));
|
|
|
|
// shear, rotate and back to top left (if needed)
|
|
aMatrix = basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
|
|
-maGeo.mfTanShearAngle,
|
|
maGeo.m_nRotationAngle ? toRadians(36000_deg100 - maGeo.m_nRotationAngle) : 0.0,
|
|
aTopLeft) * aMatrix;
|
|
|
|
// apply transformation
|
|
aCircPolygon.transform(aMatrix);
|
|
}
|
|
|
|
return aCircPolygon;
|
|
}
|
|
|
|
void SdrCircObj::RecalcXPoly()
|
|
{
|
|
basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, getRectangle(), nStartAngle, nEndAngle));
|
|
mpXPoly = XPolygon(aPolyCirc);
|
|
}
|
|
|
|
OUString SdrCircObj::TakeObjNameSingul() const
|
|
{
|
|
TranslateId pID=STR_ObjNameSingulCIRC;
|
|
if (getRectangle().GetWidth() == getRectangle().GetHeight() && maGeo.m_nShearAngle == 0_deg100)
|
|
{
|
|
switch (meCircleKind) {
|
|
case SdrCircKind::Full: pID=STR_ObjNameSingulCIRC; break;
|
|
case SdrCircKind::Section: pID=STR_ObjNameSingulSECT; break;
|
|
case SdrCircKind::Arc: pID=STR_ObjNameSingulCARC; break;
|
|
case SdrCircKind::Cut: pID=STR_ObjNameSingulCCUT; break;
|
|
default: break;
|
|
}
|
|
} else {
|
|
switch (meCircleKind) {
|
|
case SdrCircKind::Full: pID=STR_ObjNameSingulCIRCE; break;
|
|
case SdrCircKind::Section: pID=STR_ObjNameSingulSECTE; break;
|
|
case SdrCircKind::Arc: pID=STR_ObjNameSingulCARCE; break;
|
|
case SdrCircKind::Cut: pID=STR_ObjNameSingulCCUTE; break;
|
|
default: break;
|
|
}
|
|
}
|
|
OUString sName(SvxResId(pID));
|
|
|
|
OUString aName(GetName());
|
|
if (!aName.isEmpty())
|
|
sName += " '" + aName + "'";
|
|
return sName;
|
|
}
|
|
|
|
OUString SdrCircObj::TakeObjNamePlural() const
|
|
{
|
|
TranslateId pID=STR_ObjNamePluralCIRC;
|
|
if (getRectangle().GetWidth() == getRectangle().GetHeight() && maGeo.m_nShearAngle == 0_deg100)
|
|
{
|
|
switch (meCircleKind) {
|
|
case SdrCircKind::Full: pID=STR_ObjNamePluralCIRC; break;
|
|
case SdrCircKind::Section: pID=STR_ObjNamePluralSECT; break;
|
|
case SdrCircKind::Arc: pID=STR_ObjNamePluralCARC; break;
|
|
case SdrCircKind::Cut: pID=STR_ObjNamePluralCCUT; break;
|
|
default: break;
|
|
}
|
|
} else {
|
|
switch (meCircleKind) {
|
|
case SdrCircKind::Full: pID=STR_ObjNamePluralCIRCE; break;
|
|
case SdrCircKind::Section: pID=STR_ObjNamePluralSECTE; break;
|
|
case SdrCircKind::Arc: pID=STR_ObjNamePluralCARCE; break;
|
|
case SdrCircKind::Cut: pID=STR_ObjNamePluralCCUTE; break;
|
|
default: break;
|
|
}
|
|
}
|
|
return SvxResId(pID);
|
|
}
|
|
|
|
rtl::Reference<SdrObject> SdrCircObj::CloneSdrObject(SdrModel& rTargetModel) const
|
|
{
|
|
return new SdrCircObj(rTargetModel, *this);
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const
|
|
{
|
|
const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, getRectangle(), nStartAngle, nEndAngle));
|
|
return basegfx::B2DPolyPolygon(aCircPolygon);
|
|
}
|
|
|
|
namespace {
|
|
|
|
struct ImpCircUser : public SdrDragStatUserData
|
|
{
|
|
tools::Rectangle aR;
|
|
Point aCenter;
|
|
Point aP1;
|
|
tools::Long nHgt;
|
|
tools::Long nWdt;
|
|
Degree100 nStart;
|
|
Degree100 nEnd;
|
|
|
|
public:
|
|
ImpCircUser()
|
|
: nHgt(0),
|
|
nWdt(0),
|
|
nStart(0),
|
|
nEnd(0)
|
|
{}
|
|
void SetCreateParams(SdrDragStat const & rStat);
|
|
};
|
|
|
|
}
|
|
|
|
sal_uInt32 SdrCircObj::GetHdlCount() const
|
|
{
|
|
if(SdrCircKind::Full != meCircleKind)
|
|
{
|
|
return 10;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::AddToHdlList(SdrHdlList& rHdlList) const
|
|
{
|
|
for (sal_uInt32 nHdlNum=(SdrCircKind::Full==meCircleKind)?2:0; nHdlNum<=9; ++nHdlNum)
|
|
{
|
|
Point aPnt;
|
|
SdrHdlKind eLocalKind(SdrHdlKind::Move);
|
|
sal_uInt32 nPNum(0);
|
|
tools::Rectangle aRectangle = getRectangle();
|
|
switch (nHdlNum)
|
|
{
|
|
case 0:
|
|
aPnt = GetAnglePnt(aRectangle, nStartAngle);
|
|
eLocalKind = SdrHdlKind::Circle;
|
|
nPNum = 1;
|
|
break;
|
|
case 1:
|
|
aPnt = GetAnglePnt(aRectangle, nEndAngle);
|
|
eLocalKind = SdrHdlKind::Circle;
|
|
nPNum = 2;
|
|
break;
|
|
case 2:
|
|
aPnt = aRectangle.TopLeft();
|
|
eLocalKind = SdrHdlKind::UpperLeft;
|
|
break;
|
|
case 3:
|
|
aPnt = aRectangle.TopCenter();
|
|
eLocalKind = SdrHdlKind::Upper;
|
|
break;
|
|
case 4:
|
|
aPnt = aRectangle.TopRight();
|
|
eLocalKind = SdrHdlKind::UpperRight;
|
|
break;
|
|
case 5:
|
|
aPnt = aRectangle.LeftCenter();
|
|
eLocalKind = SdrHdlKind::Left;
|
|
break;
|
|
case 6:
|
|
aPnt = aRectangle.RightCenter();
|
|
eLocalKind = SdrHdlKind::Right;
|
|
break;
|
|
case 7:
|
|
aPnt = aRectangle.BottomLeft();
|
|
eLocalKind = SdrHdlKind::LowerLeft;
|
|
break;
|
|
case 8:
|
|
aPnt = aRectangle.BottomCenter();
|
|
eLocalKind = SdrHdlKind::Lower;
|
|
break;
|
|
case 9:
|
|
aPnt = aRectangle.BottomRight();
|
|
eLocalKind = SdrHdlKind::LowerRight;
|
|
break;
|
|
}
|
|
|
|
if (maGeo.m_nShearAngle)
|
|
{
|
|
ShearPoint(aPnt, aRectangle.TopLeft(), maGeo.mfTanShearAngle);
|
|
}
|
|
|
|
if (maGeo.m_nRotationAngle)
|
|
{
|
|
RotatePoint(aPnt, aRectangle.TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
}
|
|
|
|
std::unique_ptr<SdrHdl> pH(new SdrHdl(aPnt,eLocalKind));
|
|
pH->SetPointNum(nPNum);
|
|
pH->SetObj(const_cast<SdrCircObj*>(this));
|
|
pH->SetRotationAngle(maGeo.m_nRotationAngle);
|
|
rHdlList.AddHdl(std::move(pH));
|
|
}
|
|
}
|
|
|
|
|
|
bool SdrCircObj::hasSpecialDrag() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
|
|
{
|
|
const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
|
|
|
|
if(bAngle)
|
|
{
|
|
if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
|
|
{
|
|
rDrag.SetNoSnap();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return SdrTextObj::beginSpecialDrag(rDrag);
|
|
}
|
|
|
|
bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
|
|
{
|
|
const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
|
|
|
|
if(bAngle)
|
|
{
|
|
Point aPt(rDrag.GetNow());
|
|
|
|
if (maGeo.m_nRotationAngle)
|
|
RotatePoint(aPt, getRectangle().TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
|
|
if (maGeo.m_nShearAngle)
|
|
ShearPoint(aPt, getRectangle().TopLeft(), -maGeo.mfTanShearAngle);
|
|
|
|
aPt -= getRectangle().Center();
|
|
|
|
tools::Long nWdt = getRectangle().Right() - getRectangle().Left();
|
|
tools::Long nHgt = getRectangle().Bottom() - getRectangle().Top();
|
|
|
|
if(nWdt>=nHgt)
|
|
{
|
|
aPt.setY(BigMulDiv(aPt.Y(),nWdt,nHgt) );
|
|
}
|
|
else
|
|
{
|
|
aPt.setX(BigMulDiv(aPt.X(),nHgt,nWdt) );
|
|
}
|
|
|
|
Degree100 nAngle=NormAngle36000(GetAngle(aPt));
|
|
|
|
if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled())
|
|
{
|
|
Degree100 nSA=rDrag.GetView()->GetSnapAngle();
|
|
|
|
if (nSA)
|
|
{
|
|
nAngle+=nSA/2_deg100;
|
|
nAngle/=nSA;
|
|
nAngle*=nSA;
|
|
nAngle=NormAngle36000(nAngle);
|
|
}
|
|
}
|
|
|
|
if(1 == rDrag.GetHdl()->GetPointNum())
|
|
{
|
|
nStartAngle = nAngle;
|
|
}
|
|
else if(2 == rDrag.GetHdl()->GetPointNum())
|
|
{
|
|
nEndAngle = nAngle;
|
|
}
|
|
|
|
SetBoundAndSnapRectsDirty();
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
SetChanged();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return SdrTextObj::applySpecialDrag(rDrag);
|
|
}
|
|
}
|
|
|
|
OUString SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
|
|
{
|
|
const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
|
|
|
|
if(bCreateComment)
|
|
{
|
|
OUStringBuffer aBuf(ImpGetDescriptionStr(STR_ViewCreateObj));
|
|
const sal_uInt32 nPointCount(rDrag.GetPointCount());
|
|
|
|
if(SdrCircKind::Full != meCircleKind && nPointCount > 2)
|
|
{
|
|
const ImpCircUser* pU = static_cast<const ImpCircUser*>(rDrag.GetUser());
|
|
Degree100 nAngle;
|
|
|
|
aBuf.append(" (");
|
|
|
|
if(3 == nPointCount)
|
|
{
|
|
nAngle = pU->nStart;
|
|
}
|
|
else
|
|
{
|
|
nAngle = pU->nEnd;
|
|
}
|
|
|
|
aBuf.append(SdrModel::GetAngleString(nAngle));
|
|
aBuf.append(')');
|
|
}
|
|
|
|
return aBuf.makeStringAndClear();
|
|
}
|
|
else
|
|
{
|
|
const bool bAngle(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
|
|
|
|
if(bAngle)
|
|
{
|
|
const Degree100 nAngle(1 == rDrag.GetHdl()->GetPointNum() ? nStartAngle : nEndAngle);
|
|
|
|
return ImpGetDescriptionStr(STR_DragCircAngle) +
|
|
" (" +
|
|
SdrModel::GetAngleString(nAngle) +
|
|
")";
|
|
}
|
|
else
|
|
{
|
|
return SdrTextObj::getSpecialDragComment(rDrag);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ImpCircUser::SetCreateParams(SdrDragStat const & rStat)
|
|
{
|
|
rStat.TakeCreateRect(aR);
|
|
aR.Normalize();
|
|
aCenter=aR.Center();
|
|
nWdt=aR.Right()-aR.Left();
|
|
nHgt=aR.Bottom()-aR.Top();
|
|
nStart=0_deg100;
|
|
nEnd=36000_deg100;
|
|
if (rStat.GetPointCount()>2) {
|
|
Point aP(rStat.GetPoint(2)-aCenter);
|
|
if (nWdt==0) aP.setX(0 );
|
|
if (nHgt==0) aP.setY(0 );
|
|
if (nWdt>=nHgt) {
|
|
if (nHgt!=0) aP.setY(aP.Y()*nWdt/nHgt );
|
|
} else {
|
|
if (nWdt!=0) aP.setX(aP.X()*nHgt/nWdt );
|
|
}
|
|
nStart=NormAngle36000(GetAngle(aP));
|
|
if (rStat.GetView()!=nullptr && rStat.GetView()->IsAngleSnapEnabled()) {
|
|
Degree100 nSA=rStat.GetView()->GetSnapAngle();
|
|
if (nSA) { // angle snapping
|
|
nStart+=nSA/2_deg100;
|
|
nStart/=nSA;
|
|
nStart*=nSA;
|
|
nStart=NormAngle36000(nStart);
|
|
}
|
|
}
|
|
aP1 = GetAnglePnt(aR,nStart);
|
|
nEnd=nStart;
|
|
} else aP1=aCenter;
|
|
if (rStat.GetPointCount()<=3)
|
|
return;
|
|
|
|
Point aP(rStat.GetPoint(3)-aCenter);
|
|
if (nWdt>=nHgt) {
|
|
aP.setY(BigMulDiv(aP.Y(),nWdt,nHgt) );
|
|
} else {
|
|
aP.setX(BigMulDiv(aP.X(),nHgt,nWdt) );
|
|
}
|
|
nEnd=NormAngle36000(GetAngle(aP));
|
|
if (rStat.GetView()!=nullptr && rStat.GetView()->IsAngleSnapEnabled()) {
|
|
Degree100 nSA=rStat.GetView()->GetSnapAngle();
|
|
if (nSA) { // angle snapping
|
|
nEnd+=nSA/2_deg100;
|
|
nEnd/=nSA;
|
|
nEnd*=nSA;
|
|
nEnd=NormAngle36000(nEnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat)
|
|
{
|
|
ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
|
|
if (pU==nullptr) {
|
|
pU=new ImpCircUser;
|
|
rStat.SetUser(std::unique_ptr<ImpCircUser>(pU));
|
|
}
|
|
pU->SetCreateParams(rStat);
|
|
}
|
|
|
|
bool SdrCircObj::BegCreate(SdrDragStat& rStat)
|
|
{
|
|
rStat.SetOrtho4Possible();
|
|
tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
|
|
aRect1.Normalize();
|
|
rStat.SetActionRect(aRect1);
|
|
setRectangle(aRect1);
|
|
ImpSetCreateParams(rStat);
|
|
return true;
|
|
}
|
|
|
|
bool SdrCircObj::MovCreate(SdrDragStat& rStat)
|
|
{
|
|
ImpSetCreateParams(rStat);
|
|
ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
|
|
rStat.SetActionRect(pU->aR);
|
|
setRectangle(pU->aR); // for ObjName
|
|
ImpJustifyRect(maRectangle);
|
|
nStartAngle=pU->nStart;
|
|
nEndAngle=pU->nEnd;
|
|
SetBoundRectDirty();
|
|
m_bSnapRectDirty=true;
|
|
SetXPolyDirty();
|
|
|
|
// #i103058# push current angle settings to ItemSet to
|
|
// allow FullDrag visualisation
|
|
if(rStat.GetPointCount() >= 4)
|
|
{
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
|
|
{
|
|
ImpSetCreateParams(rStat);
|
|
ImpCircUser* pU=static_cast<ImpCircUser*>(rStat.GetUser());
|
|
bool bRet = false;
|
|
if (eCmd==SdrCreateCmd::ForceEnd && rStat.GetPointCount()<4) meCircleKind=SdrCircKind::Full;
|
|
if (meCircleKind==SdrCircKind::Full) {
|
|
bRet=rStat.GetPointCount()>=2;
|
|
if (bRet) {
|
|
tools::Rectangle aRectangle(pU->aR);
|
|
ImpJustifyRect(aRectangle);
|
|
setRectangle(aRectangle);
|
|
}
|
|
} else {
|
|
rStat.SetNoSnap(rStat.GetPointCount()>=2);
|
|
rStat.SetOrtho4Possible(rStat.GetPointCount()<2);
|
|
bRet=rStat.GetPointCount()>=4;
|
|
if (bRet) {
|
|
tools::Rectangle aRectangle(pU->aR);
|
|
ImpJustifyRect(aRectangle);
|
|
setRectangle(aRectangle);
|
|
nStartAngle=pU->nStart;
|
|
nEndAngle=pU->nEnd;
|
|
}
|
|
}
|
|
m_bClosedObj=meCircleKind!=SdrCircKind::Arc;
|
|
SetBoundAndSnapRectsDirty();
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
if (bRet)
|
|
rStat.SetUser(nullptr);
|
|
return bRet;
|
|
}
|
|
|
|
void SdrCircObj::BrkCreate(SdrDragStat& rStat)
|
|
{
|
|
rStat.SetUser(nullptr);
|
|
}
|
|
|
|
bool SdrCircObj::BckCreate(SdrDragStat& rStat)
|
|
{
|
|
rStat.SetNoSnap(rStat.GetPointCount()>=3);
|
|
rStat.SetOrtho4Possible(rStat.GetPointCount()<3);
|
|
return meCircleKind!=SdrCircKind::Full;
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const
|
|
{
|
|
const ImpCircUser* pU = static_cast<const ImpCircUser*>(rDrag.GetUser());
|
|
|
|
if(rDrag.GetPointCount() < 4)
|
|
{
|
|
// force to OBJ_CIRC to get full visualisation
|
|
basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(SdrCircKind::Full, pU->aR, pU->nStart, pU->nEnd));
|
|
|
|
if(3 == rDrag.GetPointCount())
|
|
{
|
|
// add edge to first point on ellipse
|
|
basegfx::B2DPolygon aNew;
|
|
|
|
aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y()));
|
|
aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y()));
|
|
aRetval.append(aNew);
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
else
|
|
{
|
|
return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd));
|
|
}
|
|
}
|
|
|
|
PointerStyle SdrCircObj::GetCreatePointer() const
|
|
{
|
|
switch (meCircleKind) {
|
|
case SdrCircKind::Full: return PointerStyle::DrawEllipse;
|
|
case SdrCircKind::Section: return PointerStyle::DrawPie;
|
|
case SdrCircKind::Arc: return PointerStyle::DrawArc;
|
|
case SdrCircKind::Cut: return PointerStyle::DrawCircleCut;
|
|
default: break;
|
|
} // switch
|
|
return PointerStyle::Cross;
|
|
}
|
|
|
|
void SdrCircObj::NbcMove(const Size& aSize)
|
|
{
|
|
moveRectangle(aSize.Width(), aSize.Height());
|
|
moveOutRectangle(aSize.Width(), aSize.Height());
|
|
maSnapRect.Move(aSize);
|
|
SetXPolyDirty();
|
|
SetBoundAndSnapRectsDirty(true);
|
|
}
|
|
|
|
void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
|
|
{
|
|
Degree100 nAngle0 = maGeo.m_nRotationAngle;
|
|
bool bNoShearRota = (maGeo.m_nRotationAngle == 0_deg100 && maGeo.m_nShearAngle == 0_deg100);
|
|
SdrTextObj::NbcResize(rRef,xFact,yFact);
|
|
bNoShearRota |= (maGeo.m_nRotationAngle == 0_deg100 && maGeo.m_nShearAngle == 0_deg100);
|
|
if (meCircleKind!=SdrCircKind::Full) {
|
|
bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
|
|
bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
|
|
if (bXMirr || bYMirr) {
|
|
// At bXMirr!=bYMirr we should actually swap both line ends.
|
|
// That, however, is pretty bad (because of forced "hard" formatting).
|
|
// Alternatively, we could implement a bMirrored flag (maybe even
|
|
// a more general one, e. g. for mirrored text, ...).
|
|
Degree100 nS0=nStartAngle;
|
|
Degree100 nE0=nEndAngle;
|
|
if (bNoShearRota) {
|
|
// the RectObj already mirrors at VMirror because of a 180deg rotation
|
|
if (! (bXMirr && bYMirr)) {
|
|
Degree100 nTmp=nS0;
|
|
nS0=18000_deg100-nE0;
|
|
nE0=18000_deg100-nTmp;
|
|
}
|
|
} else { // mirror contorted ellipses
|
|
if (bXMirr!=bYMirr) {
|
|
nS0+=nAngle0;
|
|
nE0+=nAngle0;
|
|
if (bXMirr) {
|
|
Degree100 nTmp=nS0;
|
|
nS0=18000_deg100-nE0;
|
|
nE0=18000_deg100-nTmp;
|
|
}
|
|
if (bYMirr) {
|
|
Degree100 nTmp=nS0;
|
|
nS0=-nE0;
|
|
nE0=-nTmp;
|
|
}
|
|
nS0 -= maGeo.m_nRotationAngle;
|
|
nE0 -= maGeo.m_nRotationAngle;
|
|
}
|
|
}
|
|
Degree100 nAngleDif=nE0-nS0;
|
|
nStartAngle=NormAngle36000(nS0);
|
|
nEndAngle =NormAngle36000(nE0);
|
|
if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
|
|
}
|
|
}
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
void SdrCircObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
|
|
{
|
|
SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
|
|
{
|
|
bool bFreeMirr=meCircleKind!=SdrCircKind::Full;
|
|
Point aTmpPt1;
|
|
Point aTmpPt2;
|
|
if (bFreeMirr) { // some preparations for using an arbitrary axis of reflection
|
|
Point aCenter(getRectangle().Center());
|
|
tools::Long nWdt = getRectangle().GetWidth() - 1;
|
|
tools::Long nHgt = getRectangle().GetHeight() - 1;
|
|
tools::Long nMaxRad=(std::max(nWdt,nHgt)+1) /2;
|
|
// starting point
|
|
double a = toRadians(nStartAngle);
|
|
aTmpPt1 = Point(basegfx::fround<tools::Long>(cos(a) * nMaxRad),
|
|
basegfx::fround<tools::Long>(-sin(a) * nMaxRad));
|
|
if (nWdt==0) aTmpPt1.setX(0 );
|
|
if (nHgt==0) aTmpPt1.setY(0 );
|
|
aTmpPt1+=aCenter;
|
|
// finishing point
|
|
a = toRadians(nEndAngle);
|
|
aTmpPt2 = Point(basegfx::fround<tools::Long>(cos(a) * nMaxRad),
|
|
basegfx::fround<tools::Long>(-sin(a) * nMaxRad));
|
|
if (nWdt==0) aTmpPt2.setX(0 );
|
|
if (nHgt==0) aTmpPt2.setY(0 );
|
|
aTmpPt2+=aCenter;
|
|
if (maGeo.m_nRotationAngle)
|
|
{
|
|
RotatePoint(aTmpPt1, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
RotatePoint(aTmpPt2, getRectangle().TopLeft(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
}
|
|
if (maGeo.m_nShearAngle)
|
|
{
|
|
ShearPoint(aTmpPt1, getRectangle().TopLeft(), maGeo.mfTanShearAngle);
|
|
ShearPoint(aTmpPt2, getRectangle().TopLeft(), maGeo.mfTanShearAngle);
|
|
}
|
|
}
|
|
SdrTextObj::NbcMirror(rRef1,rRef2);
|
|
if (meCircleKind!=SdrCircKind::Full) { // adapt starting and finishing angle
|
|
MirrorPoint(aTmpPt1,rRef1,rRef2);
|
|
MirrorPoint(aTmpPt2,rRef1,rRef2);
|
|
// unrotate:
|
|
if (maGeo.m_nRotationAngle)
|
|
{
|
|
RotatePoint(aTmpPt1, getRectangle().TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); // -sin for reversion
|
|
RotatePoint(aTmpPt2, getRectangle().TopLeft(), -maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle); // -sin for reversion
|
|
}
|
|
// unshear:
|
|
if (maGeo.m_nShearAngle)
|
|
{
|
|
ShearPoint(aTmpPt1, getRectangle().TopLeft(), -maGeo.mfTanShearAngle); // -tan for reversion
|
|
ShearPoint(aTmpPt2, getRectangle().TopLeft(), -maGeo.mfTanShearAngle); // -tan for reversion
|
|
}
|
|
Point aCenter(getRectangle().Center());
|
|
aTmpPt1-=aCenter;
|
|
aTmpPt2-=aCenter;
|
|
// because it's mirrored, the angles are swapped, too
|
|
nStartAngle=GetAngle(aTmpPt2);
|
|
nEndAngle =GetAngle(aTmpPt1);
|
|
Degree100 nAngleDif=nEndAngle-nStartAngle;
|
|
nStartAngle=NormAngle36000(nStartAngle);
|
|
nEndAngle =NormAngle36000(nEndAngle);
|
|
if (nAngleDif==36000_deg100) nEndAngle+=nAngleDif; // full circle
|
|
}
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
std::unique_ptr<SdrObjGeoData> SdrCircObj::NewGeoData() const
|
|
{
|
|
return std::make_unique<SdrCircObjGeoData>();
|
|
}
|
|
|
|
void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const
|
|
{
|
|
SdrRectObj::SaveGeoData(rGeo);
|
|
SdrCircObjGeoData& rCGeo=static_cast<SdrCircObjGeoData&>(rGeo);
|
|
rCGeo.nStartAngle=nStartAngle;
|
|
rCGeo.nEndAngle =nEndAngle;
|
|
}
|
|
|
|
void SdrCircObj::RestoreGeoData(const SdrObjGeoData& rGeo)
|
|
{
|
|
SdrRectObj::RestoreGeoData(rGeo);
|
|
const SdrCircObjGeoData& rCGeo=static_cast<const SdrCircObjGeoData&>(rGeo);
|
|
nStartAngle=rCGeo.nStartAngle;
|
|
nEndAngle =rCGeo.nEndAngle;
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
static void Union(tools::Rectangle& rR, const Point& rP)
|
|
{
|
|
if (rP.X()<rR.Left ()) rR.SetLeft(rP.X() );
|
|
if (rP.X()>rR.Right ()) rR.SetRight(rP.X() );
|
|
if (rP.Y()<rR.Top ()) rR.SetTop(rP.Y() );
|
|
if (rP.Y()>rR.Bottom()) rR.SetBottom(rP.Y() );
|
|
}
|
|
|
|
void SdrCircObj::TakeUnrotatedSnapRect(tools::Rectangle& rRect) const
|
|
{
|
|
rRect = getRectangle();
|
|
if (meCircleKind!=SdrCircKind::Full) {
|
|
const Point aPntStart(GetAnglePnt(getRectangle(), nStartAngle));
|
|
const Point aPntEnd(GetAnglePnt(getRectangle(), nEndAngle));
|
|
Degree100 a=nStartAngle;
|
|
Degree100 e=nEndAngle;
|
|
rRect.SetLeft(getRectangle().Right() );
|
|
rRect.SetRight(getRectangle().Left() );
|
|
rRect.SetTop(getRectangle().Bottom() );
|
|
rRect.SetBottom(getRectangle().Top() );
|
|
Union(rRect,aPntStart);
|
|
Union(rRect,aPntEnd);
|
|
if ((a<=18000_deg100 && e>=18000_deg100) || (a>e && (a<=18000_deg100 || e>=18000_deg100))) {
|
|
Union(rRect, getRectangle().LeftCenter());
|
|
}
|
|
if ((a<=27000_deg100 && e>=27000_deg100) || (a>e && (a<=27000_deg100 || e>=27000_deg100))) {
|
|
Union(rRect, getRectangle().BottomCenter());
|
|
}
|
|
if (a>e) {
|
|
Union(rRect, getRectangle().RightCenter());
|
|
}
|
|
if ((a<=9000_deg100 && e>=9000_deg100) || (a>e && (a<=9000_deg100 || e>=9000_deg100))) {
|
|
Union(rRect, getRectangle().TopCenter());
|
|
}
|
|
if (meCircleKind==SdrCircKind::Section) {
|
|
Union(rRect, getRectangle().Center());
|
|
}
|
|
if (maGeo.m_nRotationAngle)
|
|
{
|
|
Point aDst(rRect.TopLeft());
|
|
aDst -= getRectangle().TopLeft();
|
|
Point aDst0(aDst);
|
|
RotatePoint(aDst,Point(), maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
aDst-=aDst0;
|
|
rRect.Move(aDst.X(),aDst.Y());
|
|
}
|
|
}
|
|
if (maGeo.m_nShearAngle==0_deg100)
|
|
return;
|
|
|
|
tools::Long nDst = basegfx::fround<tools::Long>((rRect.Bottom() - rRect.Top()) * maGeo.mfTanShearAngle);
|
|
if (maGeo.m_nShearAngle > 0_deg100)
|
|
{
|
|
Point aRef(rRect.TopLeft());
|
|
rRect.AdjustLeft( -nDst );
|
|
Point aTmpPt(rRect.TopLeft());
|
|
RotatePoint(aTmpPt, aRef, maGeo.mfSinRotationAngle, maGeo.mfCosRotationAngle);
|
|
aTmpPt-=rRect.TopLeft();
|
|
rRect.Move(aTmpPt.X(),aTmpPt.Y());
|
|
} else {
|
|
rRect.AdjustRight( -nDst );
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::RecalcSnapRect()
|
|
{
|
|
if (PaintNeedsXPolyCirc()) {
|
|
maSnapRect=GetXPoly().GetBoundRect();
|
|
} else {
|
|
TakeUnrotatedSnapRect(maSnapRect);
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::NbcSetSnapRect(const tools::Rectangle& rRect)
|
|
{
|
|
if (maGeo.m_nRotationAngle || maGeo.m_nShearAngle || meCircleKind != SdrCircKind::Full)
|
|
{
|
|
tools::Rectangle aSR0(GetSnapRect());
|
|
tools::Long nWdt0=aSR0.Right()-aSR0.Left();
|
|
tools::Long nHgt0=aSR0.Bottom()-aSR0.Top();
|
|
tools::Long nWdt1=rRect.Right()-rRect.Left();
|
|
tools::Long nHgt1=rRect.Bottom()-rRect.Top();
|
|
NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
|
|
NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
|
|
} else {
|
|
setRectangle(rRect);
|
|
ImpJustifyRect(maRectangle);
|
|
}
|
|
SetBoundAndSnapRectsDirty();
|
|
SetXPolyDirty();
|
|
ImpSetCircInfoToAttr();
|
|
}
|
|
|
|
sal_uInt32 SdrCircObj::GetSnapPointCount() const
|
|
{
|
|
if (meCircleKind==SdrCircKind::Full) {
|
|
return 1;
|
|
} else {
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
|
|
{
|
|
switch (i)
|
|
{
|
|
case 1 : return GetAnglePnt(getRectangle(), nStartAngle);
|
|
case 2 : return GetAnglePnt(getRectangle(), nEndAngle);
|
|
default: return getRectangle().Center();
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
|
|
{
|
|
SetXPolyDirty();
|
|
SdrRectObj::Notify(rBC,rHint);
|
|
ImpSetAttrToCircInfo();
|
|
}
|
|
|
|
|
|
void SdrCircObj::ImpSetAttrToCircInfo()
|
|
{
|
|
const SfxItemSet& rSet = GetObjectItemSet();
|
|
SdrCircKind eNewKind = rSet.Get(SDRATTR_CIRCKIND).GetValue();
|
|
|
|
Degree100 nNewStart = rSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue();
|
|
Degree100 nNewEnd = rSet.Get(SDRATTR_CIRCENDANGLE).GetValue();
|
|
|
|
bool bKindChg = meCircleKind != eNewKind;
|
|
bool bAngleChg = nNewStart != nStartAngle || nNewEnd != nEndAngle;
|
|
|
|
if(bKindChg || bAngleChg)
|
|
{
|
|
meCircleKind = eNewKind;
|
|
nStartAngle = nNewStart;
|
|
nEndAngle = nNewEnd;
|
|
|
|
if(bKindChg || (meCircleKind != SdrCircKind::Full && bAngleChg))
|
|
{
|
|
SetXPolyDirty();
|
|
SetBoundAndSnapRectsDirty();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SdrCircObj::ImpSetCircInfoToAttr()
|
|
{
|
|
const SfxItemSet& rSet = GetObjectItemSet();
|
|
|
|
SdrCircKind eOldKindA = rSet.Get(SDRATTR_CIRCKIND).GetValue();
|
|
Degree100 nOldStartAngle = rSet.Get(SDRATTR_CIRCSTARTANGLE).GetValue();
|
|
Degree100 nOldEndAngle = rSet.Get(SDRATTR_CIRCENDANGLE).GetValue();
|
|
|
|
if(meCircleKind == eOldKindA && nStartAngle == nOldStartAngle && nEndAngle == nOldEndAngle)
|
|
return;
|
|
|
|
// since SetItem() implicitly calls ImpSetAttrToCircInfo()
|
|
// setting the item directly is necessary here.
|
|
if(meCircleKind != eOldKindA)
|
|
{
|
|
GetProperties().SetObjectItemDirect(SdrCircKindItem(meCircleKind));
|
|
}
|
|
|
|
if(nStartAngle != nOldStartAngle)
|
|
{
|
|
GetProperties().SetObjectItemDirect(makeSdrCircStartAngleItem(nStartAngle));
|
|
}
|
|
|
|
if(nEndAngle != nOldEndAngle)
|
|
{
|
|
GetProperties().SetObjectItemDirect(makeSdrCircEndAngleItem(nEndAngle));
|
|
}
|
|
|
|
SetXPolyDirty();
|
|
ImpSetAttrToCircInfo();
|
|
}
|
|
|
|
rtl::Reference<SdrObject> SdrCircObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
|
|
{
|
|
const bool bFill(meCircleKind != SdrCircKind::Arc);
|
|
const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, getRectangle(), nStartAngle, nEndAngle));
|
|
rtl::Reference<SdrObject> pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier);
|
|
|
|
if(bAddText)
|
|
{
|
|
pRet = ImpConvertAddText(std::move(pRet), bBezier);
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|