/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <algorithm>
#include <cassert>
#include <svx/svdhdl.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdmrkv.hxx>
#include <vcl/window.hxx>
#include <vcl/settings.hxx>
#include <vcl/virdev.hxx>
#include <tools/poly.hxx>
#include <vcl/bitmapaccess.hxx>
#include <svx/sxekitm.hxx>
#include <svx/strings.hrc>
#include <svx/svdmodel.hxx>
#include "gradtrns.hxx"
#include <svx/xflgrit.hxx>
#include <svx/svdundo.hxx>
#include <svx/dialmgr.hxx>
#include <svx/xflftrit.hxx>
#include <svx/svdopath.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
#include <svx/sdr/overlay/overlaybitmapex.hxx>
#include <sdr/overlay/overlayline.hxx>
#include <svx/sdr/overlay/overlaytriangle.hxx>
#include <sdr/overlay/overlayhandle.hxx>
#include <sdr/overlay/overlayrectangle.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <vcl/svapp.hxx>
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
#include <vcl/lazydelete.hxx>
#include <vcl/BitmapTools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <memory>
#include <bitmaps.hlst>
// #i15222#
// Due to the resource problems in Win95/98 with bitmap resources I
// will change this handle bitmap providing class. Old version was splitting
// and preparing all small handle bitmaps in device bitmap format, now this will
// be done on the fly. Thus, there is only one big bitmap in memory. With
// three source bitmaps, this will be 3 system bitmap resources instead of hundreds.
// The price for that needs to be evaluated. Maybe we will need another change here
// if this is too expensive.
class SdrHdlBitmapSet
{
// the bitmap holding all information
BitmapEx maMarkersBitmap;
// the cropped Bitmaps for reusage
::std::vector< BitmapEx > maRealMarkers;
// helpers
BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle);
public:
explicit SdrHdlBitmapSet();
const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd);
};
#define KIND_COUNT (14)
#define INDEX_COUNT (6)
#define INDIVIDUAL_COUNT (5)
SdrHdlBitmapSet::SdrHdlBitmapSet()
: maMarkersBitmap(SIP_SA_MARKERS),
// 15 kinds (BitmapMarkerKind) use index [0..5] + 5 extra
maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
{
}
BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const tools::Rectangle& rRectangle)
{
BitmapEx& rTargetBitmap = maRealMarkers[nIndex];
if(rTargetBitmap.IsEmpty())
{
rTargetBitmap = maMarkersBitmap;
rTargetBitmap.Crop(rRectangle);
}
return rTargetBitmap;
}
// change getting of bitmap to use the big resource bitmap
const BitmapEx& SdrHdlBitmapSet::GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd)
{
// fill in size and source position in maMarkersBitmap
const sal_uInt16 nYPos(nInd * 11);
switch(eKindOfMarker)
{
default:
{
OSL_FAIL( "Unknown kind of marker." );
SAL_FALLTHROUGH; // return Rect_9x9 as default
}
case BitmapMarkerKind::Rect_9x9:
{
return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, tools::Rectangle(Point(7, nYPos), Size(9, 9)));
}
case BitmapMarkerKind::Rect_7x7:
{
return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, tools::Rectangle(Point(0, nYPos), Size(7, 7)));
}
case BitmapMarkerKind::Rect_11x11:
{
return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, tools::Rectangle(Point(16, nYPos), Size(11, 11)));
}
case BitmapMarkerKind::Rect_13x13:
{
const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);
switch(nInd)
{
case 0:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 66), Size(13, 13)));
}
case 1:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 66), Size(13, 13)));
}
case 2:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(72, 79), Size(13, 13)));
}
case 3:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(85, 79), Size(13, 13)));
}
case 4:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 79), Size(13, 13)));
}
default: // case 5:
{
return impGetOrCreateTargetBitmap(nIndex, tools::Rectangle(Point(98, 66), Size(13, 13)));
}
}
}
case BitmapMarkerKind::Circ_7x7:
case BitmapMarkerKind::Customshape_7x7:
{
return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, tools::Rectangle(Point(27, nYPos), Size(7, 7)));
}
case BitmapMarkerKind::Circ_9x9:
case BitmapMarkerKind::Customshape_9x9:
{
return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, tools::Rectangle(Point(34, nYPos), Size(9, 9)));
}
case BitmapMarkerKind::Circ_11x11:
case BitmapMarkerKind::Customshape_11x11:
{
return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, tools::Rectangle(Point(43, nYPos), Size(11, 11)));
}
case BitmapMarkerKind::Elli_7x9:
{
return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, tools::Rectangle(Point(54, nYPos), Size(7, 9)));
}
case BitmapMarkerKind::Elli_9x11:
{
return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, tools::Rectangle(Point(61, nYPos), Size(9, 11)));
}
case BitmapMarkerKind::Elli_9x7:
{
return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, tools::Rectangle(Point(70, nYPos), Size(9, 7)));
}
case BitmapMarkerKind::Elli_11x9:
{
return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, tools::Rectangle(Point(79, nYPos), Size(11, 9)));
}
case BitmapMarkerKind::RectPlus_7x7:
{
return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, tools::Rectangle(Point(90, nYPos), Size(7, 7)));
}
case BitmapMarkerKind::RectPlus_9x9:
{
return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, tools::Rectangle(Point(97, nYPos), Size(9, 9)));
}
case BitmapMarkerKind::RectPlus_11x11:
{
return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, tools::Rectangle(Point(106, nYPos), Size(11, 11)));
}
case BitmapMarkerKind::Crosshair:
{
return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, tools::Rectangle(Point(0, 68), Size(15, 15)));
}
case BitmapMarkerKind::Glue:
{
return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, tools::Rectangle(Point(15, 76), Size(9, 9)));
}
case BitmapMarkerKind::Glue_Deselected:
{
return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, tools::Rectangle(Point(15, 67), Size(9, 9)));
}
case BitmapMarkerKind::Anchor: // AnchorTR for SW
case BitmapMarkerKind::AnchorTR:
{
return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, tools::Rectangle(Point(24, 67), Size(24, 24)));
}
// add AnchorPressed to be able to animate anchor control
case BitmapMarkerKind::AnchorPressed:
case BitmapMarkerKind::AnchorPressedTR:
{
return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, tools::Rectangle(Point(48, 67), Size(24, 24)));
}
}
}
SdrHdl::SdrHdl():
pObj(nullptr),
pPV(nullptr),
pHdlList(nullptr),
eKind(SdrHdlKind::Move),
nRotationAngle(0),
nObjHdlNum(0),
nPolyNum(0),
nPPntNum(0),
nSourceHdlNum(0),
bSelect(false),
b1PixMore(false),
bPlusHdl(false),
mbMoveOutside(false),
mbMouseOver(false)
{
}
SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
pObj(nullptr),
pPV(nullptr),
pHdlList(nullptr),
aPos(rPnt),
eKind(eNewKind),
nRotationAngle(0),
nObjHdlNum(0),
nPolyNum(0),
nPPntNum(0),
nSourceHdlNum(0),
bSelect(false),
b1PixMore(false),
bPlusHdl(false),
mbMoveOutside(false),
mbMouseOver(false)
{
}
SdrHdl::~SdrHdl()
{
GetRidOfIAObject();
}
void SdrHdl::Set1PixMore(bool bJa)
{
if(b1PixMore != bJa)
{
b1PixMore = bJa;
// create new display
Touch();
}
}
void SdrHdl::SetMoveOutside( bool bMoveOutside )
{
if(mbMoveOutside != bMoveOutside)
{
mbMoveOutside = bMoveOutside;
// create new display
Touch();
}
}
void SdrHdl::SetRotationAngle(long n)
{
if(nRotationAngle != n)
{
nRotationAngle = n;
// create new display
Touch();
}
}
void SdrHdl::SetPos(const Point& rPnt)
{
if(aPos != rPnt)
{
// remember new position
aPos = rPnt;
// create new display
Touch();
}
}
void SdrHdl::SetSelected(bool bJa)
{
if(bSelect != bJa)
{
// remember new value
bSelect = bJa;
// create new display
Touch();
}
}
void SdrHdl::SetHdlList(SdrHdlList* pList)
{
if(pHdlList != pList)
{
// remember list
pHdlList = pList;
// now its possible to create graphic representation
Touch();
}
}
void SdrHdl::SetObj(SdrObject* pNewObj)
{
if(pObj != pNewObj)
{
// remember new object
pObj = pNewObj;
// graphic representation may have changed
Touch();
}
}
void SdrHdl::Touch()
{
// force update of graphic representation
CreateB2dIAObject();
}
void SdrHdl::GetRidOfIAObject()
{
// OVERLAYMANAGER
maOverlayGroup.clear();
}
void SdrHdl::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList && pHdlList->GetView() && !pHdlList->GetView()->areMarkHandlesHidden())
{
BitmapColorIndex eColIndex = BitmapColorIndex::LightGreen;
BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
bool bRot = pHdlList->IsRotateShear();
if(pObj)
eColIndex = bSelect ? BitmapColorIndex::Cyan : BitmapColorIndex::LightCyan;
if(bRot)
{
// red rotation handles
if(pObj && bSelect)
eColIndex = BitmapColorIndex::Red;
else
eColIndex = BitmapColorIndex::LightRed;
}
switch(eKind)
{
case SdrHdlKind::Move:
{
eKindOfMarker = (b1PixMore) ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
break;
}
case SdrHdlKind::UpperLeft:
case SdrHdlKind::UpperRight:
case SdrHdlKind::LowerLeft:
case SdrHdlKind::LowerRight:
{
// corner handles
if(bRot)
{
eKindOfMarker = BitmapMarkerKind::Circ_7x7;
}
else
{
eKindOfMarker = BitmapMarkerKind::Rect_7x7;
}
break;
}
case SdrHdlKind::Upper:
case SdrHdlKind::Lower:
{
// Upper/Lower handles
if(bRot)
{
eKindOfMarker = BitmapMarkerKind::Elli_9x7;
}
else
{
eKindOfMarker = BitmapMarkerKind::Rect_7x7;
}
break;
}
case SdrHdlKind::Left:
case SdrHdlKind::Right:
{
// Left/Right handles
if(bRot)
{
eKindOfMarker = BitmapMarkerKind::Elli_7x9;
}
else
{
eKindOfMarker = BitmapMarkerKind::Rect_7x7;
}
break;
}
case SdrHdlKind::Poly:
{
if(bRot)
{
eKindOfMarker = b1PixMore ? BitmapMarkerKind::Circ_9x9 : BitmapMarkerKind::Circ_7x7;
}
else
{
eKindOfMarker = b1PixMore ? BitmapMarkerKind::Rect_9x9 : BitmapMarkerKind::Rect_7x7;
}
break;
}
case SdrHdlKind::BezierWeight: // weight at poly
{
eKindOfMarker = BitmapMarkerKind::Circ_7x7;
break;
}
case SdrHdlKind::Circle:
{
eKindOfMarker = BitmapMarkerKind::Rect_11x11;
break;
}
case SdrHdlKind::Ref1:
case SdrHdlKind::Ref2:
{
eKindOfMarker = BitmapMarkerKind::Crosshair;
break;
}
case SdrHdlKind::Glue:
{
eKindOfMarker = BitmapMarkerKind::Glue;
break;
}
case SdrHdlKind::Anchor:
{
eKindOfMarker = BitmapMarkerKind::Anchor;
break;
}
case SdrHdlKind::User:
{
break;
}
// top right anchor for SW
case SdrHdlKind::Anchor_TR:
{
eKindOfMarker = BitmapMarkerKind::AnchorTR;
break;
}
// for SJ and the CustomShapeHandles:
case SdrHdlKind::CustomShape1:
{
eKindOfMarker = b1PixMore ? BitmapMarkerKind::Customshape_9x9 : BitmapMarkerKind::Customshape_7x7;
eColIndex = BitmapColorIndex::Yellow;
break;
}
default:
break;
}
SdrMarkView* pView = pHdlList->GetView();
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
Point aMoveOutsideOffset(0, 0);
OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
// add offset if necessary
if(pHdlList->IsMoveOutside() || mbMoveOutside)
{
Size aOffset = rOutDev.PixelToLogic(Size(4, 4));
if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Upper || eKind == SdrHdlKind::UpperRight)
aMoveOutsideOffset.AdjustY( -(aOffset.Width()) );
if(eKind == SdrHdlKind::LowerLeft || eKind == SdrHdlKind::Lower || eKind == SdrHdlKind::LowerRight)
aMoveOutsideOffset.AdjustY(aOffset.Height() );
if(eKind == SdrHdlKind::UpperLeft || eKind == SdrHdlKind::Left || eKind == SdrHdlKind::LowerLeft)
aMoveOutsideOffset.AdjustX( -(aOffset.Width()) );
if(eKind == SdrHdlKind::UpperRight || eKind == SdrHdlKind::Right || eKind == SdrHdlKind::LowerRight)
aMoveOutsideOffset.AdjustX(aOffset.Height() );
}
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject;
if (getenv ("SVX_DRAW_HANDLES") && (eKindOfMarker == BitmapMarkerKind::Rect_7x7 || eKindOfMarker == BitmapMarkerKind::Rect_9x9 || eKindOfMarker == BitmapMarkerKind::Rect_11x11))
{
double fSize = 7.0;
switch (eKindOfMarker)
{
case BitmapMarkerKind::Rect_9x9:
fSize = 9.0;
break;
case BitmapMarkerKind::Rect_11x11:
fSize = 11.0;
break;
default:
break;
}
float fScalingFactor = rOutDev.GetDPIScaleFactor();
basegfx::B2DSize aB2DSize(fSize * fScalingFactor, fSize * fScalingFactor);
Color aHandleFillColor(COL_LIGHTGREEN);
switch (eColIndex)
{
case BitmapColorIndex::Cyan:
aHandleFillColor = COL_CYAN;
break;
case BitmapColorIndex::LightCyan:
aHandleFillColor = COL_LIGHTCYAN;
break;
case BitmapColorIndex::Red:
aHandleFillColor = COL_RED;
break;
case BitmapColorIndex::LightRed:
aHandleFillColor = COL_LIGHTRED;
break;
case BitmapColorIndex::Yellow:
aHandleFillColor = COL_YELLOW;
break;
default:
break;
}
pNewOverlayObject.reset(new sdr::overlay::OverlayHandle(aPosition, aB2DSize, /*HandleStrokeColor*/COL_BLACK, aHandleFillColor));
}
else
{
pNewOverlayObject = CreateOverlayObject(
aPosition, eColIndex, eKindOfMarker,
aMoveOutsideOffset);
}
// OVERLAYMANAGER
if (pNewOverlayObject)
{
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd)
{
BitmapMarkerKind eRetval(eKnd);
switch(eKnd)
{
case BitmapMarkerKind::Rect_7x7: eRetval = BitmapMarkerKind::Rect_9x9; break;
case BitmapMarkerKind::Rect_9x9: eRetval = BitmapMarkerKind::Rect_11x11; break;
case BitmapMarkerKind::Rect_11x11: eRetval = BitmapMarkerKind::Rect_13x13; break;
case BitmapMarkerKind::Circ_7x7: eRetval = BitmapMarkerKind::Circ_9x9; break;
case BitmapMarkerKind::Circ_9x9: eRetval = BitmapMarkerKind::Circ_11x11; break;
case BitmapMarkerKind::Customshape_7x7: eRetval = BitmapMarkerKind::Customshape_9x9; break;
case BitmapMarkerKind::Customshape_9x9: eRetval = BitmapMarkerKind::Customshape_11x11; break;
//case BitmapMarkerKind::Customshape_11x11: eRetval = ; break;
case BitmapMarkerKind::Elli_7x9: eRetval = BitmapMarkerKind::Elli_9x11; break;
case BitmapMarkerKind::Elli_9x7: eRetval = BitmapMarkerKind::Elli_11x9; break;
case BitmapMarkerKind::RectPlus_7x7: eRetval = BitmapMarkerKind::RectPlus_9x9; break;
case BitmapMarkerKind::RectPlus_9x9: eRetval = BitmapMarkerKind::RectPlus_11x11; break;
// let anchor blink with its pressed state
case BitmapMarkerKind::Anchor: eRetval = BitmapMarkerKind::AnchorPressed; break;
// same for AnchorTR
case BitmapMarkerKind::AnchorTR: eRetval = BitmapMarkerKind::AnchorPressedTR; break;
default:
break;
}
return eRetval;
}
namespace
{
OUString appendMarkerName(BitmapMarkerKind eKindOfMarker)
{
switch(eKindOfMarker)
{
case BitmapMarkerKind::Rect_7x7:
return OUString("rect7");
case BitmapMarkerKind::Rect_9x9:
return OUString("rect9");
case BitmapMarkerKind::Rect_11x11:
return OUString("rect11");
case BitmapMarkerKind::Rect_13x13:
return OUString("rect13");
case BitmapMarkerKind::Circ_7x7:
case BitmapMarkerKind::Customshape_7x7:
return OUString("circ7");
case BitmapMarkerKind::Circ_9x9:
case BitmapMarkerKind::Customshape_9x9:
return OUString("circ9");
case BitmapMarkerKind::Circ_11x11:
case BitmapMarkerKind::Customshape_11x11:
return OUString("circ11");
case BitmapMarkerKind::Elli_7x9:
return OUString("elli7x9");
case BitmapMarkerKind::Elli_9x11:
return OUString("elli9x11");
case BitmapMarkerKind::Elli_9x7:
return OUString("elli9x7");
case BitmapMarkerKind::Elli_11x9:
return OUString("elli11x9");
case BitmapMarkerKind::RectPlus_7x7:
return OUString("rectplus7");
case BitmapMarkerKind::RectPlus_9x9:
return OUString("rectplus9");
case BitmapMarkerKind::RectPlus_11x11:
return OUString("rectplus11");
case BitmapMarkerKind::Crosshair:
return OUString("cross");
case BitmapMarkerKind::Anchor:
case BitmapMarkerKind::AnchorTR:
return OUString("anchor");
case BitmapMarkerKind::AnchorPressed:
case BitmapMarkerKind::AnchorPressedTR:
return OUString("anchor-pressed");
case BitmapMarkerKind::Glue:
return OUString("glue-selected");
case BitmapMarkerKind::Glue_Deselected:
return OUString("glue-unselected");
default:
break;
}
return OUString();
}
OUString appendMarkerColor(BitmapColorIndex eIndex)
{
switch(eIndex)
{
case BitmapColorIndex::LightGreen:
return OUString("1");
case BitmapColorIndex::Cyan:
return OUString("2");
case BitmapColorIndex::LightCyan:
return OUString("3");
case BitmapColorIndex::Red:
return OUString("4");
case BitmapColorIndex::LightRed:
return OUString("5");
case BitmapColorIndex::Yellow:
return OUString("6");
default:
break;
}
return OUString();
}
BitmapEx ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, BitmapColorIndex eIndex)
{
// use this code path only when we use HiDPI (for now)
if (Application::GetDefaultDevice()->GetDPIScalePercentage() > 100)
{
OUString sMarkerPrefix("svx/res/marker-");
OUString sMarkerName = appendMarkerName(eKindOfMarker);
if (!sMarkerName.isEmpty())
{
BitmapEx aBitmapEx;
if (eKindOfMarker == BitmapMarkerKind::Crosshair
|| eKindOfMarker == BitmapMarkerKind::Anchor
|| eKindOfMarker == BitmapMarkerKind::AnchorTR
|| eKindOfMarker == BitmapMarkerKind::AnchorPressed
|| eKindOfMarker == BitmapMarkerKind::AnchorPressedTR
|| eKindOfMarker == BitmapMarkerKind::Glue
|| eKindOfMarker == BitmapMarkerKind::Glue_Deselected)
{
aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + ".png");
}
else
{
aBitmapEx = vcl::bitmap::loadFromName(sMarkerPrefix + sMarkerName + "-" + appendMarkerColor(eIndex) + ".png");
}
if (!aBitmapEx.IsEmpty())
return aBitmapEx;
}
}
// if we can't load the marker..
static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aModernSet(new SdrHdlBitmapSet);
return aModernSet.get()->GetBitmapEx(eKindOfMarker, sal_uInt16(eIndex));
}
} // end anonymous namespace
std::unique_ptr<sdr::overlay::OverlayObject> SdrHdl::CreateOverlayObject(
const basegfx::B2DPoint& rPos,
BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
{
std::unique_ptr<sdr::overlay::OverlayObject> pRetval;
// support bigger sizes
bool bForceBiggerSize(false);
if(pHdlList->GetHdlSize() > 3)
{
switch(eKindOfMarker)
{
case BitmapMarkerKind::Anchor:
case BitmapMarkerKind::AnchorPressed:
case BitmapMarkerKind::AnchorTR:
case BitmapMarkerKind::AnchorPressedTR:
{
// #i121463# For anchor, do not simply make bigger because of HdlSize,
// do it dependent of IsSelected() which Writer can set in drag mode
if(IsSelected())
{
bForceBiggerSize = true;
}
break;
}
default:
{
bForceBiggerSize = true;
break;
}
}
}
if(bForceBiggerSize)
{
eKindOfMarker = GetNextBigger(eKindOfMarker);
}
// This handle has the focus, visualize it
if(IsFocusHdl() && pHdlList && pHdlList->GetFocusHdl() == this)
{
// create animated handle
BitmapMarkerKind eNextBigger = GetNextBigger(eKindOfMarker);
if(eNextBigger == eKindOfMarker)
{
// this may happen for the not supported getting-bigger types.
// Choose an alternative here
switch(eKindOfMarker)
{
case BitmapMarkerKind::Rect_13x13: eNextBigger = BitmapMarkerKind::Rect_11x11; break;
case BitmapMarkerKind::Circ_11x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
case BitmapMarkerKind::Elli_9x11: eNextBigger = BitmapMarkerKind::Elli_11x9; break;
case BitmapMarkerKind::Elli_11x9: eNextBigger = BitmapMarkerKind::Elli_9x11; break;
case BitmapMarkerKind::RectPlus_11x11: eNextBigger = BitmapMarkerKind::Rect_13x13; break;
case BitmapMarkerKind::Crosshair:
eNextBigger = BitmapMarkerKind::Glue;
break;
case BitmapMarkerKind::Glue:
eNextBigger = BitmapMarkerKind::Crosshair;
break;
case BitmapMarkerKind::Glue_Deselected:
eNextBigger = BitmapMarkerKind::Glue;
break;
default:
break;
}
}
// create animated handle
BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, eColIndex);
BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, eColIndex);
// #i53216# Use system cursor blink time. Use the unsigned value.
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
const sal_uInt64 nBlinkTime(rStyleSettings.GetCursorBlinkTime());
if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
{
// when anchor is used take upper left as reference point inside the handle
pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime));
}
else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
{
// AnchorTR for SW, take top right as (0,0)
pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1), 0,
static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1), 0));
}
else
{
// create centered handle as default
pRetval.reset(new sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1));
}
}
else
{
// create normal handle: use ImpGetBitmapEx(...) now
BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, eColIndex);
// When the image with handles is not found, the bitmap returned is
// empty. This is a problem when we use LibreOffice as a library
// (through LOKit - for example on Android) even when we don't show
// the handles, because the hit test would always return false.
//
// This HACK replaces the empty bitmap with a black 13x13 bitmap handle
// so that the hit test works for this case.
if (aBmpEx.IsEmpty())
{
aBmpEx = BitmapEx(Bitmap(Size(13, 13), 24));
aBmpEx.Erase(COL_BLACK);
}
if(eKindOfMarker == BitmapMarkerKind::Anchor || eKindOfMarker == BitmapMarkerKind::AnchorPressed)
{
// upper left as reference point inside the handle for AnchorPressed, too
pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx));
}
else if(eKindOfMarker == BitmapMarkerKind::AnchorTR || eKindOfMarker == BitmapMarkerKind::AnchorPressedTR)
{
// AnchorTR for SW, take top right as (0,0)
pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1), 0));
}
else
{
sal_uInt16 nCenX(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1) >> 1);
sal_uInt16 nCenY(static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1) >> 1);
if(aMoveOutsideOffset.X() > 0)
{
nCenX = 0;
}
else if(aMoveOutsideOffset.X() < 0)
{
nCenX = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Width() - 1);
}
if(aMoveOutsideOffset.Y() > 0)
{
nCenY = 0;
}
else if(aMoveOutsideOffset.Y() < 0)
{
nCenY = static_cast<sal_uInt16>(aBmpEx.GetSizePixel().Height() - 1);
}
// create centered handle as default
pRetval.reset(new sdr::overlay::OverlayBitmapEx(rPos, aBmpEx, nCenX, nCenY));
}
}
return pRetval;
}
bool SdrHdl::IsHdlHit(const Point& rPnt) const
{
// OVERLAYMANAGER
basegfx::B2DPoint aPosition(rPnt.X(), rPnt.Y());
return maOverlayGroup.isHitLogic(aPosition);
}
Pointer SdrHdl::GetPointer() const
{
PointerStyle ePtr=PointerStyle::Move;
const bool bSize=eKind>=SdrHdlKind::UpperLeft && eKind<=SdrHdlKind::LowerRight;
const bool bRot=pHdlList!=nullptr && pHdlList->IsRotateShear();
const bool bDis=pHdlList!=nullptr && pHdlList->IsDistortShear();
if (bSize && pHdlList!=nullptr && (bRot || bDis)) {
switch (eKind) {
case SdrHdlKind::UpperLeft: case SdrHdlKind::UpperRight:
case SdrHdlKind::LowerLeft: case SdrHdlKind::LowerRight: ePtr=bRot ? PointerStyle::Rotate : PointerStyle::RefHand; break;
case SdrHdlKind::Left : case SdrHdlKind::Right: ePtr=PointerStyle::VShear; break;
case SdrHdlKind::Upper: case SdrHdlKind::Lower: ePtr=PointerStyle::HShear; break;
default:
break;
}
} else {
// When resizing rotated rectangles, rotate the mouse cursor slightly, too
if (bSize && nRotationAngle!=0) {
long nHdlAngle=0;
switch (eKind) {
case SdrHdlKind::LowerRight: nHdlAngle=31500; break;
case SdrHdlKind::Lower: nHdlAngle=27000; break;
case SdrHdlKind::LowerLeft: nHdlAngle=22500; break;
case SdrHdlKind::Left : nHdlAngle=18000; break;
case SdrHdlKind::UpperLeft: nHdlAngle=13500; break;
case SdrHdlKind::Upper: nHdlAngle=9000; break;
case SdrHdlKind::UpperRight: nHdlAngle=4500; break;
case SdrHdlKind::Right: nHdlAngle=0; break;
default:
break;
}
// a little bit more (for rounding)
nHdlAngle = NormAngle36000(nHdlAngle + nRotationAngle + 2249);
nHdlAngle/=4500;
switch (static_cast<sal_uInt8>(nHdlAngle)) {
case 0: ePtr=PointerStyle::ESize; break;
case 1: ePtr=PointerStyle::NESize; break;
case 2: ePtr=PointerStyle::NSize; break;
case 3: ePtr=PointerStyle::NWSize; break;
case 4: ePtr=PointerStyle::WSize; break;
case 5: ePtr=PointerStyle::SWSize; break;
case 6: ePtr=PointerStyle::SSize; break;
case 7: ePtr=PointerStyle::SESize; break;
} // switch
} else {
switch (eKind) {
case SdrHdlKind::UpperLeft: ePtr=PointerStyle::NWSize; break;
case SdrHdlKind::Upper: ePtr=PointerStyle::NSize; break;
case SdrHdlKind::UpperRight: ePtr=PointerStyle::NESize; break;
case SdrHdlKind::Left : ePtr=PointerStyle::WSize; break;
case SdrHdlKind::Right: ePtr=PointerStyle::ESize; break;
case SdrHdlKind::LowerLeft: ePtr=PointerStyle::SWSize; break;
case SdrHdlKind::Lower: ePtr=PointerStyle::SSize; break;
case SdrHdlKind::LowerRight: ePtr=PointerStyle::SESize; break;
case SdrHdlKind::Poly : ePtr=PointerStyle::MovePoint; break;
case SdrHdlKind::Circle : ePtr=PointerStyle::Hand; break;
case SdrHdlKind::Ref1 : ePtr=PointerStyle::RefHand; break;
case SdrHdlKind::Ref2 : ePtr=PointerStyle::RefHand; break;
case SdrHdlKind::BezierWeight : ePtr=PointerStyle::MoveBezierWeight; break;
case SdrHdlKind::Glue : ePtr=PointerStyle::MovePoint; break;
case SdrHdlKind::CustomShape1 : ePtr=PointerStyle::Hand; break;
default:
break;
}
}
}
return Pointer(ePtr);
}
bool SdrHdl::IsFocusHdl() const
{
switch(eKind)
{
case SdrHdlKind::UpperLeft:
case SdrHdlKind::Upper:
case SdrHdlKind::UpperRight:
case SdrHdlKind::Left:
case SdrHdlKind::Right:
case SdrHdlKind::LowerLeft:
case SdrHdlKind::Lower:
case SdrHdlKind::LowerRight:
{
// if it's an activated TextEdit, it's moved to extended points
return !pHdlList || !pHdlList->IsMoveOutside();
}
case SdrHdlKind::Move: // handle to move object
case SdrHdlKind::Poly: // selected point of polygon or curve
case SdrHdlKind::BezierWeight: // weight at a curve
case SdrHdlKind::Circle: // angle of circle segments, corner radius of rectangles
case SdrHdlKind::Ref1: // reference point 1, e. g. center of rotation
case SdrHdlKind::Ref2: // reference point 2, e. g. endpoint of reflection axis
case SdrHdlKind::Glue: // glue point
// for SJ and the CustomShapeHandles:
case SdrHdlKind::CustomShape1:
case SdrHdlKind::User:
{
return true;
}
default:
{
return false;
}
}
}
void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
{
}
void SdrHdl::onMouseLeave()
{
}
BitmapEx SdrHdl::createGluePointBitmap()
{
return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
}
SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
: SdrHdl(rRef, SdrHdlKind::Color),
aMarkerSize(rSize),
bUseLuminance(bLum)
{
if(IsUseLuminance())
aCol = GetLuminance(aCol);
// remember color
aMarkerColor = aCol;
}
SdrHdlColor::~SdrHdlColor()
{
}
void SdrHdlColor::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
BitmapEx aBmpCol(CreateColorDropper(aMarkerColor));
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
sdr::overlay::OverlayBitmapEx(
aPosition,
aBmpCol,
static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpCol.GetSizePixel().Height() - 1) >> 1
));
// OVERLAYMANAGER
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
BitmapEx SdrHdlColor::CreateColorDropper(Color aCol)
{
// get the Bitmap
VclPtr<VirtualDevice> pWrite(VclPtr<VirtualDevice>::Create());
pWrite->SetOutputSizePixel(aMarkerSize);
pWrite->SetBackground(aCol);
pWrite->Erase();
// draw outer border
sal_Int32 nWidth = aMarkerSize.Width();
sal_Int32 nHeight = aMarkerSize.Height();
pWrite->SetLineColor(COL_LIGHTGRAY);
pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
pWrite->SetLineColor(COL_GRAY);
pWrite->DrawLine(Point(1, nHeight - 1), Point(nWidth - 1, nHeight - 1));
pWrite->DrawLine(Point(nWidth - 1, 1), Point(nWidth - 1, nHeight - 2));
// draw lighter UpperLeft
const Color aLightColor(
static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) + sal_Int16(0x0040)), sal_Int16(0x00ff))),
static_cast<sal_uInt8>(::std::min(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) + sal_Int16(0x0040)), sal_Int16(0x00ff))));
pWrite->SetLineColor(aLightColor);
pWrite->DrawLine(Point(1, 1), Point(1, nHeight - 2));
pWrite->DrawLine(Point(2, 1), Point(nWidth - 2, 1));
// draw darker LowerRight
const Color aDarkColor(
static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetRed()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetGreen()) - sal_Int16(0x0040)), sal_Int16(0x0000))),
static_cast<sal_uInt8>(::std::max(static_cast<sal_Int16>(static_cast<sal_Int16>(aCol.GetBlue()) - sal_Int16(0x0040)), sal_Int16(0x0000))));
pWrite->SetLineColor(aDarkColor);
pWrite->DrawLine(Point(2, nHeight - 2), Point(nWidth - 2, nHeight - 2));
pWrite->DrawLine(Point(nWidth - 2, 2), Point(nWidth - 2, nHeight - 3));
return pWrite->GetBitmapEx(Point(0,0), aMarkerSize);
}
Color SdrHdlColor::GetLuminance(const Color& rCol)
{
sal_uInt8 aLum = rCol.GetLuminance();
Color aRetval(aLum, aLum, aLum);
return aRetval;
}
void SdrHdlColor::SetColor(Color aNew, bool bCallLink)
{
if(IsUseLuminance())
aNew = GetLuminance(aNew);
if(aMarkerColor != aNew)
{
// remember new color
aMarkerColor = aNew;
// create new display
Touch();
// tell about change
if(bCallLink)
aColorChangeHdl.Call(this);
}
}
void SdrHdlColor::SetSize(const Size& rNew)
{
if(rNew != aMarkerSize)
{
// remember new size
aMarkerSize = rNew;
// create new display
Touch();
}
}
SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, bool bGrad)
: SdrHdl(rRef1, bGrad ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)
, pColHdl1(nullptr)
, pColHdl2(nullptr)
, a2ndPos(rRef2)
, bGradient(bGrad)
, bMoveSingleHandle(false)
, bMoveFirstHandle(false)
{
}
SdrHdlGradient::~SdrHdlGradient()
{
}
void SdrHdlGradient::Set2ndPos(const Point& rPnt)
{
if(a2ndPos != rPnt)
{
// remember new position
a2ndPos = rPnt;
// create new display
Touch();
}
}
void SdrHdlGradient::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
// striped line in between
basegfx::B2DVector aVec(a2ndPos.X() - aPos.X(), a2ndPos.Y() - aPos.Y());
double fVecLen = aVec.getLength();
double fLongPercentArrow = (1.0 - 0.05) * fVecLen;
double fHalfArrowWidth = (0.05 * 0.5) * fVecLen;
aVec.normalize();
basegfx::B2DVector aPerpend(-aVec.getY(), aVec.getX());
sal_Int32 nMidX = static_cast<sal_Int32>(aPos.X() + aVec.getX() * fLongPercentArrow);
sal_Int32 nMidY = static_cast<sal_Int32>(aPos.Y() + aVec.getY() * fLongPercentArrow);
Point aMidPoint(nMidX, nMidY);
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
basegfx::B2DPoint aMidPos(aMidPoint.X(), aMidPoint.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
sdr::overlay::OverlayLineStriped(
aPosition, aMidPos
));
pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
// arrowhead
Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
aMidPoint.Y() + static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
Point aRight(aMidPoint.X() - static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
aMidPoint.Y() - static_cast<sal_Int32>(aPerpend.getY() * fHalfArrowWidth));
basegfx::B2DPoint aPositionLeft(aLeft.X(), aLeft.Y());
basegfx::B2DPoint aPositionRight(aRight.X(), aRight.Y());
basegfx::B2DPoint aPosition2(a2ndPos.X(), a2ndPos.Y());
pNewOverlayObject.reset(new
sdr::overlay::OverlayTriangle(
aPositionLeft,
aPosition2,
aPositionRight,
IsGradient() ? COL_BLACK : COL_BLUE
));
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
IMPL_LINK_NOARG(SdrHdlGradient, ColorChangeHdl, SdrHdlColor*, void)
{
if(GetObj())
FromIAOToItem(GetObj(), true, true);
}
void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, bool bSetItemOnObject, bool bUndo)
{
// from IAO positions and colors to gradient
const SfxItemSet& rSet = _pObj->GetMergedItemSet();
GradTransformer aGradTransformer;
GradTransGradient aOldGradTransGradient;
GradTransGradient aGradTransGradient;
GradTransVector aGradTransVector;
OUString aString;
aGradTransVector.maPositionA = basegfx::B2DPoint(GetPos().X(), GetPos().Y());
aGradTransVector.maPositionB = basegfx::B2DPoint(Get2ndPos().X(), Get2ndPos().Y());
if(pColHdl1)
aGradTransVector.aCol1 = pColHdl1->GetColor();
if(pColHdl2)
aGradTransVector.aCol2 = pColHdl2->GetColor();
if(IsGradient())
aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
else
aOldGradTransGradient.aGradient = rSet.Get(XATTR_FILLFLOATTRANSPARENCE).GetGradientValue();
// transform vector data to gradient
GradTransformer::VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);
if(bSetItemOnObject)
{
SdrModel& rModel(_pObj->getSdrModelFromSdrObject());
SfxItemSet aNewSet(rModel.GetItemPool());
if(IsGradient())
{
aString.clear();
XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
aNewSet.Put(aNewGradItem);
}
else
{
aString.clear();
XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
aNewSet.Put(aNewTransItem);
}
if(bUndo && rModel.IsUndoEnabled())
{
rModel.BegUndo(SvxResId(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
rModel.AddUndo(rModel.GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
rModel.EndUndo();
}
pObj->SetMergedItemSetAndBroadcast(aNewSet);
}
// back transformation, set values on pIAOHandle
GradTransformer::GradToVec(aGradTransGradient, aGradTransVector, _pObj);
SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
Set2ndPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
if(pColHdl1)
{
pColHdl1->SetPos(Point(FRound(aGradTransVector.maPositionA.getX()), FRound(aGradTransVector.maPositionA.getY())));
pColHdl1->SetColor(aGradTransVector.aCol1);
}
if(pColHdl2)
{
pColHdl2->SetPos(Point(FRound(aGradTransVector.maPositionB.getX()), FRound(aGradTransVector.maPositionB.getY())));
pColHdl2->SetColor(aGradTransVector.aCol2);
}
}
SdrHdlLine::~SdrHdlLine() {}
void SdrHdlLine::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden() && pHdl1 && pHdl2)
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), pHdl2->GetPos().Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
sdr::overlay::OverlayLineStriped(
aPosition1,
aPosition2
));
// OVERLAYMANAGER
// color(?)
pNewOverlayObject->setBaseColor(COL_LIGHTRED);
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
Pointer SdrHdlLine::GetPointer() const
{
return Pointer(PointerStyle::RefHand);
}
SdrHdlBezWgt::~SdrHdlBezWgt() {}
void SdrHdlBezWgt::CreateB2dIAObject()
{
// call parent
SdrHdl::CreateB2dIAObject();
// create lines
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
basegfx::B2DPoint aPosition2(aPos.X(), aPos.Y());
if(!aPosition1.equal(aPosition2))
{
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
sdr::overlay::OverlayLineStriped(
aPosition1,
aPosition2
));
// OVERLAYMANAGER
// line part is not hittable
pNewOverlayObject->setHittable(false);
// color(?)
pNewOverlayObject->setBaseColor(COL_LIGHTBLUE);
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
}
E3dVolumeMarker::E3dVolumeMarker(const basegfx::B2DPolyPolygon& rWireframePoly)
{
aWireframePoly = rWireframePoly;
}
void E3dVolumeMarker::CreateB2dIAObject()
{
// create lines
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is() && aWireframePoly.count())
{
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new
sdr::overlay::OverlayPolyPolygonStripedAndFilled(
aWireframePoly));
// OVERLAYMANAGER
pNewOverlayObject->setBaseColor(COL_BLACK);
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
ImpEdgeHdl::~ImpEdgeHdl()
{
}
void ImpEdgeHdl::CreateB2dIAObject()
{
if(nObjHdlNum <= 1 && pObj)
{
// first throw away old one
GetRidOfIAObject();
BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_7x7;
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
const SdrEdgeObj* pEdge = static_cast<SdrEdgeObj*>(pObj);
if(pEdge->GetConnectedNode(nObjHdlNum == 0) != nullptr)
eColIndex = BitmapColorIndex::LightRed;
if(nPPntNum < 2)
{
// Handle with plus sign inside
eKindOfMarker = BitmapMarkerKind::Circ_7x7;
}
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
aPosition,
eColIndex,
eKindOfMarker));
// OVERLAYMANAGER
if (pNewOverlayObject)
{
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
}
else
{
// call parent
SdrHdl::CreateB2dIAObject();
}
}
void ImpEdgeHdl::SetLineCode(SdrEdgeLineCode eCode)
{
if(eLineCode != eCode)
{
// remember new value
eLineCode = eCode;
// create new display
Touch();
}
}
Pointer ImpEdgeHdl::GetPointer() const
{
SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
if (pEdge==nullptr)
return SdrHdl::GetPointer();
if (nObjHdlNum<=1)
return Pointer(PointerStyle::MovePoint);
if (IsHorzDrag())
return Pointer(PointerStyle::ESize);
else
return Pointer(PointerStyle::SSize);
}
bool ImpEdgeHdl::IsHorzDrag() const
{
SdrEdgeObj* pEdge=dynamic_cast<SdrEdgeObj*>( pObj );
if (pEdge==nullptr)
return false;
if (nObjHdlNum<=1)
return false;
SdrEdgeKind eEdgeKind = pEdge->GetObjectItem(SDRATTR_EDGEKIND).GetValue();
const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
if (eEdgeKind==SdrEdgeKind::OrthoLines || eEdgeKind==SdrEdgeKind::Bezier)
{
return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
}
else if (eEdgeKind==SdrEdgeKind::ThreeLines)
{
long nAngle=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
return nAngle==0 || nAngle==18000;
}
return false;
}
ImpMeasureHdl::~ImpMeasureHdl()
{
}
void ImpMeasureHdl::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
BitmapColorIndex eColIndex = BitmapColorIndex::LightCyan;
BitmapMarkerKind eKindOfMarker = BitmapMarkerKind::Rect_9x9;
if(nObjHdlNum > 1)
{
eKindOfMarker = BitmapMarkerKind::Rect_7x7;
}
if(bSelect)
{
eColIndex = BitmapColorIndex::Cyan;
}
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(CreateOverlayObject(
aPosition,
eColIndex,
eKindOfMarker));
// OVERLAYMANAGER
if (pNewOverlayObject)
{
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
}
Pointer ImpMeasureHdl::GetPointer() const
{
switch (nObjHdlNum)
{
case 0: case 1: return Pointer(PointerStyle::Hand);
case 2: case 3: return Pointer(PointerStyle::MovePoint);
case 4: case 5: return SdrHdl::GetPointer(); // will then be rotated appropriately
} // switch
return Pointer(PointerStyle::NotAllowed);
}
ImpTextframeHdl::ImpTextframeHdl(const tools::Rectangle& rRect) :
SdrHdl(rRect.TopLeft(),SdrHdlKind::Move),
maRect(rRect)
{
}
void ImpTextframeHdl::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
if(pHdlList)
{
SdrMarkView* pView = pHdlList->GetView();
if(pView && !pView->areMarkHandlesHidden())
{
SdrPageView* pPageView = pView->GetSdrPageView();
if(pPageView)
{
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
const basegfx::B2DPoint aTopLeft(maRect.Left(), maRect.Top());
const basegfx::B2DPoint aBottomRight(maRect.Right(), maRect.Bottom());
const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
std::unique_ptr<sdr::overlay::OverlayRectangle> pNewOverlayObject(new sdr::overlay::OverlayRectangle(
aTopLeft,
aBottomRight,
aHilightColor,
fTransparence,
3.0,
3.0,
nRotationAngle * -F_PI18000,
true)); // allow animation; the Handle is not shown at text edit time
// OVERLAYMANAGER
pNewOverlayObject->setHittable(false);
xManager->add(*pNewOverlayObject);
maOverlayGroup.append(std::move(pNewOverlayObject));
}
}
}
}
}
}
}
static bool ImpSdrHdlListSorter(SdrHdl* const& lhs, SdrHdl* const& rhs)
{
SdrHdlKind eKind1=lhs->GetKind();
SdrHdlKind eKind2=rhs->GetKind();
// Level 1: first normal handles, then Glue, then User, then Plus handles, then reference point handles
unsigned n1=1;
unsigned n2=1;
if (eKind1!=eKind2)
{
if (eKind1==SdrHdlKind::Ref1 || eKind1==SdrHdlKind::Ref2 || eKind1==SdrHdlKind::MirrorAxis) n1=5;
else if (eKind1==SdrHdlKind::Glue) n1=2;
else if (eKind1==SdrHdlKind::User) n1=3;
else if (eKind1==SdrHdlKind::SmartTag) n1=0;
if (eKind2==SdrHdlKind::Ref1 || eKind2==SdrHdlKind::Ref2 || eKind2==SdrHdlKind::MirrorAxis) n2=5;
else if (eKind2==SdrHdlKind::Glue) n2=2;
else if (eKind2==SdrHdlKind::User) n2=3;
else if (eKind2==SdrHdlKind::SmartTag) n2=0;
}
if (lhs->IsPlusHdl()) n1=4;
if (rhs->IsPlusHdl()) n2=4;
if (n1==n2)
{
// Level 2: PageView (Pointer)
SdrPageView* pPV1=lhs->GetPageView();
SdrPageView* pPV2=rhs->GetPageView();
if (pPV1==pPV2)
{
// Level 3: Position (x+y)
SdrObject* pObj1=lhs->GetObj();
SdrObject* pObj2=rhs->GetObj();
if (pObj1==pObj2)
{
sal_uInt32 nNum1=lhs->GetObjHdlNum();
sal_uInt32 nNum2=rhs->GetObjHdlNum();
if (nNum1==nNum2)
{
if (eKind1==eKind2)
return lhs<rhs; // Hack, to always get to the same sorting
return static_cast<sal_uInt16>(eKind1)<static_cast<sal_uInt16>(eKind2);
}
else
return nNum1<nNum2;
}
else
{
return pObj1<pObj2;
}
}
else
{
return pPV1<pPV2;
}
}
else
{
return n1<n2;
}
}
// Helper struct for re-sorting handles
struct ImplHdlAndIndex
{
SdrHdl* mpHdl;
sal_uInt32 mnIndex;
};
// Helper method for sorting handles taking care of OrdNums, keeping order in
// single objects and re-sorting polygon handles intuitively
extern "C" int ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
{
const ImplHdlAndIndex* p1 = static_cast<ImplHdlAndIndex const *>(pVoid1);
const ImplHdlAndIndex* p2 = static_cast<ImplHdlAndIndex const *>(pVoid2);
if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
{
if(p1->mpHdl->GetObj() && dynamic_cast<const SdrPathObj*>(p1->mpHdl->GetObj()) != nullptr)
{
// same object and a path object
if((p1->mpHdl->GetKind() == SdrHdlKind::Poly || p1->mpHdl->GetKind() == SdrHdlKind::BezierWeight)
&& (p2->mpHdl->GetKind() == SdrHdlKind::Poly || p2->mpHdl->GetKind() == SdrHdlKind::BezierWeight))
{
// both handles are point or control handles
if(p1->mpHdl->GetPolyNum() == p2->mpHdl->GetPolyNum())
{
if(p1->mpHdl->GetPointNum() < p2->mpHdl->GetPointNum())
{
return -1;
}
else
{
return 1;
}
}
else if(p1->mpHdl->GetPolyNum() < p2->mpHdl->GetPolyNum())
{
return -1;
}
else
{
return 1;
}
}
}
}
else
{
if(!p1->mpHdl->GetObj())
{
return -1;
}
else if(!p2->mpHdl->GetObj())
{
return 1;
}
else
{
// different objects, use OrdNum for sort
const sal_uInt32 nOrdNum1 = p1->mpHdl->GetObj()->GetOrdNum();
const sal_uInt32 nOrdNum2 = p2->mpHdl->GetObj()->GetOrdNum();
if(nOrdNum1 < nOrdNum2)
{
return -1;
}
else
{
return 1;
}
}
}
// fallback to indices
if(p1->mnIndex < p2->mnIndex)
{
return -1;
}
else
{
return 1;
}
}
void SdrHdlList::TravelFocusHdl(bool bForward)
{
// security correction
if (mnFocusIndex >= GetHdlCount())
mnFocusIndex = SAL_MAX_SIZE;
if(aList.empty())
return;
// take care of old handle
const size_t nOldHdlNum(mnFocusIndex);
SdrHdl* pOld = GetHdl(nOldHdlNum);
if(pOld)
{
// switch off old handle
mnFocusIndex = SAL_MAX_SIZE;
pOld->Touch();
}
// allocate pointer array for sorted handle list
std::unique_ptr<ImplHdlAndIndex[]> pHdlAndIndex(new ImplHdlAndIndex[aList.size()]);
// build sorted handle list
for( size_t a = 0; a < aList.size(); ++a)
{
pHdlAndIndex[a].mpHdl = aList[a];
pHdlAndIndex[a].mnIndex = a;
}
qsort(pHdlAndIndex.get(), aList.size(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);
// look for old num in sorted array
size_t nOldHdl(nOldHdlNum);
if(nOldHdlNum != SAL_MAX_SIZE)
{
for(size_t a = 0; a < aList.size(); ++a)
{
if(pHdlAndIndex[a].mpHdl == pOld)
{
nOldHdl = a;
break;
}
}
}
// build new HdlNum
size_t nNewHdl(nOldHdl);
// do the focus travel
if(bForward)
{
if(nOldHdl != SAL_MAX_SIZE)
{
if(nOldHdl == aList.size() - 1)
{
// end forward run
nNewHdl = SAL_MAX_SIZE;
}
else
{
// simply the next handle
nNewHdl++;
}
}
else
{
// start forward run at first entry
nNewHdl = 0;
}
}
else
{
if(nOldHdl == SAL_MAX_SIZE)
{
// start backward run at last entry
nNewHdl = aList.size() - 1;
}
else
{
if(nOldHdl == 0)
{
// end backward run
nNewHdl = SAL_MAX_SIZE;
}
else
{
// simply the previous handle
nNewHdl--;
}
}
}
// build new HdlNum
sal_uIntPtr nNewHdlNum(nNewHdl);
// look for old num in sorted array
if(nNewHdl != SAL_MAX_SIZE)
{
SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;
for(size_t a = 0; a < aList.size(); ++a)
{
if(aList[a] == pNew)
{
nNewHdlNum = a;
break;
}
}
}
// take care of next handle
if(nOldHdlNum != nNewHdlNum)
{
mnFocusIndex = nNewHdlNum;
SdrHdl* pNew = GetHdl(mnFocusIndex);
if(pNew)
{
pNew->Touch();
}
}
}
SdrHdl* SdrHdlList::GetFocusHdl() const
{
if(mnFocusIndex < GetHdlCount())
return GetHdl(mnFocusIndex);
else
return nullptr;
}
void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
{
if(pNew)
{
SdrHdl* pActual = GetFocusHdl();
if(!pActual || pActual != pNew)
{
const size_t nNewHdlNum = GetHdlNum(pNew);
if(nNewHdlNum != SAL_MAX_SIZE)
{
mnFocusIndex = nNewHdlNum;
if(pActual)
{
pActual->Touch();
}
if(pNew)
{
pNew->Touch();
}
}
}
}
}
void SdrHdlList::ResetFocusHdl()
{
SdrHdl* pHdl = GetFocusHdl();
mnFocusIndex = SAL_MAX_SIZE;
if(pHdl)
{
pHdl->Touch();
}
}
SdrHdlList::SdrHdlList(SdrMarkView* pV)
: mnFocusIndex(SAL_MAX_SIZE),
pView(pV),
aList()
{
nHdlSize = 3;
bRotateShear = false;
bMoveOutside = false;
bDistortShear = false;
}
SdrHdlList::~SdrHdlList()
{
Clear();
}
void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
{
if(nHdlSize != nSiz)
{
// remember new value
nHdlSize = nSiz;
// propagate change to IAOs
for(size_t i=0; i<GetHdlCount(); ++i)
{
SdrHdl* pHdl = GetHdl(i);
pHdl->Touch();
}
}
}
void SdrHdlList::SetMoveOutside(bool bOn)
{
if(bMoveOutside != bOn)
{
// remember new value
bMoveOutside = bOn;
// propagate change to IAOs
for(size_t i=0; i<GetHdlCount(); ++i)
{
SdrHdl* pHdl = GetHdl(i);
pHdl->Touch();
}
}
}
void SdrHdlList::SetRotateShear(bool bOn)
{
bRotateShear = bOn;
}
void SdrHdlList::SetDistortShear(bool bOn)
{
bDistortShear = bOn;
}
SdrHdl* SdrHdlList::RemoveHdl(size_t nNum)
{
SdrHdl* pRetval = aList[nNum];
aList.erase(aList.begin() + nNum);
return pRetval;
}
void SdrHdlList::RemoveAllByKind(SdrHdlKind eKind)
{
for(std::deque<SdrHdl*>::iterator it = aList.begin(); it != aList.end(); )
{
SdrHdl* p = *it;
if (p->GetKind() == eKind)
{
it = aList.erase( it );
delete p;
}
else
++it;
}
}
void SdrHdlList::Clear()
{
for (size_t i=0; i<GetHdlCount(); ++i)
{
SdrHdl* pHdl=GetHdl(i);
delete pHdl;
}
aList.clear();
bRotateShear=false;
bDistortShear=false;
}
void SdrHdlList::Sort()
{
// remember currently focused handle
SdrHdl* pPrev = GetFocusHdl();
std::sort( aList.begin(), aList.end(), ImpSdrHdlListSorter );
// get now and compare
SdrHdl* pNow = GetFocusHdl();
if(pPrev != pNow)
{
if(pPrev)
{
pPrev->Touch();
}
if(pNow)
{
pNow->Touch();
}
}
}
size_t SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
{
if (pHdl==nullptr)
return SAL_MAX_SIZE;
std::deque<SdrHdl*>::const_iterator it = std::find( aList.begin(), aList.end(), pHdl);
if( it == aList.end() )
return SAL_MAX_SIZE;
return it - aList.begin();
}
void SdrHdlList::AddHdl(SdrHdl* pHdl)
{
if (pHdl!=nullptr)
{
aList.push_back(pHdl);
pHdl->SetHdlList(this);
}
}
SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt) const
{
SdrHdl* pRet=nullptr;
const size_t nCount=GetHdlCount();
size_t nNum=nCount;
while (nNum>0 && pRet==nullptr)
{
nNum--;
SdrHdl* pHdl=GetHdl(nNum);
if (pHdl->IsHdlHit(rPnt))
pRet=pHdl;
}
return pRet;
}
SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
{
SdrHdl* pRet=nullptr;
for (size_t i=0; i<GetHdlCount() && pRet==nullptr; ++i)
{
SdrHdl* pHdl=GetHdl(i);
if (pHdl->GetKind()==eKind1)
pRet=pHdl;
}
return pRet;
}
SdrCropHdl::SdrCropHdl(
const Point& rPnt,
SdrHdlKind eNewKind,
double fShearX,
double fRotation)
: SdrHdl(rPnt, eNewKind),
mfShearX(fShearX),
mfRotation(fRotation)
{
}
BitmapEx SdrCropHdl::GetBitmapForHandle( const BitmapEx& rBitmap, int nSize )
{
int nPixelSize = 0, nX = 0, nY = 0, nOffset = 0;
if( nSize <= 3 )
{
nPixelSize = 13;
nOffset = 0;
}
else if( nSize <=4 )
{
nPixelSize = 17;
nOffset = 39;
}
else
{
nPixelSize = 21;
nOffset = 90;
}
switch( eKind )
{
case SdrHdlKind::UpperLeft: nX = 0; nY = 0; break;
case SdrHdlKind::Upper: nX = 1; nY = 0; break;
case SdrHdlKind::UpperRight: nX = 2; nY = 0; break;
case SdrHdlKind::Left: nX = 0; nY = 1; break;
case SdrHdlKind::Right: nX = 2; nY = 1; break;
case SdrHdlKind::LowerLeft: nX = 0; nY = 2; break;
case SdrHdlKind::Lower: nX = 1; nY = 2; break;
case SdrHdlKind::LowerRight: nX = 2; nY = 2; break;
default: break;
}
tools::Rectangle aSourceRect( Point( nX * nPixelSize + nOffset, nY * nPixelSize), Size(nPixelSize, nPixelSize) );
BitmapEx aRetval(rBitmap);
aRetval.Crop(aSourceRect);
return aRetval;
}
void SdrCropHdl::CreateB2dIAObject()
{
// first throw away old one
GetRidOfIAObject();
SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
if( pPageView && !pView->areMarkHandlesHidden() )
{
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
int nHdlSize = pHdlList->GetHdlSize();
const BitmapEx aHandlesBitmap(SIP_SA_CROP_MARKERS);
BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if (xManager.is())
{
basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
// animate focused handles
if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
{
if( nHdlSize >= 2 )
nHdlSize = 1;
BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );
const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(
aPosition,
aBmpEx1,
aBmpEx2,
nBlinkTime,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
mfShearX,
mfRotation));
}
else
{
// create centered handle as default
pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx(
aPosition,
aBmpEx1,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
static_cast<sal_uInt16>(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
0.0,
mfShearX,
mfRotation));
}
// OVERLAYMANAGER
if(pOverlayObject)
{
xManager->add(*pOverlayObject);
maOverlayGroup.append(std::move(pOverlayObject));
}
}
}
}
}
}
// with the correction of crop handling I could get rid of the extra mirroring flag, adapted stuff
// accordingly
SdrCropViewHdl::SdrCropViewHdl(
const basegfx::B2DHomMatrix& rObjectTransform,
const Graphic& rGraphic,
double fCropLeft,
double fCropTop,
double fCropRight,
double fCropBottom)
: SdrHdl(Point(), SdrHdlKind::User),
maObjectTransform(rObjectTransform),
maGraphic(rGraphic),
mfCropLeft(fCropLeft),
mfCropTop(fCropTop),
mfCropRight(fCropRight),
mfCropBottom(fCropBottom)
{
}
namespace {
void translateRotationToMirroring(basegfx::B2DVector & scale, double * rotate) {
assert(rotate != nullptr);
// detect 180 degree rotation, this is the same as mirrored in X and Y,
// thus change to mirroring. Prefer mirroring here. Use the equal call
// with getSmallValue here, the original which uses rtl::math::approxEqual
// is too correct here. Maybe this changes with enhanced precision in aw080
// to the better so that this can be reduced to the more precise call again
if(basegfx::fTools::equal(fabs(*rotate), F_PI, 0.000000001))
{
scale.setX(scale.getX() * -1.0);
scale.setY(scale.getY() * -1.0);
*rotate = 0.0;
}
}
}
void SdrCropViewHdl::CreateB2dIAObject()
{
GetRidOfIAObject();
SdrMarkView* pView = pHdlList ? pHdlList->GetView() : nullptr;
SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
if(!pPageView || pView->areMarkHandlesHidden())
{
return;
}
// decompose to have current translate and scale
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
maObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
if(aScale.equalZero())
{
return;
}
translateRotationToMirroring(aScale, &fRotate);
// remember mirroring, reset at Scale and adapt crop values for usage;
// mirroring can stay in the object transformation, so do not have to
// cope with it here (except later for the CroppedImage transformation,
// see below)
const bool bMirroredX(aScale.getX() < 0.0);
const bool bMirroredY(aScale.getY() < 0.0);
double fCropLeft(mfCropLeft);
double fCropTop(mfCropTop);
double fCropRight(mfCropRight);
double fCropBottom(mfCropBottom);
if(bMirroredX)
{
aScale.setX(-aScale.getX());
}
if(bMirroredY)
{
aScale.setY(-aScale.getY());
}
// create target translate and scale
const basegfx::B2DVector aTargetScale(
aScale.getX() + fCropRight + fCropLeft,
aScale.getY() + fCropBottom + fCropTop);
const basegfx::B2DVector aTargetTranslate(
aTranslate.getX() - fCropLeft,
aTranslate.getY() - fCropTop);
// create ranges to make comparisons
const basegfx::B2DRange aCurrentForCompare(
aTranslate.getX(), aTranslate.getY(),
aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
basegfx::B2DRange aCropped(
aTargetTranslate.getX(), aTargetTranslate.getY(),
aTargetTranslate.getX() + aTargetScale.getX(), aTargetTranslate.getY() + aTargetScale.getY());
if(aCropped.isEmpty())
{
// nothing to return since cropped content is completely empty
return;
}
if(aCurrentForCompare.equal(aCropped))
{
// no crop at all
return;
}
// back-transform to have values in unit coordinates
basegfx::B2DHomMatrix aBackToUnit;
aBackToUnit.translate(-aTranslate.getX(), -aTranslate.getY());
aBackToUnit.scale(
basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
// transform cropped back to unit coordinates
aCropped.transform(aBackToUnit);
// prepare crop PolyPolygon
basegfx::B2DPolygon aGraphicOutlinePolygon(
basegfx::utils::createPolygonFromRect(
aCropped));
basegfx::B2DPolyPolygon aCropPolyPolygon(aGraphicOutlinePolygon);
// current range is unit range
basegfx::B2DRange aOverlap(0.0, 0.0, 1.0, 1.0);
aOverlap.intersect(aCropped);
if(!aOverlap.isEmpty())
{
aCropPolyPolygon.append(
basegfx::utils::createPolygonFromRect(
aOverlap));
}
// transform to object coordinates to prepare for clip
aCropPolyPolygon.transform(maObjectTransform);
aGraphicOutlinePolygon.transform(maObjectTransform);
// create cropped transformation
basegfx::B2DHomMatrix aCroppedTransform;
aCroppedTransform.scale(
aCropped.getWidth(),
aCropped.getHeight());
aCroppedTransform.translate(
aCropped.getMinX(),
aCropped.getMinY());
aCroppedTransform = maObjectTransform * aCroppedTransform;
// prepare graphic primitive (transformed)
const drawinglayer::primitive2d::Primitive2DReference aGraphic(
new drawinglayer::primitive2d::GraphicPrimitive2D(
aCroppedTransform,
maGraphic));
// prepare outline polygon for whole graphic
const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
const basegfx::BColor aHilightColor(aSvtOptionsDrawinglayer.getHilightColor().getBColor());
const drawinglayer::primitive2d::Primitive2DReference aGraphicOutline(
new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
aGraphicOutlinePolygon,
aHilightColor));
// combine these
drawinglayer::primitive2d::Primitive2DContainer aCombination(2);
aCombination[0] = aGraphic;
aCombination[1] = aGraphicOutline;
// embed to MaskPrimitive2D
const drawinglayer::primitive2d::Primitive2DReference aMaskedGraphic(
new drawinglayer::primitive2d::MaskPrimitive2D(
aCropPolyPolygon,
aCombination));
// embed to UnifiedTransparencePrimitive2D
const drawinglayer::primitive2d::Primitive2DReference aTransparenceMaskedGraphic(
new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
drawinglayer::primitive2d::Primitive2DContainer { aMaskedGraphic },
0.8));
const drawinglayer::primitive2d::Primitive2DContainer aSequence { aTransparenceMaskedGraphic };
for(sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
{
// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
const SdrPageWindow& rPageWindow = *(pPageView->GetPageWindow(b));
if(rPageWindow.GetPaintWindow().OutputToWindow())
{
rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
if(xManager.is())
{
std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(aSequence));
// only informative object, no hit
pNew->setHittable(false);
xManager->add(*pNew);
maOverlayGroup.append(std::move(pNew));
}
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'pNew' is always true.
↑ V668 There is no sense in testing the 'pOverlayObject' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error.