Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / svdraw / svdhdl.cxx
blob99aae2aeddd906311a089b5336b77e6b66fa661b
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 <vcl/settings.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/ptrstyle.hxx>
31 #include <svx/sxekitm.hxx>
32 #include <svx/strings.hrc>
33 #include <svx/svdmodel.hxx>
34 #include "gradtrns.hxx"
35 #include <svx/xflgrit.hxx>
36 #include <svx/svdundo.hxx>
37 #include <svx/dialmgr.hxx>
38 #include <svx/xflftrit.hxx>
40 #include <svx/svdopath.hxx>
41 #include <basegfx/vector/b2dvector.hxx>
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <svx/sdr/overlay/overlaymanager.hxx>
44 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
45 #include <svx/sdr/overlay/overlaybitmapex.hxx>
46 #include <sdr/overlay/overlayline.hxx>
47 #include <sdr/overlay/overlaytriangle.hxx>
48 #include <sdr/overlay/overlayhandle.hxx>
49 #include <sdr/overlay/overlayrectangle.hxx>
50 #include <svx/sdrpagewindow.hxx>
51 #include <svx/sdrpaintwindow.hxx>
52 #include <vcl/svapp.hxx>
53 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
54 #include <vcl/lazydelete.hxx>
55 #include <vcl/BitmapTools.hxx>
56 #include <svx/sdr/contact/objectcontact.hxx>
57 #include <svx/sdr/contact/viewcontact.hxx>
59 #include <basegfx/polygon/b2dpolygontools.hxx>
60 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
61 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
62 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
63 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
64 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
65 #include <memory>
66 #include <bitmaps.hlst>
68 namespace {
70 // #i15222#
71 // Due to the resource problems in Win95/98 with bitmap resources I
72 // will change this handle bitmap providing class. Old version was splitting
73 // and preparing all small handle bitmaps in device bitmap format, now this will
74 // be done on the fly. Thus, there is only one big bitmap in memory. With
75 // three source bitmaps, this will be 3 system bitmap resources instead of hundreds.
76 // The price for that needs to be evaluated. Maybe we will need another change here
77 // if this is too expensive.
78 class SdrHdlBitmapSet
80 // the bitmap holding all information
81 BitmapEx maMarkersBitmap;
83 // the cropped Bitmaps for reusage
84 ::std::vector< BitmapEx > maRealMarkers;
86 // helpers
87 BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle);
89 public:
90 explicit SdrHdlBitmapSet();
92 const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd);
97 #define KIND_COUNT (14)
98 #define INDEX_COUNT (6)
99 #define INDIVIDUAL_COUNT (5)
101 SdrHdlBitmapSet::SdrHdlBitmapSet()
102 : maMarkersBitmap(SIP_SA_MARKERS),
103 // 15 kinds (BitmapMarkerKind) use index [0..5] + 5 extra
104 maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
108 BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle)
110 BitmapEx& rTargetBitmap = maRealMarkers[nIndex];
112 if(rTargetBitmap.IsEmpty())
114 rTargetBitmap = maMarkersBitmap;
115 rTargetBitmap.Crop(rRectangle);
118 return rTargetBitmap;
121 // change getting of bitmap to use the big resource bitmap
122 const BitmapEx& SdrHdlBitmapSet::GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd)
124 // fill in size and source position in maMarkersBitmap
125 const sal_uInt16 nYPos(nInd * 11);
127 switch(eKindOfMarker)
129 default:
131 OSL_FAIL( "Unknown kind of marker." );
132 [[fallthrough]]; // return Rect_9x9 as default
134 case BitmapMarkerKind::Rect_9x9:
136 return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, tools::Rectangle(Point(7, nYPos), Size(9, 9)));
139 case BitmapMarkerKind::Rect_7x7:
141 return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, tools::Rectangle(Point(0, nYPos), Size(7, 7)));
144 case BitmapMarkerKind::Rect_11x11:
146 return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, tools::Rectangle(Point(16, nYPos), Size(11, 11)));
149 case BitmapMarkerKind::Rect_13x13:
151 const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);
153 switch(nInd)
155 case 0:
157 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 66), Size(13, 13)));
159 case 1:
161 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 66), Size(13, 13)));
163 case 2:
165 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 79), Size(13, 13)));
167 case 3:
169 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 79), Size(13, 13)));
171 case 4:
173 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 79), Size(13, 13)));
175 default: // case 5:
177 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 66), Size(13, 13)));
182 case BitmapMarkerKind::Circ_7x7:
183 case BitmapMarkerKind::Customshape_7x7:
185 return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, tools::Rectangle(Point(27, nYPos), Size(7, 7)));
188 case BitmapMarkerKind::Circ_9x9:
189 case BitmapMarkerKind::Customshape_9x9:
191 return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, tools::Rectangle(Point(34, nYPos), Size(9, 9)));
194 case BitmapMarkerKind::Circ_11x11:
195 case BitmapMarkerKind::Customshape_11x11:
197 return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, tools::Rectangle(Point(43, nYPos), Size(11, 11)));
200 case BitmapMarkerKind::Elli_7x9:
202 return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, tools::Rectangle(Point(54, nYPos), Size(7, 9)));
205 case BitmapMarkerKind::Elli_9x11:
207 return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, tools::Rectangle(Point(61, nYPos), Size(9, 11)));
210 case BitmapMarkerKind::Elli_9x7:
212 return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, tools::Rectangle(Point(70, nYPos), Size(9, 7)));
215 case BitmapMarkerKind::Elli_11x9:
217 return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, tools::Rectangle(Point(79, nYPos), Size(11, 9)));
220 case BitmapMarkerKind::RectPlus_7x7:
222 return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, tools::Rectangle(Point(90, nYPos), Size(7, 7)));
225 case BitmapMarkerKind::RectPlus_9x9:
227 return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, tools::Rectangle(Point(97, nYPos), Size(9, 9)));
230 case BitmapMarkerKind::RectPlus_11x11:
232 return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, tools::Rectangle(Point(106, nYPos), Size(11, 11)));
235 case BitmapMarkerKind::Crosshair:
237 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, tools::Rectangle(Point(0, 68), Size(15, 15)));
240 case BitmapMarkerKind::Glue:
242 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, tools::Rectangle(Point(15, 76), Size(9, 9)));
245 case BitmapMarkerKind::Glue_Deselected:
247 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, tools::Rectangle(Point(15, 67), Size(9, 9)));
250 case BitmapMarkerKind::Anchor: // AnchorTR for SW
251 case BitmapMarkerKind::AnchorTR:
253 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, tools::Rectangle(Point(24, 67), Size(24, 24)));
256 // add AnchorPressed to be able to animate anchor control
257 case BitmapMarkerKind::AnchorPressed:
258 case BitmapMarkerKind::AnchorPressedTR:
260 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, tools::Rectangle(Point(48, 67), Size(24, 24)));
266 SdrHdl::SdrHdl():
267 pObj(nullptr),
268 pPV(nullptr),
269 pHdlList(nullptr),
270 eKind(SdrHdlKind::Move),
271 nRotationAngle(0),
272 nObjHdlNum(0),
273 nPolyNum(0),
274 nPPntNum(0),
275 nSourceHdlNum(0),
276 bSelect(false),
277 b1PixMore(false),
278 bPlusHdl(false),
279 mbMoveOutside(false),
280 mbMouseOver(false)
284 SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
285 pObj(nullptr),
286 pPV(nullptr),
287 pHdlList(nullptr),
288 aPos(rPnt),
289 eKind(eNewKind),
290 nRotationAngle(0),
291 nObjHdlNum(0),
292 nPolyNum(0),
293 nPPntNum(0),
294 nSourceHdlNum(0),
295 bSelect(false),
296 b1PixMore(false),
297 bPlusHdl(false),
298 mbMoveOutside(false),
299 mbMouseOver(false)
303 SdrHdl::~SdrHdl()
305 GetRidOfIAObject();
308 void SdrHdl::Set1PixMore(bool bJa)
310 if(b1PixMore != bJa)
312 b1PixMore = bJa;
314 // create new display
315 Touch();
319 void SdrHdl::SetMoveOutside( bool bMoveOutside )
321 if(mbMoveOutside != bMoveOutside)
323 mbMoveOutside = bMoveOutside;
325 // create new display
326 Touch();
330 void SdrHdl::SetRotationAngle(tools::Long n)
332 if(nRotationAngle != n)
334 nRotationAngle = n;
336 // create new display
337 Touch();
341 void SdrHdl::SetPos(const Point& rPnt)
343 if(aPos != rPnt)
345 // remember new position
346 aPos = rPnt;
348 // create new display
349 Touch();
353 void SdrHdl::SetSelected(bool bJa)
355 if(bSelect != bJa)
357 // remember new value
358 bSelect = bJa;
360 // create new display
361 Touch();
365 void SdrHdl::SetHdlList(SdrHdlList* pList)
367 if(pHdlList != pList)
369 // remember list
370 pHdlList = pList;
372 // now it's possible to create graphic representation
373 Touch();
377 void SdrHdl::SetObj(SdrObject* pNewObj)
379 if(pObj != pNewObj)
381 // remember new object
382 pObj = pNewObj;
384 // graphic representation may have changed
385 Touch();
389 void SdrHdl::Touch()
391 // force update of graphic representation
392 CreateB2dIAObject();
395 void SdrHdl::GetRidOfIAObject()
398 // OVERLAYMANAGER
399 maOverlayGroup.clear();
402 void SdrHdl::CreateB2dIAObject()
404 // first throw away old one
405 GetRidOfIAObject();
407 if(!pHdlList || !pHdlList->GetView() || pHdlList->GetView()->areMarkHandlesHidden())
408 return;
410 BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
411 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
413 bool bRot = pHdlList->IsRotateShear();
414 if(pObj)
415 eColIndex = bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
416 if(bRot)
418 // red rotation handles
419 if(pObj && bSelect)
420 eColIndex = BitmapColorIndex::Red;
421 else
422 eColIndex = BitmapColorIndex::LightRed;
425 switch(eKind)
427 case SdrHdlKind::Move:
429 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
430 break;
432 case SdrHdlKind::UpperLeft:
433 case SdrHdlKind::UpperRight:
434 case SdrHdlKind::LowerLeft:
435 case SdrHdlKind::LowerRight:
437 // corner handles
438 if(bRot)
440 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
442 else
444 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
446 break;
448 case SdrHdlKind::Upper:
449 case SdrHdlKind::Lower:
451 // Upper/Lower handles
452 if(bRot)
454 eKindOfMarker = BitmapMarkerKind::Elli_9x7;
456 else
458 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
460 break;
462 case SdrHdlKind::Left:
463 case SdrHdlKind::Right:
465 // Left/Right handles
466 if(bRot)
468 eKindOfMarker = BitmapMarkerKind::Elli_7x9;
470 else
472 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
474 break;
476 case SdrHdlKind::Poly:
478 if(bRot)
480 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
482 else
484 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
486 break;
488 case SdrHdlKind::BezierWeight: // weight at poly
490 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
491 break;
493 case SdrHdlKind::Circle:
495 eKindOfMarker = BitmapMarkerKind::Rect_11x11;
496 break;
498 case SdrHdlKind::Ref1:
499 case SdrHdlKind::Ref2:
501 eKindOfMarker = BitmapMarkerKind::Crosshair;
502 break;
504 case SdrHdlKind::Glue:
506 eKindOfMarker = BitmapMarkerKind::Glue;
507 break;
509 case SdrHdlKind::Anchor:
511 eKindOfMarker = BitmapMarkerKind::Anchor;
512 break;
514 case SdrHdlKind::User:
516 break;
518 // top right anchor for SW
519 case SdrHdlKind::Anchor_TR:
521 eKindOfMarker = BitmapMarkerKind::AnchorTR;
522 break;
525 // for SJ and the CustomShapeHandles:
526 case SdrHdlKind::CustomShape1:
528 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
529 eColIndex = BitmapColorIndex::Yellow;
530 break;
532 default:
533 break;
536 SdrMarkView* pView = pHdlList->GetView();
537 SdrPageView* pPageView = pView->GetSdrPageView();
539 if(!pPageView)
540 return;
542 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
544 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
545 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
547 if(rPageWindow.GetPaintWindow().OutputToWindow())
549 Point aMoveOutsideOffset(0, 0);
550 OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
552 // add offset if necessary
553 if(pHdlList->IsMoveOutside() || mbMoveOutside)
555 Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
557 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Upper || eKind == SdrHdlKind::UpperRight)
558 aMoveOutsideOffset.AdjustY( -(aOffset.Width()) );
559 if(eKind == SdrHdlKind::LowerLeft || eKind == SdrHdlKind::Lower || eKind == SdrHdlKind::LowerRight)
560 aMoveOutsideOffset.AdjustY(aOffset.Height() );
561 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Left || eKind == SdrHdlKind::LowerLeft)
562 aMoveOutsideOffset.AdjustX( -(aOffset.Width()) );
563 if(eKind == SdrHdlKind::UpperRight || eKind == SdrHdlKind::Right || eKind == SdrHdlKind::LowerRight)
564 aMoveOutsideOffset.AdjustX(aOffset.Height() );
567 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
568 if (xManager.is())
570 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
571 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject;
572 if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker == BitmapMarkerKind::Rect_7x7 || eKindOfMarker == BitmapMarkerKind::Rect_9x9 || eKindOfMarker == BitmapMarkerKind::Rect_11x11))
574 double fSize = 7.0;
575 switch (eKindOfMarker)
577 case BitmapMarkerKind::Rect_9x9:
578 fSize = 9.0;
579 break;
580 case BitmapMarkerKind::Rect_11x11:
581 fSize = 11.0;
582 break;
583 default:
584 break;
586 float fScalingFactor = rOutDev.GetDPIScaleFactor();
587 basegfx::B2DSize aB2DSize(fSize * fScalingFactor, fSize * fScalingFactor);
589 Color aHandleFillColor(COL_LIGHTGREEN);
590 switch (eColIndex)
592 case BitmapColorIndex::Cyan:
593 aHandleFillColor = COL_CYAN;
594 break;
595 case BitmapColorIndex::LightCyan:
596 aHandleFillColor = COL_LIGHTCYAN;
597 break;
598 case BitmapColorIndex::Red:
599 aHandleFillColor = COL_RED;
600 break;
601 case BitmapColorIndex::LightRed:
602 aHandleFillColor = COL_LIGHTRED;
603 break;
604 case BitmapColorIndex::Yellow:
605 aHandleFillColor = COL_YELLOW;
606 break;
607 default:
608 break;
610 pNewOverlayObject.reset(new sdr::overlay::OverlayHandle(aPosition, aB2DSize, /*HandleStrokeColor*/COL_BLACK, aHandleFillColor));
612 else
614 pNewOverlayObject = CreateOverlayObject(
615 aPosition, eColIndex, eKindOfMarker,
616 aMoveOutsideOffset);
619 // OVERLAYMANAGER
620 insertNewlyCreatedOverlayObjectForSdrHdl(
621 std::move(pNewOverlayObject),
622 rPageWindow.GetObjectContact(),
623 *xManager);
629 BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd)
631 BitmapMarkerKind eRetval(eKnd);
633 switch(eKnd)
635 case BitmapMarkerKind::Rect_7x7: eRetval = BitmapMarkerKind::Rect_9x9; break;
636 case BitmapMarkerKind::Rect_9x9: eRetval = BitmapMarkerKind::Rect_11x11; break;
637 case BitmapMarkerKind::Rect_11x11: eRetval = BitmapMarkerKind::Rect_13x13; break;
639 case BitmapMarkerKind::Circ_7x7: eRetval = BitmapMarkerKind::Circ_9x9; break;
640 case BitmapMarkerKind::Circ_9x9: eRetval = BitmapMarkerKind::Circ_11x11; break;
642 case BitmapMarkerKind::Customshape_7x7: eRetval = BitmapMarkerKind::Customshape_9x9; break;
643 case BitmapMarkerKind::Customshape_9x9: eRetval = BitmapMarkerKind::Customshape_11x11; break;
644 //case BitmapMarkerKind::Customshape_11x11: eRetval = ; break;
646 case BitmapMarkerKind::Elli_7x9: eRetval = BitmapMarkerKind::Elli_9x11; break;
648 case BitmapMarkerKind::Elli_9x7: eRetval = BitmapMarkerKind::Elli_11x9; break;
650 case BitmapMarkerKind::RectPlus_7x7: eRetval = BitmapMarkerKind::RectPlus_9x9; break;
651 case BitmapMarkerKind::RectPlus_9x9: eRetval = BitmapMarkerKind::RectPlus_11x11; break;
653 // let anchor blink with its pressed state
654 case BitmapMarkerKind::Anchor: eRetval = BitmapMarkerKind::AnchorPressed; break;
656 // same for AnchorTR
657 case BitmapMarkerKind::AnchorTR: eRetval = BitmapMarkerKind::AnchorPressedTR; break;
658 default:
659 break;
662 return eRetval;
665 namespace
668 OUString appendMarkerName(BitmapMarkerKind eKindOfMarker)
670 switch(eKindOfMarker)
672 case BitmapMarkerKind::Rect_7x7:
673 return "rect7";
674 case BitmapMarkerKind::Rect_9x9:
675 return "rect9";
676 case BitmapMarkerKind::Rect_11x11:
677 return "rect11";
678 case BitmapMarkerKind::Rect_13x13:
679 return "rect13";
680 case BitmapMarkerKind::Circ_7x7:
681 case BitmapMarkerKind::Customshape_7x7:
682 return "circ7";
683 case BitmapMarkerKind::Circ_9x9:
684 case BitmapMarkerKind::Customshape_9x9:
685 return "circ9";
686 case BitmapMarkerKind::Circ_11x11:
687 case BitmapMarkerKind::Customshape_11x11:
688 return "circ11";
689 case BitmapMarkerKind::Elli_7x9:
690 return "elli7x9";
691 case BitmapMarkerKind::Elli_9x11:
692 return "elli9x11";
693 case BitmapMarkerKind::Elli_9x7:
694 return "elli9x7";
695 case BitmapMarkerKind::Elli_11x9:
696 return "elli11x9";
697 case BitmapMarkerKind::RectPlus_7x7:
698 return "rectplus7";
699 case BitmapMarkerKind::RectPlus_9x9:
700 return "rectplus9";
701 case BitmapMarkerKind::RectPlus_11x11:
702 return "rectplus11";
703 case BitmapMarkerKind::Crosshair:
704 return "cross";
705 case BitmapMarkerKind::Anchor:
706 case BitmapMarkerKind::AnchorTR:
707 return "anchor";
708 case BitmapMarkerKind::AnchorPressed:
709 case BitmapMarkerKind::AnchorPressedTR:
710 return "anchor-pressed";
711 case BitmapMarkerKind::Glue:
712 return "glue-selected";
713 case BitmapMarkerKind::Glue_Deselected:
714 return "glue-unselected";
715 default:
716 break;
718 return OUString();
721 OUString appendMarkerColor(BitmapColorIndex eIndex)
723 switch(eIndex)
725 case BitmapColorIndex::LightGreen:
726 return "1";
727 case BitmapColorIndex::Cyan:
728 return "2";
729 case BitmapColorIndex::LightCyan:
730 return "3";
731 case BitmapColorIndex::Red:
732 return "4";
733 case BitmapColorIndex::LightRed:
734 return "5";
735 case BitmapColorIndex::Yellow:
736 return "6";
737 default:
738 break;
740 return OUString();
743 BitmapEx ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, BitmapColorIndex eIndex)
745 // use this code path only when we use HiDPI (for now)
746 if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
748 OUString sMarkerName = appendMarkerName(eKindOfMarker);
749 if (!sMarkerName.isEmpty())
751 OUString sMarkerPrefix("svx/res/marker-");
752 BitmapEx aBitmapEx;
754 if (eKindOfMarker == BitmapMarkerKind::Crosshair
755 || eKindOfMarker == BitmapMarkerKind::Anchor
756 || eKindOfMarker == BitmapMarkerKind::AnchorTR
757 || eKindOfMarker == BitmapMarkerKind::AnchorPressed
758 || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR
759 || eKindOfMarker == BitmapMarkerKind::Glue
760 || eKindOfMarker == BitmapMarkerKind::Glue_Deselected)
762 aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + ".png");
764 else
766 aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + "-" + appendMarkerColor(eIndex) + ".png");
769 if (!aBitmapEx.IsEmpty())
770 return aBitmapEx;
774 // if we can't load the marker...
776 static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aModernSet(new SdrHdlBitmapSet);
777 return aModernSet.get()->GetBitmapEx(eKindOfMarker, sal_uInt16(eIndex));
780 } // end anonymous namespace
782 std::unique_ptr<sdr::overlay::OverlayObject> SdrHdl::CreateOverlayObject(
783 const basegfx::B2DPoint& rPos,
784 BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
786 std::unique_ptr<sdr::overlay::OverlayObject> pRetval;
788 // support bigger sizes
789 bool bForceBiggerSize(false);
791 if(pHdlList->GetHdlSize() > 3)
793 switch(eKindOfMarker)
795 case BitmapMarkerKind::Anchor:
796 case BitmapMarkerKind::AnchorPressed:
797 case BitmapMarkerKind::AnchorTR:
798 case BitmapMarkerKind::AnchorPressedTR:
800 // #i121463# For anchor, do not simply make bigger because of HdlSize,
801 // do it dependent of IsSelected() which Writer can set in drag mode
802 if(IsSelected())
804 bForceBiggerSize = true;
806 break;
808 default:
810 bForceBiggerSize = true;
811 break;
816 if(bForceBiggerSize)
818 eKindOfMarker = GetNextBigger(eKindOfMarker);
821 // This handle has the focus, visualize it
822 if(IsFocusHdl() && pHdlList && pHdlList->GetFocusHdl() == this)
824 // create animated handle
825 BitmapMarkerKind eNextBigger = GetNextBigger(eKindOfMarker);
827 if(eNextBigger == eKindOfMarker)
829 // this may happen for the not supported getting-bigger types.
830 // Choose an alternative here
831 switch(eKindOfMarker)
833 case BitmapMarkerKind::Rect_13x13: eNextBigger = BitmapMarkerKind::Rect_11x11; break;
834 case BitmapMarkerKind::Circ_11x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
835 case BitmapMarkerKind::Elli_9x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
836 case BitmapMarkerKind::Elli_11x9: eNextBigger = BitmapMarkerKind::Elli_9x11; break;
837 case BitmapMarkerKind::RectPlus_11x11: eNextBigger = BitmapMarkerKind::Rect_13x13; break;
839 case BitmapMarkerKind::Crosshair:
840 eNextBigger = BitmapMarkerKind::Glue;
841 break;
843 case BitmapMarkerKind::Glue:
844 eNextBigger = BitmapMarkerKind::Crosshair;
845 break;
846 case BitmapMarkerKind::Glue_Deselected:
847 eNextBigger = BitmapMarkerKind::Glue;
848 break;
849 default:
850 break;
854 // create animated handle
855 BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, eColIndex);
856 BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, eColIndex);
858 // #i53216# Use system cursor blink time. Use the unsigned value.
859 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
860 const sal_uInt64 nBlinkTime(rStyleSettings.GetCursorBlinkTime());
862 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
864 // when anchor is used take upper left as reference point inside the handle
865 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime));
867 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
869 // AnchorTR for SW, take top right as (0,0)
870 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
871 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1), 0,
872 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1), 0));
874 else
876 // create centered handle as default
877 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
878 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
879 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
880 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
881 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1));
884 else
886 // create normal handle: use ImpGetBitmapEx(...) now
887 BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, eColIndex);
889 // When the image with handles is not found, the bitmap returned is
890 // empty. This is a problem when we use LibreOffice as a library
891 // (through LOKit - for example on Android) even when we don't show
892 // the handles, because the hit test would always return false.
894 // This HACK replaces the empty bitmap with a black 13x13 bitmap handle
895 // so that the hit test works for this case.
896 if (aBmpEx.IsEmpty())
898 aBmpEx = BitmapEx(Size(13, 13), 24);
899 aBmpEx.Erase(COL_BLACK);
902 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
904 // upper left as reference point inside the handle for AnchorPressed, too
905 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx));
907 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
909 // AnchorTR for SW, take top right as (0,0)
910 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
911 static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1), 0));
913 else
915 sal_uInt16 nCenX(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1) >> 1);
916 sal_uInt16 nCenY(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1) >> 1);
918 if(aMoveOutsideOffset.X() > 0)
920 nCenX = 0;
922 else if(aMoveOutsideOffset.X() < 0)
924 nCenX = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1);
927 if(aMoveOutsideOffset.Y() > 0)
929 nCenY = 0;
931 else if(aMoveOutsideOffset.Y() < 0)
933 nCenY = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1);
936 // create centered handle as default
937 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx, nCenX, nCenY));
941 return pRetval;
944 bool SdrHdl::IsHdlHit(const Point& rPnt) const
946 // OVERLAYMANAGER
947 basegfx::B2DPoint aPosition(rPnt.X(), rPnt.Y());
948 return maOverlayGroup.isHitLogic(aPosition);
951 PointerStyle SdrHdl::GetPointer() const
953 PointerStyle ePtr=PointerStyle::Move;
954 const bool bSize=eKind>=SdrHdlKind::UpperLeft && eKind<=SdrHdlKind::LowerRight;
955 const bool bRot=pHdlList!=nullptr && pHdlList->IsRotateShear();
956 const bool bDis=pHdlList!=nullptr && pHdlList->IsDistortShear();
957 if (bSize && pHdlList!=nullptr && (bRot || bDis)) {
958 switch (eKind) {
959 case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
960 case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight: ePtr=bRot ? PointerStyle::Rotate : PointerStyle::RefHand; break;
961 case SdrHdlKind::Left : case SdrHdlKind::Right: ePtr=PointerStyle::VShear; break;
962 case SdrHdlKind::Upper: case SdrHdlKind::Lower: ePtr=PointerStyle::HShear; break;
963 default:
964 break;
966 } else {
967 // When resizing rotated rectangles, rotate the mouse cursor slightly, too
968 if (bSize && nRotationAngle!=0) {
969 tools::Long nHdlAngle=0;
970 switch (eKind) {
971 case SdrHdlKind::LowerRight: nHdlAngle=31500; break;
972 case SdrHdlKind::Lower: nHdlAngle=27000; break;
973 case SdrHdlKind::LowerLeft: nHdlAngle=22500; break;
974 case SdrHdlKind::Left : nHdlAngle=18000; break;
975 case SdrHdlKind::UpperLeft: nHdlAngle=13500; break;
976 case SdrHdlKind::Upper: nHdlAngle=9000; break;
977 case SdrHdlKind::UpperRight: nHdlAngle=4500; break;
978 case SdrHdlKind::Right: nHdlAngle=0; break;
979 default:
980 break;
982 // a little bit more (for rounding)
983 nHdlAngle = NormAngle36000(nHdlAngle + nRotationAngle + 2249);
984 nHdlAngle/=4500;
985 switch (static_cast<sal_uInt8>(nHdlAngle)) {
986 case 0: ePtr=PointerStyle::ESize; break;
987 case 1: ePtr=PointerStyle::NESize; break;
988 case 2: ePtr=PointerStyle::NSize; break;
989 case 3: ePtr=PointerStyle::NWSize; break;
990 case 4: ePtr=PointerStyle::WSize; break;
991 case 5: ePtr=PointerStyle::SWSize; break;
992 case 6: ePtr=PointerStyle::SSize; break;
993 case 7: ePtr=PointerStyle::SESize; break;
994 } // switch
995 } else {
996 switch (eKind) {
997 case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
998 case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
999 case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
1000 case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
1001 case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
1002 case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
1003 case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
1004 case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
1005 case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
1006 case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
1007 case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
1008 case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
1009 case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
1010 case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
1011 case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::Hand; break;
1012 default:
1013 break;
1017 return ePtr;
1020 bool SdrHdl::IsFocusHdl() const
1022 switch(eKind)
1024 case SdrHdlKind::UpperLeft:
1025 case SdrHdlKind::Upper:
1026 case SdrHdlKind::UpperRight:
1027 case SdrHdlKind::Left:
1028 case SdrHdlKind::Right:
1029 case SdrHdlKind::LowerLeft:
1030 case SdrHdlKind::Lower:
1031 case SdrHdlKind::LowerRight:
1033 // if it's an activated TextEdit, it's moved to extended points
1034 return !pHdlList || !pHdlList->IsMoveOutside();
1037 case SdrHdlKind::Move: // handle to move object
1038 case SdrHdlKind::Poly: // selected point of polygon or curve
1039 case SdrHdlKind::BezierWeight: // weight at a curve
1040 case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
1041 case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
1042 case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
1043 case SdrHdlKind::Glue: // glue point
1045 // for SJ and the CustomShapeHandles:
1046 case SdrHdlKind::CustomShape1:
1048 case SdrHdlKind::User:
1050 return true;
1053 default:
1055 return false;
1060 void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
1064 void SdrHdl::onHelpRequest()
1068 void SdrHdl::onMouseLeave()
1072 BitmapEx SdrHdl::createGluePointBitmap()
1074 return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
1077 void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
1078 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
1079 const sdr::contact::ObjectContact& rObjectContact,
1080 sdr::overlay::OverlayManager& rOverlayManager)
1082 // check if we have an OverlayObject
1083 if(!pOverlayObject)
1085 return;
1088 // Add GridOffset for non-linear ViewToDevice transformation (calc)
1089 if(nullptr != GetObj() && rObjectContact.supportsGridOffsets())
1091 basegfx::B2DVector aOffset(0.0, 0.0);
1092 const sdr::contact::ViewObjectContact& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
1093 const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
1095 rObjectContact.calculateGridOffsetForViewOjectContact(aOffset, rVOC);
1097 if(!aOffset.equalZero())
1099 pOverlayObject->setOffset(aOffset);
1103 // add to OverlayManager
1104 rOverlayManager.add(*pOverlayObject);
1106 // add to local OverlayObjectList - ownership change (!)
1107 maOverlayGroup.append(std::move(pOverlayObject));
1110 SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
1111 : SdrHdl(rRef, SdrHdlKind::Color),
1112 aMarkerSize(rSize),
1113 bUseLuminance(bLum)
1115 if(IsUseLuminance())
1116 aCol = GetLuminance(aCol);
1118 // remember color
1119 aMarkerColor = aCol;
1122 SdrHdlColor::~SdrHdlColor()
1126 void SdrHdlColor::CreateB2dIAObject()
1128 // first throw away old one
1129 GetRidOfIAObject();
1131 if(!pHdlList)
1132 return;
1134 SdrMarkView* pView = pHdlList->GetView();
1136 if(!pView || pView->areMarkHandlesHidden())
1137 return;
1139 SdrPageView* pPageView = pView->GetSdrPageView();
1141 if(!pPageView)
1142 return;
1144 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1146 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1148 if(rPageWindow.GetPaintWindow().OutputToWindow())
1150 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1151 if (xManager.is())
1153 BitmapEx aBmpCol(CreateColorDropper(aMarkerColor));
1154 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1155 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1156 sdr::overlay::OverlayBitmapEx(
1157 aPosition,
1158 aBmpCol,
1159 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Width() - 1) >> 1,
1160 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Height() - 1) >> 1
1163 // OVERLAYMANAGER
1164 insertNewlyCreatedOverlayObjectForSdrHdl(
1165 std::move(pNewOverlayObject),
1166 rPageWindow.GetObjectContact(),
1167 *xManager);
1173 BitmapEx SdrHdlColor::CreateColorDropper(Color aCol)
1175 // get the Bitmap
1176 VclPtr<VirtualDevice> pWrite(VclPtr<VirtualDevice>::Create());
1177 pWrite->SetOutputSizePixel(aMarkerSize);
1178 pWrite->SetBackground(aCol);
1179 pWrite->Erase();
1181 // draw outer border
1182 sal_Int32 nWidth = aMarkerSize.Width();
1183 sal_Int32 nHeight = aMarkerSize.Height();
1185 pWrite->SetLineColor(COL_LIGHTGRAY);
1186 pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
1187 pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
1188 pWrite->SetLineColor(COL_GRAY);
1189 pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
1190 pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
1192 // draw lighter UpperLeft
1193 const Color aLightColor(
1194 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1195 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1196 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
1197 pWrite->SetLineColor(aLightColor);
1198 pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
1199 pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
1201 // draw darker LowerRight
1202 const Color aDarkColor(
1203 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1204 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1205 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
1206 pWrite->SetLineColor(aDarkColor);
1207 pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
1208 pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
1210 return pWrite->GetBitmapEx(Point(0,0), aMarkerSize);
1213 Color SdrHdlColor::GetLuminance(const Color& rCol)
1215 sal_uInt8 aLum = rCol.GetLuminance();
1216 Color aRetval(aLum, aLum, aLum);
1217 return aRetval;
1220 void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
1222 if(IsUseLuminance())
1223 aNew = GetLuminance(aNew);
1225 if(aMarkerColor != aNew)
1227 // remember new color
1228 aMarkerColor = aNew;
1230 // create new display
1231 Touch();
1233 // tell about change
1234 if(bCallLink)
1235 aColorChangeHdl.Call(this);
1239 void SdrHdlColor::SetSize(const Size& rNew)
1241 if(rNew != aMarkerSize)
1243 // remember new size
1244 aMarkerSize = rNew;
1246 // create new display
1247 Touch();
1251 SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
1252 : SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
1253 , pColHdl1(nullptr)
1254 , pColHdl2(nullptr)
1255 , a2ndPos(rRef2)
1256 , bGradient(bGrad)
1257 , bMoveSingleHandle(false)
1258 , bMoveFirstHandle(false)
1262 SdrHdlGradient::~SdrHdlGradient()
1266 void SdrHdlGradient::Set2ndPos(const Point& rPnt)
1268 if(a2ndPos != rPnt)
1270 // remember new position
1271 a2ndPos = rPnt;
1273 // create new display
1274 Touch();
1278 void SdrHdlGradient::CreateB2dIAObject()
1280 // first throw away old one
1281 GetRidOfIAObject();
1283 if(!pHdlList)
1284 return;
1286 SdrMarkView* pView = pHdlList->GetView();
1288 if(!pView || pView->areMarkHandlesHidden())
1289 return;
1291 SdrPageView* pPageView = pView->GetSdrPageView();
1293 if(!pPageView)
1294 return;
1296 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1298 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1300 if(rPageWindow.GetPaintWindow().OutputToWindow())
1302 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1303 if (xManager.is())
1305 // striped line in between
1306 basegfx::B2DVector aVec(a2ndPos.X() - aPos.X(), a2ndPos.Y() - aPos.Y());
1307 double fVecLen = aVec.getLength();
1308 double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
1309 double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
1310 aVec.normalize();
1311 basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
1312 sal_Int32 nMidX = static_cast<sal_Int32>(aPos.X() + aVec.getX() * fLongPercentArrow);
1313 sal_Int32 nMidY = static_cast<sal_Int32>(aPos.Y() + aVec.getY() * fLongPercentArrow);
1314 Point aMidPoint(nMidX, nMidY);
1316 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1317 basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
1319 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1320 sdr::overlay::OverlayLineStriped(
1321 aPosition, aMidPos
1324 pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
1326 // OVERLAYMANAGER
1327 insertNewlyCreatedOverlayObjectForSdrHdl(
1328 std::move(pNewOverlayObject),
1329 rPageWindow.GetObjectContact(),
1330 *xManager);
1332 // arrowhead
1333 Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1334 aMidPoint.Y() + static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1335 Point aRight(aMidPoint.X() - static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1336 aMidPoint.Y() - static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1338 basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
1339 basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
1340 basegfx::B2DPoint aPosition2(a2ndPos.X(), a2ndPos.Y());
1342 pNewOverlayObject.reset(new
1343 sdr::overlay::OverlayTriangle(
1344 aPositionLeft,
1345 aPosition2,
1346 aPositionRight,
1347 IsGradient() ? COL_BLACK : COL_BLUE
1350 // OVERLAYMANAGER
1351 insertNewlyCreatedOverlayObjectForSdrHdl(
1352 std::move(pNewOverlayObject),
1353 rPageWindow.GetObjectContact(),
1354 *xManager);
1360 IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
1362 if(GetObj())
1363 FromIAOToItem(GetObj(), true, true);
1366 void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
1368 // from IAO positions and colors to gradient
1369 const SfxItemSet& rSet = _pObj->GetMergedItemSet();
1371 GradTransGradient aOldGradTransGradient;
1372 GradTransGradient aGradTransGradient;
1373 GradTransVector aGradTransVector;
1375 aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
1376 aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
1377 if(pColHdl1)
1378 aGradTransVector.aCol1 = pColHdl1->GetColor();
1379 if(pColHdl2)
1380 aGradTransVector.aCol2 = pColHdl2->GetColor();
1382 if(IsGradient())
1383 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1384 else
1385 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1387 // transform vector data to gradient
1388 GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);
1390 if(bSetItemOnObject)
1392 SdrModel& rModel(_pObj->getSdrModelFromSdrObject());
1393 SfxItemSet aNewSet(rModel.GetItemPool());
1394 const OUString aString;
1396 if(IsGradient())
1398 XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
1399 aNewSet.Put(aNewGradItem);
1401 else
1403 XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
1404 aNewSet.Put(aNewTransItem);
1407 if(bUndo && rModel.IsUndoEnabled())
1409 rModel.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
1410 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
1411 rModel.EndUndo();
1414 pObj->SetMergedItemSetAndBroadcast(aNewSet);
1417 // back transformation, set values on pIAOHandle
1418 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
1420 SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1421 Set2ndPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1422 if(pColHdl1)
1424 pColHdl1->SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1425 pColHdl1->SetColor(aGradTransVector.aCol1);
1427 if(pColHdl2)
1429 pColHdl2->SetPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1430 pColHdl2->SetColor(aGradTransVector.aCol2);
1435 SdrHdlLine::~SdrHdlLine() {}
1437 void SdrHdlLine::CreateB2dIAObject()
1439 // first throw away old one
1440 GetRidOfIAObject();
1442 if(!pHdlList)
1443 return;
1445 SdrMarkView* pView = pHdlList->GetView();
1447 if(!(pView && !pView->areMarkHandlesHidden() && pHdl1 && pHdl2))
1448 return;
1450 SdrPageView* pPageView = pView->GetSdrPageView();
1452 if(!pPageView)
1453 return;
1455 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1457 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1459 if(rPageWindow.GetPaintWindow().OutputToWindow())
1461 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1462 if (xManager.is())
1464 basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1465 basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), pHdl2->GetPos().Y());
1467 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1468 sdr::overlay::OverlayLineStriped(
1469 aPosition1,
1470 aPosition2
1473 // color(?)
1474 pNewOverlayObject->setBaseColor(COL_LIGHTRED);
1476 // OVERLAYMANAGER
1477 insertNewlyCreatedOverlayObjectForSdrHdl(
1478 std::move(pNewOverlayObject),
1479 rPageWindow.GetObjectContact(),
1480 *xManager);
1486 PointerStyle SdrHdlLine::GetPointer() const
1488 return PointerStyle::RefHand;
1492 SdrHdlBezWgt::~SdrHdlBezWgt() {}
1494 void SdrHdlBezWgt::CreateB2dIAObject()
1496 // call parent
1497 SdrHdl::CreateB2dIAObject();
1499 // create lines
1500 if(!pHdlList)
1501 return;
1503 SdrMarkView* pView = pHdlList->GetView();
1505 if(!pView || pView->areMarkHandlesHidden())
1506 return;
1508 SdrPageView* pPageView = pView->GetSdrPageView();
1510 if(!pPageView)
1511 return;
1513 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1515 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1517 if(rPageWindow.GetPaintWindow().OutputToWindow())
1519 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1520 if (xManager.is())
1522 basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1523 basegfx::B2DPoint aPosition2(aPos.X(), aPos.Y());
1525 if(!aPosition1.equal(aPosition2))
1527 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1528 sdr::overlay::OverlayLineStriped(
1529 aPosition1,
1530 aPosition2
1533 // line part is not hittable
1534 pNewOverlayObject->setHittable(false);
1536 // color(?)
1537 pNewOverlayObject->setBaseColor(COL_LIGHTBLUE);
1539 // OVERLAYMANAGER
1540 insertNewlyCreatedOverlayObjectForSdrHdl(
1541 std::move(pNewOverlayObject),
1542 rPageWindow.GetObjectContact(),
1543 *xManager);
1551 E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon& rWireframePoly)
1553 aWireframePoly = rWireframePoly;
1556 void E3dVolumeMarker::CreateB2dIAObject()
1558 // create lines
1559 if(!pHdlList)
1560 return;
1562 SdrMarkView* pView = pHdlList->GetView();
1564 if(!pView || pView->areMarkHandlesHidden())
1565 return;
1567 SdrPageView* pPageView = pView->GetSdrPageView();
1569 if(!pPageView)
1570 return;
1572 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1574 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1576 if(rPageWindow.GetPaintWindow().OutputToWindow())
1578 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1579 if (xManager.is() && aWireframePoly.count())
1581 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1582 sdr::overlay::OverlayPolyPolygonStripedAndFilled(
1583 aWireframePoly));
1585 pNewOverlayObject->setBaseColor(COL_BLACK);
1587 // OVERLAYMANAGER
1588 insertNewlyCreatedOverlayObjectForSdrHdl(
1589 std::move(pNewOverlayObject),
1590 rPageWindow.GetObjectContact(),
1591 *xManager);
1598 ImpEdgeHdl::~ImpEdgeHdl()
1602 void ImpEdgeHdl::CreateB2dIAObject()
1604 if(nObjHdlNum <= 1 && pObj)
1606 // first throw away old one
1607 GetRidOfIAObject();
1609 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1610 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1612 if(pHdlList)
1614 SdrMarkView* pView = pHdlList->GetView();
1616 if(pView && !pView->areMarkHandlesHidden())
1618 const SdrEdgeObj* pEdge = static_cast<SdrEdgeObj*>(pObj);
1620 if(pEdge->GetConnectedNode(nObjHdlNum == 0) != nullptr)
1621 eColIndex = BitmapColorIndex::LightRed;
1623 if(nPPntNum < 2)
1625 // Handle with plus sign inside
1626 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
1629 SdrPageView* pPageView = pView->GetSdrPageView();
1631 if(pPageView)
1633 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1635 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1637 if(rPageWindow.GetPaintWindow().OutputToWindow())
1639 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1640 if (xManager.is())
1642 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1643 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1644 aPosition,
1645 eColIndex,
1646 eKindOfMarker));
1648 // OVERLAYMANAGER
1649 insertNewlyCreatedOverlayObjectForSdrHdl(
1650 std::move(pNewOverlayObject),
1651 rPageWindow.GetObjectContact(),
1652 *xManager);
1660 else
1662 // call parent
1663 SdrHdl::CreateB2dIAObject();
1667 void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
1669 if(eLineCode != eCode)
1671 // remember new value
1672 eLineCode = eCode;
1674 // create new display
1675 Touch();
1679 PointerStyle ImpEdgeHdl::GetPointer() const
1681 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1682 if (pEdge==nullptr)
1683 return SdrHdl::GetPointer();
1684 if (nObjHdlNum<=1)
1685 return PointerStyle::MovePoint;
1686 if (IsHorzDrag())
1687 return PointerStyle::ESize;
1688 else
1689 return PointerStyle::SSize;
1692 bool ImpEdgeHdl::IsHorzDrag() const
1694 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1695 if (pEdge==nullptr)
1696 return false;
1697 if (nObjHdlNum<=1)
1698 return false;
1700 SdrEdgeKind eEdgeKind = pEdge->GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1702 const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
1703 if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
1705 return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
1707 else if (eEdgeKind==SdrEdgeKind::ThreeLines)
1709 tools::Long nAngle=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
1710 return nAngle==0 || nAngle==18000;
1712 return false;
1716 ImpMeasureHdl::~ImpMeasureHdl()
1720 void ImpMeasureHdl::CreateB2dIAObject()
1722 // first throw away old one
1723 GetRidOfIAObject();
1725 if(!pHdlList)
1726 return;
1728 SdrMarkView* pView = pHdlList->GetView();
1730 if(!pView || pView->areMarkHandlesHidden())
1731 return;
1733 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1734 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
1736 if(nObjHdlNum > 1)
1738 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1741 if(bSelect)
1743 eColIndex = BitmapColorIndex::Cyan;
1746 SdrPageView* pPageView = pView->GetSdrPageView();
1748 if(!pPageView)
1749 return;
1751 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1753 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1755 if(rPageWindow.GetPaintWindow().OutputToWindow())
1757 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1758 if (xManager.is())
1760 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1761 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1762 aPosition,
1763 eColIndex,
1764 eKindOfMarker));
1766 // OVERLAYMANAGER
1767 insertNewlyCreatedOverlayObjectForSdrHdl(
1768 std::move(pNewOverlayObject),
1769 rPageWindow.GetObjectContact(),
1770 *xManager);
1776 PointerStyle ImpMeasureHdl::GetPointer() const
1778 switch (nObjHdlNum)
1780 case 0: case 1: return PointerStyle::Hand;
1781 case 2: case 3: return PointerStyle::MovePoint;
1782 case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
1783 } // switch
1784 return PointerStyle::NotAllowed;
1788 ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
1789 SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
1790 maRect(rRect)
1794 void ImpTextframeHdl::CreateB2dIAObject()
1796 // first throw away old one
1797 GetRidOfIAObject();
1799 if(!pHdlList)
1800 return;
1802 SdrMarkView* pView = pHdlList->GetView();
1804 if(!pView || pView->areMarkHandlesHidden())
1805 return;
1807 SdrPageView* pPageView = pView->GetSdrPageView();
1809 if(!pPageView)
1810 return;
1812 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1814 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1816 if(rPageWindow.GetPaintWindow().OutputToWindow())
1818 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1819 if (xManager.is())
1821 const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
1822 const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
1823 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1824 const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
1825 const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
1827 std::unique_ptr<sdr::overlay::OverlayRectangle> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
1828 aTopLeft,
1829 aBottomRight,
1830 aHilightColor,
1831 fTransparence,
1832 3.0,
1833 3.0,
1834 nRotationAngle * -F_PI18000,
1835 true)); // allow animation; the Handle is not shown at text edit time
1837 pNewOverlayObject->setHittable(false);
1839 // OVERLAYMANAGER
1840 insertNewlyCreatedOverlayObjectForSdrHdl(
1841 std::move(pNewOverlayObject),
1842 rPageWindow.GetObjectContact(),
1843 *xManager);
1850 static bool ImpSdrHdlListSorter(std::unique_ptr<SdrHdl> const& lhs, std::unique_ptr<SdrHdl> const& rhs)
1852 SdrHdlKind eKind1=lhs->GetKind();
1853 SdrHdlKind eKind2=rhs->GetKind();
1854 // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
1855 unsigned n1=1;
1856 unsigned n2=1;
1857 if (eKind1!=eKind2)
1859 if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
1860 else if (eKind1==SdrHdlKind::Glue) n1=2;
1861 else if (eKind1==SdrHdlKind::User) n1=3;
1862 else if (eKind1==SdrHdlKind::SmartTag) n1=0;
1863 if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
1864 else if (eKind2==SdrHdlKind::Glue) n2=2;
1865 else if (eKind2==SdrHdlKind::User) n2=3;
1866 else if (eKind2==SdrHdlKind::SmartTag) n2=0;
1868 if (lhs->IsPlusHdl()) n1=4;
1869 if (rhs->IsPlusHdl()) n2=4;
1870 if (n1==n2)
1872 // Level 2: PageView (Pointer)
1873 SdrPageView* pPV1=lhs->GetPageView();
1874 SdrPageView* pPV2=rhs->GetPageView();
1875 if (pPV1==pPV2)
1877 // Level 3: Position (x+y)
1878 SdrObject* pObj1=lhs->GetObj();
1879 SdrObject* pObj2=rhs->GetObj();
1880 if (pObj1==pObj2)
1882 sal_uInt32 nNum1=lhs->GetObjHdlNum();
1883 sal_uInt32 nNum2=rhs->GetObjHdlNum();
1884 if (nNum1==nNum2)
1886 if (eKind1==eKind2)
1887 return lhs<rhs; // Hack, to always get to the same sorting
1888 return static_cast<sal_uInt16>(eKind1)<static_cast<sal_uInt16>(eKind2);
1890 else
1891 return nNum1<nNum2;
1893 else
1895 return pObj1<pObj2;
1898 else
1900 return pPV1<pPV2;
1903 else
1905 return n1<n2;
1909 namespace {
1911 // Helper struct for re-sorting handles
1912 struct ImplHdlAndIndex
1914 SdrHdl* mpHdl;
1915 sal_uInt32 mnIndex;
1920 extern "C" {
1922 // Helper method for sorting handles taking care of OrdNums, keeping order in
1923 // single objects and re-sorting polygon handles intuitively
1924 static int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
1926 const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
1927 const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
1929 if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
1931 if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
1933 // same object and a path object
1934 if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
1935 && (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
1937 // both handles are point or control handles
1938 if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
1940 if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
1942 return -1;
1944 else
1946 return 1;
1949 else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
1951 return -1;
1953 else
1955 return 1;
1960 else
1962 if(!p1->mpHdl->GetObj())
1964 return -1;
1966 else if(!p2->mpHdl->GetObj())
1968 return 1;
1970 else
1972 // different objects, use OrdNum for sort
1973 const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
1974 const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
1976 if(nOrdNum1 < nOrdNum2)
1978 return -1;
1980 else
1982 return 1;
1987 // fallback to indices
1988 if(p1->mnIndex < p2->mnIndex)
1990 return -1;
1992 else
1994 return 1;
2000 void SdrHdlList::TravelFocusHdl(bool bForward)
2002 // security correction
2003 if (mnFocusIndex >= GetHdlCount())
2004 mnFocusIndex = SAL_MAX_SIZE;
2006 if(maList.empty())
2007 return;
2009 // take care of old handle
2010 const size_t nOldHdlNum(mnFocusIndex);
2011 SdrHdl* pOld = nullptr;
2012 if (nOldHdlNum < GetHdlCount())
2013 pOld = GetHdl(nOldHdlNum);
2015 if(pOld)
2017 // switch off old handle
2018 mnFocusIndex = SAL_MAX_SIZE;
2019 pOld->Touch();
2022 // allocate pointer array for sorted handle list
2023 std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[maList.size()]);
2025 // build sorted handle list
2026 for( size_t a = 0; a < maList.size(); ++a)
2028 pHdlAndIndex[a].mpHdl = maList[a].get();
2029 pHdlAndIndex[a].mnIndex = a;
2032 qsort(pHdlAndIndex.get(), maList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
2034 // look for old num in sorted array
2035 size_t nOldHdl(nOldHdlNum);
2037 if(nOldHdlNum != SAL_MAX_SIZE)
2039 for(size_t a = 0; a < maList.size(); ++a)
2041 if(pHdlAndIndex[a].mpHdl == pOld)
2043 nOldHdl = a;
2044 break;
2049 // build new HdlNum
2050 size_t nNewHdl(nOldHdl);
2052 // do the focus travel
2053 if(bForward)
2055 if(nOldHdl != SAL_MAX_SIZE)
2057 if(nOldHdl == maList.size() - 1)
2059 // end forward run
2060 nNewHdl = SAL_MAX_SIZE;
2062 else
2064 // simply the next handle
2065 nNewHdl++;
2068 else
2070 // start forward run at first entry
2071 nNewHdl = 0;
2074 else
2076 if(nOldHdl == SAL_MAX_SIZE)
2078 // start backward run at last entry
2079 nNewHdl = maList.size() - 1;
2082 else
2084 if(nOldHdl == 0)
2086 // end backward run
2087 nNewHdl = SAL_MAX_SIZE;
2089 else
2091 // simply the previous handle
2092 nNewHdl--;
2097 // build new HdlNum
2098 sal_uIntPtr nNewHdlNum(nNewHdl);
2100 // look for old num in sorted array
2101 if(nNewHdl != SAL_MAX_SIZE)
2103 SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
2105 for(size_t a = 0; a < maList.size(); ++a)
2107 if(maList[a].get() == pNew)
2109 nNewHdlNum = a;
2110 break;
2115 // take care of next handle
2116 if(nOldHdlNum != nNewHdlNum)
2118 mnFocusIndex = nNewHdlNum;
2119 if (mnFocusIndex < GetHdlCount())
2121 SdrHdl* pNew = GetHdl(mnFocusIndex);
2122 pNew->Touch();
2127 SdrHdl* SdrHdlList::GetFocusHdl() const
2129 if(mnFocusIndex < GetHdlCount())
2130 return GetHdl(mnFocusIndex);
2131 else
2132 return nullptr;
2135 void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
2137 if(!pNew)
2138 return;
2140 SdrHdl* pActual = GetFocusHdl();
2142 if(pActual && pActual == pNew)
2143 return;
2145 const size_t nNewHdlNum = GetHdlNum(pNew);
2147 if(nNewHdlNum != SAL_MAX_SIZE)
2149 mnFocusIndex = nNewHdlNum;
2151 if(pActual)
2153 pActual->Touch();
2156 pNew->Touch();
2160 void SdrHdlList::ResetFocusHdl()
2162 SdrHdl* pHdl = GetFocusHdl();
2164 mnFocusIndex = SAL_MAX_SIZE;
2166 if(pHdl)
2168 pHdl->Touch();
2173 SdrHdlList::SdrHdlList(SdrMarkView* pV)
2174 : mnFocusIndex(SAL_MAX_SIZE),
2175 pView(pV)
2177 nHdlSize = 3;
2178 bRotateShear = false;
2179 bMoveOutside = false;
2180 bDistortShear = false;
2183 SdrHdlList::~SdrHdlList()
2185 Clear();
2188 void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
2190 if(nHdlSize != nSiz)
2192 // remember new value
2193 nHdlSize = nSiz;
2195 // propagate change to IAOs
2196 for(size_t i=0; i<GetHdlCount(); ++i)
2198 SdrHdl* pHdl = GetHdl(i);
2199 pHdl->Touch();
2204 void SdrHdlList::SetMoveOutside(bool bOn)
2206 if(bMoveOutside != bOn)
2208 // remember new value
2209 bMoveOutside = bOn;
2211 // propagate change to IAOs
2212 for(size_t i=0; i<GetHdlCount(); ++i)
2214 SdrHdl* pHdl = GetHdl(i);
2215 pHdl->Touch();
2220 void SdrHdlList::SetRotateShear(bool bOn)
2222 bRotateShear = bOn;
2225 void SdrHdlList::SetDistortShear(bool bOn)
2227 bDistortShear = bOn;
2230 std::unique_ptr<SdrHdl> SdrHdlList::RemoveHdl(size_t nNum)
2232 std::unique_ptr<SdrHdl> pRetval = std::move(maList[nNum]);
2233 maList.erase(maList.begin() + nNum);
2235 return pRetval;
2238 void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
2240 maList.erase(std::remove_if(maList.begin(), maList.end(),
2241 [&eKind](std::unique_ptr<SdrHdl>& rItem) { return rItem->GetKind() == eKind; }),
2242 maList.end());
2245 void SdrHdlList::Clear()
2247 maList.clear();
2249 bRotateShear=false;
2250 bDistortShear=false;
2253 void SdrHdlList::Sort()
2255 // remember currently focused handle
2256 SdrHdl* pPrev = GetFocusHdl();
2258 std::sort( maList.begin(), maList.end(), ImpSdrHdlListSorter );
2260 // get now and compare
2261 SdrHdl* pNow = GetFocusHdl();
2263 if(pPrev == pNow)
2264 return;
2266 if(pPrev)
2268 pPrev->Touch();
2271 if(pNow)
2273 pNow->Touch();
2277 size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
2279 if (pHdl==nullptr)
2280 return SAL_MAX_SIZE;
2281 auto it = std::find_if( maList.begin(), maList.end(),
2282 [&](const std::unique_ptr<SdrHdl> & p) { return p.get() == pHdl; });
2283 assert(it != maList.end());
2284 if( it == maList.end() )
2285 return SAL_MAX_SIZE;
2286 return it - maList.begin();
2289 void SdrHdlList::AddHdl(std::unique_ptr<SdrHdl> pHdl)
2291 assert(pHdl);
2292 pHdl->SetHdlList(this);
2293 maList.push_back(std::move(pHdl));
2296 SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
2298 SdrHdl* pRet=nullptr;
2299 const size_t nCount=GetHdlCount();
2300 size_t nNum=nCount;
2301 while (nNum>0 && pRet==nullptr)
2303 nNum--;
2304 SdrHdl* pHdl=GetHdl(nNum);
2305 if (pHdl->IsHdlHit(rPnt))
2306 pRet=pHdl;
2308 return pRet;
2311 SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
2313 SdrHdl* pRet=nullptr;
2314 for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
2316 SdrHdl* pHdl=GetHdl(i);
2317 if (pHdl->GetKind()==eKind1)
2318 pRet=pHdl;
2320 return pRet;
2323 void SdrHdlList::MoveTo(SdrHdlList& rOther)
2325 for (auto & pHdl : maList)
2326 pHdl->SetHdlList(&rOther);
2327 rOther.maList.insert(rOther.maList.end(),
2328 std::make_move_iterator(maList.begin()), std::make_move_iterator(maList.end()));
2329 maList.clear();
2332 SdrCropHdl::SdrCropHdl(
2333 const Point& rPnt,
2334 SdrHdlKind eNewKind,
2335 double fShearX,
2336 double fRotation)
2337 : SdrHdl(rPnt, eNewKind),
2338 mfShearX(fShearX),
2339 mfRotation(fRotation)
2344 BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
2346 int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
2348 if( nSize <= 3 )
2350 nPixelSize = 13;
2351 nOffset = 0;
2353 else if( nSize <=4 )
2355 nPixelSize = 17;
2356 nOffset = 39;
2358 else
2360 nPixelSize = 21;
2361 nOffset = 90;
2364 switch( eKind )
2366 case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
2367 case SdrHdlKind::Upper: nX = 1; nY = 0; break;
2368 case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
2369 case SdrHdlKind::Left: nX = 0; nY = 1; break;
2370 case SdrHdlKind::Right: nX = 2; nY = 1; break;
2371 case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
2372 case SdrHdlKind::Lower: nX = 1; nY = 2; break;
2373 case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
2374 default: break;
2377 tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
2379 BitmapEx aRetval(rBitmap);
2380 aRetval.Crop(aSourceRect);
2381 return aRetval;
2385 void SdrCropHdl::CreateB2dIAObject()
2387 // first throw away old one
2388 GetRidOfIAObject();
2390 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2391 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2393 if( !pPageView || pView->areMarkHandlesHidden() )
2394 return;
2396 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2397 int nHdlSize = pHdlList->GetHdlSize();
2399 const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
2400 BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
2402 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2404 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
2406 if(rPageWindow.GetPaintWindow().OutputToWindow())
2408 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2409 if (xManager.is())
2411 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
2413 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
2415 // animate focused handles
2416 if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
2418 if( nHdlSize >= 2 )
2419 nHdlSize = 1;
2421 BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
2423 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
2425 pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
2426 aPosition,
2427 aBmpEx1,
2428 aBmpEx2,
2429 nBlinkTime,
2430 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2431 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2432 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
2433 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
2434 mfShearX,
2435 mfRotation));
2437 else
2439 // create centered handle as default
2440 pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx(
2441 aPosition,
2442 aBmpEx1,
2443 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2444 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2445 0.0,
2446 mfShearX,
2447 mfRotation));
2450 // OVERLAYMANAGER
2451 insertNewlyCreatedOverlayObjectForSdrHdl(
2452 std::move(pOverlayObject),
2453 rPageWindow.GetObjectContact(),
2454 *xManager);
2461 // with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
2462 // accordingly
2464 SdrCropViewHdl::SdrCropViewHdl(
2465 const basegfx::B2DHomMatrix& rObjectTransform,
2466 const Graphic& rGraphic,
2467 double fCropLeft,
2468 double fCropTop,
2469 double fCropRight,
2470 double fCropBottom)
2471 : SdrHdl(Point(), SdrHdlKind::User),
2472 maObjectTransform(rObjectTransform),
2473 maGraphic(rGraphic),
2474 mfCropLeft(fCropLeft),
2475 mfCropTop(fCropTop),
2476 mfCropRight(fCropRight),
2477 mfCropBottom(fCropBottom)
2481 namespace {
2483 void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
2484 assert(rotate != nullptr);
2486 // detect 180 degree rotation, this is the same as mirrored in X and Y,
2487 // thus change to mirroring. Prefer mirroring here. Use the equal call
2488 // with getSmallValue here, the original which uses rtl::math::approxEqual
2489 // is too correct here. Maybe this changes with enhanced precision in aw080
2490 // to the better so that this can be reduced to the more precise call again
2491 if(basegfx::fTools::equal(fabs(*rotate), F_PI, 0.000000001))
2493 scale.setX(scale.getX() * -1.0);
2494 scale.setY(scale.getY() * -1.0);
2495 *rotate = 0.0;
2501 void SdrCropViewHdl::CreateB2dIAObject()
2503 GetRidOfIAObject();
2504 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2505 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2507 if(!pPageView || pView->areMarkHandlesHidden())
2509 return;
2512 // decompose to have current translate and scale
2513 basegfx::B2DVector aScale, aTranslate;
2514 double fRotate, fShearX;
2516 maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
2518 if(aScale.equalZero())
2520 return;
2523 translateRotationToMirroring(aScale, &fRotate);
2525 // remember mirroring, reset at Scale and adapt crop values for usage;
2526 // mirroring can stay in the object transformation, so do not have to
2527 // cope with it here (except later for the CroppedImage transformation,
2528 // see below)
2529 const bool bMirroredX(aScale.getX() < 0.0);
2530 const bool bMirroredY(aScale.getY() < 0.0);
2531 double fCropLeft(mfCropLeft);
2532 double fCropTop(mfCropTop);
2533 double fCropRight(mfCropRight);
2534 double fCropBottom(mfCropBottom);
2536 if(bMirroredX)
2538 aScale.setX(-aScale.getX());
2541 if(bMirroredY)
2543 aScale.setY(-aScale.getY());
2546 // create target translate and scale
2547 const basegfx::B2DVector aTargetScale(
2548 aScale.getX() + fCropRight + fCropLeft,
2549 aScale.getY() + fCropBottom + fCropTop);
2550 const basegfx::B2DVector aTargetTranslate(
2551 aTranslate.getX() - fCropLeft,
2552 aTranslate.getY() - fCropTop);
2554 // create ranges to make comparisons
2555 const basegfx::B2DRange aCurrentForCompare(
2556 aTranslate.getX(), aTranslate.getY(),
2557 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
2558 basegfx::B2DRange aCropped(
2559 aTargetTranslate.getX(), aTargetTranslate.getY(),
2560 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
2562 if(aCropped.isEmpty())
2564 // nothing to return since cropped content is completely empty
2565 return;
2568 if(aCurrentForCompare.equal(aCropped))
2570 // no crop at all
2571 return;
2574 // back-transform to have values in unit coordinates
2575 basegfx::B2DHomMatrix aBackToUnit;
2576 aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
2577 aBackToUnit.scale(
2578 basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
2579 basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
2581 // transform cropped back to unit coordinates
2582 aCropped.transform(aBackToUnit);
2584 // prepare crop PolyPolygon
2585 basegfx::B2DPolygon aGraphicOutlinePolygon(
2586 basegfx::utils::createPolygonFromRect(
2587 aCropped));
2588 basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
2590 // current range is unit range
2591 basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
2593 aOverlap.intersect(aCropped);
2595 if(!aOverlap.isEmpty())
2597 aCropPolyPolygon.append(
2598 basegfx::utils::createPolygonFromRect(
2599 aOverlap));
2602 // transform to object coordinates to prepare for clip
2603 aCropPolyPolygon.transform(maObjectTransform);
2604 aGraphicOutlinePolygon.transform(maObjectTransform);
2606 // create cropped transformation
2607 basegfx::B2DHomMatrix aCroppedTransform;
2609 aCroppedTransform.scale(
2610 aCropped.getWidth(),
2611 aCropped.getHeight());
2612 aCroppedTransform.translate(
2613 aCropped.getMinX(),
2614 aCropped.getMinY());
2615 aCroppedTransform = maObjectTransform * aCroppedTransform;
2617 // prepare graphic primitive (transformed)
2618 const drawinglayer::primitive2d::Primitive2DReference aGraphic(
2619 new drawinglayer::primitive2d::GraphicPrimitive2D(
2620 aCroppedTransform,
2621 maGraphic));
2623 // prepare outline polygon for whole graphic
2624 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
2625 const basegfx::BColor aHilightColor(aSvtOptionsDrawinglayer.getHilightColor().getBColor());
2626 const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
2627 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
2628 aGraphicOutlinePolygon,
2629 aHilightColor));
2631 // combine these
2632 drawinglayer::primitive2d::Primitive2DContainer aCombination(2);
2633 aCombination[0] = aGraphic;
2634 aCombination[1] = aGraphicOutline;
2636 // embed to MaskPrimitive2D
2637 const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
2638 new drawinglayer::primitive2d::MaskPrimitive2D(
2639 aCropPolyPolygon,
2640 aCombination));
2642 // embed to UnifiedTransparencePrimitive2D
2643 const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
2644 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2645 drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
2646 0.8));
2648 const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
2650 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2652 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
2653 const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
2655 if(rPageWindow.GetPaintWindow().OutputToWindow())
2657 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2658 if(xManager.is())
2660 std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(aSequence));
2662 // only informative object, no hit
2663 pNew->setHittable(false);
2665 // OVERLAYMANAGER
2666 insertNewlyCreatedOverlayObjectForSdrHdl(
2667 std::move(pNew),
2668 rPageWindow.GetObjectContact(),
2669 *xManager);
2675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */