Revert "tdf#158280 Replace usage of InputDialog with SvxNameDialog"
[LibreOffice.git] / svx / source / svdraw / svdhdl.cxx
blobaba506b0e463498546539912badd015a893693f2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <algorithm>
22 #include <cassert>
24 #include <svx/svdhdl.hxx>
25 #include <svx/svdpagv.hxx>
26 #include <svx/svdmrkv.hxx>
27 #include <utility>
28 #include <vcl/settings.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/ptrstyle.hxx>
32 #include <svx/sxekitm.hxx>
33 #include <svx/strings.hrc>
34 #include <svx/svdmodel.hxx>
35 #include "gradtrns.hxx"
36 #include <svx/xflgrit.hxx>
37 #include <svx/svdundo.hxx>
38 #include <svx/dialmgr.hxx>
39 #include <svx/xflftrit.hxx>
41 #include <svx/svdopath.hxx>
42 #include <basegfx/vector/b2dvector.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <svx/sdr/overlay/overlaymanager.hxx>
45 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
46 #include <svx/sdr/overlay/overlaybitmapex.hxx>
47 #include <sdr/overlay/overlayline.hxx>
48 #include <sdr/overlay/overlaytriangle.hxx>
49 #include <sdr/overlay/overlayhandle.hxx>
50 #include <sdr/overlay/overlayrectangle.hxx>
51 #include <svx/sdrpagewindow.hxx>
52 #include <svx/sdrpaintwindow.hxx>
53 #include <vcl/svapp.hxx>
54 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
55 #include <tools/lazydelete.hxx>
56 #include <vcl/BitmapTools.hxx>
57 #include <svx/sdr/contact/objectcontact.hxx>
58 #include <svx/sdr/contact/viewcontact.hxx>
59 #include <osl/diagnose.h>
61 #include <basegfx/polygon/b2dpolygontools.hxx>
62 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
63 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
64 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
65 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
66 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
67 #include <svtools/optionsdrawinglayer.hxx>
68 #include <memory>
69 #include <bitmaps.hlst>
71 namespace {
73 // #i15222#
74 // Due to the resource problems in Win95/98 with bitmap resources I
75 // will change this handle bitmap providing class. Old version was splitting
76 // and preparing all small handle bitmaps in device bitmap format, now this will
77 // be done on the fly. Thus, there is only one big bitmap in memory. With
78 // three source bitmaps, this will be 3 system bitmap resources instead of hundreds.
79 // The price for that needs to be evaluated. Maybe we will need another change here
80 // if this is too expensive.
81 class SdrHdlBitmapSet
83 // the bitmap holding all information
84 BitmapEx maMarkersBitmap;
86 // the cropped Bitmaps for reusage
87 ::std::vector< BitmapEx > maRealMarkers;
89 // helpers
90 BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle);
92 public:
93 explicit SdrHdlBitmapSet();
95 const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd);
100 #define KIND_COUNT (14)
101 #define INDEX_COUNT (6)
102 #define INDIVIDUAL_COUNT (5)
104 SdrHdlBitmapSet::SdrHdlBitmapSet()
105 : maMarkersBitmap(SIP_SA_MARKERS),
106 // 15 kinds (BitmapMarkerKind) use index [0..5] + 5 extra
107 maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
111 BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle)
113 BitmapEx& rTargetBitmap = maRealMarkers[nIndex];
115 if(rTargetBitmap.IsEmpty())
117 rTargetBitmap = maMarkersBitmap;
118 rTargetBitmap.Crop(rRectangle);
121 return rTargetBitmap;
124 // change getting of bitmap to use the big resource bitmap
125 const BitmapEx& SdrHdlBitmapSet::GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd)
127 // fill in size and source position in maMarkersBitmap
128 const sal_uInt16 nYPos(nInd * 11);
130 switch(eKindOfMarker)
132 default:
134 OSL_FAIL( "Unknown kind of marker." );
135 [[fallthrough]]; // return Rect_9x9 as default
137 case BitmapMarkerKind::Rect_9x9:
139 return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, tools::Rectangle(Point(7, nYPos), Size(9, 9)));
142 case BitmapMarkerKind::Rect_7x7:
144 return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, tools::Rectangle(Point(0, nYPos), Size(7, 7)));
147 case BitmapMarkerKind::Rect_11x11:
149 return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, tools::Rectangle(Point(16, nYPos), Size(11, 11)));
152 case BitmapMarkerKind::Rect_13x13:
154 const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);
156 switch(nInd)
158 case 0:
160 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 66), Size(13, 13)));
162 case 1:
164 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 66), Size(13, 13)));
166 case 2:
168 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 79), Size(13, 13)));
170 case 3:
172 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 79), Size(13, 13)));
174 case 4:
176 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 79), Size(13, 13)));
178 default: // case 5:
180 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 66), Size(13, 13)));
185 case BitmapMarkerKind::Circ_7x7:
186 case BitmapMarkerKind::Customshape_7x7:
188 return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, tools::Rectangle(Point(27, nYPos), Size(7, 7)));
191 case BitmapMarkerKind::Circ_9x9:
192 case BitmapMarkerKind::Customshape_9x9:
194 return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, tools::Rectangle(Point(34, nYPos), Size(9, 9)));
197 case BitmapMarkerKind::Circ_11x11:
198 case BitmapMarkerKind::Customshape_11x11:
200 return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, tools::Rectangle(Point(43, nYPos), Size(11, 11)));
203 case BitmapMarkerKind::Elli_7x9:
205 return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, tools::Rectangle(Point(54, nYPos), Size(7, 9)));
208 case BitmapMarkerKind::Elli_9x11:
210 return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, tools::Rectangle(Point(61, nYPos), Size(9, 11)));
213 case BitmapMarkerKind::Elli_9x7:
215 return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, tools::Rectangle(Point(70, nYPos), Size(9, 7)));
218 case BitmapMarkerKind::Elli_11x9:
220 return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, tools::Rectangle(Point(79, nYPos), Size(11, 9)));
223 case BitmapMarkerKind::RectPlus_7x7:
225 return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, tools::Rectangle(Point(90, nYPos), Size(7, 7)));
228 case BitmapMarkerKind::RectPlus_9x9:
230 return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, tools::Rectangle(Point(97, nYPos), Size(9, 9)));
233 case BitmapMarkerKind::RectPlus_11x11:
235 return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, tools::Rectangle(Point(106, nYPos), Size(11, 11)));
238 case BitmapMarkerKind::Crosshair:
240 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, tools::Rectangle(Point(0, 68), Size(15, 15)));
243 case BitmapMarkerKind::Glue:
245 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, tools::Rectangle(Point(15, 76), Size(9, 9)));
248 case BitmapMarkerKind::Glue_Deselected:
250 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, tools::Rectangle(Point(15, 67), Size(9, 9)));
253 case BitmapMarkerKind::Anchor: // AnchorTR for SW
254 case BitmapMarkerKind::AnchorTR:
256 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, tools::Rectangle(Point(24, 67), Size(24, 24)));
259 // add AnchorPressed to be able to animate anchor control
260 case BitmapMarkerKind::AnchorPressed:
261 case BitmapMarkerKind::AnchorPressedTR:
263 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, tools::Rectangle(Point(48, 67), Size(24, 24)));
269 SdrHdl::SdrHdl():
270 m_pObj(nullptr),
271 m_pPV(nullptr),
272 m_pHdlList(nullptr),
273 m_eKind(SdrHdlKind::Move),
274 m_nRotationAngle(0),
275 m_nObjHdlNum(0),
276 m_nPolyNum(0),
277 m_nPPntNum(0),
278 m_nSourceHdlNum(0),
279 m_bSelect(false),
280 m_b1PixMore(false),
281 m_bPlusHdl(false),
282 mbMoveOutside(false),
283 mbMouseOver(false)
287 SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
288 m_pObj(nullptr),
289 m_pPV(nullptr),
290 m_pHdlList(nullptr),
291 m_aPos(rPnt),
292 m_eKind(eNewKind),
293 m_nRotationAngle(0),
294 m_nObjHdlNum(0),
295 m_nPolyNum(0),
296 m_nPPntNum(0),
297 m_nSourceHdlNum(0),
298 m_bSelect(false),
299 m_b1PixMore(false),
300 m_bPlusHdl(false),
301 mbMoveOutside(false),
302 mbMouseOver(false)
306 SdrHdl::~SdrHdl()
308 GetRidOfIAObject();
311 void SdrHdl::Set1PixMore(bool bJa)
313 if(m_b1PixMore != bJa)
315 m_b1PixMore = bJa;
317 // create new display
318 Touch();
322 void SdrHdl::SetMoveOutside( bool bMoveOutside )
324 if(mbMoveOutside != bMoveOutside)
326 mbMoveOutside = bMoveOutside;
328 // create new display
329 Touch();
333 void SdrHdl::SetRotationAngle(Degree100 n)
335 if(m_nRotationAngle != n)
337 m_nRotationAngle = n;
339 // create new display
340 Touch();
344 void SdrHdl::SetPos(const Point& rPnt)
346 if(m_aPos != rPnt)
348 // remember new position
349 m_aPos = rPnt;
351 // create new display
352 Touch();
356 void SdrHdl::SetSelected(bool bJa)
358 if(m_bSelect != bJa)
360 // remember new value
361 m_bSelect = bJa;
363 // create new display
364 Touch();
368 void SdrHdl::SetHdlList(SdrHdlList* pList)
370 if(m_pHdlList != pList)
372 // remember list
373 m_pHdlList = pList;
375 // now it's possible to create graphic representation
376 Touch();
380 void SdrHdl::SetObj(SdrObject* pNewObj)
382 if(m_pObj != pNewObj)
384 // remember new object
385 m_pObj = pNewObj;
387 // graphic representation may have changed
388 Touch();
392 void SdrHdl::Touch()
394 // force update of graphic representation
395 CreateB2dIAObject();
398 void SdrHdl::GetRidOfIAObject()
401 // OVERLAYMANAGER
402 maOverlayGroup.clear();
405 void SdrHdl::CreateB2dIAObject()
407 // first throw away old one
408 GetRidOfIAObject();
410 if(!m_pHdlList || !m_pHdlList->GetView() || m_pHdlList->GetView()->areMarkHandlesHidden())
411 return;
413 BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
414 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
416 bool bRot = m_pHdlList->IsRotateShear();
417 if(m_pObj)
418 eColIndex = m_bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
419 if(bRot)
421 // red rotation handles
422 if(m_pObj && m_bSelect)
423 eColIndex = BitmapColorIndex::Red;
424 else
425 eColIndex = BitmapColorIndex::LightRed;
428 switch(m_eKind)
430 case SdrHdlKind::Move:
432 eKindOfMarker = m_b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
433 break;
435 case SdrHdlKind::UpperLeft:
436 case SdrHdlKind::UpperRight:
437 case SdrHdlKind::LowerLeft:
438 case SdrHdlKind::LowerRight:
440 // corner handles
441 if(bRot)
443 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
445 else
447 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
449 break;
451 case SdrHdlKind::Upper:
452 case SdrHdlKind::Lower:
454 // Upper/Lower handles
455 if(bRot)
457 eKindOfMarker = BitmapMarkerKind::Elli_9x7;
459 else
461 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
463 break;
465 case SdrHdlKind::Left:
466 case SdrHdlKind::Right:
468 // Left/Right handles
469 if(bRot)
471 eKindOfMarker = BitmapMarkerKind::Elli_7x9;
473 else
475 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
477 break;
479 case SdrHdlKind::Poly:
481 if(bRot)
483 eKindOfMarker = m_b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
485 else
487 eKindOfMarker = m_b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
489 break;
491 case SdrHdlKind::BezierWeight: // weight at poly
493 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
494 break;
496 case SdrHdlKind::Circle:
498 eKindOfMarker = BitmapMarkerKind::Rect_11x11;
499 break;
501 case SdrHdlKind::Ref1:
502 case SdrHdlKind::Ref2:
504 eKindOfMarker = BitmapMarkerKind::Crosshair;
505 break;
507 case SdrHdlKind::Glue:
509 eKindOfMarker = BitmapMarkerKind::Glue;
510 break;
512 case SdrHdlKind::Anchor:
514 eKindOfMarker = BitmapMarkerKind::Anchor;
515 break;
517 case SdrHdlKind::User:
519 break;
521 // top right anchor for SW
522 case SdrHdlKind::Anchor_TR:
524 eKindOfMarker = BitmapMarkerKind::AnchorTR;
525 break;
528 // for SJ and the CustomShapeHandles:
529 case SdrHdlKind::CustomShape1:
531 eKindOfMarker = m_b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
532 eColIndex = BitmapColorIndex::Yellow;
533 break;
535 default:
536 break;
539 SdrMarkView* pView = m_pHdlList->GetView();
540 SdrPageView* pPageView = pView->GetSdrPageView();
542 if(!pPageView)
543 return;
545 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
547 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
548 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
550 if(rPageWindow.GetPaintWindow().OutputToWindow())
552 Point aMoveOutsideOffset(0, 0);
553 OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
555 // add offset if necessary
556 if(m_pHdlList->IsMoveOutside() || mbMoveOutside)
558 Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
560 if(m_eKind == SdrHdlKind::UpperLeft || m_eKind == SdrHdlKind::Upper || m_eKind == SdrHdlKind::UpperRight)
561 aMoveOutsideOffset.AdjustY( -(aOffset.Width()) );
562 if(m_eKind == SdrHdlKind::LowerLeft || m_eKind == SdrHdlKind::Lower || m_eKind == SdrHdlKind::LowerRight)
563 aMoveOutsideOffset.AdjustY(aOffset.Height() );
564 if(m_eKind == SdrHdlKind::UpperLeft || m_eKind == SdrHdlKind::Left || m_eKind == SdrHdlKind::LowerLeft)
565 aMoveOutsideOffset.AdjustX( -(aOffset.Width()) );
566 if(m_eKind == SdrHdlKind::UpperRight || m_eKind == SdrHdlKind::Right || m_eKind == SdrHdlKind::LowerRight)
567 aMoveOutsideOffset.AdjustX(aOffset.Height() );
570 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
571 if (xManager.is())
573 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
574 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject;
575 if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker == BitmapMarkerKind::Rect_7x7 || eKindOfMarker == BitmapMarkerKind::Rect_9x9 || eKindOfMarker == BitmapMarkerKind::Rect_11x11))
577 double fSize = 7.0;
578 switch (eKindOfMarker)
580 case BitmapMarkerKind::Rect_9x9:
581 fSize = 9.0;
582 break;
583 case BitmapMarkerKind::Rect_11x11:
584 fSize = 11.0;
585 break;
586 default:
587 break;
589 float fScalingFactor = rOutDev.GetDPIScaleFactor();
590 basegfx::B2DSize aB2DSize(fSize * fScalingFactor, fSize * fScalingFactor);
592 Color aHandleFillColor(COL_LIGHTGREEN);
593 switch (eColIndex)
595 case BitmapColorIndex::Cyan:
596 aHandleFillColor = COL_CYAN;
597 break;
598 case BitmapColorIndex::LightCyan:
599 aHandleFillColor = COL_LIGHTCYAN;
600 break;
601 case BitmapColorIndex::Red:
602 aHandleFillColor = COL_RED;
603 break;
604 case BitmapColorIndex::LightRed:
605 aHandleFillColor = COL_LIGHTRED;
606 break;
607 case BitmapColorIndex::Yellow:
608 aHandleFillColor = COL_YELLOW;
609 break;
610 default:
611 break;
613 pNewOverlayObject.reset(new sdr::overlay::OverlayHandle(aPosition, aB2DSize, /*HandleStrokeColor*/COL_BLACK, aHandleFillColor));
615 else
617 pNewOverlayObject = CreateOverlayObject(
618 aPosition, eColIndex, eKindOfMarker,
619 aMoveOutsideOffset);
622 // OVERLAYMANAGER
623 insertNewlyCreatedOverlayObjectForSdrHdl(
624 std::move(pNewOverlayObject),
625 rPageWindow.GetObjectContact(),
626 *xManager);
632 BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd)
634 BitmapMarkerKind eRetval(eKnd);
636 switch(eKnd)
638 case BitmapMarkerKind::Rect_7x7: eRetval = BitmapMarkerKind::Rect_9x9; break;
639 case BitmapMarkerKind::Rect_9x9: eRetval = BitmapMarkerKind::Rect_11x11; break;
640 case BitmapMarkerKind::Rect_11x11: eRetval = BitmapMarkerKind::Rect_13x13; break;
642 case BitmapMarkerKind::Circ_7x7: eRetval = BitmapMarkerKind::Circ_9x9; break;
643 case BitmapMarkerKind::Circ_9x9: eRetval = BitmapMarkerKind::Circ_11x11; break;
645 case BitmapMarkerKind::Customshape_7x7: eRetval = BitmapMarkerKind::Customshape_9x9; break;
646 case BitmapMarkerKind::Customshape_9x9: eRetval = BitmapMarkerKind::Customshape_11x11; break;
647 //case BitmapMarkerKind::Customshape_11x11: eRetval = ; break;
649 case BitmapMarkerKind::Elli_7x9: eRetval = BitmapMarkerKind::Elli_9x11; break;
651 case BitmapMarkerKind::Elli_9x7: eRetval = BitmapMarkerKind::Elli_11x9; break;
653 case BitmapMarkerKind::RectPlus_7x7: eRetval = BitmapMarkerKind::RectPlus_9x9; break;
654 case BitmapMarkerKind::RectPlus_9x9: eRetval = BitmapMarkerKind::RectPlus_11x11; break;
656 // let anchor blink with its pressed state
657 case BitmapMarkerKind::Anchor: eRetval = BitmapMarkerKind::AnchorPressed; break;
659 // same for AnchorTR
660 case BitmapMarkerKind::AnchorTR: eRetval = BitmapMarkerKind::AnchorPressedTR; break;
661 default:
662 break;
665 return eRetval;
668 namespace
671 OUString appendMarkerName(BitmapMarkerKind eKindOfMarker)
673 switch(eKindOfMarker)
675 case BitmapMarkerKind::Rect_7x7:
676 return u"rect7"_ustr;
677 case BitmapMarkerKind::Rect_9x9:
678 return u"rect9"_ustr;
679 case BitmapMarkerKind::Rect_11x11:
680 return u"rect11"_ustr;
681 case BitmapMarkerKind::Rect_13x13:
682 return u"rect13"_ustr;
683 case BitmapMarkerKind::Circ_7x7:
684 case BitmapMarkerKind::Customshape_7x7:
685 return u"circ7"_ustr;
686 case BitmapMarkerKind::Circ_9x9:
687 case BitmapMarkerKind::Customshape_9x9:
688 return u"circ9"_ustr;
689 case BitmapMarkerKind::Circ_11x11:
690 case BitmapMarkerKind::Customshape_11x11:
691 return u"circ11"_ustr;
692 case BitmapMarkerKind::Elli_7x9:
693 return u"elli7x9"_ustr;
694 case BitmapMarkerKind::Elli_9x11:
695 return u"elli9x11"_ustr;
696 case BitmapMarkerKind::Elli_9x7:
697 return u"elli9x7"_ustr;
698 case BitmapMarkerKind::Elli_11x9:
699 return u"elli11x9"_ustr;
700 case BitmapMarkerKind::RectPlus_7x7:
701 return u"rectplus7"_ustr;
702 case BitmapMarkerKind::RectPlus_9x9:
703 return u"rectplus9"_ustr;
704 case BitmapMarkerKind::RectPlus_11x11:
705 return u"rectplus11"_ustr;
706 case BitmapMarkerKind::Crosshair:
707 return u"cross"_ustr;
708 case BitmapMarkerKind::Anchor:
709 case BitmapMarkerKind::AnchorTR:
710 return u"anchor"_ustr;
711 case BitmapMarkerKind::AnchorPressed:
712 case BitmapMarkerKind::AnchorPressedTR:
713 return u"anchor-pressed"_ustr;
714 case BitmapMarkerKind::Glue:
715 return u"glue-selected"_ustr;
716 case BitmapMarkerKind::Glue_Deselected:
717 return u"glue-unselected"_ustr;
718 default:
719 break;
721 return OUString();
724 OUString appendMarkerColor(BitmapColorIndex eIndex)
726 switch(eIndex)
728 case BitmapColorIndex::LightGreen:
729 return u"1"_ustr;
730 case BitmapColorIndex::Cyan:
731 return u"2"_ustr;
732 case BitmapColorIndex::LightCyan:
733 return u"3"_ustr;
734 case BitmapColorIndex::Red:
735 return u"4"_ustr;
736 case BitmapColorIndex::LightRed:
737 return u"5"_ustr;
738 case BitmapColorIndex::Yellow:
739 return u"6"_ustr;
740 default:
741 break;
743 return OUString();
746 BitmapEx ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, BitmapColorIndex eIndex)
748 // use this code path only when we use HiDPI (for now)
749 if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
751 OUString sMarkerName = appendMarkerName(eKindOfMarker);
752 if (!sMarkerName.isEmpty())
754 OUString sMarkerPrefix(u"svx/res/marker-"_ustr);
755 BitmapEx aBitmapEx;
757 if (eKindOfMarker == BitmapMarkerKind::Crosshair
758 || eKindOfMarker == BitmapMarkerKind::Anchor
759 || eKindOfMarker == BitmapMarkerKind::AnchorTR
760 || eKindOfMarker == BitmapMarkerKind::AnchorPressed
761 || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR
762 || eKindOfMarker == BitmapMarkerKind::Glue
763 || eKindOfMarker == BitmapMarkerKind::Glue_Deselected)
765 aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + ".png");
767 else
769 aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + "-" + appendMarkerColor(eIndex) + ".png");
772 if (!aBitmapEx.IsEmpty())
773 return aBitmapEx;
777 // if we can't load the marker...
779 static tools::DeleteOnDeinit< SdrHdlBitmapSet > aModernSet {};
780 return aModernSet.get()->GetBitmapEx(eKindOfMarker, sal_uInt16(eIndex));
783 } // end anonymous namespace
785 std::unique_ptr<sdr::overlay::OverlayObject> SdrHdl::CreateOverlayObject(
786 const basegfx::B2DPoint& rPos,
787 BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
789 std::unique_ptr<sdr::overlay::OverlayObject> pRetval;
791 // support bigger sizes
792 bool bForceBiggerSize(false);
794 if (m_pHdlList && m_pHdlList->GetHdlSize() > 3)
796 switch(eKindOfMarker)
798 case BitmapMarkerKind::Anchor:
799 case BitmapMarkerKind::AnchorPressed:
800 case BitmapMarkerKind::AnchorTR:
801 case BitmapMarkerKind::AnchorPressedTR:
803 // #i121463# For anchor, do not simply make bigger because of HdlSize,
804 // do it dependent of IsSelected() which Writer can set in drag mode
805 if(IsSelected())
807 bForceBiggerSize = true;
809 break;
811 default:
813 bForceBiggerSize = true;
814 break;
819 if(bForceBiggerSize)
821 eKindOfMarker = GetNextBigger(eKindOfMarker);
824 // This handle has the focus, visualize it
825 if(IsFocusHdl() && m_pHdlList && m_pHdlList->GetFocusHdl() == this)
827 // create animated handle
828 BitmapMarkerKind eNextBigger = GetNextBigger(eKindOfMarker);
830 if(eNextBigger == eKindOfMarker)
832 // this may happen for the not supported getting-bigger types.
833 // Choose an alternative here
834 switch(eKindOfMarker)
836 case BitmapMarkerKind::Rect_13x13: eNextBigger = BitmapMarkerKind::Rect_11x11; break;
837 case BitmapMarkerKind::Circ_11x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
838 case BitmapMarkerKind::Elli_9x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
839 case BitmapMarkerKind::Elli_11x9: eNextBigger = BitmapMarkerKind::Elli_9x11; break;
840 case BitmapMarkerKind::RectPlus_11x11: eNextBigger = BitmapMarkerKind::Rect_13x13; break;
841 case BitmapMarkerKind::Glue:
842 eNextBigger = BitmapMarkerKind::Crosshair;
843 break;
844 case BitmapMarkerKind::Crosshair:
845 case BitmapMarkerKind::Glue_Deselected:
846 eNextBigger = BitmapMarkerKind::Glue;
847 break;
848 default:
849 break;
853 // create animated handle
854 BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, eColIndex);
855 BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, eColIndex);
857 // #i53216# Use system cursor blink time. Use the unsigned value.
858 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
859 const sal_uInt64 nBlinkTime(rStyleSettings.GetCursorBlinkTime());
861 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
863 // when anchor is used take upper left as reference point inside the handle
864 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime));
866 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
868 // AnchorTR for SW, take top right as (0,0)
869 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
870 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1), 0,
871 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1), 0));
873 else
875 // create centered handle as default
876 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
877 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
878 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
879 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
880 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1));
883 else
885 // create normal handle: use ImpGetBitmapEx(...) now
886 BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, eColIndex);
888 // When the image with handles is not found, the bitmap returned is
889 // empty. This is a problem when we use LibreOffice as a library
890 // (through LOKit - for example on Android) even when we don't show
891 // the handles, because the hit test would always return false.
893 // This HACK replaces the empty bitmap with a black 13x13 bitmap handle
894 // so that the hit test works for this case.
895 if (aBmpEx.IsEmpty())
897 aBmpEx = BitmapEx(Size(13, 13), vcl::PixelFormat::N24_BPP);
898 aBmpEx.Erase(COL_BLACK);
901 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
903 // upper left as reference point inside the handle for AnchorPressed, too
904 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx));
906 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
908 // AnchorTR for SW, take top right as (0,0)
909 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
910 static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1), 0));
912 else
914 sal_uInt16 nCenX(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1) >> 1);
915 sal_uInt16 nCenY(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1) >> 1);
917 if(aMoveOutsideOffset.X() > 0)
919 nCenX = 0;
921 else if(aMoveOutsideOffset.X() < 0)
923 nCenX = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1);
926 if(aMoveOutsideOffset.Y() > 0)
928 nCenY = 0;
930 else if(aMoveOutsideOffset.Y() < 0)
932 nCenY = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1);
935 // create centered handle as default
936 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx, nCenX, nCenY));
940 return pRetval;
943 bool SdrHdl::IsHdlHit(const Point& rPnt) const
945 // OVERLAYMANAGER
946 basegfx::B2DPoint aPosition(rPnt.X(), rPnt.Y());
947 return maOverlayGroup.isHitLogic(aPosition);
950 PointerStyle SdrHdl::GetPointer() const
952 PointerStyle ePtr=PointerStyle::Move;
953 const bool bSize=m_eKind>=SdrHdlKind::UpperLeft && m_eKind<=SdrHdlKind::LowerRight;
954 const bool bRot=m_pHdlList!=nullptr && m_pHdlList->IsRotateShear();
955 const bool bDis=m_pHdlList!=nullptr && m_pHdlList->IsDistortShear();
956 if (bSize && m_pHdlList!=nullptr && (bRot || bDis)) {
957 switch (m_eKind) {
958 case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
959 case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight: ePtr=bRot ? PointerStyle::Rotate : PointerStyle::RefHand; break;
960 case SdrHdlKind::Left : case SdrHdlKind::Right: ePtr=PointerStyle::VShear; break;
961 case SdrHdlKind::Upper: case SdrHdlKind::Lower: ePtr=PointerStyle::HShear; break;
962 default:
963 break;
965 } else {
966 // When resizing rotated rectangles, rotate the mouse cursor slightly, too
967 if (bSize && m_nRotationAngle!=0_deg100) {
968 Degree100 nHdlAngle(0);
969 switch (m_eKind) {
970 case SdrHdlKind::LowerRight: nHdlAngle=31500_deg100; break;
971 case SdrHdlKind::Lower: nHdlAngle=27000_deg100; break;
972 case SdrHdlKind::LowerLeft: nHdlAngle=22500_deg100; break;
973 case SdrHdlKind::Left : nHdlAngle=18000_deg100; break;
974 case SdrHdlKind::UpperLeft: nHdlAngle=13500_deg100; break;
975 case SdrHdlKind::Upper: nHdlAngle=9000_deg100; break;
976 case SdrHdlKind::UpperRight: nHdlAngle=4500_deg100; break;
977 case SdrHdlKind::Right: nHdlAngle=0_deg100; break;
978 default:
979 break;
981 // a little bit more (for rounding)
982 nHdlAngle = NormAngle36000(nHdlAngle + m_nRotationAngle + 2249_deg100);
983 nHdlAngle/=4500_deg100;
984 switch (static_cast<sal_uInt8>(nHdlAngle.get())) {
985 case 0: ePtr=PointerStyle::ESize; break;
986 case 1: ePtr=PointerStyle::NESize; break;
987 case 2: ePtr=PointerStyle::NSize; break;
988 case 3: ePtr=PointerStyle::NWSize; break;
989 case 4: ePtr=PointerStyle::WSize; break;
990 case 5: ePtr=PointerStyle::SWSize; break;
991 case 6: ePtr=PointerStyle::SSize; break;
992 case 7: ePtr=PointerStyle::SESize; break;
993 } // switch
994 } else {
995 switch (m_eKind) {
996 case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
997 case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
998 case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
999 case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
1000 case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
1001 case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
1002 case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
1003 case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
1004 case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
1005 case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
1006 case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
1007 case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
1008 case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
1009 case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
1010 case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::RefHand; break;
1011 default:
1012 break;
1016 return ePtr;
1019 bool SdrHdl::IsFocusHdl() const
1021 switch(m_eKind)
1023 case SdrHdlKind::UpperLeft:
1024 case SdrHdlKind::Upper:
1025 case SdrHdlKind::UpperRight:
1026 case SdrHdlKind::Left:
1027 case SdrHdlKind::Right:
1028 case SdrHdlKind::LowerLeft:
1029 case SdrHdlKind::Lower:
1030 case SdrHdlKind::LowerRight:
1032 // if it's an activated TextEdit, it's moved to extended points
1033 return !m_pHdlList || !m_pHdlList->IsMoveOutside();
1036 case SdrHdlKind::Move: // handle to move object
1037 case SdrHdlKind::Poly: // selected point of polygon or curve
1038 case SdrHdlKind::BezierWeight: // weight at a curve
1039 case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
1040 case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
1041 case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
1042 case SdrHdlKind::Glue: // gluepoint
1044 // for SJ and the CustomShapeHandles:
1045 case SdrHdlKind::CustomShape1:
1047 case SdrHdlKind::User:
1049 return true;
1052 default:
1054 return false;
1059 void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
1063 void SdrHdl::onHelpRequest()
1067 void SdrHdl::onMouseLeave()
1071 BitmapEx SdrHdl::createGluePointBitmap()
1073 return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
1076 void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
1077 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
1078 const sdr::contact::ObjectContact& rObjectContact,
1079 sdr::overlay::OverlayManager& rOverlayManager)
1081 // check if we have an OverlayObject
1082 if(!pOverlayObject)
1084 return;
1087 // Add GridOffset for non-linear ViewToDevice transformation (calc)
1088 if(nullptr != GetObj() && rObjectContact.supportsGridOffsets())
1090 basegfx::B2DVector aOffset(0.0, 0.0);
1091 const sdr::contact::ViewObjectContact& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
1092 const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
1094 rObjectContact.calculateGridOffsetForViewObjectContact(aOffset, rVOC);
1096 if(!aOffset.equalZero())
1098 pOverlayObject->setOffset(aOffset);
1102 // add to OverlayManager
1103 rOverlayManager.add(*pOverlayObject);
1105 // add to local OverlayObjectList - ownership change (!)
1106 maOverlayGroup.append(std::move(pOverlayObject));
1109 SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
1110 : SdrHdl(rRef, SdrHdlKind::Color),
1111 m_aMarkerSize(rSize),
1112 m_bUseLuminance(bLum)
1114 if(IsUseLuminance())
1115 aCol = GetLuminance(aCol);
1117 // remember color
1118 m_aMarkerColor = aCol;
1121 SdrHdlColor::~SdrHdlColor()
1125 void SdrHdlColor::CreateB2dIAObject()
1127 // first throw away old one
1128 GetRidOfIAObject();
1130 if(!m_pHdlList)
1131 return;
1133 SdrMarkView* pView = m_pHdlList->GetView();
1135 if(!pView || pView->areMarkHandlesHidden())
1136 return;
1138 SdrPageView* pPageView = pView->GetSdrPageView();
1140 if(!pPageView)
1141 return;
1143 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1145 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1147 if(rPageWindow.GetPaintWindow().OutputToWindow())
1149 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1150 if (xManager.is())
1152 BitmapEx aBmpCol(CreateColorDropper(m_aMarkerColor));
1153 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
1154 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1155 sdr::overlay::OverlayBitmapEx(
1156 aPosition,
1157 aBmpCol,
1158 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Width() - 1) >> 1,
1159 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Height() - 1) >> 1
1162 // OVERLAYMANAGER
1163 insertNewlyCreatedOverlayObjectForSdrHdl(
1164 std::move(pNewOverlayObject),
1165 rPageWindow.GetObjectContact(),
1166 *xManager);
1172 BitmapEx SdrHdlColor::CreateColorDropper(Color aCol)
1174 // get the Bitmap
1175 VclPtr<VirtualDevice> pWrite(VclPtr<VirtualDevice>::Create());
1176 pWrite->SetOutputSizePixel(m_aMarkerSize);
1177 pWrite->SetBackground(aCol);
1178 pWrite->Erase();
1180 // draw outer border
1181 sal_Int32 nWidth = m_aMarkerSize.Width();
1182 sal_Int32 nHeight = m_aMarkerSize.Height();
1184 pWrite->SetLineColor(COL_LIGHTGRAY);
1185 pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
1186 pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
1187 pWrite->SetLineColor(COL_GRAY);
1188 pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
1189 pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
1191 // draw lighter UpperLeft
1192 const Color aLightColor(
1193 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1194 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1195 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
1196 pWrite->SetLineColor(aLightColor);
1197 pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
1198 pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
1200 // draw darker LowerRight
1201 const Color aDarkColor(
1202 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1203 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1204 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
1205 pWrite->SetLineColor(aDarkColor);
1206 pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
1207 pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
1209 return pWrite->GetBitmapEx(Point(0,0), m_aMarkerSize);
1212 Color SdrHdlColor::GetLuminance(const Color& rCol)
1214 sal_uInt8 aLum = rCol.GetLuminance();
1215 Color aRetval(aLum, aLum, aLum);
1216 return aRetval;
1219 void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
1221 if(IsUseLuminance())
1222 aNew = GetLuminance(aNew);
1224 if(m_aMarkerColor != aNew)
1226 // remember new color
1227 m_aMarkerColor = aNew;
1229 // create new display
1230 Touch();
1232 // tell about change
1233 if(bCallLink)
1234 m_aColorChangeHdl.Call(this);
1238 void SdrHdlColor::SetSize(const Size& rNew)
1240 if(rNew != m_aMarkerSize)
1242 // remember new size
1243 m_aMarkerSize = rNew;
1245 // create new display
1246 Touch();
1250 SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
1251 : SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
1252 , m_pColHdl1(nullptr)
1253 , m_pColHdl2(nullptr)
1254 , m_a2ndPos(rRef2)
1255 , m_bGradient(bGrad)
1256 , m_bMoveSingleHandle(false)
1257 , m_bMoveFirstHandle(false)
1261 SdrHdlGradient::~SdrHdlGradient()
1265 void SdrHdlGradient::Set2ndPos(const Point& rPnt)
1267 if(m_a2ndPos != rPnt)
1269 // remember new position
1270 m_a2ndPos = rPnt;
1272 // create new display
1273 Touch();
1277 void SdrHdlGradient::CreateB2dIAObject()
1279 // first throw away old one
1280 GetRidOfIAObject();
1282 if(!m_pHdlList)
1283 return;
1285 SdrMarkView* pView = m_pHdlList->GetView();
1287 if(!pView || pView->areMarkHandlesHidden())
1288 return;
1290 SdrPageView* pPageView = pView->GetSdrPageView();
1292 if(!pPageView)
1293 return;
1295 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1297 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1299 if(rPageWindow.GetPaintWindow().OutputToWindow())
1301 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1302 if (xManager.is())
1304 // striped line in between
1305 basegfx::B2DVector aVec(m_a2ndPos.X() - m_aPos.X(), m_a2ndPos.Y() - m_aPos.Y());
1306 double fVecLen = aVec.getLength();
1307 double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
1308 double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
1309 aVec.normalize();
1310 basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
1311 sal_Int32 nMidX = static_cast<sal_Int32>(m_aPos.X() + aVec.getX() * fLongPercentArrow);
1312 sal_Int32 nMidY = static_cast<sal_Int32>(m_aPos.Y() + aVec.getY() * fLongPercentArrow);
1313 Point aMidPoint(nMidX, nMidY);
1315 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
1316 basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
1318 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1319 sdr::overlay::OverlayLineStriped(
1320 aPosition, aMidPos
1323 pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
1325 // OVERLAYMANAGER
1326 insertNewlyCreatedOverlayObjectForSdrHdl(
1327 std::move(pNewOverlayObject),
1328 rPageWindow.GetObjectContact(),
1329 *xManager);
1331 // arrowhead
1332 Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1333 aMidPoint.Y() + static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1334 Point aRight(aMidPoint.X() - static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1335 aMidPoint.Y() - static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1337 basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
1338 basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
1339 basegfx::B2DPoint aPosition2(m_a2ndPos.X(), m_a2ndPos.Y());
1341 pNewOverlayObject.reset(new
1342 sdr::overlay::OverlayTriangle(
1343 aPositionLeft,
1344 aPosition2,
1345 aPositionRight,
1346 IsGradient() ? COL_BLACK : COL_BLUE
1349 // OVERLAYMANAGER
1350 insertNewlyCreatedOverlayObjectForSdrHdl(
1351 std::move(pNewOverlayObject),
1352 rPageWindow.GetObjectContact(),
1353 *xManager);
1359 IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
1361 if(GetObj())
1362 FromIAOToItem(GetObj(), true, true);
1365 void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
1367 // from IAO positions and colors to gradient
1368 const SfxItemSet& rSet = _pObj->GetMergedItemSet();
1370 GradTransGradient aOldGradTransGradient;
1371 GradTransGradient aGradTransGradient;
1372 GradTransVector aGradTransVector;
1374 aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
1375 aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
1376 if(m_pColHdl1)
1377 aGradTransVector.aCol1 = m_pColHdl1->GetColor();
1378 if(m_pColHdl2)
1379 aGradTransVector.aCol2 = m_pColHdl2->GetColor();
1381 if(IsGradient())
1382 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1383 else
1384 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1386 // transform vector data to gradient
1387 GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, m_bMoveSingleHandle, m_bMoveFirstHandle);
1389 if(bSetItemOnObject)
1391 SdrModel& rModel(_pObj->getSdrModelFromSdrObject());
1392 SfxItemSet aNewSet(rModel.GetItemPool());
1393 const OUString aString;
1395 if(IsGradient())
1397 XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
1398 aNewSet.Put(aNewGradItem);
1400 else
1402 XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
1403 aNewSet.Put(aNewTransItem);
1406 if(bUndo && rModel.IsUndoEnabled())
1408 rModel.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
1409 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
1410 rModel.EndUndo();
1413 m_pObj->SetMergedItemSetAndBroadcast(aNewSet);
1416 // back transformation, set values on pIAOHandle
1417 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
1419 SetPos({ basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getX()),
1420 basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getY()) });
1421 Set2ndPos({ basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getX()),
1422 basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getY()) });
1423 if(m_pColHdl1)
1425 m_pColHdl1->SetPos({ basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getX()),
1426 basegfx::fround<tools::Long>(aGradTransVector.maPositionA.getY()) });
1427 m_pColHdl1->SetColor(aGradTransVector.aCol1);
1429 if(m_pColHdl2)
1431 m_pColHdl2->SetPos({ basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getX()),
1432 basegfx::fround<tools::Long>(aGradTransVector.maPositionB.getY()) });
1433 m_pColHdl2->SetColor(aGradTransVector.aCol2);
1438 SdrHdlLine::~SdrHdlLine() {}
1440 void SdrHdlLine::CreateB2dIAObject()
1442 // first throw away old one
1443 GetRidOfIAObject();
1445 if(!m_pHdlList)
1446 return;
1448 SdrMarkView* pView = m_pHdlList->GetView();
1450 if(!(pView && !pView->areMarkHandlesHidden() && m_pHdl1 && m_pHdl2))
1451 return;
1453 SdrPageView* pPageView = pView->GetSdrPageView();
1455 if(!pPageView)
1456 return;
1458 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1460 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1462 if(rPageWindow.GetPaintWindow().OutputToWindow())
1464 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1465 if (xManager.is())
1467 basegfx::B2DPoint aPosition1(m_pHdl1->GetPos().X(), m_pHdl1->GetPos().Y());
1468 basegfx::B2DPoint aPosition2(m_pHdl2->GetPos().X(), m_pHdl2->GetPos().Y());
1470 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1471 sdr::overlay::OverlayLineStriped(
1472 aPosition1,
1473 aPosition2
1476 // color(?)
1477 pNewOverlayObject->setBaseColor(COL_LIGHTRED);
1479 // OVERLAYMANAGER
1480 insertNewlyCreatedOverlayObjectForSdrHdl(
1481 std::move(pNewOverlayObject),
1482 rPageWindow.GetObjectContact(),
1483 *xManager);
1489 PointerStyle SdrHdlLine::GetPointer() const
1491 return PointerStyle::RefHand;
1495 SdrHdlBezWgt::~SdrHdlBezWgt() {}
1497 void SdrHdlBezWgt::CreateB2dIAObject()
1499 // call parent
1500 SdrHdl::CreateB2dIAObject();
1502 // create lines
1503 if(!m_pHdlList)
1504 return;
1506 SdrMarkView* pView = m_pHdlList->GetView();
1508 if(!pView || pView->areMarkHandlesHidden())
1509 return;
1511 SdrPageView* pPageView = pView->GetSdrPageView();
1513 if(!pPageView)
1514 return;
1516 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1518 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1520 if(rPageWindow.GetPaintWindow().OutputToWindow())
1522 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1523 if (xManager.is())
1525 basegfx::B2DPoint aPosition1(m_pHdl1->GetPos().X(), m_pHdl1->GetPos().Y());
1526 basegfx::B2DPoint aPosition2(m_aPos.X(), m_aPos.Y());
1528 if(!aPosition1.equal(aPosition2))
1530 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1531 sdr::overlay::OverlayLineStriped(
1532 aPosition1,
1533 aPosition2
1536 // line part is not hittable
1537 pNewOverlayObject->setHittable(false);
1539 // color(?)
1540 pNewOverlayObject->setBaseColor(COL_LIGHTBLUE);
1542 // OVERLAYMANAGER
1543 insertNewlyCreatedOverlayObjectForSdrHdl(
1544 std::move(pNewOverlayObject),
1545 rPageWindow.GetObjectContact(),
1546 *xManager);
1554 E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon& rWireframePoly)
1556 m_aWireframePoly = rWireframePoly;
1559 void E3dVolumeMarker::CreateB2dIAObject()
1561 // create lines
1562 if(!m_pHdlList)
1563 return;
1565 SdrMarkView* pView = m_pHdlList->GetView();
1567 if(!pView || pView->areMarkHandlesHidden())
1568 return;
1570 SdrPageView* pPageView = pView->GetSdrPageView();
1572 if(!pPageView)
1573 return;
1575 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1577 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1579 if(rPageWindow.GetPaintWindow().OutputToWindow())
1581 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1582 if (xManager.is() && m_aWireframePoly.count())
1584 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1585 sdr::overlay::OverlayPolyPolygonStripedAndFilled(
1586 m_aWireframePoly));
1588 pNewOverlayObject->setBaseColor(COL_BLACK);
1590 // OVERLAYMANAGER
1591 insertNewlyCreatedOverlayObjectForSdrHdl(
1592 std::move(pNewOverlayObject),
1593 rPageWindow.GetObjectContact(),
1594 *xManager);
1601 ImpEdgeHdl::~ImpEdgeHdl()
1605 void ImpEdgeHdl::CreateB2dIAObject()
1607 if(m_nObjHdlNum > 1 || !m_pObj)
1609 // call parent
1610 SdrHdl::CreateB2dIAObject();
1611 return;
1614 // first throw away old one
1615 GetRidOfIAObject();
1617 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1618 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1620 if(!m_pHdlList)
1621 return;
1623 SdrMarkView* pView = m_pHdlList->GetView();
1625 if(!pView || pView->areMarkHandlesHidden())
1626 return;
1628 // tdf#159666 Crash when table and line object are selected at the same time
1629 auto pEdge = dynamic_cast<SdrEdgeObj*>(m_pObj);
1630 if (!pEdge)
1631 return;
1633 if(pEdge->GetConnectedNode(m_nObjHdlNum == 0) != nullptr)
1634 eColIndex = BitmapColorIndex::LightRed;
1636 if(m_nPPntNum < 2)
1638 // Handle with plus sign inside
1639 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
1642 SdrPageView* pPageView = pView->GetSdrPageView();
1643 if(!pPageView)
1644 return;
1646 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1648 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1650 if(rPageWindow.GetPaintWindow().OutputToWindow())
1652 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1653 if (xManager.is())
1655 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
1656 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1657 aPosition,
1658 eColIndex,
1659 eKindOfMarker));
1661 // OVERLAYMANAGER
1662 insertNewlyCreatedOverlayObjectForSdrHdl(
1663 std::move(pNewOverlayObject),
1664 rPageWindow.GetObjectContact(),
1665 *xManager);
1671 void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
1673 if(m_eLineCode != eCode)
1675 // remember new value
1676 m_eLineCode = eCode;
1678 // create new display
1679 Touch();
1683 PointerStyle ImpEdgeHdl::GetPointer() const
1685 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( m_pObj );
1686 if (pEdge==nullptr)
1687 return SdrHdl::GetPointer();
1688 if (m_nObjHdlNum<=1)
1689 return PointerStyle::MovePoint;
1690 if (IsHorzDrag())
1691 return PointerStyle::ESize;
1692 else
1693 return PointerStyle::SSize;
1696 bool ImpEdgeHdl::IsHorzDrag() const
1698 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( m_pObj );
1699 if (pEdge==nullptr)
1700 return false;
1701 if (m_nObjHdlNum<=1)
1702 return false;
1704 SdrEdgeKind eEdgeKind = pEdge->GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1706 const SdrEdgeInfoRec& rInfo=pEdge->m_aEdgeInfo;
1707 if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
1709 return !rInfo.ImpIsHorzLine(m_eLineCode,*pEdge->m_pEdgeTrack);
1711 else if (eEdgeKind==SdrEdgeKind::ThreeLines)
1713 tools::Long nAngle=m_nObjHdlNum==2 ? rInfo.m_nAngle1 : rInfo.m_nAngle2;
1714 return nAngle==0 || nAngle==18000;
1716 return false;
1720 ImpMeasureHdl::~ImpMeasureHdl()
1724 void ImpMeasureHdl::CreateB2dIAObject()
1726 // first throw away old one
1727 GetRidOfIAObject();
1729 if(!m_pHdlList)
1730 return;
1732 SdrMarkView* pView = m_pHdlList->GetView();
1734 if(!pView || pView->areMarkHandlesHidden())
1735 return;
1737 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1738 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
1740 if(m_nObjHdlNum > 1)
1742 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1745 if(m_bSelect)
1747 eColIndex = BitmapColorIndex::Cyan;
1750 SdrPageView* pPageView = pView->GetSdrPageView();
1752 if(!pPageView)
1753 return;
1755 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1757 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1759 if(rPageWindow.GetPaintWindow().OutputToWindow())
1761 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1762 if (xManager.is())
1764 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
1765 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1766 aPosition,
1767 eColIndex,
1768 eKindOfMarker));
1770 // OVERLAYMANAGER
1771 insertNewlyCreatedOverlayObjectForSdrHdl(
1772 std::move(pNewOverlayObject),
1773 rPageWindow.GetObjectContact(),
1774 *xManager);
1780 PointerStyle ImpMeasureHdl::GetPointer() const
1782 switch (m_nObjHdlNum)
1784 case 0: case 1: return PointerStyle::Hand;
1785 case 2: case 3: return PointerStyle::MovePoint;
1786 case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
1787 } // switch
1788 return PointerStyle::NotAllowed;
1792 ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
1793 SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
1794 maRect(rRect)
1798 void ImpTextframeHdl::CreateB2dIAObject()
1800 // first throw away old one
1801 GetRidOfIAObject();
1803 if(!m_pHdlList)
1804 return;
1806 SdrMarkView* pView = m_pHdlList->GetView();
1808 if(!pView || pView->areMarkHandlesHidden())
1809 return;
1811 SdrPageView* pPageView = pView->GetSdrPageView();
1813 if(!pPageView)
1814 return;
1816 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1818 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1820 if(rPageWindow.GetPaintWindow().OutputToWindow())
1822 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1823 if (xManager.is())
1825 const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
1826 const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
1827 const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
1828 const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
1830 std::unique_ptr<sdr::overlay::OverlayRectangle> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
1831 aTopLeft,
1832 aBottomRight,
1833 aHilightColor,
1834 fTransparence,
1835 3.0,
1836 3.0,
1837 -toRadians(m_nRotationAngle),
1838 true)); // allow animation; the Handle is not shown at text edit time
1840 pNewOverlayObject->setHittable(false);
1842 // OVERLAYMANAGER
1843 insertNewlyCreatedOverlayObjectForSdrHdl(
1844 std::move(pNewOverlayObject),
1845 rPageWindow.GetObjectContact(),
1846 *xManager);
1853 static bool ImpSdrHdlListSorter(std::unique_ptr<SdrHdl> const& lhs, std::unique_ptr<SdrHdl> const& rhs)
1855 SdrHdlKind eKind1=lhs->GetKind();
1856 SdrHdlKind eKind2=rhs->GetKind();
1857 // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
1858 unsigned n1=1;
1859 unsigned n2=1;
1860 if (eKind1!=eKind2)
1862 if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
1863 else if (eKind1==SdrHdlKind::Glue) n1=2;
1864 else if (eKind1==SdrHdlKind::User) n1=3;
1865 else if (eKind1==SdrHdlKind::SmartTag) n1=0;
1866 if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
1867 else if (eKind2==SdrHdlKind::Glue) n2=2;
1868 else if (eKind2==SdrHdlKind::User) n2=3;
1869 else if (eKind2==SdrHdlKind::SmartTag) n2=0;
1871 if (lhs->IsPlusHdl()) n1=4;
1872 if (rhs->IsPlusHdl()) n2=4;
1873 if (n1==n2)
1875 // Level 2: PageView (Pointer)
1876 SdrPageView* pPV1=lhs->GetPageView();
1877 SdrPageView* pPV2=rhs->GetPageView();
1878 if (pPV1==pPV2)
1880 // Level 3: Position (x+y)
1881 SdrObject* pObj1=lhs->GetObj();
1882 SdrObject* pObj2=rhs->GetObj();
1883 if (pObj1==pObj2)
1885 sal_uInt32 nNum1=lhs->GetObjHdlNum();
1886 sal_uInt32 nNum2=rhs->GetObjHdlNum();
1887 if (nNum1==nNum2)
1889 if (eKind1==eKind2)
1890 return lhs<rhs; // Hack, to always get to the same sorting
1891 return static_cast<sal_uInt16>(eKind1)<static_cast<sal_uInt16>(eKind2);
1893 else
1894 return nNum1<nNum2;
1896 else
1898 return pObj1<pObj2;
1901 else
1903 return pPV1<pPV2;
1906 else
1908 return n1<n2;
1912 namespace {
1914 // Helper struct for re-sorting handles
1915 struct ImplHdlAndIndex
1917 SdrHdl* mpHdl;
1918 sal_uInt32 mnIndex;
1923 extern "C" {
1925 // Helper method for sorting handles taking care of OrdNums, keeping order in
1926 // single objects and re-sorting polygon handles intuitively
1927 static int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
1929 const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
1930 const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
1932 if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
1934 if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
1936 // same object and a path object
1937 if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
1938 && (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
1940 // both handles are point or control handles
1941 if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
1943 if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
1945 return -1;
1947 else
1949 return 1;
1952 else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
1954 return -1;
1956 else
1958 return 1;
1963 else
1965 if(!p1->mpHdl->GetObj())
1967 return -1;
1969 else if(!p2->mpHdl->GetObj())
1971 return 1;
1973 else
1975 // different objects, use OrdNum for sort
1976 const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
1977 const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
1979 if(nOrdNum1 < nOrdNum2)
1981 return -1;
1983 else
1985 return 1;
1990 // fallback to indices
1991 if(p1->mnIndex < p2->mnIndex)
1993 return -1;
1995 else
1997 return 1;
2003 void SdrHdlList::TravelFocusHdl(bool bForward)
2005 // security correction
2006 if (mnFocusIndex >= GetHdlCount())
2007 mnFocusIndex = SAL_MAX_SIZE;
2009 if(maList.empty())
2010 return;
2012 // take care of old handle
2013 const size_t nOldHdlNum(mnFocusIndex);
2014 SdrHdl* pOld = nullptr;
2015 if (nOldHdlNum < GetHdlCount())
2016 pOld = GetHdl(nOldHdlNum);
2018 if(pOld)
2020 // switch off old handle
2021 mnFocusIndex = SAL_MAX_SIZE;
2022 pOld->Touch();
2025 // allocate pointer array for sorted handle list
2026 std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[maList.size()]);
2028 // build sorted handle list
2029 for( size_t a = 0; a < maList.size(); ++a)
2031 pHdlAndIndex[a].mpHdl = maList[a].get();
2032 pHdlAndIndex[a].mnIndex = a;
2035 qsort(pHdlAndIndex.get(), maList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
2037 // look for old num in sorted array
2038 size_t nOldHdl(nOldHdlNum);
2040 if(nOldHdlNum != SAL_MAX_SIZE)
2042 for(size_t a = 0; a < maList.size(); ++a)
2044 if(pHdlAndIndex[a].mpHdl == pOld)
2046 nOldHdl = a;
2047 break;
2052 // build new HdlNum
2053 size_t nNewHdl(nOldHdl);
2055 // do the focus travel
2056 if(bForward)
2058 if(nOldHdl != SAL_MAX_SIZE)
2060 if(nOldHdl == maList.size() - 1)
2062 // end forward run
2063 nNewHdl = SAL_MAX_SIZE;
2065 else
2067 // simply the next handle
2068 nNewHdl++;
2071 else
2073 // start forward run at first entry
2074 nNewHdl = 0;
2077 else
2079 if(nOldHdl == SAL_MAX_SIZE)
2081 // start backward run at last entry
2082 nNewHdl = maList.size() - 1;
2085 else
2087 if(nOldHdl == 0)
2089 // end backward run
2090 nNewHdl = SAL_MAX_SIZE;
2092 else
2094 // simply the previous handle
2095 nNewHdl--;
2100 // build new HdlNum
2101 sal_uIntPtr nNewHdlNum(nNewHdl);
2103 // look for old num in sorted array
2104 if(nNewHdl != SAL_MAX_SIZE)
2106 SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
2108 for(size_t a = 0; a < maList.size(); ++a)
2110 if(maList[a].get() == pNew)
2112 nNewHdlNum = a;
2113 break;
2118 // take care of next handle
2119 if(nOldHdlNum != nNewHdlNum)
2121 mnFocusIndex = nNewHdlNum;
2122 if (mnFocusIndex < GetHdlCount())
2124 SdrHdl* pNew = GetHdl(mnFocusIndex);
2125 pNew->Touch();
2130 SdrHdl* SdrHdlList::GetFocusHdl() const
2132 if(mnFocusIndex < GetHdlCount())
2133 return GetHdl(mnFocusIndex);
2134 else
2135 return nullptr;
2138 void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
2140 if(!pNew)
2141 return;
2143 SdrHdl* pActual = GetFocusHdl();
2145 if(pActual && pActual == pNew)
2146 return;
2148 const size_t nNewHdlNum = GetHdlNum(pNew);
2150 if(nNewHdlNum != SAL_MAX_SIZE)
2152 mnFocusIndex = nNewHdlNum;
2154 if(pActual)
2156 pActual->Touch();
2159 pNew->Touch();
2163 void SdrHdlList::ResetFocusHdl()
2165 SdrHdl* pHdl = GetFocusHdl();
2167 mnFocusIndex = SAL_MAX_SIZE;
2169 if(pHdl)
2171 pHdl->Touch();
2176 SdrHdlList::SdrHdlList(SdrMarkView* pV)
2177 : mnFocusIndex(SAL_MAX_SIZE),
2178 m_pView(pV)
2180 m_nHdlSize = 3;
2181 m_bRotateShear = false;
2182 m_bMoveOutside = false;
2183 m_bDistortShear = false;
2186 SdrHdlList::~SdrHdlList()
2188 Clear();
2191 void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
2193 if(m_nHdlSize != nSiz)
2195 // remember new value
2196 m_nHdlSize = nSiz;
2198 // propagate change to IAOs
2199 for(size_t i=0; i<GetHdlCount(); ++i)
2201 SdrHdl* pHdl = GetHdl(i);
2202 pHdl->Touch();
2207 void SdrHdlList::SetMoveOutside(bool bOn)
2209 if(m_bMoveOutside != bOn)
2211 // remember new value
2212 m_bMoveOutside = bOn;
2214 // propagate change to IAOs
2215 for(size_t i=0; i<GetHdlCount(); ++i)
2217 SdrHdl* pHdl = GetHdl(i);
2218 pHdl->Touch();
2223 void SdrHdlList::SetRotateShear(bool bOn)
2225 m_bRotateShear = bOn;
2228 void SdrHdlList::SetDistortShear(bool bOn)
2230 m_bDistortShear = bOn;
2233 std::unique_ptr<SdrHdl> SdrHdlList::RemoveHdl(size_t nNum)
2235 std::unique_ptr<SdrHdl> pRetval = std::move(maList[nNum]);
2236 maList.erase(maList.begin() + nNum);
2238 return pRetval;
2241 void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
2243 std::erase_if(maList, [&eKind](std::unique_ptr<SdrHdl>& rItem) { return rItem->GetKind() == eKind; });
2246 void SdrHdlList::Clear()
2248 maList.clear();
2250 m_bRotateShear=false;
2251 m_bDistortShear=false;
2254 void SdrHdlList::Sort()
2256 // remember currently focused handle
2257 SdrHdl* pPrev = GetFocusHdl();
2259 std::sort( maList.begin(), maList.end(), ImpSdrHdlListSorter );
2261 // get now and compare
2262 SdrHdl* pNow = GetFocusHdl();
2264 if(pPrev == pNow)
2265 return;
2267 if(pPrev)
2269 pPrev->Touch();
2272 if(pNow)
2274 pNow->Touch();
2278 size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
2280 if (pHdl==nullptr)
2281 return SAL_MAX_SIZE;
2282 auto it = std::find_if( maList.begin(), maList.end(),
2283 [&](const std::unique_ptr<SdrHdl> & p) { return p.get() == pHdl; });
2284 assert(it != maList.end());
2285 if( it == maList.end() )
2286 return SAL_MAX_SIZE;
2287 return it - maList.begin();
2290 void SdrHdlList::AddHdl(std::unique_ptr<SdrHdl> pHdl)
2292 assert(pHdl);
2293 pHdl->SetHdlList(this);
2294 maList.push_back(std::move(pHdl));
2297 SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
2299 SdrHdl* pRet=nullptr;
2300 const size_t nCount=GetHdlCount();
2301 size_t nNum=nCount;
2302 while (nNum>0 && pRet==nullptr)
2304 nNum--;
2305 SdrHdl* pHdl=GetHdl(nNum);
2306 if (pHdl->IsHdlHit(rPnt))
2307 pRet=pHdl;
2309 return pRet;
2312 SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
2314 SdrHdl* pRet=nullptr;
2315 for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
2317 SdrHdl* pHdl=GetHdl(i);
2318 if (pHdl->GetKind()==eKind1)
2319 pRet=pHdl;
2321 return pRet;
2324 void SdrHdlList::MoveTo(SdrHdlList& rOther)
2326 for (auto & pHdl : maList)
2327 pHdl->SetHdlList(&rOther);
2328 rOther.maList.insert(rOther.maList.end(),
2329 std::make_move_iterator(maList.begin()), std::make_move_iterator(maList.end()));
2330 maList.clear();
2333 SdrCropHdl::SdrCropHdl(
2334 const Point& rPnt,
2335 SdrHdlKind eNewKind,
2336 double fShearX,
2337 double fRotation)
2338 : SdrHdl(rPnt, eNewKind),
2339 mfShearX(fShearX),
2340 mfRotation(fRotation)
2345 BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
2347 int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
2349 if( nSize <= 3 )
2351 nPixelSize = 13;
2352 nOffset = 0;
2354 else if( nSize <=4 )
2356 nPixelSize = 17;
2357 nOffset = 39;
2359 else
2361 nPixelSize = 21;
2362 nOffset = 90;
2365 switch( m_eKind )
2367 case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
2368 case SdrHdlKind::Upper: nX = 1; nY = 0; break;
2369 case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
2370 case SdrHdlKind::Left: nX = 0; nY = 1; break;
2371 case SdrHdlKind::Right: nX = 2; nY = 1; break;
2372 case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
2373 case SdrHdlKind::Lower: nX = 1; nY = 2; break;
2374 case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
2375 default: break;
2378 tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
2380 BitmapEx aRetval(rBitmap);
2381 aRetval.Crop(aSourceRect);
2382 return aRetval;
2386 void SdrCropHdl::CreateB2dIAObject()
2388 // first throw away old one
2389 GetRidOfIAObject();
2391 SdrMarkView* pView = m_pHdlList ? m_pHdlList->GetView() : nullptr;
2392 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2394 if( !pPageView || pView->areMarkHandlesHidden() )
2395 return;
2397 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2398 int nHdlSize = m_pHdlList->GetHdlSize();
2400 const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
2401 BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
2403 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2405 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
2407 if(rPageWindow.GetPaintWindow().OutputToWindow())
2409 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2410 if (xManager.is())
2412 basegfx::B2DPoint aPosition(m_aPos.X(), m_aPos.Y());
2414 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
2416 // animate focused handles
2417 if(IsFocusHdl() && (m_pHdlList->GetFocusHdl() == this))
2419 if( nHdlSize >= 2 )
2420 nHdlSize = 1;
2422 BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
2424 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
2426 pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
2427 aPosition,
2428 aBmpEx1,
2429 aBmpEx2,
2430 nBlinkTime,
2431 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2432 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2433 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
2434 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
2435 mfShearX,
2436 mfRotation));
2438 else
2440 // create centered handle as default
2441 pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx(
2442 aPosition,
2443 aBmpEx1,
2444 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2445 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2446 0.0,
2447 mfShearX,
2448 mfRotation));
2451 // OVERLAYMANAGER
2452 insertNewlyCreatedOverlayObjectForSdrHdl(
2453 std::move(pOverlayObject),
2454 rPageWindow.GetObjectContact(),
2455 *xManager);
2462 // with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
2463 // accordingly
2465 SdrCropViewHdl::SdrCropViewHdl(
2466 basegfx::B2DHomMatrix aObjectTransform,
2467 Graphic aGraphic,
2468 double fCropLeft,
2469 double fCropTop,
2470 double fCropRight,
2471 double fCropBottom)
2472 : SdrHdl(Point(), SdrHdlKind::User),
2473 maObjectTransform(std::move(aObjectTransform)),
2474 maGraphic(std::move(aGraphic)),
2475 mfCropLeft(fCropLeft),
2476 mfCropTop(fCropTop),
2477 mfCropRight(fCropRight),
2478 mfCropBottom(fCropBottom)
2482 namespace {
2484 void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
2485 assert(rotate != nullptr);
2487 // detect 180 degree rotation, this is the same as mirrored in X and Y,
2488 // thus change to mirroring. Prefer mirroring here. Use the equal call
2489 // with getSmallValue here, the original which uses rtl::math::approxEqual
2490 // is too correct here. Maybe this changes with enhanced precision in aw080
2491 // to the better so that this can be reduced to the more precise call again
2492 if(basegfx::fTools::equal(fabs(*rotate), M_PI, 0.000000001))
2494 scale.setX(scale.getX() * -1.0);
2495 scale.setY(scale.getY() * -1.0);
2496 *rotate = 0.0;
2502 void SdrCropViewHdl::CreateB2dIAObject()
2504 GetRidOfIAObject();
2505 SdrMarkView* pView = m_pHdlList ? m_pHdlList->GetView() : nullptr;
2506 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2508 if(!pPageView || pView->areMarkHandlesHidden())
2510 return;
2513 // decompose to have current translate and scale
2514 basegfx::B2DVector aScale, aTranslate;
2515 double fRotate, fShearX;
2517 maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
2519 if(aScale.equalZero())
2521 return;
2524 translateRotationToMirroring(aScale, &fRotate);
2526 // remember mirroring, reset at Scale and adapt crop values for usage;
2527 // mirroring can stay in the object transformation, so do not have to
2528 // cope with it here (except later for the CroppedImage transformation,
2529 // see below)
2530 const bool bMirroredX(aScale.getX() < 0.0);
2531 const bool bMirroredY(aScale.getY() < 0.0);
2532 double fCropLeft(mfCropLeft);
2533 double fCropTop(mfCropTop);
2534 double fCropRight(mfCropRight);
2535 double fCropBottom(mfCropBottom);
2537 if(bMirroredX)
2539 aScale.setX(-aScale.getX());
2542 if(bMirroredY)
2544 aScale.setY(-aScale.getY());
2547 // create target translate and scale
2548 const basegfx::B2DVector aTargetScale(
2549 aScale.getX() + fCropRight + fCropLeft,
2550 aScale.getY() + fCropBottom + fCropTop);
2551 const basegfx::B2DVector aTargetTranslate(
2552 aTranslate.getX() - fCropLeft,
2553 aTranslate.getY() - fCropTop);
2555 // create ranges to make comparisons
2556 const basegfx::B2DRange aCurrentForCompare(
2557 aTranslate.getX(), aTranslate.getY(),
2558 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
2559 basegfx::B2DRange aCropped(
2560 aTargetTranslate.getX(), aTargetTranslate.getY(),
2561 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
2563 if(aCropped.isEmpty())
2565 // nothing to return since cropped content is completely empty
2566 return;
2569 if(aCurrentForCompare.equal(aCropped))
2571 // no crop at all
2572 return;
2575 // back-transform to have values in unit coordinates
2576 basegfx::B2DHomMatrix aBackToUnit;
2577 aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
2578 aBackToUnit.scale(
2579 basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
2580 basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
2582 // transform cropped back to unit coordinates
2583 aCropped.transform(aBackToUnit);
2585 // prepare crop PolyPolygon
2586 basegfx::B2DPolygon aGraphicOutlinePolygon(
2587 basegfx::utils::createPolygonFromRect(
2588 aCropped));
2589 basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
2591 // current range is unit range
2592 basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
2594 aOverlap.intersect(aCropped);
2596 if(!aOverlap.isEmpty())
2598 aCropPolyPolygon.append(
2599 basegfx::utils::createPolygonFromRect(
2600 aOverlap));
2603 // transform to object coordinates to prepare for clip
2604 aCropPolyPolygon.transform(maObjectTransform);
2605 aGraphicOutlinePolygon.transform(maObjectTransform);
2607 // create cropped transformation
2608 basegfx::B2DHomMatrix aCroppedTransform;
2610 aCroppedTransform.scale(
2611 aCropped.getWidth(),
2612 aCropped.getHeight());
2613 aCroppedTransform.translate(
2614 aCropped.getMinX(),
2615 aCropped.getMinY());
2616 aCroppedTransform = maObjectTransform * aCroppedTransform;
2618 // prepare graphic primitive (transformed)
2619 const drawinglayer::primitive2d::Primitive2DReference aGraphic(
2620 new drawinglayer::primitive2d::GraphicPrimitive2D(
2621 aCroppedTransform,
2622 maGraphic));
2624 // prepare outline polygon for whole graphic
2625 const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
2626 const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
2627 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
2628 std::move(aGraphicOutlinePolygon),
2629 aHilightColor));
2631 // combine these
2632 drawinglayer::primitive2d::Primitive2DContainer aCombination { aGraphic, aGraphicOutline };
2634 // embed to MaskPrimitive2D
2635 const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
2636 new drawinglayer::primitive2d::MaskPrimitive2D(
2637 std::move(aCropPolyPolygon),
2638 std::move(aCombination)));
2640 // embed to UnifiedTransparencePrimitive2D
2641 const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
2642 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2643 drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
2644 0.8));
2646 const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
2648 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2650 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
2651 const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
2653 if(rPageWindow.GetPaintWindow().OutputToWindow())
2655 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2656 if(xManager.is())
2658 std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer(aSequence)));
2660 // only informative object, no hit
2661 pNew->setHittable(false);
2663 // OVERLAYMANAGER
2664 insertNewlyCreatedOverlayObjectForSdrHdl(
2665 std::move(pNew),
2666 rPageWindow.GetObjectContact(),
2667 *xManager);
2673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */