/*************************************************************************************************/
/*!
   	@file		main.h
	@author 	Fanzo
 	@date 		2008/5/13
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#include	<windows.h>
#include	<math.h>

using namespace icubic;
using namespace shared;


///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

#define create_item( obj_name , title_obj_name , title , view_height )																								\
	title_obj_name->SetString( title );																																\
	title_obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , m_ts ) ) );			\
	y += title_obj_name->GetRect().Height();																														\
	obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , view_height ) ) );		\
	obj_name->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );																						\
	y += obj_name->GetRect().Size().height;

#define create_item_w( obj_name , title_obj_name , title , view_width )																								\
	title_obj_name->SetString( title );																																\
	title_obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( x , m_es ) , isize( view_width , m_ts ) ) );							\
	obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( x , title_obj_name->GetRect().Height() + m_es ) , isize( view_width , p->m_rect.Height() - title_obj_name->GetRect().Height() - m_es * 2 ) ) );		\
	obj_name->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );																						\
	x += view_width;

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

/**************************************************************************************************
"DispCfgView" class 
**************************************************************************************************/
class DispCfgView : public CheckCfgView
{
// variable member
private:
// public functions
public:
//=================================================================================================
//!	construct
//-------------------------------------------------------------------------------------------------
DispCfgView()
{
	SetCheckNum( 2 );
	SetString( 0 , L"disp clip" );
	SetString( 1 , L"disp handle" );
}
//=================================================================================================
bool GetClipState()
{
	return GetValue( 0 );
}
//=================================================================================================
bool GetHandleState()
{
	return GetValue( 1 );
}
};
/**************************************************************************************************
"AlphaCfgView" class 
**************************************************************************************************/
class AlphaCfgView : public View , public ISliderMsg
{
	query_begin()
	iface_hook( ISliderMsg , ISliderMsg_IID )
	query_end( View )
	
	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
private:
	instance<Slider>					m_alpha;
	instance<Font>					m_font;
	
	rControlMsg							m_msg;
	int									m_id;
	
	const int							m_sh;
	const int							m_info_w;
	
// ctrlmsg functions
private:
//=================================================================================================
void cb_call ValueChanged_slider
		(
		int		id
		)
{
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}

// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	m_alpha->Create
			( 
			( rViewParentCtrl )( reference )this_object() , 
			irect( ivector2( 0 , 0 ) , isize( p->m_rect.Size().width - m_info_w , m_sh ) )
			);
	m_alpha->SetValue( 1.0f );
	m_alpha->SetMsgCallback( ( rSliderMsg )( reference )this_object() , 100 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	wchar_t	text[ 256 ];
	cb_swprintf( text , L"A:%d" , GetValue() );
	DrawText( (iSurfaceDest)p->m_surface , fvector2( ( float )( GetRect().Size().width - m_info_w ) , ( float )(  m_sh / 2 ) ) , text , ( iFont )m_font , rgb(0,0,0) , Center_TextAlign );
}

// public functions
public:
//=================================================================================================
AlphaCfgView() : m_sh( 15 ) , m_info_w( 30 ) , m_id( 0 )
{
	cb_verify( true == m_font->Create( fsize( 0.0f , 7.0f ) , L"Tahoma" , Roman_FontCharsetType , 400 , false ) );
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
//=================================================================================================
uint8 GetValue()
{
	return ( uint8 )( m_alpha->GetValue() * 255.0f );
}
};
/**************************************************************************************************
"Control1View" class 
**************************************************************************************************/
class Control1View : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>			m_anti_t;
	instance<AntiCfgView>			m_anti;

	instance<SeparateView>			m_alpha_t;
	instance<AlphaCfgView>			m_alpha;

	instance<SeparateView>			m_blender_t;
	instance<BlenderCfgView_gp>		m_blender;

	instance<SeparateView>			m_disp_state_t;
	instance<DispCfgView>			m_disp_state;
	instance<SeparateView>			m_processor_t;
	instance<ProcessorCfgView>		m_processor;


private:
	rControlMsg							m_msg;
	int									m_id;
	
	const int							m_es;
	const int							m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_anti , m_anti_t , L"antialias" , 35 );
	create_item( m_alpha , m_alpha_t , L"alpha" , 20 );
	create_item( m_blender , m_blender_t , L"blender" , 20 );
	create_item( m_disp_state , m_disp_state_t , L"disp switch" , 30 );
	create_item( m_processor , m_processor_t , L"processor" , 20 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
Control1View() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};

/**************************************************************************************************
"BrushView" class 
**************************************************************************************************/
class BrushView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>			m_brush_paint_t;
	instance<BrushCfgView>			m_brush_paint;

private:
	rControlMsg							m_msg;
	int									m_id;
	
	const int							m_es;
	const int							m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		x = m_es;
	create_item_w( m_brush_paint , m_brush_paint_t , L"paint brush" , 200 );
	x += 3;
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
BrushView() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};
/**************************************************************************************************
"Coord" class 
**************************************************************************************************/
class Coord
{
// variable member
private:
	iSubCoordLayer	m_coord;
	fvector2		m_coord_vec;
	const float		m_coord_len;
	const float		m_handle_r;
	
	// brush/pen
	iFont_gp		m_font;
	iPaint_gp		m_brush;
	iPen_gp			m_pen;
	
// public functions
public:
//=================================================================================================
Coord
		(
		float		l
		) : m_coord_len( l ) , m_coord_vec( l , l ) , m_handle_r( 5.0f )
{
	m_brush		= CreatePaintSolid( rgba( 0 , 0 , 0 , 255 ) );
	m_pen		= CreatePenStroke( CreateJoint( Bevel_JointType_gp ) , CreateCap( Flat_CapType_gp ) , CreateCapArrow( 4.0f , 3.5f ) );
	m_font		= CreateFont( fsize( 0.0f , 10.0f ) , L"Tahoma" , Roman_FontCharsetType );
}
//=================================================================================================
iCoordLayer SetCoord
		(
		iCoordLayer&	coord
		)
{
	m_coord			= coord->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
	m_coord_vec		= fvector2( m_coord_len , m_coord_len );
	m_coord->m_unit	= unit_ip( value_ip::px , 1.0f , 1.0f );
	m_coord->m_org	= point_iplr( value_iplr::logical , fvector2( 0.0f , 0.0f ) );
	return m_coord;
}
//=================================================================================================
void SetPoint
		(
		int				off , 
		const fvector2&	pnt
		)
{
	if( off == 0 || off == 1 )
	{
		Coord_ld	coord;
		if( false == m_coord->GetCoord_ld( &coord , 0 , 0 ) )
			return;
		fvector2	p = coord.PDtoL( pnt );
		m_coord_vec.m[ off ] = p.m[ off ];
		
		int		c_off , c_num = m_coord->GetChildnum();
		for( c_off = 0 ; c_off < c_num ; c_off++ )
		{
			iSubCoordLayer	c = m_coord->GetChild( c_off );
			if( c == true )
				c->m_unit	= unit_ip( value_ip::inch , 0.03937f * m_coord_vec.x / m_coord_len , 0.03937f * m_coord_vec.y / m_coord_len );
		}
	}
	else if( off == 2 )
	{
		iCoordLayer	parent = m_coord->GetParent();
		if( parent == false )
			return;
		Coord_ld	coord;
		if( false == parent->GetCoord_ld( &coord , 0 , 0 ) )
			return;
		fvector2	p	= coord.PDtoL( pnt );
		m_coord->m_org	= point_iplr( value_iplr::logical , p );
	}
}
//=================================================================================================
bool Search
		(
		int*			off , 
		const fvector2&	pnt
		)
{
	Coord_ld	coord;
	if( false == m_coord->GetCoord_ld( &coord , 0 , 0 ) )
		return false;

	fvector2	p	= coord.PDtoL( pnt );
	frect		r( p.x - m_handle_r , p.y - m_handle_r , p.x + m_handle_r , p.y + m_handle_r );
	if( true == r.IsInside( fvector2( m_coord_vec.x , 0.0f ) ) )
	{
		*off	= 0;
		return true;
	}
	if( true == r.IsInside( fvector2( 0.0f , m_coord_vec.y ) ) )
	{
		*off	= 1;
		return true;
	}
	if( true == r.IsInside( fvector2( 0.0f , 0.0f ) ) )
	{
		*off	= 2;
		return true;
	}
	return false;
}
//=================================================================================================
void Draw
		(
		iGraphics_gp&	g
		)
{
	SaveAttr	save( g );
	faffine		ltod	= m_coord->LtoD();
	g->SetStrokePaint( m_brush );
	g->SetStrokePen( m_pen );
	g->SetStrokeWidth( 1.0f );
	g->SetStrokeClose( false );
	g->SetFont( m_font );
	fvector2	p[] = { -fvector2( m_coord_vec.x , 0.0f ) , fvector2( m_coord_vec.x , 0.0f ) , -fvector2( 0.0f , m_coord_vec.y ) , fvector2( 0.0f , m_coord_vec.y ) };
	g->StrokeLine( 2 , &p[0] , faffine() , ltod );
	g->StrokeLine( 2 , &p[2] , faffine() , ltod );
		
	wchar_t		buf[256];
	g->SetTextAlign( m_coord_vec.x < 0.0f ? Right_TextAlignHorz_gp : Left_TextAlignHorz_gp , Center_TextAlignVert_gp );
	cb_swprintf( buf , L"%.2f[mm]" , m_coord_vec.x / m_coord_len );
	g->DrawText( buf , wcslen( buf ) , ltod.Transform( fvector2( m_coord_vec.x + ( m_coord_vec.x < 0.0f ? -5.0f : 5.0f ) , 0.0f ) ) , rgba( 0 , 0 , 0 ) , 0 );

	g->SetTextAlign( Center_TextAlignHorz_gp , m_coord_vec.y < 0.0f ? Bottom_TextAlignVert_gp : Top_TextAlignVert_gp );
	cb_swprintf( buf , L"%.2f[mm]" , m_coord_vec.y / m_coord_len );
	g->DrawText( buf , wcslen( buf ) , ltod.Transform( fvector2( 0.0f , m_coord_vec.y + ( m_coord_vec.y < 0.0f ? -5.0f : 5.0f ) ) ) , rgba( 0 , 0 , 0 ) , 0 );
}
};
/**************************************************************************************************
"SourceCoord" class 
**************************************************************************************************/
class SourceCoord
{
// variable member
private:
	iSubCoordLayer	m_coord;
	const float		m_handle_r;
	
	// brush/pen
	iTexture		m_source;
	iFont_gp		m_font;
	iPaint_gp		m_brush;
	iPen_gp			m_pen;
	
// public functions
public:
//=================================================================================================
SourceCoord() : m_handle_r( 5.0f )
{
	m_brush		= CreatePaintSolid( rgba( 0 , 0 , 0 , 255 ) );
	m_pen		= CreatePenStroke( CreateJoint( Bevel_JointType_gp ) , CreateCap( Flat_CapType_gp ) , CreateCapArrow( 4.0f , 3.5f ) );
	m_font		= CreateFont( fsize( 0.0f , 10.0f ) , L"Tahoma" , Roman_FontCharsetType );
}
//=================================================================================================
iSubCoordLayer GetCoord()
{
	return m_coord;
}
//=================================================================================================
iCoordLayer SetCoord
		(
		iCoordLayer&	coord , 
		iTexture&		source
		)
{
	m_source		= source;
	m_coord			= coord->AddChild( (iCoordLayer)instance<SubCoordLayer>() );

	m_coord->m_unit	= unit_ip( value_ip::inch , 1.0f / m_source->TextureDPI()[0] , 1.0f / m_source->TextureDPI()[0] );
	m_coord->m_org	= point_iplr( value_iplr::px , fvector2( 0.0f , 0.0f ) );
	return m_coord;
}
//=================================================================================================
void SetPoint
		(
		int				off , 
		const fvector2&	pnt
		)
{
	if( off != 0 )
		return;

	iCoordLayer	parent = m_coord->GetParent();
	if( parent == false )
		return;
	Coord_ld	coord;
	if( false == parent->GetCoord_ld( &coord , 0 , 0 ) )
		return;
	fvector2	p	= coord.PDtoP( pnt );
	m_coord->m_org	= point_iplr( value_iplr::px , p );
}
//=================================================================================================
bool Search
		(
		int*			off , 
		const fvector2&	pnt
		)
{
	Coord_ld	coord;
	if( false == m_coord->GetCoord_ld( &coord , 0 , 0 ) )
		return false;

	fvector2	p	= coord.PDtoL( pnt );
	frect		r( p.x - m_handle_r , p.y - m_handle_r , p.x + m_handle_r , p.y + m_handle_r );
	if( true == r.IsInside( fvector2( 0.0f , 0.0f ) ) )
	{
		*off	= 0;
		return true;
	}
	return false;
}
//=================================================================================================
void Draw
		(
		iGraphics_gp&	g
		)
{
	SaveAttr	save( g );
	Coord_ld	coord;
	m_coord->GetCoord_ld( &coord , 0 , 0 );
	faffine		ltod	= coord.LtoPD();
	g->SetStrokePaint( m_brush );
	g->SetStrokePen( m_pen );
	g->SetStrokeWidth( 2.0f );
	g->SetStrokeClose( false );
	g->SetFont( m_font );

	fsize	ss	= m_source->TextureSize();
	DPI		sdpi= m_source->TextureDPI();
	DPI		tdpi= g->TextureDPI();
	fvector2	sp[] = 
		{
		fvector2( 0.0f , 0.0f ) , 
		fvector2( ss.width , 0.0f ) , 
		fvector2( ss.width , ss.height ) , 
		fvector2( 0.0f , ss.height ) , 
		};
	fvector2	tp[] = 
		{
		tdpi.DtoD( sdpi , sp[0] ) , 
		tdpi.DtoD( sdpi , sp[1] ) , 
		tdpi.DtoD( sdpi , sp[2] ) , 
		tdpi.DtoD( sdpi , sp[3] ) , 
		};
	g->StretchBlt( 4 , tp , sp , coord.DtoPD() , faffine() , (iTexture)m_source );
	
	fvector2	v( m_source->TextureSize().width + 5 , m_source->TextureSize().height + 5 );
	fvector2	p[] = { fvector2( 0.0f , 0.0f ) , fvector2( v.x , 0.0f ) , fvector2( 0.0f , 0.0f ) , fvector2( 0.0f , v.y ) };
	g->StrokeLine( 2 , &p[0] , faffine() , ltod );
	g->StrokeLine( 2 , &p[2] , faffine() , ltod );
		
	wchar_t		buf[256];
	g->SetTextAlign( Left_TextAlignHorz_gp , Center_TextAlignVert_gp );
	cb_swprintf( buf , L"%.2f[mm]" , m_source->TextureSize().width * 25.4f / m_source->TextureDPI()[0] );
	g->DrawText( buf , wcslen( buf ) , ltod.Transform( fvector2( v.x + 10.0f , 0.0f ) ) , rgba( 0 , 0 , 0 ) , 0 );

	g->SetTextAlign( Center_TextAlignHorz_gp , Top_TextAlignVert_gp );
	cb_swprintf( buf , L"%.2f[mm]" , m_source->TextureSize().height * 25.4f / m_source->TextureDPI()[1] );
	g->DrawText( buf , wcslen( buf ) , ltod.Transform( fvector2( 0.0f , v.y + 10.0f ) ) , rgba( 0 , 0 , 0 ) , 0 );
}
};
/**************************************************************************************************
"MainView" class 
**************************************************************************************************/
class MainView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_hook( Size , OnSize )
	msg_view_hook( LDragStart , OnLDragStart )
	msg_view_hook( LDrag , OnLDrag )
	msg_view_hook( LDragEnd , OnLDragEnd )
	msg_view_hook( LDragCancel , OnLDragCancel )
	msg_view_map_end( View )

// variable member
private:
	instance<Control1View>	m_control1;
	instance<BrushView>		m_brush;
	instance<TimeCfgView>	m_time;
	instance<Graphics_gp>	m_graphics;

	// edit
	int							m_edit_type;
	int							m_edit_pnt;
	frect						m_rect[3];
	fvector2					m_pnt[12];

	// coord
	iDeviceCoordLayer			m_root;
	Coord						m_coord_graphics_base;
	iSubCoordLayer				m_coord_graphics;
	SourceCoord					m_coord_source_view;
	iSubCoordLayer				m_coord_source_draw;
	iSubCoordLayer				m_coord_source_pixel;

	// source
	instance<TextureImageWeight4>	m_source;

	// brush/pen
	iPaint_gp					m_brush_back;
	iPaint_gp					m_brush_coord;
	iPaint_gp					m_brush_handle;
	iPaint_gp					m_brush_handle_lb;
	iPaint_gp					m_brush_clip;
	iPaint_gp					m_brush_coord_source;
	iPen_gp						m_pen_coord;
	iPen_gp						m_pen_handle;

	// path	
	instance<Path>			m_path_clip;
	
	const float					m_handle_r;

// private functions
private:
//=================================================================================================
int GetPointNum()
{
	return _countof( m_rect ) * 2 + _countof( m_pnt );
}
//=================================================================================================
fvector2 GetPoint
		(
		int				off
		)
{
	if( off < _countof( m_rect ) * 2 )
	{
		int			roff	= off / 2;
		int			poff	= off % 2;
		if( poff == 0 )
			return fvector2( m_rect[roff].xmin , m_rect[roff].ymin );
		else
			return fvector2( m_rect[roff].xmax , m_rect[roff].ymax );
	}
	else
	{
		return m_pnt[ off - _countof( m_rect ) * 2 ];
	}
}
//=================================================================================================
void SetPoint
		(
		int				off , 
		fvector2		pnt
		)
{
	faffine	ptol	= off < 2 ? m_coord_source_draw->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root ) : m_coord_graphics->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root );
	pnt	= ptol.Transform( pnt );
	if( off < _countof( m_rect ) * 2 )
	{
		int			roff	= off / 2;
		int			poff	= off % 2;
		if( poff == 0 )
		{
			m_rect[roff].xmin	= pnt.x;
			m_rect[roff].ymin	= pnt.y;
		}
		else
		{
			m_rect[roff].xmax	= pnt.x;
			m_rect[roff].ymax	= pnt.y;
		}
	}
	else
	{
		m_pnt[ off - _countof( m_rect ) * 2 ]	= pnt;
	}
}	
//=================================================================================================
bool Search
		(
		int*			pntoff , 
		const fvector2&	pnt
		)
{
	int		off , num = GetPointNum();
	for( off = 0 ; off < num ; off++ )
	{
		faffine		ptol= off < 2 ? m_coord_source_draw->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root ) : m_coord_graphics->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root );
		fvector2	pp	= ptol.Transform( pnt );

		fvector2	p = GetPoint( off );
		frect		r( p.x - m_handle_r , p.y - m_handle_r , p.x + m_handle_r , p.y + m_handle_r );
		if( true == r.IsInside( pp ) )
		{
			*pntoff	= off;
			return true;
		}
	}
	return false;
}
//=================================================================================================
void DrawHandleClip
		(
		iGraphics_gp&		g
		)
{
	SaveAttr	save( g );
	faffine		ltod	= m_coord_graphics->LtoD();
	g->SetStrokePaint( m_brush_clip );
	g->SetStrokePen( m_pen_handle );
	g->SetStrokeClose( true );
	g->SetStrokeWidth( 0.2f );
	g->StrokeLine( 7 , &m_pnt[0] , faffine() , ltod );

	g->SetPaint( m_brush_clip );
	int			pntoff;
	for( pntoff = 6 ; pntoff < 13 ; pntoff++ )
	{
		g->PaintCircle( GetPoint( pntoff ) , m_handle_r , m_handle_r , ltod );
	}
}
//=================================================================================================
void DrawHandle
		(
		iGraphics_gp&		g
		)
{
	g->SetStrokePaint( m_brush_handle );
	g->SetStrokePen( m_pen_handle );
	g->SetStrokeWidth( 0.3f );
	g->SetStrokeClose( true );
	{
		SaveAttr	save( g );
		faffine		ltod	= m_coord_source_draw->LtoD();
		{
			fvector2	lt		= GetPoint(0) , rb = GetPoint(1);
			fvector2	s[4]	= { lt , fvector2( rb.x , lt.y ) , rb , fvector2( lt.x , rb.y ) };
			g->SetPaint( m_brush_handle );
			g->StrokeLine( _countof( s ) , s , faffine() , ltod );
			g->SetPaint( m_brush_handle );
			g->PaintCircle( GetPoint( 0 ) , m_handle_r , m_handle_r , ltod );
			g->SetPaint( m_brush_handle_lb );
			g->PaintCircle( GetPoint( 1 ) , m_handle_r , m_handle_r , ltod );
		}
	}
	{
		SaveAttr	save( g );
		faffine		ltod	= m_coord_graphics->LtoD();
		int			pntoff , pntnum = 6;
		for( pntoff = 2 ; pntoff < pntnum ; pntoff++ )
		{
			if( (pntoff & 1) == 0 )
			{
				fvector2	lt		= GetPoint(pntoff) , rb = GetPoint(pntoff+1);
				fvector2	s[4]	= { lt , fvector2( rb.x , lt.y ) , rb , fvector2( lt.x , rb.y ) };
				g->SetPaint( m_brush_handle );
				g->StrokeLine( _countof( s ) , s , faffine() , ltod );
				g->PaintCircle( GetPoint( pntoff ) , m_handle_r , m_handle_r , ltod );
			}
			else
			{
				g->SetPaint( m_brush_handle_lb );
				g->PaintCircle( GetPoint( pntoff ) , m_handle_r , m_handle_r , ltod );
			}
		}
		{
			g->SetPaint( m_brush_handle );
			g->PaintCircle( GetPoint( 17 ) , m_handle_r , m_handle_r , ltod );
		}
		{
			g->SetPaint( m_brush_handle );
			fvector2	s[4] = { GetPoint( 13 ) , GetPoint( 14 ) , GetPoint( 15 ) , GetPoint( 16 ) };
			g->StrokeLine( _countof( s ) , s , faffine() , ltod );
			for( pntoff = 0 ; pntoff < _countof(s) ; pntoff++ )
				g->PaintCircle( s[pntoff] , m_handle_r , m_handle_r , ltod );
		}

		// edit handle
		m_brush->m_brush_paint->DrawEditHandle( (iGraphics_gp)g , ltod );
	}
}
//=================================================================================================
void SetClip
		(
		iGraphics_gp&	g , 
		const faffine&	ltod , 
		bool			draw
		)
{
	m_path_clip->Reset();
	m_path_clip->Move( m_pnt[0] , faffine() , true );
	m_path_clip->Line( m_pnt[1] );
	m_path_clip->BezierQ( m_pnt[2] , m_pnt[3] );
	m_path_clip->BezierC( m_pnt[4] , m_pnt[5] , m_pnt[6] );

	// draw
	if( draw == true )
	{
		g->SetStrokePaint( m_brush_clip );
		g->SetStrokePen( m_pen_handle );
		g->SetStrokeWidth( 0.5f );
		g->SetStrokeClose( true );
		g->StrokePath( (iPathLogicInfo)m_path_clip , faffine() , ltod );
	}
	m_graphics->SetClip( (iPathLogicInfo)m_path_clip , ltod );
}
// callback functions
private:
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
// msg functions
private:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	m_control1->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 , 1 ) , isize( 130 , 200 ) ) );
	m_control1->SetMsgCallback( ( rControlMsg )( reference )this_object() , 100 );

	m_time->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 135 , 0 ) , isize( 300 , 16 ) ) );
	m_time->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );

	m_brush->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 , p->m_rect.Size().height - 1 - 120 ) , isize( 220 , 120 ) ) );
	m_brush->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	// set surface
	m_graphics->SetSurface( p->m_surface );
	m_root->m_dpi = p->m_surface->GetDestDPI();
	m_root->m_view= p->m_surface->GetDestSize();
	
	// back
	m_graphics->SetPaint( m_brush_back );
	m_graphics->PaintRect( 0 , faffine() );
	
	// misc
	m_graphics->SetAntialias( m_control1->m_anti->GetValue() );
	m_graphics->SetBlender( m_control1->m_blender->GetBlender() );
	m_graphics->SetAlpha( m_control1->m_alpha->GetValue() );
	
	// draw source
	m_coord_source_view.Draw( (iGraphics_gp)m_graphics );

	// coord org
	m_coord_graphics_base.Draw( (iGraphics_gp)m_graphics );

	// set coord
	{
		SaveAttr	save( (iGraphics_gp)m_graphics );
		Coord_ld	coord;
		m_coord_graphics->GetCoord_ld( &coord , 0 , 0 );
		faffine		ltod	= coord.LtoPD();
		DPI			dpi		= coord.GetLogical().GetDPI();

		// draw clip
		if( m_control1->m_disp_state->GetClipState() == true )
			SetClip( (iGraphics_gp)m_graphics , ltod , m_control1->m_disp_state->GetHandleState() );
		m_time->BeginMeasure();

		// pat blt
		m_graphics->SetPaint( m_brush->m_brush_paint->GetBrush( dpi , ltod ) );
		m_graphics->PaintRect( &m_rect[1] , ltod );

		faffine		dtop	= m_coord_source_pixel->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_coord_source_draw );
		{
			// bit blt
			m_graphics->BitBlt( ltod.Transform( m_pnt[11] ) , (iTexture)m_source , dtop.Transform( m_rect[0].Min() ) );

			// stretch blt
			fvector2	t[] =
				{
					fvector2( m_rect[2].xmin , m_rect[2].ymin ) , 
					fvector2( m_rect[2].xmax , m_rect[2].ymin ) , 
					fvector2( m_rect[2].xmax , m_rect[2].ymax ) , 
					fvector2( m_rect[2].xmin , m_rect[2].ymax )
				};
			fvector2	s[] =
				{
					fvector2( m_rect[0].xmin , m_rect[0].ymin ) , 
					fvector2( m_rect[0].xmax , m_rect[0].ymin ) , 
					fvector2( m_rect[0].xmax , m_rect[0].ymax ) , 
					fvector2( m_rect[0].xmin , m_rect[0].ymax )
				};
			m_graphics->StretchBlt( 4 , t , s , ltod , dtop , (iTexture)m_source );

			// draw polygon
			fvector2	uv[] = {fvector2( 0.0f , 0.0f ) , fvector2( 1.0f , 0.0f ) , fvector2( 1.0f , 1.0f ) , fvector2( 0.0f , 1.0f ) };
			m_graphics->DrawPolygon( 4 , &m_pnt[7] , uv , ltod , (iTexture)m_source );
		}
		m_graphics->ReleaseClip();
		m_time->EndMeasure();
	}
	if( m_control1->m_disp_state->GetHandleState() == true && m_control1->m_disp_state->GetClipState() == true )
		DrawHandleClip( (iGraphics_gp)m_graphics );
	if( m_control1->m_disp_state->GetHandleState() == true )
		DrawHandle( (iGraphics_gp)m_graphics );
	m_graphics->ReleaseSurface();
}
//=================================================================================================
void OnSize
		(
		Size_ViewPM*	p
		)
{
	m_brush->Move( irect( ivector2( 1 , p->m_rect.Size().height - 120 - 1 ) , isize( 220 , 120 ) ) );
}
//=================================================================================================
void OnLDragStart
		(
		LDragStart_ViewPM*	p
		)
{
	isize	size = GetRect().Size();
	if( m_control1->m_disp_state->GetHandleState() == false )
		return;

	if( true == m_brush->m_brush_paint->SearchEditPoint( m_coord_graphics->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root ).Transform( p->m_pos ) , &m_edit_pnt ) )
	{
		m_edit_type	= 1;
		return;
	}
	if( true == Search( &m_edit_pnt , p->m_pos ) )
	{
		m_edit_type	= 0;
		return;
	}
	if( true == m_coord_graphics_base.Search( &m_edit_pnt , p->m_pos ) )
	{
		m_edit_type = 2;
		return;
	}
	if( true == m_coord_source_view.Search( &m_edit_pnt , p->m_pos ) )
	{
		m_edit_type = 4;
		return;
	}
}
//=================================================================================================
void OnLDrag
		(
		LDrag_ViewPM*	p
		)
{
	if( m_edit_pnt == -1 )
		return;
	else if( m_edit_type == 0 )
		SetPoint( m_edit_pnt , p->m_pos );
	else if( m_edit_type == 1 )
		m_brush->m_brush_paint->SetEditPoint( m_edit_pnt , m_coord_graphics->CtoC( value_ipl::logical , value_ipl::logical , (iCoordLayer)m_root ).Transform( p->m_pos ) );
	else if( m_edit_type == 2 )
		m_coord_graphics_base.SetPoint( m_edit_pnt , p->m_pos );
	else if( m_edit_type == 4 )
		m_coord_source_view.SetPoint( m_edit_pnt , p->m_pos );
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
//=================================================================================================
void OnLDragEnd
		(
		LDragEnd_ViewPM*	p
		)
{
	m_edit_type	= -1;
	m_edit_pnt = -1;
}
//=================================================================================================
void OnLDragCancel
		(
		LDragCancel_ViewPM*	p
		)
{
	m_edit_type	= -1;
	m_edit_pnt = -1;
}
// public functions
public:
//=================================================================================================
MainView() : 
		m_handle_r( 1.0f ) , 
		m_edit_type( -1 ) , 
		m_edit_pnt( -1 ) ,
		m_coord_graphics_base( 150.0f )
{
	m_brush_back		= CreatePaintSolid( rgba(255 , 255 , 235 ) );
	m_brush_coord		= CreatePaintSolid( rgba( 0 , 0 , 0 , 255 ) );
	m_brush_handle		= CreatePaintSolid( rgba( 121 , 121 , 40 ) );
	m_brush_handle_lb	= CreatePaintSolid( rgba( 121 , 40 , 121 ) );
	m_pen_coord			= CreatePenStroke( CreateJoint( Bevel_JointType_gp ) , CreateCap( Flat_CapType_gp ) , CreateCapArrow( 4.0f , 3.5f ) );
	m_brush_clip		= CreatePaintSolid( rgba(200 , 100 , 50 ) );
	m_pen_handle		= CreatePenStroke();
	m_brush_coord_source= CreatePaintSolid( rgba(50,50,160) );

	m_rect[0]	= frect( fvector2( 0.0f , 0.0f ) , fsize( 10.0f , 10.0f ) );
	m_rect[1]	= frect( fvector2( 5.0f , 5.0f ) , fsize( 25.0f , 25.0f ) );
	m_rect[2]	= frect( fvector2( -30.0f , 5.0f ) , fsize( 25.0f , 25.0f ) );
	m_pnt[0]	= fvector2( -40.0f , 0.0f );
	m_pnt[1]	= fvector2( -40.0f , -40.0f );
	m_pnt[2]	= fvector2( 40.0f , -40.0f );
	m_pnt[3]	= fvector2( 40.0f , 0.0f );
	m_pnt[4]	= fvector2( 40.0f , 40.0f );
	m_pnt[5]	= fvector2( 0.0f , 40.0f );
	m_pnt[6]	= fvector2( -40.0f , 40.0f );
	m_pnt[7]	= fvector2( -30.0f , -30.0f );
	m_pnt[8]	= fvector2( -5.0f , -30.0f );
	m_pnt[9]	= fvector2( -5.0f , -5.0f );
	m_pnt[10]	= fvector2( -30.0f , -5.0f );
	m_pnt[11]	= fvector2( 5.0f , -30.0f );
}
//=================================================================================================
bool Initialize
		(
		const wstring&	folder
		)
{
	wstring		material;
	if( 0xFFFFFFFF == GetFileAttributesW( ( folder + L"../../../../material" ).c_str() ) )
		material = folder + L"material/";
	else
		material = folder + L"../../../../material/";
		
	int		off;
	for( off = 0 ; off < 4 ; off++ )
	{
		wchar_t		path[ 256 ];
		cb_swprintf( path , L"tex%d.psd" , off );
		if( false == m_brush->m_brush_paint->AddTexture( material + path ) )
		{
			MessageBox( wstring( L"can't open file: " ) + path , L"error" );
			return false;
		}
	}
	{
		const wchar_t*	path	= L"tex4.psd";
		instance< FileReader >			file;
		if( false == file->Open( ( material + path ).c_str() ) )
		{
			MessageBox( wstring( L"can't open file: " ) + path , L"error" );
			return false;
		}
		instance< LoaderImagefile_psd >	loader;
		if( false == loader->Load( ( iFileStreamRead )file ) )
		{
			MessageBox( wstring( L"can't load file: " ) + path , L"error" );
			return false;
		}
		iSurface	surface	= CreateSurface( loader->GetImageSize( 0 ) , rgba_pixelformat , loader->GetImageDPI( 0 ) );
		if( surface->GetDestAvailableArea() != irect( ivector2( 0 , 0 ) , loader->GetImageSize( 0 ) ) )
		{
			MessageBox( wstring( L"can't load file: " ) + path , L"error" );
			return false;
		}
		int		pitchbyte;
		void	*p = surface->GetDestPixelPtr( &pitchbyte );
		loader->GetImage( 0 , surface->GetDestFormat() , p , pitchbyte );
		m_source->SetTexture( (iSurfaceSource)surface );
	}
	{
		m_root						= (iDeviceCoordLayer)instance<DeviceCoordLayer>();
		iSubCoordLayer	center		= m_root->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
		center->m_unit				= unit_ip( value_ip::px , 1.0f , 1.0f );
		center->m_org				= point_iplr( value_iplr::ratio , fvector2( 0.5f , 0.3f ) );

		iCoordLayer		t			= m_coord_graphics_base.SetCoord( (iCoordLayer)center );
		m_coord_graphics			= t->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
		m_coord_graphics->m_unit	= unit_ip( value_ip::inch , 0.03937f , 0.03937f );
		m_coord_graphics->m_org		= point_iplr( value_iplr::ratio , fvector2( 0.0f , 0.0f ) );

		center						= m_root->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
		center->m_unit				= unit_ip( value_ip::px , 1.0f , 1.0f );
		center->m_org				= point_iplr( value_iplr::ratio , fvector2( 0.5f , 0.7f ) );

		t							= m_coord_source_view.SetCoord( (iCoordLayer)center , (iTexture)m_source );
		m_coord_source_draw			= t->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
		m_coord_source_draw->m_unit	= unit_ip( value_ip::inch , 0.03937f , 0.03937f );
		m_coord_source_draw->m_org	= point_iplr( value_iplr::logical , fvector2( 0.0f , 0.0f ) );

		DPI		dpi	= m_source->TextureDPI();
		m_coord_source_pixel		= t->AddChild( (iCoordLayer)instance<SubCoordLayer>() );
		m_coord_source_pixel->m_unit= unit_ip( value_ip::inch , 1.0f/dpi[0] , 1.0f/dpi[1] );
		m_coord_source_pixel->m_org	= point_iplr( value_iplr::logical , fvector2( 0.0f , 0.0f ) );
	}
	return true;
}
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define





