
///////////////////////////////////////////////
//											 //
// All files in X-framework are Copyright    //
// of Aleksandras Gluchovas 				 //
// 											 //
// e-mail: alex@soften.ktu.lt                //
//											 //
///////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "gridg.h"
#pragma interface
#endif


// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "XPrimitives.h"
#include "wx/pmf/pm_undef.h"

/***** Implementation for class XPrimitve *****/

XPrimitive::XPrimitive()

	: mPrecision( -1 ), // undefined initially
	  mName( "" )
{}

void XPrimitive::DrawName( wxDC& canvas )
{
	if ( mName == "" ) return;

	canvas.SetBackgroundMode( wxTRANSPARENT );

	long w,h ;

	canvas.GetTextExtent( mName, &w, &h );

	XRect r = GetBounds();
	XPoint pos;

	pos.x = r.x + ( r.width  - w )/2;
	pos.y = r.y + ( r.height - h )/2;

	canvas.DrawText( mName, pos.x, pos.y );
}

/***** Implementation for class XLabelObj *****/

XLabelObj::XLabelObj()
{
}

XLabelObj::XLabelObj( const wxString& text )
{
	mName = text;
}

void XLabelObj::Draw( wxDC& canvas )
{
	canvas.SetTextForeground( mCol );
	DrawName( canvas );
}

XRect XLabelObj::GetBounds()
{
	return mBounds;
}

void XLabelObj::SetBounds( const XRect& bounds )
{
	mBounds = bounds;
}

void XLabelObj::SetColour( const wxColour& col )
{
	mCol = col;
}

void XLabelObj::SetShape( XPoly& shape )
{
	mBounds = shape.GetBoundingRect();	
}

void XLabelObj::GetShape( XPoly& shape )
{
	shape.CreateFromRect( mBounds );
}

XObject* XLabelObj::CloneCopy( bool identical )
{
	XLabelObj* pCopy = new XLabelObj( mName );

	pCopy->mBounds = mBounds;

	pCopy->SetEditor( CloneEditorCopy( identical ) );

	return pCopy;
}

/***** Implementation for class XRectObj *****/

XRectObj::XRectObj( const XRect& rect, 
					const wxColour& bgColor,
					const wxColour& outlineColor )

	: mRect ( rect ),
	  mPen  ( outlineColor, 1, wxSOLID ),
	  mBrush( bgColor, wxSOLID ),
	  mMoveStarted( FALSE )
{}

void XRectObj::Draw( wxDC& canvas )
{
	canvas.SetBrush( mBrush );
	canvas.SetPen( mPen );

	canvas.DrawRectangle( mRect.x, mRect.y, mRect.width, mRect.height );

	canvas.SetTextForeground( wxColour(255,255,255) );

	DrawName( canvas );

	canvas.SetTextForeground( wxColour(0,0,0) );
}

XRect XRectObj::GetBounds()
{
	return mRect;
}

void XRectObj::SetShape( XPoly& shape )
{
	mRect = shape.GetBoundingRect();	
}

void XRectObj::GetShape( XPoly& shape )
{
	shape.CreateFromRect( mRect );
}

XObject* XRectObj::CloneCopy( bool identical )
{
	XRectObj* pCopy = new XRectObj( mRect, mBrush.GetColour(), mPen.GetColour() );

	pCopy->SetEditor( CloneEditorCopy( identical ) );

	return pCopy;
}

/***** Implementation for class XBackgroundObj *****/

XBackgroundObj::XBackgroundObj( const wxColour& bkColor )

	: mBrush( bkColor, wxSOLID ) 
{}

void XBackgroundObj::Draw( wxDC& canvas )
{
	canvas.SetBrush( mBrush );
	canvas.SetPen  ( *wxTRANSPARENT_PEN );

	XRect r = XObject::GetUpdateRegion( canvas );

	canvas.DrawRectangle( r.x, r.y, r.width, r.height );
}

XRect XBackgroundObj::GetBounds()
{
	return XRect ( XPoint(-16384,-16384), XDim( 32768,32768 ) );
}

/***** Implementation for class XEdgedCircle *****/

XEdgedCircle::XEdgedCircle( const XPoint& pos, 
							int nEdges, 
							int radius, const wxColour& color )
	: mBounds( pos, XDim( radius*2, radius*2 ) ),
	  mBrush( color, wxSOLID )
{
	mPrecision = nEdges;

	RegenerateShape();
}

XRect XEdgedCircle::GetBounds()

	{ return mBounds; }

void XEdgedCircle::Draw( wxDC& canvas )
{
	canvas.SetBrush( mBrush );
	mShape.SolidDraw( canvas );

	DrawName( canvas );
}

void XEdgedCircle::SetShape( XPoly& shape ) 
{

	mBounds = shape.GetBoundingRect();
	RegenerateShape();
}

void XEdgedCircle::GetShape( XPoly& shape ) 
{
	shape.CreateFromRect( mBounds );
}

void XEdgedCircle::RegenerateShape()
{
	mShape.RemoveAll();

	AngleT step  = M_PI*2.0/mPrecision;
	AngleT angle = M_PI_2;

	double radius     = mBounds.Height()/2;
	double horizSheer = double(mBounds.Width())/
		                double(mBounds.Height());

	XPoint center = mBounds.GetCenter();

	for( int i = 0; i != mPrecision; ++i )
	{
		double x = radius * cos( angle );
		double y = radius * sin( angle );
		x = x * horizSheer;

		mShape.Add( XPoint( PosT(x) + center.x, 
			                PosT(y) + center.y ) );

		angle -= step;
	}
}

XObject* XEdgedCircle::CloneCopy( bool identical )
{
	XEdgedCircle* pCopy = 

		new XEdgedCircle( mBounds.UpperLeft(), 
						  mPrecision,
						  mBounds.Width()/2,
						  mBrush.GetColour()
					    );

	pCopy->SetEditor( CloneEditorCopy( identical ) );

	return pCopy;
}

/***** Implementation for class XArrow *****/

XArrow::XArrow( const XPoint& first, const XPoint& second, 
			    const wxColour& color, int shaftLen )

	: mFirst ( first  ),
	  mSecond( second ),
	  mPen( color, 1, wxSOLID ),
  	  mShaftLen( shaftLen )
{}

void XArrow::Draw( wxDC& canvas )
{
	PosT dx = mSecond.x - mFirst.x;
	PosT dy = mSecond.y - mFirst.y;

	AngleT ang = get_true_arctan( PosT(dx), PosT(dy) );

	AngleT a1 = ang + M_PI_4/2 + M_PI;
	AngleT a2 = ang - M_PI_4/2 + M_PI;

	XPoint p1;
	XPoint p2;

	p1.x = PosT( cos( a1 ) * mShaftLen );
	p1.y = PosT( sin( a1 ) * mShaftLen );

	p2.x = PosT( cos( a2 ) * mShaftLen );
	p2.y = PosT( sin( a2 ) * mShaftLen );

	p1 = mSecond.Add( p1 );
	p2 = mSecond.Add( p2 );

	canvas.SetPen( mPen );

	canvas.DrawLine( mFirst.x, mFirst.y, 
		             mSecond.x, mSecond.y );

	canvas.DrawLine( mSecond.x, mSecond.y, p1.x, p1.y );
	canvas.DrawLine( mSecond.x, mSecond.y, p2.x, p2.y );

	DrawName( canvas );
}

XRect XArrow::GetBounds()
{
	XRect r( mFirst, mSecond );

	r.Normalize();

	r.x -= mShaftLen;
	r.y -= mShaftLen;
	r.width  += mShaftLen*2;
	r.height += mShaftLen*2;

	return r;
}

void XArrow::SetShape( XPoly& shape )
{
	mFirst  = *shape.GetPoints()[0];
	mSecond = *shape.GetPoints()[1];
}

void XArrow::GetShape( XPoly& shape )
{
	shape.RemoveAll();

	shape.Add( mFirst );
	shape.Add( mSecond );
}

XObject* XArrow::CloneCopy( bool identical )
{
	XArrow* pCopy = 

		new XArrow( mFirst, mSecond, mPen.GetColour(), mShaftLen );

	pCopy->SetEditor( CloneEditorCopy( identical ) );

	return pCopy;
}

/***** Implementation for class XLineEditor *****/

static XRect inline get_handle_rect( const XPoint& hndPos, int width )
{
	int half = width/2;

	return XRect( hndPos.x - half, hndPos.y - half, width, width );
}

bool XLineEditor::IsInHandle( int isFirst, const XPoint& pos )
{
	if ( isFirst ) 

		return get_handle_rect( mFirst, mHandleWidth ).Contains( pos );
	else
		return get_handle_rect( mSecond, mHandleWidth ).Contains( pos );
}

XLineEditor::XLineEditor( int handleWidth )

	: mDragStarted( FALSE ),
	  mHandleWidth( handleWidth ),

	  mPen  ( wxColour( 0,0,0 ), 1, wxSOLID ),
	  mBrush( wxColour( 0,0,0 ),    wxSOLID )
{
}

bool XLineEditor::OnMouseDown ( const XPoint& pos )
{
	XPoly shape;

	GetParent().GetShape( shape );

	mFirstOriginal  = mFirst  = *shape.GetPoints()[0];
	mSecondOriginal = mSecond = *shape.GetPoints()[1];

	if ( !IsActive() )
	{
		GetParent().SetSelection( GetParent() );
	}

	if ( IsInHandle( TRUE, pos ) )
	
		mFirstDragged = TRUE;

	else
	if ( IsInHandle( FALSE, pos ) )

		mFirstDragged = FALSE;
	else
	{
		return FALSE;
	}

	GetParent().OnStartEdit();

	GetParent().
		MoveToFront( &GetParent() );

	SetMouseFocus( &GetParent() );

	mDragStarted = TRUE;

	mDragOrigin = pos;

	return TRUE;
}

bool XLineEditor::OnMouseUp   ( const XPoint& pos )
{
	if ( mDragStarted ) 
	{
		// simulate the last mouse movement
		OnMouseMove( pos );

		InvalidateRect( GetParent().GetInclusiveBounds() );

		GetParent().OnFinishEdit();

		InvalidateRect( GetParent().GetInclusiveBounds() );

		RefreshNow();

		ResetMouseFocus( &GetParent() );

		mDragStarted = FALSE; // finish drag action

		return TRUE;
	}
	else
		return FALSE;
}

bool XLineEditor::OnMouseMove ( const XPoint& pos )
{
	if ( mDragStarted )
	{
		InvalidateRect( GetParent().GetInclusiveBounds() );

		XPoint delta = pos.Sub( mDragOrigin );

		if ( mFirstDragged )

			mFirst  = mFirstOriginal.Add( delta );
		else
			mSecond = mSecondOriginal.Add( delta );

		XPoly shape;

		shape.Add( mFirst );
		shape.Add( mSecond );

		GetParent().SetShape( shape );

		// fire off notifications to the derived classes
		OnDragging();

		// and to the edited object
		GetParent().OnEditorDragged();

		InvalidateRect( GetParent().GetInclusiveBounds() );

		RefreshNow();

		return TRUE;
	}
	else
		return FALSE;
}

void XLineEditor::Draw( wxDC& canvas )
{
	GetParent().Draw( canvas );

	if ( !IsActive() ) return;

	canvas.SetBrush( mBrush );
	canvas.SetPen( mPen );

	XRect r1 = get_handle_rect( mFirst,  mHandleWidth );
	XRect r2 = get_handle_rect( mSecond, mHandleWidth );

	canvas.DrawRectangle( r1.x, r1.y, r1.width, r1.height );
	canvas.DrawRectangle( r2.x, r2.y, r2.width, r2.height );
}

void XLineEditor::SetShape( XPoly& shape )
{
	mFirst  = *shape.GetPoints()[0];
	mSecond = *shape.GetPoints()[1];
}

void XLineEditor::GetShape( XPoly& shape )
{
	shape.RemoveAll();

	shape.Add( mFirst );
	shape.Add( mSecond );
}

XRect XLineEditor::GetBounds()
{
	if ( !IsActive() )

		return GetParent().GetBounds();

	XRect r1 = get_handle_rect( mFirst,  mHandleWidth );
	XRect r2 = get_handle_rect( mSecond, mHandleWidth );

	r1.Accumulate( r2 );

	r1.Normalize();

	return r1;
}
