Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdocapt.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#include <sal/config.h>
21
22
#include <cassert>
23
24
#include <basegfx/matrix/b2dhommatrix.hxx>
25
#include <basegfx/polygon/b2dpolygon.hxx>
26
#include <basegfx/polygon/b2dpolygontools.hxx>
27
#include <basegfx/range/b2drange.hxx>
28
#include <basegfx/tuple/b2dtuple.hxx>
29
#include <tools/bigint.hxx>
30
#include <tools/helpers.hxx>
31
32
#include <svx/dialmgr.hxx>
33
#include <svx/strings.hrc>
34
35
#include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
36
#include <sdr/properties/captionproperties.hxx>
37
#include <svx/sdrhittesthelper.hxx>
38
#include <svx/sdooitm.hxx>
39
#include <svx/svddrag.hxx>
40
#include <svx/svdhdl.hxx>
41
#include <svx/svdmodel.hxx>
42
#include <svx/svdocapt.hxx>
43
#include <svx/svdopath.hxx>
44
#include <svx/svdogrp.hxx>
45
#include <svx/svdpage.hxx>
46
#include <svx/svdtrans.hxx>
47
#include <svx/svdview.hxx>
48
#include <svx/sxcecitm.hxx>
49
#include <svx/sxcgitm.hxx>
50
#include <svx/sxcllitm.hxx>
51
#include <svx/sxctitm.hxx>
52
#include <vcl/canvastools.hxx>
53
#include <vcl/ptrstyle.hxx>
54
55
namespace {
56
57
enum EscDir {LKS,RTS,OBN,UNT};
58
59
}
60
61
class ImpCaptParams
62
{
63
public:
64
    SdrCaptionType              eType;
65
    tools::Long                        nGap;
66
    tools::Long                        nEscRel;
67
    tools::Long                        nEscAbs;
68
    tools::Long                        nLineLen;
69
    SdrCaptionEscDir            eEscDir;
70
    bool                        bFitLineLen;
71
    bool                        bEscRel;
72
    bool                        bFixedAngle;
73
74
public:
75
    ImpCaptParams()
76
190k
      : eType(SdrCaptionType::Type3),
77
190k
        nGap(0), nEscRel(5000), nEscAbs(0),
78
190k
        nLineLen(0), eEscDir(SdrCaptionEscDir::Horizontal),
79
190k
        bFitLineLen(true), bEscRel(true), bFixedAngle(false)
80
190k
    {
81
190k
    }
82
    void CalcEscPos(const Point& rTail, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const;
83
};
84
85
void ImpCaptParams::CalcEscPos(const Point& rTailPt, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const
86
190k
{
87
190k
    Point aTl(rTailPt); // copy locally for performance reasons
88
190k
    tools::Long nX,nY;
89
190k
    if (bEscRel) {
90
190k
        nX=rRect.Right()-rRect.Left();
91
190k
        nX=BigMulDiv(nX,nEscRel,10000);
92
190k
        nY=rRect.Bottom()-rRect.Top();
93
190k
        nY=BigMulDiv(nY,nEscRel,10000);
94
190k
    } else {
95
0
        nX=nEscAbs;
96
0
        nY=nEscAbs;
97
0
    }
98
190k
    nX+=rRect.Left();
99
190k
    nY+=rRect.Top();
100
190k
    Point  aBestPt;
101
190k
    EscDir eBestDir=LKS;
102
190k
    bool bTryH=eEscDir==SdrCaptionEscDir::BestFit;
103
190k
    if (!bTryH) {
104
190k
        if (eType!=SdrCaptionType::Type1) {
105
190k
            bTryH=eEscDir==SdrCaptionEscDir::Horizontal;
106
190k
        } else {
107
21
            bTryH=eEscDir==SdrCaptionEscDir::Vertical;
108
21
        }
109
190k
    }
110
190k
    bool bTryV=eEscDir==SdrCaptionEscDir::BestFit;
111
190k
    if (!bTryV) {
112
190k
        if (eType!=SdrCaptionType::Type1) {
113
190k
            bTryV=eEscDir==SdrCaptionEscDir::Vertical;
114
190k
        } else {
115
21
            bTryV=eEscDir==SdrCaptionEscDir::Horizontal;
116
21
        }
117
190k
    }
118
119
190k
    if (bTryH) {
120
190k
        Point aLft(rRect.Left()-nGap,nY);
121
190k
        Point aRgt(rRect.Right()+nGap,nY);
122
190k
        bool bLft=(aTl.X()-aLft.X()<aRgt.X()-aTl.X());
123
190k
        if (bLft) {
124
56.6k
            eBestDir=LKS;
125
56.6k
            aBestPt=aLft;
126
133k
        } else {
127
133k
            eBestDir=RTS;
128
133k
            aBestPt=aRgt;
129
133k
        }
130
190k
    }
131
190k
    if (bTryV) {
132
21
        Point aTop(nX,rRect.Top()-nGap);
133
21
        Point aBtm(nX,rRect.Bottom()+nGap);
134
21
        bool bTop=(aTl.Y()-aTop.Y()<aBtm.Y()-aTl.Y());
135
21
        Point aBest2;
136
21
        EscDir eBest2;
137
21
        if (bTop) {
138
10
            eBest2=OBN;
139
10
            aBest2=aTop;
140
11
        } else {
141
11
            eBest2=UNT;
142
11
            aBest2=aBtm;
143
11
        }
144
21
        bool bTakeIt=eEscDir!=SdrCaptionEscDir::BestFit;
145
21
        if (!bTakeIt) {
146
0
            BigInt aHorX(aBestPt.X()-aTl.X()); aHorX*=aHorX;
147
0
            BigInt aHorY(aBestPt.Y()-aTl.Y()); aHorY*=aHorY;
148
0
            BigInt aVerX(aBest2.X()-aTl.X());  aVerX*=aVerX;
149
0
            BigInt aVerY(aBest2.Y()-aTl.Y());  aVerY*=aVerY;
150
0
            if (eType!=SdrCaptionType::Type1) {
151
0
                bTakeIt=aVerX+aVerY<aHorX+aHorY;
152
0
            } else {
153
0
                bTakeIt=aVerX+aVerY>=aHorX+aHorY;
154
0
            }
155
0
        }
156
21
        if (bTakeIt) {
157
21
            aBestPt=aBest2;
158
21
            eBestDir=eBest2;
159
21
        }
160
21
    }
161
190k
    rPt=aBestPt;
162
190k
    rDir=eBestDir;
163
190k
}
164
165
166
// BaseProperties section
167
168
std::unique_ptr<sdr::properties::BaseProperties> SdrCaptionObj::CreateObjectSpecificProperties()
169
20.4k
{
170
20.4k
    return std::make_unique<sdr::properties::CaptionProperties>(*this);
171
20.4k
}
172
173
174
// DrawContact section
175
176
std::unique_ptr<sdr::contact::ViewContact> SdrCaptionObj::CreateObjectSpecificViewContact()
177
20.4k
{
178
20.4k
    return std::make_unique<sdr::contact::ViewContactOfSdrCaptionObj>(*this);
179
20.4k
}
180
181
182
SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel)
183
0
    : SdrRectObj(rSdrModel, tools::Rectangle(), SdrObjKind::Text)
184
0
    , maTailPoly(3)  // default size: 3 points = 2 lines
185
0
    , mbSpecialTextBoxShadow(false)
186
0
    , mbFixedTail(false)
187
0
    , mbSuppressGetBitmap(false)
188
0
{
189
0
}
190
191
SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel, const tools::Rectangle& rRect, const Point& rTail)
192
20.4k
    : SdrRectObj(rSdrModel, rRect, SdrObjKind::Text)
193
20.4k
    , maTailPoly(3)  // default size: 3 points = 2 lines
194
20.4k
    , mbSpecialTextBoxShadow(false)
195
20.4k
    , mbFixedTail(false)
196
20.4k
    , mbSuppressGetBitmap(false)
197
20.4k
{
198
20.4k
    maTailPoly[0] = maFixedTailPos = rTail;
199
20.4k
}
200
201
SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel, SdrCaptionObj const & rSource)
202
0
:   SdrRectObj(rSdrModel, rSource),
203
0
    mbSuppressGetBitmap(false)
204
0
{
205
0
    maTailPoly = rSource.maTailPoly;
206
0
    mbSpecialTextBoxShadow = rSource.mbSpecialTextBoxShadow;
207
0
    mbFixedTail = rSource.mbFixedTail;
208
0
    maFixedTailPos = rSource.maFixedTailPos;
209
0
}
210
211
20.4k
SdrCaptionObj::~SdrCaptionObj() = default;
212
213
void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
214
0
{
215
0
    rInfo.bRotateFreeAllowed=false;
216
0
    rInfo.bRotate90Allowed  =false;
217
0
    rInfo.bMirrorFreeAllowed=false;
218
0
    rInfo.bMirror45Allowed  =false;
219
0
    rInfo.bMirror90Allowed  =false;
220
0
    rInfo.bTransparenceAllowed = false;
221
0
    rInfo.bShearAllowed     =false;
222
0
    rInfo.bEdgeRadiusAllowed=false;
223
0
    rInfo.bCanConvToPath    =true;
224
0
    rInfo.bCanConvToPoly    =true;
225
0
    rInfo.bCanConvToPathLineToArea=false;
226
0
    rInfo.bCanConvToPolyLineToArea=false;
227
0
    rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
228
0
}
229
230
SdrObjKind SdrCaptionObj::GetObjIdentifier() const
231
192k
{
232
192k
    return SdrObjKind::Caption;
233
192k
}
234
235
rtl::Reference<SdrObject> SdrCaptionObj::CloneSdrObject(SdrModel& rTargetModel) const
236
0
{
237
0
    return new SdrCaptionObj(rTargetModel, *this);
238
0
}
239
240
OUString SdrCaptionObj::TakeObjNameSingul() const
241
0
{
242
0
    OUString sName(SvxResId(STR_ObjNameSingulCAPTION));
243
244
0
    OUString aName(GetName());
245
0
    if (!aName.isEmpty())
246
0
        sName += " '" + aName + "'";
247
248
0
    return sName;
249
0
}
250
251
OUString SdrCaptionObj::TakeObjNamePlural() const
252
0
{
253
0
    return SvxResId(STR_ObjNamePluralCAPTION);
254
0
}
255
256
basegfx::B2DPolyPolygon SdrCaptionObj::TakeXorPoly() const
257
0
{
258
0
    basegfx::B2DPolyPolygon aPolyPoly(SdrRectObj::TakeXorPoly());
259
0
    aPolyPoly.append(maTailPoly.getB2DPolygon());
260
261
0
    return aPolyPoly;
262
0
}
263
264
sal_uInt32 SdrCaptionObj::GetHdlCount() const
265
0
{
266
0
    sal_uInt32 nCount1(SdrRectObj::GetHdlCount());
267
    // Currently only dragging the tail's end is implemented.
268
0
    return nCount1 + 1;
269
0
}
270
271
void SdrCaptionObj::AddToHdlList(SdrHdlList& rHdlList) const
272
0
{
273
0
    SdrRectObj::AddToHdlList(rHdlList);
274
    // Currently only dragging the tail's end is implemented.
275
0
    std::unique_ptr<SdrHdl> pHdl(new SdrHdl(maTailPoly.GetPoint(0), SdrHdlKind::Poly));
276
0
    pHdl->SetPolyNum(1);
277
0
    pHdl->SetPointNum(0);
278
0
    rHdlList.AddHdl(std::move(pHdl));
279
0
}
280
281
bool SdrCaptionObj::hasSpecialDrag() const
282
0
{
283
0
    return true;
284
0
}
285
286
bool SdrCaptionObj::beginSpecialDrag(SdrDragStat& rDrag) const
287
0
{
288
0
    const SdrHdl* pHdl = rDrag.GetHdl();
289
0
    rDrag.SetEndDragChangesAttributes(true);
290
0
    rDrag.SetEndDragChangesGeoAndAttributes(true);
291
292
0
    if(pHdl && 0 == pHdl->GetPolyNum())
293
0
    {
294
0
        return SdrRectObj::beginSpecialDrag(rDrag);
295
0
    }
296
0
    else
297
0
    {
298
0
        rDrag.SetOrtho8Possible();
299
300
0
        if(!pHdl)
301
0
        {
302
0
            if (m_bMovProt)
303
0
                return false;
304
305
0
            rDrag.SetNoSnap();
306
0
            rDrag.SetActionRect(getRectangle());
307
308
0
            Point aHit(rDrag.GetStart());
309
310
0
            if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, {0, 0}, *rDrag.GetPageView(), nullptr, false))
311
0
            {
312
0
                return true;
313
0
            }
314
0
        }
315
0
        else
316
0
        {
317
0
            if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
318
0
                return true;
319
0
        }
320
0
    }
321
322
0
    return false;
323
0
}
324
325
bool SdrCaptionObj::applySpecialDrag(SdrDragStat& rDrag)
326
0
{
327
0
    const SdrHdl* pHdl = rDrag.GetHdl();
328
329
0
    if(pHdl && 0 == pHdl->GetPolyNum())
330
0
    {
331
0
        const bool bRet(SdrRectObj::applySpecialDrag(rDrag));
332
0
        ImpRecalcTail();
333
0
        ActionChanged();
334
335
0
        return bRet;
336
0
    }
337
0
    else
338
0
    {
339
0
        Point aDelta(rDrag.GetNow()-rDrag.GetStart());
340
341
0
        if(!pHdl)
342
0
        {
343
0
            moveRectangle(aDelta.X(), aDelta.Y());
344
0
        }
345
0
        else
346
0
        {
347
0
            maTailPoly[0] += aDelta;
348
0
        }
349
350
0
        ImpRecalcTail();
351
0
        ActionChanged();
352
353
0
        return true;
354
0
    }
355
0
}
356
357
OUString SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
358
0
{
359
0
    const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
360
361
0
    if(bCreateComment)
362
0
    {
363
0
        return OUString();
364
0
    }
365
0
    else
366
0
    {
367
0
        const SdrHdl* pHdl = rDrag.GetHdl();
368
369
0
        if(pHdl && 0 == pHdl->GetPolyNum())
370
0
        {
371
0
            return SdrRectObj::getSpecialDragComment(rDrag);
372
0
        }
373
0
        else
374
0
        {
375
0
            if(!pHdl)
376
0
            {
377
0
                return ImpGetDescriptionStr(STR_DragCaptFram);
378
0
            }
379
0
            else
380
0
            {
381
0
                return ImpGetDescriptionStr(STR_DragCaptTail);
382
0
            }
383
0
        }
384
0
    }
385
0
}
386
387
388
void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams& rPara) const
389
190k
{
390
190k
    const SfxItemSet& rSet = GetObjectItemSet();
391
190k
    rPara.eType      =rSet.Get(SDRATTR_CAPTIONTYPE      ).GetValue();
392
190k
    rPara.bFixedAngle=rSet.Get(SDRATTR_CAPTIONFIXEDANGLE).GetValue();
393
190k
    rPara.nGap       =static_cast<const SdrCaptionGapItem&>       (rSet.Get(SDRATTR_CAPTIONGAP       )).GetValue();
394
190k
    rPara.eEscDir    =rSet.Get(SDRATTR_CAPTIONESCDIR    ).GetValue();
395
190k
    rPara.bEscRel    =rSet.Get(SDRATTR_CAPTIONESCISREL  ).GetValue();
396
190k
    rPara.nEscRel    =rSet.Get(SDRATTR_CAPTIONESCREL    ).GetValue();
397
190k
    rPara.nEscAbs    =rSet.Get(SDRATTR_CAPTIONESCABS    ).GetValue();
398
190k
    rPara.nLineLen   =rSet.Get(SDRATTR_CAPTIONLINELEN   ).GetValue();
399
190k
    rPara.bFitLineLen=rSet.Get(SDRATTR_CAPTIONFITLINELEN).GetValue();
400
190k
}
401
402
void SdrCaptionObj::ImpRecalcTail()
403
190k
{
404
190k
    ImpCaptParams aPara;
405
190k
    ImpGetCaptParams(aPara);
406
190k
    ImpCalcTail(aPara, maTailPoly, getRectangle());
407
190k
    SetBoundAndSnapRectsDirty();
408
190k
    SetXPolyDirty();
409
190k
}
410
411
// #i35971#
412
// SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
413
// I really wonder why this had not triggered problems before. I am
414
// sure there are some places where SetTailPos() is called at least
415
// twice or SetSnapRect after it again just to work around this.
416
// Changed this method to not do that.
417
// Also found why this has been done: For interactive dragging of the
418
// tail end pos for SdrCaptionType::Type1. This sure was the simplest method
419
// to achieve this, at the cost of making a whole group of const methods
420
// of this object implicitly change the object's position.
421
void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
422
21
{
423
21
    tools::Polygon aPol(2);
424
21
    Point aTl(rPoly[0]);
425
426
21
    aPol[0] = aTl;
427
21
    aPol[1] = aTl;
428
429
21
    EscDir eEscDir;
430
21
    Point aEscPos;
431
432
21
    rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
433
21
    aPol[1] = aEscPos;
434
435
21
    if(eEscDir==LKS || eEscDir==RTS)
436
0
    {
437
0
        aPol[0].setX( aEscPos.X() );
438
0
    }
439
21
    else
440
21
    {
441
21
        aPol[0].setY( aEscPos.Y() );
442
21
    }
443
444
21
    rPoly = std::move(aPol);
445
21
}
446
447
void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
448
896
{ // Gap/EscDir/EscPos/Angle
449
896
    tools::Polygon aPol(2);
450
896
    Point aTl(rPoly[0]);
451
896
    aPol[0]=aTl;
452
453
896
    EscDir eEscDir;
454
896
    Point aEscPos;
455
896
    rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
456
896
    aPol[1]=aEscPos;
457
458
896
    if (!rPara.bFixedAngle) {
459
        // TODO: Implementation missing.
460
0
    }
461
896
    rPoly = std::move(aPol);
462
896
}
463
464
void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
465
189k
{ // Gap/EscDir/EscPos/Angle/LineLen
466
189k
    tools::Polygon aPol(3);
467
189k
    Point aTl(rPoly[0]);
468
189k
    aPol[0]=aTl;
469
470
189k
    EscDir eEscDir;
471
189k
    Point aEscPos;
472
189k
    rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
473
189k
    aPol[1]=aEscPos;
474
189k
    aPol[2]=aEscPos;
475
476
189k
    if (eEscDir==LKS || eEscDir==RTS) {
477
189k
        if (rPara.bFitLineLen) {
478
189k
            aPol[1].setX((aTl.X()+aEscPos.X())/2 );
479
189k
        } else {
480
0
            if (eEscDir==LKS) aPol[1].AdjustX( -(rPara.nLineLen) );
481
0
            else aPol[1].AdjustX(rPara.nLineLen );
482
0
        }
483
189k
    } else {
484
0
        if (rPara.bFitLineLen) {
485
0
            aPol[1].setY((aTl.Y()+aEscPos.Y())/2 );
486
0
        } else {
487
0
            if (eEscDir==OBN) aPol[1].AdjustY( -(rPara.nLineLen) );
488
0
            else aPol[1].AdjustY(rPara.nLineLen );
489
0
        }
490
0
    }
491
189k
    if (!rPara.bFixedAngle) {
492
        // TODO: Implementation missing.
493
0
    }
494
189k
    rPoly = std::move(aPol);
495
189k
}
496
497
void SdrCaptionObj::ImpCalcTail(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
498
190k
{
499
190k
    switch (rPara.eType) {
500
21
        case SdrCaptionType::Type1: ImpCalcTail1(rPara,rPoly,rRect); break;
501
896
        case SdrCaptionType::Type2: ImpCalcTail2(rPara,rPoly,rRect); break;
502
189k
        case SdrCaptionType::Type3: ImpCalcTail3(rPara,rPoly,rRect); break;
503
81
        case SdrCaptionType::Type4: ImpCalcTail3(rPara,rPoly,rRect); break;
504
190k
    }
505
190k
}
506
507
bool SdrCaptionObj::BegCreate(SdrDragStat& rStat)
508
0
{
509
0
    if (getRectangle().IsEmpty())
510
0
        return false; // Create currently only works with the given Rect
511
512
0
    ImpCaptParams aPara;
513
0
    ImpGetCaptParams(aPara);
514
0
    moveRectanglePosition(rStat.GetNow().X(), rStat.GetNow().Y());
515
0
    maTailPoly[0]=rStat.GetStart();
516
0
    ImpCalcTail(aPara,maTailPoly, getRectangle());
517
0
    rStat.SetActionRect(getRectangle());
518
0
    return true;
519
0
}
520
521
bool SdrCaptionObj::MovCreate(SdrDragStat& rStat)
522
0
{
523
0
    ImpCaptParams aPara;
524
0
    ImpGetCaptParams(aPara);
525
0
    moveRectanglePosition(rStat.GetNow().X(), rStat.GetNow().Y());
526
0
    ImpCalcTail(aPara,maTailPoly, getRectangle());
527
0
    rStat.SetActionRect(getRectangle());
528
0
    SetBoundRectDirty();
529
0
    m_bSnapRectDirty=true;
530
0
    return true;
531
0
}
532
533
bool SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
534
0
{
535
0
    ImpCaptParams aPara;
536
0
    ImpGetCaptParams(aPara);
537
0
    moveRectanglePosition(rStat.GetNow().X(), rStat.GetNow().Y());
538
0
    ImpCalcTail(aPara,maTailPoly, getRectangle());
539
0
    SetBoundAndSnapRectsDirty();
540
0
    return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
541
0
}
542
543
bool SdrCaptionObj::BckCreate(SdrDragStat& /*rStat*/)
544
0
{
545
0
    return false;
546
0
}
547
548
void SdrCaptionObj::BrkCreate(SdrDragStat& /*rStat*/)
549
0
{
550
0
}
551
552
basegfx::B2DPolyPolygon SdrCaptionObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
553
0
{
554
0
    basegfx::B2DPolyPolygon aRetval;
555
0
    const basegfx::B2DRange aRange =vcl::unotools::b2DRectangleFromRectangle(getRectangle());
556
0
    aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
557
0
    aRetval.append(maTailPoly.getB2DPolygon());
558
0
    return aRetval;
559
0
}
560
561
PointerStyle SdrCaptionObj::GetCreatePointer() const
562
0
{
563
0
    return PointerStyle::DrawCaption;
564
0
}
565
566
void SdrCaptionObj::NbcMove(const Size& rSiz)
567
0
{
568
0
    SdrRectObj::NbcMove(rSiz);
569
0
    MovePoly(maTailPoly,rSiz);
570
0
    if(mbFixedTail)
571
0
        SetTailPos(GetFixedTailPos());
572
0
}
573
574
void SdrCaptionObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
575
0
{
576
0
    SdrRectObj::NbcResize(rRef,xFact,yFact);
577
0
    ResizePoly(maTailPoly,rRef,xFact,yFact);
578
0
    ImpRecalcTail();
579
0
    if(mbFixedTail)
580
0
        SetTailPos(GetFixedTailPos());
581
0
}
582
583
void SdrCaptionObj::NbcSetRelativePos(const Point& rPnt)
584
0
{
585
0
    Point aRelPos0(maTailPoly.GetPoint(0)-m_aAnchor);
586
0
    Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
587
0
    NbcMove(aSiz); // This also calls SetRectsDirty()
588
0
}
589
590
Point SdrCaptionObj::GetRelativePos() const
591
0
{
592
0
    return maTailPoly.GetPoint(0)-m_aAnchor;
593
0
}
594
595
const tools::Rectangle& SdrCaptionObj::GetLogicRect() const
596
37.6k
{
597
37.6k
    return getRectangle();
598
37.6k
}
599
600
void SdrCaptionObj::NbcSetLogicRect(const tools::Rectangle& rRect, bool bAdaptTextMinSize)
601
37.8k
{
602
37.8k
    SdrRectObj::NbcSetLogicRect(rRect, bAdaptTextMinSize);
603
37.8k
    ImpRecalcTail();
604
37.8k
}
605
606
const Point& SdrCaptionObj::GetTailPos() const
607
18.9k
{
608
18.9k
    return maTailPoly[0];
609
18.9k
}
610
611
void SdrCaptionObj::SetTailPos(const Point& rPos)
612
18.9k
{
613
18.9k
    if (maTailPoly.GetSize()==0 || maTailPoly[0]!=rPos) {
614
64
        tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
615
64
        NbcSetTailPos(rPos);
616
64
        SetChanged();
617
64
        BroadcastObjectChange();
618
64
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
619
64
    }
620
18.9k
}
621
622
void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
623
64
{
624
64
    maTailPoly[0]=rPos;
625
64
    ImpRecalcTail();
626
64
}
627
628
sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
629
0
{
630
    // TODO: Implementation missing.
631
0
    return 0;
632
0
}
633
634
Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
635
0
{
636
    // TODO: Implementation missing.
637
0
    return Point(0,0);
638
0
}
639
640
void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
641
0
{
642
0
    SdrRectObj::Notify(rBC,rHint);
643
0
    ImpRecalcTail();
644
0
}
645
646
std::unique_ptr<SdrObjGeoData> SdrCaptionObj::NewGeoData() const
647
0
{
648
0
    return std::make_unique<SdrCaptObjGeoData>();
649
0
}
650
651
void SdrCaptionObj::SaveGeoData(SdrObjGeoData& rGeo) const
652
0
{
653
0
    SdrRectObj::SaveGeoData(rGeo);
654
0
    SdrCaptObjGeoData& rCGeo=static_cast<SdrCaptObjGeoData&>(rGeo);
655
0
    rCGeo.aTailPoly=maTailPoly;
656
0
}
657
658
void SdrCaptionObj::RestoreGeoData(const SdrObjGeoData& rGeo)
659
0
{
660
0
    SdrRectObj::RestoreGeoData(rGeo);
661
0
    const SdrCaptObjGeoData& rCGeo=static_cast<const SdrCaptObjGeoData&>(rGeo);
662
0
    maTailPoly=rCGeo.aTailPoly;
663
0
}
664
665
rtl::Reference<SdrObject> SdrCaptionObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
666
0
{
667
0
    rtl::Reference<SdrObject> pRect = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
668
0
    rtl::Reference<SdrObject> pTail = ImpConvertMakeObj(basegfx::B2DPolyPolygon(maTailPoly.getB2DPolygon()), false, bBezier);
669
0
    rtl::Reference<SdrObject> pRet;
670
0
    if (pTail && !pRect)
671
0
        pRet = std::move(pTail);
672
0
    else if (pRect && !pTail)
673
0
        pRet = std::move(pRect);
674
0
    else if (pTail && pRect)
675
0
    {
676
0
        if (pTail->GetSubList())
677
0
        {
678
0
            pTail->GetSubList()->NbcInsertObject(pRect.get());
679
0
            pRet = std::move(pTail);
680
0
        }
681
0
        else if (pRect->GetSubList())
682
0
        {
683
0
            pRect->GetSubList()->NbcInsertObject(pTail.get(),0);
684
0
            pRet = std::move(pRect);
685
0
        }
686
0
        else
687
0
        {
688
0
            rtl::Reference<SdrObjGroup> pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
689
0
            pGrp->GetSubList()->NbcInsertObject(pRect.get());
690
0
            pGrp->GetSubList()->NbcInsertObject(pTail.get(),0);
691
0
            pRet = pGrp;
692
0
        }
693
0
    }
694
0
    return pRet;
695
0
}
696
697
namespace {
698
699
0
void handleNegativeScale(basegfx::B2DTuple & scale, double * rotate) {
700
0
    assert(rotate != nullptr);
701
702
    // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
703
    // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
704
0
    if(scale.getX() < 0.0 && scale.getY() < 0.0)
705
0
    {
706
0
        scale.setX(fabs(scale.getX()));
707
0
        scale.setY(fabs(scale.getY()));
708
0
        *rotate = fmod(*rotate + M_PI, 2 * M_PI);
709
0
    }
710
0
}
711
712
}
713
714
// #i32599#
715
// Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
716
void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
717
0
{
718
    // break up matrix
719
0
    basegfx::B2DTuple aScale;
720
0
    basegfx::B2DTuple aTranslate;
721
0
    double fRotate, fShearX;
722
0
    rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
723
724
0
    handleNegativeScale(aScale, &fRotate);
725
726
    // if anchor is used, make position relative to it
727
0
    if(getSdrModelFromSdrObject().IsWriter())
728
0
    {
729
0
        if(GetAnchorPos().X() || GetAnchorPos().Y())
730
0
        {
731
0
            aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
732
0
        }
733
0
    }
734
735
    // build BaseRect
736
0
    Point aPoint(basegfx::fround<tools::Long>(aTranslate.getX()),
737
0
                 basegfx::fround<tools::Long>(aTranslate.getY()));
738
0
    tools::Rectangle aBaseRect(aPoint, Size(basegfx::fround<tools::Long>(aScale.getX()),
739
0
                                            basegfx::fround<tools::Long>(aScale.getY())));
740
741
    // set BaseRect, but rescue TailPos over this call
742
0
    const Point aTailPoint = GetTailPos();
743
0
    SetSnapRect(aBaseRect);
744
0
    SetTailPos(aTailPoint);
745
0
    ImpRecalcTail();
746
0
}
747
748
// geometry access
749
basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
750
0
{
751
0
    return maTailPoly.getB2DPolygon();
752
0
}
753
754
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */