Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdcrtv.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
21
#include <svx/svdcrtv.hxx>
22
#include <svx/xlnclit.hxx>
23
#include <svx/svdocapt.hxx>
24
#include <svx/svdoedge.hxx>
25
#include <svx/svdpagv.hxx>
26
#include <svx/svdpage.hxx>
27
#include <svx/scene3d.hxx>
28
#include <svx/view3d.hxx>
29
#include <svx/xfillit0.hxx>
30
#include <svx/xflclit.hxx>
31
#include <svx/xlineit0.hxx>
32
#include <svx/svdouno.hxx>
33
#include <svx/svdopath.hxx>
34
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
35
#include <svx/sdr/overlay/overlaymanager.hxx>
36
#include <svx/sdrpaintwindow.hxx>
37
#include <fmobj.hxx>
38
#include <svx/svdocirc.hxx>
39
#include <svx/sdr/contact/viewcontact.hxx>
40
#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
41
#include <vcl/ptrstyle.hxx>
42
#include <officecfg/Office/Common.hxx>
43
44
using namespace com::sun::star;
45
46
class ImplConnectMarkerOverlay
47
{
48
    // The OverlayObjects
49
    sdr::overlay::OverlayObjectList               maObjects;
50
51
    // The remembered target object
52
    const SdrObject&                                mrObject;
53
54
public:
55
    ImplConnectMarkerOverlay(const SdrCreateView& rView, SdrObject const & rObject);
56
57
    // The OverlayObjects are cleared using the destructor of OverlayObjectList.
58
    // That destructor calls clear() at the list which removes all objects from the
59
    // OverlayManager and deletes them.
60
61
0
    const SdrObject& GetTargetObject() const { return mrObject; }
62
};
63
64
ImplConnectMarkerOverlay::ImplConnectMarkerOverlay(const SdrCreateView& rView, SdrObject const & rObject)
65
0
:   mrObject(rObject)
66
0
{
67
0
    basegfx::B2DPolyPolygon aB2DPolyPolygon(rObject.TakeXorPoly());
68
69
0
    for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
70
0
    {
71
0
        SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
72
0
        const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
73
74
0
        if(xTargetOverlay.is())
75
0
        {
76
0
            float fScalingFactor = xTargetOverlay->getOutputDevice().GetDPIScaleFactor();
77
0
            Size aHalfLogicSize(xTargetOverlay->getOutputDevice().PixelToLogic(Size(4 * fScalingFactor, 4 * fScalingFactor)));
78
79
            // object
80
0
            std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
81
0
                aB2DPolyPolygon));
82
0
            xTargetOverlay->add(*pNew);
83
0
            maObjects.append(std::move(pNew));
84
85
            // gluepoints
86
0
            for(sal_uInt16 i(0); i < 4; i++)
87
0
            {
88
0
                SdrGluePoint aGluePoint(rObject.GetVertexGluePoint(i));
89
0
                const Point aPosition = aGluePoint.GetAbsolutePos(rObject);
90
91
0
                basegfx::B2DPoint aTopLeft(aPosition.X() - aHalfLogicSize.Width(), aPosition.Y() - aHalfLogicSize.Height());
92
0
                basegfx::B2DPoint aBottomRight(aPosition.X() + aHalfLogicSize.Width(), aPosition.Y() + aHalfLogicSize.Height());
93
94
0
                basegfx::B2DPolygon aTempPoly;
95
0
                aTempPoly.append(aTopLeft);
96
0
                aTempPoly.append(basegfx::B2DPoint(aBottomRight.getX(), aTopLeft.getY()));
97
0
                aTempPoly.append(aBottomRight);
98
0
                aTempPoly.append(basegfx::B2DPoint(aTopLeft.getX(), aBottomRight.getY()));
99
0
                aTempPoly.setClosed(true);
100
101
0
                basegfx::B2DPolyPolygon aTempPolyPoly;
102
0
                aTempPolyPoly.append(aTempPoly);
103
104
0
                std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew2(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
105
0
                    std::move(aTempPolyPoly)));
106
0
                xTargetOverlay->add(*pNew2);
107
0
                maObjects.append(std::move(pNew2));
108
0
            }
109
0
        }
110
0
    }
111
0
}
112
113
class ImpSdrCreateViewExtraData
114
{
115
    // The OverlayObjects for XOR replacement
116
    sdr::overlay::OverlayObjectList               maObjects;
117
118
public:
119
    ImpSdrCreateViewExtraData();
120
    ~ImpSdrCreateViewExtraData();
121
122
    void CreateAndShowOverlay(const SdrCreateView& rView, const SdrObject* pObject, const basegfx::B2DPolyPolygon& rPolyPoly);
123
    void HideOverlay();
124
};
125
126
ImpSdrCreateViewExtraData::ImpSdrCreateViewExtraData()
127
345k
{
128
345k
}
129
130
ImpSdrCreateViewExtraData::~ImpSdrCreateViewExtraData()
131
345k
{
132
345k
    HideOverlay();
133
345k
}
134
135
void ImpSdrCreateViewExtraData::CreateAndShowOverlay(const SdrCreateView& rView, const SdrObject* pObject, const basegfx::B2DPolyPolygon& rPolyPoly)
136
0
{
137
0
    for(sal_uInt32 a(0); a < rView.PaintWindowCount(); a++)
138
0
    {
139
0
        SdrPaintWindow* pCandidate = rView.GetPaintWindow(a);
140
0
        const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager = pCandidate->GetOverlayManager();
141
142
0
        if (xOverlayManager.is())
143
0
        {
144
0
            if(pObject)
145
0
            {
146
0
                const sdr::contact::ViewContact& rVC = pObject->GetViewContact();
147
0
                drawinglayer::primitive2d::Primitive2DContainer aSequence;
148
0
                rVC.getViewIndependentPrimitive2DContainer(aSequence);
149
0
                std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(std::move(aSequence)));
150
151
0
                xOverlayManager->add(*pNew);
152
0
                maObjects.append(std::move(pNew));
153
0
            }
154
155
0
            if(rPolyPoly.count())
156
0
            {
157
0
                std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
158
0
                    rPolyPoly));
159
0
                xOverlayManager->add(*pNew);
160
0
                maObjects.append(std::move(pNew));
161
0
            }
162
0
        }
163
0
    }
164
0
}
165
166
void ImpSdrCreateViewExtraData::HideOverlay()
167
345k
{
168
    // the clear() call of the list removes all objects from the
169
    // OverlayManager and deletes them.
170
345k
    maObjects.clear();
171
345k
}
172
173
174
// CreateView
175
176
177
void SdrCreateView::ImpClearConnectMarker()
178
345k
{
179
345k
    mpCoMaOverlay.reset();
180
345k
}
181
182
SdrCreateView::SdrCreateView(SdrModel& rSdrModel, OutputDevice* pOut)
183
345k
    : SdrDragView(rSdrModel, pOut)
184
345k
    , mpCreatePV(nullptr)
185
345k
    , mpCreateViewExtraData(new ImpSdrCreateViewExtraData())
186
345k
    , maCurrentCreatePointer(PointerStyle::Cross)
187
345k
    , mnAutoCloseDistPix(5)
188
345k
    , mnFreeHandMinDistPix(officecfg::Office::Common::Misc::FreehandThresholdPixels::get())
189
345k
    , mnCurrentInvent(SdrInventor::Default)
190
345k
    , mnCurrentIdent(SdrObjKind::NONE)
191
345k
    , mb1stPointAsCenter(false)
192
345k
    , mbUseIncompatiblePathCreateInterface(false)
193
345k
{
194
345k
}
195
196
SdrCreateView::~SdrCreateView()
197
345k
{
198
345k
    ImpClearConnectMarker();
199
345k
    mpCreateViewExtraData.reset();
200
345k
}
201
202
bool SdrCreateView::IsAction() const
203
0
{
204
0
    return SdrDragView::IsAction() || mpCurrentCreate!=nullptr;
205
0
}
206
207
void SdrCreateView::MovAction(const Point& rPnt)
208
0
{
209
0
    SdrDragView::MovAction(rPnt);
210
0
    if (mpCurrentCreate != nullptr) {
211
0
        MovCreateObj(rPnt);
212
0
    }
213
0
}
214
215
void SdrCreateView::EndAction()
216
0
{
217
0
    if (mpCurrentCreate != nullptr) EndCreateObj(SdrCreateCmd::ForceEnd);
218
0
    SdrDragView::EndAction();
219
0
}
220
221
void SdrCreateView::BckAction()
222
0
{
223
0
    if (mpCurrentCreate != nullptr) BckCreateObj();
224
0
    SdrDragView::BckAction();
225
0
}
226
227
void SdrCreateView::BrkAction()
228
67.3k
{
229
67.3k
    SdrDragView::BrkAction();
230
67.3k
    BrkCreateObj();
231
67.3k
}
232
233
void SdrCreateView::TakeActionRect(tools::Rectangle& rRect) const
234
0
{
235
0
    if (mpCurrentCreate != nullptr)
236
0
    {
237
0
        rRect=maDragStat.GetActionRect();
238
0
        if (rRect.IsEmpty())
239
0
        {
240
0
            rRect=tools::Rectangle(maDragStat.GetPrev(),maDragStat.GetNow());
241
0
        }
242
0
    }
243
0
    else
244
0
    {
245
0
        SdrDragView::TakeActionRect(rRect);
246
0
    }
247
0
}
248
249
bool SdrCreateView::CheckEdgeMode()
250
0
{
251
0
    if (mpCurrentCreate != nullptr)
252
0
    {
253
        // is managed by EdgeObj
254
0
        if (mnCurrentInvent==SdrInventor::Default && mnCurrentIdent==SdrObjKind::Edge) return false;
255
0
    }
256
257
0
    if (!IsCreateMode() || mnCurrentInvent!=SdrInventor::Default || mnCurrentIdent!=SdrObjKind::Edge)
258
0
    {
259
0
        ImpClearConnectMarker();
260
0
        return false;
261
0
    }
262
0
    else
263
0
    {
264
        // sal_True, if MouseMove should check Connect
265
0
        return !IsAction();
266
0
    }
267
0
}
268
269
void SdrCreateView::SetConnectMarker(const SdrObjConnection& rCon)
270
0
{
271
0
    SdrObject* pTargetObject = rCon.m_pSdrObj;
272
273
0
    if(pTargetObject)
274
0
    {
275
        // if target object changes, throw away overlay object to make room for changes
276
0
        if(mpCoMaOverlay && pTargetObject != &mpCoMaOverlay->GetTargetObject())
277
0
        {
278
0
            ImpClearConnectMarker();
279
0
        }
280
281
0
        if(!mpCoMaOverlay)
282
0
        {
283
0
            mpCoMaOverlay.reset(new ImplConnectMarkerOverlay(*this, *pTargetObject));
284
0
        }
285
0
    }
286
0
    else
287
0
    {
288
0
        ImpClearConnectMarker();
289
0
    }
290
0
}
291
292
void SdrCreateView::HideConnectMarker()
293
0
{
294
0
    ImpClearConnectMarker();
295
0
}
296
297
bool SdrCreateView::MouseMove(const MouseEvent& rMEvt, OutputDevice* pWin)
298
0
{
299
0
    if(CheckEdgeMode() && pWin)
300
0
    {
301
0
        SdrPageView* pPV = GetSdrPageView();
302
303
0
        if(pPV)
304
0
        {
305
            // TODO: Change default hit tolerance at IsMarkedHit() some time!
306
0
            Point aPos(pWin->PixelToLogic(rMEvt.GetPosPixel()));
307
0
            bool bMarkHit=PickHandle(aPos)!=nullptr || IsMarkedObjHit(aPos);
308
0
            SdrObjConnection aCon;
309
0
            if (!bMarkHit) SdrEdgeObj::ImpFindConnector(aPos,*pPV,aCon,nullptr,pWin);
310
0
            SetConnectMarker(aCon);
311
0
        }
312
0
    }
313
0
    return SdrDragView::MouseMove(rMEvt,pWin);
314
0
}
315
316
bool SdrCreateView::IsTextTool() const
317
0
{
318
0
    return meEditMode==SdrViewEditMode::Create
319
0
        && mnCurrentInvent==SdrInventor::Default
320
0
        && (mnCurrentIdent==SdrObjKind::Text
321
0
            || mnCurrentIdent==SdrObjKind::TitleText
322
0
            || mnCurrentIdent==SdrObjKind::OutlineText);
323
0
}
324
325
bool SdrCreateView::IsEdgeTool() const
326
0
{
327
0
    return meEditMode==SdrViewEditMode::Create && mnCurrentInvent==SdrInventor::Default && (mnCurrentIdent==SdrObjKind::Edge);
328
0
}
329
330
bool SdrCreateView::IsMeasureTool() const
331
0
{
332
0
    return meEditMode==SdrViewEditMode::Create && mnCurrentInvent==SdrInventor::Default && (mnCurrentIdent==SdrObjKind::Measure);
333
0
}
334
335
void SdrCreateView::SetCurrentObj(SdrObjKind nIdent, SdrInventor nInvent)
336
0
{
337
0
    if (mnCurrentInvent!=nInvent || mnCurrentIdent!=nIdent)
338
0
    {
339
0
        mnCurrentInvent=nInvent;
340
0
        mnCurrentIdent=nIdent;
341
0
        rtl::Reference<SdrObject> pObj = (nIdent == SdrObjKind::NONE) ? nullptr :
342
0
            SdrObjFactory::MakeNewObject(
343
0
                GetModel(),
344
0
                nInvent,
345
0
                nIdent);
346
347
0
        if(pObj)
348
0
        {
349
            // Using text tool, mouse cursor is usually I-Beam,
350
            // crosshairs with tiny I-Beam appears only on MouseButtonDown.
351
0
            if(IsTextTool())
352
0
            {
353
                // Here the correct pointer needs to be used
354
                // if the default is set to vertical writing
355
0
                maCurrentCreatePointer = PointerStyle::Text;
356
0
            }
357
0
            else
358
0
                maCurrentCreatePointer = pObj->GetCreatePointer();
359
0
        }
360
0
        else
361
0
        {
362
0
            maCurrentCreatePointer = PointerStyle::Cross;
363
0
        }
364
0
    }
365
366
0
    CheckEdgeMode();
367
0
    ImpSetGlueVisible3(IsEdgeTool());
368
0
}
369
370
bool SdrCreateView::ImpBegCreateObj(SdrInventor nInvent, SdrObjKind nIdent, const Point& rPnt, OutputDevice* pOut,
371
    sal_Int16 nMinMov, const tools::Rectangle& rLogRect, SdrObject* pPreparedFactoryObject)
372
0
{
373
0
    bool bRet=false;
374
0
    UnmarkAllObj();
375
0
    BrkAction();
376
377
0
    ImpClearConnectMarker();
378
379
0
    mpCreatePV = GetSdrPageView();
380
381
0
    if (mpCreatePV != nullptr)
382
0
    { // otherwise no side registered!
383
0
        OUString aLay(maActualLayer);
384
385
0
        if(nInvent == SdrInventor::Default && nIdent == SdrObjKind::Measure && !maMeasureLayer.isEmpty())
386
0
        {
387
0
            aLay = maMeasureLayer;
388
0
        }
389
390
0
        SdrLayerID nLayer = mpCreatePV->GetPage()->GetLayerAdmin().GetLayerID(aLay);
391
0
        if (nLayer==SDRLAYER_NOTFOUND) nLayer = SdrLayerID(0);
392
0
        if (!mpCreatePV->GetLockedLayers().IsSet(nLayer) && mpCreatePV->GetVisibleLayers().IsSet(nLayer))
393
0
        {
394
0
            if(pPreparedFactoryObject)
395
0
            {
396
0
                mpCurrentCreate = pPreparedFactoryObject;
397
0
            }
398
0
            else
399
0
            {
400
0
                mpCurrentCreate = SdrObjFactory::MakeNewObject(
401
0
                    GetModel(), nInvent, nIdent);
402
0
            }
403
404
0
            Point aPnt(rPnt);
405
0
            if (mnCurrentInvent != SdrInventor::Default || (mnCurrentIdent != SdrObjKind::Edge &&
406
0
                                            mnCurrentIdent != SdrObjKind::FreehandLine &&
407
0
                                            mnCurrentIdent != SdrObjKind::FreehandFill )) { // no snapping for Edge and Freehand
408
0
                aPnt=GetSnapPos(aPnt, mpCreatePV);
409
0
            }
410
0
            if (mpCurrentCreate!=nullptr)
411
0
            {
412
0
                if (mpDefaultStyleSheet!=nullptr) mpCurrentCreate->NbcSetStyleSheet(mpDefaultStyleSheet, false);
413
414
                // SW uses a naked SdrObject for frame construction. Normally, such an
415
                // object should not be created. Since it is possible to use it as a helper
416
                // object (e.g. in letting the user define an area with the interactive
417
                // construction) at least no items should be set at that object.
418
0
                if(nInvent != SdrInventor::Default || nIdent != SdrObjKind::NewFrame)
419
0
                {
420
0
                    mpCurrentCreate->SetMergedItemSet(maDefaultAttr);
421
0
                }
422
423
0
                if (dynamic_cast<const SdrCaptionObj *>(mpCurrentCreate.get()) != nullptr)
424
0
                {
425
0
                    SfxItemSet aSet(GetModel().GetItemPool());
426
0
                    aSet.Put(XFillColorItem(OUString(),COL_WHITE)); // in case someone turns on Solid
427
0
                    aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
428
429
0
                    mpCurrentCreate->SetMergedItemSet(aSet);
430
0
                }
431
0
                if (nInvent == SdrInventor::Default && (nIdent==SdrObjKind::Text || nIdent==SdrObjKind::TitleText || nIdent==SdrObjKind::OutlineText))
432
0
                {
433
                    // default for all text frames: no background, no border
434
0
                    SfxItemSet aSet(GetModel().GetItemPool());
435
0
                    aSet.Put(XFillColorItem(OUString(),COL_WHITE)); // in case someone turns on Solid
436
0
                    aSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
437
0
                    aSet.Put(XLineColorItem(OUString(),COL_BLACK)); // in case someone turns on Solid
438
0
                    aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
439
440
0
                    mpCurrentCreate->SetMergedItemSet(aSet);
441
0
                }
442
0
                if (!rLogRect.IsEmpty()) mpCurrentCreate->NbcSetLogicRect(rLogRect);
443
444
                // make sure drag start point is inside WorkArea
445
0
                const tools::Rectangle& rWorkArea = GetWorkArea();
446
447
0
                if(!rWorkArea.IsEmpty())
448
0
                {
449
0
                    if(aPnt.X() < rWorkArea.Left())
450
0
                    {
451
0
                        aPnt.setX( rWorkArea.Left() );
452
0
                    }
453
454
0
                    if(aPnt.X() > rWorkArea.Right())
455
0
                    {
456
0
                        aPnt.setX( rWorkArea.Right() );
457
0
                    }
458
459
0
                    if(aPnt.Y() < rWorkArea.Top())
460
0
                    {
461
0
                        aPnt.setY( rWorkArea.Top() );
462
0
                    }
463
464
0
                    if(aPnt.Y() > rWorkArea.Bottom())
465
0
                    {
466
0
                        aPnt.setY( rWorkArea.Bottom() );
467
0
                    }
468
0
                }
469
470
0
                maDragStat.Reset(aPnt);
471
0
                maDragStat.SetView(static_cast<SdrView*>(this));
472
0
                maDragStat.SetPageView(mpCreatePV);
473
0
                maDragStat.SetMinMove(ImpGetMinMovLogic(nMinMov,pOut));
474
0
                mpDragWin=pOut;
475
0
                if (mpCurrentCreate->BegCreate(maDragStat))
476
0
                {
477
0
                    ShowCreateObj(/*pOut,sal_True*/);
478
0
                    bRet=true;
479
0
                }
480
0
                else
481
0
                {
482
0
                    mpCurrentCreate = nullptr;
483
0
                    mpCreatePV = nullptr;
484
0
                }
485
0
            }
486
0
        }
487
0
    }
488
0
    return bRet;
489
0
}
490
491
bool SdrCreateView::BegCreateObj(const Point& rPnt, OutputDevice* pOut, short nMinMov)
492
0
{
493
0
    return ImpBegCreateObj(mnCurrentInvent,mnCurrentIdent,rPnt,pOut,nMinMov,tools::Rectangle(), nullptr);
494
0
}
495
496
bool SdrCreateView::BegCreatePreparedObject(const Point& rPnt, sal_Int16 nMinMov, SdrObject* pPreparedFactoryObject)
497
0
{
498
0
    SdrInventor nInvent(mnCurrentInvent);
499
0
    SdrObjKind nIdent(mnCurrentIdent);
500
501
0
    if(pPreparedFactoryObject)
502
0
    {
503
0
        nInvent = pPreparedFactoryObject->GetObjInventor();
504
0
        nIdent = pPreparedFactoryObject->GetObjIdentifier();
505
0
    }
506
507
0
    return ImpBegCreateObj(nInvent, nIdent, rPnt, nullptr, nMinMov, tools::Rectangle(), pPreparedFactoryObject);
508
0
}
509
510
bool SdrCreateView::BegCreateCaptionObj(const Point& rPnt, const Size& rObjSiz,
511
    OutputDevice* pOut, short nMinMov)
512
0
{
513
0
    return ImpBegCreateObj(SdrInventor::Default,SdrObjKind::Caption,rPnt,pOut,nMinMov,
514
0
        tools::Rectangle(rPnt,Size(rObjSiz.Width()+1,rObjSiz.Height()+1)), nullptr);
515
0
}
516
517
void SdrCreateView::MovCreateObj(const Point& rPnt)
518
0
{
519
0
    if (mpCurrentCreate==nullptr)
520
0
        return;
521
522
0
    Point aPnt(rPnt);
523
0
    if (!maDragStat.IsNoSnap())
524
0
    {
525
0
        aPnt=GetSnapPos(aPnt, mpCreatePV);
526
0
    }
527
0
    if (IsOrtho())
528
0
    {
529
0
        if (maDragStat.IsOrtho8Possible()) OrthoDistance8(maDragStat.GetPrev(),aPnt,IsBigOrtho());
530
0
        else if (maDragStat.IsOrtho4Possible()) OrthoDistance4(maDragStat.GetPrev(),aPnt,IsBigOrtho());
531
0
    }
532
533
    // If the drag point was limited and Ortho is active, do
534
    // the small ortho correction (reduction) -> last parameter to FALSE.
535
0
    bool bDidLimit(ImpLimitToWorkArea(aPnt));
536
0
    if(bDidLimit && IsOrtho())
537
0
    {
538
0
        if(maDragStat.IsOrtho8Possible())
539
0
            OrthoDistance8(maDragStat.GetPrev(), aPnt, false);
540
0
        else if(maDragStat.IsOrtho4Possible())
541
0
            OrthoDistance4(maDragStat.GetPrev(), aPnt, false);
542
0
    }
543
544
0
    if (aPnt==maDragStat.GetNow()) return;
545
0
    bool bIsMinMoved(maDragStat.IsMinMoved());
546
0
    if (!maDragStat.CheckMinMoved(aPnt))
547
0
        return;
548
549
0
    if (!bIsMinMoved) maDragStat.NextPoint();
550
0
    maDragStat.NextMove(aPnt);
551
0
    mpCurrentCreate->MovCreate(maDragStat);
552
553
    // MovCreate changes the object, so use ActionChanged() on it
554
0
    mpCurrentCreate->ActionChanged();
555
556
    // replace for DrawCreateObjDiff
557
0
    HideCreateObj();
558
0
    ShowCreateObj();
559
0
}
560
561
void SdrCreateView::SetupObjLayer(const SdrPageView* pPageView, const OUString& aActiveLayer, SdrObject* pObj)
562
0
{
563
0
    const SdrLayerAdmin& rAd = pPageView->GetPage()->GetLayerAdmin();
564
0
    SdrLayerID nLayer(0);
565
566
    // #i72535#
567
0
    if(dynamic_cast<const FmFormObj*>( pObj) !=  nullptr)
568
0
    {
569
        // for FormControls, force to form layer
570
0
        nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
571
0
    }
572
0
    else
573
0
    {
574
0
        nLayer = rAd.GetLayerID(aActiveLayer);
575
0
    }
576
577
0
    if(SDRLAYER_NOTFOUND == nLayer)
578
0
    {
579
0
        nLayer = SdrLayerID(0);
580
0
    }
581
582
0
    pObj->SetLayer(nLayer);
583
0
}
584
585
bool SdrCreateView::EndCreateObj(SdrCreateCmd eCmd)
586
0
{
587
0
    bool bRet=false;
588
0
    SdrObject* pObjCreated=mpCurrentCreate.get();
589
590
0
    if (mpCurrentCreate!=nullptr)
591
0
    {
592
0
        sal_uInt32 nCount=maDragStat.GetPointCount();
593
594
0
        if (nCount<=1 && eCmd==SdrCreateCmd::ForceEnd)
595
0
        {
596
0
            BrkCreateObj(); // objects with only a single point don't exist (at least today)
597
0
            return false; // sal_False = event not interpreted
598
0
        }
599
600
0
        bool bPntsEq=nCount>1;
601
0
        sal_uInt32 i=1;
602
0
        Point aP0=maDragStat.GetPoint(0);
603
0
        while (bPntsEq && i<nCount) { bPntsEq=aP0==maDragStat.GetPoint(i); i++; }
604
605
0
        if (mpCurrentCreate->EndCreate(maDragStat,eCmd))
606
0
        {
607
0
            HideCreateObj();
608
609
0
            if (!bPntsEq)
610
0
            {
611
                // otherwise Brk, because all points are equal
612
0
                rtl::Reference<SdrObject> pObj = std::move(mpCurrentCreate);
613
614
0
                SetupObjLayer(mpCreatePV, maActualLayer, pObj.get());
615
616
                // recognize creation of a new 3D object inside a 3D scene
617
0
                bool bSceneIntoScene(false);
618
619
0
                E3dScene* pObjScene = DynCastE3dScene(pObjCreated);
620
0
                E3dScene* pCurrentScene = pObjScene ? DynCastE3dScene(mpCreatePV->GetCurrentGroup()) : nullptr;
621
0
                if (pCurrentScene)
622
0
                {
623
0
                    bool bDidInsert = static_cast<E3dView*>(this)->ImpCloneAll3DObjectsToDestScene(
624
0
                        pObjScene, pCurrentScene, Point(0, 0));
625
626
0
                    if(bDidInsert)
627
0
                    {
628
0
                        pObjCreated = nullptr;
629
0
                        bSceneIntoScene = true;
630
0
                    }
631
0
                }
632
633
0
                if(!bSceneIntoScene)
634
0
                {
635
                    // Here an interactively created SdrObject gets added, so
636
                    // take into account that interaction created an object in
637
                    // model coordinates. If we have e.g. a GirdOffset, this is a
638
                    // little bit tricky - we have an object in model coordinates,
639
                    // so the fetched offset is at the wrong point in principle
640
                    // since we need to 'substract' the offset here to get to
641
                    // 'real' model coordinates. But we have nothing better here,
642
                    // so go for it.
643
                    // The 2nd a little tricky thing is that this will early-create
644
                    // a ViewObjectContact for the new SdrObject, but these VOCs
645
                    // are anyways layouted for being create-on-demand. This will
646
                    // be adapted/replaced correctly later on.
647
                    // This *should* be the right place for getting all interactively
648
                    // created objects, see InsertObjectAtView below that calls
649
                    // CreateUndoNewObject.
650
0
                    basegfx::B2DVector aGridOffset(0.0, 0.0);
651
0
                    if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj.get(), mpCreatePV))
652
0
                    {
653
0
                        const Size aOffset(
654
0
                            basegfx::fround<tools::Long>(-aGridOffset.getX()),
655
0
                            basegfx::fround<tools::Long>(-aGridOffset.getY()));
656
657
0
                        pObj->NbcMove(aOffset);
658
0
                    }
659
660
                    // do the same as before
661
0
                    InsertObjectAtView(pObj.get(), *mpCreatePV);
662
0
                }
663
664
0
                mpCreatePV = nullptr;
665
0
                bRet=true; // sal_True = event interpreted
666
0
            }
667
0
            else
668
0
            {
669
0
                BrkCreateObj();
670
0
            }
671
0
        }
672
0
        else
673
0
        { // more points
674
0
            if (eCmd==SdrCreateCmd::ForceEnd || // nothing there -- force ending
675
0
                nCount==0 ||                             // no existing points (should never happen)
676
0
                (nCount<=1 && !maDragStat.IsMinMoved())) { // MinMove not met
677
0
                BrkCreateObj();
678
0
            }
679
0
            else
680
0
            {
681
                // replace for DrawCreateObjDiff
682
0
                HideCreateObj();
683
0
                ShowCreateObj();
684
0
                maDragStat.ResetMinMoved(); // NextPoint is at MovCreateObj()
685
0
                bRet=true;
686
0
            }
687
0
        }
688
0
    }
689
0
    return bRet;
690
0
}
691
692
void SdrCreateView::BckCreateObj()
693
0
{
694
0
    if (mpCurrentCreate==nullptr)
695
0
        return;
696
697
0
    if (maDragStat.GetPointCount()<=2 )
698
0
    {
699
0
        BrkCreateObj();
700
0
    }
701
0
    else
702
0
    {
703
0
        HideCreateObj();
704
0
        maDragStat.PrevPoint();
705
0
        if (mpCurrentCreate->BckCreate(maDragStat))
706
0
        {
707
0
            ShowCreateObj();
708
0
        }
709
0
        else
710
0
        {
711
0
            BrkCreateObj();
712
0
        }
713
0
    }
714
0
}
715
716
void SdrCreateView::BrkCreateObj()
717
67.3k
{
718
67.3k
    if (mpCurrentCreate!=nullptr)
719
0
    {
720
0
        HideCreateObj();
721
0
        mpCurrentCreate->BrkCreate(maDragStat);
722
0
        mpCurrentCreate = nullptr;
723
0
        mpCreatePV = nullptr;
724
0
    }
725
67.3k
}
726
727
void SdrCreateView::ShowCreateObj(/*OutputDevice* pOut, sal_Bool bFull*/)
728
0
{
729
0
    if(!IsCreateObj() || maDragStat.IsShown())
730
0
        return;
731
732
0
    if (mpCurrentCreate)
733
0
    {
734
        // for migration from XOR, replace DrawDragObj here to create
735
        // overlay objects instead.
736
0
        bool bUseSolidDragging(IsSolidDragging());
737
738
        // #i101648# check if dragged object is a SdrObjKind::NewFrame.
739
        // This is e.g. used in SW Frame construction as placeholder.
740
        // Do not use SolidDragging for SdrObjKind::NewFrame kind of objects,
741
        // they cannot have a valid optical representation.
742
0
        if (bUseSolidDragging && SdrObjKind::NewFrame == mpCurrentCreate->GetObjIdentifier())
743
0
        {
744
0
            bUseSolidDragging = false;
745
0
        }
746
747
        // check for objects with no fill and no line
748
0
        if(bUseSolidDragging)
749
0
        {
750
0
            const SfxItemSet& rSet = mpCurrentCreate->GetMergedItemSet();
751
0
            const drawing::FillStyle eFill(rSet.Get(XATTR_FILLSTYLE).GetValue());
752
0
            const drawing::LineStyle eLine(rSet.Get(XATTR_LINESTYLE).GetValue());
753
754
0
            if(drawing::LineStyle_NONE == eLine && drawing::FillStyle_NONE == eFill)
755
0
            {
756
0
                bUseSolidDragging = false;
757
0
            }
758
0
        }
759
760
        // check for form controls
761
0
        if(bUseSolidDragging)
762
0
        {
763
0
            if (dynamic_cast<const SdrUnoObj*>(mpCurrentCreate.get()) != nullptr)
764
0
            {
765
0
                bUseSolidDragging = false;
766
0
            }
767
0
        }
768
769
          // #i101781# force to non-solid dragging when not creating a full circle
770
0
        if(bUseSolidDragging)
771
0
        {
772
0
            SdrCircObj* pCircObj = dynamic_cast<SdrCircObj*>(mpCurrentCreate.get());
773
774
0
            if(pCircObj && SdrObjKind::CircleOrEllipse != pCircObj->GetObjIdentifier())
775
0
            {
776
                // #i103058# Allow SolidDragging with four points
777
0
                if(maDragStat.GetPointCount() < 4)
778
0
                {
779
0
                    bUseSolidDragging = false;
780
0
                }
781
0
            }
782
0
        }
783
784
0
        if(bUseSolidDragging)
785
0
        {
786
0
            basegfx::B2DPolyPolygon aDragPolyPolygon;
787
788
0
            if (dynamic_cast<const SdrRectObj*>(mpCurrentCreate.get()) != nullptr)
789
0
            {
790
                // ensure object has some size, necessary for SdrTextObj because
791
                // there are still untested divisions by that sizes
792
0
                tools::Rectangle aCurrentSnapRect(mpCurrentCreate->GetSnapRect());
793
794
0
                if(aCurrentSnapRect.GetWidth() <= 1 || aCurrentSnapRect.GetHeight() <= 1)
795
0
                {
796
0
                    tools::Rectangle aNewRect(maDragStat.GetStart(), maDragStat.GetStart() + Point(2, 2));
797
0
                    mpCurrentCreate->NbcSetSnapRect(aNewRect);
798
0
                }
799
0
            }
800
801
0
            if (auto pPathObj = dynamic_cast<SdrPathObj*>(mpCurrentCreate.get()))
802
0
            {
803
                // The up-to-now created path needs to be set at the object to have something
804
                // that can be visualized
805
0
                const basegfx::B2DPolyPolygon aCurrentPolyPolygon(pPathObj->getObjectPolyPolygon(maDragStat));
806
807
0
                if(aCurrentPolyPolygon.count())
808
0
                {
809
0
                    pPathObj->NbcSetPathPoly(aCurrentPolyPolygon);
810
0
                }
811
812
0
                aDragPolyPolygon = pPathObj->getDragPolyPolygon(maDragStat);
813
0
            }
814
815
            // use the SdrObject directly for overlay
816
0
            mpCreateViewExtraData->CreateAndShowOverlay(*this, mpCurrentCreate.get(), aDragPolyPolygon);
817
0
        }
818
0
        else
819
0
        {
820
0
            const ::basegfx::B2DPolyPolygon aPoly(mpCurrentCreate->TakeCreatePoly(maDragStat));
821
822
0
            mpCreateViewExtraData->CreateAndShowOverlay(*this, nullptr, aPoly);
823
0
        }
824
0
    }
825
826
0
    maDragStat.SetShown(true);
827
0
}
828
829
void SdrCreateView::HideCreateObj()
830
0
{
831
0
    if(IsCreateObj() && maDragStat.IsShown())
832
0
    {
833
        // for migration from XOR, replace DrawDragObj here to create
834
        // overlay objects instead.
835
0
        mpCreateViewExtraData->HideOverlay();
836
837
        //DrawCreateObj(pOut,bFull);
838
0
        maDragStat.SetShown(false);
839
0
    }
840
0
}
841
842
843
void SdrCreateView::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const
844
0
{
845
0
    if (mpCurrentCreate)
846
0
    {
847
0
        rTargetSet.Put(mpCurrentCreate->GetMergedItemSet());
848
0
    }
849
0
    else
850
0
    {
851
0
        SdrDragView::GetAttributes(rTargetSet, bOnlyHardAttr);
852
0
    }
853
0
}
854
855
bool SdrCreateView::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll)
856
0
{
857
0
    if (mpCurrentCreate)
858
0
    {
859
0
        mpCurrentCreate->SetMergedItemSetAndBroadcast(rSet, bReplaceAll);
860
861
0
        return true;
862
0
    }
863
0
    else
864
0
    {
865
0
        return SdrDragView::SetAttributes(rSet,bReplaceAll);
866
0
    }
867
0
}
868
869
SfxStyleSheet* SdrCreateView::GetStyleSheet() const
870
0
{
871
0
    if (mpCurrentCreate != nullptr)
872
0
    {
873
0
        return mpCurrentCreate->GetStyleSheet();
874
0
    }
875
0
    else
876
0
    {
877
0
        return SdrDragView::GetStyleSheet();
878
0
    }
879
0
}
880
881
void SdrCreateView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr)
882
0
{
883
0
    if (mpCurrentCreate != nullptr)
884
0
    {
885
0
        mpCurrentCreate->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
886
0
    }
887
0
    else
888
0
    {
889
0
        SdrDragView::SetStyleSheet(pStyleSheet,bDontRemoveHardAttr);
890
0
    }
891
0
}
892
893
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */