/**************************************************************
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#include <algorithm>

#include <svx/svdhdl.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdmrkv.hxx>
#include <vcl/window.hxx>

#include <vcl/virdev.hxx>
#include <tools/poly.hxx>
#include <vcl/bmpacc.hxx>

#include <svx/sxekitm.hxx>
#include "svx/svdstr.hrc"
#include "svx/svdglob.hxx"

#include <svx/svdmodel.hxx>
#include "gradtrns.hxx"
#include <svx/xflgrit.hxx>
#include <svx/svdundo.hxx>
#include <svx/dialmgr.hxx>
#include <svx/xflftrit.hxx>

// #105678#
#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 <svx/sdr/overlay/overlayline.hxx>
#include <svx/sdr/overlay/overlaytriangle.hxx>
#include <svx/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 <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>

////////////////////////////////////////////////////////////////////////////////////////////////////
// #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 the one big bitmap remembered. 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 infos
	BitmapEx					maMarkersBitmap;

	// the cropped Bitmaps for reusage
	::std::vector< BitmapEx >	maRealMarkers;

	// elpers
	BitmapEx& impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const Rectangle& rRectangle);

public:
	SdrHdlBitmapSet(sal_uInt16 nResId);
	~SdrHdlBitmapSet();

	const BitmapEx& GetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd=0);
};

////////////////////////////////////////////////////////////////////////////////////////////////////
#define KIND_COUNT			(14)
#define INDEX_COUNT			(6)
#define INDIVIDUAL_COUNT	(6)

SdrHdlBitmapSet::SdrHdlBitmapSet(sal_uInt16 nResId)
:	maMarkersBitmap(ResId(nResId, *ImpGetResMgr())), // just use resource with alpha channel
	// 14 kinds (BitmapMarkerKind) use index [0..5], 6 extra
	maRealMarkers((KIND_COUNT * INDEX_COUNT) + INDIVIDUAL_COUNT)
{
}

SdrHdlBitmapSet::~SdrHdlBitmapSet()
{
}

BitmapEx& SdrHdlBitmapSet::impGetOrCreateTargetBitmap(sal_uInt16 nIndex, const 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:
		{
			DBG_ERROR( "unknown kind of marker" );
			// no break here, return Rect_7x7 as default
		}
		case Rect_7x7:
		{
			return impGetOrCreateTargetBitmap((0 * INDEX_COUNT) + nInd, Rectangle(Point(0, nYPos), Size(7, 7)));
		}

		case Rect_9x9:
		{
			return impGetOrCreateTargetBitmap((1 * INDEX_COUNT) + nInd, Rectangle(Point(7, nYPos), Size(9, 9)));
		}

		case Rect_11x11:
		{
			return impGetOrCreateTargetBitmap((2 * INDEX_COUNT) + nInd, Rectangle(Point(16, nYPos), Size(11, 11)));
		}

		case Rect_13x13:
		{
			const sal_uInt16 nIndex((3 * INDEX_COUNT) + nInd);

			switch(nInd)
			{
				case 0:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(72, 66), Size(13, 13)));
				}
				case 1:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(85, 66), Size(13, 13)));
				}
				case 2:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(72, 79), Size(13, 13)));
				}
				case 3:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(85, 79), Size(13, 13)));
				}
				case 4:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(98, 79), Size(13, 13)));
				}
				default: // case 5:
				{
					return impGetOrCreateTargetBitmap(nIndex, Rectangle(Point(98, 66), Size(13, 13)));
				}
			}
		}

		case Circ_7x7:
		case Customshape_7x7:
		{
			return impGetOrCreateTargetBitmap((4 * INDEX_COUNT) + nInd, Rectangle(Point(27, nYPos), Size(7, 7)));
		}

		case Circ_9x9:
		case Customshape_9x9:
		{
			return impGetOrCreateTargetBitmap((5 * INDEX_COUNT) + nInd, Rectangle(Point(34, nYPos), Size(9, 9)));
		}

		case Circ_11x11:
		case Customshape_11x11:
		{
			return impGetOrCreateTargetBitmap((6 * INDEX_COUNT) + nInd, Rectangle(Point(43, nYPos), Size(11, 11)));
		}

		case Elli_7x9:
		{
			return impGetOrCreateTargetBitmap((7 * INDEX_COUNT) + nInd, Rectangle(Point(54, nYPos), Size(7, 9)));
		}

		case Elli_9x11:
		{
			return impGetOrCreateTargetBitmap((8 * INDEX_COUNT) + nInd, Rectangle(Point(61, nYPos), Size(9, 11)));
		}

		case Elli_9x7:
		{
			return impGetOrCreateTargetBitmap((9 * INDEX_COUNT) + nInd, Rectangle(Point(70, nYPos), Size(9, 7)));
		}

		case Elli_11x9:
		{
			return impGetOrCreateTargetBitmap((10 * INDEX_COUNT) + nInd, Rectangle(Point(79, nYPos), Size(11, 9)));
		}

		case RectPlus_7x7:
		{
			return impGetOrCreateTargetBitmap((11 * INDEX_COUNT) + nInd, Rectangle(Point(90, nYPos), Size(7, 7)));
		}

		case RectPlus_9x9:
		{
			return impGetOrCreateTargetBitmap((12 * INDEX_COUNT) + nInd, Rectangle(Point(97, nYPos), Size(9, 9)));
		}

		case RectPlus_11x11:
		{
			return impGetOrCreateTargetBitmap((13 * INDEX_COUNT) + nInd, Rectangle(Point(106, nYPos), Size(11, 11)));
		}

		case Crosshair:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 0, Rectangle(Point(0, 66), Size(13, 13)));
		}

		case Crosshair_Unselected:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 1, Rectangle(Point(0, 79), Size(13, 13)));
		}

		case Glue:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 2, Rectangle(Point(13, 70), Size(11, 11)));
		}

		case Glue_Unselected:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 3, Rectangle(Point(13, 81), Size(11, 11)));
		}

		case Anchor: // #101688# AnchorTR for SW
		case AnchorTR:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 4, Rectangle(Point(24, 68), Size(24, 24)));
		}

		// #98388# add AnchorPressed to be able to animate anchor control
		case AnchorPressed:
		case AnchorPressedTR:
		{
			return impGetOrCreateTargetBitmap((KIND_COUNT * INDEX_COUNT) + 5, Rectangle(Point(48, 68), Size(24, 24)));
		}
	}

	// cannot happen since all paths return something; return Rect_7x7 as default (see switch)
	return maRealMarkers[0];
}

////////////////////////////////////////////////////////////////////////////////////////////////////

SdrHdlBitmapSet& getSimpleSet()
{
	static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aSimpleSet(new SdrHdlBitmapSet(SIP_SA_MARKERS));
	return *aSimpleSet.get();
}

SdrHdlBitmapSet& getModernSet()
{
	static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aModernSet(new SdrHdlBitmapSet(SIP_SA_FINE_MARKERS));
	return *aModernSet.get();
}

SdrHdlBitmapSet& getHighContrastSet()
{
	static vcl::DeleteOnDeinit< SdrHdlBitmapSet > aHighContrastSet(new SdrHdlBitmapSet(SIP_SA_ACCESSIBILITY_MARKERS));
	return *aHighContrastSet.get();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

SdrHdl::SdrHdl():
	pObj(NULL),
	pPV(NULL),
	pHdlList(NULL),
	eKind(HDL_MOVE),
	nDrehWink(0),
	nObjHdlNum(0),
	nPolyNum(0),
	nPPntNum(0),
	nSourceHdlNum(0),
	bSelect(sal_False),
	b1PixMore(sal_False),
	bPlusHdl(sal_False),
	mbMoveOutside(false),
	mbMouseOver(false)
{
}

SdrHdl::SdrHdl(const Point& rPnt, SdrHdlKind eNewKind):
	pObj(NULL),
	pPV(NULL),
	pHdlList(NULL),
	aPos(rPnt),
	eKind(eNewKind),
	nDrehWink(0),
	nObjHdlNum(0),
	nPolyNum(0),
	nPPntNum(0),
	nSourceHdlNum(0),
	bSelect(sal_False),
	b1PixMore(sal_False),
	bPlusHdl(sal_False),
	mbMoveOutside(false),
	mbMouseOver(false)
{
}

SdrHdl::~SdrHdl()
{
	GetRidOfIAObject();
}

void SdrHdl::Set1PixMore(sal_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::SetDrehWink(long n)
{
	if(nDrehWink != n)
	{
		nDrehWink = 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(sal_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 it's 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()
{
	//OLMaIAOGroup.Delete();

	// OVERLAYMANAGER
	maOverlayGroup.clear();
}

void SdrHdl::CreateB2dIAObject()
{
	// first throw away old one
	GetRidOfIAObject();

	if(pHdlList && pHdlList->GetView() && !pHdlList->GetView()->areMarkHandlesHidden())
	{
		BitmapColorIndex eColIndex = LightGreen;
		BitmapMarkerKind eKindOfMarker = Rect_7x7;

		sal_Bool bRot = pHdlList->IsRotateShear();
		if(pObj)
			eColIndex = (bSelect) ? Cyan : LightCyan;
		if(bRot)
		{
			// Rotation handles in red
			if(pObj && bSelect)
				eColIndex = Red;
			else
				eColIndex = LightRed;
		}

		switch(eKind)
		{
			case HDL_MOVE:
			{
				eKindOfMarker = (b1PixMore) ? Rect_9x9 : Rect_7x7;
				break;
			}
			case HDL_UPLFT:
			case HDL_UPRGT:
			case HDL_LWLFT:
			case HDL_LWRGT:
			{
				// Corner handles
				if(bRot)
				{
					eKindOfMarker = Circ_7x7;
				}
				else
				{
					eKindOfMarker = Rect_7x7;
				}
				break;
			}
			case HDL_UPPER:
			case HDL_LOWER:
			{
				// Upper/Lower handles
				if(bRot)
				{
					eKindOfMarker = Elli_9x7;
				}
				else
				{
					eKindOfMarker = Rect_7x7;
				}
				break;
			}
			case HDL_LEFT:
			case HDL_RIGHT:
			{
				// Left/Right handles
				if(bRot)
				{
					eKindOfMarker = Elli_7x9;
				}
				else
				{
					eKindOfMarker = Rect_7x7;
				}
				break;
			}
			case HDL_POLY:
			{
				if(bRot)
				{
					eKindOfMarker = (b1PixMore) ? Circ_9x9 : Circ_7x7;
				}
				else
				{
					eKindOfMarker = (b1PixMore) ? Rect_9x9 : Rect_7x7;
				}
				break;
			}
			case HDL_BWGT: // weight at poly
			{
				eKindOfMarker = Circ_7x7;
				break;
			}
			case HDL_CIRC:
			{
				eKindOfMarker = Rect_11x11;
				break;
			}
			case HDL_REF1:
			case HDL_REF2:
			{
				eKindOfMarker = Crosshair;
				break;
			}
			{
				eKindOfMarker = Crosshair_Unselected;
				break;
			}
			case HDL_GLUE:
			{
				eKindOfMarker = Glue;
				break;
			}
			case HDL_GLUE_UNSEL:
			{
				eKindOfMarker = Glue_Unselected;
				break;
			}
			case HDL_ANCHOR:
			{
				eKindOfMarker = Anchor;
				break;
			}
			case HDL_USER:
			{
				break;
			}
			// #101688# top right anchor for SW
			case HDL_ANCHOR_TR:
			{
				eKindOfMarker = AnchorTR;
				break;
			}

			// for SJ and the CustomShapeHandles:
			case HDL_CUSTOMSHAPE1:
			{
				eKindOfMarker = (b1PixMore) ? Customshape_9x9 : Customshape_7x7;
				eColIndex = Yellow;
				break;
			}
			default:
				break;
		}

		SdrMarkView* pView = pHdlList->GetView();
		SdrPageView* pPageView = pView->GetSdrPageView();

		if(pPageView)
		{
			for(sal_uInt32 b(0L); b < pPageView->PageWindowCount(); b++)
			{
				// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
				const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

				if(rPageWindow.GetPaintWindow().OutputToWindow())
				{
					Point aMoveOutsideOffset(0, 0);

					// add offset if necessary
					if(pHdlList->IsMoveOutside() || mbMoveOutside)
					{
						OutputDevice& rOutDev = rPageWindow.GetPaintWindow().GetOutputDevice();
						Size aOffset = rOutDev.PixelToLogic(Size(4, 4));

						if(eKind == HDL_UPLFT || eKind == HDL_UPPER || eKind == HDL_UPRGT)
							aMoveOutsideOffset.Y() -= aOffset.Width();
						if(eKind == HDL_LWLFT || eKind == HDL_LOWER || eKind == HDL_LWRGT)
							aMoveOutsideOffset.Y() += aOffset.Height();
						if(eKind == HDL_UPLFT || eKind == HDL_LEFT  || eKind == HDL_LWLFT)
							aMoveOutsideOffset.X() -= aOffset.Width();
						if(eKind == HDL_UPRGT || eKind == HDL_RIGHT || eKind == HDL_LWRGT)
							aMoveOutsideOffset.X() += aOffset.Height();
					}

					if(rPageWindow.GetOverlayManager())
					{
						basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
						::sdr::overlay::OverlayObject* pNewOverlayObject = CreateOverlayObject(
							aPosition,
							eColIndex,
							eKindOfMarker,
							aMoveOutsideOffset);

						// OVERLAYMANAGER
						if(pNewOverlayObject)
						{
							rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
							maOverlayGroup.append(*pNewOverlayObject);
						}
					}
				}
			}
		}
	}
}

BitmapMarkerKind SdrHdl::GetNextBigger(BitmapMarkerKind eKnd) const
{
	BitmapMarkerKind eRetval(eKnd);

	switch(eKnd)
	{
		case Rect_7x7:			eRetval = Rect_9x9;			break;
		case Rect_9x9:			eRetval = Rect_11x11;		break;
		case Rect_11x11:		eRetval = Rect_13x13;		break;
		//case Rect_13x13:		eRetval = ;	break;

		case Circ_7x7:			eRetval = Circ_9x9;			break;
		case Circ_9x9:			eRetval = Circ_11x11;		break;
		//case Circ_11x11:		eRetval = ;	break;

		case Customshape_7x7:		eRetval = Customshape_9x9;		break;
		case Customshape_9x9:		eRetval = Customshape_11x11;	break;
		//case Customshape_11x11:	eRetval = ;	break;

		case Elli_7x9:			eRetval = Elli_9x11;		break;
		//case Elli_9x11:			eRetval = ;	break;

		case Elli_9x7:			eRetval = Elli_11x9;		break;
		//case Elli_11x9:			eRetval = ;	break;

		case RectPlus_7x7:		eRetval = RectPlus_9x9;		break;
		case RectPlus_9x9:		eRetval = RectPlus_11x11;	break;
		//case RectPlus_11x11:	eRetval = ;	break;

		//case Crosshair:			eRetval = ;	break;
		//case Glue:				eRetval = ;	break;

		// #98388# let anchor blink with its pressed state
		case Anchor:			eRetval = AnchorPressed;	break;

		// #101688# same for AnchorTR
		case AnchorTR:			eRetval = AnchorPressedTR;	break;
		default:
			break;
	}

	return eRetval;
}

// #101928#
BitmapEx SdrHdl::ImpGetBitmapEx(BitmapMarkerKind eKindOfMarker, sal_uInt16 nInd, sal_Bool bFine, sal_Bool bIsHighContrast)
{
	if(bIsHighContrast)
	{
		return getHighContrastSet().GetBitmapEx(eKindOfMarker, nInd);
	}
	else
	{
		if(bFine)
		{
			return getModernSet().GetBitmapEx(eKindOfMarker, nInd);
		}
		else
		{
			return getSimpleSet().GetBitmapEx(eKindOfMarker, nInd);
		}
	}
}

::sdr::overlay::OverlayObject* SdrHdl::CreateOverlayObject(
	const basegfx::B2DPoint& rPos,
	BitmapColorIndex eColIndex, BitmapMarkerKind eKindOfMarker, Point aMoveOutsideOffset)
{
	::sdr::overlay::OverlayObject* pRetval = 0L;
	sal_Bool bIsFineHdl(pHdlList->IsFineHdl());
	const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
	sal_Bool bIsHighContrast(rStyleSettings.GetHighContrastMode());

	// support bigger sizes
	sal_Bool bForceBiggerSize(sal_False);

	if(pHdlList->GetHdlSize() > 3)
	{
		switch(eKindOfMarker)
		{
			case Anchor:
			case AnchorPressed:
			case AnchorTR:
			case AnchorPressedTR:
			{
				// #121463# 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 = sal_True;
				}
				break;
			}
			default:
			{
				bForceBiggerSize = sal_True;
				break;
			}
		}
	}

	// #101928# ...for high contrast, too.
	if(!bForceBiggerSize && bIsHighContrast)
	{
		// #107925#
		// ...but not for anchors, else they will not blink when activated
		if(Anchor != eKindOfMarker && AnchorTR != eKindOfMarker)
		{
			bForceBiggerSize = sal_True;
		}
	}

	if(bForceBiggerSize)
	{
		eKindOfMarker = GetNextBigger(eKindOfMarker);
	}

	// #97016# II 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 Rect_13x13:		eNextBigger = Rect_11x11;	break;
				case Circ_11x11:		eNextBigger = Elli_11x9;	break;
				case Elli_9x11:			eNextBigger = Elli_11x9;	break;
				case Elli_11x9:			eNextBigger = Elli_9x11;	break;
				case RectPlus_11x11:	eNextBigger = Rect_13x13;	break;

				case Crosshair:
					eNextBigger = Crosshair_Unselected;
					break;

				case Glue:
					eNextBigger = Glue_Unselected;
					break;
				default:
					break;
			}
		}

		// create animated hdl
		// #101928# use ImpGetBitmapEx(...) now
		BitmapEx aBmpEx1 = ImpGetBitmapEx(eKindOfMarker, (sal_uInt16)eColIndex, bIsFineHdl, bIsHighContrast);
		BitmapEx aBmpEx2 = ImpGetBitmapEx(eNextBigger, (sal_uInt16)eColIndex, bIsFineHdl, bIsHighContrast);

		// #i53216# Use system cursor blink time. Use the unsigned value.
		const sal_uInt32 nBlinkTime((sal_uInt32)Application::GetSettings().GetStyleSettings().GetCursorBlinkTime());

		if(eKindOfMarker == Anchor || eKindOfMarker == AnchorPressed)
		{
			// #98388# when anchor is used take upper left as reference point inside the handle
			pRetval = new ::sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime);
		}
		else if(eKindOfMarker == AnchorTR || eKindOfMarker == AnchorPressedTR)
		{
			// #101688# AnchorTR for SW, take top right as (0,0)
			pRetval = new ::sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
				(sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1), 0,
				(sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1), 0);
		}
		else
		{
			// create centered handle as default
			pRetval = new ::sdr::overlay::OverlayAnimatedBitmapEx(rPos, aBmpEx1, aBmpEx2, nBlinkTime,
				(sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
				(sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
				(sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
				(sal_uInt16)(aBmpEx2.GetSizePixel().Height() - 1) >> 1);
		}
	}
	else
	{
		// create normal handle
		// #101928# use ImpGetBitmapEx(...) now
		BitmapEx aBmpEx = ImpGetBitmapEx(eKindOfMarker, (sal_uInt16)eColIndex, bIsFineHdl, bIsHighContrast);

		if(eKindOfMarker == Anchor || eKindOfMarker == AnchorPressed)
		{
			// #98388# upper left as reference point inside the handle for AnchorPressed, too
			pRetval = new ::sdr::overlay::OverlayBitmapEx(rPos, aBmpEx);
		}
		else if(eKindOfMarker == AnchorTR || eKindOfMarker == AnchorPressedTR)
		{
			// #101688# AnchorTR for SW, take top right as (0,0)
			pRetval = new ::sdr::overlay::OverlayBitmapEx(rPos, aBmpEx,
				(sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1), 0);
		}
		else
		{
			sal_uInt16 nCenX((sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1L) >> 1);
			sal_uInt16 nCenY((sal_uInt16)(aBmpEx.GetSizePixel().Height() - 1L) >> 1);

			if(aMoveOutsideOffset.X() > 0)
			{
				nCenX = 0;
			}
			else if(aMoveOutsideOffset.X() < 0)
			{
				nCenX = (sal_uInt16)(aBmpEx.GetSizePixel().Width() - 1);
			}

			if(aMoveOutsideOffset.Y() > 0)
			{
				nCenY = 0;
			}
			else if(aMoveOutsideOffset.Y() < 0)
			{
				nCenY = (sal_uInt16)(aBmpEx.GetSizePixel().Height() - 1);
			}

			// create centered handle as default
			pRetval = 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=POINTER_MOVE;
	const sal_Bool bSize=eKind>=HDL_UPLFT && eKind<=HDL_LWRGT;
	const sal_Bool bRot=pHdlList!=NULL && pHdlList->IsRotateShear();
	const sal_Bool bDis=pHdlList!=NULL && pHdlList->IsDistortShear();
	if (bSize && pHdlList!=NULL && (bRot || bDis)) {
		switch (eKind) {
			case HDL_UPLFT: case HDL_UPRGT:
			case HDL_LWLFT: case HDL_LWRGT: ePtr=bRot ? POINTER_ROTATE : POINTER_REFHAND; break;
			case HDL_LEFT : case HDL_RIGHT: ePtr=POINTER_VSHEAR; break;
			case HDL_UPPER: case HDL_LOWER: ePtr=POINTER_HSHEAR; break;
			default:
				break;
		}
	} else {
		// Fuer Resize von gedrehten Rechtecken die Mauszeiger etwas mitdrehen
		if (bSize && nDrehWink!=0) {
			long nHdlWink=0;
			switch (eKind) {
				case HDL_LWRGT: nHdlWink=31500;	break;
				case HDL_LOWER: nHdlWink=27000;	break;
				case HDL_LWLFT: nHdlWink=22500;	break;
				case HDL_LEFT : nHdlWink=18000;	break;
				case HDL_UPLFT: nHdlWink=13500;	break;
				case HDL_UPPER: nHdlWink=9000;	break;
				case HDL_UPRGT: nHdlWink=4500;	break;
				case HDL_RIGHT: nHdlWink=0;		break;
				default:
					break;
			}
			nHdlWink+=nDrehWink+2249; // und etwas drauf (zum runden)
			while (nHdlWink<0) nHdlWink+=36000;
			while (nHdlWink>=36000) nHdlWink-=36000;
			nHdlWink/=4500;
			switch ((sal_uInt8)nHdlWink) {
				case 0: ePtr=POINTER_ESIZE;		break;
				case 1: ePtr=POINTER_NESIZE;	break;
				case 2: ePtr=POINTER_NSIZE;		break;
				case 3: ePtr=POINTER_NWSIZE;	break;
				case 4: ePtr=POINTER_WSIZE;		break;
				case 5: ePtr=POINTER_SWSIZE;	break;
				case 6: ePtr=POINTER_SSIZE;		break;
				case 7: ePtr=POINTER_SESIZE;	break;
			} // switch
		} else {
			switch (eKind) {
				case HDL_UPLFT: ePtr=POINTER_NWSIZE;	break;
				case HDL_UPPER: ePtr=POINTER_NSIZE;		break;
				case HDL_UPRGT: ePtr=POINTER_NESIZE;	break;
				case HDL_LEFT : ePtr=POINTER_WSIZE;		break;
				case HDL_RIGHT: ePtr=POINTER_ESIZE;		break;
				case HDL_LWLFT: ePtr=POINTER_SWSIZE;	break;
				case HDL_LOWER: ePtr=POINTER_SSIZE;		break;
				case HDL_LWRGT: ePtr=POINTER_SESIZE;	break;
				case HDL_POLY : ePtr=POINTER_MOVEPOINT;	break;
				case HDL_CIRC : ePtr=POINTER_HAND;		break;
				case HDL_REF1 : ePtr=POINTER_REFHAND;	break;
				case HDL_REF2 : ePtr=POINTER_REFHAND;	break;
				case HDL_BWGT : ePtr=POINTER_MOVEBEZIERWEIGHT;	break;
				case HDL_GLUE : ePtr=POINTER_MOVEPOINT;	break;
				case HDL_GLUE_UNSEL : ePtr=POINTER_MOVEPOINT;	break;
				case HDL_CUSTOMSHAPE1 : ePtr=POINTER_HAND;	break;
				default:
					break;
			}
		}
	}
	return Pointer(ePtr);
}

// #97016# II
sal_Bool SdrHdl::IsFocusHdl() const
{
	switch(eKind)
	{
		case HDL_UPLFT:		// top left
		case HDL_UPPER:		// top
		case HDL_UPRGT:		// top right
		case HDL_LEFT:		// left
		case HDL_RIGHT:		// right
		case HDL_LWLFT:		// bottom left
		case HDL_LOWER:		// bottom
		case HDL_LWRGT:		// bottom right
		{
			// if it's an activated TextEdit, it's moved to extended points
			if(pHdlList && pHdlList->IsMoveOutside())
				return sal_False;
			else
				return sal_True;
		}

		case HDL_MOVE:		// Handle zum Verschieben des Objekts
		case HDL_POLY:		// Punktselektion an Polygon oder Bezierkurve
		case HDL_BWGT:		// Gewicht an einer Bezierkurve
		case HDL_CIRC:		// Winkel an Kreissegmenten, Eckenradius am Rect
		case HDL_REF1:		// Referenzpunkt 1, z.B. Rotationsmitte
		case HDL_REF2:		// Referenzpunkt 2, z.B. Endpunkt der Spiegelachse
		//case HDL_MIRX:		// Die Spiegelachse selbst
		case HDL_GLUE:		// glue point
		case HDL_GLUE_UNSEL: // glue point unselected

		// #98388# do NOT activate here, let SW implement their own SdrHdl and
		// overload IsFocusHdl() there to make the anchor accessible
		//case HDL_ANCHOR:		// anchor symbol (SD, SW)
		// #101688# same for AnchorTR
		//case HDL_ANCHOR_TR:	// anchor symbol (SD, SW)

		//case HDL_TRNS:		// interactive transparency
		//case HDL_GRAD:		// interactive gradient
		//case HDL_COLR:		// interactive color

		// for SJ and the CustomShapeHandles:
		case HDL_CUSTOMSHAPE1:

		case HDL_USER:
		{
			return sal_True;
		}

		default:
		{
			return sal_False;
		}
	}
}

void SdrHdl::onMouseEnter(const MouseEvent& /*rMEvt*/)
{
}

void SdrHdl::onMouseLeave()
{
}

bool SdrHdl::isMouseOver() const
{
	return mbMouseOver;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// class SdrHdlColor

SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, sal_Bool bLum)
:	SdrHdl(rRef, HDL_COLR),
	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(0L); b < pPageView->PageWindowCount(); b++)
				{
					// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							Bitmap aBmpCol(CreateColorDropper(aMarkerColor));
							basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());
							::sdr::overlay::OverlayObject* pNewOverlayObject = new
								::sdr::overlay::OverlayBitmapEx(
									aPosition,
									BitmapEx(aBmpCol),
									(sal_uInt16)(aBmpCol.GetSizePixel().Width() - 1) >> 1,
									(sal_uInt16)(aBmpCol.GetSizePixel().Height() - 1) >> 1
								);
							DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

							// OVERLAYMANAGER
							if(pNewOverlayObject)
							{
								rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
								maOverlayGroup.append(*pNewOverlayObject);
							}
						}
					}
				}
			}
		}
	}
}

Bitmap SdrHdlColor::CreateColorDropper(Color aCol)
{
	// get the Bitmap
	Bitmap aRetval(aMarkerSize, 24);
	aRetval.Erase(aCol);

	// get write access
	BitmapWriteAccess* pWrite = aRetval.AcquireWriteAccess();
	DBG_ASSERT(pWrite, "Got NO write access to a new Bitmap !!!");

	if(pWrite)
	{
		// draw outer border
		sal_Int32 nWidth = aMarkerSize.Width();
		sal_Int32 nHeight = aMarkerSize.Height();

		pWrite->SetLineColor(Color(COL_LIGHTGRAY));
		pWrite->DrawLine(Point(0, 0), Point(0, nHeight - 1));
		pWrite->DrawLine(Point(1, 0), Point(nWidth - 1, 0));
		pWrite->SetLineColor(Color(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(
			(sal_uInt8)(::std::min((sal_Int16)((sal_Int16)aCol.GetRed() + (sal_Int16)0x0040), (sal_Int16)0x00ff)),
			(sal_uInt8)(::std::min((sal_Int16)((sal_Int16)aCol.GetGreen() + (sal_Int16)0x0040), (sal_Int16)0x00ff)),
			(sal_uInt8)(::std::min((sal_Int16)((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(
			(sal_uInt8)(::std::max((sal_Int16)((sal_Int16)aCol.GetRed() - (sal_Int16)0x0040), (sal_Int16)0x0000)),
			(sal_uInt8)(::std::max((sal_Int16)((sal_Int16)aCol.GetGreen() - (sal_Int16)0x0040), (sal_Int16)0x0000)),
			(sal_uInt8)(::std::max((sal_Int16)((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));

		// get rid of write access
		delete pWrite;
	}

	return aRetval;
}

Color SdrHdlColor::GetLuminance(const Color& rCol)
{
	sal_uInt8 aLum = rCol.GetLuminance();
	Color aRetval(aLum, aLum, aLum);
	return aRetval;
}

void SdrHdlColor::CallColorChangeLink()
{
	aColorChangeHdl.Call(this);
}

void SdrHdlColor::SetColor(Color aNew, sal_Bool bCallLink)
{
	if(IsUseLuminance())
		aNew = GetLuminance(aNew);

	if(aMarkerColor != aNew)
	{
		// remember new color
		aMarkerColor = aNew;

		// create new display
		Touch();

		// tell about change
		if(bCallLink)
			CallColorChangeLink();
	}
}

void SdrHdlColor::SetSize(const Size& rNew)
{
	if(rNew != aMarkerSize)
	{
		// remember new size
		aMarkerSize = rNew;

		// create new display
		Touch();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// class SdrHdlGradient

SdrHdlGradient::SdrHdlGradient(const Point& rRef1, const Point& rRef2, sal_Bool bGrad)
:	SdrHdl(rRef1, bGrad ? HDL_GRAD : HDL_TRNS),
	pColHdl1(NULL),
	pColHdl2(NULL),
	a2ndPos(rRef2),
	bGradient(bGrad)
{
}

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(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							// 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 = (sal_Int32)(aPos.X() + aVec.getX() * fLongPercentArrow);
							sal_Int32 nMidY = (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());

							::sdr::overlay::OverlayObject* pNewOverlayObject = new
								::sdr::overlay::OverlayLineStriped(
									aPosition, aMidPos
								);
							DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

							pNewOverlayObject->setBaseColor(IsGradient() ? Color(COL_BLACK) : Color(COL_BLUE));
							rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
							maOverlayGroup.append(*pNewOverlayObject);

							// arrowhead
							Point aLeft(aMidPoint.X() + (sal_Int32)(aPerpend.getX() * fHalfArrowWidth),
										aMidPoint.Y() + (sal_Int32)(aPerpend.getY() * fHalfArrowWidth));
							Point aRight(aMidPoint.X() - (sal_Int32)(aPerpend.getX() * fHalfArrowWidth),
										aMidPoint.Y() - (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 = new
								::sdr::overlay::OverlayTriangle(
									aPositionLeft,
									aPosition2,
									aPositionRight,
									IsGradient() ? Color(COL_BLACK) : Color(COL_BLUE)
								);
							DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

							rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
							maOverlayGroup.append(*pNewOverlayObject);
						}
					}
				}
			}
		}
	}
}

IMPL_LINK(SdrHdlGradient, ColorChangeHdl, SdrHdl*, /*pHdl*/)
{
	if(GetObj())
		FromIAOToItem(GetObj(), sal_True, sal_True);
	return 0;
}

void SdrHdlGradient::FromIAOToItem(SdrObject* _pObj, sal_Bool bSetItemOnObject, sal_Bool bUndo)
{
	// from IAO positions and colors to gradient
	const SfxItemSet& rSet = _pObj->GetMergedItemSet();

	GradTransformer aGradTransformer;
	GradTransGradient aOldGradTransGradient;
	GradTransGradient aGradTransGradient;
	GradTransVector aGradTransVector;

	String 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 = ((XFillGradientItem&)rSet.Get(XATTR_FILLGRADIENT)).GetGradientValue();
	else
		aOldGradTransGradient.aGradient = ((XFillFloatTransparenceItem&)rSet.Get(XATTR_FILLFLOATTRANSPARENCE)).GetGradientValue();

	// transform vector data to gradient
	aGradTransformer.VecToGrad(aGradTransVector, aGradTransGradient, aOldGradTransGradient, _pObj, bMoveSingleHandle, bMoveFirstHandle);

	if(bSetItemOnObject)
	{
		SdrModel* pModel = _pObj->GetModel();
		SfxItemSet aNewSet(pModel->GetItemPool());

		if(IsGradient())
		{
			aString = String();
			XFillGradientItem aNewGradItem(aString, aGradTransGradient.aGradient);
			aNewSet.Put(aNewGradItem);
		}
		else
		{
			aString = String();
			XFillFloatTransparenceItem aNewTransItem(aString, aGradTransGradient.aGradient);
			aNewSet.Put(aNewTransItem);
		}

		if(bUndo && pModel->IsUndoEnabled())
		{
			pModel->BegUndo(SVX_RESSTR(IsGradient() ? SIP_XA_FILLGRADIENT : SIP_XA_FILLTRANSPARENCE));
			pModel->AddUndo(pModel->GetSdrUndoFactory().CreateUndoAttrObject(*_pObj));
			pModel->EndUndo();
		}

		pObj->SetMergedItemSetAndBroadcast(aNewSet);
	}

	// back transformation, set values on pIAOHandle
	aGradTransformer.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(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
							basegfx::B2DPoint aPosition2(pHdl2->GetPos().X(), pHdl2->GetPos().Y());

							::sdr::overlay::OverlayObject* pNewOverlayObject = new
								::sdr::overlay::OverlayLineStriped(
									aPosition1,
									aPosition2
								);
							DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

							// OVERLAYMANAGER
							if(pNewOverlayObject)
							{
								// color(?)
								pNewOverlayObject->setBaseColor(Color(COL_LIGHTRED));

								rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
								maOverlayGroup.append(*pNewOverlayObject);
							}
						}
					}
				}
			}
		}
	}
}

Pointer SdrHdlLine::GetPointer() const
{
	return Pointer(POINTER_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(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							basegfx::B2DPoint aPosition1(pHdl1->GetPos().X(), pHdl1->GetPos().Y());
							basegfx::B2DPoint aPosition2(aPos.X(), aPos.Y());

							if(!aPosition1.equal(aPosition2))
							{
								::sdr::overlay::OverlayObject* pNewOverlayObject = new
									::sdr::overlay::OverlayLineStriped(
										aPosition1,
										aPosition2
									);
								DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

								// OVERLAYMANAGER
								if(pNewOverlayObject)
								{
									// line part is not hittable
									pNewOverlayObject->setHittable(sal_False);

									// color(?)
									pNewOverlayObject->setBaseColor(Color(COL_LIGHTBLUE));

									rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
									maOverlayGroup.append(*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(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager() && aWireframePoly.count())
							{
								::sdr::overlay::OverlayObject* pNewOverlayObject = new
								::sdr::overlay::OverlayPolyPolygonStripedAndFilled(
									aWireframePoly);
								DBG_ASSERT(pNewOverlayObject, "Got NO new IAO!");

								// OVERLAYMANAGER
								if(pNewOverlayObject)
								{
									pNewOverlayObject->setBaseColor(Color(COL_BLACK));

									rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
									maOverlayGroup.append(*pNewOverlayObject);
								}
							}
						}
					}
				}
			}
		}
	}

////////////////////////////////////////////////////////////////////////////////////////////////////

ImpEdgeHdl::~ImpEdgeHdl()
{
}

void ImpEdgeHdl::CreateB2dIAObject()
{
	if(nObjHdlNum <= 1 && pObj)
	{
		// first throw away old one
		GetRidOfIAObject();

		BitmapColorIndex eColIndex = LightCyan;
		BitmapMarkerKind eKindOfMarker = Rect_7x7;

		if(pHdlList)
		{
			SdrMarkView* pView = pHdlList->GetView();

			if(pView && !pView->areMarkHandlesHidden())
			{
				const SdrEdgeObj* pEdge = (SdrEdgeObj*)pObj;

				if(pEdge->GetConnectedNode(nObjHdlNum == 0) != NULL)
					eColIndex = LightRed;

				if(nPPntNum < 2)
				{
					// Handle with plus sign inside
					eKindOfMarker = 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())
						{
							if(rPageWindow.GetOverlayManager())
							{
								basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());

								::sdr::overlay::OverlayObject* pNewOverlayObject = CreateOverlayObject(
									aPosition,
									eColIndex,
									eKindOfMarker);

								// OVERLAYMANAGER
								if(pNewOverlayObject)
								{
									rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
									maOverlayGroup.append(*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=PTR_CAST(SdrEdgeObj,pObj);
	if (pEdge==NULL)
		return SdrHdl::GetPointer();
	if (nObjHdlNum<=1)
		return Pointer(POINTER_MOVEPOINT); //Pointer(POINTER_DRAW_CONNECT);
	if (IsHorzDrag())
		return Pointer(POINTER_ESIZE);
	else
		return Pointer(POINTER_SSIZE);
}

sal_Bool ImpEdgeHdl::IsHorzDrag() const
{
	SdrEdgeObj* pEdge=PTR_CAST(SdrEdgeObj,pObj);
	if (pEdge==NULL)
		return sal_False;
	if (nObjHdlNum<=1)
		return sal_False;

	SdrEdgeKind eEdgeKind = ((SdrEdgeKindItem&)(pEdge->GetObjectItem(SDRATTR_EDGEKIND))).GetValue();

	const SdrEdgeInfoRec& rInfo=pEdge->aEdgeInfo;
	if (eEdgeKind==SDREDGE_ORTHOLINES || eEdgeKind==SDREDGE_BEZIER)
	{
		return !rInfo.ImpIsHorzLine(eLineCode,*pEdge->pEdgeTrack);
	}
	else if (eEdgeKind==SDREDGE_THREELINES)
	{
		long nWink=nObjHdlNum==2 ? rInfo.nAngle1 : rInfo.nAngle2;
		if (nWink==0 || nWink==18000)
			return sal_True;
		else
			return sal_False;
	}
	return sal_False;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

ImpMeasureHdl::~ImpMeasureHdl()
{
}

void ImpMeasureHdl::CreateB2dIAObject()
{
	// first throw away old one
	GetRidOfIAObject();

	if(pHdlList)
	{
		SdrMarkView* pView = pHdlList->GetView();

		if(pView && !pView->areMarkHandlesHidden())
		{
			BitmapColorIndex eColIndex = LightCyan;
			BitmapMarkerKind eKindOfMarker = Rect_9x9;

			if(nObjHdlNum > 1)
			{
				eKindOfMarker = Rect_7x7;
			}

			if(bSelect)
			{
				eColIndex = Cyan;
			}

			SdrPageView* pPageView = pView->GetSdrPageView();

			if(pPageView)
			{
				for(sal_uInt32 b(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());

							::sdr::overlay::OverlayObject* pNewOverlayObject = CreateOverlayObject(
								aPosition,
								eColIndex,
								eKindOfMarker);

							// OVERLAYMANAGER
							if(pNewOverlayObject)
							{
								rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
								maOverlayGroup.append(*pNewOverlayObject);
							}
						}
					}
				}
			}
		}
	}
}

Pointer ImpMeasureHdl::GetPointer() const
{
	switch (nObjHdlNum)
	{
		case 0: case 1: return Pointer(POINTER_HAND);
		case 2: case 3: return Pointer(POINTER_MOVEPOINT);
		case 4: case 5: return SdrHdl::GetPointer(); // will be rotated accordingly
	} // switch
	return Pointer(POINTER_NOTALLOWED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

ImpTextframeHdl::ImpTextframeHdl(const Rectangle& rRect) :
	SdrHdl(rRect.TopLeft(),HDL_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(0L); b < pPageView->PageWindowCount(); b++)
				{
					const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

					if(rPageWindow.GetPaintWindow().OutputToWindow())
					{
						if(rPageWindow.GetOverlayManager())
						{
							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);

							::sdr::overlay::OverlayRectangle* pNewOverlayObject = new ::sdr::overlay::OverlayRectangle(
								aTopLeft,
								aBottomRight,
								aHilightColor,
								fTransparence,
								3.0,
								3.0,
								nDrehWink * -F_PI18000,
								500,
								true); // allow animation; the Handle is not shown at text edit time

							pNewOverlayObject->setHittable(false);

							// OVERLAYMANAGER
							if(pNewOverlayObject)
							{
								rPageWindow.GetOverlayManager()->add(*pNewOverlayObject);
								maOverlayGroup.append(*pNewOverlayObject);
							}
						}
					}
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

class ImpSdrHdlListSorter: public ContainerSorter {
public:
	ImpSdrHdlListSorter(Container& rNewCont): ContainerSorter(rNewCont) {}
	virtual int Compare(const void* pElem1, const void* pElem2) const;
};

int ImpSdrHdlListSorter::Compare(const void* pElem1, const void* pElem2) const
{
	SdrHdlKind eKind1=((SdrHdl*)pElem1)->GetKind();
	SdrHdlKind eKind2=((SdrHdl*)pElem2)->GetKind();
	// Level 1: Erst normale Handles, dann Glue, dann User, dann Plushandles, dann Retpunkt-Handles
	unsigned n1=1;
	unsigned n2=1;
	if (eKind1!=eKind2)
	{
		if (eKind1==HDL_REF1 || eKind1==HDL_REF2 || eKind1==HDL_MIRX) n1=5;
		else if (eKind1==HDL_GLUE || eKind1==HDL_GLUE_UNSEL) n1=2;
		else if (eKind1==HDL_USER) n1=3;
		else if (eKind1==HDL_SMARTTAG) n1=0;
		if (eKind2==HDL_REF1 || eKind2==HDL_REF2 || eKind2==HDL_MIRX) n2=5;
		else if (eKind2==HDL_GLUE || eKind1==HDL_GLUE_UNSEL) n2=2;
		else if (eKind2==HDL_USER) n2=3;
		else if (eKind2==HDL_SMARTTAG) n2=0;
	}
	if (((SdrHdl*)pElem1)->IsPlusHdl()) n1=4;
	if (((SdrHdl*)pElem2)->IsPlusHdl()) n2=4;
	if (n1==n2)
	{
		// Level 2: PageView (Pointer)
		SdrPageView* pPV1=((SdrHdl*)pElem1)->GetPageView();
		SdrPageView* pPV2=((SdrHdl*)pElem2)->GetPageView();
		if (pPV1==pPV2)
		{
			// Level 3: Position (x+y)
			SdrObject* pObj1=((SdrHdl*)pElem1)->GetObj();
			SdrObject* pObj2=((SdrHdl*)pElem2)->GetObj();
			if (pObj1==pObj2)
			{
				sal_uInt32 nNum1=((SdrHdl*)pElem1)->GetObjHdlNum();
				sal_uInt32 nNum2=((SdrHdl*)pElem2)->GetObjHdlNum();
				if (nNum1==nNum2)
				{ // #48763#
					if (eKind1==eKind2)
						return (long)pElem1<(long)pElem2 ? -1 : 1; // Notloesung, um immer die gleiche Sortierung zu haben
					return (sal_uInt16)eKind1<(sal_uInt16)eKind2 ? -1 : 1;
				}
				else
					return nNum1<nNum2 ? -1 : 1;
			}
			else
			{
				return (long)pObj1<(long)pObj2 ? -1 : 1;
			}
		}
		else
		{
			return (long)pPV1<(long)pPV2 ? -1 : 1;
		}
	}
	else
	{
		return n1<n2 ? -1 : 1;
	}
}

SdrMarkView* SdrHdlList::GetView() const
{
	return pView;
}

// #105678# Help struct for re-sorting handles
struct ImplHdlAndIndex
{
	SdrHdl*						mpHdl;
	sal_uInt32					mnIndex;
};

// #105678# Help method for sorting handles taking care of OrdNums, keeping order in
// single objects and re-sorting polygon handles intuitively
extern "C" int __LOADONCALLAPI ImplSortHdlFunc( const void* pVoid1, const void* pVoid2 )
{
	const ImplHdlAndIndex* p1 = (ImplHdlAndIndex*)pVoid1;
	const ImplHdlAndIndex* p2 = (ImplHdlAndIndex*)pVoid2;

	if(p1->mpHdl->GetObj() == p2->mpHdl->GetObj())
	{
		if(p1->mpHdl->GetObj() && p1->mpHdl->GetObj()->ISA(SdrPathObj))
		{
			// same object and a path object
			if((p1->mpHdl->GetKind() == HDL_POLY || p1->mpHdl->GetKind() == HDL_BWGT)
				&& (p2->mpHdl->GetKind() == HDL_POLY || p2->mpHdl->GetKind() == HDL_BWGT))
			{
				// 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;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// #97016# II

void SdrHdlList::TravelFocusHdl(sal_Bool bForward)
{
	// security correction
	if(mnFocusIndex != CONTAINER_ENTRY_NOTFOUND && mnFocusIndex >= GetHdlCount())
		mnFocusIndex = CONTAINER_ENTRY_NOTFOUND;

	if(aList.Count())
	{
		// take care of old handle
		const sal_uIntPtr nOldHdlNum(mnFocusIndex);
		SdrHdl* pOld = GetHdl(nOldHdlNum);
		//SDOsal_Bool bRefresh(sal_False);

		if(pOld)
		{
			// switch off old handle
			mnFocusIndex = CONTAINER_ENTRY_NOTFOUND;
			pOld->Touch();
			//SDObRefresh = sal_True;
		}

		// #105678# Alloc pointer array for sorted handle list
		ImplHdlAndIndex* pHdlAndIndex = new ImplHdlAndIndex[aList.Count()];

		// #105678# build sorted handle list
		sal_uInt32 a;
		for( a = 0; a < aList.Count(); a++)
		{
			pHdlAndIndex[a].mpHdl = (SdrHdl*)aList.GetObject(a);
			pHdlAndIndex[a].mnIndex = a;
		}

		// #105678# qsort all entries
		qsort(pHdlAndIndex, aList.Count(), sizeof(ImplHdlAndIndex), ImplSortHdlFunc);

		// #105678# look for old num in sorted array
		sal_uIntPtr nOldHdl(nOldHdlNum);

		if(nOldHdlNum != CONTAINER_ENTRY_NOTFOUND)
		{
			for(a = 0; a < aList.Count(); a++)
			{
				if(pHdlAndIndex[a].mpHdl == pOld)
				{
					nOldHdl = a;
					break;
				}
			}
		}

		// #105678# build new HdlNum
		sal_uIntPtr nNewHdl(nOldHdl);

		// #105678# do the focus travel
		if(bForward)
		{
			if(nOldHdl != CONTAINER_ENTRY_NOTFOUND)
			{
				if(nOldHdl == aList.Count() - 1)
				{
					// end forward run
					nNewHdl = CONTAINER_ENTRY_NOTFOUND;
				}
				else
				{
					// simply the next handle
					nNewHdl++;
				}
			}
			else
			{
				// start forward run at first entry
				nNewHdl = 0;
			}
		}
		else
		{
			if(nOldHdl == CONTAINER_ENTRY_NOTFOUND)
			{
				// start backward run at last entry
				nNewHdl = aList.Count() - 1;

			}
			else
			{
				if(nOldHdl == 0)
				{
					// end backward run
					nNewHdl = CONTAINER_ENTRY_NOTFOUND;
				}
				else
				{
					// simply the previous handle
					nNewHdl--;
				}
			}
		}

		// #105678# build new HdlNum
		sal_uInt32 nNewHdlNum(nNewHdl);

		// look for old num in sorted array
		if(nNewHdl != CONTAINER_ENTRY_NOTFOUND)
		{
			SdrHdl* pNew = pHdlAndIndex[nNewHdl].mpHdl;

			for(a = 0; a < aList.Count(); a++)
			{
				if((SdrHdl*)aList.GetObject(a) == pNew)
				{
					nNewHdlNum = a;
					break;
				}
			}
		}

		// take care of next handle
		if(nOldHdlNum != nNewHdlNum)
		{
			mnFocusIndex = nNewHdlNum;
			SdrHdl* pNew = GetHdl(mnFocusIndex);

			if(pNew)
			{
				pNew->Touch();
				//SDObRefresh = sal_True;
			}
		}

		// #105678# free mem again
		delete [] pHdlAndIndex;
	}
}

SdrHdl* SdrHdlList::GetFocusHdl() const
{
	if(mnFocusIndex != CONTAINER_ENTRY_NOTFOUND && mnFocusIndex < GetHdlCount())
		return GetHdl(mnFocusIndex);
	else
		return 0L;
}

void SdrHdlList::SetFocusHdl(SdrHdl* pNew)
{
	if(pNew)
	{
		SdrHdl* pActual = GetFocusHdl();

		if(!pActual || pActual != pNew)
		{
			sal_uIntPtr nNewHdlNum = GetHdlNum(pNew);

			if(nNewHdlNum != CONTAINER_ENTRY_NOTFOUND)
			{
				//SDOsal_Bool bRefresh(sal_False);
				mnFocusIndex = nNewHdlNum;

				if(pActual)
				{
					pActual->Touch();
					//SDObRefresh = sal_True;
				}

				if(pNew)
				{
					pNew->Touch();
					//SDObRefresh = sal_True;
				}

				//OLMif(bRefresh)
				//OLM{
				//OLM	if(pView)
				//OLM		pView->RefreshAllIAOManagers();
				//OLM}
			}
		}
	}
}

void SdrHdlList::ResetFocusHdl()
{
	SdrHdl* pHdl = GetFocusHdl();

	mnFocusIndex = CONTAINER_ENTRY_NOTFOUND;

	if(pHdl)
	{
		pHdl->Touch();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

SdrHdlList::SdrHdlList(SdrMarkView* pV)
:	mnFocusIndex(CONTAINER_ENTRY_NOTFOUND),
	pView(pV),
	aList(1024,32,32)
{
	nHdlSize = 3;
	bRotateShear = sal_False;
	bMoveOutside = sal_False;
	bDistortShear = sal_False;
	bFineHandles = sal_True; // new default: Handles are fine handles
}

SdrHdlList::~SdrHdlList()
{
	Clear();
}

void SdrHdlList::SetHdlSize(sal_uInt16 nSiz)
{
	if(nHdlSize != nSiz)
	{
		// remember new value
		nHdlSize = nSiz;

		// propagate change to IAOs
		for(sal_uInt32 i=0; i<GetHdlCount(); i++)
		{
			SdrHdl* pHdl = GetHdl(i);
			pHdl->Touch();
		}
	}
}

void SdrHdlList::SetMoveOutside(sal_Bool bOn)
{
	if(bMoveOutside != bOn)
	{
		// remember new value
		bMoveOutside = bOn;

		// propagate change to IAOs
		for(sal_uInt32 i=0; i<GetHdlCount(); i++)
		{
			SdrHdl* pHdl = GetHdl(i);
			pHdl->Touch();
		}
	}
}

void SdrHdlList::SetRotateShear(sal_Bool bOn)
{
	bRotateShear = bOn;
}

void SdrHdlList::SetDistortShear(sal_Bool bOn)
{
	bDistortShear = bOn;
}

void SdrHdlList::SetFineHdl(sal_Bool bOn)
{
	if(bFineHandles != bOn)
	{
		// remember new state
		bFineHandles = bOn;

		// propagate change to IAOs
		for(sal_uInt32 i=0; i<GetHdlCount(); i++)
		{
			SdrHdl* pHdl = GetHdl(i);
			pHdl->Touch();
		}
	}
}

SdrHdl* SdrHdlList::RemoveHdl(sal_uIntPtr nNum)
{
	SdrHdl* pRetval = (SdrHdl*)aList.Remove(nNum);

	return pRetval;
}

void SdrHdlList::Clear()
{
	for (sal_uIntPtr i=0; i<GetHdlCount(); i++)
	{
		SdrHdl* pHdl=GetHdl(i);
		delete pHdl;
	}
	aList.Clear();

	bRotateShear=sal_False;
	bDistortShear=sal_False;
}

void SdrHdlList::Sort()
{
	// #97016# II: remember current focused handle
	SdrHdl* pPrev = GetFocusHdl();

	ImpSdrHdlListSorter aSort(aList);
	aSort.DoSort();

	// #97016# II: get now and compare
	SdrHdl* pNow = GetFocusHdl();

	if(pPrev != pNow)
	{
		//SDOsal_Bool bRefresh(sal_False);

		if(pPrev)
		{
			pPrev->Touch();
			//SDObRefresh = sal_True;
		}

		if(pNow)
		{
			pNow->Touch();
			//SDObRefresh = sal_True;
		}
	}
}

sal_uIntPtr SdrHdlList::GetHdlNum(const SdrHdl* pHdl) const
{
	if (pHdl==NULL)
		return CONTAINER_ENTRY_NOTFOUND;
	sal_uIntPtr nPos=aList.GetPos(pHdl);
	return nPos;
}

void SdrHdlList::AddHdl(SdrHdl* pHdl, sal_Bool bAtBegin)
{
	if (pHdl!=NULL)
	{
		if (bAtBegin)
		{
			aList.Insert(pHdl,sal_uIntPtr(0));
		}
		else
		{
			aList.Insert(pHdl,CONTAINER_APPEND);
		}
		pHdl->SetHdlList(this);
	}
}

SdrHdl* SdrHdlList::IsHdlListHit(const Point& rPnt, sal_Bool bBack, sal_Bool bNext, SdrHdl* pHdl0) const
{
	SdrHdl* pRet=NULL;
	sal_uIntPtr nAnz=GetHdlCount();
	sal_uIntPtr nNum=bBack ? 0 : nAnz;
	while ((bBack ? nNum<nAnz : nNum>0) && pRet==NULL)
	{
		if (!bBack)
			nNum--;
		SdrHdl* pHdl=GetHdl(nNum);
		if (bNext)
		{
			if (pHdl==pHdl0)
				bNext=sal_False;
		}
		else
		{
			if (pHdl->IsHdlHit(rPnt))
				pRet=pHdl;
		}
		if (bBack)
			nNum++;
	}
	return pRet;
}

SdrHdl* SdrHdlList::GetHdl(SdrHdlKind eKind1) const
{
	SdrHdl* pRet=NULL;
	for (sal_uIntPtr i=0; i<GetHdlCount() && pRet==NULL; i++)
	{
		SdrHdl* pHdl=GetHdl(i);
		if (pHdl->GetKind()==eKind1)
			pRet=pHdl;
	}
	return pRet;
}

// --------------------------------------------------------------------
// SdrCropHdl
// --------------------------------------------------------------------

SdrCropHdl::SdrCropHdl(
	const Point& rPnt,
	SdrHdlKind eNewKind,
	double fShearX,
	double fRotation)
:	SdrHdl(rPnt, eNewKind),
	mfShearX(fShearX),
	mfRotation(fRotation)
{
}

// --------------------------------------------------------------------

BitmapEx SdrCropHdl::GetHandlesBitmap( bool bIsFineHdl, bool bIsHighContrast )
{
	if( bIsHighContrast )
	{
		static BitmapEx* pHighContrastBitmap = 0;
		if( pHighContrastBitmap == 0 )
			pHighContrastBitmap = new BitmapEx(ResId(SIP_SA_ACCESSIBILITY_CROP_MARKERS, *ImpGetResMgr()));
		return *pHighContrastBitmap;
	}
	else if( bIsFineHdl )
	{
		static BitmapEx* pModernBitmap = 0;
		if( pModernBitmap == 0 )
			pModernBitmap = new BitmapEx(ResId(SIP_SA_CROP_FINE_MARKERS, *ImpGetResMgr()));
		return *pModernBitmap;
	}
	else
	{
		static BitmapEx* pSimpleBitmap = 0;
		if( pSimpleBitmap == 0 )
			pSimpleBitmap = new BitmapEx(ResId(SIP_SA_CROP_MARKERS, *ImpGetResMgr()));
		return *pSimpleBitmap;
	}
}

// --------------------------------------------------------------------

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 HDL_UPLFT: nX = 0; nY = 0; break;
		case HDL_UPPER: nX = 1; nY = 0; break;
		case HDL_UPRGT: nX = 2; nY = 0; break;
		case HDL_LEFT:  nX = 0; nY = 1; break;
		case HDL_RIGHT: nX = 2; nY = 1; break;
		case HDL_LWLFT: nX = 0; nY = 2; break;
		case HDL_LOWER: nX = 1; nY = 2; break;
		case HDL_LWRGT: nX = 2; nY = 2; break;
		default: break;
	}

	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() : 0;
	SdrPageView* pPageView = pView ? pView->GetSdrPageView() : 0;

	if( pPageView && !pView->areMarkHandlesHidden() )
	{
		sal_Bool bIsFineHdl(pHdlList->IsFineHdl());
		const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
		sal_Bool bIsHighContrast(rStyleSettings.GetHighContrastMode());
		int nHdlSize = pHdlList->GetHdlSize();
		if( bIsHighContrast )
			nHdlSize = 4;

		const BitmapEx aHandlesBitmap( GetHandlesBitmap( bIsFineHdl, bIsHighContrast ) );
		BitmapEx aBmpEx1( GetBitmapForHandle( aHandlesBitmap, nHdlSize ) );

		for(sal_uInt32 b(0L); b < pPageView->PageWindowCount(); b++)
		{
			// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
			const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

			if(rPageWindow.GetPaintWindow().OutputToWindow())
			{
				if(rPageWindow.GetOverlayManager())
				{
					basegfx::B2DPoint aPosition(aPos.X(), aPos.Y());

					::sdr::overlay::OverlayObject* pOverlayObject = 0L;

					// animate focused handles
					if(IsFocusHdl() && (pHdlList->GetFocusHdl() == this))
					{
						if( nHdlSize >= 2 )
							nHdlSize = 1;

						BitmapEx aBmpEx2( GetBitmapForHandle( aHandlesBitmap, nHdlSize + 1 ) );

						const sal_uInt32 nBlinkTime = sal::static_int_cast<sal_uInt32>(rStyleSettings.GetCursorBlinkTime());

						pOverlayObject = new ::sdr::overlay::OverlayAnimatedBitmapEx(
							aPosition,
							aBmpEx1,
							aBmpEx2,
							nBlinkTime,
							(sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
							(sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
							(sal_uInt16)(aBmpEx2.GetSizePixel().Width() - 1) >> 1,
							(sal_uInt16)(aBmpEx2.GetSizePixel().Height() - 1) >> 1,
							mfShearX,
							mfRotation);
					}
					else
					{
						// create centered handle as default
						pOverlayObject = new ::sdr::overlay::OverlayBitmapEx(
							aPosition,
							aBmpEx1,
							(sal_uInt16)(aBmpEx1.GetSizePixel().Width() - 1) >> 1,
							(sal_uInt16)(aBmpEx1.GetSizePixel().Height() - 1) >> 1,
							0.0,
							mfShearX,
							mfRotation);
					}

					// OVERLAYMANAGER
					if(pOverlayObject)
					{
						rPageWindow.GetOverlayManager()->add(*pOverlayObject);
						maOverlayGroup.append(*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(), HDL_USER),
	maObjectTransform(rObjectTransform),
	maGraphic(rGraphic),
	mfCropLeft(fCropLeft),
	mfCropTop(fCropTop),
	mfCropRight(fCropRight),
	mfCropBottom(fCropBottom)
{
}

void SdrCropViewHdl::CreateB2dIAObject()
{
	GetRidOfIAObject();
	SdrMarkView* pView = pHdlList ? pHdlList->GetView() : 0;
	SdrPageView* pPageView = pView ? pView->GetSdrPageView() : 0;

	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;
	}

	// 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(fRotate), F_PI, 0.000000001))
	{
		aScale.setX(aScale.getX() * -1.0);
		aScale.setY(aScale.getY() * -1.0);
		fRotate = 0.0;
	}

	// 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::tools::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::tools::createPolygonFromRect(
				aOverlap));
	}

	// transform to object coordinates to prepare for clip
	aCropPolyPolygon.transform(maObjectTransform);
	aGraphicOutlinePolygon.transform(maObjectTransform);

	// create cropped transformation
	basegfx::B2DHomMatrix aCroppedTransform;
	const bool bCombinedMirrorX(bMirroredX);

	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::Primitive2DSequence 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::Primitive2DSequence(&aMaskedGraphic, 1),
			0.8));

	const drawinglayer::primitive2d::Primitive2DSequence aSequence(&aTransparenceMaskedGraphic, 1);

	for(sal_uInt32 b(0L); b < pPageView->PageWindowCount(); b++)
	{
		// const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
		const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);

		if(rPageWindow.GetPaintWindow().OutputToWindow())
		{
			if(rPageWindow.GetOverlayManager())
			{
				::sdr::overlay::OverlayObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aSequence);
				DBG_ASSERT(pNew, "Got NO new IAO!");

				if(pNew)
				{
					// only informative object, no hit
					pNew->setHittable(false);

					rPageWindow.GetOverlayManager()->add(*pNew);
					maOverlayGroup.append(*pNew);
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// eof
