Adjust includes
[LibreOffice.git] / svx / source / svdraw / svdhdl.cxx
blobef9634ad08009590c1b984b465547f9f2c29a7e3
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/svdetc.hxx>
27 #include <svx/svdmrkv.hxx>
28 #include <vcl/window.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/virdev.hxx>
31 #include <tools/poly.hxx>
32 #include <vcl/bitmapaccess.hxx>
34 #include <svx/sxekitm.hxx>
35 #include <svx/strings.hrc>
36 #include <svdglob.hxx>
38 #include <svx/svdmodel.hxx>
39 #include "gradtrns.hxx"
40 #include <svx/xflgrit.hxx>
41 #include <svx/svdundo.hxx>
42 #include <svx/dialmgr.hxx>
43 #include <svx/xflftrit.hxx>
45 #include <svx/svdopath.hxx>
46 #include <basegfx/vector/b2dvector.hxx>
47 #include <basegfx/polygon/b2dpolygon.hxx>
48 #include <svx/sdr/overlay/overlaymanager.hxx>
49 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
50 #include <svx/sdr/overlay/overlaybitmapex.hxx>
51 #include <sdr/overlay/overlayline.hxx>
52 #include <svx/sdr/overlay/overlaytriangle.hxx>
53 #include <sdr/overlay/overlayhandle.hxx>
54 #include <sdr/overlay/overlayrectangle.hxx>
55 #include <svx/sdrpagewindow.hxx>
56 #include <svx/sdrpaintwindow.hxx>
57 #include <vcl/svapp.hxx>
58 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
59 #include <vcl/lazydelete.hxx>
60 #include <vcl/BitmapTools.hxx>
62 #include <basegfx/polygon/b2dpolygontools.hxx>
63 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
64 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
65 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
66 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
67 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
68 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
69 #include <memory>
70 #include <bitmaps.hlst>
72 // #i15222#
73 // Due to the resource problems in Win95/98 with bitmap resources I
74 // will change this handle bitmap providing class. Old version was splitting
75 // and preparing all small handle bitmaps in device bitmap format, now this will
76 // be done on the fly. Thus, there is only one big bitmap in memory. With
77 // three source bitmaps, this will be 3 system bitmap resources instead of hundreds.
78 // The price for that needs to be evaluated. Maybe we will need another change here
79 // if this is too expensive.
80 class SdrHdlBitmapSet
82 // the bitmap holding all information
83 BitmapEx maMarkersBitmap;
85 // the cropped Bitmaps for reusage
86 ::std::vector< BitmapEx > maRealMarkers;
88 // helpers
89 BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle);
91 public:
92 explicit SdrHdlBitmapSet();
94 const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd);
98 #define KIND_COUNT (14)
99 #define INDEX_COUNT (6)
100 #define INDIVIDUAL_COUNT (5)
102 SdrHdlBitmapSet::SdrHdlBitmapSet()
103 : maMarkersBitmap(SIP_SA_MARKERS),
104 // 15 kinds (BitmapMarkerKind) use index [0..5] + 5 extra
105 maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
109 BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle)
111 BitmapEx& rTargetBitmap = maRealMarkers[nIndex];
113 if(rTargetBitmap.IsEmpty())
115 rTargetBitmap = maMarkersBitmap;
116 rTargetBitmap.Crop(rRectangle);
119 return rTargetBitmap;
122 // change getting of bitmap to use the big resource bitmap
123 const BitmapEx& SdrHdlBitmapSet::GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd)
125 // fill in size and source position in maMarkersBitmap
126 const sal_uInt16 nYPos(nInd * 11);
128 switch(eKindOfMarker)
130 default:
132 OSL_FAIL( "Unknown kind of marker." );
133 SAL_FALLTHROUGH; // return Rect_9x9 as default
135 case BitmapMarkerKind::Rect_9x9:
137 return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, tools::Rectangle(Point(7, nYPos), Size(9, 9)));
140 case BitmapMarkerKind::Rect_7x7:
142 return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, tools::Rectangle(Point(0, nYPos), Size(7, 7)));
145 case BitmapMarkerKind::Rect_11x11:
147 return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, tools::Rectangle(Point(16, nYPos), Size(11, 11)));
150 case BitmapMarkerKind::Rect_13x13:
152 const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);
154 switch(nInd)
156 case 0:
158 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 66), Size(13, 13)));
160 case 1:
162 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 66), Size(13, 13)));
164 case 2:
166 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 79), Size(13, 13)));
168 case 3:
170 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 79), Size(13, 13)));
172 case 4:
174 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 79), Size(13, 13)));
176 default: // case 5:
178 return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 66), Size(13, 13)));
183 case BitmapMarkerKind::Circ_7x7:
184 case BitmapMarkerKind::Customshape_7x7:
186 return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, tools::Rectangle(Point(27, nYPos), Size(7, 7)));
189 case BitmapMarkerKind::Circ_9x9:
190 case BitmapMarkerKind::Customshape_9x9:
192 return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, tools::Rectangle(Point(34, nYPos), Size(9, 9)));
195 case BitmapMarkerKind::Circ_11x11:
196 case BitmapMarkerKind::Customshape_11x11:
198 return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, tools::Rectangle(Point(43, nYPos), Size(11, 11)));
201 case BitmapMarkerKind::Elli_7x9:
203 return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, tools::Rectangle(Point(54, nYPos), Size(7, 9)));
206 case BitmapMarkerKind::Elli_9x11:
208 return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, tools::Rectangle(Point(61, nYPos), Size(9, 11)));
211 case BitmapMarkerKind::Elli_9x7:
213 return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, tools::Rectangle(Point(70, nYPos), Size(9, 7)));
216 case BitmapMarkerKind::Elli_11x9:
218 return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, tools::Rectangle(Point(79, nYPos), Size(11, 9)));
221 case BitmapMarkerKind::RectPlus_7x7:
223 return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, tools::Rectangle(Point(90, nYPos), Size(7, 7)));
226 case BitmapMarkerKind::RectPlus_9x9:
228 return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, tools::Rectangle(Point(97, nYPos), Size(9, 9)));
231 case BitmapMarkerKind::RectPlus_11x11:
233 return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, tools::Rectangle(Point(106, nYPos), Size(11, 11)));
236 case BitmapMarkerKind::Crosshair:
238 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, tools::Rectangle(Point(0, 68), Size(15, 15)));
241 case BitmapMarkerKind::Glue:
243 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, tools::Rectangle(Point(15, 76), Size(9, 9)));
246 case BitmapMarkerKind::Glue_Deselected:
248 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, tools::Rectangle(Point(15, 67), Size(9, 9)));
251 case BitmapMarkerKind::Anchor: // AnchorTR for SW
252 case BitmapMarkerKind::AnchorTR:
254 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, tools::Rectangle(Point(24, 67), Size(24, 24)));
257 // add AnchorPressed to be able to animate anchor control
258 case BitmapMarkerKind::AnchorPressed:
259 case BitmapMarkerKind::AnchorPressedTR:
261 return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, tools::Rectangle(Point(48, 67), Size(24, 24)));
267 SdrHdl::SdrHdl():
268 pObj(nullptr),
269 pPV(nullptr),
270 pHdlList(nullptr),
271 eKind(SdrHdlKind::Move),
272 nRotationAngle(0),
273 nObjHdlNum(0),
274 nPolyNum(0),
275 nPPntNum(0),
276 nSourceHdlNum(0),
277 bSelect(false),
278 b1PixMore(false),
279 bPlusHdl(false),
280 mbMoveOutside(false),
281 mbMouseOver(false)
285 SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
286 pObj(nullptr),
287 pPV(nullptr),
288 pHdlList(nullptr),
289 aPos(rPnt),
290 eKind(eNewKind),
291 nRotationAngle(0),
292 nObjHdlNum(0),
293 nPolyNum(0),
294 nPPntNum(0),
295 nSourceHdlNum(0),
296 bSelect(false),
297 b1PixMore(false),
298 bPlusHdl(false),
299 mbMoveOutside(false),
300 mbMouseOver(false)
304 SdrHdl::~SdrHdl()
306 GetRidOfIAObject();
309 void SdrHdl::Set1PixMore(bool bJa)
311 if(b1PixMore != bJa)
313 b1PixMore = bJa;
315 // create new display
316 Touch();
320 void SdrHdl::SetMoveOutside( bool bMoveOutside )
322 if(mbMoveOutside != bMoveOutside)
324 mbMoveOutside = bMoveOutside;
326 // create new display
327 Touch();
331 void SdrHdl::SetRotationAngle(long n)
333 if(nRotationAngle != n)
335 nRotationAngle = n;
337 // create new display
338 Touch();
342 void SdrHdl::SetPos(const Point& rPnt)
344 if(aPos != rPnt)
346 // remember new position
347 aPos = rPnt;
349 // create new display
350 Touch();
354 void SdrHdl::SetSelected(bool bJa)
356 if(bSelect != bJa)
358 // remember new value
359 bSelect = bJa;
361 // create new display
362 Touch();
366 void SdrHdl::SetHdlList(SdrHdlList* pList)
368 if(pHdlList != pList)
370 // remember list
371 pHdlList = pList;
373 // now its possible to create graphic representation
374 Touch();
378 void SdrHdl::SetObj(SdrObject* pNewObj)
380 if(pObj != pNewObj)
382 // remember new object
383 pObj = pNewObj;
385 // graphic representation may have changed
386 Touch();
390 void SdrHdl::Touch()
392 // force update of graphic representation
393 CreateB2dIAObject();
396 void SdrHdl::GetRidOfIAObject()
399 // OVERLAYMANAGER
400 maOverlayGroup.clear();
403 void SdrHdl::CreateB2dIAObject()
405 // first throw away old one
406 GetRidOfIAObject();
408 if(pHdlList && pHdlList->GetView() && !pHdlList->GetView()->areMarkHandlesHidden())
410 BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
411 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
413 bool bRot = pHdlList->IsRotateShear();
414 if(pObj)
415 eColIndex = bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
416 if(bRot)
418 // red rotation handles
419 if(pObj && bSelect)
420 eColIndex = BitmapColorIndex::Red;
421 else
422 eColIndex = BitmapColorIndex::LightRed;
425 switch(eKind)
427 case SdrHdlKind::Move:
429 eKindOfMarker = (b1PixMore) ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
430 break;
432 case SdrHdlKind::UpperLeft:
433 case SdrHdlKind::UpperRight:
434 case SdrHdlKind::LowerLeft:
435 case SdrHdlKind::LowerRight:
437 // corner handles
438 if(bRot)
440 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
442 else
444 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
446 break;
448 case SdrHdlKind::Upper:
449 case SdrHdlKind::Lower:
451 // Upper/Lower handles
452 if(bRot)
454 eKindOfMarker = BitmapMarkerKind::Elli_9x7;
456 else
458 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
460 break;
462 case SdrHdlKind::Left:
463 case SdrHdlKind::Right:
465 // Left/Right handles
466 if(bRot)
468 eKindOfMarker = BitmapMarkerKind::Elli_7x9;
470 else
472 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
474 break;
476 case SdrHdlKind::Poly:
478 if(bRot)
480 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
482 else
484 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
486 break;
488 case SdrHdlKind::BezierWeight: // weight at poly
490 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
491 break;
493 case SdrHdlKind::Circle:
495 eKindOfMarker = BitmapMarkerKind::Rect_11x11;
496 break;
498 case SdrHdlKind::Ref1:
499 case SdrHdlKind::Ref2:
501 eKindOfMarker = BitmapMarkerKind::Crosshair;
502 break;
504 case SdrHdlKind::Glue:
506 eKindOfMarker = BitmapMarkerKind::Glue;
507 break;
509 case SdrHdlKind::Anchor:
511 eKindOfMarker = BitmapMarkerKind::Anchor;
512 break;
514 case SdrHdlKind::User:
516 break;
518 // top right anchor for SW
519 case SdrHdlKind::Anchor_TR:
521 eKindOfMarker = BitmapMarkerKind::AnchorTR;
522 break;
525 // for SJ and the CustomShapeHandles:
526 case SdrHdlKind::CustomShape1:
528 eKindOfMarker = b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
529 eColIndex = BitmapColorIndex::Yellow;
530 break;
532 default:
533 break;
536 SdrMarkView* pView = pHdlList->GetView();
537 SdrPageView* pPageView = pView->GetSdrPageView();
539 if(pPageView)
541 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
543 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
544 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
546 if(rPageWindow.GetPaintWindow().OutputToWindow())
548 Point aMoveOutsideOffset(0, 0);
549 OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
551 // add offset if necessary
552 if(pHdlList->IsMoveOutside() || mbMoveOutside)
554 Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
556 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Upper || eKind == SdrHdlKind::UpperRight)
557 aMoveOutsideOffset.Y() -= aOffset.Width();
558 if(eKind == SdrHdlKind::LowerLeft || eKind == SdrHdlKind::Lower || eKind == SdrHdlKind::LowerRight)
559 aMoveOutsideOffset.Y() += aOffset.Height();
560 if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Left || eKind == SdrHdlKind::LowerLeft)
561 aMoveOutsideOffset.X() -= aOffset.Width();
562 if(eKind == SdrHdlKind::UpperRight || eKind == SdrHdlKind::Right || eKind == SdrHdlKind::LowerRight)
563 aMoveOutsideOffset.X() += aOffset.Height();
566 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
567 if (xManager.is())
569 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
570 sdr::overlay::OverlayObject* pNewOverlayObject = nullptr;
571 if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker == BitmapMarkerKind::Rect_7x7 || eKindOfMarker == BitmapMarkerKind::Rect_9x9 || eKindOfMarker == BitmapMarkerKind::Rect_11x11))
573 double fSize = 7.0;
574 switch (eKindOfMarker)
576 case BitmapMarkerKind::Rect_9x9:
577 fSize = 9.0;
578 break;
579 case BitmapMarkerKind::Rect_11x11:
580 fSize = 11.0;
581 break;
582 default:
583 break;
585 float fScalingFactor = rOutDev.GetDPIScaleFactor();
586 basegfx::B2DSize aB2DSize(fSize * fScalingFactor, fSize * fScalingFactor);
588 Color aHandleStrokeColor(COL_BLACK);
589 Color aHandleFillColor(COL_LIGHTGREEN);
590 switch (eColIndex)
592 case BitmapColorIndex::Cyan:
593 aHandleFillColor = Color(COL_CYAN);
594 break;
595 case BitmapColorIndex::LightCyan:
596 aHandleFillColor = Color(COL_LIGHTCYAN);
597 break;
598 case BitmapColorIndex::Red:
599 aHandleFillColor = Color(COL_RED);
600 break;
601 case BitmapColorIndex::LightRed:
602 aHandleFillColor = Color(COL_LIGHTRED);
603 break;
604 case BitmapColorIndex::Yellow:
605 aHandleFillColor = Color(COL_YELLOW);
606 break;
607 default:
608 break;
610 pNewOverlayObject = new sdr::overlay::OverlayHandle(aPosition, aB2DSize, aHandleStrokeColor, aHandleFillColor);
612 else
614 pNewOverlayObject = CreateOverlayObject(
615 aPosition, eColIndex, eKindOfMarker,
616 aMoveOutsideOffset);
618 // OVERLAYMANAGER
619 if (pNewOverlayObject)
621 xManager->add(*pNewOverlayObject);
622 maOverlayGroup.append(pNewOverlayObject);
631 BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd)
633 BitmapMarkerKind eRetval(eKnd);
635 switch(eKnd)
637 case BitmapMarkerKind::Rect_7x7: eRetval = BitmapMarkerKind::Rect_9x9; break;
638 case BitmapMarkerKind::Rect_9x9: eRetval = BitmapMarkerKind::Rect_11x11; break;
639 case BitmapMarkerKind::Rect_11x11: eRetval = BitmapMarkerKind::Rect_13x13; break;
641 case BitmapMarkerKind::Circ_7x7: eRetval = BitmapMarkerKind::Circ_9x9; break;
642 case BitmapMarkerKind::Circ_9x9: eRetval = BitmapMarkerKind::Circ_11x11; break;
644 case BitmapMarkerKind::Customshape_7x7: eRetval = BitmapMarkerKind::Customshape_9x9; break;
645 case BitmapMarkerKind::Customshape_9x9: eRetval = BitmapMarkerKind::Customshape_11x11; break;
646 //case BitmapMarkerKind::Customshape_11x11: eRetval = ; break;
648 case BitmapMarkerKind::Elli_7x9: eRetval = BitmapMarkerKind::Elli_9x11; break;
650 case BitmapMarkerKind::Elli_9x7: eRetval = BitmapMarkerKind::Elli_11x9; break;
652 case BitmapMarkerKind::RectPlus_7x7: eRetval = BitmapMarkerKind::RectPlus_9x9; break;
653 case BitmapMarkerKind::RectPlus_9x9: eRetval = BitmapMarkerKind::RectPlus_11x11; break;
655 // let anchor blink with its pressed state
656 case BitmapMarkerKind::Anchor: eRetval = BitmapMarkerKind::AnchorPressed; break;
658 // same for AnchorTR
659 case BitmapMarkerKind::AnchorTR: eRetval = BitmapMarkerKind::AnchorPressedTR; break;
660 default:
661 break;
664 return eRetval;
667 namespace
670 OUString appendMarkerName(BitmapMarkerKind eKindOfMarker)
672 switch(eKindOfMarker)
674 case BitmapMarkerKind::Rect_7x7:
675 return OUString("rect7");
676 case BitmapMarkerKind::Rect_9x9:
677 return OUString("rect9");
678 case BitmapMarkerKind::Rect_11x11:
679 return OUString("rect11");
680 case BitmapMarkerKind::Rect_13x13:
681 return OUString("rect13");
682 case BitmapMarkerKind::Circ_7x7:
683 case BitmapMarkerKind::Customshape_7x7:
684 return OUString("circ7");
685 case BitmapMarkerKind::Circ_9x9:
686 case BitmapMarkerKind::Customshape_9x9:
687 return OUString("circ9");
688 case BitmapMarkerKind::Circ_11x11:
689 case BitmapMarkerKind::Customshape_11x11:
690 return OUString("circ11");
691 case BitmapMarkerKind::Elli_7x9:
692 return OUString("elli7x9");
693 case BitmapMarkerKind::Elli_9x11:
694 return OUString("elli9x11");
695 case BitmapMarkerKind::Elli_9x7:
696 return OUString("elli9x7");
697 case BitmapMarkerKind::Elli_11x9:
698 return OUString("elli11x9");
699 case BitmapMarkerKind::RectPlus_7x7:
700 return OUString("rectplus7");
701 case BitmapMarkerKind::RectPlus_9x9:
702 return OUString("rectplus9");
703 case BitmapMarkerKind::RectPlus_11x11:
704 return OUString("rectplus11");
705 case BitmapMarkerKind::Crosshair:
706 return OUString("cross");
707 case BitmapMarkerKind::Anchor:
708 case BitmapMarkerKind::AnchorTR:
709 return OUString("anchor");
710 case BitmapMarkerKind::AnchorPressed:
711 case BitmapMarkerKind::AnchorPressedTR:
712 return OUString("anchor-pressed");
713 case BitmapMarkerKind::Glue:
714 return OUString("glue-selected");
715 case BitmapMarkerKind::Glue_Deselected:
716 return OUString("glue-unselected");
717 default:
718 break;
720 return OUString();
723 OUString appendMarkerColor(BitmapColorIndex eIndex)
725 switch(eIndex)
727 case BitmapColorIndex::LightGreen:
728 return OUString("1");
729 case BitmapColorIndex::Cyan:
730 return OUString("2");
731 case BitmapColorIndex::LightCyan:
732 return OUString("3");
733 case BitmapColorIndex::Red:
734 return OUString("4");
735 case BitmapColorIndex::LightRed:
736 return OUString("5");
737 case BitmapColorIndex::Yellow:
738 return OUString("6");
739 default:
740 break;
742 return OUString();
745 BitmapEx ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, BitmapColorIndex eIndex)
747 // use this code path only when we use HiDPI (for now)
748 if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
750 OUString sMarkerPrefix("svx/res/marker-");
752 OUString sMarkerName = appendMarkerName(eKindOfMarker);
753 if (!sMarkerName.isEmpty())
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(new SdrHdlBitmapSet);
780 return aModernSet.get()->GetBitmapEx(eKindOfMarker, sal_uInt16(eIndex));
783 } // end anonymous namespace
785 sdr::overlay::OverlayObject* SdrHdl::CreateOverlayObject(
786 const basegfx::B2DPoint& rPos,
787 BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
789 sdr::overlay::OverlayObject* pRetval = nullptr;
791 // support bigger sizes
792 bool bForceBiggerSize(false);
794 if(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 = 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 = new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
874 (sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1), 0,
875 (sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1), 0);
877 else
879 // create centered handle as default
880 pRetval = new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
881 (sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
882 (sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
883 (sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
884 (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(Bitmap(Size(13, 13), 24));
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 = 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 = new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
914 (sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1), 0);
916 else
918 sal_uInt16 nCenX((sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1) >> 1);
919 sal_uInt16 nCenY((sal_uInt16)(aBmpEx.GetSizePixel().Height() - 1) >> 1);
921 if(aMoveOutsideOffset.X() > 0)
923 nCenX = 0;
925 else if(aMoveOutsideOffset.X() < 0)
927 nCenX = (sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1);
930 if(aMoveOutsideOffset.Y() > 0)
932 nCenY = 0;
934 else if(aMoveOutsideOffset.Y() < 0)
936 nCenY = (sal_uInt16)(aBmpEx.GetSizePixel().Height() - 1);
939 // create centered handle as default
940 pRetval = 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 Pointer 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) {
972 long nHdlAngle=0;
973 switch (eKind) {
974 case SdrHdlKind::LowerRight: nHdlAngle=31500; break;
975 case SdrHdlKind::Lower: nHdlAngle=27000; break;
976 case SdrHdlKind::LowerLeft: nHdlAngle=22500; break;
977 case SdrHdlKind::Left : nHdlAngle=18000; break;
978 case SdrHdlKind::UpperLeft: nHdlAngle=13500; break;
979 case SdrHdlKind::Upper: nHdlAngle=9000; break;
980 case SdrHdlKind::UpperRight: nHdlAngle=4500; break;
981 case SdrHdlKind::Right: nHdlAngle=0; break;
982 default:
983 break;
985 nHdlAngle+=nRotationAngle+2249; // a little bit more (for rounding)
986 while (nHdlAngle<0) nHdlAngle+=36000;
987 while (nHdlAngle>=36000) nHdlAngle-=36000;
988 nHdlAngle/=4500;
989 switch ((sal_uInt8)nHdlAngle) {
990 case 0: ePtr=PointerStyle::ESize; break;
991 case 1: ePtr=PointerStyle::NESize; break;
992 case 2: ePtr=PointerStyle::NSize; break;
993 case 3: ePtr=PointerStyle::NWSize; break;
994 case 4: ePtr=PointerStyle::WSize; break;
995 case 5: ePtr=PointerStyle::SWSize; break;
996 case 6: ePtr=PointerStyle::SSize; break;
997 case 7: ePtr=PointerStyle::SESize; break;
998 } // switch
999 } else {
1000 switch (eKind) {
1001 case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
1002 case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
1003 case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
1004 case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
1005 case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
1006 case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
1007 case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
1008 case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
1009 case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
1010 case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
1011 case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
1012 case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
1013 case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
1014 case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
1015 case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::Hand; break;
1016 default:
1017 break;
1021 return Pointer(ePtr);
1024 bool SdrHdl::IsFocusHdl() const
1026 switch(eKind)
1028 case SdrHdlKind::UpperLeft:
1029 case SdrHdlKind::Upper:
1030 case SdrHdlKind::UpperRight:
1031 case SdrHdlKind::Left:
1032 case SdrHdlKind::Right:
1033 case SdrHdlKind::LowerLeft:
1034 case SdrHdlKind::Lower:
1035 case SdrHdlKind::LowerRight:
1037 // if it's an activated TextEdit, it's moved to extended points
1038 return !pHdlList || !pHdlList->IsMoveOutside();
1041 case SdrHdlKind::Move: // handle to move object
1042 case SdrHdlKind::Poly: // selected point of polygon or curve
1043 case SdrHdlKind::BezierWeight: // weight at a curve
1044 case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
1045 case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
1046 case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
1047 case SdrHdlKind::Glue: // glue point
1049 // for SJ and the CustomShapeHandles:
1050 case SdrHdlKind::CustomShape1:
1052 case SdrHdlKind::User:
1054 return true;
1057 default:
1059 return false;
1064 void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
1068 void SdrHdl::onMouseLeave()
1072 BitmapEx SdrHdl::createGluePointBitmap()
1074 return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
1077 SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
1078 : SdrHdl(rRef, SdrHdlKind::Color),
1079 aMarkerSize(rSize),
1080 bUseLuminance(bLum)
1082 if(IsUseLuminance())
1083 aCol = GetLuminance(aCol);
1085 // remember color
1086 aMarkerColor = aCol;
1089 SdrHdlColor::~SdrHdlColor()
1093 void SdrHdlColor::CreateB2dIAObject()
1095 // first throw away old one
1096 GetRidOfIAObject();
1098 if(pHdlList)
1100 SdrMarkView* pView = pHdlList->GetView();
1102 if(pView && !pView->areMarkHandlesHidden())
1104 SdrPageView* pPageView = pView->GetSdrPageView();
1106 if(pPageView)
1108 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1110 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1112 if(rPageWindow.GetPaintWindow().OutputToWindow())
1114 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1115 if (xManager.is())
1117 Bitmap aBmpCol(CreateColorDropper(aMarkerColor));
1118 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1119 sdr::overlay::OverlayObject* pNewOverlayObject = new
1120 sdr::overlay::OverlayBitmapEx(
1121 aPosition,
1122 BitmapEx(aBmpCol),
1123 (sal_uInt16)(aBmpCol.GetSizePixel().Width() - 1) >> 1,
1124 (sal_uInt16)(aBmpCol.GetSizePixel().Height() - 1) >> 1
1127 // OVERLAYMANAGER
1128 xManager->add(*pNewOverlayObject);
1129 maOverlayGroup.append(pNewOverlayObject);
1138 Bitmap SdrHdlColor::CreateColorDropper(Color aCol)
1140 // get the Bitmap
1141 Bitmap aRetval(aMarkerSize, 24);
1142 aRetval.Erase(aCol);
1144 // get write access
1145 std::unique_ptr<BitmapWriteAccess> pWrite(aRetval.AcquireWriteAccess());
1146 DBG_ASSERT(pWrite, "Got NO write access to a new Bitmap!");
1148 if(pWrite)
1150 // draw outer border
1151 sal_Int32 nWidth = aMarkerSize.Width();
1152 sal_Int32 nHeight = aMarkerSize.Height();
1154 pWrite->SetLineColor(Color(COL_LIGHTGRAY));
1155 pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
1156 pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
1157 pWrite->SetLineColor(Color(COL_GRAY));
1158 pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
1159 pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
1161 // draw lighter UpperLeft
1162 const Color aLightColor(
1163 (sal_uInt8)(::std::min((sal_Int16)((sal_Int16)aCol.GetRed() + (sal_Int16)0x0040), (sal_Int16)0x00ff)),
1164 (sal_uInt8)(::std::min((sal_Int16)((sal_Int16)aCol.GetGreen() + (sal_Int16)0x0040), (sal_Int16)0x00ff)),
1165 (sal_uInt8)(::std::min((sal_Int16)((sal_Int16)aCol.GetBlue() + (sal_Int16)0x0040), (sal_Int16)0x00ff)));
1166 pWrite->SetLineColor(aLightColor);
1167 pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
1168 pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
1170 // draw darker LowerRight
1171 const Color aDarkColor(
1172 (sal_uInt8)(::std::max((sal_Int16)((sal_Int16)aCol.GetRed() - (sal_Int16)0x0040), (sal_Int16)0x0000)),
1173 (sal_uInt8)(::std::max((sal_Int16)((sal_Int16)aCol.GetGreen() - (sal_Int16)0x0040), (sal_Int16)0x0000)),
1174 (sal_uInt8)(::std::max((sal_Int16)((sal_Int16)aCol.GetBlue() - (sal_Int16)0x0040), (sal_Int16)0x0000)));
1175 pWrite->SetLineColor(aDarkColor);
1176 pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
1177 pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
1180 return aRetval;
1183 Color SdrHdlColor::GetLuminance(const Color& rCol)
1185 sal_uInt8 aLum = rCol.GetLuminance();
1186 Color aRetval(aLum, aLum, aLum);
1187 return aRetval;
1190 void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
1192 if(IsUseLuminance())
1193 aNew = GetLuminance(aNew);
1195 if(aMarkerColor != aNew)
1197 // remember new color
1198 aMarkerColor = aNew;
1200 // create new display
1201 Touch();
1203 // tell about change
1204 if(bCallLink)
1205 aColorChangeHdl.Call(this);
1209 void SdrHdlColor::SetSize(const Size& rNew)
1211 if(rNew != aMarkerSize)
1213 // remember new size
1214 aMarkerSize = rNew;
1216 // create new display
1217 Touch();
1221 SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
1222 : SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
1223 , pColHdl1(nullptr)
1224 , pColHdl2(nullptr)
1225 , a2ndPos(rRef2)
1226 , bGradient(bGrad)
1227 , bMoveSingleHandle(false)
1228 , bMoveFirstHandle(false)
1232 SdrHdlGradient::~SdrHdlGradient()
1236 void SdrHdlGradient::Set2ndPos(const Point& rPnt)
1238 if(a2ndPos != rPnt)
1240 // remember new position
1241 a2ndPos = rPnt;
1243 // create new display
1244 Touch();
1248 void SdrHdlGradient::CreateB2dIAObject()
1250 // first throw away old one
1251 GetRidOfIAObject();
1253 if(pHdlList)
1255 SdrMarkView* pView = pHdlList->GetView();
1257 if(pView && !pView->areMarkHandlesHidden())
1259 SdrPageView* pPageView = pView->GetSdrPageView();
1261 if(pPageView)
1263 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1265 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1267 if(rPageWindow.GetPaintWindow().OutputToWindow())
1269 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1270 if (xManager.is())
1272 // striped line in between
1273 basegfx::B2DVector aVec(a2ndPos.X() - aPos.X(), a2ndPos.Y() - aPos.Y());
1274 double fVecLen = aVec.getLength();
1275 double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
1276 double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
1277 aVec.normalize();
1278 basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
1279 sal_Int32 nMidX = (sal_Int32)(aPos.X() + aVec.getX() * fLongPercentArrow);
1280 sal_Int32 nMidY = (sal_Int32)(aPos.Y() + aVec.getY() * fLongPercentArrow);
1281 Point aMidPoint(nMidX, nMidY);
1283 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1284 basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
1286 sdr::overlay::OverlayObject* pNewOverlayObject = new
1287 sdr::overlay::OverlayLineStriped(
1288 aPosition, aMidPos
1290 DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");
1292 pNewOverlayObject->setBaseColor(IsGradient() ? Color(COL_BLACK) : Color(COL_BLUE));
1293 xManager->add(*pNewOverlayObject);
1294 maOverlayGroup.append(pNewOverlayObject);
1296 // arrowhead
1297 Point aLeft(aMidPoint.X() + (sal_Int32)(aPerpend.getX() * fHalfArrowWidth),
1298 aMidPoint.Y() + (sal_Int32)(aPerpend.getY() * fHalfArrowWidth));
1299 Point aRight(aMidPoint.X() - (sal_Int32)(aPerpend.getX() * fHalfArrowWidth),
1300 aMidPoint.Y() - (sal_Int32)(aPerpend.getY() * fHalfArrowWidth));
1302 basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
1303 basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
1304 basegfx::B2DPoint aPosition2(a2ndPos.X(), a2ndPos.Y());
1306 pNewOverlayObject = new
1307 sdr::overlay::OverlayTriangle(
1308 aPositionLeft,
1309 aPosition2,
1310 aPositionRight,
1311 IsGradient() ? Color(COL_BLACK) : Color(COL_BLUE)
1313 DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");
1315 xManager->add(*pNewOverlayObject);
1316 maOverlayGroup.append(pNewOverlayObject);
1325 IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
1327 if(GetObj())
1328 FromIAOToItem(GetObj(), true, true);
1331 void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
1333 // from IAO positions and colors to gradient
1334 const SfxItemSet& rSet = _pObj->GetMergedItemSet();
1336 GradTransformer aGradTransformer;
1337 GradTransGradient aOldGradTransGradient;
1338 GradTransGradient aGradTransGradient;
1339 GradTransVector aGradTransVector;
1341 OUString aString;
1343 aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
1344 aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
1345 if(pColHdl1)
1346 aGradTransVector.aCol1 = pColHdl1->GetColor();
1347 if(pColHdl2)
1348 aGradTransVector.aCol2 = pColHdl2->GetColor();
1350 if(IsGradient())
1351 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
1352 else
1353 aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
1355 // transform vector data to gradient
1356 GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);
1358 if(bSetItemOnObject)
1360 SdrModel* pModel = _pObj->GetModel();
1361 SfxItemSet aNewSet(pModel->GetItemPool());
1363 if(IsGradient())
1365 aString.clear();
1366 XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
1367 aNewSet.Put(aNewGradItem);
1369 else
1371 aString.clear();
1372 XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
1373 aNewSet.Put(aNewTransItem);
1376 if(bUndo && pModel->IsUndoEnabled())
1378 pModel->BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
1379 pModel->AddUndo(pModel->GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
1380 pModel->EndUndo();
1383 pObj->SetMergedItemSetAndBroadcast(aNewSet);
1386 // back transformation, set values on pIAOHandle
1387 GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
1389 SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1390 Set2ndPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1391 if(pColHdl1)
1393 pColHdl1->SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
1394 pColHdl1->SetColor(aGradTransVector.aCol1);
1396 if(pColHdl2)
1398 pColHdl2->SetPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
1399 pColHdl2->SetColor(aGradTransVector.aCol2);
1404 SdrHdlLine::~SdrHdlLine() {}
1406 void SdrHdlLine::CreateB2dIAObject()
1408 // first throw away old one
1409 GetRidOfIAObject();
1411 if(pHdlList)
1413 SdrMarkView* pView = pHdlList->GetView();
1415 if(pView && !pView->areMarkHandlesHidden() && pHdl1 && pHdl2)
1417 SdrPageView* pPageView = pView->GetSdrPageView();
1419 if(pPageView)
1421 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1423 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1425 if(rPageWindow.GetPaintWindow().OutputToWindow())
1427 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1428 if (xManager.is())
1430 basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1431 basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), pHdl2->GetPos().Y());
1433 sdr::overlay::OverlayObject* pNewOverlayObject = new
1434 sdr::overlay::OverlayLineStriped(
1435 aPosition1,
1436 aPosition2
1439 // OVERLAYMANAGER
1440 // color(?)
1441 pNewOverlayObject->setBaseColor(Color(COL_LIGHTRED));
1443 xManager->add(*pNewOverlayObject);
1444 maOverlayGroup.append(pNewOverlayObject);
1453 Pointer SdrHdlLine::GetPointer() const
1455 return Pointer(PointerStyle::RefHand);
1459 SdrHdlBezWgt::~SdrHdlBezWgt() {}
1461 void SdrHdlBezWgt::CreateB2dIAObject()
1463 // call parent
1464 SdrHdl::CreateB2dIAObject();
1466 // create lines
1467 if(pHdlList)
1469 SdrMarkView* pView = pHdlList->GetView();
1471 if(pView && !pView->areMarkHandlesHidden())
1473 SdrPageView* pPageView = pView->GetSdrPageView();
1475 if(pPageView)
1477 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1479 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1481 if(rPageWindow.GetPaintWindow().OutputToWindow())
1483 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1484 if (xManager.is())
1486 basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
1487 basegfx::B2DPoint aPosition2(aPos.X(), aPos.Y());
1489 if(!aPosition1.equal(aPosition2))
1491 sdr::overlay::OverlayObject* pNewOverlayObject = new
1492 sdr::overlay::OverlayLineStriped(
1493 aPosition1,
1494 aPosition2
1496 // OVERLAYMANAGER
1497 // line part is not hittable
1498 pNewOverlayObject->setHittable(false);
1500 // color(?)
1501 pNewOverlayObject->setBaseColor(Color(COL_LIGHTBLUE));
1503 xManager->add(*pNewOverlayObject);
1504 maOverlayGroup.append(pNewOverlayObject);
1515 E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon& rWireframePoly)
1517 aWireframePoly = rWireframePoly;
1520 void E3dVolumeMarker::CreateB2dIAObject()
1522 // create lines
1523 if(pHdlList)
1525 SdrMarkView* pView = pHdlList->GetView();
1527 if(pView && !pView->areMarkHandlesHidden())
1529 SdrPageView* pPageView = pView->GetSdrPageView();
1531 if(pPageView)
1533 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1535 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1537 if(rPageWindow.GetPaintWindow().OutputToWindow())
1539 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1540 if (xManager.is() && aWireframePoly.count())
1542 sdr::overlay::OverlayObject* pNewOverlayObject = new
1543 sdr::overlay::OverlayPolyPolygonStripedAndFilled(
1544 aWireframePoly);
1546 // OVERLAYMANAGER
1547 pNewOverlayObject->setBaseColor(Color(COL_BLACK));
1549 xManager->add(*pNewOverlayObject);
1550 maOverlayGroup.append(pNewOverlayObject);
1560 ImpEdgeHdl::~ImpEdgeHdl()
1564 void ImpEdgeHdl::CreateB2dIAObject()
1566 if(nObjHdlNum <= 1 && pObj)
1568 // first throw away old one
1569 GetRidOfIAObject();
1571 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1572 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1574 if(pHdlList)
1576 SdrMarkView* pView = pHdlList->GetView();
1578 if(pView && !pView->areMarkHandlesHidden())
1580 const SdrEdgeObj* pEdge = static_cast<SdrEdgeObj*>(pObj);
1582 if(pEdge->GetConnectedNode(nObjHdlNum == 0) != nullptr)
1583 eColIndex = BitmapColorIndex::LightRed;
1585 if(nPPntNum < 2)
1587 // Handle with plus sign inside
1588 eKindOfMarker = BitmapMarkerKind::Circ_7x7;
1591 SdrPageView* pPageView = pView->GetSdrPageView();
1593 if(pPageView)
1595 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1597 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1599 if(rPageWindow.GetPaintWindow().OutputToWindow())
1601 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1602 if (xManager.is())
1604 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1605 sdr::overlay::OverlayObject* pNewOverlayObject = CreateOverlayObject(
1606 aPosition,
1607 eColIndex,
1608 eKindOfMarker);
1610 // OVERLAYMANAGER
1611 if (pNewOverlayObject)
1613 xManager->add(*pNewOverlayObject);
1614 maOverlayGroup.append(pNewOverlayObject);
1623 else
1625 // call parent
1626 SdrHdl::CreateB2dIAObject();
1630 void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
1632 if(eLineCode != eCode)
1634 // remember new value
1635 eLineCode = eCode;
1637 // create new display
1638 Touch();
1642 Pointer ImpEdgeHdl::GetPointer() const
1644 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1645 if (pEdge==nullptr)
1646 return SdrHdl::GetPointer();
1647 if (nObjHdlNum<=1)
1648 return Pointer(PointerStyle::MovePoint);
1649 if (IsHorzDrag())
1650 return Pointer(PointerStyle::ESize);
1651 else
1652 return Pointer(PointerStyle::SSize);
1655 bool ImpEdgeHdl::IsHorzDrag() const
1657 SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
1658 if (pEdge==nullptr)
1659 return false;
1660 if (nObjHdlNum<=1)
1661 return false;
1663 SdrEdgeKind eEdgeKind = static_cast<const SdrEdgeKindItem&>(pEdge->GetObjectItem(SDRATTR_EDGEKIND)).GetValue();
1665 const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
1666 if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
1668 return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
1670 else if (eEdgeKind==SdrEdgeKind::ThreeLines)
1672 long nAngle=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
1673 return nAngle==0 || nAngle==18000;
1675 return false;
1679 ImpMeasureHdl::~ImpMeasureHdl()
1683 void ImpMeasureHdl::CreateB2dIAObject()
1685 // first throw away old one
1686 GetRidOfIAObject();
1688 if(pHdlList)
1690 SdrMarkView* pView = pHdlList->GetView();
1692 if(pView && !pView->areMarkHandlesHidden())
1694 BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
1695 BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
1697 if(nObjHdlNum > 1)
1699 eKindOfMarker = BitmapMarkerKind::Rect_7x7;
1702 if(bSelect)
1704 eColIndex = BitmapColorIndex::Cyan;
1707 SdrPageView* pPageView = pView->GetSdrPageView();
1709 if(pPageView)
1711 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1713 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1715 if(rPageWindow.GetPaintWindow().OutputToWindow())
1717 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1718 if (xManager.is())
1720 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
1721 sdr::overlay::OverlayObject* pNewOverlayObject = CreateOverlayObject(
1722 aPosition,
1723 eColIndex,
1724 eKindOfMarker);
1726 // OVERLAYMANAGER
1727 if (pNewOverlayObject)
1729 xManager->add(*pNewOverlayObject);
1730 maOverlayGroup.append(pNewOverlayObject);
1740 Pointer ImpMeasureHdl::GetPointer() const
1742 switch (nObjHdlNum)
1744 case 0: case 1: return Pointer(PointerStyle::Hand);
1745 case 2: case 3: return Pointer(PointerStyle::MovePoint);
1746 case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
1747 } // switch
1748 return Pointer(PointerStyle::NotAllowed);
1752 ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
1753 SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
1754 maRect(rRect)
1758 void ImpTextframeHdl::CreateB2dIAObject()
1760 // first throw away old one
1761 GetRidOfIAObject();
1763 if(pHdlList)
1765 SdrMarkView* pView = pHdlList->GetView();
1767 if(pView && !pView->areMarkHandlesHidden())
1769 SdrPageView* pPageView = pView->GetSdrPageView();
1771 if(pPageView)
1773 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
1775 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
1777 if(rPageWindow.GetPaintWindow().OutputToWindow())
1779 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
1780 if (xManager.is())
1782 const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
1783 const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
1784 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1785 const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
1786 const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
1788 sdr::overlay::OverlayRectangle* pNewOverlayObject = new sdr::overlay::OverlayRectangle(
1789 aTopLeft,
1790 aBottomRight,
1791 aHilightColor,
1792 fTransparence,
1793 3.0,
1794 3.0,
1795 nRotationAngle * -F_PI18000,
1796 true); // allow animation; the Handle is not shown at text edit time
1798 // OVERLAYMANAGER
1799 pNewOverlayObject->setHittable(false);
1800 xManager->add(*pNewOverlayObject);
1801 maOverlayGroup.append(pNewOverlayObject);
1811 static bool ImpSdrHdlListSorter(SdrHdl* const& lhs, SdrHdl* const& rhs)
1813 SdrHdlKind eKind1=lhs->GetKind();
1814 SdrHdlKind eKind2=rhs->GetKind();
1815 // Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
1816 unsigned n1=1;
1817 unsigned n2=1;
1818 if (eKind1!=eKind2)
1820 if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
1821 else if (eKind1==SdrHdlKind::Glue) n1=2;
1822 else if (eKind1==SdrHdlKind::User) n1=3;
1823 else if (eKind1==SdrHdlKind::SmartTag) n1=0;
1824 if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
1825 else if (eKind2==SdrHdlKind::Glue) n2=2;
1826 else if (eKind2==SdrHdlKind::User) n2=3;
1827 else if (eKind2==SdrHdlKind::SmartTag) n2=0;
1829 if (lhs->IsPlusHdl()) n1=4;
1830 if (rhs->IsPlusHdl()) n2=4;
1831 if (n1==n2)
1833 // Level 2: PageView (Pointer)
1834 SdrPageView* pPV1=lhs->GetPageView();
1835 SdrPageView* pPV2=rhs->GetPageView();
1836 if (pPV1==pPV2)
1838 // Level 3: Position (x+y)
1839 SdrObject* pObj1=lhs->GetObj();
1840 SdrObject* pObj2=rhs->GetObj();
1841 if (pObj1==pObj2)
1843 sal_uInt32 nNum1=lhs->GetObjHdlNum();
1844 sal_uInt32 nNum2=rhs->GetObjHdlNum();
1845 if (nNum1==nNum2)
1847 if (eKind1==eKind2)
1848 return lhs<rhs; // Hack, to always get to the same sorting
1849 return (sal_uInt16)eKind1<(sal_uInt16)eKind2;
1851 else
1852 return nNum1<nNum2;
1854 else
1856 return pObj1<pObj2;
1859 else
1861 return pPV1<pPV2;
1864 else
1866 return n1<n2;
1871 // Helper struct for re-sorting handles
1872 struct ImplHdlAndIndex
1874 SdrHdl* mpHdl;
1875 sal_uInt32 mnIndex;
1878 // Helper method for sorting handles taking care of OrdNums, keeping order in
1879 // single objects and re-sorting polygon handles intuitively
1880 extern "C" int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
1882 const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
1883 const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
1885 if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
1887 if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
1889 // same object and a path object
1890 if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
1891 && (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
1893 // both handles are point or control handles
1894 if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
1896 if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
1898 return -1;
1900 else
1902 return 1;
1905 else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
1907 return -1;
1909 else
1911 return 1;
1916 else
1918 if(!p1->mpHdl->GetObj())
1920 return -1;
1922 else if(!p2->mpHdl->GetObj())
1924 return 1;
1926 else
1928 // different objects, use OrdNum for sort
1929 const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
1930 const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
1932 if(nOrdNum1 < nOrdNum2)
1934 return -1;
1936 else
1938 return 1;
1943 // fallback to indices
1944 if(p1->mnIndex < p2->mnIndex)
1946 return -1;
1948 else
1950 return 1;
1955 void SdrHdlList::TravelFocusHdl(bool bForward)
1957 // security correction
1958 if (mnFocusIndex >= GetHdlCount())
1959 mnFocusIndex = SAL_MAX_SIZE;
1961 if(aList.empty())
1962 return;
1964 // take care of old handle
1965 const size_t nOldHdlNum(mnFocusIndex);
1966 SdrHdl* pOld = GetHdl(nOldHdlNum);
1968 if(pOld)
1970 // switch off old handle
1971 mnFocusIndex = SAL_MAX_SIZE;
1972 pOld->Touch();
1975 // allocate pointer array for sorted handle list
1976 std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[aList.size()]);
1978 // build sorted handle list
1979 for( size_t a = 0; a < aList.size(); ++a)
1981 pHdlAndIndex[a].mpHdl = aList[a];
1982 pHdlAndIndex[a].mnIndex = a;
1985 qsort(pHdlAndIndex.get(), aList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
1987 // look for old num in sorted array
1988 size_t nOldHdl(nOldHdlNum);
1990 if(nOldHdlNum != SAL_MAX_SIZE)
1992 for(size_t a = 0; a < aList.size(); ++a)
1994 if(pHdlAndIndex[a].mpHdl == pOld)
1996 nOldHdl = a;
1997 break;
2002 // build new HdlNum
2003 size_t nNewHdl(nOldHdl);
2005 // do the focus travel
2006 if(bForward)
2008 if(nOldHdl != SAL_MAX_SIZE)
2010 if(nOldHdl == aList.size() - 1)
2012 // end forward run
2013 nNewHdl = SAL_MAX_SIZE;
2015 else
2017 // simply the next handle
2018 nNewHdl++;
2021 else
2023 // start forward run at first entry
2024 nNewHdl = 0;
2027 else
2029 if(nOldHdl == SAL_MAX_SIZE)
2031 // start backward run at last entry
2032 nNewHdl = aList.size() - 1;
2035 else
2037 if(nOldHdl == 0)
2039 // end backward run
2040 nNewHdl = SAL_MAX_SIZE;
2042 else
2044 // simply the previous handle
2045 nNewHdl--;
2050 // build new HdlNum
2051 sal_uIntPtr nNewHdlNum(nNewHdl);
2053 // look for old num in sorted array
2054 if(nNewHdl != SAL_MAX_SIZE)
2056 SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
2058 for(size_t a = 0; a < aList.size(); ++a)
2060 if(aList[a] == pNew)
2062 nNewHdlNum = a;
2063 break;
2068 // take care of next handle
2069 if(nOldHdlNum != nNewHdlNum)
2071 mnFocusIndex = nNewHdlNum;
2072 SdrHdl* pNew = GetHdl(mnFocusIndex);
2074 if(pNew)
2076 pNew->Touch();
2081 SdrHdl* SdrHdlList::GetFocusHdl() const
2083 if(mnFocusIndex < GetHdlCount())
2084 return GetHdl(mnFocusIndex);
2085 else
2086 return nullptr;
2089 void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
2091 if(pNew)
2093 SdrHdl* pActual = GetFocusHdl();
2095 if(!pActual || pActual != pNew)
2097 const size_t nNewHdlNum = GetHdlNum(pNew);
2099 if(nNewHdlNum != SAL_MAX_SIZE)
2101 mnFocusIndex = nNewHdlNum;
2103 if(pActual)
2105 pActual->Touch();
2108 if(pNew)
2110 pNew->Touch();
2118 void SdrHdlList::ResetFocusHdl()
2120 SdrHdl* pHdl = GetFocusHdl();
2122 mnFocusIndex = SAL_MAX_SIZE;
2124 if(pHdl)
2126 pHdl->Touch();
2131 SdrHdlList::SdrHdlList(SdrMarkView* pV)
2132 : mnFocusIndex(SAL_MAX_SIZE),
2133 pView(pV),
2134 aList()
2136 nHdlSize = 3;
2137 bRotateShear = false;
2138 bMoveOutside = false;
2139 bDistortShear = false;
2142 SdrHdlList::~SdrHdlList()
2144 Clear();
2147 void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
2149 if(nHdlSize != nSiz)
2151 // remember new value
2152 nHdlSize = nSiz;
2154 // propagate change to IAOs
2155 for(size_t i=0; i<GetHdlCount(); ++i)
2157 SdrHdl* pHdl = GetHdl(i);
2158 pHdl->Touch();
2163 void SdrHdlList::SetMoveOutside(bool bOn)
2165 if(bMoveOutside != bOn)
2167 // remember new value
2168 bMoveOutside = bOn;
2170 // propagate change to IAOs
2171 for(size_t i=0; i<GetHdlCount(); ++i)
2173 SdrHdl* pHdl = GetHdl(i);
2174 pHdl->Touch();
2179 void SdrHdlList::SetRotateShear(bool bOn)
2181 bRotateShear = bOn;
2184 void SdrHdlList::SetDistortShear(bool bOn)
2186 bDistortShear = bOn;
2189 SdrHdl* SdrHdlList::RemoveHdl(size_t nNum)
2191 SdrHdl* pRetval = aList[nNum];
2192 aList.erase(aList.begin() + nNum);
2194 return pRetval;
2197 void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
2199 for(std::deque<SdrHdl*>::iterator it = aList.begin(); it != aList.end(); )
2201 SdrHdl* p = *it;
2202 if (p->GetKind() == eKind)
2204 it = aList.erase( it );
2205 delete p;
2207 else
2208 ++it;
2212 void SdrHdlList::Clear()
2214 for (size_t i=0; i<GetHdlCount(); ++i)
2216 SdrHdl* pHdl=GetHdl(i);
2217 delete pHdl;
2219 aList.clear();
2221 bRotateShear=false;
2222 bDistortShear=false;
2225 void SdrHdlList::Sort()
2227 // remember currently focused handle
2228 SdrHdl* pPrev = GetFocusHdl();
2230 std::sort( aList.begin(), aList.end(), ImpSdrHdlListSorter );
2232 // get now and compare
2233 SdrHdl* pNow = GetFocusHdl();
2235 if(pPrev != pNow)
2238 if(pPrev)
2240 pPrev->Touch();
2243 if(pNow)
2245 pNow->Touch();
2250 size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
2252 if (pHdl==nullptr)
2253 return SAL_MAX_SIZE;
2254 std::deque<SdrHdl*>::const_iterator it = std::find( aList.begin(), aList.end(), pHdl);
2255 if( it == aList.end() )
2256 return SAL_MAX_SIZE;
2257 return it - aList.begin();
2260 void SdrHdlList::AddHdl(SdrHdl* pHdl)
2262 if (pHdl!=nullptr)
2264 aList.push_back(pHdl);
2265 pHdl->SetHdlList(this);
2269 SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
2271 SdrHdl* pRet=nullptr;
2272 const size_t nCount=GetHdlCount();
2273 size_t nNum=nCount;
2274 while (nNum>0 && pRet==nullptr)
2276 nNum--;
2277 SdrHdl* pHdl=GetHdl(nNum);
2278 if (pHdl->IsHdlHit(rPnt))
2279 pRet=pHdl;
2281 return pRet;
2284 SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
2286 SdrHdl* pRet=nullptr;
2287 for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
2289 SdrHdl* pHdl=GetHdl(i);
2290 if (pHdl->GetKind()==eKind1)
2291 pRet=pHdl;
2293 return pRet;
2296 SdrCropHdl::SdrCropHdl(
2297 const Point& rPnt,
2298 SdrHdlKind eNewKind,
2299 double fShearX,
2300 double fRotation)
2301 : SdrHdl(rPnt, eNewKind),
2302 mfShearX(fShearX),
2303 mfRotation(fRotation)
2308 BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
2310 int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
2312 if( nSize <= 3 )
2314 nPixelSize = 13;
2315 nOffset = 0;
2317 else if( nSize <=4 )
2319 nPixelSize = 17;
2320 nOffset = 39;
2322 else
2324 nPixelSize = 21;
2325 nOffset = 90;
2328 switch( eKind )
2330 case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
2331 case SdrHdlKind::Upper: nX = 1; nY = 0; break;
2332 case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
2333 case SdrHdlKind::Left: nX = 0; nY = 1; break;
2334 case SdrHdlKind::Right: nX = 2; nY = 1; break;
2335 case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
2336 case SdrHdlKind::Lower: nX = 1; nY = 2; break;
2337 case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
2338 default: break;
2341 tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
2343 BitmapEx aRetval(rBitmap);
2344 aRetval.Crop(aSourceRect);
2345 return aRetval;
2349 void SdrCropHdl::CreateB2dIAObject()
2351 // first throw away old one
2352 GetRidOfIAObject();
2354 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2355 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2357 if( pPageView && !pView->areMarkHandlesHidden() )
2359 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2360 int nHdlSize = pHdlList->GetHdlSize();
2362 const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
2363 BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
2365 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2367 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
2369 if(rPageWindow.GetPaintWindow().OutputToWindow())
2371 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
2372 if (xManager.is())
2374 basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
2376 sdr::overlay::OverlayObject* pOverlayObject = nullptr;
2378 // animate focused handles
2379 if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
2381 if( nHdlSize >= 2 )
2382 nHdlSize = 1;
2384 BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
2386 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
2388 pOverlayObject = new sdr::overlay::OverlayAnimatedBitmapEx(
2389 aPosition,
2390 aBmpEx1,
2391 aBmpEx2,
2392 nBlinkTime,
2393 (sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2394 (sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2395 (sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
2396 (sal_uInt16)(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
2397 mfShearX,
2398 mfRotation);
2400 else
2402 // create centered handle as default
2403 pOverlayObject = new sdr::overlay::OverlayBitmapEx(
2404 aPosition,
2405 aBmpEx1,
2406 (sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
2407 (sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
2408 0.0,
2409 mfShearX,
2410 mfRotation);
2413 // OVERLAYMANAGER
2414 if(pOverlayObject)
2416 xManager->add(*pOverlayObject);
2417 maOverlayGroup.append(pOverlayObject);
2426 // with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
2427 // accordingly
2429 SdrCropViewHdl::SdrCropViewHdl(
2430 const basegfx::B2DHomMatrix& rObjectTransform,
2431 const Graphic& rGraphic,
2432 double fCropLeft,
2433 double fCropTop,
2434 double fCropRight,
2435 double fCropBottom)
2436 : SdrHdl(Point(), SdrHdlKind::User),
2437 maObjectTransform(rObjectTransform),
2438 maGraphic(rGraphic),
2439 mfCropLeft(fCropLeft),
2440 mfCropTop(fCropTop),
2441 mfCropRight(fCropRight),
2442 mfCropBottom(fCropBottom)
2446 namespace {
2448 void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
2449 assert(rotate != nullptr);
2451 // detect 180 degree rotation, this is the same as mirrored in X and Y,
2452 // thus change to mirroring. Prefer mirroring here. Use the equal call
2453 // with getSmallValue here, the original which uses rtl::math::approxEqual
2454 // is too correct here. Maybe this changes with enhanced precision in aw080
2455 // to the better so that this can be reduced to the more precise call again
2456 if(basegfx::fTools::equal(fabs(*rotate), F_PI, 0.000000001))
2458 scale.setX(scale.getX() * -1.0);
2459 scale.setY(scale.getY() * -1.0);
2460 *rotate = 0.0;
2466 void SdrCropViewHdl::CreateB2dIAObject()
2468 GetRidOfIAObject();
2469 SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
2470 SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
2472 if(!pPageView || pView->areMarkHandlesHidden())
2474 return;
2477 // decompose to have current translate and scale
2478 basegfx::B2DVector aScale, aTranslate;
2479 double fRotate, fShearX;
2481 maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
2483 if(aScale.equalZero())
2485 return;
2488 translateRotationToMirroring(aScale, &fRotate);
2490 // remember mirroring, reset at Scale and adapt crop values for usage;
2491 // mirroring can stay in the object transformation, so do not have to
2492 // cope with it here (except later for the CroppedImage transformation,
2493 // see below)
2494 const bool bMirroredX(aScale.getX() < 0.0);
2495 const bool bMirroredY(aScale.getY() < 0.0);
2496 double fCropLeft(mfCropLeft);
2497 double fCropTop(mfCropTop);
2498 double fCropRight(mfCropRight);
2499 double fCropBottom(mfCropBottom);
2501 if(bMirroredX)
2503 aScale.setX(-aScale.getX());
2506 if(bMirroredY)
2508 aScale.setY(-aScale.getY());
2511 // create target translate and scale
2512 const basegfx::B2DVector aTargetScale(
2513 aScale.getX() + fCropRight + fCropLeft,
2514 aScale.getY() + fCropBottom + fCropTop);
2515 const basegfx::B2DVector aTargetTranslate(
2516 aTranslate.getX() - fCropLeft,
2517 aTranslate.getY() - fCropTop);
2519 // create ranges to make comparisons
2520 const basegfx::B2DRange aCurrentForCompare(
2521 aTranslate.getX(), aTranslate.getY(),
2522 aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
2523 basegfx::B2DRange aCropped(
2524 aTargetTranslate.getX(), aTargetTranslate.getY(),
2525 aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
2527 if(aCropped.isEmpty())
2529 // nothing to return since cropped content is completely empty
2530 return;
2533 if(aCurrentForCompare.equal(aCropped))
2535 // no crop at all
2536 return;
2539 // back-transform to have values in unit coordinates
2540 basegfx::B2DHomMatrix aBackToUnit;
2541 aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
2542 aBackToUnit.scale(
2543 basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
2544 basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
2546 // transform cropped back to unit coordinates
2547 aCropped.transform(aBackToUnit);
2549 // prepare crop PolyPolygon
2550 basegfx::B2DPolygon aGraphicOutlinePolygon(
2551 basegfx::utils::createPolygonFromRect(
2552 aCropped));
2553 basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
2555 // current range is unit range
2556 basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
2558 aOverlap.intersect(aCropped);
2560 if(!aOverlap.isEmpty())
2562 aCropPolyPolygon.append(
2563 basegfx::utils::createPolygonFromRect(
2564 aOverlap));
2567 // transform to object coordinates to prepare for clip
2568 aCropPolyPolygon.transform(maObjectTransform);
2569 aGraphicOutlinePolygon.transform(maObjectTransform);
2571 // create cropped transformation
2572 basegfx::B2DHomMatrix aCroppedTransform;
2574 aCroppedTransform.scale(
2575 aCropped.getWidth(),
2576 aCropped.getHeight());
2577 aCroppedTransform.translate(
2578 aCropped.getMinX(),
2579 aCropped.getMinY());
2580 aCroppedTransform = maObjectTransform * aCroppedTransform;
2582 // prepare graphic primitive (transformed)
2583 const drawinglayer::primitive2d::Primitive2DReference aGraphic(
2584 new drawinglayer::primitive2d::GraphicPrimitive2D(
2585 aCroppedTransform,
2586 maGraphic));
2588 // prepare outline polygon for whole graphic
2589 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
2590 const basegfx::BColor aHilightColor(aSvtOptionsDrawinglayer.getHilightColor().getBColor());
2591 const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
2592 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
2593 aGraphicOutlinePolygon,
2594 aHilightColor));
2596 // combine these
2597 drawinglayer::primitive2d::Primitive2DContainer aCombination(2);
2598 aCombination[0] = aGraphic;
2599 aCombination[1] = aGraphicOutline;
2601 // embed to MaskPrimitive2D
2602 const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
2603 new drawinglayer::primitive2d::MaskPrimitive2D(
2604 aCropPolyPolygon,
2605 aCombination));
2607 // embed to UnifiedTransparencePrimitive2D
2608 const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
2609 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
2610 drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
2611 0.8));
2613 const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
2615 for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
2617 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
2618 const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
2620 if(rPageWindow.GetPaintWindow().OutputToWindow())
2622 rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
2623 if(xManager.is())
2625 sdr::overlay::OverlayObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aSequence);
2627 // only informative object, no hit
2628 pNew->setHittable(false);
2630 xManager->add(*pNew);
2631 maOverlayGroup.append(pNew);
2637 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */