/**************************************************************
 * 
 * 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 <svx/xoutbmp.hxx>
#include <svx/dialogs.hrc>
#include <svx/svxids.hrc>
#include <contdlg.hrc>
#include <contwnd.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdopath.hxx>
#include <svx/xfltrit.hxx>
#include <svx/xfillit.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>

// #i75482#
#include "svx/sdrpaintwindow.hxx"

#define TRANSCOL Color( COL_WHITE )

/*************************************************************************
|*
|*
|*
\************************************************************************/

ContourWindow::ContourWindow( Window* pParent, const ResId& rResId ) :
			GraphCtrl		( pParent, rResId ),
			aWorkRect		( 0, 0, 0, 0 ),
			bPipetteMode	( sal_False ),
			bWorkplaceMode	( sal_False ),
			bClickValid		( sal_False )
{
	SetWinStyle( WB_SDRMODE );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

ContourWindow::~ContourWindow()
{
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::SetPolyPolygon( const PolyPolygon& rPolyPoly )
{
	SdrPage*		pPage = (SdrPage*) pModel->GetPage( 0 );
	const sal_uInt16	nPolyCount = rPolyPoly.Count();

	// zuerst alle Zeichenobjekte loeschen
	aPolyPoly = rPolyPoly;

	// #117412#
	// To avoid to have destroyed objects which are still selected, it is necessary to deselect
	// them first (!)
	pView->UnmarkAllObj();

	pPage->Clear();

	for ( sal_uInt16 i = 0; i < nPolyCount; i++ )
	{
		basegfx::B2DPolyPolygon aPolyPolygon;
		aPolyPolygon.append(aPolyPoly[ i ].getB2DPolygon());
		SdrPathObj* pPathObj = new SdrPathObj( OBJ_PATHFILL, aPolyPolygon );

		if ( pPathObj )
		{
			SfxItemSet aSet( pModel->GetItemPool() );

			aSet.Put( XFillStyleItem( XFILL_SOLID ) );
			aSet.Put( XFillColorItem( String(), TRANSCOL ) );
			aSet.Put( XFillTransparenceItem( 50 ) );

			//pPathObj->SetItemSetAndBroadcast(aSet);
			pPathObj->SetMergedItemSetAndBroadcast(aSet);

			pPage->InsertObject( pPathObj );
		}
	}

	if ( nPolyCount )
	{
		pView->MarkAll();
		pView->CombineMarkedObjects( sal_False );
	}

	pModel->SetChanged( sal_False );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

const PolyPolygon& ContourWindow::GetPolyPolygon()
{
	if ( pModel->IsChanged() )
	{
		SdrPage* pPage = (SdrPage*) pModel->GetPage( 0 );

		aPolyPoly = PolyPolygon();

		if ( pPage && pPage->GetObjCount() )
		{
			SdrPathObj* pPathObj = (SdrPathObj*)pPage->GetObj(0L);
			// Not sure if subdivision is needed for ContourWindow, but maybe it cannot handle
			// curves at all. Keeping subdivision here for security
			const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(pPathObj->GetPathPoly()));
			aPolyPoly = PolyPolygon(aB2DPolyPolygon);
		}

		pModel->SetChanged( sal_False );
	}

	return aPolyPoly;
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::InitSdrModel()
{
	GraphCtrl::InitSdrModel();

	SfxItemSet aSet( pModel->GetItemPool() );

	aSet.Put( XFillColorItem( String(), TRANSCOL ) );
	aSet.Put( XFillTransparenceItem( 50 ) );
	pView->SetAttributes( aSet );
	pView->SetFrameDragSingles( sal_True );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::SdrObjCreated( const SdrObject&  )
{
	pView->MarkAll();
	pView->CombineMarkedObjects( sal_False );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

sal_Bool ContourWindow::IsContourChanged() const
{
	SdrPage*	pPage = (SdrPage*) pModel->GetPage( 0 );
	sal_Bool		bRet = sal_False;

	if ( pPage && pPage->GetObjCount() )
		bRet = ( (SdrPathObj*) pPage->GetObj( 0 ) )->GetPathPoly().count() && pModel->IsChanged();

	return bRet;
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
	if ( bWorkplaceMode )
	{
		const Point aLogPt( PixelToLogic( rMEvt.GetPosPixel() ) );

		SetPolyPolygon( PolyPolygon() );
		aWorkRect = Rectangle( aLogPt, aLogPt );
		Paint( Rectangle( Point(), GetGraphicSize() ) );
		SetEditMode( sal_True );
	}

	if ( !bPipetteMode )
		GraphCtrl::MouseButtonDown( rMEvt );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::MouseMove( const MouseEvent& rMEvt )
{
	bClickValid = sal_False;

	if ( bPipetteMode )
	{
		const Point aLogPt( PixelToLogic( rMEvt.GetPosPixel() ) );

		aPipetteColor = GetPixel( aLogPt );
		Control::MouseMove( rMEvt );

		if ( aPipetteLink.IsSet() && Rectangle( Point(), GetGraphicSize() ).IsInside( aLogPt ) )
		{
			SetPointer( POINTER_REFHAND );
			aPipetteLink.Call( this );
		}
	}
	else
		GraphCtrl::MouseMove( rMEvt );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::MouseButtonUp(const MouseEvent& rMEvt)
{
	Point aTmpPoint;
	const Rectangle	aGraphRect( aTmpPoint, GetGraphicSize() );
	const Point		aLogPt( PixelToLogic( rMEvt.GetPosPixel() ) );

	bClickValid = aGraphRect.IsInside( aLogPt );
	ReleaseMouse();

	if ( bPipetteMode )
	{
		Control::MouseButtonUp( rMEvt );

		if ( aPipetteClickLink.IsSet() )
			aPipetteClickLink.Call( this );
	}
	else if ( bWorkplaceMode )
	{
		GraphCtrl::MouseButtonUp( rMEvt );

		aWorkRect.Right() = aLogPt.X();
		aWorkRect.Bottom() = aLogPt.Y();
		aWorkRect.Intersection( aGraphRect );
		aWorkRect.Justify();

		if ( aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom() )
		{
            PolyPolygon _aPolyPoly( GetPolyPolygon() );

            _aPolyPoly.Clip( aWorkRect );
            SetPolyPolygon( _aPolyPoly );
			pView->SetWorkArea( aWorkRect );
		}
		else
			pView->SetWorkArea( aGraphRect );

		Invalidate( aGraphRect );

		if ( aWorkplaceClickLink.IsSet() )
			aWorkplaceClickLink.Call( this );
	}
	else
		GraphCtrl::MouseButtonUp( rMEvt );
}


/*************************************************************************
|*
|*
|*
\************************************************************************/

void ContourWindow::Paint( const Rectangle& rRect )
{
	// #i75482#
	// encapsulate the redraw using Begin/End and use the returned
	// data to get the target output device (e.g. when pre-rendering)
	SdrPaintWindow* pPaintWindow = pView->BeginCompleteRedraw(this);
	OutputDevice& rTarget = pPaintWindow->GetTargetOutputDevice();

	const Graphic& rGraphic = GetGraphic();
	const Color& rOldLineColor = GetLineColor();
	const Color& rOldFillColor = GetFillColor();
	
	rTarget.SetLineColor( Color( COL_BLACK ) );
	rTarget.SetFillColor( Color( COL_WHITE ) );

	rTarget.DrawRect( Rectangle( Point(), GetGraphicSize() ) );

	rTarget.SetLineColor( rOldLineColor );
	rTarget.SetFillColor( rOldFillColor );

	if ( rGraphic.GetType() != GRAPHIC_NONE )
		rGraphic.Draw( &rTarget, Point(), GetGraphicSize() );

	if ( aWorkRect.Left() != aWorkRect.Right() && aWorkRect.Top() != aWorkRect.Bottom() )
	{
        PolyPolygon _aPolyPoly( 2, 2 );
		const Color	aOldFillColor( GetFillColor() );

        _aPolyPoly.Insert( Rectangle( Point(), GetGraphicSize() ) );
        _aPolyPoly.Insert( aWorkRect );

		rTarget.SetFillColor( COL_LIGHTRED );
        rTarget.DrawTransparent( _aPolyPoly, 50 );
		rTarget.SetFillColor( aOldFillColor );
	}

	// #i75482#
	const Region aRepaintRegion(rRect);
	pView->DoCompleteRedraw(*pPaintWindow, aRepaintRegion);
	pView->EndCompleteRedraw(*pPaintWindow, true);
}

// eof