Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svdhdl.cxx
blob64f29976f5ca7db7229e1b124b9f7d04fae42297
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 <vcl/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 pObj(nullptr),
271 pPV(nullptr),
272 pHdlList(nullptr),
273 eKind(SdrHdlKind::Move),
274 nRotationAngle(0),
275 nObjHdlNum(0),
276 nPolyNum(0),
277 nPPntNum(0),
278 nSourceHdlNum(0),
279 bSelect(false),
280 b1PixMore(false),
281 bPlusHdl(false),
282 mbMoveOutside(false),
283 mbMouseOver(false)
287 SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
288 pObj(nullptr),
289 pPV(nullptr),
290 pHdlList(nullptr),
291 aPos(rPnt),
292 eKind(eNewKind),
293 nRotationAngle(0),
294 nObjHdlNum(0),
295 nPolyNum(0),
296 nPPntNum(0),
297 nSourceHdlNum(0),
298 bSelect(false),
299 b1PixMore(false),
300 bPlusHdl(false),
301 mbMoveOutside(false),
302 mbMouseOver(false)
306 SdrHdl::~SdrHdl()
308 GetRidOfIAObject();
311 void SdrHdl::Set1PixMore(bool bJa)
313 if(b1PixMore != bJa)
315 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(nRotationAngle != n)
337 nRotationAngle = n;
339 // create new display
340 Touch();
344 void SdrHdl::SetPos(const Point& rPnt)
346 if(aPos != rPnt)
348 // remember new position
349 aPos = rPnt;
351 // create new display
352 Touch();
356 void SdrHdl::SetSelected(bool bJa)
358 if(bSelect != bJa)
360 // remember new value
361 bSelect = bJa;
363 // create new display
364 Touch();
368 void SdrHdl::SetHdlList(SdrHdlList* pList)
370 if(pHdlList != pList)
372 // remember list
373 pHdlList = pList;
375 // now it's possible to create graphic representation
376 Touch();
380 void SdrHdl::SetObj(SdrObject* pNewObj)
382 if(pObj != pNewObj)
384 // remember new object
385 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(!pHdlList || !pHdlList->GetView() || pHdlList->GetView()->areMarkHandlesHidden())
411 return;
413 BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
414 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
416 bool bRot = pHdlList->IsRotateShear();
417 if(pObj)
418 eColIndex = bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
419 if(bRot)
421 // red rotation handles
422 if(pObj && bSelect)
423 eColIndex = BitmapColorIndex::Red;
424 else
425 eColIndex = BitmapColorIndex::LightRed;
428 switch(eKind)
430 case SdrHdlKind::Move:
432 eKindOfMarker = 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 = b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
485 else
487 eKindOfMarker = 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 = b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
532 eColIndex = BitmapColorIndex::Yellow;
533 break;
535 default:
536 break;
539 SdrMarkView* pView = 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(pHdlList->IsMoveOutside() || mbMoveOutside)
558 Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
560 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Upper || eKind == SdrHdlKind::UpperRight)
561 aMoveOutsideOffset.AdjustY( -(aOffset.Width()) );
562 if(eKind == SdrHdlKind::LowerLeft || eKind == SdrHdlKind::Lower || eKind == SdrHdlKind::LowerRight)
563 aMoveOutsideOffset.AdjustY(aOffset.Height() );
564 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Left || eKind == SdrHdlKind::LowerLeft)
565 aMoveOutsideOffset.AdjustX( -(aOffset.Width()) );
566 if(eKind == SdrHdlKind::UpperRight || eKind == SdrHdlKind::Right || 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(aPos.X(), 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 "rect7";
677 case BitmapMarkerKind::Rect_9x9:
678 return "rect9";
679 case BitmapMarkerKind::Rect_11x11:
680 return "rect11";
681 case BitmapMarkerKind::Rect_13x13:
682 return "rect13";
683 case BitmapMarkerKind::Circ_7x7:
684 case BitmapMarkerKind::Customshape_7x7:
685 return "circ7";
686 case BitmapMarkerKind::Circ_9x9:
687 case BitmapMarkerKind::Customshape_9x9:
688 return "circ9";
689 case BitmapMarkerKind::Circ_11x11:
690 case BitmapMarkerKind::Customshape_11x11:
691 return "circ11";
692 case BitmapMarkerKind::Elli_7x9:
693 return "elli7x9";
694 case BitmapMarkerKind::Elli_9x11:
695 return "elli9x11";
696 case BitmapMarkerKind::Elli_9x7:
697 return "elli9x7";
698 case BitmapMarkerKind::Elli_11x9:
699 return "elli11x9";
700 case BitmapMarkerKind::RectPlus_7x7:
701 return "rectplus7";
702 case BitmapMarkerKind::RectPlus_9x9:
703 return "rectplus9";
704 case BitmapMarkerKind::RectPlus_11x11:
705 return "rectplus11";
706 case BitmapMarkerKind::Crosshair:
707 return "cross";
708 case BitmapMarkerKind::Anchor:
709 case BitmapMarkerKind::AnchorTR:
710 return "anchor";
711 case BitmapMarkerKind::AnchorPressed:
712 case BitmapMarkerKind::AnchorPressedTR:
713 return "anchor-pressed";
714 case BitmapMarkerKind::Glue:
715 return "glue-selected";
716 case BitmapMarkerKind::Glue_Deselected:
717 return "glue-unselected";
718 default:
719 break;
721 return OUString();
724 OUString appendMarkerColor(BitmapColorIndex eIndex)
726 switch(eIndex)
728 case BitmapColorIndex::LightGreen:
729 return "1";
730 case BitmapColorIndex::Cyan:
731 return "2";
732 case BitmapColorIndex::LightCyan:
733 return "3";
734 case BitmapColorIndex::Red:
735 return "4";
736 case BitmapColorIndex::LightRed:
737 return "5";
738 case BitmapColorIndex::Yellow:
739 return "6";
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("svx/res/marker-");
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 vcl::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 (pHdlList && 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() && pHdlList && 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;
842 case BitmapMarkerKind::Crosshair:
843 eNextBigger = BitmapMarkerKind::Glue;
844 break;
846 case BitmapMarkerKind::Glue:
847 eNextBigger = BitmapMarkerKind::Crosshair;
848 break;
849 case BitmapMarkerKind::Glue_Deselected:
850 eNextBigger = BitmapMarkerKind::Glue;
851 break;
852 default:
853 break;
857 // create animated handle
858 BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, eColIndex);
859 BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, eColIndex);
861 // #i53216# Use system cursor blink time. Use the unsigned value.
862 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
863 const sal_uInt64 nBlinkTime(rStyleSettings.GetCursorBlinkTime());
865 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
867 // when anchor is used take upper left as reference point inside the handle
868 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime));
870 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
872 // AnchorTR for SW, take top right as (0,0)
873 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
874 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1), 0,
875 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1), 0));
877 else
879 // create centered handle as default
880 pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
881 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
882 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
883 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
884 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1));
887 else
889 // create normal handle: use ImpGetBitmapEx(...) now
890 BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, eColIndex);
892 // When the image with handles is not found, the bitmap returned is
893 // empty. This is a problem when we use LibreOffice as a library
894 // (through LOKit - for example on Android) even when we don't show
895 // the handles, because the hit test would always return false.
897 // This HACK replaces the empty bitmap with a black 13x13 bitmap handle
898 // so that the hit test works for this case.
899 if (aBmpEx.IsEmpty())
901 aBmpEx = BitmapEx(Size(13, 13), vcl::PixelFormat::N24_BPP);
902 aBmpEx.Erase(COL_BLACK);
905 if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
907 // upper left as reference point inside the handle for AnchorPressed, too
908 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx));
910 else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
912 // AnchorTR for SW, take top right as (0,0)
913 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
914 static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1), 0));
916 else
918 sal_uInt16 nCenX(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1) >> 1);
919 sal_uInt16 nCenY(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1) >> 1);
921 if(aMoveOutsideOffset.X() > 0)
923 nCenX = 0;
925 else if(aMoveOutsideOffset.X() < 0)
927 nCenX = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1);
930 if(aMoveOutsideOffset.Y() > 0)
932 nCenY = 0;
934 else if(aMoveOutsideOffset.Y() < 0)
936 nCenY = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1);
939 // create centered handle as default
940 pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx, nCenX, nCenY));
944 return pRetval;
947 bool SdrHdl::IsHdlHit(const Point& rPnt) const
949 // OVERLAYMANAGER
950 basegfx::B2DPoint aPosition(rPnt.X(), rPnt.Y());
951 return maOverlayGroup.isHitLogic(aPosition);
954 PointerStyle SdrHdl::GetPointer() const
956 PointerStyle ePtr=PointerStyle::Move;
957 const bool bSize=eKind>=SdrHdlKind::UpperLeft && eKind<=SdrHdlKind::LowerRight;
958 const bool bRot=pHdlList!=nullptr && pHdlList->IsRotateShear();
959 const bool bDis=pHdlList!=nullptr && pHdlList->IsDistortShear();
960 if (bSize && pHdlList!=nullptr && (bRot || bDis)) {
961 switch (eKind) {
962 case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
963 case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight: ePtr=bRot ? PointerStyle::Rotate : PointerStyle::RefHand; break;
964 case SdrHdlKind::Left : case SdrHdlKind::Right: ePtr=PointerStyle::VShear; break;
965 case SdrHdlKind::Upper: case SdrHdlKind::Lower: ePtr=PointerStyle::HShear; break;
966 default:
967 break;
969 } else {
970 // When resizing rotated rectangles, rotate the mouse cursor slightly, too
971 if (bSize && nRotationAngle!=0_deg100) {
972 Degree100 nHdlAngle(0);
973 switch (eKind) {
974 case SdrHdlKind::LowerRight: nHdlAngle=31500_deg100; break;
975 case SdrHdlKind::Lower: nHdlAngle=27000_deg100; break;
976 case SdrHdlKind::LowerLeft: nHdlAngle=22500_deg100; break;
977 case SdrHdlKind::Left : nHdlAngle=18000_deg100; break;
978 case SdrHdlKind::UpperLeft: nHdlAngle=13500_deg100; break;
979 case SdrHdlKind::Upper: nHdlAngle=9000_deg100; break;
980 case SdrHdlKind::UpperRight: nHdlAngle=4500_deg100; break;
981 case SdrHdlKind::Right: nHdlAngle=0_deg100; break;
982 default:
983 break;
985 // a little bit more (for rounding)
986 nHdlAngle = NormAngle36000(nHdlAngle + nRotationAngle + 2249_deg100);
987 nHdlAngle/=4500_deg100;
988 switch (static_cast<sal_uInt8>(nHdlAngle.get())) {
989 case 0: ePtr=PointerStyle::ESize; break;
990 case 1: ePtr=PointerStyle::NESize; break;
991 case 2: ePtr=PointerStyle::NSize; break;
992 case 3: ePtr=PointerStyle::NWSize; break;
993 case 4: ePtr=PointerStyle::WSize; break;
994 case 5: ePtr=PointerStyle::SWSize; break;
995 case 6: ePtr=PointerStyle::SSize; break;
996 case 7: ePtr=PointerStyle::SESize; break;
997 } // switch
998 } else {
999 switch (eKind) {
1000 case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
1001 case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
1002 case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
1003 case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
1004 case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
1005 case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
1006 case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
1007 case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
1008 case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
1009 case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
1010 case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
1011 case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
1012 case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
1013 case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
1014 case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::RefHand; break;
1015 default:
1016 break;
1020 return ePtr;
1023 bool SdrHdl::IsFocusHdl() const
1025 switch(eKind)
1027 case SdrHdlKind::UpperLeft:
1028 case SdrHdlKind::Upper:
1029 case SdrHdlKind::UpperRight:
1030 case SdrHdlKind::Left:
1031 case SdrHdlKind::Right:
1032 case SdrHdlKind::LowerLeft:
1033 case SdrHdlKind::Lower:
1034 case SdrHdlKind::LowerRight:
1036 // if it's an activated TextEdit, it's moved to extended points
1037 return !pHdlList || !pHdlList->IsMoveOutside();
1040 case SdrHdlKind::Move: // handle to move object
1041 case SdrHdlKind::Poly: // selected point of polygon or curve
1042 case SdrHdlKind::BezierWeight: // weight at a curve
1043 case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
1044 case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
1045 case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
1046 case SdrHdlKind::Glue: // gluepoint
1048 // for SJ and the CustomShapeHandles:
1049 case SdrHdlKind::CustomShape1:
1051 case SdrHdlKind::User:
1053 return true;
1056 default:
1058 return false;
1063 void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
1067 void SdrHdl::onHelpRequest()
1071 void SdrHdl::onMouseLeave()
1075 BitmapEx SdrHdl::createGluePointBitmap()
1077 return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
1080 void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
1081 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
1082 const sdr::contact::ObjectContact& rObjectContact,
1083 sdr::overlay::OverlayManager& rOverlayManager)
1085 // check if we have an OverlayObject
1086 if(!pOverlayObject)
1088 return;
1091 // Add GridOffset for non-linear ViewToDevice transformation (calc)
1092 if(nullptr != GetObj() && rObjectContact.supportsGridOffsets())
1094 basegfx::B2DVector aOffset(0.0, 0.0);
1095 const sdr::contact::ViewObjectContact& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
1096 const_cast<sdr::contact::ObjectContact&>(rObjectContact)));
1098 rObjectContact.calculateGridOffsetForViewOjectContact(aOffset, rVOC);
1100 if(!aOffset.equalZero())
1102 pOverlayObject->setOffset(aOffset);
1106 // add to OverlayManager
1107 rOverlayManager.add(*pOverlayObject);
1109 // add to local OverlayObjectList - ownership change (!)
1110 maOverlayGroup.append(std::move(pOverlayObject));
1113 SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
1114 : SdrHdl(rRef, SdrHdlKind::Color),
1115 aMarkerSize(rSize),
1116 bUseLuminance(bLum)
1118 if(IsUseLuminance())
1119 aCol = GetLuminance(aCol);
1121 // remember color
1122 aMarkerColor = aCol;
1125 SdrHdlColor::~SdrHdlColor()
1129 void SdrHdlColor::CreateB2dIAObject()
1131 // first throw away old one
1132 GetRidOfIAObject();
1134 if(!pHdlList)
1135 return;
1137 SdrMarkView* pView = pHdlList->GetView();
1139 if(!pView || pView->areMarkHandlesHidden())
1140 return;
1142 SdrPageView* pPageView = pView->GetSdrPageView();
1144 if(!pPageView)
1145 return;
1147 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1149 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1151 if(rPageWindow.GetPaintWindow().OutputToWindow())
1153 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1154 if (xManager.is())
1156 BitmapEx aBmpCol(CreateColorDropper(aMarkerColor));
1157 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1158 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1159 sdr::overlay::OverlayBitmapEx(
1160 aPosition,
1161 aBmpCol,
1162 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Width() - 1) >> 1,
1163 static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Height() - 1) >> 1
1166 // OVERLAYMANAGER
1167 insertNewlyCreatedOverlayObjectForSdrHdl(
1168 std::move(pNewOverlayObject),
1169 rPageWindow.GetObjectContact(),
1170 *xManager);
1176 BitmapEx SdrHdlColor::CreateColorDropper(Color aCol)
1178 // get the Bitmap
1179 VclPtr<VirtualDevice> pWrite(VclPtr<VirtualDevice>::Create());
1180 pWrite->SetOutputSizePixel(aMarkerSize);
1181 pWrite->SetBackground(aCol);
1182 pWrite->Erase();
1184 // draw outer border
1185 sal_Int32 nWidth = aMarkerSize.Width();
1186 sal_Int32 nHeight = aMarkerSize.Height();
1188 pWrite->SetLineColor(COL_LIGHTGRAY);
1189 pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
1190 pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
1191 pWrite->SetLineColor(COL_GRAY);
1192 pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
1193 pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
1195 // draw lighter UpperLeft
1196 const Color aLightColor(
1197 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1198 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1199 static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
1200 pWrite->SetLineColor(aLightColor);
1201 pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
1202 pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
1204 // draw darker LowerRight
1205 const Color aDarkColor(
1206 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1207 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1208 static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
1209 pWrite->SetLineColor(aDarkColor);
1210 pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
1211 pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
1213 return pWrite->GetBitmapEx(Point(0,0), aMarkerSize);
1216 Color SdrHdlColor::GetLuminance(const Color& rCol)
1218 sal_uInt8 aLum = rCol.GetLuminance();
1219 Color aRetval(aLum, aLum, aLum);
1220 return aRetval;
1223 void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
1225 if(IsUseLuminance())
1226 aNew = GetLuminance(aNew);
1228 if(aMarkerColor != aNew)
1230 // remember new color
1231 aMarkerColor = aNew;
1233 // create new display
1234 Touch();
1236 // tell about change
1237 if(bCallLink)
1238 aColorChangeHdl.Call(this);
1242 void SdrHdlColor::SetSize(const Size& rNew)
1244 if(rNew != aMarkerSize)
1246 // remember new size
1247 aMarkerSize = rNew;
1249 // create new display
1250 Touch();
1254 SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
1255 : SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
1256 , pColHdl1(nullptr)
1257 , pColHdl2(nullptr)
1258 , a2ndPos(rRef2)
1259 , bGradient(bGrad)
1260 , bMoveSingleHandle(false)
1261 , bMoveFirstHandle(false)
1265 SdrHdlGradient::~SdrHdlGradient()
1269 void SdrHdlGradient::Set2ndPos(const Point& rPnt)
1271 if(a2ndPos != rPnt)
1273 // remember new position
1274 a2ndPos = rPnt;
1276 // create new display
1277 Touch();
1281 void SdrHdlGradient::CreateB2dIAObject()
1283 // first throw away old one
1284 GetRidOfIAObject();
1286 if(!pHdlList)
1287 return;
1289 SdrMarkView* pView = pHdlList->GetView();
1291 if(!pView || pView->areMarkHandlesHidden())
1292 return;
1294 SdrPageView* pPageView = pView->GetSdrPageView();
1296 if(!pPageView)
1297 return;
1299 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1301 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1303 if(rPageWindow.GetPaintWindow().OutputToWindow())
1305 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1306 if (xManager.is())
1308 // striped line in between
1309 basegfx::B2DVector aVec(a2ndPos.X() - aPos.X(), a2ndPos.Y() - aPos.Y());
1310 double fVecLen = aVec.getLength();
1311 double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
1312 double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
1313 aVec.normalize();
1314 basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
1315 sal_Int32 nMidX = static_cast<sal_Int32>(aPos.X() + aVec.getX() * fLongPercentArrow);
1316 sal_Int32 nMidY = static_cast<sal_Int32>(aPos.Y() + aVec.getY() * fLongPercentArrow);
1317 Point aMidPoint(nMidX, nMidY);
1319 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1320 basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
1322 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1323 sdr::overlay::OverlayLineStriped(
1324 aPosition, aMidPos
1327 pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
1329 // OVERLAYMANAGER
1330 insertNewlyCreatedOverlayObjectForSdrHdl(
1331 std::move(pNewOverlayObject),
1332 rPageWindow.GetObjectContact(),
1333 *xManager);
1335 // arrowhead
1336 Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1337 aMidPoint.Y() + static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1338 Point aRight(aMidPoint.X() - static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
1339 aMidPoint.Y() - static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
1341 basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
1342 basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
1343 basegfx::B2DPoint aPosition2(a2ndPos.X(), a2ndPos.Y());
1345 pNewOverlayObject.reset(new
1346 sdr::overlay::OverlayTriangle(
1347 aPositionLeft,
1348 aPosition2,
1349 aPositionRight,
1350 IsGradient() ? COL_BLACK : COL_BLUE
1353 // OVERLAYMANAGER
1354 insertNewlyCreatedOverlayObjectForSdrHdl(
1355 std::move(pNewOverlayObject),
1356 rPageWindow.GetObjectContact(),
1357 *xManager);
1363 IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
1365 if(GetObj())
1366 FromIAOToItem(GetObj(), true, true);
1369 void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
1371 // from IAO positions and colors to gradient
1372 const SfxItemSet& rSet = _pObj->GetMergedItemSet();
1374 GradTransGradient aOldGradTransGradient;
1375 GradTransGradient aGradTransGradient;
1376 GradTransVector aGradTransVector;
1378 aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
1379 aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
1380 if(pColHdl1)
1381 aGradTransVector.aCol1 = pColHdl1->GetColor();
1382 if(pColHdl2)
1383 aGradTransVector.aCol2 = pColHdl2->GetColor();
1385 if(IsGradient())
1386 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1387 else
1388 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1390 // transform vector data to gradient
1391 GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);
1393 if(bSetItemOnObject)
1395 SdrModel& rModel(_pObj->getSdrModelFromSdrObject());
1396 SfxItemSet aNewSet(rModel.GetItemPool());
1397 const OUString aString;
1399 if(IsGradient())
1401 XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
1402 aNewSet.Put(aNewGradItem);
1404 else
1406 XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
1407 aNewSet.Put(aNewTransItem);
1410 if(bUndo && rModel.IsUndoEnabled())
1412 rModel.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
1413 rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
1414 rModel.EndUndo();
1417 pObj->SetMergedItemSetAndBroadcast(aNewSet);
1420 // back transformation, set values on pIAOHandle
1421 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
1423 SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1424 Set2ndPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1425 if(pColHdl1)
1427 pColHdl1->SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1428 pColHdl1->SetColor(aGradTransVector.aCol1);
1430 if(pColHdl2)
1432 pColHdl2->SetPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1433 pColHdl2->SetColor(aGradTransVector.aCol2);
1438 SdrHdlLine::~SdrHdlLine() {}
1440 void SdrHdlLine::CreateB2dIAObject()
1442 // first throw away old one
1443 GetRidOfIAObject();
1445 if(!pHdlList)
1446 return;
1448 SdrMarkView* pView = pHdlList->GetView();
1450 if(!(pView && !pView->areMarkHandlesHidden() && pHdl1 && 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(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1468 basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), 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(!pHdlList)
1504 return;
1506 SdrMarkView* pView = 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(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1526 basegfx::B2DPoint aPosition2(aPos.X(), 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 aWireframePoly = rWireframePoly;
1559 void E3dVolumeMarker::CreateB2dIAObject()
1561 // create lines
1562 if(!pHdlList)
1563 return;
1565 SdrMarkView* pView = 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() && aWireframePoly.count())
1584 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
1585 sdr::overlay::OverlayPolyPolygonStripedAndFilled(
1586 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(nObjHdlNum <= 1 && pObj)
1609 // first throw away old one
1610 GetRidOfIAObject();
1612 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1613 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1615 if(pHdlList)
1617 SdrMarkView* pView = pHdlList->GetView();
1619 if(pView && !pView->areMarkHandlesHidden())
1621 const SdrEdgeObj* pEdge = static_cast<SdrEdgeObj*>(pObj);
1623 if(pEdge->GetConnectedNode(nObjHdlNum == 0) != nullptr)
1624 eColIndex = BitmapColorIndex::LightRed;
1626 if(nPPntNum < 2)
1628 // Handle with plus sign inside
1629 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
1632 SdrPageView* pPageView = pView->GetSdrPageView();
1634 if(pPageView)
1636 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1638 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1640 if(rPageWindow.GetPaintWindow().OutputToWindow())
1642 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1643 if (xManager.is())
1645 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1646 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1647 aPosition,
1648 eColIndex,
1649 eKindOfMarker));
1651 // OVERLAYMANAGER
1652 insertNewlyCreatedOverlayObjectForSdrHdl(
1653 std::move(pNewOverlayObject),
1654 rPageWindow.GetObjectContact(),
1655 *xManager);
1663 else
1665 // call parent
1666 SdrHdl::CreateB2dIAObject();
1670 void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
1672 if(eLineCode != eCode)
1674 // remember new value
1675 eLineCode = eCode;
1677 // create new display
1678 Touch();
1682 PointerStyle ImpEdgeHdl::GetPointer() const
1684 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1685 if (pEdge==nullptr)
1686 return SdrHdl::GetPointer();
1687 if (nObjHdlNum<=1)
1688 return PointerStyle::MovePoint;
1689 if (IsHorzDrag())
1690 return PointerStyle::ESize;
1691 else
1692 return PointerStyle::SSize;
1695 bool ImpEdgeHdl::IsHorzDrag() const
1697 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1698 if (pEdge==nullptr)
1699 return false;
1700 if (nObjHdlNum<=1)
1701 return false;
1703 SdrEdgeKind eEdgeKind = pEdge->GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1705 const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
1706 if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
1708 return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
1710 else if (eEdgeKind==SdrEdgeKind::ThreeLines)
1712 tools::Long nAngle=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
1713 return nAngle==0 || nAngle==18000;
1715 return false;
1719 ImpMeasureHdl::~ImpMeasureHdl()
1723 void ImpMeasureHdl::CreateB2dIAObject()
1725 // first throw away old one
1726 GetRidOfIAObject();
1728 if(!pHdlList)
1729 return;
1731 SdrMarkView* pView = pHdlList->GetView();
1733 if(!pView || pView->areMarkHandlesHidden())
1734 return;
1736 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1737 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
1739 if(nObjHdlNum > 1)
1741 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1744 if(bSelect)
1746 eColIndex = BitmapColorIndex::Cyan;
1749 SdrPageView* pPageView = pView->GetSdrPageView();
1751 if(!pPageView)
1752 return;
1754 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1756 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1758 if(rPageWindow.GetPaintWindow().OutputToWindow())
1760 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1761 if (xManager.is())
1763 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1764 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
1765 aPosition,
1766 eColIndex,
1767 eKindOfMarker));
1769 // OVERLAYMANAGER
1770 insertNewlyCreatedOverlayObjectForSdrHdl(
1771 std::move(pNewOverlayObject),
1772 rPageWindow.GetObjectContact(),
1773 *xManager);
1779 PointerStyle ImpMeasureHdl::GetPointer() const
1781 switch (nObjHdlNum)
1783 case 0: case 1: return PointerStyle::Hand;
1784 case 2: case 3: return PointerStyle::MovePoint;
1785 case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
1786 } // switch
1787 return PointerStyle::NotAllowed;
1791 ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
1792 SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
1793 maRect(rRect)
1797 void ImpTextframeHdl::CreateB2dIAObject()
1799 // first throw away old one
1800 GetRidOfIAObject();
1802 if(!pHdlList)
1803 return;
1805 SdrMarkView* pView = pHdlList->GetView();
1807 if(!pView || pView->areMarkHandlesHidden())
1808 return;
1810 SdrPageView* pPageView = pView->GetSdrPageView();
1812 if(!pPageView)
1813 return;
1815 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1817 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1819 if(rPageWindow.GetPaintWindow().OutputToWindow())
1821 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
1822 if (xManager.is())
1824 const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
1825 const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
1826 const Color aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
1827 const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
1829 std::unique_ptr<sdr::overlay::OverlayRectangle> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
1830 aTopLeft,
1831 aBottomRight,
1832 aHilightColor,
1833 fTransparence,
1834 3.0,
1835 3.0,
1836 -toRadians(nRotationAngle),
1837 true)); // allow animation; the Handle is not shown at text edit time
1839 pNewOverlayObject->setHittable(false);
1841 // OVERLAYMANAGER
1842 insertNewlyCreatedOverlayObjectForSdrHdl(
1843 std::move(pNewOverlayObject),
1844 rPageWindow.GetObjectContact(),
1845 *xManager);
1852 static bool ImpSdrHdlListSorter(std::unique_ptr<SdrHdl> const& lhs, std::unique_ptr<SdrHdl> const& rhs)
1854 SdrHdlKind eKind1=lhs->GetKind();
1855 SdrHdlKind eKind2=rhs->GetKind();
1856 // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
1857 unsigned n1=1;
1858 unsigned n2=1;
1859 if (eKind1!=eKind2)
1861 if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
1862 else if (eKind1==SdrHdlKind::Glue) n1=2;
1863 else if (eKind1==SdrHdlKind::User) n1=3;
1864 else if (eKind1==SdrHdlKind::SmartTag) n1=0;
1865 if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
1866 else if (eKind2==SdrHdlKind::Glue) n2=2;
1867 else if (eKind2==SdrHdlKind::User) n2=3;
1868 else if (eKind2==SdrHdlKind::SmartTag) n2=0;
1870 if (lhs->IsPlusHdl()) n1=4;
1871 if (rhs->IsPlusHdl()) n2=4;
1872 if (n1==n2)
1874 // Level 2: PageView (Pointer)
1875 SdrPageView* pPV1=lhs->GetPageView();
1876 SdrPageView* pPV2=rhs->GetPageView();
1877 if (pPV1==pPV2)
1879 // Level 3: Position (x+y)
1880 SdrObject* pObj1=lhs->GetObj();
1881 SdrObject* pObj2=rhs->GetObj();
1882 if (pObj1==pObj2)
1884 sal_uInt32 nNum1=lhs->GetObjHdlNum();
1885 sal_uInt32 nNum2=rhs->GetObjHdlNum();
1886 if (nNum1==nNum2)
1888 if (eKind1==eKind2)
1889 return lhs<rhs; // Hack, to always get to the same sorting
1890 return static_cast<sal_uInt16>(eKind1)<static_cast<sal_uInt16>(eKind2);
1892 else
1893 return nNum1<nNum2;
1895 else
1897 return pObj1<pObj2;
1900 else
1902 return pPV1<pPV2;
1905 else
1907 return n1<n2;
1911 namespace {
1913 // Helper struct for re-sorting handles
1914 struct ImplHdlAndIndex
1916 SdrHdl* mpHdl;
1917 sal_uInt32 mnIndex;
1922 extern "C" {
1924 // Helper method for sorting handles taking care of OrdNums, keeping order in
1925 // single objects and re-sorting polygon handles intuitively
1926 static int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
1928 const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
1929 const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
1931 if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
1933 if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
1935 // same object and a path object
1936 if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
1937 && (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
1939 // both handles are point or control handles
1940 if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
1942 if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
1944 return -1;
1946 else
1948 return 1;
1951 else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
1953 return -1;
1955 else
1957 return 1;
1962 else
1964 if(!p1->mpHdl->GetObj())
1966 return -1;
1968 else if(!p2->mpHdl->GetObj())
1970 return 1;
1972 else
1974 // different objects, use OrdNum for sort
1975 const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
1976 const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
1978 if(nOrdNum1 < nOrdNum2)
1980 return -1;
1982 else
1984 return 1;
1989 // fallback to indices
1990 if(p1->mnIndex < p2->mnIndex)
1992 return -1;
1994 else
1996 return 1;
2002 void SdrHdlList::TravelFocusHdl(bool bForward)
2004 // security correction
2005 if (mnFocusIndex >= GetHdlCount())
2006 mnFocusIndex = SAL_MAX_SIZE;
2008 if(maList.empty())
2009 return;
2011 // take care of old handle
2012 const size_t nOldHdlNum(mnFocusIndex);
2013 SdrHdl* pOld = nullptr;
2014 if (nOldHdlNum < GetHdlCount())
2015 pOld = GetHdl(nOldHdlNum);
2017 if(pOld)
2019 // switch off old handle
2020 mnFocusIndex = SAL_MAX_SIZE;
2021 pOld->Touch();
2024 // allocate pointer array for sorted handle list
2025 std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[maList.size()]);
2027 // build sorted handle list
2028 for( size_t a = 0; a < maList.size(); ++a)
2030 pHdlAndIndex[a].mpHdl = maList[a].get();
2031 pHdlAndIndex[a].mnIndex = a;
2034 qsort(pHdlAndIndex.get(), maList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
2036 // look for old num in sorted array
2037 size_t nOldHdl(nOldHdlNum);
2039 if(nOldHdlNum != SAL_MAX_SIZE)
2041 for(size_t a = 0; a < maList.size(); ++a)
2043 if(pHdlAndIndex[a].mpHdl == pOld)
2045 nOldHdl = a;
2046 break;
2051 // build new HdlNum
2052 size_t nNewHdl(nOldHdl);
2054 // do the focus travel
2055 if(bForward)
2057 if(nOldHdl != SAL_MAX_SIZE)
2059 if(nOldHdl == maList.size() - 1)
2061 // end forward run
2062 nNewHdl = SAL_MAX_SIZE;
2064 else
2066 // simply the next handle
2067 nNewHdl++;
2070 else
2072 // start forward run at first entry
2073 nNewHdl = 0;
2076 else
2078 if(nOldHdl == SAL_MAX_SIZE)
2080 // start backward run at last entry
2081 nNewHdl = maList.size() - 1;
2084 else
2086 if(nOldHdl == 0)
2088 // end backward run
2089 nNewHdl = SAL_MAX_SIZE;
2091 else
2093 // simply the previous handle
2094 nNewHdl--;
2099 // build new HdlNum
2100 sal_uIntPtr nNewHdlNum(nNewHdl);
2102 // look for old num in sorted array
2103 if(nNewHdl != SAL_MAX_SIZE)
2105 SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
2107 for(size_t a = 0; a < maList.size(); ++a)
2109 if(maList[a].get() == pNew)
2111 nNewHdlNum = a;
2112 break;
2117 // take care of next handle
2118 if(nOldHdlNum != nNewHdlNum)
2120 mnFocusIndex = nNewHdlNum;
2121 if (mnFocusIndex < GetHdlCount())
2123 SdrHdl* pNew = GetHdl(mnFocusIndex);
2124 pNew->Touch();
2129 SdrHdl* SdrHdlList::GetFocusHdl() const
2131 if(mnFocusIndex < GetHdlCount())
2132 return GetHdl(mnFocusIndex);
2133 else
2134 return nullptr;
2137 void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
2139 if(!pNew)
2140 return;
2142 SdrHdl* pActual = GetFocusHdl();
2144 if(pActual && pActual == pNew)
2145 return;
2147 const size_t nNewHdlNum = GetHdlNum(pNew);
2149 if(nNewHdlNum != SAL_MAX_SIZE)
2151 mnFocusIndex = nNewHdlNum;
2153 if(pActual)
2155 pActual->Touch();
2158 pNew->Touch();
2162 void SdrHdlList::ResetFocusHdl()
2164 SdrHdl* pHdl = GetFocusHdl();
2166 mnFocusIndex = SAL_MAX_SIZE;
2168 if(pHdl)
2170 pHdl->Touch();
2175 SdrHdlList::SdrHdlList(SdrMarkView* pV)
2176 : mnFocusIndex(SAL_MAX_SIZE),
2177 pView(pV)
2179 nHdlSize = 3;
2180 bRotateShear = false;
2181 bMoveOutside = false;
2182 bDistortShear = false;
2185 SdrHdlList::~SdrHdlList()
2187 Clear();
2190 void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
2192 if(nHdlSize != nSiz)
2194 // remember new value
2195 nHdlSize = nSiz;
2197 // propagate change to IAOs
2198 for(size_t i=0; i<GetHdlCount(); ++i)
2200 SdrHdl* pHdl = GetHdl(i);
2201 pHdl->Touch();
2206 void SdrHdlList::SetMoveOutside(bool bOn)
2208 if(bMoveOutside != bOn)
2210 // remember new value
2211 bMoveOutside = bOn;
2213 // propagate change to IAOs
2214 for(size_t i=0; i<GetHdlCount(); ++i)
2216 SdrHdl* pHdl = GetHdl(i);
2217 pHdl->Touch();
2222 void SdrHdlList::SetRotateShear(bool bOn)
2224 bRotateShear = bOn;
2227 void SdrHdlList::SetDistortShear(bool bOn)
2229 bDistortShear = bOn;
2232 std::unique_ptr<SdrHdl> SdrHdlList::RemoveHdl(size_t nNum)
2234 std::unique_ptr<SdrHdl> pRetval = std::move(maList[nNum]);
2235 maList.erase(maList.begin() + nNum);
2237 return pRetval;
2240 void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
2242 maList.erase(std::remove_if(maList.begin(), maList.end(),
2243 [&eKind](std::unique_ptr<SdrHdl>& rItem) { return rItem->GetKind() == eKind; }),
2244 maList.end());
2247 void SdrHdlList::Clear()
2249 maList.clear();
2251 bRotateShear=false;
2252 bDistortShear=false;
2255 void SdrHdlList::Sort()
2257 // remember currently focused handle
2258 SdrHdl* pPrev = GetFocusHdl();
2260 std::sort( maList.begin(), maList.end(), ImpSdrHdlListSorter );
2262 // get now and compare
2263 SdrHdl* pNow = GetFocusHdl();
2265 if(pPrev == pNow)
2266 return;
2268 if(pPrev)
2270 pPrev->Touch();
2273 if(pNow)
2275 pNow->Touch();
2279 size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
2281 if (pHdl==nullptr)
2282 return SAL_MAX_SIZE;
2283 auto it = std::find_if( maList.begin(), maList.end(),
2284 [&](const std::unique_ptr<SdrHdl> & p) { return p.get() == pHdl; });
2285 assert(it != maList.end());
2286 if( it == maList.end() )
2287 return SAL_MAX_SIZE;
2288 return it - maList.begin();
2291 void SdrHdlList::AddHdl(std::unique_ptr<SdrHdl> pHdl)
2293 assert(pHdl);
2294 pHdl->SetHdlList(this);
2295 maList.push_back(std::move(pHdl));
2298 SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
2300 SdrHdl* pRet=nullptr;
2301 const size_t nCount=GetHdlCount();
2302 size_t nNum=nCount;
2303 while (nNum>0 && pRet==nullptr)
2305 nNum--;
2306 SdrHdl* pHdl=GetHdl(nNum);
2307 if (pHdl->IsHdlHit(rPnt))
2308 pRet=pHdl;
2310 return pRet;
2313 SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
2315 SdrHdl* pRet=nullptr;
2316 for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
2318 SdrHdl* pHdl=GetHdl(i);
2319 if (pHdl->GetKind()==eKind1)
2320 pRet=pHdl;
2322 return pRet;
2325 void SdrHdlList::MoveTo(SdrHdlList& rOther)
2327 for (auto & pHdl : maList)
2328 pHdl->SetHdlList(&rOther);
2329 rOther.maList.insert(rOther.maList.end(),
2330 std::make_move_iterator(maList.begin()), std::make_move_iterator(maList.end()));
2331 maList.clear();
2334 SdrCropHdl::SdrCropHdl(
2335 const Point& rPnt,
2336 SdrHdlKind eNewKind,
2337 double fShearX,
2338 double fRotation)
2339 : SdrHdl(rPnt, eNewKind),
2340 mfShearX(fShearX),
2341 mfRotation(fRotation)
2346 BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
2348 int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
2350 if( nSize <= 3 )
2352 nPixelSize = 13;
2353 nOffset = 0;
2355 else if( nSize <=4 )
2357 nPixelSize = 17;
2358 nOffset = 39;
2360 else
2362 nPixelSize = 21;
2363 nOffset = 90;
2366 switch( eKind )
2368 case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
2369 case SdrHdlKind::Upper: nX = 1; nY = 0; break;
2370 case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
2371 case SdrHdlKind::Left: nX = 0; nY = 1; break;
2372 case SdrHdlKind::Right: nX = 2; nY = 1; break;
2373 case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
2374 case SdrHdlKind::Lower: nX = 1; nY = 2; break;
2375 case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
2376 default: break;
2379 tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
2381 BitmapEx aRetval(rBitmap);
2382 aRetval.Crop(aSourceRect);
2383 return aRetval;
2387 void SdrCropHdl::CreateB2dIAObject()
2389 // first throw away old one
2390 GetRidOfIAObject();
2392 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2393 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2395 if( !pPageView || pView->areMarkHandlesHidden() )
2396 return;
2398 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2399 int nHdlSize = pHdlList->GetHdlSize();
2401 const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
2402 BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
2404 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2406 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
2408 if(rPageWindow.GetPaintWindow().OutputToWindow())
2410 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2411 if (xManager.is())
2413 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
2415 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
2417 // animate focused handles
2418 if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
2420 if( nHdlSize >= 2 )
2421 nHdlSize = 1;
2423 BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
2425 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
2427 pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
2428 aPosition,
2429 aBmpEx1,
2430 aBmpEx2,
2431 nBlinkTime,
2432 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2433 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2434 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
2435 static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
2436 mfShearX,
2437 mfRotation));
2439 else
2441 // create centered handle as default
2442 pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx(
2443 aPosition,
2444 aBmpEx1,
2445 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2446 static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2447 0.0,
2448 mfShearX,
2449 mfRotation));
2452 // OVERLAYMANAGER
2453 insertNewlyCreatedOverlayObjectForSdrHdl(
2454 std::move(pOverlayObject),
2455 rPageWindow.GetObjectContact(),
2456 *xManager);
2463 // with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
2464 // accordingly
2466 SdrCropViewHdl::SdrCropViewHdl(
2467 basegfx::B2DHomMatrix aObjectTransform,
2468 Graphic aGraphic,
2469 double fCropLeft,
2470 double fCropTop,
2471 double fCropRight,
2472 double fCropBottom)
2473 : SdrHdl(Point(), SdrHdlKind::User),
2474 maObjectTransform(std::move(aObjectTransform)),
2475 maGraphic(std::move(aGraphic)),
2476 mfCropLeft(fCropLeft),
2477 mfCropTop(fCropTop),
2478 mfCropRight(fCropRight),
2479 mfCropBottom(fCropBottom)
2483 namespace {
2485 void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
2486 assert(rotate != nullptr);
2488 // detect 180 degree rotation, this is the same as mirrored in X and Y,
2489 // thus change to mirroring. Prefer mirroring here. Use the equal call
2490 // with getSmallValue here, the original which uses rtl::math::approxEqual
2491 // is too correct here. Maybe this changes with enhanced precision in aw080
2492 // to the better so that this can be reduced to the more precise call again
2493 if(basegfx::fTools::equal(fabs(*rotate), M_PI, 0.000000001))
2495 scale.setX(scale.getX() * -1.0);
2496 scale.setY(scale.getY() * -1.0);
2497 *rotate = 0.0;
2503 void SdrCropViewHdl::CreateB2dIAObject()
2505 GetRidOfIAObject();
2506 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2507 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2509 if(!pPageView || pView->areMarkHandlesHidden())
2511 return;
2514 // decompose to have current translate and scale
2515 basegfx::B2DVector aScale, aTranslate;
2516 double fRotate, fShearX;
2518 maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
2520 if(aScale.equalZero())
2522 return;
2525 translateRotationToMirroring(aScale, &fRotate);
2527 // remember mirroring, reset at Scale and adapt crop values for usage;
2528 // mirroring can stay in the object transformation, so do not have to
2529 // cope with it here (except later for the CroppedImage transformation,
2530 // see below)
2531 const bool bMirroredX(aScale.getX() < 0.0);
2532 const bool bMirroredY(aScale.getY() < 0.0);
2533 double fCropLeft(mfCropLeft);
2534 double fCropTop(mfCropTop);
2535 double fCropRight(mfCropRight);
2536 double fCropBottom(mfCropBottom);
2538 if(bMirroredX)
2540 aScale.setX(-aScale.getX());
2543 if(bMirroredY)
2545 aScale.setY(-aScale.getY());
2548 // create target translate and scale
2549 const basegfx::B2DVector aTargetScale(
2550 aScale.getX() + fCropRight + fCropLeft,
2551 aScale.getY() + fCropBottom + fCropTop);
2552 const basegfx::B2DVector aTargetTranslate(
2553 aTranslate.getX() - fCropLeft,
2554 aTranslate.getY() - fCropTop);
2556 // create ranges to make comparisons
2557 const basegfx::B2DRange aCurrentForCompare(
2558 aTranslate.getX(), aTranslate.getY(),
2559 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
2560 basegfx::B2DRange aCropped(
2561 aTargetTranslate.getX(), aTargetTranslate.getY(),
2562 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
2564 if(aCropped.isEmpty())
2566 // nothing to return since cropped content is completely empty
2567 return;
2570 if(aCurrentForCompare.equal(aCropped))
2572 // no crop at all
2573 return;
2576 // back-transform to have values in unit coordinates
2577 basegfx::B2DHomMatrix aBackToUnit;
2578 aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
2579 aBackToUnit.scale(
2580 basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
2581 basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
2583 // transform cropped back to unit coordinates
2584 aCropped.transform(aBackToUnit);
2586 // prepare crop PolyPolygon
2587 basegfx::B2DPolygon aGraphicOutlinePolygon(
2588 basegfx::utils::createPolygonFromRect(
2589 aCropped));
2590 basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
2592 // current range is unit range
2593 basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
2595 aOverlap.intersect(aCropped);
2597 if(!aOverlap.isEmpty())
2599 aCropPolyPolygon.append(
2600 basegfx::utils::createPolygonFromRect(
2601 aOverlap));
2604 // transform to object coordinates to prepare for clip
2605 aCropPolyPolygon.transform(maObjectTransform);
2606 aGraphicOutlinePolygon.transform(maObjectTransform);
2608 // create cropped transformation
2609 basegfx::B2DHomMatrix aCroppedTransform;
2611 aCroppedTransform.scale(
2612 aCropped.getWidth(),
2613 aCropped.getHeight());
2614 aCroppedTransform.translate(
2615 aCropped.getMinX(),
2616 aCropped.getMinY());
2617 aCroppedTransform = maObjectTransform * aCroppedTransform;
2619 // prepare graphic primitive (transformed)
2620 const drawinglayer::primitive2d::Primitive2DReference aGraphic(
2621 new drawinglayer::primitive2d::GraphicPrimitive2D(
2622 aCroppedTransform,
2623 maGraphic));
2625 // prepare outline polygon for whole graphic
2626 const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
2627 const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
2628 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
2629 std::move(aGraphicOutlinePolygon),
2630 aHilightColor));
2632 // combine these
2633 drawinglayer::primitive2d::Primitive2DContainer aCombination(2);
2634 aCombination[0] = aGraphic;
2635 aCombination[1] = aGraphicOutline;
2637 // embed to MaskPrimitive2D
2638 const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
2639 new drawinglayer::primitive2d::MaskPrimitive2D(
2640 std::move(aCropPolyPolygon),
2641 std::move(aCombination)));
2643 // embed to UnifiedTransparencePrimitive2D
2644 const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
2645 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2646 drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
2647 0.8));
2649 const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
2651 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2653 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
2654 const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
2656 if(rPageWindow.GetPaintWindow().OutputToWindow())
2658 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
2659 if(xManager.is())
2661 std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer(aSequence)));
2663 // only informative object, no hit
2664 pNew->setHittable(false);
2666 // OVERLAYMANAGER
2667 insertNewlyCreatedOverlayObjectForSdrHdl(
2668 std::move(pNew),
2669 rPageWindow.GetObjectContact(),
2670 *xManager);
2676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */