1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/svdotext.hxx>
22 #include <svx/svdhdl.hxx>
23 #include <svx/svddrag.hxx>
24 #include <svx/svdview.hxx>
25 #include <svx/svdorect.hxx>
26 #include <svx/strings.hrc>
27 #include <svx/svdoashp.hxx>
28 #include <tools/bigint.hxx>
29 #include <basegfx/polygon/b2dpolygon.hxx>
30 #include <basegfx/range/b2drange.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
32 #include <vcl/canvastools.hxx>
33 #include <vcl/ptrstyle.hxx>
36 sal_uInt32
SdrTextObj::GetHdlCount() const
41 void SdrTextObj::AddToHdlList(SdrHdlList
& rHdlList
) const
43 for(sal_uInt32 nHdlNum
=0; nHdlNum
<8; ++nHdlNum
)
46 SdrHdlKind eKind
= SdrHdlKind::UpperLeft
;
48 case 0: aPnt
=maRect
.TopLeft(); eKind
=SdrHdlKind::UpperLeft
; break;
49 case 1: aPnt
=maRect
.TopCenter(); eKind
=SdrHdlKind::Upper
; break;
50 case 2: aPnt
=maRect
.TopRight(); eKind
=SdrHdlKind::UpperRight
; break;
51 case 3: aPnt
=maRect
.LeftCenter(); eKind
=SdrHdlKind::Left
; break;
52 case 4: aPnt
=maRect
.RightCenter(); eKind
=SdrHdlKind::Right
; break;
53 case 5: aPnt
=maRect
.BottomLeft(); eKind
=SdrHdlKind::LowerLeft
; break;
54 case 6: aPnt
=maRect
.BottomCenter(); eKind
=SdrHdlKind::Lower
; break;
55 case 7: aPnt
=maRect
.BottomRight(); eKind
=SdrHdlKind::LowerRight
; break;
57 if (aGeo
.nShearAngle
!=0) ShearPoint(aPnt
,maRect
.TopLeft(),aGeo
.nTan
);
58 if (aGeo
.nRotationAngle
!=0) RotatePoint(aPnt
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
59 std::unique_ptr
<SdrHdl
> pH(new SdrHdl(aPnt
,eKind
));
60 pH
->SetObj(const_cast<SdrTextObj
*>(this));
61 pH
->SetRotationAngle(aGeo
.nRotationAngle
);
62 rHdlList
.AddHdl(std::move(pH
));
67 bool SdrTextObj::hasSpecialDrag() const
72 tools::Rectangle
SdrTextObj::ImpDragCalcRect(const SdrDragStat
& rDrag
) const
74 tools::Rectangle
aTmpRect(maRect
);
75 const SdrHdl
* pHdl
=rDrag
.GetHdl();
76 SdrHdlKind eHdl
=pHdl
==nullptr ? SdrHdlKind::Move
: pHdl
->GetKind();
77 bool bEcke
=(eHdl
==SdrHdlKind::UpperLeft
|| eHdl
==SdrHdlKind::UpperRight
|| eHdl
==SdrHdlKind::LowerLeft
|| eHdl
==SdrHdlKind::LowerRight
);
78 bool bOrtho
=rDrag
.GetView()!=nullptr && rDrag
.GetView()->IsOrtho();
79 bool bBigOrtho
=bEcke
&& bOrtho
&& rDrag
.GetView()->IsBigOrtho();
80 Point
aPos(rDrag
.GetNow());
82 if (aGeo
.nRotationAngle
!=0) RotatePoint(aPos
,aTmpRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
84 if (aGeo
.nShearAngle
!=0) ShearPoint(aPos
,aTmpRect
.TopLeft(),-aGeo
.nTan
);
86 bool bLft
=(eHdl
==SdrHdlKind::UpperLeft
|| eHdl
==SdrHdlKind::Left
|| eHdl
==SdrHdlKind::LowerLeft
);
87 bool bRgt
=(eHdl
==SdrHdlKind::UpperRight
|| eHdl
==SdrHdlKind::Right
|| eHdl
==SdrHdlKind::LowerRight
);
88 bool bTop
=(eHdl
==SdrHdlKind::UpperRight
|| eHdl
==SdrHdlKind::Upper
|| eHdl
==SdrHdlKind::UpperLeft
);
89 bool bBtm
=(eHdl
==SdrHdlKind::LowerRight
|| eHdl
==SdrHdlKind::Lower
|| eHdl
==SdrHdlKind::LowerLeft
);
90 if (bLft
) aTmpRect
.SetLeft(aPos
.X() );
91 if (bRgt
) aTmpRect
.SetRight(aPos
.X() );
92 if (bTop
) aTmpRect
.SetTop(aPos
.Y() );
93 if (bBtm
) aTmpRect
.SetBottom(aPos
.Y() );
94 if (bOrtho
) { // Ortho
95 tools::Long nWdt0
=maRect
.Right() -maRect
.Left();
96 tools::Long nHgt0
=maRect
.Bottom()-maRect
.Top();
97 tools::Long nXMul
=aTmpRect
.Right() -aTmpRect
.Left();
98 tools::Long nYMul
=aTmpRect
.Bottom()-aTmpRect
.Top();
99 tools::Long nXDiv
=nWdt0
;
100 tools::Long nYDiv
=nHgt0
;
101 bool bXNeg
=(nXMul
<0)!=(nXDiv
<0);
102 bool bYNeg
=(nYMul
<0)!=(nYDiv
<0);
103 nXMul
=std::abs(nXMul
);
104 nYMul
=std::abs(nYMul
);
105 nXDiv
=std::abs(nXDiv
);
106 nYDiv
=std::abs(nYDiv
);
107 Fraction
aXFact(nXMul
,nXDiv
); // fractions for canceling
108 Fraction
aYFact(nYMul
,nYDiv
); // and for comparing
109 nXMul
=aXFact
.GetNumerator();
110 nYMul
=aYFact
.GetNumerator();
111 nXDiv
=aXFact
.GetDenominator();
112 nYDiv
=aYFact
.GetDenominator();
113 if (bEcke
) { // corner point handles
114 bool bUseX
=(aXFact
<aYFact
) != bBigOrtho
;
116 tools::Long nNeed
=tools::Long(BigInt(nHgt0
)*BigInt(nXMul
)/BigInt(nXDiv
));
117 if (bYNeg
) nNeed
=-nNeed
;
118 if (bTop
) aTmpRect
.SetTop(aTmpRect
.Bottom()-nNeed
);
119 if (bBtm
) aTmpRect
.SetBottom(aTmpRect
.Top()+nNeed
);
121 tools::Long nNeed
=tools::Long(BigInt(nWdt0
)*BigInt(nYMul
)/BigInt(nYDiv
));
122 if (bXNeg
) nNeed
=-nNeed
;
123 if (bLft
) aTmpRect
.SetLeft(aTmpRect
.Right()-nNeed
);
124 if (bRgt
) aTmpRect
.SetRight(aTmpRect
.Left()+nNeed
);
126 } else { // apex handles
127 if ((bLft
|| bRgt
) && nXDiv
!=0) {
128 tools::Long nHgt0b
=maRect
.Bottom()-maRect
.Top();
129 tools::Long nNeed
=tools::Long(BigInt(nHgt0b
)*BigInt(nXMul
)/BigInt(nXDiv
));
130 aTmpRect
.AdjustTop( -((nNeed
-nHgt0b
)/2) );
131 aTmpRect
.SetBottom(aTmpRect
.Top()+nNeed
);
133 if ((bTop
|| bBtm
) && nYDiv
!=0) {
134 tools::Long nWdt0b
=maRect
.Right()-maRect
.Left();
135 tools::Long nNeed
=tools::Long(BigInt(nWdt0b
)*BigInt(nYMul
)/BigInt(nYDiv
));
136 aTmpRect
.AdjustLeft( -((nNeed
-nWdt0b
)/2) );
137 aTmpRect
.SetRight(aTmpRect
.Left()+nNeed
);
141 if (dynamic_cast<const SdrObjCustomShape
*>(this) == nullptr) // not justifying when in CustomShapes, to be able to detect if a shape has to be mirrored
142 ImpJustifyRect(aTmpRect
);
149 bool SdrTextObj::applySpecialDrag(SdrDragStat
& rDrag
)
151 tools::Rectangle
aNewRect(ImpDragCalcRect(rDrag
));
153 if(aNewRect
.TopLeft() != maRect
.TopLeft() && (aGeo
.nRotationAngle
|| aGeo
.nShearAngle
))
155 Point
aNewPos(aNewRect
.TopLeft());
158 ShearPoint(aNewPos
,maRect
.TopLeft(),aGeo
.nTan
);
160 if(aGeo
.nRotationAngle
)
161 RotatePoint(aNewPos
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
163 aNewRect
.SetPos(aNewPos
);
166 if (aNewRect
!= maRect
)
168 NbcSetLogicRect(aNewRect
);
174 OUString
SdrTextObj::getSpecialDragComment(const SdrDragStat
& /*rDrag*/) const
176 return ImpGetDescriptionStr(STR_DragRectResize
);
182 bool SdrTextObj::BegCreate(SdrDragStat
& rStat
)
184 rStat
.SetOrtho4Possible();
185 tools::Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
187 rStat
.SetActionRect(aRect1
);
192 bool SdrTextObj::MovCreate(SdrDragStat
& rStat
)
194 tools::Rectangle aRect1
;
195 rStat
.TakeCreateRect(aRect1
);
196 ImpJustifyRect(aRect1
);
197 rStat
.SetActionRect(aRect1
);
198 maRect
= aRect1
; // for ObjName
201 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) {
202 pRectObj
->SetXPolyDirty();
207 bool SdrTextObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
209 rStat
.TakeCreateRect(maRect
);
210 ImpJustifyRect(maRect
);
215 if (auto pRectObj
= dynamic_cast<SdrRectObj
*>(this)) {
216 pRectObj
->SetXPolyDirty();
218 return (eCmd
==SdrCreateCmd::ForceEnd
|| rStat
.GetPointCount()>=2);
221 void SdrTextObj::BrkCreate(SdrDragStat
& /*rStat*/)
225 bool SdrTextObj::BckCreate(SdrDragStat
& /*rStat*/)
230 basegfx::B2DPolyPolygon
SdrTextObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
232 tools::Rectangle aRect1
;
233 rDrag
.TakeCreateRect(aRect1
);
236 basegfx::B2DPolyPolygon aRetval
;
237 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aRect1
);
238 aRetval
.append(basegfx::utils::createPolygonFromRect(aRange
));
242 PointerStyle
SdrTextObj::GetCreatePointer() const
244 if (IsTextFrame()) return PointerStyle::DrawText
;
245 return PointerStyle::Cross
;
248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */