1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include <svx/svdhdl.hxx>
25 #include <svx/svdpagv.hxx>
26 #include <svx/svdmrkv.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/ptrstyle.hxx>
32 #include <svx/sxekitm.hxx>
33 #include <svx/strings.hrc>
34 #include <svx/svdmodel.hxx>
35 #include "gradtrns.hxx"
36 #include <svx/xflgrit.hxx>
37 #include <svx/svdundo.hxx>
38 #include <svx/dialmgr.hxx>
39 #include <svx/xflftrit.hxx>
41 #include <svx/svdopath.hxx>
42 #include <basegfx/vector/b2dvector.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <svx/sdr/overlay/overlaymanager.hxx>
45 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
46 #include <svx/sdr/overlay/overlaybitmapex.hxx>
47 #include <sdr/overlay/overlayline.hxx>
48 #include <sdr/overlay/overlaytriangle.hxx>
49 #include <sdr/overlay/overlayhandle.hxx>
50 #include <sdr/overlay/overlayrectangle.hxx>
51 #include <svx/sdrpagewindow.hxx>
52 #include <svx/sdrpaintwindow.hxx>
53 #include <vcl/svapp.hxx>
54 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
55 #include <tools/lazydelete.hxx>
56 #include <vcl/BitmapTools.hxx>
57 #include <svx/sdr/contact/objectcontact.hxx>
58 #include <svx/sdr/contact/viewcontact.hxx>
59 #include <osl/diagnose.h>
61 #include <basegfx/polygon/b2dpolygontools.hxx>
62 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
63 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
64 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
65 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
66 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
67 #include <svtools/optionsdrawinglayer.hxx>
69 #include <bitmaps.hlst>
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.
83 // the bitmap holding all information
84 BitmapEx maMarkersBitmap
;
86 // the cropped Bitmaps for reusage
87 ::std::vector
< BitmapEx
> maRealMarkers
;
90 BitmapEx
& impGetOrCreateTargetBitmap(sal_uInt16 nIndex
, const tools::Rectangle
& rRectangle
);
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
)
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
);
160 return impGetOrCreateTargetBitmap(nIndex
, tools::Rectangle(Point(72, 66), Size(13, 13)));
164 return impGetOrCreateTargetBitmap(nIndex
, tools::Rectangle(Point(85, 66), Size(13, 13)));
168 return impGetOrCreateTargetBitmap(nIndex
, tools::Rectangle(Point(72, 79), Size(13, 13)));
172 return impGetOrCreateTargetBitmap(nIndex
, tools::Rectangle(Point(85, 79), Size(13, 13)));
176 return impGetOrCreateTargetBitmap(nIndex
, tools::Rectangle(Point(98, 79), Size(13, 13)));
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)));
273 m_eKind(SdrHdlKind::Move
),
282 mbMoveOutside(false),
287 SdrHdl::SdrHdl(const Point
& rPnt
, SdrHdlKind eNewKind
):
301 mbMoveOutside(false),
311 void SdrHdl::Set1PixMore(bool bJa
)
313 if(m_b1PixMore
!= bJa
)
317 // create new display
322 void SdrHdl::SetMoveOutside( bool bMoveOutside
)
324 if(mbMoveOutside
!= bMoveOutside
)
326 mbMoveOutside
= bMoveOutside
;
328 // create new display
333 void SdrHdl::SetRotationAngle(Degree100 n
)
335 if(m_nRotationAngle
!= n
)
337 m_nRotationAngle
= n
;
339 // create new display
344 void SdrHdl::SetPos(const Point
& rPnt
)
348 // remember new position
351 // create new display
356 void SdrHdl::SetSelected(bool bJa
)
360 // remember new value
363 // create new display
368 void SdrHdl::SetHdlList(SdrHdlList
* pList
)
370 if(m_pHdlList
!= pList
)
375 // now it's possible to create graphic representation
380 void SdrHdl::SetObj(SdrObject
* pNewObj
)
382 if(m_pObj
!= pNewObj
)
384 // remember new object
387 // graphic representation may have changed
394 // force update of graphic representation
398 void SdrHdl::GetRidOfIAObject()
402 maOverlayGroup
.clear();
405 void SdrHdl::CreateB2dIAObject()
407 // first throw away old one
410 if(!m_pHdlList
|| !m_pHdlList
->GetView() || m_pHdlList
->GetView()->areMarkHandlesHidden())
413 BitmapColorIndex eColIndex
= BitmapColorIndex::LightGreen
;
414 BitmapMarkerKind eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
416 bool bRot
= m_pHdlList
->IsRotateShear();
418 eColIndex
= m_bSelect
? BitmapColorIndex::Cyan
: BitmapColorIndex::LightCyan
;
421 // red rotation handles
422 if(m_pObj
&& m_bSelect
)
423 eColIndex
= BitmapColorIndex::Red
;
425 eColIndex
= BitmapColorIndex::LightRed
;
430 case SdrHdlKind::Move
:
432 eKindOfMarker
= m_b1PixMore
? BitmapMarkerKind::Rect_9x9
: BitmapMarkerKind::Rect_7x7
;
435 case SdrHdlKind::UpperLeft
:
436 case SdrHdlKind::UpperRight
:
437 case SdrHdlKind::LowerLeft
:
438 case SdrHdlKind::LowerRight
:
443 eKindOfMarker
= BitmapMarkerKind::Circ_7x7
;
447 eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
451 case SdrHdlKind::Upper
:
452 case SdrHdlKind::Lower
:
454 // Upper/Lower handles
457 eKindOfMarker
= BitmapMarkerKind::Elli_9x7
;
461 eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
465 case SdrHdlKind::Left
:
466 case SdrHdlKind::Right
:
468 // Left/Right handles
471 eKindOfMarker
= BitmapMarkerKind::Elli_7x9
;
475 eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
479 case SdrHdlKind::Poly
:
483 eKindOfMarker
= m_b1PixMore
? BitmapMarkerKind::Circ_9x9
: BitmapMarkerKind::Circ_7x7
;
487 eKindOfMarker
= m_b1PixMore
? BitmapMarkerKind::Rect_9x9
: BitmapMarkerKind::Rect_7x7
;
491 case SdrHdlKind::BezierWeight
: // weight at poly
493 eKindOfMarker
= BitmapMarkerKind::Circ_7x7
;
496 case SdrHdlKind::Circle
:
498 eKindOfMarker
= BitmapMarkerKind::Rect_11x11
;
501 case SdrHdlKind::Ref1
:
502 case SdrHdlKind::Ref2
:
504 eKindOfMarker
= BitmapMarkerKind::Crosshair
;
507 case SdrHdlKind::Glue
:
509 eKindOfMarker
= BitmapMarkerKind::Glue
;
512 case SdrHdlKind::Anchor
:
514 eKindOfMarker
= BitmapMarkerKind::Anchor
;
517 case SdrHdlKind::User
:
521 // top right anchor for SW
522 case SdrHdlKind::Anchor_TR
:
524 eKindOfMarker
= BitmapMarkerKind::AnchorTR
;
528 // for SJ and the CustomShapeHandles:
529 case SdrHdlKind::CustomShape1
:
531 eKindOfMarker
= m_b1PixMore
? BitmapMarkerKind::Customshape_9x9
: BitmapMarkerKind::Customshape_7x7
;
532 eColIndex
= BitmapColorIndex::Yellow
;
539 SdrMarkView
* pView
= m_pHdlList
->GetView();
540 SdrPageView
* pPageView
= pView
->GetSdrPageView();
545 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
547 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
548 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
550 if(rPageWindow
.GetPaintWindow().OutputToWindow())
552 Point
aMoveOutsideOffset(0, 0);
553 OutputDevice
& rOutDev
= rPageWindow
.GetPaintWindow().GetOutputDevice();
555 // add offset if necessary
556 if(m_pHdlList
->IsMoveOutside() || mbMoveOutside
)
558 Size aOffset
= rOutDev
.PixelToLogic(Size(4, 4));
560 if(m_eKind
== SdrHdlKind::UpperLeft
|| m_eKind
== SdrHdlKind::Upper
|| m_eKind
== SdrHdlKind::UpperRight
)
561 aMoveOutsideOffset
.AdjustY( -(aOffset
.Width()) );
562 if(m_eKind
== SdrHdlKind::LowerLeft
|| m_eKind
== SdrHdlKind::Lower
|| m_eKind
== SdrHdlKind::LowerRight
)
563 aMoveOutsideOffset
.AdjustY(aOffset
.Height() );
564 if(m_eKind
== SdrHdlKind::UpperLeft
|| m_eKind
== SdrHdlKind::Left
|| m_eKind
== SdrHdlKind::LowerLeft
)
565 aMoveOutsideOffset
.AdjustX( -(aOffset
.Width()) );
566 if(m_eKind
== SdrHdlKind::UpperRight
|| m_eKind
== SdrHdlKind::Right
|| m_eKind
== SdrHdlKind::LowerRight
)
567 aMoveOutsideOffset
.AdjustX(aOffset
.Height() );
570 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
573 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
574 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject
;
575 if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker
== BitmapMarkerKind::Rect_7x7
|| eKindOfMarker
== BitmapMarkerKind::Rect_9x9
|| eKindOfMarker
== BitmapMarkerKind::Rect_11x11
))
578 switch (eKindOfMarker
)
580 case BitmapMarkerKind::Rect_9x9
:
583 case BitmapMarkerKind::Rect_11x11
:
589 float fScalingFactor
= rOutDev
.GetDPIScaleFactor();
590 basegfx::B2DSize
aB2DSize(fSize
* fScalingFactor
, fSize
* fScalingFactor
);
592 Color
aHandleFillColor(COL_LIGHTGREEN
);
595 case BitmapColorIndex::Cyan
:
596 aHandleFillColor
= COL_CYAN
;
598 case BitmapColorIndex::LightCyan
:
599 aHandleFillColor
= COL_LIGHTCYAN
;
601 case BitmapColorIndex::Red
:
602 aHandleFillColor
= COL_RED
;
604 case BitmapColorIndex::LightRed
:
605 aHandleFillColor
= COL_LIGHTRED
;
607 case BitmapColorIndex::Yellow
:
608 aHandleFillColor
= COL_YELLOW
;
613 pNewOverlayObject
.reset(new sdr::overlay::OverlayHandle(aPosition
, aB2DSize
, /*HandleStrokeColor*/COL_BLACK
, aHandleFillColor
));
617 pNewOverlayObject
= CreateOverlayObject(
618 aPosition
, eColIndex
, eKindOfMarker
,
623 insertNewlyCreatedOverlayObjectForSdrHdl(
624 std::move(pNewOverlayObject
),
625 rPageWindow
.GetObjectContact(),
632 BitmapMarkerKind
SdrHdl::GetNextBigger(BitmapMarkerKind eKnd
)
634 BitmapMarkerKind
eRetval(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;
660 case BitmapMarkerKind::AnchorTR
: eRetval
= BitmapMarkerKind::AnchorPressedTR
; break;
671 OUString
appendMarkerName(BitmapMarkerKind eKindOfMarker
)
673 switch(eKindOfMarker
)
675 case BitmapMarkerKind::Rect_7x7
:
676 return u
"rect7"_ustr
;
677 case BitmapMarkerKind::Rect_9x9
:
678 return u
"rect9"_ustr
;
679 case BitmapMarkerKind::Rect_11x11
:
680 return u
"rect11"_ustr
;
681 case BitmapMarkerKind::Rect_13x13
:
682 return u
"rect13"_ustr
;
683 case BitmapMarkerKind::Circ_7x7
:
684 case BitmapMarkerKind::Customshape_7x7
:
685 return u
"circ7"_ustr
;
686 case BitmapMarkerKind::Circ_9x9
:
687 case BitmapMarkerKind::Customshape_9x9
:
688 return u
"circ9"_ustr
;
689 case BitmapMarkerKind::Circ_11x11
:
690 case BitmapMarkerKind::Customshape_11x11
:
691 return u
"circ11"_ustr
;
692 case BitmapMarkerKind::Elli_7x9
:
693 return u
"elli7x9"_ustr
;
694 case BitmapMarkerKind::Elli_9x11
:
695 return u
"elli9x11"_ustr
;
696 case BitmapMarkerKind::Elli_9x7
:
697 return u
"elli9x7"_ustr
;
698 case BitmapMarkerKind::Elli_11x9
:
699 return u
"elli11x9"_ustr
;
700 case BitmapMarkerKind::RectPlus_7x7
:
701 return u
"rectplus7"_ustr
;
702 case BitmapMarkerKind::RectPlus_9x9
:
703 return u
"rectplus9"_ustr
;
704 case BitmapMarkerKind::RectPlus_11x11
:
705 return u
"rectplus11"_ustr
;
706 case BitmapMarkerKind::Crosshair
:
707 return u
"cross"_ustr
;
708 case BitmapMarkerKind::Anchor
:
709 case BitmapMarkerKind::AnchorTR
:
710 return u
"anchor"_ustr
;
711 case BitmapMarkerKind::AnchorPressed
:
712 case BitmapMarkerKind::AnchorPressedTR
:
713 return u
"anchor-pressed"_ustr
;
714 case BitmapMarkerKind::Glue
:
715 return u
"glue-selected"_ustr
;
716 case BitmapMarkerKind::Glue_Deselected
:
717 return u
"glue-unselected"_ustr
;
724 OUString
appendMarkerColor(BitmapColorIndex eIndex
)
728 case BitmapColorIndex::LightGreen
:
730 case BitmapColorIndex::Cyan
:
732 case BitmapColorIndex::LightCyan
:
734 case BitmapColorIndex::Red
:
736 case BitmapColorIndex::LightRed
:
738 case BitmapColorIndex::Yellow
:
746 BitmapEx
ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker
, BitmapColorIndex eIndex
)
748 // use this code path only when we use HiDPI (for now)
749 if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
751 OUString sMarkerName
= appendMarkerName(eKindOfMarker
);
752 if (!sMarkerName
.isEmpty())
754 OUString
sMarkerPrefix(u
"svx/res/marker-"_ustr
);
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");
769 aBitmapEx
= vcl::bitmap::loadFromName(sMarkerPrefix
+ sMarkerName
+ "-" + appendMarkerColor(eIndex
) + ".png");
772 if (!aBitmapEx
.IsEmpty())
777 // if we can't load the marker...
779 static tools::DeleteOnDeinit
< SdrHdlBitmapSet
> aModernSet
{};
780 return aModernSet
.get()->GetBitmapEx(eKindOfMarker
, sal_uInt16(eIndex
));
783 } // end anonymous namespace
785 std::unique_ptr
<sdr::overlay::OverlayObject
> SdrHdl::CreateOverlayObject(
786 const basegfx::B2DPoint
& rPos
,
787 BitmapColorIndex eColIndex
, BitmapMarkerKind eKindOfMarker
, Point aMoveOutsideOffset
)
789 std::unique_ptr
<sdr::overlay::OverlayObject
> pRetval
;
791 // support bigger sizes
792 bool bForceBiggerSize(false);
794 if (m_pHdlList
&& m_pHdlList
->GetHdlSize() > 3)
796 switch(eKindOfMarker
)
798 case BitmapMarkerKind::Anchor
:
799 case BitmapMarkerKind::AnchorPressed
:
800 case BitmapMarkerKind::AnchorTR
:
801 case BitmapMarkerKind::AnchorPressedTR
:
803 // #i121463# For anchor, do not simply make bigger because of HdlSize,
804 // do it dependent of IsSelected() which Writer can set in drag mode
807 bForceBiggerSize
= true;
813 bForceBiggerSize
= true;
821 eKindOfMarker
= GetNextBigger(eKindOfMarker
);
824 // This handle has the focus, visualize it
825 if(IsFocusHdl() && m_pHdlList
&& m_pHdlList
->GetFocusHdl() == this)
827 // create animated handle
828 BitmapMarkerKind eNextBigger
= GetNextBigger(eKindOfMarker
);
830 if(eNextBigger
== eKindOfMarker
)
832 // this may happen for the not supported getting-bigger types.
833 // Choose an alternative here
834 switch(eKindOfMarker
)
836 case BitmapMarkerKind::Rect_13x13
: eNextBigger
= BitmapMarkerKind::Rect_11x11
; break;
837 case BitmapMarkerKind::Circ_11x11
: eNextBigger
= BitmapMarkerKind::Elli_11x9
; break;
838 case BitmapMarkerKind::Elli_9x11
: eNextBigger
= BitmapMarkerKind::Elli_11x9
; break;
839 case BitmapMarkerKind::Elli_11x9
: eNextBigger
= BitmapMarkerKind::Elli_9x11
; break;
840 case BitmapMarkerKind::RectPlus_11x11
: eNextBigger
= BitmapMarkerKind::Rect_13x13
; break;
841 case BitmapMarkerKind::Glue
:
842 eNextBigger
= BitmapMarkerKind::Crosshair
;
844 case BitmapMarkerKind::Crosshair
:
845 case BitmapMarkerKind::Glue_Deselected
:
846 eNextBigger
= BitmapMarkerKind::Glue
;
853 // create animated handle
854 BitmapEx aBmpEx1
= ImpGetBitmapEx(eKindOfMarker
, eColIndex
);
855 BitmapEx aBmpEx2
= ImpGetBitmapEx(eNextBigger
, eColIndex
);
857 // #i53216# Use system cursor blink time. Use the unsigned value.
858 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
859 const sal_uInt64
nBlinkTime(rStyleSettings
.GetCursorBlinkTime());
861 if(eKindOfMarker
== BitmapMarkerKind::Anchor
|| eKindOfMarker
== BitmapMarkerKind::AnchorPressed
)
863 // when anchor is used take upper left as reference point inside the handle
864 pRetval
.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos
, aBmpEx1
, aBmpEx2
, nBlinkTime
));
866 else if(eKindOfMarker
== BitmapMarkerKind::AnchorTR
|| eKindOfMarker
== BitmapMarkerKind::AnchorPressedTR
)
868 // AnchorTR for SW, take top right as (0,0)
869 pRetval
.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos
, aBmpEx1
, aBmpEx2
, nBlinkTime
,
870 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Width() - 1), 0,
871 static_cast<sal_uInt16
>(aBmpEx2
.GetSizePixel().Width() - 1), 0));
875 // create centered handle as default
876 pRetval
.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos
, aBmpEx1
, aBmpEx2
, nBlinkTime
,
877 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Width() - 1) >> 1,
878 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Height() - 1) >> 1,
879 static_cast<sal_uInt16
>(aBmpEx2
.GetSizePixel().Width() - 1) >> 1,
880 static_cast<sal_uInt16
>(aBmpEx2
.GetSizePixel().Height() - 1) >> 1));
885 // create normal handle: use ImpGetBitmapEx(...) now
886 BitmapEx aBmpEx
= ImpGetBitmapEx(eKindOfMarker
, eColIndex
);
888 // When the image with handles is not found, the bitmap returned is
889 // empty. This is a problem when we use LibreOffice as a library
890 // (through LOKit - for example on Android) even when we don't show
891 // the handles, because the hit test would always return false.
893 // This HACK replaces the empty bitmap with a black 13x13 bitmap handle
894 // so that the hit test works for this case.
895 if (aBmpEx
.IsEmpty())
897 aBmpEx
= BitmapEx(Size(13, 13), vcl::PixelFormat::N24_BPP
);
898 aBmpEx
.Erase(COL_BLACK
);
901 if(eKindOfMarker
== BitmapMarkerKind::Anchor
|| eKindOfMarker
== BitmapMarkerKind::AnchorPressed
)
903 // upper left as reference point inside the handle for AnchorPressed, too
904 pRetval
.reset(new sdr::overlay::OverlayBitmapEx(rPos
, aBmpEx
));
906 else if(eKindOfMarker
== BitmapMarkerKind::AnchorTR
|| eKindOfMarker
== BitmapMarkerKind::AnchorPressedTR
)
908 // AnchorTR for SW, take top right as (0,0)
909 pRetval
.reset(new sdr::overlay::OverlayBitmapEx(rPos
, aBmpEx
,
910 static_cast<sal_uInt16
>(aBmpEx
.GetSizePixel().Width() - 1), 0));
914 sal_uInt16
nCenX(static_cast<sal_uInt16
>(aBmpEx
.GetSizePixel().Width() - 1) >> 1);
915 sal_uInt16
nCenY(static_cast<sal_uInt16
>(aBmpEx
.GetSizePixel().Height() - 1) >> 1);
917 if(aMoveOutsideOffset
.X() > 0)
921 else if(aMoveOutsideOffset
.X() < 0)
923 nCenX
= static_cast<sal_uInt16
>(aBmpEx
.GetSizePixel().Width() - 1);
926 if(aMoveOutsideOffset
.Y() > 0)
930 else if(aMoveOutsideOffset
.Y() < 0)
932 nCenY
= static_cast<sal_uInt16
>(aBmpEx
.GetSizePixel().Height() - 1);
935 // create centered handle as default
936 pRetval
.reset(new sdr::overlay::OverlayBitmapEx(rPos
, aBmpEx
, nCenX
, nCenY
));
943 bool SdrHdl::IsHdlHit(const Point
& rPnt
) const
946 basegfx::B2DPoint
aPosition(rPnt
.X(), rPnt
.Y());
947 return maOverlayGroup
.isHitLogic(aPosition
);
950 PointerStyle
SdrHdl::GetPointer() const
952 PointerStyle ePtr
=PointerStyle::Move
;
953 const bool bSize
=m_eKind
>=SdrHdlKind::UpperLeft
&& m_eKind
<=SdrHdlKind::LowerRight
;
954 const bool bRot
=m_pHdlList
!=nullptr && m_pHdlList
->IsRotateShear();
955 const bool bDis
=m_pHdlList
!=nullptr && m_pHdlList
->IsDistortShear();
956 if (bSize
&& m_pHdlList
!=nullptr && (bRot
|| bDis
)) {
958 case SdrHdlKind::UpperLeft
: case SdrHdlKind::UpperRight
:
959 case SdrHdlKind::LowerLeft
: case SdrHdlKind::LowerRight
: ePtr
=bRot
? PointerStyle::Rotate
: PointerStyle::RefHand
; break;
960 case SdrHdlKind::Left
: case SdrHdlKind::Right
: ePtr
=PointerStyle::VShear
; break;
961 case SdrHdlKind::Upper
: case SdrHdlKind::Lower
: ePtr
=PointerStyle::HShear
; break;
966 // When resizing rotated rectangles, rotate the mouse cursor slightly, too
967 if (bSize
&& m_nRotationAngle
!=0_deg100
) {
968 Degree100
nHdlAngle(0);
970 case SdrHdlKind::LowerRight
: nHdlAngle
=31500_deg100
; break;
971 case SdrHdlKind::Lower
: nHdlAngle
=27000_deg100
; break;
972 case SdrHdlKind::LowerLeft
: nHdlAngle
=22500_deg100
; break;
973 case SdrHdlKind::Left
: nHdlAngle
=18000_deg100
; break;
974 case SdrHdlKind::UpperLeft
: nHdlAngle
=13500_deg100
; break;
975 case SdrHdlKind::Upper
: nHdlAngle
=9000_deg100
; break;
976 case SdrHdlKind::UpperRight
: nHdlAngle
=4500_deg100
; break;
977 case SdrHdlKind::Right
: nHdlAngle
=0_deg100
; break;
981 // a little bit more (for rounding)
982 nHdlAngle
= NormAngle36000(nHdlAngle
+ m_nRotationAngle
+ 2249_deg100
);
983 nHdlAngle
/=4500_deg100
;
984 switch (static_cast<sal_uInt8
>(nHdlAngle
.get())) {
985 case 0: ePtr
=PointerStyle::ESize
; break;
986 case 1: ePtr
=PointerStyle::NESize
; break;
987 case 2: ePtr
=PointerStyle::NSize
; break;
988 case 3: ePtr
=PointerStyle::NWSize
; break;
989 case 4: ePtr
=PointerStyle::WSize
; break;
990 case 5: ePtr
=PointerStyle::SWSize
; break;
991 case 6: ePtr
=PointerStyle::SSize
; break;
992 case 7: ePtr
=PointerStyle::SESize
; break;
996 case SdrHdlKind::UpperLeft
: ePtr
=PointerStyle::NWSize
; break;
997 case SdrHdlKind::Upper
: ePtr
=PointerStyle::NSize
; break;
998 case SdrHdlKind::UpperRight
: ePtr
=PointerStyle::NESize
; break;
999 case SdrHdlKind::Left
: ePtr
=PointerStyle::WSize
; break;
1000 case SdrHdlKind::Right
: ePtr
=PointerStyle::ESize
; break;
1001 case SdrHdlKind::LowerLeft
: ePtr
=PointerStyle::SWSize
; break;
1002 case SdrHdlKind::Lower
: ePtr
=PointerStyle::SSize
; break;
1003 case SdrHdlKind::LowerRight
: ePtr
=PointerStyle::SESize
; break;
1004 case SdrHdlKind::Poly
: ePtr
=PointerStyle::MovePoint
; break;
1005 case SdrHdlKind::Circle
: ePtr
=PointerStyle::Hand
; break;
1006 case SdrHdlKind::Ref1
: ePtr
=PointerStyle::RefHand
; break;
1007 case SdrHdlKind::Ref2
: ePtr
=PointerStyle::RefHand
; break;
1008 case SdrHdlKind::BezierWeight
: ePtr
=PointerStyle::MoveBezierWeight
; break;
1009 case SdrHdlKind::Glue
: ePtr
=PointerStyle::MovePoint
; break;
1010 case SdrHdlKind::CustomShape1
: ePtr
=PointerStyle::RefHand
; break;
1019 bool SdrHdl::IsFocusHdl() const
1023 case SdrHdlKind::UpperLeft
:
1024 case SdrHdlKind::Upper
:
1025 case SdrHdlKind::UpperRight
:
1026 case SdrHdlKind::Left
:
1027 case SdrHdlKind::Right
:
1028 case SdrHdlKind::LowerLeft
:
1029 case SdrHdlKind::Lower
:
1030 case SdrHdlKind::LowerRight
:
1032 // if it's an activated TextEdit, it's moved to extended points
1033 return !m_pHdlList
|| !m_pHdlList
->IsMoveOutside();
1036 case SdrHdlKind::Move
: // handle to move object
1037 case SdrHdlKind::Poly
: // selected point of polygon or curve
1038 case SdrHdlKind::BezierWeight
: // weight at a curve
1039 case SdrHdlKind::Circle
: // angle of circle segments, corner radius of rectangles
1040 case SdrHdlKind::Ref1
: // reference point 1, e. g. center of rotation
1041 case SdrHdlKind::Ref2
: // reference point 2, e. g. endpoint of reflection axis
1042 case SdrHdlKind::Glue
: // gluepoint
1044 // for SJ and the CustomShapeHandles:
1045 case SdrHdlKind::CustomShape1
:
1047 case SdrHdlKind::User
:
1059 void SdrHdl::onMouseEnter(const MouseEvent
& /*rMEvt*/)
1063 void SdrHdl::onHelpRequest()
1067 void SdrHdl::onMouseLeave()
1071 BitmapEx
SdrHdl::createGluePointBitmap()
1073 return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected
, BitmapColorIndex::LightGreen
);
1076 void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
1077 std::unique_ptr
<sdr::overlay::OverlayObject
> pOverlayObject
,
1078 const sdr::contact::ObjectContact
& rObjectContact
,
1079 sdr::overlay::OverlayManager
& rOverlayManager
)
1081 // check if we have an OverlayObject
1087 // Add GridOffset for non-linear ViewToDevice transformation (calc)
1088 if(nullptr != GetObj() && rObjectContact
.supportsGridOffsets())
1090 basegfx::B2DVector
aOffset(0.0, 0.0);
1091 const sdr::contact::ViewObjectContact
& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
1092 const_cast<sdr::contact::ObjectContact
&>(rObjectContact
)));
1094 rObjectContact
.calculateGridOffsetForViewObjectContact(aOffset
, rVOC
);
1096 if(!aOffset
.equalZero())
1098 pOverlayObject
->setOffset(aOffset
);
1102 // add to OverlayManager
1103 rOverlayManager
.add(*pOverlayObject
);
1105 // add to local OverlayObjectList - ownership change (!)
1106 maOverlayGroup
.append(std::move(pOverlayObject
));
1109 SdrHdlColor::SdrHdlColor(const Point
& rRef
, Color aCol
, const Size
& rSize
, bool bLum
)
1110 : SdrHdl(rRef
, SdrHdlKind::Color
),
1111 m_aMarkerSize(rSize
),
1112 m_bUseLuminance(bLum
)
1114 if(IsUseLuminance())
1115 aCol
= GetLuminance(aCol
);
1118 m_aMarkerColor
= aCol
;
1121 SdrHdlColor::~SdrHdlColor()
1125 void SdrHdlColor::CreateB2dIAObject()
1127 // first throw away old one
1133 SdrMarkView
* pView
= m_pHdlList
->GetView();
1135 if(!pView
|| pView
->areMarkHandlesHidden())
1138 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1143 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1145 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1147 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1149 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1152 BitmapEx
aBmpCol(CreateColorDropper(m_aMarkerColor
));
1153 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
1154 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(new
1155 sdr::overlay::OverlayBitmapEx(
1158 static_cast<sal_uInt16
>(aBmpCol
.GetSizePixel().Width() - 1) >> 1,
1159 static_cast<sal_uInt16
>(aBmpCol
.GetSizePixel().Height() - 1) >> 1
1163 insertNewlyCreatedOverlayObjectForSdrHdl(
1164 std::move(pNewOverlayObject
),
1165 rPageWindow
.GetObjectContact(),
1172 BitmapEx
SdrHdlColor::CreateColorDropper(Color aCol
)
1175 VclPtr
<VirtualDevice
> pWrite(VclPtr
<VirtualDevice
>::Create());
1176 pWrite
->SetOutputSizePixel(m_aMarkerSize
);
1177 pWrite
->SetBackground(aCol
);
1180 // draw outer border
1181 sal_Int32 nWidth
= m_aMarkerSize
.Width();
1182 sal_Int32 nHeight
= m_aMarkerSize
.Height();
1184 pWrite
->SetLineColor(COL_LIGHTGRAY
);
1185 pWrite
->DrawLine(Point(0, 0), Point(0, nHeight
- 1));
1186 pWrite
->DrawLine(Point(1, 0), Point(nWidth
- 1, 0));
1187 pWrite
->SetLineColor(COL_GRAY
);
1188 pWrite
->DrawLine(Point(1, nHeight
- 1), Point(nWidth
- 1, nHeight
- 1));
1189 pWrite
->DrawLine(Point(nWidth
- 1, 1), Point(nWidth
- 1, nHeight
- 2));
1191 // draw lighter UpperLeft
1192 const Color
aLightColor(
1193 static_cast<sal_uInt8
>(::std::min(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1194 static_cast<sal_uInt8
>(::std::min(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
1195 static_cast<sal_uInt8
>(::std::min(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
1196 pWrite
->SetLineColor(aLightColor
);
1197 pWrite
->DrawLine(Point(1, 1), Point(1, nHeight
- 2));
1198 pWrite
->DrawLine(Point(2, 1), Point(nWidth
- 2, 1));
1200 // draw darker LowerRight
1201 const Color
aDarkColor(
1202 static_cast<sal_uInt8
>(::std::max(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1203 static_cast<sal_uInt8
>(::std::max(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
1204 static_cast<sal_uInt8
>(::std::max(static_cast<sal_Int16
>(static_cast<sal_Int16
>(aCol
.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
1205 pWrite
->SetLineColor(aDarkColor
);
1206 pWrite
->DrawLine(Point(2, nHeight
- 2), Point(nWidth
- 2, nHeight
- 2));
1207 pWrite
->DrawLine(Point(nWidth
- 2, 2), Point(nWidth
- 2, nHeight
- 3));
1209 return pWrite
->GetBitmapEx(Point(0,0), m_aMarkerSize
);
1212 Color
SdrHdlColor::GetLuminance(const Color
& rCol
)
1214 sal_uInt8 aLum
= rCol
.GetLuminance();
1215 Color
aRetval(aLum
, aLum
, aLum
);
1219 void SdrHdlColor::SetColor(Color aNew
, bool bCallLink
)
1221 if(IsUseLuminance())
1222 aNew
= GetLuminance(aNew
);
1224 if(m_aMarkerColor
!= aNew
)
1226 // remember new color
1227 m_aMarkerColor
= aNew
;
1229 // create new display
1232 // tell about change
1234 m_aColorChangeHdl
.Call(this);
1238 void SdrHdlColor::SetSize(const Size
& rNew
)
1240 if(rNew
!= m_aMarkerSize
)
1242 // remember new size
1243 m_aMarkerSize
= rNew
;
1245 // create new display
1250 SdrHdlGradient::SdrHdlGradient(const Point
& rRef1
, const Point
& rRef2
, bool bGrad
)
1251 : SdrHdl(rRef1
, bGrad
? SdrHdlKind::Gradient
: SdrHdlKind::Transparence
)
1252 , m_pColHdl1(nullptr)
1253 , m_pColHdl2(nullptr)
1255 , m_bGradient(bGrad
)
1256 , m_bMoveSingleHandle(false)
1257 , m_bMoveFirstHandle(false)
1261 SdrHdlGradient::~SdrHdlGradient()
1265 void SdrHdlGradient::Set2ndPos(const Point
& rPnt
)
1267 if(m_a2ndPos
!= rPnt
)
1269 // remember new position
1272 // create new display
1277 void SdrHdlGradient::CreateB2dIAObject()
1279 // first throw away old one
1285 SdrMarkView
* pView
= m_pHdlList
->GetView();
1287 if(!pView
|| pView
->areMarkHandlesHidden())
1290 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1295 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1297 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1299 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1301 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1304 // striped line in between
1305 basegfx::B2DVector
aVec(m_a2ndPos
.X() - m_aPos
.X(), m_a2ndPos
.Y() - m_aPos
.Y());
1306 double fVecLen
= aVec
.getLength();
1307 double fLongPercentArrow
= (1.0 - 0.05) * fVecLen
;
1308 double fHalfArrowWidth
= (0.05 * 0.5) * fVecLen
;
1310 basegfx::B2DVector
aPerpend(-aVec
.getY(), aVec
.getX());
1311 sal_Int32 nMidX
= static_cast<sal_Int32
>(m_aPos
.X() + aVec
.getX() * fLongPercentArrow
);
1312 sal_Int32 nMidY
= static_cast<sal_Int32
>(m_aPos
.Y() + aVec
.getY() * fLongPercentArrow
);
1313 Point
aMidPoint(nMidX
, nMidY
);
1315 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
1316 basegfx::B2DPoint
aMidPos(aMidPoint
.X(), aMidPoint
.Y());
1318 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(new
1319 sdr::overlay::OverlayLineStriped(
1323 pNewOverlayObject
->setBaseColor(IsGradient() ? COL_BLACK
: COL_BLUE
);
1326 insertNewlyCreatedOverlayObjectForSdrHdl(
1327 std::move(pNewOverlayObject
),
1328 rPageWindow
.GetObjectContact(),
1332 Point
aLeft(aMidPoint
.X() + static_cast<sal_Int32
>(aPerpend
.getX() * fHalfArrowWidth
),
1333 aMidPoint
.Y() + static_cast<sal_Int32
>(aPerpend
.getY() * fHalfArrowWidth
));
1334 Point
aRight(aMidPoint
.X() - static_cast<sal_Int32
>(aPerpend
.getX() * fHalfArrowWidth
),
1335 aMidPoint
.Y() - static_cast<sal_Int32
>(aPerpend
.getY() * fHalfArrowWidth
));
1337 basegfx::B2DPoint
aPositionLeft(aLeft
.X(), aLeft
.Y());
1338 basegfx::B2DPoint
aPositionRight(aRight
.X(), aRight
.Y());
1339 basegfx::B2DPoint
aPosition2(m_a2ndPos
.X(), m_a2ndPos
.Y());
1341 pNewOverlayObject
.reset(new
1342 sdr::overlay::OverlayTriangle(
1346 IsGradient() ? COL_BLACK
: COL_BLUE
1350 insertNewlyCreatedOverlayObjectForSdrHdl(
1351 std::move(pNewOverlayObject
),
1352 rPageWindow
.GetObjectContact(),
1359 IMPL_LINK_NOARG(SdrHdlGradient
, ColorChangeHdl
, SdrHdlColor
*, void)
1362 FromIAOToItem(GetObj(), true, true);
1365 void SdrHdlGradient::FromIAOToItem(SdrObject
* _pObj
, bool bSetItemOnObject
, bool bUndo
)
1367 // from IAO positions and colors to gradient
1368 const SfxItemSet
& rSet
= _pObj
->GetMergedItemSet();
1370 GradTransGradient aOldGradTransGradient
;
1371 GradTransGradient aGradTransGradient
;
1372 GradTransVector aGradTransVector
;
1374 aGradTransVector
.maPositionA
= basegfx::B2DPoint(GetPos().X(), GetPos().Y());
1375 aGradTransVector
.maPositionB
= basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
1377 aGradTransVector
.aCol1
= m_pColHdl1
->GetColor();
1379 aGradTransVector
.aCol2
= m_pColHdl2
->GetColor();
1382 aOldGradTransGradient
.aGradient
= rSet
.Get(XATTR_FILLGRADIENT
).GetGradientValue();
1384 aOldGradTransGradient
.aGradient
= rSet
.Get(XATTR_FILLFLOATTRANSPARENCE
).GetGradientValue();
1386 // transform vector data to gradient
1387 GradTransformer::VecToGrad(aGradTransVector
, aGradTransGradient
, aOldGradTransGradient
, _pObj
, m_bMoveSingleHandle
, m_bMoveFirstHandle
);
1389 if(bSetItemOnObject
)
1391 SdrModel
& rModel(_pObj
->getSdrModelFromSdrObject());
1392 SfxItemSet
aNewSet(rModel
.GetItemPool());
1393 const OUString aString
;
1397 XFillGradientItem
aNewGradItem(aString
, aGradTransGradient
.aGradient
);
1398 aNewSet
.Put(aNewGradItem
);
1402 XFillFloatTransparenceItem
aNewTransItem(aString
, aGradTransGradient
.aGradient
);
1403 aNewSet
.Put(aNewTransItem
);
1406 if(bUndo
&& rModel
.IsUndoEnabled())
1408 rModel
.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT
: SIP_XA_FILLTRANSPARENCE
));
1409 rModel
.AddUndo(rModel
.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj
));
1413 m_pObj
->SetMergedItemSetAndBroadcast(aNewSet
);
1416 // back transformation, set values on pIAOHandle
1417 GradTransformer::GradToVec(aGradTransGradient
, aGradTransVector
, _pObj
);
1419 SetPos({ basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionA
.getX()),
1420 basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionA
.getY()) });
1421 Set2ndPos({ basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionB
.getX()),
1422 basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionB
.getY()) });
1425 m_pColHdl1
->SetPos({ basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionA
.getX()),
1426 basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionA
.getY()) });
1427 m_pColHdl1
->SetColor(aGradTransVector
.aCol1
);
1431 m_pColHdl2
->SetPos({ basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionB
.getX()),
1432 basegfx::fround
<tools::Long
>(aGradTransVector
.maPositionB
.getY()) });
1433 m_pColHdl2
->SetColor(aGradTransVector
.aCol2
);
1438 SdrHdlLine::~SdrHdlLine() {}
1440 void SdrHdlLine::CreateB2dIAObject()
1442 // first throw away old one
1448 SdrMarkView
* pView
= m_pHdlList
->GetView();
1450 if(!(pView
&& !pView
->areMarkHandlesHidden() && m_pHdl1
&& m_pHdl2
))
1453 SdrPageView
* pPageView
= pView
->GetSdrPageView();
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();
1467 basegfx::B2DPoint
aPosition1(m_pHdl1
->GetPos().X(), m_pHdl1
->GetPos().Y());
1468 basegfx::B2DPoint
aPosition2(m_pHdl2
->GetPos().X(), m_pHdl2
->GetPos().Y());
1470 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(new
1471 sdr::overlay::OverlayLineStriped(
1477 pNewOverlayObject
->setBaseColor(COL_LIGHTRED
);
1480 insertNewlyCreatedOverlayObjectForSdrHdl(
1481 std::move(pNewOverlayObject
),
1482 rPageWindow
.GetObjectContact(),
1489 PointerStyle
SdrHdlLine::GetPointer() const
1491 return PointerStyle::RefHand
;
1495 SdrHdlBezWgt::~SdrHdlBezWgt() {}
1497 void SdrHdlBezWgt::CreateB2dIAObject()
1500 SdrHdl::CreateB2dIAObject();
1506 SdrMarkView
* pView
= m_pHdlList
->GetView();
1508 if(!pView
|| pView
->areMarkHandlesHidden())
1511 SdrPageView
* pPageView
= pView
->GetSdrPageView();
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();
1525 basegfx::B2DPoint
aPosition1(m_pHdl1
->GetPos().X(), m_pHdl1
->GetPos().Y());
1526 basegfx::B2DPoint
aPosition2(m_aPos
.X(), m_aPos
.Y());
1528 if(!aPosition1
.equal(aPosition2
))
1530 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(new
1531 sdr::overlay::OverlayLineStriped(
1536 // line part is not hittable
1537 pNewOverlayObject
->setHittable(false);
1540 pNewOverlayObject
->setBaseColor(COL_LIGHTBLUE
);
1543 insertNewlyCreatedOverlayObjectForSdrHdl(
1544 std::move(pNewOverlayObject
),
1545 rPageWindow
.GetObjectContact(),
1554 E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon
& rWireframePoly
)
1556 m_aWireframePoly
= rWireframePoly
;
1559 void E3dVolumeMarker::CreateB2dIAObject()
1565 SdrMarkView
* pView
= m_pHdlList
->GetView();
1567 if(!pView
|| pView
->areMarkHandlesHidden())
1570 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1575 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1577 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1579 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1581 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1582 if (xManager
.is() && m_aWireframePoly
.count())
1584 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(new
1585 sdr::overlay::OverlayPolyPolygonStripedAndFilled(
1588 pNewOverlayObject
->setBaseColor(COL_BLACK
);
1591 insertNewlyCreatedOverlayObjectForSdrHdl(
1592 std::move(pNewOverlayObject
),
1593 rPageWindow
.GetObjectContact(),
1601 ImpEdgeHdl::~ImpEdgeHdl()
1605 void ImpEdgeHdl::CreateB2dIAObject()
1607 if(m_nObjHdlNum
> 1 || !m_pObj
)
1610 SdrHdl::CreateB2dIAObject();
1614 // first throw away old one
1617 BitmapColorIndex eColIndex
= BitmapColorIndex::LightCyan
;
1618 BitmapMarkerKind eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
1623 SdrMarkView
* pView
= m_pHdlList
->GetView();
1625 if(!pView
|| pView
->areMarkHandlesHidden())
1628 // tdf#159666 Crash when table and line object are selected at the same time
1629 auto pEdge
= dynamic_cast<SdrEdgeObj
*>(m_pObj
);
1633 if(pEdge
->GetConnectedNode(m_nObjHdlNum
== 0) != nullptr)
1634 eColIndex
= BitmapColorIndex::LightRed
;
1638 // Handle with plus sign inside
1639 eKindOfMarker
= BitmapMarkerKind::Circ_7x7
;
1642 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1646 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1648 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1650 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1652 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1655 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
1656 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(CreateOverlayObject(
1662 insertNewlyCreatedOverlayObjectForSdrHdl(
1663 std::move(pNewOverlayObject
),
1664 rPageWindow
.GetObjectContact(),
1671 void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode
)
1673 if(m_eLineCode
!= eCode
)
1675 // remember new value
1676 m_eLineCode
= eCode
;
1678 // create new display
1683 PointerStyle
ImpEdgeHdl::GetPointer() const
1685 SdrEdgeObj
* pEdge
=dynamic_cast<SdrEdgeObj
*>( m_pObj
);
1687 return SdrHdl::GetPointer();
1688 if (m_nObjHdlNum
<=1)
1689 return PointerStyle::MovePoint
;
1691 return PointerStyle::ESize
;
1693 return PointerStyle::SSize
;
1696 bool ImpEdgeHdl::IsHorzDrag() const
1698 SdrEdgeObj
* pEdge
=dynamic_cast<SdrEdgeObj
*>( m_pObj
);
1701 if (m_nObjHdlNum
<=1)
1704 SdrEdgeKind eEdgeKind
= pEdge
->GetObjectItem(SDRATTR_EDGEKIND
).GetValue();
1706 const SdrEdgeInfoRec
& rInfo
=pEdge
->m_aEdgeInfo
;
1707 if (eEdgeKind
==SdrEdgeKind::OrthoLines
|| eEdgeKind
==SdrEdgeKind::Bezier
)
1709 return !rInfo
.ImpIsHorzLine(m_eLineCode
,*pEdge
->m_pEdgeTrack
);
1711 else if (eEdgeKind
==SdrEdgeKind::ThreeLines
)
1713 tools::Long nAngle
=m_nObjHdlNum
==2 ? rInfo
.m_nAngle1
: rInfo
.m_nAngle2
;
1714 return nAngle
==0 || nAngle
==18000;
1720 ImpMeasureHdl::~ImpMeasureHdl()
1724 void ImpMeasureHdl::CreateB2dIAObject()
1726 // first throw away old one
1732 SdrMarkView
* pView
= m_pHdlList
->GetView();
1734 if(!pView
|| pView
->areMarkHandlesHidden())
1737 BitmapColorIndex eColIndex
= BitmapColorIndex::LightCyan
;
1738 BitmapMarkerKind eKindOfMarker
= BitmapMarkerKind::Rect_9x9
;
1740 if(m_nObjHdlNum
> 1)
1742 eKindOfMarker
= BitmapMarkerKind::Rect_7x7
;
1747 eColIndex
= BitmapColorIndex::Cyan
;
1750 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1755 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1757 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1759 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1761 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1764 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
1765 std::unique_ptr
<sdr::overlay::OverlayObject
> pNewOverlayObject(CreateOverlayObject(
1771 insertNewlyCreatedOverlayObjectForSdrHdl(
1772 std::move(pNewOverlayObject
),
1773 rPageWindow
.GetObjectContact(),
1780 PointerStyle
ImpMeasureHdl::GetPointer() const
1782 switch (m_nObjHdlNum
)
1784 case 0: case 1: return PointerStyle::Hand
;
1785 case 2: case 3: return PointerStyle::MovePoint
;
1786 case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
1788 return PointerStyle::NotAllowed
;
1792 ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle
& rRect
) :
1793 SdrHdl(rRect
.TopLeft(),SdrHdlKind::Move
),
1798 void ImpTextframeHdl::CreateB2dIAObject()
1800 // first throw away old one
1806 SdrMarkView
* pView
= m_pHdlList
->GetView();
1808 if(!pView
|| pView
->areMarkHandlesHidden())
1811 SdrPageView
* pPageView
= pView
->GetSdrPageView();
1816 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
1818 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
1820 if(rPageWindow
.GetPaintWindow().OutputToWindow())
1822 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
1825 const basegfx::B2DPoint
aTopLeft(maRect
.Left(), maRect
.Top());
1826 const basegfx::B2DPoint
aBottomRight(maRect
.Right(), maRect
.Bottom());
1827 const Color
aHilightColor(SvtOptionsDrawinglayer::getHilightColor());
1828 const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
1830 std::unique_ptr
<sdr::overlay::OverlayRectangle
> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
1837 -toRadians(m_nRotationAngle
),
1838 true)); // allow animation; the Handle is not shown at text edit time
1840 pNewOverlayObject
->setHittable(false);
1843 insertNewlyCreatedOverlayObjectForSdrHdl(
1844 std::move(pNewOverlayObject
),
1845 rPageWindow
.GetObjectContact(),
1853 static bool ImpSdrHdlListSorter(std::unique_ptr
<SdrHdl
> const& lhs
, std::unique_ptr
<SdrHdl
> const& rhs
)
1855 SdrHdlKind eKind1
=lhs
->GetKind();
1856 SdrHdlKind eKind2
=rhs
->GetKind();
1857 // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
1862 if (eKind1
==SdrHdlKind::Ref1
|| eKind1
==SdrHdlKind::Ref2
|| eKind1
==SdrHdlKind::MirrorAxis
) n1
=5;
1863 else if (eKind1
==SdrHdlKind::Glue
) n1
=2;
1864 else if (eKind1
==SdrHdlKind::User
) n1
=3;
1865 else if (eKind1
==SdrHdlKind::SmartTag
) n1
=0;
1866 if (eKind2
==SdrHdlKind::Ref1
|| eKind2
==SdrHdlKind::Ref2
|| eKind2
==SdrHdlKind::MirrorAxis
) n2
=5;
1867 else if (eKind2
==SdrHdlKind::Glue
) n2
=2;
1868 else if (eKind2
==SdrHdlKind::User
) n2
=3;
1869 else if (eKind2
==SdrHdlKind::SmartTag
) n2
=0;
1871 if (lhs
->IsPlusHdl()) n1
=4;
1872 if (rhs
->IsPlusHdl()) n2
=4;
1875 // Level 2: PageView (Pointer)
1876 SdrPageView
* pPV1
=lhs
->GetPageView();
1877 SdrPageView
* pPV2
=rhs
->GetPageView();
1880 // Level 3: Position (x+y)
1881 SdrObject
* pObj1
=lhs
->GetObj();
1882 SdrObject
* pObj2
=rhs
->GetObj();
1885 sal_uInt32 nNum1
=lhs
->GetObjHdlNum();
1886 sal_uInt32 nNum2
=rhs
->GetObjHdlNum();
1890 return lhs
<rhs
; // Hack, to always get to the same sorting
1891 return static_cast<sal_uInt16
>(eKind1
)<static_cast<sal_uInt16
>(eKind2
);
1914 // Helper struct for re-sorting handles
1915 struct ImplHdlAndIndex
1925 // Helper method for sorting handles taking care of OrdNums, keeping order in
1926 // single objects and re-sorting polygon handles intuitively
1927 static int ImplSortHdlFunc( const void* pVoid1
, const void* pVoid2
)
1929 const ImplHdlAndIndex
* p1
= static_cast<ImplHdlAndIndex
const *>(pVoid1
);
1930 const ImplHdlAndIndex
* p2
= static_cast<ImplHdlAndIndex
const *>(pVoid2
);
1932 if(p1
->mpHdl
->GetObj() == p2
->mpHdl
->GetObj())
1934 if(p1
->mpHdl
->GetObj() && dynamic_cast<const SdrPathObj
*>(p1
->mpHdl
->GetObj()) != nullptr)
1936 // same object and a path object
1937 if((p1
->mpHdl
->GetKind() == SdrHdlKind::Poly
|| p1
->mpHdl
->GetKind() == SdrHdlKind::BezierWeight
)
1938 && (p2
->mpHdl
->GetKind() == SdrHdlKind::Poly
|| p2
->mpHdl
->GetKind() == SdrHdlKind::BezierWeight
))
1940 // both handles are point or control handles
1941 if(p1
->mpHdl
->GetPolyNum() == p2
->mpHdl
->GetPolyNum())
1943 if(p1
->mpHdl
->GetPointNum() < p2
->mpHdl
->GetPointNum())
1952 else if(p1
->mpHdl
->GetPolyNum() < p2
->mpHdl
->GetPolyNum())
1965 if(!p1
->mpHdl
->GetObj())
1969 else if(!p2
->mpHdl
->GetObj())
1975 // different objects, use OrdNum for sort
1976 const sal_uInt32 nOrdNum1
= p1
->mpHdl
->GetObj()->GetOrdNum();
1977 const sal_uInt32 nOrdNum2
= p2
->mpHdl
->GetObj()->GetOrdNum();
1979 if(nOrdNum1
< nOrdNum2
)
1990 // fallback to indices
1991 if(p1
->mnIndex
< p2
->mnIndex
)
2003 void SdrHdlList::TravelFocusHdl(bool bForward
)
2005 // security correction
2006 if (mnFocusIndex
>= GetHdlCount())
2007 mnFocusIndex
= SAL_MAX_SIZE
;
2012 // take care of old handle
2013 const size_t nOldHdlNum(mnFocusIndex
);
2014 SdrHdl
* pOld
= nullptr;
2015 if (nOldHdlNum
< GetHdlCount())
2016 pOld
= GetHdl(nOldHdlNum
);
2020 // switch off old handle
2021 mnFocusIndex
= SAL_MAX_SIZE
;
2025 // allocate pointer array for sorted handle list
2026 std::unique_ptr
<ImplHdlAndIndex
[]> pHdlAndIndex(new ImplHdlAndIndex
[maList
.size()]);
2028 // build sorted handle list
2029 for( size_t a
= 0; a
< maList
.size(); ++a
)
2031 pHdlAndIndex
[a
].mpHdl
= maList
[a
].get();
2032 pHdlAndIndex
[a
].mnIndex
= a
;
2035 qsort(pHdlAndIndex
.get(), maList
.size(), sizeof(ImplHdlAndIndex
), ImplSortHdlFunc
);
2037 // look for old num in sorted array
2038 size_t nOldHdl(nOldHdlNum
);
2040 if(nOldHdlNum
!= SAL_MAX_SIZE
)
2042 for(size_t a
= 0; a
< maList
.size(); ++a
)
2044 if(pHdlAndIndex
[a
].mpHdl
== pOld
)
2053 size_t nNewHdl(nOldHdl
);
2055 // do the focus travel
2058 if(nOldHdl
!= SAL_MAX_SIZE
)
2060 if(nOldHdl
== maList
.size() - 1)
2063 nNewHdl
= SAL_MAX_SIZE
;
2067 // simply the next handle
2073 // start forward run at first entry
2079 if(nOldHdl
== SAL_MAX_SIZE
)
2081 // start backward run at last entry
2082 nNewHdl
= maList
.size() - 1;
2090 nNewHdl
= SAL_MAX_SIZE
;
2094 // simply the previous handle
2101 sal_uIntPtr
nNewHdlNum(nNewHdl
);
2103 // look for old num in sorted array
2104 if(nNewHdl
!= SAL_MAX_SIZE
)
2106 SdrHdl
* pNew
= pHdlAndIndex
[nNewHdl
].mpHdl
;
2108 for(size_t a
= 0; a
< maList
.size(); ++a
)
2110 if(maList
[a
].get() == pNew
)
2118 // take care of next handle
2119 if(nOldHdlNum
!= nNewHdlNum
)
2121 mnFocusIndex
= nNewHdlNum
;
2122 if (mnFocusIndex
< GetHdlCount())
2124 SdrHdl
* pNew
= GetHdl(mnFocusIndex
);
2130 SdrHdl
* SdrHdlList::GetFocusHdl() const
2132 if(mnFocusIndex
< GetHdlCount())
2133 return GetHdl(mnFocusIndex
);
2138 void SdrHdlList::SetFocusHdl(SdrHdl
* pNew
)
2143 SdrHdl
* pActual
= GetFocusHdl();
2145 if(pActual
&& pActual
== pNew
)
2148 const size_t nNewHdlNum
= GetHdlNum(pNew
);
2150 if(nNewHdlNum
!= SAL_MAX_SIZE
)
2152 mnFocusIndex
= nNewHdlNum
;
2163 void SdrHdlList::ResetFocusHdl()
2165 SdrHdl
* pHdl
= GetFocusHdl();
2167 mnFocusIndex
= SAL_MAX_SIZE
;
2176 SdrHdlList::SdrHdlList(SdrMarkView
* pV
)
2177 : mnFocusIndex(SAL_MAX_SIZE
),
2181 m_bRotateShear
= false;
2182 m_bMoveOutside
= false;
2183 m_bDistortShear
= false;
2186 SdrHdlList::~SdrHdlList()
2191 void SdrHdlList::SetHdlSize(sal_uInt16 nSiz
)
2193 if(m_nHdlSize
!= nSiz
)
2195 // remember new value
2198 // propagate change to IAOs
2199 for(size_t i
=0; i
<GetHdlCount(); ++i
)
2201 SdrHdl
* pHdl
= GetHdl(i
);
2207 void SdrHdlList::SetMoveOutside(bool bOn
)
2209 if(m_bMoveOutside
!= bOn
)
2211 // remember new value
2212 m_bMoveOutside
= bOn
;
2214 // propagate change to IAOs
2215 for(size_t i
=0; i
<GetHdlCount(); ++i
)
2217 SdrHdl
* pHdl
= GetHdl(i
);
2223 void SdrHdlList::SetRotateShear(bool bOn
)
2225 m_bRotateShear
= bOn
;
2228 void SdrHdlList::SetDistortShear(bool bOn
)
2230 m_bDistortShear
= bOn
;
2233 std::unique_ptr
<SdrHdl
> SdrHdlList::RemoveHdl(size_t nNum
)
2235 std::unique_ptr
<SdrHdl
> pRetval
= std::move(maList
[nNum
]);
2236 maList
.erase(maList
.begin() + nNum
);
2241 void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind
)
2243 std::erase_if(maList
, [&eKind
](std::unique_ptr
<SdrHdl
>& rItem
) { return rItem
->GetKind() == eKind
; });
2246 void SdrHdlList::Clear()
2250 m_bRotateShear
=false;
2251 m_bDistortShear
=false;
2254 void SdrHdlList::Sort()
2256 // remember currently focused handle
2257 SdrHdl
* pPrev
= GetFocusHdl();
2259 std::sort( maList
.begin(), maList
.end(), ImpSdrHdlListSorter
);
2261 // get now and compare
2262 SdrHdl
* pNow
= GetFocusHdl();
2278 size_t SdrHdlList::GetHdlNum(const SdrHdl
* pHdl
) const
2281 return SAL_MAX_SIZE
;
2282 auto it
= std::find_if( maList
.begin(), maList
.end(),
2283 [&](const std::unique_ptr
<SdrHdl
> & p
) { return p
.get() == pHdl
; });
2284 assert(it
!= maList
.end());
2285 if( it
== maList
.end() )
2286 return SAL_MAX_SIZE
;
2287 return it
- maList
.begin();
2290 void SdrHdlList::AddHdl(std::unique_ptr
<SdrHdl
> pHdl
)
2293 pHdl
->SetHdlList(this);
2294 maList
.push_back(std::move(pHdl
));
2297 SdrHdl
* SdrHdlList::IsHdlListHit(const Point
& rPnt
) const
2299 SdrHdl
* pRet
=nullptr;
2300 const size_t nCount
=GetHdlCount();
2302 while (nNum
>0 && pRet
==nullptr)
2305 SdrHdl
* pHdl
=GetHdl(nNum
);
2306 if (pHdl
->IsHdlHit(rPnt
))
2312 SdrHdl
* SdrHdlList::GetHdl(SdrHdlKind eKind1
) const
2314 SdrHdl
* pRet
=nullptr;
2315 for (size_t i
=0; i
<GetHdlCount() && pRet
==nullptr; ++i
)
2317 SdrHdl
* pHdl
=GetHdl(i
);
2318 if (pHdl
->GetKind()==eKind1
)
2324 void SdrHdlList::MoveTo(SdrHdlList
& rOther
)
2326 for (auto & pHdl
: maList
)
2327 pHdl
->SetHdlList(&rOther
);
2328 rOther
.maList
.insert(rOther
.maList
.end(),
2329 std::make_move_iterator(maList
.begin()), std::make_move_iterator(maList
.end()));
2333 SdrCropHdl::SdrCropHdl(
2335 SdrHdlKind eNewKind
,
2338 : SdrHdl(rPnt
, eNewKind
),
2340 mfRotation(fRotation
)
2345 BitmapEx
SdrCropHdl::GetBitmapForHandle( const BitmapEx
& rBitmap
, int nSize
)
2347 int nPixelSize
= 0, nX
= 0, nY
= 0, nOffset
= 0;
2354 else if( nSize
<=4 )
2367 case SdrHdlKind::UpperLeft
: nX
= 0; nY
= 0; break;
2368 case SdrHdlKind::Upper
: nX
= 1; nY
= 0; break;
2369 case SdrHdlKind::UpperRight
: nX
= 2; nY
= 0; break;
2370 case SdrHdlKind::Left
: nX
= 0; nY
= 1; break;
2371 case SdrHdlKind::Right
: nX
= 2; nY
= 1; break;
2372 case SdrHdlKind::LowerLeft
: nX
= 0; nY
= 2; break;
2373 case SdrHdlKind::Lower
: nX
= 1; nY
= 2; break;
2374 case SdrHdlKind::LowerRight
: nX
= 2; nY
= 2; break;
2378 tools::Rectangle
aSourceRect( Point( nX
* nPixelSize
+ nOffset
, nY
* nPixelSize
), Size(nPixelSize
, nPixelSize
) );
2380 BitmapEx
aRetval(rBitmap
);
2381 aRetval
.Crop(aSourceRect
);
2386 void SdrCropHdl::CreateB2dIAObject()
2388 // first throw away old one
2391 SdrMarkView
* pView
= m_pHdlList
? m_pHdlList
->GetView() : nullptr;
2392 SdrPageView
* pPageView
= pView
? pView
->GetSdrPageView() : nullptr;
2394 if( !pPageView
|| pView
->areMarkHandlesHidden() )
2397 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2398 int nHdlSize
= m_pHdlList
->GetHdlSize();
2400 const BitmapEx
aHandlesBitmap(SIP_SA_CROP_MARKERS
);
2401 BitmapEx
aBmpEx1( GetBitmapForHandle( aHandlesBitmap
, nHdlSize
) );
2403 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
2405 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
2407 if(rPageWindow
.GetPaintWindow().OutputToWindow())
2409 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
2412 basegfx::B2DPoint
aPosition(m_aPos
.X(), m_aPos
.Y());
2414 std::unique_ptr
<sdr::overlay::OverlayObject
> pOverlayObject
;
2416 // animate focused handles
2417 if(IsFocusHdl() && (m_pHdlList
->GetFocusHdl() == this))
2422 BitmapEx
aBmpEx2( GetBitmapForHandle( aHandlesBitmap
, nHdlSize
+ 1 ) );
2424 const sal_uInt64 nBlinkTime
= rStyleSettings
.GetCursorBlinkTime();
2426 pOverlayObject
.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
2431 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Width() - 1) >> 1,
2432 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Height() - 1) >> 1,
2433 static_cast<sal_uInt16
>(aBmpEx2
.GetSizePixel().Width() - 1) >> 1,
2434 static_cast<sal_uInt16
>(aBmpEx2
.GetSizePixel().Height() - 1) >> 1,
2440 // create centered handle as default
2441 pOverlayObject
.reset(new sdr::overlay::OverlayBitmapEx(
2444 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Width() - 1) >> 1,
2445 static_cast<sal_uInt16
>(aBmpEx1
.GetSizePixel().Height() - 1) >> 1,
2452 insertNewlyCreatedOverlayObjectForSdrHdl(
2453 std::move(pOverlayObject
),
2454 rPageWindow
.GetObjectContact(),
2462 // with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
2465 SdrCropViewHdl::SdrCropViewHdl(
2466 basegfx::B2DHomMatrix aObjectTransform
,
2472 : SdrHdl(Point(), SdrHdlKind::User
),
2473 maObjectTransform(std::move(aObjectTransform
)),
2474 maGraphic(std::move(aGraphic
)),
2475 mfCropLeft(fCropLeft
),
2476 mfCropTop(fCropTop
),
2477 mfCropRight(fCropRight
),
2478 mfCropBottom(fCropBottom
)
2484 void translateRotationToMirroring(basegfx::B2DVector
& scale
, double * rotate
) {
2485 assert(rotate
!= nullptr);
2487 // detect 180 degree rotation, this is the same as mirrored in X and Y,
2488 // thus change to mirroring. Prefer mirroring here. Use the equal call
2489 // with getSmallValue here, the original which uses rtl::math::approxEqual
2490 // is too correct here. Maybe this changes with enhanced precision in aw080
2491 // to the better so that this can be reduced to the more precise call again
2492 if(basegfx::fTools::equal(fabs(*rotate
), M_PI
, 0.000000001))
2494 scale
.setX(scale
.getX() * -1.0);
2495 scale
.setY(scale
.getY() * -1.0);
2502 void SdrCropViewHdl::CreateB2dIAObject()
2505 SdrMarkView
* pView
= m_pHdlList
? m_pHdlList
->GetView() : nullptr;
2506 SdrPageView
* pPageView
= pView
? pView
->GetSdrPageView() : nullptr;
2508 if(!pPageView
|| pView
->areMarkHandlesHidden())
2513 // decompose to have current translate and scale
2514 basegfx::B2DVector aScale
, aTranslate
;
2515 double fRotate
, fShearX
;
2517 maObjectTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2519 if(aScale
.equalZero())
2524 translateRotationToMirroring(aScale
, &fRotate
);
2526 // remember mirroring, reset at Scale and adapt crop values for usage;
2527 // mirroring can stay in the object transformation, so do not have to
2528 // cope with it here (except later for the CroppedImage transformation,
2530 const bool bMirroredX(aScale
.getX() < 0.0);
2531 const bool bMirroredY(aScale
.getY() < 0.0);
2532 double fCropLeft(mfCropLeft
);
2533 double fCropTop(mfCropTop
);
2534 double fCropRight(mfCropRight
);
2535 double fCropBottom(mfCropBottom
);
2539 aScale
.setX(-aScale
.getX());
2544 aScale
.setY(-aScale
.getY());
2547 // create target translate and scale
2548 const basegfx::B2DVector
aTargetScale(
2549 aScale
.getX() + fCropRight
+ fCropLeft
,
2550 aScale
.getY() + fCropBottom
+ fCropTop
);
2551 const basegfx::B2DVector
aTargetTranslate(
2552 aTranslate
.getX() - fCropLeft
,
2553 aTranslate
.getY() - fCropTop
);
2555 // create ranges to make comparisons
2556 const basegfx::B2DRange
aCurrentForCompare(
2557 aTranslate
.getX(), aTranslate
.getY(),
2558 aTranslate
.getX() + aScale
.getX(), aTranslate
.getY() + aScale
.getY());
2559 basegfx::B2DRange
aCropped(
2560 aTargetTranslate
.getX(), aTargetTranslate
.getY(),
2561 aTargetTranslate
.getX() + aTargetScale
.getX(), aTargetTranslate
.getY() + aTargetScale
.getY());
2563 if(aCropped
.isEmpty())
2565 // nothing to return since cropped content is completely empty
2569 if(aCurrentForCompare
.equal(aCropped
))
2575 // back-transform to have values in unit coordinates
2576 basegfx::B2DHomMatrix aBackToUnit
;
2577 aBackToUnit
.translate(-aTranslate
.getX(), -aTranslate
.getY());
2579 basegfx::fTools::equalZero(aScale
.getX()) ? 1.0 : 1.0 / aScale
.getX(),
2580 basegfx::fTools::equalZero(aScale
.getY()) ? 1.0 : 1.0 / aScale
.getY());
2582 // transform cropped back to unit coordinates
2583 aCropped
.transform(aBackToUnit
);
2585 // prepare crop PolyPolygon
2586 basegfx::B2DPolygon
aGraphicOutlinePolygon(
2587 basegfx::utils::createPolygonFromRect(
2589 basegfx::B2DPolyPolygon
aCropPolyPolygon(aGraphicOutlinePolygon
);
2591 // current range is unit range
2592 basegfx::B2DRange
aOverlap(0.0, 0.0, 1.0, 1.0);
2594 aOverlap
.intersect(aCropped
);
2596 if(!aOverlap
.isEmpty())
2598 aCropPolyPolygon
.append(
2599 basegfx::utils::createPolygonFromRect(
2603 // transform to object coordinates to prepare for clip
2604 aCropPolyPolygon
.transform(maObjectTransform
);
2605 aGraphicOutlinePolygon
.transform(maObjectTransform
);
2607 // create cropped transformation
2608 basegfx::B2DHomMatrix aCroppedTransform
;
2610 aCroppedTransform
.scale(
2611 aCropped
.getWidth(),
2612 aCropped
.getHeight());
2613 aCroppedTransform
.translate(
2615 aCropped
.getMinY());
2616 aCroppedTransform
= maObjectTransform
* aCroppedTransform
;
2618 // prepare graphic primitive (transformed)
2619 const drawinglayer::primitive2d::Primitive2DReference
aGraphic(
2620 new drawinglayer::primitive2d::GraphicPrimitive2D(
2624 // prepare outline polygon for whole graphic
2625 const basegfx::BColor
aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
2626 const drawinglayer::primitive2d::Primitive2DReference
aGraphicOutline(
2627 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
2628 std::move(aGraphicOutlinePolygon
),
2632 drawinglayer::primitive2d::Primitive2DContainer aCombination
{ aGraphic
, aGraphicOutline
};
2634 // embed to MaskPrimitive2D
2635 const drawinglayer::primitive2d::Primitive2DReference
aMaskedGraphic(
2636 new drawinglayer::primitive2d::MaskPrimitive2D(
2637 std::move(aCropPolyPolygon
),
2638 std::move(aCombination
)));
2640 // embed to UnifiedTransparencePrimitive2D
2641 const drawinglayer::primitive2d::Primitive2DReference
aTransparenceMaskedGraphic(
2642 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2643 drawinglayer::primitive2d::Primitive2DContainer
{ aMaskedGraphic
},
2646 const drawinglayer::primitive2d::Primitive2DContainer aSequence
{ aTransparenceMaskedGraphic
};
2648 for(sal_uInt32
b(0); b
< pPageView
->PageWindowCount(); b
++)
2650 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
2651 const SdrPageWindow
& rPageWindow
= *(pPageView
->GetPageWindow(b
));
2653 if(rPageWindow
.GetPaintWindow().OutputToWindow())
2655 const rtl::Reference
< sdr::overlay::OverlayManager
>& xManager
= rPageWindow
.GetOverlayManager();
2658 std::unique_ptr
<sdr::overlay::OverlayObject
> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(drawinglayer::primitive2d::Primitive2DContainer(aSequence
)));
2660 // only informative object, no hit
2661 pNew
->setHittable(false);
2664 insertNewlyCreatedOverlayObjectForSdrHdl(
2666 rPageWindow
.GetObjectContact(),
2673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */